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