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