]> source.dussan.org Git - rspamd.git/commitdiff
* Adopt printf function from nginx for comfortable printing of some data types (fixed...
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 30 Nov 2009 16:26:06 +0000 (19:26 +0300)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 30 Nov 2009 16:26:06 +0000 (19:26 +0300)
* Fix work of http maps (they were broken in some places before)
* Fix sync of statfiles (not fully tested yet)

src/binlog.c
src/buffer.c
src/controller.c
src/main.c
src/main.h
src/map.c
src/map.h
src/statfile_sync.c
src/util.c
src/util.h

index f006cd3687e81b77b0bc363759f25b90d5cf0279..830c650fe5f962aaebf8fe5a20b6e8c5ada0ed95 100644 (file)
@@ -253,7 +253,7 @@ write_binlog_tree (struct rspamd_binlog *log, GTree *nodes)
        idx->len = g_tree_nnodes (nodes) * sizeof (struct rspamd_binlog_element);
        if (lseek (log->fd, log->metaindex->indexes[log->metaindex->last_index], SEEK_SET) == -1) {
                unlock_file (log->fd, FALSE);
-               msg_info ("binlog_insert: cannot seek in file: %s, error: %s, seek: %ld, op: insert index", log->filename, 
+               msg_info ("binlog_insert: cannot seek in file: %s, error: %s, seek: %L, op: insert index", log->filename, 
                                strerror (errno), log->metaindex->indexes[log->metaindex->last_index]);
                return FALSE;
        }
@@ -456,6 +456,7 @@ binlog_sync (struct rspamd_binlog *log, uint64_t from_rev, uint64_t *from_time,
        idx = &idxb->indexes[from_rev % BINLOG_IDX_LEN];
        if (is_first && idx->time != *from_time) {
                res = FALSE;
+               *from_time = 0;
                goto end;
        }
        else {
index 6e862664acbed84b748c034ce9f3fe50bf0d8752..d55b88d4d9bd4d150f9b13252de9172215de1414 100644 (file)
@@ -70,7 +70,7 @@ write_buffers (int fd, rspamd_io_dispatcher_t * d, gboolean is_delayed)
                        buf->pos += r;
                        if (BUFREMAIN (buf) != 0) {
                                /* Continue with this buffer */
-                               msg_debug ("write_buffers: wrote %ld bytes of %ld", (long int)r, (long int)buf->data->len);
+                               msg_debug ("write_buffers: wrote %z bytes of %z", r, buf->data->len);
                                continue;
                        }
                }
@@ -185,7 +185,8 @@ read_buffers (int fd, rspamd_io_dispatcher_t * d, gboolean skip_read)
                        *pos += r;
                        *len += r;
                }
-               msg_debug ("read_buffers: read %ld characters, policy is %s, watermark is: %ld", (long int)r, d->policy == BUFFER_LINE ? "LINE" : "CHARACTER", (long int)d->nchars);
+               msg_debug ("read_buffers: read %z characters, policy is %s, watermark is: %z", r, 
+                               d->policy == BUFFER_LINE ? "LINE" : "CHARACTER", d->nchars);
        }
 
        saved_policy = d->policy;
@@ -369,7 +370,7 @@ rspamd_set_dispatcher_policy (rspamd_io_dispatcher_t * d, enum io_policy policy,
                }
        }
 
-       msg_debug ("rspamd_set_dispatcher_policy: new input length watermark is %ld", (long int)d->nchars);
+       msg_debug ("rspamd_set_dispatcher_policy: new input length watermark is %uz", d->nchars);
 }
 
 gboolean
