1 /* 2 * PROGRAMMERS: David Welch 3 * Eric Kohl 4 * 5 * TODO: 6 * - Verify the implementation of '%Z'. 7 */ 8 9 /* 10 * linux/lib/vsprintf.c 11 * 12 * Copyright (C) 1991, 1992 Linus Torvalds 13 */ 14 15 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 16 /* 17 * Wirzenius wrote this portably, Torvalds fucked it up :-) 18 */ 19 20 #include <ndk/ntndk.h> 21 22 #define ZEROPAD 1 /* pad with zero */ 23 #define SIGN 2 /* unsigned/signed long */ 24 #define PLUS 4 /* show plus */ 25 #define SPACE 8 /* space if plus */ 26 #define LEFT 16 /* left justified */ 27 #define SPECIAL 32 /* 0x */ 28 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 29 #define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */ 30 typedef struct { 31 unsigned int mantissal:32; 32 unsigned int mantissah:20; 33 unsigned int exponent:11; 34 unsigned int sign:1; 35 } double_t; 36 37 static 38 __inline 39 int 40 _isinf(double __x) 41 { 42 union 43 { 44 double* __x; 45 double_t* x; 46 } x; 47 48 x.__x = &__x; 49 return ( x.x->exponent == 0x7ff && ( x.x->mantissah == 0 && x.x->mantissal == 0 )); 50 } 51 52 static 53 __inline 54 int 55 _isnan(double __x) 56 { 57 union 58 { 59 double* __x; 60 double_t* x; 61 } x; 62 x.__x = &__x; 63 return ( x.x->exponent == 0x7ff && ( x.x->mantissah != 0 || x.x->mantissal != 0 )); 64 } 65 66 67 static 68 __inline 69 int 70 do_div(long long *n, int base) 71 { 72 int a; 73 a = ((unsigned long long) *n) % (unsigned) base; 74 *n = ((unsigned long long) *n) / (unsigned) base; 75 return a; 76 } 77 78 79 static int skip_atoi(const char **s) 80 { 81 int i=0; 82 83 while (isdigit(**s)) 84 i = i*10 + *((*s)++) - '0'; 85 return i; 86 } 87 88 89 static char * 90 number(char * buf, char * end, long long num, int base, int size, int precision, int type) 91 { 92 char c,sign,tmp[66]; 93 const char *digits; 94 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 95 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 96 int i; 97 98 digits = (type & LARGE) ? large_digits : small_digits; 99 if (type & LEFT) 100 type &= ~ZEROPAD; 101 if (base < 2 || base > 36) 102 return 0; 103 c = (type & ZEROPAD) ? '0' : ' '; 104 sign = 0; 105 if (type & SIGN) { 106 if (num < 0) { 107 sign = '-'; 108 num = -num; 109 size--; 110 } else if (type & PLUS) { 111 sign = '+'; 112 size--; 113 } else if (type & SPACE) { 114 sign = ' '; 115 size--; 116 } 117 } 118 119 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) { 120 if (base == 16) 121 size -= 2; 122 123 } 124 i = 0; 125 if ((num == 0) && (precision !=0)) 126 tmp[i++] = '0'; 127 else while (num != 0) 128 tmp[i++] = digits[do_div(&num,base)]; 129 if (i > precision) 130 precision = i; 131 size -= precision; 132 if (!(type&(ZEROPAD+LEFT))) { 133 while(size-->0) { 134 if (buf <= end) 135 *buf = ' '; 136 ++buf; 137 } 138 } 139 if (sign) { 140 if (buf <= end) 141 *buf = sign; 142 ++buf; 143 } 144 145 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) { 146 if (base==16) { 147 if (buf <= end) 148 *buf = '0'; 149 ++buf; 150 if (buf <= end) 151 *buf = digits[33]; 152 ++buf; 153 } 154 } 155 156 if (!(type & LEFT)) { 157 while (size-- > 0) { 158 if (buf <= end) 159 *buf = c; 160 ++buf; 161 } 162 } 163 while (i < precision--) { 164 if (buf <= end) 165 *buf = '0'; 166 ++buf; 167 } 168 while (i-- > 0) { 169 if (buf <= end) 170 *buf = tmp[i]; 171 ++buf; 172 } 173 while (size-- > 0) { 174 if (buf <= end) 175 *buf = ' '; 176 ++buf; 177 } 178 179 return buf; 180 } 181 182 static char * 183 numberf(char * buf, char * end, double num, int base, int size, int precision, int type) 184 { 185 char c,sign,tmp[66]; 186 const char *digits; 187 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 188 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 189 int i; 190 long long x; 191 192 /* FIXME 193 the float version of number is direcly copy of number 194 */ 195 196 digits = (type & LARGE) ? large_digits : small_digits; 197 if (type & LEFT) 198 type &= ~ZEROPAD; 199 if (base < 2 || base > 36) 200 return 0; 201 c = (type & ZEROPAD) ? '0' : ' '; 202 sign = 0; 203 if (type & SIGN) { 204 if (num < 0) { 205 sign = '-'; 206 num = -num; 207 size--; 208 } else if (type & PLUS) { 209 sign = '+'; 210 size--; 211 } else if (type & SPACE) { 212 sign = ' '; 213 size--; 214 } 215 } 216 if (type & SPECIAL) { 217 if (base == 16) 218 size -= 2; 219 else if (base == 8) 220 size--; 221 } 222 i = 0; 223 if (num == 0) 224 tmp[i++] = '0'; 225 else while (num != 0) 226 { 227 x = num; 228 tmp[i++] = digits[do_div(&x,base)]; 229 num=x; 230 } 231 if (i > precision) 232 precision = i; 233 size -= precision; 234 if (!(type&(ZEROPAD+LEFT))) { 235 while(size-->0) { 236 if (buf <= end) 237 *buf = ' '; 238 ++buf; 239 } 240 } 241 if (sign) { 242 if (buf <= end) 243 *buf = sign; 244 ++buf; 245 } 246 if (type & SPECIAL) { 247 if (base==8) { 248 if (buf <= end) 249 *buf = '0'; 250 ++buf; 251 } else if (base==16) { 252 if (buf <= end) 253 *buf = '0'; 254 ++buf; 255 if (buf <= end) 256 *buf = digits[33]; 257 ++buf; 258 } 259 } 260 if (!(type & LEFT)) { 261 while (size-- > 0) { 262 if (buf <= end) 263 *buf = c; 264 ++buf; 265 } 266 } 267 while (i < precision--) { 268 if (buf <= end) 269 *buf = '0'; 270 ++buf; 271 } 272 while (i-- > 0) { 273 if (buf <= end) 274 *buf = tmp[i]; 275 ++buf; 276 } 277 while (size-- > 0) { 278 if (buf <= end) 279 *buf = ' '; 280 ++buf; 281 } 282 return buf; 283 } 284 285 static char* 286 string(char* buf, char* end, const char* s, int len, int field_width, int precision, int flags) 287 { 288 int i; 289 char c; 290 291 c = (flags & ZEROPAD) ? '0' : ' '; 292 293 if (s == NULL) 294 { 295 s = "<NULL>"; 296 len = 6; 297 } 298 else 299 { 300 if (len == -1) 301 { 302 len = 0; 303 while ((unsigned int)len < (unsigned int)precision && s[len]) 304 len++; 305 } 306 else 307 { 308 if ((unsigned int)len > (unsigned int)precision) 309 len = precision; 310 } 311 } 312 if (!(flags & LEFT)) 313 while (len < field_width--) 314 { 315 if (buf <= end) 316 *buf = c; 317 ++buf; 318 } 319 for (i = 0; i < len; ++i) 320 { 321 if (buf <= end) 322 *buf = *s++; 323 ++buf; 324 } 325 while (len < field_width--) 326 { 327 if (buf <= end) 328 *buf = ' '; 329 ++buf; 330 } 331 return buf; 332 } 333 334 static char* 335 stringw(char* buf, char* end, const wchar_t* sw, int len, int field_width, int precision, int flags) 336 { 337 int i; 338 char c; 339 340 c = (flags & ZEROPAD) ? '0' : ' '; 341 342 if (sw == NULL) 343 { 344 sw = L"<NULL>"; 345 len = 6; 346 } 347 else 348 { 349 if (len == -1) 350 { 351 len = 0; 352 while ((unsigned int)len < (unsigned int)precision && sw[len]) 353 len++; 354 } 355 else 356 { 357 if ((unsigned int)len > (unsigned int)precision) 358 len = precision; 359 } 360 } 361 if (!(flags & LEFT)) 362 while (len < field_width--) 363 { 364 if (buf <= end) 365 *buf = c; 366 buf++; 367 } 368 for (i = 0; i < len; ++i) 369 { 370 if (buf <= end) 371 *buf = (unsigned char)(*sw++); 372 buf++; 373 } 374 while (len < field_width--) 375 { 376 if (buf <= end) 377 *buf = ' '; 378 buf++; 379 } 380 return buf; 381 } 382 383 /* 384 * @implemented 385 */ 386 int __cdecl _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args) 387 { 388 int len; 389 unsigned long long num; 390 double _double; 391 392 int base; 393 char *str, *end; 394 const char *s; 395 const wchar_t *sw; 396 397 int flags; /* flags to number() */ 398 399 int field_width; /* width of output field */ 400 int precision; /* min. # of digits for integers; max 401 number of chars for from string */ 402 int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */ 403 404 /* clear the string buffer with zero so we do not need NULL terment it at end */ 405 406 str = buf; 407 end = buf + cnt - 1; 408 if (end < buf - 1) { 409 end = ((char *) -1); 410 cnt = end - buf + 1; 411 } 412 413 for ( ; *fmt ; ++fmt) { 414 if (*fmt != '%') { 415 if (str <= end) 416 *str = *fmt; 417 ++str; 418 continue; 419 } 420 421 /* process flags */ 422 flags = 0; 423 repeat: 424 ++fmt; /* this also skips first '%' */ 425 switch (*fmt) { 426 case '-': flags |= LEFT; goto repeat; 427 case '+': flags |= PLUS; goto repeat; 428 case ' ': flags |= SPACE; goto repeat; 429 case '#': flags |= SPECIAL; goto repeat; 430 case '0': flags |= ZEROPAD; goto repeat; 431 } 432 433 /* get field width */ 434 field_width = -1; 435 if (isdigit(*fmt)) 436 field_width = skip_atoi(&fmt); 437 else if (*fmt == '*') { 438 ++fmt; 439 /* it's the next argument */ 440 field_width = va_arg(args, int); 441 if (field_width < 0) { 442 field_width = -field_width; 443 flags |= LEFT; 444 } 445 } 446 447 /* get the precision */ 448 precision = -1; 449 if (*fmt == '.') { 450 ++fmt; 451 if (isdigit(*fmt)) 452 precision = skip_atoi(&fmt); 453 else if (*fmt == '*') { 454 ++fmt; 455 /* it's the next argument */ 456 precision = va_arg(args, int); 457 } 458 if (precision < 0) 459 precision = 0; 460 } 461 462 /* get the conversion qualifier */ 463 qualifier = -1; 464 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') { 465 qualifier = *fmt; 466 ++fmt; 467 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') { 468 qualifier = *fmt; 469 fmt += 3; 470 } else if (*fmt == 'I' && *(fmt+1) == '3' && *(fmt+2) == '2') { 471 qualifier = 'l'; 472 fmt += 3; 473 } else if (*fmt == 'F' && *(fmt+1) == 'p') { 474 fmt += 1; 475 flags |= REMOVEHEX; 476 } 477 478 /* default base */ 479 base = 10; 480 481 switch (*fmt) { 482 case 'c': /* finished */ 483 if (qualifier == 'l' || qualifier == 'w') { 484 wchar_t sw1[2]; 485 /* print unicode string */ 486 sw1[0] = (wchar_t) va_arg(args, int); 487 sw1[1] = 0; 488 str = stringw(str, end, (wchar_t *)&sw1, -1, field_width, precision, flags); 489 } else { 490 char s1[2]; 491 /* print ascii string */ 492 s1[0] = ( unsigned char) va_arg(args, int); 493 s1[1] = 0; 494 str = string(str, end, (char *)&s1, -1, field_width, precision, flags); 495 } 496 continue; 497 498 case 'C': /* finished */ 499 if (!(flags & LEFT)) 500 while (--field_width > 0) { 501 if (str <= end) 502 *str = ' '; 503 ++str; 504 } 505 if (qualifier == 'h') { 506 if (str <= end) 507 *str = (unsigned char) va_arg(args, int); 508 ++str; 509 } else { 510 if (str <= end) 511 *str = (unsigned char)(wchar_t) va_arg(args, int); 512 ++str; 513 } 514 while (--field_width > 0) { 515 if (str <= end) 516 *str = ' '; 517 ++str; 518 } 519 continue; 520 521 case 's': /* finished */ 522 if (qualifier == 'l' || qualifier == 'w') { 523 /* print unicode string */ 524 sw = va_arg(args, wchar_t *); 525 str = stringw(str, end, sw, -1, field_width, precision, flags); 526 } else { 527 /* print ascii string */ 528 s = va_arg(args, char *); 529 str = string(str, end, s, -1, field_width, precision, flags); 530 } 531 continue; 532 533 case 'S': 534 if (qualifier == 'h') { 535 /* print ascii string */ 536 s = va_arg(args, char *); 537 str = string(str, end, s, -1, field_width, precision, flags); 538 } else { 539 /* print unicode string */ 540 sw = va_arg(args, wchar_t *); 541 str = stringw(str, end, sw, -1, field_width, precision, flags); 542 } 543 continue; 544 545 case 'Z': 546 if (qualifier == 'w') { 547 /* print counted unicode string */ 548 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING); 549 if ((pus == NULL) || (pus->Buffer == NULL)) { 550 sw = NULL; 551 len = -1; 552 } else { 553 sw = pus->Buffer; 554 len = pus->Length / sizeof(WCHAR); 555 } 556 str = stringw(str, end, sw, len, field_width, precision, flags); 557 } else { 558 /* print counted ascii string */ 559 PANSI_STRING pus = va_arg(args, PANSI_STRING); 560 if ((pus == NULL) || (pus->Buffer == NULL)) { 561 s = NULL; 562 len = -1; 563 } else { 564 s = pus->Buffer; 565 len = pus->Length; 566 } 567 str = string(str, end, s, len, field_width, precision, flags); 568 } 569 continue; 570 571 case 'p': 572 if ((flags & LARGE) == 0) 573 flags |= LARGE; 574 575 if (field_width == -1) { 576 field_width = 2 * sizeof(void *); 577 flags |= ZEROPAD; 578 } 579 str = number(str, end, 580 (ULONG_PTR) va_arg(args, void *), 16, 581 field_width, precision, flags); 582 continue; 583 584 case 'n': 585 /* FIXME: What does C99 say about the overflow case here? */ 586 if (qualifier == 'l') { 587 long * ip = va_arg(args, long *); 588 *ip = (str - buf); 589 } else { 590 int * ip = va_arg(args, int *); 591 *ip = (str - buf); 592 } 593 continue; 594 595 /* float number formats - set up the flags and "break" */ 596 case 'e': 597 case 'E': 598 case 'f': 599 case 'g': 600 case 'G': 601 _double = (double)va_arg(args, double); 602 if ( _isnan(_double) ) { 603 s = "Nan"; 604 len = 3; 605 while ( len > 0 ) { 606 if (str <= end) 607 *str = *s++; 608 ++str; 609 len --; 610 } 611 } else if ( _isinf(_double) < 0 ) { 612 s = "-Inf"; 613 len = 4; 614 while ( len > 0 ) { 615 if (str <= end) 616 *str = *s++; 617 ++str; 618 len --; 619 } 620 } else if ( _isinf(_double) > 0 ) { 621 s = "+Inf"; 622 len = 4; 623 while ( len > 0 ) { 624 if (str <= end) 625 *str = *s++; 626 ++str; 627 len --; 628 } 629 } else { 630 if ( precision == -1 ) 631 precision = 6; 632 str = numberf(str, end, (int)_double, base, field_width, precision, flags); 633 } 634 635 continue; 636 637 638 /* integer number formats - set up the flags and "break" */ 639 case 'o': 640 base = 8; 641 break; 642 643 case 'b': 644 base = 2; 645 break; 646 647 case 'X': 648 flags |= LARGE; 649 case 'x': 650 base = 16; 651 break; 652 653 case 'd': 654 case 'i': 655 flags |= SIGN; 656 case 'u': 657 break; 658 659 default: 660 if (*fmt) { 661 if (str <= end) 662 *str = *fmt; 663 ++str; 664 } else 665 --fmt; 666 continue; 667 } 668 669 if (qualifier == 'I') 670 num = va_arg(args, unsigned long long); 671 else if (qualifier == 'l') { 672 if (flags & SIGN) 673 num = va_arg(args, long); 674 else 675 num = va_arg(args, unsigned long); 676 } 677 else if (qualifier == 'h') { 678 if (flags & SIGN) 679 num = va_arg(args, int); 680 else 681 num = va_arg(args, unsigned int); 682 } 683 else { 684 if (flags & SIGN) 685 num = va_arg(args, int); 686 else 687 num = va_arg(args, unsigned int); 688 } 689 str = number(str, end, num, base, field_width, precision, flags); 690 } 691 if (str <= end) 692 *str = '\0'; 693 else if (cnt > 0) 694 /* don't write out a null byte if the buf size is zero */ 695 *end = '\0'; 696 return str-buf; 697 } 698 699 700 /* 701 * @implemented 702 */ 703 int sprintf(char * buf, const char *fmt, ...) 704 { 705 va_list args; 706 int i; 707 708 va_start(args, fmt); 709 i=_vsnprintf(buf,MAXLONG,fmt,args); 710 va_end(args); 711 return i; 712 } 713 714 715 /* 716 * @implemented 717 */ 718 int _snprintf(char * buf, size_t cnt, const char *fmt, ...) 719 { 720 va_list args; 721 int i; 722 723 va_start(args, fmt); 724 i=_vsnprintf(buf,cnt,fmt,args); 725 va_end(args); 726 return i; 727 } 728 729 730 /* 731 * @implemented 732 */ 733 int __cdecl vsprintf(char *buf, const char *fmt, va_list args) 734 { 735 return _vsnprintf(buf,MAXLONG,fmt,args); 736 } 737 738 /* EOF */ 739