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 | |
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')
-rw-r--r-- | src/binlog.c | 3 | ||||
-rw-r--r-- | src/buffer.c | 7 | ||||
-rw-r--r-- | src/controller.c | 4 | ||||
-rw-r--r-- | src/main.c | 30 | ||||
-rw-r--r-- | src/main.h | 4 | ||||
-rw-r--r-- | src/map.c | 57 | ||||
-rw-r--r-- | src/map.h | 2 | ||||
-rw-r--r-- | src/statfile_sync.c | 2 | ||||
-rw-r--r-- | src/util.c | 422 | ||||
-rw-r--r-- | src/util.h | 4 |
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 @@ -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; @@ -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 |