tin  2.4.5
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.4.5.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

plp_snprintf.c
Go to the documentation of this file.
1 /**************************************************************************
2  * LPRng IFHP Filter
3  * Copyright 1994-1999 Patrick Powell, San Diego, CA <papowell@astart.com>
4  **************************************************************************/
5 
6 /*
7  * Overview:
8  *
9  * This version of snprintf was developed originally for printing
10  * on a motley collection of specialized hardware that had NO IO
11  * library. Due to contractual restrictions, a clean room implementation
12  * of the printf() code had to be developed.
13  *
14  * The method chosen for printf was to be as paranoid as possible,
15  * as these platforms had NO memory protection, and very small
16  * address spaces. This made it possible to try to print
17  * very long strings, i.e. - all of memory, very easily. To guard
18  * against this, all printing was done via a buffer, generous enough
19  * to hold strings, but small enough to protect against overruns,
20  * etc.
21  *
22  * Strangely enough, this proved to be of immense importance when
23  * SPRINTFing to a buffer on a stack... The rest, of course, is
24  * well known, as buffer overruns in the stack are a common way to
25  * do horrible things to operating systems, security, etc etc.
26  *
27  * This version of snprintf is VERY limited by modern standards.
28  *
29  * COPYRIGHT AND TERMS OF USE:
30  *
31  * You may use, copy, distribute, or otherwise incorporate this software
32  * and documentation into any product or other item, provided that
33  * the copyright in the documentation and source code as well as the
34  * source code generated constant strings in the object, executable
35  * or other code remain in place and are present in executable modules
36  * or objects.
37  *
38  * You may modify this code as appropriate to your usage; however the
39  * modified version must be identified by changing the various source
40  * and object code identification strings as is appropriately noted
41  * in the source code.
42  *
43  * The next include line is expected to work in conjunction with the
44  * GNU CONFIGURE utility. You should define the following macros
45  * appropriately:
46  *
47  * HAVE_STDARG_H - if the <stdargs.h> include file is available
48  * HAVE_VARARG_H - if the <varargs.h> include file is available
49  *
50  * HAVE_STRERROR - if the strerror() routine is available.
51  * If it is not available, then examine the lines containing
52  * the tests below. You may need to fiddle with HAVE_SYS_NERR
53  * and HAVE_SYS_NERR_DEF to make compilation work correctly.
54  * HAVE_SYS_NERR
55  * HAVE_SYS_NERR_DEF
56  *
57  * HAVE_QUAD_T - if the quad_t type is defined
58  * HAVE_LONG_LONG - if the long long type is defined
59  *
60  * If you are using the GNU configure (autoconf) facility, add the
61  * following line to the configure.in file, to force checking for the
62  * quad_t and long long data types:
63  *
64  * AC_CHECK_TYPE(quad_t,NONE)
65  *
66  * dnl test to see if long long is defined
67  *
68  * AC_MSG_CHECKING(checking for long long)
69  * AC_TRY_COMPILE([
70  * #include <sys/types.h>
71  * ],[long long x; x = 0],
72  * ac_cv_long_long=yes, ac_cv_long_long=no)
73  * AC_MSG_RESULT($ac_cv_long_long)
74  * if test $ac_cv_long_long = yes; then
75  * AC_DEFINE(HAVE_LONG_LONG)
76  * fi
77  *
78  *
79  * Add the following lines to the acconfig.h in the correct
80  * position.
81  *
82  * / * Define if quad_t is NOT present on the system * /
83  * #undef quad_t
84  *
85  * / * Define if long long is present on the system * /
86  * #undef HAVE_LONG_LONG
87  *
88  * When you run configure, if quad_t is NOT defined, the config.h
89  * file will have in it:
90  * #define quad_t NONE
91  *
92  * If it is defined, the config.h file will have
93  * / * #undef quad_t * /
94  *
95  * If long long is defined, you will have:
96  * #define HAVE_LONG_LONG
97  *
98  * This code is then used in the source code to enable quad quad
99  * and long long support.
100  *
101  */
102 
103 
104 #ifndef TIN_H
105 # include "tin.h"
106 #endif /* !TIN_H */
107 
108 #if !defined(HAVE_SNPRINTF) && !defined(HAVE_VSNPRINTF)
109 
110 # if !defined(PLP_SNPRINTF_H) && !defined(TIN_H)
111 # include "plp_snprintf.h"
112 # endif /* !PLP_SNPRINTF_H && !TIN_H */
113 
114 /*
115  * KEEP THIS STRING - MODIFY AT THE END WITH YOUR REVISIONS
116  * i.e. - the LOCAL REVISIONS part is for your use
117  */
118 
119 static const char *_id = "plp_snprintf V1999.02.20 Copyright Patrick Powell 1988-1999 <papowell@astart.com> \
120 $Id: plp_snprintf.c,v 1.4 1999/02/20 17:44:16 papowell Exp papowell $\
121  LOCAL REVISIONS: tin 1.9.5-01";
122 
123 /* varargs declarations: */
124 
125 #ifdef HAVE_STDARGS
126 # undef HAVE_STDARGS /* let's hope that works everywhere (mj) */
127 #endif /* HAVE_STDARGS */
128 #ifdef VA_LOCAL_DECL
129 # undef VA_LOCAL_DECL
130 #endif /* VA_LOCAL_DECL */
131 #ifdef VA_START
132 # undef VA_START
133 #endif /* VA_START */
134 #ifdef VA_SHIFT
135 # undef VA_SHIFT
136 #endif /* VA_SHIFT */
137 #ifdef VA_END
138 # undef VA_END
139 #endif /* VA_END */
140 
141 #ifdef HAVE_STDARG_H
142 # include <stdarg.h>
143 # define HAVE_STDARGS /* let's hope that works everywhere (mj) */
144 # define VA_LOCAL_DECL va_list ap;
145 # define VA_START(f) va_start(ap, f)
146 # define VA_SHIFT(v,t) ; /* no-op for ANSI */
147 # define VA_END va_end(ap)
148 #else
149 # ifdef HAVE_VARARGS_H
150 # include <varargs.h>
151 # undef HAVE_STDARGS
152 # define VA_LOCAL_DECL va_list ap;
153 # define VA_START(f) va_start(ap) /* f is ignored! */
154 # define VA_SHIFT(v,t) v = va_arg(ap,t)
155 # define VA_END va_end(ap)
156 # else
157 XX ** NO VARARGS ** XX
158 # endif /* HAVE_VARARGS_H */
159 #endif /* HAVE_STDARG_H */
160 
161 #if 0
162 /* the dreaded QUAD_T strikes again... */
163 #ifndef HAVE_QUAD_T
164 # if defined(quad_t) && qaud_t == NONE
165 # define HAVE_QUAD_T 0
166 # else
167 # define HAVE_QUAD_T 1
168 # endif /* quad_t && qaud_t== NONE */
169 #endif /* HAVE_QUAD_T */
170 #endif /* 0 */
171 
172 #if defined(HAVE_QUAD_T) && !defined(HAVE_LONG_LONG)
173  ERROR you need long long
174 #endif
175 #ifdef HAVE_QUAD_T
176  /* suspender and belts on this one */
177  const union { quad_t t; long long v; } x;
178 #endif
179 
180 union value {
181 #if defined(HAVE_QUAD_T) || defined(HAVE_LONG_LONG)
182  long long value;
183 #else
184  long value;
185 #endif
186  double dvalue;
187 };
188 
189 #ifdef cval
190 # undef cval
191 #endif /* cval */
192 #define cval(s) (*((unsigned const char *)s))
193 
194 
195 static char *plp_Errormsg(int err);
196 static void plp_strcat(char *dest, const char *src);
197 static void dopr(char *buffer, const char *format, va_list args);
198 static void fmtstr(const char *value, int ljust, int len, int precision);
199 static void fmtnum(union value *value, int plp_base, int dosign, int ljust, int len, int zpad);
200 static void fmtdouble(int fmt, double value, int ljust, int len, int zpad, int precision);
201 static void dostr(const char *);
202 static void dopr_outch(int c);
203 
204 static char *output;
205 static char *end;
206 
208 
209 
210 int plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
211 {
212  str[0] = 0;
213  end = str+count-1;
214  dopr( str, fmt, args );
215  if( count != 0 )
216  end[0] = 0;
217  return(strlen(str));
218 }
219 
220 /* VARARGS3 */
221 #ifdef HAVE_STDARGS
222 int plp_snprintf(char *str,size_t count,const char *fmt,...)
223 #else
224 int plp_snprintf(va_alist) va_dcl
225 #endif
226 {
227 #ifndef HAVE_STDARGS
228  char *str;
229  size_t count;
230  char *fmt;
231 #endif
232  VA_LOCAL_DECL
233 
234  VA_START (fmt);
235  VA_SHIFT (str, char *);
236  VA_SHIFT (count, size_t );
237  VA_SHIFT (fmt, char *);
238  (void) plp_vsnprintf( str, count, fmt, ap);
239  VA_END;
240  return( strlen( str ) );
241 }
242 
243 static void dopr( char *buffer, const char *format, va_list args )
244 {
245  int ch;
246  union value value;
247  int longflag = 0;
248  int quadflag = 0;
249  char *strvalue;
250  int ljust;
251  int len;
252  int zpad;
253  int precision;
254  int set_precision;
255  double dval;
256  int err = errno;
257  int plp_base = 0;
258  int signed_val = 0;
259 
260  output = buffer;
261  while( (ch = *format++) ){
262  switch( ch ){
263  case '%':
264  longflag = quadflag =
265  ljust = len = zpad = plp_base = signed_val = 0;
266  precision = -1; set_precision = 0;
267  nextch:
268  ch = *format++;
269  switch( ch ){
270  case 0:
271  dostr( "**end of format**" );
272  return;
273  case '-': ljust = 1; goto nextch;
274  case '.': set_precision = 1; precision = 0; goto nextch;
275  case '*':
276  if( set_precision ){
277  precision = va_arg( args, int );
278  } else {
279  len = va_arg( args, int );
280  }
281  goto nextch;
282  case '0': /* set zero padding if len not set */
283  if(len==0 && set_precision == 0 ) zpad = '0';
284  /* FALLTHROUGH */
285  case '1': /* FALLTHROUGH */
286  case '2': /* FALLTHROUGH */
287  case '3': /* FALLTHROUGH */
288  case '4': /* FALLTHROUGH */
289  case '5': /* FALLTHROUGH */
290  case '6': /* FALLTHROUGH */
291  case '7': /* FALLTHROUGH */
292  case '8': /* FALLTHROUGH */
293  case '9':
294  if( set_precision ){
295  precision = precision*10 + ch - '0';
296  } else {
297  len = len*10 + ch - '0';
298  }
299  goto nextch;
300  case 'l': ++longflag; goto nextch;
301  case 'q': quadflag = 1; goto nextch;
302  case 'u': case 'U':
303  if( plp_base == 0 ){ plp_base = 10; signed_val = 0; }
304  /* FALLTHROUGH */
305  case 'o': case 'O':
306  if( plp_base == 0 ){ plp_base = 8; signed_val = 0; }
307  /* FALLTHROUGH */
308  case 'd': case 'D':
309  if( plp_base == 0 ){ plp_base = 10; signed_val = 1; }
310  /* FALLTHROUGH */
311  case 'x':
312  if( plp_base == 0 ){ plp_base = 16; signed_val = 0; }
313  /* FALLTHROUGH */
314  case 'X':
315  if( plp_base == 0 ){ plp_base = -16; signed_val = 0; }
316  if( quadflag || longflag > 1 ){
317 #if defined(HAVE_LONG_LONG)
318  if( signed_val ){
319  value.value = va_arg( args, long long );
320  } else {
321  value.value = va_arg( args, unsigned long long );
322  }
323 #else
324  if( signed_val ){
325  value.value = va_arg( args, long );
326  } else {
327  value.value = va_arg( args, unsigned long );
328  }
329 #endif
330  } else if( longflag ){
331  if( signed_val ){
332  value.value = va_arg( args, long );
333  } else {
334  value.value = va_arg( args, unsigned long );
335  }
336  } else {
337  if( signed_val ){
338  value.value = va_arg( args, int );
339  } else {
340  value.value = va_arg( args, unsigned int );
341  }
342  }
343  fmtnum( &value,plp_base,signed_val, ljust, len, zpad );
344  break;
345  case 's':
346  strvalue = va_arg( args, char *);
347  fmtstr(strvalue, ljust, len, precision);
348  break;
349  case 'c':
350  ch = va_arg( args, int );
351  { char b[2];
352  int vsb = visible_control;
353  b[0] = ch;
354  b[1] = 0;
355  visible_control = 0;
356  fmtstr(b, ljust, len, precision);
357  visible_control = vsb;
358  }
359  break;
360  case 'f': case 'g': case 'e':
361  dval = va_arg( args, double );
362  fmtdouble(ch, dval, ljust, len, zpad, precision);
363  break;
364  case 'm':
365  fmtstr(plp_Errormsg(err), ljust, len, precision);
366  break;
367  case '%': dopr_outch( ch ); continue;
368  default:
369  dostr( "???????" );
370  }
371  longflag = 0;
372  break;
373  default:
374  dopr_outch( ch );
375  break;
376  }
377  }
378  *output = 0;
379 }
380 
381 /*
382  * Format '%[-]len[.precision]s'
383  * - = left justify (ljust)
384  * len = minimum length
385  * precision = numbers of chars in string to use
386  */
387 static void
388 fmtstr(const char *value, int ljust, int len, int precision)
389 {
390  int padlen, slen, i, c; /* amount to pad */
391 
392  if( value == 0 ){
393  value = "<NULL>";
394  }
395  if( precision > 0 ){
396  slen = precision;
397  } else {
398  /* cheap slen so you do not have library call */
399  for( slen = i = 0; (c=cval(value+i)); ++i ){
400  if( visible_control && iscntrl( c ) && !isspace(c) ){
401  ++slen;
402  }
403  ++slen;
404  }
405  }
406  padlen = len - slen;
407  if( padlen < 0 ) padlen = 0;
408  if( ljust ) padlen = -padlen;
409  while( padlen > 0 ) {
410  dopr_outch( ' ' );
411  --padlen;
412  }
413  /* output characters */
414  for( i = 0; (c = cval(value+i)); ++i ){
415  if( visible_control && iscntrl( c ) && !isspace( c ) ){
416  dopr_outch('^');
417  c = ('@' | (c & 0x1F));
418  }
419  dopr_outch(c);
420  }
421  while( padlen < 0 ) {
422  dopr_outch( ' ' );
423  ++padlen;
424  }
425 }
426 
427 static void
428 fmtnum( union value *value, int plp_base, int dosign, int ljust,
429  int len, int zpad )
430 {
431  int signvalue = 0;
432 #ifdef HAVE_LONG_LONG
433  unsigned long long uvalue;
434 #else
435  unsigned long uvalue;
436 #endif /* HAVE_LONG_LONG */
437  char convert[64];
438  int place = 0;
439  int padlen = 0; /* amount to pad */
440  int caps = 0;
441 
442  /* fprintf(stderr,"value 0x%x, plp_base %d, dosign %d, ljust %d, len %d, zpad %d\n",
443  value, plp_base, dosign, ljust, len, zpad );/ **/
444  uvalue = value->value;
445  if( dosign ){
446  if( value->value < 0 ) {
447  signvalue = '-';
448  uvalue = -value->value;
449  }
450  }
451  if( plp_base < 0 ){
452  caps = 1;
453  plp_base = -plp_base;
454  }
455  do{
456  convert[place++] =
457  (caps? "0123456789ABCDEF":"0123456789abcdef")
458  [uvalue % (unsigned)plp_base ];
459  uvalue = (uvalue / (unsigned)plp_base );
460  }while(uvalue);
461  convert[place] = 0;
462  padlen = len - place;
463  if( padlen < 0 ) padlen = 0;
464  if( ljust ) padlen = -padlen;
465  /* fprintf( stderr, "str '%s', place %d, sign %c, padlen %d\n",
466  convert,place,signvalue,padlen); / **/
467  if( zpad && padlen > 0 ){
468  if( signvalue ){
469  dopr_outch( signvalue );
470  --padlen;
471  signvalue = 0;
472  }
473  while( padlen > 0 ){
474  dopr_outch( zpad );
475  --padlen;
476  }
477  }
478  while( padlen > 0 ) {
479  dopr_outch( ' ' );
480  --padlen;
481  }
482  if( signvalue ) dopr_outch( signvalue );
483  while( place > 0 ) dopr_outch( convert[--place] );
484  while( padlen < 0 ){
485  dopr_outch( ' ' );
486  ++padlen;
487  }
488 }
489 
490 static void
491 plp_strcat(char *dest, const char *src )
492 {
493  if( dest && src ){
494  dest += strlen(dest);
495  strcpy(dest,src);
496  }
497 }
498 
499 static void
500 fmtdouble( int fmt, double value, int ljust, int len, int zpad, int precision )
501 {
502  char convert[128];
503  char fmts[128];
504  int l;
505 
506  if( len == 0 )
507  len = 10;
508  if( len > (int) (sizeof(convert) - 20) )
509  len = sizeof(convert) - 20;
510  if( precision > (int) sizeof(convert) - 20 )
511  precision = sizeof(convert) - 20;
512  if( precision > len )
513  precision = len;
514  strcpy( fmts, "%" );
515  if( ljust )
516  plp_strcat(fmts, "-" );
517  if( zpad )
518  plp_strcat(fmts, "0" );
519  if( len )
520  sprintf( fmts+strlen(fmts), "%d", len );
521  if( precision > 0 )
522  sprintf( fmts+strlen(fmts), ".%d", precision );
523  l = strlen( fmts );
524  fmts[l] = fmt;
525  fmts[l+1] = 0;
526  /* this is easier than trying to do the portable dtostr */
527  sprintf( convert, fmts, value );
528  dostr( convert );
529 }
530 
531 static void dostr( const char *str )
532 {
533  while(*str) dopr_outch(*str++);
534 }
535 
536 static void dopr_outch( int c )
537 {
538  if( end == 0 || output < end ){
539  *output++ = c;
540  }
541 }
542 
543 
544 /****************************************************************************
545  * static char *plp_errormsg( int err )
546  * returns a printable form of the
547  * errormessage corresponding to the valie of err.
548  * This is the poor man's version of sperror(), not available on all systems
549  * Patrick Powell Tue Apr 11 08:05:05 PDT 1995
550  ****************************************************************************/
551 /****************************************************************************/
552 #if !defined(HAVE_STRERROR)
553 
554 # if defined(HAVE_SYS_NERR)
555 # if !defined(HAVE_SYS_NERR_DEF)
556  extern int sys_nerr;
557 # endif
558 # define num_errors (sys_nerr)
559 # else
560 # define num_errors (-1) /* always use "errno=%d" */
561 # endif
562 
563 # if defined(HAVE_SYS_ERRLIST)
564 # if !defined(HAVE_SYS_ERRLIST_DEF)
565  extern const char *const sys_errlist[];
566 # endif
567 # else
568 # undef num_errors
569 # define num_errors (-1) /* always use "errno=%d" */
570 # endif
571 
572 #endif
573 
574 static char * plp_Errormsg ( int err )
575 {
576  char *cp;
577 
578 #if defined(HAVE_STRERROR)
579  cp = (void *)strerror(err);
580 #else
581 # if defined(HAVE_SYS_ERRLIST)
582  if (err >= 0 && err < num_errors) {
583  cp = (void *)sys_errlist[err];
584  } else
585 # endif
586  {
587  static char msgbuf[32]; /* holds "errno=%d". */
588  /* SAFE use of sprintf */
589  (void) sprintf(msgbuf, "errno=%d", err);
590  cp = msgbuf;
591  }
592 #endif
593  return (cp);
594 }
595 
596 #if defined(TEST)
597 #include <stdio.h>
598 int main( void )
599 {
600  char buffer[128];
601  char *t;
602  char *test1 = "01234";
603  errno = 1;
604  plp_snprintf( buffer, sizeof(buffer), (t="errno '%m'")); printf( "%s = '%s'\n", t, buffer );
605  plp_snprintf( buffer, sizeof(buffer), (t = "%s"), test1 ); printf( "%s = '%s'\n", t, buffer );
606  plp_snprintf( buffer, sizeof(buffer), (t = "%12s"), test1 ); printf( "%s = '%s'\n", t, buffer );
607  plp_snprintf( buffer, sizeof(buffer), (t = "%-12s"), test1 ); printf( "%s = '%s'\n", t, buffer );
608  plp_snprintf( buffer, sizeof(buffer), (t = "%12.2s"), test1 ); printf( "%s = '%s'\n", t, buffer );
609  plp_snprintf( buffer, sizeof(buffer), (t = "%-12.2s"), test1 ); printf( "%s = '%s'\n", t, buffer );
610  plp_snprintf( buffer, sizeof(buffer), (t = "%g"), 1.25 ); printf( "%s = '%s'\n", t, buffer );
611  plp_snprintf( buffer, sizeof(buffer), (t = "%g"), 1.2345 ); printf( "%s = '%s'\n", t, buffer );
612  plp_snprintf( buffer, sizeof(buffer), (t = "%12g"), 1.25 ); printf( "%s = '%s'\n", t, buffer );
613  plp_snprintf( buffer, sizeof(buffer), (t = "%12.2g"), 1.25 ); printf( "%s = '%s'\n", t, buffer );
614  plp_snprintf( buffer, sizeof(buffer), (t = "%0*d"), 6, 1 ); printf( "%s = '%s'\n", t, buffer );
615 #if defined(HAVE_LONG_LONG)
616  plp_snprintf( buffer, sizeof(buffer), (t = "%llx"), 1, 2, 3, 4 ); printf( "%s = '%s'\n", t, buffer );
617  plp_snprintf( buffer, sizeof(buffer), (t = "%llx"), (long long)1, (long long)2 ); printf( "%s = '%s'\n", t, buffer );
618  plp_snprintf( buffer, sizeof(buffer), (t = "%qx"), 1, 2, 3, 4 ); printf( "%s = '%s'\n", t, buffer );
619  plp_snprintf( buffer, sizeof(buffer), (t = "%qx"), (quad_t)1, (quad_t)2 ); printf( "%s = '%s'\n", t, buffer );
620 #endif
621  return(0);
622 }
623 #endif
624 #endif /* !HAVE_SNPRINTF && !HAVE_VSNPRINTF */
char * sys_errlist[]
int sys_nerr
char * strerror(int n)
Definition: pcregrep.c:477
static uschar * buffer
Definition: pcretest.c:154
int visible_control
Definition: plp_snprintf.c:207
static void fmtnum(union value *value, int plp_base, int dosign, int ljust, int len, int zpad)
Definition: plp_snprintf.c:428
static void fmtstr(const char *value, int ljust, int len, int precision)
Definition: plp_snprintf.c:388
static const char * _id
Definition: plp_snprintf.c:119
#define cval(s)
Definition: plp_snprintf.c:192
static char * output
Definition: plp_snprintf.c:204
static void dopr_outch(int c)
Definition: plp_snprintf.c:536
static char * plp_Errormsg(int err)
Definition: plp_snprintf.c:574
static char * end
Definition: plp_snprintf.c:205
int plp_snprintf(va_alist)
Definition: plp_snprintf.c:224
int plp_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
Definition: plp_snprintf.c:210
#define num_errors
Definition: plp_snprintf.c:569
static void fmtdouble(int fmt, double value, int ljust, int len, int zpad, int precision)
Definition: plp_snprintf.c:500
static void dopr(char *buffer, const char *format, va_list args)
Definition: plp_snprintf.c:243
static void dostr(const char *)
Definition: plp_snprintf.c:531
static void plp_strcat(char *dest, const char *src)
Definition: plp_snprintf.c:491
int errno
int main(int argc, char *argv[])
Definition: main.c:79
@ NO
Definition: save.c:1385
long value
Definition: plp_snprintf.c:184
double dvalue
Definition: plp_snprintf.c:186