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