#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <tce/syscall.h>
#include <ctype.h>
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;
}