diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index c5be997..d97ce3a 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -1,6 +1,11 @@ #ifndef _FCNTL_H #define _FCNTL_H +/* Standard file decriptors */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + /* File access modes */ #define O_CREAT 0x0001 // Create if does not exist #define O_RDONLY 0x0002 // Read only diff --git a/libc/include/stdio.h b/libc/include/stdio.h index e2e1b28..f50ba64 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -53,6 +53,7 @@ int ungetc(int c, FILE* stream); /* Line I/O */ char* fgets(char* str, int n, FILE* stream); int fputs(const char* str, FILE* stream); +char* gets(char* str, int n); int puts(const char* str); /* TODO: Error handling diff --git a/libc/include/syscall.h b/libc/include/syscall.h index f8cff87..830c3e2 100644 --- a/libc/include/syscall.h +++ b/libc/include/syscall.h @@ -35,14 +35,14 @@ inline int syscall(int nr, int a0, int a1, int a2, int a3, int a4) { } /* Syscall wrappers */ -inline int _exit(int status) { return syscall(SYS_EXIT, status, 0, 0, 0, 0); } -inline int read(int fd, void* ptr, size_t count) { return syscall(SYS_READ, fd, (int)ptr, (int)count, 0, 0); } -inline int write(int fd, const void* ptr, size_t count) { return syscall(SYS_WRITE, fd, (int)ptr, (int)count, 0, 0); } -inline int open(const char* path, int oflag) { return syscall(SYS_OPEN, (int)path, oflag, 0, 0, 0); } -inline int close(int fd) { return syscall(SYS_CLOSE, fd, 0, 0, 0, 0); } -inline int seek(int fd, size_t offset, int whence) { return syscall(SYS_SEEK, fd, offset, whence, 0, 0); } -inline int _malloc(int size) { return syscall(SYS_MALLOC, size, 0, 0, 0, 0); } -inline int _free(void* ptr) { return syscall(SYS_FREE, (int)ptr, 0, 0, 0, 0); } -inline int _sleep(int t) { return syscall(SYS_SLEEP, t, 0, 0, 0, 0); } +static inline int _exit(int status) { return syscall(SYS_EXIT, status, 0, 0, 0, 0); } +static inline int read(int fd, void* ptr, size_t count) { return syscall(SYS_READ, fd, (int)ptr, (int)count, 0, 0); } +static inline int write(int fd, const void* ptr, size_t count) { return syscall(SYS_WRITE, fd, (int)ptr, (int)count, 0, 0); } +static inline int open(const char* path, int oflag) { return syscall(SYS_OPEN, (int)path, oflag, 0, 0, 0); } +static inline int close(int fd) { return syscall(SYS_CLOSE, fd, 0, 0, 0, 0); } +static inline int seek(int fd, size_t offset, int whence) { return syscall(SYS_SEEK, fd, offset, whence, 0, 0); } +static inline int _malloc(int size) { return syscall(SYS_MALLOC, size, 0, 0, 0, 0); } +static inline int _free(void* ptr) { return syscall(SYS_FREE, (int)ptr, 0, 0, 0, 0); } +static inline int _sleep(int t) { return syscall(SYS_SLEEP, t, 0, 0, 0, 0); } #endif diff --git a/libc/stdio/char.c b/libc/stdio/char.c index 170cb53..b77f260 100644 --- a/libc/stdio/char.c +++ b/libc/stdio/char.c @@ -7,7 +7,7 @@ int putchar(int c) { return putc(c, stdout); } int getc(FILE* stream) { if (!stream) { return EOF; } - unsigned char ch; + unsigned char ch = '\0'; ssize_t res = read(stream->_file, &ch, 1); if (res <= 0) { return EOF; } diff --git a/libc/stdio/file.c b/libc/stdio/file.c index 1621c94..b1c428f 100644 --- a/libc/stdio/file.c +++ b/libc/stdio/file.c @@ -4,6 +4,10 @@ #include #include +FILE* stdin; +FILE* stdout; +FILE* stderr; + FILE* fopen(const char* path, const char* mode) { FILE* fp = (FILE*)malloc(sizeof(FILE)); if (!fp) { return NULL; } diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index a292c4f..c535b65 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -2,6 +2,7 @@ #include #include #include +#include /* Internal definitions */ typedef struct { @@ -11,6 +12,57 @@ typedef struct { } printfEnv_t; /* Helpers */ +// Digit to character +static char _dtoc(int digit) { return digit < 10 ? '0' + digit : 'a' + (digit - 10); } +static double _fabs(double x) { return (x < 0.0) ? -x : x; } +static void _fmtInt(void (*outfn)(char c, void* arg), void* arg, int n, int base, int width, char padc) { + char buf[32]; + int negative = 0; + int i = 0; + + if (n < 0 && base == 10) { + negative = 1; + n = -n; + } + + // Convert number, this will be done in reverse + do { + buf[i++] = _dtoc(n % base); + n /= base; + } while (n > 0); + + // Padding + while (i < width) { buf[i++] = padc; } + // Add negative sign + if (negative) { buf[i++] = '-'; } + + // Funny arrow + while (i --> 0) { outfn(buf[i], arg); } +} + +static void _fmtFloat(void (*outfn)(char c, void* arg), void* arg, double f) { + int whole = (int)f; + double frac = _fabs(f - whole); + int decPlaces = 6; + + // Add negative sign + if (f < 0) { outfn('-', arg); } + + // Print whole part + _fmtInt(outfn, arg, whole, 10, 0, ' '); + + // Print decimal point + outfn('.', arg); + + // Format fractional part + for (int i = 0; i < decPlaces; i++) { + frac *= 10; + int digit = (int)frac; + outfn('0' + digit, arg); + frac -= digit; + } +} + static void _dynamicPutc(char c, void* arg) { printfEnv_t* env = (printfEnv_t*)arg; if (!env->buf) { return; } @@ -40,8 +92,67 @@ static void _staticPutc(char c, void* arg) { /* Impementation */ int vpprintf(void (*outfn)(char c, void* arg), void* arg, const char* fmt, va_list va) { - // TODO - return -1; + int i = 0; + + while (fmt[i] != '\0') { + if (fmt[i] != '%') { // Just print the character + outfn(fmt[i++], arg); + continue; + } + + i++; // Consume the % + if (fmt[i] == '\0') { // End of string + outfn('%', arg); + break; + } + + + // Parse fmt string + int width = 0; + char pad = ' '; + + // Check for zero pad and parse width + if (isdigit(fmt[i])) { + if (fmt[i] == '0') { pad = '0'; i++; } + + while (isdigit(fmt[i])) { // Parse width + width *= 10; + width += fmt[i++] - '0'; + } + } + + // Parse specifier + switch (fmt[i]) { + case 'c': { // Character + char c = va_arg(va, char); + outfn(c, arg); + break; + } case 's': { // String + char* s = va_arg(va, char*); + while (*s) { outfn(*s++, arg); } + break; + } case 'd': { // Decimal number + int d = va_arg(va, int); + _fmtInt(outfn, arg, d, 10, width, pad); + break; + } case 'x': { // Hex number + int x = va_arg(va, int); + _fmtInt(outfn, arg, x, 16, width, pad); + break; + } case 'f': { // Float + double f = va_arg(va, double); + _fmtFloat(outfn, arg, f); + break; + } default: { + outfn(fmt[i], arg); + break; + } + } + + i++; + } + + return i; } int vsnprintf(char* str, size_t size, const char* fmt, va_list va) {