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; 1112105Salx.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]"; 118*2115Szelenkov@nginx.com static const u_char null[] = "[null]"; 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': 154*2115Szelenkov@nginx.com fmt++; 155*2115Szelenkov@nginx.com 1562105Salx.manpages@gmail.com p = va_arg(args, const u_char *); 1570Sigor@sysoev.ru 158*2115Szelenkov@nginx.com if (nxt_slow_path(p == NULL)) { 159*2115Szelenkov@nginx.com goto copy; 1600Sigor@sysoev.ru } 1610Sigor@sysoev.ru 162*2115Szelenkov@nginx.com while (*p != '\0' && buf < end) { 163*2115Szelenkov@nginx.com *buf++ = *p++; 164*2115Szelenkov@nginx.com } 165*2115Szelenkov@nginx.com 1660Sigor@sysoev.ru continue; 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru case '*': 169493Spluknet@nginx.com length = va_arg(args, size_t); 1700Sigor@sysoev.ru 1710Sigor@sysoev.ru fmt++; 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru if (*fmt == 's') { 1740Sigor@sysoev.ru fmt++; 1752105Salx.manpages@gmail.com p = va_arg(args, const u_char *); 1760Sigor@sysoev.ru 177*2115Szelenkov@nginx.com goto copy; 1780Sigor@sysoev.ru } 1790Sigor@sysoev.ru 1800Sigor@sysoev.ru continue; 1810Sigor@sysoev.ru 1820Sigor@sysoev.ru default: 1830Sigor@sysoev.ru break; 1840Sigor@sysoev.ru } 1850Sigor@sysoev.ru 1860Sigor@sysoev.ru spf.hex = NULL; 1870Sigor@sysoev.ru spf.width = 0; 1880Sigor@sysoev.ru spf.frac_width = -1; 1890Sigor@sysoev.ru spf.max_width = 0; 1900Sigor@sysoev.ru spf.padding = (*fmt == '0') ? '0' : ' '; 1910Sigor@sysoev.ru 1920Sigor@sysoev.ru sign = 1; 1930Sigor@sysoev.ru 1940Sigor@sysoev.ru i64 = 0; 1950Sigor@sysoev.ru ui64 = 0; 1960Sigor@sysoev.ru 1970Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 1980Sigor@sysoev.ru spf.width = spf.width * 10 + (*fmt++ - '0'); 1990Sigor@sysoev.ru } 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru 2020Sigor@sysoev.ru for ( ;; ) { 2030Sigor@sysoev.ru switch (*fmt) { 2040Sigor@sysoev.ru 2050Sigor@sysoev.ru case 'u': 2060Sigor@sysoev.ru sign = 0; 2070Sigor@sysoev.ru fmt++; 2080Sigor@sysoev.ru continue; 2090Sigor@sysoev.ru 2100Sigor@sysoev.ru case 'm': 2110Sigor@sysoev.ru spf.max_width = 1; 2120Sigor@sysoev.ru fmt++; 2130Sigor@sysoev.ru continue; 2140Sigor@sysoev.ru 2150Sigor@sysoev.ru case 'X': 2160Sigor@sysoev.ru spf.hex = HEXADECIMAL; 2170Sigor@sysoev.ru sign = 0; 2180Sigor@sysoev.ru fmt++; 2190Sigor@sysoev.ru continue; 2200Sigor@sysoev.ru 2210Sigor@sysoev.ru case 'x': 2220Sigor@sysoev.ru spf.hex = hexadecimal; 2230Sigor@sysoev.ru sign = 0; 2240Sigor@sysoev.ru fmt++; 2250Sigor@sysoev.ru continue; 2260Sigor@sysoev.ru 2270Sigor@sysoev.ru case '.': 2280Sigor@sysoev.ru fmt++; 2290Sigor@sysoev.ru spf.frac_width = 0; 2300Sigor@sysoev.ru 2310Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 2320Sigor@sysoev.ru spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; 2330Sigor@sysoev.ru } 2340Sigor@sysoev.ru 2350Sigor@sysoev.ru break; 2360Sigor@sysoev.ru 2370Sigor@sysoev.ru default: 2380Sigor@sysoev.ru break; 2390Sigor@sysoev.ru } 2400Sigor@sysoev.ru 2410Sigor@sysoev.ru break; 2420Sigor@sysoev.ru } 2430Sigor@sysoev.ru 2440Sigor@sysoev.ru 2450Sigor@sysoev.ru switch (*fmt) { 2460Sigor@sysoev.ru 2470Sigor@sysoev.ru case 'E': 2480Sigor@sysoev.ru err = va_arg(args, nxt_err_t); 2490Sigor@sysoev.ru 2500Sigor@sysoev.ru *buf++ = '('; 2510Sigor@sysoev.ru spf.hex = NULL; 2520Sigor@sysoev.ru spf.width = 0; 2530Sigor@sysoev.ru buf = nxt_integer(&spf, buf, err); 2540Sigor@sysoev.ru 2550Sigor@sysoev.ru if (buf < end - 1) { 2560Sigor@sysoev.ru *buf++ = ':'; 2570Sigor@sysoev.ru *buf++ = ' '; 2580Sigor@sysoev.ru } 2590Sigor@sysoev.ru 2600Sigor@sysoev.ru buf = nxt_strerror(err, buf, end - buf); 2610Sigor@sysoev.ru 2620Sigor@sysoev.ru if (buf < end) { 2630Sigor@sysoev.ru *buf++ = ')'; 2640Sigor@sysoev.ru } 2650Sigor@sysoev.ru 2660Sigor@sysoev.ru fmt++; 2670Sigor@sysoev.ru continue; 2680Sigor@sysoev.ru 2690Sigor@sysoev.ru case 'O': 2700Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_off_t); 2710Sigor@sysoev.ru sign = 1; 2720Sigor@sysoev.ru goto number; 2730Sigor@sysoev.ru 2740Sigor@sysoev.ru case 'T': 2750Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_time_t); 2760Sigor@sysoev.ru sign = 1; 2770Sigor@sysoev.ru goto number; 2780Sigor@sysoev.ru 2790Sigor@sysoev.ru case 'M': 2800Sigor@sysoev.ru ms = (nxt_msec_t) va_arg(args, nxt_msec_t); 2810Sigor@sysoev.ru if ((nxt_msec_int_t) ms == -1 && spf.hex == NULL) { 2820Sigor@sysoev.ru i64 = -1; 2830Sigor@sysoev.ru sign = 1; 2840Sigor@sysoev.ru } else { 2850Sigor@sysoev.ru ui64 = (uint64_t) ms; 2860Sigor@sysoev.ru sign = 0; 2870Sigor@sysoev.ru } 2880Sigor@sysoev.ru goto number; 2890Sigor@sysoev.ru 2900Sigor@sysoev.ru case 'N': 2910Sigor@sysoev.ru ns = (nxt_nsec_t) va_arg(args, nxt_nsec_t); 2920Sigor@sysoev.ru if ((nxt_nsec_int_t) ns == -1) { 2930Sigor@sysoev.ru i64 = -1; 2940Sigor@sysoev.ru sign = 1; 2950Sigor@sysoev.ru } else { 2960Sigor@sysoev.ru ui64 = (uint64_t) ns; 2970Sigor@sysoev.ru sign = 0; 2980Sigor@sysoev.ru } 2990Sigor@sysoev.ru goto number; 3000Sigor@sysoev.ru 3010Sigor@sysoev.ru case 'z': 3020Sigor@sysoev.ru if (sign) { 3030Sigor@sysoev.ru i64 = (int64_t) va_arg(args, ssize_t); 3040Sigor@sysoev.ru } else { 3050Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, size_t); 3060Sigor@sysoev.ru } 3070Sigor@sysoev.ru goto number; 3080Sigor@sysoev.ru 3090Sigor@sysoev.ru case 'i': 3100Sigor@sysoev.ru if (sign) { 3110Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_int_t); 3120Sigor@sysoev.ru } else { 3130Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_uint_t); 3140Sigor@sysoev.ru } 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru if (spf.max_width != 0) { 3170Sigor@sysoev.ru spf.width = NXT_INT_T_LEN; 3180Sigor@sysoev.ru } 3190Sigor@sysoev.ru 3200Sigor@sysoev.ru goto number; 3210Sigor@sysoev.ru 3220Sigor@sysoev.ru case 'd': 3230Sigor@sysoev.ru if (sign) { 3240Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int); 3250Sigor@sysoev.ru } else { 3260Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_int); 3270Sigor@sysoev.ru } 3280Sigor@sysoev.ru goto number; 3290Sigor@sysoev.ru 3300Sigor@sysoev.ru case 'l': 3310Sigor@sysoev.ru if (sign) { 3320Sigor@sysoev.ru i64 = (int64_t) va_arg(args, long); 3330Sigor@sysoev.ru } else { 3340Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_long); 3350Sigor@sysoev.ru } 3360Sigor@sysoev.ru goto number; 3370Sigor@sysoev.ru 3380Sigor@sysoev.ru case 'D': 3390Sigor@sysoev.ru if (sign) { 3400Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int32_t); 3410Sigor@sysoev.ru } else { 3420Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, uint32_t); 3430Sigor@sysoev.ru } 3440Sigor@sysoev.ru goto number; 3450Sigor@sysoev.ru 3460Sigor@sysoev.ru case 'L': 3470Sigor@sysoev.ru if (sign) { 3480Sigor@sysoev.ru i64 = va_arg(args, int64_t); 3490Sigor@sysoev.ru } else { 3500Sigor@sysoev.ru ui64 = va_arg(args, uint64_t); 3510Sigor@sysoev.ru } 3520Sigor@sysoev.ru goto number; 3530Sigor@sysoev.ru 3540Sigor@sysoev.ru case 'A': 3550Sigor@sysoev.ru if (sign) { 3560Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_atomic_int_t); 3570Sigor@sysoev.ru } else { 3580Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_atomic_uint_t); 3590Sigor@sysoev.ru } 3600Sigor@sysoev.ru 3610Sigor@sysoev.ru if (spf.max_width != 0) { 3620Sigor@sysoev.ru spf.width = NXT_ATOMIC_T_LEN; 3630Sigor@sysoev.ru } 3640Sigor@sysoev.ru 3650Sigor@sysoev.ru goto number; 3660Sigor@sysoev.ru 3670Sigor@sysoev.ru case 'b': 3680Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_bool_t); 3690Sigor@sysoev.ru sign = 0; 3700Sigor@sysoev.ru goto number; 3710Sigor@sysoev.ru 3720Sigor@sysoev.ru case 'f': 3730Sigor@sysoev.ru fmt++; 3740Sigor@sysoev.ru 3750Sigor@sysoev.ru f = va_arg(args, double); 3760Sigor@sysoev.ru 3770Sigor@sysoev.ru if (f < 0) { 3780Sigor@sysoev.ru *buf++ = '-'; 3790Sigor@sysoev.ru f = -f; 3800Sigor@sysoev.ru } 3810Sigor@sysoev.ru 3820Sigor@sysoev.ru if (nxt_slow_path(isnan(f))) { 3832105Salx.manpages@gmail.com p = nan; 384703Svbart@nginx.com length = nxt_length(nan); 3850Sigor@sysoev.ru 3860Sigor@sysoev.ru goto copy; 3870Sigor@sysoev.ru 3880Sigor@sysoev.ru } else if (nxt_slow_path(isinf(f))) { 3892105Salx.manpages@gmail.com p = infinity; 390703Svbart@nginx.com length = nxt_length(infinity); 3910Sigor@sysoev.ru 3920Sigor@sysoev.ru goto copy; 3930Sigor@sysoev.ru } 3940Sigor@sysoev.ru 3950Sigor@sysoev.ru (void) modf(f, &i); 3960Sigor@sysoev.ru frac = 0; 3970Sigor@sysoev.ru 3980Sigor@sysoev.ru if (spf.frac_width > 0) { 3990Sigor@sysoev.ru 4000Sigor@sysoev.ru scale = 1; 4010Sigor@sysoev.ru for (n = spf.frac_width; n != 0; n--) { 4020Sigor@sysoev.ru scale *= 10; 4030Sigor@sysoev.ru } 4040Sigor@sysoev.ru 4050Sigor@sysoev.ru frac = (uint64_t) ((f - i) * scale + 0.5); 4060Sigor@sysoev.ru 4070Sigor@sysoev.ru if (frac == scale) { 4080Sigor@sysoev.ru i += 1; 4090Sigor@sysoev.ru frac = 0; 4100Sigor@sysoev.ru } 4110Sigor@sysoev.ru } 4120Sigor@sysoev.ru 4130Sigor@sysoev.ru buf = nxt_number(&spf, buf, i); 4140Sigor@sysoev.ru 4150Sigor@sysoev.ru if (spf.frac_width > 0) { 4160Sigor@sysoev.ru 4170Sigor@sysoev.ru if (buf < end) { 4180Sigor@sysoev.ru *buf++ = '.'; 4190Sigor@sysoev.ru 4200Sigor@sysoev.ru spf.hex = NULL; 4210Sigor@sysoev.ru spf.padding = '0'; 4220Sigor@sysoev.ru spf.width = spf.frac_width; 4230Sigor@sysoev.ru buf = nxt_integer(&spf, buf, frac); 4240Sigor@sysoev.ru } 4250Sigor@sysoev.ru 4260Sigor@sysoev.ru } else if (spf.frac_width < 0) { 4270Sigor@sysoev.ru f = modf(f, &i); 4280Sigor@sysoev.ru 4290Sigor@sysoev.ru if (!nxt_double_is_zero(f) && buf < end) { 4300Sigor@sysoev.ru *buf++ = '.'; 4310Sigor@sysoev.ru 4320Sigor@sysoev.ru while (!nxt_double_is_zero(f) && buf < end) { 4330Sigor@sysoev.ru f *= 10; 4340Sigor@sysoev.ru f = modf(f, &i); 4350Sigor@sysoev.ru *buf++ = (u_char) i + '0'; 4360Sigor@sysoev.ru } 4370Sigor@sysoev.ru } 4380Sigor@sysoev.ru } 4390Sigor@sysoev.ru 4400Sigor@sysoev.ru continue; 4410Sigor@sysoev.ru 4420Sigor@sysoev.ru case 'r': 4430Sigor@sysoev.ru i64 = (int64_t) va_arg(args, rlim_t); 4440Sigor@sysoev.ru sign = 1; 4450Sigor@sysoev.ru break; 4460Sigor@sysoev.ru 4470Sigor@sysoev.ru case 'p': 4480Sigor@sysoev.ru ui64 = (uintptr_t) va_arg(args, void *); 4490Sigor@sysoev.ru sign = 0; 4500Sigor@sysoev.ru spf.hex = HEXADECIMAL; 4510Sigor@sysoev.ru /* 4520Sigor@sysoev.ru * spf.width = NXT_PTR_SIZE * 2; 4530Sigor@sysoev.ru * spf.padding = '0'; 4540Sigor@sysoev.ru */ 4550Sigor@sysoev.ru goto number; 4560Sigor@sysoev.ru 4570Sigor@sysoev.ru case 'c': 4580Sigor@sysoev.ru d = va_arg(args, int); 459611Svbart@nginx.com *buf++ = (u_char) (d & 0xFF); 4600Sigor@sysoev.ru fmt++; 4610Sigor@sysoev.ru 4620Sigor@sysoev.ru continue; 4630Sigor@sysoev.ru 4640Sigor@sysoev.ru case 'F': 4650Sigor@sysoev.ru fmt++; 4660Sigor@sysoev.ru 4670Sigor@sysoev.ru switch (*fmt) { 4680Sigor@sysoev.ru 4690Sigor@sysoev.ru case 'D': 4700Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_fd_t); 4710Sigor@sysoev.ru sign = 1; 4720Sigor@sysoev.ru 4730Sigor@sysoev.ru goto number; 4740Sigor@sysoev.ru 4750Sigor@sysoev.ru case 'N': 4760Sigor@sysoev.ru fn = va_arg(args, nxt_file_name_t *); 4770Sigor@sysoev.ru p = fn; 4780Sigor@sysoev.ru 4790Sigor@sysoev.ru while (*p != '\0' && buf < end) { 4800Sigor@sysoev.ru *buf++ = *p++; 4810Sigor@sysoev.ru } 4820Sigor@sysoev.ru 4830Sigor@sysoev.ru fmt++; 4840Sigor@sysoev.ru continue; 4850Sigor@sysoev.ru 4860Sigor@sysoev.ru default: 4870Sigor@sysoev.ru continue; 4880Sigor@sysoev.ru } 4890Sigor@sysoev.ru 4900Sigor@sysoev.ru case 'P': 4910Sigor@sysoev.ru fmt++; 4920Sigor@sysoev.ru 4930Sigor@sysoev.ru switch (*fmt) { 4940Sigor@sysoev.ru 4950Sigor@sysoev.ru case 'I': 4960Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_pid_t); 4970Sigor@sysoev.ru sign = 1; 4980Sigor@sysoev.ru goto number; 4990Sigor@sysoev.ru 5000Sigor@sysoev.ru case 'T': 501336Spluknet@nginx.com ui64 = (uint64_t) (uintptr_t) va_arg(args, nxt_tid_t); 5020Sigor@sysoev.ru sign = 0; 5030Sigor@sysoev.ru goto number; 504326Svbart@nginx.com #if 0 5050Sigor@sysoev.ru case 'F': 5060Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_fid_t); 5070Sigor@sysoev.ru sign = 0; 5080Sigor@sysoev.ru goto number; 509326Svbart@nginx.com #endif 5100Sigor@sysoev.ru case 'H': 5110Sigor@sysoev.ru ui64 = (uint64_t) (uintptr_t) va_arg(args, pthread_t); 5120Sigor@sysoev.ru spf.hex = HEXADECIMAL; 5130Sigor@sysoev.ru sign = 0; 5140Sigor@sysoev.ru goto number; 5150Sigor@sysoev.ru 5160Sigor@sysoev.ru default: 5170Sigor@sysoev.ru continue; 5180Sigor@sysoev.ru } 5190Sigor@sysoev.ru 5200Sigor@sysoev.ru case 'Z': 5210Sigor@sysoev.ru *buf++ = '\0'; 5220Sigor@sysoev.ru fmt++; 5230Sigor@sysoev.ru continue; 5240Sigor@sysoev.ru 5250Sigor@sysoev.ru case 'n': 526704Sigor@sysoev.ru *buf++ = '\n'; 5270Sigor@sysoev.ru fmt++; 5280Sigor@sysoev.ru continue; 5290Sigor@sysoev.ru 5300Sigor@sysoev.ru case '%': 5310Sigor@sysoev.ru *buf++ = '%'; 5320Sigor@sysoev.ru fmt++; 5330Sigor@sysoev.ru continue; 5340Sigor@sysoev.ru 5350Sigor@sysoev.ru default: 5360Sigor@sysoev.ru *buf++ = *fmt++; 5370Sigor@sysoev.ru continue; 5380Sigor@sysoev.ru } 5390Sigor@sysoev.ru 5400Sigor@sysoev.ru number: 5410Sigor@sysoev.ru 5420Sigor@sysoev.ru if (sign) { 5430Sigor@sysoev.ru if (i64 < 0) { 5440Sigor@sysoev.ru *buf++ = '-'; 5450Sigor@sysoev.ru ui64 = (uint64_t) -i64; 5460Sigor@sysoev.ru 5470Sigor@sysoev.ru } else { 5480Sigor@sysoev.ru ui64 = (uint64_t) i64; 5490Sigor@sysoev.ru } 5500Sigor@sysoev.ru } 5510Sigor@sysoev.ru 5520Sigor@sysoev.ru buf = nxt_integer(&spf, buf, ui64); 5530Sigor@sysoev.ru 5540Sigor@sysoev.ru fmt++; 5550Sigor@sysoev.ru continue; 5560Sigor@sysoev.ru 5570Sigor@sysoev.ru copy: 5580Sigor@sysoev.ru 559*2115Szelenkov@nginx.com if (nxt_slow_path(p == NULL)) { 560*2115Szelenkov@nginx.com p = null; 561*2115Szelenkov@nginx.com length = nxt_length(null); 562*2115Szelenkov@nginx.com 563*2115Szelenkov@nginx.com } else { 564*2115Szelenkov@nginx.com length = nxt_min((size_t) (end - buf), length); 565*2115Szelenkov@nginx.com } 566*2115Szelenkov@nginx.com 567*2115Szelenkov@nginx.com buf = nxt_cpymem(buf, p, length); 5680Sigor@sysoev.ru continue; 5690Sigor@sysoev.ru } 5700Sigor@sysoev.ru 5710Sigor@sysoev.ru return buf; 5720Sigor@sysoev.ru } 5730Sigor@sysoev.ru 5740Sigor@sysoev.ru 5750Sigor@sysoev.ru static u_char * 5760Sigor@sysoev.ru nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) 5770Sigor@sysoev.ru { 5780Sigor@sysoev.ru u_char *p, *end; 57910Sigor@sysoev.ru size_t length; 5800Sigor@sysoev.ru u_char temp[NXT_INT64_T_LEN]; 5810Sigor@sysoev.ru 5820Sigor@sysoev.ru p = temp + NXT_INT64_T_LEN; 5830Sigor@sysoev.ru 5840Sigor@sysoev.ru if (spf->hex == NULL) { 5850Sigor@sysoev.ru 5860Sigor@sysoev.ru #if (NXT_32BIT) 5870Sigor@sysoev.ru 5880Sigor@sysoev.ru for ( ;; ) { 5890Sigor@sysoev.ru u_char *start; 5900Sigor@sysoev.ru uint32_t ui32; 5910Sigor@sysoev.ru 5920Sigor@sysoev.ru /* 5930Sigor@sysoev.ru * 32-bit platforms usually lack hardware support of 64-bit 5940Sigor@sysoev.ru * division and remainder operations. For this reason C compiler 5950Sigor@sysoev.ru * adds calls to the runtime library functions which provides 5960Sigor@sysoev.ru * these operations. These functions usually have about hundred 5970Sigor@sysoev.ru * lines of code. 5980Sigor@sysoev.ru * 5990Sigor@sysoev.ru * For 32-bit numbers and some constant divisors GCC, Clang and 6000Sigor@sysoev.ru * other compilers can use inlined multiplications and shifts 6010Sigor@sysoev.ru * which are faster than division or remainder operations. 6020Sigor@sysoev.ru * For example, unsigned "ui32 / 10" is compiled to 6030Sigor@sysoev.ru * 6040Sigor@sysoev.ru * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 6050Sigor@sysoev.ru * 6060Sigor@sysoev.ru * So a 64-bit number is split to parts by 10^9. The parts fit 6070Sigor@sysoev.ru * to 32 bits and are processed separately as 32-bit numbers. A 6080Sigor@sysoev.ru * number of 64-bit division/remainder operations is significantly 6090Sigor@sysoev.ru * decreased depending on the 64-bit number's value, it is 6100Sigor@sysoev.ru * 0 if the 64-bit value is less than 4294967296, 6110Sigor@sysoev.ru * 1 if the 64-bit value is greater than 4294967295 6120Sigor@sysoev.ru * and less than 4294967296000000000, 6130Sigor@sysoev.ru * 2 otherwise. 6140Sigor@sysoev.ru */ 6150Sigor@sysoev.ru 616611Svbart@nginx.com if (ui64 <= 0xFFFFFFFF) { 6170Sigor@sysoev.ru ui32 = (uint32_t) ui64; 6180Sigor@sysoev.ru start = NULL; 6190Sigor@sysoev.ru 6200Sigor@sysoev.ru } else { 6210Sigor@sysoev.ru ui32 = (uint32_t) (ui64 % 1000000000); 6220Sigor@sysoev.ru start = p - 9; 6230Sigor@sysoev.ru } 6240Sigor@sysoev.ru 6250Sigor@sysoev.ru do { 6260Sigor@sysoev.ru *(--p) = (u_char) (ui32 % 10 + '0'); 6270Sigor@sysoev.ru ui32 /= 10; 6280Sigor@sysoev.ru } while (ui32 != 0); 6290Sigor@sysoev.ru 6300Sigor@sysoev.ru if (start == NULL) { 6310Sigor@sysoev.ru break; 6320Sigor@sysoev.ru } 6330Sigor@sysoev.ru 6340Sigor@sysoev.ru /* Add leading zeros of part. */ 6350Sigor@sysoev.ru 6360Sigor@sysoev.ru while (p > start) { 6370Sigor@sysoev.ru *(--p) = '0'; 6380Sigor@sysoev.ru } 6390Sigor@sysoev.ru 6400Sigor@sysoev.ru ui64 /= 1000000000; 6410Sigor@sysoev.ru } 6420Sigor@sysoev.ru 6430Sigor@sysoev.ru #else /* NXT_64BIT */ 6440Sigor@sysoev.ru 6450Sigor@sysoev.ru do { 6460Sigor@sysoev.ru *(--p) = (u_char) (ui64 % 10 + '0'); 6470Sigor@sysoev.ru ui64 /= 10; 6480Sigor@sysoev.ru } while (ui64 != 0); 6490Sigor@sysoev.ru 6500Sigor@sysoev.ru #endif 6510Sigor@sysoev.ru 6520Sigor@sysoev.ru } else { 6530Sigor@sysoev.ru 6540Sigor@sysoev.ru do { 655611Svbart@nginx.com *(--p) = spf->hex[ui64 & 0xF]; 6560Sigor@sysoev.ru ui64 >>= 4; 6570Sigor@sysoev.ru } while (ui64 != 0); 6580Sigor@sysoev.ru } 6590Sigor@sysoev.ru 6600Sigor@sysoev.ru /* Zero or space padding. */ 6610Sigor@sysoev.ru 6620Sigor@sysoev.ru if (spf->width != 0) { 6630Sigor@sysoev.ru 66410Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 66510Sigor@sysoev.ru end = buf + (spf->width - length); 6660Sigor@sysoev.ru end = nxt_min(end, spf->end); 6670Sigor@sysoev.ru 6680Sigor@sysoev.ru while (buf < end) { 6690Sigor@sysoev.ru *buf++ = spf->padding; 6700Sigor@sysoev.ru } 6710Sigor@sysoev.ru } 6720Sigor@sysoev.ru 6730Sigor@sysoev.ru /* Number copying. */ 6740Sigor@sysoev.ru 67510Sigor@sysoev.ru length = (temp + NXT_INT64_T_LEN) - p; 67610Sigor@sysoev.ru end = buf + length; 6770Sigor@sysoev.ru end = nxt_min(end, spf->end); 6780Sigor@sysoev.ru 6790Sigor@sysoev.ru while (buf < end) { 6800Sigor@sysoev.ru *buf++ = *p++; 6810Sigor@sysoev.ru } 6820Sigor@sysoev.ru 6830Sigor@sysoev.ru return buf; 6840Sigor@sysoev.ru } 6850Sigor@sysoev.ru 6860Sigor@sysoev.ru 6870Sigor@sysoev.ru static u_char * 6880Sigor@sysoev.ru nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) 6890Sigor@sysoev.ru { 6900Sigor@sysoev.ru u_char *p, *end; 69110Sigor@sysoev.ru size_t length; 6920Sigor@sysoev.ru u_char temp[NXT_DOUBLE_LEN]; 6930Sigor@sysoev.ru 6940Sigor@sysoev.ru p = temp + NXT_DOUBLE_LEN; 6950Sigor@sysoev.ru 6960Sigor@sysoev.ru do { 6970Sigor@sysoev.ru *(--p) = (u_char) (fmod(n, 10) + '0'); 6980Sigor@sysoev.ru n = trunc(n / 10); 6990Sigor@sysoev.ru } while (!nxt_double_is_zero(n)); 7000Sigor@sysoev.ru 7010Sigor@sysoev.ru /* Zero or space padding. */ 7020Sigor@sysoev.ru 7030Sigor@sysoev.ru if (spf->width != 0) { 70410Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 70510Sigor@sysoev.ru end = buf + (spf->width - length); 7060Sigor@sysoev.ru end = nxt_min(end, spf->end); 7070Sigor@sysoev.ru 7080Sigor@sysoev.ru while (buf < end) { 7090Sigor@sysoev.ru *buf++ = spf->padding; 7100Sigor@sysoev.ru } 7110Sigor@sysoev.ru } 7120Sigor@sysoev.ru 7130Sigor@sysoev.ru /* Number copying. */ 7140Sigor@sysoev.ru 71510Sigor@sysoev.ru length = (temp + NXT_DOUBLE_LEN) - p; 7160Sigor@sysoev.ru 71710Sigor@sysoev.ru end = buf + length; 7180Sigor@sysoev.ru end = nxt_min(end, spf->end); 7190Sigor@sysoev.ru 7200Sigor@sysoev.ru while (buf < end) { 7210Sigor@sysoev.ru *buf++ = *p++; 7220Sigor@sysoev.ru } 7230Sigor@sysoev.ru 7240Sigor@sysoev.ru return buf; 7250Sigor@sysoev.ru } 726