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