# HG changeset patch # User Igor Sysoev # Date 1226330459 0 # Node ID 0433bc27e468675427932498e4aa535badd19dea # Parent 51487a60eba2add7cb0826714123fd150653fb33 %f format diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -8,6 +8,10 @@ #include +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()