%f format

This commit is contained in:
Igor Sysoev 2008-11-10 15:20:59 +00:00
parent 644029fa74
commit 6df4eaaf88
1 changed files with 146 additions and 72 deletions

View File

@ -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 *src)
* %[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, const char *fmt, ...)
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, const char *fmt, va_list args)
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, const char *fmt, va_list args)
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, const char *fmt, va_list args)
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, const char *fmt, va_list args)
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, const char *fmt, va_list args)
}
}
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, const char *fmt, va_list args)
}
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()