More abstraction of the gstring API
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 5 Feb 2023 16:04:14 +0000 (16:04 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 5 Feb 2023 21:30:14 +0000 (21:30 +0000)
20 files changed:
src/src/acl.c
src/src/arc.c
src/src/deliver.c
src/src/dkim.c
src/src/exim.c
src/src/expand.c
src/src/functions.h
src/src/imap_utf7.c
src/src/log.c
src/src/lookups/dnsdb.c
src/src/lookups/ldap.c
src/src/mime.c
src/src/parse.c
src/src/pdkim/pdkim.c
src/src/readconf.c
src/src/receive.c
src/src/rfc2047.c
src/src/sieve.c
src/src/smtp_in.c
src/src/tls-gnu.c

index 5ab6747764959f5380fbc998411e538fd4a5ea7f..17d6c68da009e61d0382bb44a83de3ae38aaef36 100644 (file)
@@ -1092,7 +1092,7 @@ for (header_line * h = acl_added_headers; h; h = h->next)
   g = string_append_listele_n(g, '\n', h->text, i);
   }
 
-return g ? g->s : NULL;
+return string_from_gstring(g);
 }
 
 
index 30a66320e692f854c2e40eec765edfa6c48a635c..ef44672f8fb740747d3aeb5a31603cc15f1c78d7 100644 (file)
@@ -261,8 +261,7 @@ while ((c = *s))
            if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
              g = string_catn(g, s, 1);
          if (!g) return US"no b= value";
-         al->b.data = string_from_gstring(g);
-         al->b.len = g->ptr;
+         al->b.len = len_string_from_gstring(g, &al->b.data);
          gstring_release_unused(g);
          bend = s;
          break;
@@ -278,8 +277,7 @@ while ((c = *s))
            if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
              g = string_catn(g, s, 1);
          if (!g) return US"no bh= value";
-         al->bh.data = string_from_gstring(g);
-         al->bh.len = g->ptr;
+         al->bh.len = len_string_from_gstring(g, &al->bh.data);
          gstring_release_unused(g);
          break;
        default:
@@ -1308,7 +1306,7 @@ header_line * h = (header_line *)(al+1);
 
 /* Construct the to-be-signed AMS pseudo-header: everything but the sig. */
 
-ams_off = g->ptr;
+ams_off = gstring_length(g);
 g = string_fmt_append(g, "%s i=%d; a=rsa-sha256; c=relaxed; d=%s; s=%s",
       ARC_HDR_AMS, instance, identity, selector);      /*XXX hardwired a= */
 if (options & ARC_SIGN_OPT_TSTAMP)
@@ -1352,7 +1350,7 @@ for(col = 3; rheaders; rheaders = rheaders->prev)
 
 /* Lose the last colon from the h= list */
 
-if (g->s[g->ptr - 1] == ':') g->ptr--;
+gstring_trim_trailing(g, ':');
 
 g = string_catn(g, US";\r\n\tb=;", 7);
 
@@ -1370,7 +1368,7 @@ if (!arc_sig_from_pseudoheader(hdata, hashtype, privkey, &sig, US"AMS"))
 /* Lose the trailing semicolon from the psuedo-header, and append the signature
 (folded over lines) and termination to complete it. */
 
-g->ptr--;
+gstring_trim(g, 1);
 g = arc_sign_append_sig(g, &sig);
 
 h->slen = g->ptr - ams_off;
@@ -1548,7 +1546,7 @@ into the copies.
 static const uschar *
 arc_header_sign_feed(gstring * g)
 {
-uschar * s = string_copyn(g->s, g->ptr);
+uschar * s = string_copy_from_gstring(g);
 headers_rlist = arc_rlist_entry(headers_rlist, s, g->ptr);
 return arc_try_header(&arc_sign_ctx, headers_rlist->h, TRUE);
 }
@@ -1772,10 +1770,9 @@ if (strncmpic(ARC_HDR_AMS, g->s, ARC_HDRLEN_AMS) != 0) return US"not AMS";
 DEBUG(D_receive) debug_printf("ARC: spotted AMS header\n");
 /* Parse the AMS header */
 
-h.next = NULL;
-h.slen = g->size;
-h.text = g->s;
 memset(&al, 0, sizeof(arc_line));
+h.next = NULL;
+h.slen = len_string_from_gstring(g, &h.text);
 if ((errstr = arc_parse_line(&al, &h, ARC_HDRLEN_AMS, FALSE)))
   {
   DEBUG(D_acl) if (errstr) debug_printf("ARC: %s\n", errstr);
@@ -1857,7 +1854,8 @@ for (as = arc_verify_ctx.arcset_chain, inst = 1; as; as = as->next, inst++)
   else
     g = string_catn(g, US":", 1);
   }
-return g ? g->s : US"";
+if (!g) return US"";
+return string_from_gstring(g);
 }
 
 
@@ -1870,7 +1868,7 @@ if (arc_state)
   {
   arc_line * highest_ams;
   int start = 0;               /* Compiler quietening */
-  DEBUG(D_acl) start = g->ptr;
+  DEBUG(D_acl) start = gstring_length(g);
 
   g = string_append(g, 2, US";\n\tarc=", arc_state);
   if (arc_received_instance > 0)
@@ -1890,7 +1888,7 @@ if (arc_state)
   else if (arc_state_reason)
     g = string_append(g, 3, US" (", arc_state_reason, US")");
   DEBUG(D_acl) debug_printf("ARC:  authres '%.*s'\n",
-                 g->ptr - start - 3, g->s + start + 3);
+                 gstring_length(g) - start - 3, g->s + start + 3);
   }
 else
   DEBUG(D_acl) debug_printf("ARC:  no authres\n");
