%f format
Igor Sysoev
13 years ago
5 | 5 | |
6 | 6 | #include <ngx_config.h> |
7 | 7 | #include <ngx_core.h> |
8 | ||
9 | ||
10 | static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, | |
11 | u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); | |
8 | 12 | |
9 | 13 | |
10 | 14 | void |
66 | 70 | * %[0][width][u][x|X]D int32_t/uint32_t |
67 | 71 | * %[0][width][u][x|X]L int64_t/uint64_t |
68 | 72 | * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t |
73 | * %[0][width][.width]f float | |
69 | 74 | * %P ngx_pid_t |
70 | 75 | * %M ngx_msec_t |
71 | 76 | * %r rlim_t |
117 | 122 | u_char * |
118 | 123 | ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args) |
119 | 124 | { |
120 | u_char *p, zero, *last, temp[NGX_INT64_LEN + 1]; | |
121 | /* | |
122 | * really we need temp[NGX_INT64_LEN] only, | |
123 | * but icc issues the warning | |
124 | */ | |
125 | u_char *p, zero, *last; | |
125 | 126 | int d; |
127 | float f, scale; | |
126 | 128 | size_t len, slen; |
127 | uint32_t ui32; | |
128 | 129 | int64_t i64; |
129 | 130 | uint64_t ui64; |
130 | 131 | ngx_msec_t ms; |
131 | ngx_uint_t width, sign, hexadecimal, max_width; | |
132 | ngx_uint_t width, sign, hex, max_width, frac_width, i; | |
132 | 133 | ngx_str_t *v; |
133 | 134 | ngx_variable_value_t *vv; |
134 | static u_char hex[] = "0123456789abcdef"; | |
135 | static u_char HEX[] = "0123456789ABCDEF"; | |
136 | 135 | |
137 | 136 | if (max == 0) { |
138 | 137 | return buf; |
155 | 154 | zero = (u_char) ((*++fmt == '0') ? '0' : ' '); |
156 | 155 | width = 0; |
157 | 156 | sign = 1; |
158 | hexadecimal = 0; | |
157 | hex = 0; | |
159 | 158 | max_width = 0; |
159 | frac_width = 0; | |
160 | 160 | slen = (size_t) -1; |
161 | ||
162 | p = temp + NGX_INT64_LEN; | |
163 | 161 | |
164 | 162 | while (*fmt >= '0' && *fmt <= '9') { |
165 | 163 | width = width * 10 + *fmt++ - '0'; |
180 | 178 | continue; |
181 | 179 | |
182 | 180 | case 'X': |
183 | hexadecimal = 2; | |
181 | hex = 2; | |
184 | 182 | sign = 0; |
185 | 183 | fmt++; |
186 | 184 | continue; |
187 | 185 | |
188 | 186 | case 'x': |
189 | hexadecimal = 1; | |
187 | hex = 1; | |
190 | 188 | sign = 0; |
191 | 189 | fmt++; |
192 | 190 | continue; |
191 | ||
192 | case '.': | |
193 | fmt++; | |
194 | ||
195 | while (*fmt >= '0' && *fmt <= '9') { | |
196 | frac_width = frac_width * 10 + *fmt++ - '0'; | |
197 | } | |
198 | ||
199 | break; | |
193 | 200 | |
194 | 201 | case '*': |
195 | 202 | slen = va_arg(args, size_t); |
338 | 345 | |
339 | 346 | break; |
340 | 347 | |
348 | case 'f': | |
349 | f = (float) va_arg(args, double); | |
350 | ||
351 | if (f < 0) { | |
352 | *buf++ = '-'; | |
353 | f = -f; | |
354 | } | |
355 | ||
356 | ui64 = (int64_t) f; | |
357 | ||
358 | buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width); | |
359 | ||
360 | if (frac_width) { | |
361 | ||
362 | if (buf < last) { | |
363 | *buf++ = '.'; | |
364 | } | |
365 | ||
366 | scale = 1.0; | |
367 | ||
368 | for (i = 0; i < frac_width; i++) { | |
369 | scale *= 10.0; | |
370 | } | |
371 | ||
372 | /* | |
373 | * (int64_t) cast is required for msvc6: | |
374 | * it can not convert uint64_t to double | |
375 | */ | |
376 | ui64 = (uint64_t) ((f - (int64_t) ui64) * scale); | |
377 | ||
378 | buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width); | |
379 | } | |
380 | ||
381 | fmt++; | |
382 | ||
383 | continue; | |
384 | ||
341 | 385 | #if !(NGX_WIN32) |
342 | 386 | case 'r': |
343 | 387 | i64 = (int64_t) va_arg(args, rlim_t); |
347 | 391 | |
348 | 392 | case 'p': |
349 | 393 | ui64 = (uintptr_t) va_arg(args, void *); |
350 | hexadecimal = 2; | |
394 | hex = 2; | |
351 | 395 | sign = 0; |
352 | 396 | zero = '0'; |
353 | 397 | width = NGX_PTR_SIZE * 2; |
397 | 441 | } |
398 | 442 | } |
399 | 443 | |
400 | if (hexadecimal == 1) { | |
401 | do { | |
402 | ||
403 | /* the "(uint32_t)" cast disables the BCC's warning */ | |
404 | *--p = hex[(uint32_t) (ui64 & 0xf)]; | |
405 | ||
406 | } while (ui64 >>= 4); | |
407 | ||
408 | } else if (hexadecimal == 2) { | |
409 | do { | |
410 | ||
411 | /* the "(uint32_t)" cast disables the BCC's warning */ | |
412 | *--p = HEX[(uint32_t) (ui64 & 0xf)]; | |
413 | ||
414 | } while (ui64 >>= 4); | |
415 | ||
416 | } else if (ui64 <= NGX_MAX_UINT32_VALUE) { | |
417 | ||
418 | /* | |
419 | * To divide 64-bit number and to find the remainder | |
420 | * on the x86 platform gcc and icc call the libc functions | |
421 | * [u]divdi3() and [u]moddi3(), they call another function | |
422 | * in its turn. On FreeBSD it is the qdivrem() function, | |
423 | * its source code is about 170 lines of the code. | |
424 | * The glibc counterpart is about 150 lines of the code. | |
425 | * | |
426 | * For 32-bit numbers and some divisors gcc and icc use | |
427 | * the inlined multiplication and shifts. For example, | |
428 | * unsigned "i32 / 10" is compiled to | |
429 | * | |
430 | * (i32 * 0xCCCCCCCD) >> 35 | |
431 | */ | |
432 | ||
433 | ui32 = (uint32_t) ui64; | |
434 | ||
435 | do { | |
436 | *--p = (u_char) (ui32 % 10 + '0'); | |
437 | } while (ui32 /= 10); | |
438 | ||
439 | } else { | |
440 | do { | |
441 | *--p = (u_char) (ui64 % 10 + '0'); | |
442 | } while (ui64 /= 10); | |
443 | } | |
444 | ||
445 | len = (temp + NGX_INT64_LEN) - p; | |
446 | ||
447 | while (len++ < width && buf < last) { | |
448 | *buf++ = zero; | |
449 | } | |
450 | ||
451 | len = (temp + NGX_INT64_LEN) - p; | |
452 | if (buf + len > last) { | |
453 | len = last - buf; | |
454 | } | |
455 | ||
456 | buf = ngx_cpymem(buf, p, len); | |
444 | buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width); | |
457 | 445 | |
458 | 446 | fmt++; |
459 | 447 | |
463 | 451 | } |
464 | 452 | |
465 | 453 | return buf; |
454 | } | |
455 | ||
456 | ||
457 | static u_char * | |
458 | ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, | |
459 | ngx_uint_t hexadecimal, ngx_uint_t width) | |
460 | { | |
461 | u_char *p, temp[NGX_INT64_LEN + 1]; | |
462 | /* | |
463 | * we need temp[NGX_INT64_LEN] only, | |
464 | * but icc issues the warning | |
465 | */ | |
466 | size_t len; | |
467 | uint32_t ui32; | |
468 | static u_char hex[] = "0123456789abcdef"; | |
469 | static u_char HEX[] = "0123456789ABCDEF"; | |
470 | ||
471 | p = temp + NGX_INT64_LEN; | |
472 | ||
473 | if (hexadecimal == 0) { | |
474 | ||
475 | if (ui64 <= NGX_MAX_UINT32_VALUE) { | |
476 | ||
477 | /* | |
478 | * To divide 64-bit numbers and to find remainders | |
479 | * on the x86 platform gcc and icc call the libc functions | |
480 | * [u]divdi3() and [u]moddi3(), they call another function | |
481 | * in its turn. On FreeBSD it is the qdivrem() function, | |
482 | * its source code is about 170 lines of the code. | |
483 | * The glibc counterpart is about 150 lines of the code. | |
484 | * | |
485 | * For 32-bit numbers and some divisors gcc and icc use | |
486 | * a inlined multiplication and shifts. For example, | |
487 | * unsigned "i32 / 10" is compiled to | |
488 | * | |
489 | * (i32 * 0xCCCCCCCD) >> 35 | |
490 | */ | |
491 | ||
492 | ui32 = (uint32_t) ui64; | |
493 | ||
494 | do { | |
495 | *--p = (u_char) (ui32 % 10 + '0'); | |
496 | } while (ui32 /= 10); | |
497 | ||
498 | } else { | |
499 | do { | |
500 | *--p = (u_char) (ui64 % 10 + '0'); | |
501 | } while (ui64 /= 10); | |
502 | } | |
503 | ||
504 | } else if (hexadecimal == 1) { | |
505 | ||
506 | do { | |
507 | ||
508 | /* the "(uint32_t)" cast disables the BCC's warning */ | |
509 | *--p = hex[(uint32_t) (ui64 & 0xf)]; | |
510 | ||
511 | } while (ui64 >>= 4); | |
512 | ||
513 | } else { /* hexadecimal == 2 */ | |
514 | ||
515 | do { | |
516 | ||
517 | /* the "(uint32_t)" cast disables the BCC's warning */ | |
518 | *--p = HEX[(uint32_t) (ui64 & 0xf)]; | |
519 | ||
520 | } while (ui64 >>= 4); | |
521 | } | |
522 | ||
523 | /* zero or space padding */ | |
524 | ||
525 | len = (temp + NGX_INT64_LEN) - p; | |
526 | ||
527 | while (len++ < width && buf < last) { | |
528 | *buf++ = zero; | |
529 | } | |
530 | ||
531 | /* number safe copy */ | |
532 | ||
533 | len = (temp + NGX_INT64_LEN) - p; | |
534 | ||
535 | if (buf + len > last) { | |
536 | len = last - buf; | |
537 | } | |
538 | ||
539 | return ngx_cpymem(buf, p, len); | |
466 | 540 | } |
467 | 541 | |
468 | 542 |