1 /**************************************************************************
2 * Copyright 1994-2000 Patrick Powell, San Diego, CA <papowell@astart.com>
4 * Modified for Netatalk 2002/02/12 Burkhard Schmidt <bs@cpfs.mpg.de>
5 **************************************************************************/
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
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.
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,
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.
34 This version of snprintf is VERY limited by modern standards.
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.
43 COPYRIGHT AND TERMS OF USE:
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
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
57 The next include line is expected to work in conjunction with the
58 GNU CONFIGURE utility. You should define the following macros
61 HAVE_STDARG_H - if the <stdargs.h> include file is available
62 HAVE_VARARG_H - if the <varargs.h> include file is available
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
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
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:
81 AC_CHECK_FUNCS(strerror);
82 AC_CACHE_CHECK(for errno,
85 AC_TRY_LINK(,[extern int errno; return (errno);],
86 ac_cv_errno=yes, ac_cv_errno=no)
88 if test "$ac_cv_errno" = yes; then
90 AC_CACHE_CHECK(for errno declaration,
103 ],[return(sys_nerr);],
104 ac_cv_decl_errno=yes, ac_cv_decl_errno=no)
106 if test "$ac_cv_decl_errno" = yes; then
107 AC_DEFINE(HAVE_DECL_ERRNO)
111 AC_CACHE_CHECK(for sys_nerr,
114 AC_TRY_LINK(,[extern int sys_nerr; return (sys_nerr);],
115 ac_cv_sys_nerr=yes, ac_cv_sys_nerr=no)
117 if test "$ac_cv_sys_nerr" = yes; then
118 AC_DEFINE(HAVE_SYS_NERR)
119 AC_CACHE_CHECK(for sys_nerr declaration,
129 #endif],[return(sys_nerr);],
130 ac_cv_decl_sys_nerr_def=yes, ac_cv_decl_sys_nerr_def=no)
132 if test "$ac_cv_decl_sys_nerr" = yes; then
133 AC_DEFINE(HAVE_DECL_SYS_NERR)
138 AC_CACHE_CHECK(for sys_errlist array,
140 [AC_TRY_LINK(,[extern char *sys_errlist[];
142 ac_cv_sys_errlist=yes, ac_cv_sys_errlist=no)
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,
156 #endif],[char *s = sys_errlist[0]; return(*s);],
157 ac_cv_decl_sys_errlist=yes, ac_cv_decl_sys_errlist=no)
159 if test "$ac_cv_decl_sys_errlist" = yes; then
160 AC_DEFINE(HAVE_DECL_SYS_ERRLIST)
166 AC_CACHE_CHECK(checking for long long,
171 #include <sys/types.h>
172 ], [printf("%d",sizeof(long long));],
173 ac_cv_long_long=yes, ac_cv_long_long=no)
175 if test $ac_cv_long_long = yes; then
176 AC_DEFINE(HAVE_LONG_LONG)
179 AC_CACHE_CHECK(checking for long double,
184 #include <sys/types.h>
185 ], [printf("%d",sizeof(long double));],
186 ac_cv_long_double=yes, ac_cv_long_double=no)
188 if test $ac_cv_long_double = yes; then
189 AC_DEFINE(HAVE_LONG_DOUBLE)
192 AC_CACHE_CHECK(checking for quad_t,
197 #include <sys/types.h>
198 ], [printf("%d",sizeof(quad_t));],
199 ac_cv_quad_t=yes, ac_cv_quad_t=no)
201 if test $ac_cv_quad_t = yes; then
202 AC_DEFINE(HAVE_QUAD_T)
208 plp_snprintf, plp_vsnprintf - formatted output conversion
215 plp_snprintf(const char *format, size_t size, va_list ap);
217 plp_unsafe_snprintf(const char *format, size_t size, va_list ap);
219 AKA snprintf and unsafe_snprintf in the documentation below
222 vsnprintf(char *str, size_t size, const char *format, va_list ap);
224 unsafe_vsnprintf(char *str, size_t size, const char *format, va_list ap);
226 AKA vsnprintf and unsafe_vsnprintf in the documentation below
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
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.
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.
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
270 o Zero or more of the following flags:
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.
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
285 - A space, specifying that a blank should be left before
286 a positive number produced by a signed conversion (d, e, E, f,
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.
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
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.
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.
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.
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
331 o The character L specifying that a following e, E, f, g,
332 or G conversion corresponds to a long double
335 o A character that specifies the type of conversion to be applied.
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.
344 The conversion specifiers and their meanings are:
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.
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.
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.
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
383 c The int argument is converted to an unsigned char,
384 and the resulting character is written.
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.
396 % A `%' is written. No argument is converted. The complete
397 conversion specification is `%%'.
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.
404 To print a date and time in the form `Sunday, July 3, 10:02', where
405 weekday and month are pointers to strings:
408 fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",
409 weekday, month, day, hour, min);
411 To print pi to five decimal places:
415 fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));
417 To allocate a 128 byte string and print into it:
422 char *newfmt(const char *fmt, ...)
426 if ((p = malloc(128)) == NULL)
429 (void) vsnprintf(p, 128, fmt, ap);
438 Turkey C Standardization and wimpy POSIX folks did not define
439 snprintf or vsnprintf().
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.
449 The typedef names quad_t and u_quad_t are infelicitous.
456 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
458 #include <sys/types.h>
461 #if defined(HAVE_STRING_H)
464 #if defined(HAVE_STRINGS_H)
465 # include <strings.h>
470 * For testing, define these values
473 #define HAVE_STDARG_H 1
475 #define HAVE_QUAD_T 1
478 /**** ENDINCLUDE ****/
480 /*************************************************
481 * KEEP THIS STRING - MODIFY AT THE END WITH YOUR REVISIONS
482 * i.e. - the LOCAL REVISIONS part is for your use
483 *************************************************/
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";
490 /* varargs declarations: */
492 # undef HAVE_STDARGS /* let's hope that works everywhere (mj) */
493 # undef VA_LOCAL_DECL
498 #if defined(HAVE_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)
506 # if defined(HAVE_VARARGS_H)
507 # include <varargs.h>
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)
514 XX ** NO VARARGS ** XX
519 #if defined(HAVE_QUAD_T)
522 #if defined(HAVE_LONG_LONG)
531 #define CVAL(s) (*((unsigned char *)s))
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 );
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 );
553 int plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
557 if( count < 0 ) count = 0;
559 if( count == 0 ) str = 0;
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 ){
571 return(count - left);
574 int plp_unsafe_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
578 if( count < 0 ) count = 0;
580 if( count == 0 ) str = 0;
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 ){
592 return(count - left);
597 int plp_snprintf (char *str,size_t count,const char *fmt,...)
599 int plp_snprintf (va_alist) va_dcl
611 VA_SHIFT (str, char *);
612 VA_SHIFT (count, size_t );
613 VA_SHIFT (fmt, char *);
614 n = plp_vsnprintf ( str, count, fmt, ap);
622 int plp_unsafe_snprintf (char *str,size_t count,const char *fmt,...)
624 int plp_unsafe_snprintf (va_alist) va_dcl
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);
643 static void dopr( int visible_control, char **buffer, int *left, const char *format, va_list args )
660 while( (ch = *format++) ){
663 longflag = quadflag =
664 ljust = len = zpad = base = signed_val = 0;
665 precision = -1; set_precision = 0;
670 dostr( buffer, left, "**end of format**" );
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':
681 precision = precision*10 + ch - '0';
683 len = len*10 + ch - '0';
686 case 'l': ++longflag; goto nextch;
688 #if !defined( HAVE_QUAD_T )
689 dostr( buffer, left, "*no quad_t support *");
695 if( base == 0 ){ base = 10; signed_val = 0; }
697 if( base == 0 ){ base = 8; signed_val = 0; }
699 if( base == 0 ){ base = 10; signed_val = 1; }
701 if( base == 0 ){ base = 16; signed_val = 0; }
703 if( base == 0 ){ base = -16; signed_val = 0; }
704 #if defined( HAVE_QUAD_T )
706 value.qvalue = va_arg( args, quad_t );
707 fmtquad( buffer, left, &value,base,signed_val, ljust, len, zpad, precision );
712 #if defined(HAVE_LONG_LONG)
714 value.value = va_arg( args, long long );
716 value.value = va_arg( args, unsigned long long );
720 value.value = va_arg( args, long );
722 value.value = va_arg( args, unsigned long );
725 } else if( longflag ){
727 value.value = va_arg( args, long );
729 value.value = va_arg( args, unsigned long );
733 value.value = va_arg( args, int );
735 value.value = va_arg( args, unsigned int );
738 fmtnum( buffer, left, &value,base,signed_val, ljust, len, zpad, precision ); break;
740 strvalue = va_arg( args, char *);
741 fmtstr( visible_control, buffer, left, strvalue,ljust,len, zpad, precision );
744 ch = va_arg( args, int );
748 fmtstr( 0, buffer, left, b,ljust,len, zpad, precision );
751 case 'f': case 'g': case 'e':
752 dval = va_arg( args, double );
753 fmtdouble( buffer, left, ch, dval,ljust,len, zpad, precision ); break;
755 { char shortbuffer[32];
756 fmtstr( visible_control, buffer, left,
757 plp_Errormsg(err, shortbuffer),ljust,len, zpad, precision );
760 case '%': dopr_outch( buffer, left, ch ); continue;
762 dostr( buffer, left, "???????" );
767 dopr_outch( buffer, left, ch );
774 * Format '%[-]len[.precision]s'
775 * - = left justify (ljust)
776 * len = minimum length
777 * precision = numbers of chars in string to use
780 fmtstr( int visible_control, char **buffer, int *left,
781 char *value, int ljust, int len, int zpad, int precision )
783 int padlen, strlenv, i, c; /* amount to pad */
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' ){
795 if( precision > 0 && strlenv > precision ){
798 padlen = len - strlenv;
799 if( padlen < 0 ) padlen = 0;
800 if( ljust ) padlen = -padlen;
801 while( padlen > 0 ) {
802 dopr_outch( buffer, left, ' ' );
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));
811 dopr_outch(buffer, left, c);
813 while( padlen < 0 ) {
814 dopr_outch( buffer, left, ' ' );
820 fmtnum( char **buffer, int *left,
821 union value *value, int base, int dosign, int ljust,
822 int len, int zpad, int precision )
825 #if defined(HAVE_LONG_LONG)
826 unsigned long long uvalue;
828 unsigned long uvalue;
830 char convert[sizeof( union value) * 8 + 16];
832 int padlen = 0; /* amount to pad */
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;
839 if( value->value < 0 ) {
841 uvalue = -value->value;
850 (caps? "0123456789ABCDEF":"0123456789abcdef")
851 [uvalue % (unsigned)base ];
852 uvalue = (uvalue / (unsigned)base );
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 ){
862 dopr_outch( buffer, left, signvalue );
867 dopr_outch( buffer, left, zpad );
871 while( padlen > 0 ) {
872 dopr_outch( buffer, left, ' ' );
875 if( signvalue ) dopr_outch( buffer, left, signvalue );
876 while( place > 0 ) dopr_outch( buffer, left, convert[--place] );
878 dopr_outch( buffer, left, ' ' );
883 #if defined(HAVE_QUAD_T)
886 fmtquad( char **buffer, int *left,
887 union value *value, int base, int dosign, int ljust,
888 int len, int zpad, int precision )
892 int padlen = 0; /* amount to pad */
897 unsigned char qconvert[sizeof(quad_t)];
899 char convert[2*sizeof(quad_t)+1];
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;
909 for( i = 0; i < sizeof(quad_t); ++i ){
910 c = vvalue.qconvert[i];
912 (caps? "0123456789ABCDEF":"0123456789abcdef")[ (c >> 4) & 0xF];
914 (caps? "0123456789ABCDEF":"0123456789abcdef")[ c & 0xF];
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 ){
926 dopr_outch( buffer, left, signvalue );
931 dopr_outch( buffer, left, zpad );
935 while( padlen > 0 ) {
936 dopr_outch( buffer, left, ' ' );
939 if( signvalue ) dopr_outch( buffer, left, signvalue );
940 while( place > 0 ) dopr_outch( buffer, left, convert[--place] );
942 dopr_outch( buffer, left, ' ' );
949 static void mystrcat(char *dest, char *src )
952 dest += strlen(dest);
958 fmtdouble( char **buffer, int *left,
959 int fmt, double value, int ljust, int len, int zpad, int precision )
961 char convert[sizeof( union value) * 8 + 16];
964 /* fprintf(stderr,"len %d, precision %d\n", len, precision ); */
965 if( len > (sizeof(convert) - 20) ){
966 len = sizeof(convert) - 20;
968 if( precision >= 0 && precision > sizeof(convert) - 20 ){
969 precision = sizeof(convert) - 20;
971 if( precision >= 0 && precision > len ) precision = len;
972 strcpy( formatstr, "%" );
973 if( ljust ) mystrcat(formatstr, "-" );
974 if( zpad ) mystrcat(formatstr, "0" );
976 sprintf( formatstr+strlen(formatstr), "%d", len );
978 if( precision >= 0 ){
979 sprintf( formatstr+strlen(formatstr), ".%d", precision );
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 );
988 static void dostr( char **buffer, int *left, char *str )
990 if(str)while(*str) dopr_outch( buffer, left, *str++ );
993 static void dopr_outch( char **buffer, int *left, int c )
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 /****************************************************************************/
1011 #if !defined(HAVE_STRERROR)
1013 # if defined(HAVE_SYS_ERRLIST)
1014 # if !defined(HAVE_DECL_SYS_ERRLIST)
1015 extern const char *const sys_errlist[];
1017 # if defined(HAVE_SYS_NERR)
1018 # if !defined(HAVE_DECL_SYS_NERR)
1019 extern int sys_nerr;
1021 # define num_errors (sys_nerr)
1024 # if !defined(num_errors)
1025 # define num_errors (-1) /* always use "errno=%d" */
1029 static char * plp_Errormsg ( int err, char *buffer /* int maxlen = 32 */)
1033 #if defined(HAVE_STRERROR)
1034 cp = (void *)strerror(err);
1036 # if defined(HAVE_SYS_ERRLIST)
1037 if (err >= 0 && err < num_errors) {
1038 cp = (void *)sys_errlist[err];
1042 (void) sprintf (buffer, "errno=%d", err);
1055 char *test1 = "01234";
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 );
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 );
1096 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
1098 #ifndef HAVE_VSNPRINTF
1099 int vsnprintf(char *str, size_t count, const char *fmt, va_list args)
1103 n = plp_vsnprintf(str, count, fmt, args);
1107 #endif /* ! HAVE_VSNPRINTF */
1109 #ifndef HAVE_SNPRINTF
1111 int snprintf (char *str,size_t count,const char *fmt,...)
1113 int snprintf (va_alist) va_dcl
1116 #ifndef HAVE_STDARGS
1125 VA_SHIFT (str, char *);
1126 VA_SHIFT (count, size_t );
1127 VA_SHIFT (fmt, char *);
1128 n = plp_vsnprintf ( str, count, fmt, ap);
1132 #endif /* ! HAVE_VNSPRINTF */