summaryrefslogtreecommitdiff
path: root/src/user/lib/libc/std/stdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib/libc/std/stdio.c')
-rw-r--r--src/user/lib/libc/std/stdio.c245
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;
}