xref: /vim-8.2.3635/src/ex_cmds2.c (revision ed20346f)
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 
379     if (ga_grow(&dbg_breakp, 1) == FAIL)
380 	return FAIL;
381     bp = &BREAKP(dbg_breakp.ga_len);
382 
383     /* Find "func" or "file". */
384     if (STRNCMP(p, "func", 4) == 0)
385 	bp->dbg_type = DBG_FUNC;
386     else if (STRNCMP(p, "file", 4) == 0)
387 	bp->dbg_type = DBG_FILE;
388     else
389     {
390 	EMSG2(_(e_invarg2), p);
391 	return FAIL;
392     }
393     p = skipwhite(p + 4);
394 
395     /* Find optional line number. */
396     if (VIM_ISDIGIT(*p))
397     {
398 	bp->dbg_lnum = getdigits(&p);
399 	p = skipwhite(p);
400     }
401     else
402 	bp->dbg_lnum = 0;
403 
404     /* Find the function or file name.  Don't accept a function name with (). */
405     if (*p == NUL
406 	    || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
407     {
408 	EMSG2(_(e_invarg2), arg);
409 	return FAIL;
410     }
411 
412     if (bp->dbg_type == DBG_FUNC)
413 	bp->dbg_name = vim_strsave(p);
414     else
415     {
416 	/* Expand the file name in the same way as do_source().  This means
417 	 * doing it twice, so that $DIR/file gets expanded when $DIR is
418 	 * "~/dir". */
419 #ifdef RISCOS
420 	q = mch_munge_fname(p);
421 #else
422 	q = expand_env_save(p);
423 #endif
424 	if (q == NULL)
425 	    return FAIL;
426 #ifdef RISCOS
427 	p = mch_munge_fname(q);
428 #else
429 	p = expand_env_save(q);
430 #endif
431 	vim_free(q);
432 	if (p == NULL)
433 	    return FAIL;
434 	bp->dbg_name = p;
435 #ifdef MACOS_CLASSIC
436 	if (bp->dbg_name != NULL)
437 	    slash_n_colon_adjust(bp->dbg_name);
438 #endif
439     }
440 
441     if (bp->dbg_name == NULL)
442 	return FAIL;
443     return OK;
444 }
445 
446 /*
447  * ":breakadd".
448  */
449     void
450 ex_breakadd(eap)
451     exarg_T	*eap;
452 {
453     struct debuggy *bp;
454     char_u	*pat;
455 
456     if (dbg_parsearg(eap->arg) == OK)
457     {
458 	bp = &BREAKP(dbg_breakp.ga_len);
459 	pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
460 	if (pat != NULL)
461 	{
462 	    bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
463 	    vim_free(pat);
464 	}
465 	if (pat == NULL || bp->dbg_prog == NULL)
466 	    vim_free(bp->dbg_name);
467 	else
468 	{
469 	    if (bp->dbg_lnum == 0)	/* default line number is 1 */
470 		bp->dbg_lnum = 1;
471 	    BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp;
472 	    --dbg_breakp.ga_room;
473 	    ++debug_tick;
474 	}
475     }
476 }
477 
478 /*
479  * ":debuggreedy".
480  */
481     void
482 ex_debuggreedy(eap)
483     exarg_T	*eap;
484 {
485     if (eap->addr_count == 0 || eap->line2 != 0)
486 	debug_greedy = TRUE;
487     else
488 	debug_greedy = FALSE;
489 }
490 
491 /*
492  * ":breakdel".
493  */
494     void
495 ex_breakdel(eap)
496     exarg_T	*eap;
497 {
498     struct debuggy *bp, *bpi;
499     int		nr;
500     int		todel = -1;
501     int		i;
502     linenr_T	best_lnum = 0;
503 
504     if (vim_isdigit(*eap->arg))
505     {
506 	/* ":breakdel {nr}" */
507 	nr = atol((char *)eap->arg);
508 	for (i = 0; i < dbg_breakp.ga_len; ++i)
509 	    if (BREAKP(i).dbg_nr == nr)
510 	    {
511 		todel = i;
512 		break;
513 	    }
514     }
515     else
516     {
517 	/* ":breakdel {func|file} [lnum] {name}" */
518 	if (dbg_parsearg(eap->arg) == FAIL)
519 	    return;
520 	bp = &BREAKP(dbg_breakp.ga_len);
521 	for (i = 0; i < dbg_breakp.ga_len; ++i)
522 	{
523 	    bpi = &BREAKP(i);
524 	    if (bp->dbg_type == bpi->dbg_type
525 		    && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
526 		    && (bp->dbg_lnum == bpi->dbg_lnum
527 			|| (bp->dbg_lnum == 0
528 			    && (best_lnum == 0
529 				|| bpi->dbg_lnum < best_lnum))))
530 	    {
531 		todel = i;
532 		best_lnum = bpi->dbg_lnum;
533 	    }
534 	}
535 	vim_free(bp->dbg_name);
536     }
537 
538     if (todel < 0)
539 	EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
540     else
541     {
542 	vim_free(BREAKP(todel).dbg_name);
543 	vim_free(BREAKP(todel).dbg_prog);
544 	--dbg_breakp.ga_len;
545 	++dbg_breakp.ga_room;
546 	if (todel < dbg_breakp.ga_len)
547 	    mch_memmove(&BREAKP(todel), &BREAKP(todel + 1),
548 		    (dbg_breakp.ga_len - todel) * sizeof(struct debuggy));
549 	++debug_tick;
550     }
551 }
552 
553 /*
554  * ":breaklist".
555  */
556 /*ARGSUSED*/
557     void
558 ex_breaklist(eap)
559     exarg_T	*eap;
560 {
561     struct debuggy *bp;
562     int		i;
563 
564     if (dbg_breakp.ga_len == 0)
565 	MSG(_("No breakpoints defined"));
566     else
567 	for (i = 0; i < dbg_breakp.ga_len; ++i)
568 	{
569 	    bp = &BREAKP(i);
570 	    smsg((char_u *)_("%3d  %s %s  line %ld"),
571 		    bp->dbg_nr,
572 		    bp->dbg_type == DBG_FUNC ? "func" : "file",
573 		    bp->dbg_name,
574 		    (long)bp->dbg_lnum);
575 	}
576 }
577 
578 /*
579  * Find a breakpoint for a function or sourced file.
580  * Returns line number at which to break; zero when no matching breakpoint.
581  */
582     linenr_T
583 dbg_find_breakpoint(file, fname, after)
584     int		file;	    /* TRUE for a file, FALSE for a function */
585     char_u	*fname;	    /* file or function name */
586     linenr_T	after;	    /* after this line number */
587 {
588     struct debuggy *bp;
589     int		i;
590     linenr_T	lnum = 0;
591     regmatch_T	regmatch;
592     char_u	*name = fname;
593     int		prev_got_int;
594 
595     /* Replace K_SNR in function name with "<SNR>". */
596     if (!file && fname[0] == K_SPECIAL)
597     {
598 	name = alloc((unsigned)STRLEN(fname) + 3);
599 	if (name == NULL)
600 	    name = fname;
601 	else
602 	{
603 	    STRCPY(name, "<SNR>");
604 	    STRCPY(name + 5, fname + 3);
605 	}
606     }
607 
608     for (i = 0; i < dbg_breakp.ga_len; ++i)
609     {
610 	/* skip entries that are not useful or are for a line that is beyond
611 	 * an already found breakpoint */
612 	bp = &BREAKP(i);
613 	if ((bp->dbg_type == DBG_FILE) == file
614 		&& bp->dbg_lnum > after
615 		&& (lnum == 0 || bp->dbg_lnum < lnum))
616 	{
617 	    regmatch.regprog = bp->dbg_prog;
618 	    regmatch.rm_ic = FALSE;
619 	    /*
620 	     * Save the value of got_int and reset it.  We don't want a previous
621 	     * interruption cancel matching, only hitting CTRL-C while matching
622 	     * should abort it.
623 	     */
624 	    prev_got_int = got_int;
625 	    got_int = FALSE;
626 	    if (vim_regexec(&regmatch, name, (colnr_T)0))
627 		lnum = bp->dbg_lnum;
628 	    got_int |= prev_got_int;
629 	}
630     }
631     if (name != fname)
632 	vim_free(name);
633 
634     return lnum;
635 }
636 
637 /*
638  * Called when a breakpoint was encountered.
639  */
640     void
641 dbg_breakpoint(name, lnum)
642     char_u	*name;
643     linenr_T	lnum;
644 {
645     /* We need to check if this line is actually executed in do_one_cmd() */
646     debug_breakpoint_name = name;
647     debug_breakpoint_lnum = lnum;
648 }
649 #endif
650 
651 /*
652  * If 'autowrite' option set, try to write the file.
653  * Careful: autocommands may make "buf" invalid!
654  *
655  * return FAIL for failure, OK otherwise
656  */
657     int
658 autowrite(buf, forceit)
659     buf_T	*buf;
660     int		forceit;
661 {
662     if (!(p_aw || p_awa) || !p_write
663 #ifdef FEAT_QUICKFIX
664 	/* never autowrite a "nofile" or "nowrite" buffer */
665 	|| bt_dontwrite(buf)
666 #endif
667 	|| (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
668 	return FAIL;
669     return buf_write_all(buf, forceit);
670 }
671 
672 /*
673  * flush all buffers, except the ones that are readonly
674  */
675     void
676 autowrite_all()
677 {
678     buf_T	*buf;
679 
680     if (!(p_aw || p_awa) || !p_write)
681 	return;
682     for (buf = firstbuf; buf; buf = buf->b_next)
683 	if (bufIsChanged(buf) && !buf->b_p_ro)
684 	{
685 	    (void)buf_write_all(buf, FALSE);
686 #ifdef FEAT_AUTOCMD
687 	    /* an autocommand may have deleted the buffer */
688 	    if (!buf_valid(buf))
689 		buf = firstbuf;
690 #endif
691 	}
692 }
693 
694 /*
695  * return TRUE if buffer was changed and cannot be abandoned.
696  */
697 /*ARGSUSED*/
698     int
699 check_changed(buf, checkaw, mult_win, forceit, allbuf)
700     buf_T	*buf;
701     int		checkaw;	/* do autowrite if buffer was changed */
702     int		mult_win;	/* check also when several wins for the buf */
703     int		forceit;
704     int		allbuf;		/* may write all buffers */
705 {
706     if (       !forceit
707 	    && bufIsChanged(buf)
708 	    && (mult_win || buf->b_nwindows <= 1)
709 	    && (!checkaw || autowrite(buf, forceit) == FAIL))
710     {
711 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
712 	if ((p_confirm || cmdmod.confirm) && p_write)
713 	{
714 	    buf_T	*buf2;
715 	    int		count = 0;
716 
717 	    if (allbuf)
718 		for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
719 		    if (bufIsChanged(buf2)
720 				     && (buf2->b_ffname != NULL
721 # ifdef FEAT_BROWSE
722 					 || cmdmod.browse
723 # endif
724 					))
725 			++count;
726 # ifdef FEAT_AUTOCMD
727 	    if (!buf_valid(buf))
728 		/* Autocommand deleted buffer, oops!  It's not changed now. */
729 		return FALSE;
730 # endif
731 	    dialog_changed(buf, count > 1);
732 # ifdef FEAT_AUTOCMD
733 	    if (!buf_valid(buf))
734 		/* Autocommand deleted buffer, oops!  It's not changed now. */
735 		return FALSE;
736 # endif
737 	    return bufIsChanged(buf);
738 	}
739 #endif
740 	EMSG(_(e_nowrtmsg));
741 	return TRUE;
742     }
743     return FALSE;
744 }
745 
746 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
747 
748 #if defined(FEAT_BROWSE) || defined(PROTO)
749 /*
750  * When wanting to write a file without a file name, ask the user for a name.
751  */
752     void
753 browse_save_fname(buf)
754     buf_T	*buf;
755 {
756     if (buf->b_fname == NULL)
757     {
758 	char_u *fname;
759 
760 	fname = do_browse(TRUE, (char_u *)_("Save As"), NULL, NULL, NULL,
761 								   NULL, buf);
762 	if (fname != NULL)
763 	{
764 	    if (setfname(buf, fname, NULL, TRUE) == OK)
765 		buf->b_flags |= BF_NOTEDITED;
766 	    vim_free(fname);
767 	}
768     }
769 }
770 #endif
771 
772 /*
773  * Ask the user what to do when abondoning a changed buffer.
774  * Must check 'write' option first!
775  */
776     void
777 dialog_changed(buf, checkall)
778     buf_T	*buf;
779     int		checkall;	/* may abandon all changed buffers */
780 {
781     char_u	buff[IOSIZE];
782     int		ret;
783     buf_T	*buf2;
784 
785     dialog_msg(buff, _("Save changes to \"%.*s\"?"),
786 			(buf->b_fname != NULL) ?
787 			buf->b_fname : (char_u *)_("Untitled"));
788     if (checkall)
789 	ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
790     else
791 	ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
792 
793     if (ret == VIM_YES)
794     {
795 #ifdef FEAT_BROWSE
796 	/* May get file name, when there is none */
797 	browse_save_fname(buf);
798 #endif
799 	if (buf->b_fname != NULL)   /* didn't hit Cancel */
800 	    (void)buf_write_all(buf, FALSE);
801     }
802     else if (ret == VIM_NO)
803     {
804 	unchanged(buf, TRUE);
805     }
806     else if (ret == VIM_ALL)
807     {
808 	/*
809 	 * Write all modified files that can be written.
810 	 * Skip readonly buffers, these need to be confirmed
811 	 * individually.
812 	 */
813 	for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
814 	{
815 	    if (bufIsChanged(buf2)
816 		    && (buf2->b_ffname != NULL
817 #ifdef FEAT_BROWSE
818 			|| cmdmod.browse
819 #endif
820 			)
821 		    && !buf2->b_p_ro)
822 	    {
823 #ifdef FEAT_BROWSE
824 		/* May get file name, when there is none */
825 		browse_save_fname(buf2);
826 #endif
827 		if (buf2->b_fname != NULL)   /* didn't hit Cancel */
828 		    (void)buf_write_all(buf2, FALSE);
829 #ifdef FEAT_AUTOCMD
830 		/* an autocommand may have deleted the buffer */
831 		if (!buf_valid(buf2))
832 		    buf2 = firstbuf;
833 #endif
834 	    }
835 	}
836     }
837     else if (ret == VIM_DISCARDALL)
838     {
839 	/*
840 	 * mark all buffers as unchanged
841 	 */
842 	for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
843 	    unchanged(buf2, TRUE);
844     }
845 }
846 #endif
847 
848 /*
849  * Return TRUE if the buffer "buf" can be abandoned, either by making it
850  * hidden, autowriting it or unloading it.
851  */
852     int
853 can_abandon(buf, forceit)
854     buf_T	*buf;
855     int		forceit;
856 {
857     return (	   P_HID(buf)
858 		|| !bufIsChanged(buf)
859 		|| buf->b_nwindows > 1
860 		|| autowrite(buf, forceit) == OK
861 		|| forceit);
862 }
863 
864 /*
865  * Return TRUE if any buffer was changed and cannot be abandoned.
866  * That changed buffer becomes the current buffer.
867  */
868     int
869 check_changed_any(hidden)
870     int		hidden;		/* Only check hidden buffers */
871 {
872     buf_T	*buf;
873     int		save;
874 #ifdef FEAT_WINDOWS
875     win_T	*wp;
876 #endif
877 
878     for (;;)
879     {
880 	/* check curbuf first: if it was changed we can't abandon it */
881 	if (!hidden && curbufIsChanged())
882 	    buf = curbuf;
883 	else
884 	{
885 	    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
886 		if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
887 		    break;
888 	}
889 	if (buf == NULL)    /* No buffers changed */
890 	    return FALSE;
891 
892 	if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf))
893 	    break;	    /* didn't save - still changes */
894     }
895 
896     exiting = FALSE;
897 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
898     /*
899      * When ":confirm" used, don't give an error message.
900      */
901     if (!(p_confirm || cmdmod.confirm))
902 #endif
903     {
904 	/* There must be a wait_return for this message, do_buffer()
905 	 * may cause a redraw.  But wait_return() is a no-op when vgetc()
906 	 * is busy (Quit used from window menu), then make sure we don't
907 	 * cause a scroll up. */
908 	if (vgetc_busy)
909 	{
910 	    msg_row = cmdline_row;
911 	    msg_col = 0;
912 	    msg_didout = FALSE;
913 	}
914 	if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
915 		    buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) :
916 		    buf->b_fname))
917 	{
918 	    save = no_wait_return;
919 	    no_wait_return = FALSE;
920 	    wait_return(FALSE);
921 	    no_wait_return = save;
922 	}
923     }
924 
925 #ifdef FEAT_WINDOWS
926     /* Try to find a window that contains the buffer. */
927     if (buf != curbuf)
928 	for (wp = firstwin; wp != NULL; wp = wp->w_next)
929 	    if (wp->w_buffer == buf)
930 	    {
931 		win_goto(wp);
932 # ifdef FEAT_AUTOCMD
933 		/* Paranoia: did autocms wipe out the buffer with changes? */
934 		if (!buf_valid(buf))
935 		    return TRUE;
936 # endif
937 		break;
938 	    }
939 #endif
940 
941     /* Open the changed buffer in the current window. */
942     if (buf != curbuf)
943 	set_curbuf(buf, DOBUF_GOTO);
944 
945     return TRUE;
946 }
947 
948 /*
949  * return FAIL if there is no file name, OK if there is one
950  * give error message for FAIL
951  */
952     int
953 check_fname()
954 {
955     if (curbuf->b_ffname == NULL)
956     {
957 	EMSG(_(e_noname));
958 	return FAIL;
959     }
960     return OK;
961 }
962 
963 /*
964  * flush the contents of a buffer, unless it has no file name
965  *
966  * return FAIL for failure, OK otherwise
967  */
968     int
969 buf_write_all(buf, forceit)
970     buf_T	*buf;
971     int		forceit;
972 {
973     int	    retval;
974 #ifdef FEAT_AUTOCMD
975     buf_T	*old_curbuf = curbuf;
976 #endif
977 
978     retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
979 				   (linenr_T)1, buf->b_ml.ml_line_count, NULL,
980 						  FALSE, forceit, TRUE, FALSE));
981 #ifdef FEAT_AUTOCMD
982     if (curbuf != old_curbuf)
983 	MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
984 #endif
985     return retval;
986 }
987 
988 /*
989  * Code to handle the argument list.
990  */
991 
992 /*
993  * Isolate one argument, taking quotes and backticks.
994  * Changes the argument in-place, puts a NUL after it.
995  * Quotes are removed, backticks remain.
996  * Return a pointer to the start of the next argument.
997  */
998     char_u *
999 do_one_arg(str)
1000     char_u *str;
1001 {
1002     char_u	*p;
1003     int		inquote;
1004     int		inbacktick;
1005 
1006     inquote = FALSE;
1007     inbacktick = FALSE;
1008     for (p = str; *str; ++str)
1009     {
1010 	/*
1011 	 * for MSDOS et.al. a backslash is part of a file name.
1012 	 * Only skip ", space and tab.
1013 	 */
1014 	if (rem_backslash(str))
1015 	{
1016 	    *p++ = *str++;
1017 	    *p++ = *str;
1018 	}
1019 	else
1020 	{
1021 	    /* An item ends at a space not in quotes or backticks */
1022 	    if (!inquote && !inbacktick && vim_isspace(*str))
1023 		break;
1024 	    if (!inquote && *str == '`')
1025 		inbacktick ^= TRUE;
1026 	    if (!inbacktick && *str == '"')
1027 		inquote ^= TRUE;
1028 	    else
1029 		*p++ = *str;
1030 	}
1031     }
1032     str = skipwhite(str);
1033     *p = NUL;
1034 
1035     return str;
1036 }
1037 
1038 static int do_arglist __ARGS((char_u *str, int what, int after));
1039 static void alist_check_arg_idx __ARGS((void));
1040 #ifdef FEAT_LISTCMDS
1041 static int alist_add_list __ARGS((int count, char_u **files, int after));
1042 #endif
1043 #define AL_SET	1
1044 #define AL_ADD	2
1045 #define AL_DEL	3
1046 
1047 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1048 /*
1049  * Redefine the argument list.
1050  */
1051     void
1052 set_arglist(str)
1053     char_u	*str;
1054 {
1055     do_arglist(str, AL_SET, 0);
1056 }
1057 #endif
1058 
1059 /*
1060  * "what" == AL_SET: Redefine the argument list to 'str'.
1061  * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1062  * "what" == AL_DEL: remove files in 'str' from the argument list.
1063  *
1064  * Return FAIL for failure, OK otherwise.
1065  */
1066 /*ARGSUSED*/
1067     static int
1068 do_arglist(str, what, after)
1069     char_u	*str;
1070     int		what;
1071     int		after;		/* 0 means before first one */
1072 {
1073     garray_T	new_ga;
1074     int		exp_count;
1075     char_u	**exp_files;
1076     int		i;
1077 #ifdef FEAT_LISTCMDS
1078     char_u	*p;
1079     int		match;
1080 #endif
1081 
1082     /*
1083      * Collect all file name arguments in "new_ga".
1084      */
1085     ga_init2(&new_ga, (int)sizeof(char_u *), 20);
1086     while (*str)
1087     {
1088 	if (ga_grow(&new_ga, 1) == FAIL)
1089 	{
1090 	    ga_clear(&new_ga);
1091 	    return FAIL;
1092 	}
1093 	((char_u **)new_ga.ga_data)[new_ga.ga_len++] = str;
1094 	--new_ga.ga_room;
1095 
1096 	/* Isolate one argument, change it in-place, put a NUL after it. */
1097 	str = do_one_arg(str);
1098     }
1099 
1100 #ifdef FEAT_LISTCMDS
1101     if (what == AL_DEL)
1102     {
1103 	regmatch_T	regmatch;
1104 	int		didone;
1105 
1106 	/*
1107 	 * Delete the items: use each item as a regexp and find a match in the
1108 	 * argument list.
1109 	 */
1110 #ifdef CASE_INSENSITIVE_FILENAME
1111 	regmatch.rm_ic = TRUE;		/* Always ignore case */
1112 #else
1113 	regmatch.rm_ic = FALSE;		/* Never ignore case */
1114 #endif
1115 	for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1116 	{
1117 	    p = ((char_u **)new_ga.ga_data)[i];
1118 	    p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1119 	    if (p == NULL)
1120 		break;
1121 	    regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1122 	    if (regmatch.regprog == NULL)
1123 	    {
1124 		vim_free(p);
1125 		break;
1126 	    }
1127 
1128 	    didone = FALSE;
1129 	    for (match = 0; match < ARGCOUNT; ++match)
1130 		if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1131 								  (colnr_T)0))
1132 		{
1133 		    didone = TRUE;
1134 		    vim_free(ARGLIST[match].ae_fname);
1135 		    mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1136 			    (ARGCOUNT - match - 1) * sizeof(aentry_T));
1137 		    --ALIST(curwin)->al_ga.ga_len;
1138 		    ++ALIST(curwin)->al_ga.ga_room;
1139 		    if (curwin->w_arg_idx > match)
1140 			--curwin->w_arg_idx;
1141 		    --match;
1142 		}
1143 
1144 	    vim_free(regmatch.regprog);
1145 	    vim_free(p);
1146 	    if (!didone)
1147 		EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1148 	}
1149 	ga_clear(&new_ga);
1150     }
1151     else
1152 #endif
1153     {
1154 	i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
1155 		&exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
1156 	ga_clear(&new_ga);
1157 	if (i == FAIL)
1158 	    return FAIL;
1159 	if (exp_count == 0)
1160 	{
1161 	    EMSG(_(e_nomatch));
1162 	    return FAIL;
1163 	}
1164 
1165 #ifdef FEAT_LISTCMDS
1166 	if (what == AL_ADD)
1167 	{
1168 	    (void)alist_add_list(exp_count, exp_files, after);
1169 	    vim_free(exp_files);
1170 	}
1171 	else /* what == AL_SET */
1172 #endif
1173 	    alist_set(ALIST(curwin), exp_count, exp_files, FALSE);
1174     }
1175 
1176     alist_check_arg_idx();
1177 
1178     return OK;
1179 }
1180 
1181 /*
1182  * Check the validity of the arg_idx for each other window.
1183  */
1184     static void
1185 alist_check_arg_idx()
1186 {
1187 #ifdef FEAT_WINDOWS
1188     win_T	*win;
1189 
1190     for (win = firstwin; win != NULL; win = win->w_next)
1191 	if (win->w_alist == curwin->w_alist)
1192 	    check_arg_idx(win);
1193 #else
1194     check_arg_idx(curwin);
1195 #endif
1196 }
1197 
1198 /*
1199  * Check if window "win" is editing the w_arg_idx file in its argument list.
1200  */
1201     void
1202 check_arg_idx(win)
1203     win_T	*win;
1204 {
1205     if (WARGCOUNT(win) > 1
1206 	    && (win->w_arg_idx >= WARGCOUNT(win)
1207 		|| (win->w_buffer->b_fnum
1208 				      != WARGLIST(win)[win->w_arg_idx].ae_fnum
1209 		    && (win->w_buffer->b_ffname == NULL
1210 			 || !(fullpathcmp(
1211 				 alist_name(&WARGLIST(win)[win->w_arg_idx]),
1212 				win->w_buffer->b_ffname, TRUE) & FPC_SAME)))))
1213     {
1214 	/* We are not editing the current entry in the argument list.
1215 	 * Set "arg_had_last" if we are editing the last one. */
1216 	win->w_arg_idx_invalid = TRUE;
1217 	if (win->w_arg_idx != WARGCOUNT(win) - 1
1218 		&& arg_had_last == FALSE
1219 #ifdef FEAT_WINDOWS
1220 		&& ALIST(win) == &global_alist
1221 #endif
1222 		&& GARGCOUNT > 0
1223 		&& win->w_arg_idx < GARGCOUNT
1224 		&& (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
1225 		    || (win->w_buffer->b_ffname != NULL
1226 			&& (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
1227 				win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
1228 	    arg_had_last = TRUE;
1229     }
1230     else
1231     {
1232 	/* We are editing the current entry in the argument list.
1233 	 * Set "arg_had_last" if it's also the last one */
1234 	win->w_arg_idx_invalid = FALSE;
1235 	if (win->w_arg_idx == WARGCOUNT(win) - 1
1236 #ifdef FEAT_WINDOWS
1237 		&& win->w_alist == &global_alist
1238 #endif
1239 		)
1240 	    arg_had_last = TRUE;
1241     }
1242 }
1243 
1244 /*
1245  * ":args", ":argslocal" and ":argsglobal".
1246  */
1247     void
1248 ex_args(eap)
1249     exarg_T	*eap;
1250 {
1251     int		i;
1252 
1253     if (eap->cmdidx != CMD_args)
1254     {
1255 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1256 	alist_unlink(ALIST(curwin));
1257 	if (eap->cmdidx == CMD_argglobal)
1258 	    ALIST(curwin) = &global_alist;
1259 	else /* eap->cmdidx == CMD_arglocal */
1260 	    alist_new();
1261 #else
1262 	ex_ni(eap);
1263 	return;
1264 #endif
1265     }
1266 
1267     if (!ends_excmd(*eap->arg))
1268     {
1269 	/*
1270 	 * ":args file ..": define new argument list, handle like ":next"
1271 	 * Also for ":argslocal file .." and ":argsglobal file ..".
1272 	 */
1273 	ex_next(eap);
1274     }
1275     else
1276 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1277 	if (eap->cmdidx == CMD_args)
1278 #endif
1279     {
1280 	/*
1281 	 * ":args": list arguments.
1282 	 */
1283 	if (ARGCOUNT > 0)
1284 	{
1285 	    /* Overwrite the command, for a short list there is no scrolling
1286 	     * required and no wait_return(). */
1287 	    gotocmdline(TRUE);
1288 	    for (i = 0; i < ARGCOUNT; ++i)
1289 	    {
1290 		if (i == curwin->w_arg_idx)
1291 		    msg_putchar('[');
1292 		msg_outtrans(alist_name(&ARGLIST[i]));
1293 		if (i == curwin->w_arg_idx)
1294 		    msg_putchar(']');
1295 		msg_putchar(' ');
1296 	    }
1297 	}
1298     }
1299 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
1300     else if (eap->cmdidx == CMD_arglocal)
1301     {
1302 	garray_T	*gap = &curwin->w_alist->al_ga;
1303 
1304 	/*
1305 	 * ":argslocal": make a local copy of the global argument list.
1306 	 */
1307 	if (ga_grow(gap, GARGCOUNT) == OK)
1308 	    for (i = 0; i < GARGCOUNT; ++i)
1309 		if (GARGLIST[i].ae_fname != NULL)
1310 		{
1311 		    AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
1312 					    vim_strsave(GARGLIST[i].ae_fname);
1313 		    AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
1314 							  GARGLIST[i].ae_fnum;
1315 		    ++gap->ga_len;
1316 		    --gap->ga_room;
1317 		}
1318     }
1319 #endif
1320 }
1321 
1322 /*
1323  * ":previous", ":sprevious", ":Next" and ":sNext".
1324  */
1325     void
1326 ex_previous(eap)
1327     exarg_T	*eap;
1328 {
1329     /* If past the last one already, go to the last one. */
1330     if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
1331 	do_argfile(eap, ARGCOUNT - 1);
1332     else
1333 	do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
1334 }
1335 
1336 /*
1337  * ":rewind", ":first", ":sfirst" and ":srewind".
1338  */
1339     void
1340 ex_rewind(eap)
1341     exarg_T	*eap;
1342 {
1343     do_argfile(eap, 0);
1344 }
1345 
1346 /*
1347  * ":last" and ":slast".
1348  */
1349     void
1350 ex_last(eap)
1351     exarg_T	*eap;
1352 {
1353     do_argfile(eap, ARGCOUNT - 1);
1354 }
1355 
1356 /*
1357  * ":argument" and ":sargument".
1358  */
1359     void
1360 ex_argument(eap)
1361     exarg_T	*eap;
1362 {
1363     int		i;
1364 
1365     if (eap->addr_count > 0)
1366 	i = eap->line2 - 1;
1367     else
1368 	i = curwin->w_arg_idx;
1369     do_argfile(eap, i);
1370 }
1371 
1372 /*
1373  * Edit file "argn" of the argument lists.
1374  */
1375     void
1376 do_argfile(eap, argn)
1377     exarg_T	*eap;
1378     int		argn;
1379 {
1380     int		other;
1381     char_u	*p;
1382 
1383     if (argn < 0 || argn >= ARGCOUNT)
1384     {
1385 	if (ARGCOUNT <= 1)
1386 	    EMSG(_("E163: There is only one file to edit"));
1387 	else if (argn < 0)
1388 	    EMSG(_("E164: Cannot go before first file"));
1389 	else
1390 	    EMSG(_("E165: Cannot go beyond last file"));
1391     }
1392     else
1393     {
1394 	setpcmark();
1395 #ifdef FEAT_GUI
1396 	need_mouse_correct = TRUE;
1397 #endif
1398 
1399 #ifdef FEAT_WINDOWS
1400 	if (*eap->cmd == 's')	    /* split window first */
1401 	{
1402 	    if (win_split(0, 0) == FAIL)
1403 		return;
1404 # ifdef FEAT_SCROLLBIND
1405 	    curwin->w_p_scb = FALSE;
1406 # endif
1407 	}
1408 	else
1409 #endif
1410 	{
1411 	    /*
1412 	     * if 'hidden' set, only check for changed file when re-editing
1413 	     * the same buffer
1414 	     */
1415 	    other = TRUE;
1416 	    if (P_HID(curbuf))
1417 	    {
1418 		p = fix_fname(alist_name(&ARGLIST[argn]));
1419 		other = otherfile(p);
1420 		vim_free(p);
1421 	    }
1422 	    if ((!P_HID(curbuf) || !other)
1423 		  && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE))
1424 		return;
1425 	}
1426 
1427 	curwin->w_arg_idx = argn;
1428 	if (argn == ARGCOUNT - 1
1429 #ifdef FEAT_WINDOWS
1430 		&& curwin->w_alist == &global_alist
1431 #endif
1432 	   )
1433 	    arg_had_last = TRUE;
1434 
1435 	/* Edit the file; always use the last known line number. */
1436 	(void)do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
1437 		      eap, ECMD_LAST,
1438 		      (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) +
1439 					   (eap->forceit ? ECMD_FORCEIT : 0));
1440 
1441 	/* like Vi: set the mark where the cursor is in the file. */
1442 	if (eap->cmdidx != CMD_argdo)
1443 	    setmark('\'');
1444     }
1445 }
1446 
1447 /*
1448  * ":next", and commands that behave like it.
1449  */
1450     void
1451 ex_next(eap)
1452     exarg_T	*eap;
1453 {
1454     int		i;
1455 
1456     /*
1457      * check for changed buffer now, if this fails the argument list is not
1458      * redefined.
1459      */
1460     if (       P_HID(curbuf)
1461 	    || eap->cmdidx == CMD_snext
1462 	    || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
1463     {
1464 	if (*eap->arg != NUL)		    /* redefine file list */
1465 	{
1466 	    if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
1467 		return;
1468 	    i = 0;
1469 	}
1470 	else
1471 	    i = curwin->w_arg_idx + (int)eap->line2;
1472 	do_argfile(eap, i);
1473     }
1474 }
1475 
1476 #ifdef FEAT_LISTCMDS
1477 /*
1478  * ":argedit"
1479  */
1480     void
1481 ex_argedit(eap)
1482     exarg_T	*eap;
1483 {
1484     int		fnum;
1485     int		i;
1486     char_u	*s;
1487 
1488     /* Add the argument to the buffer list and get the buffer number. */
1489     fnum = buflist_add(eap->arg, BLN_LISTED);
1490 
1491     /* Check if this argument is already in the argument list. */
1492     for (i = 0; i < ARGCOUNT; ++i)
1493 	if (ARGLIST[i].ae_fnum == fnum)
1494 	    break;
1495     if (i == ARGCOUNT)
1496     {
1497 	/* Can't find it, add it to the argument list. */
1498 	s = vim_strsave(eap->arg);
1499 	if (s == NULL)
1500 	    return;
1501 	i = alist_add_list(1, &s,
1502 	       eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
1503 	if (i < 0)
1504 	    return;
1505 	curwin->w_arg_idx = i;
1506     }
1507 
1508     alist_check_arg_idx();
1509 
1510     /* Edit the argument. */
1511     do_argfile(eap, i);
1512 }
1513 
1514 /*
1515  * ":argadd"
1516  */
1517     void
1518 ex_argadd(eap)
1519     exarg_T	*eap;
1520 {
1521     do_arglist(eap->arg, AL_ADD,
1522 	       eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
1523 #ifdef FEAT_TITLE
1524     maketitle();
1525 #endif
1526 }
1527 
1528 /*
1529  * ":argdelete"
1530  */
1531     void
1532 ex_argdelete(eap)
1533     exarg_T	*eap;
1534 {
1535     int		i;
1536     int		n;
1537 
1538     if (eap->addr_count > 0)
1539     {
1540 	/* ":1,4argdel": Delete all arguments in the range. */
1541 	if (eap->line2 > ARGCOUNT)
1542 	    eap->line2 = ARGCOUNT;
1543 	n = eap->line2 - eap->line1 + 1;
1544 	if (*eap->arg != NUL || n <= 0)
1545 	    EMSG(_(e_invarg));
1546 	else
1547 	{
1548 	    for (i = eap->line1; i <= eap->line2; ++i)
1549 		vim_free(ARGLIST[i - 1].ae_fname);
1550 	    mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
1551 			(size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
1552 	    ALIST(curwin)->al_ga.ga_len -= n;
1553 	    ALIST(curwin)->al_ga.ga_room += n;
1554 	    if (curwin->w_arg_idx >= eap->line2)
1555 		curwin->w_arg_idx -= n;
1556 	    else if (curwin->w_arg_idx > eap->line1)
1557 		curwin->w_arg_idx = eap->line1;
1558 	}
1559     }
1560     else if (*eap->arg == NUL)
1561 	EMSG(_(e_argreq));
1562     else
1563 	do_arglist(eap->arg, AL_DEL, 0);
1564 #ifdef FEAT_TITLE
1565     maketitle();
1566 #endif
1567 }
1568 
1569 /*
1570  * ":argdo", ":windo", ":bufdo"
1571  */
1572     void
1573 ex_listdo(eap)
1574     exarg_T	*eap;
1575 {
1576     int		i;
1577 #ifdef FEAT_WINDOWS
1578     win_T	*win;
1579 #endif
1580     buf_T	*buf;
1581     int		next_fnum = 0;
1582 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1583     char_u	*save_ei = NULL;
1584     char_u	*new_ei;
1585 #endif
1586 
1587 #ifndef FEAT_WINDOWS
1588     if (eap->cmdidx == CMD_windo)
1589     {
1590 	ex_ni(eap);
1591 	return;
1592     }
1593 #endif
1594 
1595 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1596     if (eap->cmdidx != CMD_windo)
1597     {
1598 	/* Add "Syntax" to 'eventignore' to skip loading syntax highlighting
1599 	 * for every buffer loaded into the window.  A considerable speed
1600 	 * improvement. */
1601 	save_ei = vim_strsave(p_ei);
1602 	if (save_ei != NULL)
1603 	{
1604 	    new_ei = vim_strnsave(p_ei, (int)STRLEN(p_ei) + 8);
1605 	    if (new_ei != NULL)
1606 	    {
1607 		STRCAT(new_ei, ",Syntax");
1608 		set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE);
1609 		vim_free(new_ei);
1610 	    }
1611 	}
1612     }
1613 #endif
1614 
1615     if (eap->cmdidx == CMD_windo
1616 	    || P_HID(curbuf)
1617 	    || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE))
1618     {
1619 	/* start at the first argument/window/buffer */
1620 	i = 0;
1621 #ifdef FEAT_WINDOWS
1622 	win = firstwin;
1623 #endif
1624 	/* set pcmark now */
1625 	if (eap->cmdidx == CMD_bufdo)
1626 	    goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
1627 	else
1628 	    setpcmark();
1629 	listcmd_busy = TRUE;	    /* avoids setting pcmark below */
1630 
1631 	while (!got_int)
1632 	{
1633 	    if (eap->cmdidx == CMD_argdo)
1634 	    {
1635 		/* go to argument "i" */
1636 		if (i == ARGCOUNT)
1637 		    break;
1638 		/* Don't call do_argfile() when already there, it will try
1639 		 * reloading the file. */
1640 		if (curwin->w_arg_idx != i)
1641 		    do_argfile(eap, i);
1642 		if (curwin->w_arg_idx != i)
1643 		    break;
1644 		++i;
1645 	    }
1646 #ifdef FEAT_WINDOWS
1647 	    else if (eap->cmdidx == CMD_windo)
1648 	    {
1649 		/* go to window "win" */
1650 		if (!win_valid(win))
1651 		    break;
1652 		win_goto(win);
1653 		win = win->w_next;
1654 	    }
1655 #endif
1656 	    else if (eap->cmdidx == CMD_bufdo)
1657 	    {
1658 		/* Remember the number of the next listed buffer, in case
1659 		 * ":bwipe" is used or autocommands do something strange. */
1660 		next_fnum = -1;
1661 		for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1662 		    if (buf->b_p_bl)
1663 		    {
1664 			next_fnum = buf->b_fnum;
1665 			break;
1666 		    }
1667 	    }
1668 
1669 	    /* execute the command */
1670 	    do_cmdline(eap->arg, eap->getline, eap->cookie,
1671 						DOCMD_VERBOSE + DOCMD_NOWAIT);
1672 
1673 	    if (eap->cmdidx == CMD_bufdo)
1674 	    {
1675 		/* Done? */
1676 		if (next_fnum < 0)
1677 		    break;
1678 		/* Check if the buffer still exists. */
1679 		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1680 		    if (buf->b_fnum == next_fnum)
1681 			break;
1682 		if (buf == NULL)
1683 		    break;
1684 		goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
1685 		/* If autocommands took us elsewhere, quit here */
1686 		if (curbuf->b_fnum != next_fnum)
1687 		    break;
1688 	    }
1689 
1690 	    if (eap->cmdidx == CMD_windo)
1691 	    {
1692 		validate_cursor();	/* cursor may have moved */
1693 #ifdef FEAT_SCROLLBIND
1694 		/* required when 'scrollbind' has been set */
1695 		if (curwin->w_p_scb)
1696 		    do_check_scrollbind(TRUE);
1697 #endif
1698 	    }
1699 	}
1700 	listcmd_busy = FALSE;
1701     }
1702 
1703 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
1704     if (save_ei != NULL)
1705     {
1706 	set_string_option_direct((char_u *)"ei", -1, save_ei, OPT_FREE);
1707 	apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
1708 					       curbuf->b_fname, TRUE, curbuf);
1709 	vim_free(save_ei);
1710     }
1711 #endif
1712 }
1713 
1714 /*
1715  * Add files[count] to the arglist of the current window after arg "after".
1716  * The file names in files[count] must have been allocated and are taken over.
1717  * Files[] itself is not taken over.
1718  * Returns index of first added argument.  Returns -1 when failed (out of mem).
1719  */
1720     static int
1721 alist_add_list(count, files, after)
1722     int		count;
1723     char_u	**files;
1724     int		after;	    /* where to add: 0 = before first one */
1725 {
1726     int		i;
1727 
1728     if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
1729     {
1730 	if (after < 0)
1731 	    after = 0;
1732 	if (after > ARGCOUNT)
1733 	    after = ARGCOUNT;
1734 	if (after < ARGCOUNT)
1735 	    mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
1736 				       (ARGCOUNT - after) * sizeof(aentry_T));
1737 	for (i = 0; i < count; ++i)
1738 	{
1739 	    ARGLIST[after + i].ae_fname = files[i];
1740 	    ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
1741 	}
1742 	ALIST(curwin)->al_ga.ga_len += count;
1743 	ALIST(curwin)->al_ga.ga_room -= count;
1744 	if (curwin->w_arg_idx >= after)
1745 	    ++curwin->w_arg_idx;
1746 	return after;
1747     }
1748 
1749     for (i = 0; i < count; ++i)
1750 	vim_free(files[i]);
1751     return -1;
1752 }
1753 
1754 #endif /* FEAT_LISTCMDS */
1755 
1756 #ifdef FEAT_EVAL
1757 /*
1758  * ":compiler[!] {name}"
1759  */
1760     void
1761 ex_compiler(eap)
1762     exarg_T	*eap;
1763 {
1764     char_u	*buf;
1765     char_u	*old_cur_comp = NULL;
1766     char_u	*p;
1767 
1768     if (*eap->arg == NUL)
1769     {
1770 	/* List all compiler scripts. */
1771 	do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1772 					/* ) keep the indenter happy... */
1773     }
1774     else
1775     {
1776 	buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
1777 	if (buf != NULL)
1778 	{
1779 	    if (eap->forceit)
1780 	    {
1781 		/* ":compiler! {name}" sets global options */
1782 		do_cmdline_cmd((char_u *)
1783 				   "command -nargs=* CompilerSet set <args>");
1784 	    }
1785 	    else
1786 	    {
1787 		/* ":compiler! {name}" sets local options.
1788 		 * To remain backwards compatible "current_compiler" is always
1789 		 * used.  A user's compiler plugin may set it, the distributed
1790 		 * plugin will then skip the settings.  Afterwards set
1791 		 * "b:current_compiler" and restore "current_compiler". */
1792 		old_cur_comp = get_var_value((char_u *)"current_compiler");
1793 		if (old_cur_comp != NULL)
1794 		    old_cur_comp = vim_strsave(old_cur_comp);
1795 		do_cmdline_cmd((char_u *)
1796 			      "command -nargs=* CompilerSet setlocal <args>");
1797 	    }
1798 	    do_unlet((char_u *)"current_compiler");
1799 	    do_unlet((char_u *)"b:current_compiler");
1800 
1801 	    sprintf((char *)buf, "compiler/%s.vim", eap->arg);
1802 	    if (cmd_runtime(buf, TRUE) == FAIL)
1803 		EMSG2(_("E666: compiler not supported: %s"), eap->arg);
1804 	    vim_free(buf);
1805 
1806 	    do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1807 
1808 	    /* Set "b:current_compiler" from "current_compiler". */
1809 	    p = get_var_value((char_u *)"current_compiler");
1810 	    if (p != NULL)
1811 		set_internal_string_var((char_u *)"b:current_compiler", p);
1812 
1813 	    /* Restore "current_compiler" for ":compiler {name}". */
1814 	    if (!eap->forceit)
1815 	    {
1816 		if (old_cur_comp != NULL)
1817 		{
1818 		    set_internal_string_var((char_u *)"current_compiler",
1819 								old_cur_comp);
1820 		    vim_free(old_cur_comp);
1821 		}
1822 		else
1823 		    do_unlet((char_u *)"current_compiler");
1824 	    }
1825 	}
1826     }
1827 }
1828 #endif
1829 
1830 /*
1831  * ":runtime {name}"
1832  */
1833     void
1834 ex_runtime(eap)
1835     exarg_T	*eap;
1836 {
1837     cmd_runtime(eap->arg, eap->forceit);
1838 }
1839 
1840 static void source_callback __ARGS((char_u *fname));
1841 
1842     static void
1843 source_callback(fname)
1844     char_u	*fname;
1845 {
1846     (void)do_source(fname, FALSE, FALSE);
1847 }
1848 
1849 /*
1850  * Source the file "name" from all directories in 'runtimepath'.
1851  * "name" can contain wildcards.
1852  * When "all" is TRUE, source all files, otherwise only the first one.
1853  * return FAIL when no file could be sourced, OK otherwise.
1854  */
1855     int
1856 cmd_runtime(name, all)
1857     char_u	*name;
1858     int		all;
1859 {
1860     return do_in_runtimepath(name, all, source_callback);
1861 }
1862 
1863 /*
1864  * Find "name" in 'runtimepath'.  When found, call the "callback" function for
1865  * it.
1866  * When "all" is TRUE repeat for all matches, otherwise only the first one is
1867  * used.
1868  * Returns OK when at least one match found, FAIL otherwise.
1869  */
1870     int
1871 do_in_runtimepath(name, all, callback)
1872     char_u	*name;
1873     int		all;
1874     void	(*callback)__ARGS((char_u *fname));
1875 {
1876     char_u	*rtp;
1877     char_u	*np;
1878     char_u	*buf;
1879     char_u	*rtp_copy;
1880     char_u	*tail;
1881     int		num_files;
1882     char_u	**files;
1883     int		i;
1884     int		did_one = FALSE;
1885 #ifdef AMIGA
1886     struct Process	*proc = (struct Process *)FindTask(0L);
1887     APTR		save_winptr = proc->pr_WindowPtr;
1888 
1889     /* Avoid a requester here for a volume that doesn't exist. */
1890     proc->pr_WindowPtr = (APTR)-1L;
1891 #endif
1892 
1893     /* Make a copy of 'runtimepath'.  Invoking the callback may change the
1894      * value. */
1895     rtp_copy = vim_strsave(p_rtp);
1896     buf = alloc(MAXPATHL);
1897     if (buf != NULL && rtp_copy != NULL)
1898     {
1899 	if (p_verbose > 1)
1900 	    smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
1901 						 (char *)name, (char *)p_rtp);
1902 	/* Loop over all entries in 'runtimepath'. */
1903 	rtp = rtp_copy;
1904 	while (*rtp != NUL && (all || !did_one))
1905 	{
1906 	    /* Copy the path from 'runtimepath' to buf[]. */
1907 	    copy_option_part(&rtp, buf, MAXPATHL, ",");
1908 	    if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
1909 	    {
1910 		add_pathsep(buf);
1911 		tail = buf + STRLEN(buf);
1912 
1913 		/* Loop over all patterns in "name" */
1914 		np = name;
1915 		while (*np != NUL && (all || !did_one))
1916 		{
1917 		    /* Append the pattern from "name" to buf[]. */
1918 		    copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
1919 								       "\t ");
1920 
1921 		    if (p_verbose > 2)
1922 			msg_str((char_u *)_("Searching for \"%s\""), buf);
1923 
1924 		    /* Expand wildcards, invoke the callback for each match. */
1925 		    if (gen_expand_wildcards(1, &buf, &num_files, &files,
1926 							       EW_FILE) == OK)
1927 		    {
1928 			for (i = 0; i < num_files; ++i)
1929 			{
1930 			    (*callback)(files[i]);
1931 			    did_one = TRUE;
1932 			    if (!all)
1933 				break;
1934 			}
1935 			FreeWild(num_files, files);
1936 		    }
1937 		}
1938 	    }
1939 	}
1940     }
1941     vim_free(buf);
1942     vim_free(rtp_copy);
1943     if (p_verbose > 0 && !did_one)
1944 	msg_str((char_u *)_("not found in 'runtimepath': \"%s\""), name);
1945 
1946 #ifdef AMIGA
1947     proc->pr_WindowPtr = save_winptr;
1948 #endif
1949 
1950     return did_one ? OK : FAIL;
1951 }
1952 
1953 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
1954 /*
1955  * ":options"
1956  */
1957 /*ARGSUSED*/
1958     void
1959 ex_options(eap)
1960     exarg_T	*eap;
1961 {
1962     cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
1963 }
1964 #endif
1965 
1966 /*
1967  * ":source {fname}"
1968  */
1969     void
1970 ex_source(eap)
1971     exarg_T	*eap;
1972 {
1973 #ifdef FEAT_BROWSE
1974     if (cmdmod.browse)
1975     {
1976 	char_u *fname = NULL;
1977 
1978 	fname = do_browse(FALSE, (char_u *)_("Source Vim script"), eap->arg,
1979 				      NULL, NULL, BROWSE_FILTER_MACROS, NULL);
1980 	if (fname != NULL)
1981 	{
1982 	    cmd_source(fname, eap);
1983 	    vim_free(fname);
1984 	}
1985     }
1986     else
1987 #endif
1988 	cmd_source(eap->arg, eap);
1989 }
1990 
1991     static void
1992 cmd_source(fname, eap)
1993     char_u	*fname;
1994     exarg_T	*eap;
1995 {
1996     if (*fname == NUL)
1997 	EMSG(_(e_argreq));
1998 
1999     /* ":source!" read vi commands */
2000     else if (eap != NULL && eap->forceit)
2001 	/* Need to execute the commands directly when:
2002 	 * - ":g" command busy
2003 	 * - after ":argdo", ":windo" or ":bufdo"
2004 	 * - another command follows
2005 	 * - inside a loop
2006 	 */
2007 	openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2008 #ifdef FEAT_EVAL
2009 						 || eap->cstack->cs_idx >= 0
2010 #endif
2011 						 );
2012 
2013     /* ":source" read ex commands */
2014     else if (do_source(fname, FALSE, FALSE) == FAIL)
2015 	EMSG2(_(e_notopen), fname);
2016 }
2017 
2018 /*
2019  * ":source" and associated commands.
2020  */
2021 /*
2022  * Structure used to store info for each sourced file.
2023  * It is shared between do_source() and getsourceline().
2024  * This is required, because it needs to be handed to do_cmdline() and
2025  * sourcing can be done recursively.
2026  */
2027 struct source_cookie
2028 {
2029     FILE	*fp;		/* opened file for sourcing */
2030     char_u      *nextline;      /* if not NULL: line that was read ahead */
2031     int		finished;	/* ":finish" used */
2032 #if defined (USE_CRNL) || defined (USE_CR)
2033     int		fileformat;	/* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2034     int		error;		/* TRUE if LF found after CR-LF */
2035 #endif
2036 #ifdef FEAT_EVAL
2037     linenr_T	breakpoint;	/* next line with breakpoint or zero */
2038     char_u	*fname;		/* name of sourced file */
2039     int		dbg_tick;	/* debug_tick when breakpoint was set */
2040     int		level;		/* top nesting level of sourced file */
2041 #endif
2042 #ifdef FEAT_MBYTE
2043     vimconv_T	conv;		/* type of conversion */
2044 #endif
2045 };
2046 
2047 #ifdef FEAT_EVAL
2048 /*
2049  * Return the address holding the next breakpoint line for a source cookie.
2050  */
2051     linenr_T *
2052 source_breakpoint(cookie)
2053     void *cookie;
2054 {
2055     return &((struct source_cookie *)cookie)->breakpoint;
2056 }
2057 
2058 /*
2059  * Return the address holding the debug tick for a source cookie.
2060  */
2061     int *
2062 source_dbg_tick(cookie)
2063     void *cookie;
2064 {
2065     return &((struct source_cookie *)cookie)->dbg_tick;
2066 }
2067 
2068 /*
2069  * Return the nesting level for a source cookie.
2070  */
2071     int
2072 source_level(cookie)
2073     void *cookie;
2074 {
2075     return ((struct source_cookie *)cookie)->level;
2076 }
2077 #endif
2078 
2079 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2080 
2081 #ifdef FEAT_EVAL
2082 /* Growarray to store the names of sourced scripts.
2083  * For Unix also store the dev/ino, so that we don't have to stat() each
2084  * script when going through the list. */
2085 struct scriptstuff
2086 {
2087     char_u	*name;
2088 # ifdef UNIX
2089     int		dev;
2090     ino_t	ino;
2091 # endif
2092 };
2093 static garray_T script_names = {0, 0, sizeof(struct scriptstuff), 4, NULL};
2094 #define SCRIPT_NAME(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].name)
2095 #define SCRIPT_DEV(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].dev)
2096 #define SCRIPT_INO(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].ino)
2097 #endif
2098 
2099 #if defined(WIN32) && defined(FEAT_CSCOPE)
2100 static FILE *fopen_noinh_readbin __ARGS((char *filename));
2101 
2102 /*
2103  * Special function to open a file without handle inheritance.
2104  */
2105     static FILE *
2106 fopen_noinh_readbin(filename)
2107     char    *filename;
2108 {
2109     int	fd_tmp = open(filename, O_RDONLY | O_BINARY | O_NOINHERIT);
2110 
2111     if (fd_tmp == -1)
2112 	return NULL;
2113     return fdopen(fd_tmp, READBIN);
2114 }
2115 #endif
2116 
2117 
2118 /*
2119  * do_source: Read the file "fname" and execute its lines as EX commands.
2120  *
2121  * This function may be called recursively!
2122  *
2123  * return FAIL if file could not be opened, OK otherwise
2124  */
2125     int
2126 do_source(fname, check_other, is_vimrc)
2127     char_u	*fname;
2128     int		check_other;	    /* check for .vimrc and _vimrc */
2129     int		is_vimrc;	    /* call vimrc_found() when file exists */
2130 {
2131     struct source_cookie    cookie;
2132     char_u		    *save_sourcing_name;
2133     linenr_T		    save_sourcing_lnum;
2134     char_u		    *p;
2135     char_u		    *fname_exp;
2136     int			    retval = FAIL;
2137 #ifdef FEAT_EVAL
2138     scid_T		    save_current_SID;
2139     static scid_T	    last_current_SID = 0;
2140     void		    *save_funccalp;
2141     int			    save_debug_break_level = debug_break_level;
2142 # ifdef UNIX
2143     struct stat		    st;
2144     int			    stat_ok;
2145 # endif
2146 #endif
2147 #ifdef STARTUPTIME
2148     struct timeval	    tv_rel;
2149     struct timeval	    tv_start;
2150 #endif
2151 
2152 #ifdef RISCOS
2153     p = mch_munge_fname(fname);
2154 #else
2155     p = expand_env_save(fname);
2156 #endif
2157     if (p == NULL)
2158 	return retval;
2159     fname_exp = fix_fname(p);
2160     vim_free(p);
2161     if (fname_exp == NULL)
2162 	return retval;
2163 #ifdef MACOS_CLASSIC
2164     slash_n_colon_adjust(fname_exp);
2165 #endif
2166     if (mch_isdir(fname_exp))
2167     {
2168 	msg_str((char_u *)_("Cannot source a directory: \"%s\""), fname);
2169 	goto theend;
2170     }
2171 
2172 #if defined(WIN32) && defined(FEAT_CSCOPE)
2173     cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2174 #else
2175     cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2176 #endif
2177     if (cookie.fp == NULL && check_other)
2178     {
2179 	/*
2180 	 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
2181 	 * and ".exrc" by "_exrc" or vice versa.
2182 	 */
2183 	p = gettail(fname_exp);
2184 	if ((*p == '.' || *p == '_')
2185 		&& (STRICMP(p + 1, "vimrc") == 0
2186 		    || STRICMP(p + 1, "gvimrc") == 0
2187 		    || STRICMP(p + 1, "exrc") == 0))
2188 	{
2189 	    if (*p == '_')
2190 		*p = '.';
2191 	    else
2192 		*p = '_';
2193 #if defined(WIN32) && defined(FEAT_CSCOPE)
2194 	    cookie.fp = fopen_noinh_readbin((char *)fname_exp);
2195 #else
2196 	    cookie.fp = mch_fopen((char *)fname_exp, READBIN);
2197 #endif
2198 	}
2199     }
2200 
2201     if (cookie.fp == NULL)
2202     {
2203 	if (p_verbose > 0)
2204 	{
2205 	    if (sourcing_name == NULL)
2206 		msg_str((char_u *)_("could not source \"%s\""), fname);
2207 	    else
2208 		smsg((char_u *)_("line %ld: could not source \"%s\""),
2209 			sourcing_lnum, fname);
2210 	}
2211 	goto theend;
2212     }
2213 
2214     /*
2215      * The file exists.
2216      * - In verbose mode, give a message.
2217      * - For a vimrc file, may want to set 'compatible', call vimrc_found().
2218      */
2219     if (p_verbose > 1)
2220     {
2221 	if (sourcing_name == NULL)
2222 	    msg_str((char_u *)_("sourcing \"%s\""), fname);
2223 	else
2224 	    smsg((char_u *)_("line %ld: sourcing \"%s\""),
2225 		    sourcing_lnum, fname);
2226     }
2227     if (is_vimrc)
2228 	vimrc_found();
2229 
2230 #ifdef USE_CRNL
2231     /* If no automatic file format: Set default to CR-NL. */
2232     if (*p_ffs == NUL)
2233 	cookie.fileformat = EOL_DOS;
2234     else
2235 	cookie.fileformat = EOL_UNKNOWN;
2236     cookie.error = FALSE;
2237 #endif
2238 
2239 #ifdef USE_CR
2240     /* If no automatic file format: Set default to CR. */
2241     if (*p_ffs == NUL)
2242 	cookie.fileformat = EOL_MAC;
2243     else
2244 	cookie.fileformat = EOL_UNKNOWN;
2245     cookie.error = FALSE;
2246 #endif
2247 
2248     cookie.nextline = NULL;
2249     cookie.finished = FALSE;
2250 
2251 #ifdef FEAT_EVAL
2252     /*
2253      * Check if this script has a breakpoint.
2254      */
2255     cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
2256     cookie.fname = fname_exp;
2257     cookie.dbg_tick = debug_tick;
2258 
2259     cookie.level = ex_nesting_level;
2260 #endif
2261 #ifdef FEAT_MBYTE
2262     cookie.conv.vc_type = CONV_NONE;		/* no conversion */
2263 
2264     /* Try reading the first few bytes to check for a UTF-8 BOM. */
2265     {
2266 	char_u	    buf[3];
2267 
2268 	if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp)
2269 								  == (size_t)3
2270 		&& buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
2271 	    /* Found BOM, setup conversion and skip over it. */
2272 	    convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
2273 	else
2274 	    /* No BOM found, rewind. */
2275 	    fseek(cookie.fp, 0L, SEEK_SET);
2276     }
2277 #endif
2278 
2279     /*
2280      * Keep the sourcing name/lnum, for recursive calls.
2281      */
2282     save_sourcing_name = sourcing_name;
2283     sourcing_name = fname_exp;
2284     save_sourcing_lnum = sourcing_lnum;
2285     sourcing_lnum = 0;
2286 
2287 #ifdef STARTUPTIME
2288     time_push(&tv_rel, &tv_start);
2289 #endif
2290 
2291 #ifdef FEAT_EVAL
2292     /*
2293      * Check if this script was sourced before to finds its SID.
2294      * If it's new, generate a new SID.
2295      */
2296     save_current_SID = current_SID;
2297 # ifdef UNIX
2298     stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
2299 # endif
2300     for (current_SID = script_names.ga_len; current_SID > 0; --current_SID)
2301 	if (SCRIPT_NAME(current_SID) != NULL
2302 		&& (
2303 # ifdef UNIX
2304 		    /* compare dev/ino when possible, it catches symbolic
2305 		     * links */
2306 		    (stat_ok && SCRIPT_DEV(current_SID) != -1)
2307 			? (SCRIPT_DEV(current_SID) == st.st_dev
2308 			    && SCRIPT_INO(current_SID) == st.st_ino) :
2309 # endif
2310 		fnamecmp(SCRIPT_NAME(current_SID), fname_exp) == 0))
2311 	    break;
2312     if (current_SID == 0)
2313     {
2314 	current_SID = ++last_current_SID;
2315 	if (ga_grow(&script_names, (int)(current_SID - script_names.ga_len))
2316 									== OK)
2317 	{
2318 	    while (script_names.ga_len < current_SID)
2319 	    {
2320 		SCRIPT_NAME(script_names.ga_len + 1) = NULL;
2321 		++script_names.ga_len;
2322 		--script_names.ga_room;
2323 	    }
2324 	    SCRIPT_NAME(current_SID) = fname_exp;
2325 # ifdef UNIX
2326 	    if (stat_ok)
2327 	    {
2328 		SCRIPT_DEV(current_SID) = st.st_dev;
2329 		SCRIPT_INO(current_SID) = st.st_ino;
2330 	    }
2331 	    else
2332 		SCRIPT_DEV(current_SID) = -1;
2333 # endif
2334 	    fname_exp = NULL;
2335 	}
2336 	/* Allocate the local script variables to use for this script. */
2337 	new_script_vars(current_SID);
2338     }
2339 
2340     /* Don't use local function variables, if called from a function */
2341     save_funccalp = save_funccal();
2342 #endif
2343 
2344     /*
2345      * Call do_cmdline, which will call getsourceline() to get the lines.
2346      */
2347     do_cmdline(NULL, getsourceline, (void *)&cookie,
2348 				     DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
2349 
2350     retval = OK;
2351     fclose(cookie.fp);
2352     vim_free(cookie.nextline);
2353 #ifdef FEAT_MBYTE
2354     convert_setup(&cookie.conv, NULL, NULL);
2355 #endif
2356 
2357     if (got_int)
2358 	EMSG(_(e_interr));
2359     sourcing_name = save_sourcing_name;
2360     sourcing_lnum = save_sourcing_lnum;
2361 #ifdef FEAT_EVAL
2362     current_SID = save_current_SID;
2363     restore_funccal(save_funccalp);
2364 #endif
2365     if (p_verbose > 1)
2366     {
2367 	msg_str((char_u *)_("finished sourcing %s"), fname);
2368 	if (sourcing_name != NULL)
2369 	    msg_str((char_u *)_("continuing in %s"), sourcing_name);
2370     }
2371 #ifdef STARTUPTIME
2372 # ifdef HAVE_SNPRINTF
2373     snprintf(IObuff, IOSIZE, "sourcing %s", fname);
2374 # else
2375     sprintf(IObuff, "sourcing %s", fname);
2376 # endif
2377     time_msg(IObuff, &tv_start);
2378     time_pop(&tv_rel);
2379 #endif
2380 
2381 #ifdef FEAT_EVAL
2382     /*
2383      * After a "finish" in debug mode, need to break at first command of next
2384      * sourced file.
2385      */
2386     if (save_debug_break_level > ex_nesting_level
2387 	    && debug_break_level == ex_nesting_level)
2388 	++debug_break_level;
2389 #endif
2390 
2391 theend:
2392     vim_free(fname_exp);
2393     return retval;
2394 }
2395 
2396 #if defined(FEAT_EVAL) || defined(PROTO)
2397 /*
2398  * ":scriptnames"
2399  */
2400 /*ARGSUSED*/
2401     void
2402 ex_scriptnames(eap)
2403     exarg_T	*eap;
2404 {
2405     int i;
2406 
2407     for (i = 1; i <= script_names.ga_len && !got_int; ++i)
2408 	if (SCRIPT_NAME(i) != NULL)
2409 	    smsg((char_u *)"%3d: %s", i, SCRIPT_NAME(i));
2410 }
2411 
2412 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
2413 /*
2414  * Fix slashes in the list of script names for 'shellslash'.
2415  */
2416     void
2417 scriptnames_slash_adjust()
2418 {
2419     int i;
2420 
2421     for (i = 1; i <= script_names.ga_len; ++i)
2422 	if (SCRIPT_NAME(i) != NULL)
2423 	    slash_adjust(SCRIPT_NAME(i));
2424 }
2425 # endif
2426 
2427 /*
2428  * Get a pointer to a script name.  Used for ":verbose set".
2429  */
2430     char_u *
2431 get_scriptname(id)
2432     scid_T	id;
2433 {
2434     if (id == SID_MODELINE)
2435 	return (char_u *)"modeline";
2436     if (id == SID_CMDARG)
2437 	return (char_u *)"--cmd argument";
2438     if (id == SID_CARG)
2439 	return (char_u *)"-c argument";
2440     if (id == SID_ENV)
2441 	return (char_u *)"environment variable";
2442     return SCRIPT_NAME(id);
2443 }
2444 #endif
2445 
2446 #if defined(USE_CR) || defined(PROTO)
2447 
2448 # if defined(__MSL__) && (__MSL__ >= 22)
2449 /*
2450  * Newer version of the Metrowerks library handle DOS and UNIX files
2451  * without help.
2452  * Test with earlier versions, MSL 2.2 is the library supplied with
2453  * Codewarrior Pro 2.
2454  */
2455     char *
2456 fgets_cr(s, n, stream)
2457     char	*s;
2458     int		n;
2459     FILE	*stream;
2460 {
2461     return fgets(s, n, stream);
2462 }
2463 # else
2464 /*
2465  * Version of fgets() which also works for lines ending in a <CR> only
2466  * (Macintosh format).
2467  * For older versions of the Metrowerks library.
2468  * At least CodeWarrior 9 needed this code.
2469  */
2470     char *
2471 fgets_cr(s, n, stream)
2472     char	*s;
2473     int		n;
2474     FILE	*stream;
2475 {
2476     int	c = 0;
2477     int char_read = 0;
2478 
2479     while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
2480     {
2481 	c = fgetc(stream);
2482 	s[char_read++] = c;
2483 	/* If the file is in DOS format, we need to skip a NL after a CR.  I
2484 	 * thought it was the other way around, but this appears to work... */
2485 	if (c == '\n')
2486 	{
2487 	    c = fgetc(stream);
2488 	    if (c != '\r')
2489 		ungetc(c, stream);
2490 	}
2491     }
2492 
2493     s[char_read] = 0;
2494     if (char_read == 0)
2495 	return NULL;
2496 
2497     if (feof(stream) && char_read == 1)
2498 	return NULL;
2499 
2500     return s;
2501 }
2502 # endif
2503 #endif
2504 
2505 /*
2506  * Get one full line from a sourced file.
2507  * Called by do_cmdline() when it's called from do_source().
2508  *
2509  * Return a pointer to the line in allocated memory.
2510  * Return NULL for end-of-file or some error.
2511  */
2512 /* ARGSUSED */
2513     char_u *
2514 getsourceline(c, cookie, indent)
2515     int		c;		/* not used */
2516     void	*cookie;
2517     int		indent;		/* not used */
2518 {
2519     struct source_cookie *sp = (struct source_cookie *)cookie;
2520     char_u		*line;
2521     char_u		*p, *s;
2522 
2523 #ifdef FEAT_EVAL
2524     /* If breakpoints have been added/deleted need to check for it. */
2525     if (sp->dbg_tick < debug_tick)
2526     {
2527 	sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2528 	sp->dbg_tick = debug_tick;
2529     }
2530 #endif
2531     /*
2532      * Get current line.  If there is a read-ahead line, use it, otherwise get
2533      * one now.
2534      */
2535     if (sp->finished)
2536 	line = NULL;
2537     else if (sp->nextline == NULL)
2538 	line = get_one_sourceline(sp);
2539     else
2540     {
2541 	line = sp->nextline;
2542 	sp->nextline = NULL;
2543 	++sourcing_lnum;
2544     }
2545 
2546     /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
2547      * contain the 'C' flag. */
2548     if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
2549     {
2550 	/* compensate for the one line read-ahead */
2551 	--sourcing_lnum;
2552 	for (;;)
2553 	{
2554 	    sp->nextline = get_one_sourceline(sp);
2555 	    if (sp->nextline == NULL)
2556 		break;
2557 	    p = skipwhite(sp->nextline);
2558 	    if (*p != '\\')
2559 		break;
2560 	    s = alloc((int)(STRLEN(line) + STRLEN(p)));
2561 	    if (s == NULL)	/* out of memory */
2562 		break;
2563 	    STRCPY(s, line);
2564 	    STRCAT(s, p + 1);
2565 	    vim_free(line);
2566 	    line = s;
2567 	    vim_free(sp->nextline);
2568 	}
2569     }
2570 
2571 #ifdef FEAT_MBYTE
2572     if (line != NULL && sp->conv.vc_type != CONV_NONE)
2573     {
2574 	/* Convert the encoding of the script line. */
2575 	s = string_convert(&sp->conv, line, NULL);
2576 	if (s != NULL)
2577 	{
2578 	    vim_free(line);
2579 	    line = s;
2580 	}
2581     }
2582 #endif
2583 
2584 #ifdef FEAT_EVAL
2585     /* Did we encounter a breakpoint? */
2586     if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
2587     {
2588 	dbg_breakpoint(sp->fname, sourcing_lnum);
2589 	/* Find next breakpoint. */
2590 	sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
2591 	sp->dbg_tick = debug_tick;
2592     }
2593 #endif
2594 
2595     return line;
2596 }
2597 
2598     static char_u *
2599 get_one_sourceline(sp)
2600     struct source_cookie    *sp;
2601 {
2602     garray_T		ga;
2603     int			len;
2604     int			c;
2605     char_u		*buf;
2606 #ifdef USE_CRNL
2607     int			has_cr;		/* CR-LF found */
2608 #endif
2609 #ifdef USE_CR
2610     char_u		*scan;
2611 #endif
2612     int			have_read = FALSE;
2613 
2614     /* use a growarray to store the sourced line */
2615     ga_init2(&ga, 1, 200);
2616 
2617     /*
2618      * Loop until there is a finished line (or end-of-file).
2619      */
2620     sourcing_lnum++;
2621     for (;;)
2622     {
2623 	/* make room to read at least 80 (more) characters */
2624 	if (ga_grow(&ga, 80) == FAIL)
2625 	    break;
2626 	buf = (char_u *)ga.ga_data;
2627 
2628 #ifdef USE_CR
2629 	if (sp->fileformat == EOL_MAC)
2630 	{
2631 	    if (fgets_cr((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
2632 		break;
2633 	}
2634 	else
2635 #endif
2636 	    if (fgets((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL)
2637 		break;
2638 	len = (int)STRLEN(buf);
2639 #ifdef USE_CRNL
2640 	/* Ignore a trailing CTRL-Z, when in Dos mode.	Only recognize the
2641 	 * CTRL-Z by its own, or after a NL. */
2642 	if (	   (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
2643 		&& sp->fileformat == EOL_DOS
2644 		&& buf[len - 1] == Ctrl_Z)
2645 	{
2646 	    buf[len - 1] = NUL;
2647 	    break;
2648 	}
2649 #endif
2650 
2651 #ifdef USE_CR
2652 	/* If the read doesn't stop on a new line, and there's
2653 	 * some CR then we assume a Mac format */
2654 	if (sp->fileformat == EOL_UNKNOWN)
2655 	{
2656 	    if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
2657 		sp->fileformat = EOL_MAC;
2658 	    else
2659 		sp->fileformat = EOL_UNIX;
2660 	}
2661 
2662 	if (sp->fileformat == EOL_MAC)
2663 	{
2664 	    scan = vim_strchr(buf, '\r');
2665 
2666 	    if (scan != NULL)
2667 	    {
2668 		*scan = '\n';
2669 		if (*(scan + 1) != 0)
2670 		{
2671 		    *(scan + 1) = 0;
2672 		    fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
2673 		}
2674 	    }
2675 	    len = STRLEN(buf);
2676 	}
2677 #endif
2678 
2679 	have_read = TRUE;
2680 	ga.ga_room -= len - ga.ga_len;
2681 	ga.ga_len = len;
2682 
2683 	/* If the line was longer than the buffer, read more. */
2684 	if (ga.ga_room == 1 && buf[len - 1] != '\n')
2685 	    continue;
2686 
2687 	if (len >= 1 && buf[len - 1] == '\n')	/* remove trailing NL */
2688 	{
2689 #ifdef USE_CRNL
2690 	    has_cr = (len >= 2 && buf[len - 2] == '\r');
2691 	    if (sp->fileformat == EOL_UNKNOWN)
2692 	    {
2693 		if (has_cr)
2694 		    sp->fileformat = EOL_DOS;
2695 		else
2696 		    sp->fileformat = EOL_UNIX;
2697 	    }
2698 
2699 	    if (sp->fileformat == EOL_DOS)
2700 	    {
2701 		if (has_cr)	    /* replace trailing CR */
2702 		{
2703 		    buf[len - 2] = '\n';
2704 		    --len;
2705 		    --ga.ga_len;
2706 		    ++ga.ga_room;
2707 		}
2708 		else	    /* lines like ":map xx yy^M" will have failed */
2709 		{
2710 		    if (!sp->error)
2711 			EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
2712 		    sp->error = TRUE;
2713 		    sp->fileformat = EOL_UNIX;
2714 		}
2715 	    }
2716 #endif
2717 	    /* The '\n' is escaped if there is an odd number of ^V's just
2718 	     * before it, first set "c" just before the 'V's and then check
2719 	     * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
2720 	    for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
2721 		;
2722 	    if ((len & 1) != (c & 1))	/* escaped NL, read more */
2723 	    {
2724 		sourcing_lnum++;
2725 		continue;
2726 	    }
2727 
2728 	    buf[len - 1] = NUL;		/* remove the NL */
2729 	}
2730 
2731 	/*
2732 	 * Check for ^C here now and then, so recursive :so can be broken.
2733 	 */
2734 	line_breakcheck();
2735 	break;
2736     }
2737 
2738     if (have_read)
2739 	return (char_u *)ga.ga_data;
2740 
2741     vim_free(ga.ga_data);
2742     return NULL;
2743 }
2744 
2745 /*
2746  * ":scriptencoding": Set encoding conversion for a sourced script.
2747  * Without the multi-byte feature it's simply ignored.
2748  */
2749 /*ARGSUSED*/
2750     void
2751 ex_scriptencoding(eap)
2752     exarg_T	*eap;
2753 {
2754 #ifdef FEAT_MBYTE
2755     struct source_cookie	*sp;
2756     char_u			*name;
2757 
2758     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
2759     {
2760 	EMSG(_("E167: :scriptencoding used outside of a sourced file"));
2761 	return;
2762     }
2763 
2764     if (*eap->arg != NUL)
2765     {
2766 	name = enc_canonize(eap->arg);
2767 	if (name == NULL)	/* out of memory */
2768 	    return;
2769     }
2770     else
2771 	name = eap->arg;
2772 
2773     /* Setup for conversion from the specified encoding to 'encoding'. */
2774     sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
2775     convert_setup(&sp->conv, name, p_enc);
2776 
2777     if (name != eap->arg)
2778 	vim_free(name);
2779 #endif
2780 }
2781 
2782 #if defined(FEAT_EVAL) || defined(PROTO)
2783 /*
2784  * ":finish": Mark a sourced file as finished.
2785  */
2786     void
2787 ex_finish(eap)
2788     exarg_T	*eap;
2789 {
2790     if (getline_equal(eap->getline, eap->cookie, getsourceline))
2791 	do_finish(eap, FALSE);
2792     else
2793 	EMSG(_("E168: :finish used outside of a sourced file"));
2794 }
2795 
2796 /*
2797  * Mark a sourced file as finished.  Possibly makes the ":finish" pending.
2798  * Also called for a pending finish at the ":endtry" or after returning from
2799  * an extra do_cmdline().  "reanimate" is used in the latter case.
2800  */
2801     void
2802 do_finish(eap, reanimate)
2803     exarg_T	*eap;
2804     int		reanimate;
2805 {
2806     int		idx;
2807 
2808     if (reanimate)
2809 	((struct source_cookie *)getline_cookie(eap->getline,
2810 					      eap->cookie))->finished = FALSE;
2811 
2812     /*
2813      * Cleanup (and inactivate) conditionals, but stop when a try conditional
2814      * not in its finally clause (which then is to be executed next) is found.
2815      * In this case, make the ":finish" pending for execution at the ":endtry".
2816      * Otherwise, finish normally.
2817      */
2818     idx = cleanup_conditionals(eap->cstack, 0, TRUE);
2819     if (idx >= 0)
2820     {
2821 	eap->cstack->cs_pending[idx] = CSTP_FINISH;
2822 	report_make_pending(CSTP_FINISH, NULL);
2823     }
2824     else
2825 	((struct source_cookie *)getline_cookie(eap->getline,
2826 					       eap->cookie))->finished = TRUE;
2827 }
2828 
2829 
2830 /*
2831  * Return TRUE when a sourced file had the ":finish" command: Don't give error
2832  * message for missing ":endif".
2833  * Return FALSE when not sourcing a file.
2834  */
2835     int
2836 source_finished(getline, cookie)
2837     char_u	*(*getline) __ARGS((int, void *, int));
2838     void	*cookie;
2839 {
2840     return (getline_equal(getline, cookie, getsourceline)
2841 	    && ((struct source_cookie *)getline_cookie(
2842 						 getline, cookie))->finished);
2843 }
2844 #endif
2845 
2846 #if defined(FEAT_LISTCMDS) || defined(PROTO)
2847 /*
2848  * ":checktime [buffer]"
2849  */
2850     void
2851 ex_checktime(eap)
2852     exarg_T	*eap;
2853 {
2854     buf_T	*buf;
2855     int		save_no_check_timestamps = no_check_timestamps;
2856 
2857     no_check_timestamps = 0;
2858     if (eap->addr_count == 0)	/* default is all buffers */
2859 	check_timestamps(FALSE);
2860     else
2861     {
2862 	buf = buflist_findnr((int)eap->line2);
2863 	if (buf != NULL)	/* cannot happen? */
2864 	    (void)buf_check_timestamp(buf, FALSE);
2865     }
2866     no_check_timestamps = save_no_check_timestamps;
2867 }
2868 #endif
2869 
2870 #if defined(FEAT_PRINTER) || defined(PROTO)
2871 /*
2872  * Printing code (Machine-independent.)
2873  * To implement printing on a platform, the following functions must be
2874  * defined:
2875  *
2876  * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
2877  * Called once.  Code should display printer dialogue (if appropriate) and
2878  * determine printer font and margin settings.  Reset has_color if the printer
2879  * doesn't support colors at all.
2880  * Returns FAIL to abort.
2881  *
2882  * int mch_print_begin(prt_settings_T *settings)
2883  * Called to start the print job.
2884  * Return FALSE to abort.
2885  *
2886  * int mch_print_begin_page(char_u *msg)
2887  * Called at the start of each page.
2888  * "msg" indicates the progress of the print job, can be NULL.
2889  * Return FALSE to abort.
2890  *
2891  * int mch_print_end_page()
2892  * Called at the end of each page.
2893  * Return FALSE to abort.
2894  *
2895  * int mch_print_blank_page()
2896  * Called to generate a blank page for collated, duplex, multiple copy
2897  * document.  Return FALSE to abort.
2898  *
2899  * void mch_print_end(prt_settings_T *psettings)
2900  * Called at normal end of print job.
2901  *
2902  * void mch_print_cleanup()
2903  * Called if print job ends normally or is abandoned. Free any memory, close
2904  * devices and handles.  Also called when mch_print_begin() fails, but not
2905  * when mch_print_init() fails.
2906  *
2907  * void mch_print_set_font(int Bold, int Italic, int Underline);
2908  * Called whenever the font style changes.
2909  *
2910  * void mch_print_set_bg(long bgcol);
2911  * Called to set the background color for the following text. Parameter is an
2912  * RGB value.
2913  *
2914  * void mch_print_set_fg(long fgcol);
2915  * Called to set the foreground color for the following text. Parameter is an
2916  * RGB value.
2917  *
2918  * mch_print_start_line(int margin, int page_line)
2919  * Sets the current position at the start of line "page_line".
2920  * If margin is TRUE start in the left margin (for header and line number).
2921  *
2922  * int mch_print_text_out(char_u *p, int len);
2923  * Output one character of text p[len] at the current position.
2924  * Return TRUE if there is no room for another character in the same line.
2925  *
2926  * Note that the generic code has no idea of margins. The machine code should
2927  * simply make the page look smaller!  The header and the line numbers are
2928  * printed in the margin.
2929  */
2930 
2931 #ifdef FEAT_SYN_HL
2932 static const long_u  cterm_color_8[8] =
2933 {
2934     (long_u)0x000000L, (long_u)0xff0000L, (long_u)0x00ff00L, (long_u)0xffff00L,
2935     (long_u)0x0000ffL, (long_u)0xff00ffL, (long_u)0x00ffffL, (long_u)0xffffffL
2936 };
2937 
2938 static const long_u  cterm_color_16[16] =
2939 {
2940     (long_u)0x000000L, (long_u)0x0000c0L, (long_u)0x008000L, (long_u)0x004080L,
2941     (long_u)0xc00000L, (long_u)0xc000c0L, (long_u)0x808000L, (long_u)0xc0c0c0L,
2942     (long_u)0x808080L, (long_u)0x6060ffL, (long_u)0x00ff00L, (long_u)0x00ffffL,
2943     (long_u)0xff8080L, (long_u)0xff40ffL, (long_u)0xffff00L, (long_u)0xffffffL
2944 };
2945 
2946 static int		current_syn_id;
2947 #endif
2948 
2949 #define PRCOLOR_BLACK	(long_u)0
2950 #define PRCOLOR_WHITE	(long_u)0xFFFFFFL
2951 
2952 static int	curr_italic;
2953 static int	curr_bold;
2954 static int	curr_underline;
2955 static long_u	curr_bg;
2956 static long_u	curr_fg;
2957 static int	page_count;
2958 
2959 /*
2960  * These values determine the print position on a page.
2961  */
2962 typedef struct
2963 {
2964     int		lead_spaces;	    /* remaining spaces for a TAB */
2965     int		print_pos;	    /* virtual column for computing TABs */
2966     colnr_T	column;		    /* byte column */
2967     linenr_T	file_line;	    /* line nr in the buffer */
2968     long_u	bytes_printed;	    /* bytes printed so far */
2969     int		ff;		    /* seen form feed character */
2970 } prt_pos_T;
2971 
2972 #ifdef FEAT_SYN_HL
2973 static long_u darken_rgb __ARGS((long_u rgb));
2974 static long_u prt_get_term_color __ARGS((int colorindex));
2975 #endif
2976 static void prt_set_fg __ARGS((long_u fg));
2977 static void prt_set_bg __ARGS((long_u bg));
2978 static void prt_set_font __ARGS((int bold, int italic, int underline));
2979 static void prt_line_number __ARGS((prt_settings_T *psettings, int page_line, linenr_T lnum));
2980 static void prt_header __ARGS((prt_settings_T *psettings, int pagenum, linenr_T lnum));
2981 static void prt_message __ARGS((char_u *s));
2982 static colnr_T hardcopy_line __ARGS((prt_settings_T *psettings, int page_line, prt_pos_T *ppos));
2983 static void prt_get_attr __ARGS((int hl_id, prt_text_attr_T* pattr, int modec));
2984 
2985 #ifdef FEAT_SYN_HL
2986 /*
2987  * If using a dark background, the colors will probably be too bright to show
2988  * up well on white paper, so reduce their brightness.
2989  */
2990     static long_u
2991 darken_rgb(rgb)
2992     long_u	rgb;
2993 {
2994     return	((rgb >> 17) << 16)
2995 	    +	(((rgb & 0xff00) >> 9) << 8)
2996 	    +	((rgb & 0xff) >> 1);
2997 }
2998 
2999     static long_u
3000 prt_get_term_color(colorindex)
3001     int	    colorindex;
3002 {
3003     /* TODO: Should check for xterm with 88 or 256 colors. */
3004     if (t_colors > 8)
3005 	return cterm_color_16[colorindex % 16];
3006     return cterm_color_8[colorindex % 8];
3007 }
3008 
3009     static void
3010 prt_get_attr(hl_id, pattr, modec)
3011     int			hl_id;
3012     prt_text_attr_T*	pattr;
3013     int			modec;
3014 {
3015     int     colorindex;
3016     long_u  fg_color;
3017     long_u  bg_color;
3018     char    *color;
3019 
3020     pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
3021     pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
3022     pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
3023 
3024 # ifdef FEAT_GUI
3025     if (gui.in_use)
3026     {
3027 	bg_color = highlight_gui_color_rgb(hl_id, FALSE);
3028 	if (bg_color == PRCOLOR_BLACK)
3029 	    bg_color = PRCOLOR_WHITE;
3030 
3031 	fg_color = highlight_gui_color_rgb(hl_id, TRUE);
3032     }
3033     else
3034 # endif
3035     {
3036 	bg_color = PRCOLOR_WHITE;
3037 
3038 	color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
3039 	if (color == NULL)
3040 	    colorindex = 0;
3041 	else
3042 	    colorindex = atoi(color);
3043 
3044 	if (colorindex >= 0 && colorindex < t_colors)
3045 	    fg_color = prt_get_term_color(colorindex);
3046 	else
3047 	    fg_color = PRCOLOR_BLACK;
3048     }
3049 
3050     if (fg_color == PRCOLOR_WHITE)
3051 	fg_color = PRCOLOR_BLACK;
3052     else if (*p_bg == 'd')
3053 	fg_color = darken_rgb(fg_color);
3054 
3055     pattr->fg_color = fg_color;
3056     pattr->bg_color = bg_color;
3057 }
3058 #endif /* FEAT_SYN_HL */
3059 
3060     static void
3061 prt_set_fg(fg)
3062     long_u fg;
3063 {
3064     if (fg != curr_fg)
3065     {
3066 	curr_fg = fg;
3067 	mch_print_set_fg(fg);
3068     }
3069 }
3070 
3071     static void
3072 prt_set_bg(bg)
3073     long_u bg;
3074 {
3075     if (bg != curr_bg)
3076     {
3077 	curr_bg = bg;
3078 	mch_print_set_bg(bg);
3079     }
3080 }
3081 
3082     static void
3083 prt_set_font(bold, italic, underline)
3084     int		bold;
3085     int		italic;
3086     int		underline;
3087 {
3088     if (curr_bold != bold
3089 	    || curr_italic != italic
3090 	    || curr_underline != underline)
3091     {
3092 	curr_underline = underline;
3093 	curr_italic = italic;
3094 	curr_bold = bold;
3095 	mch_print_set_font(bold, italic, underline);
3096     }
3097 }
3098 
3099 /*
3100  * Print the line number in the left margin.
3101  */
3102     static void
3103 prt_line_number(psettings, page_line, lnum)
3104     prt_settings_T *psettings;
3105     int		page_line;
3106     linenr_T	lnum;
3107 {
3108     int		i;
3109     char_u	tbuf[20];
3110 
3111     prt_set_fg(psettings->number.fg_color);
3112     prt_set_bg(psettings->number.bg_color);
3113     prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
3114     mch_print_start_line(TRUE, page_line);
3115 
3116     /* Leave two spaces between the number and the text; depends on
3117      * PRINT_NUMBER_WIDTH. */
3118     sprintf((char *)tbuf, "%6ld", (long)lnum);
3119     for (i = 0; i < 6; i++)
3120 	(void)mch_print_text_out(&tbuf[i], 1);
3121 
3122 #ifdef FEAT_SYN_HL
3123     if (psettings->do_syntax)
3124 	/* Set colors for next character. */
3125 	current_syn_id = -1;
3126     else
3127 #endif
3128     {
3129 	/* Set colors and font back to normal. */
3130 	prt_set_fg(PRCOLOR_BLACK);
3131 	prt_set_bg(PRCOLOR_WHITE);
3132 	prt_set_font(FALSE, FALSE, FALSE);
3133     }
3134 }
3135 
3136 static linenr_T printer_page_num;
3137 
3138     int
3139 get_printer_page_num()
3140 {
3141     return printer_page_num;
3142 }
3143 
3144 /*
3145  * Get the currently effective header height.
3146  */
3147     int
3148 prt_header_height()
3149 {
3150     if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
3151 	return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
3152     return 2;
3153 }
3154 
3155 /*
3156  * Return TRUE if using a line number for printing.
3157  */
3158     int
3159 prt_use_number()
3160 {
3161     return (printer_opts[OPT_PRINT_NUMBER].present
3162 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
3163 }
3164 
3165 /*
3166  * Return the unit used in a margin item in 'printoptions'.
3167  * Returns PRT_UNIT_NONE if not recognized.
3168  */
3169     int
3170 prt_get_unit(idx)
3171     int		idx;
3172 {
3173     int		u = PRT_UNIT_NONE;
3174     int		i;
3175     static char *(units[4]) = PRT_UNIT_NAMES;
3176 
3177     if (printer_opts[idx].present)
3178 	for (i = 0; i < 4; ++i)
3179 	    if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
3180 	    {
3181 		u = i;
3182 		break;
3183 	    }
3184     return u;
3185 }
3186 
3187 /*
3188  * Print the page header.
3189  */
3190 /*ARGSUSED*/
3191     static void
3192 prt_header(psettings, pagenum, lnum)
3193     prt_settings_T  *psettings;
3194     int		pagenum;
3195     linenr_T	lnum;
3196 {
3197     int		width = psettings->chars_per_line;
3198     int		page_line;
3199     char_u	*tbuf;
3200     char_u	*p;
3201 #ifdef FEAT_MBYTE
3202     int		l;
3203 #endif
3204 
3205     /* Also use the space for the line number. */
3206     if (prt_use_number())
3207 	width += PRINT_NUMBER_WIDTH;
3208 
3209     tbuf = alloc(width + IOSIZE);
3210     if (tbuf == NULL)
3211 	return;
3212 
3213 #ifdef FEAT_STL_OPT
3214     if (*p_header != NUL)
3215     {
3216 	linenr_T	tmp_lnum, tmp_topline, tmp_botline;
3217 
3218 	/*
3219 	 * Need to (temporarily) set current line number and first/last line
3220 	 * number on the 'window'.  Since we don't know how long the page is,
3221 	 * set the first and current line number to the top line, and guess
3222 	 * that the page length is 64.
3223 	 */
3224 	tmp_lnum = curwin->w_cursor.lnum;
3225 	tmp_topline = curwin->w_topline;
3226 	tmp_botline = curwin->w_botline;
3227 	curwin->w_cursor.lnum = lnum;
3228 	curwin->w_topline = lnum;
3229 	curwin->w_botline = lnum + 63;
3230 	printer_page_num = pagenum;
3231 
3232 	build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE),
3233 						  p_header, ' ', width, NULL);
3234 
3235 	/* Reset line numbers */
3236 	curwin->w_cursor.lnum = tmp_lnum;
3237 	curwin->w_topline = tmp_topline;
3238 	curwin->w_botline = tmp_botline;
3239     }
3240     else
3241 #endif
3242 	sprintf((char *)tbuf, _("Page %d"), pagenum);
3243 
3244     prt_set_fg(PRCOLOR_BLACK);
3245     prt_set_bg(PRCOLOR_WHITE);
3246     prt_set_font(TRUE, FALSE, FALSE);
3247 
3248     /* Use a negative line number to indicate printing in the top margin. */
3249     page_line = 0 - prt_header_height();
3250     mch_print_start_line(TRUE, page_line);
3251     for (p = tbuf; *p != NUL; )
3252     {
3253 	if (mch_print_text_out(p,
3254 #ifdef FEAT_MBYTE
3255 		(l = (*mb_ptr2len_check)(p))
3256 #else
3257 		1
3258 #endif
3259 		    ))
3260 	{
3261 	    ++page_line;
3262 	    if (page_line >= 0) /* out of room in header */
3263 		break;
3264 	    mch_print_start_line(TRUE, page_line);
3265 	}
3266 #ifdef FEAT_MBYTE
3267 	p += l;
3268 #else
3269 	p++;
3270 #endif
3271     }
3272 
3273     vim_free(tbuf);
3274 
3275 #ifdef FEAT_SYN_HL
3276     if (psettings->do_syntax)
3277 	/* Set colors for next character. */
3278 	current_syn_id = -1;
3279     else
3280 #endif
3281     {
3282 	/* Set colors and font back to normal. */
3283 	prt_set_fg(PRCOLOR_BLACK);
3284 	prt_set_bg(PRCOLOR_WHITE);
3285 	prt_set_font(FALSE, FALSE, FALSE);
3286     }
3287 }
3288 
3289 /*
3290  * Display a print status message.
3291  */
3292     static void
3293 prt_message(s)
3294     char_u	*s;
3295 {
3296     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
3297     screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R));
3298     out_flush();
3299 }
3300 
3301     void
3302 ex_hardcopy(eap)
3303     exarg_T	*eap;
3304 {
3305     linenr_T		lnum;
3306     int			collated_copies, uncollated_copies;
3307     prt_settings_T	settings;
3308     long_u		bytes_to_print = 0;
3309     int			page_line;
3310     int			jobsplit;
3311     int			id;
3312 
3313     memset(&settings, 0, sizeof(prt_settings_T));
3314     settings.has_color = TRUE;
3315 
3316 # ifdef FEAT_POSTSCRIPT
3317     if (*eap->arg == '>')
3318     {
3319 	char_u	*errormsg = NULL;
3320 
3321 	/* Expand things like "%.ps". */
3322 	if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
3323 	{
3324 	    if (errormsg != NULL)
3325 		EMSG(errormsg);
3326 	    return;
3327 	}
3328 	settings.outfile = skipwhite(eap->arg + 1);
3329     }
3330     else if (*eap->arg != NUL)
3331 	settings.arguments = eap->arg;
3332 # endif
3333 
3334     /*
3335      * Initialise for printing.  Ask the user for settings, unless forceit is
3336      * set.
3337      * The mch_print_init() code should set up margins if applicable. (It may
3338      * not be a real printer - for example the engine might generate HTML or
3339      * PS.)
3340      */
3341     if (mch_print_init(&settings,
3342 			curbuf->b_fname == NULL
3343 			    ? (char_u *)buf_spname(curbuf)
3344 			    : curbuf->b_sfname == NULL
3345 				? curbuf->b_fname
3346 				: curbuf->b_sfname,
3347 			eap->forceit) == FAIL)
3348 	return;
3349 
3350 #ifdef FEAT_SYN_HL
3351 # ifdef  FEAT_GUI
3352     if (gui.in_use)
3353 	settings.modec = 'g';
3354     else
3355 # endif
3356 	if (t_colors > 1)
3357 	    settings.modec = 'c';
3358 	else
3359 	    settings.modec = 't';
3360 
3361     if (!syntax_present(curbuf))
3362 	settings.do_syntax = FALSE;
3363     else if (printer_opts[OPT_PRINT_SYNTAX].present
3364 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
3365 	settings.do_syntax =
3366 	       (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
3367     else
3368 	settings.do_syntax = settings.has_color;
3369 #endif
3370 
3371     /* Set up printing attributes for line numbers */
3372     settings.number.fg_color = PRCOLOR_BLACK;
3373     settings.number.bg_color = PRCOLOR_WHITE;
3374     settings.number.bold = FALSE;
3375     settings.number.italic = TRUE;
3376     settings.number.underline = FALSE;
3377 #ifdef FEAT_SYN_HL
3378     /*
3379      * Syntax highlighting of line numbers.
3380      */
3381     if (prt_use_number() && settings.do_syntax)
3382     {
3383 	id = syn_name2id((char_u *)"LineNr");
3384 	if (id > 0)
3385 	    id = syn_get_final_id(id);
3386 
3387 	prt_get_attr(id, &settings.number, settings.modec);
3388     }
3389 #endif /* FEAT_SYN_HL */
3390 
3391     /*
3392      * Estimate the total lines to be printed
3393      */
3394     for (lnum = eap->line1; lnum <= eap->line2; lnum++)
3395 	bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
3396     if (bytes_to_print == 0)
3397     {
3398 	MSG(_("No text to be printed"));
3399 	goto print_fail_no_begin;
3400     }
3401 
3402     /* Set colors and font to normal. */
3403     curr_bg = (long_u)0xffffffffL;
3404     curr_fg = (long_u)0xffffffffL;
3405     curr_italic = MAYBE;
3406     curr_bold = MAYBE;
3407     curr_underline = MAYBE;
3408 
3409     prt_set_fg(PRCOLOR_BLACK);
3410     prt_set_bg(PRCOLOR_WHITE);
3411     prt_set_font(FALSE, FALSE, FALSE);
3412 #ifdef FEAT_SYN_HL
3413     current_syn_id = -1;
3414 #endif
3415 
3416     jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
3417 	   && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
3418 
3419     if (!mch_print_begin(&settings))
3420 	goto print_fail_no_begin;
3421 
3422     /*
3423      * Loop over collated copies: 1 2 3, 1 2 3, ...
3424      */
3425     page_count = 0;
3426     for (collated_copies = 0;
3427 	    collated_copies < settings.n_collated_copies;
3428 	    collated_copies++)
3429     {
3430 	prt_pos_T	prtpos;		/* current print position */
3431 	prt_pos_T	page_prtpos;	/* print position at page start */
3432 	int		side;
3433 
3434 	memset(&page_prtpos, 0, sizeof(prt_pos_T));
3435 	page_prtpos.file_line = eap->line1;
3436 	prtpos = page_prtpos;
3437 
3438 	if (jobsplit && collated_copies > 0)
3439 	{
3440 	    /* Splitting jobs: Stop a previous job and start a new one. */
3441 	    mch_print_end(&settings);
3442 	    if (!mch_print_begin(&settings))
3443 		goto print_fail_no_begin;
3444 	}
3445 
3446 	/*
3447 	 * Loop over all pages in the print job: 1 2 3 ...
3448 	 */
3449 	for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
3450 	{
3451 	    /*
3452 	     * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
3453 	     * For duplex: 12 12 12 34 34 34, ...
3454 	     */
3455 	    for (uncollated_copies = 0;
3456 		    uncollated_copies < settings.n_uncollated_copies;
3457 		    uncollated_copies++)
3458 	    {
3459 		/* Set the print position to the start of this page. */
3460 		prtpos = page_prtpos;
3461 
3462 		/*
3463 		 * Do front and rear side of a page.
3464 		 */
3465 		for (side = 0; side <= settings.duplex; ++side)
3466 		{
3467 		    /*
3468 		     * Print one page.
3469 		     */
3470 
3471 		    /* Check for interrupt character every page. */
3472 		    ui_breakcheck();
3473 		    if (got_int || settings.user_abort)
3474 			goto print_fail;
3475 
3476 		    sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
3477 			    page_count + 1 + side,
3478 			    prtpos.bytes_printed > 1000000
3479 				? (int)(prtpos.bytes_printed /
3480 						       (bytes_to_print / 100))
3481 				: (int)((prtpos.bytes_printed * 100)
3482 							   / bytes_to_print));
3483 		    if (!mch_print_begin_page(IObuff))
3484 			goto print_fail;
3485 
3486 		    if (settings.n_collated_copies > 1)
3487 			sprintf((char *)IObuff + STRLEN(IObuff),
3488 				_(" Copy %d of %d"),
3489 				collated_copies + 1,
3490 				settings.n_collated_copies);
3491 		    prt_message(IObuff);
3492 
3493 		    /*
3494 		     * Output header if required
3495 		     */
3496 		    if (prt_header_height() > 0)
3497 			prt_header(&settings, page_count + 1 + side,
3498 							prtpos.file_line);
3499 
3500 		    for (page_line = 0; page_line < settings.lines_per_page;
3501 								  ++page_line)
3502 		    {
3503 			prtpos.column = hardcopy_line(&settings,
3504 							   page_line, &prtpos);
3505 			if (prtpos.column == 0)
3506 			{
3507 			    /* finished a file line */
3508 			    prtpos.bytes_printed +=
3509 				  STRLEN(skipwhite(ml_get(prtpos.file_line)));
3510 			    if (++prtpos.file_line > eap->line2)
3511 				break; /* reached the end */
3512 			}
3513 			else if (prtpos.ff)
3514 			{
3515 			    /* Line had a formfeed in it - start new page but
3516 			     * stay on the current line */
3517 			    break;
3518 			}
3519 		    }
3520 
3521 		    if (!mch_print_end_page())
3522 			goto print_fail;
3523 		    if (prtpos.file_line > eap->line2)
3524 			break; /* reached the end */
3525 		}
3526 
3527 		/*
3528 		 * Extra blank page for duplexing with odd number of pages and
3529 		 * more copies to come.
3530 		 */
3531 		if (prtpos.file_line > eap->line2 && settings.duplex
3532 								 && side == 0
3533 		    && uncollated_copies + 1 < settings.n_uncollated_copies)
3534 		{
3535 		    if (!mch_print_blank_page())
3536 			goto print_fail;
3537 		}
3538 	    }
3539 	    if (settings.duplex && prtpos.file_line <= eap->line2)
3540 		++page_count;
3541 
3542 	    /* Remember the position where the next page starts. */
3543 	    page_prtpos = prtpos;
3544 	}
3545 
3546 	sprintf((char *)IObuff, _("Printed: %s"), settings.jobname);
3547 	prt_message(IObuff);
3548     }
3549 
3550 print_fail:
3551     if (got_int || settings.user_abort)
3552     {
3553 	sprintf((char *)IObuff, _("Printing aborted"));
3554 	prt_message(IObuff);
3555     }
3556     mch_print_end(&settings);
3557 
3558 print_fail_no_begin:
3559     mch_print_cleanup();
3560 }
3561 
3562 /*
3563  * Print one page line.
3564  * Return the next column to print, or zero if the line is finished.
3565  */
3566     static colnr_T
3567 hardcopy_line(psettings, page_line, ppos)
3568     prt_settings_T	*psettings;
3569     int			page_line;
3570     prt_pos_T		*ppos;
3571 {
3572     colnr_T	col;
3573     char_u	*line;
3574     int		need_break = FALSE;
3575     int		outputlen;
3576     int		tab_spaces;
3577     long_u	print_pos;
3578 #ifdef FEAT_SYN_HL
3579     prt_text_attr_T attr;
3580     int		id;
3581 #endif
3582 
3583     if (ppos->column == 0 || ppos->ff)
3584     {
3585 	print_pos = 0;
3586 	tab_spaces = 0;
3587 	if (!ppos->ff && prt_use_number())
3588 	    prt_line_number(psettings, page_line, ppos->file_line);
3589 	ppos->ff = FALSE;
3590     }
3591     else
3592     {
3593 	/* left over from wrap halfway a tab */
3594 	print_pos = ppos->print_pos;
3595 	tab_spaces = ppos->lead_spaces;
3596     }
3597 
3598     mch_print_start_line(0, page_line);
3599     line = ml_get(ppos->file_line);
3600 
3601     /*
3602      * Loop over the columns until the end of the file line or right margin.
3603      */
3604     for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
3605     {
3606 	outputlen = 1;
3607 #ifdef FEAT_MBYTE
3608 	if (has_mbyte && (outputlen = (*mb_ptr2len_check)(line + col)) < 1)
3609 	    outputlen = 1;
3610 #endif
3611 #ifdef FEAT_SYN_HL
3612 	/*
3613 	 * syntax highlighting stuff.
3614 	 */
3615 	if (psettings->do_syntax)
3616 	{
3617 	    id = syn_get_id(ppos->file_line, (long)col, 1);
3618 	    if (id > 0)
3619 		id = syn_get_final_id(id);
3620 	    else
3621 		id = 0;
3622 	    /* Get the line again, a multi-line regexp may invalidate it. */
3623 	    line = ml_get(ppos->file_line);
3624 
3625 	    if (id != current_syn_id)
3626 	    {
3627 		current_syn_id = id;
3628 		prt_get_attr(id, &attr, psettings->modec);
3629 		prt_set_font(attr.bold, attr.italic, attr.underline);
3630 		prt_set_fg(attr.fg_color);
3631 		prt_set_bg(attr.bg_color);
3632 	    }
3633 	}
3634 #endif /* FEAT_SYN_HL */
3635 
3636 	/*
3637 	 * Appropriately expand any tabs to spaces.
3638 	 */
3639 	if (line[col] == TAB || tab_spaces != 0)
3640 	{
3641 	    if (tab_spaces == 0)
3642 		tab_spaces = curbuf->b_p_ts - (print_pos % curbuf->b_p_ts);
3643 
3644 	    while (tab_spaces > 0)
3645 	    {
3646 		need_break = mch_print_text_out((char_u *)" ", 1);
3647 		print_pos++;
3648 		tab_spaces--;
3649 		if (need_break)
3650 		    break;
3651 	    }
3652 	    /* Keep the TAB if we didn't finish it. */
3653 	    if (need_break && tab_spaces > 0)
3654 		break;
3655 	}
3656 	else if (line[col] == FF
3657 		&& printer_opts[OPT_PRINT_FORMFEED].present
3658 		&& TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
3659 								       == 'y')
3660 	{
3661 	    ppos->ff = TRUE;
3662 	    need_break = 1;
3663 	}
3664 	else
3665 	{
3666 	    need_break = mch_print_text_out(line + col, outputlen);
3667 #ifdef FEAT_MBYTE
3668 	    if (has_mbyte)
3669 		print_pos += (*mb_ptr2cells)(line + col);
3670 	    else
3671 #endif
3672 		print_pos++;
3673 	}
3674     }
3675 
3676     ppos->lead_spaces = tab_spaces;
3677     ppos->print_pos = print_pos;
3678 
3679     /*
3680      * Start next line of file if we clip lines, or have reached end of the
3681      * line, unless we are doing a formfeed.
3682      */
3683     if (!ppos->ff
3684 	    && (line[col] == NUL
3685 		|| (printer_opts[OPT_PRINT_WRAP].present
3686 		    && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
3687 								     == 'n')))
3688 	return 0;
3689     return col;
3690 }
3691 
3692 # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
3693 
3694 /*
3695  * PS printer stuff.
3696  *
3697  * Sources of information to help maintain the PS printing code:
3698  *
3699  * 1. PostScript Language Reference, 3rd Edition,
3700  *      Addison-Wesley, 1999, ISBN 0-201-37922-8
3701  * 2. PostScript Language Program Design,
3702  *      Addison-Wesley, 1988, ISBN 0-201-14396-8
3703  * 3. PostScript Tutorial and Cookbook,
3704  *      Addison Wesley, 1985, ISBN 0-201-10179-3
3705  * 4. PostScript Language Document Structuring Conventions Specification,
3706  *    version 3.0,
3707  *      Adobe Technote 5001, 25th September 1992
3708  * 5. PostScript Printer Description File Format Specification, Version 4.3,
3709  *      Adobe technote 5003, 9th February 1996
3710  * 6. Adobe Font Metrics File Format Specification, Version 4.1,
3711  *      Adobe Technote 5007, 7th October 1998
3712  *
3713  * Some of these documents can be found in PDF form on Adobe's web site -
3714  * http://www.adobe.com
3715  */
3716 
3717 #define PRT_PS_DEFAULT_DPI	    (72)    /* Default user space resolution */
3718 #define PRT_PS_DEFAULT_FONTSIZE     (10)
3719 #define PRT_PS_DEFAULT_BUFFER_SIZE  (80)
3720 
3721 struct prt_mediasize_S
3722 {
3723     char	*name;
3724     float	width;		/* width and height in points for portrait */
3725     float	height;
3726 };
3727 
3728 #define PRT_MEDIASIZE_LEN  (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
3729 
3730 static struct prt_mediasize_S prt_mediasize[] =
3731 {
3732     {"A4",		595.0,  842.0},
3733     {"letter",		612.0,  792.0},
3734     {"10x14",		720.0, 1008.0},
3735     {"A3",		842.0, 1191.0},
3736     {"A5",		420.0,  595.0},
3737     {"B4",		729.0, 1032.0},
3738     {"B5",		516.0,  729.0},
3739     {"executive",	522.0,  756.0},
3740     {"folio",		595.0,  935.0},
3741     {"ledger",	       1224.0,  792.0},   /* Yes, it is wider than taller! */
3742     {"legal",		612.0, 1008.0},
3743     {"quarto",		610.0,  780.0},
3744     {"statement",	396.0,  612.0},
3745     {"tabloid",		792.0, 1224.0}
3746 };
3747 
3748 /* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */
3749 struct prt_ps_font_S
3750 {
3751     int		wx;
3752     int		uline_offset;
3753     int		uline_width;
3754     int		bbox_min_y;
3755     int		bbox_max_y;
3756     char	*(ps_fontname[4]);
3757 };
3758 
3759 #define PRT_PS_FONT_ROMAN	(0)
3760 #define PRT_PS_FONT_BOLD	(1)
3761 #define PRT_PS_FONT_OBLIQUE	(2)
3762 #define PRT_PS_FONT_BOLDOBLIQUE (3)
3763 
3764 static struct prt_ps_font_S prt_ps_font =
3765 {
3766     600,
3767     -100, 50,
3768     -250, 805,
3769     {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
3770 };
3771 
3772 struct prt_ps_resource_S
3773 {
3774     char_u  name[64];
3775     char_u  filename[MAXPATHL + 1];
3776     int     type;
3777     char_u  title[256];
3778     char_u  version[256];
3779 };
3780 
3781 /* Types of PS resource file currently used */
3782 #define PRT_RESOURCE_TYPE_PROCSET   (0)
3783 #define PRT_RESOURCE_TYPE_ENCODING  (1)
3784 
3785 /* The PS prolog file version number has to match - if the prolog file is
3786  * updated, increment the number in the file and here.  Version checking was
3787  * added as of VIM 6.2.
3788  * Table of VIM and prolog versions:
3789  *
3790  * VIM      Prolog
3791  * 6.2      1.3
3792  */
3793 #define PRT_PROLOG_VERSION  ((char_u *)"1.3")
3794 
3795 /* String versions of PS resource types - indexed by constants above so don't
3796  * re-order!
3797  */
3798 static char *resource_types[] =
3799 {
3800     "procset",
3801     "encoding"
3802 };
3803 
3804 /* Strings to look for in a PS resource file */
3805 #define PRT_RESOURCE_HEADER	    "%!PS-Adobe-"
3806 #define PRT_RESOURCE_RESOURCE	    "Resource-"
3807 #define PRT_RESOURCE_PROCSET	    "ProcSet"
3808 #define PRT_RESOURCE_ENCODING	    "Encoding"
3809 #define PRT_RESOURCE_TITLE	    "%%Title:"
3810 #define PRT_RESOURCE_VERSION	    "%%Version:"
3811 
3812 static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes));
3813 static void prt_write_file __ARGS((char_u *buffer));
3814 static void prt_write_file_len __ARGS((char_u *buffer, int bytes));
3815 static void prt_write_string __ARGS((char *s));
3816 static void prt_write_int __ARGS((int i));
3817 static void prt_write_boolean __ARGS((int b));
3818 static void prt_def_font __ARGS((char *new_name, char *encoding, int height, char *font));
3819 static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction));
3820 static void prt_write_real __ARGS((double val, int prec));
3821 static void prt_def_var __ARGS((char *name, double value, int prec));
3822 static void prt_flush_buffer __ARGS((void));
3823 static void prt_resource_name __ARGS((char_u *filename));
3824 static int prt_find_resource __ARGS((char *name, struct prt_ps_resource_S *resource));
3825 static int prt_open_resource __ARGS((struct prt_ps_resource_S *resource));
3826 static int prt_check_resource __ARGS((struct prt_ps_resource_S *resource, char_u *version));
3827 static void prt_dsc_start __ARGS((void));
3828 static void prt_dsc_noarg __ARGS((char *comment));
3829 static void prt_dsc_textline __ARGS((char *comment, char *text));
3830 static void prt_dsc_text __ARGS((char *comment, char *text));
3831 static void prt_dsc_ints __ARGS((char *comment, int count, int *ints));
3832 static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies));
3833 static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type));
3834 static void prt_dsc_resources __ARGS((char *comment, char *type, int count, char **strings));
3835 static float to_device_units __ARGS((int idx, double physsize, int def_number));
3836 static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom));
3837 static void prt_font_metrics __ARGS((int font_scale));
3838 static int prt_get_cpl __ARGS((void));
3839 static int prt_get_lpp __ARGS((void));
3840 static int prt_add_resource __ARGS((struct prt_ps_resource_S *resource));
3841 
3842 /*
3843  * Variables for the output PostScript file.
3844  */
3845 static FILE *prt_ps_fd;
3846 static int prt_file_error;
3847 static char_u *prt_ps_file_name = NULL;
3848 
3849 /*
3850  * Various offsets and dimensions in default PostScript user space (points).
3851  * Used for text positioning calculations
3852  */
3853 static float prt_page_width;
3854 static float prt_page_height;
3855 static float prt_left_margin;
3856 static float prt_right_margin;
3857 static float prt_top_margin;
3858 static float prt_bottom_margin;
3859 static float prt_line_height;
3860 static float prt_first_line_height;
3861 static float prt_char_width;
3862 static float prt_number_width;
3863 static float prt_bgcol_offset;
3864 static float prt_pos_x_moveto = 0.0;
3865 static float prt_pos_y_moveto = 0.0;
3866 
3867 /*
3868  * Various control variables used to decide when and how to change the
3869  * PostScript graphics state.
3870  */
3871 static int prt_need_moveto;
3872 static int prt_do_moveto;
3873 static int prt_need_font;
3874 static int prt_font;
3875 static int prt_need_underline;
3876 static int prt_underline;
3877 static int prt_do_underline;
3878 static int prt_need_fgcol;
3879 static int prt_fgcol;
3880 static int prt_need_bgcol;
3881 static int prt_do_bgcol;
3882 static int prt_bgcol;
3883 static int prt_new_bgcol;
3884 static int prt_attribute_change;
3885 static int prt_text_count;
3886 static int prt_page_num;
3887 
3888 /*
3889  * Variables controlling physical printing.
3890  */
3891 static int prt_media;
3892 static int prt_portrait;
3893 static int prt_num_copies;
3894 static int prt_duplex;
3895 static int prt_tumble;
3896 static int prt_collate;
3897 
3898 /*
3899  * Buffers used when generating PostScript output
3900  */
3901 static char_u prt_line_buffer[257];
3902 static garray_T prt_ps_buffer;
3903 
3904 # ifdef FEAT_MBYTE
3905 static int prt_do_conv;
3906 static vimconv_T prt_conv;
3907 # endif
3908 
3909     static void
3910 prt_write_file_raw_len(buffer, bytes)
3911     char_u	*buffer;
3912     int		bytes;
3913 {
3914     if (!prt_file_error
3915 	    && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
3916 							     != (size_t)bytes)
3917     {
3918 	EMSG(_("E455: Error writing to PostScript output file"));
3919 	prt_file_error = TRUE;
3920     }
3921 }
3922 
3923     static void
3924 prt_write_file(buffer)
3925     char_u	*buffer;
3926 {
3927     prt_write_file_len(buffer, STRLEN(buffer));
3928 }
3929 
3930     static void
3931 prt_write_file_len(buffer, bytes)
3932     char_u	*buffer;
3933     int		bytes;
3934 {
3935 #ifdef EBCDIC
3936     ebcdic2ascii(buffer, bytes);
3937 #endif
3938     prt_write_file_raw_len(buffer, bytes);
3939 }
3940 
3941 /*
3942  * Write a string.
3943  */
3944     static void
3945 prt_write_string(s)
3946     char	*s;
3947 {
3948     sprintf((char *)prt_line_buffer, "%s", s);
3949     prt_write_file(prt_line_buffer);
3950 }
3951 
3952 /*
3953  * Write an int and a space.
3954  */
3955     static void
3956 prt_write_int(i)
3957     int		i;
3958 {
3959     sprintf((char *)prt_line_buffer, "%d ", i);
3960     prt_write_file(prt_line_buffer);
3961 }
3962 
3963 /*
3964  * Write a boolean and a space.
3965  */
3966     static void
3967 prt_write_boolean(b)
3968     int		b;
3969 {
3970     sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
3971     prt_write_file(prt_line_buffer);
3972 }
3973 
3974 /*
3975  * Write a line to define the font.
3976  */
3977     static void
3978 prt_def_font(new_name, encoding, height, font)
3979     char	*new_name;
3980     char	*encoding;
3981     int		height;
3982     char	*font;
3983 {
3984     sprintf((char *)prt_line_buffer, "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
3985     prt_write_file(prt_line_buffer);
3986     sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n",
3987 						    new_name, height, new_name);
3988     prt_write_file(prt_line_buffer);
3989 }
3990 
3991 /*
3992  * Convert a real value into an integer and fractional part as integers, with
3993  * the fractional part being in the range [0,10^precision).  The fractional part
3994  * is also rounded based on the precision + 1'th fractional digit.
3995  */
3996     static void
3997 prt_real_bits(real, precision, pinteger, pfraction)
3998     double      real;
3999     int		precision;
4000     int		*pinteger;
4001     int		*pfraction;
4002 {
4003     int     i;
4004     int     integer;
4005     float   fraction;
4006 
4007     integer = (int)real;
4008     fraction = (float)(real - integer);
4009     if (real < (double)integer)
4010 	fraction = -fraction;
4011     for (i = 0; i < precision; i++)
4012 	fraction *= 10.0;
4013 
4014     *pinteger = integer;
4015     *pfraction = (int)(fraction + 0.5);
4016 }
4017 
4018 /*
4019  * Write a real and a space.  Save bytes if real value has no fractional part!
4020  * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
4021  * what decimal point character to use, but PS always requires a '.'.
4022  */
4023     static void
4024 prt_write_real(val, prec)
4025     double	val;
4026     int		prec;
4027 {
4028     int     integer;
4029     int     fraction;
4030 
4031     prt_real_bits(val, prec, &integer, &fraction);
4032     /* Emit integer part */
4033     sprintf((char *)prt_line_buffer, "%d", integer);
4034     prt_write_file(prt_line_buffer);
4035     /* Only emit fraction if necessary */
4036     if (fraction != 0)
4037     {
4038 	/* Remove any trailing zeros */
4039 	while ((fraction % 10) == 0)
4040 	{
4041 	    prec--;
4042 	    fraction /= 10;
4043 	}
4044 	/* Emit fraction left padded with zeros */
4045 	sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
4046 	prt_write_file(prt_line_buffer);
4047     }
4048     sprintf((char *)prt_line_buffer, " ");
4049     prt_write_file(prt_line_buffer);
4050 }
4051 
4052 /*
4053  * Write a line to define a numeric variable.
4054  */
4055     static void
4056 prt_def_var(name, value, prec)
4057     char	*name;
4058     double	value;
4059     int		prec;
4060 {
4061     sprintf((char *)prt_line_buffer, "/%s ", name);
4062     prt_write_file(prt_line_buffer);
4063     prt_write_real(value, prec);
4064     sprintf((char *)prt_line_buffer, "d\n");
4065     prt_write_file(prt_line_buffer);
4066 }
4067 
4068 /* Convert size from font space to user space at current font scale */
4069 #define PRT_PS_FONT_TO_USER(scale, size)    ((size) * ((scale)/1000.0))
4070 
4071     static void
4072 prt_flush_buffer()
4073 {
4074     if (prt_ps_buffer.ga_len > 0)
4075     {
4076 	/* Any background color must be drawn first */
4077 	if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
4078 	{
4079 	    int     r, g, b;
4080 
4081 	    if (prt_do_moveto)
4082 	    {
4083 		prt_write_real(prt_pos_x_moveto, 2);
4084 		prt_write_real(prt_pos_y_moveto, 2);
4085 		prt_write_string("m\n");
4086 		prt_do_moveto = FALSE;
4087 	    }
4088 
4089 	    /* Size of rect of background color on which text is printed */
4090 	    prt_write_real(prt_text_count * prt_char_width, 2);
4091 	    prt_write_real(prt_line_height, 2);
4092 
4093 	    /* Lastly add the color of the background */
4094 	    r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
4095 	    g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
4096 	    b = prt_new_bgcol & 0xff;
4097 	    prt_write_real(r / 255.0, 3);
4098 	    prt_write_real(g / 255.0, 3);
4099 	    prt_write_real(b / 255.0, 3);
4100 	    prt_write_string("bg\n");
4101 	}
4102 	/* Draw underlines before the text as it makes it slightly easier to
4103 	 * find the starting point.
4104 	 */
4105 	if (prt_do_underline)
4106 	{
4107 	    if (prt_do_moveto)
4108 	    {
4109 		prt_write_real(prt_pos_x_moveto, 2);
4110 		prt_write_real(prt_pos_y_moveto, 2);
4111 		prt_write_string("m\n");
4112 		prt_do_moveto = FALSE;
4113 	    }
4114 
4115 	    /* Underlining is easy - just need the number of characters to
4116 	     * print. */
4117 	    prt_write_real(prt_text_count * prt_char_width, 2);
4118 	    prt_write_string("ul\n");
4119 	}
4120 	/* Draw the text
4121 	 * Note: we write text out raw - EBCDIC conversion is handled in the
4122 	 * PostScript world via the font encoding vector. */
4123 	prt_write_string("(");
4124 	prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
4125 	prt_write_string(")");
4126 	/* Add a moveto if need be and use the appropriate show procedure */
4127 	if (prt_do_moveto)
4128 	{
4129 	    prt_write_real(prt_pos_x_moveto, 2);
4130 	    prt_write_real(prt_pos_y_moveto, 2);
4131 	    /* moveto and a show */
4132 	    prt_write_string("ms\n");
4133 	    prt_do_moveto = FALSE;
4134 	}
4135 	else /* Simple show */
4136 	    prt_write_string("s\n");
4137 
4138 	ga_clear(&prt_ps_buffer);
4139 	ga_init2(&prt_ps_buffer, (int)sizeof(char), PRT_PS_DEFAULT_BUFFER_SIZE);
4140     }
4141 }
4142 
4143 static char_u *resource_filename;
4144 
4145     static void
4146 prt_resource_name(filename)
4147     char_u  *filename;
4148 {
4149     if (STRLEN(filename) >= MAXPATHL)
4150 	*resource_filename = NUL;
4151     else
4152 	STRCPY(resource_filename, filename);
4153 }
4154 
4155     static int
4156 prt_find_resource(name, resource)
4157     char	*name;
4158     struct prt_ps_resource_S *resource;
4159 {
4160     char_u	buffer[MAXPATHL + 1];
4161 
4162     STRCPY(resource->name, name);
4163     /* Look for named resource file in runtimepath */
4164     STRCPY(buffer, "print");
4165     add_pathsep(buffer);
4166     STRCAT(buffer, name);
4167     STRCAT(buffer, ".ps");
4168     resource_filename = resource->filename;
4169     *resource_filename = NUL;
4170     return (do_in_runtimepath(buffer, FALSE, prt_resource_name)
4171 	    && resource->filename[0] != NUL);
4172 }
4173 
4174 /* PS CR and LF characters have platform independent values */
4175 #define PSLF  (0x0a)
4176 #define PSCR  (0x0d)
4177 
4178 /* Very simple hand crafted parser to get the type, title, and version number of
4179  * a PS resource file so the file details can be added to the DSC header
4180  * comments. */
4181     static int
4182 prt_open_resource(resource)
4183     struct prt_ps_resource_S *resource;
4184 {
4185     FILE	*fd_resource;
4186     char_u	buffer[128];
4187     char_u	*ch = buffer;
4188     char_u	*ch2;
4189 
4190     fd_resource = mch_fopen((char *)resource->filename, READBIN);
4191     if (fd_resource == NULL)
4192     {
4193 	EMSG2(_("E624: Can't open file \"%s\""), resource->filename);
4194 	return FALSE;
4195     }
4196     vim_memset(buffer, NUL, sizeof(buffer));
4197 
4198     /* Parse first line to ensure valid resource file */
4199     (void)fread((char *)buffer, sizeof(char_u), sizeof(buffer),
4200 								 fd_resource);
4201     if (ferror(fd_resource))
4202     {
4203 	EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
4204 		resource->filename);
4205 	fclose(fd_resource);
4206 	return FALSE;
4207     }
4208 
4209     if (STRNCMP(ch, PRT_RESOURCE_HEADER, STRLEN(PRT_RESOURCE_HEADER)) != 0)
4210     {
4211 	EMSG2(_("E618: file \"%s\" is not a PostScript resource file"),
4212 		resource->filename);
4213 	fclose(fd_resource);
4214 	return FALSE;
4215     }
4216 
4217     /* Skip over any version numbers and following ws */
4218     ch += STRLEN(PRT_RESOURCE_HEADER);
4219     while (!isspace(*ch))
4220 	ch++;
4221     while (isspace(*ch))
4222 	ch++;
4223 
4224     if (STRNCMP(ch, PRT_RESOURCE_RESOURCE, STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
4225     {
4226 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4227 		resource->filename);
4228 	fclose(fd_resource);
4229 	return FALSE;
4230     }
4231     ch += STRLEN(PRT_RESOURCE_RESOURCE);
4232 
4233     /* Decide type of resource in the file */
4234     if (STRNCMP(ch, PRT_RESOURCE_PROCSET, STRLEN(PRT_RESOURCE_PROCSET)) == 0)
4235     {
4236 	resource->type = PRT_RESOURCE_TYPE_PROCSET;
4237 	ch += STRLEN(PRT_RESOURCE_PROCSET);
4238     }
4239     else if (STRNCMP(ch, PRT_RESOURCE_ENCODING, STRLEN(PRT_RESOURCE_ENCODING)) == 0)
4240     {
4241 	resource->type = PRT_RESOURCE_TYPE_ENCODING;
4242 	ch += STRLEN(PRT_RESOURCE_ENCODING);
4243     }
4244     else
4245     {
4246 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4247 		resource->filename);
4248 	fclose(fd_resource);
4249 	return FALSE;
4250     }
4251 
4252     /* Consume up to and including the CR/LF/CR_LF */
4253     while (*ch != PSCR && *ch != PSLF)
4254 	ch++;
4255     while (*ch == PSCR || *ch == PSLF)
4256 	ch++;
4257 
4258     /* Match %%Title: */
4259     if (STRNCMP(ch, PRT_RESOURCE_TITLE, STRLEN(PRT_RESOURCE_TITLE)) != 0)
4260     {
4261 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4262 		resource->filename);
4263 	fclose(fd_resource);
4264 	return FALSE;
4265     }
4266     ch += STRLEN(PRT_RESOURCE_TITLE);
4267 
4268     /* Skip ws after %%Title: */
4269     while (isspace(*ch))
4270 	ch++;
4271 
4272     /* Copy up to the CR/LF/CR_LF */
4273     ch2 = resource->title;
4274     while (*ch != PSCR && *ch != PSLF)
4275 	*ch2++ = *ch++;
4276     *ch2 = '\0';
4277     while (*ch == PSCR || *ch == PSLF)
4278 	ch++;
4279 
4280     /* Match %%Version: */
4281     if (STRNCMP(ch, PRT_RESOURCE_VERSION, STRLEN(PRT_RESOURCE_VERSION)) != 0)
4282     {
4283 	EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
4284 		resource->filename);
4285 	fclose(fd_resource);
4286 	return FALSE;
4287     }
4288     ch += STRLEN(PRT_RESOURCE_VERSION);
4289 
4290     /* Skip ws after %%Version: */
4291     while (isspace(*ch))
4292 	ch++;
4293 
4294     /* Copy up to the CR/LF/CR_LF */
4295     ch2 = resource->version;
4296     while (*ch != PSCR && *ch != PSLF)
4297 	*ch2++ = *ch++;
4298     *ch2 = '\0';
4299 
4300     fclose(fd_resource);
4301 
4302     return TRUE;
4303 }
4304 
4305     static int
4306 prt_check_resource(resource, version)
4307     struct prt_ps_resource_S *resource;
4308     char_u  *version;
4309 {
4310     /* Version number m.n should match, the revision number does not matter */
4311     if (STRNCMP(resource->version, version, STRLEN(version)))
4312     {
4313 	EMSG2(_("E621: \"%s\" resource file has wrong version"),
4314 		resource->name);
4315 	return FALSE;
4316     }
4317 
4318     /* Other checks to be added as needed */
4319     return TRUE;
4320 }
4321 
4322     static void
4323 prt_dsc_start()
4324 {
4325     prt_write_string("%!PS-Adobe-3.0\n");
4326 }
4327 
4328     static void
4329 prt_dsc_noarg(comment)
4330     char	*comment;
4331 {
4332     sprintf((char *)prt_line_buffer, "%%%%%s\n", comment);
4333     prt_write_file(prt_line_buffer);
4334 }
4335 
4336     static void
4337 prt_dsc_textline(comment, text)
4338     char	*comment;
4339     char	*text;
4340 {
4341     sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text);
4342     prt_write_file(prt_line_buffer);
4343 }
4344 
4345     static void
4346 prt_dsc_text(comment, text)
4347     char	*comment;
4348     char	*text;
4349 {
4350     /* TODO - should scan 'text' for any chars needing escaping! */
4351     sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text);
4352     prt_write_file(prt_line_buffer);
4353 }
4354 
4355 #define prt_dsc_atend(c)	prt_dsc_text((c), "atend")
4356 
4357     static void
4358 prt_dsc_ints(comment, count, ints)
4359     char	*comment;
4360     int		count;
4361     int		*ints;
4362 {
4363     int		i;
4364 
4365     sprintf((char *)prt_line_buffer, "%%%%%s:", comment);
4366     prt_write_file(prt_line_buffer);
4367 
4368     for (i = 0; i < count; i++)
4369     {
4370 	sprintf((char *)prt_line_buffer, " %d", ints[i]);
4371 	prt_write_file(prt_line_buffer);
4372     }
4373 
4374     prt_write_string("\n");
4375 }
4376 
4377     static void
4378 prt_dsc_resources(comment, type, count, strings)
4379     char	*comment;	/* if NULL add to previous */
4380     char	*type;
4381     int		count;
4382     char	**strings;
4383 {
4384     int		i;
4385 
4386     if (comment != NULL)
4387 	sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type);
4388     else
4389 	sprintf((char *)prt_line_buffer, "%%%%+ %s", type);
4390     prt_write_file(prt_line_buffer);
4391 
4392     for (i = 0; i < count; i++)
4393     {
4394 	sprintf((char *)prt_line_buffer, " %s", strings[i]);
4395 	prt_write_file(prt_line_buffer);
4396     }
4397 
4398     prt_write_string("\n");
4399 }
4400 
4401     static void
4402 prt_dsc_requirements(duplex, tumble, collate, color, num_copies)
4403     int		duplex;
4404     int		tumble;
4405     int		collate;
4406     int		color;
4407     int		num_copies;
4408 {
4409     /* Only output the comment if we need to.
4410      * Note: tumble is ignored if we are not duplexing
4411      */
4412     if (!(duplex || collate || color || (num_copies > 1)))
4413 	return;
4414 
4415     sprintf((char *)prt_line_buffer, "%%%%Requirements:");
4416     prt_write_file(prt_line_buffer);
4417 
4418     if (duplex)
4419     {
4420 	prt_write_string(" duplex");
4421 	if (tumble)
4422 	    prt_write_string("(tumble)");
4423     }
4424     if (collate)
4425 	prt_write_string(" collate");
4426     if (color)
4427 	prt_write_string(" color");
4428     if (num_copies > 1)
4429     {
4430 	prt_write_string(" numcopies(");
4431 	/* Note: no space wanted so dont use prt_write_int() */
4432 	sprintf((char *)prt_line_buffer, "%d", num_copies);
4433 	prt_write_file(prt_line_buffer);
4434 	prt_write_string(")");
4435     }
4436     prt_write_string("\n");
4437 }
4438 
4439     static void
4440 prt_dsc_docmedia(paper_name, width, height, weight, colour, type)
4441     char	*paper_name;
4442     double	width;
4443     double	height;
4444     double	weight;
4445     char	*colour;
4446     char	*type;
4447 {
4448     sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name);
4449     prt_write_file(prt_line_buffer);
4450     prt_write_real(width, 2);
4451     prt_write_real(height, 2);
4452     prt_write_real(weight, 2);
4453     if (colour == NULL)
4454 	prt_write_string("()");
4455     else
4456 	prt_write_string(colour);
4457     prt_write_string(" ");
4458     if (type == NULL)
4459 	prt_write_string("()");
4460     else
4461 	prt_write_string(type);
4462     prt_write_string("\n");
4463 }
4464 
4465     void
4466 mch_print_cleanup()
4467 {
4468 #ifdef FEAT_MBYTE
4469     if (prt_do_conv)
4470     {
4471 	convert_setup(&prt_conv, NULL, NULL);
4472 	prt_do_conv = FALSE;
4473     }
4474 #endif
4475     if (prt_ps_fd != NULL)
4476     {
4477 	fclose(prt_ps_fd);
4478 	prt_ps_fd = NULL;
4479 	prt_file_error = FALSE;
4480     }
4481     if (prt_ps_file_name != NULL)
4482     {
4483 	vim_free(prt_ps_file_name);
4484 	prt_ps_file_name = NULL;
4485     }
4486 }
4487 
4488     static float
4489 to_device_units(idx, physsize, def_number)
4490     int		idx;
4491     double	physsize;
4492     int		def_number;
4493 {
4494     float	ret;
4495     int		u;
4496     int		nr;
4497 
4498     u = prt_get_unit(idx);
4499     if (u == PRT_UNIT_NONE)
4500     {
4501 	u = PRT_UNIT_PERC;
4502 	nr = def_number;
4503     }
4504     else
4505 	nr = printer_opts[idx].number;
4506 
4507     switch (u)
4508     {
4509 	case PRT_UNIT_INCH:
4510 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI);
4511 	    break;
4512 	case PRT_UNIT_MM:
4513 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
4514 	    break;
4515 	case PRT_UNIT_POINT:
4516 	    ret = (float)nr;
4517 	    break;
4518 	case PRT_UNIT_PERC:
4519 	default:
4520 	    ret = (float)(physsize * nr) / 100;
4521 	    break;
4522     }
4523 
4524     return ret;
4525 }
4526 
4527 /*
4528  * Calculate margins for given width and height from printoptions settings.
4529  */
4530     static void
4531 prt_page_margins(width, height, left, right, top, bottom)
4532     double	width;
4533     double	height;
4534     double	*left;
4535     double	*right;
4536     double	*top;
4537     double	*bottom;
4538 {
4539     *left   = to_device_units(OPT_PRINT_LEFT, width, 10);
4540     *right  = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
4541     *top    = height - to_device_units(OPT_PRINT_TOP, height, 5);
4542     *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
4543 }
4544 
4545     static void
4546 prt_font_metrics(font_scale)
4547     int		font_scale;
4548 {
4549     prt_line_height = (float)font_scale;
4550     prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font.wx);
4551 }
4552 
4553 
4554     static int
4555 prt_get_cpl()
4556 {
4557     if (prt_use_number())
4558     {
4559 	prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
4560 	prt_left_margin += prt_number_width;
4561     }
4562     else
4563 	prt_number_width = 0.0;
4564 
4565     return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
4566 }
4567 
4568 /*
4569  * Get number of lines of text that fit on a page (excluding the header).
4570  */
4571     static int
4572 prt_get_lpp()
4573 {
4574     int lpp;
4575 
4576     /*
4577      * Calculate offset to lower left corner of background rect based on actual
4578      * font height (based on its bounding box) and the line height, handling the
4579      * case where the font height can exceed the line height.
4580      */
4581     prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
4582 					   prt_ps_font.bbox_min_y);
4583     if ((prt_ps_font.bbox_max_y - prt_ps_font.bbox_min_y) < 1000.0)
4584     {
4585 	prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
4586 				(1000.0 - (prt_ps_font.bbox_max_y -
4587 					    prt_ps_font.bbox_min_y)) / 2);
4588     }
4589 
4590     /* Get height for topmost line based on background rect offset. */
4591     prt_first_line_height = prt_line_height + prt_bgcol_offset;
4592 
4593     /* Calculate lpp */
4594     lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
4595 
4596     /* Adjust top margin if there is a header */
4597     prt_top_margin -= prt_line_height * prt_header_height();
4598 
4599     return lpp - prt_header_height();
4600 }
4601 
4602 /*ARGSUSED*/
4603     int
4604 mch_print_init(psettings, jobname, forceit)
4605     prt_settings_T *psettings;
4606     char_u	*jobname;
4607     int		forceit;
4608 {
4609     int		i;
4610     char	*paper_name;
4611     int		paper_strlen;
4612     int		fontsize;
4613     char_u	*p;
4614     double      left;
4615     double      right;
4616     double      top;
4617     double      bottom;
4618 
4619 #if 0
4620     /*
4621      * TODO:
4622      * If "forceit" is false: pop up a dialog to select:
4623      *	- printer name
4624      *	- copies
4625      *	- collated/uncollated
4626      *	- duplex off/long side/short side
4627      *	- paper size
4628      *	- portrait/landscape
4629      *	- font size
4630      *
4631      * If "forceit" is true: use the default printer and settings
4632      */
4633     if (forceit)
4634 	s_pd.Flags |= PD_RETURNDEFAULT;
4635 #endif
4636 
4637     /*
4638      * Find the size of the paper and set the margins.
4639      */
4640     prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
4641 	   || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
4642     if (printer_opts[OPT_PRINT_PAPER].present)
4643     {
4644 	paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
4645 	paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
4646     }
4647     else
4648     {
4649 	paper_name = "A4";
4650 	paper_strlen = 2;
4651     }
4652     for (i = 0; i < PRT_MEDIASIZE_LEN; ++i)
4653 	if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
4654 		&& STRNICMP(prt_mediasize[i].name, paper_name,
4655 							   paper_strlen) == 0)
4656 	    break;
4657     if (i == PRT_MEDIASIZE_LEN)
4658 	i = 0;
4659     prt_media = i;
4660 
4661     /*
4662      * Set PS pagesize based on media dimensions and print orientation.
4663      * Note: Media and page sizes have defined meanings in PostScript and should
4664      * be kept distinct.  Media is the paper (or transparency, or ...) that is
4665      * printed on, whereas the page size is the area that the PostScript
4666      * interpreter renders into.
4667      */
4668     if (prt_portrait)
4669     {
4670 	prt_page_width = prt_mediasize[i].width;
4671 	prt_page_height = prt_mediasize[i].height;
4672     }
4673     else
4674     {
4675 	prt_page_width = prt_mediasize[i].height;
4676 	prt_page_height = prt_mediasize[i].width;
4677     }
4678 
4679     /*
4680      * Set PS page margins based on the PS pagesize, not the mediasize - this
4681      * needs to be done before the cpl and lpp are calculated.
4682      */
4683     prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
4684 								    &bottom);
4685     prt_left_margin = (float)left;
4686     prt_right_margin = (float)right;
4687     prt_top_margin = (float)top;
4688     prt_bottom_margin = (float)bottom;
4689 
4690     /*
4691      * Set up the font size.
4692      */
4693     fontsize = PRT_PS_DEFAULT_FONTSIZE;
4694     for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
4695 	if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
4696 	    fontsize = atoi((char *)p + 2);
4697     prt_font_metrics(fontsize);
4698 
4699     /*
4700      * Return the number of characters per line, and lines per page for the
4701      * generic print code.
4702      */
4703     psettings->chars_per_line = prt_get_cpl();
4704     psettings->lines_per_page = prt_get_lpp();
4705 
4706     /* Catch margin settings that leave no space for output! */
4707     if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
4708 	return FAIL;
4709 
4710     /*
4711      * Sort out the number of copies to be printed.  PS by default will do
4712      * uncollated copies for you, so once we know how many uncollated copies are
4713      * wanted cache it away and lie to the generic code that we only want one
4714      * uncollated copy.
4715      */
4716     psettings->n_collated_copies = 1;
4717     psettings->n_uncollated_copies = 1;
4718     prt_num_copies = 1;
4719     prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
4720 	    || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
4721     if (prt_collate)
4722     {
4723 	/* TODO: Get number of collated copies wanted. */
4724 	psettings->n_collated_copies = 1;
4725     }
4726     else
4727     {
4728 	/* TODO: Get number of uncollated copies wanted and update the cached
4729 	 * count.
4730 	 */
4731 	prt_num_copies = 1;
4732     }
4733 
4734     psettings->jobname = jobname;
4735 
4736     /*
4737      * Set up printer duplex and tumble based on Duplex option setting - default
4738      * is long sided duplex printing (i.e. no tumble).
4739      */
4740     prt_duplex = TRUE;
4741     prt_tumble = FALSE;
4742     psettings->duplex = 1;
4743     if (printer_opts[OPT_PRINT_DUPLEX].present)
4744     {
4745 	if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
4746 	{
4747 	    prt_duplex = FALSE;
4748 	    psettings->duplex = 0;
4749 	}
4750 	else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
4751 									 == 0)
4752 	    prt_tumble = TRUE;
4753     }
4754 
4755     /* For now user abort not supported */
4756     psettings->user_abort = 0;
4757 
4758     /* If the user didn't specify a file name, use a temp file. */
4759     if (psettings->outfile == NULL)
4760     {
4761 	prt_ps_file_name = vim_tempname('p');
4762 	if (prt_ps_file_name == NULL)
4763 	{
4764 	    EMSG(_(e_notmp));
4765 	    return FAIL;
4766 	}
4767 	prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
4768     }
4769     else
4770     {
4771 	p = expand_env_save(psettings->outfile);
4772 	if (p != NULL)
4773 	{
4774 	    prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
4775 	    vim_free(p);
4776 	}
4777     }
4778     if (prt_ps_fd == NULL)
4779     {
4780 	EMSG(_("E324: Can't open PostScript output file"));
4781 	mch_print_cleanup();
4782 	return FAIL;
4783     }
4784 
4785     ga_init2(&prt_ps_buffer, (int)sizeof(char), PRT_PS_DEFAULT_BUFFER_SIZE);
4786 
4787     prt_page_num = 0;
4788 
4789     prt_attribute_change = FALSE;
4790     prt_need_moveto = FALSE;
4791     prt_need_font = FALSE;
4792     prt_need_fgcol = FALSE;
4793     prt_need_bgcol = FALSE;
4794     prt_need_underline = FALSE;
4795 
4796     prt_file_error = FALSE;
4797 
4798     return OK;
4799 }
4800 
4801     static int
4802 prt_add_resource(resource)
4803     struct prt_ps_resource_S *resource;
4804 {
4805     FILE*	fd_resource;
4806     char_u	resource_buffer[512];
4807     char	*resource_name[1];
4808     size_t	bytes_read;
4809 
4810     fd_resource = mch_fopen((char *)resource->filename, READBIN);
4811     if (fd_resource == NULL)
4812     {
4813 	EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
4814 	return FALSE;
4815     }
4816     resource_name[0] = (char *)resource->title;
4817     prt_dsc_resources("BeginResource",
4818 			    resource_types[resource->type], 1, resource_name);
4819 
4820     prt_dsc_textline("BeginDocument", (char *)resource->filename);
4821 
4822     for (;;)
4823     {
4824 	bytes_read = fread((char *)resource_buffer, sizeof(char_u),
4825 			   sizeof(resource_buffer), fd_resource);
4826 	if (ferror(fd_resource))
4827 	{
4828 	    EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
4829 							    resource->filename);
4830 	    fclose(fd_resource);
4831 	    return FALSE;
4832 	}
4833 	if (bytes_read == 0)
4834 	    break;
4835 	prt_write_file_raw_len(resource_buffer, bytes_read);
4836 	if (prt_file_error)
4837 	{
4838 	    fclose(fd_resource);
4839 	    return FALSE;
4840 	}
4841     }
4842     fclose(fd_resource);
4843 
4844     prt_dsc_noarg("EndDocument");
4845 
4846     prt_dsc_noarg("EndResource");
4847 
4848     return TRUE;
4849 }
4850 
4851     int
4852 mch_print_begin(psettings)
4853     prt_settings_T *psettings;
4854 {
4855     time_t	now;
4856     int		bbox[4];
4857     char	*p_time;
4858     char	*resource[1];
4859     double      left;
4860     double      right;
4861     double      top;
4862     double      bottom;
4863     struct prt_ps_resource_S res_prolog;
4864     struct prt_ps_resource_S res_encoding;
4865     char_u      buffer[256];
4866     char_u      *p_encoding;
4867 #ifdef FEAT_MBYTE
4868     int		props;
4869 #endif
4870 
4871     /*
4872      * PS DSC Header comments - no PS code!
4873      */
4874     prt_dsc_start();
4875     prt_dsc_textline("Title", (char *)psettings->jobname);
4876     /* TODO - platform dependent user name retrieval */
4877     prt_dsc_textline("For", "Unknown");
4878     prt_dsc_textline("Creator", VIM_VERSION_LONG);
4879     /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
4880     now = time(NULL);
4881     p_time = ctime(&now);
4882     /* Note: ctime() adds a \n so we have to remove it :-( */
4883     *(vim_strchr((char_u *)p_time, '\n')) = '\0';
4884     prt_dsc_textline("CreationDate", p_time);
4885     prt_dsc_textline("DocumentData", "Clean8Bit");
4886     prt_dsc_textline("Orientation", "Portrait");
4887     prt_dsc_atend("Pages");
4888     prt_dsc_textline("PageOrder", "Ascend");
4889     /* The bbox does not change with orientation - it is always in the default
4890      * user coordinate system!  We have to recalculate right and bottom
4891      * coordinates based on the font metrics for the bbox to be accurate. */
4892     prt_page_margins(prt_mediasize[prt_media].width,
4893 					    prt_mediasize[prt_media].height,
4894 					    &left, &right, &top, &bottom);
4895     bbox[0] = (int)left;
4896     if (prt_portrait)
4897     {
4898 	/* In portrait printing the fixed point is the top left corner so we
4899 	 * derive the bbox from that point.  We have the expected cpl chars
4900 	 * across the media and lpp lines down the media.
4901 	 */
4902 	bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
4903 							    * prt_line_height);
4904 	bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
4905 									+ 0.5);
4906 	bbox[3] = (int)(top + 0.5);
4907     }
4908     else
4909     {
4910 	/* In landscape printing the fixed point is the bottom left corner so we
4911 	 * derive the bbox from that point.  We have lpp chars across the media
4912 	 * and cpl lines up the media.
4913 	 */
4914 	bbox[1] = (int)bottom;
4915 	bbox[2] = (int)(left + ((psettings->lines_per_page
4916 			      + prt_header_height()) * prt_line_height) + 0.5);
4917 	bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
4918 									+ 0.5);
4919     }
4920     prt_dsc_ints("BoundingBox", 4, bbox);
4921     /* The media width and height does not change with landscape printing! */
4922     prt_dsc_docmedia(prt_mediasize[prt_media].name,
4923 				prt_mediasize[prt_media].width,
4924 				prt_mediasize[prt_media].height,
4925 				(double)0, NULL, NULL);
4926     prt_dsc_resources("DocumentNeededResources", "font", 4,
4927 						     prt_ps_font.ps_fontname);
4928 
4929     /* Search for external resources we supply */
4930     if (!prt_find_resource("prolog", &res_prolog))
4931     {
4932 	EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\""));
4933 	return FALSE;
4934     }
4935     if (!prt_open_resource(&res_prolog))
4936 	return FALSE;
4937     if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION))
4938 	return FALSE;
4939     /* Find an encoding to use for printing.
4940      * Check 'printencoding'. If not set or not found, then use 'encoding'. If
4941      * that cannot be found then default to "latin1".
4942      * Note: VIM specific encoding header is always skipped.
4943      */
4944 #ifdef FEAT_MBYTE
4945     props = enc_canon_props(p_enc);
4946 #endif
4947     p_encoding = enc_skip(p_penc);
4948     if (*p_encoding == NUL
4949 	    || !prt_find_resource((char *)p_encoding, &res_encoding))
4950     {
4951 	/* 'printencoding' not set or not supported - find alternate */
4952 #ifdef FEAT_MBYTE
4953 	p_encoding = enc_skip(p_enc);
4954 	if (!(props & ENC_8BIT)
4955 		|| !prt_find_resource((char *)p_encoding, &res_encoding))
4956 	{
4957 	    /* 8-bit 'encoding' is not supported */
4958 #endif
4959 	    /* Use latin1 as default printing encoding */
4960 	    p_encoding = (char_u *)"latin1";
4961 	    if (!prt_find_resource((char *)p_encoding, &res_encoding))
4962 	    {
4963 		EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
4964 			p_encoding);
4965 		return FALSE;
4966 	    }
4967 #ifdef FEAT_MBYTE
4968 	}
4969 #endif
4970     }
4971     if (!prt_open_resource(&res_encoding))
4972 	return FALSE;
4973     /* For the moment there are no checks on encoding resource files to perform */
4974 #ifdef FEAT_MBYTE
4975     /* Set up encoding conversion if starting from multi-byte */
4976     props = enc_canon_props(p_enc);
4977     if (!(props & ENC_8BIT))
4978     {
4979 	if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
4980 	{
4981 	    EMSG2(_("E620: Unable to convert from multi-byte to \"%s\" encoding"),
4982 		    p_encoding);
4983 	    return FALSE;
4984 	}
4985 	prt_do_conv = TRUE;
4986     }
4987 #endif
4988 
4989     /* List resources supplied */
4990     resource[0] = (char *)buffer;
4991     STRCPY(buffer, res_prolog.title);
4992     STRCAT(buffer, " ");
4993     STRCAT(buffer, res_prolog.version);
4994     prt_dsc_resources("DocumentSuppliedResources", "procset", 1, resource);
4995     STRCPY(buffer, res_encoding.title);
4996     STRCAT(buffer, " ");
4997     STRCAT(buffer, res_encoding.version);
4998     prt_dsc_resources(NULL, "encoding", 1, resource);
4999     prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
5000 #ifdef FEAT_SYN_HL
5001 					psettings->do_syntax
5002 #else
5003 					0
5004 #endif
5005 					, prt_num_copies);
5006     prt_dsc_noarg("EndComments");
5007 
5008     /*
5009      * PS Document page defaults
5010      */
5011     prt_dsc_noarg("BeginDefaults");
5012 
5013     /* List font resources most likely common to all pages */
5014     prt_dsc_resources("PageResources", "font", 4, prt_ps_font.ps_fontname);
5015     /* Paper will be used for all pages */
5016     prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
5017 
5018     prt_dsc_noarg("EndDefaults");
5019 
5020     /*
5021      * PS Document prolog inclusion - all required procsets.
5022      */
5023     prt_dsc_noarg("BeginProlog");
5024 
5025     /* For now there is just the one procset to be included in the PS file. */
5026     if (!prt_add_resource(&res_prolog))
5027 	return FALSE;
5028 
5029     /* There will be only one font encoding to be included in the PS file. */
5030     if (!prt_add_resource(&res_encoding))
5031 	return FALSE;
5032 
5033     prt_dsc_noarg("EndProlog");
5034 
5035     /*
5036      * PS Document setup - must appear after the prolog
5037      */
5038     prt_dsc_noarg("BeginSetup");
5039 
5040     /* Device setup - page size and number of uncollated copies */
5041     prt_write_int((int)prt_mediasize[prt_media].width);
5042     prt_write_int((int)prt_mediasize[prt_media].height);
5043     prt_write_int(0);
5044     prt_write_string("sps\n");
5045     prt_write_int(prt_num_copies);
5046     prt_write_string("nc\n");
5047     prt_write_boolean(prt_duplex);
5048     prt_write_boolean(prt_tumble);
5049     prt_write_string("dt\n");
5050     prt_write_boolean(prt_collate);
5051     prt_write_string("c\n");
5052 
5053     /* Font resource inclusion and definition */
5054     prt_dsc_resources("IncludeResource", "font", 1,
5055 				 &prt_ps_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5056     prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
5057 				  prt_ps_font.ps_fontname[PRT_PS_FONT_ROMAN]);
5058     prt_dsc_resources("IncludeResource", "font", 1,
5059 				  &prt_ps_font.ps_fontname[PRT_PS_FONT_BOLD]);
5060     prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
5061 				   prt_ps_font.ps_fontname[PRT_PS_FONT_BOLD]);
5062     prt_dsc_resources("IncludeResource", "font", 1,
5063 			       &prt_ps_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5064     prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
5065 				prt_ps_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
5066     prt_dsc_resources("IncludeResource", "font", 1,
5067 			   &prt_ps_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5068     prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
5069 			    prt_ps_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
5070 
5071     /* Misc constant vars used for underlining and background rects */
5072     prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
5073 						prt_ps_font.uline_offset), 2);
5074     prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
5075 						 prt_ps_font.uline_width), 2);
5076     prt_def_var("BO", prt_bgcol_offset, 2);
5077 
5078     prt_dsc_noarg("EndSetup");
5079 
5080     /* Fail if any problems writing out to the PS file */
5081     return !prt_file_error;
5082 }
5083 
5084     void
5085 mch_print_end(psettings)
5086     prt_settings_T *psettings;
5087 {
5088     prt_dsc_noarg("Trailer");
5089 
5090     /*
5091      * Output any info we don't know in toto until we finish
5092      */
5093     prt_dsc_ints("Pages", 1, &prt_page_num);
5094 
5095     prt_dsc_noarg("EOF");
5096 
5097     if (!prt_file_error && psettings->outfile == NULL
5098 					&& !got_int && !psettings->user_abort)
5099     {
5100 	/* Close the file first. */
5101 	if (prt_ps_fd != NULL)
5102 	{
5103 	    fclose(prt_ps_fd);
5104 	    prt_ps_fd = NULL;
5105 	}
5106 	prt_message((char_u *)_("Sending to printer..."));
5107 
5108 	/* Not printing to a file: use 'printexpr' to print the file. */
5109 	if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
5110 	    EMSG(_("E365: Failed to print PostScript file"));
5111 	else
5112 	    prt_message((char_u *)_("Print job sent."));
5113     }
5114 
5115     mch_print_cleanup();
5116 }
5117 
5118     int
5119 mch_print_end_page()
5120 {
5121     prt_flush_buffer();
5122 
5123     prt_write_string("re sp\n");
5124 
5125     prt_dsc_noarg("PageTrailer");
5126 
5127     return !prt_file_error;
5128 }
5129 
5130 /*ARGSUSED*/
5131     int
5132 mch_print_begin_page(str)
5133     char_u	*str;
5134 {
5135     int		page_num[2];
5136 
5137     prt_page_num++;
5138 
5139     page_num[0] = page_num[1] = prt_page_num;
5140     prt_dsc_ints("Page", 2, page_num);
5141 
5142     prt_dsc_noarg("BeginPageSetup");
5143 
5144     prt_write_string("sv\n0 g\nF0 sf\n");
5145     prt_fgcol = PRCOLOR_BLACK;
5146     prt_bgcol = PRCOLOR_WHITE;
5147     prt_font = PRT_PS_FONT_ROMAN;
5148 
5149     /* Set up page transformation for landscape printing. */
5150     if (!prt_portrait)
5151     {
5152 	prt_write_int(-((int)prt_mediasize[prt_media].width));
5153 	prt_write_string("sl\n");
5154     }
5155 
5156     prt_dsc_noarg("EndPageSetup");
5157 
5158     /* We have reset the font attributes, force setting them again. */
5159     curr_bg = (long_u)0xffffffff;
5160     curr_fg = (long_u)0xffffffff;
5161     curr_bold = MAYBE;
5162 
5163     return !prt_file_error;
5164 }
5165 
5166     int
5167 mch_print_blank_page()
5168 {
5169     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
5170 }
5171 
5172 static float prt_pos_x = 0;
5173 static float prt_pos_y = 0;
5174 
5175     void
5176 mch_print_start_line(margin, page_line)
5177     int		margin;
5178     int		page_line;
5179 {
5180     prt_pos_x = prt_left_margin;
5181     if (margin)
5182 	prt_pos_x -= prt_number_width;
5183 
5184     prt_pos_y = prt_top_margin - prt_first_line_height -
5185 					page_line * prt_line_height;
5186 
5187     prt_attribute_change = TRUE;
5188     prt_need_moveto = TRUE;
5189 }
5190 
5191 /*ARGSUSED*/
5192     int
5193 mch_print_text_out(p, len)
5194     char_u	*p;
5195     int		len;
5196 {
5197     int		need_break;
5198     char_u	ch;
5199     char_u      ch_buff[8];
5200 
5201     /* Output any required changes to the graphics state, after flushing any
5202      * text buffered so far.
5203      */
5204     if (prt_attribute_change)
5205     {
5206 	prt_flush_buffer();
5207 	/* Reset count of number of chars that will be printed */
5208 	prt_text_count = 0;
5209 
5210 	if (prt_need_moveto)
5211 	{
5212 	    prt_pos_x_moveto = prt_pos_x;
5213 	    prt_pos_y_moveto = prt_pos_y;
5214 	    prt_do_moveto = TRUE;
5215 
5216 	    prt_need_moveto = FALSE;
5217 	}
5218 	if (prt_need_font)
5219 	{
5220 	    prt_write_string("F");
5221 	    prt_write_int(prt_font);
5222 	    prt_write_string("sf\n");
5223 	    prt_need_font = FALSE;
5224 	}
5225 	if (prt_need_fgcol)
5226 	{
5227 	    int     r, g, b;
5228 	    r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
5229 	    g = ((unsigned)prt_fgcol & 0xff00) >> 8;
5230 	    b = prt_fgcol & 0xff;
5231 
5232 	    prt_write_real(r / 255.0, 3);
5233 	    if (r == g && g == b)
5234 	    {
5235 		prt_write_string("g\n");
5236 	    }
5237 	    else
5238 	    {
5239 		prt_write_real(g / 255.0, 3);
5240 		prt_write_real(b / 255.0, 3);
5241 		prt_write_string("r\n");
5242 	    }
5243 	    prt_need_fgcol = FALSE;
5244 	}
5245 
5246 	if (prt_bgcol != PRCOLOR_WHITE)
5247 	{
5248 	    prt_new_bgcol = prt_bgcol;
5249 	    if (prt_need_bgcol)
5250 		prt_do_bgcol = TRUE;
5251 	}
5252 	else
5253 	    prt_do_bgcol = FALSE;
5254 	prt_need_bgcol = FALSE;
5255 
5256 	if (prt_need_underline)
5257 	    prt_do_underline = prt_underline;
5258 	prt_need_underline = FALSE;
5259 
5260 	prt_attribute_change = FALSE;
5261     }
5262 
5263 #ifdef FEAT_MBYTE
5264     if (prt_do_conv)
5265     {
5266 	/* Convert from multi-byte to 8-bit encoding */
5267 	p = string_convert(&prt_conv, p, &len);
5268 	if (p == NULL)
5269 	    p = (char_u *)"";
5270     }
5271 #endif
5272     /* Add next character to buffer of characters to output.
5273      * Note: One printed character may require several PS characters to
5274      * represent it, but we only count them as one printed character.
5275      */
5276     ch = *p;
5277     if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
5278     {
5279 	/* Convert non-printing characters to either their escape or octal
5280 	 * sequence, ensures PS sent over a serial line does not interfere with
5281 	 * the comms protocol.
5282 	 * Note: For EBCDIC we need to write out the escape sequences as ASCII
5283 	 * codes!
5284 	 * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
5285 	 */
5286 	ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
5287 	switch (ch)
5288 	{
5289 	    case BS:   ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
5290 	    case TAB:  ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
5291 	    case NL:   ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
5292 	    case FF:   ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
5293 	    case CAR:  ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
5294 	    case '(':  ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
5295 	    case ')':  ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
5296 	    case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
5297 
5298 	    default:
5299 		       sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
5300 #ifdef EBCDIC
5301 		       ebcdic2ascii(ch_buff, 3);
5302 #endif
5303 		       ga_append(&prt_ps_buffer, ch_buff[0]);
5304 		       ga_append(&prt_ps_buffer, ch_buff[1]);
5305 		       ga_append(&prt_ps_buffer, ch_buff[2]);
5306 		       break;
5307 	}
5308     }
5309     else
5310     ga_append(&prt_ps_buffer, ch);
5311 
5312 #ifdef FEAT_MBYTE
5313     /* Need to free any translated characters */
5314     if (prt_do_conv && (*p != NUL))
5315 	vim_free(p);
5316 #endif
5317 
5318     prt_text_count++;
5319     prt_pos_x += prt_char_width;
5320 
5321     /* The downside of fp - need a little tolerance in the right margin check */
5322     need_break = (prt_pos_x + prt_char_width > (prt_right_margin + 0.01));
5323 
5324     if (need_break)
5325 	prt_flush_buffer();
5326 
5327     return need_break;
5328 }
5329 
5330     void
5331 mch_print_set_font(iBold, iItalic, iUnderline)
5332     int		iBold;
5333     int		iItalic;
5334     int		iUnderline;
5335 {
5336     int		font = 0;
5337 
5338     if (iBold)
5339 	font |= 0x01;
5340     if (iItalic)
5341 	font |= 0x02;
5342 
5343     if (font != prt_font)
5344     {
5345 	prt_font = font;
5346 	prt_attribute_change = TRUE;
5347 	prt_need_font = TRUE;
5348     }
5349     if (prt_underline != iUnderline)
5350     {
5351 	prt_underline = iUnderline;
5352 	prt_attribute_change = TRUE;
5353 	prt_need_underline = TRUE;
5354     }
5355 }
5356 
5357     void
5358 mch_print_set_bg(bgcol)
5359     long_u	bgcol;
5360 {
5361     prt_bgcol = bgcol;
5362     prt_attribute_change = TRUE;
5363     prt_need_bgcol = TRUE;
5364 }
5365 
5366     void
5367 mch_print_set_fg(fgcol)
5368     long_u	fgcol;
5369 {
5370     if (fgcol != (long_u)prt_fgcol)
5371     {
5372 	prt_fgcol = fgcol;
5373 	prt_attribute_change = TRUE;
5374 	prt_need_fgcol = TRUE;
5375     }
5376 }
5377 
5378 # endif /*FEAT_POSTSCRIPT*/
5379 #endif /*FEAT_PRINTER*/
5380 
5381 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5382 	&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
5383 static char *get_locale_val __ARGS((int what));
5384 
5385     static char *
5386 get_locale_val(what)
5387     int		what;
5388 {
5389     char	*loc;
5390 
5391     /* Obtain the locale value from the libraries.  For DJGPP this is
5392      * redefined and it doesn't use the arguments. */
5393     loc = setlocale(what, NULL);
5394 
5395 # if defined(__BORLANDC__)
5396     if (loc != NULL)
5397     {
5398 	char_u	*p;
5399 
5400 	/* Borland returns something like "LC_CTYPE=<name>\n"
5401 	 * Let's try to fix that bug here... */
5402 	p = vim_strchr(loc, '=');
5403 	if (p != NULL)
5404 	{
5405 	    loc = ++p;
5406 	    while (*p != NUL)	/* remove trailing newline */
5407 	    {
5408 		if (*p < ' ')
5409 		{
5410 		    *p = NUL;
5411 		    break;
5412 		}
5413 		++p;
5414 	    }
5415 	}
5416     }
5417 # endif
5418 
5419     return loc;
5420 }
5421 #endif
5422 
5423 
5424 #ifdef WIN32
5425 /*
5426  * On MS-Windows locale names are strings like "German_Germany.1252", but
5427  * gettext expects "de".  Try to translate one into another here for a few
5428  * supported languages.
5429  */
5430     static char_u *
5431 gettext_lang(char_u *name)
5432 {
5433     int		i;
5434     static char *(mtable[]) = {
5435 			"afrikaans",	"af",
5436 			"czech",	"cs",
5437 			"dutch",	"nl",
5438 			"german",	"de",
5439 			"english_united kingdom", "en_GB",
5440 			"spanish",	"es",
5441 			"french",	"fr",
5442 			"italian",	"it",
5443 			"japanese",	"ja",
5444 			"korean",	"ko",
5445 			"norwegian",	"no",
5446 			"polish",	"pl",
5447 			"russian",	"ru",
5448 			"slovak",	"sk",
5449 			"swedish",	"sv",
5450 			"ukrainian",	"uk",
5451 			"chinese_china", "zh_CN",
5452 			"chinese_taiwan", "zh_TW",
5453 			NULL};
5454 
5455     for (i = 0; mtable[i] != NULL; i += 2)
5456 	if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
5457 	    return mtable[i + 1];
5458     return name;
5459 }
5460 #endif
5461 
5462 #if defined(FEAT_MULTI_LANG) || defined(PROTO)
5463 /*
5464  * Obtain the current messages language.  Used to set the default for
5465  * 'helplang'.  May return NULL or an empty string.
5466  */
5467     char_u *
5468 get_mess_lang()
5469 {
5470     char_u *p;
5471 
5472 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE))
5473 #  if defined(LC_MESSAGES)
5474     p = (char_u *)get_locale_val(LC_MESSAGES);
5475 #  else
5476     /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
5477      * may be set to the LCID number. */
5478     p = (char_u *)get_locale_val(LC_ALL);
5479 #  endif
5480 # else
5481     p = mch_getenv((char_u *)"LC_ALL");
5482     if (p == NULL || *p == NUL)
5483     {
5484 	p = mch_getenv((char_u *)"LC_MESSAGES");
5485 	if (p == NULL || *p == NUL)
5486 	    p = mch_getenv((char_u *)"LANG");
5487     }
5488 # endif
5489 # ifdef WIN32
5490     p = gettext_lang(p);
5491 # endif
5492     return p;
5493 }
5494 #endif
5495 
5496 #if !defined(LC_MESSAGES) \
5497     && (((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5498 		&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) \
5499 	    || defined(FEAT_EVAL))
5500 static char_u *get_mess_env __ARGS((void));
5501 
5502 /*
5503  * Get the language used for messages from the environment.
5504  */
5505     static char_u *
5506 get_mess_env()
5507 {
5508     char_u	*p;
5509 
5510     p = mch_getenv((char_u *)"LC_ALL");
5511     if (p == NULL || *p == NUL)
5512     {
5513 	p = mch_getenv((char_u *)"LC_MESSAGES");
5514 	if (p == NULL || *p == NUL)
5515 	{
5516 	    p = mch_getenv((char_u *)"LANG");
5517 	    if (p != NULL && VIM_ISDIGIT(*p))
5518 		p = NULL;		/* ignore something like "1043" */
5519 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
5520 	    if (p == NULL || *p == NUL)
5521 		p = (char_u *)get_locale_val(LC_CTYPE);
5522 # endif
5523 	}
5524     }
5525     return p;
5526 }
5527 #endif
5528 
5529 #if defined(FEAT_EVAL) || defined(PROTO)
5530 
5531 /*
5532  * Set the "v:lang" variable according to the current locale setting.
5533  * Also do "v:lc_time"and "v:ctype".
5534  */
5535     void
5536 set_lang_var()
5537 {
5538     char_u	*loc;
5539 
5540 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
5541     loc = (char_u *)get_locale_val(LC_CTYPE);
5542 # else
5543     /* setlocale() not supported: use the default value */
5544     loc = (char_u *)"C";
5545 # endif
5546     set_vim_var_string(VV_CTYPE, loc, -1);
5547 
5548     /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
5549      * back to LC_CTYPE if it's empty. */
5550 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES)
5551     loc = (char_u *)get_locale_val(LC_MESSAGES);
5552 # else
5553     loc = get_mess_env();
5554 # endif
5555     set_vim_var_string(VV_LANG, loc, -1);
5556 
5557 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
5558     loc = (char_u *)get_locale_val(LC_TIME);
5559 # endif
5560     set_vim_var_string(VV_LC_TIME, loc, -1);
5561 }
5562 #endif
5563 
5564 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5565 	&& (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
5566 /*
5567  * ":language":  Set the language (locale).
5568  */
5569     void
5570 ex_language(eap)
5571     exarg_T	*eap;
5572 {
5573     char	*loc;
5574     char_u	*p;
5575     char_u	*name;
5576     int		what = LC_ALL;
5577     char	*whatstr = "";
5578 #ifdef LC_MESSAGES
5579 # define VIM_LC_MESSAGES LC_MESSAGES
5580 #else
5581 # define VIM_LC_MESSAGES 6789
5582 #endif
5583 
5584     name = eap->arg;
5585 
5586     /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
5587      * Allow abbreviation, but require at least 3 characters to avoid
5588      * confusion with a two letter language name "me" or "ct". */
5589     p = skiptowhite(eap->arg);
5590     if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
5591     {
5592 	if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
5593 	{
5594 	    what = VIM_LC_MESSAGES;
5595 	    name = skipwhite(p);
5596 	    whatstr = "messages ";
5597 	}
5598 	else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
5599 	{
5600 	    what = LC_CTYPE;
5601 	    name = skipwhite(p);
5602 	    whatstr = "ctype ";
5603 	}
5604 	else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
5605 	{
5606 	    what = LC_TIME;
5607 	    name = skipwhite(p);
5608 	    whatstr = "time ";
5609 	}
5610     }
5611 
5612     if (*name == NUL)
5613     {
5614 #ifndef LC_MESSAGES
5615 	if (what == VIM_LC_MESSAGES)
5616 	    p = get_mess_env();
5617 	else
5618 #endif
5619 	    p = (char_u *)setlocale(what, NULL);
5620 	if (p == NULL || *p == NUL)
5621 	    p = (char_u *)"Unknown";
5622 	smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5623     }
5624     else
5625     {
5626 #ifndef LC_MESSAGES
5627 	if (what == VIM_LC_MESSAGES)
5628 	    loc = "";
5629 	else
5630 #endif
5631 	    loc = setlocale(what, (char *)name);
5632 	if (loc == NULL)
5633 	    EMSG2(_("E197: Cannot set language to \"%s\""), name);
5634 	else
5635 	{
5636 #ifdef HAVE_NL_MSG_CAT_CNTR
5637 	    /* Need to do this for GNU gettext, otherwise cached translations
5638 	     * will be used again. */
5639 	    extern int _nl_msg_cat_cntr;
5640 
5641 	    ++_nl_msg_cat_cntr;
5642 #endif
5643 	    /* Reset $LC_ALL, otherwise it would overrule everyting. */
5644 	    vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5645 
5646 	    if (what != LC_TIME)
5647 	    {
5648 		/* Tell gettext() what to translate to.  It apparently doesn't
5649 		 * use the currently effective locale.  Also do this when
5650 		 * FEAT_GETTEXT isn't defined, so that shell commands use this
5651 		 * value. */
5652 		if (what == LC_ALL)
5653 		    vim_setenv((char_u *)"LANG", name);
5654 		if (what != LC_CTYPE)
5655 		{
5656 		    char_u	*mname;
5657 #ifdef WIN32
5658 		    mname = gettext_lang(name);
5659 #else
5660 		    mname = name;
5661 #endif
5662 		    vim_setenv((char_u *)"LC_MESSAGES", mname);
5663 #ifdef FEAT_MULTI_LANG
5664 		    set_helplang_default(mname);
5665 #endif
5666 		}
5667 
5668 		/* Set $LC_CTYPE, because it overrules $LANG, and
5669 		 * gtk_set_locale() calls setlocale() again.  gnome_init()
5670 		 * sets $LC_CTYPE to "en_US" (that's a bug!). */
5671 		if (what != VIM_LC_MESSAGES)
5672 		    vim_setenv((char_u *)"LC_CTYPE", name);
5673 # ifdef FEAT_GUI_GTK
5674 		/* Let GTK know what locale we're using.  Not sure this is
5675 		 * really needed... */
5676 		if (gui.in_use)
5677 		    (void)gtk_set_locale();
5678 # endif
5679 	    }
5680 
5681 # ifdef FEAT_EVAL
5682 	    /* Set v:lang, v:lc_time and v:ctype to the final result. */
5683 	    set_lang_var();
5684 # endif
5685 	}
5686     }
5687 }
5688 
5689 # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
5690 /*
5691  * Function given to ExpandGeneric() to obtain the possible arguments of the
5692  * ":language" command.
5693  */
5694 /*ARGSUSED*/
5695     char_u *
5696 get_lang_arg(xp, idx)
5697     expand_T	*xp;
5698     int		idx;
5699 {
5700     if (idx == 0)
5701 	return (char_u *)"messages";
5702     if (idx == 1)
5703 	return (char_u *)"ctype";
5704     if (idx == 2)
5705 	return (char_u *)"time";
5706     return NULL;
5707 }
5708 # endif
5709 
5710 #endif
5711