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