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
00038 #include <unistd.h>
00039 #include <stdio.h>
00040 #include <io/printf_core.h>
00041 #include <ctype.h>
00042 #include <string.h>
00043
00044 #include <async.h>
00045
00046 #define __PRINTF_FLAG_PREFIX 0x00000001
00047 #define __PRINTF_FLAG_SIGNED 0x00000002
00048 #define __PRINTF_FLAG_ZEROPADDED 0x00000004
00049 #define __PRINTF_FLAG_LEFTALIGNED 0x00000010
00050 #define __PRINTF_FLAG_SHOWPLUS 0x00000020
00051 #define __PRINTF_FLAG_SPACESIGN 0x00000040
00052 #define __PRINTF_FLAG_BIGCHARS 0x00000080
00053 #define __PRINTF_FLAG_NEGATIVE 0x00000100
00055 #define PRINT_NUMBER_BUFFER_SIZE (64+5)
00062 typedef enum {
00063 PrintfQualifierByte = 0,
00064 PrintfQualifierShort,
00065 PrintfQualifierInt,
00066 PrintfQualifierLong,
00067 PrintfQualifierLongLong,
00068 PrintfQualifierSizeT,
00069 PrintfQualifierPointer
00070 } qualifier_t;
00071
00072 static char digits_small[] = "0123456789abcdef";
00073 static char digits_big[] = "0123456789ABCDEF";
00081 static int printf_putnchars(const char * buf, size_t count, struct printf_spec *ps)
00082 {
00083 return ps->write((void *)buf, count, ps->data);
00084 }
00085
00091 static int printf_putstr(const char * str, struct printf_spec *ps)
00092 {
00093 size_t count;
00094
00095 if (str == NULL) {
00096 return printf_putnchars("(NULL)", 6, ps);
00097 }
00098
00099 for (count = 0; str[count] != 0; count++);
00100
00101 if (ps->write((void *) str, count, ps->data) == count) {
00102 return 0;
00103 }
00104
00105 return EOF;
00106 }
00107
00113 static int printf_putchar(int c, struct printf_spec *ps)
00114 {
00115 unsigned char ch = c;
00116
00117 return ps->write((void *) &ch, 1, ps->data);
00118 }
00119
00126 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
00127 {
00128 int counter = 0;
00129
00130 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00131 while (--width > 0) {
00132 if (printf_putchar(' ', ps) > 0)
00133 ++counter;
00134 }
00135 }
00136
00137 if (printf_putchar(c, ps) > 0)
00138 counter++;
00139
00140 while (--width > 0) {
00141 if (printf_putchar(' ', ps) > 0)
00142 ++counter;
00143 }
00144
00145 return ++counter;
00146 }
00147
00156 static int print_string(char *s, int width, int precision, uint64_t flags, struct printf_spec *ps)
00157 {
00158 int counter = 0;
00159 size_t size;
00160 int retval;
00161
00162 if (s == NULL) {
00163 return printf_putstr("(NULL)", ps);
00164 }
00165
00166 size = strlen(s);
00167
00168
00169
00170 if (precision == 0)
00171 precision = size;
00172
00173 width -= precision;
00174
00175 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00176 while (width-- > 0) {
00177 if (printf_putchar(' ', ps) == 1)
00178 counter++;
00179 }
00180 }
00181
00182 while (precision > size) {
00183 precision--;
00184 if (printf_putchar(' ', ps) == 1)
00185 ++counter;
00186 }
00187
00188 if ((retval = printf_putnchars(s, precision, ps)) < 0) {
00189 return -counter;
00190 }
00191
00192 counter += retval;
00193
00194 while (width-- > 0) {
00195 if (printf_putchar(' ', ps) == 1)
00196 ++counter;
00197 }
00198
00199 return counter;
00200 }
00201
00202
00217 static int print_number(uint64_t num, int width, int precision, int base , uint64_t flags, struct printf_spec *ps)
00218 {
00219 char *digits = digits_small;
00220 char d[PRINT_NUMBER_BUFFER_SIZE];
00221 char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
00222 int size = 0;
00223 int number_size;
00224 char sgn;
00225 int retval;
00226 int counter = 0;
00227
00228 if (flags & __PRINTF_FLAG_BIGCHARS)
00229 digits = digits_big;
00230
00231 *ptr-- = 0;
00232
00233 if (num == 0) {
00234 *ptr-- = '0';
00235 size++;
00236 } else {
00237 do {
00238 *ptr-- = digits[num % base];
00239 size++;
00240 } while (num /= base);
00241 }
00242
00243 number_size = size;
00244
00245
00246 if (flags & __PRINTF_FLAG_PREFIX) {
00247 switch(base) {
00248 case 2:
00249 size += 2;
00250 break;
00251 case 8:
00252 size++;
00253 break;
00254 case 16:
00255 size += 2;
00256 break;
00257 }
00258 }
00259
00260 sgn = 0;
00261 if (flags & __PRINTF_FLAG_SIGNED) {
00262 if (flags & __PRINTF_FLAG_NEGATIVE) {
00263 sgn = '-';
00264 size++;
00265 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
00266 sgn = '+';
00267 size++;
00268 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
00269 sgn = ' ';
00270 size++;
00271 }
00272 }
00273
00274 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
00275 flags &= ~__PRINTF_FLAG_ZEROPADDED;
00276 }
00277
00278
00279 if (flags & __PRINTF_FLAG_ZEROPADDED) {
00280 if ((precision == 0) && (width > size)) {
00281 precision = width - size + number_size;
00282 }
00283 }
00284
00285
00286 if (number_size > precision)
00287 precision = number_size;
00288
00289 width -= precision + size - number_size;
00290
00291 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
00292 while (width-- > 0) {
00293 if (printf_putchar(' ', ps) == 1)
00294 counter++;
00295 }
00296 }
00297
00298
00299 if (sgn) {
00300 if (printf_putchar(sgn, ps) == 1)
00301 counter++;
00302 }
00303
00304
00305
00306 if (flags & __PRINTF_FLAG_PREFIX) {
00307 switch(base) {
00308 case 2:
00309 if (printf_putchar('0', ps) == 1)
00310 counter++;
00311 if (flags & __PRINTF_FLAG_BIGCHARS) {
00312 if (printf_putchar('B', ps) == 1)
00313 counter++;
00314 } else {
00315 if (printf_putchar('b', ps) == 1)
00316 counter++;
00317 }
00318 break;
00319 case 8:
00320 if (printf_putchar('o', ps) == 1)
00321 counter++;
00322 break;
00323 case 16:
00324 if (printf_putchar('0', ps) == 1)
00325 counter++;
00326 if (flags & __PRINTF_FLAG_BIGCHARS) {
00327 if (printf_putchar('X', ps) == 1)
00328 counter++;
00329 } else {
00330 if (printf_putchar('x', ps) == 1)
00331 counter++;
00332 }
00333 break;
00334 }
00335 }
00336
00337
00338 precision -= number_size;
00339 while (precision-- > 0) {
00340 if (printf_putchar('0', ps) == 1)
00341 counter++;
00342 }
00343
00344
00345
00346
00347 if ((retval = printf_putstr(++ptr, ps)) > 0) {
00348 counter += retval;
00349 }
00350
00351
00352
00353 while (width-- > 0) {
00354 if (printf_putchar(' ', ps) == 1)
00355 counter++;
00356 }
00357
00358 return counter;
00359 }
00360
00361
00436 int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
00437 {
00438 int i = 0, j = 0;
00439 int end;
00440 int counter;
00441 int retval;
00442 char c;
00443 qualifier_t qualifier;
00444 int base;
00445 uint64_t number;
00446 size_t size;
00447 int width, precision;
00448 uint64_t flags;
00449
00450
00451 async_serialize_start();
00452
00453 counter = 0;
00454
00455 while ((c = fmt[i])) {
00456
00457 if (c == '%' ) {
00458
00459 if (i > j) {
00460 if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) {
00461 goto minus_out;
00462 }
00463 counter += retval;
00464 }
00465
00466 j = i;
00467
00468 flags = 0;
00469 end = 0;
00470
00471 do {
00472 ++i;
00473 switch (c = fmt[i]) {
00474 case '#': flags |= __PRINTF_FLAG_PREFIX; break;
00475 case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
00476 case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
00477 case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
00478 case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
00479 default: end = 1;
00480 };
00481
00482 } while (end == 0);
00483
00484
00485 width = 0;
00486 if (isdigit(fmt[i])) {
00487 while (isdigit(fmt[i])) {
00488 width *= 10;
00489 width += fmt[i++] - '0';
00490 }
00491 } else if (fmt[i] == '*') {
00492
00493 i++;
00494 width = (int)va_arg(ap, int);
00495 if (width < 0) {
00496
00497 width *= -1;
00498 flags |= __PRINTF_FLAG_LEFTALIGNED;
00499 }
00500 }
00501
00502
00503 precision = 0;
00504 if (fmt[i] == '.') {
00505 ++i;
00506 if (isdigit(fmt[i])) {
00507 while (isdigit(fmt[i])) {
00508 precision *= 10;
00509 precision += fmt[i++] - '0';
00510 }
00511 } else if (fmt[i] == '*') {
00512
00513 i++;
00514 precision = (int)va_arg(ap, int);
00515 if (precision < 0) {
00516
00517 precision = 0;
00518 }
00519 }
00520 }
00521
00522 switch (fmt[i++]) {
00526 case 'h':
00527 qualifier = PrintfQualifierShort;
00528 if (fmt[i] == 'h') {
00529 i++;
00530 qualifier = PrintfQualifierByte;
00531 }
00532 break;
00533 case 'l':
00534 qualifier = PrintfQualifierLong;
00535 if (fmt[i] == 'l') {
00536 i++;
00537 qualifier = PrintfQualifierLongLong;
00538 }
00539 break;
00540 case 'z':
00541 qualifier = PrintfQualifierSizeT;
00542 break;
00543 default:
00544 qualifier = PrintfQualifierInt;
00545 --i;
00546 }
00547
00548 base = 10;
00549
00550 switch (c = fmt[i]) {
00551
00552
00553
00554
00555 case 's':
00556 if ((retval = print_string(va_arg(ap, char*), width, precision, flags, ps)) < 0) {
00557 goto minus_out;
00558 };
00559
00560 counter += retval;
00561 j = i + 1;
00562 goto next_char;
00563 case 'c':
00564 c = va_arg(ap, unsigned int);
00565 if ((retval = print_char(c, width, flags, ps)) < 0) {
00566 goto minus_out;
00567 };
00568
00569 counter += retval;
00570 j = i + 1;
00571 goto next_char;
00572
00573
00574
00575
00576 case 'P':
00577 flags |= __PRINTF_FLAG_BIGCHARS;
00578 case 'p':
00579 flags |= __PRINTF_FLAG_PREFIX;
00580 base = 16;
00581 qualifier = PrintfQualifierPointer;
00582 break;
00583 case 'b':
00584 base = 2;
00585 break;
00586 case 'o':
00587 base = 8;
00588 break;
00589 case 'd':
00590 case 'i':
00591 flags |= __PRINTF_FLAG_SIGNED;
00592 case 'u':
00593 break;
00594 case 'X':
00595 flags |= __PRINTF_FLAG_BIGCHARS;
00596 case 'x':
00597 base = 16;
00598 break;
00599
00600 case '%':
00601 j = i;
00602 goto next_char;
00603
00604
00605
00606 default:
00607
00608
00609
00610
00611 goto next_char;
00612 }
00613
00614
00615
00616
00617 switch (qualifier) {
00618 case PrintfQualifierByte:
00619 size = sizeof(unsigned char);
00620 number = (uint64_t)va_arg(ap, unsigned int);
00621 break;
00622 case PrintfQualifierShort:
00623 size = sizeof(unsigned short);
00624 number = (uint64_t)va_arg(ap, unsigned int);
00625 break;
00626 case PrintfQualifierInt:
00627 size = sizeof(unsigned int);
00628 number = (uint64_t)va_arg(ap, unsigned int);
00629 break;
00630 case PrintfQualifierLong:
00631 size = sizeof(unsigned long);
00632 number = (uint64_t)va_arg(ap, unsigned long);
00633 break;
00634 case PrintfQualifierLongLong:
00635 size = sizeof(unsigned long long);
00636 number = (uint64_t)va_arg(ap, unsigned long long);
00637 break;
00638 case PrintfQualifierPointer:
00639 size = sizeof(void *);
00640 number = (uint64_t)(unsigned long)va_arg(ap, void *);
00641 break;
00642 case PrintfQualifierSizeT:
00643 size = sizeof(size_t);
00644 number = (uint64_t)va_arg(ap, size_t);
00645 break;
00646 default:
00647 goto minus_out;
00648
00649 }
00650
00651 if (flags & __PRINTF_FLAG_SIGNED) {
00652 if (number & (0x1 << (size*8 - 1))) {
00653 flags |= __PRINTF_FLAG_NEGATIVE;
00654
00655 if (size == sizeof(uint64_t)) {
00656 number = -((int64_t)number);
00657 } else {
00658 number = ~number;
00659 number &= (~((0xFFFFFFFFFFFFFFFFll) << (size * 8)));
00660 number++;
00661 }
00662 }
00663 }
00664
00665 if ((retval = print_number(number, width, precision, base, flags, ps)) < 0 ) {
00666 goto minus_out;
00667 };
00668
00669 counter += retval;
00670 j = i + 1;
00671 }
00672 next_char:
00673
00674 ++i;
00675 }
00676
00677 if (i > j) {
00678 if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) {
00679 goto minus_out;
00680 }
00681 counter += retval;
00682 }
00683
00684 async_serialize_end();
00685 return counter;
00686 minus_out:
00687 async_serialize_end();
00688 return -counter;
00689 }
00690
00691
00692