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