* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* Miscellaneous string-handling functions. Some are not required for
/* Handle the case when a buffer is provided. */
-if (buffer != NULL)
+if (buffer)
{
int p = 0;
for (; *s != 0; s++)
}
while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
buffer = string_from_gstring(g);
+ gstring_reset_unused(g);
}
/* Update the current pointer and return the new string */
+/************************************************/
+/* Create a growable-string with some preassigned space */
+
+gstring *
+string_get(unsigned size)
+{
+gstring * g = store_get(sizeof(gstring) + size);
+g->size = size;
+g->ptr = 0;
+g->s = US(g + 1);
+return g;
+}
+
+/* NUL-terminate the C string in the growable-string, and return it. */
+
+uschar *
+string_from_gstring(gstring * g)
+{
+if (!g) return NULL;
+g->s[g->ptr] = '\0';
+return g->s;
+}
+
+void
+gstring_reset_unused(gstring * g)
+{
+store_reset(g->s + (g->size = g->ptr + 1));
+}
+
/*************************************************
* Add chars to string *
*************************************************/
-/* See inline functions in functions.h */
-void
+/* Arguments:
+ g the grawable-string
+ p current end of data
+ count amount to grow by
+*/
+
+static void
gstring_grow(gstring * g, int p, int count)
{
int oldsize = g->size;
store_last_get. */
if (!store_extend(g->s, oldsize, g->size))
+ g->s = store_newblock(g->s, g->size, p);
+}
+
+
+
+/* This function is used when building up strings of unknown length. Room is
+always left for a terminating zero to be added to the string that is being
+built. This function does not require the string that is being added to be NUL
+terminated, because the number of characters to add is given explicitly. It is
+sometimes called to extract parts of other strings.
+
+Arguments:
+ string points to the start of the string that is being built, or NULL
+ if this is a new string that has no contents yet
+ 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.
+
+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] */
+
+gstring *
+string_catn(gstring * g, const uschar *s, int count)
+{
+int p;
+
+if (!g)
{
- BOOL release_ok = store_last_get[store_pool] == g->s;
- uschar *newstring = store_get(g->size);
- memcpy(newstring, g->s, p);
- if (release_ok) store_release(g->s);
- g->s = newstring;
+ unsigned inc = count < 4096 ? 127 : 1023;
+ unsigned size = ((count + inc) & ~inc) + 1;
+ g = string_get(size);
}
+
+p = g->ptr;
+if (p + count >= g->size)
+ gstring_grow(g, p, count);
+
+/* 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. */
+
+memcpy(g->s + p, s, count);
+g->ptr = p + count;
+return g;
+}
+
+
+gstring *
+string_cat(gstring *string, const uschar *s)
+{
+return string_catn(string, s, Ustrlen(s));
}
break;
case 'p':
- if (p >= last - 24) { yield = FALSE; goto END_FORMAT; }
- strncpy(newformat, item_start, fp - item_start);
- newformat[fp - item_start] = 0;
- p += sprintf(CS p, newformat, va_arg(ap, void *));
+ {
+ void * ptr;
+ if (p >= last - 24) { yield = FALSE; goto END_FORMAT; }
+ /* sprintf() saying "(nil)" for a null pointer seems unreliable.
+ Handle it explicitly. */
+ if ((ptr = va_arg(ap, void *)))
+ {
+ strncpy(newformat, item_start, fp - item_start);
+ newformat[fp - item_start] = 0;
+ p += sprintf(CS p, newformat, ptr);
+ }
+ else
+ p += sprintf(CS p, "(nil)");
+ }
break;
/* %f format is inherently insecure if the numbers that it may be