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