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