details: https://hg.nginx.org/njs/rev/ea483ef4631a branches: changeset: 743:ea483ef4631a user: Dmitry Volyntsev <xei...@nginx.com> date: Wed Jan 30 18:47:59 2019 +0300 description: Imported nxt_sprintf.c.
diffstat: Makefile | 2 + njs/njs_core.h | 1 + nxt/Makefile | 13 + nxt/nxt_sprintf.c | 587 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_sprintf.h | 16 + nxt/nxt_stub.h | 2 - nxt/nxt_types.h | 19 + 7 files changed, 638 insertions(+), 2 deletions(-) diffs (723 lines): diff -r c7e18bd12776 -r ea483ef4631a Makefile --- a/Makefile Tue Jan 29 01:30:04 2019 +0800 +++ b/Makefile Wed Jan 30 18:47:59 2019 +0300 @@ -51,6 +51,7 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mp.o \ + $(NXT_BUILDDIR)/nxt_sprintf.o \ ar -r -c $(NXT_BUILDDIR)/libnjs.a \ $(NXT_BUILDDIR)/njs_shell.o \ @@ -97,6 +98,7 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mp.o \ + $(NXT_BUILDDIR)/nxt_sprintf.o \ all: test lib_test diff -r c7e18bd12776 -r ea483ef4631a njs/njs_core.h --- a/njs/njs_core.h Tue Jan 29 01:30:04 2019 +0800 +++ b/njs/njs_core.h Wed Jan 30 18:47:59 2019 +0300 @@ -27,6 +27,7 @@ #include <nxt_time.h> #include <nxt_malloc.h> #include <nxt_mp.h> +#include <nxt_sprintf.h> #include <njs.h> #include <njs_vm.h> diff -r c7e18bd12776 -r ea483ef4631a nxt/Makefile --- a/nxt/Makefile Tue Jan 29 01:30:04 2019 +0800 +++ b/nxt/Makefile Wed Jan 30 18:47:59 2019 +0300 @@ -22,6 +22,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_mp.o \ + $(NXT_BUILDDIR)/nxt_sprintf.o \ ar -r -c $(NXT_BUILDDIR)/libnxt.a \ $(NXT_BUILDDIR)/nxt_diyfp.o \ @@ -41,6 +42,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mp.o \ + $(NXT_BUILDDIR)/nxt_sprintf.o \ $(NXT_BUILDDIR)/nxt_diyfp.o: \ $(NXT_LIB)/nxt_types.h \ @@ -244,4 +246,15 @@ NXT_LIB = nxt -I$(NXT_LIB) \ $(NXT_LIB)/nxt_mp.c +$(NXT_BUILDDIR)/nxt_sprintf.o: \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_alignment.h \ + $(NXT_LIB)/nxt_sprintf.h \ + $(NXT_LIB)/nxt_sprintf.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_sprintf.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_sprintf.c + include $(NXT_LIB)/test/Makefile diff -r c7e18bd12776 -r ea483ef4631a nxt/nxt_sprintf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_sprintf.c Wed Jan 30 18:47:59 2019 +0300 @@ -0,0 +1,587 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_auto_config.h> +#include <nxt_types.h> +#include <nxt_clang.h> +#include <nxt_stub.h> +#include <nxt_string.h> +#include <nxt_sprintf.h> + +#include <math.h> +#include <float.h> +#include <string.h> + + +/* + * Supported formats: + * + * %[0][width][x][X]O nxt_off_t + * %[0][width]T nxt_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 nxt_int_t/nxt_uint_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 double, max valid number fits to %18.15f + * + * %d int + * + * %s null-terminated string + * %*s length and string + * + * %p void * + * %b nxt_bool_t + * %V nxt_str_t * + * %Z '\0' + * %n '\n' + * %c char + * %% % + * + * Reserved: + * %t ptrdiff_t + * %S null-terminated wchar string + * %C wchar + * %[0][width][u][x|X]Q int128_t/uint128_t + */ + + +u_char * +nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start(args, fmt); + p = nxt_vsprintf(buf, end, fmt, args); + va_end(args); + + return p; +} + + +/* + * nxt_sprintf_t is used: + * to pass several parameters of nxt_integer() via single pointer + * and to store little used variables of nxt_vsprintf(). + */ + +typedef struct { + u_char *end; + const u_char *hex; + uint32_t width; + int32_t frac_width; + uint8_t max_width; + u_char padding; +} nxt_sprintf_t; + + +static u_char *nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64); +static u_char *nxt_number(nxt_sprintf_t *spf, u_char *buf, double n); + + +/* A right way of "f == 0.0". */ +#define nxt_double_is_zero(f) (fabs(f) <= FLT_EPSILON) + + +u_char * +nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) +{ + u_char *p; + int d; + double f, i; + size_t length; + int64_t i64; + uint64_t ui64, frac; + nxt_str_t *v; + nxt_uint_t scale, n; + nxt_bool_t sign; + nxt_sprintf_t spf; + + static const u_char hexadecimal[16] = "0123456789abcdef"; + static const u_char HEXADECIMAL[16] = "0123456789ABCDEF"; + static const u_char nan[] = "[nan]"; + static const u_char infinity[] = "[infinity]"; + + spf.end = end; + + while (*fmt != '\0' && buf < end) { + + /* + * "buf < end" means that we could copy at least one character: + * a plain character, "%%", "%c", or a minus without test. + */ + + if (*fmt != '%') { + *buf++ = *fmt++; + continue; + } + + fmt++; + + /* Test some often used text formats first. */ + + switch (*fmt) { + + case 'V': + fmt++; + v = va_arg(args, nxt_str_t *); + + if (nxt_fast_path(v != NULL)) { + length = v->length; + p = v->start; + goto copy; + } + + continue; + + case 's': + p = va_arg(args, u_char *); + + if (nxt_fast_path(p != NULL)) { + while (*p != '\0' && buf < end) { + *buf++ = *p++; + } + } + + fmt++; + continue; + + case '*': + length = va_arg(args, size_t); + + fmt++; + + if (*fmt == 's') { + fmt++; + p = va_arg(args, u_char *); + + if (nxt_fast_path(p != NULL)) { + goto copy; + } + } + + continue; + + default: + break; + } + + spf.hex = NULL; + spf.width = 0; + spf.frac_width = -1; + spf.max_width = 0; + spf.padding = (*fmt == '0') ? '0' : ' '; + + sign = 1; + + i64 = 0; + ui64 = 0; + + while (*fmt >= '0' && *fmt <= '9') { + spf.width = spf.width * 10 + (*fmt++ - '0'); + } + + + for ( ;; ) { + switch (*fmt) { + + case 'u': + sign = 0; + fmt++; + continue; + + case 'm': + spf.max_width = 1; + fmt++; + continue; + + case 'X': + spf.hex = HEXADECIMAL; + sign = 0; + fmt++; + continue; + + case 'x': + spf.hex = hexadecimal; + sign = 0; + fmt++; + continue; + + case '.': + fmt++; + spf.frac_width = 0; + + while (*fmt >= '0' && *fmt <= '9') { + spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; + } + + break; + + default: + break; + } + + break; + } + + + switch (*fmt) { + + case 'O': + i64 = (int64_t) va_arg(args, nxt_off_t); + sign = 1; + goto number; + + case 'T': + i64 = (int64_t) va_arg(args, nxt_time_t); + sign = 1; + goto number; + + case 'z': + if (sign) { + i64 = (int64_t) va_arg(args, ssize_t); + } else { + ui64 = (uint64_t) va_arg(args, size_t); + } + goto number; + + case 'i': + if (sign) { + i64 = (int64_t) va_arg(args, nxt_int_t); + } else { + ui64 = (uint64_t) va_arg(args, nxt_uint_t); + } + + if (spf.max_width != 0) { + spf.width = NXT_INT_T_LEN; + } + + goto number; + + case 'd': + if (sign) { + i64 = (int64_t) va_arg(args, int); + } else { + ui64 = (uint64_t) va_arg(args, u_int); + } + goto number; + + case 'l': + if (sign) { + i64 = (int64_t) va_arg(args, long); + } else { + ui64 = (uint64_t) va_arg(args, u_long); + } + goto number; + + case 'D': + if (sign) { + i64 = (int64_t) va_arg(args, int32_t); + } else { + ui64 = (uint64_t) va_arg(args, uint32_t); + } + goto number; + + case 'L': + if (sign) { + i64 = va_arg(args, int64_t); + } else { + ui64 = va_arg(args, uint64_t); + } + goto number; + + case 'b': + ui64 = (uint64_t) va_arg(args, nxt_bool_t); + sign = 0; + goto number; + + case 'f': + fmt++; + + f = va_arg(args, double); + + if (f < 0) { + *buf++ = '-'; + f = -f; + } + + if (nxt_slow_path(isnan(f))) { + p = (u_char *) nan; + length = nxt_length(nan); + + goto copy; + + } else if (nxt_slow_path(isinf(f))) { + p = (u_char *) infinity; + length = nxt_length(infinity); + + goto copy; + } + + (void) modf(f, &i); + frac = 0; + + if (spf.frac_width > 0) { + + scale = 1; + for (n = spf.frac_width; n != 0; n--) { + scale *= 10; + } + + frac = (uint64_t) ((f - i) * scale + 0.5); + + if (frac == scale) { + i += 1; + frac = 0; + } + } + + buf = nxt_number(&spf, buf, i); + + if (spf.frac_width > 0) { + + if (buf < end) { + *buf++ = '.'; + + spf.hex = NULL; + spf.padding = '0'; + spf.width = spf.frac_width; + buf = nxt_integer(&spf, buf, frac); + } + + } else if (spf.frac_width < 0) { + f = modf(f, &i); + + if (!nxt_double_is_zero(f) && buf < end) { + *buf++ = '.'; + + while (!nxt_double_is_zero(f) && buf < end) { + f *= 10; + f = modf(f, &i); + *buf++ = (u_char) i + '0'; + } + } + } + + continue; + + case 'p': + ui64 = (uintptr_t) va_arg(args, void *); + sign = 0; + spf.hex = HEXADECIMAL; + /* + * spf.width = NXT_PTR_SIZE * 2; + * spf.padding = '0'; + */ + goto number; + + case 'c': + d = va_arg(args, int); + *buf++ = (u_char) (d & 0xFF); + fmt++; + + continue; + + case 'Z': + *buf++ = '\0'; + fmt++; + continue; + + case 'n': + *buf++ = '\n'; + fmt++; + continue; + + case '%': + *buf++ = '%'; + fmt++; + continue; + + default: + *buf++ = *fmt++; + continue; + } + + number: + + if (sign) { + if (i64 < 0) { + *buf++ = '-'; + ui64 = (uint64_t) -i64; + + } else { + ui64 = (uint64_t) i64; + } + } + + buf = nxt_integer(&spf, buf, ui64); + + fmt++; + continue; + + copy: + + buf = nxt_cpymem(buf, p, nxt_min((size_t) (end - buf), length)); + continue; + } + + return buf; +} + + +static u_char * +nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) +{ + u_char *p, *end; + size_t length; + u_char temp[NXT_INT64_T_LEN]; + + p = temp + NXT_INT64_T_LEN; + + if (spf->hex == NULL) { + +#if (NXT_32BIT) + + for ( ;; ) { + u_char *start; + uint32_t ui32; + + /* + * 32-bit platforms usually lack hardware support of 64-bit + * division and remainder operations. For this reason C compiler + * adds calls to the runtime library functions which provides + * these operations. These functions usually have about hundred + * lines of code. + * + * For 32-bit numbers and some constant divisors GCC, Clang and + * other compilers can use inlined multiplications and shifts + * which are faster than division or remainder operations. + * For example, unsigned "ui32 / 10" is compiled to + * + * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 + * + * So a 64-bit number is split to parts by 10^9. The parts fit + * to 32 bits and are processed separately as 32-bit numbers. A + * number of 64-bit division/remainder operations is significantly + * decreased depending on the 64-bit number's value, it is + * 0 if the 64-bit value is less than 4294967296, + * 1 if the 64-bit value is greater than 4294967295 + * and less than 4294967296000000000, + * 2 otherwise. + */ + + if (ui64 <= 0xFFFFFFFF) { + ui32 = (uint32_t) ui64; + start = NULL; + + } else { + ui32 = (uint32_t) (ui64 % 1000000000); + start = p - 9; + } + + do { + *(--p) = (u_char) (ui32 % 10 + '0'); + ui32 /= 10; + } while (ui32 != 0); + + if (start == NULL) { + break; + } + + /* Add leading zeros of part. */ + + while (p > start) { + *(--p) = '0'; + } + + ui64 /= 1000000000; + } + +#else /* NXT_64BIT */ + + do { + *(--p) = (u_char) (ui64 % 10 + '0'); + ui64 /= 10; + } while (ui64 != 0); + +#endif + + } else { + + do { + *(--p) = spf->hex[ui64 & 0xF]; + ui64 >>= 4; + } while (ui64 != 0); + } + + /* Zero or space padding. */ + + if (spf->width != 0) { + + length = (temp + NXT_INT64_T_LEN) - p; + end = buf + (spf->width - length); + end = nxt_min(end, spf->end); + + while (buf < end) { + *buf++ = spf->padding; + } + } + + /* Number copying. */ + + length = (temp + NXT_INT64_T_LEN) - p; + end = buf + length; + end = nxt_min(end, spf->end); + + while (buf < end) { + *buf++ = *p++; + } + + return buf; +} + + +static u_char * +nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) +{ + u_char *p, *end; + size_t length; + u_char temp[NXT_DOUBLE_LEN]; + + p = temp + NXT_DOUBLE_LEN; + + do { + *(--p) = (u_char) (fmod(n, 10) + '0'); + n = trunc(n / 10); + } while (!nxt_double_is_zero(n)); + + /* Zero or space padding. */ + + if (spf->width != 0) { + length = (temp + NXT_DOUBLE_LEN) - p; + end = buf + (spf->width - length); + end = nxt_min(end, spf->end); + + while (buf < end) { + *buf++ = spf->padding; + } + } + + /* Number copying. */ + + length = (temp + NXT_DOUBLE_LEN) - p; + + end = buf + length; + end = nxt_min(end, spf->end); + + while (buf < end) { + *buf++ = *p++; + } + + return buf; +} diff -r c7e18bd12776 -r ea483ef4631a nxt/nxt_sprintf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_sprintf.h Wed Jan 30 18:47:59 2019 +0300 @@ -0,0 +1,16 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_SPRINTF_H_INCLUDED_ +#define _NXT_SPRINTF_H_INCLUDED_ + + +NXT_EXPORT u_char *nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...); +NXT_EXPORT u_char *nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, + va_list args); + + +#endif /* _NXT_SPRINTF_H_INCLUDED_ */ diff -r c7e18bd12776 -r ea483ef4631a nxt/nxt_stub.h --- a/nxt/nxt_stub.h Tue Jan 29 01:30:04 2019 +0800 +++ b/nxt/nxt_stub.h Wed Jan 30 18:47:59 2019 +0300 @@ -38,8 +38,6 @@ typedef struct { #define nxt_log_error(...) #define nxt_thread_log_debug(...) -#define NXT_DOUBLE_LEN 1024 - #include <unistd.h> #define nxt_pagesize() getpagesize() diff -r c7e18bd12776 -r ea483ef4631a nxt/nxt_types.h --- a/nxt/nxt_types.h Tue Jan 29 01:30:04 2019 +0800 +++ b/nxt/nxt_types.h Wed Jan 30 18:47:59 2019 +0300 @@ -55,7 +55,20 @@ typedef unsigned __int128 nxt_uint128_t; #endif +#if (NXT_INT_T_SIZE == 8) +#define NXT_INT_T_LEN NXT_INT64_T_LEN +#define NXT_INT_T_HEXLEN NXT_INT64_T_HEXLEN +#define NXT_INT_T_MAX NXT_INT64_T_MAX + +#else +#define NXT_INT_T_LEN NXT_INT32_T_LEN +#define NXT_INT_T_HEXLEN NXT_INT32_T_HEXLEN +#define NXT_INT_T_MAX NXT_INT32_T_MAX +#endif + + typedef nxt_uint_t nxt_bool_t; +typedef int nxt_err_t; /* @@ -98,4 +111,10 @@ typedef time_t nxt_time_t; typedef pid_t nxt_pid_t; +#define NXT_INT32_T_LEN nxt_length("-2147483648") +#define NXT_INT64_T_LEN nxt_length("-9223372036854775808") + +#define NXT_DOUBLE_LEN (1 + DBL_MAX_10_EXP) + + #endif /* _NXT_TYPES_H_INCLUDED_ */ _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel