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