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