10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru #include <math.h> 90Sigor@sysoev.ru #include <float.h> 100Sigor@sysoev.ru 110Sigor@sysoev.ru 120Sigor@sysoev.ru /* 130Sigor@sysoev.ru * Supported formats: 140Sigor@sysoev.ru * 150Sigor@sysoev.ru * %[0][width][x][X]O nxt_off_t 160Sigor@sysoev.ru * %[0][width]T nxt_time_t 170Sigor@sysoev.ru * %[0][width][u][x|X]z ssize_t/size_t 180Sigor@sysoev.ru * %[0][width][u][x|X]d int/u_int 190Sigor@sysoev.ru * %[0][width][u][x|X]l long 200Sigor@sysoev.ru * %[0][width|m][u][x|X]i nxt_int_t/nxt_uint_t 210Sigor@sysoev.ru * %[0][width][u][x|X]D int32_t/uint32_t 220Sigor@sysoev.ru * %[0][width][u][x|X]L int64_t/uint64_t 230Sigor@sysoev.ru * %[0][width|m][u][x|X]A nxt_atomic_int_t/nxt_atomic_uint_t 240Sigor@sysoev.ru * %[0][width][.width]f double, max valid number fits to %18.15f 250Sigor@sysoev.ru * 260Sigor@sysoev.ru * %FD nxt_fd_t, int / HANDLE 270Sigor@sysoev.ru * %d nxt_socket_t, int 280Sigor@sysoev.ru * 290Sigor@sysoev.ru * %PI nxt_pid_t, process id 300Sigor@sysoev.ru * %PT nxt_tid_t, thread id 310Sigor@sysoev.ru * %PF nxt_fid_t, fiber id 320Sigor@sysoev.ru * %PH pthread_t handle returned by pthread_self() 330Sigor@sysoev.ru * 340Sigor@sysoev.ru * %s null-terminated string 350Sigor@sysoev.ru * %*s length and string 360Sigor@sysoev.ru * %FN nxt_file_name_t * 370Sigor@sysoev.ru * 380Sigor@sysoev.ru * %M nxt_msec_t 390Sigor@sysoev.ru * %N nxt_nsec_t 400Sigor@sysoev.ru * %r rlim_t 410Sigor@sysoev.ru * %p void * 420Sigor@sysoev.ru * %b nxt_bool_t 430Sigor@sysoev.ru * %E nxt_err_t 440Sigor@sysoev.ru * %V nxt_str_t * 450Sigor@sysoev.ru * %Z '\0' 460Sigor@sysoev.ru * %n '\n' 470Sigor@sysoev.ru * %c char 480Sigor@sysoev.ru * %% % 490Sigor@sysoev.ru * 500Sigor@sysoev.ru * Reserved: 510Sigor@sysoev.ru * %t ptrdiff_t 520Sigor@sysoev.ru * %S null-terminated wchar string 530Sigor@sysoev.ru * %C wchar 5472Sigor@sysoev.ru * %[0][width][u][x|X]Q int128_t/uint128_t 550Sigor@sysoev.ru */ 560Sigor@sysoev.ru 570Sigor@sysoev.ru 580Sigor@sysoev.ru u_char * nxt_cdecl 590Sigor@sysoev.ru nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...) 600Sigor@sysoev.ru { 610Sigor@sysoev.ru u_char *p; 620Sigor@sysoev.ru va_list args; 630Sigor@sysoev.ru 640Sigor@sysoev.ru va_start(args, fmt); 650Sigor@sysoev.ru p = nxt_vsprintf(buf, end, fmt, args); 660Sigor@sysoev.ru va_end(args); 670Sigor@sysoev.ru 680Sigor@sysoev.ru return p; 690Sigor@sysoev.ru } 700Sigor@sysoev.ru 710Sigor@sysoev.ru 720Sigor@sysoev.ru /* 730Sigor@sysoev.ru * nxt_sprintf_t is used: 740Sigor@sysoev.ru * to pass several parameters of nxt_integer() via single pointer 750Sigor@sysoev.ru * and to store little used variables of nxt_vsprintf(). 760Sigor@sysoev.ru */ 770Sigor@sysoev.ru 780Sigor@sysoev.ru typedef struct { 790Sigor@sysoev.ru u_char *end; 800Sigor@sysoev.ru const u_char *hex; 810Sigor@sysoev.ru uint32_t width; 820Sigor@sysoev.ru int32_t frac_width; 830Sigor@sysoev.ru uint8_t max_width; 840Sigor@sysoev.ru u_char padding; 850Sigor@sysoev.ru } nxt_sprintf_t; 860Sigor@sysoev.ru 870Sigor@sysoev.ru 880Sigor@sysoev.ru static u_char *nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64); 890Sigor@sysoev.ru static u_char *nxt_number(nxt_sprintf_t *spf, u_char *buf, double n); 900Sigor@sysoev.ru 910Sigor@sysoev.ru 920Sigor@sysoev.ru /* A right way of "f == 0.0". */ 930Sigor@sysoev.ru #define \ 940Sigor@sysoev.ru nxt_double_is_zero(f) \ 950Sigor@sysoev.ru (fabs(f) <= FLT_EPSILON) 960Sigor@sysoev.ru 970Sigor@sysoev.ru 980Sigor@sysoev.ru u_char * 990Sigor@sysoev.ru nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) 1000Sigor@sysoev.ru { 1010Sigor@sysoev.ru u_char *p; 1020Sigor@sysoev.ru int d; 1030Sigor@sysoev.ru double f, i; 10410Sigor@sysoev.ru size_t length; 1050Sigor@sysoev.ru int64_t i64; 1060Sigor@sysoev.ru uint64_t ui64, frac; 1070Sigor@sysoev.ru nxt_str_t *v; 1080Sigor@sysoev.ru nxt_err_t err; 1090Sigor@sysoev.ru nxt_uint_t scale, n; 1100Sigor@sysoev.ru nxt_msec_t ms; 1110Sigor@sysoev.ru nxt_nsec_t ns; 1120Sigor@sysoev.ru nxt_bool_t sign; 1130Sigor@sysoev.ru nxt_sprintf_t spf; 1140Sigor@sysoev.ru nxt_file_name_t *fn; 1150Sigor@sysoev.ru 1160Sigor@sysoev.ru static const u_char hexadecimal[16] = "0123456789abcdef"; 1170Sigor@sysoev.ru static const u_char HEXADECIMAL[16] = "0123456789ABCDEF"; 1180Sigor@sysoev.ru static const u_char nan[] = "[nan]"; 1190Sigor@sysoev.ru static const u_char infinity[] = "[infinity]"; 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru spf.end = end; 1220Sigor@sysoev.ru 1230Sigor@sysoev.ru while (*fmt != '\0' && buf < end) { 1240Sigor@sysoev.ru 1250Sigor@sysoev.ru /* 1260Sigor@sysoev.ru * "buf < end" means that we could copy at least one character: 1270Sigor@sysoev.ru * a plain character, "%%", "%c", or a minus without test. 1280Sigor@sysoev.ru */ 1290Sigor@sysoev.ru 1300Sigor@sysoev.ru if (*fmt != '%') { 1310Sigor@sysoev.ru *buf++ = *fmt++; 1320Sigor@sysoev.ru continue; 1330Sigor@sysoev.ru } 1340Sigor@sysoev.ru 1350Sigor@sysoev.ru fmt++; 1360Sigor@sysoev.ru 1370Sigor@sysoev.ru /* Test some often used text formats first. */ 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru switch (*fmt) { 1400Sigor@sysoev.ru 1410Sigor@sysoev.ru case 'V': 1420Sigor@sysoev.ru fmt++; 1430Sigor@sysoev.ru v = va_arg(args, nxt_str_t *); 1440Sigor@sysoev.ru 1450Sigor@sysoev.ru if (nxt_fast_path(v != NULL)) { 14610Sigor@sysoev.ru length = v->length; 14710Sigor@sysoev.ru p = v->start; 1480Sigor@sysoev.ru goto copy; 1490Sigor@sysoev.ru } 1500Sigor@sysoev.ru 1510Sigor@sysoev.ru continue; 1520Sigor@sysoev.ru 1530Sigor@sysoev.ru case 's': 1540Sigor@sysoev.ru p = va_arg(args, u_char *); 1550Sigor@sysoev.ru 1560Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 1570Sigor@sysoev.ru while (*p != '\0' && buf < end) { 1580Sigor@sysoev.ru *buf++ = *p++; 1590Sigor@sysoev.ru } 1600Sigor@sysoev.ru } 1610Sigor@sysoev.ru 1620Sigor@sysoev.ru fmt++; 1630Sigor@sysoev.ru continue; 1640Sigor@sysoev.ru 1650Sigor@sysoev.ru case '*': 166493Spluknet@nginx.com length = va_arg(args, size_t); 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru fmt++; 1690Sigor@sysoev.ru 1700Sigor@sysoev.ru if (*fmt == 's') { 1710Sigor@sysoev.ru fmt++; 1720Sigor@sysoev.ru p = va_arg(args, u_char *); 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 1750Sigor@sysoev.ru goto copy; 1760Sigor@sysoev.ru } 1770Sigor@sysoev.ru } 1780Sigor@sysoev.ru 1790Sigor@sysoev.ru continue; 1800Sigor@sysoev.ru 1810Sigor@sysoev.ru default: 1820Sigor@sysoev.ru break; 1830Sigor@sysoev.ru } 1840Sigor@sysoev.ru 1850Sigor@sysoev.ru spf.hex = NULL; 1860Sigor@sysoev.ru spf.width = 0; 1870Sigor@sysoev.ru spf.frac_width = -1; 1880Sigor@sysoev.ru spf.max_width = 0; 1890Sigor@sysoev.ru spf.padding = (*fmt == '0') ? '0' : ' '; 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru sign = 1; 1920Sigor@sysoev.ru 1930Sigor@sysoev.ru i64 = 0; 1940Sigor@sysoev.ru ui64 = 0; 1950Sigor@sysoev.ru 1960Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 1970Sigor@sysoev.ru spf.width = spf.width * 10 + (*fmt++ - '0'); 1980Sigor@sysoev.ru } 1990Sigor@sysoev.ru 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru for ( ;; ) { 2020Sigor@sysoev.ru switch (*fmt) { 2030Sigor@sysoev.ru 2040Sigor@sysoev.ru case 'u': 2050Sigor@sysoev.ru sign = 0; 2060Sigor@sysoev.ru fmt++; 2070Sigor@sysoev.ru continue; 2080Sigor@sysoev.ru 2090Sigor@sysoev.ru case 'm': 2100Sigor@sysoev.ru spf.max_width = 1; 2110Sigor@sysoev.ru fmt++; 2120Sigor@sysoev.ru continue; 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru case 'X': 2150Sigor@sysoev.ru spf.hex = HEXADECIMAL; 2160Sigor@sysoev.ru sign = 0; 2170Sigor@sysoev.ru fmt++; 2180Sigor@sysoev.ru continue; 2190Sigor@sysoev.ru 2200Sigor@sysoev.ru case 'x': 2210Sigor@sysoev.ru spf.hex = hexadecimal; 2220Sigor@sysoev.ru sign = 0; 2230Sigor@sysoev.ru fmt++; 2240Sigor@sysoev.ru continue; 2250Sigor@sysoev.ru 2260Sigor@sysoev.ru case '.': 2270Sigor@sysoev.ru fmt++; 2280Sigor@sysoev.ru spf.frac_width = 0; 2290Sigor@sysoev.ru 2300Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 2310Sigor@sysoev.ru spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; 2320Sigor@sysoev.ru } 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru break; 2350Sigor@sysoev.ru 2360Sigor@sysoev.ru default: 2370Sigor@sysoev.ru break; 2380Sigor@sysoev.ru } 2390Sigor@sysoev.ru 2400Sigor@sysoev.ru break; 2410Sigor@sysoev.ru } 2420Sigor@sysoev.ru 2430Sigor@sysoev.ru 2440Sigor@sysoev.ru switch (*fmt) { 2450Sigor@sysoev.ru 2460Sigor@sysoev.ru case 'E': 2470Sigor@sysoev.ru err = va_arg(args, nxt_err_t); 2480Sigor@sysoev.ru 2490Sigor@sysoev.ru *buf++ = '('; 2500Sigor@sysoev.ru spf.hex = NULL; 2510Sigor@sysoev.ru spf.width = 0; 2520Sigor@sysoev.ru buf = nxt_integer(&spf, buf, err); 2530Sigor@sysoev.ru 2540Sigor@sysoev.ru if (buf < end - 1) { 2550Sigor@sysoev.ru *buf++ = ':'; 2560Sigor@sysoev.ru *buf++ = ' '; 2570Sigor@sysoev.ru } 2580Sigor@sysoev.ru 2590Sigor@sysoev.ru buf = nxt_strerror(err, buf, end - buf); 2600Sigor@sysoev.ru 2610Sigor@sysoev.ru if (buf < end) { 2620Sigor@sysoev.ru *buf++ = ')'; 2630Sigor@sysoev.ru } 2640Sigor@sysoev.ru 2650Sigor@sysoev.ru fmt++; 2660Sigor@sysoev.ru continue; 2670Sigor@sysoev.ru 2680Sigor@sysoev.ru case 'O': 2690Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_off_t); 2700Sigor@sysoev.ru sign = 1; 2710Sigor@sysoev.ru goto number; 2720Sigor@sysoev.ru 2730Sigor@sysoev.ru case 'T': 2740Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_time_t); 2750Sigor@sysoev.ru sign = 1; 2760Sigor@sysoev.ru goto number; 2770Sigor@sysoev.ru 2780Sigor@sysoev.ru case 'M': 2790Sigor@sysoev.ru ms = (nxt_msec_t) va_arg(args, nxt_msec_t); 2800Sigor@sysoev.ru if ((nxt_msec_int_t) ms == -1 && spf.hex == NULL) { 2810Sigor@sysoev.ru i64 = -1; 2820Sigor@sysoev.ru sign = 1; 2830Sigor@sysoev.ru } else { 2840Sigor@sysoev.ru ui64 = (uint64_t) ms; 2850Sigor@sysoev.ru sign = 0; 2860Sigor@sysoev.ru } 2870Sigor@sysoev.ru goto number; 2880Sigor@sysoev.ru 2890Sigor@sysoev.ru case 'N': 2900Sigor@sysoev.ru ns = (nxt_nsec_t) va_arg(args, nxt_nsec_t); 2910Sigor@sysoev.ru if ((nxt_nsec_int_t) ns == -1) { 2920Sigor@sysoev.ru i64 = -1; 2930Sigor@sysoev.ru sign = 1; 2940Sigor@sysoev.ru } else { 2950Sigor@sysoev.ru ui64 = (uint64_t) ns; 2960Sigor@sysoev.ru sign = 0; 2970Sigor@sysoev.ru } 2980Sigor@sysoev.ru goto number; 2990Sigor@sysoev.ru 3000Sigor@sysoev.ru case 'z': 3010Sigor@sysoev.ru if (sign) { 3020Sigor@sysoev.ru i64 = (int64_t) va_arg(args, ssize_t); 3030Sigor@sysoev.ru } else { 3040Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, size_t); 3050Sigor@sysoev.ru } 3060Sigor@sysoev.ru goto number; 3070Sigor@sysoev.ru 3080Sigor@sysoev.ru case 'i': 3090Sigor@sysoev.ru if (sign) { 3100Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_int_t); 3110Sigor@sysoev.ru } else { 3120Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_uint_t); 3130Sigor@sysoev.ru } 3140Sigor@sysoev.ru 3150Sigor@sysoev.ru if (spf.max_width != 0) { 3160Sigor@sysoev.ru spf.width = NXT_INT_T_LEN; 3170Sigor@sysoev.ru } 3180Sigor@sysoev.ru 3190Sigor@sysoev.ru goto number; 3200Sigor@sysoev.ru 3210Sigor@sysoev.ru case 'd': 3220Sigor@sysoev.ru if (sign) { 3230Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int); 3240Sigor@sysoev.ru } else { 3250Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_int); 3260Sigor@sysoev.ru } 3270Sigor@sysoev.ru goto number; 3280Sigor@sysoev.ru 3290Sigor@sysoev.ru case 'l': 3300Sigor@sysoev.ru if (sign) { 3310Sigor@sysoev.ru i64 = (int64_t) va_arg(args, long); 3320Sigor@sysoev.ru } else { 3330Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_long); 3340Sigor@sysoev.ru } 3350Sigor@sysoev.ru goto number; 3360Sigor@sysoev.ru 3370Sigor@sysoev.ru case 'D': 3380Sigor@sysoev.ru if (sign) { 3390Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int32_t); 3400Sigor@sysoev.ru } else { 3410Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, uint32_t); 3420Sigor@sysoev.ru } 3430Sigor@sysoev.ru goto number; 3440Sigor@sysoev.ru 3450Sigor@sysoev.ru case 'L': 3460Sigor@sysoev.ru if (sign) { 3470Sigor@sysoev.ru i64 = va_arg(args, int64_t); 3480Sigor@sysoev.ru } else { 3490Sigor@sysoev.ru ui64 = va_arg(args, uint64_t); 3500Sigor@sysoev.ru } 3510Sigor@sysoev.ru goto number; 3520Sigor@sysoev.ru 3530Sigor@sysoev.ru case 'A': 3540Sigor@sysoev.ru if (sign) { 3550Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_atomic_int_t); 3560Sigor@sysoev.ru } else { 3570Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_atomic_uint_t); 3580Sigor@sysoev.ru } 3590Sigor@sysoev.ru 3600Sigor@sysoev.ru if (spf.max_width != 0) { 3610Sigor@sysoev.ru spf.width = NXT_ATOMIC_T_LEN; 3620Sigor@sysoev.ru } 3630Sigor@sysoev.ru 3640Sigor@sysoev.ru goto number; 3650Sigor@sysoev.ru 3660Sigor@sysoev.ru case 'b': 3670Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_bool_t); 3680Sigor@sysoev.ru sign = 0; 3690Sigor@sysoev.ru goto number; 3700Sigor@sysoev.ru 3710Sigor@sysoev.ru case 'f': 3720Sigor@sysoev.ru fmt++; 3730Sigor@sysoev.ru 3740Sigor@sysoev.ru f = va_arg(args, double); 3750Sigor@sysoev.ru 3760Sigor@sysoev.ru if (f < 0) { 3770Sigor@sysoev.ru *buf++ = '-'; 3780Sigor@sysoev.ru f = -f; 3790Sigor@sysoev.ru } 3800Sigor@sysoev.ru 3810Sigor@sysoev.ru if (nxt_slow_path(isnan(f))) { 3820Sigor@sysoev.ru p = (u_char *) nan; 383*703Svbart@nginx.com length = nxt_length(nan); 3840Sigor@sysoev.ru 3850Sigor@sysoev.ru goto copy; 3860Sigor@sysoev.ru 3870Sigor@sysoev.ru } else if (nxt_slow_path(isinf(f))) { 3880Sigor@sysoev.ru p = (u_char *) infinity; 389*703Svbart@nginx.com length = nxt_length(infinity); 3900Sigor@sysoev.ru 3910Sigor@sysoev.ru goto copy; 3920Sigor@sysoev.ru } 3930Sigor@sysoev.ru 3940Sigor@sysoev.ru (void) modf(f, &i); 3950Sigor@sysoev.ru frac = 0; 3960Sigor@sysoev.ru 3970Sigor@sysoev.ru if (spf.frac_width > 0) { 3980Sigor@sysoev.ru 3990Sigor@sysoev.ru scale = 1; 4000Sigor@sysoev.ru for (n = spf.frac_width; n != 0; n--) { 4010Sigor@sysoev.ru scale *= 10; 4020Sigor@sysoev.ru } 4030Sigor@sysoev.ru 4040Sigor@sysoev.ru frac = (uint64_t) ((f - i) * scale + 0.5); 4050Sigor@sysoev.ru 4060Sigor@sysoev.ru if (frac == scale) { 4070Sigor@sysoev.ru i += 1; 4080Sigor@sysoev.ru frac = 0; 4090Sigor@sysoev.ru } 4100Sigor@sysoev.ru } 4110Sigor@sysoev.ru 4120Sigor@sysoev.ru buf = nxt_number(&spf, buf, i); 4130Sigor@sysoev.ru 4140Sigor@sysoev.ru if (spf.frac_width > 0) { 4150Sigor@sysoev.ru 4160Sigor@sysoev.ru if (buf < end) { 4170Sigor@sysoev.ru *buf++ = '.'; 4180Sigor@sysoev.ru 4190Sigor@sysoev.ru spf.hex = NULL; 4200Sigor@sysoev.ru spf.padding = '0'; 4210Sigor@sysoev.ru spf.width = spf.frac_width; 4220Sigor@sysoev.ru buf = nxt_integer(&spf, buf, frac); 4230Sigor@sysoev.ru } 4240Sigor@sysoev.ru 4250Sigor@sysoev.ru } else if (spf.frac_width < 0) { 4260Sigor@sysoev.ru f = modf(f, &i); 4270Sigor@sysoev.ru 4280Sigor@sysoev.ru if (!nxt_double_is_zero(f) && buf < end) { 4290Sigor@sysoev.ru *buf++ = '.'; 4300Sigor@sysoev.ru 4310Sigor@sysoev.ru while (!nxt_double_is_zero(f) && buf < end) { 4320Sigor@sysoev.ru f *= 10; 4330Sigor@sysoev.ru f = modf(f, &i); 4340Sigor@sysoev.ru *buf++ = (u_char) i + '0'; 4350Sigor@sysoev.ru } 4360Sigor@sysoev.ru } 4370Sigor@sysoev.ru } 4380Sigor@sysoev.ru 4390Sigor@sysoev.ru continue; 4400Sigor@sysoev.ru 4410Sigor@sysoev.ru case 'r': 4420Sigor@sysoev.ru i64 = (int64_t) va_arg(args, rlim_t); 4430Sigor@sysoev.ru sign = 1; 4440Sigor@sysoev.ru break; 4450Sigor@sysoev.ru 4460Sigor@sysoev.ru case 'p': 4470Sigor@sysoev.ru ui64 = (uintptr_t) va_arg(args, void *); 4480Sigor@sysoev.ru sign = 0; 4490Sigor@sysoev.ru spf.hex = HEXADECIMAL; 4500Sigor@sysoev.ru /* 4510Sigor@sysoev.ru * spf.width = NXT_PTR_SIZE * 2; 4520Sigor@sysoev.ru * spf.padding = '0'; 4530Sigor@sysoev.ru */ 4540Sigor@sysoev.ru goto number; 4550Sigor@sysoev.ru 4560Sigor@sysoev.ru case 'c': 4570Sigor@sysoev.ru d = va_arg(args, int); 458611Svbart@nginx.com *buf++ = (u_char) (d & 0xFF); 4590Sigor@sysoev.ru fmt++; 4600Sigor@sysoev.ru 4610Sigor@sysoev.ru continue; 4620Sigor@sysoev.ru 4630Sigor@sysoev.ru case 'F': 4640Sigor@sysoev.ru fmt++; 4650Sigor@sysoev.ru 4660Sigor@sysoev.ru switch (*fmt) { 4670Sigor@sysoev.ru 4680Sigor@sysoev.ru case 'D': 4690Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_fd_t); 4700Sigor@sysoev.ru sign = 1; 4710Sigor@sysoev.ru 4720Sigor@sysoev.ru goto number; 4730Sigor@sysoev.ru 4740Sigor@sysoev.ru case 'N': 4750Sigor@sysoev.ru fn = va_arg(args, nxt_file_name_t *); 4760Sigor@sysoev.ru p = fn; 4770Sigor@sysoev.ru 4780Sigor@sysoev.ru while (*p != '\0' && buf < end) { 4790Sigor@sysoev.ru *buf++ = *p++; 4800Sigor@sysoev.ru } 4810Sigor@sysoev.ru 4820Sigor@sysoev.ru fmt++; 4830Sigor@sysoev.ru continue; 4840Sigor@sysoev.ru 4850Sigor@sysoev.ru default: 4860Sigor@sysoev.ru continue; 4870Sigor@sysoev.ru } 4880Sigor@sysoev.ru 4890Sigor@sysoev.ru case 'P': 4900Sigor@sysoev.ru fmt++; 4910Sigor@sysoev.ru 4920Sigor@sysoev.ru switch (*fmt) { 4930Sigor@sysoev.ru 4940Sigor@sysoev.ru case 'I': 4950Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_pid_t); 4960Sigor@sysoev.ru sign = 1; 4970Sigor@sysoev.ru goto number; 4980Sigor@sysoev.ru 4990Sigor@sysoev.ru case 'T': 500336Spluknet@nginx.com ui64 = (uint64_t) (uintptr_t) va_arg(args, nxt_tid_t); 5010Sigor@sysoev.ru sign = 0; 5020Sigor@sysoev.ru goto number; 503326Svbart@nginx.com #if 0 5040Sigor@sysoev.ru case 'F': 5050Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_fid_t); 5060Sigor@sysoev.ru sign = 0; 5070Sigor@sysoev.ru goto number; 508326Svbart@nginx.com #endif 5090Sigor@sysoev.ru case 'H': 5100Sigor@sysoev.ru ui64 = (uint64_t) (uintptr_t) va_arg(args, pthread_t); 5110Sigor@sysoev.ru spf.hex = HEXADECIMAL; 5120Sigor@sysoev.ru sign = 0; 5130Sigor@sysoev.ru goto number; 5140Sigor@sysoev.ru 5150Sigor@sysoev.ru default: 5160Sigor@sysoev.ru continue; 5170Sigor@sysoev.ru } 5180Sigor@sysoev.ru 5190Sigor@sysoev.ru case 'Z': 5200Sigor@sysoev.ru *buf++ = '\0'; 5210Sigor@sysoev.ru fmt++; 5220Sigor@sysoev.ru continue; 5230Sigor@sysoev.ru 5240Sigor@sysoev.ru case 'n': 5250Sigor@sysoev.ru *buf++ = NXT_LF; 5260Sigor@sysoev.ru fmt++; 5270Sigor@sysoev.ru continue; 5280Sigor@sysoev.ru 5290Sigor@sysoev.ru case '%': 5300Sigor@sysoev.ru *buf++ = '%'; 5310Sigor@sysoev.ru fmt++; 5320Sigor@sysoev.ru continue; 5330Sigor@sysoev.ru 5340Sigor@sysoev.ru default: 5350Sigor@sysoev.ru *buf++ = *fmt++; 5360Sigor@sysoev.ru continue; 5370Sigor@sysoev.ru } 5380Sigor@sysoev.ru 5390Sigor@sysoev.ru number: 5400Sigor@sysoev.ru 5410Sigor@sysoev.ru if (sign) { 5420Sigor@sysoev.ru if (i64 < 0) { 5430Sigor@sysoev.ru *buf++ = '-'; 5440Sigor@sysoev.ru ui64 = (uint64_t) -i64; 5450Sigor@sysoev.ru 5460Sigor@sysoev.ru } else { 5470Sigor@sysoev.ru ui64 = (uint64_t) i64; 5480Sigor@sysoev.ru } 5490Sigor@sysoev.ru } 5500Sigor@sysoev.ru 5510Sigor@sysoev.ru buf = nxt_integer(&spf, buf, ui64); 5520Sigor@sysoev.ru 5530Sigor@sysoev.ru fmt++; 5540Sigor@sysoev.ru continue; 5550Sigor@sysoev.ru 5560Sigor@sysoev.ru copy: 5570Sigor@sysoev.ru 55810Sigor@sysoev.ru buf = nxt_cpymem(buf, p, nxt_min((size_t) (end - buf), length)); 5590Sigor@sysoev.ru continue; 5600Sigor@sysoev.ru } 5610Sigor@sysoev.ru 5620Sigor@sysoev.ru return buf; 5630Sigor@sysoev.ru } 5640Sigor@sysoev.ru 5650Sigor@sysoev.ru 5660Sigor@sysoev.ru static u_char * 5670Sigor@sysoev.ru nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) 5680Sigor@sysoev.ru { 5690Sigor@sysoev.ru u_char *p, *end; 57010Sigor@sysoev.ru size_t length; 5710Sigor@sysoev.ru u_char temp[NXT_INT64_T_LEN]; 5720Sigor@sysoev.ru 5730Sigor@sysoev.ru p = temp + NXT_INT64_T_LEN; 5740Sigor@sysoev.ru 5750Sigor@sysoev.ru if (spf->hex == NULL) { 5760Sigor@sysoev.ru 5770Sigor@sysoev.ru #if (NXT_32BIT) 5780Sigor@sysoev.ru 5790Sigor@sysoev.ru for ( ;; ) { 5800Sigor@sysoev.ru u_char *start; 5810Sigor@sysoev.ru uint32_t ui32; 5820Sigor@sysoev.ru 5830Sigor@sysoev.ru /* 5840Sigor@sysoev.ru * 32-bit platforms usually lack hardware support of 64-bit 5850Sigor@sysoev.ru * division and remainder operations. For this reason C compiler 5860Sigor@sysoev.ru * adds calls to the runtime library functions which provides 5870Sigor@sysoev.ru * these operations. These functions usually have about hundred 5880Sigor@sysoev.ru * lines of code. 5890Sigor@sysoev.ru * 5900Sigor@sysoev.ru * For 32-bit numbers and some constant divisors GCC, Clang and 5910Sigor@sysoev.ru * other compilers can use inlined multiplications and shifts 5920Sigor@sysoev.ru * which are faster than division or remainder operations. 5930Sigor@sysoev.ru * For example, unsigned "ui32 / 10" is compiled to 5940Sigor@sysoev.ru * 5950Sigor@sysoev.ru * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 5960Sigor@sysoev.ru * 5970Sigor@sysoev.ru * So a 64-bit number is split to parts by 10^9. The parts fit 5980Sigor@sysoev.ru * to 32 bits and are processed separately as 32-bit numbers. A 5990Sigor@sysoev.ru * number of 64-bit division/remainder operations is significantly 6000Sigor@sysoev.ru * decreased depending on the 64-bit number's value, it is 6010Sigor@sysoev.ru * 0 if the 64-bit value is less than 4294967296, 6020Sigor@sysoev.ru * 1 if the 64-bit value is greater than 4294967295 6030Sigor@sysoev.ru * and less than 4294967296000000000, 6040Sigor@sysoev.ru * 2 otherwise. 6050Sigor@sysoev.ru */ 6060Sigor@sysoev.ru 607611Svbart@nginx.com if (ui64 <= 0xFFFFFFFF) { 6080Sigor@sysoev.ru ui32 = (uint32_t) ui64; 6090Sigor@sysoev.ru start = NULL; 6100Sigor@sysoev.ru 6110Sigor@sysoev.ru } else { 6120Sigor@sysoev.ru ui32 = (uint32_t) (ui64 % 1000000000); 6130Sigor@sysoev.ru start = p - 9; 6140Sigor@sysoev.ru } 6150Sigor@sysoev.ru 6160Sigor@sysoev.ru do { 6170Sigor@sysoev.ru *(--p) = (u_char) (ui32 % 10 + '0'); 6180Sigor@sysoev.ru ui32 /= 10; 6190Sigor@sysoev.ru } while (ui32 != 0); 6200Sigor@sysoev.ru 6210Sigor@sysoev.ru if (start == NULL) { 6220Sigor@sysoev.ru break; 6230Sigor@sysoev.ru } 6240Sigor@sysoev.ru 6250Sigor@sysoev.ru /* Add leading zeros of part. */ 6260Sigor@sysoev.ru 6270Sigor@sysoev.ru while (p > start) { 6280Sigor@sysoev.ru *(--p) = '0'; 6290Sigor@sysoev.ru } 6300Sigor@sysoev.ru 6310Sigor@sysoev.ru ui64 /= 1000000000; 6320Sigor@sysoev.ru } 6330Sigor@sysoev.ru 6340Sigor@sysoev.ru #else /* NXT_64BIT */ 6350Sigor@sysoev.ru 6360Sigor@sysoev.ru do { 6370Sigor@sysoev.ru *(--p) = (u_char) (ui64 % 10 + '0'); 6380Sigor@sysoev.ru ui64 /= 10; 6390Sigor@sysoev.ru } while (ui64 != 0); 6400Sigor@sysoev.ru 6410Sigor@sysoev.ru #endif 6420Sigor@sysoev.ru 6430Sigor@sysoev.ru } else { 6440Sigor@sysoev.ru 6450Sigor@sysoev.ru do { 646611Svbart@nginx.com *(--p) = spf->hex[ui64 & 0xF]; 6470Sigor@sysoev.ru ui64 >>= 4; 6480Sigor@sysoev.ru } while (ui64 != 0); 6490Sigor@sysoev.ru } 6500Sigor@sysoev.ru 6510Sigor@sysoev.ru /* Zero or space padding. */ 6520Sigor@sysoev.ru 6530Sigor@sysoev.ru if (spf->width != 0) { 6540Sigor@sysoev.ru 65510Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 65610Sigor@sysoev.ru end = buf + (spf->width - length); 6570Sigor@sysoev.ru end = nxt_min(end, spf->end); 6580Sigor@sysoev.ru 6590Sigor@sysoev.ru while (buf < end) { 6600Sigor@sysoev.ru *buf++ = spf->padding; 6610Sigor@sysoev.ru } 6620Sigor@sysoev.ru } 6630Sigor@sysoev.ru 6640Sigor@sysoev.ru /* Number copying. */ 6650Sigor@sysoev.ru 66610Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 66710Sigor@sysoev.ru end = buf + length; 6680Sigor@sysoev.ru end = nxt_min(end, spf->end); 6690Sigor@sysoev.ru 6700Sigor@sysoev.ru while (buf < end) { 6710Sigor@sysoev.ru *buf++ = *p++; 6720Sigor@sysoev.ru } 6730Sigor@sysoev.ru 6740Sigor@sysoev.ru return buf; 6750Sigor@sysoev.ru } 6760Sigor@sysoev.ru 6770Sigor@sysoev.ru 6780Sigor@sysoev.ru static u_char * 6790Sigor@sysoev.ru nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) 6800Sigor@sysoev.ru { 6810Sigor@sysoev.ru u_char *p, *end; 68210Sigor@sysoev.ru size_t length; 6830Sigor@sysoev.ru u_char temp[NXT_DOUBLE_LEN]; 6840Sigor@sysoev.ru 6850Sigor@sysoev.ru p = temp + NXT_DOUBLE_LEN; 6860Sigor@sysoev.ru 6870Sigor@sysoev.ru do { 6880Sigor@sysoev.ru *(--p) = (u_char) (fmod(n, 10) + '0'); 6890Sigor@sysoev.ru n = trunc(n / 10); 6900Sigor@sysoev.ru } while (!nxt_double_is_zero(n)); 6910Sigor@sysoev.ru 6920Sigor@sysoev.ru /* Zero or space padding. */ 6930Sigor@sysoev.ru 6940Sigor@sysoev.ru if (spf->width != 0) { 69510Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 69610Sigor@sysoev.ru end = buf + (spf->width - length); 6970Sigor@sysoev.ru end = nxt_min(end, spf->end); 6980Sigor@sysoev.ru 6990Sigor@sysoev.ru while (buf < end) { 7000Sigor@sysoev.ru *buf++ = spf->padding; 7010Sigor@sysoev.ru } 7020Sigor@sysoev.ru } 7030Sigor@sysoev.ru 7040Sigor@sysoev.ru /* Number copying. */ 7050Sigor@sysoev.ru 70610Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 7070Sigor@sysoev.ru 70810Sigor@sysoev.ru end = buf + length; 7090Sigor@sysoev.ru end = nxt_min(end, spf->end); 7100Sigor@sysoev.ru 7110Sigor@sysoev.ru while (buf < end) { 7120Sigor@sysoev.ru *buf++ = *p++; 7130Sigor@sysoev.ru } 7140Sigor@sysoev.ru 7150Sigor@sysoev.ru return buf; 7160Sigor@sysoev.ru } 717