X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b1c749bb7f147e7f9215fe6067c848cf02938b92..24c929a2:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index aa4f93338..83455294d 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/string.c,v 1.5 2005/06/16 14:10:13 ph10 Exp $ */ +/* $Cambridge: exim/src/src/string.c,v 1.14 2008/12/12 14:36:37 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2007 */ /* See the file NOTICE for conditions of use and distribution. */ /* Miscellaneous string-handling functions. Some are not required for @@ -28,6 +28,7 @@ Arguments: s a string maskptr NULL if no mask is permitted to follow otherwise, points to an int where the offset of '/' is placed + if there is no / followed by trailing digits, *maskptr is set 0 Returns: 0 if the string is not a textual representation of an IP address 4 if it is an IPv4 address @@ -127,7 +128,9 @@ if (Ustrchr(s, ':') != NULL) sign, which introduces the interface specifier (scope id) of a link local address. */ - if (!v4end) return (*s == 0 || *s == '%' || *s == '/')? yield : 0; + if (!v4end) + return (*s == 0 || *s == '%' || + (*s == '/' && maskptr != NULL && *maskptr != 0))? yield : 0; } /* Test for IPv4 address, which may be the tail-end of an IPv6 address. */ @@ -139,7 +142,8 @@ for (i = 0; i < 4; i++) if (isdigit(*s) && isdigit(*(++s))) s++; } -return (*s == 0 || *s == '/')? yield : 0; +return (*s == 0 || (*s == '/' && maskptr != NULL && *maskptr != 0))? + yield : 0; } #endif /* COMPILE_UTILITY */ @@ -445,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 * *************************************************/ @@ -699,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--; @@ -769,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 */ @@ -1075,7 +1168,8 @@ while (*fp != 0) case 'u': case 'x': case 'X': - if (p >= last - 24) { yield = FALSE; goto END_FORMAT; } + if (p >= last - ((length > L_LONG)? 24 : 12)) + { yield = FALSE; goto END_FORMAT; } strncpy(newformat, item_start, fp - item_start); newformat[fp - item_start] = 0; @@ -1087,11 +1181,7 @@ while (*fp != 0) case L_SHORT: case L_NORMAL: sprintf(CS p, newformat, va_arg(ap, int)); break; case L_LONG: sprintf(CS p, newformat, va_arg(ap, long int)); break; - #ifdef ASSUME_LONG_LONG_SUPPORT - case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, long long int)); break; - #else - case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, long long int)); break; - #endif + case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break; } while (*p) p++; break; @@ -1177,10 +1267,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') @@ -1471,8 +1568,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; @@ -1503,6 +1602,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); @@ -1525,11 +1629,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);