]> source.dussan.org Git - rspamd.git/commitdiff
Rework printf functions.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 23 Dec 2013 14:22:05 +0000 (14:22 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 23 Dec 2013 14:22:05 +0000 (14:22 +0000)
src/printf.c
src/printf.h

index b03e1475fff04935977ae02bae8d08c33ce1f12c..5c425b5f997a737197fbf19f1a07ebdc0936263b 100644 (file)
@@ -169,65 +169,115 @@ rspamd_sprintf_num (gchar *buf, gchar *last, guint64 ui64, gchar zero,
        return ((gchar *)memcpy (buf, p, len)) + len;
 }
 
-gint
+struct rspamd_printf_char_buf {
+       char *begin;
+       char *pos;
+       glong remain;
+};
+
+static glong
+rspamd_printf_append_char (const gchar *buf, glong buflen, gpointer ud)
+{
+       struct rspamd_printf_char_buf *dst = (struct rspamd_printf_char_buf *)ud;
+       glong wr;
+
+       if (dst->remain <= 0) {
+               return dst->remain;
+       }
+
+       wr = MIN (dst->remain, buflen);
+       memcpy (dst->pos, buf, wr);
+       dst->remain -= wr;
+       dst->pos += wr;
+
+       return wr;
+}
+
+static glong
+rspamd_printf_append_file (const gchar *buf, glong buflen, gpointer ud)
+{
+       FILE *dst = (FILE *)ud;
+
+       return fwrite (buf, 1, buflen, dst);
+}
+
+static glong
+rspamd_printf_append_gstring (const gchar *buf, glong buflen, gpointer ud)
+{
+       GString *dst = (GString *)ud;
+
+       g_string_append_len (dst, buf, buflen);
+
+       return buflen;
+}
+
+glong
 rspamd_fprintf (FILE *f, const gchar *fmt, ...)
 {
        va_list   args;
-    gchar buf[BUFSIZ];
-    gint r;
+       glong r;
 
        va_start (args, fmt);
-       rspamd_vsnprintf (buf, sizeof (buf), fmt, args);
+       r = rspamd_vprintf_common (rspamd_printf_append_file, f, fmt, args);
        va_end (args);
 
-    r = fprintf (f, "%s", buf);
-
-    return r;
+       return r;
 }
 
-gint
+glong
 rspamd_log_fprintf (FILE *f, const gchar *fmt, ...)
 {
        va_list   args;
-    gchar buf[BUFSIZ];
-    gint r;
+       glong r;
 
        va_start (args, fmt);
-       rspamd_vsnprintf (buf, sizeof (buf), fmt, args);
+       r = rspamd_vprintf_common (rspamd_printf_append_file, f, fmt, args);
        va_end (args);
 
-    r = fprintf (f, "%s\n", buf);
-    fflush (f);
+       fflush (f);
 
-    return r;
+       return r;
 }
 
-gint
-rspamd_sprintf (gchar *buf, const gchar *fmt, ...)
+
+glong
+rspamd_snprintf (gchar *buf, glong max, const gchar *fmt, ...)
 {
-       gchar   *p;
-       va_list   args;
+       gchar *r;
+       va_list args;
 
        va_start (args, fmt);
-       p = rspamd_vsnprintf (buf, /* STUB */ 65536, fmt, args);
+       r = rspamd_vsnprintf (buf, max, fmt, args);
        va_end (args);
 
-       return p - buf;
+       return (r - buf);
 }
 
+gchar *
+rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
+{
+       struct rspamd_printf_char_buf dst;
+
+       dst.begin = buf;
+       dst.pos = dst.begin;
+       dst.remain = max - 1;
+       (void)rspamd_vprintf_common (rspamd_printf_append_char, &dst, fmt, args);
+       *dst.pos = '\0';
 
-gint
-rspamd_snprintf (gchar *buf, glong max, const gchar *fmt, ...)
+       return dst.pos;
+}
+
+glong
+rspamd_printf_gstring (GString *s, const gchar *fmt, ...)
 {
-       gchar   *p;
-       va_list   args;
+       va_list args;
+       glong r;
 
        va_start (args, fmt);
-       p = rspamd_vsnprintf (buf, max - 1, fmt, args);
+       r = rspamd_vprintf_common (rspamd_printf_append_gstring, s, fmt, args);
        va_end (args);
-       *p = '\0';
 
-       return p - buf;
+       return r;
 }
 
 gchar *
@@ -284,13 +334,25 @@ rspamd_escape_string (gchar *dst, const gchar *src, glong len)
        return buf;
 }
 
-gchar *
-rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
+#define RSPAMD_PRINTF_APPEND(buf, len)                                                                                 \
+    do {                                                                                                                                               \
+    wr = func ((buf), (len), apd);                                                                                             \
+    if (wr <= 0) {                                                                                                                             \
+        goto oob;                                                                                                                              \
+    }                                                                                                                                                  \
+    written += wr;                                                                                                                             \
+    fmt ++;                                                                                                                                            \
+    buf_start = fmt;                                                                                                                   \
+    } while(0)
+
+glong
+rspamd_vprintf_common (rspamd_printf_append_func func, gpointer apd, const gchar *fmt, va_list args)
 {
-       gchar              *p, zero, *last;
+       gchar               zero, numbuf[G_ASCII_DTOSTR_BUF_SIZE], *p, *last, c;
+       const gchar        *buf_start = fmt;
        gint                d;
        long double         f, scale;
-       size_t              len, slen;
+       glong               written = 0, wr, slen;
        gint64              i64;
        guint64             ui64;
        guint               width, sign, hex, humanize, bytes, frac_width, i;
@@ -298,13 +360,7 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
        GString            *gs;
        gboolean            bv;
 
-       if (max <= 0) {
-               return buf;
-       }
-
-       last = buf + max;
-
-       while (*fmt && buf < last) {
+       while (*fmt) {
 
                /*
                 * "buf < last" means that we could copy at least one character:
@@ -313,6 +369,15 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
 
                if (*fmt == '%') {
 
+                       /* Append what we have in buf */
+                       if (fmt > buf_start) {
+                               wr = func (buf_start, fmt - buf_start, apd);
+                               if (wr <= 0) {
+                                       goto oob;
+                               }
+                               written += wr;
+                       }
+
                        i64 = 0;
                        ui64 = 0;
 
@@ -323,7 +388,7 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
                        bytes = 0;
                        humanize = 0;
                        frac_width = 0;
-                       slen = (size_t) -1;
+                       slen = -1;
 
                        while (*fmt >= '0' && *fmt <= '9') {
                                width = width * 10 + *fmt++ - '0';
@@ -376,10 +441,10 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
                                case '*':
                                        d = (gint)va_arg (args, gint);
                                        if (G_UNLIKELY (d < 0)) {
-                                               msg_err ("crititcal error: size is less than 0");
-                                               g_assert (0);
+                                               msg_err ("critical error: size is less than 0");
+                                               return 0;
                                        }
-                                       slen = (size_t)d;
+                                       slen = (glong)d;
                                        fmt++;
                                        continue;
 
@@ -395,61 +460,28 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
 
                        case 'V':
                                v = va_arg (args, f_str_t *);
-
-                               len = v->len;
-                               len = (buf + len < last) ? len : (size_t) (last - buf);
-
-                               buf = ((gchar *)memcpy (buf, v->begin, len)) + len;
-                               fmt++;
+                               RSPAMD_PRINTF_APPEND (v->begin, v->len);
 
                                continue;
 
                        case 'v':
                                gs = va_arg (args, GString *);
-                               len = gs->len;
-                               len = (buf + len < last) ? len : (size_t) (last - buf);
-
-                               buf = ((gchar *)memcpy (buf, gs->str, len)) + len;
-                               fmt++;
-                               break;
-
-                       case 's':
-                               p = va_arg(args, gchar *);
-                               if (p == NULL) {
-                                       p = "(NULL)";
-                               }
-
-                               if (slen == (size_t) -1) {
-                                       while (*p && buf < last) {
-                                               *buf++ = *p++;
-                                       }
-
-                               } else {
-                                       len = (buf + slen < last) ? slen : (size_t) (last - buf);
-
-                                       buf = ((gchar *)memcpy (buf, p, len)) + len;
-                               }
-
-                               fmt++;
+                               RSPAMD_PRINTF_APPEND (gs->str, gs->len);
 
                                continue;
 
-                       case 'S':
-                               p = va_arg(args, gchar *);
+                       case 's':
+                               p = va_arg (args, gchar *);
                                if (p == NULL) {
                                        p = "(NULL)";
                                }
 
-                               if (slen == (size_t) -1) {
-                                       buf = rspamd_escape_string (buf, p, last - buf);
-
-                               } else {
-                                       len = (buf + slen < last) ? slen : (size_t) (last - buf);
-
-                                       buf = rspamd_escape_string (buf, p, len);
+                               if (slen == -1) {
+                                       /* NULL terminated string */
+                                       slen = strlen (p);
                                }
 
-                               fmt++;
+                               RSPAMD_PRINTF_APPEND (p, slen);
 
                                continue;
 
@@ -510,57 +542,28 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
 
 
                        case 'f':
-                               f = (double) va_arg (args, double);
-                               if (f < 0) {
-                                       *buf++ = '-';
-                                       f = -f;
+                       case 'F':
+                               if (*fmt == 'f') {
+                                       f = (long double) va_arg (args, double);
                                }
-
-                               ui64 = (gint64) f;
-
-                               buf = rspamd_sprintf_num (buf, last, ui64, zero, 0, width);
-
-                               if (frac_width) {
-
-                                       if (buf < last) {
-                                               *buf++ = '.';
-                                       }
-
-                                       scale = 1.0;
-
-                                       for (i = 0; i < frac_width; i++) {
-                                               scale *= 10.0;
-                                       }
-
-                                       /*
-                                       * (gint64) cast is required for msvc6:
-                                       * it can not convert guint64 to double
-                                       */
-                                       ui64 = (guint64) ((f - (gint64) ui64) * scale);
-
-                                       buf = rspamd_sprintf_num (buf, last, ui64, '0', 0, frac_width);
+                               else {
+                                       f = (long double) va_arg (args, long double);
                                }
-
-                               fmt++;
-
-                               continue;
-
-                       case 'F':
-                               f = (long double) va_arg (args, long double);
-
+                               p = numbuf;
+                               last = p + sizeof (numbuf);
                                if (f < 0) {
-                                       *buf++ = '-';
+                                       *p++ = '-';
                                        f = -f;
                                }
 
                                ui64 = (gint64) f;
 
-                               buf = rspamd_sprintf_num (buf, last, ui64, zero, 0, width);
+                               p = rspamd_sprintf_num (p, last, ui64, zero, 0, width);
 
                                if (frac_width) {
 
-                                       if (buf < last) {
-                                               *buf++ = '.';
+                                       if (p < last) {
+                                               *p++ = '.';
                                        }
 
                                        scale = 1.0;
@@ -575,50 +578,32 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
                                        */
                                        ui64 = (guint64) ((f - (gint64) ui64) * scale);
 
-                                       buf = rspamd_sprintf_num (buf, last, ui64, '0', 0, frac_width);
+                                       p = rspamd_sprintf_num (p, last, ui64, '0', 0, frac_width);
                                }
 
-                               fmt++;
+                               slen = p - numbuf;
+                               RSPAMD_PRINTF_APPEND (numbuf, slen);
 
                                continue;
 
                        case 'g':
-                               f = (long double) va_arg (args, double);
-
-                               if (f < 0) {
-                                       *buf++ = '-';
-                                       f = -f;
-                               }
-                               g_ascii_formatd (buf, last - buf, "%g", (double)f);
-                               buf += strlen (buf);
-                               fmt++;
-
-                               continue;
-
-                       case 'b':
-                               bv = (gboolean) va_arg (args, double);
-                               if (bv) {
-                                       len = MIN (last - buf, 4);
-                                       memcpy (buf, "true", len);
+                       case 'G':
+                               if (*fmt == 'g') {
+                                       f = (long double) va_arg (args, double);
                                }
                                else {
-                                       len = MIN (last - buf, 5);
-                                       memcpy (buf, "false", len);
+                                       f = (long double) va_arg (args, long double);
                                }
-                               fmt++;
 
-                               continue;
+                               g_ascii_formatd (numbuf, sizeof (numbuf), "%g", (double)f);
+                               slen = strlen (numbuf);
+                               RSPAMD_PRINTF_APPEND (numbuf, slen);
 
-                       case 'G':
-                               f = (long double) va_arg (args, long double);
+                               continue;
 
-                               if (f < 0) {
-                                       *buf++ = '-';
-                                       f = -f;
-                               }
-                               g_ascii_formatd (buf, last - buf, "%g", (double)f);
-                               buf += strlen (buf);
-                               fmt++;
+                       case 'b':
+                               bv = (gboolean) va_arg (args, double);
+                               RSPAMD_PRINTF_APPEND (bv ? "true" : "false", bv ? 4 : 5);
 
                                continue;
 
@@ -631,39 +616,43 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
                                break;
 
                        case 'c':
-                               d = va_arg (args, gint);
-                               *buf++ = (gchar) (d & 0xff);
-                               fmt++;
+                               c = va_arg (args, gint);
+                               c &= 0xff;
+                               RSPAMD_PRINTF_APPEND (&c, 1);
 
                                continue;
 
                        case 'Z':
-                               *buf++ = '\0';
-                               fmt++;
+                               c = '\0';
+                               RSPAMD_PRINTF_APPEND (&c, 1);
 
                                continue;
 
                        case 'N':
-                               *buf++ = LF;
-                               fmt++;
+                               c = LF;
+                               RSPAMD_PRINTF_APPEND (&c, 1);
 
                                continue;
 
                        case '%':
-                               *buf++ = '%';
-                               fmt++;
+                               c = '%';
+                               RSPAMD_PRINTF_APPEND (&c, 1);
 
                                continue;
 
                        default:
-                               *buf++ = *fmt++;
+                               c = *fmt;
+                               RSPAMD_PRINTF_APPEND (&c, 1);
 
                                continue;
                        }
 
+                       /* Print number */
+                       p = numbuf;
+                       last = p + sizeof (numbuf);
                        if (sign) {
                                if (i64 < 0) {
-                                       *buf++ = '-';
+                                       *p++ = '-';
                                        ui64 = (guint64) -i64;
 
                                } else {
@@ -672,19 +661,29 @@ rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args)
                        }
 
                        if (!humanize) {
-                               buf = rspamd_sprintf_num (buf, last, ui64, zero, hex, width);
+                               p = rspamd_sprintf_num (p, last, ui64, zero, hex, width);
                        }
                        else {
-                               buf = rspamd_humanize_number (buf, last, ui64, bytes);
+                               p = rspamd_humanize_number (p, last, ui64, bytes);
                        }
+                       slen = p - numbuf;
+                       RSPAMD_PRINTF_APPEND (numbuf, slen);
 
+               } else {
                        fmt++;
+               }
+       }
 
-               } else {
-                       *buf++ = *fmt++;
+       /* Finish buffer */
+       if (fmt > buf_start) {
+               wr = func (buf_start, fmt - buf_start, apd);
+               if (wr <= 0) {
+                       goto oob;
                }
+               written += wr;
        }
 
-       return buf;
+oob:
+       return written;
 }
 
index 9d3921c3ab2386d5f2b27c88cb719dda9e4bc909..105b085037d28e01841afdc4f455eedc69f75034 100644 (file)
@@ -47,7 +47,6 @@
  *     %V                                                  f_str_t *
  *     %v                          GString *
  *     %s                                                  null-terminated string
- *     %S                                                  ascii null-terminated string
  *     %*s                                             length and string
  *     %Z                                                  '\0'
  *     %N                                                  '\n'
  *     %%                                                  %
  *
  */
-gint rspamd_sprintf (gchar *buf, const gchar *fmt, ...);
-gint rspamd_fprintf (FILE *f, const gchar *fmt, ...);
-gint rspamd_log_fprintf (FILE *f, const gchar *fmt, ...);
-gint rspamd_snprintf (gchar *buf, glong max, const gchar *fmt, ...);
+
+/**
+ * Callback used for common printf operations
+ * @param buf buffer to append
+ * @param buflen lenght of the buffer
+ * @param ud opaque pointer
+ * @return number of characters written
+ */
+typedef glong (*rspamd_printf_append_func)(const gchar *buf, glong buflen, gpointer ud);
+
+glong rspamd_fprintf (FILE *f, const gchar *fmt, ...);
+glong rspamd_log_fprintf (FILE *f, const gchar *fmt, ...);
+glong rspamd_snprintf (gchar *buf, glong max, const gchar *fmt, ...);
 gchar *rspamd_vsnprintf (gchar *buf, glong max, const gchar *fmt, va_list args);
+glong rspamd_printf_gstring (GString *s, const gchar *fmt, ...);
 
-/*
+glong rspamd_vprintf_common (rspamd_printf_append_func func, gpointer apd, const gchar *fmt, va_list args);
+
+/**
  * Escape rspamd string to write it to log file or other 7 bit prefferable places
  *
  * @param dst destination string