tin  2.6.1
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.6.1.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
119static 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
157XX ** 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
180union 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
195static char *plp_Errormsg(int err);
196static void plp_strcat(char *dest, const char *src);
197static void dopr(char *buffer, const char *format, va_list args);
198static void fmtstr(const char *value, int ljust, int len, int precision);
199static void fmtnum(union value *value, int plp_base, int dosign, int ljust, int len, int zpad);
200static void fmtdouble(int fmt, double value, int ljust, int len, int zpad, int precision);
201static void dostr(const char *);
202static void dopr_outch(int c);
203
204static char *output;
205static char *end;
206
208
209
210int 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
222int plp_snprintf(char *str,size_t count,const char *fmt,...)
223#else
224int 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
243static 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 */
387static void
388fmtstr(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
427static void
428fmtnum( 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
490static void
491plp_strcat(char *dest, const char *src )
492{
493 if( dest && src ){
494 dest += strlen(dest);
495 strcpy(dest,src);
496 }
497}
498
499static void
500fmtdouble( 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
531static void dostr( const char *str )
532{
533 while(*str) dopr_outch(*str++);
534}
535
536static 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
574static 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>
598int 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 */
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
#define strerror(n)
Definition: proto.h:700
@ NO
Definition: save.c:1356
long value
Definition: plp_snprintf.c:184
double dvalue
Definition: plp_snprintf.c:186