]> The Tcpdump Group git mirrors - libpcap/blob - missing/snprintf.c
Use %zu as the print format for size_t
[libpcap] / 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 /*
35 * We use this for platforms that don't have snprintf() at all.
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <sys/types.h>
48
49 #include "portability.h"
50
51 enum format_flags {
52 minus_flag = 1,
53 plus_flag = 2,
54 space_flag = 4,
55 alternate_flag = 8,
56 zero_flag = 16
57 };
58
59 /*
60 * Common state
61 */
62
63 struct state {
64 unsigned char *str;
65 unsigned char *s;
66 unsigned char *theend;
67 size_t sz;
68 size_t max_sz;
69 int (*append_char)(struct state *, unsigned char);
70 int (*reserve)(struct state *, size_t);
71 /* XXX - methods */
72 };
73
74 #ifndef HAVE_VSNPRINTF
75 static int
76 sn_reserve (struct state *state, size_t n)
77 {
78 return state->s + n > state->theend;
79 }
80
81 static int
82 sn_append_char (struct state *state, unsigned char c)
83 {
84 if (sn_reserve (state, 1)) {
85 return 1;
86 } else {
87 *state->s++ = c;
88 return 0;
89 }
90 }
91 #endif
92
93 #if 0
94 static int
95 as_reserve (struct state *state, size_t n)
96 {
97 if (state->s + n > state->theend) {
98 int off = state->s - state->str;
99 unsigned char *tmp;
100
101 if (state->max_sz && state->sz >= state->max_sz)
102 return 1;
103
104 state->sz = max(state->sz * 2, state->sz + n);
105 if (state->max_sz)
106 state->sz = min(state->sz, state->max_sz);
107 tmp = realloc (state->str, state->sz);
108 if (tmp == NULL)
109 return 1;
110 state->str = tmp;
111 state->s = state->str + off;
112 state->theend = state->str + state->sz - 1;
113 }
114 return 0;
115 }
116
117 static int
118 as_append_char (struct state *state, unsigned char c)
119 {
120 if(as_reserve (state, 1))
121 return 1;
122 else {
123 *state->s++ = c;
124 return 0;
125 }
126 }
127 #endif
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 int); \
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 pcap_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 = pcap_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 = pcap_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 #if 0
493 #ifndef HAVE_ASPRINTF
494 int
495 asprintf (char **ret, const char *format, ...)
496 {
497 va_list args;
498 int val;
499
500 va_start(args, format);
501 val = vasprintf (ret, format, args);
502
503 #ifdef PARANOIA
504 {
505 int ret2;
506 char *tmp;
507 tmp = malloc (val + 1);
508 if (tmp == NULL)
509 abort ();
510
511 ret2 = vsprintf (tmp, format, args);
512 if (val != ret2 || strcmp(*ret, tmp))
513 abort ();
514 free (tmp);
515 }
516 #endif
517
518 va_end(args);
519 return val;
520 }
521 #endif
522
523 #ifndef HAVE_ASNPRINTF
524 int
525 pcap_asnprintf (char **ret, size_t max_sz, const char *format, ...)
526 {
527 va_list args;
528 int val;
529
530 va_start(args, format);
531 val = pcap_vasnprintf (ret, max_sz, format, args);
532 va_end(args);
533
534 #ifdef PARANOIA
535 {
536 int ret2;
537 char *tmp;
538 tmp = malloc (val + 1);
539 if (tmp == NULL)
540 abort ();
541
542 va_start(args, format);
543 ret2 = pcap_vsprintf (tmp, format, args);
544 va_end(args);
545 if (val != ret2 || strcmp(*ret, tmp))
546 abort ();
547 free (tmp);
548 }
549 #endif
550
551 return val;
552 }
553 #endif
554
555 #ifndef HAVE_VASPRINTF
556 int
557 pcap_vasprintf (char **ret, const char *format, va_list args)
558 {
559 return pcap_vasnprintf (ret, 0, format, args);
560 }
561 #endif
562
563
564 #ifndef HAVE_VASNPRINTF
565 int
566 pcap_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
567 {
568 int st;
569 size_t len;
570 struct state state;
571
572 state.max_sz = max_sz;
573 state.sz = 1;
574 state.str = malloc(state.sz);
575 if (state.str == NULL) {
576 *ret = NULL;
577 return -1;
578 }
579 state.s = state.str;
580 state.theend = state.s + state.sz - 1;
581 state.append_char = as_append_char;
582 state.reserve = as_reserve;
583
584 st = xyzprintf (&state, format, args);
585 if (st) {
586 free (state.str);
587 *ret = NULL;
588 return -1;
589 } else {
590 char *tmp;
591
592 *state.s = '\0';
593 len = state.s - state.str;
594 tmp = realloc (state.str, len+1);
595 if (tmp == NULL) {
596 free (state.str);
597 *ret = NULL;
598 return -1;
599 }
600 *ret = tmp;
601 return len;
602 }
603 }
604 #endif
605 #endif
606
607 #ifndef HAVE_VSNPRINTF
608 int
609 pcap_vsnprintf (char *str, size_t sz, const char *format, va_list args)
610 {
611 struct state state;
612 int ret;
613 unsigned char *ustr = (unsigned char *)str;
614
615 state.max_sz = 0;
616 state.sz = sz;
617 state.str = ustr;
618 state.s = ustr;
619 state.theend = ustr + sz - 1;
620 state.append_char = sn_append_char;
621 state.reserve = sn_reserve;
622
623 ret = xyzprintf (&state, format, args);
624 *state.s = '\0';
625 if (ret)
626 return sz;
627 else
628 return state.s - state.str;
629 }
630 #endif
631