]> The Tcpdump Group git mirrors - tcpdump/blob - missing/snprintf.c
Unify rcsid[]'s.
[tcpdump] / missing / snprintf.c
1 /*
2 * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /* $Id: snprintf.c,v 1.2 2000-01-09 21:35:46 fenner Exp $ */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifndef lint
41 static const char rcsid[] =
42 "@(#) $Header: /tcpdump/master/tcpdump/missing/snprintf.c,v 1.2 2000-01-09 21:35:46 fenner Exp $";
43 #endif
44
45 #include <stdio.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50
51 #include <interface.h>
52
53 enum format_flags {
54 minus_flag = 1,
55 plus_flag = 2,
56 space_flag = 4,
57 alternate_flag = 8,
58 zero_flag = 16
59 };
60
61 /*
62 * Common state
63 */
64
65 struct state {
66 unsigned char *str;
67 unsigned char *s;
68 unsigned char *theend;
69 size_t sz;
70 size_t max_sz;
71 int (*append_char)(struct state *, unsigned char);
72 int (*reserve)(struct state *, size_t);
73 /* XXX - methods */
74 };
75
76 #ifndef HAVE_VSNPRINTF
77 static int
78 sn_reserve (struct state *state, size_t n)
79 {
80 return state->s + n > state->theend;
81 }
82
83 static int
84 sn_append_char (struct state *state, unsigned char c)
85 {
86 if (sn_reserve (state, 1)) {
87 return 1;
88 } else {
89 *state->s++ = c;
90 return 0;
91 }
92 }
93 #endif
94
95 static int
96 as_reserve (struct state *state, size_t n)
97 {
98 if (state->s + n > state->theend) {
99 int off = state->s - state->str;
100 unsigned char *tmp;
101
102 if (state->max_sz && state->sz >= state->max_sz)
103 return 1;
104
105 state->sz = max(state->sz * 2, state->sz + n);
106 if (state->max_sz)
107 state->sz = min(state->sz, state->max_sz);
108 tmp = realloc (state->str, state->sz);
109 if (tmp == NULL)
110 return 1;
111 state->str = tmp;
112 state->s = state->str + off;
113 state->theend = state->str + state->sz - 1;
114 }
115 return 0;
116 }
117
118 static int
119 as_append_char (struct state *state, unsigned char c)
120 {
121 if(as_reserve (state, 1))
122 return 1;
123 else {
124 *state->s++ = c;
125 return 0;
126 }
127 }
128
129 static int
130 append_number(struct state *state,
131 unsigned long num, unsigned base, char *rep,
132 int width, int prec, int flags, int minusp)
133 {
134 int len = 0;
135 int i;
136
137 /* given precision, ignore zero flag */
138 if(prec != -1)
139 flags &= ~zero_flag;
140 else
141 prec = 1;
142 /* zero value with zero precision -> "" */
143 if(prec == 0 && num == 0)
144 return 0;
145 do{
146 if((*state->append_char)(state, rep[num % base]))
147 return 1;
148 len++;
149 num /= base;
150 }while(num);
151 prec -= len;
152 /* pad with prec zeros */
153 while(prec-- > 0){
154 if((*state->append_char)(state, '0'))
155 return 1;
156 len++;
157 }
158 /* add length of alternate prefix (added later) to len */
159 if(flags & alternate_flag && (base == 16 || base == 8))
160 len += base / 8;
161 /* pad with zeros */
162 if(flags & zero_flag){
163 width -= len;
164 if(minusp || (flags & space_flag) || (flags & plus_flag))
165 width--;
166 while(width-- > 0){
167 if((*state->append_char)(state, '0'))
168 return 1;
169 len++;
170 }
171 }
172 /* add alternate prefix */
173 if(flags & alternate_flag && (base == 16 || base == 8)){
174 if(base == 16)
175 if((*state->append_char)(state, rep[10] + 23)) /* XXX */
176 return 1;
177 if((*state->append_char)(state, '0'))
178 return 1;
179 }
180 /* add sign */
181 if(minusp){
182 if((*state->append_char)(state, '-'))
183 return 1;
184 len++;
185 } else if(flags & plus_flag) {
186 if((*state->append_char)(state, '+'))
187 return 1;
188 len++;
189 } else if(flags & space_flag) {
190 if((*state->append_char)(state, ' '))
191 return 1;
192 len++;
193 }
194 if(flags & minus_flag)
195 /* swap before padding with spaces */
196 for(i = 0; i < len / 2; i++){
197 char c = state->s[-i-1];
198 state->s[-i-1] = state->s[-len+i];
199 state->s[-len+i] = c;
200 }
201 width -= len;
202 while(width-- > 0){
203 if((*state->append_char)(state, ' '))
204 return 1;
205 len++;
206 }
207 if(!(flags & minus_flag))
208 /* swap after padding with spaces */
209 for(i = 0; i < len / 2; i++){
210 char c = state->s[-i-1];
211 state->s[-i-1] = state->s[-len+i];
212 state->s[-len+i] = c;
213 }
214
215 return 0;
216 }
217
218 static int
219 append_string (struct state *state,
220 unsigned char *arg,
221 int width,
222 int prec,
223 int flags)
224 {
225 if(prec != -1)
226 width -= prec;
227 else
228 width -= strlen((char *)arg);
229 if(!(flags & minus_flag))
230 while(width-- > 0)
231 if((*state->append_char) (state, ' '))
232 return 1;
233 if (prec != -1) {
234 while (*arg && prec--)
235 if ((*state->append_char) (state, *arg++))
236 return 1;
237 } else {
238 while (*arg)
239 if ((*state->append_char) (state, *arg++))
240 return 1;
241 }
242 if(flags & minus_flag)
243 while(width-- > 0)
244 if((*state->append_char) (state, ' '))
245 return 1;
246 return 0;
247 }
248
249 static int
250 append_char(struct state *state,
251 unsigned char arg,
252 int width,
253 int flags)
254 {
255 while(!(flags & minus_flag) && --width > 0)
256 if((*state->append_char) (state, ' '))
257 return 1;
258
259 if((*state->append_char) (state, arg))
260 return 1;
261 while((flags & minus_flag) && --width > 0)
262 if((*state->append_char) (state, ' '))
263 return 1;
264
265 return 0;
266 }
267
268 /*
269 * This can't be made into a function...
270 */
271
272 #define PARSE_INT_FORMAT(res, arg, unsig) \
273 if (long_flag) \
274 res = (unsig long)va_arg(arg, unsig long); \
275 else if (short_flag) \
276 res = (unsig short)va_arg(arg, unsig short); \
277 else \
278 res = (unsig int)va_arg(arg, unsig int)
279
280 /*
281 * zyxprintf - return 0 or -1
282 */
283
284 static int
285 xyzprintf (struct state *state, const char *char_format, va_list ap)
286 {
287 const unsigned char *format = (const unsigned char *)char_format;
288 unsigned char c;
289
290 while((c = *format++)) {
291 if (c == '%') {
292 int flags = 0;
293 int width = 0;
294 int prec = -1;
295 int long_flag = 0;
296 int short_flag = 0;
297
298 /* flags */
299 while((c = *format++)){
300 if(c == '-')
301 flags |= minus_flag;
302 else if(c == '+')
303 flags |= plus_flag;
304 else if(c == ' ')
305 flags |= space_flag;
306 else if(c == '#')
307 flags |= alternate_flag;
308 else if(c == '0')
309 flags |= zero_flag;
310 else
311 break;
312 }
313
314 if((flags & space_flag) && (flags & plus_flag))
315 flags ^= space_flag;
316
317 if((flags & minus_flag) && (flags & zero_flag))
318 flags ^= zero_flag;
319
320 /* width */
321 if (isdigit(c))
322 do {
323 width = width * 10 + c - '0';
324 c = *format++;
325 } while(isdigit(c));
326 else if(c == '*') {
327 width = va_arg(ap, int);
328 c = *format++;
329 }
330
331 /* precision */
332 if (c == '.') {
333 prec = 0;
334 c = *format++;
335 if (isdigit(c))
336 do {
337 prec = prec * 10 + c - '0';
338 c = *format++;
339 } while(isdigit(c));
340 else if (c == '*') {
341 prec = va_arg(ap, int);
342 c = *format++;
343 }
344 }
345
346 /* size */
347
348 if (c == 'h') {
349 short_flag = 1;
350 c = *format++;
351 } else if (c == 'l') {
352 long_flag = 1;
353 c = *format++;
354 }
355
356 switch (c) {
357 case 'c' :
358 if(append_char(state, va_arg(ap, int), width, flags))
359 return -1;
360 break;
361 case 's' :
362 if (append_string(state,
363 va_arg(ap, unsigned char*),
364 width,
365 prec,
366 flags))
367 return -1;
368 break;
369 case 'd' :
370 case 'i' : {
371 long arg;
372 unsigned long num;
373 int minusp = 0;
374
375 PARSE_INT_FORMAT(arg, ap, signed);
376
377 if (arg < 0) {
378 minusp = 1;
379 num = -arg;
380 } else
381 num = arg;
382
383 if (append_number (state, num, 10, "0123456789",
384 width, prec, flags, minusp))
385 return -1;
386 break;
387 }
388 case 'u' : {
389 unsigned long arg;
390
391 PARSE_INT_FORMAT(arg, ap, unsigned);
392
393 if (append_number (state, arg, 10, "0123456789",
394 width, prec, flags, 0))
395 return -1;
396 break;
397 }
398 case 'o' : {
399 unsigned long arg;
400
401 PARSE_INT_FORMAT(arg, ap, unsigned);
402
403 if (append_number (state, arg, 010, "01234567",
404 width, prec, flags, 0))
405 return -1;
406 break;
407 }
408 case 'x' : {
409 unsigned long arg;
410
411 PARSE_INT_FORMAT(arg, ap, unsigned);
412
413 if (append_number (state, arg, 0x10, "0123456789abcdef",
414 width, prec, flags, 0))
415 return -1;
416 break;
417 }
418 case 'X' :{
419 unsigned long arg;
420
421 PARSE_INT_FORMAT(arg, ap, unsigned);
422
423 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
424 width, prec, flags, 0))
425 return -1;
426 break;
427 }
428 case 'p' : {
429 unsigned long arg = (unsigned long)va_arg(ap, void*);
430
431 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
432 width, prec, flags, 0))
433 return -1;
434 break;
435 }
436 case 'n' : {
437 int *arg = va_arg(ap, int*);
438 *arg = state->s - state->str;
439 break;
440 }
441 case '\0' :
442 --format;
443 /* FALLTHROUGH */
444 case '%' :
445 if ((*state->append_char)(state, c))
446 return -1;
447 break;
448 default :
449 if ( (*state->append_char)(state, '%')
450 || (*state->append_char)(state, c))
451 return -1;
452 break;
453 }
454 } else
455 if ((*state->append_char) (state, c))
456 return -1;
457 }
458 return 0;
459 }
460
461 #ifndef HAVE_SNPRINTF
462 int
463 snprintf (char *str, size_t sz, const char *format, ...)
464 {
465 va_list args;
466 int ret;
467
468 va_start(args, format);
469 ret = vsnprintf (str, sz, format, args);
470
471 #ifdef PARANOIA
472 {
473 int ret2;
474 char *tmp;
475
476 tmp = malloc (sz);
477 if (tmp == NULL)
478 abort ();
479
480 ret2 = vsprintf (tmp, format, args);
481 if (ret != ret2 || strcmp(str, tmp))
482 abort ();
483 free (tmp);
484 }
485 #endif
486
487 va_end(args);
488 return ret;
489 }
490 #endif
491
492 #ifndef HAVE_ASPRINTF
493 int
494 asprintf (char **ret, const char *format, ...)
495 {
496 va_list args;
497 int val;
498
499 va_start(args, format);
500 val = vasprintf (ret, format, args);
501
502 #ifdef PARANOIA
503 {
504 int ret2;
505 char *tmp;
506 tmp = malloc (val + 1);
507 if (tmp == NULL)
508 abort ();
509
510 ret2 = vsprintf (tmp, format, args);
511 if (val != ret2 || strcmp(*ret, tmp))
512 abort ();
513 free (tmp);
514 }
515 #endif
516
517 va_end(args);
518 return val;
519 }
520 #endif
521
522 #ifndef HAVE_ASNPRINTF
523 int
524 asnprintf (char **ret, size_t max_sz, const char *format, ...)
525 {
526 va_list args;
527 int val;
528
529 va_start(args, format);
530 val = vasnprintf (ret, max_sz, format, args);
531
532 #ifdef PARANOIA
533 {
534 int ret2;
535 char *tmp;
536 tmp = malloc (val + 1);
537 if (tmp == NULL)
538 abort ();
539
540 ret2 = vsprintf (tmp, format, args);
541 if (val != ret2 || strcmp(*ret, tmp))
542 abort ();
543 free (tmp);
544 }
545 #endif
546
547 va_end(args);
548 return val;
549 }
550 #endif
551
552 #ifndef HAVE_VASPRINTF
553 int
554 vasprintf (char **ret, const char *format, va_list args)
555 {
556 return vasnprintf (ret, 0, format, args);
557 }
558 #endif
559
560
561 #ifndef HAVE_VASNPRINTF
562 int
563 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
564 {
565 int st;
566 size_t len;
567 struct state state;
568
569 state.max_sz = max_sz;
570 state.sz = 1;
571 state.str = malloc(state.sz);
572 if (state.str == NULL) {
573 *ret = NULL;
574 return -1;
575 }
576 state.s = state.str;
577 state.theend = state.s + state.sz - 1;
578 state.append_char = as_append_char;
579 state.reserve = as_reserve;
580
581 st = xyzprintf (&state, format, args);
582 if (st) {
583 free (state.str);
584 *ret = NULL;
585 return -1;
586 } else {
587 char *tmp;
588
589 *state.s = '\0';
590 len = state.s - state.str;
591 tmp = realloc (state.str, len+1);
592 if (tmp == NULL) {
593 free (state.str);
594 *ret = NULL;
595 return -1;
596 }
597 *ret = tmp;
598 return len;
599 }
600 }
601 #endif
602
603 #ifndef HAVE_VSNPRINTF
604 int
605 vsnprintf (char *str, size_t sz, const char *format, va_list args)
606 {
607 struct state state;
608 int ret;
609 unsigned char *ustr = (unsigned char *)str;
610
611 state.max_sz = 0;
612 state.sz = sz;
613 state.str = ustr;
614 state.s = ustr;
615 state.theend = ustr + sz - 1;
616 state.append_char = sn_append_char;
617 state.reserve = sn_reserve;
618
619 ret = xyzprintf (&state, format, args);
620 *state.s = '\0';
621 if (ret)
622 return sz;
623 else
624 return state.s - state.str;
625 }
626 #endif
627