[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