aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binlog.c3
-rw-r--r--src/buffer.c7
-rw-r--r--src/controller.c4
-rw-r--r--src/main.c30
-rw-r--r--src/main.h4
-rw-r--r--src/map.c57
-rw-r--r--src/map.h2
-rw-r--r--src/statfile_sync.c2
-rw-r--r--src/util.c422
-rw-r--r--src/util.h4
10 files changed, 482 insertions, 53 deletions
diff --git a/src/binlog.c b/src/binlog.c
index f006cd368..830c650fe 100644
--- a/src/binlog.c
+++ b/src/binlog.c
@@ -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 {
diff --git a/src/buffer.c b/src/buffer.c
index 6e862664a..d55b88d4d 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -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
diff --git a/src/controller.c b/src/controller.c
index 31bad233a..2c541b2e9 100644
--- a/src/controller.c
+++ b/src/controller.c
@@ -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) {
diff --git a/src/main.c b/src/main.c
index 994d6c2cc..5512e30f1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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) {
diff --git a/src/main.h b/src/main.h
index 0ecc38aa9..8aea5a661 100644
--- a/src/main.h
+++ b/src/main.h
@@ -36,9 +36,13 @@
#ifdef CRLF
#undef CRLF
+#undef CR
+#undef LF
#endif
#define CRLF "\r\n"
+#define CR '\r'
+#define LF '\n'
/**
* Process type: main or worker
diff --git a/src/map.c b/src/map.c
index d78ac96e1..6a96728e3 100644
--- 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;
diff --git a/src/map.h b/src/map.h
index c5029b958..fa8669de3 100644
--- 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;
};
diff --git a/src/statfile_sync.c b/src/statfile_sync.c
index d28e0d208..300bb215e 100644
--- a/src/statfile_sync.c
+++ b/src/statfile_sync.c
@@ -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;
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
*/
diff --git a/src/util.h b/src/util.h
index 4d8955351..6c14d7469 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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