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