diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-11-30 19:26:06 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-11-30 19:26:06 +0300 |
commit | 4dce4df79683f5562d557ef80f8e2a648aacf5e8 (patch) | |
tree | 411bbc76c26b974340047d854d51bbc42f331e0e /src/util.c | |
parent | 569df8dd24eb159b069ca7f5efa6a6ba3336d63d (diff) | |
download | rspamd-4dce4df79683f5562d557ef80f8e2a648aacf5e8.tar.gz rspamd-4dce4df79683f5562d557ef80f8e2a648aacf5e8.zip |
* Adopt printf function from nginx for comfortable printing of some data types (fixed strings, pids etc)
* Fix work of http maps (they were broken in some places before)
* Fix sync of statfiles (not fully tested yet)
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 422 |
1 files changed, 418 insertions, 4 deletions
diff --git a/src/util.c b/src/util.c index 4eb0a4341..c549426c5 100644 --- a/src/util.c +++ b/src/util.c @@ -53,6 +53,7 @@ static uint32_t log_written; static time_t last_check; static char *io_buf = NULL; static gboolean log_buffered = FALSE; +static u_char* rspamd_sprintf_num (u_char *buf, u_char *last, uint64_t ui64, u_char zero, unsigned int hexadecimal, unsigned int width); int make_socket_nonblocking (int fd) @@ -778,10 +779,12 @@ rspamd_log_function (GLogLevelFlags log_level, const char *fmt, ...) { static char logbuf[BUFSIZ]; va_list vp; + u_char *end; if (log_level <= log_params.cfg->log_level) { va_start (vp, fmt); - vsnprintf (logbuf, sizeof (logbuf), fmt, vp); + end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, vp); + *end = '\0'; va_end (vp); log_params.log_func (NULL, log_level, logbuf, log_params.cfg); } @@ -856,7 +859,7 @@ file_log_function (const gchar * log_domain, GLogLevelFlags log_level, const gch } strftime (timebuf, sizeof (timebuf), "%b %d %H:%M:%S", tms); - snprintf (tmpbuf, sizeof (tmpbuf), "#%d: %s rspamd ", (int)getpid (), timebuf); + rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "#%P: %s rspamd %Z", getpid (), timebuf); fprintf (cfg->logf, "%s%s" CRLF, tmpbuf, message); log_written++; } @@ -951,8 +954,8 @@ calculate_check_time (struct timespec *begin, int resolution) diff = (ts.tv_sec - begin->tv_sec) * 1000. + /* Seconds */ (ts.tv_nsec - begin->tv_nsec) / 1000000.; /* Nanoseconds */ - sprintf (fmt, "%%.%df", resolution); - snprintf (res, sizeof (res), fmt, diff); + rspamd_sprintf (fmt, "%%.%df", resolution); + rspamd_snprintf (res, sizeof (res), fmt, diff); return (const char *)res; } @@ -1184,5 +1187,416 @@ get_statfile_by_symbol (statfile_pool_t *pool, struct classifier_config *ccf, #endif /* RSPAMD_MAIN */ /* + * supported formats: + * %[0][width][x][X]O off_t + * %[0][width]T time_t + * %[0][width][u][x|X]z ssize_t/size_t + * %[0][width][u][x|X]d int/u_int + * %[0][width][u][x|X]l long + * %[0][width|m][u][x|X]i int/ngx_int_t + * %[0][width][u][x|X]D int32_t/uint32_t + * %[0][width][u][x|X]L int64_t/uint64_t + * %[0][width][.width]f float + * %P pid_t + * %r rlim_t + * %p void * + * %V f_str_t * + * %s null-terminated string + * %*s length and string + * %Z '\0' + * %N '\n' + * %c char + * %% % + * + */ + + +int +rspamd_sprintf (u_char *buf, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start (args, fmt); + p = rspamd_vsnprintf (buf, /* STUB */ 65536, fmt, args); + va_end (args); + + return p - buf; +} + + +int +rspamd_snprintf (u_char *buf, size_t max, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start (args, fmt); + p = rspamd_vsnprintf (buf, max, fmt, args); + va_end (args); + + return p - buf; +} + + +u_char * +rspamd_vsnprintf (u_char *buf, size_t max, const char *fmt, va_list args) +{ + u_char *p, zero, *last; + int d; + float f, scale; + size_t len, slen; + int64_t i64; + uint64_t ui64; + unsigned int width, sign, hex, max_width, frac_width, i; + f_str_t *v; + + if (max == 0) { + return buf; + } + + last = buf + max; + + while (*fmt && buf < last) { + + /* + * "buf < last" means that we could copy at least one character: + * the plain character, "%%", "%c", and minus without the checking + */ + + if (*fmt == '%') { + + i64 = 0; + ui64 = 0; + + zero = (u_char) ((*++fmt == '0') ? '0' : ' '); + width = 0; + sign = 1; + hex = 0; + max_width = 0; + frac_width = 0; + slen = (size_t) -1; + + while (*fmt >= '0' && *fmt <= '9') { + width = width * 10 + *fmt++ - '0'; + } + + + for ( ;; ) { + switch (*fmt) { + + case 'u': + sign = 0; + fmt++; + continue; + + case 'm': + max_width = 1; + fmt++; + continue; + + case 'X': + hex = 2; + sign = 0; + fmt++; + continue; + + case 'x': + hex = 1; + sign = 0; + fmt++; + continue; + + case '.': + fmt++; + + while (*fmt >= '0' && *fmt <= '9') { + frac_width = frac_width * 10 + *fmt++ - '0'; + } + + break; + + case '*': + slen = va_arg(args, size_t); + fmt++; + continue; + + default: + break; + } + + break; + } + + + switch (*fmt) { + + case 'V': + v = va_arg (args, f_str_t *); + + len = v->len; + len = (buf + len < last) ? len : (size_t) (last - buf); + + buf = ((u_char *)memcpy (buf, v->begin, len)) + len; + fmt++; + + continue; + + case 's': + p = va_arg(args, u_char *); + + if (slen == (size_t) -1) { + while (*p && buf < last) { + *buf++ = *p++; + } + + } else { + len = (buf + slen < last) ? slen : (size_t) (last - buf); + + buf = ((u_char *)memcpy (buf, p, len)) + len; + } + + fmt++; + + continue; + + case 'O': + i64 = (int64_t) va_arg (args, off_t); + sign = 1; + break; + + case 'P': + i64 = (int64_t) va_arg (args, pid_t); + sign = 1; + break; + + case 'T': + i64 = (int64_t) va_arg (args, time_t); + sign = 1; + break; + + case 'z': + if (sign) { + i64 = (int64_t) va_arg (args, ssize_t); + } else { + ui64 = (uint64_t) va_arg (args, size_t); + } + break; + + case 'd': + if (sign) { + i64 = (int64_t) va_arg (args, int); + } else { + ui64 = (uint64_t) va_arg (args, unsigned int); + } + break; + + case 'l': + if (sign) { + i64 = (int64_t) va_arg(args, long); + } else { + ui64 = (uint64_t) va_arg(args, unsigned long); + } + break; + + case 'D': + if (sign) { + i64 = (int64_t) va_arg(args, int32_t); + } else { + ui64 = (uint64_t) va_arg(args, uint32_t); + } + break; + + case 'L': + if (sign) { + i64 = va_arg (args, int64_t); + } else { + ui64 = va_arg (args, uint64_t); + } + break; + + + case 'f': + f = (float) va_arg (args, double); + + if (f < 0) { + *buf++ = '-'; + f = -f; + } + + ui64 = (int64_t) 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; + } + + /* + * (int64_t) cast is required for msvc6: + * it can not convert uint64_t to double + */ + ui64 = (uint64_t) ((f - (int64_t) ui64) * scale); + + buf = rspamd_sprintf_num (buf, last, ui64, '0', 0, frac_width); + } + + fmt++; + + continue; + + case 'p': + ui64 = (uintptr_t) va_arg (args, void *); + hex = 2; + sign = 0; + zero = '0'; + width = sizeof (void *) * 2; + break; + + case 'c': + d = va_arg (args, int); + *buf++ = (u_char) (d & 0xff); + fmt++; + + continue; + + case 'Z': + *buf++ = '\0'; + fmt++; + + continue; + + case 'N': + *buf++ = LF; + fmt++; + + continue; + + case '%': + *buf++ = '%'; + fmt++; + + continue; + + default: + *buf++ = *fmt++; + + continue; + } + + if (sign) { + if (i64 < 0) { + *buf++ = '-'; + ui64 = (uint64_t) -i64; + + } else { + ui64 = (uint64_t) i64; + } + } + + buf = rspamd_sprintf_num (buf, last, ui64, zero, hex, width); + + fmt++; + + } else { + *buf++ = *fmt++; + } + } + + return buf; +} + + +static u_char * +rspamd_sprintf_num (u_char *buf, u_char *last, uint64_t ui64, u_char zero, + unsigned int hexadecimal, unsigned int width) +{ + u_char *p, temp[sizeof ("18446744073709551615")]; + size_t len; + uint32_t ui32; + static u_char hex[] = "0123456789abcdef"; + static u_char HEX[] = "0123456789ABCDEF"; + + p = temp + sizeof(temp); + + if (hexadecimal == 0) { + + if (ui64 <= G_MAXUINT32) { + + /* + * To divide 64-bit numbers and to find remainders + * on the x86 platform gcc and icc call the libc functions + * [u]divdi3() and [u]moddi3(), they call another function + * in its turn. On FreeBSD it is the qdivrem() function, + * its source code is about 170 lines of the code. + * The glibc counterpart is about 150 lines of the code. + * + * For 32-bit numbers and some divisors gcc and icc use + * a inlined multiplication and shifts. For example, + * unsigned "i32 / 10" is compiled to + * + * (i32 * 0xCCCCCCCD) >> 35 + */ + + ui32 = (uint32_t) ui64; + + do { + *--p = (u_char) (ui32 % 10 + '0'); + } while (ui32 /= 10); + + } else { + do { + *--p = (u_char) (ui64 % 10 + '0'); + } while (ui64 /= 10); + } + + } else if (hexadecimal == 1) { + + do { + + /* the "(uint32_t)" cast disables the BCC's warning */ + *--p = hex[(uint32_t) (ui64 & 0xf)]; + + } while (ui64 >>= 4); + + } else { /* hexadecimal == 2 */ + + do { + + /* the "(uint32_t)" cast disables the BCC's warning */ + *--p = HEX[(uint32_t) (ui64 & 0xf)]; + + } while (ui64 >>= 4); + } + + /* zero or space padding */ + + len = (temp + sizeof (temp)) - p; + + while (len++ < width && buf < last) { + *buf++ = zero; + } + + /* number safe copy */ + + len = (temp + sizeof (temp)) - p; + + if (buf + len > last) { + len = last - buf; + } + + return ((u_char *)memcpy (buf, p, len)) + len; +} + + +/* * vi:ts=4 */ |