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 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 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 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 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