index 31bad233a0cbe5aceacecf679536dee34e1c9121..2c541b2e96e56d75bf5dd2d36324dc5f9f606c39 100644 (file)
@@ -200,7 +200,7 @@ write_whole_statfile (struct controller_session *session, char *symbol, struct c
        /* Begin to copy all blocks into array */
        statfile_get_revision (statfile, &rev, (time_t *)&time);
        len = statfile->cur_section.length * sizeof (struct rspamd_binlog_element);
-       i = snprintf (out_buf, sizeof (out_buf), "%lu %lu %lu", (long unsigned)rev, (long unsigned)time, (long unsigned)len);
+       i = snprintf (out_buf, sizeof (out_buf), "%lu %lu %lu" CRLF, (long unsigned)rev, (long unsigned)time, (long unsigned)len);
        rspamd_dispatcher_write (session->dispatcher, out_buf, i, TRUE, FALSE);
        out = memory_pool_alloc (session->session_pool, len);
 
@@ -289,7 +289,7 @@ process_sync_command (struct controller_session *session, char **args)
        }
 
        while (binlog_sync (binlog, rev, &time, &data)) {
-               r = snprintf (out_buf, sizeof (out_buf), "%lu %lu %lu", (long unsigned)rev, (long unsigned)time, (long unsigned)data->len);
+               r = snprintf (out_buf, sizeof (out_buf), "%lu %lu %lu" CRLF, (long unsigned)rev, (long unsigned)time, (long unsigned)data->len);
                rspamd_dispatcher_write (session->dispatcher, out_buf, r, TRUE, FALSE);
                if (!rspamd_dispatcher_write (session->dispatcher, data->data, data->len, TRUE, FALSE)) {
                        if (data != NULL) {
index 994d6c2ccf96da35bfcc5567e74870e7d02ac1df..5512e30f1cb37986bd0450f2928e04c550a25678 100644 (file)
@@ -117,6 +117,7 @@ sig_handler (int signo, siginfo_t *info, void *unused)
 static const char *
 chldsigcode (int code) {
        switch (code) {
+#ifdef CLD_EXITED
                case CLD_EXITED:
                        return "Child exited normally";
                case CLD_KILLED:
@@ -125,6 +126,7 @@ chldsigcode (int code) {
                        return "Child has terminated abnormally and created a core file";
                case CLD_TRAPPED:
                        return "Traced child has trapped";
+#endif
                default:
                        return "Unknown reason";
        }
@@ -138,12 +140,12 @@ print_signals_info ()
 
        while ((inf = g_queue_pop_head (signals_info))) {
                if (inf->si_signo == SIGCHLD) {
-                       msg_info ("main: got SIGCHLD from child: %ld; reason: '%s'",
-                                       (long int)inf->si_pid, chldsigcode (inf->si_code));
+                       msg_info ("main: got SIGCHLD from child: %P; reason: '%s'",
+                                       inf->si_pid, chldsigcode (inf->si_code));
                }
                else {
-                       msg_info ("main: got signal: '%s'; received from pid: %ld; uid: %ld",
-                                       g_strsignal (inf->si_signo), (long int)inf->si_pid, (long int)inf->si_uid);
+                       msg_info ("main: got signal: '%s'; received from pid: %P; uid: %l",
+                                       g_strsignal (inf->si_signo), inf->si_pid, (long int)inf->si_uid);
                }
                g_free (inf);
        }
@@ -349,26 +351,26 @@ fork_worker (struct rspamd_main *rspamd, struct worker_conf *cf)
                        case TYPE_CONTROLLER:
                                setproctitle ("controller process");
                                pidfile_close (rspamd->pfh);
-                               msg_info ("fork_worker: starting controller process %d", getpid ());
+                               msg_info ("fork_worker: starting controller process %P", getpid ());
                                start_controller (cur);
                                break;
                        case TYPE_LMTP:
                                setproctitle ("lmtp process");
                                pidfile_close (rspamd->pfh);
-                               msg_info ("fork_worker: starting lmtp process %d", getpid ());
+                               msg_info ("fork_worker: starting lmtp process %P", getpid ());
                                start_lmtp_worker (cur);
                                break;
                        case TYPE_FUZZY:
                                setproctitle ("fuzzy storage");
                                pidfile_close (rspamd->pfh);
-                               msg_info ("fork_worker: starting fuzzy storage process %d", getpid ());
+                               msg_info ("fork_worker: starting fuzzy storage process %P", getpid ());
                                start_fuzzy_storage (cur);
                                break;
                        case TYPE_WORKER:
                        default:
                                setproctitle ("worker process");
                                pidfile_close (rspamd->pfh);
-                               msg_info ("fork_worker: starting worker process %d", getpid ());
+                               msg_info ("fork_worker: starting worker process %P", getpid ());
                                start_worker (cur);
                                break;
                        }
@@ -523,7 +525,7 @@ kill_old_workers (gpointer key, gpointer value, gpointer unused)
        struct rspamd_worker         *w = value;
 
        kill (w->pid, SIGUSR2);
-       msg_info ("rspamd_restart: send signal to worker %ld", (long int)w->pid);
+       msg_info ("rspamd_restart: send signal to worker %P", w->pid);
 }
 
 static gboolean
@@ -534,7 +536,7 @@ wait_for_workers (gpointer key, gpointer value, gpointer unused)
 
        waitpid (w->pid, &res, 0);
 
-       msg_debug ("main(cleaning): %s process %d terminated", get_process_type (w->type), w->pid);
+       msg_debug ("main(cleaning): %s process %P terminated", get_process_type (w->type), w->pid);
        g_free (w);
 
        return TRUE;
@@ -811,14 +813,14 @@ main (int argc, char **argv, char **env)
 
                                if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
                                        /* Normal worker termination, do not fork one more */
-                                       msg_info ("main: %s process %d terminated normally", get_process_type (cur->type), cur->pid);
+                                       msg_info ("main: %s process %P terminated normally", get_process_type (cur->type), cur->pid);
                                }
                                else {
                                        if (WIFSIGNALED (res)) {
-                                               msg_warn ("main: %s process %d terminated abnormally by signal: %d", get_process_type (cur->type), cur->pid, WTERMSIG (res));
+                                               msg_warn ("main: %s process %P terminated abnormally by signal: %d", get_process_type (cur->type), cur->pid, WTERMSIG (res));
                                        }
                                        else {
-                                               msg_warn ("main: %s process %d terminated abnormally", get_process_type (cur->type), cur->pid);
+                                               msg_warn ("main: %s process %P terminated abnormally", get_process_type (cur->type), cur->pid);
                                        }
                                        /* Fork another worker in replace of dead one */
                                        delay_fork (cur->cf);
@@ -827,7 +829,7 @@ main (int argc, char **argv, char **env)
                                g_free (cur);
                        }
                        else {
-                               msg_err ("main: got SIGCHLD, but pid %ld is not found in workers hash table, something goes wrong", (long int)wrk);
+                               msg_err ("main: got SIGCHLD, but pid %P is not found in workers hash table, something goes wrong", wrk);
                        }
                }
                if (do_restart) {
index 0ecc38aa95c0b975aa643ada1b10f42cf75b19d1..8aea5a661003ed26887a82286601a8a115c0f8ac 100644 (file)
 
 #ifdef CRLF
 #undef CRLF
+#undef CR
+#undef LF
 #endif
 
 #define CRLF "\r\n"
+#define CR '\r'
+#define LF '\n'
 
 /** 
  * Process type: main or worker
index d78ac96e1b86ff6fca06cd8aba8e04d3d4c723d2..6a96728e3b6efd244a149290cd3af68b6ac782fd 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -214,7 +214,7 @@ static                          gboolean
 read_http_chunked (u_char * buf, size_t len, struct rspamd_map *map, struct http_map_data *data, struct map_cb_data *cbdata)
 {
        u_char                         *p = buf, *remain;
-       uint32_t                        skip = 0, rlen;
+       uint32_t                        skip = 0;
 
        if (data->chunk == 0) {
                /* Read first chunk data */
@@ -229,8 +229,8 @@ read_http_chunked (u_char * buf, size_t len, struct rspamd_map *map, struct http
                remain = map->read_callback (map->pool, p, len - (data->chunk_read - data->chunk), cbdata);
                if (remain != NULL && remain != p) {
                        /* copy remaining buffer to start of buffer */
-                       rlen = len - (remain - p);
-                       memmove (p, remain, rlen);
+                       data->rlen = len - (remain - p);
+                       memmove (p, remain, data->rlen);
                }
 
                p = buf + (len - (data->chunk_read - data->chunk));
@@ -249,10 +249,10 @@ read_http_chunked (u_char * buf, size_t len, struct rspamd_map *map, struct http
        }
 
        remain = map->read_callback (map->pool, p, len, cbdata);
-       if (remain != NULL && remain != p) {
+       if (remain != NULL && remain != p + len) {
                /* copy remaining buffer to start of buffer */
-               rlen = len - (remain - p);
-               memmove (p, remain, rlen);
+               data->rlen = len - (remain - p);
+               memmove (p, remain, data->rlen);
        }
 
        return TRUE;
@@ -261,20 +261,20 @@ read_http_chunked (u_char * buf, size_t len, struct rspamd_map *map, struct http
 static                          gboolean
 read_http_common (struct rspamd_map *map, struct http_map_data *data, struct http_reply *reply, struct map_cb_data *cbdata, int fd)
 {
-       u_char                          buf[BUFSIZ], *remain, *pos;
-       int                             rlen;
+       u_char                         *remain, *pos;
        ssize_t                         r;
        char                           *te;
-
-       rlen = 0;
-       if ((r = read (fd, buf + rlen, sizeof (buf) - rlen - 1)) > 0) {
-               buf[r++] = '\0';
-               remain = parse_http_reply (buf, r - 1, reply);
-               if (remain != NULL && remain != buf) {
-                       /* copy remaining buffer to start of buffer */
-                       rlen = r - (remain - buf);
-                       memmove (buf, remain, rlen);
-                       r = rlen;
+       
+       if ((r = read (fd, data->read_buf + data->rlen, sizeof (data->read_buf) - data->rlen)) > 0) {
+               r += data->rlen;
+               data->rlen = 0;
+               remain = parse_http_reply (data->read_buf, r, reply);
+               if (remain != NULL && remain != data->read_buf) {
+                       /* copy remaining data->read_buffer to start of data->read_buffer */
+                       data->rlen = r - (remain - data->read_buf);
+                       memmove (data->read_buf, remain, data->rlen);
+                       r = data->rlen;
+                       data->rlen = 0;
                }
                if (r <= 0) {
                        return TRUE;
@@ -288,20 +288,20 @@ read_http_common (struct rspamd_map *map, struct http_map_data *data, struct htt
                                /* Do not read anything */
                                return FALSE;
                        }
-                       pos = buf;
+                       pos = data->read_buf;
                        if (!data->chunked && (te = g_hash_table_lookup (reply->headers, "Transfer-Encoding")) != NULL) {
                                if (g_ascii_strcasecmp (te, "chunked") == 0) {
                                        data->chunked = TRUE;
                                }
                        }
                        if (data->chunked) {
-                               return read_http_chunked (buf, r - 1, map, data, cbdata);
+                               return read_http_chunked (data->read_buf, r, map, data, cbdata);
                        }
-                       remain = map->read_callback (map->pool, pos, r - 1, cbdata);
-                       if (remain != NULL && remain != pos) {
-                               /* copy remaining buffer to start of buffer */
-                               rlen = r - (remain - pos);
-                               memmove (pos, remain, rlen);
+                       remain = map->read_callback (map->pool, pos, r, cbdata);
+                       if (remain != NULL && remain != pos + r) {
+                               /* copy remaining data->read_buffer to start of data->read_buffer */
+                               data->rlen = r - (remain - pos);
+                               memmove (pos, remain, data->rlen);
                        }
                }
        }
@@ -466,6 +466,7 @@ add_map (const char *map_line, map_cb_t read_callback, map_fin_cb_t fin_callback
                hdata->host = memory_pool_alloc (map_pool, hostend - def + 1);
                g_strlcpy (hdata->host, def, hostend - def + 1);
                hdata->path = memory_pool_strdup (map_pool, p);
+               hdata->rlen = 0;
                /* Now try to resolve */
                if (!inet_aton (hdata->host, &hdata->addr)) {
                        /* Resolve using dns */
@@ -531,11 +532,11 @@ abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct ma
                                                func (data->cur_data, s, hash_fill);
                                        }
                                        s = str;
-                                       start = p;
                                }
-                               while (*p == '\r' || *p == '\n') {
+                               while ((*p == '\r' || *p == '\n') && p - chunk < len) {
                                        p++;
                                }
+                               start = p;
                        }
                        else {
                                *s = *p;
@@ -546,7 +547,7 @@ abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct ma
                        /* SKIP_COMMENT */
                case 1:
                        if (*p == '\r' || *p == '\n') {
-                               while (*p == '\r' || *p == '\n') {
+                               while ((*p == '\r' || *p == '\n') && p - chunk < len) {
                                        p++;
                                }
                                s = str;
index c5029b958c4853e3b82183d6cd203716609c7bdd..fa8669de30aa6af52186341ee75bb9fe0821753b 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -28,6 +28,8 @@ struct http_map_data {
        char *host;
        time_t last_checked;
        gboolean chunked;
+       u_char read_buf[BUFSIZ];
+       uint32_t rlen;
        uint32_t chunk;
        uint32_t chunk_read;
 };
index d28e0d208fdbf1ff035c4083267144cbc58062d4..300bb215e998c99d395b14b5fed8eb3bcc51642e 100644 (file)
@@ -180,7 +180,7 @@ sync_read (f_str_t * in, void *arg)
                case SYNC_STATE_READ_LINE:
                        /* Try to parse line from server */
                        if (!parse_revision_line (ctx, in)) {
-                               msg_info ("sync_read: cannot parse line");
+                               msg_info ("sync_read: cannot parse line: %S", in);
                                rspamd_remove_dispatcher (ctx->dispatcher);
                                ctx->is_busy = FALSE;
                                return FALSE;
index 4eb0a4341159b71e382716c98c4e41668d9c7939..c549426c572f018bc78b97f08402513661cb6c1c 100644 (file)
@@ -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;
 }
@@ -1183,6 +1186,417 @@ 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
  */
index 4d89553516fcfa6f96d023237fe9b259afc993db..6c14d74698598b9654e89462d8373654bad6f369 100644 (file)
@@ -89,4 +89,8 @@ stat_file_t* get_statfile_by_symbol (statfile_pool_t *pool, struct classifier_co
                const char *symbol, struct statfile **st, gboolean try_create);
 #endif
 
+int rspamd_sprintf (u_char *buf, const char *fmt, ...);
+int rspamd_snprintf (u_char *buf, size_t max, const char *fmt, ...);
+u_char *rspamd_vsnprintf (u_char *buf, size_t max, const char *fmt, va_list args);
+
 #endif