diff options
author | Alex AUVOLAT <alexis211@gmail.com> | 2013-06-08 23:09:52 +0200 |
---|---|---|
committer | Alex AUVOLAT <alexis211@gmail.com> | 2013-06-08 23:09:52 +0200 |
commit | 4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4 (patch) | |
tree | c193acf64ff2db985f6664f161cf586c3caeb684 /src/user/lib/libc/std/stdio.c | |
parent | eae9997d3c2dbaef53022ddabe61c1800a619499 (diff) | |
download | TCE-4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4.tar.gz TCE-4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4.zip |
All FWIK is deleted. YOSH is now pure C. Not-working KBASIC included.
Diffstat (limited to 'src/user/lib/libc/std/stdio.c')
-rw-r--r-- | src/user/lib/libc/std/stdio.c | 245 |
1 files changed, 233 insertions, 12 deletions
diff --git a/src/user/lib/libc/std/stdio.c b/src/user/lib/libc/std/stdio.c index 12064be..be65505 100644 --- a/src/user/lib/libc/std/stdio.c +++ b/src/user/lib/libc/std/stdio.c @@ -1,37 +1,258 @@ +#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <tce/syscall.h> -#include <readline.h> +#include <ctype.h> -FILE term = 0; -void print(const char *s) { - fprint(term, s); +FILE term; + + +// GENERAL FILE ROUTINES + +FILE *fopen(const char *path, const char *mode) { + int m = 0; + if (strchr(mode, 'r')) m |= FM_READ; + if (strchr(mode, 'w')) m |= FM_WRITE; + if (strchr(mode, 't')) m |= FM_TRUNC; + if (strchr(mode, 'c')) m |= FM_CREATE; + + FILE *ret = malloc(sizeof(FILE)); + if (!ret) return NULL; + + ret->fd = open(path, m); + if (ret->fd < 0) { + errno = ret->fd; + free(ret); + return NULL; + } + __tce_libc_fsetup(ret); + + return ret; +} + +void __tce_libc_fsetup(FILE *f) { + statf(f->fd, &f->info); + f->pos = 0; + + if (f->info.type & FT_TERMINAL) { + f->pos = -1; + + f->tib_begin = malloc(TERM_INPUT_BUFFER_SIZE); + f->tib_end = f->tib_begin + TERM_INPUT_BUFFER_SIZE; + f->tib_u_begin = f->tib_begin; + f->tib_u_end = f->tib_u_begin; + f->term_echo = 1; + } +} + +int fgetc(FILE *f) { + if ((f->info.type & FT_TERMINAL) && f->tib_begin) { + if (f->tib_u_end == f->tib_u_begin) { + f->tib_u_begin = f->tib_u_end = f->tib_begin; + // read one line into buffer + int cont = 1; + while (cont) { + int k; + int n = read(f->fd, 0, f->tib_end - f->tib_u_end, f->tib_u_end); + for (k = 0; k < n; k++) { + if (f->term_echo) fprintf(f, "%c", f->tib_u_end[k]); + if (f->tib_u_end[k] == '\n' || f->tib_u_end[k] == 4) cont = 0; + } + f->tib_u_end += k; + if (f->tib_u_end == f->tib_end) cont = 0; + } + + } + + if (f->tib_u_end > f->tib_u_begin) { + char c = *f->tib_u_begin; + f->tib_u_begin++; + if (f->tib_u_begin == f->tib_end) { + f->tib_u_begin = f->tib_u_end = f->tib_begin; // empty buffer + } + return c; + } + } else { + char c; + int r = read(f->fd, (f->pos == -1 ? 0 : f->pos), 1, &c); + if (r == 1) { + if (f->pos != -1) f->pos++; + return c; + } + } + return EOF; +} + +int ungetc(int c, FILE *f) { + if (f->info.type & FT_TERMINAL && f->tib_begin) { + if (f->tib_u_begin > f->tib_begin) { + // buffer contains data which is partially read already + f->tib_u_begin--; + *(f->tib_u_begin) = c; + } else if (f->tib_u_end == f->tib_u_begin) { + // buffer is totally empty + *(f->tib_u_end) = c; + f->tib_u_end++; + } else { + return EOF; // no space in buffer. + } + } else if (f->pos >0) { + f->pos--; + } else { + return EOF; + } + return c; +} + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE* f) { + if (size * nmemb == 0) return 0; + + int r = read(f->fd, (f->pos == -1 ? 0 : f->pos), size * nmemb, ptr); + if (r > 0) { + if (f->pos != -1) f->pos += r; + return r; + } else { + errno = r; + return 0; + } +} + +size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *f) { + if (size * nmemb == 0) return 0; + int r = write(f->fd, (f->pos == -1 ? 0 : f->pos), size * nmemb, ptr); + if (r > 0) { + if (f->pos != -1) f->pos += r; + return r; + } else { + errno = r; + return 0; + } +} + +size_t fseek(FILE *f, long offset, int whence) { + // Update info + statf(f->fd, &f->info); + + if (!(f->info.type & FT_FILE)) { + errno = EBADF; + return -1; + } + + if (whence == SEEK_CUR) { + offset += f->pos; + } + if (whence == SEEK_END) { + offset = f->info.size - offset; + } + + if (offset > f->info.size || offset < 0) { + errno = EINVAL; + return -1; + } + f->pos = offset; + + return 0; +} + +long ftell(FILE *f) { + return f->pos; +} + +void fclose(FILE *f) { + if (f->tib_begin) free(f->tib_begin); + close(f->fd); + free(f); +} + +// COMFY INPUT FUNCTIONS + +int getchar() { + return fgetc(&term); +} + +int scanf(const char *format, ...) { + // rudimentary implementation + int r = 0; + + va_list ap; + va_start(ap, format); + + while (*format) { + if (*format == '%') { + format++; + if (!(*format)) break; + + if (*format == 'd' || *format == 'i') { + int c = fgetc(&term); + + int *ret = va_arg(ap, int*); + *ret = 0; + + while (isdigit(c)) { + (*ret) *= 10; + (*ret) += (c - '0'); + r++; + c = fgetc(&term); + } + ungetc(c, &term); + } else if (*format == 'c') { + char *c = va_arg(ap, char*); + *c = fgetc(&term); + r++; + } + format++; + } else { + int c = fgetc(&term); + if (c == *format) { + r++; + format++; + } else { + ungetc(c, &term); + break; + } + } + } + + va_end(ap); + return r; +} + +// COMFY OUTPUT FUNCTIONS + +int print(const char *s) { + fprint(&term, s); + return strlen(s); } -void printf(const char *format, ...) { +int printf(const char *format, ...) { va_list ap; + int l; va_start(ap, format); - vfprintf(term, format, ap); + l = vfprintf(&term, format, ap); va_end(ap); + return l; } -void fprint(FILE f, const char *s) { - write(f, 0, strlen(s), s); +int fprint(FILE *f, const char *s) { + return fwrite((void*)s, strlen(s), 1, f); } -void fprintf(FILE f, const char* format, ...) { +int fprintf(FILE *f, const char* format, ...) { va_list ap; + int l; va_start(ap, format); - vfprintf(f, format, ap); + l = vfprintf(f, format, ap); va_end(ap); + return l; } -void vfprintf(FILE f, const char *fmt, va_list ap) { +int vfprintf(FILE *f, const char *fmt, va_list ap) { va_list ap2; va_copy(ap2, ap); int l = printf_str_len(fmt, ap2); va_end(ap2); char buf[l+1]; l = vsprintf(buf, fmt, ap); - if (l > 0) write(f, 0, l, buf); + if (l > 0) return fwrite(buf, l, 1, f); + return 0; } |