aboutsummaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-11-30 19:26:06 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-11-30 19:26:06 +0300
commit4dce4df79683f5562d557ef80f8e2a648aacf5e8 (patch)
tree411bbc76c26b974340047d854d51bbc42f331e0e /src/util.c
parent569df8dd24eb159b069ca7f5efa6a6ba3336d63d (diff)
downloadrspamd-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.c422
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
*/