1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * This code is based on, and used with the permission of, the 19 * SIO stdio-replacement strx_* functions by Panos Tsirigotis 20 * <panos@alumni.cs.colorado.edu> for xinetd. 21 */ 22 23 #include "config.h" 24 #include <stdio.h> 25 #include <ctype.h> 26 #include <sys/types.h> 27 #include <stdarg.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <math.h> 31 #include <netinet/in.h> 32 33 #ifdef HAVE_LIMITS_H 34 #include <limits.h> 35 #endif 36 37 typedef struct { 38 char *curpos; 39 char *endpos; 40 } ap_vformatter_buff; 41 42 43 #define API_EXPORT(type) type 44 #define API_EXPORT_NONSTD(type) type 45 46 #define ap_isalnum(c) (isalnum(((unsigned char)(c)))) 47 #define ap_isalpha(c) (isalpha(((unsigned char)(c)))) 48 #define ap_iscntrl(c) (iscntrl(((unsigned char)(c)))) 49 #define ap_isdigit(c) (isdigit(((unsigned char)(c)))) 50 #define ap_isgraph(c) (isgraph(((unsigned char)(c)))) 51 #define ap_islower(c) (islower(((unsigned char)(c)))) 52 #define ap_isprint(c) (isprint(((unsigned char)(c)))) 53 #define ap_ispunct(c) (ispunct(((unsigned char)(c)))) 54 #define ap_isspace(c) (isspace(((unsigned char)(c)))) 55 #define ap_isupper(c) (isupper(((unsigned char)(c)))) 56 #define ap_isxdigit(c) (isxdigit(((unsigned char)(c)))) 57 #define ap_tolower(c) (tolower(((unsigned char)(c)))) 58 #define ap_toupper(c) (toupper(((unsigned char)(c)))) 59 60 61 typedef enum { 62 NO = 0, YES = 1 63 } boolean_e; 64 65 #ifndef FALSE 66 #define FALSE 0 67 #endif 68 #ifndef TRUE 69 #define TRUE 1 70 #endif 71 #ifndef AP_LONGEST_LONG 72 #define AP_LONGEST_LONG long 73 #endif 74 #define NUL '\0' 75 #define WIDE_INT long 76 #define WIDEST_INT AP_LONGEST_LONG 77 78 typedef WIDE_INT wide_int; 79 typedef unsigned WIDE_INT u_wide_int; 80 typedef WIDEST_INT widest_int; 81 #ifdef __TANDEM 82 /* Although Tandem supports "long long" there is no unsigned variant. */ 83 typedef unsigned long u_widest_int; 84 #else 85 typedef unsigned WIDEST_INT u_widest_int; 86 #endif 87 typedef int bool_int; 88 89 #define S_NULL "(null)" 90 #define S_NULL_LEN 6 91 92 #define FLOAT_DIGITS 6 93 #define EXPONENT_LENGTH 10 94 95 /* 96 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions 97 * 98 * XXX: this is a magic number; do not decrease it 99 */ 100 #define NUM_BUF_SIZE 512 101 102 /* 103 * cvt.c - IEEE floating point formatting routines for FreeBSD 104 * from GNU libc-4.6.27. Modified to be thread safe. 105 */ 106 107 /* 108 * ap_ecvt converts to decimal 109 * the number of digits is specified by ndigit 110 * decpt is set to the position of the decimal point 111 * sign is set to 0 for positive, 1 for negative 112 */ 113 114 #define NDIG 80 115 116 /* buf must have at least NDIG bytes */ 117 static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) 118 { 119 register int r2; 120 double fi, fj; 121 register char *p, *p1; 122 123 if (ndigits >= NDIG - 1) 124 ndigits = NDIG - 2; 125 r2 = 0; 126 *sign = 0; 127 p = &buf[0]; 128 if (arg < 0) { 129 *sign = 1; 130 arg = -arg; 131 } 132 arg = modf(arg, &fi); 133 p1 = &buf[NDIG]; 134 /* 135 * Do integer part 136 */ 137 if (fi != 0) { 138 p1 = &buf[NDIG]; 139 while (p1 > &buf[0] && fi != 0) { 140 fj = modf(fi / 10, &fi); 141 *--p1 = (int) ((fj + .03) * 10) + '0'; 142 r2++; 143 } 144 while (p1 < &buf[NDIG]) 145 *p++ = *p1++; 146 } 147 else if (arg > 0) { 148 while ((fj = arg * 10) < 1) { 149 arg = fj; 150 r2--; 151 } 152 } 153 p1 = &buf[ndigits]; 154 if (eflag == 0) 155 p1 += r2; 156 *decpt = r2; 157 if (p1 < &buf[0]) { 158 buf[0] = '\0'; 159 return (buf); 160 } 161 while (p <= p1 && p < &buf[NDIG]) { 162 arg *= 10; 163 arg = modf(arg, &fj); 164 *p++ = (int) fj + '0'; 165 } 166 if (p1 >= &buf[NDIG]) { 167 buf[NDIG - 1] = '\0'; 168 return (buf); 169 } 170 p = p1; 171 *p1 += 5; 172 while (*p1 > '9') { 173 *p1 = '0'; 174 if (p1 > buf) 175 ++ * --p1; 176 else { 177 *p1 = '1'; 178 (*decpt)++; 179 if (eflag == 0) { 180 if (p > buf) 181 *p = '0'; 182 p++; 183 } 184 } 185 } 186 *p = '\0'; 187 return (buf); 188 } 189 190 static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 191 { 192 return (ap_cvt(arg, ndigits, decpt, sign, 1, buf)); 193 } 194 195 static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) 196 { 197 return (ap_cvt(arg, ndigits, decpt, sign, 0, buf)); 198 } 199 200 /* 201 * ap_gcvt - Floating output conversion to 202 * minimal length string 203 */ 204 205 static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform) 206 { 207 int sign, decpt; 208 register char *p1, *p2; 209 register int i; 210 char buf1[NDIG]; 211 212 p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1); 213 p2 = buf; 214 if (sign) 215 *p2++ = '-'; 216 for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) 217 ndigit--; 218 if ((decpt >= 0 && decpt - ndigit > 4) 219 || (decpt < 0 && decpt < -3)) { /* use E-style */ 220 decpt--; 221 *p2++ = *p1++; 222 *p2++ = '.'; 223 for (i = 1; i < ndigit; i++) 224 *p2++ = *p1++; 225 *p2++ = 'e'; 226 if (decpt < 0) { 227 decpt = -decpt; 228 *p2++ = '-'; 229 } 230 else 231 *p2++ = '+'; 232 if (decpt / 100 > 0) 233 *p2++ = decpt / 100 + '0'; 234 if (decpt / 10 > 0) 235 *p2++ = (decpt % 100) / 10 + '0'; 236 *p2++ = decpt % 10 + '0'; 237 } 238 else { 239 if (decpt <= 0) { 240 if (*p1 != '0') 241 *p2++ = '.'; 242 while (decpt < 0) { 243 decpt++; 244 *p2++ = '0'; 245 } 246 } 247 for (i = 1; i <= ndigit; i++) { 248 *p2++ = *p1++; 249 if (i == decpt) 250 *p2++ = '.'; 251 } 252 if (ndigit < decpt) { 253 while (ndigit++ < decpt) 254 *p2++ = '0'; 255 *p2++ = '.'; 256 } 257 } 258 if (p2[-1] == '.' && !altform) 259 p2--; 260 *p2 = '\0'; 261 return (buf); 262 } 263 264 /* 265 * The INS_CHAR macro inserts a character in the buffer and writes 266 * the buffer back to disk if necessary 267 * It uses the char pointers sp and bep: 268 * sp points to the next available character in the buffer 269 * bep points to the end-of-buffer+1 270 * While using this macro, note that the nextb pointer is NOT updated. 271 * 272 * NOTE: Evaluation of the c argument should not have any side-effects 273 */ 274 #define INS_CHAR(c, sp, bep, cc) \ 275 { \ 276 if (sp >= bep) { \ 277 vbuff->curpos = sp; \ 278 if (flush_func(vbuff)) \ 279 return -1; \ 280 sp = vbuff->curpos; \ 281 bep = vbuff->endpos; \ 282 } \ 283 *sp++ = (c); \ 284 cc++; \ 285 } 286 287 #define NUM( c ) ( c - '0' ) 288 289 #define STR_TO_DEC( str, num ) \ 290 num = NUM( *str++ ) ; \ 291 while ( ap_isdigit( *str ) ) \ 292 { \ 293 num *= 10 ; \ 294 num += NUM( *str++ ) ; \ 295 } 296 297 /* 298 * This macro does zero padding so that the precision 299 * requirement is satisfied. The padding is done by 300 * adding '0's to the left of the string that is going 301 * to be printed. We don't allow precision to be large 302 * enough that we continue past the start of s. 303 * 304 * NOTE: this makes use of the magic info that s is 305 * always based on num_buf with a size of NUM_BUF_SIZE. 306 */ 307 #define FIX_PRECISION( adjust, precision, s, s_len ) \ 308 if ( adjust ) { \ 309 int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \ 310 while ( s_len < p ) \ 311 { \ 312 *--s = '0' ; \ 313 s_len++ ; \ 314 } \ 315 } 316 317 /* 318 * Macro that does padding. The padding is done by printing 319 * the character ch. 320 */ 321 #define PAD( width, len, ch ) do \ 322 { \ 323 INS_CHAR( ch, sp, bep, cc ) ; \ 324 width-- ; \ 325 } \ 326 while ( width > len ) 327 328 /* 329 * Prefix the character ch to the string str 330 * Increase length 331 * Set the has_prefix flag 332 */ 333 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES 334 335 336 /* 337 * Convert num to its decimal format. 338 * Return value: 339 * - a pointer to a string containing the number (no sign) 340 * - len contains the length of the string 341 * - is_negative is set to TRUE or FALSE depending on the sign 342 * of the number (always set to FALSE if is_unsigned is TRUE) 343 * 344 * The caller provides a buffer for the string: that is the buf_end argument 345 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 346 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 347 * 348 * Note: we have 2 versions. One is used when we need to use quads 349 * (conv_10_quad), the other when we don't (conv_10). We're assuming the 350 * latter is faster. 351 */ 352 static char *conv_10(register wide_int num, register bool_int is_unsigned, 353 register bool_int *is_negative, char *buf_end, 354 register int *len) 355 { 356 register char *p = buf_end; 357 register u_wide_int magnitude; 358 359 if (is_unsigned) { 360 magnitude = (u_wide_int) num; 361 *is_negative = FALSE; 362 } 363 else { 364 *is_negative = (num < 0); 365 366 /* 367 * On a 2's complement machine, negating the most negative integer 368 * results in a number that cannot be represented as a signed integer. 369 * Here is what we do to obtain the number's magnitude: 370 * a. add 1 to the number 371 * b. negate it (becomes positive) 372 * c. convert it to unsigned 373 * d. add 1 374 */ 375 if (*is_negative) { 376 wide_int t = num + 1; 377 378 magnitude = ((u_wide_int) -t) + 1; 379 } 380 else 381 magnitude = (u_wide_int) num; 382 } 383 384 /* 385 * We use a do-while loop so that we write at least 1 digit 386 */ 387 do { 388 register u_wide_int new_magnitude = magnitude / 10; 389 390 *--p = (char) (magnitude - new_magnitude * 10 + '0'); 391 magnitude = new_magnitude; 392 } 393 while (magnitude); 394 395 *len = buf_end - p; 396 return (p); 397 } 398 399 static char *conv_10_quad(widest_int num, register bool_int is_unsigned, 400 register bool_int *is_negative, char *buf_end, 401 register int *len) 402 { 403 register char *p = buf_end; 404 u_widest_int magnitude; 405 406 /* 407 * We see if we can use the faster non-quad version by checking the 408 * number against the largest long value it can be. If <=, we 409 * punt to the quicker version. 410 */ 411 if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) 412 return(conv_10( (wide_int)num, is_unsigned, is_negative, 413 buf_end, len)); 414 415 if (is_unsigned) { 416 magnitude = (u_widest_int) num; 417 *is_negative = FALSE; 418 } 419 else { 420 *is_negative = (num < 0); 421 422 /* 423 * On a 2's complement machine, negating the most negative integer 424 * results in a number that cannot be represented as a signed integer. 425 * Here is what we do to obtain the number's magnitude: 426 * a. add 1 to the number 427 * b. negate it (becomes positive) 428 * c. convert it to unsigned 429 * d. add 1 430 */ 431 if (*is_negative) { 432 widest_int t = num + 1; 433 434 magnitude = ((u_widest_int) -t) + 1; 435 } 436 else 437 magnitude = (u_widest_int) num; 438 } 439 440 /* 441 * We use a do-while loop so that we write at least 1 digit 442 */ 443 do { 444 u_widest_int new_magnitude = magnitude / 10; 445 446 *--p = (char) (magnitude - new_magnitude * 10 + '0'); 447 magnitude = new_magnitude; 448 } 449 while (magnitude); 450 451 *len = buf_end - p; 452 return (p); 453 } 454 455 456 457 static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) 458 { 459 unsigned addr = ntohl(ia->s_addr); 460 char *p = buf_end; 461 bool_int is_negative; 462 int sub_len; 463 464 p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); 465 *--p = '.'; 466 p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); 467 *--p = '.'; 468 p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); 469 *--p = '.'; 470 p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); 471 472 *len = buf_end - p; 473 return (p); 474 } 475 476 477 478 static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len) 479 { 480 char *p = buf_end; 481 bool_int is_negative; 482 int sub_len; 483 484 p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len); 485 *--p = ':'; 486 p = conv_in_addr(&si->sin_addr, p, &sub_len); 487 488 *len = buf_end - p; 489 return (p); 490 } 491 492 493 494 /* 495 * Convert a floating point number to a string formats 'f', 'e' or 'E'. 496 * The result is placed in buf, and len denotes the length of the string 497 * The sign is returned in the is_negative argument (and is not placed 498 * in buf). 499 */ 500 static char *conv_fp(register char format, register double num, 501 boolean_e add_dp, int precision, bool_int *is_negative, 502 char *buf, int *len) 503 { 504 register char *s = buf; 505 register char *p; 506 int decimal_point; 507 char buf1[NDIG]; 508 509 if (format == 'f') 510 p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1); 511 else /* either e or E format */ 512 p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); 513 514 /* 515 * Check for Infinity and NaN 516 */ 517 if (ap_isalpha(*p)) { 518 *len = strlen(strcpy(buf, p)); 519 *is_negative = FALSE; 520 return (buf); 521 } 522 523 if (format == 'f') { 524 if (decimal_point <= 0) { 525 *s++ = '0'; 526 if (precision > 0) { 527 *s++ = '.'; 528 while (decimal_point++ < 0) 529 *s++ = '0'; 530 } 531 else if (add_dp) 532 *s++ = '.'; 533 } 534 else { 535 while (decimal_point-- > 0) 536 *s++ = *p++; 537 if (precision > 0 || add_dp) 538 *s++ = '.'; 539 } 540 } 541 else { 542 *s++ = *p++; 543 if (precision > 0 || add_dp) 544 *s++ = '.'; 545 } 546 547 /* 548 * copy the rest of p, the NUL is NOT copied 549 */ 550 while (*p) 551 *s++ = *p++; 552 553 if (format != 'f') { 554 char temp[EXPONENT_LENGTH]; /* for exponent conversion */ 555 int t_len; 556 bool_int exponent_is_negative; 557 558 *s++ = format; /* either e or E */ 559 decimal_point--; 560 if (decimal_point != 0) { 561 p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, 562 &temp[EXPONENT_LENGTH], &t_len); 563 *s++ = exponent_is_negative ? '-' : '+'; 564 565 /* 566 * Make sure the exponent has at least 2 digits 567 */ 568 if (t_len == 1) 569 *s++ = '0'; 570 while (t_len--) 571 *s++ = *p++; 572 } 573 else { 574 *s++ = '+'; 575 *s++ = '0'; 576 *s++ = '0'; 577 } 578 } 579 580 *len = s - buf; 581 return (buf); 582 } 583 584 585 /* 586 * Convert num to a base X number where X is a power of 2. nbits determines X. 587 * For example, if nbits is 3, we do base 8 conversion 588 * Return value: 589 * a pointer to a string containing the number 590 * 591 * The caller provides a buffer for the string: that is the buf_end argument 592 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer 593 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) 594 * 595 * As with conv_10, we have a faster version which is used when 596 * the number isn't quad size. 597 */ 598 static char *conv_p2(register u_wide_int num, register int nbits, 599 char format, char *buf_end, register int *len) 600 { 601 register int mask = (1 << nbits) - 1; 602 register char *p = buf_end; 603 static const char low_digits[] = "0123456789abcdef"; 604 static const char upper_digits[] = "0123456789ABCDEF"; 605 register const char *digits = (format == 'X') ? upper_digits : low_digits; 606 607 do { 608 *--p = digits[num & mask]; 609 num >>= nbits; 610 } 611 while (num); 612 613 *len = buf_end - p; 614 return (p); 615 } 616 617 static char *conv_p2_quad(u_widest_int num, register int nbits, 618 char format, char *buf_end, register int *len) 619 { 620 register int mask = (1 << nbits) - 1; 621 register char *p = buf_end; 622 static const char low_digits[] = "0123456789abcdef"; 623 static const char upper_digits[] = "0123456789ABCDEF"; 624 register const char *digits = (format == 'X') ? upper_digits : low_digits; 625 626 if (num <= ULONG_MAX) 627 return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len)); 628 629 do { 630 *--p = digits[num & mask]; 631 num >>= nbits; 632 } 633 while (num); 634 635 *len = buf_end - p; 636 return (p); 637 } 638 639 640 /* 641 * Do format conversion placing the output in buffer 642 */ 643 API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), 644 ap_vformatter_buff *vbuff, const char *fmt, va_list ap) 645 { 646 register char *sp; 647 register char *bep; 648 register int cc = 0; 649 register int i; 650 651 register char *s = NULL; 652 char *q; 653 int s_len; 654 655 register int min_width = 0; 656 int precision = 0; 657 enum { 658 LEFT, RIGHT 659 } adjust; 660 char pad_char; 661 char prefix_char; 662 663 double fp_num; 664 widest_int i_quad = (widest_int) 0; 665 u_widest_int ui_quad; 666 wide_int i_num = (wide_int) 0; 667 u_wide_int ui_num; 668 669 char num_buf[NUM_BUF_SIZE]; 670 char char_buf[2]; /* for printing %% and %<unknown> */ 671 672 enum var_type_enum { 673 IS_QUAD, IS_LONG, IS_SHORT, IS_INT 674 }; 675 enum var_type_enum var_type = IS_INT; 676 677 /* 678 * Flag variables 679 */ 680 boolean_e alternate_form; 681 boolean_e print_sign; 682 boolean_e print_blank; 683 boolean_e adjust_precision; 684 boolean_e adjust_width; 685 bool_int is_negative; 686 687 sp = vbuff->curpos; 688 bep = vbuff->endpos; 689 690 while (*fmt) { 691 if (*fmt != '%') { 692 INS_CHAR(*fmt, sp, bep, cc); 693 } 694 else { 695 /* 696 * Default variable settings 697 */ 698 adjust = RIGHT; 699 alternate_form = print_sign = print_blank = NO; 700 pad_char = ' '; 701 prefix_char = NUL; 702 703 fmt++; 704 705 /* 706 * Try to avoid checking for flags, width or precision 707 */ 708 if (!ap_islower(*fmt)) { 709 /* 710 * Recognize flags: -, #, BLANK, + 711 */ 712 for (;; fmt++) { 713 if (*fmt == '-') 714 adjust = LEFT; 715 else if (*fmt == '+') 716 print_sign = YES; 717 else if (*fmt == '#') 718 alternate_form = YES; 719 else if (*fmt == ' ') 720 print_blank = YES; 721 else if (*fmt == '0') 722 pad_char = '0'; 723 else 724 break; 725 } 726 727 /* 728 * Check if a width was specified 729 */ 730 if (ap_isdigit(*fmt)) { 731 STR_TO_DEC(fmt, min_width); 732 adjust_width = YES; 733 } 734 else if (*fmt == '*') { 735 min_width = va_arg(ap, int); 736 fmt++; 737 adjust_width = YES; 738 if (min_width < 0) { 739 adjust = LEFT; 740 min_width = -min_width; 741 } 742 } 743 else 744 adjust_width = NO; 745 746 /* 747 * Check if a precision was specified 748 */ 749 if (*fmt == '.') { 750 adjust_precision = YES; 751 fmt++; 752 if (ap_isdigit(*fmt)) { 753 STR_TO_DEC(fmt, precision); 754 } 755 else if (*fmt == '*') { 756 precision = va_arg(ap, int); 757 fmt++; 758 if (precision < 0) 759 precision = 0; 760 } 761 else 762 precision = 0; 763 } 764 else 765 adjust_precision = NO; 766 } 767 else 768 adjust_precision = adjust_width = NO; 769 770 /* 771 * Modifier check 772 */ 773 if (*fmt == 'q') { 774 var_type = IS_QUAD; 775 fmt++; 776 } 777 else if (*fmt == 'l') { 778 var_type = IS_LONG; 779 fmt++; 780 } 781 else if (*fmt == 'h') { 782 var_type = IS_SHORT; 783 fmt++; 784 } 785 else { 786 var_type = IS_INT; 787 } 788 789 /* 790 * Argument extraction and printing. 791 * First we determine the argument type. 792 * Then, we convert the argument to a string. 793 * On exit from the switch, s points to the string that 794 * must be printed, s_len has the length of the string 795 * The precision requirements, if any, are reflected in s_len. 796 * 797 * NOTE: pad_char may be set to '0' because of the 0 flag. 798 * It is reset to ' ' by non-numeric formats 799 */ 800 switch (*fmt) { 801 case 'u': 802 if (var_type == IS_QUAD) { 803 i_quad = va_arg(ap, u_widest_int); 804 s = conv_10_quad(i_quad, 1, &is_negative, 805 &num_buf[NUM_BUF_SIZE], &s_len); 806 } 807 else { 808 if (var_type == IS_LONG) 809 i_num = (wide_int) va_arg(ap, u_wide_int); 810 else if (var_type == IS_SHORT) 811 i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); 812 else 813 i_num = (wide_int) va_arg(ap, unsigned int); 814 s = conv_10(i_num, 1, &is_negative, 815 &num_buf[NUM_BUF_SIZE], &s_len); 816 } 817 FIX_PRECISION(adjust_precision, precision, s, s_len); 818 break; 819 820 case 'd': 821 case 'i': 822 if (var_type == IS_QUAD) { 823 i_quad = va_arg(ap, widest_int); 824 s = conv_10_quad(i_quad, 0, &is_negative, 825 &num_buf[NUM_BUF_SIZE], &s_len); 826 } 827 else { 828 if (var_type == IS_LONG) 829 i_num = (wide_int) va_arg(ap, wide_int); 830 else if (var_type == IS_SHORT) 831 i_num = (wide_int) (short) va_arg(ap, int); 832 else 833 i_num = (wide_int) va_arg(ap, int); 834 s = conv_10(i_num, 0, &is_negative, 835 &num_buf[NUM_BUF_SIZE], &s_len); 836 } 837 FIX_PRECISION(adjust_precision, precision, s, s_len); 838 839 if (is_negative) 840 prefix_char = '-'; 841 else if (print_sign) 842 prefix_char = '+'; 843 else if (print_blank) 844 prefix_char = ' '; 845 break; 846 847 848 case 'o': 849 if (var_type == IS_QUAD) { 850 ui_quad = va_arg(ap, u_widest_int); 851 s = conv_p2_quad(ui_quad, 3, *fmt, 852 &num_buf[NUM_BUF_SIZE], &s_len); 853 } 854 else { 855 if (var_type == IS_LONG) 856 ui_num = (u_wide_int) va_arg(ap, u_wide_int); 857 else if (var_type == IS_SHORT) 858 ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); 859 else 860 ui_num = (u_wide_int) va_arg(ap, unsigned int); 861 s = conv_p2(ui_num, 3, *fmt, 862 &num_buf[NUM_BUF_SIZE], &s_len); 863 } 864 FIX_PRECISION(adjust_precision, precision, s, s_len); 865 if (alternate_form && *s != '0') { 866 *--s = '0'; 867 s_len++; 868 } 869 break; 870 871 872 case 'x': 873 case 'X': 874 if (var_type == IS_QUAD) { 875 ui_quad = va_arg(ap, u_widest_int); 876 s = conv_p2_quad(ui_quad, 4, *fmt, 877 &num_buf[NUM_BUF_SIZE], &s_len); 878 } 879 else { 880 if (var_type == IS_LONG) 881 ui_num = (u_wide_int) va_arg(ap, u_wide_int); 882 else if (var_type == IS_SHORT) 883 ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); 884 else 885 ui_num = (u_wide_int) va_arg(ap, unsigned int); 886 s = conv_p2(ui_num, 4, *fmt, 887 &num_buf[NUM_BUF_SIZE], &s_len); 888 } 889 FIX_PRECISION(adjust_precision, precision, s, s_len); 890 if (alternate_form && i_num != 0) { 891 *--s = *fmt; /* 'x' or 'X' */ 892 *--s = '0'; 893 s_len += 2; 894 } 895 break; 896 897 898 case 's': 899 s = va_arg(ap, char *); 900 if (s != NULL) { 901 s_len = strlen(s); 902 if (adjust_precision && precision < s_len) 903 s_len = precision; 904 } 905 else { 906 s = S_NULL; 907 s_len = S_NULL_LEN; 908 } 909 pad_char = ' '; 910 break; 911 912 913 case 'f': 914 case 'e': 915 case 'E': 916 fp_num = va_arg(ap, double); 917 /* 918 * * We use &num_buf[ 1 ], so that we have room for the sign 919 */ 920 #ifdef HAVE_ISNAN 921 if (isnan(fp_num)) { 922 s = "nan"; 923 s_len = 3; 924 } 925 else 926 #endif 927 #ifdef HAVE_ISINF 928 if (isinf(fp_num)) { 929 s = "inf"; 930 s_len = 3; 931 } 932 else 933 #endif 934 { 935 s = conv_fp(*fmt, fp_num, alternate_form, 936 (adjust_precision == NO) ? FLOAT_DIGITS : precision, 937 &is_negative, &num_buf[1], &s_len); 938 if (is_negative) 939 prefix_char = '-'; 940 else if (print_sign) 941 prefix_char = '+'; 942 else if (print_blank) 943 prefix_char = ' '; 944 } 945 break; 946 947 948 case 'g': 949 case 'G': 950 if (adjust_precision == NO) 951 precision = FLOAT_DIGITS; 952 else if (precision == 0) 953 precision = 1; 954 /* 955 * * We use &num_buf[ 1 ], so that we have room for the sign 956 */ 957 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1], 958 alternate_form); 959 if (*s == '-') 960 prefix_char = *s++; 961 else if (print_sign) 962 prefix_char = '+'; 963 else if (print_blank) 964 prefix_char = ' '; 965 966 s_len = strlen(s); 967 968 if (alternate_form && (q = strchr(s, '.')) == NULL) { 969 s[s_len++] = '.'; 970 s[s_len] = '\0'; /* delimit for following strchr() */ 971 } 972 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) 973 *q = 'E'; 974 break; 975 976 977 case 'c': 978 char_buf[0] = (char) (va_arg(ap, int)); 979 s = &char_buf[0]; 980 s_len = 1; 981 pad_char = ' '; 982 break; 983 984 985 case '%': 986 char_buf[0] = '%'; 987 s = &char_buf[0]; 988 s_len = 1; 989 pad_char = ' '; 990 break; 991 992 993 case 'n': 994 if (var_type == IS_QUAD) 995 *(va_arg(ap, widest_int *)) = cc; 996 else if (var_type == IS_LONG) 997 *(va_arg(ap, long *)) = cc; 998 else if (var_type == IS_SHORT) 999 *(va_arg(ap, short *)) = cc; 1000 else 1001 *(va_arg(ap, int *)) = cc; 1002 break; 1003 1004 /* 1005 * This is where we extend the printf format, with a second 1006 * type specifier 1007 */ 1008 case 'p': 1009 switch(*++fmt) { 1010 /* 1011 * If the pointer size is equal to or smaller than the size 1012 * of the largest unsigned int, we convert the pointer to a 1013 * hex number, otherwise we print "%p" to indicate that we 1014 * don't handle "%p". 1015 */ 1016 case 'p': 1017 #ifdef AP_VOID_P_IS_QUAD 1018 if (sizeof(void *) <= sizeof(u_widest_int)) { 1019 ui_quad = (u_widest_int) va_arg(ap, void *); 1020 s = conv_p2_quad(ui_quad, 4, 'x', 1021 &num_buf[NUM_BUF_SIZE], &s_len); 1022 } 1023 #else 1024 if (sizeof(void *) <= sizeof(u_wide_int)) { 1025 ui_num = (u_wide_int) va_arg(ap, void *); 1026 s = conv_p2(ui_num, 4, 'x', 1027 &num_buf[NUM_BUF_SIZE], &s_len); 1028 } 1029 #endif 1030 else { 1031 s = "%p"; 1032 s_len = 2; 1033 prefix_char = NUL; 1034 } 1035 pad_char = ' '; 1036 break; 1037 1038 /* print a struct sockaddr_in as a.b.c.d:port */ 1039 case 'I': 1040 { 1041 struct sockaddr_in *si; 1042 1043 si = va_arg(ap, struct sockaddr_in *); 1044 if (si != NULL) { 1045 s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len); 1046 if (adjust_precision && precision < s_len) 1047 s_len = precision; 1048 } 1049 else { 1050 s = S_NULL; 1051 s_len = S_NULL_LEN; 1052 } 1053 pad_char = ' '; 1054 } 1055 break; 1056 1057 /* print a struct in_addr as a.b.c.d */ 1058 case 'A': 1059 { 1060 struct in_addr *ia; 1061 1062 ia = va_arg(ap, struct in_addr *); 1063 if (ia != NULL) { 1064 s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); 1065 if (adjust_precision && precision < s_len) 1066 s_len = precision; 1067 } 1068 else { 1069 s = S_NULL; 1070 s_len = S_NULL_LEN; 1071 } 1072 pad_char = ' '; 1073 } 1074 break; 1075 1076 case NUL: 1077 /* if %p ends the string, oh well ignore it */ 1078 continue; 1079 1080 default: 1081 s = "bogus %p"; 1082 s_len = 8; 1083 prefix_char = NUL; 1084 break; 1085 } 1086 break; 1087 1088 case NUL: 1089 /* 1090 * The last character of the format string was %. 1091 * We ignore it. 1092 */ 1093 continue; 1094 1095 1096 /* 1097 * The default case is for unrecognized %'s. 1098 * We print %<char> to help the user identify what 1099 * option is not understood. 1100 * This is also useful in case the user wants to pass 1101 * the output of format_converter to another function 1102 * that understands some other %<char> (like syslog). 1103 * Note that we can't point s inside fmt because the 1104 * unknown <char> could be preceded by width etc. 1105 */ 1106 default: 1107 char_buf[0] = '%'; 1108 char_buf[1] = *fmt; 1109 s = char_buf; 1110 s_len = 2; 1111 pad_char = ' '; 1112 break; 1113 } 1114 1115 if (prefix_char != NUL && s != S_NULL && s != char_buf) { 1116 *--s = prefix_char; 1117 s_len++; 1118 } 1119 1120 if (adjust_width && adjust == RIGHT && min_width > s_len) { 1121 if (pad_char == '0' && prefix_char != NUL) { 1122 INS_CHAR(*s, sp, bep, cc); 1123 s++; 1124 s_len--; 1125 min_width--; 1126 } 1127 PAD(min_width, s_len, pad_char); 1128 } 1129 1130 /* 1131 * Print the string s. 1132 */ 1133 for (i = s_len; i != 0; i--) { 1134 INS_CHAR(*s, sp, bep, cc); 1135 s++; 1136 } 1137 1138 if (adjust_width && adjust == LEFT && min_width > s_len) 1139 PAD(min_width, s_len, pad_char); 1140 } 1141 fmt++; 1142 } 1143 vbuff->curpos = sp; 1144 1145 return cc; 1146 } 1147 1148 1149 static int snprintf_flush(ap_vformatter_buff *vbuff) 1150 { 1151 /* if the buffer fills we have to abort immediately, there is no way 1152 * to "flush" an ap_snprintf... there's nowhere to flush it to. 1153 */ 1154 return -1; 1155 } 1156 1157 1158 API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) 1159 { 1160 int cc; 1161 va_list ap; 1162 ap_vformatter_buff vbuff; 1163 1164 if (len == 0) 1165 return 0; 1166 1167 /* save one byte for nul terminator */ 1168 vbuff.curpos = buf; 1169 vbuff.endpos = buf + len - 1; 1170 va_start(ap, format); 1171 cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); 1172 va_end(ap); 1173 *vbuff.curpos = '\0'; 1174 return (cc == -1) ? len : cc; 1175 } 1176 1177 1178 API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, 1179 va_list ap) 1180 { 1181 int cc; 1182 ap_vformatter_buff vbuff; 1183 1184 if (len == 0) 1185 return 0; 1186 1187 /* save one byte for nul terminator */ 1188 vbuff.curpos = buf; 1189 vbuff.endpos = buf + len - 1; 1190 cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); 1191 *vbuff.curpos = '\0'; 1192 return (cc == -1) ? len : cc; 1193 } 1194