1 static char rcsId[] = "$Id: snprintf.c,v 2.9 2001/08/17 05:30:14 lukeh Exp $";
2 
3 #include "config.h"
4 
5 #ifndef HAVE_SNPRINTF
6 
7 /**************************************************************
8  * Original:
9  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
10  * A bombproof version of doprnt (dopr) included.
11  * Sigh. This sort of thing is always nasty do deal with. Note that
12  * the version here does not include floating point...
13  *
14  * snprintf() is used instead of sprintf() as it does limit checks
15  * for string length. This covers a nasty loophole.
16  *
17  * The other functions are there to prevent NULL pointers from
18  * causing nast effects.
19  **************************************************************/
20 
21 static void dopr ();
22 static char *end;
23 
24 #include "snprintf.h"
25 #include <string.h>
26 
27 #ifdef HAVE_CTYPE_H
28 #include <ctype.h>
29 #endif
30 
31 /* varargs declarations: */
32 
33 #if defined(HAVE_STDARG_H)
34 #include <stdarg.h>
35 #define HAVE_STDARGS		/* let's hope that works everywhere (mj) */
36 #define VA_LOCAL_DECL va_list ap;
37 #define VA_START(f) va_start(ap, f)
38 #define VA_SHIFT(v,t) ;		/* no-op for ANSI */
39 #define VA_END va_end(ap)
40 #else
41 #if defined(HAVE_VARARGS_H)
42 #include <varargs.h>
43 #undef HAVE_STDARGS
44 #define VA_LOCAL_DECL va_list ap;
45 #define VA_START(f) va_start(ap)	/* f is ignored! */
46 #define VA_SHIFT(v,t) v = va_arg(ap,t)
47 #define VA_END va_end(ap)
48 #else
49 XX **NO VARARGS ** XX
50 #endif
51 #endif
52 #ifdef HAVE_STDARGS
53 int snprintf (char *str, size_t count, const char *fmt, ...);
54 int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
55 #else
56 int snprintf ();
57 int vsnprintf ();
58 #endif
59 
60 int
vsnprintf(str,count,fmt,args)61 vsnprintf (str, count, fmt, args)
62      char *str;
63      size_t count;
64      const char *fmt;
65      va_list args;
66 {
67   str[0] = 0;
68   end = str + count - 1;
69   dopr (str, fmt, args);
70   if (count > 0)
71     {
72       end[0] = 0;
73     }
74   return (strlen (str));
75 }
76 
77 /* VARARGS3 */
78 #ifdef HAVE_STDARGS
79 int
snprintf(char * str,size_t count,const char * fmt,...)80 snprintf (char *str, size_t count, const char *fmt, ...)
81 #else
82 int
83 snprintf (va_alist)
84      va_dcl
85 #endif
86 {
87 #ifndef HAVE_STDARGS
88   char *str;
89   size_t count;
90   char *fmt;
91 #endif
92   VA_LOCAL_DECL VA_START (fmt);
93   VA_SHIFT (str, char *);
94   VA_SHIFT (count, size_t);
95   VA_SHIFT (fmt, char *);
96   (void) vsnprintf (str, count, fmt, ap);
97   VA_END;
98   return (strlen (str));
99 }
100 
101 /*
102  * dopr(): poor man's version of doprintf
103  */
104 
105 static void fmtstr (char *value, int ljust, int len, int zpad);
106 static void fmtnum (long value, int base, int dosign,
107 		    int ljust, int len, int zpad);
108 static void dostr (char *);
109 static char *output;
110 static void dopr_outch (int c);
111 
112 static void
dopr(buffer,format,args)113 dopr (buffer, format, args)
114      char *buffer;
115      char *format;
116      va_list args;
117 {
118   int ch;
119   long value;
120   int longflag = 0;
121   char *strvalue;
122   int ljust;
123   int len;
124   int zpad;
125 
126   output = buffer;
127   while ((ch = *format++))
128     {
129       switch (ch)
130 	{
131 	case '%':
132 	  ljust = len = zpad = 0;
133 	nextch:
134 	  ch = *format++;
135 	  switch (ch)
136 	    {
137 	    case 0:
138 	      dostr ("**end of format**");
139 	      return;
140 	    case '-':
141 	      ljust = 1;
142 	      goto nextch;
143 	    case '0':		/* set zero padding if len not set */
144 	      if (len == 0)
145 		zpad = '0';
146 	    case '1':
147 	    case '2':
148 	    case '3':
149 	    case '4':
150 	    case '5':
151 	    case '6':
152 	    case '7':
153 	    case '8':
154 	    case '9':
155 	      len = len * 10 + ch - '0';
156 	      goto nextch;
157 	    case 'l':
158 	      longflag = 1;
159 	      goto nextch;
160 	    case 'u':
161 	    case 'U':
162 	      /*fmtnum(value,base,dosign,ljust,len,zpad) */
163 	      if (longflag)
164 		{
165 		  value = va_arg (args, long);
166 		}
167 	      else
168 		{
169 		  value = va_arg (args, int);
170 		}
171 	      fmtnum (value, 10, 0, ljust, len, zpad);
172 	      break;
173 	    case 'o':
174 	    case 'O':
175 	      /*fmtnum(value,base,dosign,ljust,len,zpad) */
176 	      if (longflag)
177 		{
178 		  value = va_arg (args, long);
179 		}
180 	      else
181 		{
182 		  value = va_arg (args, int);
183 		}
184 	      fmtnum (value, 8, 0, ljust, len, zpad);
185 	      break;
186 	    case 'd':
187 	    case 'D':
188 	      if (longflag)
189 		{
190 		  value = va_arg (args, long);
191 		}
192 	      else
193 		{
194 		  value = va_arg (args, int);
195 		}
196 	      fmtnum (value, 10, 1, ljust, len, zpad);
197 	      break;
198 	    case 'x':
199 	      if (longflag)
200 		{
201 		  value = va_arg (args, long);
202 		}
203 	      else
204 		{
205 		  value = va_arg (args, int);
206 		}
207 	      fmtnum (value, 16, 0, ljust, len, zpad);
208 	      break;
209 	    case 'X':
210 	      if (longflag)
211 		{
212 		  value = va_arg (args, long);
213 		}
214 	      else
215 		{
216 		  value = va_arg (args, int);
217 		}
218 	      fmtnum (value, -16, 0, ljust, len, zpad);
219 	      break;
220 	    case 's':
221 	      strvalue = va_arg (args, char *);
222 	      fmtstr (strvalue, ljust, len, zpad);
223 	      break;
224 	    case 'c':
225 	      ch = va_arg (args, int);
226 	      dopr_outch (ch);
227 	      break;
228 	    case '%':
229 	      dopr_outch (ch);
230 	      continue;
231 	    default:
232 	      dostr ("???????");
233 	    }
234 	  longflag = 0;
235 	  break;
236 	default:
237 	  dopr_outch (ch);
238 	  break;
239 	}
240     }
241   *output = 0;
242 }
243 
244 static void
fmtstr(value,ljust,len,zpad)245 fmtstr (value, ljust, len, zpad)
246      char *value;
247      int ljust, len, zpad;
248 {
249   int padlen, strlen;		/* amount to pad */
250 
251   if (value == 0)
252     {
253       value = "<NULL>";
254     }
255   for (strlen = 0; value[strlen]; ++strlen);	/* strlen */
256   padlen = len - strlen;
257   if (padlen < 0)
258     padlen = 0;
259   if (ljust)
260     padlen = -padlen;
261   while (padlen > 0)
262     {
263       dopr_outch (' ');
264       --padlen;
265     }
266   dostr (value);
267   while (padlen < 0)
268     {
269       dopr_outch (' ');
270       ++padlen;
271     }
272 }
273 
274 static void
fmtnum(value,base,dosign,ljust,len,zpad)275 fmtnum (value, base, dosign, ljust, len, zpad)
276      long value;
277      int base, dosign, ljust, len, zpad;
278 {
279   int signvalue = 0;
280   unsigned long uvalue;
281   char convert[20];
282   int place = 0;
283   int padlen = 0;		/* amount to pad */
284   int caps = 0;
285 
286   /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
287      value, base, dosign, ljust, len, zpad )); */
288   uvalue = value;
289   if (dosign)
290     {
291       if (value < 0)
292 	{
293 	  signvalue = '-';
294 	  uvalue = -value;
295 	}
296     }
297   if (base < 0)
298     {
299       caps = 1;
300       base = -base;
301     }
302   do
303     {
304       convert[place++] =
305 	(caps ? "0123456789ABCDEF" : "0123456789abcdef")
306 	[uvalue % (unsigned) base];
307       uvalue = (uvalue / (unsigned) base);
308     }
309   while (uvalue);
310   convert[place] = 0;
311   padlen = len - place;
312   if (padlen < 0)
313     padlen = 0;
314   if (ljust)
315     padlen = -padlen;
316   /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
317      convert,place,signvalue,padlen)); */
318   if (zpad && padlen > 0)
319     {
320       if (signvalue)
321 	{
322 	  dopr_outch (signvalue);
323 	  --padlen;
324 	  signvalue = 0;
325 	}
326       while (padlen > 0)
327 	{
328 	  dopr_outch (zpad);
329 	  --padlen;
330 	}
331     }
332   while (padlen > 0)
333     {
334       dopr_outch (' ');
335       --padlen;
336     }
337   if (signvalue)
338     dopr_outch (signvalue);
339   while (place > 0)
340     dopr_outch (convert[--place]);
341   while (padlen < 0)
342     {
343       dopr_outch (' ');
344       ++padlen;
345     }
346 }
347 
348 static void
dostr(str)349 dostr (str)
350      char *str;
351 {
352   while (*str)
353     dopr_outch (*str++);
354 }
355 
356 static void
dopr_outch(c)357 dopr_outch (c)
358      int c;
359 {
360   if (iscntrl (c) && c != '\n' && c != '\t')
361     {
362       c = '@' + (c & 0x1F);
363       if (end == 0 || output < end)
364 	{
365 	  *output++ = '^';
366 	}
367     }
368   if (end == 0 || output < end)
369     {
370       *output++ = c;
371     }
372 }
373 
374 #endif /* !HAVE_SNPRINTF */
375