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