index ca31df5872329c50fca7f94d0c2d8e5d4a857b2d..084a048c938460383b005cb2670981d3c20c040d 100644 (file)
@@ -1045,7 +1045,7 @@ splitting is done; in those cases use the original field. */
 else
   {
   uschar * cmp;
-  int off = g->ptr;    /* start of the "full address" */
+  int off = gstring_length(g); /* start of the "full address" */
 
   if (addr->local_part)
     {
@@ -1338,23 +1338,25 @@ if (LOGGING(deliver_time))
 if (addr->message)
   g = string_append(g, 2, US": ", addr->message);
 
-(void) string_from_gstring(g);
+ {
+  const uschar * s = string_from_gstring(g);
 
-/* Log the deferment in the message log, but don't clutter it
-up with retry-time defers after the first delivery attempt. */
+  /* Log the deferment in the message log, but don't clutter it
+  up with retry-time defers after the first delivery attempt. */
 
-if (f.deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE)
-  deliver_msglog("%s %s\n", now, g->s);
+  if (f.deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE)
+    deliver_msglog("%s %s\n", now, s);
 
-/* Write the main log and reset the store.
-For errors of the type "retry time not reached" (also remotes skipped
-on queue run), logging is controlled by L_retry_defer. Note that this kind
-of error number is negative, and all the retry ones are less than any
-others. */
+  /* Write the main log and reset the store.
+  For errors of the type "retry time not reached" (also remotes skipped
+  on queue run), logging is controlled by L_retry_defer. Note that this kind
+  of error number is negative, and all the retry ones are less than any
+  others. */
 
 
-log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
-  "== %s", g->s);
+  log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
+    "== %s", s);
+ }
 
 store_reset(reset_point);
 return;
@@ -1417,17 +1419,19 @@ if (addr->message)
 if (LOGGING(deliver_time))
   g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
 
-(void) string_from_gstring(g);
-
 /* Do the logging. For the message log, "routing failed" for those cases,
 just to make it clearer. */
 
-if (driver_kind)
-  deliver_msglog("%s %s failed for %s\n", now, driver_kind, g->s);
-else
-  deliver_msglog("%s %s\n", now, g->s);
+ {
+  const uschar * s = string_from_gstring(g);
+
+  if (driver_kind)
+    deliver_msglog("%s %s failed for %s\n", now, driver_kind, s);
+  else
+    deliver_msglog("%s %s\n", now, s);
 
-log_write(0, LOG_MAIN, "** %s", g->s);
+  log_write(0, LOG_MAIN, "** %s", s);
+ }
 
 store_reset(reset_point);
 return;
index 0a8ab6fb3e8559a0e0afe0f3dba0896917185396..4c19f752f940120a438faf238ceecfe78815fc80 100644 (file)
@@ -83,7 +83,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
       return string_from_gstring(g);
       }
 
-    g->ptr = 0;                /* overwrite previous record */
+    gstring_reset(g);          /* overwrite previous record */
     }
 
 bad:
@@ -822,7 +822,7 @@ authres_dkim(gstring * g)
 {
 int start = 0;         /* compiler quietening */
 
-DEBUG(D_acl) start = g->ptr;
+DEBUG(D_acl) start = gstring_length(g);
 
 for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
   {
@@ -884,7 +884,7 @@ for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next)
   }
 
 DEBUG(D_acl)
-  if (g->ptr == start)
+  if (gstring_length(g) == start)
     debug_printf("DKIM: no authres\n");
   else
     debug_printf("DKIM: authres '%.*s'\n", g->ptr - start - 3, g->s + start + 3);
index c5de167c6b87b807e965f3f908bdf19133be659e..dcc71ea4534ab270fff63209d8e204dceb898e23 100644 (file)
@@ -203,15 +203,16 @@ Returns:   nothing
 */
 
 void
-set_process_info(const char *format, ...)
+set_process_info(const char * format, ...)
 {
 gstring gs = { .size = PROCESS_INFO_SIZE - 2, .ptr = 0, .s = process_info };
 gstring * g;
 int len;
+uschar * s;
 va_list ap;
 
 g = string_fmt_append(&gs, "%5d ", (int)getpid());
-len = g->ptr;
+len = gstring_length(g);
 va_start(ap, format);
 if (!string_vformat(g, 0, format, ap))
   {
@@ -219,8 +220,7 @@ if (!string_vformat(g, 0, format, ap))
   g = string_cat(&gs, US"**** string overflowed buffer ****");
   }
 g = string_catn(g, US"\n", 1);
-string_from_gstring(g);
-process_info_len = g->ptr;
+process_info_len = len_string_from_gstring(g, &s);
 DEBUG(D_process_info) debug_printf("set_process_info: %s", process_info);
 va_end(ap);
 }
@@ -1501,10 +1501,10 @@ for (int i = 0;; i++)
 #endif
 
   /* g can only be NULL if ss==p */
-  if (ss == p || g->s[g->ptr-1] != '\\') /* not continuation; done */
+  if (ss == p || gstring_last_char(g) != '\\') /* not continuation; done */
     break;
 
