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