1*0Sigor@sysoev.ru 2*0Sigor@sysoev.ru /* 3*0Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*0Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*0Sigor@sysoev.ru */ 6*0Sigor@sysoev.ru 7*0Sigor@sysoev.ru #include <nxt_main.h> 8*0Sigor@sysoev.ru #include <math.h> 9*0Sigor@sysoev.ru #include <float.h> 10*0Sigor@sysoev.ru 11*0Sigor@sysoev.ru 12*0Sigor@sysoev.ru /* 13*0Sigor@sysoev.ru * Supported formats: 14*0Sigor@sysoev.ru * 15*0Sigor@sysoev.ru * %[0][width][x][X]O nxt_off_t 16*0Sigor@sysoev.ru * %[0][width]T nxt_time_t 17*0Sigor@sysoev.ru * %[0][width][u][x|X]z ssize_t/size_t 18*0Sigor@sysoev.ru * %[0][width][u][x|X]d int/u_int 19*0Sigor@sysoev.ru * %[0][width][u][x|X]l long 20*0Sigor@sysoev.ru * %[0][width|m][u][x|X]i nxt_int_t/nxt_uint_t 21*0Sigor@sysoev.ru * %[0][width][u][x|X]D int32_t/uint32_t 22*0Sigor@sysoev.ru * %[0][width][u][x|X]L int64_t/uint64_t 23*0Sigor@sysoev.ru * %[0][width|m][u][x|X]A nxt_atomic_int_t/nxt_atomic_uint_t 24*0Sigor@sysoev.ru * %[0][width][.width]f double, max valid number fits to %18.15f 25*0Sigor@sysoev.ru * 26*0Sigor@sysoev.ru * %FD nxt_fd_t, int / HANDLE 27*0Sigor@sysoev.ru * %d nxt_socket_t, int 28*0Sigor@sysoev.ru * 29*0Sigor@sysoev.ru * %PI nxt_pid_t, process id 30*0Sigor@sysoev.ru * %PT nxt_tid_t, thread id 31*0Sigor@sysoev.ru * %PF nxt_fid_t, fiber id 32*0Sigor@sysoev.ru * %PH pthread_t handle returned by pthread_self() 33*0Sigor@sysoev.ru * 34*0Sigor@sysoev.ru * %s null-terminated string 35*0Sigor@sysoev.ru * %*s length and string 36*0Sigor@sysoev.ru * %FN nxt_file_name_t * 37*0Sigor@sysoev.ru * 38*0Sigor@sysoev.ru * %M nxt_msec_t 39*0Sigor@sysoev.ru * %N nxt_nsec_t 40*0Sigor@sysoev.ru * %r rlim_t 41*0Sigor@sysoev.ru * %p void * 42*0Sigor@sysoev.ru * %b nxt_bool_t 43*0Sigor@sysoev.ru * %E nxt_err_t 44*0Sigor@sysoev.ru * %V nxt_str_t * 45*0Sigor@sysoev.ru * %Z '\0' 46*0Sigor@sysoev.ru * %n '\n' 47*0Sigor@sysoev.ru * %c char 48*0Sigor@sysoev.ru * %% % 49*0Sigor@sysoev.ru * 50*0Sigor@sysoev.ru * Reserved: 51*0Sigor@sysoev.ru * %t ptrdiff_t 52*0Sigor@sysoev.ru * %S null-terminated wchar string 53*0Sigor@sysoev.ru * %C wchar 54*0Sigor@sysoev.ru * %[0][width][u][x|X]Q int182_t/uint128_t 55*0Sigor@sysoev.ru */ 56*0Sigor@sysoev.ru 57*0Sigor@sysoev.ru 58*0Sigor@sysoev.ru u_char * nxt_cdecl 59*0Sigor@sysoev.ru nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...) 60*0Sigor@sysoev.ru { 61*0Sigor@sysoev.ru u_char *p; 62*0Sigor@sysoev.ru va_list args; 63*0Sigor@sysoev.ru 64*0Sigor@sysoev.ru va_start(args, fmt); 65*0Sigor@sysoev.ru p = nxt_vsprintf(buf, end, fmt, args); 66*0Sigor@sysoev.ru va_end(args); 67*0Sigor@sysoev.ru 68*0Sigor@sysoev.ru return p; 69*0Sigor@sysoev.ru } 70*0Sigor@sysoev.ru 71*0Sigor@sysoev.ru 72*0Sigor@sysoev.ru /* 73*0Sigor@sysoev.ru * nxt_sprintf_t is used: 74*0Sigor@sysoev.ru * to pass several parameters of nxt_integer() via single pointer 75*0Sigor@sysoev.ru * and to store little used variables of nxt_vsprintf(). 76*0Sigor@sysoev.ru */ 77*0Sigor@sysoev.ru 78*0Sigor@sysoev.ru typedef struct { 79*0Sigor@sysoev.ru u_char *end; 80*0Sigor@sysoev.ru const u_char *hex; 81*0Sigor@sysoev.ru uint32_t width; 82*0Sigor@sysoev.ru int32_t frac_width; 83*0Sigor@sysoev.ru uint8_t max_width; 84*0Sigor@sysoev.ru u_char padding; 85*0Sigor@sysoev.ru } nxt_sprintf_t; 86*0Sigor@sysoev.ru 87*0Sigor@sysoev.ru 88*0Sigor@sysoev.ru static u_char *nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64); 89*0Sigor@sysoev.ru static u_char *nxt_number(nxt_sprintf_t *spf, u_char *buf, double n); 90*0Sigor@sysoev.ru 91*0Sigor@sysoev.ru 92*0Sigor@sysoev.ru /* A right way of "f == 0.0". */ 93*0Sigor@sysoev.ru #define \ 94*0Sigor@sysoev.ru nxt_double_is_zero(f) \ 95*0Sigor@sysoev.ru (fabs(f) <= FLT_EPSILON) 96*0Sigor@sysoev.ru 97*0Sigor@sysoev.ru 98*0Sigor@sysoev.ru u_char * 99*0Sigor@sysoev.ru nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) 100*0Sigor@sysoev.ru { 101*0Sigor@sysoev.ru u_char *p; 102*0Sigor@sysoev.ru int d; 103*0Sigor@sysoev.ru double f, i; 104*0Sigor@sysoev.ru size_t len; 105*0Sigor@sysoev.ru int64_t i64; 106*0Sigor@sysoev.ru uint64_t ui64, frac; 107*0Sigor@sysoev.ru nxt_str_t *v; 108*0Sigor@sysoev.ru nxt_err_t err; 109*0Sigor@sysoev.ru nxt_uint_t scale, n; 110*0Sigor@sysoev.ru nxt_msec_t ms; 111*0Sigor@sysoev.ru nxt_nsec_t ns; 112*0Sigor@sysoev.ru nxt_bool_t sign; 113*0Sigor@sysoev.ru nxt_sprintf_t spf; 114*0Sigor@sysoev.ru nxt_file_name_t *fn; 115*0Sigor@sysoev.ru 116*0Sigor@sysoev.ru static const u_char hexadecimal[16] = "0123456789abcdef"; 117*0Sigor@sysoev.ru static const u_char HEXADECIMAL[16] = "0123456789ABCDEF"; 118*0Sigor@sysoev.ru static const u_char nan[] = "[nan]"; 119*0Sigor@sysoev.ru static const u_char infinity[] = "[infinity]"; 120*0Sigor@sysoev.ru 121*0Sigor@sysoev.ru spf.end = end; 122*0Sigor@sysoev.ru 123*0Sigor@sysoev.ru while (*fmt != '\0' && buf < end) { 124*0Sigor@sysoev.ru 125*0Sigor@sysoev.ru /* 126*0Sigor@sysoev.ru * "buf < end" means that we could copy at least one character: 127*0Sigor@sysoev.ru * a plain character, "%%", "%c", or a minus without test. 128*0Sigor@sysoev.ru */ 129*0Sigor@sysoev.ru 130*0Sigor@sysoev.ru if (*fmt != '%') { 131*0Sigor@sysoev.ru *buf++ = *fmt++; 132*0Sigor@sysoev.ru continue; 133*0Sigor@sysoev.ru } 134*0Sigor@sysoev.ru 135*0Sigor@sysoev.ru fmt++; 136*0Sigor@sysoev.ru 137*0Sigor@sysoev.ru /* Test some often used text formats first. */ 138*0Sigor@sysoev.ru 139*0Sigor@sysoev.ru switch (*fmt) { 140*0Sigor@sysoev.ru 141*0Sigor@sysoev.ru case 'V': 142*0Sigor@sysoev.ru fmt++; 143*0Sigor@sysoev.ru v = va_arg(args, nxt_str_t *); 144*0Sigor@sysoev.ru 145*0Sigor@sysoev.ru if (nxt_fast_path(v != NULL)) { 146*0Sigor@sysoev.ru len = v->len; 147*0Sigor@sysoev.ru p = v->data; 148*0Sigor@sysoev.ru goto copy; 149*0Sigor@sysoev.ru } 150*0Sigor@sysoev.ru 151*0Sigor@sysoev.ru continue; 152*0Sigor@sysoev.ru 153*0Sigor@sysoev.ru case 's': 154*0Sigor@sysoev.ru p = va_arg(args, u_char *); 155*0Sigor@sysoev.ru 156*0Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 157*0Sigor@sysoev.ru while (*p != '\0' && buf < end) { 158*0Sigor@sysoev.ru *buf++ = *p++; 159*0Sigor@sysoev.ru } 160*0Sigor@sysoev.ru } 161*0Sigor@sysoev.ru 162*0Sigor@sysoev.ru fmt++; 163*0Sigor@sysoev.ru continue; 164*0Sigor@sysoev.ru 165*0Sigor@sysoev.ru case '*': 166*0Sigor@sysoev.ru len = va_arg(args, u_int); 167*0Sigor@sysoev.ru 168*0Sigor@sysoev.ru fmt++; 169*0Sigor@sysoev.ru 170*0Sigor@sysoev.ru if (*fmt == 's') { 171*0Sigor@sysoev.ru fmt++; 172*0Sigor@sysoev.ru p = va_arg(args, u_char *); 173*0Sigor@sysoev.ru 174*0Sigor@sysoev.ru if (nxt_fast_path(p != NULL)) { 175*0Sigor@sysoev.ru goto copy; 176*0Sigor@sysoev.ru } 177*0Sigor@sysoev.ru } 178*0Sigor@sysoev.ru 179*0Sigor@sysoev.ru continue; 180*0Sigor@sysoev.ru 181*0Sigor@sysoev.ru default: 182*0Sigor@sysoev.ru break; 183*0Sigor@sysoev.ru } 184*0Sigor@sysoev.ru 185*0Sigor@sysoev.ru spf.hex = NULL; 186*0Sigor@sysoev.ru spf.width = 0; 187*0Sigor@sysoev.ru spf.frac_width = -1; 188*0Sigor@sysoev.ru spf.max_width = 0; 189*0Sigor@sysoev.ru spf.padding = (*fmt == '0') ? '0' : ' '; 190*0Sigor@sysoev.ru 191*0Sigor@sysoev.ru sign = 1; 192*0Sigor@sysoev.ru 193*0Sigor@sysoev.ru i64 = 0; 194*0Sigor@sysoev.ru ui64 = 0; 195*0Sigor@sysoev.ru 196*0Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 197*0Sigor@sysoev.ru spf.width = spf.width * 10 + (*fmt++ - '0'); 198*0Sigor@sysoev.ru } 199*0Sigor@sysoev.ru 200*0Sigor@sysoev.ru 201*0Sigor@sysoev.ru for ( ;; ) { 202*0Sigor@sysoev.ru switch (*fmt) { 203*0Sigor@sysoev.ru 204*0Sigor@sysoev.ru case 'u': 205*0Sigor@sysoev.ru sign = 0; 206*0Sigor@sysoev.ru fmt++; 207*0Sigor@sysoev.ru continue; 208*0Sigor@sysoev.ru 209*0Sigor@sysoev.ru case 'm': 210*0Sigor@sysoev.ru spf.max_width = 1; 211*0Sigor@sysoev.ru fmt++; 212*0Sigor@sysoev.ru continue; 213*0Sigor@sysoev.ru 214*0Sigor@sysoev.ru case 'X': 215*0Sigor@sysoev.ru spf.hex = HEXADECIMAL; 216*0Sigor@sysoev.ru sign = 0; 217*0Sigor@sysoev.ru fmt++; 218*0Sigor@sysoev.ru continue; 219*0Sigor@sysoev.ru 220*0Sigor@sysoev.ru case 'x': 221*0Sigor@sysoev.ru spf.hex = hexadecimal; 222*0Sigor@sysoev.ru sign = 0; 223*0Sigor@sysoev.ru fmt++; 224*0Sigor@sysoev.ru continue; 225*0Sigor@sysoev.ru 226*0Sigor@sysoev.ru case '.': 227*0Sigor@sysoev.ru fmt++; 228*0Sigor@sysoev.ru spf.frac_width = 0; 229*0Sigor@sysoev.ru 230*0Sigor@sysoev.ru while (*fmt >= '0' && *fmt <= '9') { 231*0Sigor@sysoev.ru spf.frac_width = spf.frac_width * 10 + *fmt++ - '0'; 232*0Sigor@sysoev.ru } 233*0Sigor@sysoev.ru 234*0Sigor@sysoev.ru break; 235*0Sigor@sysoev.ru 236*0Sigor@sysoev.ru default: 237*0Sigor@sysoev.ru break; 238*0Sigor@sysoev.ru } 239*0Sigor@sysoev.ru 240*0Sigor@sysoev.ru break; 241*0Sigor@sysoev.ru } 242*0Sigor@sysoev.ru 243*0Sigor@sysoev.ru 244*0Sigor@sysoev.ru switch (*fmt) { 245*0Sigor@sysoev.ru 246*0Sigor@sysoev.ru case 'E': 247*0Sigor@sysoev.ru err = va_arg(args, nxt_err_t); 248*0Sigor@sysoev.ru 249*0Sigor@sysoev.ru *buf++ = '('; 250*0Sigor@sysoev.ru spf.hex = NULL; 251*0Sigor@sysoev.ru spf.width = 0; 252*0Sigor@sysoev.ru buf = nxt_integer(&spf, buf, err); 253*0Sigor@sysoev.ru 254*0Sigor@sysoev.ru if (buf < end - 1) { 255*0Sigor@sysoev.ru *buf++ = ':'; 256*0Sigor@sysoev.ru *buf++ = ' '; 257*0Sigor@sysoev.ru } 258*0Sigor@sysoev.ru 259*0Sigor@sysoev.ru buf = nxt_strerror(err, buf, end - buf); 260*0Sigor@sysoev.ru 261*0Sigor@sysoev.ru if (buf < end) { 262*0Sigor@sysoev.ru *buf++ = ')'; 263*0Sigor@sysoev.ru } 264*0Sigor@sysoev.ru 265*0Sigor@sysoev.ru fmt++; 266*0Sigor@sysoev.ru continue; 267*0Sigor@sysoev.ru 268*0Sigor@sysoev.ru case 'O': 269*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_off_t); 270*0Sigor@sysoev.ru sign = 1; 271*0Sigor@sysoev.ru goto number; 272*0Sigor@sysoev.ru 273*0Sigor@sysoev.ru case 'T': 274*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_time_t); 275*0Sigor@sysoev.ru sign = 1; 276*0Sigor@sysoev.ru goto number; 277*0Sigor@sysoev.ru 278*0Sigor@sysoev.ru case 'M': 279*0Sigor@sysoev.ru ms = (nxt_msec_t) va_arg(args, nxt_msec_t); 280*0Sigor@sysoev.ru if ((nxt_msec_int_t) ms == -1 && spf.hex == NULL) { 281*0Sigor@sysoev.ru i64 = -1; 282*0Sigor@sysoev.ru sign = 1; 283*0Sigor@sysoev.ru } else { 284*0Sigor@sysoev.ru ui64 = (uint64_t) ms; 285*0Sigor@sysoev.ru sign = 0; 286*0Sigor@sysoev.ru } 287*0Sigor@sysoev.ru goto number; 288*0Sigor@sysoev.ru 289*0Sigor@sysoev.ru case 'N': 290*0Sigor@sysoev.ru ns = (nxt_nsec_t) va_arg(args, nxt_nsec_t); 291*0Sigor@sysoev.ru if ((nxt_nsec_int_t) ns == -1) { 292*0Sigor@sysoev.ru i64 = -1; 293*0Sigor@sysoev.ru sign = 1; 294*0Sigor@sysoev.ru } else { 295*0Sigor@sysoev.ru ui64 = (uint64_t) ns; 296*0Sigor@sysoev.ru sign = 0; 297*0Sigor@sysoev.ru } 298*0Sigor@sysoev.ru goto number; 299*0Sigor@sysoev.ru 300*0Sigor@sysoev.ru case 'z': 301*0Sigor@sysoev.ru if (sign) { 302*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, ssize_t); 303*0Sigor@sysoev.ru } else { 304*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, size_t); 305*0Sigor@sysoev.ru } 306*0Sigor@sysoev.ru goto number; 307*0Sigor@sysoev.ru 308*0Sigor@sysoev.ru case 'i': 309*0Sigor@sysoev.ru if (sign) { 310*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_int_t); 311*0Sigor@sysoev.ru } else { 312*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_uint_t); 313*0Sigor@sysoev.ru } 314*0Sigor@sysoev.ru 315*0Sigor@sysoev.ru if (spf.max_width != 0) { 316*0Sigor@sysoev.ru spf.width = NXT_INT_T_LEN; 317*0Sigor@sysoev.ru } 318*0Sigor@sysoev.ru 319*0Sigor@sysoev.ru goto number; 320*0Sigor@sysoev.ru 321*0Sigor@sysoev.ru case 'd': 322*0Sigor@sysoev.ru if (sign) { 323*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int); 324*0Sigor@sysoev.ru } else { 325*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_int); 326*0Sigor@sysoev.ru } 327*0Sigor@sysoev.ru goto number; 328*0Sigor@sysoev.ru 329*0Sigor@sysoev.ru case 'l': 330*0Sigor@sysoev.ru if (sign) { 331*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, long); 332*0Sigor@sysoev.ru } else { 333*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, u_long); 334*0Sigor@sysoev.ru } 335*0Sigor@sysoev.ru goto number; 336*0Sigor@sysoev.ru 337*0Sigor@sysoev.ru case 'D': 338*0Sigor@sysoev.ru if (sign) { 339*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, int32_t); 340*0Sigor@sysoev.ru } else { 341*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, uint32_t); 342*0Sigor@sysoev.ru } 343*0Sigor@sysoev.ru goto number; 344*0Sigor@sysoev.ru 345*0Sigor@sysoev.ru case 'L': 346*0Sigor@sysoev.ru if (sign) { 347*0Sigor@sysoev.ru i64 = va_arg(args, int64_t); 348*0Sigor@sysoev.ru } else { 349*0Sigor@sysoev.ru ui64 = va_arg(args, uint64_t); 350*0Sigor@sysoev.ru } 351*0Sigor@sysoev.ru goto number; 352*0Sigor@sysoev.ru 353*0Sigor@sysoev.ru case 'A': 354*0Sigor@sysoev.ru if (sign) { 355*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_atomic_int_t); 356*0Sigor@sysoev.ru } else { 357*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_atomic_uint_t); 358*0Sigor@sysoev.ru } 359*0Sigor@sysoev.ru 360*0Sigor@sysoev.ru if (spf.max_width != 0) { 361*0Sigor@sysoev.ru spf.width = NXT_ATOMIC_T_LEN; 362*0Sigor@sysoev.ru } 363*0Sigor@sysoev.ru 364*0Sigor@sysoev.ru goto number; 365*0Sigor@sysoev.ru 366*0Sigor@sysoev.ru case 'b': 367*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_bool_t); 368*0Sigor@sysoev.ru sign = 0; 369*0Sigor@sysoev.ru goto number; 370*0Sigor@sysoev.ru 371*0Sigor@sysoev.ru case 'f': 372*0Sigor@sysoev.ru fmt++; 373*0Sigor@sysoev.ru 374*0Sigor@sysoev.ru f = va_arg(args, double); 375*0Sigor@sysoev.ru 376*0Sigor@sysoev.ru if (f < 0) { 377*0Sigor@sysoev.ru *buf++ = '-'; 378*0Sigor@sysoev.ru f = -f; 379*0Sigor@sysoev.ru } 380*0Sigor@sysoev.ru 381*0Sigor@sysoev.ru if (nxt_slow_path(isnan(f))) { 382*0Sigor@sysoev.ru p = (u_char *) nan; 383*0Sigor@sysoev.ru len = sizeof(nan) - 1; 384*0Sigor@sysoev.ru 385*0Sigor@sysoev.ru goto copy; 386*0Sigor@sysoev.ru 387*0Sigor@sysoev.ru } else if (nxt_slow_path(isinf(f))) { 388*0Sigor@sysoev.ru p = (u_char *) infinity; 389*0Sigor@sysoev.ru len = sizeof(infinity) - 1; 390*0Sigor@sysoev.ru 391*0Sigor@sysoev.ru goto copy; 392*0Sigor@sysoev.ru } 393*0Sigor@sysoev.ru 394*0Sigor@sysoev.ru (void) modf(f, &i); 395*0Sigor@sysoev.ru frac = 0; 396*0Sigor@sysoev.ru 397*0Sigor@sysoev.ru if (spf.frac_width > 0) { 398*0Sigor@sysoev.ru 399*0Sigor@sysoev.ru scale = 1; 400*0Sigor@sysoev.ru for (n = spf.frac_width; n != 0; n--) { 401*0Sigor@sysoev.ru scale *= 10; 402*0Sigor@sysoev.ru } 403*0Sigor@sysoev.ru 404*0Sigor@sysoev.ru frac = (uint64_t) ((f - i) * scale + 0.5); 405*0Sigor@sysoev.ru 406*0Sigor@sysoev.ru if (frac == scale) { 407*0Sigor@sysoev.ru i += 1; 408*0Sigor@sysoev.ru frac = 0; 409*0Sigor@sysoev.ru } 410*0Sigor@sysoev.ru } 411*0Sigor@sysoev.ru 412*0Sigor@sysoev.ru buf = nxt_number(&spf, buf, i); 413*0Sigor@sysoev.ru 414*0Sigor@sysoev.ru if (spf.frac_width > 0) { 415*0Sigor@sysoev.ru 416*0Sigor@sysoev.ru if (buf < end) { 417*0Sigor@sysoev.ru *buf++ = '.'; 418*0Sigor@sysoev.ru 419*0Sigor@sysoev.ru spf.hex = NULL; 420*0Sigor@sysoev.ru spf.padding = '0'; 421*0Sigor@sysoev.ru spf.width = spf.frac_width; 422*0Sigor@sysoev.ru buf = nxt_integer(&spf, buf, frac); 423*0Sigor@sysoev.ru } 424*0Sigor@sysoev.ru 425*0Sigor@sysoev.ru } else if (spf.frac_width < 0) { 426*0Sigor@sysoev.ru f = modf(f, &i); 427*0Sigor@sysoev.ru 428*0Sigor@sysoev.ru if (!nxt_double_is_zero(f) && buf < end) { 429*0Sigor@sysoev.ru *buf++ = '.'; 430*0Sigor@sysoev.ru 431*0Sigor@sysoev.ru while (!nxt_double_is_zero(f) && buf < end) { 432*0Sigor@sysoev.ru f *= 10; 433*0Sigor@sysoev.ru f = modf(f, &i); 434*0Sigor@sysoev.ru *buf++ = (u_char) i + '0'; 435*0Sigor@sysoev.ru } 436*0Sigor@sysoev.ru } 437*0Sigor@sysoev.ru } 438*0Sigor@sysoev.ru 439*0Sigor@sysoev.ru continue; 440*0Sigor@sysoev.ru 441*0Sigor@sysoev.ru case 'r': 442*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, rlim_t); 443*0Sigor@sysoev.ru sign = 1; 444*0Sigor@sysoev.ru break; 445*0Sigor@sysoev.ru 446*0Sigor@sysoev.ru case 'p': 447*0Sigor@sysoev.ru ui64 = (uintptr_t) va_arg(args, void *); 448*0Sigor@sysoev.ru sign = 0; 449*0Sigor@sysoev.ru spf.hex = HEXADECIMAL; 450*0Sigor@sysoev.ru /* 451*0Sigor@sysoev.ru * spf.width = NXT_PTR_SIZE * 2; 452*0Sigor@sysoev.ru * spf.padding = '0'; 453*0Sigor@sysoev.ru */ 454*0Sigor@sysoev.ru goto number; 455*0Sigor@sysoev.ru 456*0Sigor@sysoev.ru case 'c': 457*0Sigor@sysoev.ru d = va_arg(args, int); 458*0Sigor@sysoev.ru *buf++ = (u_char) (d & 0xff); 459*0Sigor@sysoev.ru fmt++; 460*0Sigor@sysoev.ru 461*0Sigor@sysoev.ru continue; 462*0Sigor@sysoev.ru 463*0Sigor@sysoev.ru case 'F': 464*0Sigor@sysoev.ru fmt++; 465*0Sigor@sysoev.ru 466*0Sigor@sysoev.ru switch (*fmt) { 467*0Sigor@sysoev.ru 468*0Sigor@sysoev.ru case 'D': 469*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_fd_t); 470*0Sigor@sysoev.ru sign = 1; 471*0Sigor@sysoev.ru 472*0Sigor@sysoev.ru goto number; 473*0Sigor@sysoev.ru 474*0Sigor@sysoev.ru case 'N': 475*0Sigor@sysoev.ru fn = va_arg(args, nxt_file_name_t *); 476*0Sigor@sysoev.ru p = fn; 477*0Sigor@sysoev.ru 478*0Sigor@sysoev.ru while (*p != '\0' && buf < end) { 479*0Sigor@sysoev.ru *buf++ = *p++; 480*0Sigor@sysoev.ru } 481*0Sigor@sysoev.ru 482*0Sigor@sysoev.ru fmt++; 483*0Sigor@sysoev.ru continue; 484*0Sigor@sysoev.ru 485*0Sigor@sysoev.ru default: 486*0Sigor@sysoev.ru continue; 487*0Sigor@sysoev.ru } 488*0Sigor@sysoev.ru 489*0Sigor@sysoev.ru case 'P': 490*0Sigor@sysoev.ru fmt++; 491*0Sigor@sysoev.ru 492*0Sigor@sysoev.ru switch (*fmt) { 493*0Sigor@sysoev.ru 494*0Sigor@sysoev.ru case 'I': 495*0Sigor@sysoev.ru i64 = (int64_t) va_arg(args, nxt_pid_t); 496*0Sigor@sysoev.ru sign = 1; 497*0Sigor@sysoev.ru goto number; 498*0Sigor@sysoev.ru 499*0Sigor@sysoev.ru case 'T': 500*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_tid_t); 501*0Sigor@sysoev.ru sign = 0; 502*0Sigor@sysoev.ru goto number; 503*0Sigor@sysoev.ru 504*0Sigor@sysoev.ru case 'F': 505*0Sigor@sysoev.ru ui64 = (uint64_t) va_arg(args, nxt_fid_t); 506*0Sigor@sysoev.ru sign = 0; 507*0Sigor@sysoev.ru goto number; 508*0Sigor@sysoev.ru 509*0Sigor@sysoev.ru case 'H': 510*0Sigor@sysoev.ru ui64 = (uint64_t) (uintptr_t) va_arg(args, pthread_t); 511*0Sigor@sysoev.ru spf.hex = HEXADECIMAL; 512*0Sigor@sysoev.ru sign = 0; 513*0Sigor@sysoev.ru goto number; 514*0Sigor@sysoev.ru 515*0Sigor@sysoev.ru default: 516*0Sigor@sysoev.ru continue; 517*0Sigor@sysoev.ru } 518*0Sigor@sysoev.ru 519*0Sigor@sysoev.ru case 'Z': 520*0Sigor@sysoev.ru *buf++ = '\0'; 521*0Sigor@sysoev.ru fmt++; 522*0Sigor@sysoev.ru continue; 523*0Sigor@sysoev.ru 524*0Sigor@sysoev.ru case 'n': 525*0Sigor@sysoev.ru *buf++ = NXT_LF; 526*0Sigor@sysoev.ru fmt++; 527*0Sigor@sysoev.ru continue; 528*0Sigor@sysoev.ru 529*0Sigor@sysoev.ru case '%': 530*0Sigor@sysoev.ru *buf++ = '%'; 531*0Sigor@sysoev.ru fmt++; 532*0Sigor@sysoev.ru continue; 533*0Sigor@sysoev.ru 534*0Sigor@sysoev.ru default: 535*0Sigor@sysoev.ru *buf++ = *fmt++; 536*0Sigor@sysoev.ru continue; 537*0Sigor@sysoev.ru } 538*0Sigor@sysoev.ru 539*0Sigor@sysoev.ru number: 540*0Sigor@sysoev.ru 541*0Sigor@sysoev.ru if (sign) { 542*0Sigor@sysoev.ru if (i64 < 0) { 543*0Sigor@sysoev.ru *buf++ = '-'; 544*0Sigor@sysoev.ru ui64 = (uint64_t) -i64; 545*0Sigor@sysoev.ru 546*0Sigor@sysoev.ru } else { 547*0Sigor@sysoev.ru ui64 = (uint64_t) i64; 548*0Sigor@sysoev.ru } 549*0Sigor@sysoev.ru } 550*0Sigor@sysoev.ru 551*0Sigor@sysoev.ru buf = nxt_integer(&spf, buf, ui64); 552*0Sigor@sysoev.ru 553*0Sigor@sysoev.ru fmt++; 554*0Sigor@sysoev.ru continue; 555*0Sigor@sysoev.ru 556*0Sigor@sysoev.ru copy: 557*0Sigor@sysoev.ru 558*0Sigor@sysoev.ru buf = nxt_cpymem(buf, p, nxt_min((size_t) (end - buf), len)); 559*0Sigor@sysoev.ru continue; 560*0Sigor@sysoev.ru } 561*0Sigor@sysoev.ru 562*0Sigor@sysoev.ru return buf; 563*0Sigor@sysoev.ru } 564*0Sigor@sysoev.ru 565*0Sigor@sysoev.ru 566*0Sigor@sysoev.ru static u_char * 567*0Sigor@sysoev.ru nxt_integer(nxt_sprintf_t *spf, u_char *buf, uint64_t ui64) 568*0Sigor@sysoev.ru { 569*0Sigor@sysoev.ru u_char *p, *end; 570*0Sigor@sysoev.ru size_t len; 571*0Sigor@sysoev.ru u_char temp[NXT_INT64_T_LEN]; 572*0Sigor@sysoev.ru 573*0Sigor@sysoev.ru p = temp + NXT_INT64_T_LEN; 574*0Sigor@sysoev.ru 575*0Sigor@sysoev.ru if (spf->hex == NULL) { 576*0Sigor@sysoev.ru 577*0Sigor@sysoev.ru #if (NXT_32BIT) 578*0Sigor@sysoev.ru 579*0Sigor@sysoev.ru for ( ;; ) { 580*0Sigor@sysoev.ru u_char *start; 581*0Sigor@sysoev.ru uint32_t ui32; 582*0Sigor@sysoev.ru 583*0Sigor@sysoev.ru /* 584*0Sigor@sysoev.ru * 32-bit platforms usually lack hardware support of 64-bit 585*0Sigor@sysoev.ru * division and remainder operations. For this reason C compiler 586*0Sigor@sysoev.ru * adds calls to the runtime library functions which provides 587*0Sigor@sysoev.ru * these operations. These functions usually have about hundred 588*0Sigor@sysoev.ru * lines of code. 589*0Sigor@sysoev.ru * 590*0Sigor@sysoev.ru * For 32-bit numbers and some constant divisors GCC, Clang and 591*0Sigor@sysoev.ru * other compilers can use inlined multiplications and shifts 592*0Sigor@sysoev.ru * which are faster than division or remainder operations. 593*0Sigor@sysoev.ru * For example, unsigned "ui32 / 10" is compiled to 594*0Sigor@sysoev.ru * 595*0Sigor@sysoev.ru * ((uint64_t) ui32 * 0xCCCCCCCD) >> 35 596*0Sigor@sysoev.ru * 597*0Sigor@sysoev.ru * So a 64-bit number is split to parts by 10^9. The parts fit 598*0Sigor@sysoev.ru * to 32 bits and are processed separately as 32-bit numbers. A 599*0Sigor@sysoev.ru * number of 64-bit division/remainder operations is significantly 600*0Sigor@sysoev.ru * decreased depending on the 64-bit number's value, it is 601*0Sigor@sysoev.ru * 0 if the 64-bit value is less than 4294967296, 602*0Sigor@sysoev.ru * 1 if the 64-bit value is greater than 4294967295 603*0Sigor@sysoev.ru * and less than 4294967296000000000, 604*0Sigor@sysoev.ru * 2 otherwise. 605*0Sigor@sysoev.ru */ 606*0Sigor@sysoev.ru 607*0Sigor@sysoev.ru if (ui64 <= 0xffffffff) { 608*0Sigor@sysoev.ru ui32 = (uint32_t) ui64; 609*0Sigor@sysoev.ru start = NULL; 610*0Sigor@sysoev.ru 611*0Sigor@sysoev.ru } else { 612*0Sigor@sysoev.ru ui32 = (uint32_t) (ui64 % 1000000000); 613*0Sigor@sysoev.ru start = p - 9; 614*0Sigor@sysoev.ru } 615*0Sigor@sysoev.ru 616*0Sigor@sysoev.ru do { 617*0Sigor@sysoev.ru *(--p) = (u_char) (ui32 % 10 + '0'); 618*0Sigor@sysoev.ru ui32 /= 10; 619*0Sigor@sysoev.ru } while (ui32 != 0); 620*0Sigor@sysoev.ru 621*0Sigor@sysoev.ru if (start == NULL) { 622*0Sigor@sysoev.ru break; 623*0Sigor@sysoev.ru } 624*0Sigor@sysoev.ru 625*0Sigor@sysoev.ru /* Add leading zeros of part. */ 626*0Sigor@sysoev.ru 627*0Sigor@sysoev.ru while (p > start) { 628*0Sigor@sysoev.ru *(--p) = '0'; 629*0Sigor@sysoev.ru } 630*0Sigor@sysoev.ru 631*0Sigor@sysoev.ru ui64 /= 1000000000; 632*0Sigor@sysoev.ru } 633*0Sigor@sysoev.ru 634*0Sigor@sysoev.ru #else /* NXT_64BIT */ 635*0Sigor@sysoev.ru 636*0Sigor@sysoev.ru do { 637*0Sigor@sysoev.ru *(--p) = (u_char) (ui64 % 10 + '0'); 638*0Sigor@sysoev.ru ui64 /= 10; 639*0Sigor@sysoev.ru } while (ui64 != 0); 640*0Sigor@sysoev.ru 641*0Sigor@sysoev.ru #endif 642*0Sigor@sysoev.ru 643*0Sigor@sysoev.ru } else { 644*0Sigor@sysoev.ru 645*0Sigor@sysoev.ru do { 646*0Sigor@sysoev.ru *(--p) = spf->hex[ui64 & 0xf]; 647*0Sigor@sysoev.ru ui64 >>= 4; 648*0Sigor@sysoev.ru } while (ui64 != 0); 649*0Sigor@sysoev.ru } 650*0Sigor@sysoev.ru 651*0Sigor@sysoev.ru /* Zero or space padding. */ 652*0Sigor@sysoev.ru 653*0Sigor@sysoev.ru if (spf->width != 0) { 654*0Sigor@sysoev.ru 655*0Sigor@sysoev.ru len = (temp + NXT_INT64_T_LEN) - p; 656*0Sigor@sysoev.ru end = buf + (spf->width - len); 657*0Sigor@sysoev.ru end = nxt_min(end, spf->end); 658*0Sigor@sysoev.ru 659*0Sigor@sysoev.ru while (buf < end) { 660*0Sigor@sysoev.ru *buf++ = spf->padding; 661*0Sigor@sysoev.ru } 662*0Sigor@sysoev.ru } 663*0Sigor@sysoev.ru 664*0Sigor@sysoev.ru /* Number copying. */ 665*0Sigor@sysoev.ru 666*0Sigor@sysoev.ru len = (temp + NXT_INT64_T_LEN) - p; 667*0Sigor@sysoev.ru end = buf + len; 668*0Sigor@sysoev.ru end = nxt_min(end, spf->end); 669*0Sigor@sysoev.ru 670*0Sigor@sysoev.ru while (buf < end) { 671*0Sigor@sysoev.ru *buf++ = *p++; 672*0Sigor@sysoev.ru } 673*0Sigor@sysoev.ru 674*0Sigor@sysoev.ru return buf; 675*0Sigor@sysoev.ru } 676*0Sigor@sysoev.ru 677*0Sigor@sysoev.ru 678*0Sigor@sysoev.ru static u_char * 679*0Sigor@sysoev.ru nxt_number(nxt_sprintf_t *spf, u_char *buf, double n) 680*0Sigor@sysoev.ru { 681*0Sigor@sysoev.ru u_char *p, *end; 682*0Sigor@sysoev.ru size_t len; 683*0Sigor@sysoev.ru u_char temp[NXT_DOUBLE_LEN]; 684*0Sigor@sysoev.ru 685*0Sigor@sysoev.ru p = temp + NXT_DOUBLE_LEN; 686*0Sigor@sysoev.ru 687*0Sigor@sysoev.ru do { 688*0Sigor@sysoev.ru *(--p) = (u_char) (fmod(n, 10) + '0'); 689*0Sigor@sysoev.ru n = trunc(n / 10); 690*0Sigor@sysoev.ru } while (!nxt_double_is_zero(n)); 691*0Sigor@sysoev.ru 692*0Sigor@sysoev.ru /* Zero or space padding. */ 693*0Sigor@sysoev.ru 694*0Sigor@sysoev.ru if (spf->width != 0) { 695*0Sigor@sysoev.ru len = (temp + NXT_DOUBLE_LEN) - p; 696*0Sigor@sysoev.ru end = buf + (spf->width - len); 697*0Sigor@sysoev.ru end = nxt_min(end, spf->end); 698*0Sigor@sysoev.ru 699*0Sigor@sysoev.ru while (buf < end) { 700*0Sigor@sysoev.ru *buf++ = spf->padding; 701*0Sigor@sysoev.ru } 702*0Sigor@sysoev.ru } 703*0Sigor@sysoev.ru 704*0Sigor@sysoev.ru /* Number copying. */ 705*0Sigor@sysoev.ru 706*0Sigor@sysoev.ru len = (temp + NXT_DOUBLE_LEN) - p; 707*0Sigor@sysoev.ru 708*0Sigor@sysoev.ru end = buf + len; 709*0Sigor@sysoev.ru end = nxt_min(end, spf->end); 710*0Sigor@sysoev.ru 711*0Sigor@sysoev.ru while (buf < end) { 712*0Sigor@sysoev.ru *buf++ = *p++; 713*0Sigor@sysoev.ru } 714*0Sigor@sysoev.ru 715*0Sigor@sysoev.ru return buf; 716*0Sigor@sysoev.ru } 717