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 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42
43 #include "netdissect.h"
44
45 enum format_flags {
46 minus_flag = 1,
47 plus_flag = 2,
48 space_flag = 4,
49 alternate_flag = 8,
50 zero_flag = 16
51 };
52
53 /*
54 * Common state
55 */
56
57 struct state {
58 unsigned char *str;
59 unsigned char *s;
60 unsigned char *theend;
61 size_t sz;
62 size_t max_sz;
63 int (*append_char)(struct state *, unsigned char);
64 int (*reserve)(struct state *, size_t);
65 /* XXX - methods */
66 };
67
68 #if 0
69 static int
70 as_reserve (struct state *state, size_t n)
71 {
72 if (state->s + n > state->theend) {
73 int off = state->s - state->str;
74 unsigned char *tmp;
75
76 if (state->max_sz && state->sz >= state->max_sz)
77 return 1;
78
79 state->sz = max(state->sz * 2, state->sz + n);
80 if (state->max_sz)
81 state->sz = min(state->sz, state->max_sz);
82 tmp = realloc (state->str, state->sz);
83 if (tmp == NULL)
84 return 1;
85 state->str = tmp;
86 state->s = state->str + off;
87 state->theend = state->str + state->sz - 1;
88 }
89 return 0;
90 }
91
92 static int
93 as_append_char (struct state *state, unsigned char c)
94 {
95 if(as_reserve (state, 1))
96 return 1;
97 else {
98 *state->s++ = c;
99 return 0;
100 }
101 }
102 #endif
103
104 static int
append_number(struct state * state,unsigned long num,unsigned base,char * rep,int width,int prec,int flags,int minusp)105 append_number(struct state *state,
106 unsigned long num, unsigned base, char *rep,
107 int width, int prec, int flags, int minusp)
108 {
109 int len = 0;
110 int i;
111
112 /* given precision, ignore zero flag */
113 if(prec != -1)
114 flags &= ~zero_flag;
115 else
116 prec = 1;
117 /* zero value with zero precision -> "" */
118 if(prec == 0 && num == 0)
119 return 0;
120 do{
121 if((*state->append_char)(state, rep[num % base]))
122 return 1;
123 len++;
124 num /= base;
125 }while(num);
126 prec -= len;
127 /* pad with prec zeros */
128 while(prec-- > 0){
129 if((*state->append_char)(state, '0'))
130 return 1;
131 len++;
132 }
133 /* add length of alternate prefix (added later) to len */
134 if(flags & alternate_flag && (base == 16 || base == 8))
135 len += base / 8;
136 /* pad with zeros */
137 if(flags & zero_flag){
138 width -= len;
139 if(minusp || (flags & space_flag) || (flags & plus_flag))
140 width--;
141 while(width-- > 0){
142 if((*state->append_char)(state, '0'))
143 return 1;
144 len++;
145 }
146 }
147 /* add alternate prefix */
148 if(flags & alternate_flag && (base == 16 || base == 8)){
149 if(base == 16)
150 if((*state->append_char)(state, rep[10] + 23)) /* XXX */
151 return 1;
152 if((*state->append_char)(state, '0'))
153 return 1;
154 }
155 /* add sign */
156 if(minusp){
157 if((*state->append_char)(state, '-'))
158 return 1;
159 len++;
160 } else if(flags & plus_flag) {
161 if((*state->append_char)(state, '+'))
162 return 1;
163 len++;
164 } else if(flags & space_flag) {
165 if((*state->append_char)(state, ' '))
166 return 1;
167 len++;
168 }
169 if(flags & minus_flag)
170 /* swap before padding with spaces */
171 for(i = 0; i < len / 2; i++){
172 char c = state->s[-i-1];
173 state->s[-i-1] = state->s[-len+i];
174 state->s[-len+i] = c;
175 }
176 width -= len;
177 while(width-- > 0){
178 if((*state->append_char)(state, ' '))
179 return 1;
180 len++;
181 }
182 if(!(flags & minus_flag))
183 /* swap after padding with spaces */
184 for(i = 0; i < len / 2; i++){
185 char c = state->s[-i-1];
186 state->s[-i-1] = state->s[-len+i];
187 state->s[-len+i] = c;
188 }
189
190 return 0;
191 }
192
193 static int
append_string(struct state * state,unsigned char * arg,int width,int prec,int flags)194 append_string (struct state *state,
195 unsigned char *arg,
196 int width,
197 int prec,
198 int flags)
199 {
200 if(prec != -1)
201 width -= prec;
202 else
203 width -= strlen((char *)arg);
204 if(!(flags & minus_flag))
205 while(width-- > 0)
206 if((*state->append_char) (state, ' '))
207 return 1;
208 if (prec != -1) {
209 while (*arg && prec--)
210 if ((*state->append_char) (state, *arg++))
211 return 1;
212 } else {
213 while (*arg)
214 if ((*state->append_char) (state, *arg++))
215 return 1;
216 }
217 if(flags & minus_flag)
218 while(width-- > 0)
219 if((*state->append_char) (state, ' '))
220 return 1;
221 return 0;
222 }
223
224 static int
append_char(struct state * state,unsigned char arg,int width,int flags)225 append_char(struct state *state,
226 unsigned char arg,
227 int width,
228 int flags)
229 {
230 while(!(flags & minus_flag) && --width > 0)
231 if((*state->append_char) (state, ' '))
232 return 1;
233
234 if((*state->append_char) (state, arg))
235 return 1;
236 while((flags & minus_flag) && --width > 0)
237 if((*state->append_char) (state, ' '))
238 return 1;
239
240 return 0;
241 }
242
243 /*
244 * This can't be made into a function...
245 */
246
247 #define PARSE_INT_FORMAT(res, arg, unsig) \
248 if (long_flag) \
249 res = (unsig long)va_arg(arg, unsig long); \
250 else if (short_flag) \
251 res = (unsig short)va_arg(arg, unsig int); \
252 else \
253 res = (unsig int)va_arg(arg, unsig int)
254
255 /*
256 * zyxprintf - return 0 or -1
257 */
258
259 static int
xyzprintf(struct state * state,const char * char_format,va_list ap)260 xyzprintf (struct state *state, const char *char_format, va_list ap)
261 {
262 const unsigned char *format = (const unsigned char *)char_format;
263 unsigned char c;
264
265 while((c = *format++)) {
266 if (c == '%') {
267 int flags = 0;
268 int width = 0;
269 int prec = -1;
270 int long_flag = 0;
271 int short_flag = 0;
272
273 /* flags */
274 while((c = *format++)){
275 if(c == '-')
276 flags |= minus_flag;
277 else if(c == '+')
278 flags |= plus_flag;
279 else if(c == ' ')
280 flags |= space_flag;
281 else if(c == '#')
282 flags |= alternate_flag;
283 else if(c == '0')
284 flags |= zero_flag;
285 else
286 break;
287 }
288
289 if((flags & space_flag) && (flags & plus_flag))
290 flags ^= space_flag;
291
292 if((flags & minus_flag) && (flags & zero_flag))
293 flags ^= zero_flag;
294
295 /* width */
296 if (isdigit(c))
297 do {
298 width = width * 10 + c - '0';
299 c = *format++;
300 } while(isdigit(c));
301 else if(c == '*') {
302 width = va_arg(ap, int);
303 c = *format++;
304 }
305
306 /* precision */
307 if (c == '.') {
308 prec = 0;
309 c = *format++;
310 if (isdigit(c))
311 do {
312 prec = prec * 10 + c - '0';
313 c = *format++;
314 } while(isdigit(c));
315 else if (c == '*') {
316 prec = va_arg(ap, int);
317 c = *format++;
318 }
319 }
320
321 /* size */
322
323 if (c == 'h') {
324 short_flag = 1;
325 c = *format++;
326 } else if (c == 'l') {
327 long_flag = 1;
328 c = *format++;
329 }
330
331 switch (c) {
332 case 'c' :
333 if(append_char(state, va_arg(ap, int), width, flags))
334 return -1;
335 break;
336 case 's' :
337 if (append_string(state,
338 va_arg(ap, unsigned char*),
339 width,
340 prec,
341 flags))
342 return -1;
343 break;
344 case 'd' :
345 case 'i' : {
346 long arg;
347 unsigned long num;
348 int minusp = 0;
349
350 PARSE_INT_FORMAT(arg, ap, signed);
351
352 if (arg < 0) {
353 minusp = 1;
354 num = -arg;
355 } else
356 num = arg;
357
358 if (append_number (state, num, 10, "0123456789",
359 width, prec, flags, minusp))
360 return -1;
361 break;
362 }
363 case 'u' : {
364 unsigned long arg;
365
366 PARSE_INT_FORMAT(arg, ap, unsigned);
367
368 if (append_number (state, arg, 10, "0123456789",
369 width, prec, flags, 0))
370 return -1;
371 break;
372 }
373 case 'o' : {
374 unsigned long arg;
375
376 PARSE_INT_FORMAT(arg, ap, unsigned);
377
378 if (append_number (state, arg, 010, "01234567",
379 width, prec, flags, 0))
380 return -1;
381 break;
382 }
383 case 'x' : {
384 unsigned long arg;
385
386 PARSE_INT_FORMAT(arg, ap, unsigned);
387
388 if (append_number (state, arg, 0x10, "0123456789abcdef",
389 width, prec, flags, 0))
390 return -1;
391 break;
392 }
393 case 'X' :{
394 unsigned long arg;
395
396 PARSE_INT_FORMAT(arg, ap, unsigned);
397
398 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
399 width, prec, flags, 0))
400 return -1;
401 break;
402 }
403 case 'p' : {
404 unsigned long arg = (unsigned long)va_arg(ap, void*);
405
406 if (append_number (state, arg, 0x10, "0123456789ABCDEF",
407 width, prec, flags, 0))
408 return -1;
409 break;
410 }
411 case 'n' : {
412 int *arg = va_arg(ap, int *);
413 *arg = state->s - state->str;
414 break;
415 }
416 case '\0' :
417 --format;
418 /* FALLTHROUGH */
419 case '%' :
420 if ((*state->append_char)(state, c))
421 return -1;
422 break;
423 default :
424 if ( (*state->append_char)(state, '%')
425 || (*state->append_char)(state, c))
426 return -1;
427 break;
428 }
429 } else
430 if ((*state->append_char) (state, c))
431 return -1;
432 }
433 return 0;
434 }
435
436 #if 0
437 #ifndef HAVE_ASPRINTF
438 int
439 asprintf (char **ret, const char *format, ...)
440 {
441 va_list args;
442 int val;
443
444 va_start(args, format);
445 val = vasprintf (ret, format, args);
446
447 #ifdef PARANOIA
448 {
449 int ret2;
450 char *tmp;
451 tmp = malloc (val + 1);
452 if (tmp == NULL)
453 abort ();
454
455 ret2 = vsprintf (tmp, format, args);
456 if (val != ret2 || strcmp(*ret, tmp))
457 abort ();
458 free (tmp);
459 }
460 #endif
461
462 va_end(args);
463 return val;
464 }
465 #endif
466
467 #ifndef HAVE_VASNPRINTF
468 int
469 nd_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
470 {
471 int st;
472 size_t len;
473 struct state state;
474
475 state.max_sz = max_sz;
476 state.sz = 1;
477 state.str = malloc(state.sz);
478 if (state.str == NULL) {
479 *ret = NULL;
480 return -1;
481 }
482 state.s = state.str;
483 state.theend = state.s + state.sz - 1;
484 state.append_char = as_append_char;
485 state.reserve = as_reserve;
486
487 st = xyzprintf (&state, format, args);
488 if (st) {
489 free (state.str);
490 *ret = NULL;
491 return -1;
492 } else {
493 char *tmp;
494
495 *state.s = '\0';
496 len = state.s - state.str;
497 tmp = realloc (state.str, len+1);
498 if (tmp == NULL) {
499 free (state.str);
500 *ret = NULL;
501 return -1;
502 }
503 *ret = tmp;
504 return len;
505 }
506 }
507 #endif
508 #endif
509