bsd-snprintf.c revision 98937
194334Sgshapiro/************************************************************** 290792Sgshapiro * Original: 390792Sgshapiro * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 490792Sgshapiro * A bombproof version of doprnt (dopr) included. 590792Sgshapiro * Sigh. This sort of thing is always nasty do deal with. Note that 690792Sgshapiro * the version here does not include floating point... 790792Sgshapiro * 894334Sgshapiro * snprintf() is used instead of sprintf() as it does limit checks 990792Sgshapiro * for string length. This covers a nasty loophole. 1090792Sgshapiro * 1190792Sgshapiro * The other functions are there to prevent NULL pointers from 1290792Sgshapiro * causing nast effects. 1390792Sgshapiro * 1490792Sgshapiro * More Recently: 1590792Sgshapiro * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 1690792Sgshapiro * This was ugly. It is still ugly. I opted out of floating point 1790792Sgshapiro * numbers, but the formatter understands just about everything 1890792Sgshapiro * from the normal C string format, at least as far as I can tell from 1990792Sgshapiro * the Solaris 2.5 printf(3S) man page. 2090792Sgshapiro * 2190792Sgshapiro * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 2290792Sgshapiro * Ok, added some minimal floating point support, which means this 2390792Sgshapiro * probably requires libm on most operating systems. Don't yet 2490792Sgshapiro * support the exponent (e,E) and sigfig (g,G). Also, fmtint() 2590792Sgshapiro * was pretty badly broken, it just wasn't being exercised in ways 2690792Sgshapiro * which showed it, so that's been fixed. Also, formated the code 2790792Sgshapiro * to mutt conventions, and removed dead code left over from the 2890792Sgshapiro * original. Also, there is now a builtin-test, just compile with: 2990792Sgshapiro * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm 3090792Sgshapiro * and run snprintf for results. 3190792Sgshapiro * 3290792Sgshapiro * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i 3390792Sgshapiro * The PGP code was using unsigned hexadecimal formats. 3490792Sgshapiro * Unfortunately, unsigned formats simply didn't work. 3590792Sgshapiro * 3690792Sgshapiro * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 3790792Sgshapiro * The original code assumed that both snprintf() and vsnprintf() were 3890792Sgshapiro * missing. Some systems only have snprintf() but not vsnprintf(), so 3990792Sgshapiro * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 4090792Sgshapiro * 4190792Sgshapiro * Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH 4290792Sgshapiro * Welcome to the world of %lld and %qd support. With other 4390792Sgshapiro * long long support. This is needed for sftp-server to work 4490792Sgshapiro * right. 4590792Sgshapiro * 4690792Sgshapiro * Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH 4790792Sgshapiro * Removed all hint of VARARGS stuff and banished it to the void, 4890792Sgshapiro * and did a bit of KNF style work to make things a bit more 4990792Sgshapiro * acceptable. Consider stealing from mutt or enlightenment. 5090792Sgshapiro **************************************************************/ 5190792Sgshapiro 5290792Sgshapiro#include "includes.h" 5390792Sgshapiro 5490792SgshapiroRCSID("$Id: bsd-snprintf.c,v 1.5 2001/02/25 23:20:41 mouring Exp $"); 5590792Sgshapiro 5690792Sgshapiro#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ 5790792Sgshapiro# undef HAVE_SNPRINTF 5890792Sgshapiro# undef HAVE_VSNPRINTF 5990792Sgshapiro#endif 6090792Sgshapiro 6190792Sgshapiro#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) 6290792Sgshapiro 6390792Sgshapirostatic void 6490792Sgshapirodopr(char *buffer, size_t maxlen, const char *format, va_list args); 6590792Sgshapiro 6690792Sgshapirostatic void 6790792Sgshapirofmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 6890792Sgshapiro int min, int max); 6990792Sgshapiro 7090792Sgshapirostatic void 7190792Sgshapirofmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 7290792Sgshapiro int min, int max, int flags); 7390792Sgshapiro 7490792Sgshapirostatic void 7590792Sgshapirofmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 7690792Sgshapiro int min, int max, int flags); 7790792Sgshapiro 7890792Sgshapirostatic void 7990792Sgshapirodopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 8090792Sgshapiro 8190792Sgshapiro/* 8290792Sgshapiro * dopr(): poor man's version of doprintf 8390792Sgshapiro */ 8490792Sgshapiro 8590792Sgshapiro/* format read states */ 8690792Sgshapiro#define DP_S_DEFAULT 0 8790792Sgshapiro#define DP_S_FLAGS 1 8890792Sgshapiro#define DP_S_MIN 2 8990792Sgshapiro#define DP_S_DOT 3 9090792Sgshapiro#define DP_S_MAX 4 9190792Sgshapiro#define DP_S_MOD 5 9290792Sgshapiro#define DP_S_CONV 6 9390792Sgshapiro#define DP_S_DONE 7 9490792Sgshapiro 9590792Sgshapiro/* format flags - Bits */ 9690792Sgshapiro#define DP_F_MINUS (1 << 0) 9790792Sgshapiro#define DP_F_PLUS (1 << 1) 9890792Sgshapiro#define DP_F_SPACE (1 << 2) 9990792Sgshapiro#define DP_F_NUM (1 << 3) 10090792Sgshapiro#define DP_F_ZERO (1 << 4) 10190792Sgshapiro#define DP_F_UP (1 << 5) 10290792Sgshapiro#define DP_F_UNSIGNED (1 << 6) 10390792Sgshapiro 10490792Sgshapiro/* Conversion Flags */ 10590792Sgshapiro#define DP_C_SHORT 1 10690792Sgshapiro#define DP_C_LONG 2 10790792Sgshapiro#define DP_C_LDOUBLE 3 10890792Sgshapiro#define DP_C_LONG_LONG 4 10990792Sgshapiro 11090792Sgshapiro#define char_to_int(p) (p - '0') 11190792Sgshapiro#define abs_val(p) (p < 0 ? -p : p) 11290792Sgshapiro 11390792Sgshapiro 11490792Sgshapirostatic void 11590792Sgshapirodopr(char *buffer, size_t maxlen, const char *format, va_list args) 11690792Sgshapiro{ 11790792Sgshapiro char *strvalue; 11890792Sgshapiro char ch; 11990792Sgshapiro long value; 12090792Sgshapiro long double fvalue; 12190792Sgshapiro int min = 0; 12290792Sgshapiro int max = -1; 12390792Sgshapiro int state = DP_S_DEFAULT; 12490792Sgshapiro int flags = 0; 12590792Sgshapiro int cflags = 0; 12690792Sgshapiro size_t currlen = 0; 12790792Sgshapiro 12890792Sgshapiro ch = *format++; 12990792Sgshapiro 13090792Sgshapiro while (state != DP_S_DONE) { 13190792Sgshapiro if ((ch == '\0') || (currlen >= maxlen)) 13290792Sgshapiro state = DP_S_DONE; 13390792Sgshapiro 13490792Sgshapiro switch(state) { 13590792Sgshapiro case DP_S_DEFAULT: 13690792Sgshapiro if (ch == '%') 13790792Sgshapiro state = DP_S_FLAGS; 13890792Sgshapiro else 13990792Sgshapiro dopr_outch(buffer, &currlen, maxlen, ch); 14090792Sgshapiro ch = *format++; 14190792Sgshapiro break; 14290792Sgshapiro case DP_S_FLAGS: 14390792Sgshapiro switch (ch) { 14494334Sgshapiro case '-': 14594334Sgshapiro flags |= DP_F_MINUS; 14694334Sgshapiro ch = *format++; 14794334Sgshapiro break; 14894334Sgshapiro case '+': 14994334Sgshapiro flags |= DP_F_PLUS; 15090792Sgshapiro ch = *format++; 15190792Sgshapiro break; 15290792Sgshapiro case ' ': 15390792Sgshapiro flags |= DP_F_SPACE; 15490792Sgshapiro ch = *format++; 15590792Sgshapiro break; 15690792Sgshapiro case '#': 15790792Sgshapiro flags |= DP_F_NUM; 15890792Sgshapiro ch = *format++; 15990792Sgshapiro break; 16090792Sgshapiro case '0': 16190792Sgshapiro flags |= DP_F_ZERO; 16290792Sgshapiro ch = *format++; 16390792Sgshapiro break; 16490792Sgshapiro default: 16590792Sgshapiro state = DP_S_MIN; 16690792Sgshapiro break; 16790792Sgshapiro } 16890792Sgshapiro break; 16990792Sgshapiro case DP_S_MIN: 17090792Sgshapiro if (isdigit((unsigned char)ch)) { 17190792Sgshapiro min = 10*min + char_to_int (ch); 17290792Sgshapiro ch = *format++; 17390792Sgshapiro } else if (ch == '*') { 17490792Sgshapiro min = va_arg (args, int); 17590792Sgshapiro ch = *format++; 17690792Sgshapiro state = DP_S_DOT; 17790792Sgshapiro } else 17890792Sgshapiro state = DP_S_DOT; 17990792Sgshapiro break; 18090792Sgshapiro case DP_S_DOT: 18190792Sgshapiro if (ch == '.') { 18290792Sgshapiro state = DP_S_MAX; 18390792Sgshapiro ch = *format++; 18490792Sgshapiro } else 18590792Sgshapiro state = DP_S_MOD; 18690792Sgshapiro break; 18790792Sgshapiro case DP_S_MAX: 18890792Sgshapiro if (isdigit((unsigned char)ch)) { 18990792Sgshapiro if (max < 0) 19090792Sgshapiro max = 0; 19190792Sgshapiro max = 10*max + char_to_int(ch); 19290792Sgshapiro ch = *format++; 19390792Sgshapiro } else if (ch == '*') { 19490792Sgshapiro max = va_arg (args, int); 19590792Sgshapiro ch = *format++; 19690792Sgshapiro state = DP_S_MOD; 19790792Sgshapiro } else 19890792Sgshapiro state = DP_S_MOD; 19990792Sgshapiro break; 20090792Sgshapiro case DP_S_MOD: 20190792Sgshapiro switch (ch) { 20290792Sgshapiro case 'h': 20390792Sgshapiro cflags = DP_C_SHORT; 20490792Sgshapiro ch = *format++; 20590792Sgshapiro break; 20690792Sgshapiro case 'l': 20790792Sgshapiro cflags = DP_C_LONG; 20890792Sgshapiro ch = *format++; 20990792Sgshapiro if (ch == 'l') { 21090792Sgshapiro cflags = DP_C_LONG_LONG; 21190792Sgshapiro ch = *format++; 21290792Sgshapiro } 21390792Sgshapiro break; 21490792Sgshapiro case 'q': 21590792Sgshapiro cflags = DP_C_LONG_LONG; 21690792Sgshapiro ch = *format++; 21790792Sgshapiro break; 21890792Sgshapiro case 'L': 21990792Sgshapiro cflags = DP_C_LDOUBLE; 22090792Sgshapiro ch = *format++; 22190792Sgshapiro break; 22290792Sgshapiro default: 22390792Sgshapiro break; 22490792Sgshapiro } 22590792Sgshapiro state = DP_S_CONV; 22690792Sgshapiro break; 22790792Sgshapiro case DP_S_CONV: 22890792Sgshapiro switch (ch) { 22990792Sgshapiro case 'd': 23090792Sgshapiro case 'i': 23190792Sgshapiro if (cflags == DP_C_SHORT) 232 value = va_arg(args, int); 233 else if (cflags == DP_C_LONG) 234 value = va_arg(args, long int); 235 else if (cflags == DP_C_LONG_LONG) 236 value = va_arg (args, long long); 237 else 238 value = va_arg (args, int); 239 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); 240 break; 241 case 'o': 242 flags |= DP_F_UNSIGNED; 243 if (cflags == DP_C_SHORT) 244 value = va_arg(args, unsigned int); 245 else if (cflags == DP_C_LONG) 246 value = va_arg(args, unsigned long int); 247 else if (cflags == DP_C_LONG_LONG) 248 value = va_arg(args, unsigned long long); 249 else 250 value = va_arg(args, unsigned int); 251 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); 252 break; 253 case 'u': 254 flags |= DP_F_UNSIGNED; 255 if (cflags == DP_C_SHORT) 256 value = va_arg(args, unsigned int); 257 else if (cflags == DP_C_LONG) 258 value = va_arg(args, unsigned long int); 259 else if (cflags == DP_C_LONG_LONG) 260 value = va_arg(args, unsigned long long); 261 else 262 value = va_arg(args, unsigned int); 263 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 264 break; 265 case 'X': 266 flags |= DP_F_UP; 267 case 'x': 268 flags |= DP_F_UNSIGNED; 269 if (cflags == DP_C_SHORT) 270 value = va_arg(args, unsigned int); 271 else if (cflags == DP_C_LONG) 272 value = va_arg(args, unsigned long int); 273 else if (cflags == DP_C_LONG_LONG) 274 value = va_arg(args, unsigned long long); 275 else 276 value = va_arg(args, unsigned int); 277 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); 278 break; 279 case 'f': 280 if (cflags == DP_C_LDOUBLE) 281 fvalue = va_arg(args, long double); 282 else 283 fvalue = va_arg(args, double); 284 /* um, floating point? */ 285 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); 286 break; 287 case 'E': 288 flags |= DP_F_UP; 289 case 'e': 290 if (cflags == DP_C_LDOUBLE) 291 fvalue = va_arg(args, long double); 292 else 293 fvalue = va_arg(args, double); 294 break; 295 case 'G': 296 flags |= DP_F_UP; 297 case 'g': 298 if (cflags == DP_C_LDOUBLE) 299 fvalue = va_arg(args, long double); 300 else 301 fvalue = va_arg(args, double); 302 break; 303 case 'c': 304 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); 305 break; 306 case 's': 307 strvalue = va_arg(args, char *); 308 if (max < 0) 309 max = maxlen; /* ie, no max */ 310 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); 311 break; 312 case 'p': 313 strvalue = va_arg(args, void *); 314 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 315 break; 316 case 'n': 317 if (cflags == DP_C_SHORT) { 318 short int *num; 319 num = va_arg(args, short int *); 320 *num = currlen; 321 } else if (cflags == DP_C_LONG) { 322 long int *num; 323 num = va_arg(args, long int *); 324 *num = currlen; 325 } else if (cflags == DP_C_LONG_LONG) { 326 long long *num; 327 num = va_arg(args, long long *); 328 *num = currlen; 329 } else { 330 int *num; 331 num = va_arg(args, int *); 332 *num = currlen; 333 } 334 break; 335 case '%': 336 dopr_outch(buffer, &currlen, maxlen, ch); 337 break; 338 case 'w': /* not supported yet, treat as next char */ 339 ch = *format++; 340 break; 341 default: /* Unknown, skip */ 342 break; 343 } 344 ch = *format++; 345 state = DP_S_DEFAULT; 346 flags = cflags = min = 0; 347 max = -1; 348 break; 349 case DP_S_DONE: 350 break; 351 default: /* hmm? */ 352 break; /* some picky compilers need this */ 353 } 354 } 355 if (currlen < maxlen - 1) 356 buffer[currlen] = '\0'; 357 else 358 buffer[maxlen - 1] = '\0'; 359} 360 361static void 362fmtstr(char *buffer, size_t *currlen, size_t maxlen, 363 char *value, int flags, int min, int max) 364{ 365 int padlen, strln; /* amount to pad */ 366 int cnt = 0; 367 368 if (value == 0) 369 value = "<NULL>"; 370 371 for (strln = 0; value[strln]; ++strln); /* strlen */ 372 padlen = min - strln; 373 if (padlen < 0) 374 padlen = 0; 375 if (flags & DP_F_MINUS) 376 padlen = -padlen; /* Left Justify */ 377 378 while ((padlen > 0) && (cnt < max)) { 379 dopr_outch(buffer, currlen, maxlen, ' '); 380 --padlen; 381 ++cnt; 382 } 383 while (*value && (cnt < max)) { 384 dopr_outch(buffer, currlen, maxlen, *value++); 385 ++cnt; 386 } 387 while ((padlen < 0) && (cnt < max)) { 388 dopr_outch(buffer, currlen, maxlen, ' '); 389 ++padlen; 390 ++cnt; 391 } 392} 393 394/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 395 396static void 397fmtint(char *buffer, size_t *currlen, size_t maxlen, 398 long value, int base, int min, int max, int flags) 399{ 400 unsigned long uvalue; 401 char convert[20]; 402 int signvalue = 0; 403 int place = 0; 404 int spadlen = 0; /* amount to space pad */ 405 int zpadlen = 0; /* amount to zero pad */ 406 int caps = 0; 407 408 if (max < 0) 409 max = 0; 410 411 uvalue = value; 412 413 if (!(flags & DP_F_UNSIGNED)) { 414 if (value < 0) { 415 signvalue = '-'; 416 uvalue = -value; 417 } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 418 signvalue = '+'; 419 else if (flags & DP_F_SPACE) 420 signvalue = ' '; 421 } 422 423 if (flags & DP_F_UP) 424 caps = 1; /* Should characters be upper case? */ 425 426 do { 427 convert[place++] = 428 (caps? "0123456789ABCDEF":"0123456789abcdef") 429 [uvalue % (unsigned)base]; 430 uvalue = (uvalue / (unsigned)base ); 431 } while (uvalue && (place < 20)); 432 if (place == 20) 433 place--; 434 convert[place] = 0; 435 436 zpadlen = max - place; 437 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 438 if (zpadlen < 0) 439 zpadlen = 0; 440 if (spadlen < 0) 441 spadlen = 0; 442 if (flags & DP_F_ZERO) { 443 zpadlen = MAX(zpadlen, spadlen); 444 spadlen = 0; 445 } 446 if (flags & DP_F_MINUS) 447 spadlen = -spadlen; /* Left Justifty */ 448 449 450 /* Spaces */ 451 while (spadlen > 0) { 452 dopr_outch(buffer, currlen, maxlen, ' '); 453 --spadlen; 454 } 455 456 /* Sign */ 457 if (signvalue) 458 dopr_outch(buffer, currlen, maxlen, signvalue); 459 460 /* Zeros */ 461 if (zpadlen > 0) { 462 while (zpadlen > 0) { 463 dopr_outch(buffer, currlen, maxlen, '0'); 464 --zpadlen; 465 } 466 } 467 468 /* Digits */ 469 while (place > 0) 470 dopr_outch(buffer, currlen, maxlen, convert[--place]); 471 472 /* Left Justified spaces */ 473 while (spadlen < 0) { 474 dopr_outch (buffer, currlen, maxlen, ' '); 475 ++spadlen; 476 } 477} 478 479static long double 480pow10(int exp) 481{ 482 long double result = 1; 483 484 while (exp) { 485 result *= 10; 486 exp--; 487 } 488 489 return result; 490} 491 492static long 493round(long double value) 494{ 495 long intpart = value; 496 497 value -= intpart; 498 if (value >= 0.5) 499 intpart++; 500 501 return intpart; 502} 503 504static void 505fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 506 int min, int max, int flags) 507{ 508 char iconvert[20]; 509 char fconvert[20]; 510 int signvalue = 0; 511 int iplace = 0; 512 int fplace = 0; 513 int padlen = 0; /* amount to pad */ 514 int zpadlen = 0; 515 int caps = 0; 516 long intpart; 517 long fracpart; 518 long double ufvalue; 519 520 /* 521 * AIX manpage says the default is 0, but Solaris says the default 522 * is 6, and sprintf on AIX defaults to 6 523 */ 524 if (max < 0) 525 max = 6; 526 527 ufvalue = abs_val(fvalue); 528 529 if (fvalue < 0) 530 signvalue = '-'; 531 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 532 signvalue = '+'; 533 else if (flags & DP_F_SPACE) 534 signvalue = ' '; 535 536 intpart = ufvalue; 537 538 /* 539 * Sorry, we only support 9 digits past the decimal because of our 540 * conversion method 541 */ 542 if (max > 9) 543 max = 9; 544 545 /* We "cheat" by converting the fractional part to integer by 546 * multiplying by a factor of 10 547 */ 548 fracpart = round((pow10 (max)) * (ufvalue - intpart)); 549 550 if (fracpart >= pow10 (max)) { 551 intpart++; 552 fracpart -= pow10 (max); 553 } 554 555 /* Convert integer part */ 556 do { 557 iconvert[iplace++] = 558 (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; 559 intpart = (intpart / 10); 560 } while(intpart && (iplace < 20)); 561 if (iplace == 20) 562 iplace--; 563 iconvert[iplace] = 0; 564 565 /* Convert fractional part */ 566 do { 567 fconvert[fplace++] = 568 (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; 569 fracpart = (fracpart / 10); 570 } while(fracpart && (fplace < 20)); 571 if (fplace == 20) 572 fplace--; 573 fconvert[fplace] = 0; 574 575 /* -1 for decimal point, another -1 if we are printing a sign */ 576 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 577 zpadlen = max - fplace; 578 if (zpadlen < 0) 579 zpadlen = 0; 580 if (padlen < 0) 581 padlen = 0; 582 if (flags & DP_F_MINUS) 583 padlen = -padlen; /* Left Justifty */ 584 585 if ((flags & DP_F_ZERO) && (padlen > 0)) { 586 if (signvalue) { 587 dopr_outch(buffer, currlen, maxlen, signvalue); 588 --padlen; 589 signvalue = 0; 590 } 591 while (padlen > 0) { 592 dopr_outch(buffer, currlen, maxlen, '0'); 593 --padlen; 594 } 595 } 596 while (padlen > 0) { 597 dopr_outch(buffer, currlen, maxlen, ' '); 598 --padlen; 599 } 600 if (signvalue) 601 dopr_outch(buffer, currlen, maxlen, signvalue); 602 603 while (iplace > 0) 604 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); 605 606 /* 607 * Decimal point. This should probably use locale to find the correct 608 * char to print out. 609 */ 610 dopr_outch(buffer, currlen, maxlen, '.'); 611 612 while (fplace > 0) 613 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); 614 615 while (zpadlen > 0) { 616 dopr_outch(buffer, currlen, maxlen, '0'); 617 --zpadlen; 618 } 619 620 while (padlen < 0) { 621 dopr_outch(buffer, currlen, maxlen, ' '); 622 ++padlen; 623 } 624} 625 626static void 627dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) 628{ 629 if (*currlen < maxlen) 630 buffer[(*currlen)++] = c; 631} 632#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ 633 634#ifndef HAVE_VSNPRINTF 635int 636vsnprintf(char *str, size_t count, const char *fmt, va_list args) 637{ 638 str[0] = 0; 639 dopr(str, count, fmt, args); 640 641 return(strlen(str)); 642} 643#endif /* !HAVE_VSNPRINTF */ 644 645#ifndef HAVE_SNPRINTF 646int 647snprintf(char *str,size_t count,const char *fmt,...) 648{ 649 va_list ap; 650 651 va_start(ap, fmt); 652 (void) vsnprintf(str, count, fmt, ap); 653 va_end(ap); 654 655 return(strlen(str)); 656} 657 658#ifdef TEST_SNPRINTF 659int 660main(void) 661{ 662#define LONG_STRING 1024 663 char buf1[LONG_STRING]; 664 char buf2[LONG_STRING]; 665 char *fp_fmt[] = { 666 "%-1.5f", 667 "%1.5f", 668 "%123.9f", 669 "%10.5f", 670 "% 10.5f", 671 "%+22.9f", 672 "%+4.9f", 673 "%01.3f", 674 "%4f", 675 "%3.1f", 676 "%3.2f", 677 NULL 678 }; 679 double fp_nums[] = { 680 -1.5, 681 134.21, 682 91340.2, 683 341.1234, 684 0203.9, 685 0.96, 686 0.996, 687 0.9996, 688 1.996, 689 4.136, 690 0 691 }; 692 char *int_fmt[] = { 693 "%-1.5d", 694 "%1.5d", 695 "%123.9d", 696 "%5.5d", 697 "%10.5d", 698 "% 10.5d", 699 "%+22.33d", 700 "%01.3d", 701 "%4d", 702 "%lld", 703 "%qd", 704 NULL 705 }; 706 long long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 9999999 }; 707 int x, y; 708 int fail = 0; 709 int num = 0; 710 711 printf("Testing snprintf format codes against system sprintf...\n"); 712 713 for (x = 0; fp_fmt[x] != NULL ; x++) { 714 for (y = 0; fp_nums[y] != 0 ; y++) { 715 snprintf(buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]); 716 sprintf (buf2, fp_fmt[x], fp_nums[y]); 717 if (strcmp (buf1, buf2)) { 718 printf("snprintf doesn't match Format: %s\n\t" 719 "snprintf = %s\n\tsprintf = %s\n", 720 fp_fmt[x], buf1, buf2); 721 fail++; 722 } 723 num++; 724 } 725 } 726 for (x = 0; int_fmt[x] != NULL ; x++) { 727 for (y = 0; int_nums[y] != 0 ; y++) { 728 snprintf(buf1, sizeof (buf1), int_fmt[x], int_nums[y]); 729 sprintf(buf2, int_fmt[x], int_nums[y]); 730 if (strcmp (buf1, buf2)) { 731 printf("snprintf doesn't match Format: %s\n\t" 732 "snprintf = %s\n\tsprintf = %s\n", 733 int_fmt[x], buf1, buf2); 734 fail++; 735 } 736 num++; 737 } 738 } 739 printf("%d tests failed out of %d.\n", fail, num); 740 return(0); 741} 742#endif /* SNPRINTF_TEST */ 743 744#endif /* !HAVE_SNPRINTF */ 745