#include #include #include #include #include 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); } int printf(const char *format, ...) { va_list ap; int l; va_start(ap, format); l = vfprintf(&term, format, ap); va_end(ap); return l; } int fprint(FILE *f, const char *s) { return fwrite((void*)s, strlen(s), 1, f); } int fprintf(FILE *f, const char* format, ...) { va_list ap; int l; va_start(ap, format); l = vfprintf(f, format, ap); va_end(ap); return l; } 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) return fwrite(buf, l, 1, f); return 0; }