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