00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00039 #include <unistd.h>
00040 #include <stdio.h>
00041 #include <io/printf_core.h>
00042 #include <ctype.h>
00043 #include <str.h>
00044
00046 #define __PRINTF_FLAG_PREFIX 0x00000001
00047
00049 #define __PRINTF_FLAG_SIGNED 0x00000002
00050
00052 #define __PRINTF_FLAG_ZEROPADDED 0x00000004
00053
00055 #define __PRINTF_FLAG_LEFTALIGNED 0x00000010
00056
00058 #define __PRINTF_FLAG_SHOWPLUS 0x00000020
00059
00061 #define __PRINTF_FLAG_SPACESIGN 0x00000040
00062
00064 #define __PRINTF_FLAG_BIGCHARS 0x00000080
00065
00067 #define __PRINTF_FLAG_NEGATIVE 0x00000100
00068
00074 #define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
00075
00078 typedef enum {
00079 PrintfQualifierByte = 0,
00080 PrintfQualifierShort,
00081 PrintfQualifierInt,
00082 PrintfQualifierLong,
00083 PrintfQualifierLongLong,
00084 PrintfQualifierPointer,
00085 PrintfQualifierSize
00086 } qualifier_t;
00087
00088 static const char *nullstr = "(NULL)";
00089 static const char *digits_small = "0123456789abcdef";
00090 static const char *digits_big = "0123456789ABCDEF";
00091 static const char invalch = U_SPECIAL;
00092
00103 static int printf_putnchars(const char *buf, size_t size,
00104 printf_spec_t *ps)
00105 {
00106 return ps->str_write((void *) buf, size, ps->data);
00107 }
00108
00119 static int printf_wputnchars(const wchar_t *buf, size_t size,
00120 printf_spec_t *ps)
00121 {
00122 return ps->wstr_write((void *) buf, size, ps->data);
00123 }
00124
00133 static int printf_putstr(const char *str, printf_spec_t *ps)
00134 {
00135 if (str == NULL)
00136 return printf_putnchars(nullstr, str_size(nullstr), ps);
00137
00138 return ps->str_write((void *) str, str_size(str), ps->data);
00139 }
00140
00149 static int printf_putchar(const char ch, printf_spec_t *ps)
00150 {
00151 if (!ascii_check(ch))
00152 return ps->str_write((void *) &invalch, 1, ps->data);
00153
00154 return ps->str_write(&ch, 1, ps->data);
00155 }
00156
00165 static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
00166 {
00167 if (!chr_check(ch))
00168 return ps->str_write((void *) &invalch, 1, ps->data);
00169
00170 return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
00171 }
00172
00182 static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
00183 {
00184 size_t counter = 0;
00185 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00186 while (--width > 0) {
00187
00188
00189
00190
00191 if (printf_putchar(' ', ps) > 0)
00192 counter++;
00193 }
00194 }
00195
00196 if (printf_putchar(ch, ps) > 0)
00197 counter++;
00198
00199 while (--width > 0) {
00200
00201
00202
00203
00204 if (printf_putchar(' ', ps) > 0)
00205 counter++;
00206 }
00207
00208 return (int) (counter + 1);
00209 }
00210
00220 static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
00221 {
00222 size_t counter = 0;
00223 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00224 while (--width > 0) {
00225
00226
00227
00228
00229 if (printf_putchar(' ', ps) > 0)
00230 counter++;
00231 }
00232 }
00233
00234 if (printf_putwchar(ch, ps) > 0)
00235 counter++;
00236
00237 while (--width > 0) {
00238
00239
00240
00241
00242 if (printf_putchar(' ', ps) > 0)
00243 counter++;
00244 }
00245
00246 return (int) (counter + 1);
00247 }
00248
00258 static int print_str(char *str, int width, unsigned int precision,
00259 uint32_t flags, printf_spec_t *ps)
00260 {
00261 if (str == NULL)
00262 return printf_putstr(nullstr, ps);
00263
00264
00265 size_t strw = str_length(str);
00266 if (precision == 0)
00267 precision = strw;
00268
00269
00270 size_t counter = 0;
00271 width -= precision;
00272 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00273 while (width-- > 0) {
00274 if (printf_putchar(' ', ps) == 1)
00275 counter++;
00276 }
00277 }
00278
00279
00280 int retval;
00281 size_t size = str_lsize(str, precision);
00282 if ((retval = printf_putnchars(str, size, ps)) < 0)
00283 return -counter;
00284
00285 counter += retval;
00286
00287
00288 while (width-- > 0) {
00289 if (printf_putchar(' ', ps) == 1)
00290 counter++;
00291 }
00292
00293 return ((int) counter);
00294
00295 }
00296
00306 static int print_wstr(wchar_t *str, int width, unsigned int precision,
00307 uint32_t flags, printf_spec_t *ps)
00308 {
00309 if (str == NULL)
00310 return printf_putstr(nullstr, ps);
00311
00312
00313 size_t strw = wstr_length(str);
00314 if (precision == 0)
00315 precision = strw;
00316
00317
00318 size_t counter = 0;
00319 width -= precision;
00320 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00321 while (width-- > 0) {
00322 if (printf_putchar(' ', ps) == 1)
00323 counter++;
00324 }
00325 }
00326
00327
00328 int retval;
00329 size_t size = wstr_lsize(str, precision);
00330 if ((retval = printf_wputnchars(str, size, ps)) < 0)
00331 return -counter;
00332
00333 counter += retval;
00334
00335
00336 while (width-- > 0) {
00337 if (printf_putchar(' ', ps) == 1)
00338 counter++;
00339 }
00340
00341 return ((int) counter);
00342 }
00343
00357 static int print_number(uint64_t num, int width, int precision, int base,
00358 uint32_t flags, printf_spec_t *ps)
00359 {
00360 const char *digits;
00361 if (flags & __PRINTF_FLAG_BIGCHARS)
00362 digits = digits_big;
00363 else
00364 digits = digits_small;
00365
00366 char data[PRINT_NUMBER_BUFFER_SIZE];
00367 char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
00368
00369
00370 int size = 0;
00371
00372
00373 *ptr-- = 0;
00374
00375 if (num == 0) {
00376 *ptr-- = '0';
00377 size++;
00378 } else {
00379 do {
00380 *ptr-- = digits[num % base];
00381 size++;
00382 } while (num /= base);
00383 }
00384
00385
00386 int number_size = size;
00387
00388
00389
00390
00391
00392 if (flags & __PRINTF_FLAG_PREFIX) {
00393 switch (base) {
00394 case 2:
00395
00396 size += 2;
00397 break;
00398 case 8:
00399 size++;
00400 break;
00401 case 16:
00402 size += 2;
00403 break;
00404 }
00405 }
00406
00407 char sgn = 0;
00408 if (flags & __PRINTF_FLAG_SIGNED) {
00409 if (flags & __PRINTF_FLAG_NEGATIVE) {
00410 sgn = '-';
00411 size++;
00412 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
00413 sgn = '+';
00414 size++;
00415 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
00416 sgn = ' ';
00417 size++;
00418 }
00419 }
00420
00421 if (flags & __PRINTF_FLAG_LEFTALIGNED)
00422 flags &= ~__PRINTF_FLAG_ZEROPADDED;
00423
00424
00425
00426
00427
00428 if (flags & __PRINTF_FLAG_ZEROPADDED) {
00429 if ((precision == 0) && (width > size))
00430 precision = width - size + number_size;
00431 }
00432
00433
00434 if (number_size > precision) {
00435
00436 precision = number_size;
00437 }
00438
00439 width -= precision + size - number_size;
00440 size_t counter = 0;
00441
00442 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00443 while (width-- > 0) {
00444 if (printf_putchar(' ', ps) == 1)
00445 counter++;
00446 }
00447 }
00448
00449
00450 if (sgn) {
00451 if (printf_putchar(sgn, ps) == 1)
00452 counter++;
00453 }
00454
00455
00456 if (flags & __PRINTF_FLAG_PREFIX) {
00457 switch (base) {
00458 case 2:
00459
00460 if (printf_putchar('0', ps) == 1)
00461 counter++;
00462 if (flags & __PRINTF_FLAG_BIGCHARS) {
00463 if (printf_putchar('B', ps) == 1)
00464 counter++;
00465 } else {
00466 if (printf_putchar('b', ps) == 1)
00467 counter++;
00468 }
00469 break;
00470 case 8:
00471 if (printf_putchar('o', ps) == 1)
00472 counter++;
00473 break;
00474 case 16:
00475 if (printf_putchar('0', ps) == 1)
00476 counter++;
00477 if (flags & __PRINTF_FLAG_BIGCHARS) {
00478 if (printf_putchar('X', ps) == 1)
00479 counter++;
00480 } else {
00481 if (printf_putchar('x', ps) == 1)
00482 counter++;
00483 }
00484 break;
00485 }
00486 }
00487
00488
00489 precision -= number_size;
00490 while (precision-- > 0) {
00491 if (printf_putchar('0', ps) == 1)
00492 counter++;
00493 }
00494
00495
00496 int retval;
00497 if ((retval = printf_putstr(++ptr, ps)) > 0)
00498 counter += retval;
00499
00500
00501
00502 while (width-- > 0) {
00503 if (printf_putchar(' ', ps) == 1)
00504 counter++;
00505 }
00506
00507 return ((int) counter);
00508 }
00509
00599 int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
00600 {
00601 size_t i;
00602 size_t nxt = 0;
00603 size_t j = 0;
00604
00605 size_t counter = 0;
00606 int retval;
00607
00608 while (true) {
00609 i = nxt;
00610 wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00611
00612 if (uc == 0)
00613 break;
00614
00615
00616 if (uc == '%') {
00617
00618 if (i > j) {
00619 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
00620
00621 counter = -counter;
00622 goto out;
00623 }
00624 counter += retval;
00625 }
00626
00627 j = i;
00628
00629
00630 uint32_t flags = 0;
00631 bool end = false;
00632
00633 do {
00634 i = nxt;
00635 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00636 switch (uc) {
00637 case '#':
00638 flags |= __PRINTF_FLAG_PREFIX;
00639 break;
00640 case '-':
00641 flags |= __PRINTF_FLAG_LEFTALIGNED;
00642 break;
00643 case '+':
00644 flags |= __PRINTF_FLAG_SHOWPLUS;
00645 break;
00646 case ' ':
00647 flags |= __PRINTF_FLAG_SPACESIGN;
00648 break;
00649 case '0':
00650 flags |= __PRINTF_FLAG_ZEROPADDED;
00651 break;
00652 default:
00653 end = true;
00654 };
00655 } while (!end);
00656
00657
00658 int width = 0;
00659 if (isdigit(uc)) {
00660 while (true) {
00661 width *= 10;
00662 width += uc - '0';
00663
00664 i = nxt;
00665 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00666 if (uc == 0)
00667 break;
00668 if (!isdigit(uc))
00669 break;
00670 }
00671 } else if (uc == '*') {
00672
00673 i = nxt;
00674 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00675 width = (int) va_arg(ap, int);
00676 if (width < 0) {
00677
00678 width *= -1;
00679 flags |= __PRINTF_FLAG_LEFTALIGNED;
00680 }
00681 }
00682
00683
00684 int precision = 0;
00685 if (uc == '.') {
00686 i = nxt;
00687 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00688 if (isdigit(uc)) {
00689 while (true) {
00690 precision *= 10;
00691 precision += uc - '0';
00692
00693 i = nxt;
00694 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00695 if (uc == 0)
00696 break;
00697 if (!isdigit(uc))
00698 break;
00699 }
00700 } else if (uc == '*') {
00701
00702 i = nxt;
00703 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00704 precision = (int) va_arg(ap, int);
00705 if (precision < 0) {
00706
00707 precision = 0;
00708 }
00709 }
00710 }
00711
00712 qualifier_t qualifier;
00713
00714 switch (uc) {
00718 case 'h':
00719
00720 qualifier = PrintfQualifierShort;
00721 i = nxt;
00722 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00723 if (uc == 'h') {
00724 i = nxt;
00725 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00726 qualifier = PrintfQualifierByte;
00727 }
00728 break;
00729 case 'l':
00730
00731 qualifier = PrintfQualifierLong;
00732 i = nxt;
00733 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00734 if (uc == 'l') {
00735 i = nxt;
00736 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00737 qualifier = PrintfQualifierLongLong;
00738 }
00739 break;
00740 case 'z':
00741 qualifier = PrintfQualifierSize;
00742 i = nxt;
00743 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
00744 break;
00745 default:
00746
00747 qualifier = PrintfQualifierInt;
00748 }
00749
00750 unsigned int base = 10;
00751
00752 switch (uc) {
00753
00754
00755
00756 case 's':
00757 if (qualifier == PrintfQualifierLong)
00758 retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
00759 else
00760 retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
00761
00762 if (retval < 0) {
00763 counter = -counter;
00764 goto out;
00765 }
00766
00767 counter += retval;
00768 j = nxt;
00769 goto next_char;
00770 case 'c':
00771 if (qualifier == PrintfQualifierLong)
00772 retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
00773 else
00774 retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
00775
00776 if (retval < 0) {
00777 counter = -counter;
00778 goto out;
00779 };
00780
00781 counter += retval;
00782 j = nxt;
00783 goto next_char;
00784
00785
00786
00787
00788 case 'P':
00789
00790 flags |= __PRINTF_FLAG_BIGCHARS;
00791 case 'p':
00792 flags |= __PRINTF_FLAG_PREFIX;
00793 flags |= __PRINTF_FLAG_ZEROPADDED;
00794 base = 16;
00795 qualifier = PrintfQualifierPointer;
00796 break;
00797 case 'b':
00798 base = 2;
00799 break;
00800 case 'o':
00801 base = 8;
00802 break;
00803 case 'd':
00804 case 'i':
00805 flags |= __PRINTF_FLAG_SIGNED;
00806 case 'u':
00807 break;
00808 case 'X':
00809 flags |= __PRINTF_FLAG_BIGCHARS;
00810 case 'x':
00811 base = 16;
00812 break;
00813
00814
00815 case '%':
00816 j = i;
00817 goto next_char;
00818
00819
00820
00821
00822 default:
00823
00824
00825
00826
00827 goto next_char;
00828 }
00829
00830
00831 size_t size;
00832 uint64_t number;
00833 switch (qualifier) {
00834 case PrintfQualifierByte:
00835 size = sizeof(unsigned char);
00836 number = (uint64_t) va_arg(ap, unsigned int);
00837 break;
00838 case PrintfQualifierShort:
00839 size = sizeof(unsigned short);
00840 number = (uint64_t) va_arg(ap, unsigned int);
00841 break;
00842 case PrintfQualifierInt:
00843 size = sizeof(unsigned int);
00844 number = (uint64_t) va_arg(ap, unsigned int);
00845 break;
00846 case PrintfQualifierLong:
00847 size = sizeof(unsigned long);
00848 number = (uint64_t) va_arg(ap, unsigned long);
00849 break;
00850 case PrintfQualifierLongLong:
00851 size = sizeof(unsigned long long);
00852 number = (uint64_t) va_arg(ap, unsigned long long);
00853 break;
00854 case PrintfQualifierPointer:
00855 size = sizeof(void *);
00856 precision = size << 1;
00857 number = (uint64_t) (uintptr_t) va_arg(ap, void *);
00858 break;
00859 case PrintfQualifierSize:
00860 size = sizeof(size_t);
00861 number = (uint64_t) va_arg(ap, size_t);
00862 break;
00863 default:
00864
00865 counter = -counter;
00866 goto out;
00867 }
00868
00869 if (flags & __PRINTF_FLAG_SIGNED) {
00870 if (number & (0x1 << (size * 8 - 1))) {
00871 flags |= __PRINTF_FLAG_NEGATIVE;
00872
00873 if (size == sizeof(uint64_t)) {
00874 number = -((int64_t) number);
00875 } else {
00876 number = ~number;
00877 number &=
00878 ~(0xFFFFFFFFFFFFFFFFll <<
00879 (size * 8));
00880 number++;
00881 }
00882 }
00883 }
00884
00885 if ((retval = print_number(number, width, precision,
00886 base, flags, ps)) < 0) {
00887 counter = -counter;
00888 goto out;
00889 }
00890
00891 counter += retval;
00892 j = nxt;
00893 }
00894 next_char:
00895 ;
00896 }
00897
00898 if (i > j) {
00899 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
00900
00901 counter = -counter;
00902 goto out;
00903 }
00904 counter += retval;
00905 }
00906
00907 out:
00908 return ((int) counter);
00909 }
00910