#include #include #include #include #include #include static bool print(const char * str, size_t len) { const unsigned char * bytes = (const unsigned char *) str; for(size_t i = 0; i < len; i++) { if(putchar(bytes[i]) == EOF) { return false; } } return true; } static bool print_oct(unsigned int strint) { int i = strint, j = 10; char str[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; while(j >= 0 && i > 0) { switch(i % 010) { case 0: str[j] = '0'; break; case 1: str[j] = '1'; break; case 2: str[j] = '2'; break; case 3: str[j] = '3'; break; case 4: str[j] = '4'; break; case 5: str[j] = '5'; break; case 6: str[j] = '6'; break; case 7: str[j] = '7'; break; default: return false; } i /= 010; j--; } for(i = 0; str[i] == '\0'; i++) {} return print(str+i, 11-i); } static bool print_ptr(void * ptrstr) { int i = (int) ptrstr, j = 9; char str[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; while(j >= 2 && i > 0) { switch(i % 0x10) { case 0: str[j] = '0'; break; case 1: str[j] = '1'; break; case 2: str[j] = '2'; break; case 3: str[j] = '3'; break; case 4: str[j] = '4'; break; case 5: str[j] = '5'; break; case 6: str[j] = '6'; break; case 7: str[j] = '7'; break; case 8: str[j] = '8'; break; case 9: str[j] = '9'; break; case 0xA: str[j] = 'A'; break; case 0xB: str[j] = 'B'; break; case 0xC: str[j] = 'C'; break; case 0xD: str[j] = 'D'; break; case 0xE: str[j] = 'E'; break; case 0xF: str[j] = 'F'; break; default: return false; } i /= 0x10; j--; } for(i = 0; str[i] == '\0'; i++) {} i--; str[i] = 'x'; i--; str[i] = '0'; return print(str+i, 10-i); } static bool print_caphex(unsigned int strint) { int i = strint, j = 7; char str[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; while(j >= 0 && i > 0) { switch(i % 0x10) { case 0: str[j] = '0'; break; case 1: str[j] = '1'; break; case 2: str[j] = '2'; break; case 3: str[j] = '3'; break; case 4: str[j] = '4'; break; case 5: str[j] = '5'; break; case 6: str[j] = '6'; break; case 7: str[j] = '7'; break; case 8: str[j] = '8'; break; case 9: str[j] = '9'; break; case 0xA: str[j] = 'A'; break; case 0xB: str[j] = 'B'; break; case 0xC: str[j] = 'C'; break; case 0xD: str[j] = 'D'; break; case 0xE: str[j] = 'E'; break; case 0xF: str[j] = 'F'; break; default: return false; } i /= 0x10; j--; } for(i = 0; str[i] == '\0'; i++) {} return print(str+i, 8-i); } static bool print_hex(unsigned int strint) { int i = strint, j = 7; char str[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; while(j >= 0 && i > 0) { switch(i % 0x10) { case 0: str[j] = '0'; break; case 1: str[j] = '1'; break; case 2: str[j] = '2'; break; case 3: str[j] = '3'; break; case 4: str[j] = '4'; break; case 5: str[j] = '5'; break; case 6: str[j] = '6'; break; case 7: str[j] = '7'; break; case 8: str[j] = '8'; break; case 9: str[j] = '9'; break; case 0xA: str[j] = 'a'; break; case 0xB: str[j] = 'b'; break; case 0xC: str[j] = 'c'; break; case 0xD: str[j] = 'd'; break; case 0xE: str[j] = 'e'; break; case 0xF: str[j] = 'f'; break; default: return false; } i /= 0x10; j--; } for(i = 0; str[i] == '\0'; i++) {} return print(str+i, 8-i); } static bool print_int(int strint) { int i = strint, j = 10; char str[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if(i < 0) { i = -i; } while(j > 0 && i > 0) { switch(i % 10) { case 0: str[j] = '0'; break; case 1: str[j] = '1'; break; case 2: str[j] = '2'; break; case 3: str[j] = '3'; break; case 4: str[j] = '4'; break; case 5: str[j] = '5'; break; case 6: str[j] = '6'; break; case 7: str[j] = '7'; break; case 8: str[j] = '8'; break; case 9: str[j] = '9'; break; default: return false; } i /= 10; j--; } for(i = 0; str[i] == '\0'; i++) {} if(strint < 0) { i--; str[i] = '-'; } return print(str+i, 11-i); } static bool print_uint(unsigned int strint) { int i = strint; if(i < 0) { i = -i; } return print_int(i); } int printf(const char * restrict format, ...) { int errno; va_list parameters; va_start(parameters, format); int written = 0; while(*format != '\0') { size_t maxrem = INT_MAX - written; if(format[0] != '%' || format[1] == '%') { if(format[0] == '%') { format++; } size_t amount = 1; while(format[amount] && format[amount] != '%') { amount++; } if(maxrem < amount) { errno = EOVERFLOW; return -1; } if(!print(format, amount)) { return -1; } format += amount; written += amount; continue; } const char * format_begun_at = format++; /* TODO: Implement all format specifiers (%g, %o, &c.) */ if(*format == 'c') { format++; char c = (char) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print(&c, sizeof(c))) { return -1; } written++; } else if(*format == 's') { format++; const char * str = va_arg(parameters, const char *); size_t len = strlen(str); if(maxrem < len) { errno = EOVERFLOW; return -1; } if(!print(str, len)) { return -1; } written += len; } else if(*format == 'd' || *format == 'i') { format++; int i = (int) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_int(i)) { return -1; } written += 11; } else if(*format == 'u') { format++; int i = (int) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_uint(i)) { return -1; } written += 10; } else if(*format == 'o') { format++; int i = (int) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_oct(i)) { return -1; } written += 11; } else if(*format == 'x') { format++; int i = (int) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_hex(i)) { return -1; } written += 10; } else if(*format == 'X') { format++; int i = (int) va_arg(parameters, int); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_caphex(i)) { return -1; } written += 8; } else if(*format == 'p') { format++; void * ptr = (void *) va_arg(parameters, void *); if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_ptr(ptr)) { return -1; } /* This is gonna need a change on 64-bit systems. */ written += 10; }else if(*format == 'n') { format++; if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print_int(written)) { return -1; } written += 11; } else if(*format == '%') { format++; if(!maxrem) { errno = EOVERFLOW; return -1; } if(!print("%", 1)) { return -1; } written++; } else { format = format_begun_at; size_t len = strlen(format); if(maxrem < len) { errno = EOVERFLOW; return -1; } if(!print(format, len)) { return -1; } format += len; } } va_end(parameters); return(written); }