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