1 #include "../include/sane/config.h" 2 3 #ifndef HAVE_SNPRINTF 4 5 /************************************************************************** 6 * Copyright 1994-2003 Patrick Powell, San Diego, CA <papowell@lprng.com> 7 **************************************************************************/ 8 9 /* 10 Overview: 11 12 snprintf( char *buffer, int len, const char *format,...) 13 plp_unsafe_snprintf( char *buffer, int len, const char *format,...) 14 its horribly unsafe companion that does NOT protect you from 15 the printing of evil control characters, but may be necessary 16 See the man page documentation below 17 18 This version of snprintf was developed originally for printing 19 on a motley collection of specialized hardware that had NO IO 20 library. Due to contractual restrictions, a clean room implementation 21 of the printf() code had to be developed. 22 23 The method chosen for printf was to be as paranoid as possible, 24 as these platforms had NO memory protection, and very small 25 address spaces. This made it possible to try to print 26 very long strings, i.e. - all of memory, very easily. To guard 27 against this, all printing was done via a buffer, generous enough 28 to hold strings, but small enough to protect against overruns, 29 etc. 30 31 Strangely enough, this proved to be of immense importance when 32 SPRINTFing to a buffer on a stack... The rest, of course, is 33 well known, as buffer overruns in the stack are a common way to 34 do horrible things to operating systems, security, etc etc. 35 36 This version of snprintf is VERY limited by modern standards. 37 38 Revision History: 39 First Released Version - 1994. This version had NO comments. 40 First Released Version - 1994. This version had NO comments. 41 Second Major Released Version - Tue May 23 10:43:44 PDT 2000 42 Configuration and other items changed. Read this doc. 43 Treat this as a new version. 44 Minor Revision - Mon Apr 1 09:41:28 PST 2002 45 - fixed up some constants and casts 46 47 COPYRIGHT AND TERMS OF USE: 48 49 You may use, copy, distribute, or otherwise incorporate this software 50 and documentation into any product or other item, provided that 51 the copyright in the documentation and source code as well as the 52 source code generated constant strings in the object, executable 53 or other code remain in place and are present in executable modules 54 or objects. 55 56 You may modify this code as appropriate to your usage; however the 57 modified version must be identified by changing the various source 58 and object code identification strings as is appropriately noted 59 in the source code. 60 61 You can use this with the GNU CONFIGURE utility. 62 This should define the following macros appropriately: 63 64 HAVE_STDARG_H - if the <stdargs.h> include file is available 65 HAVE_VARARG_H - if the <varargs.h> include file is available 66 67 HAVE_STRERROR - if the strerror() routine is available. 68 If it is not available, then examine the lines containing 69 the tests below. 70 71 HAVE_SYS_ERRLIST - have sys_errlist available 72 HAVE_DECL_SYS_ERRLIST - sys_errlist declaration in include files 73 HAVE_SYS_NERR - have sys_nerr available 74 HAVE_DECL_SYS_NERR - sys_nerr declaration in include files 75 76 HAVE_QUAD_T - if the quad_t type is defined 77 HAVE_LONG_LONG - if the long long type is defined 78 HAVE_LONG_DOUBLE - if the long double type is defined 79 80 If you are using the GNU configure (autoconf) facility, add the 81 following line to the configure.in file, to force checking for the 82 quad_t and long long data types: 83 84 85 AC_CHECK_HEADERS(stdlib.h,stdio.h,unistd.h,errno.h) 86 AC_CHECK_FUNCS(strerror) 87 AC_CACHE_CHECK(for errno, 88 ac_cv_errno, 89 [ 90 AC_TRY_LINK(,[extern int errno; return (errno);], 91 ac_cv_errno=yes, ac_cv_errno=no) 92 ]) 93 if test "$ac_cv_errno" = yes; then 94 AC_DEFINE(HAVE_ERRNO) 95 AC_CACHE_CHECK(for errno declaration, 96 ac_cv_decl_errno, 97 [ 98 AC_TRY_COMPILE([ 99 #include <stdio.h> 100 #ifdef HAVE_STDLIB_H 101 #include <stdlib.h> 102 #endif 103 #ifdef HAVE_UNISTD_H 104 #include <unistd.h> 105 #endif 106 #ifdef HAVE_ERRNO_H 107 #include <errno.h> 108 ],[return(sys_nerr);], 109 ac_cv_decl_errno=yes, ac_cv_decl_errno=no) 110 ]) 111 if test "$ac_cv_decl_errno" = yes; then 112 AC_DEFINE(HAVE_DECL_ERRNO) 113 fi; 114 fi 115 116 AC_CACHE_CHECK(for sys_nerr, 117 ac_cv_sys_nerr, 118 [ 119 AC_TRY_LINK(,[extern int sys_nerr; return (sys_nerr);], 120 ac_cv_sys_nerr=yes, ac_cv_sys_nerr=no) 121 ]) 122 if test "$ac_cv_sys_nerr" = yes; then 123 AC_DEFINE(HAVE_SYS_NERR) 124 AC_CACHE_CHECK(for sys_nerr declaration, 125 ac_cv_decl_sys_nerr, 126 [ 127 AC_TRY_COMPILE([ 128 #include <stdio.h> 129 #ifdef HAVE_STDLIB_H 130 #include <stdlib.h> 131 #endif 132 #ifdef HAVE_UNISTD_H 133 #include <unistd.h> 134 #endif],[return(sys_nerr);], 135 ac_cv_decl_sys_nerr_def=yes, ac_cv_decl_sys_nerr_def=no) 136 ]) 137 if test "$ac_cv_decl_sys_nerr" = yes; then 138 AC_DEFINE(HAVE_DECL_SYS_NERR) 139 fi 140 fi 141 142 143 AC_CACHE_CHECK(for sys_errlist array, 144 ac_cv_sys_errlist, 145 [AC_TRY_LINK(,[extern char *sys_errlist[]; 146 sys_errlist[0];], 147 ac_cv_sys_errlist=yes, ac_cv_sys_errlist=no) 148 ]) 149 if test "$ac_cv_sys_errlist" = yes; then 150 AC_DEFINE(HAVE_SYS_ERRLIST) 151 AC_CACHE_CHECK(for sys_errlist declaration, 152 ac_cv_sys_errlist_def, 153 [AC_TRY_COMPILE([ 154 #include <stdio.h> 155 #include <errno.h> 156 #ifdef HAVE_STDLIB_H 157 #include <stdlib.h> 158 #endif 159 #ifdef HAVE_UNISTD_H 160 #include <unistd.h> 161 #endif],[char *s = sys_errlist[0]; return(*s);], 162 ac_cv_decl_sys_errlist=yes, ac_cv_decl_sys_errlist=no) 163 ]) 164 if test "$ac_cv_decl_sys_errlist" = yes; then 165 AC_DEFINE(HAVE_DECL_SYS_ERRLIST) 166 fi 167 fi 168 169 170 171 AC_CACHE_CHECK(checking for long long, 172 ac_cv_long_long, 173 [ 174 AC_TRY_COMPILE([ 175 #include <stdio.h> 176 #include <sys/types.h> 177 ], [printf("%d",sizeof(long long));], 178 ac_cv_long_long=yes, ac_cv_long_long=no) 179 ]) 180 if test $ac_cv_long_long = yes; then 181 AC_DEFINE(HAVE_LONG_LONG) 182 fi 183 184 AC_CACHE_CHECK(checking for long double, 185 ac_cv_long_double, 186 [ 187 AC_TRY_COMPILE([ 188 #include <stdio.h> 189 #include <sys/types.h> 190 ], [printf("%d",sizeof(long double));], 191 ac_cv_long_double=yes, ac_cv_long_double=no) 192 ]) 193 if test $ac_cv_long_double = yes; then 194 AC_DEFINE(HAVE_LONG_DOUBLE) 195 fi 196 197 AC_CACHE_CHECK(checking for quad_t, 198 ac_cv_quad_t, 199 [ 200 AC_TRY_COMPILE([ 201 #include <stdio.h> 202 #include <sys/types.h> 203 ], [printf("%d",sizeof(quad_t));], 204 ac_cv_quad_t=yes, ac_cv_quad_t=no) 205 ]) 206 if test $ac_cv_quad_t = yes; then 207 AC_DEFINE(HAVE_QUAD_T) 208 fi 209 210 211 212 NAME 213 snprintf, plp_vsnprintf - formatted output conversion 214 215 SYNOPSIS 216 #include <stdio.h> 217 #include <stdarg.h> 218 219 int 220 snprintf(const char *format, size_t size, va_list ap); 221 int 222 plp_unsafe_snprintf(const char *format, size_t size, va_list ap); 223 224 AKA snprintf and unsafe_snprintf in the documentation below 225 226 int 227 vsnprintf(char *str, size_t size, const char *format, va_list ap); 228 int 229 unsafe_vsnprintf(char *str, size_t size, const char *format, va_list ap); 230 231 AKA vsnprintf and unsafe_vsnprintf in the documentation below 232 233 (Multithreaded Safe) 234 235 DESCRIPTION 236 The printf() family of functions produces output according to 237 a format as described below. Snprintf(), and vsnprintf() 238 write to the character string str. These functions write the 239 output under the control of a format string that specifies 240 how subsequent arguments (or arguments accessed via the 241 variable-length argument facilities of stdarg(3)) are converted 242 for output. These functions return the number of characters 243 printed (not including the trailing `\0' used to end output 244 to strings). Snprintf() and vsnprintf() will write at most 245 size-1 of the characters printed into the output string (the 246 size'th character then gets the terminating `\0'); if the 247 return value is greater than or equal to the size argument, 248 the string was too short and some of the printed characters 249 were discarded. The size or str may be given as zero to find 250 out how many characters are needed; in this case, the str 251 argument is ignored. 252 253 By default, the snprintf function will not format control 254 characters (except new line and tab) in strings. This is a 255 safety feature that has proven to be extremely critical when 256 using snprintf for secure applications and when debugging. 257 If you MUST have control characters formatted or printed, 258 then use the unsafe_snprintf() and unsafe_vsnprintf() and on 259 your own head be the consequences. You have been warned. 260 261 There is one exception to the comments above, and that is 262 the "%c" (character) format. It brutally assumes that the 263 user will have performed the necessary 'isprint()' or other 264 checks and uses the integer value as a character. 265 266 The format string is composed of zero or more directives: 267 ordinary characters (not %), which are copied unchanged to 268 the output stream; and conversion specifications, each 269 of which results in fetching zero or more subsequent arguments. 270 Each conversion specification is introduced by the character 271 %. The arguments must correspond properly (after type promotion) 272 with the conversion specifier. After the %, the following 273 appear in sequence: 274 275 o Zero or more of the following flags: 276 277 - A zero `0' character specifying zero padding. For 278 all conversions except n, the converted value is padded 279 on the left with zeros rather than blanks. If a 280 precision is given with a numeric conversion (d, i, 281 o, u, i, x, and X), the `0' flag is ignored. 282 283 - A negative field width flag `-' indicates the converted 284 value is to be left adjusted on the field boundary. Except 285 for n conversions, the converted value is padded on 286 the right with blanks, rather than on the left with 287 blanks or zeros. A `-' overrides a `0' if both are 288 given. 289 290 - A space, specifying that a blank should be left before 291 a positive number produced by a signed conversion (d, e, E, f, 292 g, G, or i). 293 294 - A `+' character specifying that a sign always be placed 295 before a number produced by a signed conversion. A `+' overrides 296 a space if both are used. 297 298 o An optional decimal digit string specifying a minimum 299 field width. If the converted value has fewer 300 characters than the field width, it will be padded 301 with spaces on the left (or right, if the 302 left-adjustment flag has been given) to fill out 303 the field width. 304 305 o An optional precision, in the form of a period `.' followed 306 by an optional digit string. If the digit string 307 is omitted, the precision is taken as zero. This 308 gives the minimum number of digits to appear for 309 d, i, o, u, x, and X conversions, the number of 310 digits to appear after the decimal-point for e, 311 E, and f conversions, the maximum number of 312 significant digits for g and G conversions, or 313 the maximum number of characters to be printed 314 from a string for s conversions. 315 316 o The optional character h, specifying that a following d, 317 i, o, u, x, or X conversion corresponds to a short 318 int or unsigned short int argument, or that a 319 following n conversion corresponds to a pointer 320 to a short int argument. 321 322 o The optional character l (ell) specifying that a following 323 d, i, o, u, x, or X conversion applies to a pointer 324 to a long int or unsigned long int argument, or 325 that a following n conversion corresponds to a 326 pointer to a long int argument. 327 328 o The optional character q, specifying that a following d, 329 i, o, u, x, or X conversion corresponds to a quad_t 330 or u_quad_t argument, or that a following n 331 conversion corresponds to a quad_t argument. 332 This value is always printed in HEX notation. Tough. 333 quad_t's are an OS system implementation, and should 334 not be allowed. 335 336 o The character L specifying that a following e, E, f, g, 337 or G conversion corresponds to a long double 338 argument. 339 340 o A character that specifies the type of conversion to be applied. 341 342 343 A field width or precision, or both, may be indicated by an asterisk `*' 344 instead of a digit string. In this case, an int argument supplies the 345 field width or precision. A negative field width is treated as a left 346 adjustment flag followed by a positive field width; a negative precision 347 is treated as though it were missing. 348 349 The conversion specifiers and their meanings are: 350 351 diouxX The int (or appropriate variant) argument is converted to signed 352 decimal (d and i), unsigned octal (o), unsigned decimal 353 (u), or unsigned hexadecimal (x and X) notation. The 354 letters abcdef are used for x conversions; the letters 355 ABCDEF are used for X conversions. The precision, if 356 any, gives the minimum number of digits that must 357 appear; if the converted value requires fewer digits, 358 it is padded on the left with zeros. 359 360 eE The double argument is rounded and converted in the style 361 [-]d.ddde+-dd where there is one digit before the decimal-point 362 character and the number of digits after it is equal 363 to the precision; if the precision is missing, it is 364 taken as 6; if the precision is zero, no decimal-point 365 character appears. An E conversion uses the letter 366 E (rather than e) to introduce the exponent. 367 The exponent always contains at least two digits; if 368 the value is zero, the exponent is 00. 369 370 f The double argument is rounded and converted to decimal notation 371 in the style [-]ddd.ddd, where the number of digits after the 372 decimal-point character is equal to the precision specification. 373 If the precision is missing, it is taken as 6; if the precision 374 is explicitly zero, no decimal-point character appears. If a 375 decimal point appears, at least one digit appears before it. 376 377 g The double argument is converted in style f or e (or 378 E for G conversions). The precision specifies the 379 number of significant digits. If the precision is 380 missing, 6 digits are given; if the precision is zero, 381 it is treated as 1. Style e is used if the exponent 382 from its conversion is less than -4 or greater than 383 or equal to the precision. Trailing zeros are removed 384 from the fractional part of the result; a decimal 385 point appears only if it is followed by at least one 386 digit. 387 388 c The int argument is converted to an unsigned char, 389 and the resulting character is written. 390 391 s The ``char *'' argument is expected to be a pointer to an array 392 of character type (pointer to a string). Characters 393 from the array are written up to (but not including) 394 a terminating NUL character; if a precision is 395 specified, no more than the number specified are 396 written. If a precision is given, no null character 397 need be present; if the precision is not specified, 398 or is greater than the size of the array, the array 399 must contain a terminating NUL character. 400 401 % A `%' is written. No argument is converted. The complete 402 conversion specification is `%%'. 403 404 In no case does a non-existent or small field width cause truncation of a 405 field; if the result of a conversion is wider than the field width, the 406 field is expanded to contain the conversion result. 407 408 EXAMPLES 409 To print a date and time in the form `Sunday, July 3, 10:02', where 410 weekday and month are pointers to strings: 411 412 #include <stdio.h> 413 fprintf(stdout, "%s, %s %d, %.2d:%.2d\n", 414 weekday, month, day, hour, min); 415 416 To print pi to five decimal places: 417 418 #include <math.h> 419 #include <stdio.h> 420 fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0)); 421 422 To allocate a 128 byte string and print into it: 423 424 #include <stdio.h> 425 #include <stdlib.h> 426 #include <stdarg.h> 427 char *newfmt(const char *fmt, ...) 428 { 429 char *p; 430 va_list ap; 431 if ((p = malloc(128)) == NULL) 432 return (NULL); 433 va_start(ap, fmt); 434 (void) vsnprintf(p, 128, fmt, ap); 435 va_end(ap); 436 return (p); 437 } 438 439 SEE ALSO 440 printf(1), scanf(3) 441 442 STANDARDS 443 Turkey C Standardization and wimpy POSIX folks did not define 444 snprintf or vsnprintf(). 445 446 BUGS 447 The conversion formats %D, %O, and %U are not standard and are provided 448 only for backward compatibility. The effect of padding the %p format 449 with zeros (either by the `0' flag or by specifying a precision), and the 450 benign effect (i.e., none) of the `#' flag on %n and %p conversions, as 451 well as other nonsensical combinations such as %Ld, are not standard; 452 such combinations should be avoided. 453 454 The typedef names quad_t and u_quad_t are infelicitous. 455 456 */ 457 458 459 #include <sys/types.h> 460 #include <ctype.h> 461 #include <stdlib.h> 462 #include <stdio.h> 463 #if defined(HAVE_STRING_H) 464 # include <string.h> 465 #endif 466 #if defined(HAVE_STRINGS_H) 467 # include <strings.h> 468 #endif 469 #if defined(HAVE_ERRNO_H) 470 #include <errno.h> 471 #endif 472 473 /* 474 * For testing, define these values 475 */ 476 #if 0 477 #define HAVE_STDARG_H 1 478 #define TEST 1 479 #define HAVE_QUAD_T 1 480 #endif 481 482 /**** ENDINCLUDE ****/ 483 484 /************************************************* 485 * KEEP THIS STRING - MODIFY AT THE END WITH YOUR REVISIONS 486 * i.e. - the LOCAL REVISIONS part is for your use 487 *************************************************/ 488 489 490 static char *const _id = "plp_snprintf V2000.08.18 Copyright Patrick Powell 1988-2000 " 491 "$Id: plp_snprintf.c,v 1.4 2005/04/14 20:05:19 papowell Exp $" 492 " LOCAL REVISIONS: renamed plp_snprintf to snprintf, conditionalized everything on HAVE_SNPRINTF"; 493 494 /* varargs declarations: */ 495 496 # undef HAVE_STDARGS /* let's hope that works everywhere (mj) */ 497 # undef VA_LOCAL_DECL 498 # undef VA_START 499 # undef VA_SHIFT 500 # undef VA_END 501 502 #if defined(HAVE_STDARG_H) 503 # include <stdarg.h> 504 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */ 505 # define VA_LOCAL_DECL va_list ap; 506 # define VA_START(f) va_start(ap, f) 507 # define VA_SHIFT(v,t) ; /* no-op for ANSI */ 508 # define VA_END va_end(ap) 509 #else 510 # if defined(HAVE_VARARGS_H) 511 # include <varargs.h> 512 # undef HAVE_STDARGS 513 # define VA_LOCAL_DECL va_list ap; 514 # define VA_START(f) va_start(ap) /* f is ignored! */ 515 # define VA_SHIFT(v,t) v = va_arg(ap,t) 516 # define VA_END va_end(ap) 517 # else 518 XX ** NO VARARGS ** XX 519 # endif 520 #endif 521 522 union value { 523 #if defined(HAVE_QUAD_T) 524 quad_t qvalue; 525 #endif 526 #if defined(HAVE_LONG_LONG) 527 long long value; 528 #else 529 long value; 530 #endif 531 double dvalue; 532 }; 533 534 #undef CVAL 535 #define CVAL(s) (*((unsigned char *)s)) 536 #define safestrlen(s) ((s)?strlen(s):0) 537 538 539 static char * plp_Errormsg ( int err, char *buffer ); 540 static void dopr( int visible_control, char **buffer, int *left, 541 const char *format, va_list args ); 542 static void fmtstr( int visible_control, char **buffer, int *left, 543 char *value, int ljust, int len, int zpad, int precision ); 544 static void fmtnum( char **buffer, int *left, 545 union value *value, int base, int dosign, 546 int ljust, int len, int zpad, int precision ); 547 #if defined(HAVE_QUAD_T) 548 static void fmtquad( char **buffer, int *left, 549 union value *value, int base, int dosign, 550 int ljust, int len, int zpad, int precision ); 551 #endif 552 static void fmtdouble( char **buffer, int *left, 553 int fmt, double value, 554 int ljust, int len, int zpad, int precision ); 555 static void dostr( char **buffer, int *left, char *str ); 556 static void dopr_outch( char **buffer, int *left, int c ); 557 /* VARARGS3 */ 558 #ifdef HAVE_STDARGS plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args)559 int plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args) 560 #else 561 int plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args) 562 #endif 563 564 { 565 int left; 566 char *buffer; 567 if( (int)count < 0 ) count = 0; 568 left = count; 569 if( count == 0 ) str = 0; 570 buffer = str; 571 dopr( 1, &buffer, &left, fmt, args ); 572 /* fprintf(stderr,"str 0x%x, buffer 0x%x, count %d, left %d\n", 573 (int)str, (int)buffer, count, left ); */ 574 if( str && count > 0 ){ 575 if( left > 0 ){ 576 str[count-left] = 0; 577 } else { 578 str[count-1] = 0; 579 } 580 } 581 return(count - left); 582 } 583 584 /* VARARGS3 */ 585 #ifdef HAVE_STDARGS plp_unsafe_vsnprintf(char *str, size_t count, const char *fmt, va_list args)586 int plp_unsafe_vsnprintf(char *str, size_t count, const char *fmt, va_list args) 587 #else 588 int plp_unsafe_vsnprintf(char *str, size_t count, const char *fmt, va_list args) 589 #endif 590 { 591 int left; 592 char *buffer; 593 if( (int)count < 0 ) count = 0; 594 left = count; 595 if( count == 0 ) str = 0; 596 buffer = str; 597 dopr( 0, &buffer, &left, fmt, args ); 598 /* fprintf(stderr,"str 0x%x, buffer 0x%x, count %d, left %d\n", 599 (int)str, (int)buffer, count, left ); */ 600 if( str && count > 0 ){ 601 if( left > 0 ){ 602 str[count-left] = 0; 603 } else { 604 str[count-1] = 0; 605 } 606 } 607 return(count - left); 608 } 609 610 /* VARARGS3 */ 611 #ifdef HAVE_STDARGS snprintf(char *str,size_t count,const char *fmt,...)612 int snprintf (char *str,size_t count,const char *fmt,...) 613 #else 614 int snprintf (va_alist) va_dcl 615 #endif 616 { 617 #ifndef HAVE_STDARGS 618 char *str; 619 size_t count; 620 char *fmt; 621 #endif 622 int n = 0; 623 VA_LOCAL_DECL 624 625 VA_START (fmt); 626 VA_SHIFT (str, char *); 627 VA_SHIFT (count, size_t ); 628 VA_SHIFT (fmt, char *); 629 n = plp_vsnprintf ( str, count, fmt, ap); 630 VA_END; 631 return( n ); 632 } 633 634 635 /* VARARGS3 */ 636 #ifdef HAVE_STDARGS plp_unsafe_snprintf(char *str,size_t count,const char *fmt,...)637 int plp_unsafe_snprintf (char *str,size_t count,const char *fmt,...) 638 #else 639 int plp_unsafe_snprintf (va_alist) va_dcl 640 #endif 641 { 642 #ifndef HAVE_STDARGS 643 char *str; 644 size_t count; 645 char *fmt; 646 #endif 647 int n = 0; 648 VA_LOCAL_DECL 649 650 VA_START (fmt); 651 VA_SHIFT (str, char *); 652 VA_SHIFT (count, size_t ); 653 VA_SHIFT (fmt, char *); 654 n = plp_unsafe_vsnprintf ( str, count, fmt, ap); 655 VA_END; 656 return( n ); 657 } dopr( int visible_control, char **buffer, int *left, const char *format, va_list args )658 static void dopr( int visible_control, char **buffer, int *left, const char *format, va_list args ) 659 { 660 int ch; 661 union value value; 662 int longflag = 0; 663 int quadflag = 0; 664 char *strvalue; 665 int ljust; 666 int len; 667 int zpad; 668 int precision; 669 int set_precision; 670 double dval; 671 int err = errno; 672 int base = 0; 673 int signed_val = 0; 674 675 while( (ch = *format++) ){ 676 switch( ch ){ 677 case '%': 678 longflag = quadflag = 679 ljust = len = zpad = base = signed_val = 0; 680 precision = -1; set_precision = 0; 681 nextch: 682 ch = *format++; 683 switch( ch ){ 684 case 0: 685 dostr( buffer, left, "**end of format**" ); 686 return; 687 case '-': ljust = 1; goto nextch; 688 case '.': set_precision = 1; precision = 0; goto nextch; 689 case '*': 690 if( set_precision ){ 691 precision = va_arg( args, int ); 692 } else { 693 len = va_arg( args, int ); 694 } 695 goto nextch; 696 case '0': /* set zero padding if len not set */ 697 if(len==0 && set_precision == 0 ) zpad = '0'; 698 case '1': case '2': case '3': 699 case '4': case '5': case '6': 700 case '7': case '8': case '9': 701 if( set_precision ){ 702 precision = precision*10 + ch - '0'; 703 } else { 704 len = len*10 + ch - '0'; 705 } 706 goto nextch; 707 case 'l': ++longflag; goto nextch; 708 case 'q': 709 #if !defined( HAVE_QUAD_T ) 710 dostr( buffer, left, "*no quad_t support *"); 711 return; 712 #endif 713 quadflag = 1; 714 goto nextch; 715 case 'u': case 'U': 716 if( base == 0 ){ base = 10; signed_val = 0; } 717 case 'o': case 'O': 718 if( base == 0 ){ base = 8; signed_val = 0; } 719 case 'd': case 'D': 720 if( base == 0 ){ base = 10; signed_val = 1; } 721 case 'x': 722 if( base == 0 ){ base = 16; signed_val = 0; } 723 case 'X': 724 if( base == 0 ){ base = -16; signed_val = 0; } 725 #if defined( HAVE_QUAD_T ) 726 if( quadflag ){ 727 value.qvalue = va_arg( args, quad_t ); 728 fmtquad( buffer, left, &value,base,signed_val, ljust, len, zpad, precision ); 729 break; 730 } else 731 #endif 732 if( longflag > 1 ){ 733 #if defined(HAVE_LONG_LONG) 734 if( signed_val ){ 735 value.value = va_arg( args, long long ); 736 } else { 737 value.value = va_arg( args, unsigned long long ); 738 } 739 #else 740 if( signed_val ){ 741 value.value = va_arg( args, long ); 742 } else { 743 value.value = va_arg( args, unsigned long ); 744 } 745 #endif 746 } else if( longflag ){ 747 if( signed_val ){ 748 value.value = va_arg( args, long ); 749 } else { 750 value.value = va_arg( args, unsigned long ); 751 } 752 } else { 753 if( signed_val ){ 754 value.value = va_arg( args, int ); 755 } else { 756 value.value = va_arg( args, unsigned int ); 757 } 758 } 759 fmtnum( buffer, left, &value,base,signed_val, ljust, len, zpad, precision ); break; 760 case 's': 761 strvalue = va_arg( args, char *); 762 fmtstr( visible_control, buffer, left, strvalue,ljust,len, zpad, precision ); 763 break; 764 case 'c': 765 ch = va_arg( args, int ); 766 { char b[2]; 767 b[0] = ch; 768 b[1] = 0; 769 fmtstr( 0, buffer, left, b,ljust,len, zpad, precision ); 770 } 771 break; 772 case 'f': case 'g': case 'e': 773 dval = va_arg( args, double ); 774 fmtdouble( buffer, left, ch, dval,ljust,len, zpad, precision ); break; 775 case 'm': 776 { char shortbuffer[32]; 777 fmtstr( visible_control, buffer, left, 778 plp_Errormsg(err, shortbuffer),ljust,len, zpad, precision ); 779 } 780 break; 781 case '%': dopr_outch( buffer, left, ch ); continue; 782 default: 783 dostr( buffer, left, "???????" ); 784 } 785 longflag = 0; 786 break; 787 default: 788 dopr_outch( buffer, left, ch ); 789 break; 790 } 791 } 792 } 793 794 /* 795 * Format '%[-]len[.precision]s' 796 * - = left justify (ljust) 797 * len = minimum length 798 * precision = numbers of chars in string to use 799 */ 800 static void fmtstr( int visible_control, char **buffer, int *left, char *value, int ljust, int len, int zpad, int precision )801 fmtstr( int visible_control, char **buffer, int *left, 802 char *value, int ljust, int len, int zpad, int precision ) 803 { 804 int padlen, strlenv, i, c; /* amount to pad */ 805 806 if( value == 0 ){ 807 value = "<NULL>"; 808 } 809 /* cheap strlen so you do not have library call */ 810 for( strlenv = i = 0; (c=CVAL(value+i)); ++i ){ 811 if( visible_control && iscntrl( c ) && c != '\t' && c != '\n' ){ 812 ++strlenv; 813 } 814 ++strlenv; 815 } 816 if( precision > 0 && strlenv > precision ){ 817 strlenv = precision; 818 } 819 padlen = len - strlenv; 820 if( padlen < 0 ) padlen = 0; 821 if( ljust ) padlen = -padlen; 822 while( padlen > 0 ) { 823 dopr_outch( buffer, left, ' ' ); 824 --padlen; 825 } 826 /* output characters */ 827 for( i = 0; i < strlenv && (c = CVAL(value+i)); ++i ){ 828 if( visible_control && iscntrl( c ) && c != '\t' && c != '\n' ){ 829 dopr_outch(buffer, left, '^'); 830 c = ('@' | (c & 0x1F)); 831 } 832 dopr_outch(buffer, left, c); 833 } 834 while( padlen < 0 ) { 835 dopr_outch( buffer, left, ' ' ); 836 ++padlen; 837 } 838 } 839 840 static void fmtnum( char **buffer, int *left, union value *value, int base, int dosign, int ljust, int len, int zpad, int precision )841 fmtnum( char **buffer, int *left, 842 union value *value, int base, int dosign, int ljust, 843 int len, int zpad, int precision ) 844 { 845 int signvalue = 0; 846 #if defined(HAVE_LONG_LONG) 847 unsigned long long uvalue; 848 #else 849 unsigned long uvalue; 850 #endif 851 char convert[sizeof( union value) * 8 + 16]; 852 int place = 0; 853 int padlen = 0; /* amount to pad */ 854 int caps = 0; 855 856 /* fprintf(stderr,"value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", 857 value, base, dosign, ljust, len, zpad );/ **/ 858 uvalue = value->value; 859 if( dosign ){ 860 if( value->value < 0 ) { 861 signvalue = '-'; 862 uvalue = -value->value; 863 } 864 } 865 if( base < 0 ){ 866 caps = 1; 867 base = -base; 868 } 869 do{ 870 convert[place++] = 871 (caps? "0123456789ABCDEF":"0123456789abcdef") 872 [uvalue % (unsigned)base ]; 873 uvalue = (uvalue / (unsigned)base ); 874 }while(uvalue); 875 convert[place] = 0; 876 padlen = len - place; 877 if( padlen < 0 ) padlen = 0; 878 if( ljust ) padlen = -padlen; 879 /* fprintf( stderr, "str '%s', place %d, sign %c, padlen %d\n", 880 convert,place,signvalue,padlen); / **/ 881 if( zpad && padlen > 0 ){ 882 if( signvalue ){ 883 dopr_outch( buffer, left, signvalue ); 884 --padlen; 885 signvalue = 0; 886 } 887 while( padlen > 0 ){ 888 dopr_outch( buffer, left, zpad ); 889 --padlen; 890 } 891 } 892 while( padlen > 0 ) { 893 dopr_outch( buffer, left, ' ' ); 894 --padlen; 895 } 896 if( signvalue ) dopr_outch( buffer, left, signvalue ); 897 while( place > 0 ) dopr_outch( buffer, left, convert[--place] ); 898 while( padlen < 0 ){ 899 dopr_outch( buffer, left, ' ' ); 900 ++padlen; 901 } 902 } 903 904 #if defined(HAVE_QUAD_T) 905 906 static void fmtquad( char **buffer, int *left, union value *value, int base, int dosign, int ljust, int len, int zpad, int precision )907 fmtquad( char **buffer, int *left, 908 union value *value, int base, int dosign, int ljust, 909 int len, int zpad, int precision ) 910 { 911 int signvalue = 0; 912 int place = 0; 913 int padlen = 0; /* amount to pad */ 914 int caps = 0; 915 int i, c; 916 union { 917 quad_t qvalue; 918 unsigned char qconvert[sizeof(quad_t)]; 919 } vvalue; 920 char convert[2*sizeof(quad_t)+1]; 921 922 /* fprintf(stderr,"value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", 923 value, base, dosign, ljust, len, zpad );/ **/ 924 vvalue.qvalue = value->qvalue; 925 926 if( base < 0 ){ 927 caps = 1; 928 } 929 930 for( i = 0; i < (int)sizeof(quad_t); ++i ){ 931 c = vvalue.qconvert[i]; 932 convert[2*i] = 933 (caps? "0123456789ABCDEF":"0123456789abcdef")[ (c >> 4) & 0xF]; 934 convert[2*i+1] = 935 (caps? "0123456789ABCDEF":"0123456789abcdef")[ c & 0xF]; 936 } 937 convert[2*i] = 0; 938 939 place = strlen(convert); 940 padlen = len - place; 941 if( padlen < 0 ) padlen = 0; 942 if( ljust ) padlen = -padlen; 943 /* fprintf( stderr, "str '%s', place %d, sign %c, padlen %d\n", 944 convert,place,signvalue,padlen); / **/ 945 if( zpad && padlen > 0 ){ 946 if( signvalue ){ 947 dopr_outch( buffer, left, signvalue ); 948 --padlen; 949 signvalue = 0; 950 } 951 while( padlen > 0 ){ 952 dopr_outch( buffer, left, zpad ); 953 --padlen; 954 } 955 } 956 while( padlen > 0 ) { 957 dopr_outch( buffer, left, ' ' ); 958 --padlen; 959 } 960 if( signvalue ) dopr_outch( buffer, left, signvalue ); 961 while( place > 0 ) dopr_outch( buffer, left, convert[--place] ); 962 while( padlen < 0 ){ 963 dopr_outch( buffer, left, ' ' ); 964 ++padlen; 965 } 966 } 967 968 #endif 969 mystrcat(char *dest, char *src )970 static void mystrcat(char *dest, char *src ) 971 { 972 if( dest && src ){ 973 dest += safestrlen(dest); 974 strcpy(dest,src); 975 } 976 } 977 978 static void fmtdouble( char **buffer, int *left, int fmt, double value, int ljust, int len, int zpad, int precision )979 fmtdouble( char **buffer, int *left, 980 int fmt, double value, int ljust, int len, int zpad, int precision ) 981 { 982 char convert[sizeof( union value) * 8 + 512]; 983 char formatstr[128]; 984 985 /* fprintf(stderr,"len %d, precision %d\n", len, precision ); */ 986 if( len > 255 ){ 987 len = 255; 988 } 989 if( precision > 255 ){ 990 precision = 255; 991 } 992 if( precision >= 0 && len > 0 && precision > len ) precision = len; 993 strcpy( formatstr, "%" ); /* 1 */ 994 if( ljust ) mystrcat(formatstr, "-" ); /* 1 */ 995 if( zpad ) mystrcat(formatstr, "0" ); /* 1 */ 996 if( len >= 0 ){ 997 sprintf( formatstr+strlen(formatstr), "%d", len ); /* 3 */ 998 } 999 if( precision >= 0 ){ 1000 sprintf( formatstr+strlen(formatstr), ".%d", precision ); /* 3 */ 1001 } 1002 /* format string will be at most 10 chars long ... */ 1003 sprintf( formatstr+strlen(formatstr), "%c", fmt ); 1004 /* this is easier than trying to do the portable dtostr */ 1005 /* fprintf(stderr,"format string '%s'\n", formatstr); */ 1006 sprintf( convert, formatstr, value ); 1007 dostr( buffer, left, convert ); 1008 } 1009 dostr( char **buffer, int *left, char *str )1010 static void dostr( char **buffer, int *left, char *str ) 1011 { 1012 if(str)while(*str) dopr_outch( buffer, left, *str++ ); 1013 } 1014 dopr_outch( char **buffer, int *left, int c )1015 static void dopr_outch( char **buffer, int *left, int c ) 1016 { 1017 if( *left > 0 ){ 1018 *(*buffer)++ = c; 1019 } 1020 *left -= 1; 1021 } 1022 1023 1024 /**************************************************************************** 1025 * static char *plp_errormsg( int err ) 1026 * returns a printable form of the 1027 * errormessage corresponding to the valie of err. 1028 * This is the poor man's version of sperror(), not available on all systems 1029 * Patrick Powell Tue Apr 11 08:05:05 PDT 1995 1030 ****************************************************************************/ 1031 /****************************************************************************/ 1032 1033 #if !defined(HAVE_STRERROR) 1034 # undef num_errors 1035 # if defined(HAVE_SYS_ERRLIST) 1036 # if !defined(HAVE_DECL_SYS_ERRLIST) 1037 extern const char *const sys_errlist[]; 1038 # endif 1039 # if defined(HAVE_SYS_NERR) 1040 # if !defined(HAVE_DECL_SYS_NERR) 1041 extern int sys_nerr; 1042 # endif 1043 # define num_errors (sys_nerr) 1044 # endif 1045 # endif 1046 # if !defined(num_errors) 1047 # define num_errors (-1) /* always use "errno=%d" */ 1048 # endif 1049 #endif 1050 plp_Errormsg( int err, char *buffer )1051 static char * plp_Errormsg ( int err, char *buffer /* int maxlen = 32 */) 1052 { 1053 char *cp; 1054 1055 #if defined(HAVE_STRERROR) 1056 cp = (void *)strerror(err); 1057 #else 1058 # if defined(HAVE_SYS_ERRLIST) 1059 if (err >= 0 && err < num_errors) { 1060 cp = (void *)sys_errlist[err]; 1061 } else 1062 # endif 1063 { 1064 (void) sprintf (buffer, "errno=%d", err); 1065 cp = buffer; 1066 } 1067 #endif 1068 return (cp); 1069 } 1070 1071 #if defined(TEST) 1072 #include <stdio.h> main( void )1073 int main( void ) 1074 { 1075 char buffer[128]; 1076 char *t; 1077 char *test1 = "01234"; 1078 int n; 1079 errno = 1; 1080 buffer[0] = 0; 1081 n = snprintf( buffer, 0, (t="test")); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1082 n = snprintf( buffer, sizeof(buffer), (t="errno '%m'")); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1083 n = snprintf( buffer, sizeof(buffer), (t = "%s"), test1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1084 n = snprintf( buffer, sizeof(buffer), (t = "%12s"), test1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1085 n = snprintf( buffer, sizeof(buffer), (t = "%-12s"), test1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1086 n = snprintf( buffer, sizeof(buffer), (t = "%12.2s"), test1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1087 n = snprintf( buffer, sizeof(buffer), (t = "%-12.2s"), test1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1088 n = snprintf( buffer, sizeof(buffer), (t = "%g"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1089 n = snprintf( buffer, sizeof(buffer), (t = "%g"), 1.2345 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1090 n = snprintf( buffer, sizeof(buffer), (t = "%12g"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1091 n = snprintf( buffer, sizeof(buffer), (t = "%12.1g"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1092 n = snprintf( buffer, sizeof(buffer), (t = "%12.2g"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1093 n = snprintf( buffer, sizeof(buffer), (t = "%12.3g"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1094 n = snprintf( buffer, sizeof(buffer), (t = "%0*d"), 6, 1 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1095 #if defined(HAVE_LONG_LONG) 1096 n = snprintf( buffer, sizeof(buffer), (t = "%llx"), 1, 2, 3, 4 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1097 n = snprintf( buffer, sizeof(buffer), (t = "%llx"), (long long)1, (long long)2 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1098 n = snprintf( buffer, sizeof(buffer), (t = "%qx"), 1, 2, 3, 4 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1099 n = snprintf( buffer, sizeof(buffer), (t = "%qx"), (quad_t)1, (quad_t)2 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1100 #endif 1101 n = snprintf( buffer, sizeof(buffer), (t = "0%x, 0%x"), (char *)(0x01234567), (char *)0, 0, 0, 0); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1102 n = snprintf( buffer, sizeof(buffer), (t = "0%x, 0%x"), (char *)(0x01234567), (char *)0x89ABCDEF, 0, 0, 0); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1103 n = snprintf( buffer, sizeof(buffer), (t = "0%x, 0%x"), t, 0, 0, 0, 0); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1104 n = snprintf( buffer, sizeof(buffer), (t = "%f"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1105 n = snprintf( buffer, sizeof(buffer), (t = "%f"), 1.2345 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1106 n = snprintf( buffer, sizeof(buffer), (t = "%12f"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1107 n = snprintf( buffer, sizeof(buffer), (t = "%12.2f"), 1.25 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1108 n = snprintf( buffer, sizeof(buffer), (t = "%f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1109 n = snprintf( buffer, sizeof(buffer), (t = "%.0f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1110 n = snprintf( buffer, sizeof(buffer), (t = "%0.0f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1111 n = snprintf( buffer, sizeof(buffer), (t = "%1.0f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1112 n = snprintf( buffer, sizeof(buffer), (t = "%1.5f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1113 n = snprintf( buffer, sizeof(buffer), (t = "%5.5f"), 1.0 ); printf( "[%d] %s = '%s'\n", n, t, buffer ); 1114 return(0); 1115 } 1116 #endif 1117 1118 1119 #endif /* HAVE_SNPRINTF */ 1120