xref: /vim-8.2.3635/src/strings.c (revision 8ee52aff)
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  * strings.c: string manipulation functions
12  */
13 
14 #define USING_FLOAT_STUFF
15 #include "vim.h"
16 
17 /*
18  * Copy "string" into newly allocated memory.
19  */
20     char_u *
21 vim_strsave(char_u *string)
22 {
23     char_u	*p;
24     size_t	len;
25 
26     len = STRLEN(string) + 1;
27     p = alloc(len);
28     if (p != NULL)
29 	mch_memmove(p, string, len);
30     return p;
31 }
32 
33 /*
34  * Copy up to "len" bytes of "string" into newly allocated memory and
35  * terminate with a NUL.
36  * The allocated memory always has size "len + 1", also when "string" is
37  * shorter.
38  */
39     char_u *
40 vim_strnsave(char_u *string, size_t len)
41 {
42     char_u	*p;
43 
44     p = alloc(len + 1);
45     if (p != NULL)
46     {
47 	STRNCPY(p, string, len);
48 	p[len] = NUL;
49     }
50     return p;
51 }
52 
53 /*
54  * Same as vim_strsave(), but any characters found in esc_chars are preceded
55  * by a backslash.
56  */
57     char_u *
58 vim_strsave_escaped(char_u *string, char_u *esc_chars)
59 {
60     return vim_strsave_escaped_ext(string, esc_chars, '\\', FALSE);
61 }
62 
63 /*
64  * Same as vim_strsave_escaped(), but when "bsl" is TRUE also escape
65  * characters where rem_backslash() would remove the backslash.
66  * Escape the characters with "cc".
67  */
68     char_u *
69 vim_strsave_escaped_ext(
70     char_u	*string,
71     char_u	*esc_chars,
72     int		cc,
73     int		bsl)
74 {
75     char_u	*p;
76     char_u	*p2;
77     char_u	*escaped_string;
78     unsigned	length;
79     int		l;
80 
81     // First count the number of backslashes required.
82     // Then allocate the memory and insert them.
83     length = 1;				// count the trailing NUL
84     for (p = string; *p; p++)
85     {
86 	if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
87 	{
88 	    length += l;		// count a multibyte char
89 	    p += l - 1;
90 	    continue;
91 	}
92 	if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
93 	    ++length;			// count a backslash
94 	++length;			// count an ordinary char
95     }
96     escaped_string = alloc(length);
97     if (escaped_string != NULL)
98     {
99 	p2 = escaped_string;
100 	for (p = string; *p; p++)
101 	{
102 	    if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
103 	    {
104 		mch_memmove(p2, p, (size_t)l);
105 		p2 += l;
106 		p += l - 1;		// skip multibyte char
107 		continue;
108 	    }
109 	    if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
110 		*p2++ = cc;
111 	    *p2++ = *p;
112 	}
113 	*p2 = NUL;
114     }
115     return escaped_string;
116 }
117 
118 /*
119  * Return TRUE when 'shell' has "csh" in the tail.
120  */
121     int
122 csh_like_shell(void)
123 {
124     return (strstr((char *)gettail(p_sh), "csh") != NULL);
125 }
126 
127 /*
128  * Escape "string" for use as a shell argument with system().
129  * This uses single quotes, except when we know we need to use double quotes
130  * (MS-DOS and MS-Windows not using PowerShell and without 'shellslash' set).
131  * PowerShell also uses a novel escaping for enclosed single quotes - double
132  * them up.
133  * Escape a newline, depending on the 'shell' option.
134  * When "do_special" is TRUE also replace "!", "%", "#" and things starting
135  * with "<" like "<cfile>".
136  * When "do_newline" is FALSE do not escape newline unless it is csh shell.
137  * Returns the result in allocated memory, NULL if we have run out.
138  */
139     char_u *
140 vim_strsave_shellescape(char_u *string, int do_special, int do_newline)
141 {
142     unsigned	length;
143     char_u	*p;
144     char_u	*d;
145     char_u	*escaped_string;
146     int		l;
147     int		csh_like;
148     char_u	*shname;
149     int		powershell;
150 # ifdef MSWIN
151     int		double_quotes;
152 # endif
153 
154     // Only csh and similar shells expand '!' within single quotes.  For sh and
155     // the like we must not put a backslash before it, it will be taken
156     // literally.  If do_special is set the '!' will be escaped twice.
157     // Csh also needs to have "\n" escaped twice when do_special is set.
158     csh_like = csh_like_shell();
159 
160     // PowerShell uses it's own version for quoting single quotes
161     shname = gettail(p_sh);
162     powershell = strstr((char *)shname, "pwsh") != NULL;
163 # ifdef MSWIN
164     powershell = powershell || strstr((char *)shname, "powershell") != NULL;
165     // PowerShell only accepts single quotes so override shellslash.
166     double_quotes = !powershell && !p_ssl;
167 # endif
168 
169     // First count the number of extra bytes required.
170     length = (unsigned)STRLEN(string) + 3;  // two quotes and a trailing NUL
171     for (p = string; *p != NUL; MB_PTR_ADV(p))
172     {
173 # ifdef MSWIN
174 	if (double_quotes)
175 	{
176 	    if (*p == '"')
177 		++length;		// " -> ""
178 	}
179 	else
180 # endif
181 	if (*p == '\'')
182 	{
183 	    if (powershell)
184 		length +=2;		// ' => ''
185 	    else
186 		length += 3;		// ' => '\''
187 	}
188 	if ((*p == '\n' && (csh_like || do_newline))
189 		|| (*p == '!' && (csh_like || do_special)))
190 	{
191 	    ++length;			// insert backslash
192 	    if (csh_like && do_special)
193 		++length;		// insert backslash
194 	}
195 	if (do_special && find_cmdline_var(p, &l) >= 0)
196 	{
197 	    ++length;			// insert backslash
198 	    p += l - 1;
199 	}
200     }
201 
202     // Allocate memory for the result and fill it.
203     escaped_string = alloc(length);
204     if (escaped_string != NULL)
205     {
206 	d = escaped_string;
207 
208 	// add opening quote
209 # ifdef MSWIN
210 	if (double_quotes)
211 	    *d++ = '"';
212 	else
213 # endif
214 	    *d++ = '\'';
215 
216 	for (p = string; *p != NUL; )
217 	{
218 # ifdef MSWIN
219 	    if (double_quotes)
220 	    {
221 		if (*p == '"')
222 		{
223 		    *d++ = '"';
224 		    *d++ = '"';
225 		    ++p;
226 		    continue;
227 		}
228 	    }
229 	    else
230 # endif
231 	    if (*p == '\'')
232 	    {
233 		if (powershell)
234 		{
235 		    *d++ = '\'';
236 		    *d++ = '\'';
237 		}
238 		else
239 		{
240 		    *d++ = '\'';
241 		    *d++ = '\\';
242 		    *d++ = '\'';
243 		    *d++ = '\'';
244 		}
245 		++p;
246 		continue;
247 	    }
248 	    if ((*p == '\n' && (csh_like || do_newline))
249 		    || (*p == '!' && (csh_like || do_special)))
250 	    {
251 		*d++ = '\\';
252 		if (csh_like && do_special)
253 		    *d++ = '\\';
254 		*d++ = *p++;
255 		continue;
256 	    }
257 	    if (do_special && find_cmdline_var(p, &l) >= 0)
258 	    {
259 		*d++ = '\\';		// insert backslash
260 		while (--l >= 0)	// copy the var
261 		    *d++ = *p++;
262 		continue;
263 	    }
264 
265 	    MB_COPY_CHAR(p, d);
266 	}
267 
268 	// add terminating quote and finish with a NUL
269 # ifdef MSWIN
270 	if (double_quotes)
271 	    *d++ = '"';
272 	else
273 # endif
274 	    *d++ = '\'';
275 	*d = NUL;
276     }
277 
278     return escaped_string;
279 }
280 
281 /*
282  * Like vim_strsave(), but make all characters uppercase.
283  * This uses ASCII lower-to-upper case translation, language independent.
284  */
285     char_u *
286 vim_strsave_up(char_u *string)
287 {
288     char_u *p1;
289 
290     p1 = vim_strsave(string);
291     vim_strup(p1);
292     return p1;
293 }
294 
295 /*
296  * Like vim_strnsave(), but make all characters uppercase.
297  * This uses ASCII lower-to-upper case translation, language independent.
298  */
299     char_u *
300 vim_strnsave_up(char_u *string, size_t len)
301 {
302     char_u *p1;
303 
304     p1 = vim_strnsave(string, len);
305     vim_strup(p1);
306     return p1;
307 }
308 
309 /*
310  * ASCII lower-to-upper case translation, language independent.
311  */
312     void
313 vim_strup(
314     char_u	*p)
315 {
316     char_u  *p2;
317     int	    c;
318 
319     if (p != NULL)
320     {
321 	p2 = p;
322 	while ((c = *p2) != NUL)
323 #ifdef EBCDIC
324 	    *p2++ = isalpha(c) ? toupper(c) : c;
325 #else
326 	    *p2++ = (c < 'a' || c > 'z') ? c : (c - 0x20);
327 #endif
328     }
329 }
330 
331 #if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
332 /*
333  * Make string "s" all upper-case and return it in allocated memory.
334  * Handles multi-byte characters as well as possible.
335  * Returns NULL when out of memory.
336  */
337     static char_u *
338 strup_save(char_u *orig)
339 {
340     char_u	*p;
341     char_u	*res;
342 
343     res = p = vim_strsave(orig);
344 
345     if (res != NULL)
346 	while (*p != NUL)
347 	{
348 	    int		l;
349 
350 	    if (enc_utf8)
351 	    {
352 		int	c, uc;
353 		int	newl;
354 		char_u	*s;
355 
356 		c = utf_ptr2char(p);
357 		l = utf_ptr2len(p);
358 		if (c == 0)
359 		{
360 		    // overlong sequence, use only the first byte
361 		    c = *p;
362 		    l = 1;
363 		}
364 		uc = utf_toupper(c);
365 
366 		// Reallocate string when byte count changes.  This is rare,
367 		// thus it's OK to do another malloc()/free().
368 		newl = utf_char2len(uc);
369 		if (newl != l)
370 		{
371 		    s = alloc(STRLEN(res) + 1 + newl - l);
372 		    if (s == NULL)
373 		    {
374 			vim_free(res);
375 			return NULL;
376 		    }
377 		    mch_memmove(s, res, p - res);
378 		    STRCPY(s + (p - res) + newl, p + l);
379 		    p = s + (p - res);
380 		    vim_free(res);
381 		    res = s;
382 		}
383 
384 		utf_char2bytes(uc, p);
385 		p += newl;
386 	    }
387 	    else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
388 		p += l;		// skip multi-byte character
389 	    else
390 	    {
391 		*p = TOUPPER_LOC(*p); // note that toupper() can be a macro
392 		p++;
393 	    }
394 	}
395 
396     return res;
397 }
398 
399 /*
400  * Make string "s" all lower-case and return it in allocated memory.
401  * Handles multi-byte characters as well as possible.
402  * Returns NULL when out of memory.
403  */
404     char_u *
405 strlow_save(char_u *orig)
406 {
407     char_u	*p;
408     char_u	*res;
409 
410     res = p = vim_strsave(orig);
411 
412     if (res != NULL)
413 	while (*p != NUL)
414 	{
415 	    int		l;
416 
417 	    if (enc_utf8)
418 	    {
419 		int	c, lc;
420 		int	newl;
421 		char_u	*s;
422 
423 		c = utf_ptr2char(p);
424 		l = utf_ptr2len(p);
425 		if (c == 0)
426 		{
427 		    // overlong sequence, use only the first byte
428 		    c = *p;
429 		    l = 1;
430 		}
431 		lc = utf_tolower(c);
432 
433 		// Reallocate string when byte count changes.  This is rare,
434 		// thus it's OK to do another malloc()/free().
435 		newl = utf_char2len(lc);
436 		if (newl != l)
437 		{
438 		    s = alloc(STRLEN(res) + 1 + newl - l);
439 		    if (s == NULL)
440 		    {
441 			vim_free(res);
442 			return NULL;
443 		    }
444 		    mch_memmove(s, res, p - res);
445 		    STRCPY(s + (p - res) + newl, p + l);
446 		    p = s + (p - res);
447 		    vim_free(res);
448 		    res = s;
449 		}
450 
451 		utf_char2bytes(lc, p);
452 		p += newl;
453 	    }
454 	    else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
455 		p += l;		// skip multi-byte character
456 	    else
457 	    {
458 		*p = TOLOWER_LOC(*p); // note that tolower() can be a macro
459 		p++;
460 	    }
461 	}
462 
463     return res;
464 }
465 #endif
466 
467 /*
468  * delete spaces at the end of a string
469  */
470     void
471 del_trailing_spaces(char_u *ptr)
472 {
473     char_u	*q;
474 
475     q = ptr + STRLEN(ptr);
476     while (--q > ptr && VIM_ISWHITE(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
477 	*q = NUL;
478 }
479 
480 /*
481  * Like strncpy(), but always terminate the result with one NUL.
482  * "to" must be "len + 1" long!
483  */
484     void
485 vim_strncpy(char_u *to, char_u *from, size_t len)
486 {
487     STRNCPY(to, from, len);
488     to[len] = NUL;
489 }
490 
491 /*
492  * Like strcat(), but make sure the result fits in "tosize" bytes and is
493  * always NUL terminated. "from" and "to" may overlap.
494  */
495     void
496 vim_strcat(char_u *to, char_u *from, size_t tosize)
497 {
498     size_t tolen = STRLEN(to);
499     size_t fromlen = STRLEN(from);
500 
501     if (tolen + fromlen + 1 > tosize)
502     {
503 	mch_memmove(to + tolen, from, tosize - tolen - 1);
504 	to[tosize - 1] = NUL;
505     }
506     else
507 	mch_memmove(to + tolen, from, fromlen + 1);
508 }
509 
510 #if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO)
511 /*
512  * Compare two strings, ignoring case, using current locale.
513  * Doesn't work for multi-byte characters.
514  * return 0 for match, < 0 for smaller, > 0 for bigger
515  */
516     int
517 vim_stricmp(char *s1, char *s2)
518 {
519     int		i;
520 
521     for (;;)
522     {
523 	i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
524 	if (i != 0)
525 	    return i;			    // this character different
526 	if (*s1 == NUL)
527 	    break;			    // strings match until NUL
528 	++s1;
529 	++s2;
530     }
531     return 0;				    // strings match
532 }
533 #endif
534 
535 #if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO)
536 /*
537  * Compare two strings, for length "len", ignoring case, using current locale.
538  * Doesn't work for multi-byte characters.
539  * return 0 for match, < 0 for smaller, > 0 for bigger
540  */
541     int
542 vim_strnicmp(char *s1, char *s2, size_t len)
543 {
544     int		i;
545 
546     while (len > 0)
547     {
548 	i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
549 	if (i != 0)
550 	    return i;			    // this character different
551 	if (*s1 == NUL)
552 	    break;			    // strings match until NUL
553 	++s1;
554 	++s2;
555 	--len;
556     }
557     return 0;				    // strings match
558 }
559 #endif
560 
561 /*
562  * Search for first occurrence of "c" in "string".
563  * Version of strchr() that handles unsigned char strings with characters from
564  * 128 to 255 correctly.  It also doesn't return a pointer to the NUL at the
565  * end of the string.
566  */
567     char_u  *
568 vim_strchr(char_u *string, int c)
569 {
570     char_u	*p;
571     int		b;
572 
573     p = string;
574     if (enc_utf8 && c >= 0x80)
575     {
576 	while (*p != NUL)
577 	{
578 	    int l = utfc_ptr2len(p);
579 
580 	    // Avoid matching an illegal byte here.
581 	    if (utf_ptr2char(p) == c && l > 1)
582 		return p;
583 	    p += l;
584 	}
585 	return NULL;
586     }
587     if (enc_dbcs != 0 && c > 255)
588     {
589 	int	n2 = c & 0xff;
590 
591 	c = ((unsigned)c >> 8) & 0xff;
592 	while ((b = *p) != NUL)
593 	{
594 	    if (b == c && p[1] == n2)
595 		return p;
596 	    p += (*mb_ptr2len)(p);
597 	}
598 	return NULL;
599     }
600     if (has_mbyte)
601     {
602 	while ((b = *p) != NUL)
603 	{
604 	    if (b == c)
605 		return p;
606 	    p += (*mb_ptr2len)(p);
607 	}
608 	return NULL;
609     }
610     while ((b = *p) != NUL)
611     {
612 	if (b == c)
613 	    return p;
614 	++p;
615     }
616     return NULL;
617 }
618 
619 /*
620  * Version of strchr() that only works for bytes and handles unsigned char
621  * strings with characters above 128 correctly. It also doesn't return a
622  * pointer to the NUL at the end of the string.
623  */
624     char_u  *
625 vim_strbyte(char_u *string, int c)
626 {
627     char_u	*p = string;
628 
629     while (*p != NUL)
630     {
631 	if (*p == c)
632 	    return p;
633 	++p;
634     }
635     return NULL;
636 }
637 
638 /*
639  * Search for last occurrence of "c" in "string".
640  * Version of strrchr() that handles unsigned char strings with characters from
641  * 128 to 255 correctly.  It also doesn't return a pointer to the NUL at the
642  * end of the string.
643  * Return NULL if not found.
644  * Does not handle multi-byte char for "c"!
645  */
646     char_u  *
647 vim_strrchr(char_u *string, int c)
648 {
649     char_u	*retval = NULL;
650     char_u	*p = string;
651 
652     while (*p)
653     {
654 	if (*p == c)
655 	    retval = p;
656 	MB_PTR_ADV(p);
657     }
658     return retval;
659 }
660 
661 /*
662  * Vim's version of strpbrk(), in case it's missing.
663  * Don't generate a prototype for this, causes problems when it's not used.
664  */
665 #ifndef PROTO
666 # ifndef HAVE_STRPBRK
667 #  ifdef vim_strpbrk
668 #   undef vim_strpbrk
669 #  endif
670     char_u *
671 vim_strpbrk(char_u *s, char_u *charset)
672 {
673     while (*s)
674     {
675 	if (vim_strchr(charset, *s) != NULL)
676 	    return s;
677 	MB_PTR_ADV(s);
678     }
679     return NULL;
680 }
681 # endif
682 #endif
683 
684 /*
685  * Sort an array of strings.
686  */
687 static int sort_compare(const void *s1, const void *s2);
688 
689     static int
690 sort_compare(const void *s1, const void *s2)
691 {
692     return STRCMP(*(char **)s1, *(char **)s2);
693 }
694 
695     void
696 sort_strings(
697     char_u	**files,
698     int		count)
699 {
700     qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
701 }
702 
703 #if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO)
704 /*
705  * Return TRUE if string "s" contains a non-ASCII character (128 or higher).
706  * When "s" is NULL FALSE is returned.
707  */
708     int
709 has_non_ascii(char_u *s)
710 {
711     char_u	*p;
712 
713     if (s != NULL)
714 	for (p = s; *p != NUL; ++p)
715 	    if (*p >= 128)
716 		return TRUE;
717     return FALSE;
718 }
719 #endif
720 
721 /*
722  * Concatenate two strings and return the result in allocated memory.
723  * Returns NULL when out of memory.
724  */
725     char_u  *
726 concat_str(char_u *str1, char_u *str2)
727 {
728     char_u  *dest;
729     size_t  l = str1 == NULL ? 0 : STRLEN(str1);
730 
731     dest = alloc(l + (str2 == NULL ? 0 : STRLEN(str2)) + 1L);
732     if (dest != NULL)
733     {
734 	if (str1 == NULL)
735 	    *dest = NUL;
736 	else
737 	    STRCPY(dest, str1);
738 	if (str2 != NULL)
739 	    STRCPY(dest + l, str2);
740     }
741     return dest;
742 }
743 
744 #if defined(FEAT_EVAL) || defined(PROTO)
745 
746 /*
747  * Return string "str" in ' quotes, doubling ' characters.
748  * If "str" is NULL an empty string is assumed.
749  * If "function" is TRUE make it function('string').
750  */
751     char_u *
752 string_quote(char_u *str, int function)
753 {
754     unsigned	len;
755     char_u	*p, *r, *s;
756 
757     len = (function ? 13 : 3);
758     if (str != NULL)
759     {
760 	len += (unsigned)STRLEN(str);
761 	for (p = str; *p != NUL; MB_PTR_ADV(p))
762 	    if (*p == '\'')
763 		++len;
764     }
765     s = r = alloc(len);
766     if (r != NULL)
767     {
768 	if (function)
769 	{
770 	    STRCPY(r, "function('");
771 	    r += 10;
772 	}
773 	else
774 	    *r++ = '\'';
775 	if (str != NULL)
776 	    for (p = str; *p != NUL; )
777 	    {
778 		if (*p == '\'')
779 		    *r++ = '\'';
780 		MB_COPY_CHAR(p, r);
781 	    }
782 	*r++ = '\'';
783 	if (function)
784 	    *r++ = ')';
785 	*r++ = NUL;
786     }
787     return s;
788 }
789 
790     static void
791 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
792 {
793     char_u	*t;
794     char_u	*str;
795     varnumber_T	idx;
796 
797     rettv->vval.v_number = -1;
798 
799     if (in_vim9script()
800 	    && (check_for_string_arg(argvars, 0) == FAIL
801 		|| check_for_number_arg(argvars, 1) == FAIL))
802 	return;
803 
804     str = tv_get_string_chk(&argvars[0]);
805     idx = tv_get_number_chk(&argvars[1], NULL);
806     if (str == NULL || idx < 0)
807 	return;
808 
809     t = str;
810     for ( ; idx > 0; idx--)
811     {
812 	if (*t == NUL)		// EOL reached
813 	    return;
814 	if (enc_utf8 && comp)
815 	    t += utf_ptr2len(t);
816 	else
817 	    t += (*mb_ptr2len)(t);
818     }
819     rettv->vval.v_number = (varnumber_T)(t - str);
820 }
821 
822 /*
823  * "byteidx()" function
824  */
825     void
826 f_byteidx(typval_T *argvars, typval_T *rettv)
827 {
828     byteidx(argvars, rettv, FALSE);
829 }
830 
831 /*
832  * "byteidxcomp()" function
833  */
834     void
835 f_byteidxcomp(typval_T *argvars, typval_T *rettv)
836 {
837     byteidx(argvars, rettv, TRUE);
838 }
839 
840 /*
841  * "charidx()" function
842  */
843     void
844 f_charidx(typval_T *argvars, typval_T *rettv)
845 {
846     char_u	*str;
847     varnumber_T	idx;
848     varnumber_T	countcc = FALSE;
849     char_u	*p;
850     int		len;
851     int		(*ptr2len)(char_u *);
852 
853     rettv->vval.v_number = -1;
854 
855     if (in_vim9script()
856 	    && (check_for_string_arg(argvars, 0) == FAIL
857 		|| check_for_number_arg(argvars, 1) == FAIL
858 		|| check_for_opt_bool_arg(argvars, 2) == FAIL))
859 	return;
860 
861     if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_NUMBER
862 	    || (argvars[2].v_type != VAR_UNKNOWN
863 					   && argvars[2].v_type != VAR_NUMBER
864 					   && argvars[2].v_type != VAR_BOOL))
865     {
866 	emsg(_(e_invarg));
867 	return;
868     }
869 
870     str = tv_get_string_chk(&argvars[0]);
871     idx = tv_get_number_chk(&argvars[1], NULL);
872     if (str == NULL || idx < 0)
873 	return;
874 
875     if (argvars[2].v_type != VAR_UNKNOWN)
876 	countcc = tv_get_bool(&argvars[2]);
877     if (countcc < 0 || countcc > 1)
878     {
879 	semsg(_(e_using_number_as_bool_nr), countcc);
880 	return;
881     }
882 
883     if (enc_utf8 && countcc)
884 	ptr2len = utf_ptr2len;
885     else
886 	ptr2len = mb_ptr2len;
887 
888     for (p = str, len = 0; p <= str + idx; len++)
889     {
890 	if (*p == NUL)
891 	    return;
892 	p += ptr2len(p);
893     }
894 
895     rettv->vval.v_number = len > 0 ? len - 1 : 0;
896 }
897 
898 /*
899  * "str2list()" function
900  */
901     void
902 f_str2list(typval_T *argvars, typval_T *rettv)
903 {
904     char_u	*p;
905     int		utf8 = FALSE;
906 
907     if (rettv_list_alloc(rettv) == FAIL)
908 	return;
909 
910     if (in_vim9script()
911 	    && (check_for_string_arg(argvars, 0) == FAIL
912 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
913 	return;
914 
915     if (argvars[1].v_type != VAR_UNKNOWN)
916 	utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
917 
918     p = tv_get_string(&argvars[0]);
919 
920     if (has_mbyte || utf8)
921     {
922 	int (*ptr2len)(char_u *);
923 	int (*ptr2char)(char_u *);
924 
925 	if (utf8 || enc_utf8)
926 	{
927 	    ptr2len = utf_ptr2len;
928 	    ptr2char = utf_ptr2char;
929 	}
930 	else
931 	{
932 	    ptr2len = mb_ptr2len;
933 	    ptr2char = mb_ptr2char;
934 	}
935 
936 	for ( ; *p != NUL; p += (*ptr2len)(p))
937 	    list_append_number(rettv->vval.v_list, (*ptr2char)(p));
938     }
939     else
940 	for ( ; *p != NUL; ++p)
941 	    list_append_number(rettv->vval.v_list, *p);
942 }
943 
944 /*
945  * "str2nr()" function
946  */
947     void
948 f_str2nr(typval_T *argvars, typval_T *rettv)
949 {
950     int		base = 10;
951     char_u	*p;
952     varnumber_T	n;
953     int		what = 0;
954     int		isneg;
955 
956     if (in_vim9script()
957 	    && (check_for_string_arg(argvars, 0) == FAIL
958 		|| check_for_opt_number_arg(argvars, 1) == FAIL
959 		|| (argvars[1].v_type != VAR_UNKNOWN
960 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
961 	return;
962 
963     if (argvars[1].v_type != VAR_UNKNOWN)
964     {
965 	base = (int)tv_get_number(&argvars[1]);
966 	if (base != 2 && base != 8 && base != 10 && base != 16)
967 	{
968 	    emsg(_(e_invarg));
969 	    return;
970 	}
971 	if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2]))
972 	    what |= STR2NR_QUOTE;
973     }
974 
975     p = skipwhite(tv_get_string_strict(&argvars[0]));
976     isneg = (*p == '-');
977     if (*p == '+' || *p == '-')
978 	p = skipwhite(p + 1);
979     switch (base)
980     {
981 	case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
982 	case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
983 	case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
984     }
985     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
986     // Text after the number is silently ignored.
987     if (isneg)
988 	rettv->vval.v_number = -n;
989     else
990 	rettv->vval.v_number = n;
991 
992 }
993 
994 /*
995  * "strgetchar()" function
996  */
997     void
998 f_strgetchar(typval_T *argvars, typval_T *rettv)
999 {
1000     char_u	*str;
1001     int		len;
1002     int		error = FALSE;
1003     int		charidx;
1004     int		byteidx = 0;
1005 
1006     rettv->vval.v_number = -1;
1007 
1008     if (in_vim9script()
1009 	    && (check_for_string_arg(argvars, 0) == FAIL
1010 		|| check_for_number_arg(argvars, 1) == FAIL))
1011 	return;
1012 
1013     str = tv_get_string_chk(&argvars[0]);
1014     if (str == NULL)
1015 	return;
1016     len = (int)STRLEN(str);
1017     charidx = (int)tv_get_number_chk(&argvars[1], &error);
1018     if (error)
1019 	return;
1020 
1021     while (charidx >= 0 && byteidx < len)
1022     {
1023 	if (charidx == 0)
1024 	{
1025 	    rettv->vval.v_number = mb_ptr2char(str + byteidx);
1026 	    break;
1027 	}
1028 	--charidx;
1029 	byteidx += MB_CPTR2LEN(str + byteidx);
1030     }
1031 }
1032 
1033 /*
1034  * "stridx()" function
1035  */
1036     void
1037 f_stridx(typval_T *argvars, typval_T *rettv)
1038 {
1039     char_u	buf[NUMBUFLEN];
1040     char_u	*needle;
1041     char_u	*haystack;
1042     char_u	*save_haystack;
1043     char_u	*pos;
1044     int		start_idx;
1045 
1046     if (in_vim9script()
1047 	    && (check_for_string_arg(argvars, 0) == FAIL
1048 		|| check_for_string_arg(argvars, 1) == FAIL
1049 		|| check_for_opt_number_arg(argvars, 2) == FAIL))
1050 	return;
1051 
1052     needle = tv_get_string_chk(&argvars[1]);
1053     save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
1054     rettv->vval.v_number = -1;
1055     if (needle == NULL || haystack == NULL)
1056 	return;		// type error; errmsg already given
1057 
1058     if (argvars[2].v_type != VAR_UNKNOWN)
1059     {
1060 	int	    error = FALSE;
1061 
1062 	start_idx = (int)tv_get_number_chk(&argvars[2], &error);
1063 	if (error || start_idx >= (int)STRLEN(haystack))
1064 	    return;
1065 	if (start_idx >= 0)
1066 	    haystack += start_idx;
1067     }
1068 
1069     pos	= (char_u *)strstr((char *)haystack, (char *)needle);
1070     if (pos != NULL)
1071 	rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
1072 }
1073 
1074 /*
1075  * "string()" function
1076  */
1077     void
1078 f_string(typval_T *argvars, typval_T *rettv)
1079 {
1080     char_u	*tofree;
1081     char_u	numbuf[NUMBUFLEN];
1082 
1083     rettv->v_type = VAR_STRING;
1084     rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
1085 								get_copyID());
1086     // Make a copy if we have a value but it's not in allocated memory.
1087     if (rettv->vval.v_string != NULL && tofree == NULL)
1088 	rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
1089 }
1090 
1091 /*
1092  * "strlen()" function
1093  */
1094     void
1095 f_strlen(typval_T *argvars, typval_T *rettv)
1096 {
1097     if (in_vim9script()
1098 	    && check_for_string_or_number_arg(argvars, 0) == FAIL)
1099 	return;
1100 
1101     rettv->vval.v_number = (varnumber_T)(STRLEN(
1102 					      tv_get_string(&argvars[0])));
1103 }
1104 
1105     static void
1106 strchar_common(typval_T *argvars, typval_T *rettv, int skipcc)
1107 {
1108     char_u		*s = tv_get_string(&argvars[0]);
1109     varnumber_T		len = 0;
1110     int			(*func_mb_ptr2char_adv)(char_u **pp);
1111 
1112     func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
1113     while (*s != NUL)
1114     {
1115 	func_mb_ptr2char_adv(&s);
1116 	++len;
1117     }
1118     rettv->vval.v_number = len;
1119 }
1120 
1121 /*
1122  * "strcharlen()" function
1123  */
1124     void
1125 f_strcharlen(typval_T *argvars, typval_T *rettv)
1126 {
1127     if (in_vim9script()
1128 	    && check_for_string_or_number_arg(argvars, 0) == FAIL)
1129 	return;
1130 
1131     strchar_common(argvars, rettv, TRUE);
1132 }
1133 
1134 /*
1135  * "strchars()" function
1136  */
1137     void
1138 f_strchars(typval_T *argvars, typval_T *rettv)
1139 {
1140     varnumber_T		skipcc = FALSE;
1141 
1142     if (in_vim9script()
1143 	    && (check_for_string_arg(argvars, 0) == FAIL
1144 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
1145 	return;
1146 
1147     if (argvars[1].v_type != VAR_UNKNOWN)
1148 	skipcc = tv_get_bool(&argvars[1]);
1149     if (skipcc < 0 || skipcc > 1)
1150 	semsg(_(e_using_number_as_bool_nr), skipcc);
1151     else
1152 	strchar_common(argvars, rettv, skipcc);
1153 }
1154 
1155 /*
1156  * "strdisplaywidth()" function
1157  */
1158     void
1159 f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
1160 {
1161     char_u	*s;
1162     int		col = 0;
1163 
1164     rettv->vval.v_number = -1;
1165 
1166     if (in_vim9script()
1167 	    && (check_for_string_arg(argvars, 0) == FAIL
1168 		|| check_for_opt_number_arg(argvars, 1) == FAIL))
1169 	return;
1170 
1171     s = tv_get_string(&argvars[0]);
1172     if (argvars[1].v_type != VAR_UNKNOWN)
1173 	col = (int)tv_get_number(&argvars[1]);
1174 
1175     rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
1176 }
1177 
1178 /*
1179  * "strwidth()" function
1180  */
1181     void
1182 f_strwidth(typval_T *argvars, typval_T *rettv)
1183 {
1184     char_u	*s;
1185 
1186     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1187 	return;
1188 
1189     s = tv_get_string_strict(&argvars[0]);
1190     rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
1191 }
1192 
1193 /*
1194  * "strcharpart()" function
1195  */
1196     void
1197 f_strcharpart(typval_T *argvars, typval_T *rettv)
1198 {
1199     char_u	*p;
1200     int		nchar;
1201     int		nbyte = 0;
1202     int		charlen;
1203     int		skipcc = FALSE;
1204     int		len = 0;
1205     int		slen;
1206     int		error = FALSE;
1207 
1208     if (in_vim9script()
1209 	    && (check_for_string_arg(argvars, 0) == FAIL
1210 		|| check_for_number_arg(argvars, 1) == FAIL
1211 		|| check_for_opt_number_arg(argvars, 2) == FAIL
1212 		|| (argvars[2].v_type != VAR_UNKNOWN
1213 		    && check_for_opt_bool_arg(argvars, 3) == FAIL)))
1214 	return;
1215 
1216     p = tv_get_string(&argvars[0]);
1217     slen = (int)STRLEN(p);
1218 
1219     nchar = (int)tv_get_number_chk(&argvars[1], &error);
1220     if (!error)
1221     {
1222 	if (argvars[2].v_type != VAR_UNKNOWN
1223 					   && argvars[3].v_type != VAR_UNKNOWN)
1224 	{
1225 	    skipcc = tv_get_bool(&argvars[3]);
1226 	    if (skipcc < 0 || skipcc > 1)
1227 	    {
1228 		semsg(_(e_using_number_as_bool_nr), skipcc);
1229 		return;
1230 	    }
1231 	}
1232 
1233 	if (nchar > 0)
1234 	    while (nchar > 0 && nbyte < slen)
1235 	    {
1236 		if (skipcc)
1237 		    nbyte += mb_ptr2len(p + nbyte);
1238 		else
1239 		    nbyte += MB_CPTR2LEN(p + nbyte);
1240 		--nchar;
1241 	    }
1242 	else
1243 	    nbyte = nchar;
1244 	if (argvars[2].v_type != VAR_UNKNOWN)
1245 	{
1246 	    charlen = (int)tv_get_number(&argvars[2]);
1247 	    while (charlen > 0 && nbyte + len < slen)
1248 	    {
1249 		int off = nbyte + len;
1250 
1251 		if (off < 0)
1252 		    len += 1;
1253 		else
1254 		{
1255 		    if (skipcc)
1256 			len += mb_ptr2len(p + off);
1257 		    else
1258 			len += MB_CPTR2LEN(p + off);
1259 		}
1260 		--charlen;
1261 	    }
1262 	}
1263 	else
1264 	    len = slen - nbyte;    // default: all bytes that are available.
1265     }
1266 
1267     // Only return the overlap between the specified part and the actual
1268     // string.
1269     if (nbyte < 0)
1270     {
1271 	len += nbyte;
1272 	nbyte = 0;
1273     }
1274     else if (nbyte > slen)
1275 	nbyte = slen;
1276     if (len < 0)
1277 	len = 0;
1278     else if (nbyte + len > slen)
1279 	len = slen - nbyte;
1280 
1281     rettv->v_type = VAR_STRING;
1282     rettv->vval.v_string = vim_strnsave(p + nbyte, len);
1283 }
1284 
1285 /*
1286  * "strpart()" function
1287  */
1288     void
1289 f_strpart(typval_T *argvars, typval_T *rettv)
1290 {
1291     char_u	*p;
1292     int		n;
1293     int		len;
1294     int		slen;
1295     int		error = FALSE;
1296 
1297     if (in_vim9script()
1298 	    && (check_for_string_arg(argvars, 0) == FAIL
1299 		|| check_for_number_arg(argvars, 1) == FAIL
1300 		|| check_for_opt_number_arg(argvars, 2) == FAIL
1301 		|| (argvars[2].v_type != VAR_UNKNOWN
1302 		    && check_for_opt_bool_arg(argvars, 3) == FAIL)))
1303 	return;
1304 
1305     p = tv_get_string(&argvars[0]);
1306     slen = (int)STRLEN(p);
1307 
1308     n = (int)tv_get_number_chk(&argvars[1], &error);
1309     if (error)
1310 	len = 0;
1311     else if (argvars[2].v_type != VAR_UNKNOWN)
1312 	len = (int)tv_get_number(&argvars[2]);
1313     else
1314 	len = slen - n;	    // default len: all bytes that are available.
1315 
1316     // Only return the overlap between the specified part and the actual
1317     // string.
1318     if (n < 0)
1319     {
1320 	len += n;
1321 	n = 0;
1322     }
1323     else if (n > slen)
1324 	n = slen;
1325     if (len < 0)
1326 	len = 0;
1327     else if (n + len > slen)
1328 	len = slen - n;
1329 
1330     if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
1331     {
1332 	int off;
1333 
1334 	// length in characters
1335 	for (off = n; off < slen && len > 0; --len)
1336 	    off += mb_ptr2len(p + off);
1337 	len = off - n;
1338     }
1339 
1340     rettv->v_type = VAR_STRING;
1341     rettv->vval.v_string = vim_strnsave(p + n, len);
1342 }
1343 
1344 /*
1345  * "strridx()" function
1346  */
1347     void
1348 f_strridx(typval_T *argvars, typval_T *rettv)
1349 {
1350     char_u	buf[NUMBUFLEN];
1351     char_u	*needle;
1352     char_u	*haystack;
1353     char_u	*rest;
1354     char_u	*lastmatch = NULL;
1355     int		haystack_len, end_idx;
1356 
1357     if (in_vim9script()
1358 	    && (check_for_string_arg(argvars, 0) == FAIL
1359 		|| check_for_string_arg(argvars, 1) == FAIL
1360 		|| check_for_opt_number_arg(argvars, 2) == FAIL))
1361 	return;
1362 
1363     needle = tv_get_string_chk(&argvars[1]);
1364     haystack = tv_get_string_buf_chk(&argvars[0], buf);
1365 
1366     rettv->vval.v_number = -1;
1367     if (needle == NULL || haystack == NULL)
1368 	return;		// type error; errmsg already given
1369 
1370     haystack_len = (int)STRLEN(haystack);
1371     if (argvars[2].v_type != VAR_UNKNOWN)
1372     {
1373 	// Third argument: upper limit for index
1374 	end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
1375 	if (end_idx < 0)
1376 	    return;	// can never find a match
1377     }
1378     else
1379 	end_idx = haystack_len;
1380 
1381     if (*needle == NUL)
1382     {
1383 	// Empty string matches past the end.
1384 	lastmatch = haystack + end_idx;
1385     }
1386     else
1387     {
1388 	for (rest = haystack; *rest != '\0'; ++rest)
1389 	{
1390 	    rest = (char_u *)strstr((char *)rest, (char *)needle);
1391 	    if (rest == NULL || rest > haystack + end_idx)
1392 		break;
1393 	    lastmatch = rest;
1394 	}
1395     }
1396 
1397     if (lastmatch == NULL)
1398 	rettv->vval.v_number = -1;
1399     else
1400 	rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
1401 }
1402 
1403 /*
1404  * "strtrans()" function
1405  */
1406     void
1407 f_strtrans(typval_T *argvars, typval_T *rettv)
1408 {
1409     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1410 	return;
1411 
1412     rettv->v_type = VAR_STRING;
1413     rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
1414 }
1415 
1416 /*
1417  * "tolower(string)" function
1418  */
1419     void
1420 f_tolower(typval_T *argvars, typval_T *rettv)
1421 {
1422     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1423 	return;
1424 
1425     rettv->v_type = VAR_STRING;
1426     rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
1427 }
1428 
1429 /*
1430  * "toupper(string)" function
1431  */
1432     void
1433 f_toupper(typval_T *argvars, typval_T *rettv)
1434 {
1435     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1436 	return;
1437 
1438     rettv->v_type = VAR_STRING;
1439     rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
1440 }
1441 
1442 /*
1443  * "tr(string, fromstr, tostr)" function
1444  */
1445     void
1446 f_tr(typval_T *argvars, typval_T *rettv)
1447 {
1448     char_u	*in_str;
1449     char_u	*fromstr;
1450     char_u	*tostr;
1451     char_u	*p;
1452     int		inlen;
1453     int		fromlen;
1454     int		tolen;
1455     int		idx;
1456     char_u	*cpstr;
1457     int		cplen;
1458     int		first = TRUE;
1459     char_u	buf[NUMBUFLEN];
1460     char_u	buf2[NUMBUFLEN];
1461     garray_T	ga;
1462 
1463     if (in_vim9script()
1464 	    && (check_for_string_arg(argvars, 0) == FAIL
1465 		|| check_for_string_arg(argvars, 1) == FAIL
1466 		|| check_for_string_arg(argvars, 2) == FAIL))
1467 	return;
1468 
1469     in_str = tv_get_string(&argvars[0]);
1470     fromstr = tv_get_string_buf_chk(&argvars[1], buf);
1471     tostr = tv_get_string_buf_chk(&argvars[2], buf2);
1472 
1473     // Default return value: empty string.
1474     rettv->v_type = VAR_STRING;
1475     rettv->vval.v_string = NULL;
1476     if (fromstr == NULL || tostr == NULL)
1477 	    return;		// type error; errmsg already given
1478     ga_init2(&ga, (int)sizeof(char), 80);
1479 
1480     if (!has_mbyte)
1481 	// not multi-byte: fromstr and tostr must be the same length
1482 	if (STRLEN(fromstr) != STRLEN(tostr))
1483 	{
1484 error:
1485 	    semsg(_(e_invarg2), fromstr);
1486 	    ga_clear(&ga);
1487 	    return;
1488 	}
1489 
1490     // fromstr and tostr have to contain the same number of chars
1491     while (*in_str != NUL)
1492     {
1493 	if (has_mbyte)
1494 	{
1495 	    inlen = (*mb_ptr2len)(in_str);
1496 	    cpstr = in_str;
1497 	    cplen = inlen;
1498 	    idx = 0;
1499 	    for (p = fromstr; *p != NUL; p += fromlen)
1500 	    {
1501 		fromlen = (*mb_ptr2len)(p);
1502 		if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
1503 		{
1504 		    for (p = tostr; *p != NUL; p += tolen)
1505 		    {
1506 			tolen = (*mb_ptr2len)(p);
1507 			if (idx-- == 0)
1508 			{
1509 			    cplen = tolen;
1510 			    cpstr = p;
1511 			    break;
1512 			}
1513 		    }
1514 		    if (*p == NUL)	// tostr is shorter than fromstr
1515 			goto error;
1516 		    break;
1517 		}
1518 		++idx;
1519 	    }
1520 
1521 	    if (first && cpstr == in_str)
1522 	    {
1523 		// Check that fromstr and tostr have the same number of
1524 		// (multi-byte) characters.  Done only once when a character
1525 		// of in_str doesn't appear in fromstr.
1526 		first = FALSE;
1527 		for (p = tostr; *p != NUL; p += tolen)
1528 		{
1529 		    tolen = (*mb_ptr2len)(p);
1530 		    --idx;
1531 		}
1532 		if (idx != 0)
1533 		    goto error;
1534 	    }
1535 
1536 	    (void)ga_grow(&ga, cplen);
1537 	    mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
1538 	    ga.ga_len += cplen;
1539 
1540 	    in_str += inlen;
1541 	}
1542 	else
1543 	{
1544 	    // When not using multi-byte chars we can do it faster.
1545 	    p = vim_strchr(fromstr, *in_str);
1546 	    if (p != NULL)
1547 		ga_append(&ga, tostr[p - fromstr]);
1548 	    else
1549 		ga_append(&ga, *in_str);
1550 	    ++in_str;
1551 	}
1552     }
1553 
1554     // add a terminating NUL
1555     (void)ga_grow(&ga, 1);
1556     ga_append(&ga, NUL);
1557 
1558     rettv->vval.v_string = ga.ga_data;
1559 }
1560 
1561 /*
1562  * "trim({expr})" function
1563  */
1564     void
1565 f_trim(typval_T *argvars, typval_T *rettv)
1566 {
1567     char_u	buf1[NUMBUFLEN];
1568     char_u	buf2[NUMBUFLEN];
1569     char_u	*head;
1570     char_u	*mask = NULL;
1571     char_u	*tail;
1572     char_u	*prev;
1573     char_u	*p;
1574     int		c1;
1575     int		dir = 0;
1576 
1577     rettv->v_type = VAR_STRING;
1578     rettv->vval.v_string = NULL;
1579 
1580     if (in_vim9script()
1581 	    && (check_for_string_arg(argvars, 0) == FAIL
1582 		|| check_for_opt_string_arg(argvars, 1) == FAIL
1583 		|| (argvars[1].v_type != VAR_UNKNOWN
1584 		    && check_for_opt_number_arg(argvars, 2) == FAIL)))
1585 	return;
1586 
1587     head = tv_get_string_buf_chk(&argvars[0], buf1);
1588     if (head == NULL)
1589 	return;
1590 
1591     if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_STRING)
1592     {
1593 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
1594 	return;
1595     }
1596 
1597     if (argvars[1].v_type == VAR_STRING)
1598     {
1599 	mask = tv_get_string_buf_chk(&argvars[1], buf2);
1600 
1601 	if (argvars[2].v_type != VAR_UNKNOWN)
1602 	{
1603 	    int	error = 0;
1604 
1605 	    // leading or trailing characters to trim
1606 	    dir = (int)tv_get_number_chk(&argvars[2], &error);
1607 	    if (error)
1608 		return;
1609 	    if (dir < 0 || dir > 2)
1610 	    {
1611 		semsg(_(e_invarg2), tv_get_string(&argvars[2]));
1612 		return;
1613 	    }
1614 	}
1615     }
1616 
1617     if (dir == 0 || dir == 1)
1618     {
1619 	// Trim leading characters
1620 	while (*head != NUL)
1621 	{
1622 	    c1 = PTR2CHAR(head);
1623 	    if (mask == NULL)
1624 	    {
1625 		if (c1 > ' ' && c1 != 0xa0)
1626 		    break;
1627 	    }
1628 	    else
1629 	    {
1630 		for (p = mask; *p != NUL; MB_PTR_ADV(p))
1631 		    if (c1 == PTR2CHAR(p))
1632 			break;
1633 		if (*p == NUL)
1634 		    break;
1635 	    }
1636 	    MB_PTR_ADV(head);
1637 	}
1638     }
1639 
1640     tail = head + STRLEN(head);
1641     if (dir == 0 || dir == 2)
1642     {
1643 	// Trim trailing characters
1644 	for (; tail > head; tail = prev)
1645 	{
1646 	    prev = tail;
1647 	    MB_PTR_BACK(head, prev);
1648 	    c1 = PTR2CHAR(prev);
1649 	    if (mask == NULL)
1650 	    {
1651 		if (c1 > ' ' && c1 != 0xa0)
1652 		    break;
1653 	    }
1654 	    else
1655 	    {
1656 		for (p = mask; *p != NUL; MB_PTR_ADV(p))
1657 		    if (c1 == PTR2CHAR(p))
1658 			break;
1659 		if (*p == NUL)
1660 		    break;
1661 	    }
1662 	}
1663     }
1664     rettv->vval.v_string = vim_strnsave(head, tail - head);
1665 }
1666 
1667 #endif
1668 
1669 #if defined(FEAT_EVAL)
1670 static char *e_printf = N_("E766: Insufficient arguments for printf()");
1671 
1672 /*
1673  * Get number argument from "idxp" entry in "tvs".  First entry is 1.
1674  */
1675     static varnumber_T
1676 tv_nr(typval_T *tvs, int *idxp)
1677 {
1678     int		idx = *idxp - 1;
1679     varnumber_T	n = 0;
1680     int		err = FALSE;
1681 
1682     if (tvs[idx].v_type == VAR_UNKNOWN)
1683 	emsg(_(e_printf));
1684     else
1685     {
1686 	++*idxp;
1687 	n = tv_get_number_chk(&tvs[idx], &err);
1688 	if (err)
1689 	    n = 0;
1690     }
1691     return n;
1692 }
1693 
1694 /*
1695  * Get string argument from "idxp" entry in "tvs".  First entry is 1.
1696  * If "tofree" is NULL tv_get_string_chk() is used.  Some types (e.g. List)
1697  * are not converted to a string.
1698  * If "tofree" is not NULL echo_string() is used.  All types are converted to
1699  * a string with the same format as ":echo".  The caller must free "*tofree".
1700  * Returns NULL for an error.
1701  */
1702     static char *
1703 tv_str(typval_T *tvs, int *idxp, char_u **tofree)
1704 {
1705     int		    idx = *idxp - 1;
1706     char	    *s = NULL;
1707     static char_u   numbuf[NUMBUFLEN];
1708 
1709     if (tvs[idx].v_type == VAR_UNKNOWN)
1710 	emsg(_(e_printf));
1711     else
1712     {
1713 	++*idxp;
1714 	if (tofree != NULL)
1715 	    s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID());
1716 	else
1717 	    s = (char *)tv_get_string_chk(&tvs[idx]);
1718     }
1719     return s;
1720 }
1721 
1722 # ifdef FEAT_FLOAT
1723 /*
1724  * Get float argument from "idxp" entry in "tvs".  First entry is 1.
1725  */
1726     static double
1727 tv_float(typval_T *tvs, int *idxp)
1728 {
1729     int		idx = *idxp - 1;
1730     double	f = 0;
1731 
1732     if (tvs[idx].v_type == VAR_UNKNOWN)
1733 	emsg(_(e_printf));
1734     else
1735     {
1736 	++*idxp;
1737 	if (tvs[idx].v_type == VAR_FLOAT)
1738 	    f = tvs[idx].vval.v_float;
1739 	else if (tvs[idx].v_type == VAR_NUMBER)
1740 	    f = (double)tvs[idx].vval.v_number;
1741 	else
1742 	    emsg(_("E807: Expected Float argument for printf()"));
1743     }
1744     return f;
1745 }
1746 # endif
1747 #endif
1748 
1749 #ifdef FEAT_FLOAT
1750 /*
1751  * Return the representation of infinity for printf() function:
1752  * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
1753  */
1754     static const char *
1755 infinity_str(int positive,
1756 	     char fmt_spec,
1757 	     int force_sign,
1758 	     int space_for_positive)
1759 {
1760     static const char *table[] =
1761     {
1762 	"-inf", "inf", "+inf", " inf",
1763 	"-INF", "INF", "+INF", " INF"
1764     };
1765     int idx = positive * (1 + force_sign + force_sign * space_for_positive);
1766 
1767     if (ASCII_ISUPPER(fmt_spec))
1768 	idx += 4;
1769     return table[idx];
1770 }
1771 #endif
1772 
1773 /*
1774  * This code was included to provide a portable vsnprintf() and snprintf().
1775  * Some systems may provide their own, but we always use this one for
1776  * consistency.
1777  *
1778  * This code is based on snprintf.c - a portable implementation of snprintf
1779  * by Mark Martinec <[email protected]>, Version 2.2, 2000-10-06.
1780  * Included with permission.  It was heavily modified to fit in Vim.
1781  * The original code, including useful comments, can be found here:
1782  *	http://www.ijs.si/software/snprintf/
1783  *
1784  * This snprintf() only supports the following conversion specifiers:
1785  * s, c, d, u, o, x, X, p  (and synonyms: i, D, U, O - see below)
1786  * with flags: '-', '+', ' ', '0' and '#'.
1787  * An asterisk is supported for field width as well as precision.
1788  *
1789  * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
1790  *
1791  * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
1792  * are supported.  NOTE: for 'll' the argument is varnumber_T or uvarnumber_T.
1793  *
1794  * The locale is not used, the string is used as a byte string.  This is only
1795  * relevant for double-byte encodings where the second byte may be '%'.
1796  *
1797  * It is permitted for "str_m" to be zero, and it is permitted to specify NULL
1798  * pointer for resulting string argument if "str_m" is zero (as per ISO C99).
1799  *
1800  * The return value is the number of characters which would be generated
1801  * for the given input, excluding the trailing NUL. If this value
1802  * is greater or equal to "str_m", not all characters from the result
1803  * have been stored in str, output bytes beyond the ("str_m"-1) -th character
1804  * are discarded. If "str_m" is greater than zero it is guaranteed
1805  * the resulting string will be NUL-terminated.
1806  */
1807 
1808 /*
1809  * When va_list is not supported we only define vim_snprintf().
1810  *
1811  * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of
1812  * "typval_T".  When the latter is not used it must be NULL.
1813  */
1814 
1815 // When generating prototypes all of this is skipped, cproto doesn't
1816 // understand this.
1817 #ifndef PROTO
1818 
1819 // Like vim_vsnprintf() but append to the string.
1820     int
1821 vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...)
1822 {
1823     va_list	ap;
1824     int		str_l;
1825     size_t	len = STRLEN(str);
1826     size_t	space;
1827 
1828     if (str_m <= len)
1829 	space = 0;
1830     else
1831 	space = str_m - len;
1832     va_start(ap, fmt);
1833     str_l = vim_vsnprintf(str + len, space, fmt, ap);
1834     va_end(ap);
1835     return str_l;
1836 }
1837 
1838     int
1839 vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
1840 {
1841     va_list	ap;
1842     int		str_l;
1843 
1844     va_start(ap, fmt);
1845     str_l = vim_vsnprintf(str, str_m, fmt, ap);
1846     va_end(ap);
1847     return str_l;
1848 }
1849 
1850     int
1851 vim_vsnprintf(
1852     char	*str,
1853     size_t	str_m,
1854     const char	*fmt,
1855     va_list	ap)
1856 {
1857     return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL);
1858 }
1859 
1860     int
1861 vim_vsnprintf_typval(
1862     char	*str,
1863     size_t	str_m,
1864     const char	*fmt,
1865     va_list	ap,
1866     typval_T	*tvs)
1867 {
1868     size_t	str_l = 0;
1869     const char	*p = fmt;
1870     int		arg_idx = 1;
1871 
1872     if (p == NULL)
1873 	p = "";
1874     while (*p != NUL)
1875     {
1876 	if (*p != '%')
1877 	{
1878 	    char    *q = strchr(p + 1, '%');
1879 	    size_t  n = (q == NULL) ? STRLEN(p) : (size_t)(q - p);
1880 
1881 	    // Copy up to the next '%' or NUL without any changes.
1882 	    if (str_l < str_m)
1883 	    {
1884 		size_t avail = str_m - str_l;
1885 
1886 		mch_memmove(str + str_l, p, n > avail ? avail : n);
1887 	    }
1888 	    p += n;
1889 	    str_l += n;
1890 	}
1891 	else
1892 	{
1893 	    size_t  min_field_width = 0, precision = 0;
1894 	    int	    zero_padding = 0, precision_specified = 0, justify_left = 0;
1895 	    int	    alternate_form = 0, force_sign = 0;
1896 
1897 	    // If both the ' ' and '+' flags appear, the ' ' flag should be
1898 	    // ignored.
1899 	    int	    space_for_positive = 1;
1900 
1901 	    // allowed values: \0, h, l, L
1902 	    char    length_modifier = '\0';
1903 
1904 	    // temporary buffer for simple numeric->string conversion
1905 # if defined(FEAT_FLOAT)
1906 #  define TMP_LEN 350	// On my system 1e308 is the biggest number possible.
1907 			// That sounds reasonable to use as the maximum
1908 			// printable.
1909 # else
1910 #  define TMP_LEN 66
1911 # endif
1912 	    char    tmp[TMP_LEN];
1913 
1914 	    // string address in case of string argument
1915 	    const char  *str_arg = NULL;
1916 
1917 	    // natural field width of arg without padding and sign
1918 	    size_t  str_arg_l;
1919 
1920 	    // unsigned char argument value - only defined for c conversion.
1921 	    // N.B. standard explicitly states the char argument for the c
1922 	    // conversion is unsigned
1923 	    unsigned char uchar_arg;
1924 
1925 	    // number of zeros to be inserted for numeric conversions as
1926 	    // required by the precision or minimal field width
1927 	    size_t  number_of_zeros_to_pad = 0;
1928 
1929 	    // index into tmp where zero padding is to be inserted
1930 	    size_t  zero_padding_insertion_ind = 0;
1931 
1932 	    // current conversion specifier character
1933 	    char    fmt_spec = '\0';
1934 
1935 	    // buffer for 's' and 'S' specs
1936 	    char_u  *tofree = NULL;
1937 
1938 
1939 	    p++;  // skip '%'
1940 
1941 	    // parse flags
1942 	    while (*p == '0' || *p == '-' || *p == '+' || *p == ' '
1943 						   || *p == '#' || *p == '\'')
1944 	    {
1945 		switch (*p)
1946 		{
1947 		    case '0': zero_padding = 1; break;
1948 		    case '-': justify_left = 1; break;
1949 		    case '+': force_sign = 1; space_for_positive = 0; break;
1950 		    case ' ': force_sign = 1;
1951 			      // If both the ' ' and '+' flags appear, the ' '
1952 			      // flag should be ignored
1953 			      break;
1954 		    case '#': alternate_form = 1; break;
1955 		    case '\'': break;
1956 		}
1957 		p++;
1958 	    }
1959 	    // If the '0' and '-' flags both appear, the '0' flag should be
1960 	    // ignored.
1961 
1962 	    // parse field width
1963 	    if (*p == '*')
1964 	    {
1965 		int j;
1966 
1967 		p++;
1968 		j =
1969 # if defined(FEAT_EVAL)
1970 		    tvs != NULL ? tv_nr(tvs, &arg_idx) :
1971 # endif
1972 			va_arg(ap, int);
1973 		if (j >= 0)
1974 		    min_field_width = j;
1975 		else
1976 		{
1977 		    min_field_width = -j;
1978 		    justify_left = 1;
1979 		}
1980 	    }
1981 	    else if (VIM_ISDIGIT((int)(*p)))
1982 	    {
1983 		// size_t could be wider than unsigned int; make sure we treat
1984 		// argument like common implementations do
1985 		unsigned int uj = *p++ - '0';
1986 
1987 		while (VIM_ISDIGIT((int)(*p)))
1988 		    uj = 10 * uj + (unsigned int)(*p++ - '0');
1989 		min_field_width = uj;
1990 	    }
1991 
1992 	    // parse precision
1993 	    if (*p == '.')
1994 	    {
1995 		p++;
1996 		precision_specified = 1;
1997 		if (*p == '*')
1998 		{
1999 		    int j;
2000 
2001 		    j =
2002 # if defined(FEAT_EVAL)
2003 			tvs != NULL ? tv_nr(tvs, &arg_idx) :
2004 # endif
2005 			    va_arg(ap, int);
2006 		    p++;
2007 		    if (j >= 0)
2008 			precision = j;
2009 		    else
2010 		    {
2011 			precision_specified = 0;
2012 			precision = 0;
2013 		    }
2014 		}
2015 		else if (VIM_ISDIGIT((int)(*p)))
2016 		{
2017 		    // size_t could be wider than unsigned int; make sure we
2018 		    // treat argument like common implementations do
2019 		    unsigned int uj = *p++ - '0';
2020 
2021 		    while (VIM_ISDIGIT((int)(*p)))
2022 			uj = 10 * uj + (unsigned int)(*p++ - '0');
2023 		    precision = uj;
2024 		}
2025 	    }
2026 
2027 	    // parse 'h', 'l' and 'll' length modifiers
2028 	    if (*p == 'h' || *p == 'l')
2029 	    {
2030 		length_modifier = *p;
2031 		p++;
2032 		if (length_modifier == 'l' && *p == 'l')
2033 		{
2034 		    // double l = __int64 / varnumber_T
2035 		    length_modifier = 'L';
2036 		    p++;
2037 		}
2038 	    }
2039 	    fmt_spec = *p;
2040 
2041 	    // common synonyms:
2042 	    switch (fmt_spec)
2043 	    {
2044 		case 'i': fmt_spec = 'd'; break;
2045 		case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
2046 		case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
2047 		case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
2048 		default: break;
2049 	    }
2050 
2051 # if defined(FEAT_EVAL)
2052 	    switch (fmt_spec)
2053 	    {
2054 		case 'd': case 'u': case 'o': case 'x': case 'X':
2055 		    if (tvs != NULL && length_modifier == '\0')
2056 			length_modifier = 'L';
2057 	    }
2058 # endif
2059 
2060 	    // get parameter value, do initial processing
2061 	    switch (fmt_spec)
2062 	    {
2063 		// '%' and 'c' behave similar to 's' regarding flags and field
2064 		// widths
2065 	    case '%':
2066 	    case 'c':
2067 	    case 's':
2068 	    case 'S':
2069 		str_arg_l = 1;
2070 		switch (fmt_spec)
2071 		{
2072 		case '%':
2073 		    str_arg = p;
2074 		    break;
2075 
2076 		case 'c':
2077 		    {
2078 			int j;
2079 
2080 			j =
2081 # if defined(FEAT_EVAL)
2082 			    tvs != NULL ? tv_nr(tvs, &arg_idx) :
2083 # endif
2084 				va_arg(ap, int);
2085 			// standard demands unsigned char
2086 			uchar_arg = (unsigned char)j;
2087 			str_arg = (char *)&uchar_arg;
2088 			break;
2089 		    }
2090 
2091 		case 's':
2092 		case 'S':
2093 		    str_arg =
2094 # if defined(FEAT_EVAL)
2095 				tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) :
2096 # endif
2097 				    va_arg(ap, char *);
2098 		    if (str_arg == NULL)
2099 		    {
2100 			str_arg = "[NULL]";
2101 			str_arg_l = 6;
2102 		    }
2103 		    // make sure not to address string beyond the specified
2104 		    // precision !!!
2105 		    else if (!precision_specified)
2106 			str_arg_l = strlen(str_arg);
2107 		    // truncate string if necessary as requested by precision
2108 		    else if (precision == 0)
2109 			str_arg_l = 0;
2110 		    else
2111 		    {
2112 			// Don't put the #if inside memchr(), it can be a
2113 			// macro.
2114 			// memchr on HP does not like n > 2^31  !!!
2115 			char *q = memchr(str_arg, '\0',
2116 				  precision <= (size_t)0x7fffffffL ? precision
2117 						       : (size_t)0x7fffffffL);
2118 			str_arg_l = (q == NULL) ? precision
2119 						      : (size_t)(q - str_arg);
2120 		    }
2121 		    if (fmt_spec == 'S')
2122 		    {
2123 			if (min_field_width != 0)
2124 			    min_field_width += STRLEN(str_arg)
2125 				     - mb_string2cells((char_u *)str_arg, -1);
2126 			if (precision)
2127 			{
2128 			    char_u  *p1;
2129 			    size_t  i = 0;
2130 
2131 			    for (p1 = (char_u *)str_arg; *p1;
2132 							  p1 += mb_ptr2len(p1))
2133 			    {
2134 				i += (size_t)mb_ptr2cells(p1);
2135 				if (i > precision)
2136 				    break;
2137 			    }
2138 			    str_arg_l = precision = p1 - (char_u *)str_arg;
2139 			}
2140 		    }
2141 		    break;
2142 
2143 		default:
2144 		    break;
2145 		}
2146 		break;
2147 
2148 	    case 'd': case 'u':
2149 	    case 'b': case 'B':
2150 	    case 'o':
2151 	    case 'x': case 'X':
2152 	    case 'p':
2153 		{
2154 		    // NOTE: the u, b, o, x, X and p conversion specifiers
2155 		    // imply the value is unsigned;  d implies a signed
2156 		    // value
2157 
2158 		    // 0 if numeric argument is zero (or if pointer is
2159 		    // NULL for 'p'), +1 if greater than zero (or nonzero
2160 		    // for unsigned arguments), -1 if negative (unsigned
2161 		    // argument is never negative)
2162 		    int arg_sign = 0;
2163 
2164 		    // only set for length modifier h, or for no length
2165 		    // modifiers
2166 		    int int_arg = 0;
2167 		    unsigned int uint_arg = 0;
2168 
2169 		    // only set for length modifier l
2170 		    long int long_arg = 0;
2171 		    unsigned long int ulong_arg = 0;
2172 
2173 		    // only set for length modifier ll
2174 		    varnumber_T llong_arg = 0;
2175 		    uvarnumber_T ullong_arg = 0;
2176 
2177 		    // only set for b conversion
2178 		    uvarnumber_T bin_arg = 0;
2179 
2180 		    // pointer argument value -only defined for p
2181 		    // conversion
2182 		    void *ptr_arg = NULL;
2183 
2184 		    if (fmt_spec == 'p')
2185 		    {
2186 			length_modifier = '\0';
2187 			ptr_arg =
2188 # if defined(FEAT_EVAL)
2189 				 tvs != NULL ? (void *)tv_str(tvs, &arg_idx,
2190 									NULL) :
2191 # endif
2192 					va_arg(ap, void *);
2193 			if (ptr_arg != NULL)
2194 			    arg_sign = 1;
2195 		    }
2196 		    else if (fmt_spec == 'b' || fmt_spec == 'B')
2197 		    {
2198 			bin_arg =
2199 # if defined(FEAT_EVAL)
2200 				    tvs != NULL ?
2201 					   (uvarnumber_T)tv_nr(tvs, &arg_idx) :
2202 # endif
2203 					va_arg(ap, uvarnumber_T);
2204 			if (bin_arg != 0)
2205 			    arg_sign = 1;
2206 		    }
2207 		    else if (fmt_spec == 'd')
2208 		    {
2209 			// signed
2210 			switch (length_modifier)
2211 			{
2212 			case '\0':
2213 			case 'h':
2214 			    // char and short arguments are passed as int.
2215 			    int_arg =
2216 # if defined(FEAT_EVAL)
2217 					tvs != NULL ? tv_nr(tvs, &arg_idx) :
2218 # endif
2219 					    va_arg(ap, int);
2220 			    if (int_arg > 0)
2221 				arg_sign =  1;
2222 			    else if (int_arg < 0)
2223 				arg_sign = -1;
2224 			    break;
2225 			case 'l':
2226 			    long_arg =
2227 # if defined(FEAT_EVAL)
2228 					tvs != NULL ? tv_nr(tvs, &arg_idx) :
2229 # endif
2230 					    va_arg(ap, long int);
2231 			    if (long_arg > 0)
2232 				arg_sign =  1;
2233 			    else if (long_arg < 0)
2234 				arg_sign = -1;
2235 			    break;
2236 			case 'L':
2237 			    llong_arg =
2238 # if defined(FEAT_EVAL)
2239 					tvs != NULL ? tv_nr(tvs, &arg_idx) :
2240 # endif
2241 					    va_arg(ap, varnumber_T);
2242 			    if (llong_arg > 0)
2243 				arg_sign =  1;
2244 			    else if (llong_arg < 0)
2245 				arg_sign = -1;
2246 			    break;
2247 			}
2248 		    }
2249 		    else
2250 		    {
2251 			// unsigned
2252 			switch (length_modifier)
2253 			{
2254 			    case '\0':
2255 			    case 'h':
2256 				uint_arg =
2257 # if defined(FEAT_EVAL)
2258 					    tvs != NULL ? (unsigned)
2259 							tv_nr(tvs, &arg_idx) :
2260 # endif
2261 						va_arg(ap, unsigned int);
2262 				if (uint_arg != 0)
2263 				    arg_sign = 1;
2264 				break;
2265 			    case 'l':
2266 				ulong_arg =
2267 # if defined(FEAT_EVAL)
2268 					    tvs != NULL ? (unsigned long)
2269 							tv_nr(tvs, &arg_idx) :
2270 # endif
2271 						va_arg(ap, unsigned long int);
2272 				if (ulong_arg != 0)
2273 				    arg_sign = 1;
2274 				break;
2275 			    case 'L':
2276 				ullong_arg =
2277 # if defined(FEAT_EVAL)
2278 					    tvs != NULL ? (uvarnumber_T)
2279 							tv_nr(tvs, &arg_idx) :
2280 # endif
2281 						va_arg(ap, uvarnumber_T);
2282 				if (ullong_arg != 0)
2283 				    arg_sign = 1;
2284 				break;
2285 			}
2286 		    }
2287 
2288 		    str_arg = tmp;
2289 		    str_arg_l = 0;
2290 
2291 		    // NOTE:
2292 		    //   For d, i, u, o, x, and X conversions, if precision is
2293 		    //   specified, the '0' flag should be ignored. This is so
2294 		    //   with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux,
2295 		    //   FreeBSD, NetBSD; but not with Perl.
2296 		    if (precision_specified)
2297 			zero_padding = 0;
2298 		    if (fmt_spec == 'd')
2299 		    {
2300 			if (force_sign && arg_sign >= 0)
2301 			    tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
2302 			// leave negative numbers for sprintf to handle, to
2303 			// avoid handling tricky cases like (short int)-32768
2304 		    }
2305 		    else if (alternate_form)
2306 		    {
2307 			if (arg_sign != 0
2308 				     && (fmt_spec == 'b' || fmt_spec == 'B'
2309 				      || fmt_spec == 'x' || fmt_spec == 'X') )
2310 			{
2311 			    tmp[str_arg_l++] = '0';
2312 			    tmp[str_arg_l++] = fmt_spec;
2313 			}
2314 			// alternate form should have no effect for p
2315 			// conversion, but ...
2316 		    }
2317 
2318 		    zero_padding_insertion_ind = str_arg_l;
2319 		    if (!precision_specified)
2320 			precision = 1;   // default precision is 1
2321 		    if (precision == 0 && arg_sign == 0)
2322 		    {
2323 			// When zero value is formatted with an explicit
2324 			// precision 0, the resulting formatted string is
2325 			// empty (d, i, u, b, B, o, x, X, p).
2326 		    }
2327 		    else
2328 		    {
2329 			char	f[6];
2330 			int	f_l = 0;
2331 
2332 			// construct a simple format string for sprintf
2333 			f[f_l++] = '%';
2334 			if (!length_modifier)
2335 			    ;
2336 			else if (length_modifier == 'L')
2337 			{
2338 # ifdef MSWIN
2339 			    f[f_l++] = 'I';
2340 			    f[f_l++] = '6';
2341 			    f[f_l++] = '4';
2342 # else
2343 			    f[f_l++] = 'l';
2344 			    f[f_l++] = 'l';
2345 # endif
2346 			}
2347 			else
2348 			    f[f_l++] = length_modifier;
2349 			f[f_l++] = fmt_spec;
2350 			f[f_l++] = '\0';
2351 
2352 			if (fmt_spec == 'p')
2353 			    str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
2354 			else if (fmt_spec == 'b' || fmt_spec == 'B')
2355 			{
2356 			    char	    b[8 * sizeof(uvarnumber_T)];
2357 			    size_t	    b_l = 0;
2358 			    uvarnumber_T    bn = bin_arg;
2359 
2360 			    do
2361 			    {
2362 				b[sizeof(b) - ++b_l] = '0' + (bn & 0x1);
2363 				bn >>= 1;
2364 			    }
2365 			    while (bn != 0);
2366 
2367 			    memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l);
2368 			    str_arg_l += b_l;
2369 			}
2370 			else if (fmt_spec == 'd')
2371 			{
2372 			    // signed
2373 			    switch (length_modifier)
2374 			    {
2375 			    case '\0': str_arg_l += sprintf(
2376 						 tmp + str_arg_l, f,
2377 						 int_arg);
2378 				       break;
2379 			    case 'h': str_arg_l += sprintf(
2380 						 tmp + str_arg_l, f,
2381 						 (short)int_arg);
2382 				      break;
2383 			    case 'l': str_arg_l += sprintf(
2384 						tmp + str_arg_l, f, long_arg);
2385 				      break;
2386 			    case 'L': str_arg_l += sprintf(
2387 					       tmp + str_arg_l, f, llong_arg);
2388 				      break;
2389 			    }
2390 			}
2391 			else
2392 			{
2393 			    // unsigned
2394 			    switch (length_modifier)
2395 			    {
2396 			    case '\0': str_arg_l += sprintf(
2397 						tmp + str_arg_l, f,
2398 						uint_arg);
2399 				       break;
2400 			    case 'h': str_arg_l += sprintf(
2401 						tmp + str_arg_l, f,
2402 						(unsigned short)uint_arg);
2403 				      break;
2404 			    case 'l': str_arg_l += sprintf(
2405 					       tmp + str_arg_l, f, ulong_arg);
2406 				      break;
2407 			    case 'L': str_arg_l += sprintf(
2408 					      tmp + str_arg_l, f, ullong_arg);
2409 				      break;
2410 			    }
2411 			}
2412 
2413 			// include the optional minus sign and possible
2414 			// "0x" in the region before the zero padding
2415 			// insertion point
2416 			if (zero_padding_insertion_ind < str_arg_l
2417 				&& tmp[zero_padding_insertion_ind] == '-')
2418 			    zero_padding_insertion_ind++;
2419 			if (zero_padding_insertion_ind + 1 < str_arg_l
2420 				&& tmp[zero_padding_insertion_ind]   == '0'
2421 				&& (tmp[zero_padding_insertion_ind + 1] == 'x'
2422 				 || tmp[zero_padding_insertion_ind + 1] == 'X'))
2423 			    zero_padding_insertion_ind += 2;
2424 		    }
2425 
2426 		    {
2427 			size_t num_of_digits = str_arg_l
2428 						 - zero_padding_insertion_ind;
2429 
2430 			if (alternate_form && fmt_spec == 'o'
2431 				// unless zero is already the first
2432 				// character
2433 				&& !(zero_padding_insertion_ind < str_arg_l
2434 				    && tmp[zero_padding_insertion_ind] == '0'))
2435 			{
2436 			    // assure leading zero for alternate-form
2437 			    // octal numbers
2438 			    if (!precision_specified
2439 					     || precision < num_of_digits + 1)
2440 			    {
2441 				// precision is increased to force the
2442 				// first character to be zero, except if a
2443 				// zero value is formatted with an
2444 				// explicit precision of zero
2445 				precision = num_of_digits + 1;
2446 			    }
2447 			}
2448 			// zero padding to specified precision?
2449 			if (num_of_digits < precision)
2450 			    number_of_zeros_to_pad = precision - num_of_digits;
2451 		    }
2452 		    // zero padding to specified minimal field width?
2453 		    if (!justify_left && zero_padding)
2454 		    {
2455 			int n = (int)(min_field_width - (str_arg_l
2456 						    + number_of_zeros_to_pad));
2457 			if (n > 0)
2458 			    number_of_zeros_to_pad += n;
2459 		    }
2460 		    break;
2461 		}
2462 
2463 # ifdef FEAT_FLOAT
2464 	    case 'f':
2465 	    case 'F':
2466 	    case 'e':
2467 	    case 'E':
2468 	    case 'g':
2469 	    case 'G':
2470 		{
2471 		    // Floating point.
2472 		    double	f;
2473 		    double	abs_f;
2474 		    char	format[40];
2475 		    int		l;
2476 		    int		remove_trailing_zeroes = FALSE;
2477 
2478 		    f =
2479 #  if defined(FEAT_EVAL)
2480 			tvs != NULL ? tv_float(tvs, &arg_idx) :
2481 #  endif
2482 			    va_arg(ap, double);
2483 		    abs_f = f < 0 ? -f : f;
2484 
2485 		    if (fmt_spec == 'g' || fmt_spec == 'G')
2486 		    {
2487 			// Would be nice to use %g directly, but it prints
2488 			// "1.0" as "1", we don't want that.
2489 			if ((abs_f >= 0.001 && abs_f < 10000000.0)
2490 							      || abs_f == 0.0)
2491 			    fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
2492 			else
2493 			    fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
2494 			remove_trailing_zeroes = TRUE;
2495 		    }
2496 
2497 		    if ((fmt_spec == 'f' || fmt_spec == 'F') &&
2498 #  ifdef VAX
2499 			    abs_f > 1.0e38
2500 #  else
2501 			    abs_f > 1.0e307
2502 #  endif
2503 			    )
2504 		    {
2505 			// Avoid a buffer overflow
2506 			STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
2507 					      force_sign, space_for_positive));
2508 			str_arg_l = STRLEN(tmp);
2509 			zero_padding = 0;
2510 		    }
2511 		    else
2512 		    {
2513 			if (isnan(f))
2514 			{
2515 			    // Not a number: nan or NAN
2516 			    STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN"
2517 								      : "nan");
2518 			    str_arg_l = 3;
2519 			    zero_padding = 0;
2520 			}
2521 			else if (isinf(f))
2522 			{
2523 			    STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
2524 					      force_sign, space_for_positive));
2525 			    str_arg_l = STRLEN(tmp);
2526 			    zero_padding = 0;
2527 			}
2528 			else
2529 			{
2530 			    // Regular float number
2531 			    format[0] = '%';
2532 			    l = 1;
2533 			    if (force_sign)
2534 				format[l++] = space_for_positive ? ' ' : '+';
2535 			    if (precision_specified)
2536 			    {
2537 				size_t max_prec = TMP_LEN - 10;
2538 
2539 				// Make sure we don't get more digits than we
2540 				// have room for.
2541 				if ((fmt_spec == 'f' || fmt_spec == 'F')
2542 								&& abs_f > 1.0)
2543 				    max_prec -= (size_t)log10(abs_f);
2544 				if (precision > max_prec)
2545 				    precision = max_prec;
2546 				l += sprintf(format + l, ".%d", (int)precision);
2547 			    }
2548 			    format[l] = fmt_spec == 'F' ? 'f' : fmt_spec;
2549 			    format[l + 1] = NUL;
2550 
2551 			    str_arg_l = sprintf(tmp, format, f);
2552 			}
2553 
2554 			if (remove_trailing_zeroes)
2555 			{
2556 			    int i;
2557 			    char *tp;
2558 
2559 			    // Using %g or %G: remove superfluous zeroes.
2560 			    if (fmt_spec == 'f' || fmt_spec == 'F')
2561 				tp = tmp + str_arg_l - 1;
2562 			    else
2563 			    {
2564 				tp = (char *)vim_strchr((char_u *)tmp,
2565 						 fmt_spec == 'e' ? 'e' : 'E');
2566 				if (tp != NULL)
2567 				{
2568 				    // Remove superfluous '+' and leading
2569 				    // zeroes from the exponent.
2570 				    if (tp[1] == '+')
2571 				    {
2572 					// Change "1.0e+07" to "1.0e07"
2573 					STRMOVE(tp + 1, tp + 2);
2574 					--str_arg_l;
2575 				    }
2576 				    i = (tp[1] == '-') ? 2 : 1;
2577 				    while (tp[i] == '0')
2578 				    {
2579 					// Change "1.0e07" to "1.0e7"
2580 					STRMOVE(tp + i, tp + i + 1);
2581 					--str_arg_l;
2582 				    }
2583 				    --tp;
2584 				}
2585 			    }
2586 
2587 			    if (tp != NULL && !precision_specified)
2588 				// Remove trailing zeroes, but keep the one
2589 				// just after a dot.
2590 				while (tp > tmp + 2 && *tp == '0'
2591 							     && tp[-1] != '.')
2592 				{
2593 				    STRMOVE(tp, tp + 1);
2594 				    --tp;
2595 				    --str_arg_l;
2596 				}
2597 			}
2598 			else
2599 			{
2600 			    char *tp;
2601 
2602 			    // Be consistent: some printf("%e") use 1.0e+12
2603 			    // and some 1.0e+012.  Remove one zero in the last
2604 			    // case.
2605 			    tp = (char *)vim_strchr((char_u *)tmp,
2606 						 fmt_spec == 'e' ? 'e' : 'E');
2607 			    if (tp != NULL && (tp[1] == '+' || tp[1] == '-')
2608 					  && tp[2] == '0'
2609 					  && vim_isdigit(tp[3])
2610 					  && vim_isdigit(tp[4]))
2611 			    {
2612 				STRMOVE(tp + 2, tp + 3);
2613 				--str_arg_l;
2614 			    }
2615 			}
2616 		    }
2617 		    if (zero_padding && min_field_width > str_arg_l
2618 					      && (tmp[0] == '-' || force_sign))
2619 		    {
2620 			// padding 0's should be inserted after the sign
2621 			number_of_zeros_to_pad = min_field_width - str_arg_l;
2622 			zero_padding_insertion_ind = 1;
2623 		    }
2624 		    str_arg = tmp;
2625 		    break;
2626 		}
2627 # endif
2628 
2629 	    default:
2630 		// unrecognized conversion specifier, keep format string
2631 		// as-is
2632 		zero_padding = 0;  // turn zero padding off for non-numeric
2633 				   // conversion
2634 		justify_left = 1;
2635 		min_field_width = 0;		    // reset flags
2636 
2637 		// discard the unrecognized conversion, just keep *
2638 		// the unrecognized conversion character
2639 		str_arg = p;
2640 		str_arg_l = 0;
2641 		if (*p != NUL)
2642 		    str_arg_l++;  // include invalid conversion specifier
2643 				  // unchanged if not at end-of-string
2644 		break;
2645 	    }
2646 
2647 	    if (*p != NUL)
2648 		p++;     // step over the just processed conversion specifier
2649 
2650 	    // insert padding to the left as requested by min_field_width;
2651 	    // this does not include the zero padding in case of numerical
2652 	    // conversions
2653 	    if (!justify_left)
2654 	    {
2655 		// left padding with blank or zero
2656 		int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad));
2657 
2658 		if (pn > 0)
2659 		{
2660 		    if (str_l < str_m)
2661 		    {
2662 			size_t avail = str_m - str_l;
2663 
2664 			vim_memset(str + str_l, zero_padding ? '0' : ' ',
2665 					     (size_t)pn > avail ? avail
2666 								: (size_t)pn);
2667 		    }
2668 		    str_l += pn;
2669 		}
2670 	    }
2671 
2672 	    // zero padding as requested by the precision or by the minimal
2673 	    // field width for numeric conversions required?
2674 	    if (number_of_zeros_to_pad == 0)
2675 	    {
2676 		// will not copy first part of numeric right now, *
2677 		// force it to be copied later in its entirety
2678 		zero_padding_insertion_ind = 0;
2679 	    }
2680 	    else
2681 	    {
2682 		// insert first part of numerics (sign or '0x') before zero
2683 		// padding
2684 		int zn = (int)zero_padding_insertion_ind;
2685 
2686 		if (zn > 0)
2687 		{
2688 		    if (str_l < str_m)
2689 		    {
2690 			size_t avail = str_m - str_l;
2691 
2692 			mch_memmove(str + str_l, str_arg,
2693 					     (size_t)zn > avail ? avail
2694 								: (size_t)zn);
2695 		    }
2696 		    str_l += zn;
2697 		}
2698 
2699 		// insert zero padding as requested by the precision or min
2700 		// field width
2701 		zn = (int)number_of_zeros_to_pad;
2702 		if (zn > 0)
2703 		{
2704 		    if (str_l < str_m)
2705 		    {
2706 			size_t avail = str_m - str_l;
2707 
2708 			vim_memset(str + str_l, '0',
2709 					     (size_t)zn > avail ? avail
2710 								: (size_t)zn);
2711 		    }
2712 		    str_l += zn;
2713 		}
2714 	    }
2715 
2716 	    // insert formatted string
2717 	    // (or as-is conversion specifier for unknown conversions)
2718 	    {
2719 		int sn = (int)(str_arg_l - zero_padding_insertion_ind);
2720 
2721 		if (sn > 0)
2722 		{
2723 		    if (str_l < str_m)
2724 		    {
2725 			size_t avail = str_m - str_l;
2726 
2727 			mch_memmove(str + str_l,
2728 				str_arg + zero_padding_insertion_ind,
2729 				(size_t)sn > avail ? avail : (size_t)sn);
2730 		    }
2731 		    str_l += sn;
2732 		}
2733 	    }
2734 
2735 	    // insert right padding
2736 	    if (justify_left)
2737 	    {
2738 		// right blank padding to the field width
2739 		int pn = (int)(min_field_width
2740 				      - (str_arg_l + number_of_zeros_to_pad));
2741 
2742 		if (pn > 0)
2743 		{
2744 		    if (str_l < str_m)
2745 		    {
2746 			size_t avail = str_m - str_l;
2747 
2748 			vim_memset(str + str_l, ' ',
2749 					     (size_t)pn > avail ? avail
2750 								: (size_t)pn);
2751 		    }
2752 		    str_l += pn;
2753 		}
2754 	    }
2755 	    vim_free(tofree);
2756 	}
2757     }
2758 
2759     if (str_m > 0)
2760     {
2761 	// make sure the string is nul-terminated even at the expense of
2762 	// overwriting the last character (shouldn't happen, but just in case)
2763 	//
2764 	str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
2765     }
2766 
2767     if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
2768 	emsg(_("E767: Too many arguments to printf()"));
2769 
2770     // Return the number of characters formatted (excluding trailing nul
2771     // character), that is, the number of characters that would have been
2772     // written to the buffer if it were large enough.
2773     return (int)str_l;
2774 }
2775 
2776 #endif // PROTO
2777