diff src/core/ngx_string.c @ 416:b4f69f2ef02c NGINX_0_7_20

nginx 0.7.20 *) Changes in the ngx_http_gzip_filter_module. *) Feature: the ngx_http_limit_req_module. *) Bugfix: worker processes might exit on a SIGBUS signal on sparc and ppc platforms; the bug had appeared in 0.7.3. Thanks to Maxim Dounin. *) Bugfix: the "proxy_pass http://host/some:uri" directives did not work; the bug had appeared in 0.7.12. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error. *) Bugfix: the ngx_http_secure_link_module did not work inside locations, whose names are less than 3 characters. *) Bugfix: $server_addr variable might have no value.
author Igor Sysoev <http://sysoev.ru>
date Mon, 10 Nov 2008 00:00:00 +0300
parents 34fb3a573548
children 09f0ef15d544
line wrap: on
line diff
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -8,6 +8,10 @@
 #include <ngx_core.h>
 
 
+static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
+    u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
+
+
 void
 ngx_strlow(u_char *dst, u_char *src, size_t n)
 {
@@ -67,6 +71,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t 
  *    %[0][width][u][x|X]D      int32_t/uint32_t
  *    %[0][width][u][x|X]L      int64_t/uint64_t
  *    %[0][width|m][u][x|X]A    ngx_atomic_int_t/ngx_atomic_uint_t
+ *    %[0][width][.width]f      float
  *    %P                        ngx_pid_t
  *    %M                        ngx_msec_t
  *    %r                        rlim_t
@@ -118,22 +123,16 @@ ngx_snprintf(u_char *buf, size_t max, co
 u_char *
 ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
 {
-    u_char                *p, zero, *last, temp[NGX_INT64_LEN + 1];
-                                    /*
-                                     * really we need temp[NGX_INT64_LEN] only,
-                                     * but icc issues the warning
-                                     */
+    u_char                *p, zero, *last;
     int                    d;
+    float                  f, scale;
     size_t                 len, slen;
-    uint32_t               ui32;
     int64_t                i64;
     uint64_t               ui64;
     ngx_msec_t             ms;
-    ngx_uint_t             width, sign, hexadecimal, max_width;
+    ngx_uint_t             width, sign, hex, max_width, frac_width, i;
     ngx_str_t             *v;
     ngx_variable_value_t  *vv;
-    static u_char          hex[] = "0123456789abcdef";
-    static u_char          HEX[] = "0123456789ABCDEF";
 
     if (max == 0) {
         return buf;
@@ -156,12 +155,11 @@ ngx_vsnprintf(u_char *buf, size_t max, c
             zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
             width = 0;
             sign = 1;
-            hexadecimal = 0;
+            hex = 0;
             max_width = 0;
+            frac_width = 0;
             slen = (size_t) -1;
 
-            p = temp + NGX_INT64_LEN;
-
             while (*fmt >= '0' && *fmt <= '9') {
                 width = width * 10 + *fmt++ - '0';
             }
@@ -181,17 +179,26 @@ ngx_vsnprintf(u_char *buf, size_t max, c
                     continue;
 
                 case 'X':
-                    hexadecimal = 2;
+                    hex = 2;
                     sign = 0;
                     fmt++;
                     continue;
 
                 case 'x':
-                    hexadecimal = 1;
+                    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++;
@@ -339,6 +346,43 @@ ngx_vsnprintf(u_char *buf, size_t max, c
 
                 break;
 
+            case 'f':
+                f = (float) va_arg(args, double);
+
+                if (f < 0) {
+                    *buf++ = '-';
+                    f = -f;
+                }
+
+                ui64 = (int64_t) f;
+
+                buf = ngx_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 = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
+                }
+
+                fmt++;
+
+                continue;
+
 #if !(NGX_WIN32)
             case 'r':
                 i64 = (int64_t) va_arg(args, rlim_t);
@@ -348,7 +392,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
 
             case 'p':
                 ui64 = (uintptr_t) va_arg(args, void *);
-                hexadecimal = 2;
+                hex = 2;
                 sign = 0;
                 zero = '0';
                 width = NGX_PTR_SIZE * 2;
@@ -398,63 +442,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
                 }
             }
 
-            if (hexadecimal == 1) {
-                do {
-
-                    /* the "(uint32_t)" cast disables the BCC's warning */
-                    *--p = hex[(uint32_t) (ui64 & 0xf)];
-
-                } while (ui64 >>= 4);
-
-            } else if (hexadecimal == 2) {
-                do {
-
-                    /* the "(uint32_t)" cast disables the BCC's warning */
-                    *--p = HEX[(uint32_t) (ui64 & 0xf)];
-
-                } while (ui64 >>= 4);
-
-            } else if (ui64 <= NGX_MAX_UINT32_VALUE) {
-
-                /*
-                 * To divide 64-bit number and to find the remainder
-                 * 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
-                 * the 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);
-            }
-
-            len = (temp + NGX_INT64_LEN) - p;
-
-            while (len++ < width && buf < last) {
-                *buf++ = zero;
-            }
-
-            len = (temp + NGX_INT64_LEN) - p;
-            if (buf + len > last) {
-                len = last - buf;
-            }
-
-            buf = ngx_cpymem(buf, p, len);
+            buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
 
             fmt++;
 
@@ -467,6 +455,92 @@ ngx_vsnprintf(u_char *buf, size_t max, c
 }
 
 
+static u_char *
+ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
+    ngx_uint_t hexadecimal, ngx_uint_t width)
+{
+    u_char         *p, temp[NGX_INT64_LEN + 1];
+                       /*
+                        * we need temp[NGX_INT64_LEN] only,
+                        * but icc issues the warning
+                        */
+    size_t          len;
+    uint32_t        ui32;
+    static u_char   hex[] = "0123456789abcdef";
+    static u_char   HEX[] = "0123456789ABCDEF";
+
+    p = temp + NGX_INT64_LEN;
+
+    if (hexadecimal == 0) {
+
+        if (ui64 <= NGX_MAX_UINT32_VALUE) {
+
+            /*
+             * 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 + NGX_INT64_LEN) - p;
+
+    while (len++ < width && buf < last) {
+        *buf++ = zero;
+    }
+
+    /* number safe copy */
+
+    len = (temp + NGX_INT64_LEN) - p;
+
+    if (buf + len > last) {
+        len = last - buf;
+    }
+
+    return ngx_cpymem(buf, p, len);
+}
+
+
 /*
  * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
  * and implement our own ngx_strcasecmp()/ngx_strncasecmp()