diff options
author | Alex Auvolat <alex@adnab.me> | 2016-07-16 23:39:51 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2016-07-16 23:39:51 +0200 |
commit | 6466208ec051e58b824cc3c839b6b086ae910fe6 (patch) | |
tree | 434741997865ec6f0c4c3badb4fcfde557a7af35 /src/lib/libc/stdio.c | |
parent | bb2dd23f315bafa7b0b64845c2fe25d7a0893b10 (diff) | |
download | kogata-6466208ec051e58b824cc3c839b6b086ae910fe6.tar.gz kogata-6466208ec051e58b824cc3c839b6b086ae910fe6.zip |
Progress on stdio impementation
Diffstat (limited to 'src/lib/libc/stdio.c')
-rw-r--r-- | src/lib/libc/stdio.c | 215 |
1 files changed, 179 insertions, 36 deletions
diff --git a/src/lib/libc/stdio.c b/src/lib/libc/stdio.c index c849683..f825c1b 100644 --- a/src/lib/libc/stdio.c +++ b/src/lib/libc/stdio.c @@ -1,5 +1,6 @@ #include <string.h> #include <stdio.h> +#include <stdlib.h> #include <proto/launch.h> @@ -12,28 +13,69 @@ FILE *stderr = 0; FILE libc_tty_stdio, libc_stdin, libc_stdout, libc_stderr; +void initialize_out_buffer(FILE* f, int buf_mode) { + if (buf_mode == 0) { + f->buf_mode = 0; + f->out_buf = 0; + f->out_buf_size = f->out_buf_used = 0; + f->out_buf_owned = false; + } else { + f->buf_mode = buf_mode; + f->out_buf = malloc(BUFSIZ); + f->out_buf_size = BUFSIZ; + f->out_buf_used = 0; + f->out_buf_owned = true; + } +} + void setup_libc_stdio() { if (sc_stat_open(STD_FD_TTY_STDIO, &libc_tty_stdio.st)) { libc_tty_stdio.fd = STD_FD_TTY_STDIO; + libc_tty_stdio.file_mode = (libc_tty_stdio.st.access & (FM_READ | FM_WRITE)); + libc_tty_stdio.pos = 0; + + initialize_out_buffer(&libc_tty_stdio, _IOLBF); + sc_fctl(libc_tty_stdio.fd, FC_SET_BLOCKING, 0); - // TODO: initialize libc_tty_stdio as a TTY + libc_tty_stdio.file_mode |= FM_BLOCKING; + libc_tty_stdio.ungetc_char = EOF; + stdin = &libc_tty_stdio; stdout = &libc_tty_stdio; stderr = &libc_tty_stdio; } if (sc_stat_open(STD_FD_STDIN, &libc_stdin.st)) { libc_stdin.fd = STD_FD_STDIN; - // TODO: initialize + ASSERT(libc_stdin.st.access & FM_READ); + libc_stdin.file_mode = FM_READ; + libc_stdin.pos = 0; + + initialize_out_buffer(&libc_stdin, 0); + + sc_fctl(libc_stdin.fd, FC_SET_BLOCKING, 0); + libc_stdin.file_mode |= FM_BLOCKING; + libc_stdin.ungetc_char = EOF; + stdin = &libc_stdin; } if (sc_stat_open(STD_FD_STDOUT, &libc_stdout.st)) { libc_stdout.fd = STD_FD_STDOUT; - // TODO: initialize + ASSERT(libc_stdout.st.access & FM_WRITE); + libc_stdout.file_mode = FM_WRITE; + libc_stdout.pos = 0; + + initialize_out_buffer(&libc_stdout, _IOLBF); + stdout = &libc_stdout; } if (sc_stat_open(STD_FD_STDERR, &libc_stderr.st)) { libc_stderr.fd = STD_FD_STDERR; - // TODO: initialize + ASSERT(libc_stderr.st.access & FM_WRITE); + libc_stderr.file_mode = FM_WRITE; + libc_stderr.pos = 0; + + initialize_out_buffer(&libc_stderr, _IONBF); + stderr = &libc_stderr; } } @@ -85,11 +127,16 @@ int fclose(FILE* f) { // --------------- size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + ASSERT(size == 1); //TODO all cases + if (stream == NULL || stream->fd == 0) return 0; // TODO buffering - // TODO position - return sc_read(stream->fd, 0, size * nmemb, ptr); + size_t ret = sc_read(stream->fd, stream->pos, size * nmemb, ptr); + if (!(stream->st.type & (FT_CHARDEV | FT_CHANNEL | FT_DIR))) { + stream->pos += ret; + } + return ret; } int fgetc(FILE *stream) { @@ -108,8 +155,14 @@ char *fgets(char *s, int size, FILE *stream) { if (c == EOF) { break; } else if (c == '\b') { - if (l > 0) l--; - // TODO if terminal write back space or something + if (l > 0) { + l--; + } else { + //HACK + if (stream == &libc_tty_stdio) { + putc(' ', stream); + } + } } else { s[l] = c; l++; @@ -132,26 +185,122 @@ int ungetc(int c, FILE *stream) { // OUTPUT FUNCTIONS // ---------------- +// buffering + +void setbuf(FILE *stream, char *buf) { + setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} +void setbuffer(FILE *stream, char *buf, size_t size) { + setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size); +} +void setlinebuf(FILE *stream) { + setvbuf(stream, NULL, _IOLBF, 0); +} +int setvbuf(FILE *stream, char *buf, int mode, size_t size) { + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return EOF; + + if (fflush(stream) == EOF) return EOF; + + if (stream->out_buf_owned) free(stream->out_buf); + if (buf == NULL) { + stream->out_buf = malloc(size); + + // if we cannot allocate a buffer, set file to read-only mode + if (stream->out_buf == NULL) { + stream->file_mode &= ~FM_WRITE; + stream->buf_mode = 0; + return EOF; + } + + stream->out_buf_owned = true; + } else { + stream->out_buf = buf; + stream->out_buf_owned = false; + } + + stream->buf_mode = mode; + + return 0; +} + +int fflush(FILE* stream) { + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return EOF; + + if (stream->buf_mode != 0 && stream->out_buf_used > 0) { + size_t ret = sc_write(stream->fd, stream->pos, stream->out_buf_used, stream->out_buf); + stream->out_buf_used = 0; + + if (ret != stream->out_buf_used) { + return EOF; + } + if (!(stream->st.type & (FT_CHARDEV | FT_CHANNEL | FT_DIR))) { + stream->pos += ret; + } + } + return 0; +} + +int buffered_putc(int c, FILE* stream) { + ASSERT(stream->buf_mode != 0 && stream->out_buf_used < stream->out_buf_size); + stream->out_buf[stream->out_buf_used++] = c; + if (stream->out_buf_used == stream->out_buf_size || + (stream->buf_mode == _IOLBF && c == '\n')) { + fflush(stream); + } + return c; +} + + +// real output functions + size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - if (stream == NULL || stream->fd == 0) return 0; + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return 0; - // TODO buffering - // TODO position - return sc_write(stream->fd, 0, size * nmemb, ptr); + fflush(stream); + + size_t ret = sc_write(stream->fd, stream->pos, size * nmemb, ptr); + if (!(stream->st.type & (FT_CHARDEV | FT_CHANNEL | FT_DIR))) { + stream->pos += ret; + } + return ret / size; } int fputc(int c, FILE *stream) { - unsigned char x = c; - return fwrite(&x, 1, 1, stream); + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return EOF; + + buffered_putc(c, stream); + if (stream->buf_mode == _IONBF) { + if (fflush(stream) == EOF) return EOF; + } + return c; } int fputs(const char *s, FILE *stream) { - return fwrite(s, strlen(s), 1, stream); + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return EOF; + + int i = 0; + while (s[i]) { + buffered_putc(s[i], stream); + i++; + } + if (stream->buf_mode == _IONBF) { + if (fflush(stream) == EOF) return EOF; + } + return i; } int putc(int c, FILE *stream) { + // just an alias return fputc(c, stream); } int fprintf(FILE *stream, const char *fmt, ...) { + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return -1; + va_list ap; va_start(ap, fmt); @@ -160,34 +309,28 @@ int fprintf(FILE *stream, const char *fmt, ...) { return ret; } -int vfprintf(FILE *stream, const char *format, va_list ap) { - char buf[1024]; - vsnprintf(buf, 1024, format, ap); - return fputs(buf, stream); +int vfprintf_putc_fun(int c, void* p) { + FILE *stream = (FILE*)p; + if (buffered_putc(c, stream) == EOF) + return -1; + else + return 1; } +int vfprintf(FILE *stream, const char *format, va_list ap) { + if (stream == NULL || stream->fd == 0 + || !(stream->file_mode & FM_WRITE)) return -1; -// buffering + int ret = vcprintf(vfprintf_putc_fun, stream, format, ap); -void setbuf(FILE *stream, char *buf) { - setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); -} -void setbuffer(FILE *stream, char *buf, size_t size) { - // TODO -} -void setlinebuf(FILE *stream) { - setvbuf(stream, NULL, _IOLBF, 0); -} -int setvbuf(FILE *stream, char *buf, int mode, size_t size) { - // TODO - return 0; -} + if (stream->buf_mode == _IONBF) { + if (fflush(stream) == EOF) return -1; + } -int fflush(FILE* f) { - // TODO - return 0; + return ret; } + // --------------------- // COMPLICATED FUNCTIONS // --------------------- |