/* If value2 is unset, just compute one number */
if (value2 < 0)
- s = string_sprintf("%d", total % value1);
+ s = string_sprintf("%lu", total % value1);
/* Otherwise do a div/mod hash */
else
{
total = total % (value1 * value2);
- s = string_sprintf("%d/%d", total/value2, total % value2);
+ s = string_sprintf("%lu/%lu", total/value2, total % value2);
}
*len = Ustrlen(s);
static uschar *
fn_recipients(void)
{
-if (!enable_dollar_recipients) return NULL; else
+gstring * g = NULL;
+int i;
+
+if (!enable_dollar_recipients) return NULL;
+
+for (i = 0; i < recipients_count; i++)
{
- int size = 128;
- int ptr = 0;
- int i;
- uschar * s = store_get(size);
- for (i = 0; i < recipients_count; i++)
- {
- if (i != 0) s = string_catn(s, &size, &ptr, US", ", 2);
- s = string_cat(s, &size, &ptr, recipients_list[i].address);
- }
- s[ptr] = 0; /* string_cat() leaves room */
- return s;
+ /*XXX variant of list_appendele? */
+ if (i != 0) g = string_catn(g, US", ", 2);
+ g = string_cat(g, recipients_list[i].address);
}
+return string_from_gstring(g);
}
uschar *sub[10];
uschar *user_msg;
BOOL cond = FALSE;
- int size = 0;
- int ptr = 0;
while (isspace(*s)) s++;
if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/
case FAIL:
lookup_value = NULL;
if (user_msg)
- {
- lookup_value = string_cat(NULL, &size, &ptr, user_msg);
- lookup_value[ptr] = '\0';
- }
+ lookup_value = string_copy(user_msg);
*yield = cond == testfor;
break;
uschar *save_iterate_item = iterate_item;
int (*compare)(const uschar *, const uschar *);
- DEBUG(D_expand) debug_printf_indent("condition: %s\n", name);
+ DEBUG(D_expand) debug_printf_indent("condition: %s item: %s\n", name, sub[0]);
tempcond = FALSE;
compare = cond_type == ECOND_INLISTI
? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp;
while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)))
+ {
+ DEBUG(D_expand) debug_printf_indent(" compare %s\n", iterate_item);
if (compare(sub[0], iterate_item) == 0)
{
tempcond = TRUE;
break;
}
+ }
iterate_item = save_iterate_item;
}
yes TRUE if the first string is to be used, else use the second
save_lookup a value to put back into lookup_value before the 2nd expansion
sptr points to the input string pointer
- yieldptr points to the output string pointer
- sizeptr points to the output string size
- ptrptr points to the output string pointer
+ yieldptr points to the output growable-string pointer
type "lookup", "if", "extract", "run", "env", "listextract" or
"certextract" for error message
resetok if not NULL, pointer to flag - write FALSE if unsafe to reset
static int
process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, const uschar **sptr,
- uschar **yieldptr, int *sizeptr, int *ptrptr, uschar *type, BOOL *resetok)
+ gstring ** yieldptr, uschar *type, BOOL *resetok)
{
int rc = 0;
const uschar *s = *sptr; /* Local value */
if (type[0] == 'i')
{
if (yes && !skipping)
- *yieldptr = string_catn(*yieldptr, sizeptr, ptrptr, US"true", 4);
+ *yieldptr = string_catn(*yieldptr, US"true", 4);
}
else
{
if (yes && lookup_value && !skipping)
- *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value);
+ *yieldptr = string_cat(*yieldptr, lookup_value);
lookup_value = save_lookup;
}
s++;
/* If we want the first string, add it to the output */
if (yes)
- *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub1);
+ *yieldptr = string_cat(*yieldptr, sub1);
/* If this is called from a lookup/env or a (cert)extract, we want to restore
$value to what it was at the start of the item, so that it has this value
/* If we want the second string, add it to the output */
if (!yes)
- *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub2);
+ *yieldptr = string_cat(*yieldptr, sub2);
}
/* If there is no second string, but the word "fail" is present when the use of
static uschar *
prvs_hmac_sha1(uschar *address, uschar *key, uschar *key_num, uschar *daystamp)
{
-uschar *hash_source, *p;
-int size = 0,offset = 0,i;
+gstring * hash_source;
+uschar * p;
+int i;
hctx h;
uschar innerhash[20];
uschar finalhash[20];
if (Ustrlen(key) > 64)
return NULL;
-hash_source = string_catn(NULL, &size, &offset, key_num, 1);
-hash_source = string_catn(hash_source, &size, &offset, daystamp, 3);
-hash_source = string_cat(hash_source, &size, &offset, address);
-hash_source[offset] = '\0';
+hash_source = string_catn(NULL, key_num, 1);
+hash_source = string_catn(hash_source, daystamp, 3);
+hash_source = string_cat(hash_source, address);
+(void) string_from_gstring(hash_source);
-DEBUG(D_expand) debug_printf_indent("prvs: hash source is '%s'\n", hash_source);
+DEBUG(D_expand)
+ debug_printf_indent("prvs: hash source is '%s'\n", hash_source->s);
memset(innerkey, 0x36, 64);
memset(outerkey, 0x5c, 64);
chash_start(HMAC_SHA1, &h);
chash_mid(HMAC_SHA1, &h, innerkey);
-chash_end(HMAC_SHA1, &h, hash_source, offset, innerhash);
+chash_end(HMAC_SHA1, &h, hash_source->s, hash_source->ptr, innerhash);
chash_start(HMAC_SHA1, &h);
chash_mid(HMAC_SHA1, &h, outerkey);
Arguments:
f the FILE
- yield pointer to the expandable string
- sizep pointer to the current size
- ptrp pointer to the current position
+ yield pointer to the expandable string struct
eol newline replacement string, or NULL
-Returns: new value of string pointer
+Returns: new pointer for expandable string, terminated if non-null
*/
-static uschar *
-cat_file(FILE *f, uschar *yield, int *sizep, int *ptrp, uschar *eol)
+static gstring *
+cat_file(FILE *f, gstring *yield, uschar *eol)
{
uschar buffer[1024];
{
int len = Ustrlen(buffer);
if (eol && buffer[len-1] == '\n') len--;
- yield = string_catn(yield, sizep, ptrp, buffer, len);
+ yield = string_catn(yield, buffer, len);
if (eol && buffer[len])
- yield = string_cat(yield, sizep, ptrp, eol);
+ yield = string_cat(yield, eol);
}
-if (yield) yield[*ptrp] = 0;
-
+(void) string_from_gstring(yield);
return yield;
}
expand_string_internal(const uschar *string, BOOL ket_ends, const uschar **left,
BOOL skipping, BOOL honour_dollar, BOOL *resetok_p)
{
-int ptr = 0;
-int size = Ustrlen(string)+ 64;
-uschar *yield = store_get(size);
+gstring * yield = string_get(Ustrlen(string) + 64);
int item_type;
const uschar *s = string;
uschar *save_expand_nstring[EXPAND_MAXN+1];
{
const uschar * t = s + 2;
for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break;
- yield = string_catn(yield, &size, &ptr, t, s - t);
+ yield = string_catn(yield, t, s - t);
if (*s != 0) s += 2;
}
uschar ch[1];
ch[0] = string_interpret_escape(&s);
s++;
- yield = string_catn(yield, &size, &ptr, ch, 1);
+ yield = string_catn(yield, ch, 1);
}
continue;
if (*s != '$' || !honour_dollar)
{
- yield = string_catn(yield, &size, &ptr, s++, 1);
+ yield = string_catn(yield, s++, 1);
continue;
}
{
int len;
int newsize = 0;
+ gstring * g = NULL;
s = read_name(name, sizeof(name), s, US"_");
/* If this is the first thing to be expanded, release the pre-allocated
buffer. */
- if (ptr == 0 && yield != NULL)
+ if (!yield)
+ g = store_get(sizeof(gstring));
+ else if (yield->ptr == 0)
{
if (resetok) store_reset(yield);
yield = NULL;
- size = 0;
+ g = store_get(sizeof(gstring)); /* alloc _before_ calling find_variable() */
}
/* Header */
has been omitted. Set a flag to adjust the error message in this case.
But there is no error here - nothing gets inserted. */
- if (value == NULL)
+ if (!value)
{
if (Ustrchr(name, '}') != NULL) malformed_header = TRUE;
continue;
size of that buffer. If this is the first thing in an expansion string,
yield will be NULL; just point it at the new store instead of copying. Many
expansion strings contain just one reference, so this is a useful
- optimization, especially for humungous headers. */
+ optimization, especially for humungous headers. We need to use a gstring
+ structure that is not allocated after that new-buffer, else a later store
+ reset in the middle of the buffer will make it inaccessible. */
len = Ustrlen(value);
- if (yield == NULL && newsize != 0)
+ if (!yield && newsize != 0)
{
- yield = value;
- size = newsize;
- ptr = len;
+ yield = g;
+ yield->size = newsize;
+ yield->ptr = len;
+ yield->s = value;
}
- else yield = string_catn(yield, &size, &ptr, value, len);
+ else
+ yield = string_catn(yield, value, len);
continue;
}
int n;
s = read_cnumber(&n, s);
if (n >= 0 && n <= expand_nmax)
- yield = string_catn(yield, &size, &ptr, expand_nstring[n],
- expand_nlength[n]);
+ yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
continue;
}
goto EXPAND_FAILED;
}
if (n >= 0 && n <= expand_nmax)
- yield = string_catn(yield, &size, &ptr, expand_nstring[n],
- expand_nlength[n]);
+ yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
continue;
}
DEBUG(D_expand)
debug_printf_indent("acl expansion yield: %s\n", user_msg);
if (user_msg)
- yield = string_cat(yield, &size, &ptr, user_msg);
+ yield = string_cat(yield, user_msg);
continue;
case DEFER:
lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"if", /* condition type */
&resetok))
{
if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
sub_arg[1][0], sub_arg[2], &expand_string_message)))
goto EXPAND_FAILED;
- yield = string_cat(yield, &size, &ptr, encoded);
+ yield = string_cat(yield, encoded);
}
continue;
}
save_lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"lookup", /* condition type */
&resetok))
{
#else /* EXIM_PERL */
{
uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2];
- uschar *new_yield;
+ gstring *new_yield;
if ((expand_forbid & RDO_PERL) != 0)
{
/* Call the function */
sub_arg[EXIM_PERL_MAX_ARGS + 1] = NULL;
- new_yield = call_perl_cat(yield, &size, &ptr, &expand_string_message,
+ new_yield = call_perl_cat(yield, &expand_string_message,
sub_arg[0], sub_arg + 1);
/* NULL yield indicates failure; if the message pointer has been set to
/* Now separate the domain from the local part */
*domain++ = '\0';
- yield = string_catn(yield, &size, &ptr, US"prvs=", 5);
- yield = string_catn(yield, &size, &ptr, sub_arg[2] ? sub_arg[2] : US"0", 1);
- yield = string_catn(yield, &size, &ptr, prvs_daystamp(7), 3);
- yield = string_catn(yield, &size, &ptr, p, 6);
- yield = string_catn(yield, &size, &ptr, US"=", 1);
- yield = string_cat (yield, &size, &ptr, sub_arg[0]);
- yield = string_catn(yield, &size, &ptr, US"@", 1);
- yield = string_cat (yield, &size, &ptr, domain);
+ yield = string_catn(yield, US"prvs=", 5);
+ yield = string_catn(yield, sub_arg[2] ? sub_arg[2] : US"0", 1);
+ yield = string_catn(yield, prvs_daystamp(7), 3);
+ yield = string_catn(yield, p, 6);
+ yield = string_catn(yield, US"=", 1);
+ yield = string_cat (yield, sub_arg[0]);
+ yield = string_catn(yield, US"@", 1);
+ yield = string_cat (yield, domain);
continue;
}
case EITEM_PRVSCHECK:
{
uschar *sub_arg[3];
- int mysize = 0, myptr = 0;
+ gstring * g;
const pcre *re;
uschar *p;
DEBUG(D_expand) debug_printf_indent("prvscheck domain: %s\n", domain);
/* Set up expansion variables */
- prvscheck_address = string_cat (NULL, &mysize, &myptr, local_part);
- prvscheck_address = string_catn(prvscheck_address, &mysize, &myptr, US"@", 1);
- prvscheck_address = string_cat (prvscheck_address, &mysize, &myptr, domain);
- prvscheck_address[myptr] = '\0';
+ g = string_cat (NULL, local_part);
+ g = string_catn(g, US"@", 1);
+ g = string_cat (g, domain);
+ prvscheck_address = string_from_gstring(g);
prvscheck_keynum = string_copy(key_num);
/* Now expand the second argument */
p = prvs_hmac_sha1(prvscheck_address, sub_arg[0], prvscheck_keynum,
daystamp);
- if (p == NULL)
+ if (!p)
{
expand_string_message = US"hmac-sha1 conversion failed";
goto EXPAND_FAILED;
case 3: goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr,
+ yield = string_cat(yield,
!sub_arg[0] || !*sub_arg[0] ? prvscheck_address : sub_arg[0]);
/* Reset the "internal" variables afterwards, because they are in
goto EXPAND_FAILED;
}
- yield = cat_file(f, yield, &size, &ptr, sub_arg[1]);
+ yield = cat_file(f, yield, sub_arg[1]);
(void)fclose(f);
continue;
}
{
int fd;
int timeout = 5;
- int save_ptr = ptr;
+ int save_ptr = yield->ptr;
FILE *f;
uschar *arg;
uschar *sub_arg[4];
f = fdopen(fd, "rb");
sigalrm_seen = FALSE;
alarm(timeout);
- yield = cat_file(f, yield, &size, &ptr, sub_arg[3]);
+ yield = cat_file(f, yield, sub_arg[3]);
alarm(0);
(void)fclose(f);
if (sigalrm_seen)
{
- ptr = save_ptr;
+ yield->ptr = save_ptr;
expand_string_message = US "socket read timed out";
goto SOCK_FAIL;
}
DEBUG(D_any) debug_printf("%s\n", expand_string_message);
if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok)))
goto EXPAND_FAILED;
- yield = string_cat(yield, &size, &ptr, arg);
+ yield = string_cat(yield, arg);
if (*s++ != '}')
{
expand_string_message = US"missing '}' closing failstring for readsocket";
const uschar **argv;
pid_t pid;
int fd_in, fd_out;
- int lsize = 0, lptr = 0;
if ((expand_forbid & RDO_RUN) != 0)
{
f = fdopen(fd_out, "rb");
sigalrm_seen = FALSE;
alarm(60);
- lookup_value = cat_file(f, NULL, &lsize, &lptr, NULL);
+ lookup_value = string_from_gstring(cat_file(f, NULL, NULL));
alarm(0);
(void)fclose(f);
lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"run", /* condition type */
&resetok))
{
case EITEM_TR:
{
- int oldptr = ptr;
+ int oldptr = yield->ptr;
int o2m;
uschar *sub[3];
case 3: goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, sub[0]);
+ yield = string_cat(yield, sub[0]);
o2m = Ustrlen(sub[2]) - 1;
- if (o2m >= 0) for (; oldptr < ptr; oldptr++)
+ if (o2m >= 0) for (; oldptr < yield->ptr; oldptr++)
{
- uschar *m = Ustrrchr(sub[1], yield[oldptr]);
+ uschar *m = Ustrrchr(sub[1], yield->s[oldptr]);
if (m != NULL)
{
int o = m - sub[1];
- yield[oldptr] = sub[2][(o < o2m)? o : o2m];
+ yield->s[oldptr] = sub[2][(o < o2m)? o : o2m];
}
}
extract_substr(sub[2], val[0], val[1], &len);
if (ret == NULL) goto EXPAND_FAILED;
- yield = string_catn(yield, &size, &ptr, ret, len);
+ yield = string_catn(yield, ret, len);
continue;
}
DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
- yield = string_catn(yield, &size, &ptr, finalhash_hex, hashlen*2);
+ yield = string_catn(yield, finalhash_hex, hashlen*2);
}
continue;
}
emptyopt = 0;
continue;
}
- yield = string_catn(yield, &size, &ptr, subject+moffset, slen-moffset);
+ yield = string_catn(yield, subject+moffset, slen-moffset);
break;
}
/* Copy the characters before the match, plus the expanded insertion. */
- yield = string_catn(yield, &size, &ptr, subject + moffset,
- ovector[0] - moffset);
+ yield = string_catn(yield, subject + moffset, ovector[0] - moffset);
insert = expand_string(sub[2]);
if (insert == NULL) goto EXPAND_FAILED;
- yield = string_cat(yield, &size, &ptr, insert);
+ yield = string_cat(yield, insert);
moffset = ovector[1];
moffsetextra = 0;
save_lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"extract", /* condition type */
&resetok))
{
save_lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"listextract", /* condition type */
&resetok))
{
save_lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"certextract", /* condition type */
&resetok))
{
case EITEM_REDUCE:
{
int sep = 0;
- int save_ptr = ptr;
+ int save_ptr = yield->ptr;
uschar outsep[2] = { '\0', '\0' };
const uschar *list, *expr, *temp;
uschar *save_iterate_item = iterate_item;
item of the output list, add in a space if the new item begins with the
separator character, or is an empty string. */
- if (ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0))
- yield = string_catn(yield, &size, &ptr, US" ", 1);
+ if (yield->ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0))
+ yield = string_catn(yield, US" ", 1);
/* Add the string in "temp" to the output list that we are building,
This is done in chunks by searching for the separator character. */
{
size_t seglen = Ustrcspn(temp, outsep);
- yield = string_catn(yield, &size, &ptr, temp, seglen + 1);
+ yield = string_catn(yield, temp, seglen + 1);
/* If we got to the end of the string we output one character
too many; backup and end the loop. Otherwise arrange to double the
separator. */
- if (temp[seglen] == '\0') { ptr--; break; }
- yield = string_catn(yield, &size, &ptr, outsep, 1);
+ if (temp[seglen] == '\0') { yield->ptr--; break; }
+ yield = string_catn(yield, outsep, 1);
temp += seglen + 1;
}
/* Output a separator after the string: we will remove the redundant
final one at the end. */
- yield = string_catn(yield, &size, &ptr, outsep, 1);
+ yield = string_catn(yield, outsep, 1);
} /* End of iteration over the list loop */
/* REDUCE has generated no output above: output the final value of
if (item_type == EITEM_REDUCE)
{
- yield = string_cat(yield, &size, &ptr, lookup_value);
+ yield = string_cat(yield, lookup_value);
lookup_value = save_lookup_value; /* Restore $value */
}
the redundant final separator. Even though an empty item at the end of a
list does not count, this is tidier. */
- else if (ptr != save_ptr) ptr--;
+ else if (yield->ptr != save_ptr) yield->ptr--;
/* Restore preserved $item */
while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0)))
{
uschar * dstitem;
- uschar * newlist = NULL;
- int size = 0, len = 0;
- uschar * newkeylist = NULL;
- int ksize = 0, klen = 0;
+ gstring * newlist = NULL;
+ gstring * newkeylist = NULL;
uschar * srcfield;
DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
/* New-item sorts before this dst-item. Append new-item,
then dst-item, then remainder of dst list. */
- newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
- newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
+ newlist = string_append_listele(newlist, sep, srcitem);
+ newkeylist = string_append_listele(newkeylist, sep, srcfield);
srcitem = NULL;
- newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
+ newlist = string_append_listele(newlist, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, sep, dstfield);
while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
{
if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
goto sort_mismatch;
- newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
+ newlist = string_append_listele(newlist, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, sep, dstfield);
}
break;
}
- newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
- newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
+ newlist = string_append_listele(newlist, sep, dstitem);
+ newkeylist = string_append_listele(newkeylist, sep, dstfield);
}
/* If we ran out of dstlist without consuming srcitem, append it */
if (srcitem)
{
- newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
- newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
+ newlist = string_append_listele(newlist, sep, srcitem);
+ newkeylist = string_append_listele(newkeylist, sep, srcfield);
}
- dstlist = newlist;
- dstkeylist = newkeylist;
+ dstlist = newlist->s;
+ dstkeylist = newkeylist->s;
DEBUG(D_expand) debug_printf_indent("%s: dstlist = \"%s\"\n", name, dstlist);
DEBUG(D_expand) debug_printf_indent("%s: dstkeylist = \"%s\"\n", name, dstkeylist);
}
if (dstlist)
- yield = string_cat(yield, &size, &ptr, dstlist);
+ yield = string_cat(yield, dstlist);
/* Restore preserved $item */
iterate_item = save_iterate_item;
if(status == OK)
{
if (result == NULL) result = US"";
- yield = string_cat(yield, &size, &ptr, result);
+ yield = string_cat(yield, result);
continue;
}
else
save_lookup_value, /* value to reset for string2 */
&s, /* input pointer */
&yield, /* output pointer */
- &size, /* output size */
- &ptr, /* output current point */
US"env", /* condition type */
&resetok))
{
{
uschar *t;
unsigned long int n = Ustrtoul(sub, &t, 10);
- uschar * s = NULL;
- int sz = 0, i = 0;
+ gstring * g = NULL;
if (*t != 0)
{
goto EXPAND_FAILED;
}
for ( ; n; n >>= 5)
- s = string_catn(s, &sz, &i, &base32_chars[n & 0x1f], 1);
+ g = string_catn(g, &base32_chars[n & 0x1f], 1);
- while (i > 0) yield = string_catn(yield, &size, &ptr, &s[--i], 1);
+ if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1);
continue;
}
n = n * 32 + (t - base32_chars);
}
s = string_sprintf("%ld", n);
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
goto EXPAND_FAILED;
}
t = string_base62(n);
- yield = string_cat(yield, &size, &ptr, t);
+ yield = string_cat(yield, t);
continue;
}
n = n * BASE_62 + (t - base62_chars);
}
(void)sprintf(CS buf, "%ld", n);
- yield = string_cat(yield, &size, &ptr, buf);
+ yield = string_cat(yield, buf);
continue;
}
expand_string_message);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, expanded);
+ yield = string_cat(yield, expanded);
continue;
}
int count = 0;
uschar *t = sub - 1;
while (*(++t) != 0) { *t = tolower(*t); count++; }
- yield = string_catn(yield, &size, &ptr, sub, count);
+ yield = string_catn(yield, sub, count);
continue;
}
int count = 0;
uschar *t = sub - 1;
while (*(++t) != 0) { *t = toupper(*t); count++; }
- yield = string_catn(yield, &size, &ptr, sub, count);
+ yield = string_catn(yield, sub, count);
continue;
}
if (vp && *(void **)vp->value)
{
uschar * cp = tls_cert_fprt_md5(*(void **)vp->value);
- yield = string_cat(yield, &size, &ptr, cp);
+ yield = string_cat(yield, cp);
}
else
#endif
md5_start(&base);
md5_end(&base, sub, Ustrlen(sub), digest);
for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]);
- yield = string_cat(yield, &size, &ptr, US st);
+ yield = string_cat(yield, US st);
}
continue;
if (vp && *(void **)vp->value)
{
uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value);
- yield = string_cat(yield, &size, &ptr, cp);
+ yield = string_cat(yield, cp);
}
else
#endif
sha1_start(&h);
sha1_end(&h, sub, Ustrlen(sub), digest);
for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]);
- yield = string_catn(yield, &size, &ptr, US st, 40);
+ yield = string_catn(yield, US st, 40);
}
continue;
if (vp && *(void **)vp->value)
{
uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value);
- yield = string_cat(yield, &size, &ptr, cp);
+ yield = string_cat(yield, cp);
}
else
{
while (b.len-- > 0)
{
sprintf(st, "%02X", *b.data++);
- yield = string_catn(yield, &size, &ptr, US st, 2);
+ yield = string_catn(yield, US st, 2);
}
}
#else
while (b.len-- > 0)
{
sprintf(st, "%02X", *b.data++);
- yield = string_catn(yield, &size, &ptr, US st, 2);
+ yield = string_catn(yield, US st, 2);
}
}
continue;
}
enc = b64encode(sub, out - sub);
- yield = string_cat(yield, &size, &ptr, enc);
+ yield = string_cat(yield, enc);
continue;
}
while (*(++t) != 0)
{
if (*t < 0x21 || 0x7E < *t)
- yield = string_catn(yield, &size, &ptr,
- string_sprintf("\\x%02x", *t), 4);
+ yield = string_catn(yield, string_sprintf("\\x%02x", *t), 4);
else
- yield = string_catn(yield, &size, &ptr, t, 1);
+ yield = string_catn(yield, t, 1);
}
continue;
}
while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++;
cp = string_sprintf("%d", cnt);
- yield = string_cat(yield, &size, &ptr, cp);
+ yield = string_cat(yield, cp);
continue;
}
list = ((namedlist_block *)(t->data.ptr))->string;
- while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
+ while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
{
uschar * buf = US" : ";
if (needsep)
- yield = string_catn(yield, &size, &ptr, buf, 3);
+ yield = string_catn(yield, buf, 3);
else
needsep = TRUE;
tok[0] = sep; tok[1] = ':'; tok[2] = 0;
while ((cp= strpbrk(CCS item, tok)))
{
- yield = string_catn(yield, &size, &ptr, item, cp-CS item);
+ yield = string_catn(yield, item, cp - CS item);
if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
{
- yield = string_catn(yield, &size, &ptr, US"::", 2);
+ yield = string_catn(yield, US"::", 2);
item = US cp;
}
else /* sep in item; should already be doubled; emit once */
{
- yield = string_catn(yield, &size, &ptr, US tok, 1);
+ yield = string_catn(yield, US tok, 1);
if (*cp == sep) cp++;
item = US cp;
}
}
}
- yield = string_cat(yield, &size, &ptr, item);
+ yield = string_cat(yield, item);
}
continue;
}
/* Convert to masked textual format and add to output. */
- yield = string_catn(yield, &size, &ptr, buffer,
+ yield = string_catn(yield, buffer,
host_nmtoa(count, binary, mask, buffer, '.'));
continue;
}
goto EXPAND_FAILED;
}
- yield = string_catn(yield, &size, &ptr, buffer,
- c == EOP_IPV6NORM
+ yield = string_catn(yield, buffer, c == EOP_IPV6NORM
? ipv6_nmtoa(binary, buffer)
: host_nmtoa(4, binary, -1, buffer, ':')
);
if (c != EOP_DOMAIN)
{
if (c == EOP_LOCAL_PART && domain != 0) end = start + domain - 1;
- yield = string_catn(yield, &size, &ptr, sub+start, end-start);
+ yield = string_catn(yield, sub+start, end-start);
}
else if (domain != 0)
{
domain += start;
- yield = string_catn(yield, &size, &ptr, sub+domain, end-domain);
+ yield = string_catn(yield, sub+domain, end-domain);
}
continue;
}
{
uschar outsep[2] = { ':', '\0' };
uschar *address, *error;
- int save_ptr = ptr;
+ int save_ptr = yield->ptr;
int start, end, domain; /* Not really used */
while (isspace(*sub)) sub++;
if (*sub == '>')
if (*outsep = *++sub) ++sub;
- else {
+ else
+ {
expand_string_message = string_sprintf("output separator "
"missing in expanding ${addresses:%s}", --sub);
goto EXPAND_FAILED;
- }
+ }
parse_allow_group = TRUE;
for (;;)
if (address != NULL)
{
- if (ptr != save_ptr && address[0] == *outsep)
- yield = string_catn(yield, &size, &ptr, US" ", 1);
+ if (yield->ptr != save_ptr && address[0] == *outsep)
+ yield = string_catn(yield, US" ", 1);
for (;;)
{
size_t seglen = Ustrcspn(address, outsep);
- yield = string_catn(yield, &size, &ptr, address, seglen + 1);
+ yield = string_catn(yield, address, seglen + 1);
/* If we got to the end of the string we output one character
too many. */
- if (address[seglen] == '\0') { ptr--; break; }
- yield = string_catn(yield, &size, &ptr, outsep, 1);
+ if (address[seglen] == '\0') { yield->ptr--; break; }
+ yield = string_catn(yield, outsep, 1);
address += seglen + 1;
}
/* Output a separator after the string: we will remove the
redundant final one at the end. */
- yield = string_catn(yield, &size, &ptr, outsep, 1);
+ yield = string_catn(yield, outsep, 1);
}
if (saveend == '\0') break;
/* If we have generated anything, remove the redundant final
separator. */
- if (ptr != save_ptr) ptr--;
+ if (yield->ptr != save_ptr) yield->ptr--;
parse_allow_group = FALSE;
continue;
}
if (needs_quote)
{
- yield = string_catn(yield, &size, &ptr, US"\"", 1);
+ yield = string_catn(yield, US"\"", 1);
t = sub - 1;
while (*(++t) != 0)
{
if (*t == '\n')
- yield = string_catn(yield, &size, &ptr, US"\\n", 2);
+ yield = string_catn(yield, US"\\n", 2);
else if (*t == '\r')
- yield = string_catn(yield, &size, &ptr, US"\\r", 2);
+ yield = string_catn(yield, US"\\r", 2);
else
{
if (*t == '\\' || *t == '"')
- yield = string_catn(yield, &size, &ptr, US"\\", 1);
- yield = string_catn(yield, &size, &ptr, t, 1);
+ yield = string_catn(yield, US"\\", 1);
+ yield = string_catn(yield, t, 1);
}
}
- yield = string_catn(yield, &size, &ptr, US"\"", 1);
+ yield = string_catn(yield, US"\"", 1);
}
- else yield = string_cat(yield, &size, &ptr, sub);
+ else yield = string_cat(yield, sub);
continue;
}
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, sub);
+ yield = string_cat(yield, sub);
continue;
}
while (*(++t) != 0)
{
if (!isalnum(*t))
- yield = string_catn(yield, &size, &ptr, US"\\", 1);
- yield = string_catn(yield, &size, &ptr, t, 1);
+ yield = string_catn(yield, US"\\", 1);
+ yield = string_catn(yield, t, 1);
}
continue;
}
uschar buffer[2048];
const uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset,
buffer, sizeof(buffer), FALSE);
- yield = string_cat(yield, &size, &ptr, string);
+ yield = string_cat(yield, string);
continue;
}
expand_string_message = error;
goto EXPAND_FAILED;
}
- yield = string_catn(yield, &size, &ptr, decoded, len);
+ yield = string_catn(yield, decoded, len);
continue;
}
GETUTF8INC(c, sub);
if (c > 255) c = '_';
buff[0] = c;
- yield = string_catn(yield, &size, &ptr, buff, 1);
+ yield = string_catn(yield, buff, 1);
}
continue;
}
complete = -1; /* error (RFC3629 limit) */
else
{ /* finished; output utf-8 sequence */
- yield = string_catn(yield, &size, &ptr, seq_buff, seq_len);
+ yield = string_catn(yield, seq_buff, seq_len);
index = 0;
}
}
{
if((c & 0x80) == 0) /* 1-byte sequence, US-ASCII, keep it */
{
- yield = string_catn(yield, &size, &ptr, &c, 1);
+ yield = string_catn(yield, &c, 1);
continue;
}
if((c & 0xe0) == 0xc0) /* 2-byte sequence */
if (complete != 0)
{
bytes_left = index = 0;
- yield = string_catn(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1);
+ yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
}
if ((complete == 1) && ((c & 0x80) == 0))
/* ASCII character follows incomplete sequence */
- yield = string_catn(yield, &size, &ptr, &c, 1);
+ yield = string_catn(yield, &c, 1);
}
continue;
}
string_printing(sub), error);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
string_printing(sub), error);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
string_printing(sub), error);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, s);
- DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield);
+ yield = string_cat(yield, s);
+ DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s);
continue;
}
string_printing(sub), error);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
#endif /* EXPERIMENTAL_INTERNATIONAL */
case EOP_ESCAPE:
{
const uschar * t = string_printing(sub);
- yield = string_cat(yield, &size, &ptr, t);
+ yield = string_cat(yield, t);
continue;
}
for (s = sub; (c = *s); s++)
yield = c < 127 && c != '\\'
- ? string_catn(yield, &size, &ptr, s, 1)
- : string_catn(yield, &size, &ptr, string_sprintf("\\%03o", c), 4);
+ ? string_catn(yield, s, 1)
+ : string_catn(yield, string_sprintf("\\%03o", c), 4);
continue;
}
if (error != NULL)
{
expand_string_message = string_sprintf("error in expression "
- "evaluation: %s (after processing \"%.*s\")", error, sub-save_sub,
- save_sub);
+ "evaluation: %s (after processing \"%.*s\")", error,
+ (int)(sub-save_sub), save_sub);
goto EXPAND_FAILED;
}
sprintf(CS var_buffer, PR_EXIM_ARITH, n);
- yield = string_cat(yield, &size, &ptr, var_buffer);
+ yield = string_cat(yield, var_buffer);
continue;
}
goto EXPAND_FAILED;
}
sprintf(CS var_buffer, "%d", n);
- yield = string_cat(yield, &size, &ptr, var_buffer);
+ yield = string_cat(yield, var_buffer);
continue;
}
goto EXPAND_FAILED;
}
t = readconf_printtime(n);
- yield = string_cat(yield, &size, &ptr, t);
+ yield = string_cat(yield, t);
continue;
}
#else
uschar * s = b64encode(sub, Ustrlen(sub));
#endif
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
"well-formed for \"%s\" operator", sub, name);
goto EXPAND_FAILED;
}
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
{
uschar buff[24];
(void)sprintf(CS buff, "%d", Ustrlen(sub));
- yield = string_cat(yield, &size, &ptr, buff);
+ yield = string_cat(yield, buff);
continue;
}
extract_substr(sub, value1, value2, &len);
if (ret == NULL) goto EXPAND_FAILED;
- yield = string_catn(yield, &size, &ptr, ret, len);
+ yield = string_catn(yield, ret, len);
continue;
}
(long)st.st_dev, (long)st.st_nlink, (long)st.st_uid,
(long)st.st_gid, st.st_size, (long)st.st_atime,
(long)st.st_mtime, (long)st.st_ctime);
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
if (expand_string_message != NULL)
goto EXPAND_FAILED;
s = string_sprintf("%d", vaguely_random_number((int)max));
- yield = string_cat(yield, &size, &ptr, s);
+ yield = string_cat(yield, s);
continue;
}
goto EXPAND_FAILED;
}
invert_address(reversed, sub);
- yield = string_cat(yield, &size, &ptr, reversed);
+ yield = string_cat(yield, reversed);
continue;
}
{
int len;
int newsize = 0;
- if (ptr == 0)
+ gstring * g = NULL;
+
+ if (!yield)
+ g = store_get(sizeof(gstring));
+ else if (yield->ptr == 0)
{
if (resetok) store_reset(yield);
yield = NULL;
- size = 0;
+ g = store_get(sizeof(gstring)); /* alloc _before_ calling find_variable() */
}
if (!(value = find_variable(name, FALSE, skipping, &newsize)))
{
len = Ustrlen(value);
if (!yield && newsize)
{
- yield = value;
- size = newsize;
- ptr = len;
+ yield = g;
+ yield->size = newsize;
+ yield->ptr = len;
+ yield->s = value;
}
else
- yield = string_catn(yield, &size, &ptr, value, len);
+ yield = string_catn(yield, value, len);
continue;
}
added to the string. If so, set up an empty string. Add a terminating zero. If
left != NULL, return a pointer to the terminator. */
-if (yield == NULL) yield = store_get(1);
-yield[ptr] = 0;
-if (left != NULL) *left = s;
+if (!yield)
+ yield = string_get(1);
+(void) string_from_gstring(yield);
+if (left) *left = s;
/* Any stacking store that was used above the final string is no longer needed.
In many cases the final string will be the first one that was got and so there
will be optimal store usage. */
-if (resetok) store_reset(yield + ptr + 1);
+if (resetok) store_reset(yield->s + (yield->size = yield->ptr + 1));
else if (resetok_p) *resetok_p = FALSE;
DEBUG(D_expand)
UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
"result: %s\n",
skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
- yield);
+ yield->s);
if (skipping)
debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
"skipping: result is not used\n");
}
expand_level--;
-return yield;
+return yield->s;
/* This is the failure exit: easiest to program with a goto. We still need
to update the pointer to the terminator, for cases of nested calls with "fail".
that is a bad idea, because expand_string_message is in dynamic store. */
EXPAND_FAILED:
-if (left != NULL) *left = s;
+if (left) *left = s;
DEBUG(D_expand)
{
debug_printf_indent(UTF8_VERT_RIGHT "failed to expand: %s\n",