X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fstring.c;h=963948f77657bcb1cc88550662e4f648458cc09b;hb=65de12cc1acfeeacf85c3fd77d244b9dc7e79bdc;hp=914390255f43f59e55a919f00a3fb3d0d55d8689;hpb=9aa512a1898155484e00ee089057d28f2432b30e;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/string.c b/src/src/string.c index 914390255..963948f77 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2014 */ +/* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ /* Miscellaneous string-handling functions. Some are not required for @@ -165,7 +165,7 @@ Returns: pointer to the buffer uschar * string_format_size(int size, uschar *buffer) { -if (size == 0) Ustrcpy(CS buffer, " "); +if (size == 0) Ustrcpy(buffer, " "); else if (size < 1024) sprintf(CS buffer, "%5d", size); else if (size < 10*1024) sprintf(CS buffer, "%4.1fK", (double)size / 1024.0); @@ -224,13 +224,13 @@ Returns: the value of the character escape */ int -string_interpret_escape(uschar **pp) +string_interpret_escape(const uschar **pp) { #ifdef COMPILE_UTILITY const uschar *hex_digits= CUS"0123456789abcdef"; #endif int ch; -uschar *p = *pp; +const uschar *p = *pp; ch = *(++p); if (isdigit(ch) && ch != '8' && ch != '9') { @@ -284,12 +284,12 @@ Arguments: Returns: string with non-printers encoded as printing sequences */ -uschar * -string_printing2(uschar *s, BOOL allow_tab) +const uschar * +string_printing2(const uschar *s, BOOL allow_tab) { int nonprintcount = 0; int length = 0; -uschar *t = s; +const uschar *t = s; uschar *ss, *tt; while (*t != 0) @@ -304,7 +304,7 @@ if (nonprintcount == 0) return s; /* Get a new block of store guaranteed big enough to hold the expanded string. */ -ss = store_get(length + nonprintcount * 4 + 1); +ss = store_get(length + nonprintcount * 3 + 1); /* Copy everying, escaping non printers. */ @@ -374,7 +374,7 @@ while (*p) { if (*p == '\\') { - *q++ = string_interpret_escape(&p); + *q++ = string_interpret_escape((const uschar **)&p); p++; } else @@ -437,7 +437,7 @@ Returns: copy of string in new store */ uschar * -string_copy_malloc(uschar *s) +string_copy_malloc(const uschar *s) { int len = Ustrlen(s) + 1; uschar *ss = store_malloc(len); @@ -457,7 +457,7 @@ Returns: copy of string in new store, with letters lowercased */ uschar * -string_copylc(uschar *s) +string_copylc(const uschar *s) { uschar *ss = store_get(Ustrlen(s) + 1); uschar *p = ss; @@ -483,7 +483,7 @@ Returns: copy of string in new store */ uschar * -string_copyn(uschar *s, int n) +string_copyn(const uschar *s, int n) { uschar *ss = store_get(n + 1); Ustrncpy(ss, s, n); @@ -639,9 +639,9 @@ Returns: the new string */ uschar * -string_dequote(uschar **sptr) +string_dequote(const uschar **sptr) { -uschar *s = *sptr; +const uschar *s = *sptr; uschar *t, *yield; /* First find the end of the string */ @@ -717,8 +717,9 @@ uschar buffer[STRING_SPRINTF_BUFFER_SIZE]; va_start(ap, format); if (!string_vformat(buffer, sizeof(buffer), format, ap)) log_write(0, LOG_MAIN|LOG_PANIC_DIE, - "string_sprintf expansion was longer than " SIZE_T_FMT " (%s)", - sizeof(buffer), format); + "string_sprintf expansion was longer than " SIZE_T_FMT + "; format string was (%s)\nexpansion started '%.32s'", + sizeof(buffer), format, buffer); va_end(ap); return string_copy(buffer); } @@ -868,10 +869,10 @@ Returns: pointer to buffer, containing the next substring, */ uschar * -string_nextinlist(uschar **listptr, int *separator, uschar *buffer, int buflen) +string_nextinlist(const uschar **listptr, int *separator, uschar *buffer, int buflen) { -register int sep = *separator; -register uschar *s = *listptr; +int sep = *separator; +const uschar *s = *listptr; BOOL sep_is_special; if (s == NULL) return NULL; @@ -912,7 +913,7 @@ sep_is_special = iscntrl(sep); if (buffer != NULL) { - register int p = 0; + int p = 0; for (; *s != 0; s++) { if (*s == sep && (*(++s) != sep || sep_is_special)) break; @@ -928,7 +929,7 @@ else { int size = 0; int ptr = 0; - uschar *ss; + const 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 (if an ispunct() @@ -951,7 +952,7 @@ else for (;;) { for (ss = s + 1; *ss != 0 && *ss != sep; ss++); - buffer = string_cat(buffer, &size, &ptr, s, ss-s); + buffer = string_catn(buffer, &size, &ptr, s, ss-s); s = ss; if (*s == 0 || *(++s) != sep || sep_is_special) break; } @@ -969,7 +970,7 @@ return buffer; #ifndef COMPILE_UTILITY /************************************************ -* Add element to seperated list * +* Add element to separated list * ************************************************/ /* This function is used to build a list, returning an allocated null-terminated growable string. The @@ -994,17 +995,62 @@ uschar * sp; if (list) { - new = string_cat(new, &sz, &off, list, Ustrlen(list)); - new = string_cat(new, &sz, &off, &sep, 1); + new = string_cat (new, &sz, &off, list); + new = string_catn(new, &sz, &off, &sep, 1); } while((sp = Ustrchr(ele, sep))) { - new = string_cat(new, &sz, &off, ele, sp-ele+1); - new = string_cat(new, &sz, &off, &sep, 1); + new = string_catn(new, &sz, &off, ele, sp-ele+1); + new = string_catn(new, &sz, &off, &sep, 1); + ele = sp+1; + } +new = string_cat(new, &sz, &off, ele); +new[off] = '\0'; +return new; +} + + +static const uschar * +Ustrnchr(const uschar * s, int c, unsigned * len) +{ +unsigned siz = *len; +while (siz) + { + if (!*s) return NULL; + if (*s == c) + { + *len = siz; + return s; + } + s++; + siz--; + } +return NULL; +} + +uschar * +string_append_listele_n(uschar * list, uschar sep, const uschar * ele, + unsigned len) +{ +uschar * new = NULL; +int sz = 0, off = 0; +const uschar * sp; + +if (list) + { + new = string_cat (new, &sz, &off, list); + new = string_catn(new, &sz, &off, &sep, 1); + } + +while((sp = Ustrnchr(ele, sep, &len))) + { + new = string_catn(new, &sz, &off, ele, sp-ele+1); + new = string_catn(new, &sz, &off, &sep, 1); ele = sp+1; + len--; } -new = string_cat(new, &sz, &off, ele, Ustrlen(ele)); +new = string_catn(new, &sz, &off, ele, len); new[off] = '\0'; return new; } @@ -1032,7 +1078,7 @@ Arguments: characters, updated to the new offset s points to characters to add count count of characters to add; must not exceed the length of s, if s - is a C string + is a C string. If -1 given, strlen(s) is used. If string is given as NULL, *size and *ptr should both be zero. @@ -1040,10 +1086,12 @@ Returns: pointer to the start of the string, changed if copied for expansion. Note that a NUL is not added, though space is left for one. This is because string_cat() is often called multiple times to build up a string - there's no point adding the NUL till the end. + */ +/* coverity[+alloc] */ uschar * -string_cat(uschar *string, int *size, int *ptr, const uschar *s, int count) +string_catn(uschar *string, int *size, int *ptr, const uschar *s, int count) { int p = *ptr; @@ -1086,12 +1134,25 @@ if (p + count >= *size) /* Because we always specify the exact number of characters to copy, we can use memcpy(), which is likely to be more efficient than strncopy() because the -latter has to check for zero bytes. */ +latter has to check for zero bytes. +The Coverity annotation deals with the lack of correlated variable tracking; +common use is a null string and zero size and pointer, on first use for a +string being built. The "if" above then allocates, but Coverity assume that +the "if" might not happen and whines for a null-deref done by the memcpy(). */ + +/* coverity[deref_parm_field_in_call] */ memcpy(string + p, s, count); *ptr = p + count; return string; } + + +uschar * +string_cat(uschar *string, int *size, int *ptr, const uschar *s) +{ +return string_catn(string, size, ptr, s, Ustrlen(s)); +} #endif /* COMPILE_UTILITY */ @@ -1129,7 +1190,7 @@ va_start(ap, count); for (i = 0; i < count; i++) { uschar *t = va_arg(ap, uschar *); - string = string_cat(string, size, ptr, t, Ustrlen(t)); + string = string_cat(string, size, ptr, t); } va_end(ap); @@ -1472,6 +1533,7 @@ specified messages. If it does, the message just gets truncated, and there doesn't seem much we can do about that. */ (void)string_vformat(buffer+15, sizeof(buffer) - 15, format, ap); +va_end(ap); return (eno == EACCES)? string_sprintf("%s: %s (euid=%ld egid=%ld)", buffer, strerror(eno), @@ -1502,14 +1564,35 @@ static uschar * string_get_localpart(address_item *addr, uschar *yield, int *sizeptr, int *ptrptr) { -if (testflag(addr, af_include_affixes) && addr->prefix != NULL) - yield = string_cat(yield, sizeptr, ptrptr, addr->prefix, - Ustrlen(addr->prefix)); -yield = string_cat(yield, sizeptr, ptrptr, addr->local_part, - Ustrlen(addr->local_part)); -if (testflag(addr, af_include_affixes) && addr->suffix != NULL) - yield = string_cat(yield, sizeptr, ptrptr, addr->suffix, - Ustrlen(addr->suffix)); +uschar * s; + +s = addr->prefix; +if (testflag(addr, af_include_affixes) && s) + { +#ifdef SUPPORT_I18N + if (testflag(addr, af_utf8_downcvt)) + s = string_localpart_utf8_to_alabel(s, NULL); +#endif + yield = string_cat(yield, sizeptr, ptrptr, s); + } + +s = addr->local_part; +#ifdef SUPPORT_I18N +if (testflag(addr, af_utf8_downcvt)) + s = string_localpart_utf8_to_alabel(s, NULL); +#endif +yield = string_cat(yield, sizeptr, ptrptr, s); + +s = addr->suffix; +if (testflag(addr, af_include_affixes) && s) + { +#ifdef SUPPORT_I18N + if (testflag(addr, af_utf8_downcvt)) + s = string_localpart_utf8_to_alabel(s, NULL); +#endif + yield = string_cat(yield, sizeptr, ptrptr, s); + } + return yield; } @@ -1558,7 +1641,7 @@ if (testflag(addr, af_pfr) || addr->transport != NULL && addr->transport->info->local)) { if (testflag(addr, af_file) && addr->local_part[0] != '/') - yield = string_cat(yield, &size, &ptr, CUS"save ", 5); + yield = string_catn(yield, &size, &ptr, CUS"save ", 5); yield = string_get_localpart(addr, yield, &size, &ptr); } @@ -1570,15 +1653,18 @@ else { if (addr->local_part != NULL) { + const uschar * s; yield = string_get_localpart(addr, yield, &size, &ptr); - yield = string_cat(yield, &size, &ptr, US"@", 1); - yield = string_cat(yield, &size, &ptr, addr->domain, - Ustrlen(addr->domain) ); + yield = string_catn(yield, &size, &ptr, US"@", 1); + s = addr->domain; +#ifdef SUPPORT_I18N + if (testflag(addr, af_utf8_downcvt)) + s = string_localpart_utf8_to_alabel(s, NULL); +#endif + yield = string_cat(yield, &size, &ptr, s); } else - { - yield = string_cat(yield, &size, &ptr, addr->address, Ustrlen(addr->address)); - } + yield = string_cat(yield, &size, &ptr, addr->address); yield[ptr] = 0; /* If the address we are going to print is the same as the top address, @@ -1605,28 +1691,24 @@ if ((all_parents || testflag(addr, af_pfr)) && address_item *addr2; for (addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent) { - yield = string_cat(yield, &size, &ptr, s, 2); - yield = string_cat(yield, &size, &ptr, addr2->address, Ustrlen(addr2->address)); + yield = string_catn(yield, &size, &ptr, s, 2); + yield = string_cat (yield, &size, &ptr, addr2->address); if (!all_parents) break; s = US", "; } - yield = string_cat(yield, &size, &ptr, US")", 1); + yield = string_catn(yield, &size, &ptr, US")", 1); } /* Add the top address if it is required */ if (add_topaddr) { - yield = string_cat(yield, &size, &ptr, US" <", 2); + yield = string_catn(yield, &size, &ptr, US" <", 2); - if (addr->onetime_parent == NULL) - yield = string_cat(yield, &size, &ptr, topaddr->address, - Ustrlen(topaddr->address)); - else - yield = string_cat(yield, &size, &ptr, addr->onetime_parent, - Ustrlen(addr->onetime_parent)); + yield = string_cat(yield, &size, &ptr, + addr->onetime_parent ? addr->onetime_parent : topaddr->address); - yield = string_cat(yield, &size, &ptr, US">", 1); + yield = string_catn(yield, &size, &ptr, US">", 1); } yield[ptr] = 0; /* string_cat() leaves space */ @@ -1635,6 +1717,17 @@ return yield; #endif /* COMPILE_UTILITY */ +#ifndef COMPILE_UTILITY +/* qsort(3), currently used to sort the environment variables +for -bP environment output, needs a function to compare two pointers to string +pointers. Here it is. */ + +int +string_compare_by_pointer(const void *a, const void *b) +{ +return Ustrcmp(* CUSS a, * CUSS b); +} +#endif /* COMPILE_UTILITY */