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