/* * printf.c : tiny printf * */ /* TODO: * - alt_fl (#) not actually used to control %X and %x formatting * - floating pointer support * - + not supported */ #include "stdio.h" #include "string.h" #include #undef PRINTF_SUPPORT_FLOAT /* do not support floating point numbers */ static const char number_l[] = "0123456789abcdef"; /* lowercase numbers */ static const char number_u[] = "0123456789ABCDEF"; /* uppercase numbers */ static char number_buffer[64]; /* holding error for convert_xxx routines */ static int number_len; /* length of value in the number_buffer */ int vsprintf(char *buf, const char *fmt, va_list args); int sprintf(char *buf, const char *fmt, ...); static const char *convert_number(unsigned n, const char *tab, unsigned base) { char *o; /* output */ if(base<2) base=2; o=number_buffer+sizeof number_buffer; *--o=0; do { *--o=tab[n%base]; n/=base; } while(n); number_len=number_buffer+sizeof number_buffer-1-o; return o; } static const char *convert_hex(unsigned n, const char *tab) { char *o; /* output */ o=number_buffer+sizeof number_buffer; *--o=0; do { *--o=tab[n&15]; n>>=4; } while(n); number_len=number_buffer+sizeof number_buffer-1-o; return o; } /* zero or space fill */ static unsigned pad_fill(unsigned field_width, unsigned object_width, char fill_ch) { unsigned r=0; while(object_width0x7fffffff) precision=0; /* clamp negative numbers to 0 */ precision_fl=1; } else while(*fmt) { switch(*fmt) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': precision=precision*10+*fmt-'0'; precision_fl=1; break; default: goto finished3; } fmt++; } } finished3: /* look for modifier flags */ while(*fmt) { switch(*fmt) { case 'h': size_h++; break; case 'l': size_l++; break; default: goto finished4; } } finished4: switch(*fmt++) { case 0: return n; case '%': putchar('%'); n++; break; case 'b': /* binary */ tmp=convert_number(va_arg(ap, int), number_l, 2); n+=pad_fill(field_width, number_len, zero_fl?'0':' '); puts(tmp); n+=number_len; break; case 'c': /* character */ putchar(va_arg(ap, unsigned)&255); n++; break; case 'd': case 'i': tmp=convert_number(va_arg(ap, int), number_l, 10); if(left_fl) { puts(tmp); n+=pad_fill(field_width, number_len, ' '); } else { n+=pad_fill(field_width, number_len, zero_fl?'0':' '); puts(tmp); } n+=number_len; break; case 'o': tmp=convert_number(va_arg(ap, int), number_l, 8); if(left_fl) { puts(tmp); n+=pad_fill(field_width, number_len, ' '); } else { n+=pad_fill(field_width, number_len, zero_fl?'0':' '); puts(tmp); } n+=number_len; break; case 'p': tmp=convert_hex((unsigned long)va_arg(ap, void *), number_l); puts("0x"); n+=pad_fill(sizeof(unsigned long)*2, number_len, '0'); puts(tmp); n+=number_len+2; break; case 's': { /* string */ int tmp_len=0; tmp=va_arg(ap, const char *); if(tmp) { if(precision_fl) { /* %.*s */ if(!left_fl) { /* right justify when field width is positive */ /* TODO: we're just guessing here, fix this */ n+=pad_fill(field_width, precision, ' '); } /* stop until precision or until '\0' character */ while(precision && *tmp) { putchar(*tmp++); precision--; tmp_len++; } } else { tmp_len=strlen(tmp); if(!left_fl) { /* right justify when field width is positive */ n+=pad_fill(field_width, tmp_len, ' '); } puts(tmp); } } else { puts("(null)"); tmp_len=6; } if(left_fl) { /* left justify when field width is negative */ n+=pad_fill(field_width, tmp_len, ' '); } n+=tmp_len; break; } case 'X': /* uppercase hexidecimal */ tmp=convert_hex(va_arg(ap, int), number_u); if(left_fl) { puts(tmp); n+=pad_fill(field_width, number_len, ' '); } else { n+=pad_fill(field_width, number_len, zero_fl?'0':' '); puts(tmp); } n+=number_len; break; case 'x': /* lowercase hexidecimal */ tmp=convert_hex(va_arg(ap, int), number_l); if(left_fl) { puts(tmp); n+=pad_fill(field_width, number_len, ' '); } else { n+=pad_fill(field_width, number_len, zero_fl?'0':' '); puts(tmp); } n+=number_len; break; #ifdef PRINTF_SUPPORT_FLOAT case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': #error Floating point support was not implemented #endif } } else { putchar(*fmt++); n++; } } return n; } int printf(const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n=vprintf(fmt, ap); va_end(ap); return n; } /*** test code ***/ #if 0 #include void putchar(char ch) { write(0, &ch, 1); } void puts(const char *s) { while(*s) putchar(*s++); } int main() { puts("printf test\n"); printf("%d %% %d = %d\n", 42, 13, 42%13); printf("%04x %% %#02X = %08X\n", 42, 13, 42%13); printf("%5d %% %5d = %04.69d\n", 42, 13, 42%13); printf("ok %s %s %s\n", "hello", "world", 0); printf("%c%c%c%c%p\n", 65, 66, 67, 10, main); printf("%-5d %% %-5d = %04.69d\n", 42, 13, 42%13); printf("%-40s\n", "Hello world"); printf("%40.8s\n", "Hello world"); return 0; } #endif