xref: /vim-8.2.3635/src/ex_cmds2.c (revision 5eb86f91)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * ex_cmds2.c: some more functions for command line commands
12  */
13 
14 #if defined(WIN32) && defined(FEAT_CSCOPE)
15 # include <io.h>
16 #endif
17 
18 #include "vim.h"
19 
20 #if defined(WIN32) && defined(FEAT_CSCOPE)
21 # include <fcntl.h>
22 #endif
23 
24 #include "version.h"
25 
26 static void	cmd_source __ARGS((char_u *fname, exarg_T *eap));
27 
28 #if defined(FEAT_EVAL) || defined(PROTO)
29 static int debug_greedy = FALSE;	/* batch mode debugging: don't save
30 					   and restore typeahead. */
31 
32 /*
33  * do_debug(): Debug mode.
34  * Repeatedly get Ex commands, until told to continue normal execution.
35  */
36     void
37 do_debug(cmd)
38     char_u	*cmd;
39 {
40     int		save_msg_scroll = msg_scroll;
41     int		save_State = State;
42     int		save_did_emsg = did_emsg;
43     int		save_cmd_silent = cmd_silent;
44     int		save_msg_silent = msg_silent;
45     int		save_emsg_silent = emsg_silent;
46     int		save_redir_off = redir_off;
47     tasave_T	typeaheadbuf;
48 # ifdef FEAT_EX_EXTRA
49     int		save_ex_normal_busy;
50 # endif
51     int		n;
52     char_u	*cmdline = NULL;
53     char_u	*p;
54     char	*tail = NULL;
55     static int	last_cmd = 0;
56 #define CMD_CONT	1
57 #define CMD_NEXT	2
58 #define CMD_STEP	3
59 #define CMD_FINISH	4
60 #define CMD_QUIT	5
61 #define CMD_INTERRUPT	6
62 
63 #ifdef ALWAYS_USE_GUI
64     /* Can't do this when there is no terminal for input/output. */
65     if (!gui.in_use)
66     {
67 	/* Break as soon as possible. */
68 	debug_break_level = 9999;
69 	return;
70     }
71 #endif
72 
73     /* Make sure we are in raw mode and start termcap mode.  Might have side
74      * effects... */
75     settmode(TMODE_RAW);
76     starttermcap();
77 
78     ++RedrawingDisabled;	/* don't redisplay the window */
79     ++no_wait_return;		/* don't wait for return */
80     did_emsg = FALSE;		/* don't use error from debugged stuff */
81     cmd_silent = FALSE;		/* display commands */
82     msg_silent = FALSE;		/* display messages */
83     emsg_silent = FALSE;	/* display error messages */
84     redir_off = TRUE;		/* don't redirect debug commands */
85 
86     State = NORMAL;
87 #ifdef FEAT_SNIFF
88     want_sniff_request = 0;    /* No K_SNIFF wanted */
89 #endif
90 
91     if (!debug_did_msg)
92 	MSG(_("Entering Debug mode.  Type \"cont\" to continue."));
93     if (sourcing_name != NULL)
94 	msg(sourcing_name);
95     if (sourcing_lnum != 0)
96 	smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
97     else
98 	msg_str((char_u *)_("cmd: %s"), cmd);
99 
100     /*
101      * Repeat getting a command and executing it.
102      */
103     for (;;)
104     {
105 	msg_scroll = TRUE;
106 	need_wait_return = FALSE;
107 #ifdef FEAT_SNIFF
108 	ProcessSniffRequests();
109 #endif
110 	/* Save the current typeahead buffer and replace it with an empty one.
111 	 * This makes sure we get input from the user here and don't interfere
112 	 * with the commands being executed.  Reset "ex_normal_busy" to avoid
113 	 * the side effects of using ":normal". Save the stuff buffer and make
114 	 * it empty. */
115 # ifdef FEAT_EX_EXTRA
116 	save_ex_normal_busy = ex_normal_busy;
117 	ex_normal_busy = 0;
118 # endif
119 	if (!debug_greedy)
120 	    save_typeahead(&typeaheadbuf);
121 
122 	cmdline = getcmdline_prompt('>', NULL, 0);
123 
124 	if (!debug_greedy)
125 	    restore_typeahead(&typeaheadbuf);
126 # ifdef FEAT_EX_EXTRA
127 	ex_normal_busy = save_ex_normal_busy;
128 # endif
129 
130 	cmdline_row = msg_row;
131 	if (cmdline != NULL)
132 	{
133 	    /* If this is a debug command, set "last_cmd".
134 	     * If not, reset "last_cmd".
135 	     * For a blank line use previous command. */
136 	    p = skipwhite(cmdline);
137 	    if (*p != NUL)
138 	    {
139 		switch (*p)
140 		{
141 		    case 'c': last_cmd = CMD_CONT;
142 			      tail = "ont";
143 			      break;
144 		    case 'n': last_cmd = CMD_NEXT;
145 			      tail = "ext";
146 			      break;
147 		    case 's': last_cmd = CMD_STEP;
148 			      tail = "tep";
149 			      break;
150 		    case 'f': last_cmd = CMD_FINISH;
151 			      tail = "inish";
152 			      break;
153 		    case 'q': last_cmd = CMD_QUIT;
154 			      tail = "uit";
155 			      break;
156 		    case 'i': last_cmd = CMD_INTERRUPT;
157 			      tail = "nterrupt";
158 			      break;
159 		    default: last_cmd = 0;
160 		}
161 		if (last_cmd != 0)
162 		{
163 		    /* Check that the tail matches. */
164 		    ++p;
165 		    while (*p != NUL && *p == *tail)
166 		    {
167 			++p;
168 			++tail;
169 		    }
170 		    if (ASCII_ISALPHA(*p))
171 			last_cmd = 0;
172 		}
173 	    }
174 
175 	    if (last_cmd != 0)
176 	    {
177 		/* Execute debug command: decided where to break next and
178 		 * return. */
179 		switch (last_cmd)
180 		{
181 		    case CMD_CONT:
182 			debug_break_level = -1;
183 			break;
184 		    case CMD_NEXT:
185 			debug_break_level = ex_nesting_level;
186 			break;
187 		    case CMD_STEP:
188 			debug_break_level = 9999;
189 			break;
190 		    case CMD_FINISH:
191 			debug_break_level = ex_nesting_level - 1;
192 			break;
193 		    case CMD_QUIT:
194 			got_int = TRUE;
195 			debug_break_level = -1;
196 			break;
197 		    case CMD_INTERRUPT:
198 			got_int = TRUE;
199 			debug_break_level = 9999;
200 			/* Do not repeat ">interrupt" cmd, continue stepping. */
201 			last_cmd = CMD_STEP;
202 			break;
203 		}
204 		break;
205 	    }
206 
207 	    /* don't debug this command */
208 	    n = debug_break_level;
209 	    debug_break_level = -1;
210 	    (void)do_cmdline(cmdline, getexline, NULL,
211 						DOCMD_VERBOSE|DOCMD_EXCRESET);
212 	    debug_break_level = n;
213 
214 	    vim_free(cmdline);
215 	}
216 	lines_left = Rows - 1;
217     }
218     vim_free(cmdline);
219 
220     --RedrawingDisabled;
221     --no_wait_return;
222     redraw_all_later(NOT_VALID);
223     need_wait_return = FALSE;
224     msg_scroll = save_msg_scroll;
225     lines_left = Rows - 1;
226     State = save_State;
227     did_emsg = save_did_emsg;
228     cmd_silent = save_cmd_silent;
229     msg_silent = save_msg_silent;
230     emsg_silent = save_emsg_silent;
231     redir_off = save_redir_off;
232 
233     /* Only print the message again when typing a command before coming back
234      * here. */
235     debug_did_msg = TRUE;
236 }
237 
238 /*
239  * ":debug".
240  */
241     void
242 ex_debug(eap)
243     exarg_T	*eap;
244 {
245     int		debug_break_level_save = debug_break_level;
246 
247     debug_break_level = 9999;
248     do_cmdline_cmd(eap->arg);
249     debug_break_level = debug_break_level_save;
250 }
251 
252 static char_u	*debug_breakpoint_name = NULL;
253 static linenr_T	debug_breakpoint_lnum;
254 
255 /*
256  * When debugging or a breakpoint is set on a skipped command, no debug prompt
257  * is shown by do_one_cmd().  This situation is indicated by debug_skipped, and
258  * debug_skipped_name is then set to the source name in the breakpoint case.  If
259  * a skipped command decides itself that a debug prompt should be displayed, it
260  * can do so by calling dbg_check_skipped().
261  */
262 static int	debug_skipped;
263 static char_u	*debug_skipped_name;
264 
265 /*
266  * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
267  * at or below the break level.  But only when the line is actually
268  * executed.  Return TRUE and set breakpoint_name for skipped commands that
269  * decide to execute something themselves.
270  * Called from do_one_cmd() before executing a command.
271  */
272     void
273 dbg_check_breakpoint(eap)
274     exarg_T	*eap;
275 {
276     char_u	*p;
277 
278     debug_skipped = FALSE;
279     if (debug_breakpoint_name != NULL)
280     {
281 	if (!eap->skip)
282 	{
283 	    /* replace K_SNR with "<SNR>" */
284 	    if (debug_breakpoint_name[0] == K_SPECIAL
285 		    && debug_breakpoint_name[1] == KS_EXTRA
286 		    && debug_breakpoint_name[2] == (int)KE_SNR)
287 		p = (char_u *)"<SNR>";
288 	    else
289 		p = (char_u *)"";
290 	    smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"), p,
291 		    debug_breakpoint_name + (*p == NUL ? 0 : 3),
292 		    (long)debug_breakpoint_lnum);
293 	    debug_breakpoint_name = NULL;
294 	    do_debug(eap->cmd);
295 	}
296 	else
297 	{
298 	    debug_skipped = TRUE;
299 	    debug_skipped_name = debug_breakpoint_name;
300 	    debug_breakpoint_name = NULL;
301 	}
302     }
303     else if (ex_nesting_level <= debug_break_level)
304     {
305 	if (!eap->skip)
306 	    do_debug(eap->cmd);
307 	else
308 	{
309 	    debug_skipped = TRUE;
310 	    debug_skipped_name = NULL;
311 	}
312     }
313 }
314 
315 /*
316  * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
317  * set.  Return TRUE when the debug mode is entered this time.
318  */
319     int
320 dbg_check_skipped(eap)
321     exarg_T	*eap;
322 {
323     int		prev_got_int;
324 
325     if (debug_skipped)
326     {
327 	/*
328 	 * Save the value of got_int and reset it.  We don't want a previous
329 	 * interruption cause flushing the input buffer.
330 	 */
331 	prev_got_int = got_int;
332 	got_int = FALSE;
333 	debug_breakpoint_name = debug_skipped_name;
334 	/* eap->skip is TRUE */
335 	eap->skip = FALSE;
336 	(void)dbg_check_breakpoint(eap);
337 	eap->skip = TRUE;
338 	got_int |= prev_got_int;
339 	return TRUE;
340     }
341     return FALSE;
342 }
343 
344 /*
345  * The list of breakpoints: dbg_breakp.
346  * This is a grow-array of structs.
347  */
348 struct debuggy
349 {
350     int		dbg_nr;		/* breakpoint number */
351     int		dbg_type;	/* DBG_FUNC or DBG_FILE */
352     char_u	*dbg_name;	/* function or file name */
353     regprog_T	*dbg_prog;	/* regexp program */
354     linenr_T	dbg_lnum;	/* line number in function or file */
355 };
356 
357 static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
358 #define BREAKP(idx)	(((struct debuggy *)dbg_breakp.ga_data)[idx])
359 static int last_breakp = 0;	/* nr of last defined breakpoint */
360 
361 #define DBG_FUNC	1
362 #define DBG_FILE	2
363 
364 static int dbg_parsearg __ARGS((char_u *arg));
365 
366 /*
367  * Parse the arguments of ":breakadd" or ":breakdel" and put them in the entry
368  * just after the last one in dbg_breakp.  Note that "dbg_name" is allocated.
369  * Returns FAIL for failure.
370  */
371     static int
372 dbg_parsearg(arg)
373     char_u	*arg;
374 {
375     char_u	*p = arg;
376     char_u	*q;
377     struct debuggy *bp;
378     int		here = FALSE;
379 
380     if (ga_grow(&dbg_breakp, 1) == FAIL)
381 	return FAIL;
382     bp = &BREAKP(dbg_breakp.ga_len);
383 
384     /* Find "func" or "file". */
385     if (STRNCMP(p, "func", 4) == 0)
386 	bp->dbg_type = DBG_FUNC;
387     else if (STRNCMP(p, "file", 4) == 0)
388 	bp->dbg_type = DBG_FILE;
389     else if (STRNCMP(p, "here", 4) == 0)
390     {
391 	if (curbuf->b_ffname == NULL)
392 	{
393 	    EMSG(_(e_noname));
394 	    return FAIL;
395 	}
396 	bp->dbg_type = DBG_FILE;
397 	here = TRUE;
398     }
399     else
400     {
401 	EMSG2(_(e_invarg2), p);
402 	return FAIL;
403     }
404     p = skipwhite(p + 4);
405 
406     /* Find optional line number. */
407     if (here)
408 	bp->dbg_lnum = curwin->w_cursor.lnum;
409     else if (VIM_ISDIGIT(*p))
410     {
411 	bp->dbg_lnum = getdigits(&p);
412 	p = skipwhite(p);
413     }
414     else
415 	bp->dbg_lnum = 0;
416 
417     /* Find the function or file name.  Don't accept a function name with (). */
418     if ((!here && *p == NUL)
419 	    || (here && *p != NUL)
420 	    || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
421     {
422 	EMSG2(_(e_invarg2), arg);
423 	return FAIL;
424     }
425 
426     if (bp->dbg_type == DBG_FUNC)
427 	bp->dbg_name = vim_strsave(p);
428     else if (here)
429 	bp->dbg_name = vim_strsave(curbuf->b_ffname);
430     else
431     {
432 	/* Expand the file name in the same way as do_source().  This means
433 	 * doing it twice, so that $DIR/file gets expanded when $DIR is
434 	 * "~/dir". */
435 #ifdef RISCOS
436 	q = mch_munge_fname(p);
437 #else
438 	q = expand_env_save(p);
439 #endif
440 	if (q == NULL)
441 	    return FAIL;
442 #ifdef RISCOS
443 	p = mch_munge_fname(q);
444 #else
445 	p = expand_env_save(q);
446 #endif
447 	vim_free(q);
448 	if (p == NULL)
449 	    return FAIL;
450 	if (*p != '*')
451 	{
452 	    bp->dbg_name = fix_fname(p);
453 	    vim_free(p);
454 	}
455 	else
456 	    bp->dbg_name = p;
457 #ifdef MACOS_CLASSIC
458 	if (bp->dbg_name != NULL)
459 	    slash_n_colon_adjust(bp->dbg_name);
460 #endif
461     }
462 
463     if (bp->dbg_name == NULL)
464 	return FAIL;
465     return OK;
466 }
467 
468 /*
469  * ":breakadd".
470  */
471     void
472 ex_breakadd(eap)
473     exarg_T	*eap;
474 {
475     struct debuggy *bp;
476     char_u	*pat;
477 
478     if (dbg_parsearg(eap->arg) == OK)
479     {
480 	bp = &BREAKP(dbg_breakp.ga_len);
481 	pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
482 	if (pat != NULL)
483 	{
484 	    bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
485 	    vim_free(pat);
486 	}
487 	if (pat == NULL || bp->dbg_prog == NULL)
488 	    vim_free(bp->dbg_name);
489 	else
490 	{
491 	    if (bp->dbg_lnum == 0)	/* default line number is 1 */
492 		bp->dbg_lnum = 1;
493 	    BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp;
494 	    --dbg_breakp.ga_room;
495 	    ++debug_tick;
496 	}
497     }
498 }
499 
500 /*
501  * ":debuggreedy".
502  */
503     void
504 ex_debuggreedy(eap)
505     exarg_T	*eap;
506 {
507     if (eap->addr_count == 0 || eap->line2 != 0)
508 	debug_greedy = TRUE;
509     else
510 	debug_greedy = FALSE;
511 }
512 
513 /*
514  * ":breakdel".
515  */
516     void
517 ex_breakdel(eap)
518     exarg_T	*eap;
519 {
520     struct debuggy *bp, *bpi;
521     int		nr;
522     int		todel = -1;
523     int		i;
524     linenr_T	best_lnum = 0;
525 
526     if (vim_isdigit(*eap->arg))
527     {
528 	/* ":breakdel {nr}" */
529 	nr = atol((char *)eap->arg);
530 	for (i = 0; i < dbg_breakp.ga_len; ++i)
531 	    if (BREAKP(i).dbg_nr == nr)
532 	    {
533 		todel = i;
534 		break;
535 	    }
536     }
537     else
538     {
539 	/* ":breakdel {func|file} [lnum] {name}" */
540 	if (dbg_parsearg(eap->arg) == FAIL)
541 	    return;
542 	bp = &BREAKP(dbg_breakp.ga_len);
543 	for (i = 0; i < dbg_breakp.ga_len; ++i)
544 	{
545 	    bpi = &BREAKP(i);
546 	    if (bp->dbg_type == bpi->dbg_type
547 		    && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
548 		    && (bp->dbg_lnum == bpi->dbg_lnum
549 			|| (bp->dbg_lnum == 0
550 			    && (best_lnum == 0
551 				|| bpi->dbg_lnum < best_lnum))))
552 	    {
553 		todel = i;
554 		best_lnum = bpi->dbg_lnum;
555 	    }
556 	}
557 	vim_free(bp->dbg_name);
558     }
559 
560     if (todel < 0)
561 	EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
562     else
563     {
564 	vim_free(BREAKP(todel).dbg_name);
565 	vim_free(BREAKP(todel).dbg_prog);
566 	--dbg_breakp.ga_len;
567 	++dbg_breakp.ga_room;
568 	if (todel < dbg_breakp.ga_len)
569 	    mch_memmove(&BREAKP(todel), &BREAKP(todel + 1),
570 		    (dbg_breakp.ga_len - todel) * sizeof(struct debuggy));
571 	++debug_tick;
572     }
573 }
574 
575 /*
576  * ":breaklist".
577  */
578 /*ARGSUSED*/
579     void
580 ex_breaklist(eap)
581     exarg_T	*eap;
582 {
583     struct debuggy *bp;
584     int		i;
585 
586     if (dbg_breakp.ga_len == 0)
587 	MSG(_("No breakpoints defined"));
588     else
589 	for (i = 0; i < dbg_breakp.ga_len; ++i)
590 	{
591 	    bp = &BREAKP(i);
592 	    smsg((char_u *)_("%3d  %s %s  line %ld"),
593 		    bp->dbg_nr,
594 		    bp->dbg_type == DBG_FUNC ? "func" : "file",
595 		    bp->dbg_name,
596 		    (long)bp->dbg_lnum);
597 	}
598 }
599 
600 /*
601  * Find a breakpoint for a function or sourced file.
602  * Returns line number at which to break; zero when no matching breakpoint.
603  */
604     linenr_T
605 dbg_find_breakpoint(file, fname, after)
606     int		file;	    /* TRUE for a file, FALSE for a function */
607     char_u	*fname;	    /* file or function name */
608     linenr_T	after;	    /* after this line number */
609 {
610     struct debuggy *bp;
611     int		i;
612     linenr_T	lnum = 0;
613     regmatch_T	regmatch;
614     char_u	*name = fname;
615     int		prev_got_int;
616 
617     /* Replace K_SNR in function name with "<SNR>". */
618     if (!file && fname[0] == K_SPECIAL)
619     {
620 	name = alloc((unsigned)STRLEN(fname) + 3);
621 	if (name == NULL)
622 	    name = fname;
623 	else
624 	{
625 	    STRCPY(name, "<SNR>");
626 	    STRCPY(name + 5, fname + 3);
627 	}
628     }
629 
630     for (i = 0; i < dbg_breakp.ga_len; ++i)
631     {
632 	/* skip entries that are not useful or are for a line that is beyond
633 	 * an already found breakpoint */
634 	bp = &BREAKP(i);
635 	if ((bp->dbg_type == DBG_FILE) == file
636 		&& bp->dbg_lnum > after
637 		&& (lnum == 0 || bp->dbg_lnum < lnum))
638 	{
639 	    regmatch.regprog = bp->dbg_prog;
640 	    regmatch.rm_ic = FALSE;
641 	    /*
642 	     * Save the value of got_int and reset it.  We don't want a previous
643 	     * interruption cancel matching, only hitting CTRL-C while matching
644 	     * should abort it.
645 	     */
646 	    prev_got_int = got_int;
647 	    got_int = FALSE;
648 	    if (vim_regexec(&regmatch, name, (colnr_T)0))
649 		lnum = bp->dbg_lnum;
650 	    got_int |= prev_got_int;
651 	}
652     }
653     if (name != fname)
654 	vim_free(name);
655 
656     return lnum;
657 }
658 
659 /*
660  * Called when a breakpoint was encountered.
661  */
662     void
663 dbg_breakpoint(name, lnum)
664     char_u	*name;
665     linenr_T	lnum;
666 {
667     /* We need to check if this line is actually executed in do_one_cmd() */
668     debug_breakpoint_name = name;
669     debug_breakpoint_lnum = lnum;
670 }
671 #endif
672 
673 /*
674  * If 'autowrite' option set, try to write the file.
675  * Careful: autocommands may make "buf" invalid!
676  *
677  * return FAIL for failure, OK otherwise
678  */
679     int
680 autowrite(buf, forceit)
681     buf_T	*buf;
682     int		forceit;
683 {
684     if (!(p_aw || p_awa) || !p_write
685 #ifdef FEAT_QUICKFIX
686 	/* never autowrite a "nofile" or "nowrite" buffer */
687 	|| bt_dontwrite(buf)
688 #endif
689 	|| (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
690 	return FAIL;
691     return buf_write_all(buf, forceit);
692 }
693 
694 /*
695  * flush all buffers, except the ones that are readonly
696  */
697     void
698 autowrite_all()
699 {
700     buf_T	*buf;
701 
702     if (!(p_aw || p_awa) || !p_write)
703 	return;
704     for (buf = firstbuf; buf; buf = buf->b_next)
705 	if (bufIsChanged(buf) && !buf->b_p_ro)
706 	{
707 	    (void)buf_write_all(buf, FALSE);
708 #ifdef FEAT_AUTOCMD
709 	    /* an autocommand may have deleted the buffer */
710 	    if (!buf_valid(buf))
711 		buf = firstbuf;
712 #endif
713 	}
714 }
715 
716 /*
717  * return TRUE if buffer was changed and cannot be abandoned.
718  */
719 /*ARGSUSED*/
720     int
721 check_changed(buf, checkaw, mult_win, forceit, allbuf)
722     buf_T	*buf;
723     int		checkaw;	/* do autowrite if buffer was changed */
724     int		mult_win;	/* check also when several wins for the buf */
725     int		forceit;
726     int		allbuf;		/* may write all buffers */
727 {
728     if (       !forceit
729 	    && bufIsChanged(buf)
730 	    && (mult_win || buf->b_nwindows <= 1)
731 	    && (!checkaw || autowrite(buf, forceit) == FAIL))
732     {
733 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
734 	if ((p_confirm || cmdmod.confirm) && p_write)
735 	{
736 	    buf_T	*buf2;
737 	    int		count = 0;
738 
739 	    if (allbuf)
740 		for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
741 		    if (bufIsChanged(buf2)
742 				     && (buf2->b_ffname != NULL
743 # ifdef FEAT_BROWSE
744 					 || cmdmod.browse
745 # endif
746 					))
747 			++count;
748 # ifdef FEAT_AUTOCMD
749 	    if (!buf_valid(buf))
750 		/* Autocommand deleted buffer, oops!  It's not changed now. */
751 		return FALSE;
752 # endif
753 	    dialog_changed(buf, count > 1);
754 # ifdef FEAT_AUTOCMD
755 	    if (!buf_valid(buf))
756 		/* Autocommand deleted buffer, oops!  It's not changed now. */
757 		return FALSE;
758 # endif
759 	    return bufIsChanged(buf);
760 	}
761 #endif
762 	EMSG(_(e_nowrtmsg));
763 	return TRUE;
764     }
765     return FALSE;
766 }
767 
768 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
769 
770 #if defined(FEAT_BROWSE) || defined(PROTO)
771 /*
772  * When wanting to write a file without a file name, ask the user for a name.
773  */
774     void
775 browse_save_fname(buf)
776     buf_T	*buf;
777 {
778     if (buf->b_fname == NULL)
779     {
780 	char_u *fname;
781 
782 	fname = do_browse(TRUE, (char_u *)_("Save As"), NULL, NULL, NULL,
783 								   NULL, buf);
784 	if (fname != NULL)
785 	{
786 	    if (setfname(buf, fname, NULL, TRUE) == OK)
787 		buf->b_flags |= BF_NOTEDITED;
788 	    vim_free(fname);
789 	}
790     }
791 }
792 #endif
793 
794 /*
795  * Ask the user what to do when abondoning a changed buffer.
796  * Must check 'write' option first!
797  */
798     void
799 dialog_changed(buf, checkall)
800     buf_T	*buf;
801     int		checkall;	/* may abandon all changed buffers */
802 {
803     char_u	buff[IOSIZE];
804     int		ret;
805     buf_T	*buf2;
806 
807     dialog_msg(buff, _("Save changes to \"%.*s\"?"),
808 			(buf->b_fname != NULL) ?
809 			buf->b_fname : (char_u *)_("Untitled"));
810     if (checkall)
811 	ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
812     else
813 	ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
814 
815     if (ret == VIM_YES)
816     {
817 #ifdef FEAT_BROWSE
818 	/* May get file name, when there is none */
819 	browse_save_fname(buf);
820 #endif
821 	if (buf->b_fname != NULL)   /* didn't hit Cancel */
822 	    (void)buf_write_all(buf, FALSE);
823     }
824     else if (ret == VIM_NO)
825     {
826 	unchanged(buf, TRUE);
827     }
828     else if (ret == VIM_ALL)
829     {
830 	/*
831 	 * Write all modified files that can be written.
832 	 * Skip readonly buffers, these need to be confirmed
833 	 * individually.
834 	 */
835 	for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
836 	{
837 	    if (bufIsChanged(buf2)
838 		    && (buf2->b_ffname != NULL
839 #ifdef FEAT_BROWSE
840 			|| cmdmod.browse
841 #endif
842 			)
843 		    && !buf2->b_p_ro)
844 	    {
845 #ifdef FEAT_BROWSE
846 		/* May get file name, when there is none */
847 		browse_save_fname(buf2);
848 #endif
849 		if (buf2->b_fname != NULL)   /* didn't hit Cancel */
850 		    (void)buf_write_all(buf2, FALSE);
851 #ifdef FEAT_AUTOCMD
852 		/* an autocommand may have deleted the buffer */
853 		if (!buf_valid(buf2))
854 		    buf2 = firstbuf;
855 #endif
856 	    }
857 	}
858     }
859     else if (ret == VIM_DISCARDALL)
860     {
861 	/*
862 	 * mark all buffers as unchanged
863 	 */
864 	for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
865 	    unchanged(buf2, TRUE);
866     }
867 }
868 #endif
869 
870 /*
871  * Return TRUE if the buffer "buf" can be abandoned, either by making it
872  * hidden, autowriting it or unloading it.
873  */
874     int
875 can_abandon(buf, forceit)
876     buf_T	*buf;
877     int		forceit;
878 {
879     return (	   P_HID(buf)
880 		|| !bufIsChanged(buf)
881 		|| buf->b_nwindows > 1
882 		|| autowrite(buf, forceit) == OK
883 		|| forceit);
884 }
885 
886 /*
887  * Return TRUE if any buffer was changed and cannot be abandoned.
888  * That changed buffer becomes the current buffer.
889  */
890     int
891 check_changed_any(hidden)
892     int		hidden;		/* Only check hidden buffers */
893 {
894     buf_T	*buf;
895     int		save;
896 #ifdef FEAT_WINDOWS
897     win_T	*wp;
898 #endif
899 
900     for (;;)
901     {
902 	/* check curbuf first: if it was changed we can't abandon it */
903 	if (!hidden && curbufIsChanged())
904 	    buf = curbuf;
905 	else
906 	{
907 	    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
908 		if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
909 		    break;
910 	}
911 	if (buf == NULL)    /* No buffers changed */
912 	    return FALSE;
913 
914 	if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
915 	    break;	    /* didn't save - still changes */
916     }
917 
918     exiting = FALSE;
919 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
920     /*
921      * When ":confirm" used, don't give an error message.
922      */
923     if (!(p_confirm || cmdmod.confirm))
924 #endif
925     {
926 	/* There must be a wait_return for this message, do_buffer()
927 	 * may cause a redraw.  But wait_return() is a no-op when vgetc()
928 	 * is busy (Quit used from window menu), then make sure we don't
929 	 * cause a scroll up. */
930 	if (vgetc_busy)
931 	{
932 	    msg_row = cmdline_row;
933 	    msg_col = 0;
934 	    msg_didout = FALSE;
935 	}
936 	if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
937 		    buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
938 		    buf->b_fname))
939 	{
940 	    save = no_wait_return;
941 	    no_wait_return = FALSE;
942 	    wait_return(FALSE);
943 	    no_wait_return = save;
944 	}
945     }
946 
947 #ifdef FEAT_WINDOWS
948     /* Try to find a window that contains the buffer. */
949     if (buf != curbuf)
950 	for (wp = firstwin; wp != NULL; wp = wp->w_next)
951 	    if (wp->w_buffer == buf)
952 	    {
953 		win_goto(wp);
954 # ifdef FEAT_AUTOCMD
955 		/* Paranoia: did autocms wipe out the buffer with changes? */
956 		if (!buf_valid(buf))
957 		    return TRUE;
958 # endif
959 		break;
960 	    }
961 #endif
962 
963     /* Open the changed buffer in the current window. */
964     if (buf != curbuf)
965 	set_curbuf(buf, DOBUF_GOTO);
966 
967     return TRUE;
968 }
969 
970 /*
971  * return FAIL if there is no file name, OK if there is one
972  * give error message for FAIL
973  */
974     int
975 check_fname()
976 {
977     if (curbuf->b_ffname == NULL)
978     {
979 	EMSG(_(e_noname));
980 	return FAIL;
981     }
982     return OK;
983 }
984 
985 /*
986  * flush the contents of a buffer, unless it has no file name
987  *
988  * return FAIL for failure, OK otherwise
989  */
990     int
991 buf_write_all(buf, forceit)
992     buf_T	*buf;
993     int		forceit;
994 {
995     int	    retval;
996 #ifdef FEAT_AUTOCMD
997     buf_T	*old_curbuf = curbuf;
998 #endif
999 
1000     retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1001 				   (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1002 						  FALSE, forceit, TRUE, FALSE));
1003 #ifdef FEAT_AUTOCMD
1004     if (curbuf != old_curbuf)
1005     {
1006 	msg_source(hl_attr(HLF_W));
1007 	MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
1008     }
1009 #endif
1010     return retval;
1011 }
1012 
1013 /*
1014  * Code to handle the argument list.
1015  */
1016 
1017 /*
1018  * Isolate one argument, taking quotes and backticks.
1019  * Changes the argument in-place, puts a NUL after it.
1020  * Quotes are removed, backticks remain.
1021  * Return a pointer to the start of the next argument.
1022  */
1023     char_u *
1024 do_one_arg(str)
1025     char_u *str;
1026 {
1027     char_u	*p;
1028     int		inquote;
1029     int		inbacktick;
1030 
1031     inquote = FALSE;
1032     inbacktick = FALSE;
1033     for (p = str; *str; ++str)
1034     {
1035 	/*
1036 	 * for MSDOS et.al. a backslash is part of a file name.
1037 	 * Only skip ", space and tab.
1038 	 */
1039 	if (rem_backslash(str))
1040 	{
1041 	    *p++ = *str++;
1042 	    *p++ = *str;
1043 	}
1044 	else
1045 	{
1046 	    /* An item ends at a space not in quotes or backticks */
1047 	    if (!inquote && !inbacktick && vim_isspace(*str))
1048 		break;
1049 	    if (!inquote && *str == '`')
1050 		inbacktick ^= TRUE;
1051 	    if (!inbacktick && *str == '"')
1052 		inquote ^= TRUE;
1053 	    else
1054 		*p++ = *str;
1055 	}
1056     }
1057     str = skipwhite(str);
1058     *p = NUL;
1059 
1060     return str;
1061 }
1062 
1063 static int do_arglist __ARGS((char_u *str, int what, int after));
1064 static void alist_check_arg_idx __ARGS((void));
1065 #ifdef FEAT_LISTCMDS
1066 static int alist_add_list __ARGS((int count, char_u **files, int after));
1067 #endif
1068 #define AL_SET	1
1069 #define AL_ADD	2
1070 #define AL_DEL	3
1071 
1072 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1073 /*
1074  * Redefine the argument list.
1075  */
1076     void
1077 set_arglist(str)
1078     char_u	*str;
1079 {
1080     do_arglist(str, AL_SET, 0);
1081 }
1082 #endif
1083 
1084 /*
1085  * "what" == AL_SET: Redefine the argument list to 'str'.
1086  * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1087  * "what" == AL_DEL: remove files in 'str' from the argument list.
1088  *
1089  * Return FAIL for failure, OK otherwise.
1090  */
1091 /*ARGSUSED*/
1092     static int
1093 do_arglist(str, what, after)
1094     char_u	*str;
1095     int		what;
1096     int		after;		/* 0 means before first one */
1097 {
1098     garray_T	new_ga;
1099     int		exp_count;
1100     char_u	**exp_files;
1101     int		i;
1102 #ifdef FEAT_LISTCMDS
1103     char_u	*p;
1104     int		match;
1105 #endif
1106 
1107     /*
1108      * Collect all file name arguments in "new_ga".
1109      */
1110     ga_init2(&new_ga, (int)sizeof(char_u *), 20);
1111     while (*str)
1112     {
1113 	if (ga_grow(&new_ga, 1) == FAIL)
1114 	{
1115 	    ga_clear(&new_ga);
1116 	    return FAIL;
1117 	}
1118 	((char_u **)new_ga.ga_data)[new_ga.ga_len++] = str;
1119 	--new_ga.ga_room;
1120 
1121 	/* Isolate one argument, change it in-place, put a NUL after it. */
1122 	str = do_one_arg(str);
1123     }
1124 
1125 #ifdef FEAT_LISTCMDS
1126     if (what == AL_DEL)
1127     {
1128 	regmatch_T	regmatch;
1129 	int		didone;
1130 
1131 	/*
1132 	 * Delete the items: use each item as a regexp and find a match in the
1133 	 * argument list.
1134 	 */
1135 #ifdef CASE_INSENSITIVE_FILENAME
1136 	regmatch.rm_ic = TRUE;		/* Always ignore case */
1137 #else
1138 	regmatch.rm_ic = FALSE;		/* Never ignore case */
1139 #endif
1140 	for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1141 	{
1142 	    p = ((char_u **)new_ga.ga_data)[i];
1143 	    p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1144 	    if (p == NULL)
1145 		break;
1146 	    regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1147 	    if (regmatch.regprog == NULL)
1148 	    {
1149 		vim_free(p);
1150 		break;
1151 	    }
1152 
1153 	    didone = FALSE;
1154 	    for (match = 0; match < ARGCOUNT; ++match)
1155 		if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1156 								  (colnr_T)0))
1157 		{
1158 		    didone = TRUE;
1159 		    vim_free(ARGLIST[match].ae_fname);
1160 		    mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1161 			    (ARGCOUNT - match - 1) * sizeof(aentry_T));
1162 		    --ALIST(curwin)->al_ga.ga_len;
1163 		    ++ALIST(curwin)->al_ga.ga_room;
1164 		    if (curwin->w_arg_idx > match)
1165 			--curwin->w_arg_idx;
1166 		    --match;
1167 		}
1168 
1169 	    vim_free(regmatch.regprog);
1170 	    vim_free(p);
1171 	    if (!didone)
1172 		EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1173 	}
1174 	ga_clear(&new_ga);
1175     }
1176     else
1177 #endif
1178     {
1179 	i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1180 		&exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1181 	ga_clear(&new_ga);
1182 	if (i == FAIL)
1183 	    return FAIL;
1184 	if (exp_count == 0)
1185 	{
1186 	    EMSG(_(e_nomatch));
1187 	    return FAIL;
1188 	}
1189 
1190 #ifdef FEAT_LISTCMDS
1191 	if (what == AL_ADD)
1192 	{
1193 	    (void)alist_add_list(exp_count, exp_files, after);
1194 	    vim_free(exp_files);
1195 	}
1196 	else /* what == AL_SET */
1197 #endif
1198 	    alist_set(ALIST(curwin), exp_count, exp_files, FALSE);
1199     }
1200 
1201     alist_check_arg_idx();
1202 
1203     return OK;
1204 }
1205 
1206 /*
1207  * Check the validity of the arg_idx for each other window.
1208  */
1209     static void
1210 alist_check_arg_idx()
1211 {
1212 #ifdef FEAT_WINDOWS
1213     win_T	*win;
1214 
1215     for (win = firstwin; win != NULL; win = win->w_next)
1216 	if (win->w_alist == curwin->w_alist)
1217 	    check_arg_idx(win);
1218 #else
1219     check_arg_idx(curwin);
1220 #endif
1221 }
1222 
1223 /*
1224  * Check if window "win" is editing the w_arg_idx file in its argument list.
1225  */
1226     void
1227 check_arg_idx(win)
1228     win_T	*win;
1229 {
1230     if (WARGCOUNT(win) > 1
1231 	    && (win->w_arg_idx >= WARGCOUNT(win)
1232 		|| (win->w_buffer->b_fnum
1233 				      != WARGLIST(win)[win->w_arg_idx].ae_fnum
1234 		    && (win->w_buffer->b_ffname == NULL
1235 			 || !(fullpathcmp(
1236 				 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1237 				win->w_buffer->b_ffname, TRUE) & FPC_SAME)))))
1238     {
1239 	/* We are not editing the current entry in the argument list.
1240 	 * Set "arg_had_last" if we are editing the last one. */
1241 	win->w_arg_idx_invalid = TRUE;
1242 	if (win->w_arg_idx != WARGCOUNT(win) - 1
1243 		&& arg_had_last == FALSE
1244 #ifdef FEAT_WINDOWS
1245 		&& ALIST(win) == &global_alist
1246 #endif
1247 		&& GARGCOUNT > 0
1248 		&& win->w_arg_idx < GARGCOUNT
1249 		&& (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1250 		    || (win->w_buffer->b_ffname != NULL
1251 			&& (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1252 				win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1253 	    arg_had_last = TRUE;
1254     }
1255     else
1256     {
1257 	/* We are editing the current entry in the argument list.
1258 	 * Set "arg_had_last" if it's also the last one */
1259 	win->w_arg_idx_invalid = FALSE;
1260 	if (win->w_arg_idx == WARGCOUNT(win) - 1
1261 #ifdef FEAT_WINDOWS
1262 		&& win->w_alist == &global_alist
1263 #endif
1264 		)
1265 	    arg_had_last = TRUE;
1266     }
1267 }
1268 
1269 /*
1270  * ":args", ":argslocal" and ":argsglobal".
1271  */
1272     void
1273 ex_args(eap)
1274     exarg_T	*eap;
1275 {
1276     int		i;
1277 
1278     if (eap->cmdidx != CMD_args)
1279     {
1280 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1281 	alist_unlink(ALIST(curwin));
1282 	if (eap->cmdidx == CMD_argglobal)
1283 	    ALIST(curwin) = &global_alist;
1284 	else /* eap->cmdidx == CMD_arglocal */
1285 	    alist_new();
1286 #else
1287 	ex_ni(eap);
1288 	return;
1289 #endif
1290     }
1291 
1292     if (!ends_excmd(*eap->arg))
1293     {
1294 	/*
1295 	 * ":args file ..": define new argument list, handle like ":next"
1296 	 * Also for ":argslocal file .." and ":argsglobal file ..".
1297 	 */
1298 	ex_next(eap);
1299     }
1300     else
1301 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1302 	if (eap->cmdidx == CMD_args)
1303 #endif
1304     {
1305 	/*
1306 	 * ":args": list arguments.
1307 	 */
1308 	if (ARGCOUNT > 0)
1309 	{
1310 	    /* Overwrite the command, for a short list there is no scrolling
1311 	     * required and no wait_return(). */
1312 	    gotocmdline(TRUE);
1313 	    for (i = 0; i < ARGCOUNT; ++i)
1314 	    {
1315 		if (i == curwin->w_arg_idx)
1316 		    msg_putchar('[');
1317 		msg_outtrans(alist_name(&ARGLIST[i]));
1318 		if (i == curwin->w_arg_idx)
1319 		    msg_putchar(']');
1320 		msg_putchar(' ');
1321 	    }
1322 	}
1323     }
1324 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1325     else if (eap->cmdidx == CMD_arglocal)
1326     {
1327 	garray_T	*gap = &curwin->w_alist->al_ga;
1328 
1329 	/*
1330 	 * ":argslocal": make a local copy of the global argument list.
1331 	 */
1332 	if (ga_grow(gap, GARGCOUNT) == OK)
1333 	    for (i = 0; i < GARGCOUNT; ++i)
1334 		if (GARGLIST[i].ae_fname != NULL)
1335 		{
1336 		    AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1337 					    vim_strsave(GARGLIST[i].ae_fname);
1338 		    AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1339 							  GARGLIST[i].ae_fnum;
1340 		    ++gap->ga_len;
1341 		    --gap->ga_room;
1342 		}
1343     }
1344 #endif
1345 }
1346 
1347 /*
1348  * ":previous", ":sprevious", ":Next" and ":sNext".
1349  */
1350     void
1351 ex_previous(eap)
1352     exarg_T	*eap;
1353 {
1354     /* If past the last one already, go to the last one. */
1355     if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1356 	do_argfile(eap, ARGCOUNT - 1);
1357     else
1358 	do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1359 }
1360 
1361 /*
1362  * ":rewind", ":first", ":sfirst" and ":srewind".
1363  */
1364     void
1365 ex_rewind(eap)
1366     exarg_T	*eap;
1367 {
1368     do_argfile(eap, 0);
1369 }
1370 
1371 /*
1372  * ":last" and ":slast".
1373  */
1374     void
1375 ex_last(eap)
1376     exarg_T	*eap;
1377 {
1378     do_argfile(eap, ARGCOUNT - 1);
1379 }
1380 
1381 /*
1382  * ":argument" and ":sargument".
1383  */
1384     void
1385 ex_argument(eap)
1386     exarg_T	*eap;
1387 {
1388     int		i;
1389 
1390     if (eap->addr_count > 0)
1391 	i = eap->line2 - 1;
1392     else
1393 	i = curwin->w_arg_idx;
1394     do_argfile(eap, i);
1395 }
1396 
1397 /*
1398  * Edit file "argn" of the argument lists.
1399  */
1400     void
1401 do_argfile(eap, argn)
1402     exarg_T	*eap;
1403     int		argn;
1404 {
1405     int		other;
1406     char_u	*p;
1407 
1408     if (argn < 0 || argn >= ARGCOUNT)
1409     {
1410 	if (ARGCOUNT <= 1)
1411 	    EMSG(_("E163: There is only one file to edit"));
1412 	else if (argn < 0)
1413 	    EMSG(_("E164: Cannot go before first file"));
1414 	else
1415 	    EMSG(_("E165: Cannot go beyond last file"));
1416     }
1417     else
1418     {
1419 	setpcmark();
1420 #ifdef FEAT_GUI
1421 	need_mouse_correct = TRUE;
1422 #endif
1423 
1424 #ifdef FEAT_WINDOWS
1425 	if (*eap->cmd == 's')	    /* split window first */
1426 	{
1427 	    if (win_split(0, 0) == FAIL)
1428 		return;
1429 # ifdef FEAT_SCROLLBIND
1430 	    curwin->w_p_scb = FALSE;
1431 # endif
1432 	}
1433 	else
1434 #endif
1435 	{
1436 	    /*
1437 	     * if 'hidden' set, only check for changed file when re-editing
1438 	     * the same buffer
1439 	     */
1440 	    other = TRUE;
1441 	    if (P_HID(curbuf))
1442 	    {
1443 		p = fix_fname(alist_name(&ARGLIST[argn]));
1444 		other = otherfile(p);
1445 		vim_free(p);
1446 	    }
1447 	    if ((!P_HID(curbuf) || !other)
1448 		  && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
1449 		return;
1450 	}
1451 
1452 	curwin->w_arg_idx = argn;
1453 	if (argn == ARGCOUNT - 1
1454 #ifdef FEAT_WINDOWS
1455 		&& curwin->w_alist == &global_alist
1456 #endif
1457 	   )
1458 	    arg_had_last = TRUE;
1459 
1460 	/* Edit the file; always use the last known line number. */
1461 	(void)do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
1462 		      eap, ECMD_LAST,
1463 		      (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
1464 					   (eap->forceit ? ECMD_FORCEIT : 0));
1465 
1466 	/* like Vi: set the mark where the cursor is in the file. */
1467 	if (eap->cmdidx != CMD_argdo)
1468 	    setmark('\'');
1469     }
1470 }
1471 
1472 /*
1473  * ":next", and commands that behave like it.
1474  */
1475     void
1476 ex_next(eap)
1477     exarg_T	*eap;
1478 {
1479     int		i;
1480 
1481     /*
1482      * check for changed buffer now, if this fails the argument list is not
1483      * redefined.
1484      */
1485     if (       P_HID(curbuf)
1486 	    || eap->cmdidx == CMD_snext
1487 	    || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
1488     {
1489 	if (*eap->arg != NUL)		    /* redefine file list */
1490 	{
1491 	    if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
1492 		return;
1493 	    i = 0;
1494 	}
1495 	else
1496 	    i = curwin->w_arg_idx + (int)eap->line2;
1497 	do_argfile(eap, i);
1498     }
1499 }
1500 
1501 #ifdef FEAT_LISTCMDS
1502 /*
1503  * ":argedit"
1504  */
1505     void
1506 ex_argedit(eap)
1507     exarg_T	*eap;
1508 {
1509     int		fnum;
1510     int		i;
1511     char_u	*s;
1512 
1513     /* Add the argument to the buffer list and get the buffer number. */
1514     fnum = buflist_add(eap->arg, BLN_LISTED);
1515 
1516     /* Check if this argument is already in the argument list. */
1517     for (i = 0; i < ARGCOUNT; ++i)
1518 	if (ARGLIST[i].ae_fnum == fnum)
1519 	    break;
1520     if (i == ARGCOUNT)
1521     {
1522 	/* Can't find it, add it to the argument list. */
1523 	s = vim_strsave(eap->arg);
1524 	if (s == NULL)
1525 	    return;
1526 	i = alist_add_list(1, &s,
1527 	       eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
1528 	if (i < 0)
1529 	    return;
1530 	curwin->w_arg_idx = i;
1531     }
1532 
1533     alist_check_arg_idx();
1534 
1535     /* Edit the argument. */
1536     do_argfile(eap, i);
1537 }
1538 
1539 /*
1540  * ":argadd"
1541  */
1542     void
1543 ex_argadd(eap)
1544     exarg_T	*eap;
1545 {
1546     do_arglist(eap->arg, AL_ADD,
1547 	       eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
1548 #ifdef FEAT_TITLE
1549     maketitle();
1550 #endif
1551 }
1552 
1553 /*
1554  * ":argdelete"
1555  */
1556     void
1557 ex_argdelete(eap)
1558     exarg_T	*eap;
1559 {
1560     int		i;
1561     int		n;
1562 
1563     if (eap->addr_count > 0)
1564     {
1565 	/* ":1,4argdel": Delete all arguments in the range. */
1566 	if (eap->line2 > ARGCOUNT)
1567 	    eap->line2 = ARGCOUNT;
1568 	n = eap->line2 - eap->line1 + 1;
1569 	if (*eap->arg != NUL || n <= 0)
1570 	    EMSG(_(e_invarg));
1571 	else
1572 	{
1573 	    for (i = eap->line1; i <= eap->line2; ++i)
1574 		vim_free(ARGLIST[i - 1].ae_fname);
1575 	    mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
1576 			(size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
1577 	    ALIST(curwin)->al_ga.ga_len -= n;
1578 	    ALIST(curwin)->al_ga.ga_room += n;
1579 	    if (curwin->w_arg_idx >= eap->line2)
1580 		curwin->w_arg_idx -= n;
1581 	    else if (curwin->w_arg_idx > eap->line1)
1582 		curwin->w_arg_idx = eap->line1;
1583 	}
1584     }
1585     else if (*eap->arg == NUL)
1586 	EMSG(_(e_argreq));
1587     else
1588 	do_arglist(eap->arg, AL_DEL, 0);
1589 #ifdef FEAT_TITLE
1590     maketitle();
1591 #endif
1592 }
1593 
1594 /*
1595  * ":argdo", ":windo", ":bufdo"
1596  */
1597     void
1598 ex_listdo(eap)
1599     exarg_T	*eap;
1600 {
1601     int		i;
1602 #ifdef FEAT_WINDOWS
1603     win_T	*win;
1604 #endif
1605     buf_T	*buf;
1606     int		next_fnum = 0;
1607 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1608     char_u	*save_ei = NULL;
1609     char_u	*new_ei;
1610 #endif
1611 
1612 #ifndef FEAT_WINDOWS
1613     if (eap->cmdidx == CMD_windo)
1614     {
1615 	ex_ni(eap);
1616 	return;
1617     }
1618 #endif
1619 
1620 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1621     if (eap->cmdidx != CMD_windo)
1622     {
1623 	/* Add "Syntax" to 'eventignore' to skip loading syntax highlighting
1624 	 * for every buffer loaded into the window.  A considerable speed
1625 	 * improvement. */
1626 	save_ei = vim_strsave(p_ei);
1627 	if (save_ei != NULL)
1628 	{
1629 	    new_ei = vim_strnsave(p_ei, (int)STRLEN(p_ei) + 8);
1630 	    if (new_ei != NULL)
1631 	    {
1632 		STRCAT(new_ei, ",Syntax");
1633 		set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
1634 		vim_free(new_ei);
1635 	    }
1636 	}
1637     }
1638 #endif
1639 
1640     if (eap->cmdidx == CMD_windo
1641 	    || P_HID(curbuf)
1642 	    || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
1643     {
1644 	/* start at the first argument/window/buffer */
1645 	i = 0;
1646 #ifdef FEAT_WINDOWS
1647 	win = firstwin;
1648 #endif
1649 	/* set pcmark now */
1650 	if (eap->cmdidx == CMD_bufdo)
1651 	    goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
1652 	else
1653 	    setpcmark();
1654 	listcmd_busy = TRUE;	    /* avoids setting pcmark below */
1655 
1656 	while (!got_int)
1657 	{
1658 	    if (eap->cmdidx == CMD_argdo)
1659 	    {
1660 		/* go to argument "i" */
1661 		if (i == ARGCOUNT)
1662 		    break;
1663 		/* Don't call do_argfile() when already there, it will try
1664 		 * reloading the file. */
1665 		if (curwin->w_arg_idx != i)
1666 		    do_argfile(eap, i);
1667 		if (curwin->w_arg_idx != i)
1668 		    break;
1669 		++i;
1670 	    }
1671 #ifdef FEAT_WINDOWS
1672 	    else if (eap->cmdidx == CMD_windo)
1673 	    {
1674 		/* go to window "win" */
1675 		if (!win_valid(win))
1676 		    break;
1677 		win_goto(win);
1678 		win = win->w_next;
1679 	    }
1680 #endif
1681 	    else if (eap->cmdidx == CMD_bufdo)
1682 	    {
1683 		/* Remember the number of the next listed buffer, in case
1684 		 * ":bwipe" is used or autocommands do something strange. */
1685 		next_fnum = -1;
1686 		for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1687 		    if (buf->b_p_bl)
1688 		    {
1689 			next_fnum = buf->b_fnum;
1690 			break;
1691 		    }
1692 	    }
1693 
1694 	    /* execute the command */
1695 	    do_cmdline(eap->arg, eap->getline, eap->cookie,
1696 						DOCMD_VERBOSE + DOCMD_NOWAIT);
1697 
1698 	    if (eap->cmdidx == CMD_bufdo)
1699 	    {
1700 		/* Done? */
1701 		if (next_fnum < 0)
1702 		    break;
1703 		/* Check if the buffer still exists. */
1704 		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1705 		    if (buf->b_fnum == next_fnum)
1706 			break;
1707 		if (buf == NULL)
1708 		    break;
1709 		goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
1710 		/* If autocommands took us elsewhere, quit here */
1711 		if (curbuf->b_fnum != next_fnum)
1712 		    break;
1713 	    }
1714 
1715 	    if (eap->cmdidx == CMD_windo)
1716 	    {
1717 		validate_cursor();	/* cursor may have moved */
1718 #ifdef FEAT_SCROLLBIND
1719 		/* required when 'scrollbind' has been set */
1720 		if (curwin->w_p_scb)
1721 		    do_check_scrollbind(TRUE);
1722 #endif
1723 	    }
1724 	}
1725 	listcmd_busy = FALSE;
1726     }
1727 
1728 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1729     if (save_ei != NULL)
1730     {
1731 	set_string_option_direct((char_u *)"ei", -1, save_ei, OPT_FREE);
1732 	apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
1733 					       curbuf->b_fname, TRUE, curbuf);
1734 	vim_free(save_ei);
1735     }
1736 #endif
1737 }
1738 
1739 /*
1740  * Add files[count] to the arglist of the current window after arg "after".
1741  * The file names in files[count] must have been allocated and are taken over.
1742  * Files[] itself is not taken over.
1743  * Returns index of first added argument.  Returns -1 when failed (out of mem).
1744  */
1745     static int
1746 alist_add_list(count, files, after)
1747     int		count;
1748     char_u	**files;
1749     int		after;	    /* where to add: 0 = before first one */
1750 {
1751     int		i;
1752 
1753     if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
1754     {
1755 	if (after < 0)
1756 	    after = 0;
1757 	if (after > ARGCOUNT)
1758 	    after = ARGCOUNT;
1759 	if (after < ARGCOUNT)
1760 	    mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
1761 				       (ARGCOUNT - after) * sizeof(aentry_T));
1762 	for (i = 0; i < count; ++i)
1763 	{
1764 	    ARGLIST[after + i].ae_fname = files[i];
1765 	    ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
1766 	}
1767 	ALIST(curwin)->al_ga.ga_len += count;
1768 	ALIST(curwin)->al_ga.ga_room -= count;
1769 	if (curwin->w_arg_idx >= after)
1770 	    ++curwin->w_arg_idx;
1771 	return after;
1772     }
1773 
1774     for (i = 0; i < count; ++i)
1775 	vim_free(files[i]);
1776     return -1;
1777 }
1778 
1779 #endif /* FEAT_LISTCMDS */
1780 
1781 #ifdef FEAT_EVAL
1782 /*
1783  * ":compiler[!] {name}"
1784  */
1785     void
1786 ex_compiler(eap)
1787     exarg_T	*eap;
1788 {
1789     char_u	*buf;
1790     char_u	*old_cur_comp = NULL;
1791     char_u	*p;
1792 
1793     if (*eap->arg == NUL)
1794     {
1795 	/* List all compiler scripts. */
1796 	do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1797 					/* ) keep the indenter happy... */
1798     }
1799     else
1800     {
1801 	buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
1802 	if (buf != NULL)
1803 	{
1804 	    if (eap->forceit)
1805 	    {
1806 		/* ":compiler! {name}" sets global options */
1807 		do_cmdline_cmd((char_u *)
1808 				   "command -nargs=* CompilerSet set <args>");
1809 	    }
1810 	    else
1811 	    {
1812 		/* ":compiler! {name}" sets local options.
1813 		 * To remain backwards compatible "current_compiler" is always
1814 		 * used.  A user's compiler plugin may set it, the distributed
1815 		 * plugin will then skip the settings.  Afterwards set
1816 		 * "b:current_compiler" and restore "current_compiler". */
1817 		old_cur_comp = get_var_value((char_u *)"current_compiler");
1818 		if (old_cur_comp != NULL)
1819 		    old_cur_comp = vim_strsave(old_cur_comp);
1820 		do_cmdline_cmd((char_u *)
1821 			      "command -nargs=* CompilerSet setlocal <args>");
1822 	    }
1823 	    do_unlet((char_u *)"current_compiler");
1824 	    do_unlet((char_u *)"b:current_compiler");
1825 
1826 	    sprintf((char *)buf, "compiler/%s.vim", eap->arg);
1827 	    if (cmd_runtime(buf, TRUE) == FAIL)
1828 		EMSG2(_("E666: compiler not supported: %s"), eap->arg);
1829 	    vim_free(buf);
1830 
1831 	    do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1832 
1833 	    /* Set "b:current_compiler" from "current_compiler". */
1834 	    p = get_var_value((char_u *)"current_compiler");
1835 	    if (p != NULL)
1836 		set_internal_string_var((char_u *)"b:current_compiler", p);
1837 
1838 	    /* Restore "current_compiler" for ":compiler {name}". */
1839 	    if (!eap->forceit)
1840 	    {
1841 		if (old_cur_comp != NULL)
1842 		{
1843 		    set_internal_string_var((char_u *)"current_compiler",
1844 								old_cur_comp);
1845 		    vim_free(old_cur_comp);
1846 		}
1847 		else
1848 		    do_unlet((char_u *)"current_compiler");
1849 	    }
1850 	}
1851     }
1852 }
1853 #endif
1854 
1855 /*
1856  * ":runtime {name}"
1857  */
1858     void
1859 ex_runtime(eap)
1860     exarg_T	*eap;
1861 {
1862     cmd_runtime(eap->arg, eap->forceit);
1863 }
1864 
1865 static void source_callback __ARGS((char_u *fname));
1866 
1867     static void
1868 source_callback(fname)
1869     char_u	*fname;
1870 {
1871     (void)do_source(fname, FALSE, FALSE);
1872 }
1873 
1874 /*
1875  * Source the file "name" from all directories in 'runtimepath'.
1876  * "name" can contain wildcards.
1877  * When "all" is TRUE, source all files, otherwise only the first one.
1878  * return FAIL when no file could be sourced, OK otherwise.
1879  */
1880     int
1881 cmd_runtime(name, all)
1882     char_u	*name;
1883     int		all;
1884 {
1885     return do_in_runtimepath(name, all, source_callback);
1886 }
1887 
1888 /*
1889  * Find "name" in 'runtimepath'.  When found, call the "callback" function for
1890  * it.
1891  * When "all" is TRUE repeat for all matches, otherwise only the first one is
1892  * used.
1893  * Returns OK when at least one match found, FAIL otherwise.
1894  */
1895     int
1896 do_in_runtimepath(name, all, callback)
1897     char_u	*name;
1898     int		all;
1899     void	(*callback)__ARGS((char_u *fname));
1900 {
1901     char_u	*rtp;
1902     char_u	*np;
1903     char_u	*buf;
1904     char_u	*rtp_copy;
1905     char_u	*tail;
1906     int		num_files;
1907     char_u	**files;
1908     int		i;
1909     int		did_one = FALSE;
1910 #ifdef AMIGA
1911     struct Process	*proc = (struct Process *)FindTask(0L);
1912     APTR		save_winptr = proc->pr_WindowPtr;
1913 
1914     /* Avoid a requester here for a volume that doesn't exist. */
1915     proc->pr_WindowPtr = (APTR)-1L;
1916 #endif
1917 
1918     /* Make a copy of 'runtimepath'.  Invoking the callback may change the
1919      * value. */
1920     rtp_copy = vim_strsave(p_rtp);
1921     buf = alloc(MAXPATHL);
1922     if (buf != NULL && rtp_copy != NULL)
1923     {
1924 	if (p_verbose > 1)
1925 	    smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
1926 						 (char *)name, (char *)p_rtp);
1927 	/* Loop over all entries in 'runtimepath'. */
1928 	rtp = rtp_copy;
1929 	while (*rtp != NUL && (all || !did_one))
1930 	{
1931 	    /* Copy the path from 'runtimepath' to buf[]. */
1932 	    copy_option_part(&rtp, buf, MAXPATHL, ",");
1933 	    if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
1934 	    {
1935 		add_pathsep(buf);
1936 		tail = buf + STRLEN(buf);
1937 
1938 		/* Loop over all patterns in "name" */
1939 		np = name;
1940 		while (*np != NUL && (all || !did_one))
1941 		{
1942 		    /* Append the pattern from "name" to buf[]. */
1943 		    copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1944 								       "\t ");
1945 
1946 		    if (p_verbose > 2)
1947 			msg_str((char_u *)_("Searching for \"%s\""), buf);
1948 
1949 		    /* Expand wildcards, invoke the callback for each match. */
1950 		    if (gen_expand_wildcards(1, &buf, &num_files, &files,
1951 							       EW_FILE) == OK)
1952 		    {
1953 			for (i = 0; i < num_files; ++i)
1954 			{
1955 			    (*callback)(files[i]);
1956 			    did_one = TRUE;
1957 			    if (!all)
1958 				break;
1959 			}
1960 			FreeWild(num_files, files);
1961 		    }
1962 		}
1963 	    }
1964 	}
1965     }
1966     vim_free(buf);
1967     vim_free(rtp_copy);
1968     if (p_verbose > 0 && !did_one)
1969 	msg_str((char_u *)_("not found in 'runtimepath': \"%s\""), name);
1970 
1971 #ifdef AMIGA
1972     proc->pr_WindowPtr = save_winptr;
1973 #endif
1974 
1975     return did_one ? OK : FAIL;
1976 }
1977 
1978 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
1979 /*
1980  * ":options"
1981  */
1982 /*ARGSUSED*/
1983     void
1984 ex_options(eap)
1985     exarg_T	*eap;
1986 {
1987     cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
1988 }
1989 #endif
1990 
1991 /*
1992  * ":source {fname}"
1993  */
1994     void
1995 ex_source(eap)
1996     exarg_T	*eap;
1997 {
1998 #ifdef FEAT_BROWSE
1999     if (cmdmod.browse)
2000     {
2001 	char_u *fname = NULL;
2002 
2003 	fname = do_browse(FALSE, (char_u *)_("Source Vim script"), eap->arg,
2004 				      NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2005 	if (fname != NULL)
2006 	{
2007 	    cmd_source(fname, eap);
2008 	    vim_free(fname);
2009 	}
2010     }
2011     else
2012 #endif
2013 	cmd_source(eap->arg, eap);
2014 }
2015 
2016     static void
2017 cmd_source(fname, eap)
2018     char_u	*fname;
2019     exarg_T	*eap;
2020 {
2021     if (*fname == NUL)
2022 	EMSG(_(e_argreq));
2023 
2024     /* ":source!" read vi commands */
2025     else if (eap != NULL && eap->forceit)
2026 	/* Need to execute the commands directly when:
2027 	 * - ":g" command busy
2028 	 * - after ":argdo", ":windo" or ":bufdo"
2029 	 * - another command follows
2030 	 * - inside a loop
2031 	 */
2032 	openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2033 #ifdef FEAT_EVAL
2034 						 || eap->cstack->cs_idx >= 0
2035 #endif
2036 						 );
2037 
2038     /* ":source" read ex commands */
2039     else if (do_source(fname, FALSE, FALSE) == FAIL)
2040 	EMSG2(_(e_notopen), fname);
2041 }
2042 
2043 /*
2044  * ":source" and associated commands.
2045  */
2046 /*
2047  * Structure used to store info for each sourced file.
2048  * It is shared between do_source() and getsourceline().
2049  * This is required, because it needs to be handed to do_cmdline() and
2050  * sourcing can be done recursively.
2051  */
2052 struct source_cookie
2053 {
2054     FILE	*fp;		/* opened file for sourcing */
2055     char_u      *nextline;      /* if not NULL: line that was read ahead */
2056     int		finished;	/* ":finish" used */
2057 #if defined (USE_CRNL) || defined (USE_CR)
2058     int		fileformat;	/* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2059     int		error;		/* TRUE if LF found after CR-LF */
2060 #endif
2061 #ifdef FEAT_EVAL
2062     linenr_T	breakpoint;	/* next line with breakpoint or zero */
2063     char_u	*fname;		/* name of sourced file */
2064     int		dbg_tick;	/* debug_tick when breakpoint was set */
2065     int		level;		/* top nesting level of sourced file */
2066 #endif
2067 #ifdef FEAT_MBYTE
2068     vimconv_T	conv;		/* type of conversion */
2069 #endif
2070 };
2071 
2072 #ifdef FEAT_EVAL
2073 /*
2074  * Return the address holding the next breakpoint line for a source cookie.
2075  */
2076     linenr_T *
2077 source_breakpoint(cookie)
2078     void *cookie;
2079 {
2080     return &((struct source_cookie *)cookie)->breakpoint;
2081 }
2082 
2083 /*
2084  * Return the address holding the debug tick for a source cookie.
2085  */
2086     int *
2087 source_dbg_tick(cookie)
2088     void *cookie;
2089 {
2090     return &((struct source_cookie *)cookie)->dbg_tick;
2091 }
2092 
2093 /*
2094  * Return the nesting level for a source cookie.
2095  */
2096     int
2097 source_level(cookie)
2098     void *cookie;
2099 {
2100     return ((struct source_cookie *)cookie)->level;
2101 }
2102 #endif
2103 
2104 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2105 
2106 #ifdef FEAT_EVAL
2107 /* Growarray to store the names of sourced scripts.
2108  * For Unix also store the dev/ino, so that we don't have to stat() each
2109  * script when going through the list. */
2110 struct scriptstuff
2111 {
2112     char_u	*name;
2113 # ifdef UNIX
2114     int		dev;
2115     ino_t	ino;
2116 # endif
2117 };
2118 static garray_T script_names = {0, 0, sizeof(struct scriptstuff), 4, NULL};
2119 #define SCRIPT_NAME(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].name)
2120 #define SCRIPT_DEV(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].dev)
2121 #define SCRIPT_INO(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].ino)
2122 #endif
2123 
2124 #if defined(WIN32) && defined(FEAT_CSCOPE)
2125 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2126 
2127 /*
2128  * Special function to open a file without handle inheritance.
2129  */
2130     static FILE *
2131 fopen_noinh_readbin(filename)
2132     char    *filename;
2133 {
2134     int	fd_tmp = open(filename, O_RDONLY | O_BINARY | O_NOINHERIT);
2135 
2136     if (fd_tmp == -1)
2137 	return NULL;
2138     return fdopen(fd_tmp, READBIN);
2139 }
2140 #endif
2141 
2142 
2143 /*
2144  * do_source: Read the file "fname" and execute its lines as EX commands.
2145  *
2146  * This function may be called recursively!
2147  *
2148  * return FAIL if file could not be opened, OK otherwise
2149  */
2150     int
2151 do_source(fname, check_other, is_vimrc)
2152     char_u	*fname;
2153     int		check_other;	    /* check for .vimrc and _vimrc */
2154     int		is_vimrc;	    /* call vimrc_found() when file exists */
2155 {
2156     struct source_cookie    cookie;
2157     char_u		    *save_sourcing_name;
2158     linenr_T		    save_sourcing_lnum;
2159     char_u		    *p;
2160     char_u		    *fname_exp;
2161     int			    retval = FAIL;
2162 #ifdef FEAT_EVAL
2163     scid_T		    save_current_SID;
2164     static scid_T	    last_current_SID = 0;
2165     void		    *save_funccalp;
2166     int			    save_debug_break_level = debug_break_level;
2167 # ifdef UNIX
2168     struct stat		    st;
2169     int			    stat_ok;
2170 # endif
2171 #endif
2172 #ifdef STARTUPTIME
2173     struct timeval	    tv_rel;
2174     struct timeval	    tv_start;
2175 #endif
2176 
2177 #ifdef RISCOS
2178     p = mch_munge_fname(fname);
2179 #else
2180     p = expand_env_save(fname);
2181 #endif
2182     if (p == NULL)
2183 	return retval;
2184     fname_exp = fix_fname(p);
2185     vim_free(p);
2186     if (fname_exp == NULL)
2187 	return retval;
2188 #ifdef MACOS_CLASSIC
2189     slash_n_colon_adjust(fname_exp);
2190 #endif
2191     if (mch_isdir(fname_exp))
2192     {
2193 	msg_str((char_u *)_("Cannot source a directory: \"%s\""), fname);
2194 	goto theend;
2195     }
2196 
2197 #if defined(WIN32) && defined(FEAT_CSCOPE)
2198     cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2199 #else
2200     cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2201 #endif
2202     if (cookie.fp == NULL && check_other)
2203     {
2204 	/*
2205 	 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2206 	 * and ".exrc" by "_exrc" or vice versa.
2207 	 */
2208 	p = gettail(fname_exp);
2209 	if ((*p == '.' || *p == '_')
2210 		&& (STRICMP(p + 1, "vimrc") == 0
2211 		    || STRICMP(p + 1, "gvimrc") == 0
2212 		    || STRICMP(p + 1, "exrc") == 0))
2213 	{
2214 	    if (*p == '_')
2215 		*p = '.';
2216 	    else
2217 		*p = '_';
2218 #if defined(WIN32) && defined(FEAT_CSCOPE)
2219 	    cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2220 #else
2221 	    cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2222 #endif
2223 	}
2224     }
2225 
2226     if (cookie.fp == NULL)
2227     {
2228 	if (p_verbose > 0)
2229 	{
2230 	    if (sourcing_name == NULL)
2231 		msg_str((char_u *)_("could not source \"%s\""), fname);
2232 	    else
2233 		smsg((char_u *)_("line %ld: could not source \"%s\""),
2234 			sourcing_lnum, fname);
2235 	}
2236 	goto theend;
2237     }
2238 
2239     /*
2240      * The file exists.
2241      * - In verbose mode, give a message.
2242      * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2243      */
2244     if (p_verbose > 1)
2245     {
2246 	if (sourcing_name == NULL)
2247 	    msg_str((char_u *)_("sourcing \"%s\""), fname);
2248 	else
2249 	    smsg((char_u *)_("line %ld: sourcing \"%s\""),
2250 		    sourcing_lnum, fname);
2251     }
2252     if (is_vimrc)
2253 	vimrc_found();
2254 
2255 #ifdef USE_CRNL
2256     /* If no automatic file format: Set default to CR-NL. */
2257     if (*p_ffs == NUL)
2258 	cookie.fileformat = EOL_DOS;
2259     else
2260 	cookie.fileformat = EOL_UNKNOWN;
2261     cookie.error = FALSE;
2262 #endif
2263 
2264 #ifdef USE_CR
2265     /* If no automatic file format: Set default to CR. */
2266     if (*p_ffs == NUL)
2267 	cookie.fileformat = EOL_MAC;
2268     else
2269 	cookie.fileformat = EOL_UNKNOWN;
2270     cookie.error = FALSE;
2271 #endif
2272 
2273     cookie.nextline = NULL;
2274     cookie.finished = FALSE;
2275 
2276 #ifdef FEAT_EVAL
2277     /*
2278      * Check if this script has a breakpoint.
2279      */
2280     cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2281     cookie.fname = fname_exp;
2282     cookie.dbg_tick = debug_tick;
2283 
2284     cookie.level = ex_nesting_level;
2285 #endif
2286 #ifdef FEAT_MBYTE
2287     cookie.conv.vc_type = CONV_NONE;		/* no conversion */
2288 
2289     /* Try reading the first few bytes to check for a UTF-8 BOM. */
2290     {
2291 	char_u	    buf[3];
2292 
2293 	if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
2294 								  == (size_t)3
2295 		&& buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
2296 	    /* Found BOM, setup conversion and skip over it. */
2297 	    convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2298 	else
2299 	    /* No BOM found, rewind. */
2300 	    fseek(cookie.fp, 0L, SEEK_SET);
2301     }
2302 #endif
2303 
2304     /*
2305      * Keep the sourcing name/lnum, for recursive calls.
2306      */
2307     save_sourcing_name = sourcing_name;
2308     sourcing_name = fname_exp;
2309     save_sourcing_lnum = sourcing_lnum;
2310     sourcing_lnum = 0;
2311 
2312 #ifdef STARTUPTIME
2313     time_push(&tv_rel, &tv_start);
2314 #endif
2315 
2316 #ifdef FEAT_EVAL
2317     /*
2318      * Check if this script was sourced before to finds its SID.
2319      * If it's new, generate a new SID.
2320      */
2321     save_current_SID = current_SID;
2322 # ifdef UNIX
2323     stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2324 # endif
2325     for (current_SID = script_names.ga_len; current_SID > 0; --current_SID)
2326 	if (SCRIPT_NAME(current_SID) != NULL
2327 		&& (
2328 # ifdef UNIX
2329 		    /* compare dev/ino when possible, it catches symbolic
2330 		     * links */
2331 		    (stat_ok && SCRIPT_DEV(current_SID) != -1)
2332 			? (SCRIPT_DEV(current_SID) == st.st_dev
2333 			    && SCRIPT_INO(current_SID) == st.st_ino) :
2334 # endif
2335 		fnamecmp(SCRIPT_NAME(current_SID), fname_exp) == 0))
2336 	    break;
2337     if (current_SID == 0)
2338     {
2339 	current_SID = ++last_current_SID;
2340 	if (ga_grow(&script_names, (int)(current_SID - script_names.ga_len))
2341 									== OK)
2342 	{
2343 	    while (script_names.ga_len < current_SID)
2344 	    {
2345 		SCRIPT_NAME(script_names.ga_len + 1) = NULL;
2346 		++script_names.ga_len;
2347 		--script_names.ga_room;
2348 	    }
2349 	    SCRIPT_NAME(current_SID) = fname_exp;
2350 # ifdef UNIX
2351 	    if (stat_ok)
2352 	    {
2353 		SCRIPT_DEV(current_SID) = st.st_dev;
2354 		SCRIPT_INO(current_SID) = st.st_ino;
2355 	    }
2356 	    else
2357 		SCRIPT_DEV(current_SID) = -1;
2358 # endif
2359 	    fname_exp = NULL;
2360 	}
2361 	/* Allocate the local script variables to use for this script. */
2362 	new_script_vars(current_SID);
2363     }
2364 
2365     /* Don't use local function variables, if called from a function */
2366     save_funccalp = save_funccal();
2367 #endif
2368 
2369     /*
2370      * Call do_cmdline, which will call getsourceline() to get the lines.
2371      */
2372     do_cmdline(NULL, getsourceline, (void *)&cookie,
2373 				     DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
2374 
2375     retval = OK;
2376     fclose(cookie.fp);
2377     vim_free(cookie.nextline);
2378 #ifdef FEAT_MBYTE
2379     convert_setup(&cookie.conv, NULL, NULL);
2380 #endif
2381 
2382     if (got_int)
2383 	EMSG(_(e_interr));
2384     sourcing_name = save_sourcing_name;
2385     sourcing_lnum = save_sourcing_lnum;
2386 #ifdef FEAT_EVAL
2387     current_SID = save_current_SID;
2388     restore_funccal(save_funccalp);
2389 #endif
2390     if (p_verbose > 1)
2391     {
2392 	msg_str((char_u *)_("finished sourcing %s"), fname);
2393 	if (sourcing_name != NULL)
2394 	    msg_str((char_u *)_("continuing in %s"), sourcing_name);
2395     }
2396 #ifdef STARTUPTIME
2397 # ifdef HAVE_SNPRINTF
2398     snprintf(IObuff, IOSIZE, "sourcing %s", fname);
2399 # else
2400     sprintf(IObuff, "sourcing %s", fname);
2401 # endif
2402     time_msg(IObuff, &tv_start);
2403     time_pop(&tv_rel);
2404 #endif
2405 
2406 #ifdef FEAT_EVAL
2407     /*
2408      * After a "finish" in debug mode, need to break at first command of next
2409      * sourced file.
2410      */
2411     if (save_debug_break_level > ex_nesting_level
2412 	    && debug_break_level == ex_nesting_level)
2413 	++debug_break_level;
2414 #endif
2415 
2416 theend:
2417     vim_free(fname_exp);
2418     return retval;
2419 }
2420 
2421 #if defined(FEAT_EVAL) || defined(PROTO)
2422 /*
2423  * ":scriptnames"
2424  */
2425 /*ARGSUSED*/
2426     void
2427 ex_scriptnames(eap)
2428     exarg_T	*eap;
2429 {
2430     int i;
2431 
2432     for (i = 1; i <= script_names.ga_len && !got_int; ++i)
2433 	if (SCRIPT_NAME(i) != NULL)
2434 	    smsg((char_u *)"%3d: %s", i, SCRIPT_NAME(i));
2435 }
2436 
2437 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
2438 /*
2439  * Fix slashes in the list of script names for 'shellslash'.
2440  */
2441     void
2442 scriptnames_slash_adjust()
2443 {
2444     int i;
2445 
2446     for (i = 1; i <= script_names.ga_len; ++i)
2447 	if (SCRIPT_NAME(i) != NULL)
2448 	    slash_adjust(SCRIPT_NAME(i));
2449 }
2450 # endif
2451 
2452 /*
2453  * Get a pointer to a script name.  Used for ":verbose set".
2454  */
2455     char_u *
2456 get_scriptname(id)
2457     scid_T	id;
2458 {
2459     if (id == SID_MODELINE)
2460 	return (char_u *)"modeline";
2461     if (id == SID_CMDARG)
2462 	return (char_u *)"--cmd argument";
2463     if (id == SID_CARG)
2464 	return (char_u *)"-c argument";
2465     if (id == SID_ENV)
2466 	return (char_u *)"environment variable";
2467     return SCRIPT_NAME(id);
2468 }
2469 #endif
2470 
2471 #if defined(USE_CR) || defined(PROTO)
2472 
2473 # if defined(__MSL__) && (__MSL__ >= 22)
2474 /*
2475  * Newer version of the Metrowerks library handle DOS and UNIX files
2476  * without help.
2477  * Test with earlier versions, MSL 2.2 is the library supplied with
2478  * Codewarrior Pro 2.
2479  */
2480     char *
2481 fgets_cr(s, n, stream)
2482     char	*s;
2483     int		n;
2484     FILE	*stream;
2485 {
2486     return fgets(s, n, stream);
2487 }
2488 # else
2489 /*
2490  * Version of fgets() which also works for lines ending in a <CR> only
2491  * (Macintosh format).
2492  * For older versions of the Metrowerks library.
2493  * At least CodeWarrior 9 needed this code.
2494  */
2495     char *
2496 fgets_cr(s, n, stream)
2497     char	*s;
2498     int		n;
2499     FILE	*stream;
2500 {
2501     int	c = 0;
2502     int char_read = 0;
2503 
2504     while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
2505     {
2506 	c = fgetc(stream);
2507 	s[char_read++] = c;
2508 	/* If the file is in DOS format, we need to skip a NL after a CR.  I
2509 	 * thought it was the other way around, but this appears to work... */
2510 	if (c == '\n')
2511 	{
2512 	    c = fgetc(stream);
2513 	    if (c != '\r')
2514 		ungetc(c, stream);
2515 	}
2516     }
2517 
2518     s[char_read] = 0;
2519     if (char_read == 0)
2520 	return NULL;
2521 
2522     if (feof(stream) && char_read == 1)
2523 	return NULL;
2524 
2525     return s;
2526 }
2527 # endif
2528 #endif
2529 
2530 /*
2531  * Get one full line from a sourced file.
2532  * Called by do_cmdline() when it's called from do_source().
2533  *
2534  * Return a pointer to the line in allocated memory.
2535  * Return NULL for end-of-file or some error.
2536  */
2537 /* ARGSUSED */
2538     char_u *
2539 getsourceline(c, cookie, indent)
2540     int		c;		/* not used */
2541     void	*cookie;
2542     int		indent;		/* not used */
2543 {
2544     struct source_cookie *sp = (struct source_cookie *)cookie;
2545     char_u		*line;
2546     char_u		*p, *s;
2547 
2548 #ifdef FEAT_EVAL
2549     /* If breakpoints have been added/deleted need to check for it. */
2550     if (sp->dbg_tick < debug_tick)
2551     {
2552 	sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2553 	sp->dbg_tick = debug_tick;
2554     }
2555 #endif
2556     /*
2557      * Get current line.  If there is a read-ahead line, use it, otherwise get
2558      * one now.
2559      */
2560     if (sp->finished)
2561 	line = NULL;
2562     else if (sp->nextline == NULL)
2563 	line = get_one_sourceline(sp);
2564     else
2565     {
2566 	line = sp->nextline;
2567 	sp->nextline = NULL;
2568 	++sourcing_lnum;
2569     }
2570 
2571     /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
2572      * contain the 'C' flag. */
2573     if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
2574     {
2575 	/* compensate for the one line read-ahead */
2576 	--sourcing_lnum;
2577 	for (;;)
2578 	{
2579 	    sp->nextline = get_one_sourceline(sp);
2580 	    if (sp->nextline == NULL)
2581 		break;
2582 	    p = skipwhite(sp->nextline);
2583 	    if (*p != '\\')
2584 		break;
2585 	    s = alloc((int)(STRLEN(line) + STRLEN(p)));
2586 	    if (s == NULL)	/* out of memory */
2587 		break;
2588 	    STRCPY(s, line);
2589 	    STRCAT(s, p + 1);
2590 	    vim_free(line);
2591 	    line = s;
2592 	    vim_free(sp->nextline);
2593 	}
2594     }
2595 
2596 #ifdef FEAT_MBYTE
2597     if (line != NULL && sp->conv.vc_type != CONV_NONE)
2598     {
2599 	/* Convert the encoding of the script line. */
2600 	s = string_convert(&sp->conv, line, NULL);
2601 	if (s != NULL)
2602 	{
2603 	    vim_free(line);
2604 	    line = s;
2605 	}
2606     }
2607 #endif
2608 
2609 #ifdef FEAT_EVAL
2610     /* Did we encounter a breakpoint? */
2611     if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
2612     {
2613 	dbg_breakpoint(sp->fname, sourcing_lnum);
2614 	/* Find next breakpoint. */
2615 	sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2616 	sp->dbg_tick = debug_tick;
2617     }
2618 #endif
2619 
2620     return line;
2621 }
2622 
2623     static char_u *
2624 get_one_sourceline(sp)
2625     struct source_cookie    *sp;
2626 {
2627     garray_T		ga;
2628     int			len;
2629     int			c;
2630     char_u		*buf;
2631 #ifdef USE_CRNL
2632     int			has_cr;		/* CR-LF found */
2633 #endif
2634 #ifdef USE_CR
2635     char_u		*scan;
2636 #endif
2637     int			have_read = FALSE;
2638 
2639     /* use a growarray to store the sourced line */
2640     ga_init2(&ga, 1, 200);
2641 
2642     /*
2643      * Loop until there is a finished line (or end-of-file).
2644      */
2645     sourcing_lnum++;
2646     for (;;)
2647     {
2648 	/* make room to read at least 80 (more) characters */
2649 	if (ga_grow(&ga, 80) == FAIL)
2650 	    break;
2651 	buf = (char_u *)ga.ga_data;
2652 
2653 #ifdef USE_CR
2654 	if (sp->fileformat == EOL_MAC)
2655 	{
2656 	    if (fgets_cr((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
2657 		break;
2658 	}
2659 	else
2660 #endif
2661 	    if (fgets((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
2662 		break;
2663 	len = (int)STRLEN(buf);
2664 #ifdef USE_CRNL
2665 	/* Ignore a trailing CTRL-Z, when in Dos mode.	Only recognize the
2666 	 * CTRL-Z by its own, or after a NL. */
2667 	if (	   (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
2668 		&& sp->fileformat == EOL_DOS
2669 		&& buf[len - 1] == Ctrl_Z)
2670 	{
2671 	    buf[len - 1] = NUL;
2672 	    break;
2673 	}
2674 #endif
2675 
2676 #ifdef USE_CR
2677 	/* If the read doesn't stop on a new line, and there's
2678 	 * some CR then we assume a Mac format */
2679 	if (sp->fileformat == EOL_UNKNOWN)
2680 	{
2681 	    if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
2682 		sp->fileformat = EOL_MAC;
2683 	    else
2684 		sp->fileformat = EOL_UNIX;
2685 	}
2686 
2687 	if (sp->fileformat == EOL_MAC)
2688 	{
2689 	    scan = vim_strchr(buf, '\r');
2690 
2691 	    if (scan != NULL)
2692 	    {
2693 		*scan = '\n';
2694 		if (*(scan + 1) != 0)
2695 		{
2696 		    *(scan + 1) = 0;
2697 		    fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
2698 		}
2699 	    }
2700 	    len = STRLEN(buf);
2701 	}
2702 #endif
2703 
2704 	have_read = TRUE;
2705 	ga.ga_room -= len - ga.ga_len;
2706 	ga.ga_len = len;
2707 
2708 	/* If the line was longer than the buffer, read more. */
2709 	if (ga.ga_room == 1 && buf[len - 1] != '\n')
2710 	    continue;
2711 
2712 	if (len >= 1 && buf[len - 1] == '\n')	/* remove trailing NL */
2713 	{
2714 #ifdef USE_CRNL
2715 	    has_cr = (len >= 2 && buf[len - 2] == '\r');
2716 	    if (sp->fileformat == EOL_UNKNOWN)
2717 	    {
2718 		if (has_cr)
2719 		    sp->fileformat = EOL_DOS;
2720 		else
2721 		    sp->fileformat = EOL_UNIX;
2722 	    }
2723 
2724 	    if (sp->fileformat == EOL_DOS)
2725 	    {
2726 		if (has_cr)	    /* replace trailing CR */
2727 		{
2728 		    buf[len - 2] = '\n';
2729 		    --len;
2730 		    --ga.ga_len;
2731 		    ++ga.ga_room;
2732 		}
2733 		else	    /* lines like ":map xx yy^M" will have failed */
2734 		{
2735 		    if (!sp->error)
2736 		    {
2737 			msg_source(hl_attr(HLF_W));
2738 			EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
2739 		    }
2740 		    sp->error = TRUE;
2741 		    sp->fileformat = EOL_UNIX;
2742 		}
2743 	    }
2744 #endif
2745 	    /* The '\n' is escaped if there is an odd number of ^V's just
2746 	     * before it, first set "c" just before the 'V's and then check
2747 	     * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
2748 	    for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
2749 		;
2750 	    if ((len & 1) != (c & 1))	/* escaped NL, read more */
2751 	    {
2752 		sourcing_lnum++;
2753 		continue;
2754 	    }
2755 
2756 	    buf[len - 1] = NUL;		/* remove the NL */
2757 	}
2758 
2759 	/*
2760 	 * Check for ^C here now and then, so recursive :so can be broken.
2761 	 */
2762 	line_breakcheck();
2763 	break;
2764     }
2765 
2766     if (have_read)
2767 	return (char_u *)ga.ga_data;
2768 
2769     vim_free(ga.ga_data);
2770     return NULL;
2771 }
2772 
2773 /*
2774  * ":scriptencoding": Set encoding conversion for a sourced script.
2775  * Without the multi-byte feature it's simply ignored.
2776  */
2777 /*ARGSUSED*/
2778     void
2779 ex_scriptencoding(eap)
2780     exarg_T	*eap;
2781 {
2782 #ifdef FEAT_MBYTE
2783     struct source_cookie	*sp;
2784     char_u			*name;
2785 
2786     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
2787     {
2788 	EMSG(_("E167: :scriptencoding used outside of a sourced file"));
2789 	return;
2790     }
2791 
2792     if (*eap->arg != NUL)
2793     {
2794 	name = enc_canonize(eap->arg);
2795 	if (name == NULL)	/* out of memory */
2796 	    return;
2797     }
2798     else
2799 	name = eap->arg;
2800 
2801     /* Setup for conversion from the specified encoding to 'encoding'. */
2802     sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
2803     convert_setup(&sp->conv, name, p_enc);
2804 
2805     if (name != eap->arg)
2806 	vim_free(name);
2807 #endif
2808 }
2809 
2810 #if defined(FEAT_EVAL) || defined(PROTO)
2811 /*
2812  * ":finish": Mark a sourced file as finished.
2813  */
2814     void
2815 ex_finish(eap)
2816     exarg_T	*eap;
2817 {
2818     if (getline_equal(eap->getline, eap->cookie, getsourceline))
2819 	do_finish(eap, FALSE);
2820     else
2821 	EMSG(_("E168: :finish used outside of a sourced file"));
2822 }
2823 
2824 /*
2825  * Mark a sourced file as finished.  Possibly makes the ":finish" pending.
2826  * Also called for a pending finish at the ":endtry" or after returning from
2827  * an extra do_cmdline().  "reanimate" is used in the latter case.
2828  */
2829     void
2830 do_finish(eap, reanimate)
2831     exarg_T	*eap;
2832     int		reanimate;
2833 {
2834     int		idx;
2835 
2836     if (reanimate)
2837 	((struct source_cookie *)getline_cookie(eap->getline,
2838 					      eap->cookie))->finished = FALSE;
2839 
2840     /*
2841      * Cleanup (and inactivate) conditionals, but stop when a try conditional
2842      * not in its finally clause (which then is to be executed next) is found.
2843      * In this case, make the ":finish" pending for execution at the ":endtry".
2844      * Otherwise, finish normally.
2845      */
2846     idx = cleanup_conditionals(eap->cstack, 0, TRUE);
2847     if (idx >= 0)
2848     {
2849 	eap->cstack->cs_pending[idx] = CSTP_FINISH;
2850 	report_make_pending(CSTP_FINISH, NULL);
2851     }
2852     else
2853 	((struct source_cookie *)getline_cookie(eap->getline,
2854 					       eap->cookie))->finished = TRUE;
2855 }
2856 
2857 
2858 /*
2859  * Return TRUE when a sourced file had the ":finish" command: Don't give error
2860  * message for missing ":endif".
2861  * Return FALSE when not sourcing a file.
2862  */
2863     int
2864 source_finished(getline, cookie)
2865     char_u	*(*getline) __ARGS((int, void *, int));
2866     void	*cookie;
2867 {
2868     return (getline_equal(getline, cookie, getsourceline)
2869 	    && ((struct source_cookie *)getline_cookie(
2870 						 getline, cookie))->finished);
2871 }
2872 #endif
2873 
2874 #if defined(FEAT_LISTCMDS) || defined(PROTO)
2875 /*
2876  * ":checktime [buffer]"
2877  */
2878     void
2879 ex_checktime(eap)
2880     exarg_T	*eap;
2881 {
2882     buf_T	*buf;
2883     int		save_no_check_timestamps = no_check_timestamps;
2884 
2885     no_check_timestamps = 0;
2886     if (eap->addr_count == 0)	/* default is all buffers */
2887 	check_timestamps(FALSE);
2888     else
2889     {
2890 	buf = buflist_findnr((int)eap->line2);
2891 	if (buf != NULL)	/* cannot happen? */
2892 	    (void)buf_check_timestamp(buf, FALSE);
2893     }
2894     no_check_timestamps = save_no_check_timestamps;
2895 }
2896 #endif
2897 
2898 #if defined(FEAT_PRINTER) || defined(PROTO)
2899 /*
2900  * Printing code (Machine-independent.)
2901  * To implement printing on a platform, the following functions must be
2902  * defined:
2903  *
2904  * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
2905  * Called once.  Code should display printer dialogue (if appropriate) and
2906  * determine printer font and margin settings.  Reset has_color if the printer
2907  * doesn't support colors at all.
2908  * Returns FAIL to abort.
2909  *
2910  * int mch_print_begin(prt_settings_T *settings)
2911  * Called to start the print job.
2912  * Return FALSE to abort.
2913  *
2914  * int mch_print_begin_page(char_u *msg)
2915  * Called at the start of each page.
2916  * "msg" indicates the progress of the print job, can be NULL.
2917  * Return FALSE to abort.
2918  *
2919  * int mch_print_end_page()
2920  * Called at the end of each page.
2921  * Return FALSE to abort.
2922  *
2923  * int mch_print_blank_page()
2924  * Called to generate a blank page for collated, duplex, multiple copy
2925  * document.  Return FALSE to abort.
2926  *
2927  * void mch_print_end(prt_settings_T *psettings)
2928  * Called at normal end of print job.
2929  *
2930  * void mch_print_cleanup()
2931  * Called if print job ends normally or is abandoned. Free any memory, close
2932  * devices and handles.  Also called when mch_print_begin() fails, but not
2933  * when mch_print_init() fails.
2934  *
2935  * void mch_print_set_font(int Bold, int Italic, int Underline);
2936  * Called whenever the font style changes.
2937  *
2938  * void mch_print_set_bg(long bgcol);
2939  * Called to set the background color for the following text. Parameter is an
2940  * RGB value.
2941  *
2942  * void mch_print_set_fg(long fgcol);
2943  * Called to set the foreground color for the following text. Parameter is an
2944  * RGB value.
2945  *
2946  * mch_print_start_line(int margin, int page_line)
2947  * Sets the current position at the start of line "page_line".
2948  * If margin is TRUE start in the left margin (for header and line number).
2949  *
2950  * int mch_print_text_out(char_u *p, int len);
2951  * Output one character of text p[len] at the current position.
2952  * Return TRUE if there is no room for another character in the same line.
2953  *
2954  * Note that the generic code has no idea of margins. The machine code should
2955  * simply make the page look smaller!  The header and the line numbers are
2956  * printed in the margin.
2957  */
2958 
2959 #ifdef FEAT_SYN_HL
2960 static const long_u  cterm_color_8[8] =
2961 {
2962     (long_u)0x000000L, (long_u)0xff0000L, (long_u)0x00ff00L, (long_u)0xffff00L,
2963     (long_u)0x0000ffL, (long_u)0xff00ffL, (long_u)0x00ffffL, (long_u)0xffffffL
2964 };
2965 
2966 static const long_u  cterm_color_16[16] =
2967 {
2968     (long_u)0x000000L, (long_u)0x0000c0L, (long_u)0x008000L, (long_u)0x004080L,
2969     (long_u)0xc00000L, (long_u)0xc000c0L, (long_u)0x808000L, (long_u)0xc0c0c0L,
2970     (long_u)0x808080L, (long_u)0x6060ffL, (long_u)0x00ff00L, (long_u)0x00ffffL,
2971     (long_u)0xff8080L, (long_u)0xff40ffL, (long_u)0xffff00L, (long_u)0xffffffL
2972 };
2973 
2974 static int		current_syn_id;
2975 #endif
2976 
2977 #define PRCOLOR_BLACK	(long_u)0
2978 #define PRCOLOR_WHITE	(long_u)0xFFFFFFL
2979 
2980 static int	curr_italic;
2981 static int	curr_bold;
2982 static int	curr_underline;
2983 static long_u	curr_bg;
2984 static long_u	curr_fg;
2985 static int	page_count;
2986 
2987 /*
2988  * These values determine the print position on a page.
2989  */
2990 typedef struct
2991 {
2992     int		lead_spaces;	    /* remaining spaces for a TAB */
2993     int		print_pos;	    /* virtual column for computing TABs */
2994     colnr_T	column;		    /* byte column */
2995     linenr_T	file_line;	    /* line nr in the buffer */
2996     long_u	bytes_printed;	    /* bytes printed so far */
2997     int		ff;		    /* seen form feed character */
2998 } prt_pos_T;
2999 
3000 #ifdef FEAT_SYN_HL
3001 static long_u darken_rgb __ARGS((long_u rgb));
3002 static long_u prt_get_term_color __ARGS((int colorindex));
3003 #endif
3004 static void prt_set_fg __ARGS((long_u fg));
3005 static void prt_set_bg __ARGS((long_u bg));
3006 static void prt_set_font __ARGS((int bold, int italic, int underline));
3007 static void prt_line_number __ARGS((prt_settings_T *psettings, int page_line, linenr_T lnum));
3008 static void prt_header __ARGS((prt_settings_T *psettings, int pagenum, linenr_T lnum));
3009 static void prt_message __ARGS((char_u *s));
3010 static colnr_T hardcopy_line __ARGS((prt_settings_T *psettings, int page_line, prt_pos_T *ppos));
3011 static void prt_get_attr __ARGS((int hl_id, prt_text_attr_T* pattr, int modec));
3012 
3013 #ifdef FEAT_SYN_HL
3014 /*
3015  * If using a dark background, the colors will probably be too bright to show
3016  * up well on white paper, so reduce their brightness.
3017  */
3018     static long_u
3019 darken_rgb(rgb)
3020     long_u	rgb;
3021 {
3022     return	((rgb >> 17) << 16)
3023 	    +	(((rgb & 0xff00) >> 9) << 8)
3024 	    +	((rgb & 0xff) >> 1);
3025 }
3026 
3027     static long_u
3028 prt_get_term_color(colorindex)
3029     int	    colorindex;
3030 {
3031     /* TODO: Should check for xterm with 88 or 256 colors. */
3032     if (t_colors > 8)
3033 	return cterm_color_16[colorindex % 16];
3034     return cterm_color_8[colorindex % 8];
3035 }
3036 
3037     static void
3038 prt_get_attr(hl_id, pattr, modec)
3039     int			hl_id;
3040     prt_text_attr_T*	pattr;
3041     int			modec;
3042 {
3043     int     colorindex;
3044     long_u  fg_color;
3045     long_u  bg_color;
3046     char    *color;
3047 
3048     pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
3049     pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
3050     pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
3051 
3052 # ifdef FEAT_GUI
3053     if (gui.in_use)
3054     {
3055 	bg_color = highlight_gui_color_rgb(hl_id, FALSE);
3056 	if (bg_color == PRCOLOR_BLACK)
3057 	    bg_color = PRCOLOR_WHITE;
3058 
3059 	fg_color = highlight_gui_color_rgb(hl_id, TRUE);
3060     }
3061     else
3062 # endif
3063     {
3064 	bg_color = PRCOLOR_WHITE;
3065 
3066 	color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
3067 	if (color == NULL)
3068 	    colorindex = 0;
3069 	else
3070 	    colorindex = atoi(color);
3071 
3072 	if (colorindex >= 0 && colorindex < t_colors)
3073 	    fg_color = prt_get_term_color(colorindex);
3074 	else
3075 	    fg_color = PRCOLOR_BLACK;
3076     }
3077 
3078     if (fg_color == PRCOLOR_WHITE)
3079 	fg_color = PRCOLOR_BLACK;
3080     else if (*p_bg == 'd')
3081 	fg_color = darken_rgb(fg_color);
3082 
3083     pattr->fg_color = fg_color;
3084     pattr->bg_color = bg_color;
3085 }
3086 #endif /* FEAT_SYN_HL */
3087 
3088     static void
3089 prt_set_fg(fg)
3090     long_u fg;
3091 {
3092     if (fg != curr_fg)
3093     {
3094 	curr_fg = fg;
3095 	mch_print_set_fg(fg);
3096     }
3097 }
3098 
3099     static void
3100 prt_set_bg(bg)
3101     long_u bg;
3102 {
3103     if (bg != curr_bg)
3104     {
3105 	curr_bg = bg;
3106 	mch_print_set_bg(bg);
3107     }
3108 }
3109 
3110     static void
3111 prt_set_font(bold, italic, underline)
3112     int		bold;
3113     int		italic;
3114     int		underline;
3115 {
3116     if (curr_bold != bold
3117 	    || curr_italic != italic
3118 	    || curr_underline != underline)
3119     {
3120 	curr_underline = underline;
3121 	curr_italic = italic;
3122 	curr_bold = bold;
3123 	mch_print_set_font(bold, italic, underline);
3124     }
3125 }
3126 
3127 /*
3128  * Print the line number in the left margin.
3129  */
3130     static void
3131 prt_line_number(psettings, page_line, lnum)
3132     prt_settings_T *psettings;
3133     int		page_line;
3134     linenr_T	lnum;
3135 {
3136     int		i;
3137     char_u	tbuf[20];
3138 
3139     prt_set_fg(psettings->number.fg_color);
3140     prt_set_bg(psettings->number.bg_color);
3141     prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
3142     mch_print_start_line(TRUE, page_line);
3143 
3144     /* Leave two spaces between the number and the text; depends on
3145      * PRINT_NUMBER_WIDTH. */
3146     sprintf((char *)tbuf, "%6ld", (long)lnum);
3147     for (i = 0; i < 6; i++)
3148 	(void)mch_print_text_out(&tbuf[i], 1);
3149 
3150 #ifdef FEAT_SYN_HL
3151     if (psettings->do_syntax)
3152 	/* Set colors for next character. */
3153 	current_syn_id = -1;
3154     else
3155 #endif
3156     {
3157 	/* Set colors and font back to normal. */
3158 	prt_set_fg(PRCOLOR_BLACK);
3159 	prt_set_bg(PRCOLOR_WHITE);
3160 	prt_set_font(FALSE, FALSE, FALSE);
3161     }
3162 }
3163 
3164 static linenr_T printer_page_num;
3165 
3166     int
3167 get_printer_page_num()
3168 {
3169     return printer_page_num;
3170 }
3171 
3172 /*
3173  * Get the currently effective header height.
3174  */
3175     int
3176 prt_header_height()
3177 {
3178     if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
3179 	return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
3180     return 2;
3181 }
3182 
3183 /*
3184  * Return TRUE if using a line number for printing.
3185  */
3186     int
3187 prt_use_number()
3188 {
3189     return (printer_opts[OPT_PRINT_NUMBER].present
3190 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
3191 }
3192 
3193 /*
3194  * Return the unit used in a margin item in 'printoptions'.
3195  * Returns PRT_UNIT_NONE if not recognized.
3196  */
3197     int
3198 prt_get_unit(idx)
3199     int		idx;
3200 {
3201     int		u = PRT_UNIT_NONE;
3202     int		i;
3203     static char *(units[4]) = PRT_UNIT_NAMES;
3204 
3205     if (printer_opts[idx].present)
3206 	for (i = 0; i < 4; ++i)
3207 	    if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
3208 	    {
3209 		u = i;
3210 		break;
3211 	    }
3212     return u;
3213 }
3214 
3215 /*
3216  * Print the page header.
3217  */
3218 /*ARGSUSED*/
3219     static void
3220 prt_header(psettings, pagenum, lnum)
3221     prt_settings_T  *psettings;
3222     int		pagenum;
3223     linenr_T	lnum;
3224 {
3225     int		width = psettings->chars_per_line;
3226     int		page_line;
3227     char_u	*tbuf;
3228     char_u	*p;
3229 #ifdef FEAT_MBYTE
3230     int		l;
3231 #endif
3232 
3233     /* Also use the space for the line number. */
3234     if (prt_use_number())
3235 	width += PRINT_NUMBER_WIDTH;
3236 
3237     tbuf = alloc(width + IOSIZE);
3238     if (tbuf == NULL)
3239 	return;
3240 
3241 #ifdef FEAT_STL_OPT
3242     if (*p_header != NUL)
3243     {
3244 	linenr_T	tmp_lnum, tmp_topline, tmp_botline;
3245 
3246 	/*
3247 	 * Need to (temporarily) set current line number and first/last line
3248 	 * number on the 'window'.  Since we don't know how long the page is,
3249 	 * set the first and current line number to the top line, and guess
3250 	 * that the page length is 64.
3251 	 */
3252 	tmp_lnum = curwin->w_cursor.lnum;
3253 	tmp_topline = curwin->w_topline;
3254 	tmp_botline = curwin->w_botline;
3255 	curwin->w_cursor.lnum = lnum;
3256 	curwin->w_topline = lnum;
3257 	curwin->w_botline = lnum + 63;
3258 	printer_page_num = pagenum;
3259 
3260 	build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE),
3261 						  p_header, ' ', width, NULL);
3262 
3263 	/* Reset line numbers */
3264 	curwin->w_cursor.lnum = tmp_lnum;
3265 	curwin->w_topline = tmp_topline;
3266 	curwin->w_botline = tmp_botline;
3267     }
3268     else
3269 #endif
3270 	sprintf((char *)tbuf, _("Page %d"), pagenum);
3271 
3272     prt_set_fg(PRCOLOR_BLACK);
3273     prt_set_bg(PRCOLOR_WHITE);
3274     prt_set_font(TRUE, FALSE, FALSE);
3275 
3276     /* Use a negative line number to indicate printing in the top margin. */
3277     page_line = 0 - prt_header_height();
3278     mch_print_start_line(TRUE, page_line);
3279     for (p = tbuf; *p != NUL; )
3280     {
3281 	if (mch_print_text_out(p,
3282 #ifdef FEAT_MBYTE
3283 		(l = (*mb_ptr2len_check)(p))
3284 #else
3285 		1
3286 #endif
3287 		    ))
3288 	{
3289 	    ++page_line;
3290 	    if (page_line >= 0) /* out of room in header */
3291 		break;
3292 	    mch_print_start_line(TRUE, page_line);
3293 	}
3294 #ifdef FEAT_MBYTE
3295 	p += l;
3296 #else
3297 	p++;
3298 #endif
3299     }
3300 
3301     vim_free(tbuf);
3302 
3303 #ifdef FEAT_SYN_HL
3304     if (psettings->do_syntax)
3305 	/* Set colors for next character. */
3306 	current_syn_id = -1;
3307     else
3308 #endif
3309     {
3310 	/* Set colors and font back to normal. */
3311 	prt_set_fg(PRCOLOR_BLACK);
3312 	prt_set_bg(PRCOLOR_WHITE);
3313 	prt_set_font(FALSE, FALSE, FALSE);
3314     }
3315 }
3316 
3317 /*
3318  * Display a print status message.
3319  */
3320     static void
3321 prt_message(s)
3322     char_u	*s;
3323 {
3324     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
3325     screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R));
3326     out_flush();
3327 }
3328 
3329     void
3330 ex_hardcopy(eap)
3331     exarg_T	*eap;
3332 {
3333     linenr_T		lnum;
3334     int			collated_copies, uncollated_copies;
3335     prt_settings_T	settings;
3336     long_u		bytes_to_print = 0;
3337     int			page_line;
3338     int			jobsplit;
3339     int			id;
3340 
3341     memset(&settings, 0, sizeof(prt_settings_T));
3342     settings.has_color = TRUE;
3343 
3344 # ifdef FEAT_POSTSCRIPT
3345     if (*eap->arg == '>')
3346     {
3347 	char_u	*errormsg = NULL;
3348 
3349 	/* Expand things like "%.ps". */
3350 	if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
3351 	{
3352 	    if (errormsg != NULL)
3353 		EMSG(errormsg);
3354 	    return;
3355 	}
3356 	settings.outfile = skipwhite(eap->arg + 1);
3357     }
3358     else if (*eap->arg != NUL)
3359 	settings.arguments = eap->arg;
3360 # endif
3361 
3362     /*
3363      * Initialise for printing.  Ask the user for settings, unless forceit is
3364      * set.
3365      * The mch_print_init() code should set up margins if applicable. (It may
3366      * not be a real printer - for example the engine might generate HTML or
3367      * PS.)
3368      */
3369     if (mch_print_init(&settings,
3370 			curbuf->b_fname == NULL
3371 			    ? (char_u *)buf_spname(curbuf)
3372 			    : curbuf->b_sfname == NULL
3373 				? curbuf->b_fname
3374 				: curbuf->b_sfname,
3375 			eap->forceit) == FAIL)
3376 	return;
3377 
3378 #ifdef FEAT_SYN_HL
3379 # ifdef  FEAT_GUI
3380     if (gui.in_use)
3381 	settings.modec = 'g';
3382     else
3383 # endif
3384 	if (t_colors > 1)
3385 	    settings.modec = 'c';
3386 	else
3387 	    settings.modec = 't';
3388 
3389     if (!syntax_present(curbuf))
3390 	settings.do_syntax = FALSE;
3391     else if (printer_opts[OPT_PRINT_SYNTAX].present
3392 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
3393 	settings.do_syntax =
3394 	       (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
3395     else
3396 	settings.do_syntax = settings.has_color;
3397 #endif
3398 
3399     /* Set up printing attributes for line numbers */
3400     settings.number.fg_color = PRCOLOR_BLACK;
3401     settings.number.bg_color = PRCOLOR_WHITE;
3402     settings.number.bold = FALSE;
3403     settings.number.italic = TRUE;
3404     settings.number.underline = FALSE;
3405 #ifdef FEAT_SYN_HL
3406     /*
3407      * Syntax highlighting of line numbers.
3408      */
3409     if (prt_use_number() && settings.do_syntax)
3410     {
3411 	id = syn_name2id((char_u *)"LineNr");
3412 	if (id > 0)
3413 	    id = syn_get_final_id(id);
3414 
3415 	prt_get_attr(id, &settings.number, settings.modec);
3416     }
3417 #endif /* FEAT_SYN_HL */
3418 
3419     /*
3420      * Estimate the total lines to be printed
3421      */
3422     for (lnum = eap->line1; lnum <= eap->line2; lnum++)
3423 	bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
3424     if (bytes_to_print == 0)
3425     {
3426 	MSG(_("No text to be printed"));
3427 	goto print_fail_no_begin;
3428     }
3429 
3430     /* Set colors and font to normal. */
3431     curr_bg = (long_u)0xffffffffL;
3432     curr_fg = (long_u)0xffffffffL;
3433     curr_italic = MAYBE;
3434     curr_bold = MAYBE;
3435     curr_underline = MAYBE;
3436 
3437     prt_set_fg(PRCOLOR_BLACK);
3438     prt_set_bg(PRCOLOR_WHITE);
3439     prt_set_font(FALSE, FALSE, FALSE);
3440 #ifdef FEAT_SYN_HL
3441     current_syn_id = -1;
3442 #endif
3443 
3444     jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
3445 	   && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
3446 
3447     if (!mch_print_begin(&settings))
3448 	goto print_fail_no_begin;
3449 
3450     /*
3451      * Loop over collated copies: 1 2 3, 1 2 3, ...
3452      */
3453     page_count = 0;
3454     for (collated_copies = 0;
3455 	    collated_copies < settings.n_collated_copies;
3456 	    collated_copies++)
3457     {
3458 	prt_pos_T	prtpos;		/* current print position */
3459 	prt_pos_T	page_prtpos;	/* print position at page start */
3460 	int		side;
3461 
3462 	memset(&page_prtpos, 0, sizeof(prt_pos_T));
3463 	page_prtpos.file_line = eap->line1;
3464 	prtpos = page_prtpos;
3465 
3466 	if (jobsplit && collated_copies > 0)
3467 	{
3468 	    /* Splitting jobs: Stop a previous job and start a new one. */
3469 	    mch_print_end(&settings);
3470 	    if (!mch_print_begin(&settings))
3471 		goto print_fail_no_begin;
3472 	}
3473 
3474 	/*
3475 	 * Loop over all pages in the print job: 1 2 3 ...
3476 	 */
3477 	for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
3478 	{
3479 	    /*
3480 	     * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
3481 	     * For duplex: 12 12 12 34 34 34, ...
3482 	     */
3483 	    for (uncollated_copies = 0;
3484 		    uncollated_copies < settings.n_uncollated_copies;
3485 		    uncollated_copies++)
3486 	    {
3487 		/* Set the print position to the start of this page. */
3488 		prtpos = page_prtpos;
3489 
3490 		/*
3491 		 * Do front and rear side of a page.
3492 		 */
3493 		for (side = 0; side <= settings.duplex; ++side)
3494 		{
3495 		    /*
3496 		     * Print one page.
3497 		     */
3498 
3499 		    /* Check for interrupt character every page. */
3500 		    ui_breakcheck();
3501 		    if (got_int || settings.user_abort)
3502 			goto print_fail;
3503 
3504 		    sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
3505 			    page_count + 1 + side,
3506 			    prtpos.bytes_printed > 1000000
3507 				? (int)(prtpos.bytes_printed /
3508 						       (bytes_to_print / 100))
3509 				: (int)((prtpos.bytes_printed * 100)
3510 							   / bytes_to_print));
3511 		    if (!mch_print_begin_page(IObuff))
3512 			goto print_fail;
3513 
3514 		    if (settings.n_collated_copies > 1)
3515 			sprintf((char *)IObuff + STRLEN(IObuff),
3516 				_(" Copy %d of %d"),
3517 				collated_copies + 1,
3518 				settings.n_collated_copies);
3519 		    prt_message(IObuff);
3520 
3521 		    /*
3522 		     * Output header if required
3523 		     */
3524 		    if (prt_header_height() > 0)
3525 			prt_header(&settings, page_count + 1 + side,
3526 							prtpos.file_line);
3527 
3528 		    for (page_line = 0; page_line < settings.lines_per_page;
3529 								  ++page_line)
3530 		    {
3531 			prtpos.column = hardcopy_line(&settings,
3532 							   page_line, &prtpos);
3533 			if (prtpos.column == 0)
3534 			{
3535 			    /* finished a file line */
3536 			    prtpos.bytes_printed +=
3537 				  STRLEN(skipwhite(ml_get(prtpos.file_line)));
3538 			    if (++prtpos.file_line > eap->line2)
3539 				break; /* reached the end */
3540 			}
3541 			else if (prtpos.ff)
3542 			{
3543 			    /* Line had a formfeed in it - start new page but
3544 			     * stay on the current line */
3545 			    break;
3546 			}
3547 		    }
3548 
3549 		    if (!mch_print_end_page())
3550 			goto print_fail;
3551 		    if (prtpos.file_line > eap->line2)
3552 			break; /* reached the end */
3553 		}
3554 
3555 		/*
3556 		 * Extra blank page for duplexing with odd number of pages and
3557 		 * more copies to come.
3558 		 */
3559 		if (prtpos.file_line > eap->line2 && settings.duplex
3560 								 && side == 0
3561 		    && uncollated_copies + 1 < settings.n_uncollated_copies)
3562 		{
3563 		    if (!mch_print_blank_page())
3564 			goto print_fail;
3565 		}
3566 	    }
3567 	    if (settings.duplex && prtpos.file_line <= eap->line2)
3568 		++page_count;
3569 
3570 	    /* Remember the position where the next page starts. */
3571 	    page_prtpos = prtpos;
3572 	}
3573 
3574 	sprintf((char *)IObuff, _("Printed: %s"), settings.jobname);
3575 	prt_message(IObuff);
3576     }
3577 
3578 print_fail:
3579     if (got_int || settings.user_abort)
3580     {
3581 	sprintf((char *)IObuff, _("Printing aborted"));
3582 	prt_message(IObuff);
3583     }
3584     mch_print_end(&settings);
3585 
3586 print_fail_no_begin:
3587     mch_print_cleanup();
3588 }
3589 
3590 /*
3591  * Print one page line.
3592  * Return the next column to print, or zero if the line is finished.
3593  */
3594     static colnr_T
3595 hardcopy_line(psettings, page_line, ppos)
3596     prt_settings_T	*psettings;
3597     int			page_line;
3598     prt_pos_T		*ppos;
3599 {
3600     colnr_T	col;
3601     char_u	*line;
3602     int		need_break = FALSE;
3603     int		outputlen;
3604     int		tab_spaces;
3605     long_u	print_pos;
3606 #ifdef FEAT_SYN_HL
3607     prt_text_attr_T attr;
3608     int		id;
3609 #endif
3610 
3611     if (ppos->column == 0 || ppos->ff)
3612     {
3613 	print_pos = 0;
3614 	tab_spaces = 0;
3615 	if (!ppos->ff && prt_use_number())
3616 	    prt_line_number(psettings, page_line, ppos->file_line);
3617 	ppos->ff = FALSE;
3618     }
3619     else
3620     {
3621 	/* left over from wrap halfway a tab */
3622 	print_pos = ppos->print_pos;
3623 	tab_spaces = ppos->lead_spaces;
3624     }
3625 
3626     mch_print_start_line(0, page_line);
3627     line = ml_get(ppos->file_line);
3628 
3629     /*
3630      * Loop over the columns until the end of the file line or right margin.
3631      */
3632     for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
3633     {
3634 	outputlen = 1;
3635 #ifdef FEAT_MBYTE
3636 	if (has_mbyte && (outputlen = (*mb_ptr2len_check)(line + col)) < 1)
3637 	    outputlen = 1;
3638 #endif
3639 #ifdef FEAT_SYN_HL
3640 	/*
3641 	 * syntax highlighting stuff.
3642 	 */
3643 	if (psettings->do_syntax)
3644 	{
3645 	    id = syn_get_id(ppos->file_line, (long)col, 1);
3646 	    if (id > 0)
3647 		id = syn_get_final_id(id);
3648 	    else
3649 		id = 0;
3650 	    /* Get the line again, a multi-line regexp may invalidate it. */
3651 	    line = ml_get(ppos->file_line);
3652 
3653 	    if (id != current_syn_id)
3654 	    {
3655 		current_syn_id = id;
3656 		prt_get_attr(id, &attr, psettings->modec);
3657 		prt_set_font(attr.bold, attr.italic, attr.underline);
3658 		prt_set_fg(attr.fg_color);
3659 		prt_set_bg(attr.bg_color);
3660 	    }
3661 	}
3662 #endif /* FEAT_SYN_HL */
3663 
3664 	/*
3665 	 * Appropriately expand any tabs to spaces.
3666 	 */
3667 	if (line[col] == TAB || tab_spaces != 0)
3668 	{
3669 	    if (tab_spaces == 0)
3670 		tab_spaces = curbuf->b_p_ts - (print_pos % curbuf->b_p_ts);
3671 
3672 	    while (tab_spaces > 0)
3673 	    {
3674 		need_break = mch_print_text_out((char_u *)" ", 1);
3675 		print_pos++;
3676 		tab_spaces--;
3677 		if (need_break)
3678 		    break;
3679 	    }
3680 	    /* Keep the TAB if we didn't finish it. */
3681 	    if (need_break && tab_spaces > 0)
3682 		break;
3683 	}
3684 	else if (line[col] == FF
3685 		&& printer_opts[OPT_PRINT_FORMFEED].present
3686 		&& TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
3687 								       == 'y')
3688 	{
3689 	    ppos->ff = TRUE;
3690 	    need_break = 1;
3691 	}
3692 	else
3693 	{
3694 	    need_break = mch_print_text_out(line + col, outputlen);
3695 #ifdef FEAT_MBYTE
3696 	    if (has_mbyte)
3697 		print_pos += (*mb_ptr2cells)(line + col);
3698 	    else
3699 #endif
3700 		print_pos++;
3701 	}
3702     }
3703 
3704     ppos->lead_spaces = tab_spaces;
3705     ppos->print_pos = print_pos;
3706 
3707     /*
3708      * Start next line of file if we clip lines, or have reached end of the
3709      * line, unless we are doing a formfeed.
3710      */
3711     if (!ppos->ff
3712 	    && (line[col] == NUL
3713 		|| (printer_opts[OPT_PRINT_WRAP].present
3714 		    && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
3715 								     == 'n')))
3716 	return 0;
3717     return col;
3718 }
3719 
3720 # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
3721 
3722 /*
3723  * PS printer stuff.
3724  *
3725  * Sources of information to help maintain the PS printing code:
3726  *
3727  * 1. PostScript Language Reference, 3rd Edition,
3728  *      Addison-Wesley, 1999, ISBN 0-201-37922-8
3729  * 2. PostScript Language Program Design,
3730  *      Addison-Wesley, 1988, ISBN 0-201-14396-8
3731  * 3. PostScript Tutorial and Cookbook,
3732  *      Addison Wesley, 1985, ISBN 0-201-10179-3
3733  * 4. PostScript Language Document Structuring Conventions Specification,
3734  *    version 3.0,
3735  *      Adobe Technote 5001, 25th September 1992
3736  * 5. PostScript Printer Description File Format Specification, Version 4.3,
3737  *      Adobe technote 5003, 9th February 1996
3738  * 6. Adobe Font Metrics File Format Specification, Version 4.1,
3739  *      Adobe Technote 5007, 7th October 1998
3740  * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
3741  *      Adobe Technote 5014, 8th October 1996
3742  * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
3743  *      Adoboe Technote 5094, 8th September, 2001
3744  * 9. CJKV Information Processing, 2nd Edition,
3745  *      O'Reilly, 2002, ISBN 1-56592-224-7
3746  *
3747  * Some of these documents can be found in PDF form on Adobe's web site -
3748  * http://www.adobe.com
3749  */
3750 
3751 #define NUM_ELEMENTS(arr)   (sizeof(arr)/sizeof((arr)[0]))
3752 
3753 #define PRT_PS_DEFAULT_DPI	    (72)    /* Default user space resolution */
3754 #define PRT_PS_DEFAULT_FONTSIZE     (10)
3755 #define PRT_PS_DEFAULT_BUFFER_SIZE  (80)
3756 
3757 struct prt_mediasize_S
3758 {
3759     char	*name;
3760     float	width;		/* width and height in points for portrait */
3761     float	height;
3762 };
3763 
3764 #define PRT_MEDIASIZE_LEN  (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
3765 
3766 static struct prt_mediasize_S prt_mediasize[] =
3767 {
3768     {"A4",		595.0,  842.0},
3769     {"letter",		612.0,  792.0},
3770     {"10x14",		720.0, 1008.0},
3771     {"A3",		842.0, 1191.0},
3772     {"A5",		420.0,  595.0},
3773     {"B4",		729.0, 1032.0},
3774     {"B5",		516.0,  729.0},
3775     {"executive",	522.0,  756.0},
3776     {"folio",		595.0,  935.0},
3777     {"ledger",	       1224.0,  792.0},   /* Yes, it is wider than taller! */
3778     {"legal",		612.0, 1008.0},
3779     {"quarto",		610.0,  780.0},
3780     {"statement",	396.0,  612.0},
3781     {"tabloid",		792.0, 1224.0}
3782 };
3783 
3784 /* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */
3785 struct prt_ps_font_S
3786 {
3787     int		wx;
3788     int		uline_offset;
3789     int		uline_width;
3790     int		bbox_min_y;
3791     int		bbox_max_y;
3792     char	*(ps_fontname[4]);
3793 };
3794 
3795 #define PRT_PS_FONT_ROMAN	(0)
3796 #define PRT_PS_FONT_BOLD	(1)
3797 #define PRT_PS_FONT_OBLIQUE	(2)
3798 #define PRT_PS_FONT_BOLDOBLIQUE (3)
3799 
3800 /* Standard font metrics for Courier family */
3801 static struct prt_ps_font_S prt_ps_courier_font =
3802 {
3803     600,
3804     -100, 50,
3805     -250, 805,
3806     {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
3807 };
3808 
3809 #ifdef FEAT_MBYTE
3810 /* Generic font metrics for multi-byte fonts */
3811 static struct prt_ps_font_S prt_ps_mb_font =
3812 {
3813     1000,
3814     -100, 50,
3815     -250, 805,
3816     {NULL, NULL, NULL, NULL}
3817 };
3818 #endif
3819 
3820 /* Pointer to current font set being used */
3821 static struct prt_ps_font_S* prt_ps_font;
3822 
3823 /* Structures to map user named encoding and mapping to PS equivalents for
3824  * building CID font name */
3825 struct prt_ps_encoding_S
3826 {
3827     char	*encoding;
3828     char	*cmap_encoding;
3829     int		needs_charset;
3830 };
3831 
3832 struct prt_ps_charset_S
3833 {
3834     char	*charset;
3835     char	*cmap_charset;
3836     int		has_charset;
3837 };
3838 
3839 #ifdef FEAT_MBYTE
3840 
3841 #define CS_JIS_C_1978   (0x01)
3842 #define CS_JIS_X_1983   (0x02)
3843 #define CS_JIS_X_1990   (0x04)
3844 #define CS_NEC          (0x08)
3845 #define CS_MSWINDOWS    (0x10)
3846 #define CS_CP932        (0x20)
3847 #define CS_KANJITALK6   (0x40)
3848 #define CS_KANJITALK7   (0x80)
3849 
3850 /* Japanese encodings and charsets */
3851 static struct prt_ps_encoding_S j_encodings[] =
3852 {
3853     {"iso-2022-jp", NULL,       (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
3854                                                                     CS_NEC)},
3855     {"euc-jp",      "EUC",      (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
3856     {"sjis",        "RKSJ",     (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
3857                                                 CS_KANJITALK6|CS_KANJITALK7)},
3858     {"cp932",       "RKSJ",     CS_JIS_X_1983},
3859     {"ucs-2",       "UCS2",     CS_JIS_X_1990},
3860     {"utf-8",       "UTF8" ,    CS_JIS_X_1990}
3861 };
3862 static struct prt_ps_charset_S j_charsets[] =
3863 {
3864     {"JIS_C_1978",  "78",       CS_JIS_C_1978},
3865     {"JIS_X_1983",  NULL,       CS_JIS_X_1983},
3866     {"JIS_X_1990",  "Hojo",     CS_JIS_X_1990},
3867     {"NEC",         "Ext",      CS_NEC},
3868     {"MSWINDOWS",   "90ms",     CS_MSWINDOWS},
3869     {"CP932",       "90ms",     CS_JIS_X_1983},
3870     {"KANJITALK6",  "83pv",     CS_KANJITALK6},
3871     {"KANJITALK7",  "90pv",     CS_KANJITALK7}
3872 };
3873 
3874 #define CS_GB_2312_80       (0x01)
3875 #define CS_GBT_12345_90     (0x02)
3876 #define CS_GBK2K            (0x04)
3877 #define CS_SC_MAC           (0x08)
3878 #define CS_GBT_90_MAC       (0x10)
3879 #define CS_GBK              (0x20)
3880 #define CS_SC_ISO10646      (0x40)
3881 
3882 /* Simplified Chinese encodings and charsets */
3883 static struct prt_ps_encoding_S sc_encodings[] =
3884 {
3885     {"iso-2022",    NULL,       (CS_GB_2312_80|CS_GBT_12345_90)},
3886     {"gb18030",     NULL,       CS_GBK2K},
3887     {"euc-cn",      "EUC",      (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
3888                                                                 CS_GBT_90_MAC)},
3889     {"gbk",         "EUC",      CS_GBK},
3890     {"ucs-2",       "UCS2",     CS_SC_ISO10646},
3891     {"utf-8",       "UTF8",     CS_SC_ISO10646}
3892 };
3893 static struct prt_ps_charset_S sc_charsets[] =
3894 {
3895     {"GB_2312-80",  "GB",       CS_GB_2312_80},
3896     {"GBT_12345-90","GBT",      CS_GBT_12345_90},
3897     {"MAC",         "GBpc",     CS_SC_MAC},
3898     {"GBT-90_MAC",  "GBTpc",    CS_GBT_90_MAC},
3899     {"GBK",         "GBK",      CS_GBK},
3900     {"GB18030",     "GBK2K",    CS_GBK2K},
3901     {"ISO10646",    "UniGB",    CS_SC_ISO10646}
3902 };
3903 
3904 #define CS_CNS_PLANE_1      (0x01)
3905 #define CS_CNS_PLANE_2      (0x02)
3906 #define CS_CNS_PLANE_1_2    (0x04)
3907 #define CS_B5               (0x08)
3908 #define CS_ETEN             (0x10)
3909 #define CS_HK_GCCS          (0x20)
3910 #define CS_HK_SCS           (0x40)
3911 #define CS_HK_SCS_ETEN      (0x80)
3912 #define CS_MTHKL            (0x100)
3913 #define CS_MTHKS            (0x200)
3914 #define CS_DLHKL            (0x400)
3915 #define CS_DLHKS            (0x800)
3916 #define CS_TC_ISO10646      (0x1000)
3917 
3918 /* Traditional Chinese encodings and charsets */
3919 static struct prt_ps_encoding_S tc_encodings[] =
3920 {
3921     {"iso-2022",    NULL,       (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
3922     {"euc-tw",      "EUC",      CS_CNS_PLANE_1_2},
3923     {"big5",        "B5",       (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
3924                                     CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
3925                                                                     CS_DLHKS)},
3926     {"cp950",       "B5",       CS_B5},
3927     {"ucs-2",       "UCS2",     CS_TC_ISO10646},
3928     {"utf-8",       "UTF8",     CS_TC_ISO10646},
3929     {"utf-16",      "UTF16",    CS_TC_ISO10646},
3930     {"utf-32",      "UTF32",    CS_TC_ISO10646}
3931 };
3932 static struct prt_ps_charset_S tc_charsets[] =
3933 {
3934     {"CNS_1992_1",  "CNS1",     CS_CNS_PLANE_1},
3935     {"CNS_1992_2",  "CNS2",     CS_CNS_PLANE_2},
3936     {"CNS_1993",    "CNS",      CS_CNS_PLANE_1_2},
3937     {"BIG5",        NULL,       CS_B5},
3938     {"CP950",       NULL,       CS_B5},
3939     {"ETEN",        "ETen",     CS_ETEN},
3940     {"HK_GCCS",     "HKgccs",   CS_HK_GCCS},
3941     {"SCS",         "HKscs",    CS_HK_SCS},
3942     {"SCS_ETEN",    "ETHK",     CS_HK_SCS_ETEN},
3943     {"MTHKL",       "HKm471",   CS_MTHKL},
3944     {"MTHKS",       "HKm314",   CS_MTHKS},
3945     {"DLHKL",       "HKdla",    CS_DLHKL},
3946     {"DLHKS",       "HKdlb",    CS_DLHKS},
3947     {"ISO10646",    "UniCNS",   CS_TC_ISO10646}
3948 };
3949 
3950 #define CS_KR_X_1992        (0x01)
3951 #define CS_KR_MAC           (0x02)
3952 #define CS_KR_X_1992_MS     (0x04)
3953 #define CS_KR_ISO10646      (0x08)
3954 
3955 /* Korean encodings and charsets */
3956 static struct prt_ps_encoding_S k_encodings[] =
3957 {
3958     {"iso-2022-kr", NULL,       CS_KR_X_1992},
3959     {"euc-kr",      "EUC",      (CS_KR_X_1992|CS_KR_MAC)},
3960     {"johab",       "Johab",    CS_KR_X_1992},
3961     {"cp1361",      "Johab",    CS_KR_X_1992},
3962     {"uhc",         "UHC",      CS_KR_X_1992_MS},
3963     {"cp949",       "UHC",      CS_KR_X_1992_MS},
3964     {"ucs-2",       "UCS2",     CS_KR_ISO10646},
3965     {"utf-8",       "UTF8",     CS_KR_ISO10646}
3966 };
3967 static struct prt_ps_charset_S k_charsets[] =
3968 {
3969     {"KS_X_1992",   "KSC",      CS_KR_X_1992},
3970     {"CP1361",      "KSC",      CS_KR_X_1992},
3971     {"MAC",         "KSCpc",    CS_KR_MAC},
3972     {"MSWINDOWS",   "KSCms",    CS_KR_X_1992_MS},
3973     {"CP949",       "KSCms",    CS_KR_X_1992_MS},
3974     {"WANSUNG",     "KSCms",    CS_KR_X_1992_MS},
3975     {"ISO10646",    "UniKS",    CS_KR_ISO10646}
3976 };
3977 
3978 /* Collections of encodings and charsets for multi-byte printing */
3979 struct prt_ps_mbfont_S
3980 {
3981     int                         num_encodings;
3982     struct prt_ps_encoding_S    *encodings;
3983     int                         num_charsets;
3984     struct prt_ps_charset_S     *charsets;
3985     char                        *ascii_enc;
3986     char                        *defcs;
3987 };
3988 
3989 static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
3990 {
3991     {
3992         NUM_ELEMENTS(j_encodings),
3993         j_encodings,
3994         NUM_ELEMENTS(j_charsets),
3995         j_charsets,
3996         "jis_roman",
3997         "JIS_X_1983"
3998     },
3999     {
4000         NUM_ELEMENTS(sc_encodings),
4001         sc_encodings,
4002         NUM_ELEMENTS(sc_charsets),
4003         sc_charsets,
4004         "gb_roman",
4005         "GB_2312-80"
4006     },
4007     {
4008         NUM_ELEMENTS(tc_encodings),
4009         tc_encodings,
4010         NUM_ELEMENTS(tc_charsets),
4011         tc_charsets,
4012         "cns_roman",
4013         "BIG5"
4014     },
4015     {
4016         NUM_ELEMENTS(k_encodings),
4017         k_encodings,
4018         NUM_ELEMENTS(k_charsets),
4019         k_charsets,
4020         "ks_roman",
4021         "KS_X_1992"
4022     }
4023 };
4024 #endif /* FEAT_MBYTE */
4025 
4026 struct prt_ps_resource_S
4027 {
4028     char_u  name[64];
4029     char_u  filename[MAXPATHL + 1];
4030     int     type;
4031     char_u  title[256];
4032     char_u  version[256];
4033 };
4034 
4035 /* Types of PS resource file currently used */
4036 #define PRT_RESOURCE_TYPE_PROCSET   (0)
4037 #define PRT_RESOURCE_TYPE_ENCODING  (1)
4038 #define PRT_RESOURCE_TYPE_CMAP      (2)
4039 
4040 /* The PS prolog file version number has to match - if the prolog file is
4041  * updated, increment the number in the file and here.  Version checking was
4042  * added as of VIM 6.2.
4043  * The CID prolog file version number behaves as per PS prolog.
4044  * Table of VIM and prolog versions:
4045  *
4046  * VIM      Prolog  CIDProlog
4047  * 6.2      1.3
4048  * 7.0      1.4	    1.0
4049  */
4050 #define PRT_PROLOG_VERSION  ((char_u *)"1.4")
4051 #define PRT_CID_PROLOG_VERSION  ((char_u *)"1.0")
4052 
4053 /* String versions of PS resource types - indexed by constants above so don't
4054  * re-order!
4055  */
4056 static char *prt_resource_types[] =
4057 {
4058     "procset",
4059     "encoding",
4060     "cmap"
4061 };
4062 
4063 /* Strings to look for in a PS resource file */
4064 #define PRT_RESOURCE_HEADER	    "%!PS-Adobe-"
4065 #define PRT_RESOURCE_RESOURCE	    "Resource-"
4066 #define PRT_RESOURCE_PROCSET	    "ProcSet"
4067 #define PRT_RESOURCE_ENCODING	    "Encoding"
4068 #define PRT_RESOURCE_CMAP           "CMap"
4069 
4070 
4071 /* Data for table based DSC comment recognition, easy to extend if VIM needs to
4072  * read more comments. */
4073 #define PRT_DSC_MISC_TYPE           (-1)
4074 #define PRT_DSC_TITLE_TYPE          (1)
4075 #define PRT_DSC_VERSION_TYPE        (2)
4076 #define PRT_DSC_ENDCOMMENTS_TYPE    (3)
4077 
4078 #define PRT_DSC_TITLE	            "%%Title:"
4079 #define PRT_DSC_VERSION	            "%%Version:"
4080 #define PRT_DSC_ENDCOMMENTS         "%%EndComments:"
4081 
4082 struct prt_dsc_comment_S
4083 {
4084     char	*string;
4085     int		len;
4086     int		type;
4087 };
4088 
4089 struct prt_dsc_line_S
4090 {
4091     int		type;
4092     char_u	*string;
4093     int		len;
4094 };
4095 
4096 
4097 #define SIZEOF_CSTR(s)      (sizeof(s) - 1)
4098 struct prt_dsc_comment_S prt_dsc_table[] =
4099 {
4100     {PRT_DSC_TITLE,       SIZEOF_CSTR(PRT_DSC_TITLE),     PRT_DSC_TITLE_TYPE},
4101     {PRT_DSC_VERSION,     SIZEOF_CSTR(PRT_DSC_VERSION),
4102 							PRT_DSC_VERSION_TYPE},
4103     {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
4104 						     PRT_DSC_ENDCOMMENTS_TYPE}
4105 };
4106 
4107 static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes));
4108 static void prt_write_file __ARGS((char_u *buffer));
4109 static void prt_write_file_len __ARGS((char_u *buffer, int bytes));
4110 static void prt_write_string __ARGS((char *s));
4111 static void prt_write_int __ARGS((int i));
4112 static void prt_write_boolean __ARGS((int b));
4113 static void prt_def_font __ARGS((char *new_name, char *encoding, int height, char *font));
4114 static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction));
4115 static void prt_write_real __ARGS((double val, int prec));
4116 static void prt_def_var __ARGS((char *name, double value, int prec));
4117 static void prt_flush_buffer __ARGS((void));
4118 static void prt_resource_name __ARGS((char_u *filename));
4119 static int prt_find_resource __ARGS((char *name, struct prt_ps_resource_S *resource));
4120 static int prt_open_resource __ARGS((struct prt_ps_resource_S *resource));
4121 static int prt_check_resource __ARGS((struct prt_ps_resource_S *resource, char_u *version));
4122 static void prt_dsc_start __ARGS((void));
4123 static void prt_dsc_noarg __ARGS((char *comment));
4124 static void prt_dsc_textline __ARGS((char *comment, char *text));
4125 static void prt_dsc_text __ARGS((char *comment, char *text));
4126 static void prt_dsc_ints __ARGS((char *comment, int count, int *ints));
4127 static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies));
4128 static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type));
4129 static void prt_dsc_resources __ARGS((char *comment, char *type, char *strings));
4130 static void prt_dsc_font_resource __ARGS((char *resource, struct prt_ps_font_S *ps_font));
4131 static float to_device_units __ARGS((int idx, double physsize, int def_number));
4132 static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom));
4133 static void prt_font_metrics __ARGS((int font_scale));
4134 static int prt_get_cpl __ARGS((void));
4135 static int prt_get_lpp __ARGS((void));
4136 static int prt_add_resource __ARGS((struct prt_ps_resource_S *resource));
4137 static int prt_resfile_next_line __ARGS((void));
4138 static int prt_resfile_strncmp __ARGS((int offset, char *string, int len));
4139 static int prt_resfile_skip_nonws __ARGS((int offset));
4140 static int prt_resfile_skip_ws __ARGS((int offset));
4141 static int prt_next_dsc __ARGS((struct prt_dsc_line_S *p_dsc_line));
4142 #ifdef FEAT_MBYTE
4143 static int prt_build_cid_fontname __ARGS((int font, char_u *name, int name_len));
4144 static void prt_def_cidfont __ARGS((char *new_name, int height, char *cidfont));
4145 static int prt_match_encoding __ARGS((char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc));
4146 static int prt_match_charset __ARGS((char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar));
4147 #endif
4148 
4149 /*
4150  * Variables for the output PostScript file.
4151  */
4152 static FILE *prt_ps_fd;
4153 static int prt_file_error;
4154 static char_u *prt_ps_file_name = NULL;
4155 
4156 /*
4157  * Various offsets and dimensions in default PostScript user space (points).
4158  * Used for text positioning calculations
4159  */
4160 static float prt_page_width;
4161 static float prt_page_height;
4162 static float prt_left_margin;
4163 static float prt_right_margin;
4164 static float prt_top_margin;
4165 static float prt_bottom_margin;
4166 static float prt_line_height;
4167 static float prt_first_line_height;
4168 static float prt_char_width;
4169 static float prt_number_width;
4170 static float prt_bgcol_offset;
4171 static float prt_pos_x_moveto = 0.0;
4172 static float prt_pos_y_moveto = 0.0;
4173 
4174 /*
4175  * Various control variables used to decide when and how to change the
4176  * PostScript graphics state.
4177  */
4178 static int prt_need_moveto;
4179 static int prt_do_moveto;
4180 static int prt_need_font;
4181 static int prt_font;
4182 static int prt_need_underline;
4183 static int prt_underline;
4184 static int prt_do_underline;
4185 static int prt_need_fgcol;
4186 static int prt_fgcol;
4187 static int prt_need_bgcol;
4188 static int prt_do_bgcol;
4189 static int prt_bgcol;
4190 static int prt_new_bgcol;
4191 static int prt_attribute_change;
4192 static float prt_text_run;
4193 static int prt_page_num;
4194 static int prt_bufsiz;
4195 
4196 /*
4197  * Variables controlling physical printing.
4198  */
4199 static int prt_media;
4200 static int prt_portrait;
4201 static int prt_num_copies;
4202 static int prt_duplex;
4203 static int prt_tumble;
4204 static int prt_collate;
4205 
4206 /*
4207  * Buffers used when generating PostScript output
4208  */
4209 static char_u prt_line_buffer[257];
4210 static garray_T prt_ps_buffer;
4211 
4212 # ifdef FEAT_MBYTE
4213 static int prt_do_conv;
4214 static vimconv_T prt_conv;
4215 
4216 static int prt_out_mbyte;
4217 static int prt_custom_cmap;
4218 static char prt_cmap[80];
4219 static int prt_use_courier;
4220 static int prt_in_ascii;
4221 static int prt_half_width;
4222 static char *prt_ascii_encoding;
4223 static char_u prt_hexchar[] = "0123456789abcdef";
4224 # endif
4225 
4226     static void
4227 prt_write_file_raw_len(buffer, bytes)
4228     char_u	*buffer;
4229     int		bytes;
4230 {
4231     if (!prt_file_error
4232 	    && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
4233 							     != (size_t)bytes)
4234     {
4235 	EMSG(_("E455: Error writing to PostScript output file"));
4236 	prt_file_error = TRUE;
4237     }
4238 }
4239 
4240     static void
4241 prt_write_file(buffer)
4242     char_u	*buffer;
4243 {
4244     prt_write_file_len(buffer, STRLEN(buffer));
4245 }
4246 
4247     static void
4248 prt_write_file_len(buffer, bytes)
4249     char_u	*buffer;
4250     int		bytes;
4251 {
4252 #ifdef EBCDIC
4253     ebcdic2ascii(buffer, bytes);
4254 #endif
4255     prt_write_file_raw_len(buffer, bytes);
4256 }
4257 
4258 /*
4259  * Write a string.
4260  */
4261     static void
4262 prt_write_string(s)
4263     char	*s;
4264 {
4265     sprintf((char *)prt_line_buffer, "%s", s);
4266     prt_write_file(prt_line_buffer);
4267 }
4268 
4269 /*
4270  * Write an int and a space.
4271  */
4272     static void
4273 prt_write_int(i)
4274     int		i;
4275 {
4276     sprintf((char *)prt_line_buffer, "%d ", i);
4277     prt_write_file(prt_line_buffer);
4278 }
4279 
4280 /*
4281  * Write a boolean and a space.
4282  */
4283     static void
4284 prt_write_boolean(b)
4285     int		b;
4286 {
4287     sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
4288     prt_write_file(prt_line_buffer);
4289 }
4290 
4291 /*
4292  * Write PostScript to re-encode and define the font.
4293  */
4294     static void
4295 prt_def_font(new_name, encoding, height, font)
4296     char	*new_name;
4297     char	*encoding;
4298     int		height;
4299     char	*font;
4300 {
4301     sprintf((char *)prt_line_buffer, "/_%s /VIM-%s /%s ref\n",
4302                                                      new_name, encoding, font);
4303     prt_write_file(prt_line_buffer);
4304 #ifdef FEAT_MBYTE
4305     if (prt_out_mbyte)
4306         sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
4307 		       new_name, height, 500./prt_ps_courier_font.wx, new_name);
4308     else
4309 #endif
4310     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n",
4311 						    new_name, height, new_name);
4312     prt_write_file(prt_line_buffer);
4313 }
4314 
4315 #ifdef FEAT_MBYTE
4316 /*
4317  * Write a line to define the CID font.
4318  */
4319     static void
4320 prt_def_cidfont(new_name, height, cidfont)
4321     char	*new_name;
4322     int		height;
4323     char	*cidfont;
4324 {
4325     sprintf((char *)prt_line_buffer, "/_%s /%s[/%s] vim_composefont\n",
4326                                                 new_name, prt_cmap, cidfont);
4327     prt_write_file(prt_line_buffer);
4328     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", new_name, height,
4329                                                                     new_name);
4330     prt_write_file(prt_line_buffer);
4331 }
4332 
4333 /*
4334  * Write a line to define a duplicate of a CID font
4335  */
4336     static void
4337 prt_dup_cidfont(original_name, new_name)
4338     char	*original_name;
4339     char	*new_name;
4340 {
4341     sprintf((char *)prt_line_buffer, "/%s %s d\n", new_name, original_name);
4342     prt_write_file(prt_line_buffer);
4343 }
4344 #endif
4345 
4346 /*
4347  * Convert a real value into an integer and fractional part as integers, with
4348  * the fractional part being in the range [0,10^precision).  The fractional part
4349  * is also rounded based on the precision + 1'th fractional digit.
4350  */
4351     static void
4352 prt_real_bits(real, precision, pinteger, pfraction)
4353     double      real;
4354     int		precision;
4355     int		*pinteger;
4356     int		*pfraction;
4357 {
4358     int     i;
4359     int     integer;
4360     float   fraction;
4361 
4362     integer = (int)real;
4363     fraction = (float)(real - integer);
4364     if (real < (double)integer)
4365 	fraction = -fraction;
4366     for (i = 0; i < precision; i++)
4367 	fraction *= 10.0;
4368 
4369     *pinteger = integer;
4370     *pfraction = (int)(fraction + 0.5);
4371 }
4372 
4373 /*
4374  * Write a real and a space.  Save bytes if real value has no fractional part!
4375  * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
4376  * what decimal point character to use, but PS always requires a '.'.
4377  */
4378     static void
4379 prt_write_real(val, prec)
4380     double	val;
4381     int		prec;
4382 {
4383     int     integer;
4384     int     fraction;
4385 
4386     prt_real_bits(val, prec, &integer, &fraction);
4387     /* Emit integer part */
4388     sprintf((char *)prt_line_buffer, "%d", integer);
4389     prt_write_file(prt_line_buffer);
4390     /* Only emit fraction if necessary */
4391     if (fraction != 0)
4392     {
4393 	/* Remove any trailing zeros */
4394 	while ((fraction % 10) == 0)
4395 	{
4396 	    prec--;
4397 	    fraction /= 10;
4398 	}
4399 	/* Emit fraction left padded with zeros */
4400 	sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
4401 	prt_write_file(prt_line_buffer);
4402     }
4403     sprintf((char *)prt_line_buffer, " ");
4404     prt_write_file(prt_line_buffer);
4405 }
4406 
4407 /*
4408  * Write a line to define a numeric variable.
4409  */
4410     static void
4411 prt_def_var(name, value, prec)
4412     char	*name;
4413     double	value;
4414     int		prec;
4415 {
4416     sprintf((char *)prt_line_buffer, "/%s ", name);
4417     prt_write_file(prt_line_buffer);
4418     prt_write_real(value, prec);
4419     sprintf((char *)prt_line_buffer, "d\n");
4420     prt_write_file(prt_line_buffer);
4421 }
4422 
4423 /* Convert size from font space to user space at current font scale */
4424 #define PRT_PS_FONT_TO_USER(scale, size)    ((size) * ((scale)/1000.0))
4425 
4426     static void
4427 prt_flush_buffer()
4428 {
4429     if (prt_ps_buffer.ga_len > 0)
4430     {
4431 	/* Any background color must be drawn first */
4432 	if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
4433 	{
4434 	    int     r, g, b;
4435 
4436 	    if (prt_do_moveto)
4437 	    {
4438 		prt_write_real(prt_pos_x_moveto, 2);
4439 		prt_write_real(prt_pos_y_moveto, 2);
4440 		prt_write_string("m\n");
4441 		prt_do_moveto = FALSE;
4442 	    }
4443 
4444 	    /* Size of rect of background color on which text is printed */
4445 	    prt_write_real(prt_text_run, 2);
4446 	    prt_write_real(prt_line_height, 2);
4447 
4448 	    /* Lastly add the color of the background */
4449 	    r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
4450 	    g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
4451 	    b = prt_new_bgcol & 0xff;
4452 	    prt_write_real(r / 255.0, 3);
4453 	    prt_write_real(g / 255.0, 3);
4454 	    prt_write_real(b / 255.0, 3);
4455 	    prt_write_string("bg\n");
4456 	}
4457 	/* Draw underlines before the text as it makes it slightly easier to
4458 	 * find the starting point.
4459 	 */
4460 	if (prt_do_underline)
4461 	{
4462 	    if (prt_do_moveto)
4463 	    {
4464 		prt_write_real(prt_pos_x_moveto, 2);
4465 		prt_write_real(prt_pos_y_moveto, 2);
4466 		prt_write_string("m\n");
4467 		prt_do_moveto = FALSE;
4468 	    }
4469 
4470             /* Underline length of text run */
4471 	    prt_write_real(prt_text_run, 2);
4472 	    prt_write_string("ul\n");
4473 	}
4474 	/* Draw the text
4475 	 * Note: we write text out raw - EBCDIC conversion is handled in the
4476 	 * PostScript world via the font encoding vector. */
4477 #ifdef FEAT_MBYTE
4478         if (prt_out_mbyte)
4479             prt_write_string("<");
4480         else
4481 #endif
4482             prt_write_string("(");
4483 	prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
4484 #ifdef FEAT_MBYTE
4485         if (prt_out_mbyte)
4486             prt_write_string(">");
4487         else
4488 #endif
4489             prt_write_string(")");
4490 	/* Add a moveto if need be and use the appropriate show procedure */
4491 	if (prt_do_moveto)
4492 	{
4493 	    prt_write_real(prt_pos_x_moveto, 2);
4494 	    prt_write_real(prt_pos_y_moveto, 2);
4495 	    /* moveto and a show */
4496 	    prt_write_string("ms\n");
4497 	    prt_do_moveto = FALSE;
4498 	}
4499 	else /* Simple show */
4500 	    prt_write_string("s\n");
4501 
4502 	ga_clear(&prt_ps_buffer);
4503 	ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
4504     }
4505 }
4506 
4507 static char_u *resource_filename;
4508 
4509     static void
4510 prt_resource_name(filename)
4511     char_u  *filename;
4512 {
4513     if (STRLEN(filename) >= MAXPATHL)
4514 	*resource_filename = NUL;
4515     else
4516 	STRCPY(resource_filename, filename);
4517 }
4518 
4519     static int
4520 prt_find_resource(name, resource)
4521     char	*name;
4522     struct prt_ps_resource_S *resource;
4523 {
4524     char_u	buffer[MAXPATHL + 1];
4525 
4526     STRCPY(resource->name, name);
4527     /* Look for named resource file in runtimepath */
4528     STRCPY(buffer, "print");
4529     add_pathsep(buffer);
4530     STRCAT(buffer, name);
4531     STRCAT(buffer, ".ps");
4532     resource_filename = resource->filename;
4533     *resource_filename = NUL;
4534     return (do_in_runtimepath(buffer, FALSE, prt_resource_name)
4535 	    && resource->filename[0] != NUL);
4536 }
4537 
4538 /* PS CR and LF characters have platform independent values */
4539 #define PSLF  (0x0a)
4540 #define PSCR  (0x0d)
4541 
4542 /* Static buffer to read initial comments in a resource file, some can have a
4543  * couple of KB of comments! */
4544 #define PRT_FILE_BUFFER_LEN (2048)
4545 struct prt_resfile_buffer_S
4546 {
4547     char_u  buffer[PRT_FILE_BUFFER_LEN];
4548     int     len;
4549     int     line_start;
4550     int     line_end;
4551 };
4552 
4553 static struct prt_resfile_buffer_S prt_resfile;
4554 
4555     static int
4556 prt_resfile_next_line()
4557 {
4558     int     index;
4559 
4560     /* Move to start of next line and then find end of line */
4561     index = prt_resfile.line_end + 1;
4562     while (index < prt_resfile.len)
4563     {
4564         if (prt_resfile.buffer[index] != PSLF && prt_resfile.buffer[index]
4565                                                                         != PSCR)
4566             break;
4567         index++;
4568     }
4569     prt_resfile.line_start = index;
4570 
4571     while (index < prt_resfile.len)
4572     {
4573         if (prt_resfile.buffer[index] == PSLF || prt_resfile.buffer[index]
4574                                                                         == PSCR)
4575             break;
4576         index++;
4577     }
4578     prt_resfile.line_end = index;
4579 
4580     return (index < prt_resfile.len);
4581 }
4582 
4583     static int
4584 prt_resfile_strncmp(offset, string, len)
4585     int     offset;
4586     char    *string;
4587     int     len;
4588 {
4589     /* Force not equal if string is longer than remainder of line */
4590     if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
4591         return 1;
4592 
4593     return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
4594                                                                 string, len);
4595 }
4596 
4597     static int
4598 prt_resfile_skip_nonws(offset)
4599     int     offset;
4600 {
4601     int     index;
4602 
4603     index = prt_resfile.line_start + offset;
4604     while (index < prt_resfile.line_end)
4605     {
4606         if (isspace(prt_resfile.buffer[index]))
4607             return index - prt_resfile.line_start;
4608         index++;
4609     }
4610     return -1;
4611 }
4612 
4613     static int
4614 prt_resfile_skip_ws(offset)
4615     int     offset;
4616 {
4617     int     index;
4618 
4619     index = prt_resfile.line_start + offset;
4620     while (index < prt_resfile.line_end)
4621     {
4622         if (!isspace(prt_resfile.buffer[index]))
4623             return index - prt_resfile.line_start;
4624         index++;
4625     }
4626     return -1;
4627 }
4628 
4629 /* prt_next_dsc() - returns detail on next DSC comment line found.  Returns true
4630  * if a DSC comment is found, else false */
4631     static int
4632 prt_next_dsc(p_dsc_line)
4633     struct prt_dsc_line_S *p_dsc_line;
4634 {
4635     int     comment;
4636     int     offset;
4637 
4638     /* Move to start of next line */
4639     if (!prt_resfile_next_line())
4640         return FALSE;
4641 
4642     /* DSC comments always start %% */
4643     if (prt_resfile_strncmp(0, "%%", 2) != 0)
4644         return FALSE;
4645 
4646     /* Find type of DSC comment */
4647     for (comment = 0; comment < NUM_ELEMENTS(prt_dsc_table); comment++)
4648         if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
4649                                             prt_dsc_table[comment].len) == 0)
4650             break;
4651 
4652     if (comment != NUM_ELEMENTS(prt_dsc_table))
4653     {
4654         /* Return type of comment */
4655         p_dsc_line->type = prt_dsc_table[comment].type;
4656         offset = prt_dsc_table[comment].len;
4657     }
4658     else
4659     {
4660         /* Unrecognised DSC comment, skip to ws after comment leader */
4661         p_dsc_line->type = PRT_DSC_MISC_TYPE;
4662         offset = prt_resfile_skip_nonws(0);
4663         if (offset == -1)
4664             return FALSE;
4665     }
4666 
4667     /* Skip ws to comment value */
4668     offset = prt_resfile_skip_ws(offset);
4669     if (offset == -1)
4670         return FALSE;
4671 
4672     p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
4673     p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
4674 
4675     return TRUE;
4676 }
4677 
4678 /* Improved hand crafted parser to get the type, title, and version number of a
4679  * PS resource file so the file details can be added to the DSC header comments.
4680  */
4681     static int
4682 prt_open_resource(resource)
4683     struct prt_ps_resource_S *resource;
4684 {
4685     int         offset;
4686     int         seen_all;
4687     int         seen_title;
4688     int         seen_version;
4689     FILE	*fd_resource;
4690     struct prt_dsc_line_S dsc_line;
4691 
4692     fd_resource = mch_fopen((char *)resource->filename, READBIN);
4693     if (fd_resource == NULL)
4694     {
4695 	EMSG2(_("E624: Can't open file \"%s\""), resource->filename);
4696 	return FALSE;
4697     }
4698     vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN);
4699 
4700     /* Parse first line to ensure valid resource file */
4701     prt_resfile.len = fread((char *)prt_resfile.buffer, sizeof(char_u),
4702                                             PRT_FILE_BUFFER_LEN, fd_resource);
4703     if (ferror(fd_resource))
4704     {
4705 	EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
4706 		resource->filename);
4707 	fclose(fd_resource);
4708 	return FALSE;
4709     }
4710 
4711     prt_resfile.line_end = -1;
4712     prt_resfile.line_start = 0;
4713     if (!prt_resfile_next_line())
4714         return FALSE;
4715 
4716     offset = 0;
4717 
4718     if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
4719                                             STRLEN(PRT_RESOURCE_HEADER)) != 0)
4720     {
4721 	EMSG2(_("E618: file \"%s\" is not a PostScript resource file"),
4722 		resource->filename);
4723 	fclose(fd_resource);
4724 	return FALSE;
4725     }
4726 
4727     /* Skip over any version numbers and following ws */
4728     offset += STRLEN(PRT_RESOURCE_HEADER);
4729     offset = prt_resfile_skip_nonws(offset);
4730     if (offset == -1)
4731         return FALSE;
4732     offset = prt_resfile_skip_ws(offset);
4733     if (offset == -1)
4734         return FALSE;
4735 
4736     if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
4737                                             STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
4738     {
4739 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4740 		resource->filename);
4741 	fclose(fd_resource);
4742 	return FALSE;
4743     }
4744     offset += STRLEN(PRT_RESOURCE_RESOURCE);
4745 
4746     /* Decide type of resource in the file */
4747     if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
4748                                             STRLEN(PRT_RESOURCE_PROCSET)) == 0)
4749 	resource->type = PRT_RESOURCE_TYPE_PROCSET;
4750     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
4751                                             STRLEN(PRT_RESOURCE_ENCODING)) == 0)
4752 	resource->type = PRT_RESOURCE_TYPE_ENCODING;
4753     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
4754                                             STRLEN(PRT_RESOURCE_CMAP)) == 0)
4755 	resource->type = PRT_RESOURCE_TYPE_CMAP;
4756     else
4757     {
4758 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4759 		resource->filename);
4760 	fclose(fd_resource);
4761 	return FALSE;
4762     }
4763 
4764     /* Look for title and version of resource */
4765     resource->title[0] = '\0';
4766     resource->version[0] = '\0';
4767     seen_title = FALSE;
4768     seen_version = FALSE;
4769     seen_all = FALSE;
4770     while (!seen_all && prt_next_dsc(&dsc_line))
4771     {
4772         switch (dsc_line.type)
4773         {
4774         case PRT_DSC_TITLE_TYPE:
4775             STRNCPY(resource->title, dsc_line.string, dsc_line.len);
4776             resource->title[dsc_line.len] = '\0';
4777             seen_title = TRUE;
4778             if (seen_version)
4779                 seen_all = TRUE;
4780             break;
4781 
4782         case PRT_DSC_VERSION_TYPE:
4783             STRNCPY(resource->version, dsc_line.string, dsc_line.len);
4784             resource->version[dsc_line.len] = '\0';
4785             seen_version = TRUE;
4786             if (seen_title)
4787                 seen_all = TRUE;
4788             break;
4789 
4790         case PRT_DSC_ENDCOMMENTS_TYPE:
4791             /* Wont find title or resource after this comment, stop searching */
4792             seen_all = TRUE;
4793             break;
4794 
4795         case PRT_DSC_MISC_TYPE:
4796             /* Not interested in whatever comment this line had */
4797             break;
4798         }
4799     }
4800 
4801     if (!seen_title || !seen_version)
4802     {
4803 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4804 		resource->filename);
4805 	fclose(fd_resource);
4806 	return FALSE;
4807     }
4808 
4809     fclose(fd_resource);
4810 
4811     return TRUE;
4812 }
4813 
4814     static int
4815 prt_check_resource(resource, version)
4816     struct prt_ps_resource_S *resource;
4817     char_u  *version;
4818 {
4819     /* Version number m.n should match, the revision number does not matter */
4820     if (STRNCMP(resource->version, version, STRLEN(version)))
4821     {
4822 	EMSG2(_("E621: \"%s\" resource file has wrong version"),
4823 		resource->name);
4824 	return FALSE;
4825     }
4826 
4827     /* Other checks to be added as needed */
4828     return TRUE;
4829 }
4830 
4831     static void
4832 prt_dsc_start()
4833 {
4834     prt_write_string("%!PS-Adobe-3.0\n");
4835 }
4836 
4837     static void
4838 prt_dsc_noarg(comment)
4839     char	*comment;
4840 {
4841     sprintf((char *)prt_line_buffer, "%%%%%s\n", comment);
4842     prt_write_file(prt_line_buffer);
4843 }
4844 
4845     static void
4846 prt_dsc_textline(comment, text)
4847     char	*comment;
4848     char	*text;
4849 {
4850     sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text);
4851     prt_write_file(prt_line_buffer);
4852 }
4853 
4854     static void
4855 prt_dsc_text(comment, text)
4856     char	*comment;
4857     char	*text;
4858 {
4859     /* TODO - should scan 'text' for any chars needing escaping! */
4860     sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text);
4861     prt_write_file(prt_line_buffer);
4862 }
4863 
4864 #define prt_dsc_atend(c)	prt_dsc_text((c), "atend")
4865 
4866     static void
4867 prt_dsc_ints(comment, count, ints)
4868     char	*comment;
4869     int		count;
4870     int		*ints;
4871 {
4872     int		i;
4873 
4874     sprintf((char *)prt_line_buffer, "%%%%%s:", comment);
4875     prt_write_file(prt_line_buffer);
4876 
4877     for (i = 0; i < count; i++)
4878     {
4879 	sprintf((char *)prt_line_buffer, " %d", ints[i]);
4880 	prt_write_file(prt_line_buffer);
4881     }
4882 
4883     prt_write_string("\n");
4884 }
4885 
4886     static void
4887 prt_dsc_resources(comment, type, string)
4888     char	*comment;	/* if NULL add to previous */
4889     char	*type;
4890     char	*string;
4891 {
4892     if (comment != NULL)
4893 	sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type);
4894     else
4895 	sprintf((char *)prt_line_buffer, "%%%%+ %s", type);
4896     prt_write_file(prt_line_buffer);
4897 
4898     sprintf((char *)prt_line_buffer, " %s\n", string);
4899     prt_write_file(prt_line_buffer);
4900 }
4901 
4902     static void
4903 prt_dsc_font_resource(resource, ps_font)
4904     char	*resource;
4905     struct prt_ps_font_S *ps_font;
4906 {
4907     int     i;
4908 
4909     prt_dsc_resources(resource, "font",
4910                                     ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
4911     for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
4912         if (ps_font->ps_fontname[i] != NULL)
4913             prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
4914 }
4915 
4916     static void
4917 prt_dsc_requirements(duplex, tumble, collate, color, num_copies)
4918     int		duplex;
4919     int		tumble;
4920     int		collate;
4921     int		color;
4922     int		num_copies;
4923 {
4924     /* Only output the comment if we need to.
4925      * Note: tumble is ignored if we are not duplexing
4926      */
4927     if (!(duplex || collate || color || (num_copies > 1)))
4928 	return;
4929 
4930     sprintf((char *)prt_line_buffer, "%%%%Requirements:");
4931     prt_write_file(prt_line_buffer);
4932 
4933     if (duplex)
4934     {
4935 	prt_write_string(" duplex");
4936 	if (tumble)
4937 	    prt_write_string("(tumble)");
4938     }
4939     if (collate)
4940 	prt_write_string(" collate");
4941     if (color)
4942 	prt_write_string(" color");
4943     if (num_copies > 1)
4944     {
4945 	prt_write_string(" numcopies(");
4946 	/* Note: no space wanted so dont use prt_write_int() */
4947 	sprintf((char *)prt_line_buffer, "%d", num_copies);
4948 	prt_write_file(prt_line_buffer);
4949 	prt_write_string(")");
4950     }
4951     prt_write_string("\n");
4952 }
4953 
4954     static void
4955 prt_dsc_docmedia(paper_name, width, height, weight, colour, type)
4956     char	*paper_name;
4957     double	width;
4958     double	height;
4959     double	weight;
4960     char	*colour;
4961     char	*type;
4962 {
4963     sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name);
4964     prt_write_file(prt_line_buffer);
4965     prt_write_real(width, 2);
4966     prt_write_real(height, 2);
4967     prt_write_real(weight, 2);
4968     if (colour == NULL)
4969 	prt_write_string("()");
4970     else
4971 	prt_write_string(colour);
4972     prt_write_string(" ");
4973     if (type == NULL)
4974 	prt_write_string("()");
4975     else
4976 	prt_write_string(type);
4977     prt_write_string("\n");
4978 }
4979 
4980     void
4981 mch_print_cleanup()
4982 {
4983 #ifdef FEAT_MBYTE
4984     if (prt_out_mbyte)
4985     {
4986         int     i;
4987 
4988         /* Free off all CID font names created, but first clear duplicate
4989          * pointers to the same string (when the same font is used for more than
4990          * one style).
4991          */
4992         for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
4993         {
4994             if (prt_ps_mb_font.ps_fontname[i] != NULL)
4995                 vim_free(prt_ps_mb_font.ps_fontname[i]);
4996             prt_ps_mb_font.ps_fontname[i] = NULL;
4997         }
4998     }
4999 
5000     if (prt_do_conv)
5001     {
5002 	convert_setup(&prt_conv, NULL, NULL);
5003 	prt_do_conv = FALSE;
5004     }
5005 #endif
5006     if (prt_ps_fd != NULL)
5007     {
5008 	fclose(prt_ps_fd);
5009 	prt_ps_fd = NULL;
5010 	prt_file_error = FALSE;
5011     }
5012     if (prt_ps_file_name != NULL)
5013     {
5014 	vim_free(prt_ps_file_name);
5015 	prt_ps_file_name = NULL;
5016     }
5017 }
5018 
5019     static float
5020 to_device_units(idx, physsize, def_number)
5021     int		idx;
5022     double	physsize;
5023     int		def_number;
5024 {
5025     float	ret;
5026     int		u;
5027     int		nr;
5028 
5029     u = prt_get_unit(idx);
5030     if (u == PRT_UNIT_NONE)
5031     {
5032 	u = PRT_UNIT_PERC;
5033 	nr = def_number;
5034     }
5035     else
5036 	nr = printer_opts[idx].number;
5037 
5038     switch (u)
5039     {
5040 	case PRT_UNIT_INCH:
5041 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI);
5042 	    break;
5043 	case PRT_UNIT_MM:
5044 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
5045 	    break;
5046 	case PRT_UNIT_POINT:
5047 	    ret = (float)nr;
5048 	    break;
5049 	case PRT_UNIT_PERC:
5050 	default:
5051 	    ret = (float)(physsize * nr) / 100;
5052 	    break;
5053     }
5054 
5055     return ret;
5056 }
5057 
5058 /*
5059  * Calculate margins for given width and height from printoptions settings.
5060  */
5061     static void
5062 prt_page_margins(width, height, left, right, top, bottom)
5063     double	width;
5064     double	height;
5065     double	*left;
5066     double	*right;
5067     double	*top;
5068     double	*bottom;
5069 {
5070     *left   = to_device_units(OPT_PRINT_LEFT, width, 10);
5071     *right  = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
5072     *top    = height - to_device_units(OPT_PRINT_TOP, height, 5);
5073     *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
5074 }
5075 
5076     static void
5077 prt_font_metrics(font_scale)
5078     int		font_scale;
5079 {
5080     prt_line_height = (float)font_scale;
5081     prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
5082 }
5083 
5084 
5085     static int
5086 prt_get_cpl()
5087 {
5088     if (prt_use_number())
5089     {
5090 	prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
5091 #ifdef FEAT_MBYTE
5092         /* If we are outputting multi-byte characters then line numbers will be
5093          * printed with half width characters
5094          */
5095         if (prt_out_mbyte)
5096             prt_number_width /= 2;
5097 #endif
5098 	prt_left_margin += prt_number_width;
5099     }
5100     else
5101 	prt_number_width = 0.0;
5102 
5103     return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
5104 }
5105 
5106 #ifdef FEAT_MBYTE
5107     static int
5108 prt_build_cid_fontname(font, name, name_len)
5109     int     font;
5110     char_u  *name;
5111     int     name_len;
5112 {
5113     char    *fontname;
5114 
5115     fontname = (char *)alloc(name_len + 1);
5116     if (fontname == NULL)
5117         return FALSE;
5118     STRNCPY(fontname, name, name_len);
5119     fontname[name_len] = '\0';
5120     prt_ps_mb_font.ps_fontname[font] = fontname;
5121 
5122     return TRUE;
5123 }
5124 #endif
5125 
5126 /*
5127  * Get number of lines of text that fit on a page (excluding the header).
5128  */
5129     static int
5130 prt_get_lpp()
5131 {
5132     int lpp;
5133 
5134     /*
5135      * Calculate offset to lower left corner of background rect based on actual
5136      * font height (based on its bounding box) and the line height, handling the
5137      * case where the font height can exceed the line height.
5138      */
5139     prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
5140 					   prt_ps_font->bbox_min_y);
5141     if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
5142     {
5143 	prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
5144 				(1000.0 - (prt_ps_font->bbox_max_y -
5145 					    prt_ps_font->bbox_min_y)) / 2);
5146     }
5147 
5148     /* Get height for topmost line based on background rect offset. */
5149     prt_first_line_height = prt_line_height + prt_bgcol_offset;
5150 
5151     /* Calculate lpp */
5152     lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
5153 
5154     /* Adjust top margin if there is a header */
5155     prt_top_margin -= prt_line_height * prt_header_height();
5156 
5157     return lpp - prt_header_height();
5158 }
5159 
5160 #ifdef FEAT_MBYTE
5161     static int
5162 prt_match_encoding(p_encoding, p_cmap, pp_mbenc)
5163     char			*p_encoding;
5164     struct prt_ps_mbfont_S	*p_cmap;
5165     struct prt_ps_encoding_S	**pp_mbenc;
5166 {
5167     int				mbenc;
5168     int				enc_len;
5169     struct prt_ps_encoding_S	*p_mbenc;
5170 
5171     *pp_mbenc = NULL;
5172     /* Look for recognised encoding */
5173     enc_len = STRLEN(p_encoding);
5174     p_mbenc = p_cmap->encodings;
5175     for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
5176     {
5177         if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
5178         {
5179             *pp_mbenc = p_mbenc;
5180             return TRUE;
5181         }
5182         p_mbenc++;
5183     }
5184     return FALSE;
5185 }
5186 
5187     static int
5188 prt_match_charset(p_charset, p_cmap, pp_mbchar)
5189     char		    *p_charset;
5190     struct prt_ps_mbfont_S  *p_cmap;
5191     struct prt_ps_charset_S **pp_mbchar;
5192 {
5193     int			    mbchar;
5194     int			    char_len;
5195     struct prt_ps_charset_S *p_mbchar;
5196 
5197     /* Look for recognised character set, using default if one is not given */
5198     if (*p_charset == NUL)
5199         p_charset = p_cmap->defcs;
5200     char_len = STRLEN(p_charset);
5201     p_mbchar = p_cmap->charsets;
5202     for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
5203     {
5204         if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
5205         {
5206             *pp_mbchar = p_mbchar;
5207             return TRUE;
5208         }
5209         p_mbchar++;
5210     }
5211     return FALSE;
5212 }
5213 #endif
5214 
5215 /*ARGSUSED*/
5216     int
5217 mch_print_init(psettings, jobname, forceit)
5218     prt_settings_T *psettings;
5219     char_u	*jobname;
5220     int		forceit;
5221 {
5222     int		i;
5223     char	*paper_name;
5224     int		paper_strlen;
5225     int		fontsize;
5226     char_u	*p;
5227     double      left;
5228     double      right;
5229     double      top;
5230     double      bottom;
5231 #ifdef FEAT_MBYTE
5232     int         cmap;
5233     int         pmcs_len;
5234     char_u	*p_encoding;
5235     struct prt_ps_encoding_S *p_mbenc;
5236     struct prt_ps_encoding_S *p_mbenc_first;
5237     struct prt_ps_charset_S  *p_mbchar;
5238 #endif
5239 
5240 #if 0
5241     /*
5242      * TODO:
5243      * If "forceit" is false: pop up a dialog to select:
5244      *	- printer name
5245      *	- copies
5246      *	- collated/uncollated
5247      *	- duplex off/long side/short side
5248      *	- paper size
5249      *	- portrait/landscape
5250      *	- font size
5251      *
5252      * If "forceit" is true: use the default printer and settings
5253      */
5254     if (forceit)
5255 	s_pd.Flags |= PD_RETURNDEFAULT;
5256 #endif
5257 
5258     /*
5259      * Set up font and encoding.
5260      */
5261 #ifdef FEAT_MBYTE
5262     p_encoding = enc_skip(p_penc);
5263     if (*p_encoding == NUL)
5264         p_encoding = enc_skip(p_enc);
5265 
5266     /* Look for recognised multi-byte coding, and if the charset is recognised.
5267      * This is to cope with the fact that various unicode encodings are
5268      * supported in more than one of CJK. */
5269     p_mbenc = NULL;
5270     p_mbenc_first = NULL;
5271     p_mbchar = NULL;
5272     for (cmap = 0; cmap < NUM_ELEMENTS(prt_ps_mbfonts); cmap++)
5273         if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
5274 								    &p_mbenc))
5275         {
5276             if (p_mbenc_first == NULL)
5277                 p_mbenc_first = p_mbenc;
5278             if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
5279 								   &p_mbchar))
5280                 break;
5281         }
5282 
5283     /* Use first encoding matched if no charset matched */
5284     if (p_mbchar == NULL && p_mbenc_first != NULL)
5285         p_mbenc = p_mbenc_first;
5286 
5287     prt_out_mbyte = (p_mbenc != NULL);
5288     if (prt_out_mbyte)
5289     {
5290         /* Build CMap name - will be same for all multi-byte fonts used */
5291         prt_cmap[0] = '\0';
5292 
5293         prt_custom_cmap = prt_out_mbyte && p_mbchar == NULL;
5294 
5295         if (!prt_custom_cmap)
5296         {
5297             /* Check encoding and character set are compatible */
5298             if ((p_mbenc->needs_charset&p_mbchar->has_charset) == 0)
5299             {
5300                 EMSG(_("E673: Incompatible multi-byte encoding and character set."));
5301                 return FALSE;
5302             }
5303 
5304             /* Add charset name if not empty */
5305             if (p_mbchar->cmap_charset != NULL)
5306             {
5307                 STRCAT(prt_cmap, p_mbchar->cmap_charset);
5308                 STRCAT(prt_cmap, "-");
5309             }
5310         }
5311         else
5312         {
5313             /* Add custom CMap character set name */
5314             pmcs_len = STRLEN(p_pmcs);
5315             if (pmcs_len == 0)
5316             {
5317                 EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
5318                 return FALSE;
5319             }
5320             STRNCPY(prt_cmap, p_pmcs, STRLEN(p_pmcs));
5321             prt_cmap[pmcs_len] = '\0';
5322             STRCAT(prt_cmap, "-");
5323         }
5324 
5325         /* CMap name ends with (optional) encoding name and -H for horizontal */
5326         if (p_mbenc->cmap_encoding != NULL)
5327         {
5328             STRCAT(prt_cmap, p_mbenc->cmap_encoding);
5329             STRCAT(prt_cmap, "-");
5330         }
5331         STRCAT(prt_cmap, "H");
5332 
5333         if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
5334         {
5335             EMSG(_("E675: No default font specfifed for multi-byte printing."));
5336             return FALSE;
5337         }
5338 
5339         /* Derive CID font names with fallbacks if not defined */
5340         if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
5341                                     mbfont_opts[OPT_MBFONT_REGULAR].string,
5342                                     mbfont_opts[OPT_MBFONT_REGULAR].strlen))
5343             return FALSE;
5344         if (mbfont_opts[OPT_MBFONT_BOLD].present)
5345             if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
5346                                         mbfont_opts[OPT_MBFONT_BOLD].string,
5347                                         mbfont_opts[OPT_MBFONT_BOLD].strlen))
5348                 return FALSE;
5349         if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
5350             if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
5351                                         mbfont_opts[OPT_MBFONT_OBLIQUE].string,
5352                                         mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
5353                 return FALSE;
5354         if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
5355             if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
5356 				   mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
5357 				  mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
5358                 return FALSE;
5359 
5360         /* Check if need to use Courier for ASCII code range, and if so pick up
5361          * the encoding to use */
5362         prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
5363             (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
5364         if (prt_use_courier)
5365         {
5366             /* Use national ASCII variant unless ASCII wanted */
5367             if (mbfont_opts[OPT_MBFONT_ASCII].present &&
5368                 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
5369                 prt_ascii_encoding = "ascii";
5370             else
5371                 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
5372         }
5373 
5374         prt_ps_font = &prt_ps_mb_font;
5375     }
5376     else
5377 #endif
5378     {
5379 #ifdef FEAT_MBYTE
5380         prt_use_courier = FALSE;
5381 #endif
5382         prt_ps_font = &prt_ps_courier_font;
5383     }
5384 
5385     /*
5386      * Find the size of the paper and set the margins.
5387      */
5388     prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
5389 	   || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
5390     if (printer_opts[OPT_PRINT_PAPER].present)
5391     {
5392 	paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
5393 	paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
5394     }
5395     else
5396     {
5397 	paper_name = "A4";
5398 	paper_strlen = 2;
5399     }
5400     for (i = 0; i < PRT_MEDIASIZE_LEN; ++i)
5401 	if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
5402 		&& STRNICMP(prt_mediasize[i].name, paper_name,
5403 							   paper_strlen) == 0)
5404 	    break;
5405     if (i == PRT_MEDIASIZE_LEN)
5406 	i = 0;
5407     prt_media = i;
5408 
5409     /*
5410      * Set PS pagesize based on media dimensions and print orientation.
5411      * Note: Media and page sizes have defined meanings in PostScript and should
5412      * be kept distinct.  Media is the paper (or transparency, or ...) that is
5413      * printed on, whereas the page size is the area that the PostScript
5414      * interpreter renders into.
5415      */
5416     if (prt_portrait)
5417     {
5418 	prt_page_width = prt_mediasize[i].width;
5419 	prt_page_height = prt_mediasize[i].height;
5420     }
5421     else
5422     {
5423 	prt_page_width = prt_mediasize[i].height;
5424 	prt_page_height = prt_mediasize[i].width;
5425     }
5426 
5427     /*
5428      * Set PS page margins based on the PS pagesize, not the mediasize - this
5429      * needs to be done before the cpl and lpp are calculated.
5430      */
5431     prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
5432 								    &bottom);
5433     prt_left_margin = (float)left;
5434     prt_right_margin = (float)right;
5435     prt_top_margin = (float)top;
5436     prt_bottom_margin = (float)bottom;
5437 
5438     /*
5439      * Set up the font size.
5440      */
5441     fontsize = PRT_PS_DEFAULT_FONTSIZE;
5442     for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
5443 	if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
5444 	    fontsize = atoi((char *)p + 2);
5445     prt_font_metrics(fontsize);
5446 
5447     /*
5448      * Return the number of characters per line, and lines per page for the
5449      * generic print code.
5450      */
5451     psettings->chars_per_line = prt_get_cpl();
5452     psettings->lines_per_page = prt_get_lpp();
5453 
5454     /* Catch margin settings that leave no space for output! */
5455     if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
5456 	return FAIL;
5457 
5458     /*
5459      * Sort out the number of copies to be printed.  PS by default will do
5460      * uncollated copies for you, so once we know how many uncollated copies are
5461      * wanted cache it away and lie to the generic code that we only want one
5462      * uncollated copy.
5463      */
5464     psettings->n_collated_copies = 1;
5465     psettings->n_uncollated_copies = 1;
5466     prt_num_copies = 1;
5467     prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
5468 	    || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
5469     if (prt_collate)
5470     {
5471 	/* TODO: Get number of collated copies wanted. */
5472 	psettings->n_collated_copies = 1;
5473     }
5474     else
5475     {
5476 	/* TODO: Get number of uncollated copies wanted and update the cached
5477 	 * count.
5478 	 */
5479 	prt_num_copies = 1;
5480     }
5481 
5482     psettings->jobname = jobname;
5483 
5484     /*
5485      * Set up printer duplex and tumble based on Duplex option setting - default
5486      * is long sided duplex printing (i.e. no tumble).
5487      */
5488     prt_duplex = TRUE;
5489     prt_tumble = FALSE;
5490     psettings->duplex = 1;
5491     if (printer_opts[OPT_PRINT_DUPLEX].present)
5492     {
5493 	if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
5494 	{
5495 	    prt_duplex = FALSE;
5496 	    psettings->duplex = 0;
5497 	}
5498 	else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
5499 									 == 0)
5500 	    prt_tumble = TRUE;
5501     }
5502 
5503     /* For now user abort not supported */
5504     psettings->user_abort = 0;
5505 
5506     /* If the user didn't specify a file name, use a temp file. */
5507     if (psettings->outfile == NULL)
5508     {
5509 	prt_ps_file_name = vim_tempname('p');
5510 	if (prt_ps_file_name == NULL)
5511 	{
5512 	    EMSG(_(e_notmp));
5513 	    return FAIL;
5514 	}
5515 	prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
5516     }
5517     else
5518     {
5519 	p = expand_env_save(psettings->outfile);
5520 	if (p != NULL)
5521 	{
5522 	    prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
5523 	    vim_free(p);
5524 	}
5525     }
5526     if (prt_ps_fd == NULL)
5527     {
5528 	EMSG(_("E324: Can't open PostScript output file"));
5529 	mch_print_cleanup();
5530 	return FAIL;
5531     }
5532 
5533     prt_bufsiz = psettings->chars_per_line;
5534 #ifdef FEAT_MBYTE
5535     if (prt_out_mbyte)
5536         prt_bufsiz *= 2;
5537 #endif
5538     ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
5539 
5540     prt_page_num = 0;
5541 
5542     prt_attribute_change = FALSE;
5543     prt_need_moveto = FALSE;
5544     prt_need_font = FALSE;
5545     prt_need_fgcol = FALSE;
5546     prt_need_bgcol = FALSE;
5547     prt_need_underline = FALSE;
5548 
5549     prt_file_error = FALSE;
5550 
5551     return OK;
5552 }
5553 
5554     static int
5555 prt_add_resource(resource)
5556     struct prt_ps_resource_S *resource;
5557 {
5558     FILE*	fd_resource;
5559     char_u	resource_buffer[512];
5560     size_t	bytes_read;
5561 
5562     fd_resource = mch_fopen((char *)resource->filename, READBIN);
5563     if (fd_resource == NULL)
5564     {
5565 	EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
5566 	return FALSE;
5567     }
5568     prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
5569 						     (char *)resource->title);
5570 
5571     prt_dsc_textline("BeginDocument", (char *)resource->filename);
5572 
5573     for (;;)
5574     {
5575 	bytes_read = fread((char *)resource_buffer, sizeof(char_u),
5576 			   sizeof(resource_buffer), fd_resource);
5577 	if (ferror(fd_resource))
5578 	{
5579 	    EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
5580 							    resource->filename);
5581 	    fclose(fd_resource);
5582 	    return FALSE;
5583 	}
5584 	if (bytes_read == 0)
5585 	    break;
5586 	prt_write_file_raw_len(resource_buffer, bytes_read);
5587 	if (prt_file_error)
5588 	{
5589 	    fclose(fd_resource);
5590 	    return FALSE;
5591 	}
5592     }
5593     fclose(fd_resource);
5594 
5595     prt_dsc_noarg("EndDocument");
5596 
5597     prt_dsc_noarg("EndResource");
5598 
5599     return TRUE;
5600 }
5601 
5602     int
5603 mch_print_begin(psettings)
5604     prt_settings_T *psettings;
5605 {
5606     time_t	now;
5607     int		bbox[4];
5608     char	*p_time;
5609     double      left;
5610     double      right;
5611     double      top;
5612     double      bottom;
5613     struct prt_ps_resource_S res_prolog;
5614     struct prt_ps_resource_S res_encoding;
5615     char	buffer[256];
5616     char_u      *p_encoding;
5617 #ifdef FEAT_MBYTE
5618     struct prt_ps_resource_S res_cidfont;
5619     struct prt_ps_resource_S res_cmap;
5620 #endif
5621 
5622     /*
5623      * PS DSC Header comments - no PS code!
5624      */
5625     prt_dsc_start();
5626     prt_dsc_textline("Title", (char *)psettings->jobname);
5627     if (!get_user_name((char_u *)buffer, 256))
5628         STRCPY(buffer, "Unknown");
5629     prt_dsc_textline("For", buffer);
5630     prt_dsc_textline("Creator", VIM_VERSION_LONG);
5631     /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
5632     now = time(NULL);
5633     p_time = ctime(&now);
5634     /* Note: ctime() adds a \n so we have to remove it :-( */
5635     *(vim_strchr((char_u *)p_time, '\n')) = '\0';
5636     prt_dsc_textline("CreationDate", p_time);
5637     prt_dsc_textline("DocumentData", "Clean8Bit");
5638     prt_dsc_textline("Orientation", "Portrait");
5639     prt_dsc_atend("Pages");
5640     prt_dsc_textline("PageOrder", "Ascend");
5641     /* The bbox does not change with orientation - it is always in the default
5642      * user coordinate system!  We have to recalculate right and bottom
5643      * coordinates based on the font metrics for the bbox to be accurate. */
5644     prt_page_margins(prt_mediasize[prt_media].width,
5645 					    prt_mediasize[prt_media].height,
5646 					    &left, &right, &top, &bottom);
5647     bbox[0] = (int)left;
5648     if (prt_portrait)
5649     {
5650 	/* In portrait printing the fixed point is the top left corner so we
5651 	 * derive the bbox from that point.  We have the expected cpl chars
5652 	 * across the media and lpp lines down the media.
5653 	 */
5654 	bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
5655 							    * prt_line_height);
5656 	bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
5657 									+ 0.5);
5658 	bbox[3] = (int)(top + 0.5);
5659     }
5660     else
5661     {
5662 	/* In landscape printing the fixed point is the bottom left corner so we
5663 	 * derive the bbox from that point.  We have lpp chars across the media
5664 	 * and cpl lines up the media.
5665 	 */
5666 	bbox[1] = (int)bottom;
5667 	bbox[2] = (int)(left + ((psettings->lines_per_page
5668 			      + prt_header_height()) * prt_line_height) + 0.5);
5669 	bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
5670 									+ 0.5);
5671     }
5672     prt_dsc_ints("BoundingBox", 4, bbox);
5673     /* The media width and height does not change with landscape printing! */
5674     prt_dsc_docmedia(prt_mediasize[prt_media].name,
5675 				prt_mediasize[prt_media].width,
5676 				prt_mediasize[prt_media].height,
5677 				(double)0, NULL, NULL);
5678     /* Define fonts needed */
5679 #ifdef FEAT_MBYTE
5680     if (!prt_out_mbyte || prt_use_courier)
5681 #endif
5682         prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
5683 #ifdef FEAT_MBYTE
5684     if (prt_out_mbyte)
5685     {
5686         prt_dsc_font_resource((prt_use_courier ? NULL
5687                                  : "DocumentNeededResources"), &prt_ps_mb_font);
5688         if (!prt_custom_cmap)
5689             prt_dsc_resources(NULL, "cmap", prt_cmap);
5690     }
5691 #endif
5692 
5693     /* Search for external resources VIM supplies */
5694     if (!prt_find_resource("prolog", &res_prolog))
5695     {
5696 	EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\""));
5697 	return FALSE;
5698     }
5699     if (!prt_open_resource(&res_prolog))
5700 	return FALSE;
5701     if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION))
5702 	return FALSE;
5703 #ifdef FEAT_MBYTE
5704     if (prt_out_mbyte)
5705     {
5706         /* Look for required version of multi-byte printing procset */
5707         if (!prt_find_resource("cidfont", &res_cidfont))
5708         {
5709             EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
5710             return FALSE;
5711         }
5712         if (!prt_open_resource(&res_cidfont))
5713             return FALSE;
5714         if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION))
5715             return FALSE;
5716     }
5717 #endif
5718 
5719     /* Find an encoding to use for printing.
5720      * Check 'printencoding'. If not set or not found, then use 'encoding'. If
5721      * that cannot be found then default to "latin1".
5722      * Note: VIM specific encoding header is always skipped.
5723      */
5724 #ifdef FEAT_MBYTE
5725     if (!prt_out_mbyte)
5726     {
5727 #endif
5728         p_encoding = enc_skip(p_penc);
5729         if (*p_encoding == NUL
5730                 || !prt_find_resource((char *)p_encoding, &res_encoding))
5731         {
5732             /* 'printencoding' not set or not supported - find alternate */
5733 #ifdef FEAT_MBYTE
5734             int		props;
5735 
5736             p_encoding = enc_skip(p_enc);
5737             props = enc_canon_props(p_encoding);
5738             if (!(props & ENC_8BIT)
5739                     || !prt_find_resource((char *)p_encoding, &res_encoding))
5740                 /* 8-bit 'encoding' is not supported */
5741 #endif
5742                 {
5743                 /* Use latin1 as default printing encoding */
5744                 p_encoding = (char_u *)"latin1";
5745                 if (!prt_find_resource((char *)p_encoding, &res_encoding))
5746                 {
5747                     EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5748                             p_encoding);
5749                     return FALSE;
5750                 }
5751             }
5752         }
5753         if (!prt_open_resource(&res_encoding))
5754             return FALSE;
5755         /* For the moment there are no checks on encoding resource files to
5756          * perform */
5757 #ifdef FEAT_MBYTE
5758     }
5759     else
5760     {
5761         p_encoding = enc_skip(p_penc);
5762         if (*p_encoding == NUL)
5763             p_encoding = enc_skip(p_enc);
5764         if (prt_use_courier)
5765         {
5766             /* Include ASCII range encoding vector */
5767             if (!prt_find_resource(prt_ascii_encoding, &res_encoding))
5768             {
5769                 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5770 							  prt_ascii_encoding);
5771                 return FALSE;
5772             }
5773             if (!prt_open_resource(&res_encoding))
5774                 return FALSE;
5775             /* For the moment there are no checks on encoding resource files to
5776              * perform */
5777         }
5778     }
5779 
5780     prt_conv.vc_type = CONV_NONE;
5781     if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
5782         /* Set up encoding conversion if required */
5783 	if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
5784 	{
5785             EMSG2(_("E620: Unable to convert to print encoding \"%s\""),
5786 		    p_encoding);
5787 	    return FALSE;
5788 	}
5789 	prt_do_conv = TRUE;
5790     }
5791     prt_do_conv = prt_conv.vc_type != CONV_NONE;
5792 
5793     if (prt_out_mbyte && prt_custom_cmap)
5794     {
5795         /* Find user supplied CMap */
5796         if (!prt_find_resource(prt_cmap, &res_cmap))
5797         {
5798             EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5799 								    prt_cmap);
5800             return FALSE;
5801         }
5802         if (!prt_open_resource(&res_cmap))
5803             return FALSE;
5804     }
5805 #endif
5806 
5807     /* List resources supplied */
5808     STRCPY(buffer, res_prolog.title);
5809     STRCAT(buffer, " ");
5810     STRCAT(buffer, res_prolog.version);
5811     prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
5812 #ifdef FEAT_MBYTE
5813     if (prt_out_mbyte)
5814     {
5815         STRCPY(buffer, res_cidfont.title);
5816         STRCAT(buffer, " ");
5817         STRCAT(buffer, res_cidfont.version);
5818         prt_dsc_resources(NULL, "procset", buffer);
5819 
5820         if (prt_custom_cmap)
5821         {
5822             STRCPY(buffer, res_cmap.title);
5823             STRCAT(buffer, " ");
5824             STRCAT(buffer, res_cmap.version);
5825             prt_dsc_resources(NULL, "cmap", buffer);
5826         }
5827     }
5828     if (!prt_out_mbyte || prt_use_courier)
5829 #endif
5830     {
5831         STRCPY(buffer, res_encoding.title);
5832         STRCAT(buffer, " ");
5833         STRCAT(buffer, res_encoding.version);
5834         prt_dsc_resources(NULL, "encoding", buffer);
5835     }
5836     prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
5837 #ifdef FEAT_SYN_HL
5838 					psettings->do_syntax
5839 #else
5840 					0
5841 #endif
5842 					, prt_num_copies);
5843     prt_dsc_noarg("EndComments");
5844 
5845     /*
5846      * PS Document page defaults
5847      */
5848     prt_dsc_noarg("BeginDefaults");
5849 
5850     /* List font resources most likely common to all pages */
5851 #ifdef FEAT_MBYTE
5852     if (!prt_out_mbyte || prt_use_courier)
5853 #endif
5854         prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
5855 #ifdef FEAT_MBYTE
5856     if (prt_out_mbyte)
5857     {
5858         prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
5859                                                             &prt_ps_mb_font);
5860         if (!prt_custom_cmap)
5861             prt_dsc_resources(NULL, "cmap", prt_cmap);
5862     }
5863 #endif
5864 
5865     /* Paper will be used for all pages */
5866     prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
5867 
5868     prt_dsc_noarg("EndDefaults");
5869 
5870     /*
5871      * PS Document prolog inclusion - all required procsets.
5872      */
5873     prt_dsc_noarg("BeginProlog");
5874 
5875     /* Add required procsets - NOTE: order is important! */
5876     if (!prt_add_resource(&res_prolog))
5877 	return FALSE;
5878 #ifdef FEAT_MBYTE
5879     if (prt_out_mbyte)
5880     {
5881         /* Add CID font procset, and any user supplied CMap */
5882         if (!prt_add_resource(&res_cidfont))
5883             return FALSE;
5884         if (prt_custom_cmap && !prt_add_resource(&res_cmap))
5885             return FALSE;
5886     }
5887 #endif
5888 
5889 #ifdef FEAT_MBYTE
5890     if (!prt_out_mbyte || prt_use_courier)
5891 #endif
5892         /* There will be only one Roman font encoding to be included in the PS
5893          * file. */
5894         if (!prt_add_resource(&res_encoding))
5895             return FALSE;
5896 
5897     prt_dsc_noarg("EndProlog");
5898 
5899     /*
5900      * PS Document setup - must appear after the prolog
5901      */
5902     prt_dsc_noarg("BeginSetup");
5903 
5904     /* Device setup - page size and number of uncollated copies */
5905     prt_write_int((int)prt_mediasize[prt_media].width);
5906     prt_write_int((int)prt_mediasize[prt_media].height);
5907     prt_write_int(0);
5908     prt_write_string("sps\n");
5909     prt_write_int(prt_num_copies);
5910     prt_write_string("nc\n");
5911     prt_write_boolean(prt_duplex);
5912     prt_write_boolean(prt_tumble);
5913     prt_write_string("dt\n");
5914     prt_write_boolean(prt_collate);
5915     prt_write_string("c\n");
5916 
5917     /* Font resource inclusion and definition */
5918 #ifdef FEAT_MBYTE
5919     if (!prt_out_mbyte || prt_use_courier)
5920     {
5921         /* When using Courier for ASCII range when printing multi-byte, need to
5922          * pick up ASCII encoding to use with it. */
5923         if (prt_use_courier)
5924             p_encoding = (char_u *)prt_ascii_encoding;
5925 #endif
5926         prt_dsc_resources("IncludeResource", "font",
5927                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5928         prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
5929                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5930         prt_dsc_resources("IncludeResource", "font",
5931                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
5932         prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
5933                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
5934         prt_dsc_resources("IncludeResource", "font",
5935                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5936         prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
5937                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5938         prt_dsc_resources("IncludeResource", "font",
5939                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5940         prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
5941                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5942 #ifdef FEAT_MBYTE
5943     }
5944     if (prt_out_mbyte)
5945     {
5946         /* Define the CID fonts to be used in the job.  Typically CJKV fonts do
5947          * not have an italic form being a western style, so where no font is
5948          * defined for these faces VIM falls back to an existing face.
5949          * Note: if using Courier for the ASCII range then the printout will
5950          * have bold/italic/bolditalic regardless of the setting of printmbfont.
5951          */
5952         prt_dsc_resources("IncludeResource", "font",
5953                           prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5954         if (!prt_custom_cmap)
5955             prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5956         prt_def_cidfont("CF0", (int)prt_line_height,
5957                         prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5958 
5959         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
5960         {
5961             prt_dsc_resources("IncludeResource", "font",
5962                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
5963             if (!prt_custom_cmap)
5964                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5965             prt_def_cidfont("CF1", (int)prt_line_height,
5966                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
5967         }
5968         else
5969             /* Use ROMAN for BOLD */
5970             prt_dup_cidfont("CF0", "CF1");
5971 
5972         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
5973         {
5974             prt_dsc_resources("IncludeResource", "font",
5975                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5976             if (!prt_custom_cmap)
5977                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5978             prt_def_cidfont("CF2", (int)prt_line_height,
5979                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5980         }
5981         else
5982             /* Use ROMAN for OBLIQUE */
5983             prt_dup_cidfont("CF0", "CF2");
5984 
5985         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
5986         {
5987             prt_dsc_resources("IncludeResource", "font",
5988                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5989             if (!prt_custom_cmap)
5990                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5991             prt_def_cidfont("CF3", (int)prt_line_height,
5992                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5993         }
5994         else
5995             /* Use BOLD for BOLDOBLIQUE */
5996             prt_dup_cidfont("CF1", "CF3");
5997     }
5998 #endif
5999 
6000     /* Misc constant vars used for underlining and background rects */
6001     prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
6002 						prt_ps_font->uline_offset), 2);
6003     prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
6004 						 prt_ps_font->uline_width), 2);
6005     prt_def_var("BO", prt_bgcol_offset, 2);
6006 
6007     prt_dsc_noarg("EndSetup");
6008 
6009     /* Fail if any problems writing out to the PS file */
6010     return !prt_file_error;
6011 }
6012 
6013     void
6014 mch_print_end(psettings)
6015     prt_settings_T *psettings;
6016 {
6017     prt_dsc_noarg("Trailer");
6018 
6019     /*
6020      * Output any info we don't know in toto until we finish
6021      */
6022     prt_dsc_ints("Pages", 1, &prt_page_num);
6023 
6024     prt_dsc_noarg("EOF");
6025 
6026     /* Write CTRL-D to close serial communication link if used.
6027      * NOTHING MUST BE WRITTEN AFTER THIS! */
6028     prt_write_file((char_u *)IF_EB("\004", "\067"));
6029 
6030     if (!prt_file_error && psettings->outfile == NULL
6031 					&& !got_int && !psettings->user_abort)
6032     {
6033 	/* Close the file first. */
6034 	if (prt_ps_fd != NULL)
6035 	{
6036 	    fclose(prt_ps_fd);
6037 	    prt_ps_fd = NULL;
6038 	}
6039 	prt_message((char_u *)_("Sending to printer..."));
6040 
6041 	/* Not printing to a file: use 'printexpr' to print the file. */
6042 	if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
6043 	    EMSG(_("E365: Failed to print PostScript file"));
6044 	else
6045 	    prt_message((char_u *)_("Print job sent."));
6046     }
6047 
6048     mch_print_cleanup();
6049 }
6050 
6051     int
6052 mch_print_end_page()
6053 {
6054     prt_flush_buffer();
6055 
6056     prt_write_string("re sp\n");
6057 
6058     prt_dsc_noarg("PageTrailer");
6059 
6060     return !prt_file_error;
6061 }
6062 
6063 /*ARGSUSED*/
6064     int
6065 mch_print_begin_page(str)
6066     char_u	*str;
6067 {
6068     int		page_num[2];
6069 
6070     prt_page_num++;
6071 
6072     page_num[0] = page_num[1] = prt_page_num;
6073     prt_dsc_ints("Page", 2, page_num);
6074 
6075     prt_dsc_noarg("BeginPageSetup");
6076 
6077     prt_write_string("sv\n0 g\n");
6078 #ifdef FEAT_MBYTE
6079     prt_in_ascii = !prt_out_mbyte;
6080     if (prt_out_mbyte)
6081         prt_write_string("CF0 sf\n");
6082     else
6083 #endif
6084         prt_write_string("F0 sf\n");
6085     prt_fgcol = PRCOLOR_BLACK;
6086     prt_bgcol = PRCOLOR_WHITE;
6087     prt_font = PRT_PS_FONT_ROMAN;
6088 
6089     /* Set up page transformation for landscape printing. */
6090     if (!prt_portrait)
6091     {
6092 	prt_write_int(-((int)prt_mediasize[prt_media].width));
6093 	prt_write_string("sl\n");
6094     }
6095 
6096     prt_dsc_noarg("EndPageSetup");
6097 
6098     /* We have reset the font attributes, force setting them again. */
6099     curr_bg = (long_u)0xffffffff;
6100     curr_fg = (long_u)0xffffffff;
6101     curr_bold = MAYBE;
6102 
6103     return !prt_file_error;
6104 }
6105 
6106     int
6107 mch_print_blank_page()
6108 {
6109     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
6110 }
6111 
6112 static float prt_pos_x = 0;
6113 static float prt_pos_y = 0;
6114 
6115     void
6116 mch_print_start_line(margin, page_line)
6117     int		margin;
6118     int		page_line;
6119 {
6120     prt_pos_x = prt_left_margin;
6121     if (margin)
6122 	prt_pos_x -= prt_number_width;
6123 
6124     prt_pos_y = prt_top_margin - prt_first_line_height -
6125 					page_line * prt_line_height;
6126 
6127     prt_attribute_change = TRUE;
6128     prt_need_moveto = TRUE;
6129 #ifdef FEAT_MBYTE
6130     prt_half_width = FALSE;
6131 #endif
6132 }
6133 
6134 /*ARGSUSED*/
6135     int
6136 mch_print_text_out(p, len)
6137     char_u	*p;
6138     int		len;
6139 {
6140     int		need_break;
6141     char_u	ch;
6142     char_u      ch_buff[8];
6143     float       char_width;
6144     float       next_pos;
6145 #ifdef FEAT_MBYTE
6146     int         in_ascii;
6147     int         half_width;
6148 #endif
6149 
6150     char_width = prt_char_width;
6151 
6152 #ifdef FEAT_MBYTE
6153     /* Ideally VIM would create a rearranged CID font to combine a Roman and
6154      * CJKV font to do what VIM is doing here - use a Roman font for characters
6155      * in the ASCII range, and the origingal CID font for everything else.
6156      * The problem is that GhostScript still (as of 8.13) does not support
6157      * rearranged fonts even though they have been documented by Adobe for 7
6158      * years!  If they ever do, a lot of this code will disappear.
6159      */
6160     if (prt_use_courier)
6161     {
6162         in_ascii = (len == 1 && *p < 0x80);
6163         if (prt_in_ascii)
6164         {
6165             if (!in_ascii)
6166             {
6167                 /* No longer in ASCII range - need to switch font */
6168                 prt_in_ascii = FALSE;
6169                 prt_need_font = TRUE;
6170                 prt_attribute_change = TRUE;
6171             }
6172         }
6173         else if (in_ascii)
6174         {
6175             /* Now in ASCII range - need to switch font */
6176             prt_in_ascii = TRUE;
6177             prt_need_font = TRUE;
6178             prt_attribute_change = TRUE;
6179         }
6180     }
6181     if (prt_out_mbyte)
6182     {
6183         half_width = ((*mb_ptr2cells)(p) == 1);
6184         if (half_width)
6185             char_width /= 2;
6186         if (prt_half_width)
6187         {
6188             if (!half_width)
6189             {
6190                 prt_half_width = FALSE;
6191                 prt_pos_x += prt_char_width/4;
6192                 prt_need_moveto = TRUE;
6193                 prt_attribute_change = TRUE;
6194             }
6195         }
6196         else if (half_width)
6197         {
6198             prt_half_width = TRUE;
6199             prt_pos_x += prt_char_width/4;
6200             prt_need_moveto = TRUE;
6201             prt_attribute_change = TRUE;
6202         }
6203     }
6204 #endif
6205 
6206     /* Output any required changes to the graphics state, after flushing any
6207      * text buffered so far.
6208      */
6209     if (prt_attribute_change)
6210     {
6211 	prt_flush_buffer();
6212 	/* Reset count of number of chars that will be printed */
6213 	prt_text_run = 0;
6214 
6215 	if (prt_need_moveto)
6216 	{
6217 	    prt_pos_x_moveto = prt_pos_x;
6218 	    prt_pos_y_moveto = prt_pos_y;
6219 	    prt_do_moveto = TRUE;
6220 
6221 	    prt_need_moveto = FALSE;
6222 	}
6223 	if (prt_need_font)
6224 	{
6225 #ifdef FEAT_MBYTE
6226             if (!prt_in_ascii)
6227                 prt_write_string("CF");
6228             else
6229 #endif
6230                 prt_write_string("F");
6231             prt_write_int(prt_font);
6232             prt_write_string("sf\n");
6233             prt_need_font = FALSE;
6234 	}
6235 	if (prt_need_fgcol)
6236 	{
6237 	    int     r, g, b;
6238 	    r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
6239 	    g = ((unsigned)prt_fgcol & 0xff00) >> 8;
6240 	    b = prt_fgcol & 0xff;
6241 
6242 	    prt_write_real(r / 255.0, 3);
6243 	    if (r == g && g == b)
6244 		prt_write_string("g\n");
6245 	    else
6246 	    {
6247 		prt_write_real(g / 255.0, 3);
6248 		prt_write_real(b / 255.0, 3);
6249 		prt_write_string("r\n");
6250 	    }
6251 	    prt_need_fgcol = FALSE;
6252 	}
6253 
6254 	if (prt_bgcol != PRCOLOR_WHITE)
6255 	{
6256 	    prt_new_bgcol = prt_bgcol;
6257 	    if (prt_need_bgcol)
6258 		prt_do_bgcol = TRUE;
6259 	}
6260 	else
6261 	    prt_do_bgcol = FALSE;
6262 	prt_need_bgcol = FALSE;
6263 
6264 	if (prt_need_underline)
6265 	    prt_do_underline = prt_underline;
6266 	prt_need_underline = FALSE;
6267 
6268 	prt_attribute_change = FALSE;
6269     }
6270 
6271 #ifdef FEAT_MBYTE
6272     if (prt_do_conv)
6273     {
6274 	/* Convert from multi-byte to 8-bit encoding */
6275 	p = string_convert(&prt_conv, p, &len);
6276 	if (p == NULL)
6277 	    p = (char_u *)"";
6278     }
6279 
6280     if (prt_out_mbyte)
6281     {
6282         /* Multi-byte character strings are represented more efficiently as hex
6283          * strings when outputting clean 8 bit PS.
6284          */
6285         do
6286         {
6287            ch = prt_hexchar[(unsigned)(*p) >> 4];
6288            ga_append(&prt_ps_buffer, ch);
6289            ch = prt_hexchar[(*p) & 0xf];
6290            ga_append(&prt_ps_buffer, ch);
6291            p++;
6292         }
6293         while (--len);
6294     }
6295     else
6296 #endif
6297     {
6298         /* Add next character to buffer of characters to output.
6299          * Note: One printed character may require several PS characters to
6300          * represent it, but we only count them as one printed character.
6301          */
6302         ch = *p;
6303         if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
6304         {
6305             /* Convert non-printing characters to either their escape or octal
6306              * sequence, ensures PS sent over a serial line does not interfere
6307              * with the comms protocol.  Note: For EBCDIC we need to write out
6308              * the escape sequences as ASCII codes!
6309 	     * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
6310 	     */
6311             ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
6312             switch (ch)
6313             {
6314                 case BS:   ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
6315                 case TAB:  ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
6316                 case NL:   ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
6317                 case FF:   ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
6318                 case CAR:  ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
6319                 case '(':  ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
6320                 case ')':  ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
6321                 case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
6322 
6323                 default:
6324                            sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
6325 #ifdef EBCDIC
6326                            ebcdic2ascii(ch_buff, 3);
6327 #endif
6328                            ga_append(&prt_ps_buffer, ch_buff[0]);
6329                            ga_append(&prt_ps_buffer, ch_buff[1]);
6330                            ga_append(&prt_ps_buffer, ch_buff[2]);
6331                            break;
6332             }
6333         }
6334         else
6335             ga_append(&prt_ps_buffer, ch);
6336     }
6337 
6338 #ifdef FEAT_MBYTE
6339     /* Need to free any translated characters */
6340     if (prt_do_conv && (*p != NUL))
6341 	vim_free(p);
6342 #endif
6343 
6344     prt_text_run += char_width;
6345     prt_pos_x += char_width;
6346 
6347     /* The downside of fp - use relative error on right margin check */
6348     next_pos = prt_pos_x + prt_char_width;
6349     need_break = (next_pos > prt_right_margin) &&
6350                     ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
6351 
6352     if (need_break)
6353 	prt_flush_buffer();
6354 
6355     return need_break;
6356 }
6357 
6358     void
6359 mch_print_set_font(iBold, iItalic, iUnderline)
6360     int		iBold;
6361     int		iItalic;
6362     int		iUnderline;
6363 {
6364     int		font = 0;
6365 
6366     if (iBold)
6367 	font |= 0x01;
6368     if (iItalic)
6369 	font |= 0x02;
6370 
6371     if (font != prt_font)
6372     {
6373 	prt_font = font;
6374 	prt_attribute_change = TRUE;
6375 	prt_need_font = TRUE;
6376     }
6377     if (prt_underline != iUnderline)
6378     {
6379 	prt_underline = iUnderline;
6380 	prt_attribute_change = TRUE;
6381 	prt_need_underline = TRUE;
6382     }
6383 }
6384 
6385     void
6386 mch_print_set_bg(bgcol)
6387     long_u	bgcol;
6388 {
6389     prt_bgcol = bgcol;
6390     prt_attribute_change = TRUE;
6391     prt_need_bgcol = TRUE;
6392 }
6393 
6394     void
6395 mch_print_set_fg(fgcol)
6396     long_u	fgcol;
6397 {
6398     if (fgcol != (long_u)prt_fgcol)
6399     {
6400 	prt_fgcol = fgcol;
6401 	prt_attribute_change = TRUE;
6402 	prt_need_fgcol = TRUE;
6403     }
6404 }
6405 
6406 # endif /*FEAT_POSTSCRIPT*/
6407 #endif /*FEAT_PRINTER*/
6408 
6409 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6410 	&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
6411 static char *get_locale_val __ARGS((int what));
6412 
6413     static char *
6414 get_locale_val(what)
6415     int		what;
6416 {
6417     char	*loc;
6418 
6419     /* Obtain the locale value from the libraries.  For DJGPP this is
6420      * redefined and it doesn't use the arguments. */
6421     loc = setlocale(what, NULL);
6422 
6423 # if defined(__BORLANDC__)
6424     if (loc != NULL)
6425     {
6426 	char_u	*p;
6427 
6428 	/* Borland returns something like "LC_CTYPE=<name>\n"
6429 	 * Let's try to fix that bug here... */
6430 	p = vim_strchr(loc, '=');
6431 	if (p != NULL)
6432 	{
6433 	    loc = ++p;
6434 	    while (*p != NUL)	/* remove trailing newline */
6435 	    {
6436 		if (*p < ' ')
6437 		{
6438 		    *p = NUL;
6439 		    break;
6440 		}
6441 		++p;
6442 	    }
6443 	}
6444     }
6445 # endif
6446 
6447     return loc;
6448 }
6449 #endif
6450 
6451 
6452 #ifdef WIN32
6453 /*
6454  * On MS-Windows locale names are strings like "German_Germany.1252", but
6455  * gettext expects "de".  Try to translate one into another here for a few
6456  * supported languages.
6457  */
6458     static char_u *
6459 gettext_lang(char_u *name)
6460 {
6461     int		i;
6462     static char *(mtable[]) = {
6463 			"afrikaans",	"af",
6464 			"czech",	"cs",
6465 			"dutch",	"nl",
6466 			"german",	"de",
6467 			"english_united kingdom", "en_GB",
6468 			"spanish",	"es",
6469 			"french",	"fr",
6470 			"italian",	"it",
6471 			"japanese",	"ja",
6472 			"korean",	"ko",
6473 			"norwegian",	"no",
6474 			"polish",	"pl",
6475 			"russian",	"ru",
6476 			"slovak",	"sk",
6477 			"swedish",	"sv",
6478 			"ukrainian",	"uk",
6479 			"chinese_china", "zh_CN",
6480 			"chinese_taiwan", "zh_TW",
6481 			NULL};
6482 
6483     for (i = 0; mtable[i] != NULL; i += 2)
6484 	if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
6485 	    return mtable[i + 1];
6486     return name;
6487 }
6488 #endif
6489 
6490 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
6491 /*
6492  * Obtain the current messages language.  Used to set the default for
6493  * 'helplang'.  May return NULL or an empty string.
6494  */
6495     char_u *
6496 get_mess_lang()
6497 {
6498     char_u *p;
6499 
6500 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
6501 #  if defined(LC_MESSAGES)
6502     p = (char_u *)get_locale_val(LC_MESSAGES);
6503 #  else
6504     /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
6505      * may be set to the LCID number. */
6506     p = (char_u *)get_locale_val(LC_ALL);
6507 #  endif
6508 # else
6509     p = mch_getenv((char_u *)"LC_ALL");
6510     if (p == NULL || *p == NUL)
6511     {
6512 	p = mch_getenv((char_u *)"LC_MESSAGES");
6513 	if (p == NULL || *p == NUL)
6514 	    p = mch_getenv((char_u *)"LANG");
6515     }
6516 # endif
6517 # ifdef WIN32
6518     p = gettext_lang(p);
6519 # endif
6520     return p;
6521 }
6522 #endif
6523 
6524 #if !defined(LC_MESSAGES) \
6525     && (((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6526 		&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) \
6527 	    || defined(FEAT_EVAL))
6528 static char_u *get_mess_env __ARGS((void));
6529 
6530 /*
6531  * Get the language used for messages from the environment.
6532  */
6533     static char_u *
6534 get_mess_env()
6535 {
6536     char_u	*p;
6537 
6538     p = mch_getenv((char_u *)"LC_ALL");
6539     if (p == NULL || *p == NUL)
6540     {
6541 	p = mch_getenv((char_u *)"LC_MESSAGES");
6542 	if (p == NULL || *p == NUL)
6543 	{
6544 	    p = mch_getenv((char_u *)"LANG");
6545 	    if (p != NULL && VIM_ISDIGIT(*p))
6546 		p = NULL;		/* ignore something like "1043" */
6547 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6548 	    if (p == NULL || *p == NUL)
6549 		p = (char_u *)get_locale_val(LC_CTYPE);
6550 # endif
6551 	}
6552     }
6553     return p;
6554 }
6555 #endif
6556 
6557 #if defined(FEAT_EVAL) || defined(PROTO)
6558 
6559 /*
6560  * Set the "v:lang" variable according to the current locale setting.
6561  * Also do "v:lc_time"and "v:ctype".
6562  */
6563     void
6564 set_lang_var()
6565 {
6566     char_u	*loc;
6567 
6568 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6569     loc = (char_u *)get_locale_val(LC_CTYPE);
6570 # else
6571     /* setlocale() not supported: use the default value */
6572     loc = (char_u *)"C";
6573 # endif
6574     set_vim_var_string(VV_CTYPE, loc, -1);
6575 
6576     /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
6577      * back to LC_CTYPE if it's empty. */
6578 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
6579     loc = (char_u *)get_locale_val(LC_MESSAGES);
6580 # else
6581     loc = get_mess_env();
6582 # endif
6583     set_vim_var_string(VV_LANG, loc, -1);
6584 
6585 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6586     loc = (char_u *)get_locale_val(LC_TIME);
6587 # endif
6588     set_vim_var_string(VV_LC_TIME, loc, -1);
6589 }
6590 #endif
6591 
6592 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6593 	&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
6594 /*
6595  * ":language":  Set the language (locale).
6596  */
6597     void
6598 ex_language(eap)
6599     exarg_T	*eap;
6600 {
6601     char	*loc;
6602     char_u	*p;
6603     char_u	*name;
6604     int		what = LC_ALL;
6605     char	*whatstr = "";
6606 #ifdef LC_MESSAGES
6607 # define VIM_LC_MESSAGES LC_MESSAGES
6608 #else
6609 # define VIM_LC_MESSAGES 6789
6610 #endif
6611 
6612     name = eap->arg;
6613 
6614     /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
6615      * Allow abbreviation, but require at least 3 characters to avoid
6616      * confusion with a two letter language name "me" or "ct". */
6617     p = skiptowhite(eap->arg);
6618     if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
6619     {
6620 	if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
6621 	{
6622 	    what = VIM_LC_MESSAGES;
6623 	    name = skipwhite(p);
6624 	    whatstr = "messages ";
6625 	}
6626 	else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
6627 	{
6628 	    what = LC_CTYPE;
6629 	    name = skipwhite(p);
6630 	    whatstr = "ctype ";
6631 	}
6632 	else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
6633 	{
6634 	    what = LC_TIME;
6635 	    name = skipwhite(p);
6636 	    whatstr = "time ";
6637 	}
6638     }
6639 
6640     if (*name == NUL)
6641     {
6642 #ifndef LC_MESSAGES
6643 	if (what == VIM_LC_MESSAGES)
6644 	    p = get_mess_env();
6645 	else
6646 #endif
6647 	    p = (char_u *)setlocale(what, NULL);
6648 	if (p == NULL || *p == NUL)
6649 	    p = (char_u *)"Unknown";
6650 	smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
6651     }
6652     else
6653     {
6654 #ifndef LC_MESSAGES
6655 	if (what == VIM_LC_MESSAGES)
6656 	    loc = "";
6657 	else
6658 #endif
6659 	    loc = setlocale(what, (char *)name);
6660 	if (loc == NULL)
6661 	    EMSG2(_("E197: Cannot set language to \"%s\""), name);
6662 	else
6663 	{
6664 #ifdef HAVE_NL_MSG_CAT_CNTR
6665 	    /* Need to do this for GNU gettext, otherwise cached translations
6666 	     * will be used again. */
6667 	    extern int _nl_msg_cat_cntr;
6668 
6669 	    ++_nl_msg_cat_cntr;
6670 #endif
6671 	    /* Reset $LC_ALL, otherwise it would overrule everyting. */
6672 	    vim_setenv((char_u *)"LC_ALL", (char_u *)"");
6673 
6674 	    if (what != LC_TIME)
6675 	    {
6676 		/* Tell gettext() what to translate to.  It apparently doesn't
6677 		 * use the currently effective locale.  Also do this when
6678 		 * FEAT_GETTEXT isn't defined, so that shell commands use this
6679 		 * value. */
6680 		if (what == LC_ALL)
6681 		    vim_setenv((char_u *)"LANG", name);
6682 		if (what != LC_CTYPE)
6683 		{
6684 		    char_u	*mname;
6685 #ifdef WIN32
6686 		    mname = gettext_lang(name);
6687 #else
6688 		    mname = name;
6689 #endif
6690 		    vim_setenv((char_u *)"LC_MESSAGES", mname);
6691 #ifdef FEAT_MULTI_LANG
6692 		    set_helplang_default(mname);
6693 #endif
6694 		}
6695 
6696 		/* Set $LC_CTYPE, because it overrules $LANG, and
6697 		 * gtk_set_locale() calls setlocale() again.  gnome_init()
6698 		 * sets $LC_CTYPE to "en_US" (that's a bug!). */
6699 		if (what != VIM_LC_MESSAGES)
6700 		    vim_setenv((char_u *)"LC_CTYPE", name);
6701 # ifdef FEAT_GUI_GTK
6702 		/* Let GTK know what locale we're using.  Not sure this is
6703 		 * really needed... */
6704 		if (gui.in_use)
6705 		    (void)gtk_set_locale();
6706 # endif
6707 	    }
6708 
6709 # ifdef FEAT_EVAL
6710 	    /* Set v:lang, v:lc_time and v:ctype to the final result. */
6711 	    set_lang_var();
6712 # endif
6713 	}
6714     }
6715 }
6716 
6717 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
6718 /*
6719  * Function given to ExpandGeneric() to obtain the possible arguments of the
6720  * ":language" command.
6721  */
6722 /*ARGSUSED*/
6723     char_u *
6724 get_lang_arg(xp, idx)
6725     expand_T	*xp;
6726     int		idx;
6727 {
6728     if (idx == 0)
6729 	return (char_u *)"messages";
6730     if (idx == 1)
6731 	return (char_u *)"ctype";
6732     if (idx == 2)
6733 	return (char_u *)"time";
6734     return NULL;
6735 }
6736 # endif
6737 
6738 #endif
6739