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