String-handling: rename string_cat() to string_catn() and intro a new string_cat()
[exim.git] / src / src / string.c
index be5a8deda633965ad33300b716352278e3374a83..963948f77657bcb1cc88550662e4f648458cc09b 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* 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
@@ -913,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;
@@ -952,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;
     }
@@ -995,17 +995,17 @@ 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, Ustrlen(ele));
+new = string_cat(new, &sz, &off, ele);
 new[off] = '\0';
 return new;
 }
@@ -1039,18 +1039,18 @@ const 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 = Ustrnchr(ele, sep, &len)))
   {
-  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;
   len--;
   }
-new = string_cat(new, &sz, &off, ele, len);
+new = string_catn(new, &sz, &off, ele, len);
 new[off] = '\0';
 return new;
 }
@@ -1078,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.
 
@@ -1086,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;
 
@@ -1132,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 */
 
 
@@ -1175,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);
 
@@ -1518,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),
@@ -1557,7 +1573,7 @@ if (testflag(addr, af_include_affixes) && s)
   if (testflag(addr, af_utf8_downcvt))
     s = string_localpart_utf8_to_alabel(s, NULL);
 #endif
-  yield = string_cat(yield, sizeptr, ptrptr, s, Ustrlen(s));
+  yield = string_cat(yield, sizeptr, ptrptr, s);
   }
 
 s = addr->local_part;
@@ -1565,7 +1581,7 @@ s = addr->local_part;
 if (testflag(addr, af_utf8_downcvt))
   s = string_localpart_utf8_to_alabel(s, NULL);
 #endif
-yield = string_cat(yield, sizeptr, ptrptr, s, Ustrlen(s));
+yield = string_cat(yield, sizeptr, ptrptr, s);
 
 s = addr->suffix;
 if (testflag(addr, af_include_affixes) && s)
@@ -1574,7 +1590,7 @@ if (testflag(addr, af_include_affixes) && s)
   if (testflag(addr, af_utf8_downcvt))
     s = string_localpart_utf8_to_alabel(s, NULL);
 #endif
-  yield = string_cat(yield, sizeptr, ptrptr, s, Ustrlen(s));
+  yield = string_cat(yield, sizeptr, ptrptr, s);
   }
 
 return yield;
@@ -1625,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);
   }
 
@@ -1639,18 +1655,16 @@ else
     {
     const uschar * s;
     yield = string_get_localpart(addr, yield, &size, &ptr);
-    yield = string_cat(yield, &size, &ptr, US"@", 1);
+    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, Ustrlen(s) );
+    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,
@@ -1677,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 */
@@ -1715,7 +1725,7 @@ pointers. Here it is. */
 int
 string_compare_by_pointer(const void *a, const void *b)
 {
-return Ustrcmp(CUSS *(const char**) a, CUSS *(const char**) b);
+return Ustrcmp(* CUSS a, * CUSS b);
 }
 #endif /* COMPILE_UTILITY */