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 * 151183Svbart@nginx.com * %[0][width][x|X]O nxt_off_t 161183Svbart@nginx.com * %[0][width][x|X]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 { 791008Szelenkov@nginx.com u_char *end; 801008Szelenkov@nginx.com const u_char *hex; 811008Szelenkov@nginx.com uint32_t width; 821008Szelenkov@nginx.com int32_t frac_width; 831008Szelenkov@nginx.com uint8_t max_width; 841008Szelenkov@nginx.com 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". */ 932084Salx.manpages@gmail.com #define nxt_double_is_zero(f) \ 940Sigor@sysoev.ru (fabs(f) <= FLT_EPSILON) 950Sigor@sysoev.ru 960Sigor@sysoev.ru 970Sigor@sysoev.ru u_char * 980Sigor@sysoev.ru nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) 990Sigor@sysoev.ru { 1000Sigor@sysoev.ru int d; 1010Sigor@sysoev.ru double f, i; 10210Sigor@sysoev.ru size_t length; 1030Sigor@sysoev.ru int64_t i64; 1040Sigor@sysoev.ru uint64_t ui64, frac; 1050Sigor@sysoev.ru nxt_str_t *v; 1060Sigor@sysoev.ru nxt_err_t err; 1070Sigor@sysoev.ru nxt_uint_t scale, n; 1080Sigor@sysoev.ru nxt_msec_t ms; 1090Sigor@sysoev.ru nxt_nsec_t ns; 1100Sigor@sysoev.ru nxt_bool_t sign; 111*2105Salx.manpages@gmail.com const u_char *p; 1120Sigor@sysoev.ru nxt_sprintf_t spf; 1130Sigor@sysoev.ru nxt_file_name_t *fn; 1140Sigor@sysoev.ru 1150Sigor@sysoev.ru static const u_char hexadecimal[16] = "0123456789abcdef"; 1160Sigor@sysoev.ru static const u_char HEXADECIMAL[16] = "0123456789ABCDEF"; 1170Sigor@sysoev.ru static const u_char nan[] = "[nan]"; 1180Sigor@sysoev.ru static const u_char infinity[] = "[infinity]"; 1190Sigor@sysoev.ru 1200Sigor@sysoev.ru spf.end = end; 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru while (*fmt != '\0' && buf < end) { 1230Sigor@sysoev.ru 1240Sigor@sysoev.ru /* 1250Sigor@sysoev.ru * "buf < end" means that we could copy at least one character: 1260Sigor@sysoev.ru * a plain character, "%%", "%c", or a minus without test. 1270Sigor@sysoev.ru */ 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru if (*fmt != '%') { 1300Sigor@sysoev.ru *buf++ = *fmt++; 1310Sigor@sysoev.ru continue; 1320Sigor@sysoev.ru } 1330Sigor@sysoev.ru 1340Sigor@sysoev.ru fmt++; 1350Sigor@sysoev.ru 1360Sigor@sysoev.ru /* Test some often used text formats first. */ 1370Sigor@sysoev.ru 1380Sigor@sysoev.ru switch (*fmt) { 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru case 'V': 1410Sigor@sysoev.ru fmt++; 1420Sigor@sysoev.ru v = va_arg(args, nxt_str_t *); 1430Sigor@sysoev.ru 1440Sigor@sysoev.ru if (nxt_fast_path(v != NULL)) { 14510Sigor@sysoev.ru length = v->length; 14610Sigor@sysoev.ru p = v->start; 1470Sigor@sysoev.ru goto copy; 1480Sigor@sysoev.ru } 1490Sigor@sysoev.ru 1500Sigor@sysoev.ru continue; 1510Sigor@sysoev.ru 1520Sigor@sysoev.ru case 's': 153*2105Salx.manpages@gmail.com p = va_arg(args, const u_char *); 1540Sigor@sysoev.ru 1550Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 1560Sigor@sysoev.ru while (*p != '\0' && buf < end) { 1570Sigor@sysoev.ru *buf++ = *p++; 1580Sigor@sysoev.ru } 1590Sigor@sysoev.ru } 1600Sigor@sysoev.ru 1610Sigor@sysoev.ru fmt++; 1620Sigor@sysoev.ru continue; 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru case '*': 165493Spluknet@nginx.com length = va_arg(args, size_t); 1660Sigor@sysoev.ru 1670Sigor@sysoev.ru fmt++; 1680Sigor@sysoev.ru 1690Sigor@sysoev.ru if (*fmt == 's') { 1700Sigor@sysoev.ru fmt++; 171*2105Salx.manpages@gmail.com p = va_arg(args, const u_char *); 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 1740Sigor@sysoev.ru goto copy; 1750Sigor@sysoev.ru } 1760Sigor@sysoev.ru } 1770Sigor@sysoev.ru 1780Sigor@sysoev.ru continue; 1790Sigor@sysoev.ru 1800Sigor@sysoev.ru default: 1810Sigor@sysoev.ru break; 1820Sigor@sysoev.ru } 1830Sigor@sysoev.ru 1840Sigor@sysoev.ru spf.hex = NULL; 1850Sigor@sysoev.ru spf.width = 0; 1860Sigor@sysoev.ru spf.frac_width = -1; 1870Sigor@sysoev.ru spf.max_width = 0; 1880Sigor@sysoev.ru spf.padding = (*fmt == '0') ? '0' : ' '; 1890Sigor@sysoev.ru 1900Sigor@sysoev.ru sign = 1; 1910Sigor@sysoev.ru 1920Sigor@sysoev.ru i64 = 0; 1930Sigor@sysoev.ru ui64 = 0; 1940Sigor@sysoev.ru 1950Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 1960Sigor@sysoev.ru spf.width = spf.width * 10 + (*fmt++ - '0'); 1970Sigor@sysoev.ru } 1980Sigor@sysoev.ru 1990Sigor@sysoev.ru 2000Sigor@sysoev.ru for ( ;; ) { 2010Sigor@sysoev.ru switch (*fmt) { 2020Sigor@sysoev.ru 2030Sigor@sysoev.ru case 'u': 2040Sigor@sysoev.ru sign = 0; 2050Sigor@sysoev.ru fmt++; 2060Sigor@sysoev.ru continue; 2070Sigor@sysoev.ru 2080Sigor@sysoev.ru case 'm': 2090Sigor@sysoev.ru spf.max_width = 1; 2100Sigor@sysoev.ru fmt++; 2110Sigor@sysoev.ru continue; 2120Sigor@sysoev.ru 2130Sigor@sysoev.ru case 'X': 2140Sigor@sysoev.ru spf.hex = HEXADECIMAL; 2150Sigor@sysoev.ru sign = 0; 2160Sigor@sysoev.ru fmt++; 2170Sigor@sysoev.ru continue; 2180Sigor@sysoev.ru 2190Sigor@sysoev.ru case 'x': 2200Sigor@sysoev.ru spf.hex = hexadecimal; 2210Sigor@sysoev.ru sign = 0; 2220Sigor@sysoev.ru fmt++; 2230Sigor@sysoev.ru continue; 2240Sigor@sysoev.ru 2250Sigor@sysoev.ru case '.': 2260Sigor@sysoev.ru fmt++; 2270Sigor@sysoev.ru spf.frac_width = 0; 2280Sigor@sysoev.ru 2290Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 2300Sigor@sysoev.ru spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; 2310Sigor@sysoev.ru } 2320Sigor@sysoev.ru 2330Sigor@sysoev.ru break; 2340Sigor@sysoev.ru 2350Sigor@sysoev.ru default: 2360Sigor@sysoev.ru break; 2370Sigor@sysoev.ru } 2380Sigor@sysoev.ru 2390Sigor@sysoev.ru break; 2400Sigor@sysoev.ru } 2410Sigor@sysoev.ru 2420Sigor@sysoev.ru 2430Sigor@sysoev.ru switch (*fmt) { 2440Sigor@sysoev.ru 2450Sigor@sysoev.ru case 'E': 2460Sigor@sysoev.ru err = va_arg(args, nxt_err_t); 2470Sigor@sysoev.ru 2480Sigor@sysoev.ru *buf++ = '('; 2490Sigor@sysoev.ru spf.hex = NULL; 2500Sigor@sysoev.ru spf.width = 0; 2510Sigor@sysoev.ru buf = nxt_integer(&spf, buf, err); 2520Sigor@sysoev.ru 2530Sigor@sysoev.ru if (buf < end - 1) { 2540Sigor@sysoev.ru *buf++ = ':'; 2550Sigor@sysoev.ru *buf++ = ' '; 2560Sigor@sysoev.ru } 2570Sigor@sysoev.ru 2580Sigor@sysoev.ru buf = nxt_strerror(err, buf, end - buf); 2590Sigor@sysoev.ru 2600Sigor@sysoev.ru if (buf < end) { 2610Sigor@sysoev.ru *buf++ = ')'; 2620Sigor@sysoev.ru } 2630Sigor@sysoev.ru 2640Sigor@sysoev.ru fmt++; 2650Sigor@sysoev.ru continue; 2660Sigor@sysoev.ru 2670Sigor@sysoev.ru case 'O': 2680Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_off_t); 2690Sigor@sysoev.ru sign = 1; 2700Sigor@sysoev.ru goto number; 2710Sigor@sysoev.ru 2720Sigor@sysoev.ru case 'T': 2730Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_time_t); 2740Sigor@sysoev.ru sign = 1; 2750Sigor@sysoev.ru goto number; 2760Sigor@sysoev.ru 2770Sigor@sysoev.ru case 'M': 2780Sigor@sysoev.ru ms = (nxt_msec_t) va_arg(args, nxt_msec_t); 2790Sigor@sysoev.ru if ((nxt_msec_int_t) ms == -1 && spf.hex == NULL) { 2800Sigor@sysoev.ru i64 = -1; 2810Sigor@sysoev.ru sign = 1; 2820Sigor@sysoev.ru } else { 2830Sigor@sysoev.ru ui64 = (uint64_t) ms; 2840Sigor@sysoev.ru sign = 0; 2850Sigor@sysoev.ru } 2860Sigor@sysoev.ru goto number; 2870Sigor@sysoev.ru 2880Sigor@sysoev.ru case 'N': 2890Sigor@sysoev.ru ns = (nxt_nsec_t) va_arg(args, nxt_nsec_t); 2900Sigor@sysoev.ru if ((nxt_nsec_int_t) ns == -1) { 2910Sigor@sysoev.ru i64 = -1; 2920Sigor@sysoev.ru sign = 1; 2930Sigor@sysoev.ru } else { 2940Sigor@sysoev.ru ui64 = (uint64_t) ns; 2950Sigor@sysoev.ru sign = 0; 2960Sigor@sysoev.ru } 2970Sigor@sysoev.ru goto number; 2980Sigor@sysoev.ru 2990Sigor@sysoev.ru case 'z': 3000Sigor@sysoev.ru if (sign) { 3010Sigor@sysoev.ru i64 = (int64_t) va_arg(args, ssize_t); 3020Sigor@sysoev.ru } else { 3030Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, size_t); 3040Sigor@sysoev.ru } 3050Sigor@sysoev.ru goto number; 3060Sigor@sysoev.ru 3070Sigor@sysoev.ru case 'i': 3080Sigor@sysoev.ru if (sign) { 3090Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_int_t); 3100Sigor@sysoev.ru } else { 3110Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_uint_t); 3120Sigor@sysoev.ru } 3130Sigor@sysoev.ru 3140Sigor@sysoev.ru if (spf.max_width != 0) { 3150Sigor@sysoev.ru spf.width = NXT_INT_T_LEN; 3160Sigor@sysoev.ru } 3170Sigor@sysoev.ru 3180Sigor@sysoev.ru goto number; 3190Sigor@sysoev.ru 3200Sigor@sysoev.ru case 'd': 3210Sigor@sysoev.ru if (sign) { 3220Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int); 3230Sigor@sysoev.ru } else { 3240Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_int); 3250Sigor@sysoev.ru } 3260Sigor@sysoev.ru goto number; 3270Sigor@sysoev.ru 3280Sigor@sysoev.ru case 'l': 3290Sigor@sysoev.ru if (sign) { 3300Sigor@sysoev.ru i64 = (int64_t) va_arg(args, long); 3310Sigor@sysoev.ru } else { 3320Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_long); 3330Sigor@sysoev.ru } 3340Sigor@sysoev.ru goto number; 3350Sigor@sysoev.ru 3360Sigor@sysoev.ru case 'D': 3370Sigor@sysoev.ru if (sign) { 3380Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int32_t); 3390Sigor@sysoev.ru } else { 3400Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, uint32_t); 3410Sigor@sysoev.ru } 3420Sigor@sysoev.ru goto number; 3430Sigor@sysoev.ru 3440Sigor@sysoev.ru case 'L': 3450Sigor@sysoev.ru if (sign) { 3460Sigor@sysoev.ru i64 = va_arg(args, int64_t); 3470Sigor@sysoev.ru } else { 3480Sigor@sysoev.ru ui64 = va_arg(args, uint64_t); 3490Sigor@sysoev.ru } 3500Sigor@sysoev.ru goto number; 3510Sigor@sysoev.ru 3520Sigor@sysoev.ru case 'A': 3530Sigor@sysoev.ru if (sign) { 3540Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_atomic_int_t); 3550Sigor@sysoev.ru } else { 3560Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_atomic_uint_t); 3570Sigor@sysoev.ru } 3580Sigor@sysoev.ru 3590Sigor@sysoev.ru if (spf.max_width != 0) { 3600Sigor@sysoev.ru spf.width = NXT_ATOMIC_T_LEN; 3610Sigor@sysoev.ru } 3620Sigor@sysoev.ru 3630Sigor@sysoev.ru goto number; 3640Sigor@sysoev.ru 3650Sigor@sysoev.ru case 'b': 3660Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_bool_t); 3670Sigor@sysoev.ru sign = 0; 3680Sigor@sysoev.ru goto number; 3690Sigor@sysoev.ru 3700Sigor@sysoev.ru case 'f': 3710Sigor@sysoev.ru fmt++; 3720Sigor@sysoev.ru 3730Sigor@sysoev.ru f = va_arg(args, double); 3740Sigor@sysoev.ru 3750Sigor@sysoev.ru if (f < 0) { 3760Sigor@sysoev.ru *buf++ = '-'; 3770Sigor@sysoev.ru f = -f; 3780Sigor@sysoev.ru } 3790Sigor@sysoev.ru 3800Sigor@sysoev.ru if (nxt_slow_path(isnan(f))) { 381*2105Salx.manpages@gmail.com p = nan; 382703Svbart@nginx.com length = nxt_length(nan); 3830Sigor@sysoev.ru 3840Sigor@sysoev.ru goto copy; 3850Sigor@sysoev.ru 3860Sigor@sysoev.ru } else if (nxt_slow_path(isinf(f))) { 387*2105Salx.manpages@gmail.com p = infinity; 388703Svbart@nginx.com length = nxt_length(infinity); 3890Sigor@sysoev.ru 3900Sigor@sysoev.ru goto copy; 3910Sigor@sysoev.ru } 3920Sigor@sysoev.ru 3930Sigor@sysoev.ru (void) modf(f, &i); 3940Sigor@sysoev.ru frac = 0; 3950Sigor@sysoev.ru 3960Sigor@sysoev.ru if (spf.frac_width > 0) { 3970Sigor@sysoev.ru 3980Sigor@sysoev.ru scale = 1; 3990Sigor@sysoev.ru for (n = spf.frac_width; n != 0; n--) { 4000Sigor@sysoev.ru scale *= 10; 4010Sigor@sysoev.ru } 4020Sigor@sysoev.ru 4030Sigor@sysoev.ru frac = (uint64_t) ((f - i) * scale + 0.5); 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru if (frac == scale) { 4060Sigor@sysoev.ru i += 1; 4070Sigor@sysoev.ru frac = 0; 4080Sigor@sysoev.ru } 4090Sigor@sysoev.ru } 4100Sigor@sysoev.ru 4110Sigor@sysoev.ru buf = nxt_number(&spf, buf, i); 4120Sigor@sysoev.ru 4130Sigor@sysoev.ru if (spf.frac_width > 0) { 4140Sigor@sysoev.ru 4150Sigor@sysoev.ru if (buf < end) { 4160Sigor@sysoev.ru *buf++ = '.'; 4170Sigor@sysoev.ru 4180Sigor@sysoev.ru spf.hex = NULL; 4190Sigor@sysoev.ru spf.padding = '0'; 4200Sigor@sysoev.ru spf.width = spf.frac_width; 4210Sigor@sysoev.ru buf = nxt_integer(&spf, buf, frac); 4220Sigor@sysoev.ru } 4230Sigor@sysoev.ru 4240Sigor@sysoev.ru } else if (spf.frac_width < 0) { 4250Sigor@sysoev.ru f = modf(f, &i); 4260Sigor@sysoev.ru 4270Sigor@sysoev.ru if (!nxt_double_is_zero(f) && buf < end) { 4280Sigor@sysoev.ru *buf++ = '.'; 4290Sigor@sysoev.ru 4300Sigor@sysoev.ru while (!nxt_double_is_zero(f) && buf < end) { 4310Sigor@sysoev.ru f *= 10; 4320Sigor@sysoev.ru f = modf(f, &i); 4330Sigor@sysoev.ru *buf++ = (u_char) i + '0'; 4340Sigor@sysoev.ru } 4350Sigor@sysoev.ru } 4360Sigor@sysoev.ru } 4370Sigor@sysoev.ru 4380Sigor@sysoev.ru continue; 4390Sigor@sysoev.ru 4400Sigor@sysoev.ru case 'r': 4410Sigor@sysoev.ru i64 = (int64_t) va_arg(args, rlim_t); 4420Sigor@sysoev.ru sign = 1; 4430Sigor@sysoev.ru break; 4440Sigor@sysoev.ru 4450Sigor@sysoev.ru case 'p': 4460Sigor@sysoev.ru ui64 = (uintptr_t) va_arg(args, void *); 4470Sigor@sysoev.ru sign = 0; 4480Sigor@sysoev.ru spf.hex = HEXADECIMAL; 4490Sigor@sysoev.ru /* 4500Sigor@sysoev.ru * spf.width = NXT_PTR_SIZE * 2; 4510Sigor@sysoev.ru * spf.padding = '0'; 4520Sigor@sysoev.ru */ 4530Sigor@sysoev.ru goto number; 4540Sigor@sysoev.ru 4550Sigor@sysoev.ru case 'c': 4560Sigor@sysoev.ru d = va_arg(args, int); 457611Svbart@nginx.com *buf++ = (u_char) (d & 0xFF); 4580Sigor@sysoev.ru fmt++; 4590Sigor@sysoev.ru 4600Sigor@sysoev.ru continue; 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru case 'F': 4630Sigor@sysoev.ru fmt++; 4640Sigor@sysoev.ru 4650Sigor@sysoev.ru switch (*fmt) { 4660Sigor@sysoev.ru 4670Sigor@sysoev.ru case 'D': 4680Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_fd_t); 4690Sigor@sysoev.ru sign = 1; 4700Sigor@sysoev.ru 4710Sigor@sysoev.ru goto number; 4720Sigor@sysoev.ru 4730Sigor@sysoev.ru case 'N': 4740Sigor@sysoev.ru fn = va_arg(args, nxt_file_name_t *); 4750Sigor@sysoev.ru p = fn; 4760Sigor@sysoev.ru 4770Sigor@sysoev.ru while (*p != '\0' && buf < end) { 4780Sigor@sysoev.ru *buf++ = *p++; 4790Sigor@sysoev.ru } 4800Sigor@sysoev.ru 4810Sigor@sysoev.ru fmt++; 4820Sigor@sysoev.ru continue; 4830Sigor@sysoev.ru 4840Sigor@sysoev.ru default: 4850Sigor@sysoev.ru continue; 4860Sigor@sysoev.ru } 4870Sigor@sysoev.ru 4880Sigor@sysoev.ru case 'P': 4890Sigor@sysoev.ru fmt++; 4900Sigor@sysoev.ru 4910Sigor@sysoev.ru switch (*fmt) { 4920Sigor@sysoev.ru 4930Sigor@sysoev.ru case 'I': 4940Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_pid_t); 4950Sigor@sysoev.ru sign = 1; 4960Sigor@sysoev.ru goto number; 4970Sigor@sysoev.ru 4980Sigor@sysoev.ru case 'T': 499336Spluknet@nginx.com ui64 = (uint64_t) (uintptr_t) va_arg(args, nxt_tid_t); 5000Sigor@sysoev.ru sign = 0; 5010Sigor@sysoev.ru goto number; 502326Svbart@nginx.com #if 0 5030Sigor@sysoev.ru case 'F': 5040Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_fid_t); 5050Sigor@sysoev.ru sign = 0; 5060Sigor@sysoev.ru goto number; 507326Svbart@nginx.com #endif 5080Sigor@sysoev.ru case 'H': 5090Sigor@sysoev.ru ui64 = (uint64_t) (uintptr_t) va_arg(args, pthread_t); 5100Sigor@sysoev.ru spf.hex = HEXADECIMAL; 5110Sigor@sysoev.ru sign = 0; 5120Sigor@sysoev.ru goto number; 5130Sigor@sysoev.ru 5140Sigor@sysoev.ru default: 5150Sigor@sysoev.ru continue; 5160Sigor@sysoev.ru } 5170Sigor@sysoev.ru 5180Sigor@sysoev.ru case 'Z': 5190Sigor@sysoev.ru *buf++ = '\0'; 5200Sigor@sysoev.ru fmt++; 5210Sigor@sysoev.ru continue; 5220Sigor@sysoev.ru 5230Sigor@sysoev.ru case 'n': 524704Sigor@sysoev.ru *buf++ = '\n'; 5250Sigor@sysoev.ru fmt++; 5260Sigor@sysoev.ru continue; 5270Sigor@sysoev.ru 5280Sigor@sysoev.ru case '%': 5290Sigor@sysoev.ru *buf++ = '%'; 5300Sigor@sysoev.ru fmt++; 5310Sigor@sysoev.ru continue; 5320Sigor@sysoev.ru 5330Sigor@sysoev.ru default: 5340Sigor@sysoev.ru *buf++ = *fmt++; 5350Sigor@sysoev.ru continue; 5360Sigor@sysoev.ru } 5370Sigor@sysoev.ru 5380Sigor@sysoev.ru number: 5390Sigor@sysoev.ru 5400Sigor@sysoev.ru if (sign) { 5410Sigor@sysoev.ru if (i64 < 0) { 5420Sigor@sysoev.ru *buf++ = '-'; 5430Sigor@sysoev.ru ui64 = (uint64_t) -i64; 5440Sigor@sysoev.ru 5450Sigor@sysoev.ru } else { 5460Sigor@sysoev.ru ui64 = (uint64_t) i64; 5470Sigor@sysoev.ru } 5480Sigor@sysoev.ru } 5490Sigor@sysoev.ru 5500Sigor@sysoev.ru buf = nxt_integer(&spf, buf, ui64); 5510Sigor@sysoev.ru 5520Sigor@sysoev.ru fmt++; 5530Sigor@sysoev.ru continue; 5540Sigor@sysoev.ru 5550Sigor@sysoev.ru copy: 5560Sigor@sysoev.ru 55710Sigor@sysoev.ru buf = nxt_cpymem(buf, p, nxt_min((size_t) (end - buf), length)); 5580Sigor@sysoev.ru continue; 5590Sigor@sysoev.ru } 5600Sigor@sysoev.ru 5610Sigor@sysoev.ru return buf; 5620Sigor@sysoev.ru } 5630Sigor@sysoev.ru 5640Sigor@sysoev.ru 5650Sigor@sysoev.ru static u_char * 5660Sigor@sysoev.ru nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) 5670Sigor@sysoev.ru { 5680Sigor@sysoev.ru u_char *p, *end; 56910Sigor@sysoev.ru size_t length; 5700Sigor@sysoev.ru u_char temp[NXT_INT64_T_LEN]; 5710Sigor@sysoev.ru 5720Sigor@sysoev.ru p = temp + NXT_INT64_T_LEN; 5730Sigor@sysoev.ru 5740Sigor@sysoev.ru if (spf->hex == NULL) { 5750Sigor@sysoev.ru 5760Sigor@sysoev.ru #if (NXT_32BIT) 5770Sigor@sysoev.ru 5780Sigor@sysoev.ru for ( ;; ) { 5790Sigor@sysoev.ru u_char *start; 5800Sigor@sysoev.ru uint32_t ui32; 5810Sigor@sysoev.ru 5820Sigor@sysoev.ru /* 5830Sigor@sysoev.ru * 32-bit platforms usually lack hardware support of 64-bit 5840Sigor@sysoev.ru * division and remainder operations. For this reason C compiler 5850Sigor@sysoev.ru * adds calls to the runtime library functions which provides 5860Sigor@sysoev.ru * these operations. These functions usually have about hundred 5870Sigor@sysoev.ru * lines of code. 5880Sigor@sysoev.ru * 5890Sigor@sysoev.ru * For 32-bit numbers and some constant divisors GCC, Clang and 5900Sigor@sysoev.ru * other compilers can use inlined multiplications and shifts 5910Sigor@sysoev.ru * which are faster than division or remainder operations. 5920Sigor@sysoev.ru * For example, unsigned "ui32 / 10" is compiled to 5930Sigor@sysoev.ru * 5940Sigor@sysoev.ru * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 5950Sigor@sysoev.ru * 5960Sigor@sysoev.ru * So a 64-bit number is split to parts by 10^9. The parts fit 5970Sigor@sysoev.ru * to 32 bits and are processed separately as 32-bit numbers. A 5980Sigor@sysoev.ru * number of 64-bit division/remainder operations is significantly 5990Sigor@sysoev.ru * decreased depending on the 64-bit number's value, it is 6000Sigor@sysoev.ru * 0 if the 64-bit value is less than 4294967296, 6010Sigor@sysoev.ru * 1 if the 64-bit value is greater than 4294967295 6020Sigor@sysoev.ru * and less than 4294967296000000000, 6030Sigor@sysoev.ru * 2 otherwise. 6040Sigor@sysoev.ru */ 6050Sigor@sysoev.ru 606611Svbart@nginx.com if (ui64 <= 0xFFFFFFFF) { 6070Sigor@sysoev.ru ui32 = (uint32_t) ui64; 6080Sigor@sysoev.ru start = NULL; 6090Sigor@sysoev.ru 6100Sigor@sysoev.ru } else { 6110Sigor@sysoev.ru ui32 = (uint32_t) (ui64 % 1000000000); 6120Sigor@sysoev.ru start = p - 9; 6130Sigor@sysoev.ru } 6140Sigor@sysoev.ru 6150Sigor@sysoev.ru do { 6160Sigor@sysoev.ru *(--p) = (u_char) (ui32 % 10 + '0'); 6170Sigor@sysoev.ru ui32 /= 10; 6180Sigor@sysoev.ru } while (ui32 != 0); 6190Sigor@sysoev.ru 6200Sigor@sysoev.ru if (start == NULL) { 6210Sigor@sysoev.ru break; 6220Sigor@sysoev.ru } 6230Sigor@sysoev.ru 6240Sigor@sysoev.ru /* Add leading zeros of part. */ 6250Sigor@sysoev.ru 6260Sigor@sysoev.ru while (p > start) { 6270Sigor@sysoev.ru *(--p) = '0'; 6280Sigor@sysoev.ru } 6290Sigor@sysoev.ru 6300Sigor@sysoev.ru ui64 /= 1000000000; 6310Sigor@sysoev.ru } 6320Sigor@sysoev.ru 6330Sigor@sysoev.ru #else /* NXT_64BIT */ 6340Sigor@sysoev.ru 6350Sigor@sysoev.ru do { 6360Sigor@sysoev.ru *(--p) = (u_char) (ui64 % 10 + '0'); 6370Sigor@sysoev.ru ui64 /= 10; 6380Sigor@sysoev.ru } while (ui64 != 0); 6390Sigor@sysoev.ru 6400Sigor@sysoev.ru #endif 6410Sigor@sysoev.ru 6420Sigor@sysoev.ru } else { 6430Sigor@sysoev.ru 6440Sigor@sysoev.ru do { 645611Svbart@nginx.com *(--p) = spf->hex[ui64 & 0xF]; 6460Sigor@sysoev.ru ui64 >>= 4; 6470Sigor@sysoev.ru } while (ui64 != 0); 6480Sigor@sysoev.ru } 6490Sigor@sysoev.ru 6500Sigor@sysoev.ru /* Zero or space padding. */ 6510Sigor@sysoev.ru 6520Sigor@sysoev.ru if (spf->width != 0) { 6530Sigor@sysoev.ru 65410Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 65510Sigor@sysoev.ru end = buf + (spf->width - length); 6560Sigor@sysoev.ru end = nxt_min(end, spf->end); 6570Sigor@sysoev.ru 6580Sigor@sysoev.ru while (buf < end) { 6590Sigor@sysoev.ru *buf++ = spf->padding; 6600Sigor@sysoev.ru } 6610Sigor@sysoev.ru } 6620Sigor@sysoev.ru 6630Sigor@sysoev.ru /* Number copying. */ 6640Sigor@sysoev.ru 66510Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 66610Sigor@sysoev.ru end = buf + length; 6670Sigor@sysoev.ru end = nxt_min(end, spf->end); 6680Sigor@sysoev.ru 6690Sigor@sysoev.ru while (buf < end) { 6700Sigor@sysoev.ru *buf++ = *p++; 6710Sigor@sysoev.ru } 6720Sigor@sysoev.ru 6730Sigor@sysoev.ru return buf; 6740Sigor@sysoev.ru } 6750Sigor@sysoev.ru 6760Sigor@sysoev.ru 6770Sigor@sysoev.ru static u_char * 6780Sigor@sysoev.ru nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) 6790Sigor@sysoev.ru { 6800Sigor@sysoev.ru u_char *p, *end; 68110Sigor@sysoev.ru size_t length; 6820Sigor@sysoev.ru u_char temp[NXT_DOUBLE_LEN]; 6830Sigor@sysoev.ru 6840Sigor@sysoev.ru p = temp + NXT_DOUBLE_LEN; 6850Sigor@sysoev.ru 6860Sigor@sysoev.ru do { 6870Sigor@sysoev.ru *(--p) = (u_char) (fmod(n, 10) + '0'); 6880Sigor@sysoev.ru n = trunc(n / 10); 6890Sigor@sysoev.ru } while (!nxt_double_is_zero(n)); 6900Sigor@sysoev.ru 6910Sigor@sysoev.ru /* Zero or space padding. */ 6920Sigor@sysoev.ru 6930Sigor@sysoev.ru if (spf->width != 0) { 69410Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 69510Sigor@sysoev.ru end = buf + (spf->width - length); 6960Sigor@sysoev.ru end = nxt_min(end, spf->end); 6970Sigor@sysoev.ru 6980Sigor@sysoev.ru while (buf < end) { 6990Sigor@sysoev.ru *buf++ = spf->padding; 7000Sigor@sysoev.ru } 7010Sigor@sysoev.ru } 7020Sigor@sysoev.ru 7030Sigor@sysoev.ru /* Number copying. */ 7040Sigor@sysoev.ru 70510Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 7060Sigor@sysoev.ru 70710Sigor@sysoev.ru end = buf + length; 7080Sigor@sysoev.ru end = nxt_min(end, spf->end); 7090Sigor@sysoev.ru 7100Sigor@sysoev.ru while (buf < end) { 7110Sigor@sysoev.ru *buf++ = *p++; 7120Sigor@sysoev.ru } 7130Sigor@sysoev.ru 7140Sigor@sysoev.ru return buf; 7150Sigor@sysoev.ru } 716