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