X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/1688f43b3071b3b4d7d3a88a6ccf28c1bc3272e0..1ba28e2b955b005ce4825fec792df17f75a8de1e:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index 2fe57b303..d501453c7 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/string.c,v 1.9 2006/02/13 11:13:37 ph10 Exp $ */ +/* $Cambridge: exim/src/src/string.c,v 1.15 2009/11/16 19:50:37 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* 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 @@ -449,6 +449,67 @@ return ss; +/************************************************* +* Copy string if long, inserting newlines * +*************************************************/ + +/* If the given string is longer than 75 characters, it is copied, and within +the copy, certain space characters are converted into newlines. + +Argument: pointer to the string +Returns: pointer to the possibly altered string +*/ + +uschar * +string_split_message(uschar *msg) +{ +uschar *s, *ss; + +if (msg == NULL || Ustrlen(msg) <= 75) return msg; +s = ss = msg = string_copy(msg); + +for (;;) + { + int i = 0; + while (i < 75 && *ss != 0 && *ss != '\n') ss++, i++; + if (*ss == 0) break; + if (*ss == '\n') + s = ++ss; + else + { + uschar *t = ss + 1; + uschar *tt = NULL; + while (--t > s + 35) + { + if (*t == ' ') + { + if (t[-1] == ':') { tt = t; break; } + if (tt == NULL) tt = t; + } + } + + if (tt == NULL) /* Can't split behind - try ahead */ + { + t = ss + 1; + while (*t != 0) + { + if (*t == ' ' || *t == '\n') + { tt = t; break; } + t++; + } + } + + if (tt == NULL) break; /* Can't find anywhere to split */ + *tt = '\n'; + s = ss = tt+1; + } + } + +return msg; +} + + + /************************************************* * Copy returned DNS domain name, de-escaping * *************************************************/ @@ -580,7 +641,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]; @@ -608,7 +669,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--) { @@ -632,7 +693,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) { @@ -703,19 +764,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--; @@ -773,31 +856,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 */ @@ -950,7 +1039,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: @@ -963,7 +1052,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; @@ -975,17 +1064,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 */ @@ -994,8 +1085,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 */ @@ -1140,19 +1231,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. */ @@ -1178,10 +1281,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') @@ -1230,7 +1340,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]; @@ -1472,8 +1582,10 @@ printf("Testing string_format\n"); while (fgets(CS buffer, sizeof(buffer), stdin) != NULL) { void *args[3]; + long long llargs[3]; double dargs[3]; int dflag = 0; + int llflag = 0; int n = 0; int count; int countset = 0; @@ -1504,6 +1616,11 @@ while (fgets(CS buffer, sizeof(buffer), stdin) != NULL) dflag = 1; dargs[n++] = Ustrtod(outbuf, NULL); } + else if (Ustrstr(outbuf, "ll") != NULL) + { + llflag = 1; + llargs[n++] = strtoull(CS outbuf, NULL, 10); + } else { args[n++] = (void *)Uatoi(outbuf); @@ -1526,11 +1643,16 @@ while (fgets(CS buffer, sizeof(buffer), stdin) != NULL) if (*s == ',') s++; } - if (!dflag) printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format, - args[0], args[1], args[2])? "True" : "False"); + if (!dflag && !llflag) + printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format, + args[0], args[1], args[2])? "True" : "False"); + + else if (dflag) + printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format, + dargs[0], dargs[1], dargs[2])? "True" : "False"); else printf("%s\n", string_format(outbuf, sizeof(outbuf), CS format, - dargs[0], dargs[1], dargs[2])? "True" : "False"); + llargs[0], llargs[1], llargs[2])? "True" : "False"); printf("%s\n", CS outbuf); if (countset) printf("count=%d\n", count);