1 /**************************************************************
   2  * Original:
   3  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
   4  * A bombproof version of doprnt (dopr) included.
   5  * Sigh.  This sort of thing is always nasty do deal with.  Note that
   6  * the version here does not include floating point...
   7  *
   8  * snprintf() is used instead of sprintf() as it does limit checks
   9  * for string length.  This covers a nasty loophole.
  10  *
  11  * The other functions are there to prevent NULL pointers from
  12  * causing nast effects.
  13  *
  14  * More Recently:
  15  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
  16  *  This was ugly.  It is still ugly.  I opted out of floating point
  17  *  numbers, but the formatter understands just about everything
  18  *  from the normal C string format, at least as far as I can tell from
  19  *  the Solaris 2.5 printf(3S) man page.
  20  *
  21  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
  22  *    Ok, added some minimal floating point support, which means this
  23  *    probably requires libm on most operating systems.  Don't yet
  24  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
  25  *    was pretty badly broken, it just wasn't being exercised in ways
  26  *    which showed it, so that's been fixed.  Also, formated the code
  27  *    to mutt conventions, and removed dead code left over from the
  28  *    original.  Also, there is now a builtin-test, just compile with:
  29  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
  30  *    and run snprintf for results.
  31  * 
  32  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
  33  *    The PGP code was using unsigned hexadecimal formats. 
  34  *    Unfortunately, unsigned formats simply didn't work.
  35  *
  36  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
  37  *    The original code assumed that both snprintf() and vsnprintf() were
  38  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
  39  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
  40  *
  41  *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
  42  *    Welcome to the world of %lld and %qd support.  With other
  43  *    long long support.  This is needed for sftp-server to work
  44  *    right.
  45  *
  46  *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
  47  *    Removed all hint of VARARGS stuff and banished it to the void,
  48  *    and did a bit of KNF style work to make things a bit more
  49  *    acceptable.  Consider stealing from mutt or enlightenment.
  50  **************************************************************/
  51 
  52 #include "includes.h"
  53 
  54 RCSID("$Id: bsd-snprintf.c,v 1.5 2001/02/25 23:20:41 mouring Exp $");
  55 
  56 #pragma ident   "%Z%%M% %I%     %E% SMI"
  57 
  58 #if defined(BROKEN_SNPRINTF)            /* For those with broken snprintf() */
  59 # undef HAVE_SNPRINTF
  60 # undef HAVE_VSNPRINTF
  61 #endif
  62 
  63 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
  64 
  65 static void 
  66 dopr(char *buffer, size_t maxlen, const char *format, va_list args);
  67 
  68 static void 
  69 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
  70        int min, int max);
  71 
  72 static void 
  73 fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
  74        int min, int max, int flags);
  75 
  76 static void 
  77 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
  78       int min, int max, int flags);
  79 
  80 static void
  81 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
  82 
  83 /*
  84  * dopr(): poor man's version of doprintf
  85  */
  86 
  87 /* format read states */
  88 #define DP_S_DEFAULT 0
  89 #define DP_S_FLAGS   1
  90 #define DP_S_MIN     2
  91 #define DP_S_DOT     3
  92 #define DP_S_MAX     4
  93 #define DP_S_MOD     5
  94 #define DP_S_CONV    6
  95 #define DP_S_DONE    7
  96 
  97 /* format flags - Bits */
  98 #define DP_F_MINUS      (1 << 0)
  99 #define DP_F_PLUS       (1 << 1)
 100 #define DP_F_SPACE      (1 << 2)
 101 #define DP_F_NUM        (1 << 3)
 102 #define DP_F_ZERO       (1 << 4)
 103 #define DP_F_UP         (1 << 5)
 104 #define DP_F_UNSIGNED   (1 << 6)
 105 
 106 /* Conversion Flags */
 107 #define DP_C_SHORT     1
 108 #define DP_C_LONG      2
 109 #define DP_C_LDOUBLE   3
 110 #define DP_C_LONG_LONG 4
 111 
 112 #define char_to_int(p) (p - '0')
 113 #define abs_val(p) (p < 0 ? -p : p)
 114 
 115 
 116 static void 
 117 dopr(char *buffer, size_t maxlen, const char *format, va_list args)
 118 {
 119         char *strvalue;
 120         char ch;
 121         long value;
 122         long double fvalue;
 123         int min = 0;
 124         int max = -1;
 125         int state = DP_S_DEFAULT;
 126         int flags = 0;
 127         int cflags = 0;
 128         size_t currlen = 0;
 129   
 130         ch = *format++;
 131 
 132         while (state != DP_S_DONE) {
 133                 if ((ch == '\0') || (currlen >= maxlen)) 
 134                         state = DP_S_DONE;
 135 
 136                 switch(state) {
 137                         case DP_S_DEFAULT:
 138                                 if (ch == '%') 
 139                                         state = DP_S_FLAGS;
 140                                 else 
 141                                         dopr_outch(buffer, &currlen, maxlen, ch);
 142                                 ch = *format++;
 143                                 break;
 144                         case DP_S_FLAGS:
 145                                 switch (ch) {
 146                                         case '-':
 147                                                 flags |= DP_F_MINUS;
 148                                                 ch = *format++;
 149                                                 break;
 150                                         case '+':
 151                                                 flags |= DP_F_PLUS;
 152                                                 ch = *format++;
 153                                                 break;
 154                                         case ' ':
 155                                                 flags |= DP_F_SPACE;
 156                                                 ch = *format++;
 157                                                 break;
 158                                         case '#':
 159                                                 flags |= DP_F_NUM;
 160                                                 ch = *format++;
 161                                                 break;
 162                                         case '0':
 163                                                 flags |= DP_F_ZERO;
 164                                                 ch = *format++;
 165                                                 break;
 166                                         default:
 167                                                 state = DP_S_MIN;
 168                                                 break;
 169                                 }
 170                                 break;
 171                         case DP_S_MIN:
 172                                 if (isdigit((unsigned char)ch)) {
 173                                         min = 10*min + char_to_int (ch);
 174                                         ch = *format++;
 175                                 } else if (ch == '*') {
 176                                         min = va_arg (args, int);
 177                                         ch = *format++;
 178                                         state = DP_S_DOT;
 179                                 } else 
 180                                         state = DP_S_DOT;
 181                                 break;
 182                         case DP_S_DOT:
 183                                 if (ch == '.') {
 184                                         state = DP_S_MAX;
 185                                         ch = *format++;
 186                                 } else 
 187                                         state = DP_S_MOD;
 188                                 break;
 189                         case DP_S_MAX:
 190                                 if (isdigit((unsigned char)ch)) {
 191                                         if (max < 0)
 192                                                 max = 0;
 193                                         max = 10*max + char_to_int(ch);
 194                                         ch = *format++;
 195                                 } else if (ch == '*') {
 196                                         max = va_arg (args, int);
 197                                         ch = *format++;
 198                                         state = DP_S_MOD;
 199                                 } else 
 200                                         state = DP_S_MOD;
 201                                 break;
 202                         case DP_S_MOD:
 203                                 switch (ch) {
 204                                         case 'h':
 205                                                 cflags = DP_C_SHORT;
 206                                                 ch = *format++;
 207                                                 break;
 208                                         case 'l':
 209                                                 cflags = DP_C_LONG;
 210                                                 ch = *format++;
 211                                                 if (ch == 'l') {
 212                                                         cflags = DP_C_LONG_LONG;
 213                                                         ch = *format++;
 214                                                 }
 215                                                 break;
 216                                         case 'q':
 217                                                 cflags = DP_C_LONG_LONG;
 218                                                 ch = *format++;
 219                                                 break;
 220                                         case 'L':
 221                                                 cflags = DP_C_LDOUBLE;
 222                                                 ch = *format++;
 223                                                 break;
 224                                         default:
 225                                                 break;
 226                                 }
 227                                 state = DP_S_CONV;
 228                                 break;
 229                         case DP_S_CONV:
 230                                 switch (ch) {
 231                                         case 'd':
 232                                         case 'i':
 233                                                 if (cflags == DP_C_SHORT) 
 234                                                         value = va_arg(args, int);
 235                                                 else if (cflags == DP_C_LONG)
 236                                                         value = va_arg(args, long int);
 237                                                 else if (cflags == DP_C_LONG_LONG)
 238                                                         value = va_arg (args, long long);
 239                                                 else
 240                                                         value = va_arg (args, int);
 241                                                 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
 242                                                 break;
 243                                         case 'o':
 244                                                 flags |= DP_F_UNSIGNED;
 245                                                 if (cflags == DP_C_SHORT)
 246                                                         value = va_arg(args, unsigned int);
 247                                                 else if (cflags == DP_C_LONG)
 248                                                         value = va_arg(args, unsigned long int);
 249                                                 else if (cflags == DP_C_LONG_LONG)
 250                                                         value = va_arg(args, unsigned long long);
 251                                                 else
 252                                                         value = va_arg(args, unsigned int);
 253                                                 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
 254                                                 break;
 255                                         case 'u':
 256                                                 flags |= DP_F_UNSIGNED;
 257                                                 if (cflags == DP_C_SHORT)
 258                                                         value = va_arg(args, unsigned int);
 259                                                 else if (cflags == DP_C_LONG)
 260                                                         value = va_arg(args, unsigned long int);
 261                                                 else if (cflags == DP_C_LONG_LONG)
 262                                                         value = va_arg(args, unsigned long long);
 263                                                 else
 264                                                         value = va_arg(args, unsigned int);
 265                                                 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
 266                                                 break;
 267                                         case 'X':
 268                                                 flags |= DP_F_UP;
 269                                         case 'x':
 270                                                 flags |= DP_F_UNSIGNED;
 271                                                 if (cflags == DP_C_SHORT)
 272                                                         value = va_arg(args, unsigned int);
 273                                                 else if (cflags == DP_C_LONG)
 274                                                         value = va_arg(args, unsigned long int);
 275                                                 else if (cflags == DP_C_LONG_LONG)
 276                                                         value = va_arg(args, unsigned long long);
 277                                                 else
 278                                                         value = va_arg(args, unsigned int);
 279                                                 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
 280                                                 break;
 281                                         case 'f':
 282                                                 if (cflags == DP_C_LDOUBLE)
 283                                                         fvalue = va_arg(args, long double);
 284                                                 else
 285                                                         fvalue = va_arg(args, double);
 286                                                 /* um, floating point? */
 287                                                 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
 288                                                 break;
 289                                         case 'E':
 290                                                 flags |= DP_F_UP;
 291                                         case 'e':
 292                                                 if (cflags == DP_C_LDOUBLE)
 293                                                         fvalue = va_arg(args, long double);
 294                                                 else
 295                                                         fvalue = va_arg(args, double);
 296                                                 break;
 297                                         case 'G':
 298                                                 flags |= DP_F_UP;
 299                                         case 'g':
 300                                                 if (cflags == DP_C_LDOUBLE)
 301                                                         fvalue = va_arg(args, long double);
 302                                                 else
 303                                                         fvalue = va_arg(args, double);
 304                                                 break;
 305                                         case 'c':
 306                                                 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
 307                                                 break;
 308                                         case 's':
 309                                                 strvalue = va_arg(args, char *);
 310                                                 if (max < 0) 
 311                                                         max = maxlen; /* ie, no max */
 312                                                 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
 313                                                 break;
 314                                         case 'p':
 315                                                 strvalue = va_arg(args, void *);
 316                                                 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
 317                                                 break;
 318                                         case 'n':
 319                                                 if (cflags == DP_C_SHORT) {
 320                                                         short int *num;
 321                                                         num = va_arg(args, short int *);
 322                                                         *num = currlen;
 323                                                 } else if (cflags == DP_C_LONG) {
 324                                                         long int *num;
 325                                                         num = va_arg(args, long int *);
 326                                                         *num = currlen;
 327                                                 } else if (cflags == DP_C_LONG_LONG) {
 328                                                         long long *num;
 329                                                         num = va_arg(args, long long *);
 330                                                         *num = currlen;
 331                                                 } else {
 332                                                         int *num;
 333                                                         num = va_arg(args, int *);
 334                                                         *num = currlen;
 335                                                 }
 336                                                 break;
 337                                         case '%':
 338                                                 dopr_outch(buffer, &currlen, maxlen, ch);
 339                                                 break;
 340                                         case 'w': /* not supported yet, treat as next char */
 341                                                 ch = *format++;
 342                                                 break;
 343                                         default: /* Unknown, skip */
 344                                         break;
 345                                 }
 346                                 ch = *format++;
 347                                 state = DP_S_DEFAULT;
 348                                 flags = cflags = min = 0;
 349                                 max = -1;
 350                                 break;
 351                         case DP_S_DONE:
 352                                 break;
 353                         default: /* hmm? */
 354                                 break; /* some picky compilers need this */
 355                 }
 356         }
 357         if (currlen < maxlen - 1) 
 358                 buffer[currlen] = '\0';
 359         else 
 360                 buffer[maxlen - 1] = '\0';
 361 }
 362 
 363 static void
 364 fmtstr(char *buffer, size_t *currlen, size_t maxlen,
 365        char *value, int flags, int min, int max)
 366 {
 367         int padlen, strln;     /* amount to pad */
 368         int cnt = 0;
 369   
 370         if (value == 0) 
 371                 value = "<NULL>";
 372 
 373         for (strln = 0; value[strln]; ++strln); /* strlen */
 374         padlen = min - strln;
 375         if (padlen < 0) 
 376                 padlen = 0;
 377         if (flags & DP_F_MINUS) 
 378                 padlen = -padlen; /* Left Justify */
 379 
 380         while ((padlen > 0) && (cnt < max)) {
 381                 dopr_outch(buffer, currlen, maxlen, ' ');
 382                 --padlen;
 383                 ++cnt;
 384         }
 385         while (*value && (cnt < max)) {
 386                 dopr_outch(buffer, currlen, maxlen, *value++);
 387                 ++cnt;
 388         }
 389         while ((padlen < 0) && (cnt < max)) {
 390                 dopr_outch(buffer, currlen, maxlen, ' ');
 391                 ++padlen;
 392                 ++cnt;
 393         }
 394 }
 395 
 396 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
 397 
 398 static void 
 399 fmtint(char *buffer, size_t *currlen, size_t maxlen,
 400        long value, int base, int min, int max, int flags)
 401 {
 402         unsigned long uvalue;
 403         char convert[20];
 404         int signvalue = 0;
 405         int place = 0;
 406         int spadlen = 0; /* amount to space pad */
 407         int zpadlen = 0; /* amount to zero pad */
 408         int caps = 0;
 409   
 410         if (max < 0)
 411                 max = 0;
 412 
 413         uvalue = value;
 414 
 415         if (!(flags & DP_F_UNSIGNED)) {
 416                 if (value < 0) {
 417                         signvalue = '-';
 418                         uvalue = -value;
 419                 } else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
 420                         signvalue = '+';
 421                 else if (flags & DP_F_SPACE)
 422                         signvalue = ' ';
 423         }
 424   
 425         if (flags & DP_F_UP) 
 426                 caps = 1; /* Should characters be upper case? */
 427 
 428         do {
 429                 convert[place++] =
 430                         (caps? "0123456789ABCDEF":"0123456789abcdef")
 431                         [uvalue % (unsigned)base];
 432                 uvalue = (uvalue / (unsigned)base );
 433         } while (uvalue && (place < 20));
 434         if (place == 20) 
 435                 place--;
 436         convert[place] = 0;
 437 
 438         zpadlen = max - place;
 439         spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
 440         if (zpadlen < 0)
 441                 zpadlen = 0;
 442         if (spadlen < 0)
 443                 spadlen = 0;
 444         if (flags & DP_F_ZERO) {
 445                 zpadlen = MAX(zpadlen, spadlen);
 446                 spadlen = 0;
 447         }
 448         if (flags & DP_F_MINUS) 
 449                 spadlen = -spadlen; /* Left Justifty */
 450 
 451 
 452         /* Spaces */
 453         while (spadlen > 0) {
 454                 dopr_outch(buffer, currlen, maxlen, ' ');
 455                 --spadlen;
 456         }
 457 
 458         /* Sign */
 459         if (signvalue) 
 460                 dopr_outch(buffer, currlen, maxlen, signvalue);
 461 
 462         /* Zeros */
 463         if (zpadlen > 0) {
 464                 while (zpadlen > 0) {
 465                         dopr_outch(buffer, currlen, maxlen, '0');
 466                         --zpadlen;
 467                 }
 468         }
 469 
 470         /* Digits */
 471         while (place > 0) 
 472                 dopr_outch(buffer, currlen, maxlen, convert[--place]);
 473   
 474         /* Left Justified spaces */
 475         while (spadlen < 0) {
 476                 dopr_outch (buffer, currlen, maxlen, ' ');
 477                 ++spadlen;
 478         }
 479 }
 480 
 481 static long double 
 482 pow10(int exp)
 483 {
 484         long double result = 1;
 485 
 486         while (exp) {
 487                 result *= 10;
 488                 exp--;
 489         }
 490   
 491         return result;
 492 }
 493 
 494 static long 
 495 round(long double value)
 496 {
 497         long intpart = value;
 498 
 499         value -= intpart;
 500         if (value >= 0.5)
 501                 intpart++;
 502 
 503         return intpart;
 504 }
 505 
 506 static void 
 507 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
 508       int min, int max, int flags)
 509 {
 510         char iconvert[20];
 511         char fconvert[20];
 512         int signvalue = 0;
 513         int iplace = 0;
 514         int fplace = 0;
 515         int padlen = 0; /* amount to pad */
 516         int zpadlen = 0; 
 517         int caps = 0;
 518         long intpart;
 519         long fracpart;
 520         long double ufvalue;
 521   
 522         /* 
 523          * AIX manpage says the default is 0, but Solaris says the default
 524          * is 6, and sprintf on AIX defaults to 6
 525          */
 526         if (max < 0)
 527                 max = 6;
 528 
 529         ufvalue = abs_val(fvalue);
 530 
 531         if (fvalue < 0)
 532                 signvalue = '-';
 533         else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
 534                 signvalue = '+';
 535         else if (flags & DP_F_SPACE)
 536                 signvalue = ' ';
 537 
 538         intpart = ufvalue;
 539 
 540         /* 
 541          * Sorry, we only support 9 digits past the decimal because of our 
 542          * conversion method
 543          */
 544         if (max > 9)
 545                 max = 9;
 546 
 547         /* We "cheat" by converting the fractional part to integer by
 548          * multiplying by a factor of 10
 549          */
 550         fracpart = round((pow10 (max)) * (ufvalue - intpart));
 551 
 552         if (fracpart >= pow10 (max)) {
 553                 intpart++;
 554                 fracpart -= pow10 (max);
 555         }
 556 
 557         /* Convert integer part */
 558         do {
 559                 iconvert[iplace++] =
 560                   (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
 561                 intpart = (intpart / 10);
 562         } while(intpart && (iplace < 20));
 563         if (iplace == 20) 
 564                 iplace--;
 565         iconvert[iplace] = 0;
 566 
 567         /* Convert fractional part */
 568         do {
 569                 fconvert[fplace++] =
 570                   (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
 571                 fracpart = (fracpart / 10);
 572         } while(fracpart && (fplace < 20));
 573         if (fplace == 20) 
 574                 fplace--;
 575         fconvert[fplace] = 0;
 576 
 577         /* -1 for decimal point, another -1 if we are printing a sign */
 578         padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
 579         zpadlen = max - fplace;
 580         if (zpadlen < 0)
 581                 zpadlen = 0;
 582         if (padlen < 0) 
 583                 padlen = 0;
 584         if (flags & DP_F_MINUS) 
 585                 padlen = -padlen; /* Left Justifty */
 586 
 587         if ((flags & DP_F_ZERO) && (padlen > 0)) {
 588                 if (signvalue) {
 589                         dopr_outch(buffer, currlen, maxlen, signvalue);
 590                         --padlen;
 591                         signvalue = 0;
 592                 }
 593                 while (padlen > 0) {
 594                         dopr_outch(buffer, currlen, maxlen, '0');
 595                         --padlen;
 596                 }
 597         }
 598         while (padlen > 0) {
 599                 dopr_outch(buffer, currlen, maxlen, ' ');
 600                 --padlen;
 601         }
 602         if (signvalue) 
 603                 dopr_outch(buffer, currlen, maxlen, signvalue);
 604 
 605         while (iplace > 0) 
 606                 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
 607 
 608         /*
 609          * Decimal point.  This should probably use locale to find the correct
 610          * char to print out.
 611          */
 612         dopr_outch(buffer, currlen, maxlen, '.');
 613 
 614         while (fplace > 0) 
 615                 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
 616 
 617         while (zpadlen > 0) {
 618                 dopr_outch(buffer, currlen, maxlen, '0');
 619                 --zpadlen;
 620         }
 621 
 622         while (padlen < 0) {
 623                 dopr_outch(buffer, currlen, maxlen, ' ');
 624                 ++padlen;
 625         }
 626 }
 627 
 628 static void 
 629 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
 630 {
 631         if (*currlen < maxlen)
 632                 buffer[(*currlen)++] = c;
 633 }
 634 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
 635 
 636 #ifndef HAVE_VSNPRINTF
 637 int 
 638 vsnprintf(char *str, size_t count, const char *fmt, va_list args)
 639 {
 640         str[0] = 0;
 641         dopr(str, count, fmt, args);
 642 
 643         return(strlen(str));
 644 }
 645 #endif /* !HAVE_VSNPRINTF */
 646 
 647 #ifndef HAVE_SNPRINTF
 648 int 
 649 snprintf(char *str,size_t count,const char *fmt,...)
 650 {
 651         va_list ap;
 652 
 653         va_start(ap, fmt);
 654         (void) vsnprintf(str, count, fmt, ap);
 655         va_end(ap);
 656 
 657         return(strlen(str));
 658 }
 659 
 660 #ifdef TEST_SNPRINTF
 661 int 
 662 main(void)
 663 {
 664 #define LONG_STRING 1024
 665         char buf1[LONG_STRING];
 666         char buf2[LONG_STRING];
 667         char *fp_fmt[] = {
 668                 "%-1.5f",
 669                 "%1.5f",
 670                 "%123.9f",
 671                 "%10.5f",
 672                 "% 10.5f",
 673                 "%+22.9f",
 674                 "%+4.9f",
 675                 "%01.3f",
 676                 "%4f",
 677                 "%3.1f",
 678                 "%3.2f",
 679                 NULL
 680         };
 681         double fp_nums[] = { 
 682                 -1.5, 
 683                 134.21, 
 684                 91340.2, 
 685                 341.1234, 
 686                 0203.9, 
 687                 0.96, 
 688                 0.996, 
 689                 0.9996, 
 690                 1.996, 
 691                 4.136, 
 692                 0
 693         };
 694         char *int_fmt[] = {
 695                 "%-1.5d",
 696                 "%1.5d",
 697                 "%123.9d",
 698                 "%5.5d",
 699                 "%10.5d",
 700                 "% 10.5d",
 701                 "%+22.33d",
 702                 "%01.3d",
 703                 "%4d",
 704                 "%lld",
 705                 "%qd",
 706                 NULL
 707         };
 708         long long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 9999999 };
 709         int x, y;
 710         int fail = 0;
 711         int num = 0;
 712 
 713         printf("Testing snprintf format codes against system sprintf...\n");
 714 
 715         for (x = 0; fp_fmt[x] != NULL ; x++) {
 716                 for (y = 0; fp_nums[y] != 0 ; y++) {
 717                         snprintf(buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
 718                         sprintf (buf2, fp_fmt[x], fp_nums[y]);
 719                         if (strcmp (buf1, buf2)) {
 720                                 printf("snprintf doesn't match Format: %s\n\t"
 721                                        "snprintf = %s\n\tsprintf  = %s\n", 
 722                                         fp_fmt[x], buf1, buf2);
 723                                 fail++;
 724                         }
 725                         num++;
 726                 }
 727         }
 728         for (x = 0; int_fmt[x] != NULL ; x++) {
 729                 for (y = 0; int_nums[y] != 0 ; y++) {
 730                         snprintf(buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
 731                         sprintf(buf2, int_fmt[x], int_nums[y]);
 732                         if (strcmp (buf1, buf2)) {
 733                                 printf("snprintf doesn't match Format: %s\n\t"
 734                                        "snprintf = %s\n\tsprintf  = %s\n", 
 735                                         int_fmt[x], buf1, buf2);
 736                                 fail++;
 737                         }
 738                         num++;
 739                 }
 740         }
 741         printf("%d tests failed out of %d.\n", fail, num);
 742         return(0);
 743 }
 744 #endif /* SNPRINTF_TEST */
 745 
 746 #endif /* !HAVE_SNPRINTF */