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