1/* snprintf - formatted output to strings, with bounds checking and allocation */ 2 3/* 4 build a test version with 5 gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o 6*/ 7 8/* 9 Unix snprintf implementation. 10 derived from inetutils/libinetutils/snprintf.c Version 1.1 11 12 Copyright (C) 2001,2006 Free Software Foundation, Inc. 13 14 This file is part of GNU Bash, the Bourne Again SHell. 15 16 Bash is free software: you can redistribute it and/or modify 17 it under the terms of the GNU General Public License as published by 18 the Free Software Foundation, either version 3 of the License, or 19 (at your option) any later version. 20 21 Bash is distributed in the hope that it will be useful, 22 but WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 GNU General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with Bash. If not, see <http://www.gnu.org/licenses/>. 28 29 Revision History: 30 31 1.1: 32 * added changes from Miles Bader 33 * corrected a bug with %f 34 * added support for %#g 35 * added more comments :-) 36 1.0: 37 * supporting must ANSI syntaxic_sugars 38 0.0: 39 * support %s %c %d 40 41 THANKS(for the patches and ideas): 42 Miles Bader 43 Cyrille Rustom 44 Jacek Slabocewiz 45 Mike Parker(mouse) 46 47*/ 48 49/* 50 * Currently doesn't handle (and bash/readline doesn't use): 51 * * *M$ width, precision specifications 52 * * %N$ numbered argument conversions 53 * * inf, nan floating values imperfect (if isinf(), isnan() not in libc) 54 * * support for `F' is imperfect with ldfallback(), since underlying 55 * printf may not handle it -- should ideally have another autoconf test 56 */ 57 58#define FLOATING_POINT 59 60#ifdef HAVE_CONFIG_H 61# include <config.h> 62#endif 63 64#if defined(DEBUG) 65# undef HAVE_SNPRINTF 66# undef HAVE_ASPRINTF 67#endif 68 69#if defined(DRIVER) && !defined(HAVE_CONFIG_H) 70#define HAVE_LONG_LONG 71#define HAVE_LONG_DOUBLE 72#ifdef __linux__ 73#define HAVE_PRINTF_A_FORMAT 74#endif 75#define HAVE_ISINF_IN_LIBC 76#define HAVE_ISNAN_IN_LIBC 77#define PREFER_STDARG 78#define HAVE_STRINGIZE 79#define HAVE_LIMITS_H 80#define HAVE_STDDEF_H 81#define HAVE_LOCALE_H 82#define intmax_t long 83#endif 84 85#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF) 86 87#include <bashtypes.h> 88 89#if defined(PREFER_STDARG) 90# include <stdarg.h> 91#else 92# include <varargs.h> 93#endif 94 95#ifdef HAVE_LIMITS_H 96# include <limits.h> 97#endif 98#include <bashansi.h> 99#ifdef HAVE_STDDEF_H 100# include <stddef.h> 101#endif 102#include <chartypes.h> 103 104#ifdef HAVE_STDINT_H 105# include <stdint.h> 106#endif 107 108#ifdef FLOATING_POINT 109# include <float.h> /* for manifest constants */ 110# include <stdio.h> /* for sprintf */ 111#endif 112 113#include <typemax.h> 114 115#ifdef HAVE_LOCALE_H 116# include <locale.h> 117#endif 118 119#include "stdc.h" 120#include <shmbutil.h> 121 122#ifndef DRIVER 123# include "shell.h" 124#else 125# define FL_PREFIX 0x01 /* add 0x, 0X, or 0 prefix as appropriate */ 126# define FL_ADDBASE 0x02 /* add base# prefix to converted value */ 127# define FL_HEXUPPER 0x04 /* use uppercase when converting to hex */ 128# define FL_UNSIGNED 0x08 /* don't add any sign */ 129extern char *fmtulong __P((unsigned long int, int, char *, size_t, int)); 130extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int)); 131#endif 132 133#ifndef FREE 134# define FREE(x) if (x) free (x) 135#endif 136 137/* Bound on length of the string representing an integer value of type T. 138 Subtract one for the sign bit if T is signed; 139 302 / 1000 is log10 (2) rounded up; 140 add one for integer division truncation; 141 add one more for a minus sign if t is signed. */ 142#define INT_STRLEN_BOUND(t) \ 143 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ 144 + 1 + TYPE_SIGNED (t)) 145 146/* conversion flags */ 147#define PF_ALTFORM 0x00001 /* # */ 148#define PF_HEXPREFIX 0x00002 /* 0[Xx] */ 149#define PF_LADJUST 0x00004 /* - */ 150#define PF_ZEROPAD 0x00008 /* 0 */ 151#define PF_PLUS 0x00010 /* + */ 152#define PF_SPACE 0x00020 /* ' ' */ 153#define PF_THOUSANDS 0x00040 /* ' */ 154 155#define PF_DOT 0x00080 /* `.precision' */ 156#define PF_STAR_P 0x00100 /* `*' after precision */ 157#define PF_STAR_W 0x00200 /* `*' before or without precision */ 158 159/* length modifiers */ 160#define PF_SIGNEDCHAR 0x00400 /* hh */ 161#define PF_SHORTINT 0x00800 /* h */ 162#define PF_LONGINT 0x01000 /* l */ 163#define PF_LONGLONG 0x02000 /* ll */ 164#define PF_LONGDBL 0x04000 /* L */ 165#define PF_INTMAX_T 0x08000 /* j */ 166#define PF_SIZE_T 0x10000 /* z */ 167#define PF_PTRDIFF_T 0x20000 /* t */ 168 169#define PF_ALLOCBUF 0x40000 /* for asprintf, vasprintf */ 170 171#define PFM_SN 0x01 /* snprintf, vsnprintf */ 172#define PFM_AS 0x02 /* asprintf, vasprintf */ 173 174#define ASBUFSIZE 128 175 176#define x_digs "0123456789abcdef" 177#define X_digs "0123456789ABCDEF" 178 179static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1]; 180 181static int decpoint; 182static int thoussep; 183static char *grouping; 184 185/* 186 * For the FLOATING POINT FORMAT : 187 * the challenge was finding a way to 188 * manipulate the Real numbers without having 189 * to resort to mathematical function(it 190 * would require to link with -lm) and not 191 * going down to the bit pattern(not portable) 192 * 193 * so a number, a real is: 194 195 real = integral + fraction 196 197 integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0 198 fraction = b(1)*10^-1 + b(2)*10^-2 + ... 199 200 where: 201 0 <= a(i) => 9 202 0 <= b(i) => 9 203 204 from then it was simple math 205 */ 206 207/* 208 * size of the buffer for the integral part 209 * and the fraction part 210 */ 211#define MAX_INT 99 + 1 /* 1 for the null */ 212#define MAX_FRACT 307 + 1 213 214/* 215 * These functions use static buffers to store the results, 216 * and so are not reentrant 217 */ 218#define itoa(n) fmtulong(n, 10, intbuf, sizeof(intbuf), 0); 219#define dtoa(n, p, f) numtoa(n, 10, p, f) 220 221#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;} 222 223#define GETARG(type) (va_arg(args, type)) 224 225/* Macros that do proper sign extension and handle length modifiers. Used 226 for the integer conversion specifiers. */ 227#define GETSIGNED(p) \ 228 (((p)->flags & PF_LONGINT) \ 229 ? GETARG (long) \ 230 : (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \ 231 : (long)GETARG (int))) 232 233#define GETUNSIGNED(p) \ 234 (((p)->flags & PF_LONGINT) \ 235 ? GETARG (unsigned long) \ 236 : (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \ 237 : (unsigned long)GETARG (unsigned int))) 238 239 240#ifdef HAVE_LONG_DOUBLE 241#define GETLDOUBLE(p) GETARG (long double) 242#endif 243#define GETDOUBLE(p) GETARG (double) 244 245#define SET_SIZE_FLAGS(p, type) \ 246 if (sizeof (type) > sizeof (int)) \ 247 (p)->flags |= PF_LONGINT; \ 248 if (sizeof (type) > sizeof (long)) \ 249 (p)->flags |= PF_LONGLONG; 250 251/* this struct holds everything we need */ 252struct DATA 253{ 254 int length; 255 char *base; /* needed for [v]asprintf */ 256 char *holder; 257 int counter; 258 const char *pf; 259 260/* FLAGS */ 261 int flags; 262 int justify; 263 int width, precision; 264 char pad; 265}; 266 267/* the floating point stuff */ 268#ifdef FLOATING_POINT 269static double pow_10 __P((int)); 270static int log_10 __P((double)); 271static double integral __P((double, double *)); 272static char *numtoa __P((double, int, int, char **)); 273#endif 274 275static void init_data __P((struct DATA *, char *, size_t, const char *, int)); 276static void init_conv_flag __P((struct DATA *)); 277 278/* for the format */ 279#ifdef FLOATING_POINT 280static void floating __P((struct DATA *, double)); 281static void exponent __P((struct DATA *, double)); 282#endif 283static void number __P((struct DATA *, unsigned long, int)); 284#ifdef HAVE_LONG_LONG 285static void lnumber __P((struct DATA *, unsigned long long, int)); 286#endif 287static void pointer __P((struct DATA *, unsigned long)); 288static void strings __P((struct DATA *, char *)); 289 290#ifdef FLOATING_POINT 291# define FALLBACK_FMTSIZE 32 292# define FALLBACK_BASE 4096 293# define LFALLBACK_BASE 5120 294# ifdef HAVE_LONG_DOUBLE 295static void ldfallback __P((struct DATA *, const char *, const char *, long double)); 296# endif 297static void dfallback __P((struct DATA *, const char *, const char *, double)); 298#endif 299 300static char *groupnum __P((char *)); 301 302#ifdef DRIVER 303static void memory_error_and_abort (); 304static void *xmalloc __P((size_t)); 305static void *xrealloc __P((void *, size_t)); 306static void xfree __P((void *)); 307#else 308# include <xmalloc.h> 309#endif 310 311/* those are defines specific to snprintf to hopefully 312 * make the code clearer :-) 313 */ 314#define RIGHT 1 315#define LEFT 0 316#define NOT_FOUND -1 317#define FOUND 1 318#define MAX_FIELD 15 319 320/* round off to the precision */ 321#define ROUND(d, p) \ 322 (d < 0.) ? \ 323 d - pow_10(-(p)->precision) * 0.5 : \ 324 d + pow_10(-(p)->precision) * 0.5 325 326/* set default precision */ 327#define DEF_PREC(p) \ 328 if ((p)->precision == NOT_FOUND) \ 329 (p)->precision = 6 330 331/* put a char. increment the number of chars written even if we've exceeded 332 the vsnprintf/snprintf buffer size (for the return value) */ 333#define PUT_CHAR(c, p) \ 334 do \ 335 { \ 336 if (((p)->flags & PF_ALLOCBUF) && ((p)->counter >= (p)->length - 1)) \ 337 { \ 338 (p)->length += ASBUFSIZE; \ 339 (p)->base = (char *)xrealloc((p)->base, (p)->length); \ 340 (p)->holder = (p)->base + (p)->counter; /* in case reallocated */ \ 341 } \ 342 if ((p)->counter < (p)->length) \ 343 *(p)->holder++ = (c); \ 344 (p)->counter++; \ 345 } \ 346 while (0) 347 348/* Output a string. P->WIDTH has already been adjusted for padding. */ 349#define PUT_STRING(string, len, p) \ 350 do \ 351 { \ 352 PAD_RIGHT (p); \ 353 while ((len)-- > 0) \ 354 { \ 355 PUT_CHAR (*(string), (p)); \ 356 (string)++; \ 357 } \ 358 PAD_LEFT (p); \ 359 } \ 360 while (0) 361 362#define PUT_PLUS(d, p, zero) \ 363 if ((d) > zero && (p)->justify == RIGHT) \ 364 PUT_CHAR('+', p) 365 366#define PUT_SPACE(d, p, zero) \ 367 if (((p)->flags & PF_SPACE) && (d) > zero) \ 368 PUT_CHAR(' ', p) 369 370/* pad right */ 371#define PAD_RIGHT(p) \ 372 if ((p)->width > 0 && (p)->justify != LEFT) \ 373 for (; (p)->width > 0; (p)->width--) \ 374 PUT_CHAR((p)->pad, p) 375 376/* pad left */ 377#define PAD_LEFT(p) \ 378 if ((p)->width > 0 && (p)->justify == LEFT) \ 379 for (; (p)->width > 0; (p)->width--) \ 380 PUT_CHAR((p)->pad, p) 381 382/* pad with zeros from decimal precision */ 383#define PAD_ZERO(p) \ 384 if ((p)->precision > 0) \ 385 for (; (p)->precision > 0; (p)->precision--) \ 386 PUT_CHAR('0', p) 387 388/* if width and prec. in the args */ 389#define STAR_ARGS(p) \ 390 do { \ 391 if ((p)->flags & PF_STAR_W) \ 392 { \ 393 (p)->width = GETARG (int); \ 394 if ((p)->width < 0) \ 395 { \ 396 (p)->flags |= PF_LADJUST; \ 397 (p)->justify = LEFT; \ 398 (p)->width = -(p)->width; \ 399 } \ 400 } \ 401 if ((p)->flags & PF_STAR_P) \ 402 { \ 403 (p)->precision = GETARG (int); \ 404 if ((p)->precision < 0) \ 405 { \ 406 (p)->flags &= ~PF_STAR_P; \ 407 (p)->precision = NOT_FOUND; \ 408 } \ 409 } \ 410 } while (0) 411 412#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV) 413# define GETLOCALEDATA(d, t, g) \ 414 do \ 415 { \ 416 struct lconv *lv; \ 417 if ((d) == 0) { \ 418 (d) = '.'; (t) = -1; (g) = 0; /* defaults */ \ 419 lv = localeconv(); \ 420 if (lv) \ 421 { \ 422 if (lv->decimal_point && lv->decimal_point[0]) \ 423 (d) = lv->decimal_point[0]; \ 424 if (lv->thousands_sep && lv->thousands_sep[0]) \ 425 (t) = lv->thousands_sep[0]; \ 426 (g) = lv->grouping ? lv->grouping : ""; \ 427 if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \ 428 } \ 429 } \ 430 } \ 431 while (0); 432#else 433# define GETLOCALEDATA(d, t, g) \ 434 ( (d) = '.', (t) = ',', g = "\003" ) 435#endif 436 437#ifdef FLOATING_POINT 438/* 439 * Find the nth power of 10 440 */ 441static double 442pow_10(n) 443 int n; 444{ 445 double P; 446 447 /* handle common cases with fast switch statement. */ 448 switch (n) 449 { 450 case -3: return .001; 451 case -2: return .01; 452 case -1: return .1; 453 case 0: return 1.; 454 case 1: return 10.; 455 case 2: return 100.; 456 case 3: return 1000.; 457 } 458 459 if (n < 0) 460 { 461 P = .0001; 462 for (n += 4; n < 0; n++) 463 P /= 10.; 464 } 465 else 466 { 467 P = 10000.; 468 for (n -= 4; n > 0; n--) 469 P *= 10.; 470 } 471 472 return P; 473} 474 475/* 476 * Find the integral part of the log in base 10 477 * Note: this not a real log10() 478 I just need and approximation(integerpart) of x in: 479 10^x ~= r 480 * log_10(200) = 2; 481 * log_10(250) = 2; 482 * 483 * NOTE: do not call this with r == 0 -- an infinite loop results. 484 */ 485static int 486log_10(r) 487 double r; 488{ 489 int i = 0; 490 double result = 1.; 491 492 if (r < 0.) 493 r = -r; 494 495 if (r < 1.) 496 { 497 while (result >= r) 498 { 499 result /= 10.; 500 i++; 501 } 502 return (-i); 503 } 504 else 505 { 506 while (result <= r) 507 { 508 result *= 10.; 509 i++; 510 } 511 return (i - 1); 512 } 513} 514 515/* 516 * This function return the fraction part of a double 517 * and set in ip the integral part. 518 * In many ways it resemble the modf() found on most Un*x 519 */ 520static double 521integral(real, ip) 522 double real; 523 double *ip; 524{ 525 int j; 526 double i, s, p; 527 double real_integral = 0.; 528 529 /* take care of the obvious */ 530 /* equal to zero ? */ 531 if (real == 0.) 532 { 533 *ip = 0.; 534 return (0.); 535 } 536 537 /* negative number ? */ 538 if (real < 0.) 539 real = -real; 540 541 /* a fraction ? */ 542 if ( real < 1.) 543 { 544 *ip = 0.; 545 return real; 546 } 547 548 /* the real work :-) */ 549 for (j = log_10(real); j >= 0; j--) 550 { 551 p = pow_10(j); 552 s = (real - real_integral)/p; 553 i = 0.; 554 while (i + 1. <= s) 555 i++; 556 real_integral += i*p; 557 } 558 *ip = real_integral; 559 return (real - real_integral); 560} 561 562#define PRECISION 1.e-6 563/* 564 * return an ascii representation of the integral part of the number 565 * and set fract to be an ascii representation of the fraction part 566 * the container for the fraction and the integral part or staticly 567 * declare with fix size 568 */ 569static char * 570numtoa(number, base, precision, fract) 571 double number; 572 int base, precision; 573 char **fract; 574{ 575 register int i, j; 576 double ip, fp; /* integer and fraction part */ 577 double fraction; 578 int digits = MAX_INT - 1; 579 static char integral_part[MAX_INT]; 580 static char fraction_part[MAX_FRACT]; 581 double sign; 582 int ch; 583 584 /* taking care of the obvious case: 0.0 */ 585 if (number == 0.) 586 { 587 integral_part[0] = '0'; 588 integral_part[1] = '\0'; 589 /* The fractional part has to take the precision into account */ 590 for (ch = 0; ch < precision-1; ch++) 591 fraction_part[ch] = '0'; 592 fraction_part[ch] = '0'; 593 fraction_part[ch+1] = '\0'; 594 if (fract) 595 *fract = fraction_part; 596 return integral_part; 597 } 598 599 /* for negative numbers */ 600 if ((sign = number) < 0.) 601 { 602 number = -number; 603 digits--; /* sign consume one digit */ 604 } 605 606 fraction = integral(number, &ip); 607 number = ip; 608 609 /* do the integral part */ 610 if (ip == 0.) 611 { 612 integral_part[0] = '0'; 613 i = 1; 614 } 615 else 616 { 617 for ( i = 0; i < digits && number != 0.; ++i) 618 { 619 number /= base; 620 fp = integral(number, &ip); 621 ch = (int)((fp + PRECISION)*base); /* force to round */ 622 integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; 623 if (! ISXDIGIT((unsigned char)integral_part[i])) 624 break; /* bail out overflow !! */ 625 number = ip; 626 } 627 } 628 629 /* Oh No !! out of bound, ho well fill it up ! */ 630 if (number != 0.) 631 for (i = 0; i < digits; ++i) 632 integral_part[i] = '9'; 633 634 /* put the sign ? */ 635 if (sign < 0.) 636 integral_part[i++] = '-'; 637 638 integral_part[i] = '\0'; 639 640 /* reverse every thing */ 641 for ( i--, j = 0; j < i; j++, i--) 642 SWAP_INT(integral_part[i], integral_part[j]); 643 644 /* the fractional part */ 645 for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--) 646 { 647 fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); 648 if (! DIGIT(fraction_part[i])) /* underflow ? */ 649 break; 650 fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); 651 } 652 fraction_part[i] = '\0'; 653 654 if (fract != (char **)0) 655 *fract = fraction_part; 656 657 return integral_part; 658} 659#endif 660 661/* for %d and friends, it puts in holder 662 * the representation with the right padding 663 */ 664static void 665number(p, d, base) 666 struct DATA *p; 667 unsigned long d; 668 int base; 669{ 670 char *tmp, *t; 671 long sd; 672 int flags; 673 674 /* An explicit precision turns off the zero-padding flag. */ 675 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) 676 p->flags &= ~PF_ZEROPAD; 677 678 sd = d; /* signed for ' ' padding in base 10 */ 679 flags = 0; 680 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; 681 if (*p->pf == 'X') 682 flags |= FL_HEXUPPER; 683 684 tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags); 685 t = 0; 686 if ((p->flags & PF_THOUSANDS)) 687 { 688 GETLOCALEDATA(decpoint, thoussep, grouping); 689 if (grouping && (t = groupnum (tmp))) 690 tmp = t; 691 } 692 693 p->width -= strlen(tmp); 694 PAD_RIGHT(p); 695 696 if ((p->flags & PF_DOT) && p->precision > 0) 697 { 698 p->precision -= strlen(tmp); 699 PAD_ZERO(p); 700 } 701 702 switch (base) 703 { 704 case 10: 705 PUT_PLUS(sd, p, 0); 706 PUT_SPACE(sd, p, 0); 707 break; 708 case 8: 709 if (p->flags & PF_ALTFORM) 710 PUT_CHAR('0', p); 711 break; 712 case 16: 713 if (p->flags & PF_ALTFORM) 714 { 715 PUT_CHAR('0', p); 716 PUT_CHAR(*p->pf, p); 717 } 718 break; 719 } 720 721 while (*tmp) 722 { 723 PUT_CHAR(*tmp, p); 724 tmp++; 725 } 726 727 PAD_LEFT(p); 728 FREE (t); 729} 730 731#ifdef HAVE_LONG_LONG 732/* 733 * identical to number() but works for `long long' 734 */ 735static void 736lnumber(p, d, base) 737 struct DATA *p; 738 unsigned long long d; 739 int base; 740{ 741 char *tmp, *t; 742 long long sd; 743 int flags; 744 745 /* An explicit precision turns off the zero-padding flag. */ 746 if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT)) 747 p->flags &= ~PF_ZEROPAD; 748 749 sd = d; /* signed for ' ' padding in base 10 */ 750 flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; 751 if (*p->pf == 'X') 752 flags |= FL_HEXUPPER; 753 754 tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags); 755 t = 0; 756 if ((p->flags & PF_THOUSANDS)) 757 { 758 GETLOCALEDATA(decpoint, thoussep, grouping); 759 if (grouping && (t = groupnum (tmp))) 760 tmp = t; 761 } 762 763 p->width -= strlen(tmp); 764 PAD_RIGHT(p); 765 766 if ((p->flags & PF_DOT) && p->precision > 0) 767 { 768 p->precision -= strlen(tmp); 769 PAD_ZERO(p); 770 } 771 772 switch (base) 773 { 774 case 10: 775 PUT_PLUS(sd, p, 0); 776 PUT_SPACE(sd, p, 0); 777 break; 778 case 8: 779 if (p->flags & PF_ALTFORM) 780 PUT_CHAR('0', p); 781 break; 782 case 16: 783 if (p->flags & PF_ALTFORM) 784 { 785 PUT_CHAR('0', p); 786 PUT_CHAR(*p->pf, p); 787 } 788 break; 789 } 790 791 while (*tmp) 792 { 793 PUT_CHAR(*tmp, p); 794 tmp++; 795 } 796 797 PAD_LEFT(p); 798 FREE (t); 799} 800#endif 801 802static void 803pointer(p, d) 804 struct DATA *p; 805 unsigned long d; 806{ 807 char *tmp; 808 809 tmp = fmtulong(d, 16, intbuf, sizeof(intbuf), 0); 810 p->width -= strlen(tmp); 811 PAD_RIGHT(p); 812 813 /* prefix '0x' for pointers */ 814 PUT_CHAR('0', p); 815 PUT_CHAR('x', p); 816 817 while (*tmp) 818 { 819 PUT_CHAR(*tmp, p); 820 tmp++; 821 } 822 823 PAD_LEFT(p); 824} 825 826/* %s strings */ 827static void 828strings(p, tmp) 829 struct DATA *p; 830 char *tmp; 831{ 832 size_t len; 833 834 len = strlen(tmp); 835 if (p->precision != NOT_FOUND) /* the smallest number */ 836 len = (len < p->precision ? len : p->precision); 837 p->width -= len; 838 839 PUT_STRING (tmp, len, p); 840} 841 842#if HANDLE_MULTIBYTE 843/* %ls wide-character strings */ 844static void 845wstrings(p, tmp) 846 struct DATA *p; 847 wchar_t *tmp; 848{ 849 size_t len; 850 mbstate_t mbs; 851 char *os; 852 const wchar_t *ws; 853 854 memset (&mbs, '\0', sizeof (mbstate_t)); 855 ws = (const wchar_t *)tmp; 856 857 os = (char *)NULL; 858 if (p->precision != NOT_FOUND) 859 { 860 os = (char *)xmalloc (p->precision + 1); 861 len = wcsrtombs (os, &ws, p->precision, &mbs); 862 } 863 else 864 { 865 len = wcsrtombs (NULL, &ws, 0, &mbs); 866 if (len != (size_t)-1) 867 { 868 memset (&mbs, '\0', sizeof (mbstate_t)); 869 os = (char *)xmalloc (len + 1); 870 (void)wcsrtombs (os, &ws, len + 1, &mbs); 871 } 872 } 873 if (len == (size_t)-1) 874 { 875 /* invalid multibyte sequence; bail now. */ 876 FREE (os); 877 return; 878 } 879 880 p->width -= len; 881 PUT_STRING (os, len, p); 882 free (os); 883} 884 885static void 886wchars (p, wc) 887 struct DATA *p; 888 wint_t wc; 889{ 890 char *lbuf, *l; 891 mbstate_t mbs; 892 size_t len; 893 894 lbuf = (char *)malloc (MB_CUR_MAX+1); 895 if (lbuf == 0) 896 return; 897 memset (&mbs, '\0', sizeof (mbstate_t)); 898 len = wcrtomb (lbuf, wc, &mbs); 899 if (len == (size_t)-1) 900 /* conversion failed; bail now. */ 901 return; 902 p->width -= len; 903 l = lbuf; 904 PUT_STRING (l, len, p); 905 free (lbuf); 906} 907#endif /* HANDLE_MULTIBYTE */ 908 909#ifdef FLOATING_POINT 910 911#ifndef HAVE_ISINF_IN_LIBC 912/* Half-assed versions, since we don't want to link with libm. */ 913static int 914isinf(d) 915 double d; 916{ 917#ifdef DBL_MAX 918 if (d < DBL_MIN) 919 return -1; 920 else if (d > DBL_MAX) 921 return 1; 922 else 923#endif 924 return 0; 925} 926#endif 927 928#ifndef HAVE_ISNAN_IN_LIBC 929static int 930isnan(d) 931 double d; 932{ 933 return 0; 934} 935#endif 936 937/* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else 938 (mode == 2) we check for NaN. This does the necessary printing. Returns 939 1 if Inf or Nan, 0 if not. */ 940static int 941chkinfnan(p, d, mode) 942 struct DATA *p; 943 double d; 944 int mode; /* == 1 for inf, == 2 for nan */ 945{ 946 int i; 947 char *tmp; 948 char *big, *small; 949 950 i = (mode == 1) ? isinf(d) : isnan(d); 951 if (i == 0) 952 return 0; 953 big = (mode == 1) ? "INF" : "NAN"; 954 small = (mode == 1) ? "inf" : "nan"; 955 956 tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small; 957 958 if (i < 0) 959 PUT_CHAR('-', p); 960 961 while (*tmp) 962 { 963 PUT_CHAR (*tmp, p); 964 tmp++; 965 } 966 967 return 1; 968} 969 970/* %f %F %g %G floating point representation */ 971static void 972floating(p, d) 973 struct DATA *p; 974 double d; 975{ 976 char *tmp, *tmp2, *t; 977 int i; 978 979 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))) 980 return; /* already printed nan or inf */ 981 982 GETLOCALEDATA(decpoint, thoussep, grouping); 983 DEF_PREC(p); 984 d = ROUND(d, p); 985 tmp = dtoa(d, p->precision, &tmp2); 986 t = 0; 987 if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp))) 988 tmp = t; 989 990 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) 991 { 992 /* smash the trailing zeros unless altform */ 993 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) 994 tmp2[i] = '\0'; 995 if (tmp2[0] == '\0') 996 p->precision = 0; 997 } 998 999 /* calculate the padding. 1 for the dot */ 1000 p->width = p->width - 1001 ((d > 0. && p->justify == RIGHT) ? 1:0) - 1002 ((p->flags & PF_SPACE) ? 1:0) - 1003 strlen(tmp) - p->precision - 1004 ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0); /* radix char */ 1005 PAD_RIGHT(p); 1006 PUT_PLUS(d, p, 0.); 1007 PUT_SPACE(d, p, 0.); 1008 1009 while (*tmp) 1010 { 1011 PUT_CHAR(*tmp, p); /* the integral */ 1012 tmp++; 1013 } 1014 FREE (t); 1015 1016 if (p->precision != 0 || (p->flags & PF_ALTFORM)) 1017 PUT_CHAR(decpoint, p); /* put the '.' */ 1018 1019 for (; *tmp2; tmp2++) 1020 PUT_CHAR(*tmp2, p); /* the fraction */ 1021 1022 PAD_LEFT(p); 1023} 1024 1025/* %e %E %g %G exponent representation */ 1026static void 1027exponent(p, d) 1028 struct DATA *p; 1029 double d; 1030{ 1031 char *tmp, *tmp2; 1032 int j, i; 1033 1034 if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))) 1035 return; /* already printed nan or inf */ 1036 1037 GETLOCALEDATA(decpoint, thoussep, grouping); 1038 DEF_PREC(p); 1039 if (d == 0.) 1040 j = 0; 1041 else 1042 { 1043 j = log_10(d); 1044 d = d / pow_10(j); /* get the Mantissa */ 1045 d = ROUND(d, p); 1046 } 1047 tmp = dtoa(d, p->precision, &tmp2); 1048 1049 /* 1 for unit, 1 for the '.', 1 for 'e|E', 1050 * 1 for '+|-', 2 for 'exp' */ 1051 /* calculate how much padding need */ 1052 p->width = p->width - 1053 ((d > 0. && p->justify == RIGHT) ? 1:0) - 1054 ((p->flags & PF_SPACE) ? 1:0) - p->precision - 6; 1055 1056 PAD_RIGHT(p); 1057 PUT_PLUS(d, p, 0.); 1058 PUT_SPACE(d, p, 0.); 1059 1060 while (*tmp) 1061 { 1062 PUT_CHAR(*tmp, p); 1063 tmp++; 1064 } 1065 1066 if (p->precision != 0 || (p->flags & PF_ALTFORM)) 1067 PUT_CHAR(decpoint, p); /* the '.' */ 1068 1069 if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0) 1070 /* smash the trailing zeros unless altform */ 1071 for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) 1072 tmp2[i] = '\0'; 1073 1074 for (; *tmp2; tmp2++) 1075 PUT_CHAR(*tmp2, p); /* the fraction */ 1076 1077 /* the exponent put the 'e|E' */ 1078 if (*p->pf == 'g' || *p->pf == 'e') 1079 PUT_CHAR('e', p); 1080 else 1081 PUT_CHAR('E', p); 1082 1083 /* the sign of the exp */ 1084 if (j >= 0) 1085 PUT_CHAR('+', p); 1086 else 1087 { 1088 PUT_CHAR('-', p); 1089 j = -j; 1090 } 1091 1092 tmp = itoa(j); 1093 /* pad out to at least two spaces. pad with `0' if the exponent is a 1094 single digit. */ 1095 if (j <= 9) 1096 PUT_CHAR('0', p); 1097 1098 /* the exponent */ 1099 while (*tmp) 1100 { 1101 PUT_CHAR(*tmp, p); 1102 tmp++; 1103 } 1104 1105 PAD_LEFT(p); 1106} 1107#endif 1108 1109/* Return a new string with the digits in S grouped according to the locale's 1110 grouping info and thousands separator. If no grouping should be performed, 1111 this returns NULL; the caller needs to check for it. */ 1112static char * 1113groupnum (s) 1114 char *s; 1115{ 1116 char *se, *ret, *re, *g; 1117 int len, slen; 1118 1119 if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX) 1120 return ((char *)NULL); 1121 1122 /* find min grouping to size returned string */ 1123 for (len = *grouping, g = grouping; *g; g++) 1124 if (*g > 0 && *g < len) 1125 len = *g; 1126 1127 slen = strlen (s); 1128 len = slen / len + 1; 1129 ret = (char *)xmalloc (slen + len + 1); 1130 re = ret + slen + len; 1131 *re = '\0'; 1132 1133 g = grouping; 1134 se = s + slen; 1135 len = *g; 1136 1137 while (se > s) 1138 { 1139 *--re = *--se; 1140 1141 /* handle `-' inserted by numtoa() and the fmtu* family here. */ 1142 if (se > s && se[-1] == '-') 1143 continue; 1144 1145 /* begin new group. */ 1146 if (--len == 0 && se > s) 1147 { 1148 *--re = thoussep; 1149 len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */ 1150 if (*g == '\0') 1151 len = *--g; /* use previous grouping */ 1152 else if (*g == CHAR_MAX) 1153 { 1154 do 1155 *--re = *--se; 1156 while (se > s); 1157 break; 1158 } 1159 } 1160 } 1161 1162 if (re > ret) 1163#ifdef HAVE_MEMMOVE 1164 memmove (ret, re, strlen (re) + 1); 1165#else 1166 strcpy (ret, re); 1167#endif 1168 1169 return ret; 1170} 1171 1172/* initialize the conversion specifiers */ 1173static void 1174init_conv_flag (p) 1175 struct DATA *p; 1176{ 1177 p->flags &= PF_ALLOCBUF; /* preserve PF_ALLOCBUF flag */ 1178 p->precision = p->width = NOT_FOUND; 1179 p->justify = NOT_FOUND; 1180 p->pad = ' '; 1181} 1182 1183static void 1184init_data (p, string, length, format, mode) 1185 struct DATA *p; 1186 char *string; 1187 size_t length; 1188 const char *format; 1189 int mode; 1190{ 1191 p->length = length - 1; /* leave room for '\0' */ 1192 p->holder = p->base = string; 1193 p->pf = format; 1194 p->counter = 0; 1195 p->flags = (mode == PFM_AS) ? PF_ALLOCBUF : 0; 1196} 1197 1198static int 1199#if defined (__STDC__) 1200vsnprintf_internal(struct DATA *data, char *string, size_t length, const char *format, va_list args) 1201#else 1202vsnprintf_internal(data, string, length, format, args) 1203 struct DATA *data; 1204 char *string; 1205 size_t length; 1206 const char *format; 1207 va_list args; 1208#endif 1209{ 1210 double d; /* temporary holder */ 1211#ifdef HAVE_LONG_DOUBLE 1212 long double ld; /* for later */ 1213#endif 1214 unsigned long ul; 1215#ifdef HAVE_LONG_LONG 1216 unsigned long long ull; 1217#endif 1218 int state, i, c, n; 1219 char *s; 1220#if HANDLE_MULTIBYTE 1221 wchar_t *ws; 1222 wint_t wc; 1223#endif 1224 const char *convstart; 1225 int negprec; 1226 1227 /* Sanity check, the string length must be >= 0. C99 actually says that 1228 LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never 1229 0 in the case of asprintf/vasprintf), and the return value is the number 1230 of characters that would have been written. */ 1231 if (length < 0) 1232 return -1; 1233 1234 if (format == 0) 1235 return 0; 1236 1237 /* Reset these for each call because the locale might have changed. */ 1238 decpoint = thoussep = 0; 1239 grouping = 0; 1240 1241 negprec = 0; 1242 for (; c = *(data->pf); data->pf++) 1243 { 1244 if (c != '%') 1245 { 1246 PUT_CHAR (c, data); 1247 continue; 1248 } 1249 1250 convstart = data->pf; 1251 init_conv_flag (data); /* initialise format flags */ 1252 1253 state = 1; 1254 for (state = 1; state && *data->pf; ) 1255 { 1256 c = *(++data->pf); 1257 /* fmtend = data->pf */ 1258#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) 1259 if (data->flags & PF_LONGDBL) 1260 { 1261 switch (c) 1262 { 1263 case 'f': case 'F': 1264 case 'e': case 'E': 1265 case 'g': case 'G': 1266# ifdef HAVE_PRINTF_A_FORMAT 1267 case 'a': case 'A': 1268# endif 1269 STAR_ARGS (data); 1270 ld = GETLDOUBLE (data); 1271 ldfallback (data, convstart, data->pf, ld); 1272 goto conv_break; 1273 } 1274 } 1275#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ 1276 1277 switch (c) 1278 { 1279 /* Parse format flags */ 1280 case '\0': /* a NULL here ? ? bail out */ 1281 *data->holder = '\0'; 1282 return data->counter; 1283 break; 1284 case '#': 1285 data->flags |= PF_ALTFORM; 1286 continue; 1287 case '0': 1288 data->flags |= PF_ZEROPAD; 1289 data->pad = '0'; 1290 continue; 1291 case '*': 1292 if (data->flags & PF_DOT) 1293 data->flags |= PF_STAR_P; 1294 else 1295 data->flags |= PF_STAR_W; 1296 continue; 1297 case '-': 1298 if ((data->flags & PF_DOT) == 0) 1299 { 1300 data->flags |= PF_LADJUST; 1301 data->justify = LEFT; 1302 } 1303 else 1304 negprec = 1; 1305 continue; 1306 case ' ': 1307 if ((data->flags & PF_PLUS) == 0) 1308 data->flags |= PF_SPACE; 1309 continue; 1310 case '+': 1311 if ((data->flags & PF_DOT) == 0) 1312 { 1313 data->flags |= PF_PLUS; 1314 data->justify = RIGHT; 1315 } 1316 continue; 1317 case '\'': 1318 data->flags |= PF_THOUSANDS; 1319 continue; 1320 1321 case '1': case '2': case '3': 1322 case '4': case '5': case '6': 1323 case '7': case '8': case '9': 1324 n = 0; 1325 do 1326 { 1327 n = n * 10 + TODIGIT(c); 1328 c = *(++data->pf); 1329 } 1330 while (DIGIT(c)); 1331 data->pf--; /* went too far */ 1332 if (n < 0) 1333 n = 0; 1334 if (data->flags & PF_DOT) 1335 data->precision = negprec ? NOT_FOUND : n; 1336 else 1337 data->width = n; 1338 continue; 1339 1340 /* optional precision */ 1341 case '.': 1342 data->flags |= PF_DOT; 1343 data->precision = 0; 1344 continue; 1345 1346 /* length modifiers */ 1347 case 'h': 1348 data->flags |= (data->flags & PF_SHORTINT) ? PF_SIGNEDCHAR : PF_SHORTINT; 1349 continue; 1350 case 'l': 1351 data->flags |= (data->flags & PF_LONGINT) ? PF_LONGLONG : PF_LONGINT; 1352 continue; 1353 case 'L': 1354 data->flags |= PF_LONGDBL; 1355 continue; 1356 case 'q': 1357 data->flags |= PF_LONGLONG; 1358 continue; 1359 case 'j': 1360 data->flags |= PF_INTMAX_T; 1361 SET_SIZE_FLAGS(data, intmax_t); 1362 continue; 1363 case 'z': 1364 data->flags |= PF_SIZE_T; 1365 SET_SIZE_FLAGS(data, size_t); 1366 continue; 1367 case 't': 1368 data->flags |= PF_PTRDIFF_T; 1369 SET_SIZE_FLAGS(data, ptrdiff_t); 1370 continue; 1371 1372 /* Conversion specifiers */ 1373#ifdef FLOATING_POINT 1374 case 'f': /* float, double */ 1375 case 'F': 1376 STAR_ARGS(data); 1377 d = GETDOUBLE(data); 1378 floating(data, d); 1379conv_break: 1380 state = 0; 1381 break; 1382 case 'g': 1383 case 'G': 1384 STAR_ARGS(data); 1385 DEF_PREC(data); 1386 d = GETDOUBLE(data); 1387 i = (d != 0.) ? log_10(d) : -1; 1388 /* 1389 * for '%g|%G' ANSI: use f if exponent 1390 * is in the range or [-4,p] exclusively 1391 * else use %e|%E 1392 */ 1393 if (-4 < i && i < data->precision) 1394 { 1395 /* reset precision */ 1396 data->precision -= i + 1; 1397 floating(data, d); 1398 } 1399 else 1400 { 1401 /* reduce precision by 1 because of leading digit before 1402 decimal point in e format. */ 1403 data->precision--; 1404 exponent(data, d); 1405 } 1406 state = 0; 1407 break; 1408 case 'e': 1409 case 'E': /* Exponent double */ 1410 STAR_ARGS(data); 1411 d = GETDOUBLE(data); 1412 exponent(data, d); 1413 state = 0; 1414 break; 1415# ifdef HAVE_PRINTF_A_FORMAT 1416 case 'a': 1417 case 'A': 1418 STAR_ARGS(data); 1419 d = GETDOUBLE(data); 1420 dfallback(data, convstart, data->pf, d); 1421 state = 0; 1422 break; 1423# endif /* HAVE_PRINTF_A_FORMAT */ 1424#endif /* FLOATING_POINT */ 1425 case 'U': 1426 data->flags |= PF_LONGINT; 1427 /* FALLTHROUGH */ 1428 case 'u': 1429 STAR_ARGS(data); 1430#ifdef HAVE_LONG_LONG 1431 if (data->flags & PF_LONGLONG) 1432 { 1433 ull = GETARG (unsigned long long); 1434 lnumber(data, ull, 10); 1435 } 1436 else 1437#endif 1438 { 1439 ul = GETUNSIGNED(data); 1440 number(data, ul, 10); 1441 } 1442 state = 0; 1443 break; 1444 case 'D': 1445 data->flags |= PF_LONGINT; 1446 /* FALLTHROUGH */ 1447 case 'd': /* decimal */ 1448 case 'i': 1449 STAR_ARGS(data); 1450#ifdef HAVE_LONG_LONG 1451 if (data->flags & PF_LONGLONG) 1452 { 1453 ull = GETARG (long long); 1454 lnumber(data, ull, 10); 1455 } 1456 else 1457#endif 1458 { 1459 ul = GETSIGNED(data); 1460 number(data, ul, 10); 1461 } 1462 state = 0; 1463 break; 1464 case 'o': /* octal */ 1465 STAR_ARGS(data); 1466#ifdef HAVE_LONG_LONG 1467 if (data->flags & PF_LONGLONG) 1468 { 1469 ull = GETARG (unsigned long long); 1470 lnumber(data, ull, 8); 1471 } 1472 else 1473#endif 1474 { 1475 ul = GETUNSIGNED(data); 1476 number(data, ul, 8); 1477 } 1478 state = 0; 1479 break; 1480 case 'x': 1481 case 'X': /* hexadecimal */ 1482 STAR_ARGS(data); 1483#ifdef HAVE_LONG_LONG 1484 if (data->flags & PF_LONGLONG) 1485 { 1486 ull = GETARG (unsigned long long); 1487 lnumber(data, ull, 16); 1488 } 1489 else 1490#endif 1491 { 1492 ul = GETUNSIGNED(data); 1493 number(data, ul, 16); 1494 } 1495 state = 0; 1496 break; 1497 case 'p': 1498 STAR_ARGS(data); 1499 ul = (unsigned long)GETARG (void *); 1500 pointer(data, ul); 1501 state = 0; 1502 break; 1503#if HANDLE_MULTIBYTE 1504 case 'C': 1505 data->flags |= PF_LONGINT; 1506 /* FALLTHROUGH */ 1507#endif 1508 case 'c': /* character */ 1509 STAR_ARGS(data); 1510#if HANDLE_MULTIBYTE 1511 if (data->flags & PF_LONGINT) 1512 { 1513 wc = GETARG (wint_t); 1514 wchars (data, wc); 1515 } 1516 else 1517#endif 1518 { 1519 ul = GETARG (int); 1520 PUT_CHAR(ul, data); 1521 } 1522 state = 0; 1523 break; 1524#if HANDLE_MULTIBYTE 1525 case 'S': 1526 data->flags |= PF_LONGINT; 1527 /* FALLTHROUGH */ 1528#endif 1529 case 's': /* string */ 1530 STAR_ARGS(data); 1531#if HANDLE_MULTIBYTE 1532 if (data->flags & PF_LONGINT) 1533 { 1534 ws = GETARG (wchar_t *); 1535 wstrings (data, ws); 1536 } 1537 else 1538#endif 1539 { 1540 s = GETARG (char *); 1541 strings(data, s); 1542 } 1543 state = 0; 1544 break; 1545 case 'n': 1546#ifdef HAVE_LONG_LONG 1547 if (data->flags & PF_LONGLONG) 1548 *(GETARG (long long *)) = data->counter; 1549 else 1550#endif 1551 if (data->flags & PF_LONGINT) 1552 *(GETARG (long *)) = data->counter; 1553 else if (data->flags & PF_SHORTINT) 1554 *(GETARG (short *)) = data->counter; 1555 else 1556 *(GETARG (int *)) = data->counter; 1557 state = 0; 1558 break; 1559 case '%': /* nothing just % */ 1560 PUT_CHAR('%', data); 1561 state = 0; 1562 break; 1563 default: 1564 /* is this an error ? maybe bail out */ 1565 state = 0; 1566 break; 1567 } /* end switch */ 1568 } /* end of `%' for loop */ 1569 } /* end of format string for loop */ 1570 1571 if (data->length >= 0) 1572 *data->holder = '\0'; /* the end ye ! */ 1573 1574 return data->counter; 1575} 1576 1577#if defined (FLOATING_POINT) && defined (HAVE_LONG_DOUBLE) 1578/* 1579 * Printing floating point numbers accurately is an art. I'm not good 1580 * at it. Fall back to sprintf for long double formats. 1581 */ 1582static void 1583ldfallback (data, fs, fe, ld) 1584 struct DATA *data; 1585 const char *fs, *fe; 1586 long double ld; 1587{ 1588 register char *x; 1589 char fmtbuf[FALLBACK_FMTSIZE], *obuf; 1590 int fl; 1591 1592 fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2; 1593 obuf = (char *)xmalloc (fl); 1594 fl = fe - fs + 1; 1595 strncpy (fmtbuf, fs, fl); 1596 fmtbuf[fl] = '\0'; 1597 1598 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) 1599 sprintf (obuf, fmtbuf, data->width, data->precision, ld); 1600 else if (data->flags & PF_STAR_W) 1601 sprintf (obuf, fmtbuf, data->width, ld); 1602 else if (data->flags & PF_STAR_P) 1603 sprintf (obuf, fmtbuf, data->precision, ld); 1604 else 1605 sprintf (obuf, fmtbuf, ld); 1606 1607 for (x = obuf; *x; x++) 1608 PUT_CHAR (*x, data); 1609 xfree (obuf); 1610} 1611#endif /* FLOATING_POINT && HAVE_LONG_DOUBLE */ 1612 1613#ifdef FLOATING_POINT 1614/* Used for %a, %A if the libc printf supports them. */ 1615static void 1616dfallback (data, fs, fe, d) 1617 struct DATA *data; 1618 const char *fs, *fe; 1619 double d; 1620{ 1621 register char *x; 1622 char fmtbuf[FALLBACK_FMTSIZE], obuf[FALLBACK_BASE]; 1623 int fl; 1624 1625 fl = fe - fs + 1; 1626 strncpy (fmtbuf, fs, fl); 1627 fmtbuf[fl] = '\0'; 1628 1629 if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P)) 1630 sprintf (obuf, fmtbuf, data->width, data->precision, d); 1631 else if (data->flags & PF_STAR_W) 1632 sprintf (obuf, fmtbuf, data->width, d); 1633 else if (data->flags & PF_STAR_P) 1634 sprintf (obuf, fmtbuf, data->precision, d); 1635 else 1636 sprintf (obuf, fmtbuf, d); 1637 1638 for (x = obuf; *x; x++) 1639 PUT_CHAR (*x, data); 1640} 1641#endif /* FLOATING_POINT */ 1642 1643#ifndef HAVE_SNPRINTF 1644 1645int 1646#if defined (__STDC__) 1647vsnprintf(char *string, size_t length, const char *format, va_list args) 1648#else 1649vsnprintf(string, length, format, args) 1650 char *string; 1651 size_t length; 1652 const char *format; 1653 va_list args; 1654#endif 1655{ 1656 struct DATA data; 1657 1658 if (string == 0 && length != 0) 1659 return 0; 1660 init_data (&data, string, length, format, PFM_SN); 1661 return (vsnprintf_internal(&data, string, length, format, args)); 1662} 1663 1664int 1665#if defined(PREFER_STDARG) 1666snprintf(char *string, size_t length, const char * format, ...) 1667#else 1668snprintf(string, length, format, va_alist) 1669 char *string; 1670 size_t length; 1671 const char *format; 1672 va_dcl 1673#endif 1674{ 1675 struct DATA data; 1676 int rval; 1677 va_list args; 1678 1679 SH_VA_START(args, format); 1680 1681 if (string == 0 && length != 0) 1682 return 0; 1683 init_data (&data, string, length, format, PFM_SN); 1684 rval = vsnprintf_internal (&data, string, length, format, args); 1685 1686 va_end(args); 1687 1688 return rval; 1689} 1690 1691#endif /* HAVE_SNPRINTF */ 1692 1693#ifndef HAVE_ASPRINTF 1694 1695int 1696#if defined (__STDC__) 1697vasprintf(char **stringp, const char *format, va_list args) 1698#else 1699vasprintf(stringp, format, args) 1700 char **stringp; 1701 const char *format; 1702 va_list args; 1703#endif 1704{ 1705 struct DATA data; 1706 char *string; 1707 int r; 1708 1709 string = (char *)xmalloc(ASBUFSIZE); 1710 init_data (&data, string, ASBUFSIZE, format, PFM_AS); 1711 r = vsnprintf_internal(&data, string, ASBUFSIZE, format, args); 1712 *stringp = data.base; /* not string in case reallocated */ 1713 return r; 1714} 1715 1716int 1717#if defined(PREFER_STDARG) 1718asprintf(char **stringp, const char * format, ...) 1719#else 1720asprintf(stringp, format, va_alist) 1721 char **stringp; 1722 const char *format; 1723 va_dcl 1724#endif 1725{ 1726 int rval; 1727 va_list args; 1728 1729 SH_VA_START(args, format); 1730 1731 rval = vasprintf (stringp, format, args); 1732 1733 va_end(args); 1734 1735 return rval; 1736} 1737 1738#endif 1739 1740#endif 1741 1742#ifdef DRIVER 1743 1744static void 1745memory_error_and_abort () 1746{ 1747 write (2, "out of virtual memory\n", 22); 1748 abort (); 1749} 1750 1751static void * 1752xmalloc(bytes) 1753 size_t bytes; 1754{ 1755 void *ret; 1756 1757 ret = malloc(bytes); 1758 if (ret == 0) 1759 memory_error_and_abort (); 1760 return ret; 1761} 1762 1763static void * 1764xrealloc (pointer, bytes) 1765 void *pointer; 1766 size_t bytes; 1767{ 1768 void *ret; 1769 1770 ret = pointer ? realloc(pointer, bytes) : malloc(bytes); 1771 if (ret == 0) 1772 memory_error_and_abort (); 1773 return ret; 1774} 1775 1776static void 1777xfree(x) 1778 void *x; 1779{ 1780 if (x) 1781 free (x); 1782} 1783 1784/* set of small tests for snprintf() */ 1785main() 1786{ 1787 char holder[100]; 1788 char *h; 1789 int i, si, ai; 1790 1791#ifdef HAVE_LOCALE_H 1792 setlocale(LC_ALL, ""); 1793#endif 1794 1795#if 1 1796 si = snprintf((char *)NULL, 0, "abcde\n"); 1797 printf("snprintf returns %d with NULL first argument and size of 0\n", si); 1798 si = snprintf(holder, 0, "abcde\n"); 1799 printf("snprintf returns %d with non-NULL first argument and size of 0\n", si); 1800 si = snprintf((char *)NULL, 16, "abcde\n"); 1801 printf("snprintf returns %d with NULL first argument and non-zero size\n", si); 1802 1803/* 1804 printf("Suite of test for snprintf:\n"); 1805 printf("a_format\n"); 1806 printf("printf() format\n"); 1807 printf("snprintf() format\n\n"); 1808*/ 1809/* Checking the field widths */ 1810 1811 printf("/%%ld %%ld/, 336, 336\n"); 1812 snprintf(holder, sizeof holder, "/%ld %ld/\n", 336, 336); 1813 asprintf(&h, "/%ld %ld/\n", 336, 336); 1814 printf("/%ld %ld/\n", 336, 336); 1815 printf("%s", holder); 1816 printf("%s\n", h); 1817 1818 printf("/%%d/, 336\n"); 1819 snprintf(holder, sizeof holder, "/%d/\n", 336); 1820 asprintf(&h, "/%d/\n", 336); 1821 printf("/%d/\n", 336); 1822 printf("%s", holder); 1823 printf("%s\n", h); 1824 1825 printf("/%%2d/, 336\n"); 1826 snprintf(holder, sizeof holder, "/%2d/\n", 336); 1827 asprintf(&h, "/%2d/\n", 336); 1828 printf("/%2d/\n", 336); 1829 printf("%s", holder); 1830 printf("%s\n", h); 1831 1832 printf("/%%10d/, 336\n"); 1833 snprintf(holder, sizeof holder, "/%10d/\n", 336); 1834 asprintf(&h, "/%10d/\n", 336); 1835 printf("/%10d/\n", 336); 1836 printf("%s", holder); 1837 printf("%s\n", h); 1838 1839 printf("/%%-10d/, 336\n"); 1840 snprintf(holder, sizeof holder, "/%-10d/\n", 336); 1841 asprintf(&h, "/%-10d/\n", 336); 1842 printf("/%-10d/\n", 336); 1843 printf("%s", holder); 1844 printf("%s\n", h); 1845 1846 1847/* floating points */ 1848 1849 printf("/%%f/, 1234.56\n"); 1850 snprintf(holder, sizeof holder, "/%f/\n", 1234.56); 1851 asprintf(&h, "/%f/\n", 1234.56); 1852 printf("/%f/\n", 1234.56); 1853 printf("%s", holder); 1854 printf("%s\n", h); 1855 1856 printf("/%%e/, 1234.56\n"); 1857 snprintf(holder, sizeof holder, "/%e/\n", 1234.56); 1858 asprintf(&h, "/%e/\n", 1234.56); 1859 printf("/%e/\n", 1234.56); 1860 printf("%s", holder); 1861 printf("%s\n", h); 1862 1863 printf("/%%4.2f/, 1234.56\n"); 1864 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56); 1865 asprintf(&h, "/%4.2f/\n", 1234.56); 1866 printf("/%4.2f/\n", 1234.56); 1867 printf("%s", holder); 1868 printf("%s\n", h); 1869 1870 printf("/%%3.1f/, 1234.56\n"); 1871 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56); 1872 asprintf(&h, "/%3.1f/\n", 1234.56); 1873 printf("/%3.1f/\n", 1234.56); 1874 printf("%s", holder); 1875 printf("%s\n", h); 1876 1877 printf("/%%10.3f/, 1234.56\n"); 1878 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56); 1879 asprintf(&h, "/%10.3f/\n", 1234.56); 1880 printf("/%10.3f/\n", 1234.56); 1881 printf("%s", holder); 1882 printf("%s\n", h); 1883 1884 printf("/%%10.3e/, 1234.56\n"); 1885 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56); 1886 asprintf(&h, "/%10.3e/\n", 1234.56); 1887 printf("/%10.3e/\n", 1234.56); 1888 printf("%s", holder); 1889 printf("%s\n", h); 1890 1891 printf("/%%+4.2f/, 1234.56\n"); 1892 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56); 1893 asprintf(&h, "/%+4.2f/\n", 1234.56); 1894 printf("/%+4.2f/\n", 1234.56); 1895 printf("%s", holder); 1896 printf("%s\n", h); 1897 1898 printf("/%%010.2f/, 1234.56\n"); 1899 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56); 1900 asprintf(&h, "/%010.2f/\n", 1234.56); 1901 printf("/%010.2f/\n", 1234.56); 1902 printf("%s", holder); 1903 printf("%s\n", h); 1904 1905#define BLURB "Outstanding acting !" 1906/* strings precisions */ 1907 1908 printf("/%%2s/, \"%s\"\n", BLURB); 1909 snprintf(holder, sizeof holder, "/%2s/\n", BLURB); 1910 asprintf(&h, "/%2s/\n", BLURB); 1911 printf("/%2s/\n", BLURB); 1912 printf("%s", holder); 1913 printf("%s\n", h); 1914 1915 printf("/%%22s/ %s\n", BLURB); 1916 snprintf(holder, sizeof holder, "/%22s/\n", BLURB); 1917 asprintf(&h, "/%22s/\n", BLURB); 1918 printf("/%22s/\n", BLURB); 1919 printf("%s", holder); 1920 printf("%s\n", h); 1921 1922 printf("/%%22.5s/ %s\n", BLURB); 1923 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB); 1924 asprintf(&h, "/%22.5s/\n", BLURB); 1925 printf("/%22.5s/\n", BLURB); 1926 printf("%s", holder); 1927 printf("%s\n", h); 1928 1929 printf("/%%-22.5s/ %s\n", BLURB); 1930 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB); 1931 asprintf(&h, "/%-22.5s/\n", BLURB); 1932 printf("/%-22.5s/\n", BLURB); 1933 printf("%s", holder); 1934 printf("%s\n", h); 1935 1936/* see some flags */ 1937 1938 printf("%%x %%X %%#x, 31, 31, 31\n"); 1939 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31); 1940 asprintf(&h, "%x %X %#x\n", 31, 31, 31); 1941 printf("%x %X %#x\n", 31, 31, 31); 1942 printf("%s", holder); 1943 printf("%s\n", h); 1944 1945 printf("**%%d**%% d**%% d**, 42, 42, -42\n"); 1946 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42); 1947 asprintf(&h, "**%d**% d**% d**\n", 42, 42, -42); 1948 printf("**%d**% d**% d**\n", 42, 42, -42); 1949 printf("%s", holder); 1950 printf("%s\n", h); 1951 1952/* other flags */ 1953 1954 printf("/%%g/, 31.4\n"); 1955 snprintf(holder, sizeof holder, "/%g/\n", 31.4); 1956 asprintf(&h, "/%g/\n", 31.4); 1957 printf("/%g/\n", 31.4); 1958 printf("%s", holder); 1959 printf("%s\n", h); 1960 1961 printf("/%%.6g/, 31.4\n"); 1962 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4); 1963 asprintf(&h, "/%.6g/\n", 31.4); 1964 printf("/%.6g/\n", 31.4); 1965 printf("%s", holder); 1966 printf("%s\n", h); 1967 1968 printf("/%%.1G/, 31.4\n"); 1969 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4); 1970 asprintf(&h, "/%.1G/\n", 31.4); 1971 printf("/%.1G/\n", 31.4); 1972 printf("%s", holder); 1973 printf("%s\n", h); 1974 1975 printf("/%%.1G/, 3100000000.4\n"); 1976 snprintf(holder, sizeof holder, "/%.1G/\n", 3100000000.4); 1977 asprintf(&h, "/%.1G/\n", 3100000000.4); 1978 printf("/%.1G/\n", 3100000000.4); 1979 printf("%s", holder); 1980 printf("%s\n", h); 1981 1982 printf("abc%%n\n"); 1983 printf("abc%n", &i); printf("%d\n", i); 1984 snprintf(holder, sizeof holder, "abc%n", &i); 1985 printf("%s", holder); printf("%d\n\n", i); 1986 asprintf(&h, "abc%n", &i); 1987 printf("%s", h); printf("%d\n\n", i); 1988 1989 printf("%%*.*s --> 10.10\n"); 1990 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB); 1991 asprintf(&h, "%*.*s\n", 10, 10, BLURB); 1992 printf("%*.*s\n", 10, 10, BLURB); 1993 printf("%s", holder); 1994 printf("%s\n", h); 1995 1996 printf("%%%%%%%%\n"); 1997 snprintf(holder, sizeof holder, "%%%%\n"); 1998 asprintf(&h, "%%%%\n"); 1999 printf("%%%%\n"); 2000 printf("%s", holder); 2001 printf("%s\n", h); 2002 2003#define BIG "Hello this is a too big string for the buffer" 2004/* printf("A buffer to small of 10, trying to put this:\n");*/ 2005 printf("<%%>, %s\n", BIG); 2006 i = snprintf(holder, 10, "%s\n", BIG); 2007 i = asprintf(&h, "%s", BIG); 2008 printf("<%s>\n", BIG); 2009 printf("<%s>\n", holder); 2010 printf("<%s>\n\n", h); 2011 2012 printf ("<%%p> vsnprintf\n"); 2013 i = snprintf(holder, 100, "%p", vsnprintf); 2014 i = asprintf(&h, "%p", vsnprintf); 2015 printf("<%p>\n", vsnprintf); 2016 printf("<%s>\n", holder); 2017 printf("<%s>\n\n", h); 2018 2019 printf ("<%%lu> LONG_MAX+1\n"); 2020 i = snprintf(holder, 100, "%lu", (unsigned long)(LONG_MAX)+1); 2021 i = asprintf(&h, "%lu", (unsigned long)(LONG_MAX)+1); 2022 printf("<%lu>\n", (unsigned long)(LONG_MAX)+1); 2023 printf("<%s>\n", holder); 2024 printf("<%s>\n\n", h); 2025 2026#ifdef HAVE_LONG_LONG 2027 printf ("<%%llu> LLONG_MAX+1\n"); 2028 i = snprintf(holder, 100, "%llu", (unsigned long long)(LLONG_MAX)+1); 2029 i = asprintf(&h, "%llu", (unsigned long long)(LLONG_MAX)+1); 2030 printf("<%llu>\n", (unsigned long long)(LLONG_MAX)+1); 2031 printf("<%s>\n", holder); 2032 printf("<%s>\n\n", h); 2033#endif 2034 2035#ifdef HAVE_LONG_DOUBLE 2036 printf ("<%%6.2LE> 42.42\n"); 2037 i = snprintf(holder, 100, "%6.2LE", (long double)42.42); 2038 i = asprintf(&h, "%6.2LE", (long double)42.42); 2039 printf ("<%6.2LE>\n", (long double)42.42); 2040 printf ("<%s>\n", holder); 2041 printf ("<%s>\n\n", h); 2042#endif 2043 2044#ifdef HAVE_PRINTF_A_FORMAT 2045 printf ("<%%6.2A> 42.42\n"); 2046 i = snprintf(holder, 100, "%6.2A", 42.42); 2047 i = asprintf(&h, "%6.2A", 42.42); 2048 printf ("<%6.2A>\n", 42.42); 2049 printf ("<%s>\n", holder); 2050 printf ("<%s>\n\n", h); 2051 2052 printf ("<%%6.2LA> 42.42\n"); 2053 i = snprintf(holder, 100, "%6.2LA", (long double)42.42); 2054 i = asprintf(&h, "%6.2LA", (long double)42.42); 2055 printf ("<%6.2LA>\n", (long double)42.42); 2056 printf ("<%s>\n", holder); 2057 printf ("<%s>\n\n", h); 2058#endif 2059 2060 printf ("<%%.10240f> DBL_MAX\n"); 2061 si = snprintf(holder, 100, "%.10240f", DBL_MAX); 2062 ai = asprintf(&h, "%.10240f", DBL_MAX); 2063 printf ("<%.10240f>\n", DBL_MAX); 2064 printf ("<%d> <%s>\n", si, holder); 2065 printf ("<%d> <%s>\n\n", ai, h); 2066 2067 printf ("<%%.10240Lf> LDBL_MAX\n"); 2068 si = snprintf(holder, 100, "%.10240Lf", (long double)LDBL_MAX); 2069 ai = asprintf(&h, "%.10240Lf", (long double)LDBL_MAX); 2070 printf ("<%.10240Lf>\n", (long double)LDBL_MAX); 2071 printf ("<%d> <%s>\n", si, holder); 2072 printf ("<%d> <%s>\n\n", ai, h); 2073 2074 /* huh? */ 2075 printf("/%%g/, 421.2345\n"); 2076 snprintf(holder, sizeof holder, "/%g/\n", 421.2345); 2077 asprintf(&h, "/%g/\n", 421.2345); 2078 printf("/%g/\n", 421.2345); 2079 printf("%s", holder); 2080 printf("%s\n", h); 2081 2082 printf("/%%g/, 4214.2345\n"); 2083 snprintf(holder, sizeof holder, "/%g/\n", 4214.2345); 2084 asprintf(&h, "/%g/\n", 4214.2345); 2085 printf("/%g/\n", 4214.2345); 2086 printf("%s", holder); 2087 printf("%s\n", h); 2088 2089 printf("/%%.5g/, 4214.2345\n"); 2090 snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345); 2091 asprintf(&h, "/%.5g/\n", 4214.2345); 2092 printf("/%.5g/\n", 4214.2345); 2093 printf("%s", holder); 2094 printf("%s\n", h); 2095 2096 printf("/%%.4g/, 4214.2345\n"); 2097 snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345); 2098 asprintf(&h, "/%.4g/\n", 4214.2345); 2099 printf("/%.4g/\n", 4214.2345); 2100 printf("%s", holder); 2101 printf("%s\n", h); 2102 2103 printf("/%%'ld %%'ld/, 12345, 1234567\n"); 2104 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567); 2105 asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567); 2106 printf("/%'ld %'ld/\n", 12345, 1234567); 2107 printf("%s", holder); 2108 printf("%s\n", h); 2109 2110 printf("/%%'ld %%'ld/, 336, 3336\n"); 2111 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336); 2112 asprintf(&h, "/%'ld %'ld/\n", 336, 3336); 2113 printf("/%'ld %'ld/\n", 336, 3336); 2114 printf("%s", holder); 2115 printf("%s\n", h); 2116 2117 printf("/%%'ld %%'ld/, -42786, -142786\n"); 2118 snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786); 2119 asprintf(&h, "/%'ld %'ld/\n", -42786, -142786); 2120 printf("/%'ld %'ld/\n", -42786, -142786); 2121 printf("%s", holder); 2122 printf("%s\n", h); 2123 2124 printf("/%%'f %%'f/, 421.2345, 421234.56789\n"); 2125 snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789); 2126 asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789); 2127 printf("/%'f %'f/\n", 421.2345, 421234.56789); 2128 printf("%s", holder); 2129 printf("%s\n", h); 2130 2131 printf("/%%'f %%'f/, -421.2345, -421234.56789\n"); 2132 snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789); 2133 asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789); 2134 printf("/%'f %'f/\n", -421.2345, -421234.56789); 2135 printf("%s", holder); 2136 printf("%s\n", h); 2137 2138 printf("/%%'g %%'g/, 421.2345, 421234.56789\n"); 2139 snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789); 2140 asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789); 2141 printf("/%'g %'g/\n", 421.2345, 421234.56789); 2142 printf("%s", holder); 2143 printf("%s\n", h); 2144 2145 printf("/%%'g %%'g/, -421.2345, -421234.56789\n"); 2146 snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789); 2147 asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789); 2148 printf("/%'g %'g/\n", -421.2345, -421234.56789); 2149 printf("%s", holder); 2150 printf("%s\n", h); 2151#endif 2152 2153 printf("/%%'g/, 4213455.8392\n"); 2154 snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392); 2155 asprintf(&h, "/%'g/\n", 4213455.8392); 2156 printf("/%'g/\n", 4213455.8392); 2157 printf("%s", holder); 2158 printf("%s\n", h); 2159 2160 exit (0); 2161} 2162#endif 2163