[njs] Imported nxt_sprintf.c.
Dmitry Volyntsev
xeioex at nginx.com
Wed Jan 30 15:56:39 UTC 2019
details: https://hg.nginx.org/njs/rev/ea483ef4631a
branches:
changeset: 743:ea483ef4631a
user: Dmitry Volyntsev <xeioex at 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_ */
More information about the nginx-devel
mailing list