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
nxt_sprintf(u_char * buf,u_char * end,const char * fmt,...)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 *
nxt_vsprintf(u_char * buf,u_char * end,const char * fmt,va_list args)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 *
nxt_integer(nxt_sprintf_t * spf,u_char * buf,uint64_t ui64)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 *
nxt_number(nxt_sprintf_t * spf,u_char * buf,double n)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