-  --g->ptr;                            /* drop the \ */
+  gstring_trim(g, 1);                          /* drop the \ */
   }
 
 if (had_input) return g ? string_from_gstring(g) : US"";
index a7e6e4fb3ea7dbeb1893af97b1080d0c62177e9d..1daf10044df22a35c8d4edf88b1a0463dacaea2d 100644 (file)
@@ -1667,12 +1667,13 @@ Returns:        NULL if the header does not exist, else a pointer to a new
 */
 
 static uschar *
-find_header(uschar *name, int *newsize, unsigned flags, const uschar *charset)
+find_header(uschar * name, int * newsize, unsigned flags, const uschar * charset)
 {
 BOOL found = !name;
 int len = name ? Ustrlen(name) : 0;
 BOOL comma = FALSE;
 gstring * g = NULL;
+uschar * rawhdr;
 
 for (header_line * h = header_list; h; h = h->next)
   if (h->type != htype_old && h->text)  /* NULL => Received: placeholder */
@@ -1735,8 +1736,9 @@ if (!g) return US"";
 /* That's all we do for raw header expansion. */
 
 *newsize = g->size;
+rawhdr = string_from_gstring(g);
 if (flags & FH_WANT_RAW)
-  return string_from_gstring(g);
+  return rawhdr;
 
 /* Otherwise do RFC 2047 decoding, translating the charset if requested.
 The rfc2047_decode2() function can return an error with decoded data if the
@@ -1744,12 +1746,12 @@ charset translation fails. If decoding fails, it returns NULL. */
 
 else
   {
-  uschar * error, * decoded = rfc2047_decode2(string_from_gstring(g),
+  uschar * error, * decoded = rfc2047_decode2(rawhdr,
     check_rfc2047_length, charset, '?', NULL, newsize, &error);
   if (error)
     DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n"
-      "    input was: %s\n", error, g->s);
-  return decoded ? decoded : string_from_gstring(g);
+      "    input was: %s\n", error, rawhdr);
+  return decoded ? decoded : rawhdr;
   }
 }
 
@@ -1814,7 +1816,7 @@ for (int i = 0; i < recipients_count; i++)
   s = recipients_list[i].address;
   g = string_append2_listele_n(g, US", ", s, Ustrlen(s));
   }
-return g ? g->s : NULL;
+return string_from_gstring(g);
 }
 
 
@@ -4804,7 +4806,7 @@ while (*s)
   skipping, but "break" otherwise so we get debug output for the item
   expansion. */
   {
-  int start = gstring_length(yield);
+  int expansion_start = gstring_length(yield);
   switch(item_type)
     {
     /* Call an ACL from an expansion.  We feed data in via $acl_arg1 - $acl_arg9.
@@ -4868,7 +4870,7 @@ while (*s)
 
       yield = string_append(yield, 3,
                        US"Authentication-Results: ", sub_arg[0], US"; none");
-      yield->ptr -= 6;
+      yield->ptr -= 6;                 /* ignore tha ": none" for now */
 
       yield = authres_local(yield, sub_arg[0]);
       yield = authres_iprev(yield);
@@ -5785,7 +5787,7 @@ while (*s)
 
       if (o2m >= 0) for (; oldptr < yield->ptr; oldptr++)
         {
-        uschar *m = Ustrrchr(sub[1], yield->s[oldptr]);
+        uschar * m = Ustrrchr(sub[1], yield->s[oldptr]);
         if (m)
           {
           int o = m - sub[1];
@@ -7107,7 +7109,7 @@ while (*s)
        it was for good reason */
 
        if (quoted) yield = string_catn(yield, US"\"", 1);
-       yield = string_catn(yield, g->s, g->ptr);
+       yield = gstring_append(yield, g);
        if (quoted) yield = string_catn(yield, US"\"", 1);
 
        /* @$original_domain */
@@ -7126,10 +7128,11 @@ while (*s)
     }  /* EITEM_* switch */
     /*NOTREACHED*/
 
-  DEBUG(D_expand)
-    if (yield && (start > 0 || *s))    /* only if not the sole expansion of the line */
+  DEBUG(D_expand)              /* only if not the sole expansion of the line */
+    if (yield && (expansion_start > 0 || *s))
       debug_expansion_interim(US"item-res",
-                             yield->s + start, yield->ptr - start, !!(flags & ESI_SKIPPING));
+         yield->s + expansion_start, yield->ptr - expansion_start,
+         !!(flags & ESI_SKIPPING));
   continue;
 
 NOT_ITEM: ;
@@ -7219,11 +7222,11 @@ NOT_ITEM: ;
       {
       case EOP_BASE32:
        {
-       uschar *t;
+       uschar * t;
        unsigned long int n = Ustrtoul(sub, &t, 10);
        gstring * g = NULL;
 
-       if (*t != 0)
+       if (*t)
          {
          expand_string_message = string_sprintf("argument for base32 "
            "operator is \"%s\", which is not a decimal number", sub);
@@ -7832,16 +7835,19 @@ NOT_ITEM: ;
 
        case EOP_UTF8CLEAN:
          {
-         int seq_len = 0, index = 0;
-         int bytes_left = 0;
+         int seq_len = 0, index = 0, bytes_left = 0, complete;
          long codepoint = -1;
-         int complete;
          uschar seq_buff[4];                   /* accumulate utf-8 here */
 
          /* Manually track tainting, as we deal in individual chars below */
 
-         if (!yield->s || !yield->ptr)
+         if (!yield)
+           yield = string_get_tainted(Ustrlen(sub), sub);
+         else if (!yield->s || !yield->ptr)
+           {
            yield->s = store_get(yield->size = Ustrlen(sub), sub);
+           gstring_reset(yield);
+           }
          else if (is_incompatible(yield->s, sub))
            gstring_rebuffer(yield, sub);
 
@@ -7967,7 +7973,7 @@ NOT_ITEM: ;
            goto EXPAND_FAILED;
            }
          yield = string_cat(yield, s);
-         DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s);
+         DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", string_from_gstring(yield));
          break;
          }
 
@@ -8276,7 +8282,8 @@ NOT_ITEM: ;
 
        DEBUG(D_expand)
        {
-       const uschar * s = yield->s + expansion_start;
+       const uschar * res = string_from_gstring(yield);
+       const uschar * s = res + expansion_start;
        int i = gstring_length(yield) - expansion_start;
        BOOL tainted = is_tainted(s);
 
@@ -8286,7 +8293,7 @@ NOT_ITEM: ;
          if (tainted)
            {
            debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
-           debug_print_taint(yield->s);
+           debug_print_taint(res);
            }
          }
        else
@@ -8299,7 +8306,7 @@ NOT_ITEM: ;
            debug_printf_indent("%s",
              flags & ESI_SKIPPING
              ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
-           debug_print_taint(yield->s);
+           debug_print_taint(res);
            }
          }
        }
@@ -8374,58 +8381,62 @@ if (flags & ESI_BRACE_ENDS && !*s)
 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)
