Added d, u, o, x, X, p, n, % format specifiers
This commit is contained in:
parent
80f7a6ea93
commit
b40777bcc4
1 changed files with 291 additions and 4 deletions
295
stdio/printf.c
295
stdio/printf.c
|
@ -3,6 +3,7 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
static bool print(const char * str, size_t len) {
|
static bool print(const char * str, size_t len) {
|
||||||
const unsigned char * bytes = (const unsigned char *) str;
|
const unsigned char * bytes = (const unsigned char *) str;
|
||||||
|
@ -16,6 +17,174 @@ static bool print(const char * str, size_t len) {
|
||||||
return true;
|
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 printf(const char * restrict format, ...) {
|
||||||
va_list parameters;
|
va_list parameters;
|
||||||
va_start(parameters, format);
|
va_start(parameters, format);
|
||||||
|
@ -37,7 +206,7 @@ int printf(const char * restrict format, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(maxrem < amount) {
|
if(maxrem < amount) {
|
||||||
/* TODO: Set errno to EOVERFLOW after implementing errno.h */
|
errno = EOVERFLOW;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +227,7 @@ int printf(const char * restrict format, ...) {
|
||||||
char c = (char) va_arg(parameters, int);
|
char c = (char) va_arg(parameters, int);
|
||||||
|
|
||||||
if(!maxrem) {
|
if(!maxrem) {
|
||||||
/* TODO: Set errno to EOVERFLOW after implementing errno.h */
|
errno = EOVERFLOW;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +243,7 @@ int printf(const char * restrict format, ...) {
|
||||||
size_t len = strlen(str);
|
size_t len = strlen(str);
|
||||||
|
|
||||||
if(maxrem < len) {
|
if(maxrem < len) {
|
||||||
/* TODO: Set errno to EOVERFLOW after implementing errno.h */
|
errno = EOVERFLOW;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,12 +253,130 @@ int printf(const char * restrict format, ...) {
|
||||||
|
|
||||||
written += len;
|
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 {
|
else {
|
||||||
format = format_begun_at;
|
format = format_begun_at;
|
||||||
size_t len = strlen(format);
|
size_t len = strlen(format);
|
||||||
|
|
||||||
if(maxrem < len) {
|
if(maxrem < len) {
|
||||||
/* TODO: Set errno to EOVERFLOW after implementing errno.h */
|
errno = EOVERFLOW;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue