From 4ed70df2fbc849b080aea7977321daeec81db6f0 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 23 Dec 2013 14:22:05 +0000 Subject: [PATCH] Rework printf functions. --- src/printf.c | 341 +++++++++++++++++++++++++-------------------------- src/printf.h | 23 +++- 2 files changed, 187 insertions(+), 177 deletions(-) diff --git a/src/printf.c b/src/printf.c index b03e1475f..5c425b5f9 100644 --- a/src/printf.c +++ b/src/printf.c @@ -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; } diff --git a/src/printf.h b/src/printf.h index 9d3921c3a..105b08503 100644 --- a/src/printf.h +++ b/src/printf.h @@ -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' @@ -55,13 +54,25 @@ * %% % * */ -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 -- 2.39.5