xref: /vim-8.2.3635/src/ex_cmds2.c (revision 2df6dcc5)
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 /* Generic font metrics for multi-byte fonts */
3810 static struct prt_ps_font_S prt_ps_mb_font =
3811 {
3812     1000,
3813     -100, 50,
3814     -250, 805,
3815     {NULL, NULL, NULL, NULL}
3816 };
3817 
3818 /* Pointer to current font set being used */
3819 static struct prt_ps_font_S* prt_ps_font;
3820 
3821 /* Structures to map user named encoding and mapping to PS equivalents for
3822  * building CID font name */
3823 struct prt_ps_encoding_S
3824 {
3825     char_u	*encoding;
3826     char_u	*cmap_encoding;
3827     int		needs_charset;
3828 };
3829 
3830 struct prt_ps_charset_S
3831 {
3832     char	*charset;
3833     char	*cmap_charset;
3834     int		has_charset;
3835 };
3836 
3837 #define CS_JIS_C_1978   (0x01)
3838 #define CS_JIS_X_1983   (0x02)
3839 #define CS_JIS_X_1990   (0x04)
3840 #define CS_NEC          (0x08)
3841 #define CS_MSWINDOWS    (0x10)
3842 #define CS_CP932        (0x20)
3843 #define CS_KANJITALK6   (0x40)
3844 #define CS_KANJITALK7   (0x80)
3845 
3846 /* Japanese encodings and charsets */
3847 static struct prt_ps_encoding_S j_encodings[] =
3848 {
3849     {"iso-2022-jp", NULL,       (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
3850                                                                     CS_NEC)},
3851     {"euc-jp",      "EUC",      (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
3852     {"sjis",        "RKSJ",     (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
3853                                                 CS_KANJITALK6|CS_KANJITALK7)},
3854     {"cp932",       "RKSJ",     CS_JIS_X_1983},
3855     {"ucs-2",       "UCS2",     CS_JIS_X_1990},
3856     {"utf-8",       "UTF8" ,    CS_JIS_X_1990}
3857 };
3858 static struct prt_ps_charset_S j_charsets[] =
3859 {
3860     {"JIS_C_1978",  "78",       CS_JIS_C_1978},
3861     {"JIS_X_1983",  NULL,       CS_JIS_X_1983},
3862     {"JIS_X_1990",  "Hojo",     CS_JIS_X_1990},
3863     {"NEC",         "Ext",      CS_NEC},
3864     {"MSWINDOWS",   "90ms",     CS_MSWINDOWS},
3865     {"CP932",       "90ms",     CS_JIS_X_1983},
3866     {"KANJITALK6",  "83pv",     CS_KANJITALK6},
3867     {"KANJITALK7",  "90pv",     CS_KANJITALK7}
3868 };
3869 
3870 #define CS_GB_2312_80       (0x01)
3871 #define CS_GBT_12345_90     (0x02)
3872 #define CS_GBK2K            (0x04)
3873 #define CS_SC_MAC           (0x08)
3874 #define CS_GBT_90_MAC       (0x10)
3875 #define CS_GBK              (0x20)
3876 #define CS_SC_ISO10646      (0x40)
3877 
3878 /* Simplified Chinese encodings and charsets */
3879 static struct prt_ps_encoding_S sc_encodings[] =
3880 {
3881     {"iso-2022",    NULL,       (CS_GB_2312_80|CS_GBT_12345_90)},
3882     {"gb18030",     NULL,       CS_GBK2K},
3883     {"euc-cn",      "EUC",      (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
3884                                                                 CS_GBT_90_MAC)},
3885     {"gbk",         "EUC",      CS_GBK},
3886     {"ucs-2",       "UCS2",     CS_SC_ISO10646},
3887     {"utf-8",       "UTF8",     CS_SC_ISO10646}
3888 };
3889 static struct prt_ps_charset_S sc_charsets[] =
3890 {
3891     {"GB_2312-80",  "GB",       CS_GB_2312_80},
3892     {"GBT_12345-90","GBT",      CS_GBT_12345_90},
3893     {"MAC",         "GBpc",     CS_SC_MAC},
3894     {"GBT-90_MAC",  "GBTpc",    CS_GBT_90_MAC},
3895     {"GBK",         "GBK",      CS_GBK},
3896     {"GB18030",     "GBK2K",    CS_GBK2K},
3897     {"ISO10646",    "UniGB",    CS_SC_ISO10646}
3898 };
3899 
3900 #define CS_CNS_PLANE_1      (0x01)
3901 #define CS_CNS_PLANE_2      (0x02)
3902 #define CS_CNS_PLANE_1_2    (0x04)
3903 #define CS_B5               (0x08)
3904 #define CS_ETEN             (0x10)
3905 #define CS_HK_GCCS          (0x20)
3906 #define CS_HK_SCS           (0x40)
3907 #define CS_HK_SCS_ETEN      (0x80)
3908 #define CS_MTHKL            (0x100)
3909 #define CS_MTHKS            (0x200)
3910 #define CS_DLHKL            (0x400)
3911 #define CS_DLHKS            (0x800)
3912 #define CS_TC_ISO10646      (0x1000)
3913 
3914 /* Traditional Chinese encodings and charsets */
3915 static struct prt_ps_encoding_S tc_encodings[] =
3916 {
3917     {"iso-2022",    NULL,       (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
3918     {"euc-tw",      "EUC",      CS_CNS_PLANE_1_2},
3919     {"big5",        "B5",       (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
3920                                     CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
3921                                                                     CS_DLHKS)},
3922     {"cp950",       "B5",       CS_B5},
3923     {"ucs-2",       "UCS2",     CS_TC_ISO10646},
3924     {"utf-8",       "UTF8",     CS_TC_ISO10646},
3925     {"utf-16",      "UTF16",    CS_TC_ISO10646},
3926     {"utf-32",      "UTF32",    CS_TC_ISO10646}
3927 };
3928 static struct prt_ps_charset_S tc_charsets[] =
3929 {
3930     {"CNS_1992_1",  "CNS1",     CS_CNS_PLANE_1},
3931     {"CNS_1992_2",  "CNS2",     CS_CNS_PLANE_2},
3932     {"CNS_1993",    "CNS",      CS_CNS_PLANE_1_2},
3933     {"BIG5",        NULL,       CS_B5},
3934     {"CP950",       NULL,       CS_B5},
3935     {"ETEN",        "ETen",     CS_ETEN},
3936     {"HK_GCCS",     "HKgccs",   CS_HK_GCCS},
3937     {"SCS",         "HKscs",    CS_HK_SCS},
3938     {"SCS_ETEN",    "ETHK",     CS_HK_SCS_ETEN},
3939     {"MTHKL",       "HKm471",   CS_MTHKL},
3940     {"MTHKS",       "HKm314",   CS_MTHKS},
3941     {"DLHKL",       "HKdla",    CS_DLHKL},
3942     {"DLHKS",       "HKdlb",    CS_DLHKS},
3943     {"ISO10646",    "UniCNS",   CS_TC_ISO10646}
3944 };
3945 
3946 #define CS_KR_X_1992        (0x01)
3947 #define CS_KR_MAC           (0x02)
3948 #define CS_KR_X_1992_MS     (0x04)
3949 #define CS_KR_ISO10646      (0x08)
3950 
3951 /* Korean encodings and charsets */
3952 static struct prt_ps_encoding_S k_encodings[] =
3953 {
3954     {"iso-2022-kr", NULL,       CS_KR_X_1992},
3955     {"euc-kr",      "EUC",      (CS_KR_X_1992|CS_KR_MAC)},
3956     {"johab",       "Johab",    CS_KR_X_1992},
3957     {"cp1361",      "Johab",    CS_KR_X_1992},
3958     {"uhc",         "UHC",      CS_KR_X_1992_MS},
3959     {"cp949",       "UHC",      CS_KR_X_1992_MS},
3960     {"ucs-2",       "UCS2",     CS_KR_ISO10646},
3961     {"utf-8",       "UTF8",     CS_KR_ISO10646}
3962 };
3963 static struct prt_ps_charset_S k_charsets[] =
3964 {
3965     {"KS_X_1992",   "KSC",      CS_KR_X_1992},
3966     {"CP1361",      "KSC",      CS_KR_X_1992},
3967     {"MAC",         "KSCpc",    CS_KR_MAC},
3968     {"MSWINDOWS",   "KSCms",    CS_KR_X_1992_MS},
3969     {"CP949",       "KSCms",    CS_KR_X_1992_MS},
3970     {"WANSUNG",     "KSCms",    CS_KR_X_1992_MS},
3971     {"ISO10646",    "UniKS",    CS_KR_ISO10646}
3972 };
3973 
3974 /* Collections of encodings and charsets for multi-byte printing */
3975 struct prt_ps_mbfont_S
3976 {
3977     int                         num_encodings;
3978     struct prt_ps_encoding_S    *encodings;
3979     int                         num_charsets;
3980     struct prt_ps_charset_S     *charsets;
3981     char                        *ascii_enc;
3982     char                        *defcs;
3983 };
3984 
3985 static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
3986 {
3987     {
3988         NUM_ELEMENTS(j_encodings),
3989         j_encodings,
3990         NUM_ELEMENTS(j_charsets),
3991         j_charsets,
3992         "jis_roman",
3993         "JIS_X_1983"
3994     },
3995     {
3996         NUM_ELEMENTS(sc_encodings),
3997         sc_encodings,
3998         NUM_ELEMENTS(sc_charsets),
3999         sc_charsets,
4000         "gb_roman",
4001         "GB_2312-80"
4002     },
4003     {
4004         NUM_ELEMENTS(tc_encodings),
4005         tc_encodings,
4006         NUM_ELEMENTS(tc_charsets),
4007         tc_charsets,
4008         "cns_roman",
4009         "BIG5"
4010     },
4011     {
4012         NUM_ELEMENTS(k_encodings),
4013         k_encodings,
4014         NUM_ELEMENTS(k_charsets),
4015         k_charsets,
4016         "ks_roman",
4017         "KS_X_1992"
4018     }
4019 };
4020 
4021 struct prt_ps_resource_S
4022 {
4023     char_u  name[64];
4024     char_u  filename[MAXPATHL + 1];
4025     int     type;
4026     char_u  title[256];
4027     char_u  version[256];
4028 };
4029 
4030 /* Types of PS resource file currently used */
4031 #define PRT_RESOURCE_TYPE_PROCSET   (0)
4032 #define PRT_RESOURCE_TYPE_ENCODING  (1)
4033 #define PRT_RESOURCE_TYPE_CMAP      (2)
4034 
4035 /* The PS prolog file version number has to match - if the prolog file is
4036  * updated, increment the number in the file and here.  Version checking was
4037  * added as of VIM 6.2.
4038  * The CID prolog file version number behaves as per PS prolog.
4039  * Table of VIM and prolog versions:
4040  *
4041  * VIM      Prolog  CIDProlog
4042  * 6.2      1.3
4043  * 7.0      1.4	    1.0
4044  */
4045 #define PRT_PROLOG_VERSION  ((char_u *)"1.4")
4046 #define PRT_CID_PROLOG_VERSION  ((char_u *)"1.0")
4047 
4048 /* String versions of PS resource types - indexed by constants above so don't
4049  * re-order!
4050  */
4051 static char *prt_resource_types[] =
4052 {
4053     "procset",
4054     "encoding",
4055     "cmap"
4056 };
4057 
4058 /* Strings to look for in a PS resource file */
4059 #define PRT_RESOURCE_HEADER	    "%!PS-Adobe-"
4060 #define PRT_RESOURCE_RESOURCE	    "Resource-"
4061 #define PRT_RESOURCE_PROCSET	    "ProcSet"
4062 #define PRT_RESOURCE_ENCODING	    "Encoding"
4063 #define PRT_RESOURCE_CMAP           "CMap"
4064 
4065 
4066 /* Data for table based DSC comment recognition, easy to extend if VIM needs to
4067  * read more comments. */
4068 #define PRT_DSC_MISC_TYPE           (-1)
4069 #define PRT_DSC_TITLE_TYPE          (1)
4070 #define PRT_DSC_VERSION_TYPE        (2)
4071 #define PRT_DSC_ENDCOMMENTS_TYPE    (3)
4072 
4073 #define PRT_DSC_TITLE	            "%%Title:"
4074 #define PRT_DSC_VERSION	            "%%Version:"
4075 #define PRT_DSC_ENDCOMMENTS         "%%EndComments:"
4076 
4077 struct prt_dsc_comment_S
4078 {
4079     char_u	*string;
4080     int		len;
4081     int		type;
4082 };
4083 
4084 struct prt_dsc_line_S
4085 {
4086     int		type;
4087     char_u	*string;
4088     int		len;
4089 };
4090 
4091 
4092 #define SIZEOF_CSTR(s)      (sizeof(s) - 1)
4093 struct prt_dsc_comment_S prt_dsc_table[] =
4094 {
4095     {PRT_DSC_TITLE,       SIZEOF_CSTR(PRT_DSC_TITLE),       PRT_DSC_TITLE_TYPE},
4096     {PRT_DSC_VERSION,     SIZEOF_CSTR(PRT_DSC_VERSION),
4097                                                         PRT_DSC_VERSION_TYPE},
4098     {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
4099                                                     PRT_DSC_ENDCOMMENTS_TYPE}
4100 };
4101 
4102 static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes));
4103 static void prt_write_file __ARGS((char_u *buffer));
4104 static void prt_write_file_len __ARGS((char_u *buffer, int bytes));
4105 static void prt_write_string __ARGS((char *s));
4106 static void prt_write_int __ARGS((int i));
4107 static void prt_write_boolean __ARGS((int b));
4108 static void prt_def_font __ARGS((char *new_name, char *encoding, int height, char *font));
4109 static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction));
4110 static void prt_write_real __ARGS((double val, int prec));
4111 static void prt_def_var __ARGS((char *name, double value, int prec));
4112 static void prt_flush_buffer __ARGS((void));
4113 static void prt_resource_name __ARGS((char_u *filename));
4114 static int prt_find_resource __ARGS((char *name, struct prt_ps_resource_S *resource));
4115 static int prt_open_resource __ARGS((struct prt_ps_resource_S *resource));
4116 static int prt_check_resource __ARGS((struct prt_ps_resource_S *resource, char_u *version));
4117 static void prt_dsc_start __ARGS((void));
4118 static void prt_dsc_noarg __ARGS((char *comment));
4119 static void prt_dsc_textline __ARGS((char *comment, char *text));
4120 static void prt_dsc_text __ARGS((char *comment, char *text));
4121 static void prt_dsc_ints __ARGS((char *comment, int count, int *ints));
4122 static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies));
4123 static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type));
4124 static void prt_dsc_resources __ARGS((char *comment, char *type, char *strings));
4125 static void prt_dsc_font_resource __ARGS((char *resource, struct prt_ps_font_S *ps_font));
4126 static float to_device_units __ARGS((int idx, double physsize, int def_number));
4127 static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom));
4128 static void prt_font_metrics __ARGS((int font_scale));
4129 static int prt_get_cpl __ARGS((void));
4130 static int prt_get_lpp __ARGS((void));
4131 static int prt_add_resource __ARGS((struct prt_ps_resource_S *resource));
4132 static int prt_resfile_next_line __ARGS((void));
4133 static int prt_resfile_strncmp __ARGS((int offset, char *string, int len));
4134 static int prt_resfile_skip_nonws __ARGS((int offset));
4135 static int prt_resfile_skip_ws __ARGS((int offset));
4136 static int prt_next_dsc __ARGS((struct prt_dsc_line_S *p_dsc_line));
4137 #ifdef FEAT_MBYTE
4138 static void prt_def_cidfont __ARGS((char *new_name, int height, char *cidfont));
4139 static int prt_match_encoding __ARGS((char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc));
4140 static int prt_match_charset __ARGS((char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar));
4141 #endif
4142 
4143 /*
4144  * Variables for the output PostScript file.
4145  */
4146 static FILE *prt_ps_fd;
4147 static int prt_file_error;
4148 static char_u *prt_ps_file_name = NULL;
4149 
4150 /*
4151  * Various offsets and dimensions in default PostScript user space (points).
4152  * Used for text positioning calculations
4153  */
4154 static float prt_page_width;
4155 static float prt_page_height;
4156 static float prt_left_margin;
4157 static float prt_right_margin;
4158 static float prt_top_margin;
4159 static float prt_bottom_margin;
4160 static float prt_line_height;
4161 static float prt_first_line_height;
4162 static float prt_char_width;
4163 static float prt_number_width;
4164 static float prt_bgcol_offset;
4165 static float prt_pos_x_moveto = 0.0;
4166 static float prt_pos_y_moveto = 0.0;
4167 
4168 /*
4169  * Various control variables used to decide when and how to change the
4170  * PostScript graphics state.
4171  */
4172 static int prt_need_moveto;
4173 static int prt_do_moveto;
4174 static int prt_need_font;
4175 static int prt_font;
4176 static int prt_need_underline;
4177 static int prt_underline;
4178 static int prt_do_underline;
4179 static int prt_need_fgcol;
4180 static int prt_fgcol;
4181 static int prt_need_bgcol;
4182 static int prt_do_bgcol;
4183 static int prt_bgcol;
4184 static int prt_new_bgcol;
4185 static int prt_attribute_change;
4186 static float prt_text_run;
4187 static int prt_page_num;
4188 static int prt_bufsiz;
4189 
4190 /*
4191  * Variables controlling physical printing.
4192  */
4193 static int prt_media;
4194 static int prt_portrait;
4195 static int prt_num_copies;
4196 static int prt_duplex;
4197 static int prt_tumble;
4198 static int prt_collate;
4199 
4200 /*
4201  * Buffers used when generating PostScript output
4202  */
4203 static char_u prt_line_buffer[257];
4204 static garray_T prt_ps_buffer;
4205 
4206 # ifdef FEAT_MBYTE
4207 static int prt_do_conv;
4208 static vimconv_T prt_conv;
4209 
4210 static int prt_out_mbyte;
4211 static int prt_custom_cmap;
4212 static char prt_cmap[80];
4213 static int prt_use_courier;
4214 static int prt_in_ascii;
4215 static int prt_half_width;
4216 static char *prt_ascii_encoding;
4217 static char_u prt_hexchar[] = "0123456789abcdef";
4218 # endif
4219 
4220     static void
4221 prt_write_file_raw_len(buffer, bytes)
4222     char_u	*buffer;
4223     int		bytes;
4224 {
4225     if (!prt_file_error
4226 	    && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
4227 							     != (size_t)bytes)
4228     {
4229 	EMSG(_("E455: Error writing to PostScript output file"));
4230 	prt_file_error = TRUE;
4231     }
4232 }
4233 
4234     static void
4235 prt_write_file(buffer)
4236     char_u	*buffer;
4237 {
4238     prt_write_file_len(buffer, STRLEN(buffer));
4239 }
4240 
4241     static void
4242 prt_write_file_len(buffer, bytes)
4243     char_u	*buffer;
4244     int		bytes;
4245 {
4246 #ifdef EBCDIC
4247     ebcdic2ascii(buffer, bytes);
4248 #endif
4249     prt_write_file_raw_len(buffer, bytes);
4250 }
4251 
4252 /*
4253  * Write a string.
4254  */
4255     static void
4256 prt_write_string(s)
4257     char	*s;
4258 {
4259     sprintf((char *)prt_line_buffer, "%s", s);
4260     prt_write_file(prt_line_buffer);
4261 }
4262 
4263 /*
4264  * Write an int and a space.
4265  */
4266     static void
4267 prt_write_int(i)
4268     int		i;
4269 {
4270     sprintf((char *)prt_line_buffer, "%d ", i);
4271     prt_write_file(prt_line_buffer);
4272 }
4273 
4274 /*
4275  * Write a boolean and a space.
4276  */
4277     static void
4278 prt_write_boolean(b)
4279     int		b;
4280 {
4281     sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
4282     prt_write_file(prt_line_buffer);
4283 }
4284 
4285 /*
4286  * Write PostScript to re-encode and define the font.
4287  */
4288     static void
4289 prt_def_font(new_name, encoding, height, font)
4290     char	*new_name;
4291     char	*encoding;
4292     int		height;
4293     char	*font;
4294 {
4295     sprintf((char *)prt_line_buffer, "/_%s /VIM-%s /%s ref\n",
4296                                                      new_name, encoding, font);
4297     prt_write_file(prt_line_buffer);
4298 #ifdef FEAT_MBYTE
4299     if (prt_out_mbyte)
4300         sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
4301 		       new_name, height, 500./prt_ps_courier_font.wx, new_name);
4302     else
4303 #endif
4304     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n",
4305 						    new_name, height, new_name);
4306     prt_write_file(prt_line_buffer);
4307 }
4308 
4309 #ifdef FEAT_MBYTE
4310 /*
4311  * Write a line to define the CID font.
4312  */
4313     static void
4314 prt_def_cidfont(new_name, height, cidfont)
4315     char	*new_name;
4316     int		height;
4317     char	*cidfont;
4318 {
4319     sprintf((char *)prt_line_buffer, "/_%s /%s[/%s] vim_composefont\n",
4320                                                 new_name, prt_cmap, cidfont);
4321     prt_write_file(prt_line_buffer);
4322     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", new_name, height,
4323                                                                     new_name);
4324     prt_write_file(prt_line_buffer);
4325 }
4326 
4327 /*
4328  * Write a line to define a duplicate of a CID font
4329  */
4330     static void
4331 prt_dup_cidfont(original_name, new_name)
4332     char	*original_name;
4333     char	*new_name;
4334 {
4335     sprintf((char *)prt_line_buffer, "/%s %s d\n", new_name, original_name);
4336     prt_write_file(prt_line_buffer);
4337 }
4338 #endif
4339 
4340 /*
4341  * Convert a real value into an integer and fractional part as integers, with
4342  * the fractional part being in the range [0,10^precision).  The fractional part
4343  * is also rounded based on the precision + 1'th fractional digit.
4344  */
4345     static void
4346 prt_real_bits(real, precision, pinteger, pfraction)
4347     double      real;
4348     int		precision;
4349     int		*pinteger;
4350     int		*pfraction;
4351 {
4352     int     i;
4353     int     integer;
4354     float   fraction;
4355 
4356     integer = (int)real;
4357     fraction = (float)(real - integer);
4358     if (real < (double)integer)
4359 	fraction = -fraction;
4360     for (i = 0; i < precision; i++)
4361 	fraction *= 10.0;
4362 
4363     *pinteger = integer;
4364     *pfraction = (int)(fraction + 0.5);
4365 }
4366 
4367 /*
4368  * Write a real and a space.  Save bytes if real value has no fractional part!
4369  * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
4370  * what decimal point character to use, but PS always requires a '.'.
4371  */
4372     static void
4373 prt_write_real(val, prec)
4374     double	val;
4375     int		prec;
4376 {
4377     int     integer;
4378     int     fraction;
4379 
4380     prt_real_bits(val, prec, &integer, &fraction);
4381     /* Emit integer part */
4382     sprintf((char *)prt_line_buffer, "%d", integer);
4383     prt_write_file(prt_line_buffer);
4384     /* Only emit fraction if necessary */
4385     if (fraction != 0)
4386     {
4387 	/* Remove any trailing zeros */
4388 	while ((fraction % 10) == 0)
4389 	{
4390 	    prec--;
4391 	    fraction /= 10;
4392 	}
4393 	/* Emit fraction left padded with zeros */
4394 	sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
4395 	prt_write_file(prt_line_buffer);
4396     }
4397     sprintf((char *)prt_line_buffer, " ");
4398     prt_write_file(prt_line_buffer);
4399 }
4400 
4401 /*
4402  * Write a line to define a numeric variable.
4403  */
4404     static void
4405 prt_def_var(name, value, prec)
4406     char	*name;
4407     double	value;
4408     int		prec;
4409 {
4410     sprintf((char *)prt_line_buffer, "/%s ", name);
4411     prt_write_file(prt_line_buffer);
4412     prt_write_real(value, prec);
4413     sprintf((char *)prt_line_buffer, "d\n");
4414     prt_write_file(prt_line_buffer);
4415 }
4416 
4417 /* Convert size from font space to user space at current font scale */
4418 #define PRT_PS_FONT_TO_USER(scale, size)    ((size) * ((scale)/1000.0))
4419 
4420     static void
4421 prt_flush_buffer()
4422 {
4423     if (prt_ps_buffer.ga_len > 0)
4424     {
4425 	/* Any background color must be drawn first */
4426 	if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
4427 	{
4428 	    int     r, g, b;
4429 
4430 	    if (prt_do_moveto)
4431 	    {
4432 		prt_write_real(prt_pos_x_moveto, 2);
4433 		prt_write_real(prt_pos_y_moveto, 2);
4434 		prt_write_string("m\n");
4435 		prt_do_moveto = FALSE;
4436 	    }
4437 
4438 	    /* Size of rect of background color on which text is printed */
4439 	    prt_write_real(prt_text_run, 2);
4440 	    prt_write_real(prt_line_height, 2);
4441 
4442 	    /* Lastly add the color of the background */
4443 	    r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
4444 	    g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
4445 	    b = prt_new_bgcol & 0xff;
4446 	    prt_write_real(r / 255.0, 3);
4447 	    prt_write_real(g / 255.0, 3);
4448 	    prt_write_real(b / 255.0, 3);
4449 	    prt_write_string("bg\n");
4450 	}
4451 	/* Draw underlines before the text as it makes it slightly easier to
4452 	 * find the starting point.
4453 	 */
4454 	if (prt_do_underline)
4455 	{
4456 	    if (prt_do_moveto)
4457 	    {
4458 		prt_write_real(prt_pos_x_moveto, 2);
4459 		prt_write_real(prt_pos_y_moveto, 2);
4460 		prt_write_string("m\n");
4461 		prt_do_moveto = FALSE;
4462 	    }
4463 
4464             /* Underline length of text run */
4465 	    prt_write_real(prt_text_run, 2);
4466 	    prt_write_string("ul\n");
4467 	}
4468 	/* Draw the text
4469 	 * Note: we write text out raw - EBCDIC conversion is handled in the
4470 	 * PostScript world via the font encoding vector. */
4471 #ifdef FEAT_MBYTE
4472         if (prt_out_mbyte)
4473             prt_write_string("<");
4474         else
4475 #endif
4476             prt_write_string("(");
4477 	prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
4478 #ifdef FEAT_MBYTE
4479         if (prt_out_mbyte)
4480             prt_write_string(">");
4481         else
4482 #endif
4483             prt_write_string(")");
4484 	/* Add a moveto if need be and use the appropriate show procedure */
4485 	if (prt_do_moveto)
4486 	{
4487 	    prt_write_real(prt_pos_x_moveto, 2);
4488 	    prt_write_real(prt_pos_y_moveto, 2);
4489 	    /* moveto and a show */
4490 	    prt_write_string("ms\n");
4491 	    prt_do_moveto = FALSE;
4492 	}
4493 	else /* Simple show */
4494 	    prt_write_string("s\n");
4495 
4496 	ga_clear(&prt_ps_buffer);
4497 	ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
4498     }
4499 }
4500 
4501 static char_u *resource_filename;
4502 
4503     static void
4504 prt_resource_name(filename)
4505     char_u  *filename;
4506 {
4507     if (STRLEN(filename) >= MAXPATHL)
4508 	*resource_filename = NUL;
4509     else
4510 	STRCPY(resource_filename, filename);
4511 }
4512 
4513     static int
4514 prt_find_resource(name, resource)
4515     char	*name;
4516     struct prt_ps_resource_S *resource;
4517 {
4518     char_u	buffer[MAXPATHL + 1];
4519 
4520     STRCPY(resource->name, name);
4521     /* Look for named resource file in runtimepath */
4522     STRCPY(buffer, "print");
4523     add_pathsep(buffer);
4524     STRCAT(buffer, name);
4525     STRCAT(buffer, ".ps");
4526     resource_filename = resource->filename;
4527     *resource_filename = NUL;
4528     return (do_in_runtimepath(buffer, FALSE, prt_resource_name)
4529 	    && resource->filename[0] != NUL);
4530 }
4531 
4532 /* PS CR and LF characters have platform independent values */
4533 #define PSLF  (0x0a)
4534 #define PSCR  (0x0d)
4535 
4536 /* Static buffer to read initial comments in a resource file, some can have a
4537  * couple of KB of comments! */
4538 #define PRT_FILE_BUFFER_LEN (2048)
4539 struct prt_resfile_buffer_S
4540 {
4541     char_u  buffer[PRT_FILE_BUFFER_LEN];
4542     int     len;
4543     int     line_start;
4544     int     line_end;
4545 };
4546 
4547 static struct prt_resfile_buffer_S prt_resfile;
4548 
4549     static int
4550 prt_resfile_next_line()
4551 {
4552     int     index;
4553 
4554     /* Move to start of next line and then find end of line */
4555     index = prt_resfile.line_end + 1;
4556     while (index < prt_resfile.len)
4557     {
4558         if (prt_resfile.buffer[index] != PSLF && prt_resfile.buffer[index]
4559                                                                         != PSCR)
4560             break;
4561         index++;
4562     }
4563     prt_resfile.line_start = index;
4564 
4565     while (index < prt_resfile.len)
4566     {
4567         if (prt_resfile.buffer[index] == PSLF || prt_resfile.buffer[index]
4568                                                                         == PSCR)
4569             break;
4570         index++;
4571     }
4572     prt_resfile.line_end = index;
4573 
4574     return (index < prt_resfile.len);
4575 }
4576 
4577     static int
4578 prt_resfile_strncmp(offset, string, len)
4579     int     offset;
4580     char    *string;
4581     int     len;
4582 {
4583     /* Force not equal if string is longer than remainder of line */
4584     if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
4585         return 1;
4586 
4587     return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
4588                                                                 string, len);
4589 }
4590 
4591     static int
4592 prt_resfile_skip_nonws(offset)
4593     int     offset;
4594 {
4595     int     index;
4596 
4597     index = prt_resfile.line_start + offset;
4598     while (index < prt_resfile.line_end)
4599     {
4600         if (isspace(prt_resfile.buffer[index]))
4601             return index - prt_resfile.line_start;
4602         index++;
4603     }
4604     return -1;
4605 }
4606 
4607     static int
4608 prt_resfile_skip_ws(offset)
4609     int     offset;
4610 {
4611     int     index;
4612 
4613     index = prt_resfile.line_start + offset;
4614     while (index < prt_resfile.line_end)
4615     {
4616         if (!isspace(prt_resfile.buffer[index]))
4617             return index - prt_resfile.line_start;
4618         index++;
4619     }
4620     return -1;
4621 }
4622 
4623 /* prt_next_dsc() - returns detail on next DSC comment line found.  Returns true
4624  * if a DSC comment is found, else false */
4625     static int
4626 prt_next_dsc(p_dsc_line)
4627     struct prt_dsc_line_S *p_dsc_line;
4628 {
4629     int     comment;
4630     int     offset;
4631 
4632     /* Move to start of next line */
4633     if (!prt_resfile_next_line())
4634         return FALSE;
4635 
4636     /* DSC comments always start %% */
4637     if (prt_resfile_strncmp(0, "%%", 2) != 0)
4638         return FALSE;
4639 
4640     /* Find type of DSC comment */
4641     for (comment = 0; comment < NUM_ELEMENTS(prt_dsc_table); comment++)
4642         if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
4643                                             prt_dsc_table[comment].len) == 0)
4644             break;
4645 
4646     if (comment != NUM_ELEMENTS(prt_dsc_table))
4647     {
4648         /* Return type of comment */
4649         p_dsc_line->type = prt_dsc_table[comment].type;
4650         offset = prt_dsc_table[comment].len;
4651     }
4652     else
4653     {
4654         /* Unrecognised DSC comment, skip to ws after comment leader */
4655         p_dsc_line->type = PRT_DSC_MISC_TYPE;
4656         offset = prt_resfile_skip_nonws(0);
4657         if (offset == -1)
4658             return FALSE;
4659     }
4660 
4661     /* Skip ws to comment value */
4662     offset = prt_resfile_skip_ws(offset);
4663     if (offset == -1)
4664         return FALSE;
4665 
4666     p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
4667     p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
4668 
4669     return TRUE;
4670 }
4671 
4672 /* Improved hand crafted parser to get the type, title, and version number of a
4673  * PS resource file so the file details can be added to the DSC header comments.
4674  */
4675     static int
4676 prt_open_resource(resource)
4677     struct prt_ps_resource_S *resource;
4678 {
4679     int         offset;
4680     int         seen_all;
4681     int         seen_title;
4682     int         seen_version;
4683     FILE	*fd_resource;
4684     struct prt_dsc_line_S dsc_line;
4685 
4686     fd_resource = mch_fopen((char *)resource->filename, READBIN);
4687     if (fd_resource == NULL)
4688     {
4689 	EMSG2(_("E624: Can't open file \"%s\""), resource->filename);
4690 	return FALSE;
4691     }
4692     vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN);
4693 
4694     /* Parse first line to ensure valid resource file */
4695     prt_resfile.len = fread((char *)prt_resfile.buffer, sizeof(char_u),
4696                                             PRT_FILE_BUFFER_LEN, fd_resource);
4697     if (ferror(fd_resource))
4698     {
4699 	EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
4700 		resource->filename);
4701 	fclose(fd_resource);
4702 	return FALSE;
4703     }
4704 
4705     prt_resfile.line_end = -1;
4706     prt_resfile.line_start = 0;
4707     if (!prt_resfile_next_line())
4708         return FALSE;
4709 
4710     offset = 0;
4711 
4712     if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
4713                                             STRLEN(PRT_RESOURCE_HEADER)) != 0)
4714     {
4715 	EMSG2(_("E618: file \"%s\" is not a PostScript resource file"),
4716 		resource->filename);
4717 	fclose(fd_resource);
4718 	return FALSE;
4719     }
4720 
4721     /* Skip over any version numbers and following ws */
4722     offset += STRLEN(PRT_RESOURCE_HEADER);
4723     offset = prt_resfile_skip_nonws(offset);
4724     if (offset == -1)
4725         return FALSE;
4726     offset = prt_resfile_skip_ws(offset);
4727     if (offset == -1)
4728         return FALSE;
4729 
4730     if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
4731                                             STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
4732     {
4733 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4734 		resource->filename);
4735 	fclose(fd_resource);
4736 	return FALSE;
4737     }
4738     offset += STRLEN(PRT_RESOURCE_RESOURCE);
4739 
4740     /* Decide type of resource in the file */
4741     if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
4742                                             STRLEN(PRT_RESOURCE_PROCSET)) == 0)
4743 	resource->type = PRT_RESOURCE_TYPE_PROCSET;
4744     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
4745                                             STRLEN(PRT_RESOURCE_ENCODING)) == 0)
4746 	resource->type = PRT_RESOURCE_TYPE_ENCODING;
4747     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
4748                                             STRLEN(PRT_RESOURCE_CMAP)) == 0)
4749 	resource->type = PRT_RESOURCE_TYPE_CMAP;
4750     else
4751     {
4752 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4753 		resource->filename);
4754 	fclose(fd_resource);
4755 	return FALSE;
4756     }
4757 
4758     /* Look for title and version of resource */
4759     resource->title[0] = '\0';
4760     resource->version[0] = '\0';
4761     seen_title = FALSE;
4762     seen_version = FALSE;
4763     seen_all = FALSE;
4764     while (!seen_all && prt_next_dsc(&dsc_line))
4765     {
4766         switch (dsc_line.type)
4767         {
4768         case PRT_DSC_TITLE_TYPE:
4769             STRNCPY(resource->title, dsc_line.string, dsc_line.len);
4770             resource->title[dsc_line.len] = '\0';
4771             seen_title = TRUE;
4772             if (seen_version)
4773                 seen_all = TRUE;
4774             break;
4775 
4776         case PRT_DSC_VERSION_TYPE:
4777             STRNCPY(resource->version, dsc_line.string, dsc_line.len);
4778             resource->version[dsc_line.len] = '\0';
4779             seen_version = TRUE;
4780             if (seen_title)
4781                 seen_all = TRUE;
4782             break;
4783 
4784         case PRT_DSC_ENDCOMMENTS_TYPE:
4785             /* Wont find title or resource after this comment, stop searching */
4786             seen_all = TRUE;
4787             break;
4788 
4789         case PRT_DSC_MISC_TYPE:
4790             /* Not interested in whatever comment this line had */
4791             break;
4792         }
4793     }
4794 
4795     if (!seen_title || !seen_version)
4796     {
4797 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4798 		resource->filename);
4799 	fclose(fd_resource);
4800 	return FALSE;
4801     }
4802 
4803     fclose(fd_resource);
4804 
4805     return TRUE;
4806 }
4807 
4808     static int
4809 prt_check_resource(resource, version)
4810     struct prt_ps_resource_S *resource;
4811     char_u  *version;
4812 {
4813     /* Version number m.n should match, the revision number does not matter */
4814     if (STRNCMP(resource->version, version, STRLEN(version)))
4815     {
4816 	EMSG2(_("E621: \"%s\" resource file has wrong version"),
4817 		resource->name);
4818 	return FALSE;
4819     }
4820 
4821     /* Other checks to be added as needed */
4822     return TRUE;
4823 }
4824 
4825     static void
4826 prt_dsc_start()
4827 {
4828     prt_write_string("%!PS-Adobe-3.0\n");
4829 }
4830 
4831     static void
4832 prt_dsc_noarg(comment)
4833     char	*comment;
4834 {
4835     sprintf((char *)prt_line_buffer, "%%%%%s\n", comment);
4836     prt_write_file(prt_line_buffer);
4837 }
4838 
4839     static void
4840 prt_dsc_textline(comment, text)
4841     char	*comment;
4842     char	*text;
4843 {
4844     sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text);
4845     prt_write_file(prt_line_buffer);
4846 }
4847 
4848     static void
4849 prt_dsc_text(comment, text)
4850     char	*comment;
4851     char	*text;
4852 {
4853     /* TODO - should scan 'text' for any chars needing escaping! */
4854     sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text);
4855     prt_write_file(prt_line_buffer);
4856 }
4857 
4858 #define prt_dsc_atend(c)	prt_dsc_text((c), "atend")
4859 
4860     static void
4861 prt_dsc_ints(comment, count, ints)
4862     char	*comment;
4863     int		count;
4864     int		*ints;
4865 {
4866     int		i;
4867 
4868     sprintf((char *)prt_line_buffer, "%%%%%s:", comment);
4869     prt_write_file(prt_line_buffer);
4870 
4871     for (i = 0; i < count; i++)
4872     {
4873 	sprintf((char *)prt_line_buffer, " %d", ints[i]);
4874 	prt_write_file(prt_line_buffer);
4875     }
4876 
4877     prt_write_string("\n");
4878 }
4879 
4880     static void
4881 prt_dsc_resources(comment, type, string)
4882     char	*comment;	/* if NULL add to previous */
4883     char	*type;
4884     char	*string;
4885 {
4886     if (comment != NULL)
4887 	sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type);
4888     else
4889 	sprintf((char *)prt_line_buffer, "%%%%+ %s", type);
4890     prt_write_file(prt_line_buffer);
4891 
4892     sprintf((char *)prt_line_buffer, " %s\n", string);
4893     prt_write_file(prt_line_buffer);
4894 }
4895 
4896     static void
4897 prt_dsc_font_resource(resource, ps_font)
4898     char	*resource;
4899     struct prt_ps_font_S *ps_font;
4900 {
4901     int     i;
4902 
4903     prt_dsc_resources(resource, "font",
4904                                     ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
4905     for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
4906         if (ps_font->ps_fontname[i] != NULL)
4907             prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
4908 }
4909 
4910     static void
4911 prt_dsc_requirements(duplex, tumble, collate, color, num_copies)
4912     int		duplex;
4913     int		tumble;
4914     int		collate;
4915     int		color;
4916     int		num_copies;
4917 {
4918     /* Only output the comment if we need to.
4919      * Note: tumble is ignored if we are not duplexing
4920      */
4921     if (!(duplex || collate || color || (num_copies > 1)))
4922 	return;
4923 
4924     sprintf((char *)prt_line_buffer, "%%%%Requirements:");
4925     prt_write_file(prt_line_buffer);
4926 
4927     if (duplex)
4928     {
4929 	prt_write_string(" duplex");
4930 	if (tumble)
4931 	    prt_write_string("(tumble)");
4932     }
4933     if (collate)
4934 	prt_write_string(" collate");
4935     if (color)
4936 	prt_write_string(" color");
4937     if (num_copies > 1)
4938     {
4939 	prt_write_string(" numcopies(");
4940 	/* Note: no space wanted so dont use prt_write_int() */
4941 	sprintf((char *)prt_line_buffer, "%d", num_copies);
4942 	prt_write_file(prt_line_buffer);
4943 	prt_write_string(")");
4944     }
4945     prt_write_string("\n");
4946 }
4947 
4948     static void
4949 prt_dsc_docmedia(paper_name, width, height, weight, colour, type)
4950     char	*paper_name;
4951     double	width;
4952     double	height;
4953     double	weight;
4954     char	*colour;
4955     char	*type;
4956 {
4957     sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name);
4958     prt_write_file(prt_line_buffer);
4959     prt_write_real(width, 2);
4960     prt_write_real(height, 2);
4961     prt_write_real(weight, 2);
4962     if (colour == NULL)
4963 	prt_write_string("()");
4964     else
4965 	prt_write_string(colour);
4966     prt_write_string(" ");
4967     if (type == NULL)
4968 	prt_write_string("()");
4969     else
4970 	prt_write_string(type);
4971     prt_write_string("\n");
4972 }
4973 
4974     void
4975 mch_print_cleanup()
4976 {
4977 #ifdef FEAT_MBYTE
4978     if (prt_out_mbyte)
4979     {
4980         int     i;
4981 
4982         /* Free off all CID font names created, but first clear duplicate
4983          * pointers to the same string (when the same font is used for more than
4984          * one style).
4985          */
4986         for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
4987         {
4988             if (prt_ps_mb_font.ps_fontname[i] != NULL)
4989                 vim_free(prt_ps_mb_font.ps_fontname[i]);
4990             prt_ps_mb_font.ps_fontname[i] = NULL;
4991         }
4992     }
4993 
4994     if (prt_do_conv)
4995     {
4996 	convert_setup(&prt_conv, NULL, NULL);
4997 	prt_do_conv = FALSE;
4998     }
4999 #endif
5000     if (prt_ps_fd != NULL)
5001     {
5002 	fclose(prt_ps_fd);
5003 	prt_ps_fd = NULL;
5004 	prt_file_error = FALSE;
5005     }
5006     if (prt_ps_file_name != NULL)
5007     {
5008 	vim_free(prt_ps_file_name);
5009 	prt_ps_file_name = NULL;
5010     }
5011 }
5012 
5013     static float
5014 to_device_units(idx, physsize, def_number)
5015     int		idx;
5016     double	physsize;
5017     int		def_number;
5018 {
5019     float	ret;
5020     int		u;
5021     int		nr;
5022 
5023     u = prt_get_unit(idx);
5024     if (u == PRT_UNIT_NONE)
5025     {
5026 	u = PRT_UNIT_PERC;
5027 	nr = def_number;
5028     }
5029     else
5030 	nr = printer_opts[idx].number;
5031 
5032     switch (u)
5033     {
5034 	case PRT_UNIT_INCH:
5035 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI);
5036 	    break;
5037 	case PRT_UNIT_MM:
5038 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
5039 	    break;
5040 	case PRT_UNIT_POINT:
5041 	    ret = (float)nr;
5042 	    break;
5043 	case PRT_UNIT_PERC:
5044 	default:
5045 	    ret = (float)(physsize * nr) / 100;
5046 	    break;
5047     }
5048 
5049     return ret;
5050 }
5051 
5052 /*
5053  * Calculate margins for given width and height from printoptions settings.
5054  */
5055     static void
5056 prt_page_margins(width, height, left, right, top, bottom)
5057     double	width;
5058     double	height;
5059     double	*left;
5060     double	*right;
5061     double	*top;
5062     double	*bottom;
5063 {
5064     *left   = to_device_units(OPT_PRINT_LEFT, width, 10);
5065     *right  = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
5066     *top    = height - to_device_units(OPT_PRINT_TOP, height, 5);
5067     *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
5068 }
5069 
5070     static void
5071 prt_font_metrics(font_scale)
5072     int		font_scale;
5073 {
5074     prt_line_height = (float)font_scale;
5075     prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
5076 }
5077 
5078 
5079     static int
5080 prt_get_cpl()
5081 {
5082     if (prt_use_number())
5083     {
5084 	prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
5085 #ifdef FEAT_MBYTE
5086         /* If we are outputting multi-byte characters then line numbers will be
5087          * printed with half width characters
5088          */
5089         if (prt_out_mbyte)
5090             prt_number_width /= 2;
5091 #endif
5092 	prt_left_margin += prt_number_width;
5093     }
5094     else
5095 	prt_number_width = 0.0;
5096 
5097     return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
5098 }
5099 
5100     static int
5101 prt_build_cid_fontname(font, name, name_len)
5102     int     font;
5103     char    *name;
5104     int     name_len;
5105 {
5106     char    *fontname;
5107 
5108     fontname = alloc(name_len + 1);
5109     if (fontname == NULL)
5110         return FALSE;
5111     STRNCPY(fontname, name, name_len);
5112     fontname[name_len] = '\0';
5113     prt_ps_mb_font.ps_fontname[font] = fontname;
5114 
5115     return TRUE;
5116 }
5117 
5118 /*
5119  * Get number of lines of text that fit on a page (excluding the header).
5120  */
5121     static int
5122 prt_get_lpp()
5123 {
5124     int lpp;
5125 
5126     /*
5127      * Calculate offset to lower left corner of background rect based on actual
5128      * font height (based on its bounding box) and the line height, handling the
5129      * case where the font height can exceed the line height.
5130      */
5131     prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
5132 					   prt_ps_font->bbox_min_y);
5133     if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
5134     {
5135 	prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
5136 				(1000.0 - (prt_ps_font->bbox_max_y -
5137 					    prt_ps_font->bbox_min_y)) / 2);
5138     }
5139 
5140     /* Get height for topmost line based on background rect offset. */
5141     prt_first_line_height = prt_line_height + prt_bgcol_offset;
5142 
5143     /* Calculate lpp */
5144     lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
5145 
5146     /* Adjust top margin if there is a header */
5147     prt_top_margin -= prt_line_height * prt_header_height();
5148 
5149     return lpp - prt_header_height();
5150 }
5151 
5152 #ifdef FEAT_MBYTE
5153     static int
5154 prt_match_encoding(p_encoding, p_cmap, pp_mbenc)
5155     char    *p_encoding;
5156     struct prt_ps_mbfont_S *p_cmap;
5157     struct prt_ps_encoding_S **pp_mbenc;
5158 {
5159     int     mbenc;
5160     int     enc_len;
5161     struct prt_ps_encoding_S *p_mbenc;
5162 
5163     *pp_mbenc = NULL;
5164     /* Look for recognised encoding */
5165     enc_len = STRLEN(p_encoding);
5166     p_mbenc = p_cmap->encodings;
5167     for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
5168     {
5169         if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
5170         {
5171             *pp_mbenc = p_mbenc;
5172             return TRUE;
5173         }
5174         p_mbenc++;
5175     }
5176     return FALSE;
5177 }
5178 
5179     static int
5180 prt_match_charset(p_charset, p_cmap, pp_mbchar)
5181     char    *p_charset;
5182     struct prt_ps_mbfont_S *p_cmap;
5183     struct prt_ps_charset_S **pp_mbchar;
5184 {
5185     int     mbchar;
5186     int     char_len;
5187     struct prt_ps_charset_S *p_mbchar;
5188 
5189     /* Look for recognised character set, using default if one is not given */
5190     if (*p_charset == NUL)
5191         p_charset = p_cmap->defcs;
5192     char_len = STRLEN(p_charset);
5193     p_mbchar = p_cmap->charsets;
5194     for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
5195     {
5196         if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
5197         {
5198             *pp_mbchar = p_mbchar;
5199             return TRUE;
5200         }
5201         p_mbchar++;
5202     }
5203     return FALSE;
5204 }
5205 #endif
5206 
5207 /*ARGSUSED*/
5208     int
5209 mch_print_init(psettings, jobname, forceit)
5210     prt_settings_T *psettings;
5211     char_u	*jobname;
5212     int		forceit;
5213 {
5214     int		i;
5215     char	*paper_name;
5216     int		paper_strlen;
5217     int		fontsize;
5218     char_u	*p;
5219     double      left;
5220     double      right;
5221     double      top;
5222     double      bottom;
5223 #ifdef FEAT_MBYTE
5224     int         cmap;
5225     int         pmcs_len;
5226     char_u	*p_encoding;
5227     struct prt_ps_encoding_S *p_mbenc;
5228     struct prt_ps_encoding_S *p_mbenc_first;
5229     struct prt_ps_charset_S *p_mbchar;
5230 #endif
5231 
5232 #if 0
5233     /*
5234      * TODO:
5235      * If "forceit" is false: pop up a dialog to select:
5236      *	- printer name
5237      *	- copies
5238      *	- collated/uncollated
5239      *	- duplex off/long side/short side
5240      *	- paper size
5241      *	- portrait/landscape
5242      *	- font size
5243      *
5244      * If "forceit" is true: use the default printer and settings
5245      */
5246     if (forceit)
5247 	s_pd.Flags |= PD_RETURNDEFAULT;
5248 #endif
5249 
5250     /*
5251      * Set up font and encoding.
5252      */
5253 #ifdef FEAT_MBYTE
5254     p_encoding = enc_skip(p_penc);
5255     if (*p_encoding == NUL)
5256         p_encoding = enc_skip(p_enc);
5257 
5258     /* Look for recognised multi-byte coding, and if the charset is recognised.
5259      * This is to cope with the fact that various unicode encodings are
5260      * supported in more than one of CJK. */
5261     p_mbenc = NULL;
5262     p_mbenc_first = NULL;
5263     p_mbchar = NULL;
5264     for (cmap = 0; cmap < NUM_ELEMENTS(prt_ps_mbfonts); cmap++)
5265         if (prt_match_encoding(p_encoding, &prt_ps_mbfonts[cmap], &p_mbenc))
5266         {
5267             if (p_mbenc_first == NULL)
5268                 p_mbenc_first = p_mbenc;
5269             if (prt_match_charset(p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar))
5270                 break;
5271         }
5272 
5273     /* Use first encoding matched if no charset matched */
5274     if (p_mbchar == NULL && p_mbenc_first != NULL)
5275         p_mbenc = p_mbenc_first;
5276 
5277     prt_out_mbyte = (p_mbenc != NULL);
5278     if (prt_out_mbyte)
5279     {
5280         /* Build CMap name - will be same for all multi-byte fonts used */
5281         prt_cmap[0] = '\0';
5282 
5283         prt_custom_cmap = prt_out_mbyte && p_mbchar == NULL;
5284 
5285         if (!prt_custom_cmap)
5286         {
5287             /* Check encoding and character set are compatible */
5288             if ((p_mbenc->needs_charset&p_mbchar->has_charset) == 0)
5289             {
5290                 EMSG(_("E673: Incompatible multi-byte encoding and character set."));
5291                 return FALSE;
5292             }
5293 
5294             /* Add charset name if not empty */
5295             if (p_mbchar->cmap_charset != NULL)
5296             {
5297                 STRCAT(prt_cmap, p_mbchar->cmap_charset);
5298                 STRCAT(prt_cmap, "-");
5299             }
5300         }
5301         else
5302         {
5303             /* Add custom CMap character set name */
5304             pmcs_len = STRLEN(p_pmcs);
5305             if (pmcs_len == 0)
5306             {
5307                 EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
5308                 return FALSE;
5309             }
5310             STRNCPY(prt_cmap, p_pmcs, STRLEN(p_pmcs));
5311             prt_cmap[pmcs_len] = '\0';
5312             STRCAT(prt_cmap, "-");
5313         }
5314 
5315         /* CMap name ends with (optional) encoding name and -H for horizontal */
5316         if (p_mbenc->cmap_encoding != NULL)
5317         {
5318             STRCAT(prt_cmap, p_mbenc->cmap_encoding);
5319             STRCAT(prt_cmap, "-");
5320         }
5321         STRCAT(prt_cmap, "H");
5322 
5323         if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
5324         {
5325             EMSG(_("E675: No default font specfifed for multi-byte printing."));
5326             return FALSE;
5327         }
5328 
5329         /* Derive CID font names with fallbacks if not defined */
5330         if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
5331                                     mbfont_opts[OPT_MBFONT_REGULAR].string,
5332                                     mbfont_opts[OPT_MBFONT_REGULAR].strlen))
5333             return FALSE;
5334         if (mbfont_opts[OPT_MBFONT_BOLD].present)
5335             if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
5336                                         mbfont_opts[OPT_MBFONT_BOLD].string,
5337                                         mbfont_opts[OPT_MBFONT_BOLD].strlen))
5338                 return FALSE;
5339         if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
5340             if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
5341                                         mbfont_opts[OPT_MBFONT_OBLIQUE].string,
5342                                         mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
5343                 return FALSE;
5344         if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
5345             if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
5346                                         mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
5347                                         mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
5348                 return FALSE;
5349 
5350         /* Check if need to use Courier for ASCII code range, and if so pick up
5351          * the encoding to use */
5352         prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
5353             (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
5354         if (prt_use_courier)
5355         {
5356             /* Use national ASCII variant unless ASCII wanted */
5357             if (mbfont_opts[OPT_MBFONT_ASCII].present &&
5358                 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
5359                 prt_ascii_encoding = "ascii";
5360             else
5361                 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
5362         }
5363 
5364         prt_ps_font = &prt_ps_mb_font;
5365     }
5366     else
5367 #endif
5368     {
5369 #ifdef FEAT_MBYTE
5370         prt_use_courier = FALSE;
5371 #endif
5372         prt_ps_font = &prt_ps_courier_font;
5373     }
5374 
5375     /*
5376      * Find the size of the paper and set the margins.
5377      */
5378     prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
5379 	   || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
5380     if (printer_opts[OPT_PRINT_PAPER].present)
5381     {
5382 	paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
5383 	paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
5384     }
5385     else
5386     {
5387 	paper_name = "A4";
5388 	paper_strlen = 2;
5389     }
5390     for (i = 0; i < PRT_MEDIASIZE_LEN; ++i)
5391 	if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
5392 		&& STRNICMP(prt_mediasize[i].name, paper_name,
5393 							   paper_strlen) == 0)
5394 	    break;
5395     if (i == PRT_MEDIASIZE_LEN)
5396 	i = 0;
5397     prt_media = i;
5398 
5399     /*
5400      * Set PS pagesize based on media dimensions and print orientation.
5401      * Note: Media and page sizes have defined meanings in PostScript and should
5402      * be kept distinct.  Media is the paper (or transparency, or ...) that is
5403      * printed on, whereas the page size is the area that the PostScript
5404      * interpreter renders into.
5405      */
5406     if (prt_portrait)
5407     {
5408 	prt_page_width = prt_mediasize[i].width;
5409 	prt_page_height = prt_mediasize[i].height;
5410     }
5411     else
5412     {
5413 	prt_page_width = prt_mediasize[i].height;
5414 	prt_page_height = prt_mediasize[i].width;
5415     }
5416 
5417     /*
5418      * Set PS page margins based on the PS pagesize, not the mediasize - this
5419      * needs to be done before the cpl and lpp are calculated.
5420      */
5421     prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
5422 								    &bottom);
5423     prt_left_margin = (float)left;
5424     prt_right_margin = (float)right;
5425     prt_top_margin = (float)top;
5426     prt_bottom_margin = (float)bottom;
5427 
5428     /*
5429      * Set up the font size.
5430      */
5431     fontsize = PRT_PS_DEFAULT_FONTSIZE;
5432     for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
5433 	if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
5434 	    fontsize = atoi((char *)p + 2);
5435     prt_font_metrics(fontsize);
5436 
5437     /*
5438      * Return the number of characters per line, and lines per page for the
5439      * generic print code.
5440      */
5441     psettings->chars_per_line = prt_get_cpl();
5442     psettings->lines_per_page = prt_get_lpp();
5443 
5444     /* Catch margin settings that leave no space for output! */
5445     if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
5446 	return FAIL;
5447 
5448     /*
5449      * Sort out the number of copies to be printed.  PS by default will do
5450      * uncollated copies for you, so once we know how many uncollated copies are
5451      * wanted cache it away and lie to the generic code that we only want one
5452      * uncollated copy.
5453      */
5454     psettings->n_collated_copies = 1;
5455     psettings->n_uncollated_copies = 1;
5456     prt_num_copies = 1;
5457     prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
5458 	    || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
5459     if (prt_collate)
5460     {
5461 	/* TODO: Get number of collated copies wanted. */
5462 	psettings->n_collated_copies = 1;
5463     }
5464     else
5465     {
5466 	/* TODO: Get number of uncollated copies wanted and update the cached
5467 	 * count.
5468 	 */
5469 	prt_num_copies = 1;
5470     }
5471 
5472     psettings->jobname = jobname;
5473 
5474     /*
5475      * Set up printer duplex and tumble based on Duplex option setting - default
5476      * is long sided duplex printing (i.e. no tumble).
5477      */
5478     prt_duplex = TRUE;
5479     prt_tumble = FALSE;
5480     psettings->duplex = 1;
5481     if (printer_opts[OPT_PRINT_DUPLEX].present)
5482     {
5483 	if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
5484 	{
5485 	    prt_duplex = FALSE;
5486 	    psettings->duplex = 0;
5487 	}
5488 	else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
5489 									 == 0)
5490 	    prt_tumble = TRUE;
5491     }
5492 
5493     /* For now user abort not supported */
5494     psettings->user_abort = 0;
5495 
5496     /* If the user didn't specify a file name, use a temp file. */
5497     if (psettings->outfile == NULL)
5498     {
5499 	prt_ps_file_name = vim_tempname('p');
5500 	if (prt_ps_file_name == NULL)
5501 	{
5502 	    EMSG(_(e_notmp));
5503 	    return FAIL;
5504 	}
5505 	prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
5506     }
5507     else
5508     {
5509 	p = expand_env_save(psettings->outfile);
5510 	if (p != NULL)
5511 	{
5512 	    prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
5513 	    vim_free(p);
5514 	}
5515     }
5516     if (prt_ps_fd == NULL)
5517     {
5518 	EMSG(_("E324: Can't open PostScript output file"));
5519 	mch_print_cleanup();
5520 	return FAIL;
5521     }
5522 
5523     prt_bufsiz = psettings->chars_per_line;
5524 #ifdef FEAT_MBYTE
5525     if (prt_out_mbyte)
5526         prt_bufsiz *= 2;
5527 #endif
5528     ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
5529 
5530     prt_page_num = 0;
5531 
5532     prt_attribute_change = FALSE;
5533     prt_need_moveto = FALSE;
5534     prt_need_font = FALSE;
5535     prt_need_fgcol = FALSE;
5536     prt_need_bgcol = FALSE;
5537     prt_need_underline = FALSE;
5538 
5539     prt_file_error = FALSE;
5540 
5541     return OK;
5542 }
5543 
5544     static int
5545 prt_add_resource(resource)
5546     struct prt_ps_resource_S *resource;
5547 {
5548     FILE*	fd_resource;
5549     char_u	resource_buffer[512];
5550     size_t	bytes_read;
5551 
5552     fd_resource = mch_fopen((char *)resource->filename, READBIN);
5553     if (fd_resource == NULL)
5554     {
5555 	EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
5556 	return FALSE;
5557     }
5558     prt_dsc_resources("BeginResource",
5559                         prt_resource_types[resource->type], resource->title);
5560 
5561     prt_dsc_textline("BeginDocument", (char *)resource->filename);
5562 
5563     for (;;)
5564     {
5565 	bytes_read = fread((char *)resource_buffer, sizeof(char_u),
5566 			   sizeof(resource_buffer), fd_resource);
5567 	if (ferror(fd_resource))
5568 	{
5569 	    EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
5570 							    resource->filename);
5571 	    fclose(fd_resource);
5572 	    return FALSE;
5573 	}
5574 	if (bytes_read == 0)
5575 	    break;
5576 	prt_write_file_raw_len(resource_buffer, bytes_read);
5577 	if (prt_file_error)
5578 	{
5579 	    fclose(fd_resource);
5580 	    return FALSE;
5581 	}
5582     }
5583     fclose(fd_resource);
5584 
5585     prt_dsc_noarg("EndDocument");
5586 
5587     prt_dsc_noarg("EndResource");
5588 
5589     return TRUE;
5590 }
5591 
5592     int
5593 mch_print_begin(psettings)
5594     prt_settings_T *psettings;
5595 {
5596     time_t	now;
5597     int		bbox[4];
5598     char	*p_time;
5599     double      left;
5600     double      right;
5601     double      top;
5602     double      bottom;
5603     struct prt_ps_resource_S res_prolog;
5604     struct prt_ps_resource_S res_encoding;
5605     char_u      buffer[256];
5606     char_u      *p_encoding;
5607 #ifdef FEAT_MBYTE
5608     struct prt_ps_resource_S res_cidfont;
5609     struct prt_ps_resource_S res_cmap;
5610 #endif
5611 
5612     /*
5613      * PS DSC Header comments - no PS code!
5614      */
5615     prt_dsc_start();
5616     prt_dsc_textline("Title", (char *)psettings->jobname);
5617     if (!get_user_name(buffer, 256))
5618         STRCPY(buffer, "Unknown");
5619     prt_dsc_textline("For", buffer);
5620     prt_dsc_textline("Creator", VIM_VERSION_LONG);
5621     /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
5622     now = time(NULL);
5623     p_time = ctime(&now);
5624     /* Note: ctime() adds a \n so we have to remove it :-( */
5625     *(vim_strchr((char_u *)p_time, '\n')) = '\0';
5626     prt_dsc_textline("CreationDate", p_time);
5627     prt_dsc_textline("DocumentData", "Clean8Bit");
5628     prt_dsc_textline("Orientation", "Portrait");
5629     prt_dsc_atend("Pages");
5630     prt_dsc_textline("PageOrder", "Ascend");
5631     /* The bbox does not change with orientation - it is always in the default
5632      * user coordinate system!  We have to recalculate right and bottom
5633      * coordinates based on the font metrics for the bbox to be accurate. */
5634     prt_page_margins(prt_mediasize[prt_media].width,
5635 					    prt_mediasize[prt_media].height,
5636 					    &left, &right, &top, &bottom);
5637     bbox[0] = (int)left;
5638     if (prt_portrait)
5639     {
5640 	/* In portrait printing the fixed point is the top left corner so we
5641 	 * derive the bbox from that point.  We have the expected cpl chars
5642 	 * across the media and lpp lines down the media.
5643 	 */
5644 	bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
5645 							    * prt_line_height);
5646 	bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
5647 									+ 0.5);
5648 	bbox[3] = (int)(top + 0.5);
5649     }
5650     else
5651     {
5652 	/* In landscape printing the fixed point is the bottom left corner so we
5653 	 * derive the bbox from that point.  We have lpp chars across the media
5654 	 * and cpl lines up the media.
5655 	 */
5656 	bbox[1] = (int)bottom;
5657 	bbox[2] = (int)(left + ((psettings->lines_per_page
5658 			      + prt_header_height()) * prt_line_height) + 0.5);
5659 	bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
5660 									+ 0.5);
5661     }
5662     prt_dsc_ints("BoundingBox", 4, bbox);
5663     /* The media width and height does not change with landscape printing! */
5664     prt_dsc_docmedia(prt_mediasize[prt_media].name,
5665 				prt_mediasize[prt_media].width,
5666 				prt_mediasize[prt_media].height,
5667 				(double)0, NULL, NULL);
5668     /* Define fonts needed */
5669 #ifdef FEAT_MBYTE
5670     if (!prt_out_mbyte || prt_use_courier)
5671 #endif
5672         prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
5673 #ifdef FEAT_MBYTE
5674     if (prt_out_mbyte)
5675     {
5676         prt_dsc_font_resource((prt_use_courier ? NULL
5677                                  : "DocumentNeededResources"), &prt_ps_mb_font);
5678         if (!prt_custom_cmap)
5679             prt_dsc_resources(NULL, "cmap", prt_cmap);
5680     }
5681 #endif
5682 
5683     /* Search for external resources VIM supplies */
5684     if (!prt_find_resource("prolog", &res_prolog))
5685     {
5686 	EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\""));
5687 	return FALSE;
5688     }
5689     if (!prt_open_resource(&res_prolog))
5690 	return FALSE;
5691     if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION))
5692 	return FALSE;
5693 #ifdef FEAT_MBYTE
5694     if (prt_out_mbyte)
5695     {
5696         /* Look for required version of multi-byte printing procset */
5697         if (!prt_find_resource("cidfont", &res_cidfont))
5698         {
5699             EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
5700             return FALSE;
5701         }
5702         if (!prt_open_resource(&res_cidfont))
5703             return FALSE;
5704         if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION))
5705             return FALSE;
5706     }
5707 #endif
5708 
5709     /* Find an encoding to use for printing.
5710      * Check 'printencoding'. If not set or not found, then use 'encoding'. If
5711      * that cannot be found then default to "latin1".
5712      * Note: VIM specific encoding header is always skipped.
5713      */
5714 #ifdef FEAT_MBYTE
5715     if (!prt_out_mbyte)
5716     {
5717 #endif
5718         p_encoding = enc_skip(p_penc);
5719         if (*p_encoding == NUL
5720                 || !prt_find_resource((char *)p_encoding, &res_encoding))
5721         {
5722             /* 'printencoding' not set or not supported - find alternate */
5723 #ifdef FEAT_MBYTE
5724             int		props;
5725 
5726             p_encoding = enc_skip(p_enc);
5727             props = enc_canon_props(p_encoding);
5728             if (!(props & ENC_8BIT)
5729                     || !prt_find_resource((char *)p_encoding, &res_encoding))
5730                 /* 8-bit 'encoding' is not supported */
5731 #endif
5732                 {
5733                 /* Use latin1 as default printing encoding */
5734                 p_encoding = (char_u *)"latin1";
5735                 if (!prt_find_resource((char *)p_encoding, &res_encoding))
5736                 {
5737                     EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5738                             p_encoding);
5739                     return FALSE;
5740                 }
5741             }
5742         }
5743         if (!prt_open_resource(&res_encoding))
5744             return FALSE;
5745         /* For the moment there are no checks on encoding resource files to
5746          * perform */
5747 #ifdef FEAT_MBYTE
5748     }
5749     else
5750     {
5751         p_encoding = enc_skip(p_penc);
5752         if (*p_encoding == NUL)
5753             p_encoding = enc_skip(p_enc);
5754         if (prt_use_courier)
5755         {
5756             /* Include ASCII range encoding vector */
5757             if (!prt_find_resource(prt_ascii_encoding, &res_encoding))
5758             {
5759                 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5760                       prt_ascii_encoding);
5761                 return FALSE;
5762             }
5763             if (!prt_open_resource(&res_encoding))
5764                 return FALSE;
5765             /* For the moment there are no checks on encoding resource files to
5766              * perform */
5767         }
5768     }
5769 
5770     prt_conv.vc_type = CONV_NONE;
5771     if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
5772         /* Set up encoding conversion if required */
5773 	if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
5774 	{
5775             EMSG2(_("E620: Unable to convert to print encoding \"%s\""),
5776 		    p_encoding);
5777 	    return FALSE;
5778 	}
5779 	prt_do_conv = TRUE;
5780     }
5781     prt_do_conv = prt_conv.vc_type != CONV_NONE;
5782 
5783     if (prt_out_mbyte && prt_custom_cmap)
5784     {
5785         /* Find user supplied CMap */
5786         if (!prt_find_resource(prt_cmap, &res_cmap))
5787         {
5788             EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
5789                   prt_cmap);
5790             return FALSE;
5791         }
5792         if (!prt_open_resource(&res_cmap))
5793             return FALSE;
5794     }
5795 #endif
5796 
5797     /* List resources supplied */
5798     STRCPY(buffer, res_prolog.title);
5799     STRCAT(buffer, " ");
5800     STRCAT(buffer, res_prolog.version);
5801     prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
5802 #ifdef FEAT_MBYTE
5803     if (prt_out_mbyte)
5804     {
5805         STRCPY(buffer, res_cidfont.title);
5806         STRCAT(buffer, " ");
5807         STRCAT(buffer, res_cidfont.version);
5808         prt_dsc_resources(NULL, "procset", buffer);
5809 
5810         if (prt_custom_cmap)
5811         {
5812             STRCPY(buffer, res_cmap.title);
5813             STRCAT(buffer, " ");
5814             STRCAT(buffer, res_cmap.version);
5815             prt_dsc_resources(NULL, "cmap", buffer);
5816         }
5817     }
5818     if (!prt_out_mbyte || prt_use_courier)
5819 #endif
5820     {
5821         STRCPY(buffer, res_encoding.title);
5822         STRCAT(buffer, " ");
5823         STRCAT(buffer, res_encoding.version);
5824         prt_dsc_resources(NULL, "encoding", buffer);
5825     }
5826     prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
5827 #ifdef FEAT_SYN_HL
5828 					psettings->do_syntax
5829 #else
5830 					0
5831 #endif
5832 					, prt_num_copies);
5833     prt_dsc_noarg("EndComments");
5834 
5835     /*
5836      * PS Document page defaults
5837      */
5838     prt_dsc_noarg("BeginDefaults");
5839 
5840     /* List font resources most likely common to all pages */
5841 #ifdef FEAT_MBYTE
5842     if (!prt_out_mbyte || prt_use_courier)
5843 #endif
5844         prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
5845 #ifdef FEAT_MBYTE
5846     if (prt_out_mbyte)
5847     {
5848         prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
5849                                                             &prt_ps_mb_font);
5850         if (!prt_custom_cmap)
5851             prt_dsc_resources(NULL, "cmap", prt_cmap);
5852     }
5853 #endif
5854 
5855     /* Paper will be used for all pages */
5856     prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
5857 
5858     prt_dsc_noarg("EndDefaults");
5859 
5860     /*
5861      * PS Document prolog inclusion - all required procsets.
5862      */
5863     prt_dsc_noarg("BeginProlog");
5864 
5865     /* Add required procsets - NOTE: order is important! */
5866     if (!prt_add_resource(&res_prolog))
5867 	return FALSE;
5868 #ifdef FEAT_MBYTE
5869     if (prt_out_mbyte)
5870     {
5871         /* Add CID font procset, and any user supplied CMap */
5872         if (!prt_add_resource(&res_cidfont))
5873             return FALSE;
5874         if (prt_custom_cmap && !prt_add_resource(&res_cmap))
5875             return FALSE;
5876     }
5877 #endif
5878 
5879 #ifdef FEAT_MBYTE
5880     if (!prt_out_mbyte || prt_use_courier)
5881 #endif
5882         /* There will be only one Roman font encoding to be included in the PS
5883          * file. */
5884         if (!prt_add_resource(&res_encoding))
5885             return FALSE;
5886 
5887     prt_dsc_noarg("EndProlog");
5888 
5889     /*
5890      * PS Document setup - must appear after the prolog
5891      */
5892     prt_dsc_noarg("BeginSetup");
5893 
5894     /* Device setup - page size and number of uncollated copies */
5895     prt_write_int((int)prt_mediasize[prt_media].width);
5896     prt_write_int((int)prt_mediasize[prt_media].height);
5897     prt_write_int(0);
5898     prt_write_string("sps\n");
5899     prt_write_int(prt_num_copies);
5900     prt_write_string("nc\n");
5901     prt_write_boolean(prt_duplex);
5902     prt_write_boolean(prt_tumble);
5903     prt_write_string("dt\n");
5904     prt_write_boolean(prt_collate);
5905     prt_write_string("c\n");
5906 
5907     /* Font resource inclusion and definition */
5908 #ifdef FEAT_MBYTE
5909     if (!prt_out_mbyte || prt_use_courier)
5910     {
5911         /* When using Courier for ASCII range when printing multi-byte, need to
5912          * pick up ASCII encoding to use with it. */
5913         if (prt_use_courier)
5914             p_encoding = prt_ascii_encoding;
5915 #endif
5916         prt_dsc_resources("IncludeResource", "font",
5917                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5918         prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
5919                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5920         prt_dsc_resources("IncludeResource", "font",
5921                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
5922         prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
5923                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
5924         prt_dsc_resources("IncludeResource", "font",
5925                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5926         prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
5927                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5928         prt_dsc_resources("IncludeResource", "font",
5929                           prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5930         prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
5931                      prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5932 #ifdef FEAT_MBYTE
5933     }
5934     if (prt_out_mbyte)
5935     {
5936         /* Define the CID fonts to be used in the job.  Typically CJKV fonts do
5937          * not have an italic form being a western style, so where no font is
5938          * defined for these faces VIM falls back to an existing face.
5939          * Note: if using Courier for the ASCII range then the printout will
5940          * have bold/italic/bolditalic regardless of the setting of printmbfont.
5941          */
5942         prt_dsc_resources("IncludeResource", "font",
5943                           prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5944         if (!prt_custom_cmap)
5945             prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5946         prt_def_cidfont("CF0", (int)prt_line_height,
5947                         prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5948 
5949         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
5950         {
5951             prt_dsc_resources("IncludeResource", "font",
5952                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
5953             if (!prt_custom_cmap)
5954                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5955             prt_def_cidfont("CF1", (int)prt_line_height,
5956                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
5957         }
5958         else
5959             /* Use ROMAN for BOLD */
5960             prt_dup_cidfont("CF0", "CF1");
5961 
5962         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
5963         {
5964             prt_dsc_resources("IncludeResource", "font",
5965                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5966             if (!prt_custom_cmap)
5967                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5968             prt_def_cidfont("CF2", (int)prt_line_height,
5969                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5970         }
5971         else
5972             /* Use ROMAN for OBLIQUE */
5973             prt_dup_cidfont("CF0", "CF2");
5974 
5975         if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
5976         {
5977             prt_dsc_resources("IncludeResource", "font",
5978                               prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5979             if (!prt_custom_cmap)
5980                 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
5981             prt_def_cidfont("CF3", (int)prt_line_height,
5982                             prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5983         }
5984         else
5985             /* Use BOLD for BOLDOBLIQUE */
5986             prt_dup_cidfont("CF1", "CF3");
5987     }
5988 #endif
5989 
5990     /* Misc constant vars used for underlining and background rects */
5991     prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
5992 						prt_ps_font->uline_offset), 2);
5993     prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
5994 						 prt_ps_font->uline_width), 2);
5995     prt_def_var("BO", prt_bgcol_offset, 2);
5996 
5997     prt_dsc_noarg("EndSetup");
5998 
5999     /* Fail if any problems writing out to the PS file */
6000     return !prt_file_error;
6001 }
6002 
6003     void
6004 mch_print_end(psettings)
6005     prt_settings_T *psettings;
6006 {
6007     prt_dsc_noarg("Trailer");
6008 
6009     /*
6010      * Output any info we don't know in toto until we finish
6011      */
6012     prt_dsc_ints("Pages", 1, &prt_page_num);
6013 
6014     prt_dsc_noarg("EOF");
6015 
6016     /* Write CTRL-D to close serial communication link if used.
6017      * NOTHING MUST BE WRITTEN AFTER THIS! */
6018     prt_write_file(IF_EB("\004", "\067"));
6019 
6020     if (!prt_file_error && psettings->outfile == NULL
6021 					&& !got_int && !psettings->user_abort)
6022     {
6023 	/* Close the file first. */
6024 	if (prt_ps_fd != NULL)
6025 	{
6026 	    fclose(prt_ps_fd);
6027 	    prt_ps_fd = NULL;
6028 	}
6029 	prt_message((char_u *)_("Sending to printer..."));
6030 
6031 	/* Not printing to a file: use 'printexpr' to print the file. */
6032 	if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
6033 	    EMSG(_("E365: Failed to print PostScript file"));
6034 	else
6035 	    prt_message((char_u *)_("Print job sent."));
6036     }
6037 
6038     mch_print_cleanup();
6039 }
6040 
6041     int
6042 mch_print_end_page()
6043 {
6044     prt_flush_buffer();
6045 
6046     prt_write_string("re sp\n");
6047 
6048     prt_dsc_noarg("PageTrailer");
6049 
6050     return !prt_file_error;
6051 }
6052 
6053 /*ARGSUSED*/
6054     int
6055 mch_print_begin_page(str)
6056     char_u	*str;
6057 {
6058     int		page_num[2];
6059 
6060     prt_page_num++;
6061 
6062     page_num[0] = page_num[1] = prt_page_num;
6063     prt_dsc_ints("Page", 2, page_num);
6064 
6065     prt_dsc_noarg("BeginPageSetup");
6066 
6067     prt_write_string("sv\n0 g\n");
6068 #ifdef FEAT_MBYTE
6069     prt_in_ascii = !prt_out_mbyte;
6070     if (prt_out_mbyte)
6071         prt_write_string("CF0 sf\n");
6072     else
6073 #endif
6074         prt_write_string("F0 sf\n");
6075     prt_fgcol = PRCOLOR_BLACK;
6076     prt_bgcol = PRCOLOR_WHITE;
6077     prt_font = PRT_PS_FONT_ROMAN;
6078 
6079     /* Set up page transformation for landscape printing. */
6080     if (!prt_portrait)
6081     {
6082 	prt_write_int(-((int)prt_mediasize[prt_media].width));
6083 	prt_write_string("sl\n");
6084     }
6085 
6086     prt_dsc_noarg("EndPageSetup");
6087 
6088     /* We have reset the font attributes, force setting them again. */
6089     curr_bg = (long_u)0xffffffff;
6090     curr_fg = (long_u)0xffffffff;
6091     curr_bold = MAYBE;
6092 
6093     return !prt_file_error;
6094 }
6095 
6096     int
6097 mch_print_blank_page()
6098 {
6099     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
6100 }
6101 
6102 static float prt_pos_x = 0;
6103 static float prt_pos_y = 0;
6104 
6105     void
6106 mch_print_start_line(margin, page_line)
6107     int		margin;
6108     int		page_line;
6109 {
6110     prt_pos_x = prt_left_margin;
6111     if (margin)
6112 	prt_pos_x -= prt_number_width;
6113 
6114     prt_pos_y = prt_top_margin - prt_first_line_height -
6115 					page_line * prt_line_height;
6116 
6117     prt_attribute_change = TRUE;
6118     prt_need_moveto = TRUE;
6119 #ifdef FEAT_MBYTE
6120     prt_half_width = FALSE;
6121 #endif
6122 }
6123 
6124 /*ARGSUSED*/
6125     int
6126 mch_print_text_out(p, len)
6127     char_u	*p;
6128     int		len;
6129 {
6130     int		need_break;
6131     char_u	ch;
6132     char_u      ch_buff[8];
6133     float       char_width;
6134     float       next_pos;
6135 #ifdef FEAT_MBYTE
6136     int         in_ascii;
6137     int         half_width;
6138 #endif
6139 
6140     char_width = prt_char_width;
6141 
6142 #ifdef FEAT_MBYTE
6143     /* Ideally VIM would create a rearranged CID font to combine a Roman and
6144      * CJKV font to do what VIM is doing here - use a Roman font for characters
6145      * in the ASCII range, and the origingal CID font for everything else.
6146      * The problem is that GhostScript still (as of 8.13) does not support
6147      * rearranged fonts even though they have been documented by Adobe for 7
6148      * years!  If they ever do, a lot of this code will disappear.
6149      */
6150     if (prt_use_courier)
6151     {
6152         in_ascii = (len == 1 && *p < 0x80);
6153         if (prt_in_ascii)
6154         {
6155             if (!in_ascii)
6156             {
6157                 /* No longer in ASCII range - need to switch font */
6158                 prt_in_ascii = FALSE;
6159                 prt_need_font = TRUE;
6160                 prt_attribute_change = TRUE;
6161             }
6162         }
6163         else if (in_ascii)
6164         {
6165             /* Now in ASCII range - need to switch font */
6166             prt_in_ascii = TRUE;
6167             prt_need_font = TRUE;
6168             prt_attribute_change = TRUE;
6169         }
6170     }
6171     if (prt_out_mbyte)
6172     {
6173         half_width = ((*mb_ptr2cells)(p) == 1);
6174         if (half_width)
6175             char_width /= 2;
6176         if (prt_half_width)
6177         {
6178             if (!half_width)
6179             {
6180                 prt_half_width = FALSE;
6181                 prt_pos_x += prt_char_width/4;
6182                 prt_need_moveto = TRUE;
6183                 prt_attribute_change = TRUE;
6184             }
6185         }
6186         else if (half_width)
6187         {
6188             prt_half_width = TRUE;
6189             prt_pos_x += prt_char_width/4;
6190             prt_need_moveto = TRUE;
6191             prt_attribute_change = TRUE;
6192         }
6193     }
6194 #endif
6195 
6196     /* Output any required changes to the graphics state, after flushing any
6197      * text buffered so far.
6198      */
6199     if (prt_attribute_change)
6200     {
6201 	prt_flush_buffer();
6202 	/* Reset count of number of chars that will be printed */
6203 	prt_text_run = 0;
6204 
6205 	if (prt_need_moveto)
6206 	{
6207 	    prt_pos_x_moveto = prt_pos_x;
6208 	    prt_pos_y_moveto = prt_pos_y;
6209 	    prt_do_moveto = TRUE;
6210 
6211 	    prt_need_moveto = FALSE;
6212 	}
6213 	if (prt_need_font)
6214 	{
6215 #ifdef FEAT_MBYTE
6216             if (!prt_in_ascii)
6217                 prt_write_string("CF");
6218             else
6219 #endif
6220                 prt_write_string("F");
6221             prt_write_int(prt_font);
6222             prt_write_string("sf\n");
6223             prt_need_font = FALSE;
6224 	}
6225 	if (prt_need_fgcol)
6226 	{
6227 	    int     r, g, b;
6228 	    r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
6229 	    g = ((unsigned)prt_fgcol & 0xff00) >> 8;
6230 	    b = prt_fgcol & 0xff;
6231 
6232 	    prt_write_real(r / 255.0, 3);
6233 	    if (r == g && g == b)
6234 		prt_write_string("g\n");
6235 	    else
6236 	    {
6237 		prt_write_real(g / 255.0, 3);
6238 		prt_write_real(b / 255.0, 3);
6239 		prt_write_string("r\n");
6240 	    }
6241 	    prt_need_fgcol = FALSE;
6242 	}
6243 
6244 	if (prt_bgcol != PRCOLOR_WHITE)
6245 	{
6246 	    prt_new_bgcol = prt_bgcol;
6247 	    if (prt_need_bgcol)
6248 		prt_do_bgcol = TRUE;
6249 	}
6250 	else
6251 	    prt_do_bgcol = FALSE;
6252 	prt_need_bgcol = FALSE;
6253 
6254 	if (prt_need_underline)
6255 	    prt_do_underline = prt_underline;
6256 	prt_need_underline = FALSE;
6257 
6258 	prt_attribute_change = FALSE;
6259     }
6260 
6261 #ifdef FEAT_MBYTE
6262     if (prt_do_conv)
6263     {
6264 	/* Convert from multi-byte to 8-bit encoding */
6265 	p = string_convert(&prt_conv, p, &len);
6266 	if (p == NULL)
6267 	    p = (char_u *)"";
6268     }
6269 
6270     if (prt_out_mbyte)
6271     {
6272         /* Multi-byte character strings are represented more efficiently as hex
6273          * strings when outputting clean 8 bit PS.
6274          */
6275         do
6276         {
6277            ch = prt_hexchar[(*p) >> 4];
6278            ga_append(&prt_ps_buffer, ch);
6279            ch = prt_hexchar[(*p) & 0xf];
6280            ga_append(&prt_ps_buffer, ch);
6281            p++;
6282         }
6283         while (--len);
6284     }
6285     else
6286 #endif
6287     {
6288         /* Add next character to buffer of characters to output.
6289          * Note: One printed character may require several PS characters to
6290          * represent it, but we only count them as one printed character.
6291          */
6292         ch = *p;
6293         if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
6294         {
6295             /* Convert non-printing characters to either their escape or octal
6296              * sequence, ensures PS sent over a serial line does not interfere
6297              * with the comms protocol.  Note: For EBCDIC we need to write out
6298              * the escape sequences as ASCII codes!
6299 	     * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
6300 	     */
6301             ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
6302             switch (ch)
6303             {
6304                 case BS:   ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
6305                 case TAB:  ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
6306                 case NL:   ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
6307                 case FF:   ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
6308                 case CAR:  ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
6309                 case '(':  ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
6310                 case ')':  ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
6311                 case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
6312 
6313                 default:
6314                            sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
6315 #ifdef EBCDIC
6316                            ebcdic2ascii(ch_buff, 3);
6317 #endif
6318                            ga_append(&prt_ps_buffer, ch_buff[0]);
6319                            ga_append(&prt_ps_buffer, ch_buff[1]);
6320                            ga_append(&prt_ps_buffer, ch_buff[2]);
6321                            break;
6322             }
6323         }
6324         else
6325             ga_append(&prt_ps_buffer, ch);
6326     }
6327 
6328 #ifdef FEAT_MBYTE
6329     /* Need to free any translated characters */
6330     if (prt_do_conv && (*p != NUL))
6331 	vim_free(p);
6332 #endif
6333 
6334     prt_text_run += char_width;
6335     prt_pos_x += char_width;
6336 
6337     /* The downside of fp - use relative error on right margin check */
6338     next_pos = prt_pos_x + prt_char_width;
6339     need_break = (next_pos > prt_right_margin) &&
6340                     ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
6341 
6342     if (need_break)
6343 	prt_flush_buffer();
6344 
6345     return need_break;
6346 }
6347 
6348     void
6349 mch_print_set_font(iBold, iItalic, iUnderline)
6350     int		iBold;
6351     int		iItalic;
6352     int		iUnderline;
6353 {
6354     int		font = 0;
6355 
6356     if (iBold)
6357 	font |= 0x01;
6358     if (iItalic)
6359 	font |= 0x02;
6360 
6361     if (font != prt_font)
6362     {
6363 	prt_font = font;
6364 	prt_attribute_change = TRUE;
6365 	prt_need_font = TRUE;
6366     }
6367     if (prt_underline != iUnderline)
6368     {
6369 	prt_underline = iUnderline;
6370 	prt_attribute_change = TRUE;
6371 	prt_need_underline = TRUE;
6372     }
6373 }
6374 
6375     void
6376 mch_print_set_bg(bgcol)
6377     long_u	bgcol;
6378 {
6379     prt_bgcol = bgcol;
6380     prt_attribute_change = TRUE;
6381     prt_need_bgcol = TRUE;
6382 }
6383 
6384     void
6385 mch_print_set_fg(fgcol)
6386     long_u	fgcol;
6387 {
6388     if (fgcol != (long_u)prt_fgcol)
6389     {
6390 	prt_fgcol = fgcol;
6391 	prt_attribute_change = TRUE;
6392 	prt_need_fgcol = TRUE;
6393     }
6394 }
6395 
6396 # endif /*FEAT_POSTSCRIPT*/
6397 #endif /*FEAT_PRINTER*/
6398 
6399 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6400 	&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
6401 static char *get_locale_val __ARGS((int what));
6402 
6403     static char *
6404 get_locale_val(what)
6405     int		what;
6406 {
6407     char	*loc;
6408 
6409     /* Obtain the locale value from the libraries.  For DJGPP this is
6410      * redefined and it doesn't use the arguments. */
6411     loc = setlocale(what, NULL);
6412 
6413 # if defined(__BORLANDC__)
6414     if (loc != NULL)
6415     {
6416 	char_u	*p;
6417 
6418 	/* Borland returns something like "LC_CTYPE=<name>\n"
6419 	 * Let's try to fix that bug here... */
6420 	p = vim_strchr(loc, '=');
6421 	if (p != NULL)
6422 	{
6423 	    loc = ++p;
6424 	    while (*p != NUL)	/* remove trailing newline */
6425 	    {
6426 		if (*p < ' ')
6427 		{
6428 		    *p = NUL;
6429 		    break;
6430 		}
6431 		++p;
6432 	    }
6433 	}
6434     }
6435 # endif
6436 
6437     return loc;
6438 }
6439 #endif
6440 
6441 
6442 #ifdef WIN32
6443 /*
6444  * On MS-Windows locale names are strings like "German_Germany.1252", but
6445  * gettext expects "de".  Try to translate one into another here for a few
6446  * supported languages.
6447  */
6448     static char_u *
6449 gettext_lang(char_u *name)
6450 {
6451     int		i;
6452     static char *(mtable[]) = {
6453 			"afrikaans",	"af",
6454 			"czech",	"cs",
6455 			"dutch",	"nl",
6456 			"german",	"de",
6457 			"english_united kingdom", "en_GB",
6458 			"spanish",	"es",
6459 			"french",	"fr",
6460 			"italian",	"it",
6461 			"japanese",	"ja",
6462 			"korean",	"ko",
6463 			"norwegian",	"no",
6464 			"polish",	"pl",
6465 			"russian",	"ru",
6466 			"slovak",	"sk",
6467 			"swedish",	"sv",
6468 			"ukrainian",	"uk",
6469 			"chinese_china", "zh_CN",
6470 			"chinese_taiwan", "zh_TW",
6471 			NULL};
6472 
6473     for (i = 0; mtable[i] != NULL; i += 2)
6474 	if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
6475 	    return mtable[i + 1];
6476     return name;
6477 }
6478 #endif
6479 
6480 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
6481 /*
6482  * Obtain the current messages language.  Used to set the default for
6483  * 'helplang'.  May return NULL or an empty string.
6484  */
6485     char_u *
6486 get_mess_lang()
6487 {
6488     char_u *p;
6489 
6490 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
6491 #  if defined(LC_MESSAGES)
6492     p = (char_u *)get_locale_val(LC_MESSAGES);
6493 #  else
6494     /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
6495      * may be set to the LCID number. */
6496     p = (char_u *)get_locale_val(LC_ALL);
6497 #  endif
6498 # else
6499     p = mch_getenv((char_u *)"LC_ALL");
6500     if (p == NULL || *p == NUL)
6501     {
6502 	p = mch_getenv((char_u *)"LC_MESSAGES");
6503 	if (p == NULL || *p == NUL)
6504 	    p = mch_getenv((char_u *)"LANG");
6505     }
6506 # endif
6507 # ifdef WIN32
6508     p = gettext_lang(p);
6509 # endif
6510     return p;
6511 }
6512 #endif
6513 
6514 #if !defined(LC_MESSAGES) \
6515     && (((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6516 		&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) \
6517 	    || defined(FEAT_EVAL))
6518 static char_u *get_mess_env __ARGS((void));
6519 
6520 /*
6521  * Get the language used for messages from the environment.
6522  */
6523     static char_u *
6524 get_mess_env()
6525 {
6526     char_u	*p;
6527 
6528     p = mch_getenv((char_u *)"LC_ALL");
6529     if (p == NULL || *p == NUL)
6530     {
6531 	p = mch_getenv((char_u *)"LC_MESSAGES");
6532 	if (p == NULL || *p == NUL)
6533 	{
6534 	    p = mch_getenv((char_u *)"LANG");
6535 	    if (p != NULL && VIM_ISDIGIT(*p))
6536 		p = NULL;		/* ignore something like "1043" */
6537 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6538 	    if (p == NULL || *p == NUL)
6539 		p = (char_u *)get_locale_val(LC_CTYPE);
6540 # endif
6541 	}
6542     }
6543     return p;
6544 }
6545 #endif
6546 
6547 #if defined(FEAT_EVAL) || defined(PROTO)
6548 
6549 /*
6550  * Set the "v:lang" variable according to the current locale setting.
6551  * Also do "v:lc_time"and "v:ctype".
6552  */
6553     void
6554 set_lang_var()
6555 {
6556     char_u	*loc;
6557 
6558 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6559     loc = (char_u *)get_locale_val(LC_CTYPE);
6560 # else
6561     /* setlocale() not supported: use the default value */
6562     loc = (char_u *)"C";
6563 # endif
6564     set_vim_var_string(VV_CTYPE, loc, -1);
6565 
6566     /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
6567      * back to LC_CTYPE if it's empty. */
6568 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
6569     loc = (char_u *)get_locale_val(LC_MESSAGES);
6570 # else
6571     loc = get_mess_env();
6572 # endif
6573     set_vim_var_string(VV_LANG, loc, -1);
6574 
6575 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
6576     loc = (char_u *)get_locale_val(LC_TIME);
6577 # endif
6578     set_vim_var_string(VV_LC_TIME, loc, -1);
6579 }
6580 #endif
6581 
6582 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
6583 	&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
6584 /*
6585  * ":language":  Set the language (locale).
6586  */
6587     void
6588 ex_language(eap)
6589     exarg_T	*eap;
6590 {
6591     char	*loc;
6592     char_u	*p;
6593     char_u	*name;
6594     int		what = LC_ALL;
6595     char	*whatstr = "";
6596 #ifdef LC_MESSAGES
6597 # define VIM_LC_MESSAGES LC_MESSAGES
6598 #else
6599 # define VIM_LC_MESSAGES 6789
6600 #endif
6601 
6602     name = eap->arg;
6603 
6604     /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
6605      * Allow abbreviation, but require at least 3 characters to avoid
6606      * confusion with a two letter language name "me" or "ct". */
6607     p = skiptowhite(eap->arg);
6608     if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
6609     {
6610 	if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
6611 	{
6612 	    what = VIM_LC_MESSAGES;
6613 	    name = skipwhite(p);
6614 	    whatstr = "messages ";
6615 	}
6616 	else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
6617 	{
6618 	    what = LC_CTYPE;
6619 	    name = skipwhite(p);
6620 	    whatstr = "ctype ";
6621 	}
6622 	else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
6623 	{
6624 	    what = LC_TIME;
6625 	    name = skipwhite(p);
6626 	    whatstr = "time ";
6627 	}
6628     }
6629 
6630     if (*name == NUL)
6631     {
6632 #ifndef LC_MESSAGES
6633 	if (what == VIM_LC_MESSAGES)
6634 	    p = get_mess_env();
6635 	else
6636 #endif
6637 	    p = (char_u *)setlocale(what, NULL);
6638 	if (p == NULL || *p == NUL)
6639 	    p = (char_u *)"Unknown";
6640 	smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
6641     }
6642     else
6643     {
6644 #ifndef LC_MESSAGES
6645 	if (what == VIM_LC_MESSAGES)
6646 	    loc = "";
6647 	else
6648 #endif
6649 	    loc = setlocale(what, (char *)name);
6650 	if (loc == NULL)
6651 	    EMSG2(_("E197: Cannot set language to \"%s\""), name);
6652 	else
6653 	{
6654 #ifdef HAVE_NL_MSG_CAT_CNTR
6655 	    /* Need to do this for GNU gettext, otherwise cached translations
6656 	     * will be used again. */
6657 	    extern int _nl_msg_cat_cntr;
6658 
6659 	    ++_nl_msg_cat_cntr;
6660 #endif
6661 	    /* Reset $LC_ALL, otherwise it would overrule everyting. */
6662 	    vim_setenv((char_u *)"LC_ALL", (char_u *)"");
6663 
6664 	    if (what != LC_TIME)
6665 	    {
6666 		/* Tell gettext() what to translate to.  It apparently doesn't
6667 		 * use the currently effective locale.  Also do this when
6668 		 * FEAT_GETTEXT isn't defined, so that shell commands use this
6669 		 * value. */
6670 		if (what == LC_ALL)
6671 		    vim_setenv((char_u *)"LANG", name);
6672 		if (what != LC_CTYPE)
6673 		{
6674 		    char_u	*mname;
6675 #ifdef WIN32
6676 		    mname = gettext_lang(name);
6677 #else
6678 		    mname = name;
6679 #endif
6680 		    vim_setenv((char_u *)"LC_MESSAGES", mname);
6681 #ifdef FEAT_MULTI_LANG
6682 		    set_helplang_default(mname);
6683 #endif
6684 		}
6685 
6686 		/* Set $LC_CTYPE, because it overrules $LANG, and
6687 		 * gtk_set_locale() calls setlocale() again.  gnome_init()
6688 		 * sets $LC_CTYPE to "en_US" (that's a bug!). */
6689 		if (what != VIM_LC_MESSAGES)
6690 		    vim_setenv((char_u *)"LC_CTYPE", name);
6691 # ifdef FEAT_GUI_GTK
6692 		/* Let GTK know what locale we're using.  Not sure this is
6693 		 * really needed... */
6694 		if (gui.in_use)
6695 		    (void)gtk_set_locale();
6696 # endif
6697 	    }
6698 
6699 # ifdef FEAT_EVAL
6700 	    /* Set v:lang, v:lc_time and v:ctype to the final result. */
6701 	    set_lang_var();
6702 # endif
6703 	}
6704     }
6705 }
6706 
6707 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
6708 /*
6709  * Function given to ExpandGeneric() to obtain the possible arguments of the
6710  * ":language" command.
6711  */
6712 /*ARGSUSED*/
6713     char_u *
6714 get_lang_arg(xp, idx)
6715     expand_T	*xp;
6716     int		idx;
6717 {
6718     if (idx == 0)
6719 	return (char_u *)"messages";
6720     if (idx == 1)
6721 	return (char_u *)"ctype";
6722     if (idx == 2)
6723 	return (char_u *)"time";
6724     return NULL;
6725 }
6726 # endif
6727 
6728 #endif
6729