-  yield = string_get(1);
-(void) string_from_gstring(yield);
-if (left) *left = s;
+ {
+  uschar * res;
 
-/* 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 (!yield)
+    yield = string_get(1);
+  res = string_from_gstring(yield);
+  if (left) *left = s;
 
-if (resetok) gstring_release_unused(yield);
-else if (resetok_p) *resetok_p = FALSE;
+  /* 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. */
 
-DEBUG(D_expand)
-  {
-  BOOL tainted = is_tainted(yield->s);
-  DEBUG(D_noutf8)
+  if (resetok) gstring_release_unused(yield);
+  else if (resetok_p) *resetok_p = FALSE;
+
+  DEBUG(D_expand)
     {
-    debug_printf_indent("|--expanding: %.*s\n", (int)(s - string), string);
-    debug_printf_indent("%sresult: %s\n",
-      flags & ESI_SKIPPING ? "|-----" : "\\_____", yield->s);
-    if (tainted)
+    BOOL tainted = is_tainted(res);
+    DEBUG(D_noutf8)
       {
-      debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
-      debug_print_taint(yield->s);
+      debug_printf_indent("|--expanding: %.*s\n", (int)(s - string), string);
+      debug_printf_indent("%sresult: %s\n",
+       flags & ESI_SKIPPING ? "|-----" : "\\_____", res);
+      if (tainted)
+       {
+       debug_printf_indent("%s     \\__", flags & ESI_SKIPPING ? "|     " : "      ");
+       debug_print_taint(res);
+       }
+      if (flags & ESI_SKIPPING)
+       debug_printf_indent("\\___skipping: result is not used\n");
       }
-    if (flags & ESI_SKIPPING)
-      debug_printf_indent("\\___skipping: result is not used\n");
-    }
-  else
-    {
-    debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
-      "expanding: %.*s\n",
-      (int)(s - string), string);
-    debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
-      "result: %s\n",
-      flags & ESI_SKIPPING ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
-      yield->s);
-    if (tainted)
+    else
       {
-      debug_printf_indent("%s",
-       flags & ESI_SKIPPING
-       ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
-      debug_print_taint(yield->s);
+      debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
+       "expanding: %.*s\n",
+       (int)(s - string), string);
+      debug_printf_indent("%s" UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
+       "result: %s\n",
+       flags & ESI_SKIPPING ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
+       res);
+      if (tainted)
+       {
+       debug_printf_indent("%s",
+         flags & ESI_SKIPPING
+         ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
+       debug_print_taint(res);
+       }
+      if (flags & ESI_SKIPPING)
+       debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
+         "skipping: result is not used\n");
       }
-    if (flags & ESI_SKIPPING)
-      debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
-       "skipping: result is not used\n");
     }
