string.c: do not interpret '\\' before '\0' (CVE-2019-15846)
[exim.git] / src / src / string.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Miscellaneous string-handling functions. Some are not required for
9utilities and tests, and are cut out by the COMPILE_UTILITY macro. */
10
11
12#include "exim.h"
d12746bc 13#include <assert.h>
059ec3d9
PH
14
15
16#ifndef COMPILE_UTILITY
17/*************************************************
18* Test for IP address *
19*************************************************/
20
21/* This used just to be a regular expression, but with IPv6 things are a bit
22more complicated. If the address contains a colon, it is assumed to be a v6
23address (assuming HAVE_IPV6 is set). If a mask is permitted and one is present,
24and maskptr is not NULL, its offset is placed there.
25
26Arguments:
27 s a string
28 maskptr NULL if no mask is permitted to follow
29 otherwise, points to an int where the offset of '/' is placed
1688f43b 30 if there is no / followed by trailing digits, *maskptr is set 0
059ec3d9
PH
31
32Returns: 0 if the string is not a textual representation of an IP address
33 4 if it is an IPv4 address
34 6 if it is an IPv6 address
35*/
36
37int
b1f8e4f8 38string_is_ip_address(const uschar *s, int *maskptr)
059ec3d9
PH
39{
40int i;
41int yield = 4;
42
43/* If an optional mask is permitted, check for it. If found, pass back the
44offset. */
45
8d909960 46if (maskptr)
059ec3d9 47 {
b1f8e4f8 48 const uschar *ss = s + Ustrlen(s);
059ec3d9
PH
49 *maskptr = 0;
50 if (s != ss && isdigit(*(--ss)))
51 {
52 while (ss > s && isdigit(ss[-1])) ss--;
53 if (ss > s && *(--ss) == '/') *maskptr = ss - s;
54 }
55 }
56
57/* A colon anywhere in the string => IPv6 address */
58
59if (Ustrchr(s, ':') != NULL)
60 {
61 BOOL had_double_colon = FALSE;
62 BOOL v4end = FALSE;
63 int count = 0;
64
65 yield = 6;
66
67 /* An IPv6 address must start with hex digit or double colon. A single
68 colon is invalid. */
69
70 if (*s == ':' && *(++s) != ':') return 0;
71
72 /* Now read up to 8 components consisting of up to 4 hex digits each. There
73 may be one and only one appearance of double colon, which implies any number
74 of binary zero bits. The number of preceding components is held in count. */
75
76 for (count = 0; count < 8; count++)
77 {
78 /* If the end of the string is reached before reading 8 components, the
79 address is valid provided a double colon has been read. This also applies
80 if we hit the / that introduces a mask or the % that introduces the
81 interface specifier (scope id) of a link-local address. */
82
8d909960 83 if (*s == 0 || *s == '%' || *s == '/') return had_double_colon ? yield : 0;
059ec3d9
PH
84
85 /* If a component starts with an additional colon, we have hit a double
86 colon. This is permitted to appear once only, and counts as at least
87 one component. The final component may be of this form. */
88
89 if (*s == ':')
90 {
91 if (had_double_colon) return 0;
92 had_double_colon = TRUE;
93 s++;
94 continue;
95 }
96
97 /* If the remainder of the string contains a dot but no colons, we
98 can expect a trailing IPv4 address. This is valid if either there has
99 been no double-colon and this is the 7th component (with the IPv4 address
100 being the 7th & 8th components), OR if there has been a double-colon
101 and fewer than 6 components. */
102
103 if (Ustrchr(s, ':') == NULL && Ustrchr(s, '.') != NULL)
104 {
105 if ((!had_double_colon && count != 6) ||
106 (had_double_colon && count > 6)) return 0;
107 v4end = TRUE;
108 yield = 6;
109 break;
110 }
111
112 /* Check for at least one and not more than 4 hex digits for this
113 component. */
114
115 if (!isxdigit(*s++)) return 0;
116 if (isxdigit(*s) && isxdigit(*(++s)) && isxdigit(*(++s))) s++;
117
118 /* If the component is terminated by colon and there is more to
119 follow, skip over the colon. If there is no more to follow the address is
120 invalid. */
121
122 if (*s == ':' && *(++s) == 0) return 0;
123 }
124
125 /* If about to handle a trailing IPv4 address, drop through. Otherwise
126 all is well if we are at the end of the string or at the mask or at a percent
127 sign, which introduces the interface specifier (scope id) of a link local
128 address. */
129
1688f43b
PH
130 if (!v4end)
131 return (*s == 0 || *s == '%' ||
132 (*s == '/' && maskptr != NULL && *maskptr != 0))? yield : 0;
059ec3d9
PH
133 }
134
135/* Test for IPv4 address, which may be the tail-end of an IPv6 address. */
136
137for (i = 0; i < 4; i++)
138 {
8d909960
JH
139 long n;
140 uschar * end;
141
059ec3d9 142 if (i != 0 && *s++ != '.') return 0;
8d909960
JH
143 n = strtol(CCS s, CSS &end, 10);
144 if (n > 255 || n < 0 || end <= s || end > s+3) return 0;
145 s = end;
059ec3d9
PH
146 }
147
8d909960 148return !*s || (*s == '/' && maskptr && *maskptr != 0) ? yield : 0;
059ec3d9
PH
149}
150#endif /* COMPILE_UTILITY */
151
152
153/*************************************************
154* Format message size *
155*************************************************/
156
157/* Convert a message size in bytes to printing form, rounding
158according to the magnitude of the number. A value of zero causes
159a string of spaces to be returned.
160
161Arguments:
162 size the message size in bytes
163 buffer where to put the answer
164
165Returns: pointer to the buffer
166 a string of exactly 5 characters is normally returned
167*/
168
169uschar *
170string_format_size(int size, uschar *buffer)
171{
45500060 172if (size == 0) Ustrcpy(buffer, " ");
059ec3d9
PH
173else if (size < 1024) sprintf(CS buffer, "%5d", size);
174else if (size < 10*1024)
175 sprintf(CS buffer, "%4.1fK", (double)size / 1024.0);
176else if (size < 1024*1024)
177 sprintf(CS buffer, "%4dK", (size + 512)/1024);
178else if (size < 10*1024*1024)
179 sprintf(CS buffer, "%4.1fM", (double)size / (1024.0 * 1024.0));
180else
181 sprintf(CS buffer, "%4dM", (size + 512 * 1024)/(1024*1024));
182return buffer;
183}
184
185
186
187#ifndef COMPILE_UTILITY
188/*************************************************
189* Convert a number to base 62 format *
190*************************************************/
191
192/* Convert a long integer into an ASCII base 62 string. For Cygwin the value of
193BASE_62 is actually 36. Always return exactly 6 characters plus zero, in a
194static area.
195
196Argument: a long integer
197Returns: pointer to base 62 string
198*/
199
200uschar *
201string_base62(unsigned long int value)
202{
203static uschar yield[7];
204uschar *p = yield + sizeof(yield) - 1;
205*p = 0;
206while (p > yield)
207 {
208 *(--p) = base62_chars[value % BASE_62];
209 value /= BASE_62;
210 }
211return yield;
212}
213#endif /* COMPILE_UTILITY */
214
215
216
059ec3d9
PH
217/*************************************************
218* Interpret escape sequence *
219*************************************************/
220
221/* This function is called from several places where escape sequences are to be
222interpreted in strings.
223
224Arguments:
225 pp points a pointer to the initiating "\" in the string;
226 the pointer gets updated to point to the final character
2600301b
HSHR
227 If the backslash is the last character in the string, it
228 is not interpreted.
059ec3d9
PH
229Returns: the value of the character escape
230*/
231
232int
55414b25 233string_interpret_escape(const uschar **pp)
059ec3d9 234{
3fb3c68d
JH
235#ifdef COMPILE_UTILITY
236const uschar *hex_digits= CUS"0123456789abcdef";
237#endif
059ec3d9 238int ch;
55414b25 239const uschar *p = *pp;
059ec3d9 240ch = *(++p);
2600301b 241if (ch == '\0') return **pp;
059ec3d9
PH
242if (isdigit(ch) && ch != '8' && ch != '9')
243 {
244 ch -= '0';
245 if (isdigit(p[1]) && p[1] != '8' && p[1] != '9')
246 {
247 ch = ch * 8 + *(++p) - '0';
248 if (isdigit(p[1]) && p[1] != '8' && p[1] != '9')
249 ch = ch * 8 + *(++p) - '0';
250 }
251 }
252else switch(ch)
253 {
c7396ac5
PP
254 case 'b': ch = '\b'; break;
255 case 'f': ch = '\f'; break;
059ec3d9
PH
256 case 'n': ch = '\n'; break;
257 case 'r': ch = '\r'; break;
258 case 't': ch = '\t'; break;
c7396ac5 259 case 'v': ch = '\v'; break;
059ec3d9
PH
260 case 'x':
261 ch = 0;
262 if (isxdigit(p[1]))
263 {
264 ch = ch * 16 +
265 Ustrchr(hex_digits, tolower(*(++p))) - hex_digits;
266 if (isxdigit(p[1])) ch = ch * 16 +
267 Ustrchr(hex_digits, tolower(*(++p))) - hex_digits;
268 }
269 break;
270 }
271*pp = p;
272return ch;
273}
059ec3d9
PH
274
275
276
277#ifndef COMPILE_UTILITY
278/*************************************************
279* Ensure string is printable *
280*************************************************/
281
282/* This function is called for critical strings. It checks for any
283non-printing characters, and if any are found, it makes a new copy
284of the string with suitable escape sequences. It is most often called by the
285macro string_printing(), which sets allow_tab TRUE.
286
287Arguments:
288 s the input string
289 allow_tab TRUE to allow tab as a printing character
290
291Returns: string with non-printers encoded as printing sequences
292*/
293
55414b25
JH
294const uschar *
295string_printing2(const uschar *s, BOOL allow_tab)
059ec3d9
PH
296{
297int nonprintcount = 0;
298int length = 0;
55414b25 299const uschar *t = s;
059ec3d9
PH
300uschar *ss, *tt;
301
302while (*t != 0)
303 {
304 int c = *t++;
305 if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++;
306 length++;
307 }
308
309if (nonprintcount == 0) return s;
310
311/* Get a new block of store guaranteed big enough to hold the
312expanded string. */
313
36719342 314ss = store_get(length + nonprintcount * 3 + 1);
059ec3d9 315
4c04137d 316/* Copy everything, escaping non printers. */
059ec3d9
PH
317
318t = s;
319tt = ss;
320
321while (*t != 0)
322 {
323 int c = *t;
324 if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else
325 {
326 *tt++ = '\\';
327 switch (*t)
328 {
329 case '\n': *tt++ = 'n'; break;
330 case '\r': *tt++ = 'r'; break;
331 case '\b': *tt++ = 'b'; break;
332 case '\v': *tt++ = 'v'; break;
333 case '\f': *tt++ = 'f'; break;
334 case '\t': *tt++ = 't'; break;
335 default: sprintf(CS tt, "%03o", *t); tt += 3; break;
336 }
337 t++;
338 }
339 }
340*tt = 0;
341return ss;
342}
79fe97d8
PP
343#endif /* COMPILE_UTILITY */
344
c7396ac5
PP
345/*************************************************
346* Undo printing escapes in string *
347*************************************************/
348
349/* This function is the reverse of string_printing2. It searches for
350backslash characters and if any are found, it makes a new copy of the
351string with escape sequences parsed. Otherwise it returns the original
352string.
353
354Arguments:
355 s the input string
356
357Returns: string with printing escapes parsed back
358*/
359
360uschar *
361string_unprinting(uschar *s)
362{
363uschar *p, *q, *r, *ss;
364int len, off;
365
366p = Ustrchr(s, '\\');
367if (!p) return s;
368
369len = Ustrlen(s) + 1;
370ss = store_get(len);
371
372q = ss;
373off = p - s;
374if (off)
375 {
376 memcpy(q, s, off);
377 q += off;
378 }
379
380while (*p)
381 {
382 if (*p == '\\')
383 {
55414b25 384 *q++ = string_interpret_escape((const uschar **)&p);
823ad74f 385 p++;
c7396ac5
PP
386 }
387 else
388 {
389 r = Ustrchr(p, '\\');
390 if (!r)
391 {
392 off = Ustrlen(p);
393 memcpy(q, p, off);
394 p += off;
395 q += off;
396 break;
397 }
398 else
399 {
400 off = r - p;
401 memcpy(q, p, off);
402 q += off;
403 p = r;
404 }
405 }
406 }
407*q = '\0';
408
409return ss;
410}
059ec3d9
PH
411
412
413
414
415/*************************************************
416* Copy and save string *
417*************************************************/
418
419/* This function assumes that memcpy() is faster than strcpy().
420
421Argument: string to copy
422Returns: copy of string in new store
423*/
424
425uschar *
3f0945ff 426string_copy(const uschar *s)
059ec3d9
PH
427{
428int len = Ustrlen(s) + 1;
429uschar *ss = store_get(len);
430memcpy(ss, s, len);
431return ss;
432}
433
434
435
436/*************************************************
437* Copy and save string in malloc'd store *
438*************************************************/
439
440/* This function assumes that memcpy() is faster than strcpy().
441
442Argument: string to copy
443Returns: copy of string in new store
444*/
445
446uschar *
55414b25 447string_copy_malloc(const uschar *s)
059ec3d9
PH
448{
449int len = Ustrlen(s) + 1;
450uschar *ss = store_malloc(len);
451memcpy(ss, s, len);
452return ss;
453}
454
455
456
457/*************************************************
458* Copy, lowercase and save string *
459*************************************************/
460
461/*
462Argument: string to copy
463Returns: copy of string in new store, with letters lowercased
464*/
465
466uschar *
1dc92d5a 467string_copylc(const uschar *s)
059ec3d9
PH
468{
469uschar *ss = store_get(Ustrlen(s) + 1);
470uschar *p = ss;
471while (*s != 0) *p++ = tolower(*s++);
472*p = 0;
473return ss;
474}
475
476
477
478/*************************************************
479* Copy and save string, given length *
480*************************************************/
481
482/* It is assumed the data contains no zeros. A zero is added
483onto the end.
484
485Arguments:
486 s string to copy
487 n number of characters
488
489Returns: copy of string in new store
490*/
491
492uschar *
1dc92d5a 493string_copyn(const uschar *s, int n)
059ec3d9
PH
494{
495uschar *ss = store_get(n + 1);
496Ustrncpy(ss, s, n);
497ss[n] = 0;
498return ss;
499}
500
501
502/*************************************************
503* Copy, lowercase, and save string, given length *
504*************************************************/
505
506/* It is assumed the data contains no zeros. A zero is added
507onto the end.
508
509Arguments:
510 s string to copy
511 n number of characters
512
513Returns: copy of string in new store, with letters lowercased
514*/
515
516uschar *
517string_copynlc(uschar *s, int n)
518{
519uschar *ss = store_get(n + 1);
520uschar *p = ss;
521while (n-- > 0) *p++ = tolower(*s++);
522*p = 0;
523return ss;
524}
525
526
527
528/*************************************************
e28326d8
PH
529* Copy string if long, inserting newlines *
530*************************************************/
531
532/* If the given string is longer than 75 characters, it is copied, and within
533the copy, certain space characters are converted into newlines.
534
535Argument: pointer to the string
536Returns: pointer to the possibly altered string
537*/
538
539uschar *
540string_split_message(uschar *msg)
541{
542uschar *s, *ss;
543
544if (msg == NULL || Ustrlen(msg) <= 75) return msg;
545s = ss = msg = string_copy(msg);
546
547for (;;)
548 {
549 int i = 0;
550 while (i < 75 && *ss != 0 && *ss != '\n') ss++, i++;
551 if (*ss == 0) break;
552 if (*ss == '\n')
553 s = ++ss;
554 else
555 {
556 uschar *t = ss + 1;
557 uschar *tt = NULL;
558 while (--t > s + 35)
559 {
560 if (*t == ' ')
561 {
562 if (t[-1] == ':') { tt = t; break; }
563 if (tt == NULL) tt = t;
564 }
565 }
566
567 if (tt == NULL) /* Can't split behind - try ahead */
568 {
569 t = ss + 1;
570 while (*t != 0)
571 {
572 if (*t == ' ' || *t == '\n')
573 { tt = t; break; }
574 t++;
575 }
576 }
577
578 if (tt == NULL) break; /* Can't find anywhere to split */
579 *tt = '\n';
580 s = ss = tt+1;
581 }
582 }
583
584return msg;
585}
586
587
588
589/*************************************************
059ec3d9
PH
590* Copy returned DNS domain name, de-escaping *
591*************************************************/
592
593/* If a domain name contains top-bit characters, some resolvers return
594the fully qualified name with those characters turned into escapes. The
595convention is a backslash followed by _decimal_ digits. We convert these
596back into the original binary values. This will be relevant when
597allow_utf8_domains is set true and UTF-8 characters are used in domain
598names. Backslash can also be used to escape other characters, though we
599shouldn't come across them in domain names.
600
601Argument: the domain name string
602Returns: copy of string in new store, de-escaped
603*/
604
605uschar *
606string_copy_dnsdomain(uschar *s)
607{
608uschar *yield;
609uschar *ss = yield = store_get(Ustrlen(s) + 1);
610
611while (*s != 0)
612 {
613 if (*s != '\\')
614 {
615 *ss++ = *s++;
616 }
617 else if (isdigit(s[1]))
618 {
619 *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
620 s += 4;
621 }
622 else if (*(++s) != 0)
623 {
624 *ss++ = *s++;
625 }
626 }
627
628*ss = 0;
629return yield;
630}
631
632
633#ifndef COMPILE_UTILITY
634/*************************************************
635* Copy space-terminated or quoted string *
636*************************************************/
637
638/* This function copies from a string until its end, or until whitespace is
639encountered, unless the string begins with a double quote, in which case the
640terminating quote is sought, and escaping within the string is done. The length
641of a de-quoted string can be no longer than the original, since escaping always
642turns n characters into 1 character.
643
644Argument: pointer to the pointer to the first character, which gets updated
645Returns: the new string
646*/
647
648uschar *
55414b25 649string_dequote(const uschar **sptr)
059ec3d9 650{
55414b25 651const uschar *s = *sptr;
059ec3d9
PH
652uschar *t, *yield;
653
654/* First find the end of the string */
655
656if (*s != '\"')
059ec3d9 657 while (*s != 0 && !isspace(*s)) s++;
059ec3d9
PH
658else
659 {
660 s++;
8c513105 661 while (*s && *s != '\"')
059ec3d9
PH
662 {
663 if (*s == '\\') (void)string_interpret_escape(&s);
664 s++;
665 }
8c513105 666 if (*s) s++;
059ec3d9
PH
667 }
668
669/* Get enough store to copy into */
670
671t = yield = store_get(s - *sptr + 1);
672s = *sptr;
673
674/* Do the copy */
675
676if (*s != '\"')
677 {
678 while (*s != 0 && !isspace(*s)) *t++ = *s++;
679 }
680else
681 {
682 s++;
683 while (*s != 0 && *s != '\"')
684 {
685 if (*s == '\\') *t++ = string_interpret_escape(&s);
686 else *t++ = *s;
687 s++;
688 }
689 if (*s != 0) s++;
690 }
691
692/* Update the pointer and return the terminated copy */
693
694*sptr = s;
695*t = 0;
696return yield;
697}
698#endif /* COMPILE_UTILITY */
699
700
701
702/*************************************************
703* Format a string and save it *
704*************************************************/
705
94759fce 706/* The formatting is done by string_vformat, which checks the length of
059ec3d9
PH
707everything.
708
709Arguments:
710 format a printf() format - deliberately char * rather than uschar *
711 because it will most usually be a literal string
712 ... arguments for format
713
714Returns: pointer to fresh piece of store containing sprintf'ed string
715*/
716
717uschar *
1ba28e2b 718string_sprintf(const char *format, ...)
059ec3d9 719{
d12746bc 720#ifdef COMPILE_UTILITY
059ec3d9 721uschar buffer[STRING_SPRINTF_BUFFER_SIZE];
d12746bc
JH
722gstring g = { .size = STRING_SPRINTF_BUFFER_SIZE, .ptr = 0, .s = buffer };
723gstring * gp = &g;
724#else
725gstring * gp = string_get(STRING_SPRINTF_BUFFER_SIZE);
726#endif
727gstring * gp2;
728va_list ap;
729
059ec3d9 730va_start(ap, format);
d12746bc
JH
731gp2 = string_vformat(gp, FALSE, format, ap);
732gp->s[gp->ptr] = '\0';
059ec3d9 733va_end(ap);
d12746bc
JH
734
735if (!gp2)
736 log_write(0, LOG_MAIN|LOG_PANIC_DIE,
737 "string_sprintf expansion was longer than %d; format string was (%s)\n"
738 "expansion started '%.32s'",
739 gp->size, format, gp->s);
740
741#ifdef COMPILE_UTILITY
742return string_copy(gp->s);
743#else
744gstring_reset_unused(gp);
745return gp->s;
746#endif
059ec3d9
PH
747}
748
749
750
751/*************************************************
752* Case-independent strncmp() function *
753*************************************************/
754
755/*
756Arguments:
757 s first string
758 t second string
759 n number of characters to compare
760
761Returns: < 0, = 0, or > 0, according to the comparison
762*/
763
764int
1ba28e2b 765strncmpic(const uschar *s, const uschar *t, int n)
059ec3d9
PH
766{
767while (n--)
768 {
769 int c = tolower(*s++) - tolower(*t++);
770 if (c) return c;
771 }
772return 0;
773}
774
775
776/*************************************************
777* Case-independent strcmp() function *
778*************************************************/
779
780/*
781Arguments:
782 s first string
783 t second string
784
785Returns: < 0, = 0, or > 0, according to the comparison
786*/
787
788int
1ba28e2b 789strcmpic(const uschar *s, const uschar *t)
059ec3d9
PH
790{
791while (*s != 0)
792 {
793 int c = tolower(*s++) - tolower(*t++);
794 if (c != 0) return c;
795 }
796return *t;
797}
798
799
800/*************************************************
801* Case-independent strstr() function *
802*************************************************/
803
804/* The third argument specifies whether whitespace is required
805to follow the matched string.
806
807Arguments:
808 s string to search
809 t substring to search for
810 space_follows if TRUE, match only if whitespace follows
811
812Returns: pointer to substring in string, or NULL if not found
813*/
814
815uschar *
816strstric(uschar *s, uschar *t, BOOL space_follows)
817{
818uschar *p = t;
819uschar *yield = NULL;
820int cl = tolower(*p);
821int cu = toupper(*p);
822
823while (*s)
824 {
825 if (*s == cl || *s == cu)
826 {
827 if (yield == NULL) yield = s;
828 if (*(++p) == 0)
829 {
830 if (!space_follows || s[1] == ' ' || s[1] == '\n' ) return yield;
831 yield = NULL;
832 p = t;
833 }
834 cl = tolower(*p);
835 cu = toupper(*p);
836 s++;
837 }
838 else if (yield != NULL)
839 {
840 yield = NULL;
841 p = t;
842 cl = tolower(*p);
843 cu = toupper(*p);
844 }
845 else s++;
846 }
847return NULL;
848}
849
850
851
d12746bc
JH
852#ifdef COMPILE_UTILITY
853/* Dummy version for this function; it should never be called */
854static void
855gstring_grow(gstring * g, int p, int count)
856{
857assert(FALSE);
858}
859#endif
860
861
862
059ec3d9
PH
863#ifndef COMPILE_UTILITY
864/*************************************************
865* Get next string from separated list *
866*************************************************/
867
868/* Leading and trailing space is removed from each item. The separator in the
869list is controlled by the int pointed to by the separator argument as follows:
870
ec95d1a6
PH
871 If the value is > 0 it is used as the separator. This is typically used for
872 sublists such as slash-separated options. The value is always a printing
873 character.
874
875 (If the value is actually > UCHAR_MAX there is only one item in the list.
059ec3d9
PH
876 This is used for some cases when called via functions that sometimes
877 plough through lists, and sometimes are given single items.)
059ec3d9 878
ec95d1a6
PH
879 If the value is <= 0, the string is inspected for a leading <x, where x is an
880 ispunct() or an iscntrl() character. If found, x is used as the separator. If
881 not found:
882
883 (a) if separator == 0, ':' is used
884 (b) if separator <0, -separator is used
885
886 In all cases the value of the separator that is used is written back to the
887 int so that it is used on subsequent calls as we progress through the list.
888
889A literal ispunct() separator can be represented in an item by doubling, but
890there is no way to include an iscntrl() separator as part of the data.
059ec3d9
PH
891
892Arguments:
893 listptr points to a pointer to the current start of the list; the
894 pointer gets updated to point after the end of the next item
895 separator a pointer to the separator character in an int (see above)
896 buffer where to put a copy of the next string in the list; or
897 NULL if the next string is returned in new memory
898 buflen when buffer is not NULL, the size of buffer; otherwise ignored
899
900Returns: pointer to buffer, containing the next substring,
901 or NULL if no more substrings
902*/
903
904uschar *
55414b25 905string_nextinlist(const uschar **listptr, int *separator, uschar *buffer, int buflen)
059ec3d9 906{
55414b25
JH
907int sep = *separator;
908const uschar *s = *listptr;
ec95d1a6 909BOOL sep_is_special;
059ec3d9 910
8b455685 911if (!s) return NULL;
ec95d1a6
PH
912
913/* This allows for a fixed specified separator to be an iscntrl() character,
914but at the time of implementation, this is never the case. However, it's best
915to be conservative. */
916
917while (isspace(*s) && *s != sep) s++;
918
919/* A change of separator is permitted, so look for a leading '<' followed by an
920allowed character. */
059ec3d9
PH
921
922if (sep <= 0)
923 {
ec95d1a6 924 if (*s == '<' && (ispunct(s[1]) || iscntrl(s[1])))
059ec3d9
PH
925 {
926 sep = s[1];
b72f857f 927 if (*++s) ++s;
ec95d1a6 928 while (isspace(*s) && *s != sep) s++;
059ec3d9
PH
929 }
930 else
8b455685 931 sep = sep ? -sep : ':';
059ec3d9
PH
932 *separator = sep;
933 }
934
ec95d1a6
PH
935/* An empty string has no list elements */
936
8b455685 937if (!*s) return NULL;
059ec3d9 938
ec95d1a6
PH
939/* Note whether whether or not the separator is an iscntrl() character. */
940
941sep_is_special = iscntrl(sep);
942
059ec3d9
PH
943/* Handle the case when a buffer is provided. */
944
617d3932 945if (buffer)
059ec3d9 946 {
d4ff61d1 947 int p = 0;
8b455685 948 for (; *s; s++)
059ec3d9 949 {
ec95d1a6 950 if (*s == sep && (*(++s) != sep || sep_is_special)) break;
059ec3d9
PH
951 if (p < buflen - 1) buffer[p++] = *s;
952 }
953 while (p > 0 && isspace(buffer[p-1])) p--;
8b455685 954 buffer[p] = '\0';
059ec3d9
PH
955 }
956
957/* Handle the case when a buffer is not provided. */
958
959else
960 {
55414b25 961 const uschar *ss;
acec9514 962 gstring * g = NULL;
ec95d1a6 963
059ec3d9 964 /* We know that *s != 0 at this point. However, it might be pointing to a
ec95d1a6
PH
965 separator, which could indicate an empty string, or (if an ispunct()
966 character) could be doubled to indicate a separator character as data at the
967 start of a string. Avoid getting working memory for an empty item. */
059ec3d9
PH
968
969 if (*s == sep)
970 {
971 s++;
ec95d1a6
PH
972 if (*s != sep || sep_is_special)
973 {
974 *listptr = s;
975 return string_copy(US"");
976 }
059ec3d9
PH
977 }
978
ec95d1a6
PH
979 /* Not an empty string; the first character is guaranteed to be a data
980 character. */
981
982 for (;;)
059ec3d9 983 {
8b455685 984 for (ss = s + 1; *ss && *ss != sep; ss++) ;
acec9514 985 g = string_catn(g, s, ss-s);
ec95d1a6 986 s = ss;
8b455685 987 if (!*s || *++s != sep || sep_is_special) break;
059ec3d9 988 }
acec9514
JH
989 while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
990 buffer = string_from_gstring(g);
617d3932 991 gstring_reset_unused(g);
059ec3d9
PH
992 }
993
994/* Update the current pointer and return the new string */
995
996*listptr = s;
997return buffer;
998}
059ec3d9
PH
999
1000
4226691b
JH
1001static const uschar *
1002Ustrnchr(const uschar * s, int c, unsigned * len)
1003{
1004unsigned siz = *len;
1005while (siz)
1006 {
1007 if (!*s) return NULL;
1008 if (*s == c)
1009 {
1010 *len = siz;
1011 return s;
1012 }
1013 s++;
1014 siz--;
1015 }
1016return NULL;
1017}
1018
1019
76146973 1020/************************************************
1d9ddac9 1021* Add element to separated list *
76146973 1022************************************************/
4226691b
JH
1023/* This function is used to build a list, returning an allocated null-terminated
1024growable string. The given element has any embedded separator characters
76146973
JH
1025doubled.
1026
4226691b
JH
1027Despite having the same growable-string interface as string_cat() the list is
1028always returned null-terminated.
1029
76146973 1030Arguments:
acec9514 1031 list expanding-string for the list that is being built, or NULL
76146973 1032 if this is a new list that has no contents yet
4c04137d
JS
1033 sep list separator character
1034 ele new element to be appended to the list
76146973
JH
1035
1036Returns: pointer to the start of the list, changed if copied for expansion.
1037*/
1038
acec9514
JH
1039gstring *
1040string_append_listele(gstring * list, uschar sep, const uschar * ele)
76146973 1041{
76146973
JH
1042uschar * sp;
1043
acec9514
JH
1044if (list && list->ptr)
1045 list = string_catn(list, &sep, 1);
76146973 1046
e3dd1d67 1047while((sp = Ustrchr(ele, sep)))
76146973 1048 {
acec9514
JH
1049 list = string_catn(list, ele, sp-ele+1);
1050 list = string_catn(list, &sep, 1);
76146973
JH
1051 ele = sp+1;
1052 }
acec9514
JH
1053list = string_cat(list, ele);
1054(void) string_from_gstring(list);
4226691b 1055return list;
76146973 1056}
00ba27c5
JH
1057
1058
acec9514
JH
1059gstring *
1060string_append_listele_n(gstring * list, uschar sep, const uschar * ele,
1061 unsigned len)
00ba27c5 1062{
00ba27c5
JH
1063const uschar * sp;
1064
acec9514
JH
1065if (list && list->ptr)
1066 list = string_catn(list, &sep, 1);
00ba27c5
JH
1067
1068while((sp = Ustrnchr(ele, sep, &len)))
1069 {
acec9514
JH
1070 list = string_catn(list, ele, sp-ele+1);
1071 list = string_catn(list, &sep, 1);
00ba27c5
JH
1072 ele = sp+1;
1073 len--;
1074 }
acec9514
JH
1075list = string_catn(list, ele, len);
1076(void) string_from_gstring(list);
4226691b 1077return list;
00ba27c5 1078}
76146973
JH
1079
1080
059ec3d9 1081
bce15b62
JH
1082/* A slightly-bogus listmaker utility; the separator is a string so
1083can be multiple chars - there is no checking for the element content
1084containing any of the separator. */
1085
1086gstring *
1087string_append2_listele_n(gstring * list, const uschar * sepstr,
1088 const uschar * ele, unsigned len)
1089{
bce15b62
JH
1090if (list && list->ptr)
1091 list = string_cat(list, sepstr);
1092
1093list = string_catn(list, ele, len);
1094(void) string_from_gstring(list);
1095return list;
1096}
1097
1098
1099
acec9514
JH
1100/************************************************/
1101/* Create a growable-string with some preassigned space */
1102
1103gstring *
1104string_get(unsigned size)
1105{
1106gstring * g = store_get(sizeof(gstring) + size);
1107g->size = size;
1108g->ptr = 0;
1109g->s = US(g + 1);
1110return g;
1111}
1112
1113/* NUL-terminate the C string in the growable-string, and return it. */
1114
1115uschar *
1116string_from_gstring(gstring * g)
1117{
1118if (!g) return NULL;
1119g->s[g->ptr] = '\0';
1120return g->s;
1121}
1122
617d3932
JH
1123void
1124gstring_reset_unused(gstring * g)
1125{
1126store_reset(g->s + (g->size = g->ptr + 1));
1127}
1128
059ec3d9 1129
d12746bc
JH
1130/* Add more space to a growable-string.
1131
1132Arguments:
1133 g the growable-string
938593e9
JH
1134 p current end of data
1135 count amount to grow by
1136*/
1137
1138static void
acec9514
JH
1139gstring_grow(gstring * g, int p, int count)
1140{
1141int oldsize = g->size;
1142
1143/* Mostly, string_cat() is used to build small strings of a few hundred
1144characters at most. There are times, however, when the strings are very much
1145longer (for example, a lookup that returns a vast number of alias addresses).
1146To try to keep things reasonable, we use increments whose size depends on the
1147existing length of the string. */
1148
1149unsigned inc = oldsize < 4096 ? 127 : 1023;
1150g->size = ((p + count + inc) & ~inc) + 1;
1151
1152/* Try to extend an existing allocation. If the result of calling
1153store_extend() is false, either there isn't room in the current memory block,
1154or this string is not the top item on the dynamic store stack. We then have
1155to get a new chunk of store and copy the old string. When building large
1156strings, it is helpful to call store_release() on the old string, to release
1157memory blocks that have become empty. (The block will be freed if the string
1158is at its start.) However, we can do this only if we know that the old string
1159was the last item on the dynamic memory stack. This is the case if it matches
1160store_last_get. */
1161
1162if (!store_extend(g->s, oldsize, g->size))
459fca58 1163 g->s = store_newblock(g->s, g->size, p);
acec9514
JH
1164}
1165
1166
1167
d12746bc
JH
1168/*************************************************
1169* Add chars to string *
1170*************************************************/
059ec3d9
PH
1171/* This function is used when building up strings of unknown length. Room is
1172always left for a terminating zero to be added to the string that is being
1173built. This function does not require the string that is being added to be NUL
1174terminated, because the number of characters to add is given explicitly. It is
1175sometimes called to extract parts of other strings.
1176
1177Arguments:
1178 string points to the start of the string that is being built, or NULL
1179 if this is a new string that has no contents yet
059ec3d9
PH
1180 s points to characters to add
1181 count count of characters to add; must not exceed the length of s, if s
42055a33 1182 is a C string.
059ec3d9 1183
059ec3d9
PH
1184Returns: pointer to the start of the string, changed if copied for expansion.
1185 Note that a NUL is not added, though space is left for one. This is
1186 because string_cat() is often called multiple times to build up a
1187 string - there's no point adding the NUL till the end.
a1b8a755 1188
059ec3d9 1189*/
96f5fe4c 1190/* coverity[+alloc] */
059ec3d9 1191
acec9514
JH
1192gstring *
1193string_catn(gstring * g, const uschar *s, int count)
059ec3d9 1194{
acec9514 1195int p;
059ec3d9 1196
acec9514 1197if (!g)
059ec3d9 1198 {
acec9514
JH
1199 unsigned inc = count < 4096 ? 127 : 1023;
1200 unsigned size = ((count + inc) & ~inc) + 1;
1201 g = string_get(size);
059ec3d9
PH
1202 }
1203
acec9514
JH
1204p = g->ptr;
1205if (p + count >= g->size)
1206 gstring_grow(g, p, count);
1207
059ec3d9
PH
1208/* Because we always specify the exact number of characters to copy, we can
1209use memcpy(), which is likely to be more efficient than strncopy() because the
acec9514 1210latter has to check for zero bytes. */
059ec3d9 1211
acec9514
JH
1212memcpy(g->s + p, s, count);
1213g->ptr = p + count;
1214return g;
059ec3d9 1215}
2600301b
HSHR
1216
1217
acec9514
JH
1218gstring *
1219string_cat(gstring *string, const uschar *s)
c2f669a4 1220{
acec9514 1221return string_catn(string, s, Ustrlen(s));
c2f669a4 1222}
059ec3d9
PH
1223
1224
1225
059ec3d9
PH
1226/*************************************************
1227* Append strings to another string *
1228*************************************************/
1229
1230/* This function can be used to build a string from many other strings.
1231It calls string_cat() to do the dirty work.
1232
1233Arguments:
acec9514 1234 string expanding-string that is being built, or NULL
059ec3d9 1235 if this is a new string that has no contents yet
059ec3d9
PH
1236 count the number of strings to append
1237 ... "count" uschar* arguments, which must be valid zero-terminated
1238 C strings
1239
1240Returns: pointer to the start of the string, changed if copied for expansion.
1241 The string is not zero-terminated - see string_cat() above.
1242*/
1243
acec9514
JH
1244__inline__ gstring *
1245string_append(gstring *string, int count, ...)
059ec3d9
PH
1246{
1247va_list ap;
059ec3d9
PH
1248
1249va_start(ap, count);
acec9514 1250while (count-- > 0)
059ec3d9
PH
1251 {
1252 uschar *t = va_arg(ap, uschar *);
acec9514 1253 string = string_cat(string, t);
059ec3d9
PH
1254 }
1255va_end(ap);
1256
1257return string;
1258}
1259#endif
1260
1261
1262
1263/*************************************************
1264* Format a string with length checks *
1265*************************************************/
1266
1267/* This function is used to format a string with checking of the length of the
1268output for all conversions. It protects Exim from absent-mindedness when
1269calling functions like debug_printf and string_sprintf, and elsewhere. There
1270are two different entry points to what is actually the same function, depending
1271on whether the variable length list of data arguments are given explicitly or
1272as a va_list item.
1273
1274The formats are the usual printf() ones, with some omissions (never used) and
c0b9d3e8 1275three additions for strings: %S forces lower case, %T forces upper case, and
acec9514 1276%#s or %#S prints nothing for a NULL string. Without the # "NULL" is printed
c0b9d3e8
JH
1277(useful in debugging). There is also the addition of %D and %M, which insert
1278the date in the form used for datestamped log files.
059ec3d9
PH
1279
1280Arguments:
1281 buffer a buffer in which to put the formatted string
1282 buflen the length of the buffer
1283 format the format string - deliberately char * and not uschar *
1284 ... or ap variable list of supplementary arguments
1285
1286Returns: TRUE if the result fitted in the buffer
1287*/
1288
1289BOOL
d12746bc 1290string_format(uschar * buffer, int buflen, const char * format, ...)
059ec3d9 1291{
d12746bc 1292gstring g = { .size = buflen, .ptr = 0, .s = buffer }, *gp;
059ec3d9
PH
1293va_list ap;
1294va_start(ap, format);
d12746bc 1295gp = string_vformat(&g, FALSE, format, ap);
059ec3d9 1296va_end(ap);
d12746bc
JH
1297g.s[g.ptr] = '\0';
1298return !!gp;
059ec3d9
PH
1299}
1300
1301
d12746bc
JH
1302
1303
1304
1305/* Bulid or append to a growing-string, sprintf-style.
1306
1307If the "extend" argument is true, the string passed in can be NULL,
1308empty, or non-empty.
1309
1310If the "extend" argument is false, the string passed in may not be NULL,
1311will not be grown, and is usable in the original place after return.
1312The return value can be NULL to signify overflow.
1313
1314Returns the possibly-new (if copy for growth was needed) string,
1315not nul-terminated.
1316*/
1317
1318gstring *
1319string_vformat(gstring * g, BOOL extend, const char *format, va_list ap)
059ec3d9 1320{
d12746bc
JH
1321enum ltypes { L_NORMAL=1, L_SHORT=2, L_LONG=3, L_LONGLONG=4, L_LONGDOUBLE=5, L_SIZE=6 };
1322
1323int width, precision, off, lim;
1324const char * fp = format; /* Deliberately not unsigned */
b1c749bb 1325
d12746bc
JH
1326string_datestamp_offset = -1; /* Datestamp not inserted */
1327string_datestamp_length = 0; /* Datestamp not inserted */
1328string_datestamp_type = 0; /* Datestamp not inserted */
059ec3d9 1329
d12746bc
JH
1330#ifdef COMPILE_UTILITY
1331assert(!extend);
1332assert(g);
1333#else
1334
1335/* Ensure we have a string, to save on checking later */
1336if (!g) g = string_get(16);
1337#endif /*!COMPILE_UTILITY*/
1338
1339lim = g->size - 1; /* leave one for a nul */
1340off = g->ptr; /* remember initial offset in gstring */
059ec3d9
PH
1341
1342/* Scan the format and handle the insertions */
1343
d12746bc 1344while (*fp)
059ec3d9 1345 {
b1c749bb 1346 int length = L_NORMAL;
059ec3d9
PH
1347 int *nptr;
1348 int slen;
d12746bc
JH
1349 const char *null = "NULL"; /* ) These variables */
1350 const char *item_start, *s; /* ) are deliberately */
1351 char newformat[16]; /* ) not unsigned */
1352 char * gp = CS g->s + g->ptr; /* ) */
059ec3d9
PH
1353
1354 /* Non-% characters just get copied verbatim */
1355
1356 if (*fp != '%')
1357 {
d12746bc
JH
1358 /* Avoid string_copyn() due to COMPILE_UTILITY */
1359 if (g->ptr >= lim - 1)
1100a343
JH
1360 {
1361 if (!extend) return NULL;
1362 gstring_grow(g, g->ptr, 1);
1363 lim = g->size - 1;
1364 }
d12746bc 1365 g->s[g->ptr++] = (uschar) *fp++;
059ec3d9
PH
1366 continue;
1367 }
1368
1369 /* Deal with % characters. Pick off the width and precision, for checking
1370 strings, skipping over the flag and modifier characters. */
1371
1372 item_start = fp;
1373 width = precision = -1;
1374
1375 if (strchr("-+ #0", *(++fp)) != NULL)
1376 {
1377 if (*fp == '#') null = "";
1378 fp++;
1379 }
1380
1381 if (isdigit((uschar)*fp))
1382 {
1383 width = *fp++ - '0';
1384 while (isdigit((uschar)*fp)) width = width * 10 + *fp++ - '0';
1385 }
1386 else if (*fp == '*')
1387 {
1388 width = va_arg(ap, int);
1389 fp++;
1390 }
1391
1392 if (*fp == '.')
059ec3d9
PH
1393 if (*(++fp) == '*')
1394 {
1395 precision = va_arg(ap, int);
1396 fp++;
1397 }
1398 else
d12746bc
JH
1399 for (precision = 0; isdigit((uschar)*fp); fp++)
1400 precision = precision*10 + *fp - '0';
059ec3d9 1401
91a246f6 1402 /* Skip over 'h', 'L', 'l', 'll' and 'z', remembering the item length */
b1c749bb
PH
1403
1404 if (*fp == 'h')
1405 { fp++; length = L_SHORT; }
1406 else if (*fp == 'L')
1407 { fp++; length = L_LONGDOUBLE; }
1408 else if (*fp == 'l')
b1c749bb 1409 if (fp[1] == 'l')
d12746bc 1410 { fp += 2; length = L_LONGLONG; }
b1c749bb 1411 else
d12746bc 1412 { fp++; length = L_LONG; }
91a246f6
PP
1413 else if (*fp == 'z')
1414 { fp++; length = L_SIZE; }
059ec3d9
PH
1415
1416 /* Handle each specific format type. */
1417
1418 switch (*fp++)
1419 {
1420 case 'n':
d12746bc
JH
1421 nptr = va_arg(ap, int *);
1422 *nptr = g->ptr - off;
1423 break;
059ec3d9
PH
1424
1425 case 'd':
1426 case 'o':
1427 case 'u':
1428 case 'x':
1429 case 'X':
d12746bc
JH
1430 width = length > L_LONG ? 24 : 12;
1431 if (g->ptr >= lim - width)
1100a343
JH
1432 {
1433 if (!extend) return NULL;
1434 gstring_grow(g, g->ptr, width);
1435 lim = g->size - 1;
1436 gp = CS g->s + g->ptr;
1437 }
d12746bc
JH
1438 strncpy(newformat, item_start, fp - item_start);
1439 newformat[fp - item_start] = 0;
b1c749bb 1440
d12746bc
JH
1441 /* Short int is promoted to int when passing through ..., so we must use
1442 int for va_arg(). */
b1c749bb 1443
d12746bc
JH
1444 switch(length)
1445 {
1446 case L_SHORT:
1447 case L_NORMAL:
1448 g->ptr += sprintf(gp, newformat, va_arg(ap, int)); break;
1449 case L_LONG:
1450 g->ptr += sprintf(gp, newformat, va_arg(ap, long int)); break;
1451 case L_LONGLONG:
1452 g->ptr += sprintf(gp, newformat, va_arg(ap, LONGLONG_T)); break;
1453 case L_SIZE:
1454 g->ptr += sprintf(gp, newformat, va_arg(ap, size_t)); break;
1455 }
1456 break;
059ec3d9
PH
1457
1458 case 'p':
2e8db779
JH
1459 {
1460 void * ptr;
d12746bc 1461 if (g->ptr >= lim - 24)
1100a343
JH
1462 {
1463 if (!extend) return NULL;
1464 gstring_grow(g, g->ptr, 24);
1465 lim = g->size - 1;
1466 gp = CS g->s + g->ptr;
1467 }
81f358da
JH
1468 /* sprintf() saying "(nil)" for a null pointer seems unreliable.
1469 Handle it explicitly. */
2e8db779
JH
1470 if ((ptr = va_arg(ap, void *)))
1471 {
1472 strncpy(newformat, item_start, fp - item_start);
1473 newformat[fp - item_start] = 0;
d12746bc 1474 g->ptr += sprintf(gp, newformat, ptr);
2e8db779
JH
1475 }
1476 else
d12746bc 1477 g->ptr += sprintf(gp, "(nil)");
2e8db779 1478 }
059ec3d9
PH
1479 break;
1480
1481 /* %f format is inherently insecure if the numbers that it may be
870f6ba8
TF
1482 handed are unknown (e.g. 1e300). However, in Exim, %f is used for
1483 printing load averages, and these are actually stored as integers
1484 (load average * 1000) so the size of the numbers is constrained.
1485 It is also used for formatting sending rates, where the simplicity
1486 of the format prevents overflow. */
059ec3d9
PH
1487
1488 case 'f':
1489 case 'e':
1490 case 'E':
1491 case 'g':
1492 case 'G':
d12746bc
JH
1493 if (precision < 0) precision = 6;
1494 if (g->ptr >= lim - precision - 8)
1100a343
JH
1495 {
1496 if (!extend) return NULL;
1497 gstring_grow(g, g->ptr, precision+8);
1498 lim = g->size - 1;
1499 gp = CS g->s + g->ptr;
1500 }
d12746bc
JH
1501 strncpy(newformat, item_start, fp - item_start);
1502 newformat[fp-item_start] = 0;
1503 if (length == L_LONGDOUBLE)
1504 g->ptr += sprintf(gp, newformat, va_arg(ap, long double));
1505 else
1506 g->ptr += sprintf(gp, newformat, va_arg(ap, double));
1507 break;
059ec3d9
PH
1508
1509 /* String types */
1510
1511 case '%':
d12746bc 1512 if (g->ptr >= lim - 1)
1100a343
JH
1513 {
1514 if (!extend) return NULL;
1515 gstring_grow(g, g->ptr, 1);
1516 lim = g->size - 1;
1517 }
d12746bc
JH
1518 g->s[g->ptr++] = (uschar) '%';
1519 break;
059ec3d9
PH
1520
1521 case 'c':
d12746bc 1522 if (g->ptr >= lim - 1)
1100a343
JH
1523 {
1524 if (!extend) return NULL;
1525 gstring_grow(g, g->ptr, 1);
1526 lim = g->size - 1;
1527 }
d12746bc
JH
1528 g->s[g->ptr++] = (uschar) va_arg(ap, int);
1529 break;
059ec3d9 1530
f1e5fef5 1531 case 'D': /* Insert daily datestamp for log file names */
d12746bc
JH
1532 s = CS tod_stamp(tod_log_datestamp_daily);
1533 string_datestamp_offset = g->ptr; /* Passed back via global */
1534 string_datestamp_length = Ustrlen(s); /* Passed back via global */
1535 string_datestamp_type = tod_log_datestamp_daily;
1536 slen = string_datestamp_length;
1537 goto INSERT_STRING;
f1e5fef5
PP
1538
1539 case 'M': /* Insert monthly datestamp for log file names */
d12746bc
JH
1540 s = CS tod_stamp(tod_log_datestamp_monthly);
1541 string_datestamp_offset = g->ptr; /* Passed back via global */
1542 string_datestamp_length = Ustrlen(s); /* Passed back via global */
1543 string_datestamp_type = tod_log_datestamp_monthly;
1544 slen = string_datestamp_length;
1545 goto INSERT_STRING;
059ec3d9
PH
1546
1547 case 's':
1548 case 'S': /* Forces *lower* case */
c0b9d3e8 1549 case 'T': /* Forces *upper* case */
d12746bc 1550 s = va_arg(ap, char *);
059ec3d9 1551
d12746bc
JH
1552 if (!s) s = null;
1553 slen = Ustrlen(s);
059ec3d9 1554
f1e5fef5
PP
1555 INSERT_STRING: /* Come to from %D or %M above */
1556
059ec3d9 1557 {
d12746bc 1558 BOOL truncated = FALSE;
059ec3d9 1559
d12746bc
JH
1560 /* If the width is specified, check that there is a precision
1561 set; if not, set it to the width to prevent overruns of long
1562 strings. */
059ec3d9 1563
d12746bc
JH
1564 if (width >= 0)
1565 {
1566 if (precision < 0) precision = width;
1567 }
059ec3d9 1568
d12746bc
JH
1569 /* If a width is not specified and the precision is specified, set
1570 the width to the precision, or the string length if shorted. */
059ec3d9 1571
d12746bc
JH
1572 else if (precision >= 0)
1573 width = precision < slen ? precision : slen;
059ec3d9 1574
d12746bc 1575 /* If neither are specified, set them both to the string length. */
059ec3d9 1576
d12746bc
JH
1577 else
1578 width = precision = slen;
1579
1580 if (!extend)
1581 {
1582 if (g->ptr == lim) return NULL;
1583 if (g->ptr >= lim - width)
1584 {
1585 truncated = TRUE;
1586 width = precision = lim - g->ptr - 1;
1587 if (width < 0) width = 0;
1588 if (precision < 0) precision = 0;
1589 }
1590 }
1591 else if (g->ptr >= lim - width)
1100a343
JH
1592 {
1593 gstring_grow(g, g->ptr, width - (lim - g->ptr));
1594 lim = g->size - 1;
1595 gp = CS g->s + g->ptr;
1596 }
d12746bc
JH
1597
1598 g->ptr += sprintf(gp, "%*.*s", width, precision, s);
1599 if (fp[-1] == 'S')
1600 while (*gp) { *gp = tolower(*gp); gp++; }
1601 else if (fp[-1] == 'T')
1602 while (*gp) { *gp = toupper(*gp); gp++; }
1603
1604 if (truncated) return NULL;
1605 break;
059ec3d9 1606 }
059ec3d9
PH
1607
1608 /* Some things are never used in Exim; also catches junk. */
1609
1610 default:
d12746bc
JH
1611 strncpy(newformat, item_start, fp - item_start);
1612 newformat[fp-item_start] = 0;
1613 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "string_format: unsupported type "
1614 "in \"%s\" in \"%s\"", newformat, format);
1615 break;
059ec3d9
PH
1616 }
1617 }
1618
d12746bc
JH
1619return g;
1620}
059ec3d9 1621
059ec3d9 1622
d12746bc
JH
1623
1624#ifndef COMPILE_UTILITY
1625
1626gstring *
1627string_fmt_append(gstring * g, const char *format, ...)
1628{
1629va_list ap;
1630va_start(ap, format);
1631g = string_vformat(g, TRUE, format, ap);
1632va_end(ap);
1633return g;
059ec3d9
PH
1634}
1635
1636
1637
059ec3d9
PH
1638/*************************************************
1639* Generate an "open failed" message *
1640*************************************************/
1641
1642/* This function creates a message after failure to open a file. It includes a
1643string supplied as data, adds the strerror() text, and if the failure was
1644"Permission denied", reads and includes the euid and egid.
1645
1646Arguments:
1647 eno the value of errno after the failure
1648 format a text format string - deliberately not uschar *
1649 ... arguments for the format string
1650
1651Returns: a message, in dynamic store
1652*/
1653
1654uschar *
1ba28e2b 1655string_open_failed(int eno, const char *format, ...)
059ec3d9
PH
1656{
1657va_list ap;
d12746bc 1658gstring * g = string_get(1024);
059ec3d9 1659
d12746bc 1660g = string_catn(g, US"failed to open ", 15);
059ec3d9
PH
1661
1662/* Use the checked formatting routine to ensure that the buffer
1663does not overflow. It should not, since this is called only for internally
1664specified messages. If it does, the message just gets truncated, and there
1665doesn't seem much we can do about that. */
1666
d12746bc
JH
1667va_start(ap, format);
1668(void) string_vformat(g, FALSE, format, ap);
1669string_from_gstring(g);
1670gstring_reset_unused(g);
cb570b5e 1671va_end(ap);
059ec3d9 1672
d12746bc
JH
1673return eno == EACCES
1674 ? string_sprintf("%s: %s (euid=%ld egid=%ld)", g->s, strerror(eno),
1675 (long int)geteuid(), (long int)getegid())
1676 : string_sprintf("%s: %s", g->s, strerror(eno));
059ec3d9
PH
1677}
1678#endif /* COMPILE_UTILITY */
1679
1680
1681
059ec3d9
PH
1682
1683
bc3c7bb7
HSHR
1684#ifndef COMPILE_UTILITY
1685/* qsort(3), currently used to sort the environment variables
1686for -bP environment output, needs a function to compare two pointers to string
1687pointers. Here it is. */
1688
1689int
84bbb4d8 1690string_compare_by_pointer(const void *a, const void *b)
bc3c7bb7 1691{
35a5627d 1692return Ustrcmp(* CUSS a, * CUSS b);
bc3c7bb7
HSHR
1693}
1694#endif /* COMPILE_UTILITY */
059ec3d9
PH
1695
1696
1697
d12746bc 1698
059ec3d9
PH
1699/*************************************************
1700**************************************************
1701* Stand-alone test program *
1702**************************************************
1703*************************************************/
1704
1705#ifdef STAND_ALONE
1706int main(void)
1707{
1708uschar buffer[256];
1709
1710printf("Testing is_ip_address\n");
1711
1712while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
1713 {
1714 int offset;
1715 buffer[Ustrlen(buffer) - 1] = 0;
1716 printf("%d\n", string_is_ip_address(buffer, NULL));
1717 printf("%d %d %s\n", string_is_ip_address(buffer, &offset), offset, buffer);
1718 }
1719
1720printf("Testing string_nextinlist\n");
1721
1722while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
1723 {
1724 uschar *list = buffer;
1725 uschar *lp1, *lp2;
1726 uschar item[256];
1727 int sep1 = 0;
1728 int sep2 = 0;
1729
1730 if (*list == '<')
1731 {
1732 sep1 = sep2 = list[1];
1733 list += 2;
1734 }
1735
1736 lp1 = lp2 = list;
1737 for (;;)
1738 {
1739 uschar *item1 = string_nextinlist(&lp1, &sep1, item, sizeof(item));
1740 uschar *item2 = string_nextinlist(&lp2, &sep2, NULL, 0);
1741
1742 if (item1 == NULL && item2 == NULL) break;
1743 if (item == NULL || item2 == NULL || Ustrcmp(item1, item2) != 0)
1744 {
1745 printf("***ERROR\nitem1=\"%s\"\nitem2=\"%s\"\n",
1746 (item1 == NULL)? "NULL" : CS item1,
1747 (item2 == NULL)? "NULL" : CS item2);
1748 break;
1749 }
1750 else printf(" \"%s\"\n", CS item1);
1751 }
1752 }
1753
1754/* This is a horrible lash-up, but it serves its purpose. */
1755
1756printf("Testing string_format\n");
1757
1758while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
1759 {
1760 void *args[3];
ed72ace5 1761 long long llargs[3];
059ec3d9
PH
1762 double dargs[3];
1763 int dflag = 0;
ed72ace5 1764 int llflag = 0;
059ec3d9
PH
1765 int n = 0;
1766 int count;
1767 int countset = 0;
1768 uschar format[256];
1769 uschar outbuf[256];
1770 uschar *s;
1771 buffer[Ustrlen(buffer) - 1] = 0;
1772
1773 s = Ustrchr(buffer, ',');
1774 if (s == NULL) s = buffer + Ustrlen(buffer);
1775
1776 Ustrncpy(format, buffer, s - buffer);
1777 format[s-buffer] = 0;
1778
1779 if (*s == ',') s++;
1780
1781 while (*s != 0)
1782 {
1783 uschar *ss = s;
1784 s = Ustrchr(ss, ',');
1785 if (s == NULL) s = ss + Ustrlen(ss);
1786
1787 if (isdigit(*ss))
1788 {
1789 Ustrncpy(outbuf, ss, s-ss);
1790 if (Ustrchr(outbuf, '.') != NULL)
1791 {
1792 dflag = 1;
1793 dargs[n++] = Ustrtod(outbuf, NULL);
1794 }
ed72ace5
PH
1795 else if (Ustrstr(outbuf, "ll") != NULL)
1796 {
1797 llflag = 1;
1798 llargs[n++] = strtoull(CS outbuf, NULL, 10);
1799 }
059ec3d9
PH
1800 else
1801 {
1802 args[n++] = (void *)Uatoi(outbuf);
1803 }
1804 }
1805
1806 else if (Ustrcmp(ss, "*") == 0)
1807 {
1808 args[n++] = (void *)(&count);
1809 countset = 1;
1810 }
1811
1812 else
1813 {
1814 uschar *sss = malloc(s - ss + 1);
1815 Ustrncpy(sss, ss, s-ss);
1816 args[n++] = sss;
1817 }
1818
1819 if (*s == ',') s++;
1820 }
1821
ed72ace5
PH
1822 if (!dflag && !llflag)
1823 printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format,
1824 args[0], args[1], args[2])? "True" : "False");
1825
1826 else if (dflag)
1827 printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format,
1828 dargs[0], dargs[1], dargs[2])? "True" : "False");
059ec3d9
PH
1829
1830 else printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format,
ed72ace5 1831 llargs[0], llargs[1], llargs[2])? "True" : "False");
059ec3d9
PH
1832
1833 printf("%s\n", CS outbuf);
1834 if (countset) printf("count=%d\n", count);
1835 }
1836
1837return 0;
1838}
1839#endif
1840
1841/* End of string.c */