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