-  }
-if (textonly_p) *textonly_p = textonly;
-expand_level--;
-return yield->s;
+  if (textonly_p) *textonly_p = textonly;
+  expand_level--;
+  return res;
+ }
 
 /* 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".
index 1817144ead49f724ad819d68cb2e0311bf999c8b..961db2dc03c4cb0a925f7f7a78c8bfb67a9c45e0 100644 (file)
@@ -963,12 +963,58 @@ g->s[g->ptr] = '\0';
 return g->s;
 }
 
+static inline int
+len_string_from_gstring(gstring * g, uschar ** sp)
+{
+if (g)
+  {
+  *sp = g->s;
+  g->s[g->ptr] = '\0';
+  return g->ptr;
+  }
+else
+  {
+  *sp = NULL;
+  return 0;
+  }
+}
+
+static inline uschar *
+string_copy_from_gstring(gstring * g)
+{
+return g ? string_copyn(g->s, g->ptr) : NULL;
+}
+
 static inline unsigned
 gstring_length(const gstring * g)
 {
 return g ? (unsigned)g->ptr : 0;
 }
 
+static inline uschar
+gstring_last_char(gstring * g)
+{
+return g->s[g->ptr-1];
+}
+
+static inline void
+gstring_trim(gstring * g, unsigned amount)
+{
+g->ptr -= amount;
+}
+
+static inline void
+gstring_trim_trailing(gstring * g, uschar c)
+{
+if (gstring_last_char(g) == c) gstring_trim(g, 1);
+}
+
+static inline void
+gstring_reset(gstring * g)
+{
+g->ptr = 0;
+}
+
 
 #define gstring_release_unused(g) \
        gstring_release_unused_trc(g, __FUNCTION__, __LINE__)
@@ -1014,6 +1060,13 @@ memcpy(s, g->s, g->ptr);
 g->s = s;
 }
 
+/* Append one gstring to another */
+static inline gstring *
+gstring_append(gstring * dest, gstring * item)
+{
+return string_catn(dest, item->s, item->ptr);
+}
+
 
 # ifndef COMPILE_UTILITY
 /******************************************************************************/
index 1c09db6215ad466b10301829d548aa2ed418385e..6c9b5c17926d65768c2e39f282228206f2ee7df4 100644 (file)
@@ -200,9 +200,7 @@ iconv_close(icd);
 #endif
 
 yield = string_catn(yield, outbuf, outptr - outbuf);
-
-if (yield->s[yield->ptr-1] == '.')
-  yield->ptr--;
+gstring_trim_trailing(yield, '.');
 
 return string_from_gstring(yield);
 }
index d11b933f9aa043c0c64cbde02fe00ee646b311ce..08ece6158eb41e02f087f65d01c3f3778ea3fbc5 100644 (file)
@@ -684,11 +684,11 @@ Returns:
   length actually written, persisting an errno from write()
 */
 ssize_t
-write_to_fd_buf(int fd, const uschar *buf, size_t length)
+write_to_fd_buf(int fd, const uschar * buf, size_t length)
 {
 ssize_t wrote;
 size_t total_written = 0;
-const uschar *p = buf;
+const uschar * p = buf;
 size_t left = length;
 
 while (1)
@@ -711,6 +711,12 @@ while (1)
 return total_written;
 }
 
+static inline ssize_t
+write_gstring_to_fd_buf(int fd, const gstring * g)
+{
+return write_to_fd_buf(fd, g->s, g->ptr);
+}
+
 
 
 static void
