X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e28326d8a5aad335b724b9ff1e5222c914e56143..23ecb73de01ae47e2282790a75c7e07114bd5702:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index b52d4ab95..1c1f2dd83 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/string.c,v 1.12 2007/02/07 11:24:56 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ /* Miscellaneous string-handling functions. Some are not required for @@ -641,7 +639,7 @@ Returns: pointer to fresh piece of store containing sprintf'ed string */ uschar * -string_sprintf(char *format, ...) +string_sprintf(const char *format, ...) { va_list ap; uschar buffer[STRING_SPRINTF_BUFFER_SIZE]; @@ -669,7 +667,7 @@ Returns: < 0, = 0, or > 0, according to the comparison */ int -strncmpic(uschar *s, uschar *t, int n) +strncmpic(const uschar *s, const uschar *t, int n) { while (n--) { @@ -693,7 +691,7 @@ Returns: < 0, = 0, or > 0, according to the comparison */ int -strcmpic(uschar *s, uschar *t) +strcmpic(const uschar *s, const uschar *t) { while (*s != 0) { @@ -764,19 +762,26 @@ return NULL; /* Leading and trailing space is removed from each item. The separator in the list is controlled by the int pointed to by the separator argument as follows: - If its value is > 0 it is used as the delimiter. - (If its value is actually > UCHAR_MAX there is only one item in the list. + If the value is > 0 it is used as the separator. This is typically used for + sublists such as slash-separated options. The value is always a printing + character. + + (If the value is actually > UCHAR_MAX there is only one item in the list. This is used for some cases when called via functions that sometimes plough through lists, and sometimes are given single items.) - If its value is <= 0, the string is inspected for a leading 0 && isspace(buffer[p-1])) p--; @@ -834,31 +854,37 @@ if (buffer != NULL) else { + int size = 0; + int ptr = 0; + uschar *ss; + /* We know that *s != 0 at this point. However, it might be pointing to a - separator, which could indicate an empty string, or could be doubled to - indicate a separator character as data at the start of a string. */ + separator, which could indicate an empty string, or (if an ispunct() + character) could be doubled to indicate a separator character as data at the + start of a string. Avoid getting working memory for an empty item. */ if (*s == sep) { s++; - if (*s != sep) buffer = string_copy(US""); + if (*s != sep || sep_is_special) + { + *listptr = s; + return string_copy(US""); + } } - if (buffer == NULL) + /* Not an empty string; the first character is guaranteed to be a data + character. */ + + for (;;) { - int size = 0; - int ptr = 0; - uschar *ss; - for (;;) - { - for (ss = s + 1; *ss != 0 && *ss != sep; ss++); - buffer = string_cat(buffer, &size, &ptr, s, ss-s); - s = ss; - if (*s == 0 || *(++s) != sep) break; - } - while (ptr > 0 && isspace(buffer[ptr-1])) ptr--; - buffer[ptr] = 0; + for (ss = s + 1; *ss != 0 && *ss != sep; ss++); + buffer = string_cat(buffer, &size, &ptr, s, ss-s); + s = ss; + if (*s == 0 || *(++s) != sep || sep_is_special) break; } + while (ptr > 0 && isspace(buffer[ptr-1])) ptr--; + buffer[ptr] = 0; } /* Update the current pointer and return the new string */ @@ -1011,7 +1037,7 @@ as a va_list item. The formats are the usual printf() ones, with some omissions (never used) and two additions for strings: %S forces lower case, and %#s or %#S prints nothing for a NULL string. Without the # "NULL" is printed (useful in debugging). There -is also the addition of %D, which inserts the date in the form used for +is also the addition of %D and %M, which insert the date in the form used for datestamped log files. Arguments: @@ -1024,7 +1050,7 @@ Returns: TRUE if the result fitted in the buffer */ BOOL -string_format(uschar *buffer, int buflen, char *format, ...) +string_format(uschar *buffer, int buflen, const char *format, ...) { BOOL yield; va_list ap; @@ -1036,17 +1062,19 @@ return yield; BOOL -string_vformat(uschar *buffer, int buflen, char *format, va_list ap) +string_vformat(uschar *buffer, int buflen, const char *format, va_list ap) { enum { L_NORMAL, L_SHORT, L_LONG, L_LONGLONG, L_LONGDOUBLE }; BOOL yield = TRUE; int width, precision; -char *fp = format; /* Deliberately not unsigned */ +const char *fp = format; /* Deliberately not unsigned */ uschar *p = buffer; uschar *last = buffer + buflen - 1; string_datestamp_offset = -1; /* Datestamp not inserted */ +string_datestamp_length = 0; /* Datestamp not inserted */ +string_datestamp_type = 0; /* Datestamp not inserted */ /* Scan the format and handle the insertions */ @@ -1055,8 +1083,8 @@ while (*fp != 0) int length = L_NORMAL; int *nptr; int slen; - char *null = "NULL"; /* ) These variables */ - char *item_start, *s; /* ) are deliberately */ + const char *null = "NULL"; /* ) These variables */ + const char *item_start, *s; /* ) are deliberately */ char newformat[16]; /* ) not unsigned */ /* Non-% characters just get copied verbatim */ @@ -1201,19 +1229,31 @@ while (*fp != 0) *p++ = va_arg(ap, int); break; - case 'D': /* Insert datestamp for log file names */ - s = CS tod_stamp(tod_log_datestamp); + case 'D': /* Insert daily datestamp for log file names */ + s = CS tod_stamp(tod_log_datestamp_daily); + string_datestamp_offset = p - buffer; /* Passed back via global */ + string_datestamp_length = Ustrlen(s); /* Passed back via global */ + string_datestamp_type = tod_log_datestamp_daily; + slen = string_datestamp_length; + goto INSERT_STRING; + + case 'M': /* Insert monthly datestamp for log file names */ + s = CS tod_stamp(tod_log_datestamp_monthly); string_datestamp_offset = p - buffer; /* Passed back via global */ + string_datestamp_length = Ustrlen(s); /* Passed back via global */ + string_datestamp_type = tod_log_datestamp_monthly; + slen = string_datestamp_length; goto INSERT_STRING; case 's': case 'S': /* Forces *lower* case */ s = va_arg(ap, char *); - INSERT_STRING: /* Come to from %D above */ if (s == NULL) s = null; slen = Ustrlen(s); + INSERT_STRING: /* Come to from %D or %M above */ + /* If the width is specified, check that there is a precision set; if not, set it to the width to prevent overruns of long strings. */ @@ -1239,10 +1279,17 @@ while (*fp != 0) not OK, add part of the string (debugging uses this to show as much as possible). */ + if (p == last) + { + yield = FALSE; + goto END_FORMAT; + } if (p >= last - width) { yield = FALSE; width = precision = last - p - 1; + if (width < 0) width = 0; + if (precision < 0) precision = 0; } sprintf(CS p, "%*.*s", width, precision, s); if (fp[-1] == 'S') @@ -1291,7 +1338,7 @@ Returns: a message, in dynamic store */ uschar * -string_open_failed(int eno, char *format, ...) +string_open_failed(int eno, const char *format, ...) { va_list ap; uschar buffer[1024];