Merge from vendor branch GCC:
[dragonfly.git] / contrib / libpcap-0.8.3 / 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.1 2003/12/15 01:35:05 guy Exp $ */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifndef lint
41 static const char rcsid[] _U_ =
42      "@(#) $Header: /tcpdump/master/libpcap/snprintf.c,v 1.1 2003/12/15 01:35:05 guy 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 #include <sys/types.h>
51
52 #include <pcap-int.h>
53
54 enum format_flags {
55     minus_flag     =  1,
56     plus_flag      =  2,
57     space_flag     =  4,
58     alternate_flag =  8,
59     zero_flag      = 16
60 };
61
62 /*
63  * Common state
64  */
65
66 struct state {
67   unsigned char *str;
68   unsigned char *s;
69   unsigned char *theend;
70   size_t sz;
71   size_t max_sz;
72   int (*append_char)(struct state *, unsigned char);
73   int (*reserve)(struct state *, size_t);
74   /* XXX - methods */
75 };
76
77 #ifndef HAVE_VSNPRINTF
78 static int
79 sn_reserve (struct state *state, size_t n)
80 {
81   return state->s + n > state->theend;
82 }
83
84 static int
85 sn_append_char (struct state *state, unsigned char c)
86 {
87   if (sn_reserve (state, 1)) {
88     return 1;
89   } else {
90     *state->s++ = c;
91     return 0;
92   }
93 }
94 #endif
95
96 #if 0
97 static int
98 as_reserve (struct state *state, size_t n)
99 {
100   if (state->s + n > state->theend) {
101     int off = state->s - state->str;
102     unsigned char *tmp;
103
104     if (state->max_sz && state->sz >= state->max_sz)
105       return 1;
106
107     state->sz = max(state->sz * 2, state->sz + n);
108     if (state->max_sz)
109       state->sz = min(state->sz, state->max_sz);
110     tmp = realloc (state->str, state->sz);
111     if (tmp == NULL)
112       return 1;
113     state->str = tmp;
114     state->s = state->str + off;
115     state->theend = state->str + state->sz - 1;
116   }
117   return 0;
118 }
119
120 static int
121 as_append_char (struct state *state, unsigned char c)
122 {
123   if(as_reserve (state, 1))
124     return 1;
125   else {
126     *state->s++ = c;
127     return 0;
128   }
129 }
130 #endif
131
132 static int
133 append_number(struct state *state,
134               unsigned long num, unsigned base, char *rep,
135               int width, int prec, int flags, int minusp)
136 {
137   int len = 0;
138   int i;
139
140   /* given precision, ignore zero flag */
141   if(prec != -1)
142     flags &= ~zero_flag;
143   else
144     prec = 1;
145   /* zero value with zero precision -> "" */
146   if(prec == 0 && num == 0)
147     return 0;
148   do{
149     if((*state->append_char)(state, rep[num % base]))
150       return 1;
151     len++;
152     num /= base;
153   }while(num);
154   prec -= len;
155   /* pad with prec zeros */
156   while(prec-- > 0){
157     if((*state->append_char)(state, '0'))
158       return 1;
159     len++;
160   }
161   /* add length of alternate prefix (added later) to len */
162   if(flags & alternate_flag && (base == 16 || base == 8))
163     len += base / 8;
164   /* pad with zeros */
165   if(flags & zero_flag){
166     width -= len;
167     if(minusp || (flags & space_flag) || (flags & plus_flag))
168       width--;
169     while(width-- > 0){
170       if((*state->append_char)(state, '0'))
171         return 1;
172       len++;
173     }
174   }
175   /* add alternate prefix */
176   if(flags & alternate_flag && (base == 16 || base == 8)){
177     if(base == 16)
178       if((*state->append_char)(state, rep[10] + 23)) /* XXX */
179         return 1;
180     if((*state->append_char)(state, '0'))
181       return 1;
182   }
183   /* add sign */
184   if(minusp){
185     if((*state->append_char)(state, '-'))
186       return 1;
187     len++;
188   } else if(flags & plus_flag) {
189     if((*state->append_char)(state, '+'))
190       return 1;
191     len++;
192   } else if(flags & space_flag) {
193     if((*state->append_char)(state, ' '))
194       return 1;
195     len++;
196   }
197   if(flags & minus_flag)
198     /* swap before padding with spaces */
199     for(i = 0; i < len / 2; i++){
200       char c = state->s[-i-1];
201       state->s[-i-1] = state->s[-len+i];
202       state->s[-len+i] = c;
203     }
204   width -= len;
205   while(width-- > 0){
206     if((*state->append_char)(state,  ' '))
207       return 1;
208     len++;
209   }
210   if(!(flags & minus_flag))
211     /* swap after padding with spaces */
212     for(i = 0; i < len / 2; i++){
213       char c = state->s[-i-1];
214       state->s[-i-1] = state->s[-len+i];
215       state->s[-len+i] = c;
216     }
217
218   return 0;
219 }
220
221 static int
222 append_string (struct state *state,
223                unsigned char *arg,
224                int width,
225                int prec,
226                int flags)
227 {
228   if(prec != -1)
229     width -= prec;
230   else
231     width -= strlen((char *)arg);
232   if(!(flags & minus_flag))
233     while(width-- > 0)
234       if((*state->append_char) (state, ' '))
235         return 1;
236   if (prec != -1) {
237     while (*arg && prec--)
238       if ((*state->append_char) (state, *arg++))
239         return 1;
240   } else {
241     while (*arg)
242       if ((*state->append_char) (state, *arg++))
243         return 1;
244   }
245   if(flags & minus_flag)
246     while(width-- > 0)
247       if((*state->append_char) (state, ' '))
248         return 1;
249   return 0;
250 }
251
252 static int
253 append_char(struct state *state,
254             unsigned char arg,
255             int width,
256             int flags)
257 {
258   while(!(flags & minus_flag) && --width > 0)
259     if((*state->append_char) (state, ' '))
260       return 1;
261
262   if((*state->append_char) (state, arg))
263     return 1;
264   while((flags & minus_flag) && --width > 0)
265     if((*state->append_char) (state, ' '))
266       return 1;
267
268   return 0;
269 }
270
271 /*
272  * This can't be made into a function...
273  */
274
275 #define PARSE_INT_FORMAT(res, arg, unsig) \
276 if (long_flag) \
277      res = (unsig long)va_arg(arg, unsig long); \
278 else if (short_flag) \
279      res = (unsig short)va_arg(arg, unsig int); \
280 else \
281      res = (unsig int)va_arg(arg, unsig int)
282
283 /*
284  * zyxprintf - return 0 or -1
285  */
286
287 static int
288 xyzprintf (struct state *state, const char *char_format, va_list ap)
289 {
290   const unsigned char *format = (const unsigned char *)char_format;
291   unsigned char c;
292
293   while((c = *format++)) {
294     if (c == '%') {
295       int flags      = 0;
296       int width      = 0;
297       int prec       = -1;
298       int long_flag  = 0;
299       int short_flag = 0;
300
301       /* flags */
302       while((c = *format++)){
303         if(c == '-')
304           flags |= minus_flag;
305         else if(c == '+')
306           flags |= plus_flag;
307         else if(c == ' ')
308           flags |= space_flag;
309         else if(c == '#')
310           flags |= alternate_flag;
311         else if(c == '0')
312           flags |= zero_flag;
313         else
314           break;
315       }
316
317       if((flags & space_flag) && (flags & plus_flag))
318         flags ^= space_flag;
319
320       if((flags & minus_flag) && (flags & zero_flag))
321         flags ^= zero_flag;
322
323       /* width */
324       if (isdigit(c))
325         do {
326           width = width * 10 + c - '0';
327           c = *format++;
328         } while(isdigit(c));
329       else if(c == '*') {
330         width = va_arg(ap, int);
331         c = *format++;
332       }
333
334       /* precision */
335       if (c == '.') {
336         prec = 0;
337         c = *format++;
338         if (isdigit(c))
339           do {
340             prec = prec * 10 + c - '0';
341             c = *format++;
342           } while(isdigit(c));
343         else if (c == '*') {
344           prec = va_arg(ap, int);
345           c = *format++;
346         }
347       }
348
349       /* size */
350
351       if (c == 'h') {
352         short_flag = 1;
353         c = *format++;
354       } else if (c == 'l') {
355         long_flag = 1;
356         c = *format++;
357       }
358
359       switch (c) {
360       case 'c' :
361         if(append_char(state, va_arg(ap, int), width, flags))
362           return -1;
363         break;
364       case 's' :
365         if (append_string(state,
366                           va_arg(ap, unsigned char*),
367                           width,
368                           prec,
369                           flags))
370           return -1;
371         break;
372       case 'd' :
373       case 'i' : {
374         long arg;
375         unsigned long num;
376         int minusp = 0;
377
378         PARSE_INT_FORMAT(arg, ap, signed);
379
380         if (arg < 0) {
381           minusp = 1;
382           num = -arg;
383         } else
384           num = arg;
385
386         if (append_number (state, num, 10, "0123456789",
387                            width, prec, flags, minusp))
388           return -1;
389         break;
390       }
391       case 'u' : {
392         unsigned long arg;
393
394         PARSE_INT_FORMAT(arg, ap, unsigned);
395
396         if (append_number (state, arg, 10, "0123456789",
397                            width, prec, flags, 0))
398           return -1;
399         break;
400       }
401       case 'o' : {
402         unsigned long arg;
403
404         PARSE_INT_FORMAT(arg, ap, unsigned);
405
406         if (append_number (state, arg, 010, "01234567",
407                            width, prec, flags, 0))
408           return -1;
409         break;
410       }
411       case 'x' : {
412         unsigned long arg;
413
414         PARSE_INT_FORMAT(arg, ap, unsigned);
415
416         if (append_number (state, arg, 0x10, "0123456789abcdef",
417                            width, prec, flags, 0))
418           return -1;
419         break;
420       }
421       case 'X' :{
422         unsigned long arg;
423
424         PARSE_INT_FORMAT(arg, ap, unsigned);
425
426         if (append_number (state, arg, 0x10, "0123456789ABCDEF",
427                            width, prec, flags, 0))
428           return -1;
429         break;
430       }
431       case 'p' : {
432         unsigned long arg = (unsigned long)va_arg(ap, void*);
433
434         if (append_number (state, arg, 0x10, "0123456789ABCDEF",
435                            width, prec, flags, 0))
436           return -1;
437         break;
438       }
439       case 'n' : {
440         int *arg = va_arg(ap, int*);
441         *arg = state->s - state->str;
442         break;
443       }
444       case '\0' :
445           --format;
446           /* FALLTHROUGH */
447       case '%' :
448         if ((*state->append_char)(state, c))
449           return -1;
450         break;
451       default :
452         if (   (*state->append_char)(state, '%')
453             || (*state->append_char)(state, c))
454           return -1;
455         break;
456       }
457     } else
458       if ((*state->append_char) (state, c))
459         return -1;
460   }
461   return 0;
462 }
463
464 #ifndef HAVE_SNPRINTF
465 int
466 snprintf (char *str, size_t sz, const char *format, ...)
467 {
468   va_list args;
469   int ret;
470
471   va_start(args, format);
472   ret = vsnprintf (str, sz, format, args);
473
474 #ifdef PARANOIA
475   {
476     int ret2;
477     char *tmp;
478
479     tmp = malloc (sz);
480     if (tmp == NULL)
481       abort ();
482
483     ret2 = vsprintf (tmp, format, args);
484     if (ret != ret2 || strcmp(str, tmp))
485       abort ();
486     free (tmp);
487   }
488 #endif
489
490   va_end(args);
491   return ret;
492 }
493 #endif
494
495 #if 0
496 #ifndef HAVE_ASPRINTF
497 int
498 asprintf (char **ret, const char *format, ...)
499 {
500   va_list args;
501   int val;
502
503   va_start(args, format);
504   val = vasprintf (ret, format, args);
505
506 #ifdef PARANOIA
507   {
508     int ret2;
509     char *tmp;
510     tmp = malloc (val + 1);
511     if (tmp == NULL)
512       abort ();
513
514     ret2 = vsprintf (tmp, format, args);
515     if (val != ret2 || strcmp(*ret, tmp))
516       abort ();
517     free (tmp);
518   }
519 #endif
520
521   va_end(args);
522   return val;
523 }
524 #endif
525
526 #ifndef HAVE_ASNPRINTF
527 int
528 asnprintf (char **ret, size_t max_sz, const char *format, ...)
529 {
530   va_list args;
531   int val;
532
533   va_start(args, format);
534   val = vasnprintf (ret, max_sz, format, args);
535
536 #ifdef PARANOIA
537   {
538     int ret2;
539     char *tmp;
540     tmp = malloc (val + 1);
541     if (tmp == NULL)
542       abort ();
543
544     ret2 = vsprintf (tmp, format, args);
545     if (val != ret2 || strcmp(*ret, tmp))
546       abort ();
547     free (tmp);
548   }
549 #endif
550
551   va_end(args);
552   return val;
553 }
554 #endif
555
556 #ifndef HAVE_VASPRINTF
557 int
558 vasprintf (char **ret, const char *format, va_list args)
559 {
560   return vasnprintf (ret, 0, format, args);
561 }
562 #endif
563
564
565 #ifndef HAVE_VASNPRINTF
566 int
567 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
568 {
569   int st;
570   size_t len;
571   struct state state;
572
573   state.max_sz = max_sz;
574   state.sz     = 1;
575   state.str    = malloc(state.sz);
576   if (state.str == NULL) {
577     *ret = NULL;
578     return -1;
579   }
580   state.s = state.str;
581   state.theend = state.s + state.sz - 1;
582   state.append_char = as_append_char;
583   state.reserve     = as_reserve;
584
585   st = xyzprintf (&state, format, args);
586   if (st) {
587     free (state.str);
588     *ret = NULL;
589     return -1;
590   } else {
591     char *tmp;
592
593     *state.s = '\0';
594     len = state.s - state.str;
595     tmp = realloc (state.str, len+1);
596     if (tmp == NULL) {
597       free (state.str);
598       *ret = NULL;
599       return -1;
600     }
601     *ret = tmp;
602     return len;
603   }
604 }
605 #endif
606 #endif
607
608 #ifndef HAVE_VSNPRINTF
609 int
610 vsnprintf (char *str, size_t sz, const char *format, va_list args)
611 {
612   struct state state;
613   int ret;
614   unsigned char *ustr = (unsigned char *)str;
615
616   state.max_sz = 0;
617   state.sz     = sz;
618   state.str    = ustr;
619   state.s      = ustr;
620   state.theend = ustr + sz - 1;
621   state.append_char = sn_append_char;
622   state.reserve     = sn_reserve;
623
624   ret = xyzprintf (&state, format, args);
625   *state.s = '\0';
626   if (ret)
627     return sz;
628   else
629     return state.s - state.str;
630 }
631 #endif
632