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