Klaus Demo nginx / 74b7e5f
%f format Igor Sysoev 13 years ago
1 changed file(s) with 146 addition(s) and 72 deletion(s). Raw diff Collapse all Expand all
55
66 #include <ngx_config.h>
77 #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);
812
913
1014 void
6670 * %[0][width][u][x|X]D int32_t/uint32_t
6771 * %[0][width][u][x|X]L int64_t/uint64_t
6872 * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
73 * %[0][width][.width]f float
6974 * %P ngx_pid_t
7075 * %M ngx_msec_t
7176 * %r rlim_t
117122 u_char *
118123 ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
119124 {
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;
125126 int d;
127 float f, scale;
126128 size_t len, slen;
127 uint32_t ui32;
128129 int64_t i64;
129130 uint64_t ui64;
130131 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;
132133 ngx_str_t *v;
133134 ngx_variable_value_t *vv;
134 static u_char hex[] = "0123456789abcdef";
135 static u_char HEX[] = "0123456789ABCDEF";
136135
137136 if (max == 0) {
138137 return buf;
155154 zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
156155 width = 0;
157156 sign = 1;
158 hexadecimal = 0;
157 hex = 0;
159158 max_width = 0;
159 frac_width = 0;
160160 slen = (size_t) -1;
161
162 p = temp + NGX_INT64_LEN;
163161
164162 while (*fmt >= '0' && *fmt <= '9') {
165163 width = width * 10 + *fmt++ - '0';
180178 continue;
181179
182180 case 'X':
183 hexadecimal = 2;
181 hex = 2;
184182 sign = 0;
185183 fmt++;
186184 continue;
187185
188186 case 'x':
189 hexadecimal = 1;
187 hex = 1;
190188 sign = 0;
191189 fmt++;
192190 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;
193200
194201 case '*':
195202 slen = va_arg(args, size_t);
338345
339346 break;
340347
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
341385 #if !(NGX_WIN32)
342386 case 'r':
343387 i64 = (int64_t) va_arg(args, rlim_t);
347391
348392 case 'p':
349393 ui64 = (uintptr_t) va_arg(args, void *);
350 hexadecimal = 2;
394 hex = 2;
351395 sign = 0;
352396 zero = '0';
353397 width = NGX_PTR_SIZE * 2;
397441 }
398442 }
399443
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);
457445
458446 fmt++;
459447
463451 }
464452
465453 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);
466540 }
467541
468542