blob: 0c9e20d176a28673ca6c8ac885b0d01648cd8cd3 [file] [log] [blame]
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001/* 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
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +020014#define USING_FLOAT_STUFF
Yegappan Lakshmanana2438132021-07-10 21:29:18 +020015#include "vim.h"
16
17/*
18 * Copy "string" into newly allocated memory.
19 */
20 char_u *
21vim_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 *
40vim_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 *
58vim_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 *
69vim_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
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +020081 // First count the number of backslashes required.
82 // Then allocate the memory and insert them.
Yegappan Lakshmanana2438132021-07-10 21:29:18 +020083 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
122csh_like_shell(void)
123{
124 return (strstr((char *)gettail(p_sh), "csh") != NULL);
125}
126
127/*
Jason Cox6e823512021-08-29 12:36:49 +0200128 * Return TRUE when 'shell' has "fish" in the tail.
129 */
Dominique Pellede05ae72021-08-30 19:57:34 +0200130 static int
Jason Cox6e823512021-08-29 12:36:49 +0200131fish_like_shell(void)
132{
133 return (strstr((char *)gettail(p_sh), "fish") != NULL);
134}
135
136/*
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200137 * 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 *
149vim_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;
Jason Cox6e823512021-08-29 12:36:49 +0200157 int fish_like;
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200158 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
Jason Cox6e823512021-08-29 12:36:49 +0200170 // 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200174 // 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 }
Jason Cox6e823512021-08-29 12:36:49 +0200214 if (*p == '\\' && fish_like)
215 ++length; // insert backslash
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200216 }
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 }
Jason Cox6e823512021-08-29 12:36:49 +0200280 if (*p == '\\' && fish_like)
281 {
282 *d++ = '\\';
283 *d++ = *p++;
284 }
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200285
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 *
307vim_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 *
321vim_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
334vim_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 *
359strup_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 *
426strlow_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
492del_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
506vim_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
517vim_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
538vim_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
563vim_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 *
589vim_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 *
646vim_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 *
668vim_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 *
692vim_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 */
708static int sort_compare(const void *s1, const void *s2);
709
710 static int
711sort_compare(const void *s1, const void *s2)
712{
713 return STRCMP(*(char **)s1, *(char **)s2);
714}
715
716 void
717sort_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
730has_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 *
747concat_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 *
773string_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
812byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
813{
814 char_u *t;
815 char_u *str;
816 varnumber_T idx;
817
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200818 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200825 str = tv_get_string_chk(&argvars[0]);
826 idx = tv_get_number_chk(&argvars[1], NULL);
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200827 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
847f_byteidx(typval_T *argvars, typval_T *rettv)
848{
849 byteidx(argvars, rettv, FALSE);
850}
851
852/*
853 * "byteidxcomp()" function
854 */
855 void
856f_byteidxcomp(typval_T *argvars, typval_T *rettv)
857{
858 byteidx(argvars, rettv, TRUE);
859}
860
861/*
862 * "charidx()" function
863 */
864 void
865f_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
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200876 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200882 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
923f_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
Yegappan Lakshmanana9a7c0c2021-07-17 19:11:07 +0200931 if (in_vim9script()
932 && (check_for_string_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200933 || check_for_opt_bool_arg(argvars, 1) == FAIL))
Yegappan Lakshmanana9a7c0c2021-07-17 19:11:07 +0200934 return;
935
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200936 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
969f_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
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200977 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +0200984 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
1019f_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;
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +02001028
1029 if (in_vim9script()
1030 && (check_for_string_arg(argvars, 0) == FAIL
1031 || check_for_number_arg(argvars, 1) == FAIL))
1032 return;
1033
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001034 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
1058f_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
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001067 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001073 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
1099f_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
1116f_strlen(typval_T *argvars, typval_T *rettv)
1117{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001118 if (in_vim9script()
1119 && check_for_string_or_number_arg(argvars, 0) == FAIL)
1120 return;
1121
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001122 rettv->vval.v_number = (varnumber_T)(STRLEN(
1123 tv_get_string(&argvars[0])));
1124}
1125
1126 static void
1127strchar_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
1146f_strcharlen(typval_T *argvars, typval_T *rettv)
1147{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001148 if (in_vim9script()
1149 && check_for_string_or_number_arg(argvars, 0) == FAIL)
1150 return;
1151
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001152 strchar_common(argvars, rettv, TRUE);
1153}
1154
1155/*
1156 * "strchars()" function
1157 */
1158 void
1159f_strchars(typval_T *argvars, typval_T *rettv)
1160{
1161 varnumber_T skipcc = FALSE;
1162
Yegappan Lakshmanana9a7c0c2021-07-17 19:11:07 +02001163 if (in_vim9script()
1164 && (check_for_string_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02001165 || check_for_opt_bool_arg(argvars, 1) == FAIL))
Yegappan Lakshmanana9a7c0c2021-07-17 19:11:07 +02001166 return;
1167
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001168 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
1180f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
1181{
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +02001182 char_u *s;
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001183 int col = 0;
1184
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +02001185 rettv->vval.v_number = -1;
1186
1187 if (in_vim9script()
1188 && (check_for_string_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02001189 || check_for_opt_number_arg(argvars, 1) == FAIL))
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +02001190 return;
1191
1192 s = tv_get_string(&argvars[0]);
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001193 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
1203f_strwidth(typval_T *argvars, typval_T *rettv)
1204{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001205 char_u *s;
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001206
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001207 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1208 return;
1209
1210 s = tv_get_string_strict(&argvars[0]);
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001211 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
1212}
1213
1214/*
1215 * "strcharpart()" function
1216 */
1217 void
1218f_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
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02001229 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001237 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
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +02001288 // Only return the overlap between the specified part and the actual
1289 // string.
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001290 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
1310f_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
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02001318 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001326 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
1369f_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
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001378 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001384 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
1428f_strtrans(typval_T *argvars, typval_T *rettv)
1429{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001430 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1431 return;
1432
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001433 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
1441f_tolower(typval_T *argvars, typval_T *rettv)
1442{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001443 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1444 return;
1445
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001446 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
1454f_toupper(typval_T *argvars, typval_T *rettv)
1455{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001456 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
1457 return;
1458
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001459 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
1467f_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
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001484 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
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001490 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 {
1505error:
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
1586f_trim(typval_T *argvars, typval_T *rettv)
1587{
1588 char_u buf1[NUMBUFLEN];
1589 char_u buf2[NUMBUFLEN];
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001590 char_u *head;
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001591 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;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001600
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);
Yegappan Lakshmanana2438132021-07-10 21:29:18 +02001609 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
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +02001689
1690#if defined(FEAT_EVAL)
1691static 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
1697tv_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 *
1724tv_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
1748tv_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 *
1776infinity_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 <mark.martinec@ijs.si>, 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
1842vim_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
1860vim_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
1872vim_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
1882vim_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