xref: /vim-8.2.3635/src/message.c (revision df1bdc92)
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  * message.c: functions for displaying messages on the command line
12  */
13 
14 #define MESSAGE_FILE		/* don't include prototype for smsg() */
15 
16 #include "vim.h"
17 
18 static int other_sourcing_name __ARGS((void));
19 static char_u *get_emsg_source __ARGS((void));
20 static char_u *get_emsg_lnum __ARGS((void));
21 static void add_msg_hist __ARGS((char_u *s, int len, int attr));
22 static void hit_return_msg __ARGS((void));
23 static void msg_home_replace_attr __ARGS((char_u *fname, int attr));
24 #ifdef FEAT_MBYTE
25 static char_u *screen_puts_mbyte __ARGS((char_u *s, int l, int attr));
26 #endif
27 static void msg_puts_attr_len __ARGS((char_u *str, int maxlen, int attr));
28 static void msg_puts_display __ARGS((char_u *str, int maxlen, int attr, int recurse));
29 static void msg_scroll_up __ARGS((void));
30 static void inc_msg_scrolled __ARGS((void));
31 static void store_sb_text __ARGS((char_u **sb_str, char_u *s, int attr, int *sb_col, int finish));
32 static void t_puts __ARGS((int *t_col, char_u *t_s, char_u *s, int attr));
33 static void msg_puts_printf __ARGS((char_u *str, int maxlen));
34 static int do_more_prompt __ARGS((int typed_char));
35 static void msg_screen_putchar __ARGS((int c, int attr));
36 static int  msg_check_screen __ARGS((void));
37 static void redir_write __ARGS((char_u *s, int maxlen));
38 static void verbose_write __ARGS((char_u *s, int maxlen));
39 #ifdef FEAT_CON_DIALOG
40 static char_u *msg_show_console_dialog __ARGS((char_u *message, char_u *buttons, int dfltbutton));
41 static int	confirm_msg_used = FALSE;	/* displaying confirm_msg */
42 static char_u	*confirm_msg = NULL;		/* ":confirm" message */
43 static char_u	*confirm_msg_tail;		/* tail of confirm_msg */
44 #endif
45 
46 struct msg_hist
47 {
48     struct msg_hist	*next;
49     char_u		*msg;
50     int			attr;
51 };
52 
53 static struct msg_hist *first_msg_hist = NULL;
54 static struct msg_hist *last_msg_hist = NULL;
55 static int msg_hist_len = 0;
56 static int msg_hist_off = FALSE;	/* don't add messages to history */
57 
58 /*
59  * When writing messages to the screen, there are many different situations.
60  * A number of variables is used to remember the current state:
61  * msg_didany	    TRUE when messages were written since the last time the
62  *		    user reacted to a prompt.
63  *		    Reset: After hitting a key for the hit-return prompt,
64  *		    hitting <CR> for the command line or input().
65  *		    Set: When any message is written to the screen.
66  * msg_didout	    TRUE when something was written to the current line.
67  *		    Reset: When advancing to the next line, when the current
68  *		    text can be overwritten.
69  *		    Set: When any message is written to the screen.
70  * msg_nowait	    No extra delay for the last drawn message.
71  *		    Used in normal_cmd() before the mode message is drawn.
72  * emsg_on_display  There was an error message recently.  Indicates that there
73  *		    should be a delay before redrawing.
74  * msg_scroll	    The next message should not overwrite the current one.
75  * msg_scrolled	    How many lines the screen has been scrolled (because of
76  *		    messages).  Used in update_screen() to scroll the screen
77  *		    back.  Incremented each time the screen scrolls a line.
78  * msg_scrolled_ign  TRUE when msg_scrolled is non-zero and msg_puts_attr()
79  *		    writes something without scrolling should not make
80  *		    need_wait_return to be set.  This is a hack to make ":ts"
81  *		    work without an extra prompt.
82  * lines_left	    Number of lines available for messages before the
83  *		    more-prompt is to be given.
84  * need_wait_return TRUE when the hit-return prompt is needed.
85  *		    Reset: After giving the hit-return prompt, when the user
86  *		    has answered some other prompt.
87  *		    Set: When the ruler or typeahead display is overwritten,
88  *		    scrolling the screen for some message.
89  * keep_msg	    Message to be displayed after redrawing the screen, in
90  *		    main_loop().
91  *		    This is an allocated string or NULL when not used.
92  */
93 
94 /*
95  * msg(s) - displays the string 's' on the status line
96  * When terminal not initialized (yet) mch_errmsg(..) is used.
97  * return TRUE if wait_return not called
98  */
99     int
100 msg(s)
101     char_u	*s;
102 {
103     return msg_attr_keep(s, 0, FALSE);
104 }
105 
106 #if defined(FEAT_EVAL) || defined(FEAT_X11) || defined(USE_XSMP) \
107     || defined(PROTO)
108 /*
109  * Like msg() but keep it silent when 'verbosefile' is set.
110  */
111     int
112 verb_msg(s)
113     char_u	*s;
114 {
115     int		n;
116 
117     verbose_enter();
118     n = msg_attr_keep(s, 0, FALSE);
119     verbose_leave();
120 
121     return n;
122 }
123 #endif
124 
125     int
126 msg_attr(s, attr)
127     char_u	*s;
128     int		attr;
129 {
130     return msg_attr_keep(s, attr, FALSE);
131 }
132 
133     int
134 msg_attr_keep(s, attr, keep)
135     char_u	*s;
136     int		attr;
137     int		keep;	    /* TRUE: set keep_msg if it doesn't scroll */
138 {
139     static int	entered = 0;
140     int		retval;
141     char_u	*buf = NULL;
142 
143 #ifdef FEAT_EVAL
144     if (attr == 0)
145 	set_vim_var_string(VV_STATUSMSG, s, -1);
146 #endif
147 
148     /*
149      * It is possible that displaying a messages causes a problem (e.g.,
150      * when redrawing the window), which causes another message, etc..	To
151      * break this loop, limit the recursiveness to 3 levels.
152      */
153     if (entered >= 3)
154 	return TRUE;
155     ++entered;
156 
157     /* Add message to history (unless it's a repeated kept message or a
158      * truncated message) */
159     if (s != keep_msg
160 	    || (*s != '<'
161 		&& last_msg_hist != NULL
162 		&& last_msg_hist->msg != NULL
163 		&& STRCMP(s, last_msg_hist->msg)))
164 	add_msg_hist(s, -1, attr);
165 
166     /* When displaying keep_msg, don't let msg_start() free it, caller must do
167      * that. */
168     if (s == keep_msg)
169 	keep_msg = NULL;
170 
171     /* Truncate the message if needed. */
172     msg_start();
173     buf = msg_strtrunc(s, FALSE);
174     if (buf != NULL)
175 	s = buf;
176 
177     msg_outtrans_attr(s, attr);
178     msg_clr_eos();
179     retval = msg_end();
180 
181     if (keep && retval && vim_strsize(s) < (int)(Rows - cmdline_row - 1)
182 							   * Columns + sc_col)
183 	set_keep_msg(s, 0);
184 
185     vim_free(buf);
186     --entered;
187     return retval;
188 }
189 
190 /*
191  * Truncate a string such that it can be printed without causing a scroll.
192  * Returns an allocated string or NULL when no truncating is done.
193  */
194     char_u *
195 msg_strtrunc(s, force)
196     char_u	*s;
197     int		force;	    /* always truncate */
198 {
199     char_u	*buf = NULL;
200     int		len;
201     int		room;
202 
203     /* May truncate message to avoid a hit-return prompt */
204     if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL)
205 			       && !exmode_active && msg_silent == 0) || force)
206     {
207 	len = vim_strsize(s);
208 	if (msg_scrolled != 0)
209 	    /* Use all the columns. */
210 	    room = (int)(Rows - msg_row) * Columns - 1;
211 	else
212 	    /* Use up to 'showcmd' column. */
213 	    room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
214 	if (len > room && room > 0)
215 	{
216 #ifdef FEAT_MBYTE
217 	    if (enc_utf8)
218 		/* may have up to 18 bytes per cell (6 per char, up to two
219 		 * composing chars) */
220 		buf = alloc((room + 2) * 18);
221 	    else if (enc_dbcs == DBCS_JPNU)
222 		/* may have up to 2 bytes per cell for euc-jp */
223 		buf = alloc((room + 2) * 2);
224 	    else
225 #endif
226 		buf = alloc(room + 2);
227 	    if (buf != NULL)
228 		trunc_string(s, buf, room);
229 	}
230     }
231     return buf;
232 }
233 
234 /*
235  * Truncate a string "s" to "buf" with cell width "room".
236  * "s" and "buf" may be equal.
237  */
238     void
239 trunc_string(s, buf, room)
240     char_u	*s;
241     char_u	*buf;
242     int		room;
243 {
244     int		half;
245     int		len;
246     int		e;
247     int		i;
248     int		n;
249 
250     room -= 3;
251     half = room / 2;
252     len = 0;
253 
254     /* First part: Start of the string. */
255     for (e = 0; len < half; ++e)
256     {
257 	if (s[e] == NUL)
258 	{
259 	    /* text fits without truncating! */
260 	    buf[e] = NUL;
261 	    return;
262 	}
263 	n = ptr2cells(s + e);
264 	if (len + n >= half)
265 	    break;
266 	len += n;
267 	buf[e] = s[e];
268 #ifdef FEAT_MBYTE
269 	if (has_mbyte)
270 	    for (n = (*mb_ptr2len)(s + e); --n > 0; )
271 	    {
272 		++e;
273 		buf[e] = s[e];
274 	    }
275 #endif
276     }
277 
278     /* Last part: End of the string. */
279     i = e;
280 #ifdef FEAT_MBYTE
281     if (enc_dbcs != 0)
282     {
283 	/* For DBCS going backwards in a string is slow, but
284 	 * computing the cell width isn't too slow: go forward
285 	 * until the rest fits. */
286 	n = vim_strsize(s + i);
287 	while (len + n > room)
288 	{
289 	    n -= ptr2cells(s + i);
290 	    i += (*mb_ptr2len)(s + i);
291 	}
292     }
293     else if (enc_utf8)
294     {
295 	/* For UTF-8 we can go backwards easily. */
296 	i = (int)STRLEN(s);
297 	for (;;)
298 	{
299 	    half = i - (*mb_head_off)(s, s + i - 1) - 1;
300 	    n = ptr2cells(s + half);
301 	    if (len + n > room)
302 		break;
303 	    len += n;
304 	    i = half;
305 	}
306     }
307     else
308 #endif
309     {
310 	for (i = (int)STRLEN(s); len + (n = ptr2cells(s + i - 1)) <= room; --i)
311 	    len += n;
312     }
313 
314     /* Set the middle and copy the last part. */
315     mch_memmove(buf + e, "...", (size_t)3);
316     mch_memmove(buf + e + 3, s + i, STRLEN(s + i) + 1);
317 }
318 
319 /*
320  * Automatic prototype generation does not understand this function.
321  * Note: Caller of smgs() and smsg_attr() must check the resulting string is
322  * shorter than IOSIZE!!!
323  */
324 #ifndef PROTO
325 # ifndef HAVE_STDARG_H
326 
327 int
328 #ifdef __BORLANDC__
329 _RTLENTRYF
330 #endif
331 smsg __ARGS((char_u *, long, long, long,
332 			long, long, long, long, long, long, long));
333 int
334 #ifdef __BORLANDC__
335 _RTLENTRYF
336 #endif
337 smsg_attr __ARGS((int, char_u *, long, long, long,
338 			long, long, long, long, long, long, long));
339 
340 int vim_snprintf __ARGS((char *, size_t, char *, long, long, long,
341 				   long, long, long, long, long, long, long));
342 
343 /*
344  * smsg(str, arg, ...) is like using sprintf(buf, str, arg, ...) and then
345  * calling msg(buf).
346  * The buffer used is IObuff, the message is truncated at IOSIZE.
347  */
348 
349 /* VARARGS */
350     int
351 #ifdef __BORLANDC__
352 _RTLENTRYF
353 #endif
354 smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
355     char_u	*s;
356     long	a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
357 {
358     return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
359 }
360 
361 /* VARARGS */
362     int
363 #ifdef __BORLANDC__
364 _RTLENTRYF
365 #endif
366 smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
367     int		attr;
368     char_u	*s;
369     long	a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
370 {
371     vim_snprintf((char *)IObuff, IOSIZE, (char *)s,
372 				     a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
373     return msg_attr(IObuff, attr);
374 }
375 
376 # else /* HAVE_STDARG_H */
377 
378 int vim_snprintf(char *str, size_t str_m, char *fmt, ...);
379 
380     int
381 #ifdef __BORLANDC__
382 _RTLENTRYF
383 #endif
384 smsg(char_u *s, ...)
385 {
386     va_list arglist;
387 
388     va_start(arglist, s);
389     vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist, NULL);
390     va_end(arglist);
391     return msg(IObuff);
392 }
393 
394     int
395 #ifdef __BORLANDC__
396 _RTLENTRYF
397 #endif
398 smsg_attr(int attr, char_u *s, ...)
399 {
400     va_list arglist;
401 
402     va_start(arglist, s);
403     vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist, NULL);
404     va_end(arglist);
405     return msg_attr(IObuff, attr);
406 }
407 
408 # endif /* HAVE_STDARG_H */
409 #endif
410 
411 /*
412  * Remember the last sourcing name/lnum used in an error message, so that it
413  * isn't printed each time when it didn't change.
414  */
415 static int	last_sourcing_lnum = 0;
416 static char_u   *last_sourcing_name = NULL;
417 
418 /*
419  * Reset the last used sourcing name/lnum.  Makes sure it is displayed again
420  * for the next error message;
421  */
422     void
423 reset_last_sourcing()
424 {
425     vim_free(last_sourcing_name);
426     last_sourcing_name = NULL;
427     last_sourcing_lnum = 0;
428 }
429 
430 /*
431  * Return TRUE if "sourcing_name" differs from "last_sourcing_name".
432  */
433     static int
434 other_sourcing_name()
435 {
436     if (sourcing_name != NULL)
437     {
438 	if (last_sourcing_name != NULL)
439 	    return STRCMP(sourcing_name, last_sourcing_name) != 0;
440 	return TRUE;
441     }
442     return FALSE;
443 }
444 
445 /*
446  * Get the message about the source, as used for an error message.
447  * Returns an allocated string with room for one more character.
448  * Returns NULL when no message is to be given.
449  */
450     static char_u *
451 get_emsg_source()
452 {
453     char_u	*Buf, *p;
454 
455     if (sourcing_name != NULL && other_sourcing_name())
456     {
457 	p = (char_u *)_("Error detected while processing %s:");
458 	Buf = alloc((unsigned)(STRLEN(sourcing_name) + STRLEN(p)));
459 	if (Buf != NULL)
460 	    sprintf((char *)Buf, (char *)p, sourcing_name);
461 	return Buf;
462     }
463     return NULL;
464 }
465 
466 /*
467  * Get the message about the source lnum, as used for an error message.
468  * Returns an allocated string with room for one more character.
469  * Returns NULL when no message is to be given.
470  */
471     static char_u *
472 get_emsg_lnum()
473 {
474     char_u	*Buf, *p;
475 
476     /* lnum is 0 when executing a command from the command line
477      * argument, we don't want a line number then */
478     if (sourcing_name != NULL
479 	    && (other_sourcing_name() || sourcing_lnum != last_sourcing_lnum)
480 	    && sourcing_lnum != 0)
481     {
482 	p = (char_u *)_("line %4ld:");
483 	Buf = alloc((unsigned)(STRLEN(p) + 20));
484 	if (Buf != NULL)
485 	    sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);
486 	return Buf;
487     }
488     return NULL;
489 }
490 
491 /*
492  * Display name and line number for the source of an error.
493  * Remember the file name and line number, so that for the next error the info
494  * is only displayed if it changed.
495  */
496     void
497 msg_source(attr)
498     int		attr;
499 {
500     char_u	*p;
501 
502     ++no_wait_return;
503     p = get_emsg_source();
504     if (p != NULL)
505     {
506 	msg_attr(p, attr);
507 	vim_free(p);
508     }
509     p = get_emsg_lnum();
510     if (p != NULL)
511     {
512 	msg_attr(p, hl_attr(HLF_N));
513 	vim_free(p);
514 	last_sourcing_lnum = sourcing_lnum;  /* only once for each line */
515     }
516 
517     /* remember the last sourcing name printed, also when it's empty */
518     if (sourcing_name == NULL || other_sourcing_name())
519     {
520 	vim_free(last_sourcing_name);
521 	if (sourcing_name == NULL)
522 	    last_sourcing_name = NULL;
523 	else
524 	    last_sourcing_name = vim_strsave(sourcing_name);
525     }
526     --no_wait_return;
527 }
528 
529 /*
530  * emsg() - display an error message
531  *
532  * Rings the bell, if appropriate, and calls message() to do the real work
533  * When terminal not initialized (yet) mch_errmsg(..) is used.
534  *
535  * return TRUE if wait_return not called
536  */
537     int
538 emsg(s)
539     char_u	*s;
540 {
541     int		attr;
542     char_u	*p;
543 #ifdef FEAT_EVAL
544     int		ignore = FALSE;
545     int		severe;
546 #endif
547 
548     called_emsg = TRUE;
549     ex_exitval = 1;
550 
551     /*
552      * If "emsg_severe" is TRUE: When an error exception is to be thrown,
553      * prefer this message over previous messages for the same command.
554      */
555 #ifdef FEAT_EVAL
556     severe = emsg_severe;
557     emsg_severe = FALSE;
558 #endif
559 
560     /*
561      * If "emsg_off" is set: no error messages at the moment.
562      * If 'debug' is set: do error message anyway, but without side effects.
563      * If "emsg_skip" is set: never do error messages.
564      */
565     if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL)
566 #ifdef FEAT_EVAL
567 	    || emsg_skip > 0
568 #endif
569 	    )
570 	return TRUE;
571 
572     if (!emsg_off)
573     {
574 #ifdef FEAT_EVAL
575 	/*
576 	 * Cause a throw of an error exception if appropriate.  Don't display
577 	 * the error message in this case.  (If no matching catch clause will
578 	 * be found, the message will be displayed later on.)  "ignore" is set
579 	 * when the message should be ignored completely (used for the
580 	 * interrupt message).
581 	 */
582 	if (cause_errthrow(s, severe, &ignore) == TRUE)
583 	{
584 	    if (!ignore)
585 		did_emsg = TRUE;
586 	    return TRUE;
587 	}
588 
589 	/* set "v:errmsg", also when using ":silent! cmd" */
590 	set_vim_var_string(VV_ERRMSG, s, -1);
591 #endif
592 
593 	/*
594 	 * When using ":silent! cmd" ignore error messsages.
595 	 * But do write it to the redirection file.
596 	 */
597 	if (emsg_silent != 0)
598 	{
599 	    msg_start();
600 	    p = get_emsg_source();
601 	    if (p != NULL)
602 	    {
603 		STRCAT(p, "\n");
604 		redir_write(p, -1);
605 		vim_free(p);
606 	    }
607 	    p = get_emsg_lnum();
608 	    if (p != NULL)
609 	    {
610 		STRCAT(p, "\n");
611 		redir_write(p, -1);
612 		vim_free(p);
613 	    }
614 	    redir_write(s, -1);
615 	    return TRUE;
616 	}
617 
618 	/* Reset msg_silent, an error causes messages to be switched back on. */
619 	msg_silent = 0;
620 	cmd_silent = FALSE;
621 
622 	if (global_busy)		/* break :global command */
623 	    ++global_busy;
624 
625 	if (p_eb)
626 	    beep_flush();		/* also includes flush_buffers() */
627 	else
628 	    flush_buffers(FALSE);	/* flush internal buffers */
629 	did_emsg = TRUE;		/* flag for DoOneCmd() */
630     }
631 
632     emsg_on_display = TRUE;	/* remember there is an error message */
633     ++msg_scroll;		/* don't overwrite a previous message */
634     attr = hl_attr(HLF_E);	/* set highlight mode for error messages */
635     if (msg_scrolled != 0)
636 	need_wait_return = TRUE;    /* needed in case emsg() is called after
637 				     * wait_return has reset need_wait_return
638 				     * and a redraw is expected because
639 				     * msg_scrolled is non-zero */
640 
641     /*
642      * Display name and line number for the source of the error.
643      */
644     msg_source(attr);
645 
646     /*
647      * Display the error message itself.
648      */
649     msg_nowait = FALSE;			/* wait for this msg */
650     return msg_attr(s, attr);
651 }
652 
653 /*
654  * Print an error message with one "%s" and one string argument.
655  */
656     int
657 emsg2(s, a1)
658     char_u *s, *a1;
659 {
660     return emsg3(s, a1, NULL);
661 }
662 
663 /* emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. */
664 
665     void
666 emsg_invreg(name)
667     int	    name;
668 {
669     EMSG2(_("E354: Invalid register name: '%s'"), transchar(name));
670 }
671 
672 /*
673  * Like msg(), but truncate to a single line if p_shm contains 't', or when
674  * "force" is TRUE.  This truncates in another way as for normal messages.
675  * Careful: The string may be changed by msg_may_trunc()!
676  * Returns a pointer to the printed message, if wait_return() not called.
677  */
678     char_u *
679 msg_trunc_attr(s, force, attr)
680     char_u	*s;
681     int		force;
682     int		attr;
683 {
684     int		n;
685 
686     /* Add message to history before truncating */
687     add_msg_hist(s, -1, attr);
688 
689     s = msg_may_trunc(force, s);
690 
691     msg_hist_off = TRUE;
692     n = msg_attr(s, attr);
693     msg_hist_off = FALSE;
694 
695     if (n)
696 	return s;
697     return NULL;
698 }
699 
700 /*
701  * Check if message "s" should be truncated at the start (for filenames).
702  * Return a pointer to where the truncated message starts.
703  * Note: May change the message by replacing a character with '<'.
704  */
705     char_u *
706 msg_may_trunc(force, s)
707     int		force;
708     char_u	*s;
709 {
710     int		n;
711     int		room;
712 
713     room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
714     if ((force || (shortmess(SHM_TRUNC) && !exmode_active))
715 	    && (n = (int)STRLEN(s) - room) > 0)
716     {
717 #ifdef FEAT_MBYTE
718 	if (has_mbyte)
719 	{
720 	    int	size = vim_strsize(s);
721 
722 	    /* There may be room anyway when there are multibyte chars. */
723 	    if (size <= room)
724 		return s;
725 
726 	    for (n = 0; size >= room; )
727 	    {
728 		size -= (*mb_ptr2cells)(s + n);
729 		n += (*mb_ptr2len)(s + n);
730 	    }
731 	    --n;
732 	}
733 #endif
734 	s += n;
735 	*s = '<';
736     }
737     return s;
738 }
739 
740     static void
741 add_msg_hist(s, len, attr)
742     char_u	*s;
743     int		len;		/* -1 for undetermined length */
744     int		attr;
745 {
746     struct msg_hist *p;
747 
748     if (msg_hist_off || msg_silent != 0)
749 	return;
750 
751     /* Don't let the message history get too big */
752     while (msg_hist_len > MAX_MSG_HIST_LEN)
753 	(void)delete_first_msg();
754 
755     /* allocate an entry and add the message at the end of the history */
756     p = (struct msg_hist *)alloc((int)sizeof(struct msg_hist));
757     if (p != NULL)
758     {
759 	if (len < 0)
760 	    len = (int)STRLEN(s);
761 	/* remove leading and trailing newlines */
762 	while (len > 0 && *s == '\n')
763 	{
764 	    ++s;
765 	    --len;
766 	}
767 	while (len > 0 && s[len - 1] == '\n')
768 	    --len;
769 	p->msg = vim_strnsave(s, len);
770 	p->next = NULL;
771 	p->attr = attr;
772 	if (last_msg_hist != NULL)
773 	    last_msg_hist->next = p;
774 	last_msg_hist = p;
775 	if (first_msg_hist == NULL)
776 	    first_msg_hist = last_msg_hist;
777 	++msg_hist_len;
778     }
779 }
780 
781 /*
782  * Delete the first (oldest) message from the history.
783  * Returns FAIL if there are no messages.
784  */
785     int
786 delete_first_msg()
787 {
788     struct msg_hist *p;
789 
790     if (msg_hist_len <= 0)
791 	return FAIL;
792     p = first_msg_hist;
793     first_msg_hist = p->next;
794     vim_free(p->msg);
795     vim_free(p);
796     --msg_hist_len;
797     return OK;
798 }
799 
800 /*
801  * ":messages" command.
802  */
803 /*ARGSUSED*/
804     void
805 ex_messages(eap)
806     exarg_T	*eap;
807 {
808     struct msg_hist *p;
809     char_u	    *s;
810 
811     msg_hist_off = TRUE;
812 
813     s = mch_getenv((char_u *)"LANG");
814     if (s != NULL && *s != NUL)
815 	msg_attr((char_u *)
816 		_("Messages maintainer: Bram Moolenaar <[email protected]>"),
817 		hl_attr(HLF_T));
818 
819     for (p = first_msg_hist; p != NULL; p = p->next)
820 	if (p->msg != NULL)
821 	    msg_attr(p->msg, p->attr);
822 
823     msg_hist_off = FALSE;
824 }
825 
826 #if defined(FEAT_CON_DIALOG) || defined(FIND_REPLACE_DIALOG) || defined(PROTO)
827 /*
828  * Call this after prompting the user.  This will avoid a hit-return message
829  * and a delay.
830  */
831     void
832 msg_end_prompt()
833 {
834     need_wait_return = FALSE;
835     emsg_on_display = FALSE;
836     cmdline_row = msg_row;
837     msg_col = 0;
838     msg_clr_eos();
839 }
840 #endif
841 
842 /*
843  * wait for the user to hit a key (normally a return)
844  * if 'redraw' is TRUE, clear and redraw the screen
845  * if 'redraw' is FALSE, just redraw the screen
846  * if 'redraw' is -1, don't redraw at all
847  */
848     void
849 wait_return(redraw)
850     int		redraw;
851 {
852     int		c;
853     int		oldState;
854     int		tmpState;
855     int		had_got_int;
856 
857     if (redraw == TRUE)
858 	must_redraw = CLEAR;
859 
860     /* If using ":silent cmd", don't wait for a return.  Also don't set
861      * need_wait_return to do it later. */
862     if (msg_silent != 0)
863 	return;
864 
865 /*
866  * With the global command (and some others) we only need one return at the
867  * end. Adjust cmdline_row to avoid the next message overwriting the last one.
868  * When inside vgetc(), we can't wait for a typed character at all.
869  */
870     if (vgetc_busy)
871 	return;
872     if (no_wait_return)
873     {
874 	need_wait_return = TRUE;
875 	if (!exmode_active)
876 	    cmdline_row = msg_row;
877 	return;
878     }
879 
880     redir_off = TRUE;		/* don't redirect this message */
881     oldState = State;
882     if (quit_more)
883     {
884 	c = CAR;		/* just pretend CR was hit */
885 	quit_more = FALSE;
886 	got_int = FALSE;
887     }
888     else if (exmode_active)
889     {
890 	MSG_PUTS(" ");		/* make sure the cursor is on the right line */
891 	c = CAR;		/* no need for a return in ex mode */
892 	got_int = FALSE;
893     }
894     else
895     {
896 	/* Make sure the hit-return prompt is on screen when 'guioptions' was
897 	 * just changed. */
898 	screenalloc(FALSE);
899 
900 	State = HITRETURN;
901 #ifdef FEAT_MOUSE
902 	setmouse();
903 #endif
904 #ifdef USE_ON_FLY_SCROLL
905 	dont_scroll = TRUE;		/* disallow scrolling here */
906 #endif
907 	hit_return_msg();
908 
909 	do
910 	{
911 	    /* Remember "got_int", if it is set vgetc() probably returns a
912 	     * CTRL-C, but we need to loop then. */
913 	    had_got_int = got_int;
914 
915 	    /* Don't do mappings here, we put the character back in the
916 	     * typeahead buffer. */
917 	    ++no_mapping;
918 	    ++allow_keys;
919 	    c = safe_vgetc();
920 	    if (had_got_int && !global_busy)
921 		got_int = FALSE;
922 	    --no_mapping;
923 	    --allow_keys;
924 
925 #ifdef FEAT_CLIPBOARD
926 	    /* Strange way to allow copying (yanking) a modeless selection at
927 	     * the hit-enter prompt.  Use CTRL-Y, because the same is used in
928 	     * Cmdline-mode and it's harmless when there is no selection. */
929 	    if (c == Ctrl_Y && clip_star.state == SELECT_DONE)
930 	    {
931 		clip_copy_modeless_selection(TRUE);
932 		c = K_IGNORE;
933 	    }
934 #endif
935 	    if (p_more && !p_cp && (c == 'b' || c == 'k' || c == 'u'
936 						    || c == 'g' || c == K_UP))
937 	    {
938 		/* scroll back to show older messages */
939 		do_more_prompt(c);
940 		if (quit_more)
941 		{
942 		    c = CAR;		/* just pretend CR was hit */
943 		    quit_more = FALSE;
944 		    got_int = FALSE;
945 		}
946 		else
947 		{
948 		    c = K_IGNORE;
949 		    hit_return_msg();
950 		}
951 	    }
952 	} while ((had_got_int && c == Ctrl_C)
953 				|| c == K_IGNORE
954 #ifdef FEAT_GUI
955 				|| c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR
956 #endif
957 #ifdef FEAT_MOUSE
958 				|| c == K_LEFTDRAG   || c == K_LEFTRELEASE
959 				|| c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
960 				|| c == K_RIGHTDRAG  || c == K_RIGHTRELEASE
961 				|| c == K_MOUSEDOWN  || c == K_MOUSEUP
962 				|| (!mouse_has(MOUSE_RETURN)
963 				    && mouse_row < msg_row
964 				    && (c == K_LEFTMOUSE
965 					|| c == K_MIDDLEMOUSE
966 					|| c == K_RIGHTMOUSE
967 					|| c == K_X1MOUSE
968 					|| c == K_X2MOUSE))
969 #endif
970 				);
971 	ui_breakcheck();
972 #ifdef FEAT_MOUSE
973 	/*
974 	 * Avoid that the mouse-up event causes visual mode to start.
975 	 */
976 	if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
977 					  || c == K_X1MOUSE || c == K_X2MOUSE)
978 	    (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0);
979 	else
980 #endif
981 	    if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C)
982 	{
983 	    char_u	buf[2];
984 
985 	    /* Put the character back in the typeahead buffer.  Don't use the
986 	     * stuff buffer, because lmaps wouldn't work. */
987 	    buf[0] = c;
988 	    buf[1] = NUL;
989 	    ins_typebuf(buf, REMAP_YES, 0, !KeyTyped, FALSE);
990 	    do_redraw = TRUE;	    /* need a redraw even though there is
991 				       typeahead */
992 	}
993     }
994     redir_off = FALSE;
995 
996     /*
997      * If the user hits ':', '?' or '/' we get a command line from the next
998      * line.
999      */
1000     if (c == ':' || c == '?' || c == '/')
1001     {
1002 	if (!exmode_active)
1003 	    cmdline_row = msg_row;
1004 	skip_redraw = TRUE;	    /* skip redraw once */
1005 	do_redraw = FALSE;
1006     }
1007 
1008     /*
1009      * If the window size changed set_shellsize() will redraw the screen.
1010      * Otherwise the screen is only redrawn if 'redraw' is set and no ':'
1011      * typed.
1012      */
1013     tmpState = State;
1014     State = oldState;		    /* restore State before set_shellsize */
1015 #ifdef FEAT_MOUSE
1016     setmouse();
1017 #endif
1018     msg_check();
1019 
1020 #if defined(UNIX) || defined(VMS)
1021     /*
1022      * When switching screens, we need to output an extra newline on exit.
1023      */
1024     if (swapping_screen() && !termcap_active)
1025 	newline_on_exit = TRUE;
1026 #endif
1027 
1028     need_wait_return = FALSE;
1029     did_wait_return = TRUE;
1030     emsg_on_display = FALSE;	/* can delete error message now */
1031     lines_left = -1;		/* reset lines_left at next msg_start() */
1032     reset_last_sourcing();
1033     if (keep_msg != NULL && vim_strsize(keep_msg) >=
1034 				  (Rows - cmdline_row - 1) * Columns + sc_col)
1035     {
1036 	vim_free(keep_msg);
1037 	keep_msg = NULL;	    /* don't redisplay message, it's too long */
1038     }
1039 
1040     if (tmpState == SETWSIZE)	    /* got resize event while in vgetc() */
1041     {
1042 	starttermcap();		    /* start termcap before redrawing */
1043 	shell_resized();
1044     }
1045     else if (!skip_redraw
1046 	    && (redraw == TRUE || (msg_scrolled != 0 && redraw != -1)))
1047     {
1048 	starttermcap();		    /* start termcap before redrawing */
1049 	redraw_later(VALID);
1050     }
1051 }
1052 
1053 /*
1054  * Write the hit-return prompt.
1055  */
1056     static void
1057 hit_return_msg()
1058 {
1059     int		save_p_more = p_more;
1060 
1061     p_more = FALSE;	/* don't want see this message when scrolling back */
1062     if (msg_didout)	/* start on a new line */
1063 	msg_putchar('\n');
1064     if (got_int)
1065 	MSG_PUTS(_("Interrupt: "));
1066 
1067     MSG_PUTS_ATTR(_("Press ENTER or type command to continue"), hl_attr(HLF_R));
1068     if (!msg_use_printf())
1069 	msg_clr_eos();
1070     p_more = save_p_more;
1071 }
1072 
1073 /*
1074  * Set "keep_msg" to "s".  Free the old value and check for NULL pointer.
1075  */
1076     void
1077 set_keep_msg(s, attr)
1078     char_u	*s;
1079     int		attr;
1080 {
1081     vim_free(keep_msg);
1082     if (s != NULL && msg_silent == 0)
1083 	keep_msg = vim_strsave(s);
1084     else
1085 	keep_msg = NULL;
1086     keep_msg_more = FALSE;
1087     keep_msg_attr = attr;
1088 }
1089 
1090 #if defined(FEAT_TERMRESPONSE) || defined(PROTO)
1091 /*
1092  * If there currently is a message being displayed, set "keep_msg" to it, so
1093  * that it will be displayed again after redraw.
1094  */
1095     void
1096 set_keep_msg_from_hist()
1097 {
1098     if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0
1099 							  && (State & NORMAL))
1100 	set_keep_msg(last_msg_hist->msg, last_msg_hist->attr);
1101 }
1102 #endif
1103 
1104 /*
1105  * Prepare for outputting characters in the command line.
1106  */
1107     void
1108 msg_start()
1109 {
1110     int		did_return = FALSE;
1111 
1112     vim_free(keep_msg);
1113     keep_msg = NULL;			/* don't display old message now */
1114     if (!msg_scroll && full_screen)	/* overwrite last message */
1115     {
1116 	msg_row = cmdline_row;
1117 	msg_col =
1118 #ifdef FEAT_RIGHTLEFT
1119 	    cmdmsg_rl ? Columns - 1 :
1120 #endif
1121 	    0;
1122     }
1123     else if (msg_didout)		    /* start message on next line */
1124     {
1125 	msg_putchar('\n');
1126 	did_return = TRUE;
1127 	if (exmode_active != EXMODE_NORMAL)
1128 	    cmdline_row = msg_row;
1129     }
1130     if (!msg_didany || lines_left < 0)
1131 	msg_starthere();
1132     if (msg_silent == 0)
1133     {
1134 	msg_didout = FALSE;		    /* no output on current line yet */
1135 	cursor_off();
1136     }
1137 
1138     /* when redirecting, may need to start a new line. */
1139     if (!did_return)
1140 	redir_write((char_u *)"\n", -1);
1141 }
1142 
1143 /*
1144  * Note that the current msg position is where messages start.
1145  */
1146     void
1147 msg_starthere()
1148 {
1149     lines_left = cmdline_row;
1150     msg_didany = FALSE;
1151 }
1152 
1153     void
1154 msg_putchar(c)
1155     int		c;
1156 {
1157     msg_putchar_attr(c, 0);
1158 }
1159 
1160     void
1161 msg_putchar_attr(c, attr)
1162     int		c;
1163     int		attr;
1164 {
1165 #ifdef FEAT_MBYTE
1166     char_u	buf[MB_MAXBYTES + 1];
1167 #else
1168     char_u	buf[4];
1169 #endif
1170 
1171     if (IS_SPECIAL(c))
1172     {
1173 	buf[0] = K_SPECIAL;
1174 	buf[1] = K_SECOND(c);
1175 	buf[2] = K_THIRD(c);
1176 	buf[3] = NUL;
1177     }
1178     else
1179     {
1180 #ifdef FEAT_MBYTE
1181 	buf[(*mb_char2bytes)(c, buf)] = NUL;
1182 #else
1183 	buf[0] = c;
1184 	buf[1] = NUL;
1185 #endif
1186     }
1187     msg_puts_attr(buf, attr);
1188 }
1189 
1190     void
1191 msg_outnum(n)
1192     long	n;
1193 {
1194     char_u	buf[20];
1195 
1196     sprintf((char *)buf, "%ld", n);
1197     msg_puts(buf);
1198 }
1199 
1200     void
1201 msg_home_replace(fname)
1202     char_u	*fname;
1203 {
1204     msg_home_replace_attr(fname, 0);
1205 }
1206 
1207 #if defined(FEAT_FIND_ID) || defined(PROTO)
1208     void
1209 msg_home_replace_hl(fname)
1210     char_u	*fname;
1211 {
1212     msg_home_replace_attr(fname, hl_attr(HLF_D));
1213 }
1214 #endif
1215 
1216     static void
1217 msg_home_replace_attr(fname, attr)
1218     char_u  *fname;
1219     int	    attr;
1220 {
1221     char_u	*name;
1222 
1223     name = home_replace_save(NULL, fname);
1224     if (name != NULL)
1225 	msg_outtrans_attr(name, attr);
1226     vim_free(name);
1227 }
1228 
1229 /*
1230  * Output 'len' characters in 'str' (including NULs) with translation
1231  * if 'len' is -1, output upto a NUL character.
1232  * Use attributes 'attr'.
1233  * Return the number of characters it takes on the screen.
1234  */
1235     int
1236 msg_outtrans(str)
1237     char_u	    *str;
1238 {
1239     return msg_outtrans_attr(str, 0);
1240 }
1241 
1242     int
1243 msg_outtrans_attr(str, attr)
1244     char_u	*str;
1245     int		attr;
1246 {
1247     return msg_outtrans_len_attr(str, (int)STRLEN(str), attr);
1248 }
1249 
1250     int
1251 msg_outtrans_len(str, len)
1252     char_u	*str;
1253     int		len;
1254 {
1255     return msg_outtrans_len_attr(str, len, 0);
1256 }
1257 
1258 /*
1259  * Output one character at "p".  Return pointer to the next character.
1260  * Handles multi-byte characters.
1261  */
1262     char_u *
1263 msg_outtrans_one(p, attr)
1264     char_u	*p;
1265     int		attr;
1266 {
1267 #ifdef FEAT_MBYTE
1268     int		l;
1269 
1270     if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
1271     {
1272 	msg_outtrans_len_attr(p, l, attr);
1273 	return p + l;
1274     }
1275 #endif
1276     msg_puts_attr(transchar_byte(*p), attr);
1277     return p + 1;
1278 }
1279 
1280     int
1281 msg_outtrans_len_attr(msgstr, len, attr)
1282     char_u	*msgstr;
1283     int		len;
1284     int		attr;
1285 {
1286     int		retval = 0;
1287     char_u	*str = msgstr;
1288     char_u	*plain_start = msgstr;
1289     char_u	*s;
1290 #ifdef FEAT_MBYTE
1291     int		mb_l;
1292     int		c;
1293 #endif
1294 
1295     /* if MSG_HIST flag set, add message to history */
1296     if (attr & MSG_HIST)
1297     {
1298 	add_msg_hist(str, len, attr);
1299 	attr &= ~MSG_HIST;
1300     }
1301 
1302 #ifdef FEAT_MBYTE
1303     /* If the string starts with a composing character first draw a space on
1304      * which the composing char can be drawn. */
1305     if (enc_utf8 && utf_iscomposing(utf_ptr2char(msgstr)))
1306 	msg_puts_attr((char_u *)" ", attr);
1307 #endif
1308 
1309     /*
1310      * Go over the string.  Special characters are translated and printed.
1311      * Normal characters are printed several at a time.
1312      */
1313     while (--len >= 0)
1314     {
1315 #ifdef FEAT_MBYTE
1316 	if (enc_utf8)
1317 	    /* Don't include composing chars after the end. */
1318 	    mb_l = utfc_ptr2len_len(str, len + 1);
1319 	else if (has_mbyte)
1320 	    mb_l = (*mb_ptr2len)(str);
1321 	else
1322 	    mb_l = 1;
1323 	if (has_mbyte && mb_l > 1)
1324 	{
1325 	    c = (*mb_ptr2char)(str);
1326 	    if (vim_isprintc(c))
1327 		/* printable multi-byte char: count the cells. */
1328 		retval += (*mb_ptr2cells)(str);
1329 	    else
1330 	    {
1331 		/* unprintable multi-byte char: print the printable chars so
1332 		 * far and the translation of the unprintable char. */
1333 		if (str > plain_start)
1334 		    msg_puts_attr_len(plain_start, (int)(str - plain_start),
1335 									attr);
1336 		plain_start = str + mb_l;
1337 		msg_puts_attr(transchar(c), attr == 0 ? hl_attr(HLF_8) : attr);
1338 		retval += char2cells(c);
1339 	    }
1340 	    len -= mb_l - 1;
1341 	    str += mb_l;
1342 	}
1343 	else
1344 #endif
1345 	{
1346 	    s = transchar_byte(*str);
1347 	    if (s[1] != NUL)
1348 	    {
1349 		/* unprintable char: print the printable chars so far and the
1350 		 * translation of the unprintable char. */
1351 		if (str > plain_start)
1352 		    msg_puts_attr_len(plain_start, (int)(str - plain_start),
1353 									attr);
1354 		plain_start = str + 1;
1355 		msg_puts_attr(s, attr == 0 ? hl_attr(HLF_8) : attr);
1356 	    }
1357 	    retval += ptr2cells(str);
1358 	    ++str;
1359 	}
1360     }
1361 
1362     if (str > plain_start)
1363 	/* print the printable chars at the end */
1364 	msg_puts_attr_len(plain_start, (int)(str - plain_start), attr);
1365 
1366     return retval;
1367 }
1368 
1369 #if defined(FEAT_QUICKFIX) || defined(PROTO)
1370     void
1371 msg_make(arg)
1372     char_u  *arg;
1373 {
1374     int	    i;
1375     static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
1376 
1377     arg = skipwhite(arg);
1378     for (i = 5; *arg && i >= 0; --i)
1379 	if (*arg++ != str[i])
1380 	    break;
1381     if (i < 0)
1382     {
1383 	msg_putchar('\n');
1384 	for (i = 0; rs[i]; ++i)
1385 	    msg_putchar(rs[i] - 3);
1386     }
1387 }
1388 #endif
1389 
1390 /*
1391  * Output the string 'str' upto a NUL character.
1392  * Return the number of characters it takes on the screen.
1393  *
1394  * If K_SPECIAL is encountered, then it is taken in conjunction with the
1395  * following character and shown as <F1>, <S-Up> etc.  Any other character
1396  * which is not printable shown in <> form.
1397  * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
1398  * If a character is displayed in one of these special ways, is also
1399  * highlighted (its highlight name is '8' in the p_hl variable).
1400  * Otherwise characters are not highlighted.
1401  * This function is used to show mappings, where we want to see how to type
1402  * the character/string -- webb
1403  */
1404     int
1405 msg_outtrans_special(strstart, from)
1406     char_u	*strstart;
1407     int		from;	/* TRUE for lhs of a mapping */
1408 {
1409     char_u	*str = strstart;
1410     int		retval = 0;
1411     char_u	*string;
1412     int		attr;
1413     int		len;
1414 
1415     attr = hl_attr(HLF_8);
1416     while (*str != NUL)
1417     {
1418 	/* Leading and trailing spaces need to be displayed in <> form. */
1419 	if ((str == strstart || str[1] == NUL) && *str == ' ')
1420 	{
1421 	    string = (char_u *)"<Space>";
1422 	    ++str;
1423 	}
1424 	else
1425 	    string = str2special(&str, from);
1426 	len = vim_strsize(string);
1427 	/* Highlight special keys */
1428 	msg_puts_attr(string, len > 1
1429 #ifdef FEAT_MBYTE
1430 		&& (*mb_ptr2len)(string) <= 1
1431 #endif
1432 		? attr : 0);
1433 	retval += len;
1434     }
1435     return retval;
1436 }
1437 
1438 /*
1439  * Return the printable string for the key codes at "*sp".
1440  * Used for translating the lhs or rhs of a mapping to printable chars.
1441  * Advances "sp" to the next code.
1442  */
1443     char_u *
1444 str2special(sp, from)
1445     char_u	**sp;
1446     int		from;	/* TRUE for lhs of mapping */
1447 {
1448     int			c;
1449     static char_u	buf[7];
1450     char_u		*str = *sp;
1451     int			modifiers = 0;
1452     int			special = FALSE;
1453 
1454 #ifdef FEAT_MBYTE
1455     if (has_mbyte)
1456     {
1457 	char_u	*p;
1458 
1459 	/* Try to un-escape a multi-byte character.  Return the un-escaped
1460 	 * string if it is a multi-byte character. */
1461 	p = mb_unescape(sp);
1462 	if (p != NULL)
1463 	    return p;
1464     }
1465 #endif
1466 
1467     c = *str;
1468     if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
1469     {
1470 	if (str[1] == KS_MODIFIER)
1471 	{
1472 	    modifiers = str[2];
1473 	    str += 3;
1474 	    c = *str;
1475 	}
1476 	if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
1477 	{
1478 	    c = TO_SPECIAL(str[1], str[2]);
1479 	    str += 2;
1480 	    if (c == K_ZERO)	/* display <Nul> as ^@ */
1481 		c = NUL;
1482 	}
1483 	if (IS_SPECIAL(c) || modifiers)	/* special key */
1484 	    special = TRUE;
1485     }
1486     *sp = str + 1;
1487 
1488 #ifdef FEAT_MBYTE
1489     /* For multi-byte characters check for an illegal byte. */
1490     if (has_mbyte && MB_BYTE2LEN(*str) > (*mb_ptr2len)(str))
1491     {
1492 	transchar_nonprint(buf, c);
1493 	return buf;
1494     }
1495 #endif
1496 
1497     /* Make unprintable characters in <> form, also <M-Space> and <Tab>.
1498      * Use <Space> only for lhs of a mapping. */
1499     if (special || char2cells(c) > 1 || (from && c == ' '))
1500 	return get_special_key_name(c, modifiers);
1501     buf[0] = c;
1502     buf[1] = NUL;
1503     return buf;
1504 }
1505 
1506 /*
1507  * Translate a key sequence into special key names.
1508  */
1509     void
1510 str2specialbuf(sp, buf, len)
1511     char_u	*sp;
1512     char_u	*buf;
1513     int		len;
1514 {
1515     char_u	*s;
1516 
1517     *buf = NUL;
1518     while (*sp)
1519     {
1520 	s = str2special(&sp, FALSE);
1521 	if ((int)(STRLEN(s) + STRLEN(buf)) < len)
1522 	    STRCAT(buf, s);
1523     }
1524 }
1525 
1526 /*
1527  * print line for :print or :list command
1528  */
1529     void
1530 msg_prt_line(s, list)
1531     char_u	*s;
1532     int		list;
1533 {
1534     int		c;
1535     int		col = 0;
1536     int		n_extra = 0;
1537     int		c_extra = 0;
1538     char_u	*p_extra = NULL;	    /* init to make SASC shut up */
1539     int		n;
1540     int		attr= 0;
1541     char_u	*trail = NULL;
1542 #ifdef FEAT_MBYTE
1543     int		l;
1544     char_u	buf[MB_MAXBYTES + 1];
1545 #endif
1546 
1547     if (curwin->w_p_list)
1548 	list = TRUE;
1549 
1550     /* find start of trailing whitespace */
1551     if (list && lcs_trail)
1552     {
1553 	trail = s + STRLEN(s);
1554 	while (trail > s && vim_iswhite(trail[-1]))
1555 	    --trail;
1556     }
1557 
1558     /* output a space for an empty line, otherwise the line will be
1559      * overwritten */
1560     if (*s == NUL && !(list && lcs_eol != NUL))
1561 	msg_putchar(' ');
1562 
1563     while (!got_int)
1564     {
1565 	if (n_extra)
1566 	{
1567 	    --n_extra;
1568 	    if (c_extra)
1569 		c = c_extra;
1570 	    else
1571 		c = *p_extra++;
1572 	}
1573 #ifdef FEAT_MBYTE
1574 	else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
1575 	{
1576 	    col += (*mb_ptr2cells)(s);
1577 	    mch_memmove(buf, s, (size_t)l);
1578 	    buf[l] = NUL;
1579 	    msg_puts_attr(buf, attr);
1580 	    s += l;
1581 	    continue;
1582 	}
1583 #endif
1584 	else
1585 	{
1586 	    attr = 0;
1587 	    c = *s++;
1588 	    if (c == TAB && (!list || lcs_tab1))
1589 	    {
1590 		/* tab amount depends on current column */
1591 		n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
1592 		if (!list)
1593 		{
1594 		    c = ' ';
1595 		    c_extra = ' ';
1596 		}
1597 		else
1598 		{
1599 		    c = lcs_tab1;
1600 		    c_extra = lcs_tab2;
1601 		    attr = hl_attr(HLF_8);
1602 		}
1603 	    }
1604 	    else if (c == NUL && list && lcs_eol != NUL)
1605 	    {
1606 		p_extra = (char_u *)"";
1607 		c_extra = NUL;
1608 		n_extra = 1;
1609 		c = lcs_eol;
1610 		attr = hl_attr(HLF_AT);
1611 		--s;
1612 	    }
1613 	    else if (c != NUL && (n = byte2cells(c)) > 1)
1614 	    {
1615 		n_extra = n - 1;
1616 		p_extra = transchar_byte(c);
1617 		c_extra = NUL;
1618 		c = *p_extra++;
1619 	    }
1620 	    else if (c == ' ' && trail != NULL && s > trail)
1621 	    {
1622 		c = lcs_trail;
1623 		attr = hl_attr(HLF_8);
1624 	    }
1625 	}
1626 
1627 	if (c == NUL)
1628 	    break;
1629 
1630 	msg_putchar_attr(c, attr);
1631 	col++;
1632     }
1633     msg_clr_eos();
1634 }
1635 
1636 #ifdef FEAT_MBYTE
1637 /*
1638  * Use screen_puts() to output one multi-byte character.
1639  * Return the pointer "s" advanced to the next character.
1640  */
1641     static char_u *
1642 screen_puts_mbyte(s, l, attr)
1643     char_u	*s;
1644     int		l;
1645     int		attr;
1646 {
1647     int		cw;
1648 
1649     msg_didout = TRUE;		/* remember that line is not empty */
1650     cw = (*mb_ptr2cells)(s);
1651     if (cw > 1 && (
1652 #ifdef FEAT_RIGHTLEFT
1653 		cmdmsg_rl ? msg_col <= 1 :
1654 #endif
1655 		msg_col == Columns - 1))
1656     {
1657 	/* Doesn't fit, print a highlighted '>' to fill it up. */
1658 	msg_screen_putchar('>', hl_attr(HLF_AT));
1659 	return s;
1660     }
1661 
1662     screen_puts_len(s, l, msg_row, msg_col, attr);
1663 #ifdef FEAT_RIGHTLEFT
1664     if (cmdmsg_rl)
1665     {
1666 	msg_col -= cw;
1667 	if (msg_col == 0)
1668 	{
1669 	    msg_col = Columns;
1670 	    ++msg_row;
1671 	}
1672     }
1673     else
1674 #endif
1675     {
1676 	msg_col += cw;
1677 	if (msg_col >= Columns)
1678 	{
1679 	    msg_col = 0;
1680 	    ++msg_row;
1681 	}
1682     }
1683     return s + l;
1684 }
1685 #endif
1686 
1687 /*
1688  * Output a string to the screen at position msg_row, msg_col.
1689  * Update msg_row and msg_col for the next message.
1690  */
1691     void
1692 msg_puts(s)
1693     char_u	*s;
1694 {
1695     msg_puts_attr(s, 0);
1696 }
1697 
1698     void
1699 msg_puts_title(s)
1700     char_u	*s;
1701 {
1702     msg_puts_attr(s, hl_attr(HLF_T));
1703 }
1704 
1705 /*
1706  * Show a message in such a way that it always fits in the line.  Cut out a
1707  * part in the middle and replace it with "..." when necessary.
1708  * Does not handle multi-byte characters!
1709  */
1710     void
1711 msg_puts_long_attr(longstr, attr)
1712     char_u	*longstr;
1713     int		attr;
1714 {
1715     msg_puts_long_len_attr(longstr, (int)strlen((char *)longstr), attr);
1716 }
1717 
1718     void
1719 msg_puts_long_len_attr(longstr, len, attr)
1720     char_u	*longstr;
1721     int		len;
1722     int		attr;
1723 {
1724     int		slen = len;
1725     int		room;
1726 
1727     room = Columns - msg_col;
1728     if (len > room && room >= 20)
1729     {
1730 	slen = (room - 3) / 2;
1731 	msg_outtrans_len_attr(longstr, slen, attr);
1732 	msg_puts_attr((char_u *)"...", hl_attr(HLF_8));
1733     }
1734     msg_outtrans_len_attr(longstr + len - slen, slen, attr);
1735 }
1736 
1737 /*
1738  * Basic function for writing a message with highlight attributes.
1739  */
1740     void
1741 msg_puts_attr(s, attr)
1742     char_u	*s;
1743     int		attr;
1744 {
1745     msg_puts_attr_len(s, -1, attr);
1746 }
1747 
1748 /*
1749  * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
1750  * When "maxlen" is -1 there is no maximum length.
1751  * When "maxlen" is >= 0 the message is not put in the history.
1752  */
1753     static void
1754 msg_puts_attr_len(str, maxlen, attr)
1755     char_u	*str;
1756     int		maxlen;
1757     int		attr;
1758 {
1759     /*
1760      * If redirection is on, also write to the redirection file.
1761      */
1762     redir_write(str, maxlen);
1763 
1764     /*
1765      * Don't print anything when using ":silent cmd".
1766      */
1767     if (msg_silent != 0)
1768 	return;
1769 
1770     /* if MSG_HIST flag set, add message to history */
1771     if ((attr & MSG_HIST) && maxlen < 0)
1772     {
1773 	add_msg_hist(str, -1, attr);
1774 	attr &= ~MSG_HIST;
1775     }
1776 
1777     /*
1778      * When writing something to the screen after it has scrolled, requires a
1779      * wait-return prompt later.  Needed when scrolling, resetting
1780      * need_wait_return after some prompt, and then outputting something
1781      * without scrolling
1782      */
1783     if (msg_scrolled != 0 && !msg_scrolled_ign)
1784 	need_wait_return = TRUE;
1785     msg_didany = TRUE;		/* remember that something was outputted */
1786 
1787     /*
1788      * If there is no valid screen, use fprintf so we can see error messages.
1789      * If termcap is not active, we may be writing in an alternate console
1790      * window, cursor positioning may not work correctly (window size may be
1791      * different, e.g. for Win32 console) or we just don't know where the
1792      * cursor is.
1793      */
1794     if (msg_use_printf())
1795 	msg_puts_printf(str, maxlen);
1796     else
1797 	msg_puts_display(str, maxlen, attr, FALSE);
1798 }
1799 
1800 /*
1801  * The display part of msg_puts_attr_len().
1802  * May be called recursively to display scroll-back text.
1803  */
1804     static void
1805 msg_puts_display(str, maxlen, attr, recurse)
1806     char_u	*str;
1807     int		maxlen;
1808     int		attr;
1809     int		recurse;
1810 {
1811     char_u	*s = str;
1812     char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
1813     int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
1814 #ifdef FEAT_MBYTE
1815     int		l;
1816     int		cw;
1817 #endif
1818     char_u	*sb_str = str;
1819     int		sb_col = msg_col;
1820     int		wrap;
1821 
1822     did_wait_return = FALSE;
1823     while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
1824     {
1825 	/*
1826 	 * We are at the end of the screen line when:
1827 	 * - When outputting a newline.
1828 	 * - When outputting a character in the last column.
1829 	 */
1830 	if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || (
1831 #ifdef FEAT_RIGHTLEFT
1832 		    cmdmsg_rl
1833 		    ? (
1834 			msg_col <= 1
1835 			|| (*s == TAB && msg_col <= 7)
1836 # ifdef FEAT_MBYTE
1837 			|| (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2)
1838 # endif
1839 		      )
1840 		    :
1841 #endif
1842 		      (msg_col + t_col >= Columns - 1
1843 		       || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7))
1844 # ifdef FEAT_MBYTE
1845 		       || (has_mbyte && (*mb_ptr2cells)(s) > 1
1846 					    && msg_col + t_col >= Columns - 2)
1847 # endif
1848 		      ))))
1849 	{
1850 	    /*
1851 	     * The screen is scrolled up when at the last row (some terminals
1852 	     * scroll automatically, some don't.  To avoid problems we scroll
1853 	     * ourselves).
1854 	     */
1855 	    if (t_col > 0)
1856 		/* output postponed text */
1857 		t_puts(&t_col, t_s, s, attr);
1858 
1859 	    /* When no more prompt an no more room, truncate here */
1860 	    if (msg_no_more && lines_left == 0)
1861 		break;
1862 
1863 	    /* Scroll the screen up one line. */
1864 	    msg_scroll_up();
1865 
1866 	    msg_row = Rows - 2;
1867 	    if (msg_col >= Columns)	/* can happen after screen resize */
1868 		msg_col = Columns - 1;
1869 
1870 	    /* Display char in last column before showing more-prompt. */
1871 	    if (*s >= ' '
1872 #ifdef FEAT_RIGHTLEFT
1873 		    && !cmdmsg_rl
1874 #endif
1875 	       )
1876 	    {
1877 #ifdef FEAT_MBYTE
1878 		if (has_mbyte)
1879 		{
1880 		    if (enc_utf8 && maxlen >= 0)
1881 			/* avoid including composing chars after the end */
1882 			l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
1883 		    else
1884 			l = (*mb_ptr2len)(s);
1885 		    s = screen_puts_mbyte(s, l, attr);
1886 		}
1887 		else
1888 #endif
1889 		    msg_screen_putchar(*s++, attr);
1890 	    }
1891 
1892 	    if (p_more)
1893 		/* store text for scrolling back */
1894 		store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
1895 
1896 	    inc_msg_scrolled();
1897 	    need_wait_return = TRUE; /* may need wait_return in main() */
1898 	    if (must_redraw < VALID)
1899 		must_redraw = VALID;
1900 	    redraw_cmdline = TRUE;
1901 	    if (cmdline_row > 0 && !exmode_active)
1902 		--cmdline_row;
1903 
1904 	    /*
1905 	     * If screen is completely filled and 'more' is set then wait
1906 	     * for a character.
1907 	     */
1908 	    if (p_more && --lines_left == 0 && State != HITRETURN
1909 					    && !msg_no_more && !exmode_active)
1910 	    {
1911 #ifdef FEAT_CON_DIALOG
1912 		if (do_more_prompt(NUL))
1913 		    s = confirm_msg_tail;
1914 #else
1915 		(void)do_more_prompt(NUL);
1916 #endif
1917 		if (quit_more)
1918 		    return;
1919 	    }
1920 
1921 	    /* When we displayed a char in last column need to check if there
1922 	     * is still more. */
1923 	    if (*s >= ' '
1924 #ifdef FEAT_RIGHTLEFT
1925 		    && !cmdmsg_rl
1926 #endif
1927 	       )
1928 		continue;
1929 	}
1930 
1931 	wrap = *s == '\n'
1932 		    || msg_col + t_col >= Columns
1933 #ifdef FEAT_MBYTE
1934 		    || (has_mbyte && (*mb_ptr2cells)(s) > 1
1935 					    && msg_col + t_col >= Columns - 1)
1936 #endif
1937 		    ;
1938 	if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
1939 						 || *s == '\t' || *s == BELL))
1940 	    /* output any postponed text */
1941 	    t_puts(&t_col, t_s, s, attr);
1942 
1943 	if (wrap && p_more && !recurse)
1944 	    /* store text for scrolling back */
1945 	    store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
1946 
1947 	if (*s == '\n')		    /* go to next line */
1948 	{
1949 	    msg_didout = FALSE;	    /* remember that line is empty */
1950 #ifdef FEAT_RIGHTLEFT
1951 	    if (cmdmsg_rl)
1952 		msg_col = Columns - 1;
1953 	    else
1954 #endif
1955 		msg_col = 0;
1956 	    if (++msg_row >= Rows)  /* safety check */
1957 		msg_row = Rows - 1;
1958 	}
1959 	else if (*s == '\r')	    /* go to column 0 */
1960 	{
1961 	    msg_col = 0;
1962 	}
1963 	else if (*s == '\b')	    /* go to previous char */
1964 	{
1965 	    if (msg_col)
1966 		--msg_col;
1967 	}
1968 	else if (*s == TAB)	    /* translate Tab into spaces */
1969 	{
1970 	    do
1971 		msg_screen_putchar(' ', attr);
1972 	    while (msg_col & 7);
1973 	}
1974 	else if (*s == BELL)	    /* beep (from ":sh") */
1975 	    vim_beep();
1976 	else
1977 	{
1978 #ifdef FEAT_MBYTE
1979 	    if (has_mbyte)
1980 	    {
1981 		cw = (*mb_ptr2cells)(s);
1982 		if (enc_utf8 && maxlen >= 0)
1983 		    /* avoid including composing chars after the end */
1984 		    l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
1985 		else
1986 		    l = (*mb_ptr2len)(s);
1987 	    }
1988 	    else
1989 	    {
1990 		cw = 1;
1991 		l = 1;
1992 	    }
1993 #endif
1994 	    /* When drawing from right to left or when a double-wide character
1995 	     * doesn't fit, draw a single character here.  Otherwise collect
1996 	     * characters and draw them all at once later. */
1997 #if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
1998 	    if (
1999 # ifdef FEAT_RIGHTLEFT
2000 		    cmdmsg_rl
2001 #  ifdef FEAT_MBYTE
2002 		    ||
2003 #  endif
2004 # endif
2005 # ifdef FEAT_MBYTE
2006 		    (cw > 1 && msg_col + t_col >= Columns - 1)
2007 # endif
2008 		    )
2009 	    {
2010 # ifdef FEAT_MBYTE
2011 		if (l > 1)
2012 		    s = screen_puts_mbyte(s, l, attr) - 1;
2013 		else
2014 # endif
2015 		    msg_screen_putchar(*s, attr);
2016 	    }
2017 	    else
2018 #endif
2019 	    {
2020 		/* postpone this character until later */
2021 		if (t_col == 0)
2022 		    t_s = s;
2023 #ifdef FEAT_MBYTE
2024 		t_col += cw;
2025 		s += l - 1;
2026 #else
2027 		++t_col;
2028 #endif
2029 	    }
2030 	}
2031 	++s;
2032     }
2033 
2034     /* output any postponed text */
2035     if (t_col > 0)
2036 	t_puts(&t_col, t_s, s, attr);
2037     if (p_more && !recurse)
2038 	store_sb_text(&sb_str, s, attr, &sb_col, FALSE);
2039 
2040     msg_check();
2041 }
2042 
2043 /*
2044  * Scroll the screen up one line for displaying the next message line.
2045  */
2046     static void
2047 msg_scroll_up()
2048 {
2049 #ifdef FEAT_GUI
2050     /* Remove the cursor before scrolling, ScreenLines[] is going
2051      * to become invalid. */
2052     if (gui.in_use)
2053 	gui_undraw_cursor();
2054 #endif
2055     /* scrolling up always works */
2056     screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
2057 
2058     if (!can_clear((char_u *)" "))
2059     {
2060 	/* Scrolling up doesn't result in the right background.  Set the
2061 	 * background here.  It's not efficient, but avoids that we have to do
2062 	 * it all over the code. */
2063 	screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2064 
2065 	/* Also clear the last char of the last but one line if it was not
2066 	 * cleared before to avoid a scroll-up. */
2067 	if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1)
2068 	    screen_fill((int)Rows - 2, (int)Rows - 1,
2069 				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
2070     }
2071 }
2072 
2073 /*
2074  * Increment "msg_scrolled".
2075  */
2076     static void
2077 inc_msg_scrolled()
2078 {
2079 #ifdef FEAT_EVAL
2080     if (*get_vim_var_str(VV_SCROLLSTART) == NUL)
2081     {
2082 	char_u	    *p = sourcing_name;
2083 	char_u	    *tofree = NULL;
2084 	int	    len;
2085 
2086 	/* v:scrollstart is empty, set it to the script/function name and line
2087 	 * number */
2088 	if (p == NULL)
2089 	    p = (char_u *)_("Unknown");
2090 	else
2091 	{
2092 	    len = STRLEN(p) + 40;
2093 	    tofree = alloc(len);
2094 	    if (tofree != NULL)
2095 	    {
2096 		vim_snprintf((char *)tofree, len, _("%s line %ld"),
2097 						      p, (long)sourcing_lnum);
2098 		p = tofree;
2099 	    }
2100 	}
2101 	set_vim_var_string(VV_SCROLLSTART, p, -1);
2102 	vim_free(tofree);
2103     }
2104 #endif
2105     ++msg_scrolled;
2106 }
2107 
2108 /*
2109  * To be able to scroll back at the "more" and "hit-enter" prompts we need to
2110  * store the displayed text and remember where screen lines start.
2111  */
2112 typedef struct msgchunk_S msgchunk_T;
2113 struct msgchunk_S
2114 {
2115     msgchunk_T	*sb_next;
2116     msgchunk_T	*sb_prev;
2117     char	sb_eol;		/* TRUE when line ends after this text */
2118     int		sb_msg_col;	/* column in which text starts */
2119     int		sb_attr;	/* text attributes */
2120     char_u	sb_text[1];	/* text to be displayed, actually longer */
2121 };
2122 
2123 static msgchunk_T *last_msgchunk = NULL; /* last displayed text */
2124 
2125 static msgchunk_T *msg_sb_start __ARGS((msgchunk_T *mps));
2126 static msgchunk_T *disp_sb_line __ARGS((int row, msgchunk_T *smp));
2127 
2128 static int do_clear_sb_text = FALSE;	/* clear text on next msg */
2129 
2130 /*
2131  * Store part of a printed message for displaying when scrolling back.
2132  */
2133     static void
2134 store_sb_text(sb_str, s, attr, sb_col, finish)
2135     char_u	**sb_str;	/* start of string */
2136     char_u	*s;		/* just after string */
2137     int		attr;
2138     int		*sb_col;
2139     int		finish;		/* line ends */
2140 {
2141     msgchunk_T	*mp;
2142 
2143     if (do_clear_sb_text)
2144     {
2145 	clear_sb_text();
2146 	do_clear_sb_text = FALSE;
2147     }
2148 
2149     if (s > *sb_str)
2150     {
2151 	mp = (msgchunk_T *)alloc((int)(sizeof(msgchunk_T) + (s - *sb_str)));
2152 	if (mp != NULL)
2153 	{
2154 	    mp->sb_eol = finish;
2155 	    mp->sb_msg_col = *sb_col;
2156 	    mp->sb_attr = attr;
2157 	    vim_strncpy(mp->sb_text, *sb_str, s - *sb_str);
2158 
2159 	    if (last_msgchunk == NULL)
2160 	    {
2161 		last_msgchunk = mp;
2162 		mp->sb_prev = NULL;
2163 	    }
2164 	    else
2165 	    {
2166 		mp->sb_prev = last_msgchunk;
2167 		last_msgchunk->sb_next = mp;
2168 		last_msgchunk = mp;
2169 	    }
2170 	    mp->sb_next = NULL;
2171 	}
2172     }
2173     else if (finish && last_msgchunk != NULL)
2174 	last_msgchunk->sb_eol = TRUE;
2175 
2176     *sb_str = s;
2177     *sb_col = 0;
2178 }
2179 
2180 /*
2181  * Finished showing messages, clear the scroll-back text on the next message.
2182  */
2183     void
2184 may_clear_sb_text()
2185 {
2186     do_clear_sb_text = TRUE;
2187 }
2188 
2189 /*
2190  * Clear any text remembered for scrolling back.
2191  * Called when redrawing the screen.
2192  */
2193     void
2194 clear_sb_text()
2195 {
2196     msgchunk_T	*mp;
2197 
2198     while (last_msgchunk != NULL)
2199     {
2200 	mp = last_msgchunk->sb_prev;
2201 	vim_free(last_msgchunk);
2202 	last_msgchunk = mp;
2203     }
2204 }
2205 
2206 /*
2207  * "g<" command.
2208  */
2209     void
2210 show_sb_text()
2211 {
2212     msgchunk_T	*mp;
2213 
2214     /* Only show somethign if there is more than one line, otherwise it looks
2215      * weird, typing a command without output results in one line. */
2216     mp = msg_sb_start(last_msgchunk);
2217     if (mp == NULL || mp->sb_prev == NULL)
2218 	vim_beep();
2219     else
2220     {
2221 	do_more_prompt('G');
2222 	wait_return(FALSE);
2223     }
2224 }
2225 
2226 /*
2227  * Move to the start of screen line in already displayed text.
2228  */
2229     static msgchunk_T *
2230 msg_sb_start(mps)
2231     msgchunk_T *mps;
2232 {
2233     msgchunk_T *mp = mps;
2234 
2235     while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol)
2236 	mp = mp->sb_prev;
2237     return mp;
2238 }
2239 
2240 /*
2241  * Display a screen line from previously displayed text at row "row".
2242  * Returns a pointer to the text for the next line (can be NULL).
2243  */
2244     static msgchunk_T *
2245 disp_sb_line(row, smp)
2246     int		row;
2247     msgchunk_T	*smp;
2248 {
2249     msgchunk_T	*mp = smp;
2250     char_u	*p;
2251 
2252     for (;;)
2253     {
2254 	msg_row = row;
2255 	msg_col = mp->sb_msg_col;
2256 	p = mp->sb_text;
2257 	if (*p == '\n')	    /* don't display the line break */
2258 	    ++p;
2259 	msg_puts_display(p, -1, mp->sb_attr, TRUE);
2260 	if (mp->sb_eol || mp->sb_next == NULL)
2261 	    break;
2262 	mp = mp->sb_next;
2263     }
2264     return mp->sb_next;
2265 }
2266 
2267 /*
2268  * Output any postponed text for msg_puts_attr_len().
2269  */
2270     static void
2271 t_puts(t_col, t_s, s, attr)
2272     int		*t_col;
2273     char_u	*t_s;
2274     char_u	*s;
2275     int		attr;
2276 {
2277     /* output postponed text */
2278     msg_didout = TRUE;		/* remember that line is not empty */
2279     screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr);
2280     msg_col += *t_col;
2281     *t_col = 0;
2282 #ifdef FEAT_MBYTE
2283     /* If the string starts with a composing character don't increment the
2284      * column position for it. */
2285     if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s)))
2286 	--msg_col;
2287 #endif
2288     if (msg_col >= Columns)
2289     {
2290 	msg_col = 0;
2291 	++msg_row;
2292     }
2293 }
2294 
2295 /*
2296  * Returns TRUE when messages should be printed with mch_errmsg().
2297  * This is used when there is no valid screen, so we can see error messages.
2298  * If termcap is not active, we may be writing in an alternate console
2299  * window, cursor positioning may not work correctly (window size may be
2300  * different, e.g. for Win32 console) or we just don't know where the
2301  * cursor is.
2302  */
2303     int
2304 msg_use_printf()
2305 {
2306     return (!msg_check_screen()
2307 #if defined(WIN3264) && !defined(FEAT_GUI_MSWIN)
2308 	    || !termcap_active
2309 #endif
2310 	    || (swapping_screen() && !termcap_active)
2311 	       );
2312 }
2313 
2314 /*
2315  * Print a message when there is no valid screen.
2316  */
2317     static void
2318 msg_puts_printf(str, maxlen)
2319     char_u	*str;
2320     int		maxlen;
2321 {
2322     char_u	*s = str;
2323     char_u	buf[4];
2324     char_u	*p;
2325 
2326 #ifdef WIN3264
2327     if (!(silent_mode && p_verbose == 0))
2328 	mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
2329 #endif
2330     while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
2331     {
2332 	if (!(silent_mode && p_verbose == 0))
2333 	{
2334 	    /* NL --> CR NL translation (for Unix, not for "--version") */
2335 	    /* NL --> CR translation (for Mac) */
2336 	    p = &buf[0];
2337 	    if (*s == '\n' && !info_message)
2338 		*p++ = '\r';
2339 #if defined(USE_CR) && !defined(MACOS_X_UNIX)
2340 	    else
2341 #endif
2342 		*p++ = *s;
2343 	    *p = '\0';
2344 	    if (info_message)	/* informative message, not an error */
2345 		mch_msg((char *)buf);
2346 	    else
2347 		mch_errmsg((char *)buf);
2348 	}
2349 
2350 	/* primitive way to compute the current column */
2351 #ifdef FEAT_RIGHTLEFT
2352 	if (cmdmsg_rl)
2353 	{
2354 	    if (*s == '\r' || *s == '\n')
2355 		msg_col = Columns - 1;
2356 	    else
2357 		--msg_col;
2358 	}
2359 	else
2360 #endif
2361 	{
2362 	    if (*s == '\r' || *s == '\n')
2363 		msg_col = 0;
2364 	    else
2365 		++msg_col;
2366 	}
2367 	++s;
2368     }
2369     msg_didout = TRUE;	    /* assume that line is not empty */
2370 
2371 #ifdef WIN3264
2372     if (!(silent_mode && p_verbose == 0))
2373 	mch_settmode(TMODE_RAW);
2374 #endif
2375 }
2376 
2377 /*
2378  * Show the more-prompt and handle the user response.
2379  * This takes care of scrolling back and displaying previously displayed text.
2380  * When at hit-enter prompt "typed_char" is the already typed character,
2381  * otherwise it's NUL.
2382  * Returns TRUE when jumping ahead to "confirm_msg_tail".
2383  */
2384     static int
2385 do_more_prompt(typed_char)
2386     int		typed_char;
2387 {
2388     int		used_typed_char = typed_char;
2389     int		oldState = State;
2390     int		c;
2391 #ifdef FEAT_CON_DIALOG
2392     int		retval = FALSE;
2393 #endif
2394     int		scroll;
2395     msgchunk_T	*mp_last = NULL;
2396     msgchunk_T	*mp;
2397     int		i;
2398 
2399     if (typed_char == 'G')
2400     {
2401 	/* "g<": Find first line on the last page. */
2402 	mp_last = msg_sb_start(last_msgchunk);
2403 	for (i = 0; i < Rows - 2 && mp_last != NULL
2404 					     && mp_last->sb_prev != NULL; ++i)
2405 	    mp_last = msg_sb_start(mp_last->sb_prev);
2406     }
2407 
2408     State = ASKMORE;
2409 #ifdef FEAT_MOUSE
2410     setmouse();
2411 #endif
2412     if (typed_char == NUL)
2413 	msg_moremsg(FALSE);
2414     for (;;)
2415     {
2416 	/*
2417 	 * Get a typed character directly from the user.
2418 	 */
2419 	if (used_typed_char != NUL)
2420 	{
2421 	    c = used_typed_char;	/* was typed at hit-enter prompt */
2422 	    used_typed_char = NUL;
2423 	}
2424 	else
2425 	    c = get_keystroke();
2426 
2427 #if defined(FEAT_MENU) && defined(FEAT_GUI)
2428 	if (c == K_MENU)
2429 	{
2430 	    int idx = get_menu_index(current_menu, ASKMORE);
2431 
2432 	    /* Used a menu.  If it starts with CTRL-Y, it must
2433 	     * be a "Copy" for the clipboard.  Otherwise
2434 	     * assume that we end */
2435 	    if (idx == MENU_INDEX_INVALID)
2436 		continue;
2437 	    c = *current_menu->strings[idx];
2438 	    if (c != NUL && current_menu->strings[idx][1] != NUL)
2439 		ins_typebuf(current_menu->strings[idx] + 1,
2440 				current_menu->noremap[idx], 0, TRUE,
2441 						   current_menu->silent[idx]);
2442 	}
2443 #endif
2444 
2445 	scroll = 0;
2446 	switch (c)
2447 	{
2448 	case BS:		/* scroll one line back */
2449 	case K_BS:
2450 	case 'k':
2451 	case K_UP:
2452 	    scroll = -1;
2453 	    break;
2454 
2455 	case CAR:		/* one extra line */
2456 	case NL:
2457 	case 'j':
2458 	case K_DOWN:
2459 	    scroll = 1;
2460 	    break;
2461 
2462 	case 'u':		/* Up half a page */
2463 	case K_PAGEUP:
2464 	    scroll = -(Rows / 2);
2465 	    break;
2466 
2467 	case 'd':		/* Down half a page */
2468 	    scroll = Rows / 2;
2469 	    break;
2470 
2471 	case 'b':		/* one page back */
2472 	    scroll = -(Rows - 1);
2473 	    break;
2474 
2475 	case ' ':		/* one extra page */
2476 	case K_PAGEDOWN:
2477 	case K_LEFTMOUSE:
2478 	    scroll = Rows - 1;
2479 	    break;
2480 
2481 	case 'g':		/* all the way back to the start */
2482 	    scroll = -999999;
2483 	    break;
2484 
2485 	case 'G':		/* all the way to the end */
2486 	    scroll = 999999;
2487 	    lines_left = 999999;
2488 	    break;
2489 
2490 	case ':':		/* start new command line */
2491 #ifdef FEAT_CON_DIALOG
2492 	    if (!confirm_msg_used)
2493 #endif
2494 	    {
2495 		/* Since got_int is set all typeahead will be flushed, but we
2496 		 * want to keep this ':', remember that in a special way. */
2497 		typeahead_noflush(':');
2498 		cmdline_row = Rows - 1;		/* put ':' on this line */
2499 		skip_redraw = TRUE;		/* skip redraw once */
2500 		need_wait_return = FALSE;	/* don't wait in main() */
2501 	    }
2502 	    /*FALLTHROUGH*/
2503 	case 'q':		/* quit */
2504 	case Ctrl_C:
2505 	case ESC:
2506 #ifdef FEAT_CON_DIALOG
2507 	    if (confirm_msg_used)
2508 	    {
2509 		/* Jump to the choices of the dialog. */
2510 		retval = TRUE;
2511 		lines_left = Rows - 1;
2512 	    }
2513 	    else
2514 #endif
2515 	    {
2516 		got_int = TRUE;
2517 		quit_more = TRUE;
2518 	    }
2519 	    break;
2520 
2521 #ifdef FEAT_CLIPBOARD
2522 	case Ctrl_Y:
2523 	    /* Strange way to allow copying (yanking) a modeless
2524 	     * selection at the more prompt.  Use CTRL-Y,
2525 	     * because the same is used in Cmdline-mode and at the
2526 	     * hit-enter prompt.  However, scrolling one line up
2527 	     * might be expected... */
2528 	    if (clip_star.state == SELECT_DONE)
2529 		clip_copy_modeless_selection(TRUE);
2530 	    continue;
2531 #endif
2532 	default:		/* no valid response */
2533 	    msg_moremsg(TRUE);
2534 	    continue;
2535 	}
2536 
2537 	if (scroll != 0)
2538 	{
2539 	    if (scroll < 0)
2540 	    {
2541 		/* go to start of last line */
2542 		if (mp_last == NULL)
2543 		    mp = msg_sb_start(last_msgchunk);
2544 		else if (mp_last->sb_prev != NULL)
2545 		    mp = msg_sb_start(mp_last->sb_prev);
2546 		else
2547 		    mp = NULL;
2548 
2549 		/* go to start of line at top of the screen */
2550 		for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
2551 									  ++i)
2552 		    mp = msg_sb_start(mp->sb_prev);
2553 
2554 		if (mp != NULL && mp->sb_prev != NULL)
2555 		{
2556 		    /* Find line to be displayed at top. */
2557 		    for (i = 0; i > scroll; --i)
2558 		    {
2559 			if (mp == NULL || mp->sb_prev == NULL)
2560 			    break;
2561 			mp = msg_sb_start(mp->sb_prev);
2562 			if (mp_last == NULL)
2563 			    mp_last = msg_sb_start(last_msgchunk);
2564 			else
2565 			    mp_last = msg_sb_start(mp_last->sb_prev);
2566 		    }
2567 
2568 		    if (scroll == -1 && screen_ins_lines(0, 0, 1,
2569 						       (int)Rows, NULL) == OK)
2570 		    {
2571 			/* display line at top */
2572 			(void)disp_sb_line(0, mp);
2573 		    }
2574 		    else
2575 		    {
2576 			/* redisplay all lines */
2577 			screenclear();
2578 			for (i = 0; i < Rows - 1; ++i)
2579 			    mp = disp_sb_line(i, mp);
2580 		    }
2581 		    scroll = 0;
2582 		}
2583 	    }
2584 	    else
2585 	    {
2586 		/* First display any text that we scrolled back. */
2587 		while (scroll > 0 && mp_last != NULL)
2588 		{
2589 		    /* scroll up, display line at bottom */
2590 		    msg_scroll_up();
2591 		    inc_msg_scrolled();
2592 		    screen_fill((int)Rows - 2, (int)Rows - 1, 0,
2593 						   (int)Columns, ' ', ' ', 0);
2594 		    mp_last = disp_sb_line((int)Rows - 2, mp_last);
2595 		    --scroll;
2596 		}
2597 	    }
2598 
2599 	    if (scroll < 0 || (scroll == 0 && mp_last != NULL))
2600 	    {
2601 		/* displayed the requested text, more prompt again */
2602 		screen_fill((int)Rows - 1, (int)Rows, 0,
2603 						   (int)Columns, ' ', ' ', 0);
2604 		msg_moremsg(FALSE);
2605 		continue;
2606 	    }
2607 
2608 	    /* display more text, return to caller */
2609 	    lines_left = scroll;
2610 	}
2611 
2612 	break;
2613     }
2614 
2615     /* clear the --more-- message */
2616     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2617     State = oldState;
2618 #ifdef FEAT_MOUSE
2619     setmouse();
2620 #endif
2621     if (quit_more)
2622     {
2623 	msg_row = Rows - 1;
2624 	msg_col = 0;
2625     }
2626 #ifdef FEAT_RIGHTLEFT
2627     else if (cmdmsg_rl)
2628 	msg_col = Columns - 1;
2629 #endif
2630 
2631 #ifdef FEAT_CON_DIALOG
2632     return retval;
2633 #else
2634     return FALSE;
2635 #endif
2636 }
2637 
2638 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
2639 
2640 #ifdef mch_errmsg
2641 # undef mch_errmsg
2642 #endif
2643 #ifdef mch_msg
2644 # undef mch_msg
2645 #endif
2646 
2647 /*
2648  * Give an error message.  To be used when the screen hasn't been initialized
2649  * yet.  When stderr can't be used, collect error messages until the GUI has
2650  * started and they can be displayed in a message box.
2651  */
2652     void
2653 mch_errmsg(str)
2654     char	*str;
2655 {
2656     int		len;
2657 
2658 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
2659     /* On Unix use stderr if it's a tty.
2660      * When not going to start the GUI also use stderr.
2661      * On Mac, when started from Finder, stderr is the console. */
2662     if (
2663 # ifdef UNIX
2664 #  ifdef MACOS_X_UNIX
2665 	    (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
2666 #  else
2667 	    isatty(2)
2668 #  endif
2669 #  ifdef FEAT_GUI
2670 	    ||
2671 #  endif
2672 # endif
2673 # ifdef FEAT_GUI
2674 	    !(gui.in_use || gui.starting)
2675 # endif
2676 	    )
2677     {
2678 	fprintf(stderr, "%s", str);
2679 	return;
2680     }
2681 #endif
2682 
2683     /* avoid a delay for a message that isn't there */
2684     emsg_on_display = FALSE;
2685 
2686     len = (int)STRLEN(str) + 1;
2687     if (error_ga.ga_growsize == 0)
2688     {
2689 	error_ga.ga_growsize = 80;
2690 	error_ga.ga_itemsize = 1;
2691     }
2692     if (ga_grow(&error_ga, len) == OK)
2693     {
2694 	mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
2695 							  (char_u *)str, len);
2696 #ifdef UNIX
2697 	/* remove CR characters, they are displayed */
2698 	{
2699 	    char_u	*p;
2700 
2701 	    p = (char_u *)error_ga.ga_data + error_ga.ga_len;
2702 	    for (;;)
2703 	    {
2704 		p = vim_strchr(p, '\r');
2705 		if (p == NULL)
2706 		    break;
2707 		*p = ' ';
2708 	    }
2709 	}
2710 #endif
2711 	--len;		/* don't count the NUL at the end */
2712 	error_ga.ga_len += len;
2713     }
2714 }
2715 
2716 /*
2717  * Give a message.  To be used when the screen hasn't been initialized yet.
2718  * When there is no tty, collect messages until the GUI has started and they
2719  * can be displayed in a message box.
2720  */
2721     void
2722 mch_msg(str)
2723     char	*str;
2724 {
2725 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
2726     /* On Unix use stdout if we have a tty.  This allows "vim -h | more" and
2727      * uses mch_errmsg() when started from the desktop.
2728      * When not going to start the GUI also use stdout.
2729      * On Mac, when started from Finder, stderr is the console. */
2730     if (
2731 #  ifdef UNIX
2732 #   ifdef MACOS_X_UNIX
2733 	    (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
2734 #   else
2735 	    isatty(2)
2736 #    endif
2737 #   ifdef FEAT_GUI
2738 	    ||
2739 #   endif
2740 #  endif
2741 #  ifdef FEAT_GUI
2742 	    !(gui.in_use || gui.starting)
2743 #  endif
2744 	    )
2745     {
2746 	printf("%s", str);
2747 	return;
2748     }
2749 # endif
2750     mch_errmsg(str);
2751 }
2752 #endif /* USE_MCH_ERRMSG */
2753 
2754 /*
2755  * Put a character on the screen at the current message position and advance
2756  * to the next position.  Only for printable ASCII!
2757  */
2758     static void
2759 msg_screen_putchar(c, attr)
2760     int		c;
2761     int		attr;
2762 {
2763     msg_didout = TRUE;		/* remember that line is not empty */
2764     screen_putchar(c, msg_row, msg_col, attr);
2765 #ifdef FEAT_RIGHTLEFT
2766     if (cmdmsg_rl)
2767     {
2768 	if (--msg_col == 0)
2769 	{
2770 	    msg_col = Columns;
2771 	    ++msg_row;
2772 	}
2773     }
2774     else
2775 #endif
2776     {
2777 	if (++msg_col >= Columns)
2778 	{
2779 	    msg_col = 0;
2780 	    ++msg_row;
2781 	}
2782     }
2783 }
2784 
2785     void
2786 msg_moremsg(full)
2787     int	    full;
2788 {
2789     int		attr;
2790     char_u	*s = (char_u *)_("-- More --");
2791 
2792     attr = hl_attr(HLF_M);
2793     screen_puts(s, (int)Rows - 1, 0, attr);
2794     if (full)
2795 	screen_puts((char_u *)
2796 		_(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
2797 		(int)Rows - 1, vim_strsize(s), attr);
2798 }
2799 
2800 /*
2801  * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or
2802  * exmode_active.
2803  */
2804     void
2805 repeat_message()
2806 {
2807     if (State == ASKMORE)
2808     {
2809 	msg_moremsg(TRUE);	/* display --more-- message again */
2810 	msg_row = Rows - 1;
2811     }
2812 #ifdef FEAT_CON_DIALOG
2813     else if (State == CONFIRM)
2814     {
2815 	display_confirm_msg();	/* display ":confirm" message again */
2816 	msg_row = Rows - 1;
2817     }
2818 #endif
2819     else if (State == EXTERNCMD)
2820     {
2821 	windgoto(msg_row, msg_col); /* put cursor back */
2822     }
2823     else if (State == HITRETURN || State == SETWSIZE)
2824     {
2825 	hit_return_msg();
2826 	msg_row = Rows - 1;
2827     }
2828 }
2829 
2830 /*
2831  * msg_check_screen - check if the screen is initialized.
2832  * Also check msg_row and msg_col, if they are too big it may cause a crash.
2833  * While starting the GUI the terminal codes will be set for the GUI, but the
2834  * output goes to the terminal.  Don't use the terminal codes then.
2835  */
2836     static int
2837 msg_check_screen()
2838 {
2839     if (!full_screen || !screen_valid(FALSE))
2840 	return FALSE;
2841 
2842     if (msg_row >= Rows)
2843 	msg_row = Rows - 1;
2844     if (msg_col >= Columns)
2845 	msg_col = Columns - 1;
2846     return TRUE;
2847 }
2848 
2849 /*
2850  * Clear from current message position to end of screen.
2851  * Skip this when ":silent" was used, no need to clear for redirection.
2852  */
2853     void
2854 msg_clr_eos()
2855 {
2856     if (msg_silent == 0)
2857 	msg_clr_eos_force();
2858 }
2859 
2860 /*
2861  * Clear from current message position to end of screen.
2862  * Note: msg_col is not updated, so we remember the end of the message
2863  * for msg_check().
2864  */
2865     void
2866 msg_clr_eos_force()
2867 {
2868     if (msg_use_printf())
2869     {
2870 	if (full_screen)	/* only when termcap codes are valid */
2871 	{
2872 	    if (*T_CD)
2873 		out_str(T_CD);	/* clear to end of display */
2874 	    else if (*T_CE)
2875 		out_str(T_CE);	/* clear to end of line */
2876 	}
2877     }
2878     else
2879     {
2880 #ifdef FEAT_RIGHTLEFT
2881 	if (cmdmsg_rl)
2882 	{
2883 	    screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0);
2884 	    screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2885 	}
2886 	else
2887 #endif
2888 	{
2889 	    screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns,
2890 								 ' ', ' ', 0);
2891 	    screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2892 	}
2893     }
2894 }
2895 
2896 /*
2897  * Clear the command line.
2898  */
2899     void
2900 msg_clr_cmdline()
2901 {
2902     msg_row = cmdline_row;
2903     msg_col = 0;
2904     msg_clr_eos_force();
2905 }
2906 
2907 /*
2908  * end putting a message on the screen
2909  * call wait_return if the message does not fit in the available space
2910  * return TRUE if wait_return not called.
2911  */
2912     int
2913 msg_end()
2914 {
2915     /*
2916      * if the string is larger than the window,
2917      * or the ruler option is set and we run into it,
2918      * we have to redraw the window.
2919      * Do not do this if we are abandoning the file or editing the command line.
2920      */
2921     if (!exiting && need_wait_return && !(State & CMDLINE))
2922     {
2923 	wait_return(FALSE);
2924 	return FALSE;
2925     }
2926     out_flush();
2927     return TRUE;
2928 }
2929 
2930 /*
2931  * If the written message runs into the shown command or ruler, we have to
2932  * wait for hit-return and redraw the window later.
2933  */
2934     void
2935 msg_check()
2936 {
2937     if (msg_row == Rows - 1 && msg_col >= sc_col)
2938     {
2939 	need_wait_return = TRUE;
2940 	redraw_cmdline = TRUE;
2941     }
2942 }
2943 
2944 /*
2945  * May write a string to the redirection file.
2946  * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes.
2947  */
2948     static void
2949 redir_write(str, maxlen)
2950     char_u	*str;
2951     int		maxlen;
2952 {
2953     char_u	*s = str;
2954     static int	cur_col = 0;
2955 
2956     /* Don't do anything for displaying prompts and the like. */
2957     if (redir_off)
2958 	return;
2959 
2960     /*
2961      * If 'verbosefile' is set write message in that file.
2962      * Must come before the rest because of updating "msg_col".
2963      */
2964     if (*p_vfile != NUL)
2965 	verbose_write(s, maxlen);
2966 
2967     if (redir_fd != NULL
2968 #ifdef FEAT_EVAL
2969 			  || redir_reg || redir_vname
2970 #endif
2971 				       )
2972     {
2973 	/* If the string doesn't start with CR or NL, go to msg_col */
2974 	if (*s != '\n' && *s != '\r')
2975 	{
2976 	    while (cur_col < msg_col)
2977 	    {
2978 #ifdef FEAT_EVAL
2979 		if (redir_reg)
2980 		    write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
2981 		else if (redir_vname)
2982 		    var_redir_str((char_u *)" ", -1);
2983 		else if (redir_fd)
2984 #endif
2985 		    fputs(" ", redir_fd);
2986 		++cur_col;
2987 	    }
2988 	}
2989 
2990 #ifdef FEAT_EVAL
2991 	if (redir_reg)
2992 	    write_reg_contents(redir_reg, s, maxlen, TRUE);
2993 	if (redir_vname)
2994 	    var_redir_str(s, maxlen);
2995 #endif
2996 
2997 	/* Adjust the current column */
2998 	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
2999 	{
3000 #ifdef FEAT_EVAL
3001 	    if (!redir_reg && !redir_vname && redir_fd != NULL)
3002 #endif
3003 		putc(*s, redir_fd);
3004 	    if (*s == '\r' || *s == '\n')
3005 		cur_col = 0;
3006 	    else if (*s == '\t')
3007 		cur_col += (8 - cur_col % 8);
3008 	    else
3009 		++cur_col;
3010 	    ++s;
3011 	}
3012 
3013 	if (msg_silent != 0)	/* should update msg_col */
3014 	    msg_col = cur_col;
3015     }
3016 }
3017 
3018 /*
3019  * Before giving verbose messsage.
3020  * Must always be called paired with verbose_leave()!
3021  */
3022     void
3023 verbose_enter()
3024 {
3025     if (*p_vfile != NUL)
3026 	++msg_silent;
3027 }
3028 
3029 /*
3030  * After giving verbose message.
3031  * Must always be called paired with verbose_enter()!
3032  */
3033     void
3034 verbose_leave()
3035 {
3036     if (*p_vfile != NUL)
3037 	if (--msg_silent < 0)
3038 	    msg_silent = 0;
3039 }
3040 
3041 /*
3042  * Like verbose_enter() and set msg_scroll when displaying the message.
3043  */
3044     void
3045 verbose_enter_scroll()
3046 {
3047     if (*p_vfile != NUL)
3048 	++msg_silent;
3049     else
3050 	/* always scroll up, don't overwrite */
3051 	msg_scroll = TRUE;
3052 }
3053 
3054 /*
3055  * Like verbose_leave() and set cmdline_row when displaying the message.
3056  */
3057     void
3058 verbose_leave_scroll()
3059 {
3060     if (*p_vfile != NUL)
3061     {
3062 	if (--msg_silent < 0)
3063 	    msg_silent = 0;
3064     }
3065     else
3066 	cmdline_row = msg_row;
3067 }
3068 
3069 static FILE *verbose_fd = NULL;
3070 static int  verbose_did_open = FALSE;
3071 
3072 /*
3073  * Called when 'verbosefile' is set: stop writing to the file.
3074  */
3075     void
3076 verbose_stop()
3077 {
3078     if (verbose_fd != NULL)
3079     {
3080 	fclose(verbose_fd);
3081 	verbose_fd = NULL;
3082     }
3083     verbose_did_open = FALSE;
3084 }
3085 
3086 /*
3087  * Open the file 'verbosefile'.
3088  * Return FAIL or OK.
3089  */
3090     int
3091 verbose_open()
3092 {
3093     if (verbose_fd == NULL && !verbose_did_open)
3094     {
3095 	/* Only give the error message once. */
3096 	verbose_did_open = TRUE;
3097 
3098 	verbose_fd = mch_fopen((char *)p_vfile, "a");
3099 	if (verbose_fd == NULL)
3100 	{
3101 	    EMSG2(_(e_notopen), p_vfile);
3102 	    return FAIL;
3103 	}
3104     }
3105     return OK;
3106 }
3107 
3108 /*
3109  * Write a string to 'verbosefile'.
3110  * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes.
3111  */
3112     static void
3113 verbose_write(str, maxlen)
3114     char_u	*str;
3115     int		maxlen;
3116 {
3117     char_u	*s = str;
3118     static int	cur_col = 0;
3119 
3120     /* Open the file when called the first time. */
3121     if (verbose_fd == NULL)
3122 	verbose_open();
3123 
3124     if (verbose_fd != NULL)
3125     {
3126 	/* If the string doesn't start with CR or NL, go to msg_col */
3127 	if (*s != '\n' && *s != '\r')
3128 	{
3129 	    while (cur_col < msg_col)
3130 	    {
3131 		fputs(" ", verbose_fd);
3132 		++cur_col;
3133 	    }
3134 	}
3135 
3136 	/* Adjust the current column */
3137 	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
3138 	{
3139 	    putc(*s, verbose_fd);
3140 	    if (*s == '\r' || *s == '\n')
3141 		cur_col = 0;
3142 	    else if (*s == '\t')
3143 		cur_col += (8 - cur_col % 8);
3144 	    else
3145 		++cur_col;
3146 	    ++s;
3147 	}
3148     }
3149 }
3150 
3151 /*
3152  * Give a warning message (for searching).
3153  * Use 'w' highlighting and may repeat the message after redrawing
3154  */
3155     void
3156 give_warning(message, hl)
3157     char_u  *message;
3158     int	    hl;
3159 {
3160     /* Don't do this for ":silent". */
3161     if (msg_silent != 0)
3162 	return;
3163 
3164     /* Don't want a hit-enter prompt here. */
3165     ++no_wait_return;
3166 
3167 #ifdef FEAT_EVAL
3168     set_vim_var_string(VV_WARNINGMSG, message, -1);
3169 #endif
3170     vim_free(keep_msg);
3171     keep_msg = NULL;
3172     if (hl)
3173 	keep_msg_attr = hl_attr(HLF_W);
3174     else
3175 	keep_msg_attr = 0;
3176     if (msg_attr(message, keep_msg_attr) && msg_scrolled == 0)
3177 	set_keep_msg(message, keep_msg_attr);
3178     msg_didout = FALSE;	    /* overwrite this message */
3179     msg_nowait = TRUE;	    /* don't wait for this message */
3180     msg_col = 0;
3181 
3182     --no_wait_return;
3183 }
3184 
3185 /*
3186  * Advance msg cursor to column "col".
3187  */
3188     void
3189 msg_advance(col)
3190     int	    col;
3191 {
3192     if (msg_silent != 0)	/* nothing to advance to */
3193     {
3194 	msg_col = col;		/* for redirection, may fill it up later */
3195 	return;
3196     }
3197     if (col >= Columns)		/* not enough room */
3198 	col = Columns - 1;
3199 #ifdef FEAT_RIGHTLEFT
3200     if (cmdmsg_rl)
3201 	while (msg_col > Columns - col)
3202 	    msg_putchar(' ');
3203     else
3204 #endif
3205 	while (msg_col < col)
3206 	    msg_putchar(' ');
3207 }
3208 
3209 #if defined(FEAT_CON_DIALOG) || defined(PROTO)
3210 /*
3211  * Used for "confirm()" function, and the :confirm command prefix.
3212  * Versions which haven't got flexible dialogs yet, and console
3213  * versions, get this generic handler which uses the command line.
3214  *
3215  * type  = one of:
3216  *	   VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
3217  * title = title string (can be NULL for default)
3218  * (neither used in console dialogs at the moment)
3219  *
3220  * Format of the "buttons" string:
3221  * "Button1Name\nButton2Name\nButton3Name"
3222  * The first button should normally be the default/accept
3223  * The second button should be the 'Cancel' button
3224  * Other buttons- use your imagination!
3225  * A '&' in a button name becomes a shortcut, so each '&' should be before a
3226  * different letter.
3227  */
3228 /* ARGSUSED */
3229     int
3230 do_dialog(type, title, message, buttons, dfltbutton, textfield)
3231     int		type;
3232     char_u	*title;
3233     char_u	*message;
3234     char_u	*buttons;
3235     int		dfltbutton;
3236     char_u	*textfield;	/* IObuff for inputdialog(), NULL otherwise */
3237 {
3238     int		oldState;
3239     int		retval = 0;
3240     char_u	*hotkeys;
3241     int		c;
3242     int		i;
3243 
3244 #ifndef NO_CONSOLE
3245     /* Don't output anything in silent mode ("ex -s") */
3246     if (silent_mode)
3247 	return dfltbutton;   /* return default option */
3248 #endif
3249 
3250 #ifdef FEAT_GUI_DIALOG
3251     /* When GUI is running and 'c' not in 'guioptions', use the GUI dialog */
3252     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
3253     {
3254 	c = gui_mch_dialog(type, title, message, buttons, dfltbutton,
3255 								   textfield);
3256 	msg_end_prompt();
3257 
3258 	/* Flush output to avoid that further messages and redrawing is done
3259 	 * in the wrong order. */
3260 	out_flush();
3261 	gui_mch_update();
3262 
3263 	return c;
3264     }
3265 #endif
3266 
3267     oldState = State;
3268     State = CONFIRM;
3269 #ifdef FEAT_MOUSE
3270     setmouse();
3271 #endif
3272 
3273     /*
3274      * Since we wait for a keypress, don't make the
3275      * user press RETURN as well afterwards.
3276      */
3277     ++no_wait_return;
3278     hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
3279 
3280     if (hotkeys != NULL)
3281     {
3282 	for (;;)
3283 	{
3284 	    /* Get a typed character directly from the user. */
3285 	    c = get_keystroke();
3286 	    switch (c)
3287 	    {
3288 	    case CAR:		/* User accepts default option */
3289 	    case NL:
3290 		retval = dfltbutton;
3291 		break;
3292 	    case Ctrl_C:	/* User aborts/cancels */
3293 	    case ESC:
3294 		retval = 0;
3295 		break;
3296 	    default:		/* Could be a hotkey? */
3297 		if (c < 0)	/* special keys are ignored here */
3298 		    continue;
3299 		/* Make the character lowercase, as chars in "hotkeys" are. */
3300 		c = MB_TOLOWER(c);
3301 		retval = 1;
3302 		for (i = 0; hotkeys[i]; ++i)
3303 		{
3304 #ifdef FEAT_MBYTE
3305 		    if (has_mbyte)
3306 		    {
3307 			if ((*mb_ptr2char)(hotkeys + i) == c)
3308 			    break;
3309 			i += (*mb_ptr2len)(hotkeys + i) - 1;
3310 		    }
3311 		    else
3312 #endif
3313 			if (hotkeys[i] == c)
3314 			    break;
3315 		    ++retval;
3316 		}
3317 		if (hotkeys[i])
3318 		    break;
3319 		/* No hotkey match, so keep waiting */
3320 		continue;
3321 	    }
3322 	    break;
3323 	}
3324 
3325 	vim_free(hotkeys);
3326     }
3327 
3328     State = oldState;
3329 #ifdef FEAT_MOUSE
3330     setmouse();
3331 #endif
3332     --no_wait_return;
3333     msg_end_prompt();
3334 
3335     return retval;
3336 }
3337 
3338 static int copy_char __ARGS((char_u *from, char_u *to, int lowercase));
3339 
3340 /*
3341  * Copy one character from "*from" to "*to", taking care of multi-byte
3342  * characters.  Return the length of the character in bytes.
3343  */
3344     static int
3345 copy_char(from, to, lowercase)
3346     char_u	*from;
3347     char_u	*to;
3348     int		lowercase;	/* make character lower case */
3349 {
3350 #ifdef FEAT_MBYTE
3351     int		len;
3352     int		c;
3353 
3354     if (has_mbyte)
3355     {
3356 	if (lowercase)
3357 	{
3358 	    c = MB_TOLOWER((*mb_ptr2char)(from));
3359 	    return (*mb_char2bytes)(c, to);
3360 	}
3361 	else
3362 	{
3363 	    len = (*mb_ptr2len)(from);
3364 	    mch_memmove(to, from, (size_t)len);
3365 	    return len;
3366 	}
3367     }
3368     else
3369 #endif
3370     {
3371 	if (lowercase)
3372 	    *to = (char_u)TOLOWER_LOC(*from);
3373 	else
3374 	    *to = *from;
3375 	return 1;
3376     }
3377 }
3378 
3379 /*
3380  * Format the dialog string, and display it at the bottom of
3381  * the screen. Return a string of hotkey chars (if defined) for
3382  * each 'button'. If a button has no hotkey defined, the first character of
3383  * the button is used.
3384  * The hotkeys can be multi-byte characters, but without combining chars.
3385  *
3386  * Returns an allocated string with hotkeys, or NULL for error.
3387  */
3388     static char_u *
3389 msg_show_console_dialog(message, buttons, dfltbutton)
3390     char_u	*message;
3391     char_u	*buttons;
3392     int		dfltbutton;
3393 {
3394     int		len = 0;
3395 #ifdef FEAT_MBYTE
3396 # define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1)
3397 #else
3398 # define HOTK_LEN 1
3399 #endif
3400     int		lenhotkey = HOTK_LEN;	/* count first button */
3401     char_u	*hotk = NULL;
3402     char_u	*msgp = NULL;
3403     char_u	*hotkp = NULL;
3404     char_u	*r;
3405     int		copy;
3406 #define HAS_HOTKEY_LEN 30
3407     char_u	has_hotkey[HAS_HOTKEY_LEN];
3408     int		first_hotkey = FALSE;	/* first char of button is hotkey */
3409     int		idx;
3410 
3411     has_hotkey[0] = FALSE;
3412 
3413     /*
3414      * First loop: compute the size of memory to allocate.
3415      * Second loop: copy to the allocated memory.
3416      */
3417     for (copy = 0; copy <= 1; ++copy)
3418     {
3419 	r = buttons;
3420 	idx = 0;
3421 	while (*r)
3422 	{
3423 	    if (*r == DLG_BUTTON_SEP)
3424 	    {
3425 		if (copy)
3426 		{
3427 		    *msgp++ = ',';
3428 		    *msgp++ = ' ';	    /* '\n' -> ', ' */
3429 
3430 		    /* advance to next hotkey and set default hotkey */
3431 #ifdef FEAT_MBYTE
3432 		    if (has_mbyte)
3433 			hotkp += (*mb_ptr2len)(hotkp);
3434 		    else
3435 #endif
3436 			++hotkp;
3437 		    (void)copy_char(r + 1, hotkp, TRUE);
3438 		    if (dfltbutton)
3439 			--dfltbutton;
3440 
3441 		    /* If no hotkey is specified first char is used. */
3442 		    if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx])
3443 			first_hotkey = TRUE;
3444 		}
3445 		else
3446 		{
3447 		    len += 3;		    /* '\n' -> ', '; 'x' -> '(x)' */
3448 		    lenhotkey += HOTK_LEN;  /* each button needs a hotkey */
3449 		    if (idx < HAS_HOTKEY_LEN - 1)
3450 			has_hotkey[++idx] = FALSE;
3451 		}
3452 	    }
3453 	    else if (*r == DLG_HOTKEY_CHAR || first_hotkey)
3454 	    {
3455 		if (*r == DLG_HOTKEY_CHAR)
3456 		    ++r;
3457 		first_hotkey = FALSE;
3458 		if (copy)
3459 		{
3460 		    if (*r == DLG_HOTKEY_CHAR)		/* '&&a' -> '&a' */
3461 			*msgp++ = *r;
3462 		    else
3463 		    {
3464 			/* '&a' -> '[a]' */
3465 			*msgp++ = (dfltbutton == 1) ? '[' : '(';
3466 			msgp += copy_char(r, msgp, FALSE);
3467 			*msgp++ = (dfltbutton == 1) ? ']' : ')';
3468 
3469 			/* redefine hotkey */
3470 			(void)copy_char(r, hotkp, TRUE);
3471 		    }
3472 		}
3473 		else
3474 		{
3475 		    ++len;	    /* '&a' -> '[a]' */
3476 		    if (idx < HAS_HOTKEY_LEN - 1)
3477 			has_hotkey[idx] = TRUE;
3478 		}
3479 	    }
3480 	    else
3481 	    {
3482 		/* everything else copy literally */
3483 		if (copy)
3484 		    msgp += copy_char(r, msgp, FALSE);
3485 	    }
3486 
3487 	    /* advance to the next character */
3488 	    mb_ptr_adv(r);
3489 	}
3490 
3491 	if (copy)
3492 	{
3493 	    *msgp++ = ':';
3494 	    *msgp++ = ' ';
3495 	    *msgp = NUL;
3496 	    mb_ptr_adv(hotkp);
3497 	    *hotkp = NUL;
3498 	}
3499 	else
3500 	{
3501 	    len += STRLEN(message)
3502 		    + 2			/* for the NL's */
3503 		    + STRLEN(buttons)
3504 		    + 3;		/* for the ": " and NUL */
3505 	    lenhotkey++;		/* for the NUL */
3506 
3507 	    /* If no hotkey is specified first char is used. */
3508 	    if (!has_hotkey[0])
3509 	    {
3510 		first_hotkey = TRUE;
3511 		len += 2;		/* "x" -> "[x]" */
3512 	    }
3513 
3514 	    /*
3515 	     * Now allocate and load the strings
3516 	     */
3517 	    vim_free(confirm_msg);
3518 	    confirm_msg = alloc(len);
3519 	    if (confirm_msg == NULL)
3520 		return NULL;
3521 	    *confirm_msg = NUL;
3522 	    hotk = alloc(lenhotkey);
3523 	    if (hotk == NULL)
3524 		return NULL;
3525 
3526 	    *confirm_msg = '\n';
3527 	    STRCPY(confirm_msg + 1, message);
3528 
3529 	    msgp = confirm_msg + 1 + STRLEN(message);
3530 	    hotkp = hotk;
3531 
3532 	    /* define first default hotkey */
3533 	    (void)copy_char(buttons, hotkp, TRUE);
3534 
3535 	    /* Remember where the choices start, displaying starts here when
3536 	     * "hotkp" typed at the more prompt. */
3537 	    confirm_msg_tail = msgp;
3538 	    *msgp++ = '\n';
3539 	}
3540     }
3541 
3542     display_confirm_msg();
3543     return hotk;
3544 }
3545 
3546 /*
3547  * Display the ":confirm" message.  Also called when screen resized.
3548  */
3549     void
3550 display_confirm_msg()
3551 {
3552     /* avoid that 'q' at the more prompt truncates the message here */
3553     ++confirm_msg_used;
3554     if (confirm_msg != NULL)
3555 	msg_puts_attr(confirm_msg, hl_attr(HLF_M));
3556     --confirm_msg_used;
3557 }
3558 
3559 #endif /* FEAT_CON_DIALOG */
3560 
3561 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
3562 
3563     int
3564 vim_dialog_yesno(type, title, message, dflt)
3565     int		type;
3566     char_u	*title;
3567     char_u	*message;
3568     int		dflt;
3569 {
3570     if (do_dialog(type,
3571 		title == NULL ? (char_u *)_("Question") : title,
3572 		message,
3573 		(char_u *)_("&Yes\n&No"), dflt, NULL) == 1)
3574 	return VIM_YES;
3575     return VIM_NO;
3576 }
3577 
3578     int
3579 vim_dialog_yesnocancel(type, title, message, dflt)
3580     int		type;
3581     char_u	*title;
3582     char_u	*message;
3583     int		dflt;
3584 {
3585     switch (do_dialog(type,
3586 		title == NULL ? (char_u *)_("Question") : title,
3587 		message,
3588 		(char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL))
3589     {
3590 	case 1: return VIM_YES;
3591 	case 2: return VIM_NO;
3592     }
3593     return VIM_CANCEL;
3594 }
3595 
3596     int
3597 vim_dialog_yesnoallcancel(type, title, message, dflt)
3598     int		type;
3599     char_u	*title;
3600     char_u	*message;
3601     int		dflt;
3602 {
3603     switch (do_dialog(type,
3604 		title == NULL ? (char_u *)"Question" : title,
3605 		message,
3606 		(char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"),
3607 								  dflt, NULL))
3608     {
3609 	case 1: return VIM_YES;
3610 	case 2: return VIM_NO;
3611 	case 3: return VIM_ALL;
3612 	case 4: return VIM_DISCARDALL;
3613     }
3614     return VIM_CANCEL;
3615 }
3616 
3617 #endif /* FEAT_GUI_DIALOG || FEAT_CON_DIALOG */
3618 
3619 #if defined(FEAT_BROWSE) || defined(PROTO)
3620 /*
3621  * Generic browse function.  Calls gui_mch_browse() when possible.
3622  * Later this may pop-up a non-GUI file selector (external command?).
3623  */
3624     char_u *
3625 do_browse(flags, title, dflt, ext, initdir, filter, buf)
3626     int		flags;		/* BROWSE_SAVE and BROWSE_DIR */
3627     char_u	*title;		/* title for the window */
3628     char_u	*dflt;		/* default file name (may include directory) */
3629     char_u	*ext;		/* extension added */
3630     char_u	*initdir;	/* initial directory, NULL for current dir or
3631 				   when using path from "dflt" */
3632     char_u	*filter;	/* file name filter */
3633     buf_T	*buf;		/* buffer to read/write for */
3634 {
3635     char_u		*fname;
3636     static char_u	*last_dir = NULL;    /* last used directory */
3637     char_u		*tofree = NULL;
3638     int			save_browse = cmdmod.browse;
3639 
3640     /* Must turn off browse to avoid that autocommands will get the
3641      * flag too!  */
3642     cmdmod.browse = FALSE;
3643 
3644     if (title == NULL || *title == NUL)
3645     {
3646 	if (flags & BROWSE_DIR)
3647 	    title = (char_u *)_("Select Directory dialog");
3648 	else if (flags & BROWSE_SAVE)
3649 	    title = (char_u *)_("Save File dialog");
3650 	else
3651 	    title = (char_u *)_("Open File dialog");
3652     }
3653 
3654     /* When no directory specified, use default file name, default dir, buffer
3655      * dir, last dir or current dir */
3656     if ((initdir == NULL || *initdir == NUL) && dflt != NULL && *dflt != NUL)
3657     {
3658 	if (mch_isdir(dflt))		/* default file name is a directory */
3659 	{
3660 	    initdir = dflt;
3661 	    dflt = NULL;
3662 	}
3663 	else if (gettail(dflt) != dflt)	/* default file name includes a path */
3664 	{
3665 	    tofree = vim_strsave(dflt);
3666 	    if (tofree != NULL)
3667 	    {
3668 		initdir = tofree;
3669 		*gettail(initdir) = NUL;
3670 		dflt = gettail(dflt);
3671 	    }
3672 	}
3673     }
3674 
3675     if (initdir == NULL || *initdir == NUL)
3676     {
3677 	/* When 'browsedir' is a directory, use it */
3678 	if (STRCMP(p_bsdir, "last") != 0
3679 		&& STRCMP(p_bsdir, "buffer") != 0
3680 		&& STRCMP(p_bsdir, "current") != 0
3681 		&& mch_isdir(p_bsdir))
3682 	    initdir = p_bsdir;
3683 	/* When saving or 'browsedir' is "buffer", use buffer fname */
3684 	else if (((flags & BROWSE_SAVE) || *p_bsdir == 'b')
3685 		&& buf != NULL && buf->b_ffname != NULL)
3686 	{
3687 	    if (dflt == NULL || *dflt == NUL)
3688 		dflt = gettail(curbuf->b_ffname);
3689 	    tofree = vim_strsave(curbuf->b_ffname);
3690 	    if (tofree != NULL)
3691 	    {
3692 		initdir = tofree;
3693 		*gettail(initdir) = NUL;
3694 	    }
3695 	}
3696 	/* When 'browsedir' is "last", use dir from last browse */
3697 	else if (*p_bsdir == 'l')
3698 	    initdir = last_dir;
3699 	/* When 'browsedir is "current", use current directory.  This is the
3700 	 * default already, leave initdir empty. */
3701     }
3702 
3703 # ifdef FEAT_GUI
3704     if (gui.in_use)		/* when this changes, also adjust f_has()! */
3705     {
3706 	if (filter == NULL
3707 #  ifdef FEAT_EVAL
3708 		&& (filter = get_var_value((char_u *)"b:browsefilter")) == NULL
3709 		&& (filter = get_var_value((char_u *)"g:browsefilter")) == NULL
3710 #  endif
3711 	)
3712 	    filter = BROWSE_FILTER_DEFAULT;
3713 	if (flags & BROWSE_DIR)
3714 	{
3715 #  if defined(HAVE_GTK2) || defined(WIN3264)
3716 	    /* For systems that have a directory dialog. */
3717 	    fname = gui_mch_browsedir(title, initdir);
3718 #  else
3719 	    /* Generic solution for selecting a directory: select a file and
3720 	     * remove the file name. */
3721 	    fname = gui_mch_browse(0, title, dflt, ext, initdir, (char_u *)"");
3722 #  endif
3723 #  if !defined(HAVE_GTK2)
3724 	    /* Win32 adds a dummy file name, others return an arbitrary file
3725 	     * name.  GTK+ 2 returns only the directory, */
3726 	    if (fname != NULL && *fname != NUL && !mch_isdir(fname))
3727 	    {
3728 		/* Remove the file name. */
3729 		char_u	    *tail = gettail_sep(fname);
3730 
3731 		if (tail == fname)
3732 		    *tail++ = '.';	/* use current dir */
3733 		*tail = NUL;
3734 	    }
3735 #  endif
3736 	}
3737 	else
3738 	    fname = gui_mch_browse(flags & BROWSE_SAVE,
3739 					   title, dflt, ext, initdir, filter);
3740 
3741 	/* We hang around in the dialog for a while, the user might do some
3742 	 * things to our files.  The Win32 dialog allows deleting or renaming
3743 	 * a file, check timestamps. */
3744 	need_check_timestamps = TRUE;
3745 	did_check_timestamps = FALSE;
3746     }
3747     else
3748 # endif
3749     {
3750 	/* TODO: non-GUI file selector here */
3751 	EMSG(_("E338: Sorry, no file browser in console mode"));
3752 	fname = NULL;
3753     }
3754 
3755     /* keep the directory for next time */
3756     if (fname != NULL)
3757     {
3758 	vim_free(last_dir);
3759 	last_dir = vim_strsave(fname);
3760 	if (last_dir != NULL && !(flags & BROWSE_DIR))
3761 	{
3762 	    *gettail(last_dir) = NUL;
3763 	    if (*last_dir == NUL)
3764 	    {
3765 		/* filename only returned, must be in current dir */
3766 		vim_free(last_dir);
3767 		last_dir = alloc(MAXPATHL);
3768 		if (last_dir != NULL)
3769 		    mch_dirname(last_dir, MAXPATHL);
3770 	    }
3771 	}
3772     }
3773 
3774     vim_free(tofree);
3775     cmdmod.browse = save_browse;
3776 
3777     return fname;
3778 }
3779 #endif
3780 
3781 #if defined(HAVE_STDARG_H) && defined(FEAT_EVAL)
3782 static char *e_printf = N_("E766: Insufficient arguments for printf()");
3783 
3784 static long tv_nr __ARGS((typval_T *tvs, int *idxp));
3785 static char *tv_str __ARGS((typval_T *tvs, int *idxp));
3786 
3787 /*
3788  * Get number argument from "idxp" entry in "tvs".  First entry is 1.
3789  */
3790     static long
3791 tv_nr(tvs, idxp)
3792     typval_T	*tvs;
3793     int		*idxp;
3794 {
3795     int		idx = *idxp - 1;
3796     long	n = 0;
3797     int		err = FALSE;
3798 
3799     if (tvs[idx].v_type == VAR_UNKNOWN)
3800 	EMSG(_(e_printf));
3801     else
3802     {
3803 	++*idxp;
3804 	n = get_tv_number_chk(&tvs[idx], &err);
3805 	if (err)
3806 	    n = 0;
3807     }
3808     return n;
3809 }
3810 
3811 /*
3812  * Get string argument from "idxp" entry in "tvs".  First entry is 1.
3813  * Returns NULL for an error.
3814  */
3815     static char *
3816 tv_str(tvs, idxp)
3817     typval_T	*tvs;
3818     int		*idxp;
3819 {
3820     int		idx = *idxp - 1;
3821     char	*s = NULL;
3822 
3823     if (tvs[idx].v_type == VAR_UNKNOWN)
3824 	EMSG(_(e_printf));
3825     else
3826     {
3827 	++*idxp;
3828 	s = (char *)get_tv_string_chk(&tvs[idx]);
3829     }
3830     return s;
3831 }
3832 #endif
3833 
3834 /*
3835  * This code was included to provide a portable vsnprintf() and snprintf().
3836  * Some systems may provide their own, but we always use these for
3837  * consistency.
3838  *
3839  * This code is based on snprintf.c - a portable implementation of snprintf
3840  * by Mark Martinec <[email protected]>, Version 2.2, 2000-10-06.
3841  * Included with permission.  It was heavely modified to fit in Vim.
3842  * The original code, including useful comments, can be found here:
3843  *	http://www.ijs.si/software/snprintf/
3844  *
3845  * This snprintf() only supports the following conversion specifiers:
3846  * s, c, d, u, o, x, X, p  (and synonyms: i, D, U, O - see below)
3847  * with flags: '-', '+', ' ', '0' and '#'.
3848  * An asterisk is supported for field width as well as precision.
3849  *
3850  * Length modifiers 'h' (short int) and 'l' (long int) are supported.
3851  * 'll' (long long int) is not supported.
3852  *
3853  * The locale is not used, the string is used as a byte string.  This is only
3854  * relevant for double-byte encodings where the second byte may be '%'.
3855  *
3856  * It is permitted for str_m to be zero, and it is permitted to specify NULL
3857  * pointer for resulting string argument if str_m is zero (as per ISO C99).
3858  *
3859  * The return value is the number of characters which would be generated
3860  * for the given input, excluding the trailing null. If this value
3861  * is greater or equal to str_m, not all characters from the result
3862  * have been stored in str, output bytes beyond the (str_m-1) -th character
3863  * are discarded. If str_m is greater than zero it is guaranteed
3864  * the resulting string will be null-terminated.
3865  */
3866 
3867 /*
3868  * When va_list is not supported we only define vim_snprintf().
3869  *
3870  * vim_vsnprintf() can be invoked with either "va_list" or a list of
3871  * "typval_T".  When the latter is not used it must be NULL.
3872  */
3873 
3874 /* When generating prototypes all of this is skipped, cproto doesn't
3875  * understand this. */
3876 #ifndef PROTO
3877 # ifdef HAVE_STDARG_H
3878     int
3879 vim_snprintf(char *str, size_t str_m, char *fmt, ...)
3880 {
3881     va_list	ap;
3882     int		str_l;
3883 
3884     va_start(ap, fmt);
3885     str_l = vim_vsnprintf(str, str_m, fmt, ap, NULL);
3886     va_end(ap);
3887     return str_l;
3888 }
3889 
3890     int
3891 vim_vsnprintf(str, str_m, fmt, ap, tvs)
3892 # else
3893     /* clumsy way to work around missing va_list */
3894 #  define get_a_arg(i) (++i, i == 2 ? a1 : i == 3 ? a2 : i == 4 ? a3 : i == 5 ? a4 : i == 6 ? a5 : i == 7 ? a6 : i == 8 ? a7 : i == 9 ? a8 : i == 10 ? a9 : a10)
3895 
3896 /* VARARGS */
3897     int
3898 #ifdef __BORLANDC__
3899 _RTLENTRYF
3900 #endif
3901 vim_snprintf(str, str_m, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
3902 # endif
3903     char	*str;
3904     size_t	str_m;
3905     char	*fmt;
3906 # ifdef HAVE_STDARG_H
3907     va_list	ap;
3908     typval_T	*tvs;
3909 # else
3910     long	a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
3911 # endif
3912 {
3913     size_t	str_l = 0;
3914     char	*p = fmt;
3915     int		arg_idx = 1;
3916 
3917     if (p == NULL)
3918 	p = "";
3919     while (*p != NUL)
3920     {
3921 	if (*p != '%')
3922 	{
3923 	    char    *q = strchr(p + 1, '%');
3924 	    size_t  n = (q == NULL) ? STRLEN(p) : (q - p);
3925 
3926 	    /* Copy up to the next '%' or NUL without any changes. */
3927 	    if (str_l < str_m)
3928 	    {
3929 		size_t avail = str_m - str_l;
3930 
3931 		mch_memmove(str + str_l, p, n > avail ? avail : n);
3932 	    }
3933 	    p += n;
3934 	    str_l += n;
3935 	}
3936 	else
3937 	{
3938 	    size_t  min_field_width = 0, precision = 0;
3939 	    int	    zero_padding = 0, precision_specified = 0, justify_left = 0;
3940 	    int	    alternate_form = 0, force_sign = 0;
3941 
3942 	    /* If both the ' ' and '+' flags appear, the ' ' flag should be
3943 	     * ignored. */
3944 	    int	    space_for_positive = 1;
3945 
3946 	    /* allowed values: \0, h, l, L */
3947 	    char    length_modifier = '\0';
3948 
3949 	    /* temporary buffer for simple numeric->string conversion */
3950 	    char    tmp[32];
3951 
3952 	    /* string address in case of string argument */
3953 	    char    *str_arg;
3954 
3955 	    /* natural field width of arg without padding and sign */
3956 	    size_t  str_arg_l;
3957 
3958 	    /* unsigned char argument value - only defined for c conversion.
3959 	     * N.B. standard explicitly states the char argument for the c
3960 	     * conversion is unsigned */
3961 	    unsigned char uchar_arg;
3962 
3963 	    /* number of zeros to be inserted for numeric conversions as
3964 	     * required by the precision or minimal field width */
3965 	    size_t  number_of_zeros_to_pad = 0;
3966 
3967 	    /* index into tmp where zero padding is to be inserted */
3968 	    size_t  zero_padding_insertion_ind = 0;
3969 
3970 	    /* current conversion specifier character */
3971 	    char    fmt_spec = '\0';
3972 
3973 	    str_arg = NULL;
3974 	    p++;  /* skip '%' */
3975 
3976 	    /* parse flags */
3977 	    while (*p == '0' || *p == '-' || *p == '+' || *p == ' '
3978 						   || *p == '#' || *p == '\'')
3979 	    {
3980 		switch (*p)
3981 		{
3982 		    case '0': zero_padding = 1; break;
3983 		    case '-': justify_left = 1; break;
3984 		    case '+': force_sign = 1; space_for_positive = 0; break;
3985 		    case ' ': force_sign = 1;
3986 			      /* If both the ' ' and '+' flags appear, the ' '
3987 			       * flag should be ignored */
3988 			      break;
3989 		    case '#': alternate_form = 1; break;
3990 		    case '\'': break;
3991 		}
3992 		p++;
3993 	    }
3994 	    /* If the '0' and '-' flags both appear, the '0' flag should be
3995 	     * ignored. */
3996 
3997 	    /* parse field width */
3998 	    if (*p == '*')
3999 	    {
4000 		int j;
4001 
4002 		p++;
4003 		j =
4004 #ifndef HAVE_STDARG_H
4005 		    get_a_arg(arg_idx);
4006 #else
4007 # if defined(FEAT_EVAL)
4008 		    tvs != NULL ? tv_nr(tvs, &arg_idx) :
4009 # endif
4010 			va_arg(ap, int);
4011 #endif
4012 		if (j >= 0)
4013 		    min_field_width = j;
4014 		else
4015 		{
4016 		    min_field_width = -j;
4017 		    justify_left = 1;
4018 		}
4019 	    }
4020 	    else if (VIM_ISDIGIT((int)(*p)))
4021 	    {
4022 		/* size_t could be wider than unsigned int; make sure we treat
4023 		 * argument like common implementations do */
4024 		unsigned int uj = *p++ - '0';
4025 
4026 		while (VIM_ISDIGIT((int)(*p)))
4027 		    uj = 10 * uj + (unsigned int)(*p++ - '0');
4028 		min_field_width = uj;
4029 	    }
4030 
4031 	    /* parse precision */
4032 	    if (*p == '.')
4033 	    {
4034 		p++;
4035 		precision_specified = 1;
4036 		if (*p == '*')
4037 		{
4038 		    int j;
4039 
4040 		    j =
4041 #ifndef HAVE_STDARG_H
4042 			get_a_arg(arg_idx);
4043 #else
4044 # if defined(FEAT_EVAL)
4045 			tvs != NULL ? tv_nr(tvs, &arg_idx) :
4046 # endif
4047 			    va_arg(ap, int);
4048 #endif
4049 		    p++;
4050 		    if (j >= 0)
4051 			precision = j;
4052 		    else
4053 		    {
4054 			precision_specified = 0;
4055 			precision = 0;
4056 		    }
4057 		}
4058 		else if (VIM_ISDIGIT((int)(*p)))
4059 		{
4060 		    /* size_t could be wider than unsigned int; make sure we
4061 		     * treat argument like common implementations do */
4062 		    unsigned int uj = *p++ - '0';
4063 
4064 		    while (VIM_ISDIGIT((int)(*p)))
4065 			uj = 10 * uj + (unsigned int)(*p++ - '0');
4066 		    precision = uj;
4067 		}
4068 	    }
4069 
4070 	    /* parse 'h', 'l' and 'll' length modifiers */
4071 	    if (*p == 'h' || *p == 'l')
4072 	    {
4073 		length_modifier = *p;
4074 		p++;
4075 		if (length_modifier == 'l' && *p == 'l')
4076 		{
4077 		    /* double l = long long */
4078 		    length_modifier = 'l';	/* treat it as a single 'l' */
4079 		    p++;
4080 		}
4081 	    }
4082 	    fmt_spec = *p;
4083 
4084 	    /* common synonyms: */
4085 	    switch (fmt_spec)
4086 	    {
4087 		case 'i': fmt_spec = 'd'; break;
4088 		case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
4089 		case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
4090 		case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
4091 		default: break;
4092 	    }
4093 
4094 	    /* get parameter value, do initial processing */
4095 	    switch (fmt_spec)
4096 	    {
4097 		/* '%' and 'c' behave similar to 's' regarding flags and field
4098 		 * widths */
4099 	    case '%':
4100 	    case 'c':
4101 	    case 's':
4102 		length_modifier = '\0';
4103 		zero_padding = 0;    /* turn zero padding off for string
4104 					conversions */
4105 		str_arg_l = 1;
4106 		switch (fmt_spec)
4107 		{
4108 		case '%':
4109 		    str_arg = p;
4110 		    break;
4111 
4112 		case 'c':
4113 		    {
4114 			int j;
4115 
4116 			j =
4117 #ifndef HAVE_STDARG_H
4118 			    get_a_arg(arg_idx);
4119 #else
4120 # if defined(FEAT_EVAL)
4121 			    tvs != NULL ? tv_nr(tvs, &arg_idx) :
4122 # endif
4123 				va_arg(ap, int);
4124 #endif
4125 			/* standard demands unsigned char */
4126 			uchar_arg = (unsigned char)j;
4127 			str_arg = (char *)&uchar_arg;
4128 			break;
4129 		    }
4130 
4131 		case 's':
4132 		    str_arg =
4133 #ifndef HAVE_STDARG_H
4134 				(char *)get_a_arg(arg_idx);
4135 #else
4136 # if defined(FEAT_EVAL)
4137 				tvs != NULL ? tv_str(tvs, &arg_idx) :
4138 # endif
4139 				    va_arg(ap, char *);
4140 #endif
4141 		    if (str_arg == NULL)
4142 		    {
4143 			str_arg = "[NULL]";
4144 			str_arg_l = 6;
4145 		    }
4146 		    /* make sure not to address string beyond the specified
4147 		     * precision !!! */
4148 		    else if (!precision_specified)
4149 			str_arg_l = strlen(str_arg);
4150 		    /* truncate string if necessary as requested by precision */
4151 		    else if (precision == 0)
4152 			str_arg_l = 0;
4153 		    else
4154 		    {
4155 			/* memchr on HP does not like n > 2^31  !!! */
4156 			char *q = memchr(str_arg, '\0',
4157 				precision <= 0x7fffffff ? precision
4158 								: 0x7fffffff);
4159 			str_arg_l = (q == NULL) ? precision : q - str_arg;
4160 		    }
4161 		    break;
4162 
4163 		default:
4164 		    break;
4165 		}
4166 		break;
4167 
4168 	    case 'd': case 'u': case 'o': case 'x': case 'X': case 'p':
4169 		{
4170 		    /* NOTE: the u, o, x, X and p conversion specifiers
4171 		     * imply the value is unsigned;  d implies a signed
4172 		     * value */
4173 
4174 		    /* 0 if numeric argument is zero (or if pointer is
4175 		     * NULL for 'p'), +1 if greater than zero (or nonzero
4176 		     * for unsigned arguments), -1 if negative (unsigned
4177 		     * argument is never negative) */
4178 		    int arg_sign = 0;
4179 
4180 		    /* only defined for length modifier h, or for no
4181 		     * length modifiers */
4182 		    int int_arg = 0;
4183 		    unsigned int uint_arg = 0;
4184 
4185 		    /* only defined for length modifier l */
4186 		    long int long_arg = 0;
4187 		    unsigned long int ulong_arg = 0;
4188 
4189 		    /* pointer argument value -only defined for p
4190 		     * conversion */
4191 		    void *ptr_arg = NULL;
4192 
4193 		    if (fmt_spec == 'p')
4194 		    {
4195 			length_modifier = '\0';
4196 			ptr_arg =
4197 #ifndef HAVE_STDARG_H
4198 				 (void *)get_a_arg(arg_idx);
4199 #else
4200 # if defined(FEAT_EVAL)
4201 				 tvs != NULL ? (void *)tv_str(tvs, &arg_idx) :
4202 # endif
4203 					va_arg(ap, void *);
4204 #endif
4205 			if (ptr_arg != NULL)
4206 			    arg_sign = 1;
4207 		    }
4208 		    else if (fmt_spec == 'd')
4209 		    {
4210 			/* signed */
4211 			switch (length_modifier)
4212 			{
4213 			case '\0':
4214 			case 'h':
4215 			    /* char and short arguments are passed as int. */
4216 			    int_arg =
4217 #ifndef HAVE_STDARG_H
4218 					get_a_arg(arg_idx);
4219 #else
4220 # if defined(FEAT_EVAL)
4221 					tvs != NULL ? tv_nr(tvs, &arg_idx) :
4222 # endif
4223 					    va_arg(ap, int);
4224 #endif
4225 			    if (int_arg > 0)
4226 				arg_sign =  1;
4227 			    else if (int_arg < 0)
4228 				arg_sign = -1;
4229 			    break;
4230 			case 'l':
4231 			    long_arg =
4232 #ifndef HAVE_STDARG_H
4233 					get_a_arg(arg_idx);
4234 #else
4235 # if defined(FEAT_EVAL)
4236 					tvs != NULL ? tv_nr(tvs, &arg_idx) :
4237 # endif
4238 					    va_arg(ap, long int);
4239 #endif
4240 			    if (long_arg > 0)
4241 				arg_sign =  1;
4242 			    else if (long_arg < 0)
4243 				arg_sign = -1;
4244 			    break;
4245 			}
4246 		    }
4247 		    else
4248 		    {
4249 			/* unsigned */
4250 			switch (length_modifier)
4251 			{
4252 			    case '\0':
4253 			    case 'h':
4254 				uint_arg =
4255 #ifndef HAVE_STDARG_H
4256 					    get_a_arg(arg_idx);
4257 #else
4258 # if defined(FEAT_EVAL)
4259 					    tvs != NULL ? tv_nr(tvs, &arg_idx) :
4260 # endif
4261 						va_arg(ap, unsigned int);
4262 #endif
4263 				if (uint_arg != 0)
4264 				    arg_sign = 1;
4265 				break;
4266 			    case 'l':
4267 				ulong_arg =
4268 #ifndef HAVE_STDARG_H
4269 					    get_a_arg(arg_idx);
4270 #else
4271 # if defined(FEAT_EVAL)
4272 					    tvs != NULL ? tv_nr(tvs, &arg_idx) :
4273 # endif
4274 						va_arg(ap, unsigned long int);
4275 #endif
4276 				if (ulong_arg != 0)
4277 				    arg_sign = 1;
4278 				break;
4279 			}
4280 		    }
4281 
4282 		    str_arg = tmp;
4283 		    str_arg_l = 0;
4284 
4285 		    /* NOTE:
4286 		     *   For d, i, u, o, x, and X conversions, if precision is
4287 		     *   specified, the '0' flag should be ignored. This is so
4288 		     *   with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux,
4289 		     *   FreeBSD, NetBSD; but not with Perl.
4290 		     */
4291 		    if (precision_specified)
4292 			zero_padding = 0;
4293 		    if (fmt_spec == 'd')
4294 		    {
4295 			if (force_sign && arg_sign >= 0)
4296 			    tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
4297 			/* leave negative numbers for sprintf to handle, to
4298 			 * avoid handling tricky cases like (short int)-32768 */
4299 		    }
4300 		    else if (alternate_form)
4301 		    {
4302 			if (arg_sign != 0
4303 				     && (fmt_spec == 'x' || fmt_spec == 'X') )
4304 			{
4305 			    tmp[str_arg_l++] = '0';
4306 			    tmp[str_arg_l++] = fmt_spec;
4307 			}
4308 			/* alternate form should have no effect for p
4309 			 * conversion, but ... */
4310 		    }
4311 
4312 		    zero_padding_insertion_ind = str_arg_l;
4313 		    if (!precision_specified)
4314 			precision = 1;   /* default precision is 1 */
4315 		    if (precision == 0 && arg_sign == 0)
4316 		    {
4317 			/* When zero value is formatted with an explicit
4318 			 * precision 0, the resulting formatted string is
4319 			 * empty (d, i, u, o, x, X, p).   */
4320 		    }
4321 		    else
4322 		    {
4323 			char	f[5];
4324 			int	f_l = 0;
4325 
4326 			/* construct a simple format string for sprintf */
4327 			f[f_l++] = '%';
4328 			if (!length_modifier)
4329 			    ;
4330 			else if (length_modifier == '2')
4331 			{
4332 			    f[f_l++] = 'l';
4333 			    f[f_l++] = 'l';
4334 			}
4335 			else
4336 			    f[f_l++] = length_modifier;
4337 			f[f_l++] = fmt_spec;
4338 			f[f_l++] = '\0';
4339 
4340 			if (fmt_spec == 'p')
4341 			    str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
4342 			else if (fmt_spec == 'd')
4343 			{
4344 			    /* signed */
4345 			    switch (length_modifier)
4346 			    {
4347 			    case '\0':
4348 			    case 'h': str_arg_l += sprintf(
4349 						 tmp + str_arg_l, f, int_arg);
4350 				      break;
4351 			    case 'l': str_arg_l += sprintf(
4352 						tmp + str_arg_l, f, long_arg);
4353 				      break;
4354 			    }
4355 			}
4356 			else
4357 			{
4358 			    /* unsigned */
4359 			    switch (length_modifier)
4360 			    {
4361 			    case '\0':
4362 			    case 'h': str_arg_l += sprintf(
4363 						tmp + str_arg_l, f, uint_arg);
4364 				      break;
4365 			    case 'l': str_arg_l += sprintf(
4366 					       tmp + str_arg_l, f, ulong_arg);
4367 				      break;
4368 			    }
4369 			}
4370 
4371 			/* include the optional minus sign and possible
4372 			 * "0x" in the region before the zero padding
4373 			 * insertion point */
4374 			if (zero_padding_insertion_ind < str_arg_l
4375 				&& tmp[zero_padding_insertion_ind] == '-')
4376 			    zero_padding_insertion_ind++;
4377 			if (zero_padding_insertion_ind + 1 < str_arg_l
4378 				&& tmp[zero_padding_insertion_ind]   == '0'
4379 				&& (tmp[zero_padding_insertion_ind + 1] == 'x'
4380 				 || tmp[zero_padding_insertion_ind + 1] == 'X'))
4381 			    zero_padding_insertion_ind += 2;
4382 		    }
4383 
4384 		    {
4385 			size_t num_of_digits = str_arg_l
4386 						 - zero_padding_insertion_ind;
4387 
4388 			if (alternate_form && fmt_spec == 'o'
4389 				/* unless zero is already the first
4390 				 * character */
4391 				&& !(zero_padding_insertion_ind < str_arg_l
4392 				    && tmp[zero_padding_insertion_ind] == '0'))
4393 			{
4394 			    /* assure leading zero for alternate-form
4395 			     * octal numbers */
4396 			    if (!precision_specified
4397 					     || precision < num_of_digits + 1)
4398 			    {
4399 				/* precision is increased to force the
4400 				 * first character to be zero, except if a
4401 				 * zero value is formatted with an
4402 				 * explicit precision of zero */
4403 				precision = num_of_digits + 1;
4404 				precision_specified = 1;
4405 			    }
4406 			}
4407 			/* zero padding to specified precision? */
4408 			if (num_of_digits < precision)
4409 			    number_of_zeros_to_pad = precision - num_of_digits;
4410 		    }
4411 		    /* zero padding to specified minimal field width? */
4412 		    if (!justify_left && zero_padding)
4413 		    {
4414 			int n = min_field_width - (str_arg_l
4415 						    + number_of_zeros_to_pad);
4416 			if (n > 0)
4417 			    number_of_zeros_to_pad += n;
4418 		    }
4419 		    break;
4420 		}
4421 
4422 	    default:
4423 		/* unrecognized conversion specifier, keep format string
4424 		 * as-is */
4425 		zero_padding = 0;  /* turn zero padding off for non-numeric
4426 				      convers. */
4427 		justify_left = 1;
4428 		min_field_width = 0;                /* reset flags */
4429 
4430 		/* discard the unrecognized conversion, just keep *
4431 		 * the unrecognized conversion character          */
4432 		str_arg = p;
4433 		str_arg_l = 0;
4434 		if (*p != NUL)
4435 		    str_arg_l++;  /* include invalid conversion specifier
4436 				     unchanged if not at end-of-string */
4437 		break;
4438 	    }
4439 
4440 	    if (*p != NUL)
4441 		p++;     /* step over the just processed conversion specifier */
4442 
4443 	    /* insert padding to the left as requested by min_field_width;
4444 	     * this does not include the zero padding in case of numerical
4445 	     * conversions*/
4446 	    if (!justify_left)
4447 	    {
4448 		/* left padding with blank or zero */
4449 		int pn = min_field_width - (str_arg_l + number_of_zeros_to_pad);
4450 
4451 		if (pn > 0)
4452 		{
4453 		    if (str_l < str_m)
4454 		    {
4455 			size_t avail = str_m - str_l;
4456 
4457 			vim_memset(str + str_l, zero_padding ? '0' : ' ',
4458 					     (size_t)pn > avail ? avail : pn);
4459 		    }
4460 		    str_l += pn;
4461 		}
4462 	    }
4463 
4464 	    /* zero padding as requested by the precision or by the minimal
4465 	     * field width for numeric conversions required? */
4466 	    if (number_of_zeros_to_pad == 0)
4467 	    {
4468 		/* will not copy first part of numeric right now, *
4469 		 * force it to be copied later in its entirety    */
4470 		zero_padding_insertion_ind = 0;
4471 	    }
4472 	    else
4473 	    {
4474 		/* insert first part of numerics (sign or '0x') before zero
4475 		 * padding */
4476 		int zn = zero_padding_insertion_ind;
4477 
4478 		if (zn > 0)
4479 		{
4480 		    if (str_l < str_m)
4481 		    {
4482 			size_t avail = str_m - str_l;
4483 
4484 			mch_memmove(str + str_l, str_arg,
4485 					     (size_t)zn > avail ? avail : zn);
4486 		    }
4487 		    str_l += zn;
4488 		}
4489 
4490 		/* insert zero padding as requested by the precision or min
4491 		 * field width */
4492 		zn = number_of_zeros_to_pad;
4493 		if (zn > 0)
4494 		{
4495 		    if (str_l < str_m)
4496 		    {
4497 			size_t avail = str_m-str_l;
4498 
4499 			vim_memset(str + str_l, '0',
4500 					     (size_t)zn > avail ? avail : zn);
4501 		    }
4502 		    str_l += zn;
4503 		}
4504 	    }
4505 
4506 	    /* insert formatted string
4507 	     * (or as-is conversion specifier for unknown conversions) */
4508 	    {
4509 		int sn = str_arg_l - zero_padding_insertion_ind;
4510 
4511 		if (sn > 0)
4512 		{
4513 		    if (str_l < str_m)
4514 		    {
4515 			size_t avail = str_m - str_l;
4516 
4517 			mch_memmove(str + str_l,
4518 				str_arg + zero_padding_insertion_ind,
4519 				(size_t)sn > avail ? avail : sn);
4520 		    }
4521 		    str_l += sn;
4522 		}
4523 	    }
4524 
4525 	    /* insert right padding */
4526 	    if (justify_left)
4527 	    {
4528 		/* right blank padding to the field width */
4529 		int pn = min_field_width - (str_arg_l + number_of_zeros_to_pad);
4530 
4531 		if (pn > 0)
4532 		{
4533 		    if (str_l < str_m)
4534 		    {
4535 			size_t avail = str_m - str_l;
4536 
4537 			vim_memset(str + str_l, ' ',
4538 					     (size_t)pn > avail ? avail : pn);
4539 		    }
4540 		    str_l += pn;
4541 		}
4542 	    }
4543 	}
4544     }
4545 
4546     if (str_m > 0)
4547     {
4548 	/* make sure the string is nul-terminated even at the expense of
4549 	 * overwriting the last character (shouldn't happen, but just in case)
4550 	 * */
4551 	str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
4552     }
4553 
4554 #ifdef HAVE_STDARG_H
4555     if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
4556 	EMSG(_("E767: Too many arguments to printf()"));
4557 #endif
4558 
4559     /* Return the number of characters formatted (excluding trailing nul
4560      * character), that is, the number of characters that would have been
4561      * written to the buffer if it were large enough. */
4562     return (int)str_l;
4563 }
4564 
4565 #endif /* PROTO */
4566