diff --git a/apps/src/sh.c b/apps/src/sh.c index 422d2a28..e1d0caef 100644 --- a/apps/src/sh.c +++ b/apps/src/sh.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -135,37 +136,41 @@ void command_execute(command* cmd) show_prompt(); } +void command_concat_char(command* cmd, char c) +{ + if (c == '\b') + { + if (cmd->size != 0) + { + putchar(c); + command_pop(cmd); + } + } + else if (c == '\n') + { + if (cmd->size == 0) + { + putchar(c); + show_prompt(); + } + else + { + putchar(c); + command_execute(cmd); + } + } + else + { + putchar(c); + command_push(cmd, c); + } +} + void command_concat(command* cmd, const char* str) { while (*str) { - if (*str == '\b') - { - if (cmd->size == 0) - { - str++; - continue; - } - putchar(*str); - command_pop(cmd); - } - else if (*str == '\n') - { - if (cmd->size == 0) - { - putchar(*str); - show_prompt(); - str++; - continue; - } - putchar(*str); - command_execute(cmd); - } - else - { - putchar(*str); - command_push(cmd, *str); - } + command_concat_char(cmd, *str); str++; } } @@ -174,21 +179,22 @@ int main() { show_prompt(); - char buffer[33]; - command shell_command; command_init(&shell_command); while (1) { - size_t nread = fread(buffer, sizeof(buffer) - 1, 1, stdin); - if (ferror(stdin)) + int c = getchar(); + if (c == EOF) { - perror("fread"); - return 1; + if (ferror(stdin)) + { + perror("getchar"); + return 1; + } + if (feof(stdin)) { return 0; } + assert(false); // we should never get here } - if (feof(stdin)) { return 0; } - buffer[nread] = 0; - command_concat(&shell_command, buffer); + command_concat_char(&shell_command, (char)c); } } \ No newline at end of file diff --git a/libs/libc/include/stdio.h b/libs/libc/include/stdio.h index 07a37152..774aaac2 100644 --- a/libs/libc/include/stdio.h +++ b/libs/libc/include/stdio.h @@ -13,6 +13,10 @@ typedef struct int f_fd; int f_eof; int f_err; + char* f_buf; + long f_bufsize; + long f_bufoff; + long f_bufrsize; } FILE; extern FILE* stderr; @@ -22,6 +26,8 @@ extern FILE* stdin; #define stdout stdout #define stderr stderr +#define EOF -1 + typedef struct { long f_offset; @@ -74,6 +80,18 @@ extern "C" /* Writes nmemb items of size size from buf into the file stream. */ size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream); + /* Reads a line from stream into buf. */ + char* fgets(char* buf, int size, FILE* stream); + + /* Retrieves a character from stream. */ + int fgetc(FILE* stream); + + /* Retrieves a character from stream. */ + int getc(FILE* stream); + + /* Retrieves a character from standard input. */ + int getchar(); + /* Returns nonzero if the error flag in stream was set. */ int ferror(FILE* stream); diff --git a/libs/libc/src/file.cpp b/libs/libc/src/file.cpp index e4bd1107..ca54b19a 100644 --- a/libs/libc/src/file.cpp +++ b/libs/libc/src/file.cpp @@ -9,10 +9,33 @@ FILE* stderr; FILE* stdout; FILE* stdin; +void file_read_buf(FILE* stream) +{ + if (!stream->f_buf) + { + stream->f_buf = (char*)malloc(32); + stream->f_bufrsize = 32; + } + stream->f_bufoff = 0; + ssize_t nread = read(stream->f_fd, stream->f_buf, stream->f_bufrsize); + if (nread < 0) + { + stream->f_err = 1; + return; + } + if (nread == 0) + { + stream->f_eof = 1; + return; + } + stream->f_bufsize = nread; +} + extern "C" { int fclose(FILE* stream) { + if (stream->f_buf) free(stream->f_buf); int status = close(stream->f_fd); if (status < 0) { @@ -49,6 +72,9 @@ extern "C" if (!stream) { return 0; } stream->f_fd = fd; clearerr(stream); + stream->f_buf = 0; + stream->f_bufoff = 0; + stream->f_bufsize = 0; return stream; } @@ -73,7 +99,9 @@ extern "C" size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream) { - ssize_t status = read(stream->f_fd, buf, size * nmemb); + ssize_t status = + read(stream->f_fd, buf, + size * nmemb); // FIXME: This function should use file_read_buf() to not conflict with fgets(). if (status < 0) { stream->f_err = 1; @@ -83,6 +111,65 @@ extern "C" return (size_t)status; } + char* fgets(char* buf, int size, FILE* stream) + { + char* s = buf; + int original_size = size; + while (size > 1) + { + if (stream->f_bufoff < stream->f_bufsize) + { + *buf = *(stream->f_buf + stream->f_bufoff); + stream->f_bufoff++; + if (*buf == '\n') + { + buf++; + break; + } + buf++; + size--; + } + else + { + file_read_buf(stream); + if (ferror(stream)) return NULL; + if (feof(stream)) break; + } + } + if (size == original_size && feof(stream)) return NULL; // EOF while reading the first character + *buf = 0; + return s; + } + + int fgetc(FILE* stream) + { + char result; + read: + if (stream->f_bufoff < stream->f_bufsize) + { + result = *(stream->f_buf + stream->f_bufoff); + stream->f_bufoff++; + } + else + { + file_read_buf(stream); + if (ferror(stream)) return EOF; + if (feof(stream)) return EOF; + goto read; + } + return (int)result; + } + + int getc(FILE* stream) + { + return fgetc(stream); + } + + int getchar() + { + return fgetc(stdin); + } + int ferror(FILE* stream) { return stream->f_err;