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