X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c988f1f4faa9f679f79beddf3c14676c5dcb8e28..184e88237dea64ce48076cdd0184612d057cbafd:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index 2f69cd494..c0a8805fe 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/string.c,v 1.2 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/string.c,v 1.11 2007/01/08 10:50:18 ph10 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 */ @@ -944,9 +948,9 @@ on whether the variable length list of data arguments are given explicitly or 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, %#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 +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 datestamped log files. Arguments: @@ -973,6 +977,8 @@ return yield; BOOL string_vformat(uschar *buffer, int buflen, 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 */ @@ -985,6 +991,7 @@ string_datestamp_offset = -1; /* Datestamp not inserted */ while (*fp != 0) { + int length = L_NORMAL; int *nptr; int slen; char *null = "NULL"; /* ) These variables */ @@ -1038,7 +1045,25 @@ while (*fp != 0) } } - if (strchr("hlL", *fp) != NULL) fp++; + /* Skip over 'h', 'L', 'l', and 'll', remembering the item length */ + + if (*fp == 'h') + { fp++; length = L_SHORT; } + else if (*fp == 'L') + { fp++; length = L_LONGDOUBLE; } + else if (*fp == 'l') + { + if (fp[1] == 'l') + { + fp += 2; + length = L_LONGLONG; + } + else + { + fp++; + length = L_LONG; + } + } /* Handle each specific format type. */ @@ -1054,10 +1079,21 @@ while (*fp != 0) case 'u': case 'x': case 'X': - if (p >= last - 12) { 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; - sprintf(CS p, newformat, va_arg(ap, int)); + + /* Short int is promoted to int when passing through ..., so we must use + int for va_arg(). */ + + switch(length) + { + 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; + case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break; + } while (*p) p++; break; @@ -1070,9 +1106,11 @@ while (*fp != 0) break; /* %f format is inherently insecure if the numbers that it may be - handed are unknown (e.g. 1e300). However, in Exim, the only use of %f - is for printing load averages, and these are actually stored as integers - (load average * 1000) so the size of the numbers is constrained. */ + handed are unknown (e.g. 1e300). However, in Exim, %f is used for + printing load averages, and these are actually stored as integers + (load average * 1000) so the size of the numbers is constrained. + It is also used for formatting sending rates, where the simplicity + of the format prevents overflow. */ case 'f': case 'e': @@ -1083,7 +1121,10 @@ while (*fp != 0) if (p >= last - precision - 8) { yield = FALSE; goto END_FORMAT; } strncpy(newformat, item_start, fp - item_start); newformat[fp-item_start] = 0; - sprintf(CS p, newformat, va_arg(ap, double)); + if (length == L_LONGDOUBLE) + sprintf(CS p, newformat, va_arg(ap, long double)); + else + sprintf(CS p, newformat, va_arg(ap, double)); while (*p) p++; break; @@ -1431,8 +1472,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; @@ -1463,6 +1506,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); @@ -1485,11 +1533,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);