@@ -1113,7 +1119,7 @@ if (  flags & LOG_MAIN
 
     /* Failing to write to the log is disastrous */
 
-    written_len = write_to_fd_buf(mainlogfd, g->s, g->ptr);
+    written_len = write_gstring_to_fd_buf(mainlogfd, g);
     if (written_len != g->ptr)
       {
       log_write_failed(US"main log", g->ptr, written_len);
@@ -1172,8 +1178,8 @@ if (flags & LOG_REJECT)
        g = g2;
       else             /* Buffer is full; truncate */
         {
-        g->ptr -= 100;        /* For message and separator */
-        if (g->s[g->ptr-1] == '\n') g->ptr--;
+       gstring_trim(g, 100);        /* For message and separator */
+       gstring_trim_trailing(g, '\n');
         g = string_cat(g, US"\n*** truncated ***\n");
         break;
         }
@@ -1228,7 +1234,7 @@ if (flags & LOG_REJECT)
       if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
       }
 
-    written_len = write_to_fd_buf(rejectlogfd, g->s, g->ptr);
+    written_len = write_gstring_to_fd_buf(rejectlogfd, g);
     if (written_len != g->ptr)
       {
       log_write_failed(US"reject log", g->ptr, written_len);
@@ -1263,7 +1269,7 @@ if (flags & LOG_PANIC)
     if (panic_save_buffer)
       (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
 
-    written_len = write_to_fd_buf(paniclogfd, g->s, g->ptr);
+    written_len = write_gstring_to_fd_buf(paniclogfd, g);
     if (written_len != g->ptr)
       {
       int save_errno = errno;
index 5482cd9d16cafc6b437882a4dfc5c29624067959..1563eda56d0a73b2172f8a4d8cd6b22ccdb845ee 100644 (file)
@@ -136,15 +136,12 @@ dnsdb_find(void * handle, const uschar * filename, const uschar * keystring,
 {
 int rc;
 int sep = 0;
-int defer_mode = PASS;
-int dnssec_mode = PASS;
-int save_retrans = dns_retrans;
-int save_retry =   dns_retry;
+int defer_mode = PASS, dnssec_mode = PASS;
+int save_retrans = dns_retrans, save_retry =   dns_retry;
 int type;
 int failrc = FAIL;
-const uschar *outsep = CUS"\n";
-const uschar *outsep2 = NULL;
-uschar *equals, *domain, *found;
+const uschar * outsep = CUS"\n", * outsep2 = NULL;
+uschar * equals, * domain, * found;
 
 dns_answer * dnsa = store_get_dns_answer();
 dns_scan dnss;
@@ -385,10 +382,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
       if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
         {
         for (dns_address * da = dns_address_from_rr(dnsa, rr); da; da = da->next)
-          {
-          if (yield->ptr) yield = string_catn(yield, outsep, 1);
-          yield = string_cat(yield, da->address);
-          }
+         yield = string_append_listele(yield, *outsep, da->address);
         continue;
         }
 
@@ -399,21 +393,17 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
 
       if (type == T_TXT || type == T_SPF)
         {
-        if (outsep2 == NULL)   /* output only the first item of data */
+        if (!outsep2)                  /* output only the first item of data */
           yield = string_catn(yield, US (rr->data+1), (rr->data)[0]);
         else
-          {
-          /* output all items */
-          int data_offset = 0;
-          while (data_offset < rr->size)
+          for (unsigned data_offset = 0; data_offset < rr->size; )
             {
-            uschar chunk_len = (rr->data)[data_offset++];
-            if (outsep2[0] != '\0' && data_offset != 1)
+            uschar chunk_len = (rr->data)[data_offset];
+            if (*outsep2  && data_offset != 0)
               yield = string_catn(yield, outsep2, 1);
-            yield = string_catn(yield, US ((rr->data)+data_offset), chunk_len);
+            yield = string_catn(yield, US ((rr->data) + ++data_offset), chunk_len);
             data_offset += chunk_len;
             }
-          }
         }
       else if (type == T_TLSA)
         {
index b2ad3bbbc995be796055a4d28c55f1bef511e0af..82d6954ff09592620bc2443f72a0046e308996e0 100644 (file)
@@ -326,17 +326,19 @@ if (!lcp)
     g = string_catn(NULL, ldap_url, init_ptr - ldap_url);
     g = string_fmt_append(g, "//%s:%d/", shost, port);
     }
-  string_from_gstring(g);
 
   /* Call ldap_initialize() and check the result */
+   {
+    const uschar * s = string_from_gstring(g);
 
-  DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", g->s);
-  if ((rc = ldap_initialize(&ld, CS g->s)) != LDAP_SUCCESS)
-    {
-    *errmsg = string_sprintf("ldap_initialize: (error %d) URL \"%s\"\n",
-      rc, g->s);
-    goto RETURN_ERROR;
-    }
+    DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", s);
+    if ((rc = ldap_initialize(&ld, CS s)) != LDAP_SUCCESS)
+      {
+      *errmsg = string_sprintf("ldap_initialize: (error %d) URL \"%s\"\n",
+       rc, s);
+      goto RETURN_ERROR;
+      }
+   }
   store_reset(reset_point);   /* Might as well save memory when we can */
 
 
index 7c3a33d623b83c2bb1e2e0524c7b0d8a9c819354..d4c26540a6e5279f4c1ffc7f39c54aec71edc4c9 100644 (file)
@@ -755,7 +755,7 @@ while(1)
     int result = 0;
 
     /* must find first free sequential filename */
-    for (gstring * g = string_get(64); result != -1; g->ptr = 0)
+    for (gstring * g = string_get(64); result != -1; gstring_reset(g))
       {
       struct stat mystat;
       g = string_fmt_append(g,
index 53d660869d7077413ad54abab15bee57dfab6355..ead8751ae3998c1ebfc7f7bad26a91230de943e9 100644 (file)
@@ -875,26 +875,26 @@ Returns:       pointer to the original string, if no quoting needed, or
 */
 
 const uschar *
-parse_quote_2047(const uschar *string, int len, const uschar *charset,
+parse_quote_2047(const uschar * string, int len, const uschar * charset,
   BOOL fold)
 {
 const uschar * s = string;
-int hlen, l;
+int hlen, line_off;
 BOOL coded = FALSE;
 BOOL first_byte = FALSE;
 gstring * g =
-  string_fmt_append(NULL, "=?%s?Q?", charset ? charset : US"iso-8859-1");
+  string_fmt_append(NULL, "=?%s?Q?%n", charset ? charset : US"iso-8859-1", &hlen);
 
-hlen = l = g->ptr;
+line_off = hlen;
 
 for (s = string; len > 0; s++, len--)
   {
   int ch = *s;
 
-  if (g->ptr - l > 67 && !first_byte)
+  if (g->ptr - line_off > 67 && !first_byte)
     {
     g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3);
-    l = g->ptr;
+    line_off = g->ptr;
     g = string_catn(g, g->s, hlen);
     }
 
index eb26b3864651e117b675e89a6642a9d4af9dc97e..c8f180a588c66ef8fd0fd21e23322a3ee51d75f6 100644 (file)
@@ -957,9 +957,8 @@ return;
 static int
 pdkim_header_complete(pdkim_ctx * ctx)
 {
-if ( (ctx->cur_header->ptr > 1) &&
-     (ctx->cur_header->s[ctx->cur_header->ptr-1] == '\r') )
-  --ctx->cur_header->ptr;
+if (ctx->cur_header->ptr > 1)
+  gstring_trim_trailing(ctx->cur_header, '\r');
 (void) string_from_gstring(ctx->cur_header);
 
 #ifdef EXPERIMENTAL_ARC
index 48b648bb25871162ab907d00dfbc46415c87536e..6dba11ca1b29cb1c62e7d744aa7cbaa6ddd44fc9 100644 (file)
@@ -3219,7 +3219,7 @@ if (config_file)
     g = string_cat(NULL, buf);
 
     /* If the dir does not end with a "/", append one */
-    if (g->s[g->ptr-1] != '/')
+    if (gstring_last_char(g) != '/')
       g = string_catn(g, US"/", 1);
 
     /* If the config file contains a "/", extract the directory part */
index 9bf834aafdc107c11f4744f7b34dede79ddc92cf..77665d89f6d3e3c61ac4d359fcc40248c237e4c8 100644 (file)
@@ -4214,7 +4214,8 @@ if (message_logs && !blackholed_by)
       }
     else
       {
-      uschar *now = tod_stamp(tod_log);
+      uschar * now = tod_stamp(tod_log);
+      /* Drop the initial "<= " */
       fprintf(message_log, "%s Received from %s\n", now, g->s+3);
       if (f.deliver_freeze) fprintf(message_log, "%s frozen by %s\n", now,
         frozen_by);
@@ -4266,7 +4267,7 @@ if (  smtp_input && sender_host_address && !f.sender_host_notsocket
 
       /* Re-use the log line workspace */
 
-      g->ptr = 0;
+      gstring_reset(g);
       g = string_cat(g, US"SMTP connection lost after final dot");
       g = add_host_info_for_log(g);
       log_write(0, LOG_MAIN, "%s", string_from_gstring(g));
index c40518a5d340b91be1979d4a172597703c988c76..d5e33b9b1a6ec127e18789dbb85b87e21971e603 100644 (file)
@@ -192,9 +192,9 @@ rfc2047_decode2(uschar *string, BOOL lencheck, const uschar *target,
 {
 int size = Ustrlen(string);
 size_t dlen;
-uschar *dptr;
-gstring *yield;
-uschar *mimeword, *q1, *q2, *endword;
+uschar * dptr;
+gstring * yield;
+uschar * mimeword, * q1, * q2, * endword;
 
 *error = NULL;
 mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr);
@@ -210,17 +210,14 @@ building the result as we go. The result may be longer than the input if it is
 translated into a multibyte code such as UTF-8. That's why we use the dynamic
 string building code. */
 
-yield = store_get(sizeof(gstring) + ++size, string);
-yield->size = size;
-yield->ptr = 0;
-yield->s = US(yield + 1);
+yield = string_get_tainted(++size, string);
 
 while (mimeword)
   {
 
-  #if HAVE_ICONV
+#if HAVE_ICONV
   iconv_t icd = (iconv_t)(-1);
-  #endif
+#endif
 
   if (mimeword != string)
     yield = string_catn(yield, string, mimeword - string);
@@ -233,7 +230,7 @@ while (mimeword)
   of long strings - the RFC puts limits on the length, but it's best to be
   robust. */
 
-  #if HAVE_ICONV
+#if HAVE_ICONV
   *q1 = 0;
   if (target && strcmpic(target, mimeword+2) != 0)
     if ((icd = iconv_open(CS target, CS(mimeword+2))) == (iconv_t)-1)
@@ -241,14 +238,14 @@ while (mimeword)
         target, mimeword+2, strerror(errno),
         (errno == EINVAL)? " (maybe unsupported conversion)" : "");
   *q1 = '?';
-  #endif
+#endif
 
   while (dlen > 0)
     {
     uschar *tptr = NULL;   /* Stops compiler warning */
     int tlen = -1;
 
-    #if HAVE_ICONV
+#if HAVE_ICONV
     uschar tbuffer[256];
     uschar *outptr = tbuffer;
     size_t outleft = sizeof(tbuffer);
@@ -281,7 +278,7 @@ while (mimeword)
         }
       }
 
-    #endif
+#endif
 
     /* No charset translation is happening or there was a translation error;
     just set up the original as the string to be added, and mark it all used.
@@ -305,9 +302,9 @@ while (mimeword)
     yield = string_catn(yield, tptr, tlen);
     }
 
-  #if HAVE_ICONV
+#if HAVE_ICONV
   if (icd != (iconv_t)(-1))  iconv_close(icd);
-  #endif
+#endif
 
   /* Update string past the MIME word; skip any white space if the next thing
   is another MIME word. */
index 0b347e48df68b059190312063aa05a68bce0f485..4793d5756c9a1a6f451a4e8d916b1b8d097d6b95 100644 (file)
@@ -439,8 +439,7 @@ if (*uri && *uri!='?')
       {
       gstring * g = string_catn(NULL, start, uri-start);
 
-      to.character = string_from_gstring(g);
-      to.length = g->ptr;
+      to.length = len_string_from_gstring(g, &to.character);
       if (uri_decode(&to)==-1)
         {
         filter->errmsg=US"Invalid URI encoding";
@@ -472,8 +471,7 @@ if (*uri=='?')
       {
       gstring * g = string_catn(NULL, start, uri-start);
 
-      hname.character = string_from_gstring(g);
-      hname.length = g->ptr;
+      hname.length = len_string_from_gstring(g, &hname.character);
       if (uri_decode(&hname)==-1)
         {
         filter->errmsg=US"Invalid URI encoding";
@@ -494,8 +492,7 @@ if (*uri=='?')
       {
       gstring * g = string_catn(NULL, start, uri-start);
 
-      hname.character = string_from_gstring(g);
-      hname.length = g->ptr;
+      hname.length = len_string_from_gstring(g, &hname.character);
       if (uri_decode(&hvalue)==-1)
         {
         filter->errmsg=US"Invalid URI encoding";
@@ -541,8 +538,7 @@ if (*uri=='?')
         g = string_catn(g, hvalue.character, hvalue.length);
         g = string_catn(g, CUS "\n", 1);
 
-       header->character = string_from_gstring(g);
-       header->length = g->ptr;
+       hname.length = len_string_from_gstring(g, &hname.character);
         }
       }
     if (*uri=='&') ++uri;
@@ -1482,10 +1478,7 @@ if (*filter->pc=='"') /* quoted string */
       ++filter->pc;
 
       if (g)
-       {
-       data->character = string_from_gstring(g);
-       data->length = g->ptr;
-       }
+       data->length = len_string_from_gstring(g, &data->character);
       else
        data->character = US"\0";
       /* that way, there will be at least one character allocated */
@@ -1569,10 +1562,7 @@ else if (Ustrncmp(filter->pc,CUS "text:",5)==0) /* multiline string */
 #endif
         {
        if (g)
-         {
-         data->character = string_from_gstring(g);
-         data->length = g->ptr;
-         }
+         data->length = len_string_from_gstring(g, &data->character);
        else
          data->character = US"\0";
        /* that way, there will be at least one character allocated */
@@ -3303,7 +3293,7 @@ while (*filter->pc)
 
           if (subject.length==-1)
             {
-            uschar *subject_def;
+            uschar * subject_def;
 
             subject_def = expand_string(US"${if def:header_subject {true}{false}}");
             if (subject_def && Ustrcmp(subject_def,"true")==0)
@@ -3312,13 +3302,12 @@ while (*filter->pc)
 
               expand_header(&subject,&str_subject);
               g = string_catn(g, subject.character, subject.length);
-             subject.character = string_from_gstring(g);
-              subject.length = g->ptr;
+             subject.length = len_string_from_gstring(g, &subject.character);
               }
             else
               {
-              subject.character=US"Automated reply";
-              subject.length=Ustrlen(subject.character);
+              subject.character = US"Automated reply";
+              subject.length = Ustrlen(subject.character);
               }
             }
 
index 04b20d27ce262c81c0776d37dfc670bb46fceec3..a13af867aaa2c010b80c0a04e3eb81dc588c7f2d 100644 (file)
@@ -4508,7 +4508,7 @@ while (done <= 0)
 
       if (fl.esmtp)
        {
-       g->s[3] = '-';
+       g->s[3] = '-';  /* overwrite the space after the SMTP response code */
 
        /* I'm not entirely happy with this, as an MTA is supposed to check
        that it has enough room to accept a message of maximum size before
@@ -4639,9 +4639,9 @@ while (done <= 0)
                  first = FALSE;
                  fl.auth_advertised = TRUE;
                  }
-               saveptr = g->ptr;
+               saveptr = gstring_length(g);
                g = string_catn(g, US" ", 1);
-               g = string_cat (g, au->public_name);
+               g = string_cat(g, au->public_name);
                while (++saveptr < g->ptr) g->s[saveptr] = toupper(g->s[saveptr]);
                au->advertised = TRUE;
                }
@@ -4704,25 +4704,29 @@ while (done <= 0)
       /* Terminate the string (for debug), write it, and note that HELO/EHLO
       has been seen. */
 
+       {
+       uschar * ehlo_resp;
+       int len = len_string_from_gstring(g, &ehlo_resp);
 #ifndef DISABLE_TLS
-      if (tls_in.active.sock >= 0)
-       (void)tls_write(NULL, g->s, g->ptr,
+       if (tls_in.active.sock >= 0)
+         (void) tls_write(NULL, ehlo_resp, len,
 # ifndef DISABLE_PIPE_CONNECT
-                       fl.pipe_connect_acceptable && pipeline_connect_sends());
+                         fl.pipe_connect_acceptable && pipeline_connect_sends());
 # else
-                       FALSE);
+                         FALSE);
 # endif
-      else
+       else
 #endif
-       (void) fwrite(g->s, 1, g->ptr, smtp_out);
-
-      DEBUG(D_receive) for (const uschar * t, * s = string_from_gstring(g);
-                           s && (t = Ustrchr(s, '\r'));
-                           s = t + 2)                          /* \r\n */
-         debug_printf("%s %.*s\n",
-                       s == g->s ? "SMTP>>" : "      ",
-                       (int)(t - s), s);
-      fl.helo_seen = TRUE;
+         (void) fwrite(ehlo_resp, 1, len, smtp_out);
+
+       DEBUG(D_receive) for (const uschar * t, * s = ehlo_resp;
+                             s && (t = Ustrchr(s, '\r'));
+                             s = t + 2)                                /* \r\n */
+           debug_printf("%s %.*s\n",
+                         s == g->s ? "SMTP>>" : "      ",
+                         (int)(t - s), s);
+       fl.helo_seen = TRUE;
+       }
 
       /* Reset the protocol and the state, abandoning any previous message. */
       received_protocol =
index b47fabf1d0cc91dfaf50e1a11b19fffa5e2dd72f..f3f70d2e07b1fc7b53a67227d3f4905b99b8fa2c 100644 (file)
@@ -2302,7 +2302,7 @@ old_pool = store_pool;
 
     for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1);
 
-    tlsp->ver = string_copyn(g->s, g->ptr);
+    tlsp->ver = string_copy_from_gstring(g);
     for (uschar * p = US tlsp->ver; *p; p++)
       if (*p == '-') { *p = '\0'; break; }     /* TLS1.0-PKIX -> TLS1.0 */