From 6466208ec051e58b824cc3c839b6b086ae910fe6 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Sat, 16 Jul 2016 23:39:51 +0200 Subject: Progress on stdio impementation --- src/common/include/kogata/printf.h | 2 + src/common/libc/printf.c | 210 +++++++++++++++++++----------------- src/common/libc/string.c | 3 +- src/lib/include/stdio.h | 16 ++- src/lib/libc/stdio.c | 215 ++++++++++++++++++++++++++++++------- src/lib/lua/luaconf.h | 2 +- 6 files changed, 309 insertions(+), 139 deletions(-) diff --git a/src/common/include/kogata/printf.h b/src/common/include/kogata/printf.h index b4e1c1b..121af78 100644 --- a/src/common/include/kogata/printf.h +++ b/src/common/include/kogata/printf.h @@ -7,4 +7,6 @@ int snprintf(char* s, size_t n, const char* format, ...); int vsnprintf(char* s, size_t n, const char* format, va_list arg); +int vcprintf(int (*putc_fun)(int c, void* p), void* p, const char* format, va_list arg); + /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/common/libc/printf.c b/src/common/libc/printf.c index 0498b2d..fbebafe 100644 --- a/src/common/libc/printf.c +++ b/src/common/libc/printf.c @@ -1,6 +1,7 @@ #include #include +#include #include int snprintf(char * buff, size_t len, const char *format, ...) { @@ -13,20 +14,48 @@ int snprintf(char * buff, size_t len, const char *format, ...) { return len; } -int vsnprintf(char *buff, size_t len, const char* format, va_list ap){ - size_t i, result; +struct vsnprintf_s { + char* buff; + size_t len; + size_t i; +}; +int vsnprintf_putc_fun(int c, void* p) { + struct vsnprintf_s *s = (struct vsnprintf_s*)p; + if (s->i < s->len - 1) { + s->buff[s->i] = c; + s->i++; + return 1; + } else { + return 0; + } +} +int vsnprintf(char *buff, size_t len, const char* format, va_list arg){ if (!buff || !format) return -1; -#define PUTCHAR(thechar) \ - do { \ - if (result < len-1) \ - *buff++ = (thechar); \ - result++; \ - } while (0) + struct vsnprintf_s s; + s.buff = buff; + s.len = len; + s.i = 0; + + size_t ret = vcprintf(vsnprintf_putc_fun, &s, format, arg); + ASSERT(ret == s.i); + + buff[s.i] = 0; + return s.i; +} + +int vcprintf(int (*putc_fun)(int c, void* p), void* p, const char* format, va_list ap) { + if (!format) return -1; + + int ret = 0; +#define PUTCHAR(thechar) { int _tmp = putc_fun(thechar, p);\ + if (_tmp == 1) ret++; \ + else if (_tmp == 0) return ret; \ + else if (_tmp < 0) return _tmp; } - result = 0; + size_t i; for(i = 0; format[i] != '\0' ; i++) { if (format[i] == '%') { i++; @@ -34,111 +63,98 @@ int vsnprintf(char *buff, size_t len, const char* format, va_list ap){ int l = 0; bool spec = true; while (spec) { - switch(format[i]) { - case 'l': { - l++; - i++; - break; - } - case 'u': { - u = 1; - i++; - break; - } - default: - spec = false; + if (format[i] == 'l') { + l++; + i++; + } else if (format[i] == 'u') { + u = 1; + i++; + } else { + spec = false; } } - switch(format[i]) { - case '%': + if (format[i] == '%') { PUTCHAR('%'); - break; - case 'i':; - case 'd': { - if (u) { - // TODO - } else { - long long int integer; - if (l == 0) integer = va_arg(ap, int); - if (l == 1) integer = va_arg(ap, long int); - if (l == 2) integer = va_arg(ap, long long int); - - int cpt2 = 0; - char buff_int[32]; - - if (integer<0) - PUTCHAR('-'); - - do { - int m10 = integer%10; - m10 = (m10 < 0)? -m10:m10; - buff_int[cpt2++] = (char)('0'+ m10); - integer = integer/10; - } while(integer != 0); - - for(cpt2 = cpt2 - 1; cpt2 >= 0; cpt2--) - PUTCHAR(buff_int[cpt2]); + } else if (format[i] == 'i' || format[i] == 'd') { + if (u) { + // TODO + } else { + long long int integer; + if (l == 0) integer = va_arg(ap, int); + if (l == 1) integer = va_arg(ap, long int); + if (l == 2) integer = va_arg(ap, long long int); + + int cpt2 = 0; + char buff_int[32]; + + if (integer<0) { + PUTCHAR('-'); } - break; + + do { + int m10 = integer%10; + m10 = (m10 < 0)? -m10:m10; + buff_int[cpt2++] = (char)('0'+ m10); + integer = integer/10; + } while(integer != 0); + + for(cpt2 = cpt2 - 1; cpt2 >= 0; cpt2--) + PUTCHAR(buff_int[cpt2]); } - case 'c': { + } else if (format[i] == 'c') { int value = va_arg(ap,int); PUTCHAR((char)value); break; + } else if (format[i] == 's') { + char *string = va_arg(ap,char *); + if (!string) + string = "(null)"; + for(; *string != '\0' ; string++) + PUTCHAR(*string); + } else if (format[i] == 'x') { + unsigned int hexa = va_arg(ap,int); + int had_nonzero = 0; + for(int j = 0; j < 8; j++) { + unsigned int nb = (unsigned int)(hexa << (j*4)); + nb = (nb >> 28) & 0xf; + // Skip the leading zeros + if (nb == 0) { + if (had_nonzero) { + PUTCHAR('0'); + } + } else { + had_nonzero = 1; + if (nb < 10) { + PUTCHAR('0'+nb); + } else { + PUTCHAR('a'+(nb-10)); + } + } } - case 's': { - char *string = va_arg(ap,char *); - if (!string) - string = "(null)"; - for(; *string != '\0' ; string++) - PUTCHAR(*string); - break; - } - case 'x': { - unsigned int hexa = va_arg(ap,int); - int had_nonzero = 0; - for(int j = 0; j < 8; j++) { - unsigned int nb = (unsigned int)(hexa << (j*4)); - nb = (nb >> 28) & 0xf; - // Skip the leading zeros - if (nb == 0) { - if (had_nonzero) - PUTCHAR('0'); - } else { - had_nonzero = 1; - if (nb < 10) - PUTCHAR('0'+nb); - else - PUTCHAR('a'+(nb-10)); - } - } - if (!had_nonzero) - PUTCHAR('0'); - break; + if (!had_nonzero) { + PUTCHAR('0'); } - case 'p': { - unsigned int hexa = va_arg(ap,int); - for (int j = 0; j < 8; j++) { - unsigned int nb = (unsigned int)(hexa << (j*4)); - nb = (nb >> 28) & 0xf; - if (nb < 10) - PUTCHAR('0'+nb); - else - PUTCHAR('a'+(nb-10)); - } - break; + } else if (format[i] == 'p') { + unsigned int hexa = va_arg(ap,int); + for (int j = 0; j < 8; j++) { + unsigned int nb = (unsigned int)(hexa << (j*4)); + nb = (nb >> 28) & 0xf; + if (nb < 10) { + PUTCHAR('0'+nb); + } else { + PUTCHAR('a'+(nb-10)); + } } - default: - PUTCHAR('%'); - PUTCHAR(format[i]); + } else { + PUTCHAR('%'); + PUTCHAR(format[i]); } } else { PUTCHAR(format[i]); } } - *buff = '\0'; - return result; + return ret; } /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/common/libc/string.c b/src/common/libc/string.c index 4b99dda..b2c6bb8 100644 --- a/src/common/libc/string.c +++ b/src/common/libc/string.c @@ -176,8 +176,9 @@ size_t strspn(const char *s, const char *accept) { } const char *strstr(const char *haystack, const char *needle) { + int n = strlen(needle); for (const char* p = haystack; *p != 0; p++) { - if (!strcmp(p, needle)) return p; + if (!strncmp(p, needle, n)) return p; } return NULL; } diff --git a/src/lib/include/stdio.h b/src/lib/include/stdio.h index a67553c..5bb3b71 100644 --- a/src/lib/include/stdio.h +++ b/src/lib/include/stdio.h @@ -10,13 +10,22 @@ void setup_libc_stdio(); +#define BUFSIZ 256 + -//TODO below struct file_t { fd_t fd; stat_t st; - int mode; - int flags; + int file_mode; + + size_t pos; + + int buf_mode; + char *out_buf; + size_t out_buf_size, out_buf_used; + bool out_buf_owned; + + int ungetc_char; }; typedef struct file_t FILE; @@ -52,7 +61,6 @@ int fclose(FILE* f); extern FILE *stdin, *stdout, *stderr; -#define BUFSIZ 1024 void setbuf(FILE *stream, char *buf); void setbuffer(FILE *stream, char *buf, size_t size); void setlinebuf(FILE *stream); 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 #include +#include #include @@ -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 // --------------------- diff --git a/src/lib/lua/luaconf.h b/src/lib/lua/luaconf.h index c6592fb..22418f3 100644 --- a/src/lib/lua/luaconf.h +++ b/src/lib/lua/luaconf.h @@ -178,7 +178,7 @@ LUA_ROOT"?.lua;" LUA_ROOT"?/init.lua;" \ "./?.lua;" "./?/init.lua" #define LUA_CPATH_DEFAULT \ - LUA_ROOT"?.so;" LUA_ROOT"loadall.so;" "./?.so" + LUA_ROOT"?.so;" "./?.so" /* -- cgit v1.2.3