From 00cde353baf5393ea2f5b19780090e4c6537af77 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Thu, 28 May 2015 23:28:55 +0900 Subject: [PATCH] xfile completely refactored --- extlib/benz/include/picrin.h | 2 - extlib/benz/include/picrin/config.h | 1 + extlib/benz/include/picrin/xfile.h | 694 ++++------------------------ extlib/benz/port.c | 89 ++-- extlib/benz/read.c | 9 +- extlib/benz/state.c | 10 +- extlib/benz/xfile.c | 472 +++++++++++++++++++ 7 files changed, 606 insertions(+), 671 deletions(-) create mode 100644 extlib/benz/xfile.c diff --git a/extlib/benz/include/picrin.h b/extlib/benz/include/picrin.h index 19fe9e16..c5fa86a9 100644 --- a/extlib/benz/include/picrin.h +++ b/extlib/benz/include/picrin.h @@ -32,8 +32,6 @@ extern "C" { #include #include -#include - #include "picrin/config.h" #include "picrin/util.h" #include "picrin/compat.h" diff --git a/extlib/benz/include/picrin/config.h b/extlib/benz/include/picrin/config.h index 1de25976..a0274422 100644 --- a/extlib/benz/include/picrin/config.h +++ b/extlib/benz/include/picrin/config.h @@ -156,6 +156,7 @@ #endif #if DEBUG +# include # define GC_STRESS 0 # define VM_DEBUG 1 # define GC_DEBUG 0 diff --git a/extlib/benz/include/picrin/xfile.h b/extlib/benz/include/picrin/xfile.h index cce8fd05..eff7d269 100644 --- a/extlib/benz/include/picrin/xfile.h +++ b/extlib/benz/include/picrin/xfile.h @@ -5,632 +5,104 @@ extern "C" { #endif +#include + +#ifndef NULL +# define NULL 0 +#endif + +#ifndef EOF +# define EOF (-1) +#endif + +#define XBUFSIZ 1024 +#define XOPEN_MAX 1024 + typedef struct { - int ungot; - int flags; + /* buffer */ + char buf[1]; /* fallback buffer */ + long cnt; /* characters left */ + char *ptr; /* next character position */ + char *base; /* location of the buffer */ /* operators */ struct { void *cookie; int (*read)(void *, char *, int); int (*write)(void *, const char *, int); long (*seek)(void *, long, int); - int (*flush)(void *); int (*close)(void *); } vtable; + int flag; /* mode of the file access */ } xFILE; -/* generic file constructor */ -PIC_INLINE xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *)); +extern xFILE x_iob[XOPEN_MAX]; -/* resource aquisition */ -PIC_INLINE xFILE *xfpopen(FILE *); -PIC_INLINE xFILE *xmopen(); -PIC_INLINE xFILE *xfopen(const char *, const char *); -PIC_INLINE int xfclose(xFILE *); +#define xstdin (x_iob[0].vtable.cookie || (x_iob[0].vtable.cookie = stdin ), &x_iob[0]) +#define xstdout (x_iob[1].vtable.cookie || (x_iob[1].vtable.cookie = stdout), &x_iob[1]) +#define xstderr (x_iob[2].vtable.cookie || (x_iob[2].vtable.cookie = stderr), &x_iob[2]) -/* buffer management */ -PIC_INLINE int xfflush(xFILE *); - -/* direct IO with buffering */ -PIC_INLINE size_t xfread(void *, size_t, size_t, xFILE *); -PIC_INLINE size_t xfwrite(const void *, size_t, size_t, xFILE *); - -/* indicator positioning */ -PIC_INLINE long xfseek(xFILE *, long offset, int whence); -PIC_INLINE long xftell(xFILE *); -PIC_INLINE void xrewind(xFILE *); - -/* stream status */ -PIC_INLINE void xclearerr(xFILE *); -PIC_INLINE int xfeof(xFILE *); -PIC_INLINE int xferror(xFILE *); - -/* character IO */ -PIC_INLINE int xfgetc(xFILE *); -PIC_INLINE char *xfgets(char *, int, xFILE *); -PIC_INLINE int xfputc(int, xFILE *); -PIC_INLINE int xfputs(const char *, xFILE *); -PIC_INLINE int xgetc(xFILE *); -PIC_INLINE int xgetchar(void); -PIC_INLINE int xputc(int, xFILE *); -PIC_INLINE int xputchar(int); -PIC_INLINE int xputs(const char *); -PIC_INLINE int xungetc(int, xFILE *); - -/* formatted I/O */ -PIC_INLINE int xprintf(const char *, ...); -PIC_INLINE int xfprintf(xFILE *, const char *, ...); -PIC_INLINE int xvfprintf(xFILE *, const char *, va_list); - -/* standard I/O */ -#define xstdin (xstdin_()) -#define xstdout (xstdout_()) -#define xstderr (xstderr_()) - - -/* private */ - -#define XF_EOF 1 -#define XF_ERR 2 - -PIC_INLINE xFILE * -xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *)) -{ - xFILE *file; - - file = (xFILE *)malloc(sizeof(xFILE)); - if (! file) { - return NULL; - } - file->ungot = -1; - file->flags = 0; - /* set vtable */ - file->vtable.cookie = cookie; - file->vtable.read = read; - file->vtable.write = write; - file->vtable.seek = seek; - file->vtable.flush = flush; - file->vtable.close = close; - - return file; -} - -/* - * Derieved xFILE Classes - */ - -PIC_INLINE int -xf_file_read(void *cookie, char *ptr, int size) -{ - FILE *file = cookie; - int r; - - r = (int)fread(ptr, 1, (size_t)size, file); - if (r < size && ferror(file)) { - return -1; - } - if (r == 0 && feof(file)) { - clearerr(file); - } - return r; -} - -PIC_INLINE int -xf_file_write(void *cookie, const char *ptr, int size) -{ - FILE *file = cookie; - int r; - - r = (int)fwrite(ptr, 1, (size_t)size, file); - if (r < size) { - return -1; - } - return r; -} - -PIC_INLINE long -xf_file_seek(void *cookie, long pos, int whence) -{ - return fseek(cookie, pos, whence); -} - -PIC_INLINE int -xf_file_flush(void *cookie) -{ - return fflush(cookie); -} - -PIC_INLINE int -xf_file_close(void *cookie) -{ - return fclose(cookie); -} - -PIC_INLINE xFILE * -xfpopen(FILE *fp) -{ - xFILE *file; - - file = xfunopen(fp, xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close); - if (! file) { - return NULL; - } - - return file; -} - -#define XF_FILE_VTABLE xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close - -PIC_INLINE xFILE * -xstdin_() -{ - static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } }; - - if (! x.vtable.cookie) { - x.vtable.cookie = stdin; - } - return &x; -} - -PIC_INLINE xFILE * -xstdout_() -{ - static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } }; - - if (! x.vtable.cookie) { - x.vtable.cookie = stdout; - } - return &x; -} - -PIC_INLINE xFILE * -xstderr_() -{ - static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } }; - - if (! x.vtable.cookie) { - x.vtable.cookie = stderr; - } - return &x; -} - -struct xf_membuf { - char *buf; - long pos, end, capa; +enum _flags { + X_READ = 01, + X_WRITE = 02, + X_UNBUF = 04, + X_EOF = 010, + X_ERR = 020, + X_LNBUF = 040 }; -PIC_INLINE int -xf_mem_read(void *cookie, char *ptr, int size) -{ - struct xf_membuf *mem; - - mem = (struct xf_membuf *)cookie; - - if (size > (int)(mem->end - mem->pos)) - size = (int)(mem->end - mem->pos); - memcpy(ptr, mem->buf + mem->pos, size); - mem->pos += size; - return size; -} - -PIC_INLINE int -xf_mem_write(void *cookie, const char *ptr, int size) -{ - struct xf_membuf *mem; - - mem = (struct xf_membuf *)cookie; - - if (mem->pos + size >= mem->capa) { - mem->capa = (mem->pos + size) * 2; - mem->buf = realloc(mem->buf, (size_t)mem->capa); - } - memcpy(mem->buf + mem->pos, ptr, size); - mem->pos += size; - if (mem->end < mem->pos) - mem->end = mem->pos; - return size; -} - -PIC_INLINE long -xf_mem_seek(void *cookie, long pos, int whence) -{ - struct xf_membuf *mem; - - mem = (struct xf_membuf *)cookie; - - switch (whence) { - case SEEK_SET: - mem->pos = pos; - break; - case SEEK_CUR: - mem->pos += pos; - break; - case SEEK_END: - mem->pos = mem->end + pos; - break; - } - - return mem->pos; -} - -PIC_INLINE int -xf_mem_flush(void *cookie) -{ - (void)cookie; - - return 0; -} - -PIC_INLINE int -xf_mem_close(void *cookie) -{ - struct xf_membuf *mem; - - mem = (struct xf_membuf *)cookie; - free(mem->buf); - free(mem); - return 0; -} - -PIC_INLINE xFILE * -xmopen() -{ - struct xf_membuf *mem; - - mem = (struct xf_membuf *)malloc(sizeof(struct xf_membuf)); - mem->buf = (char *)malloc(BUFSIZ); - mem->pos = 0; - mem->end = 0; - mem->capa = BUFSIZ; - - return xfunopen(mem, xf_mem_read, xf_mem_write, xf_mem_seek, xf_mem_flush, xf_mem_close); -} - -#undef XF_FILE_VTABLE - -PIC_INLINE xFILE * -xfopen(const char *filename, const char *mode) -{ - FILE *fp; - xFILE *file; - - fp = fopen(filename, mode); - if (! fp) { - return NULL; - } - - file = xfpopen(fp); - if (! file) { - return NULL; - } - - return file; -} - -PIC_INLINE int -xfclose(xFILE *file) -{ - int r; - - r = file->vtable.close(file->vtable.cookie); - if (r == EOF) { - return -1; - } - - free(file); - return 0; -} - -PIC_INLINE int -xfflush(xFILE *file) -{ - return file->vtable.flush(file->vtable.cookie); -} - -PIC_INLINE size_t -xfread(void *ptr, size_t block, size_t nitems, xFILE *file) -{ - char cbuf[256], *buf; - char *dst = (char *)ptr; - size_t i, offset; - int n; - - if (block <= 256) { - buf = cbuf; - } else { - buf = malloc(block); - } - - for (i = 0; i < nitems; ++i) { - offset = 0; - if (file->ungot != -1 && block > 0) { - buf[0] = (char)file->ungot; - offset += 1; - file->ungot = -1; - } - while (offset < block) { - n = file->vtable.read(file->vtable.cookie, buf + offset, (int)(block - offset)); - if (n < 0) { - file->flags |= XF_ERR; - goto exit; - } - if (n == 0) { - file->flags |= XF_EOF; - goto exit; - } - offset += (unsigned)n; - } - memcpy(dst, buf, block); - dst += block; - } - - exit: - - if (cbuf != buf) { - free(buf); - } - return i; -} - -PIC_INLINE size_t -xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file) -{ - char *dst = (char *)ptr; - size_t i, offset; - int n; - - for (i = 0; i < nitems; ++i) { - offset = 0; - while (offset < block) { - n = file->vtable.write(file->vtable.cookie, dst + offset, (int)(block - offset)); - if (n < 0) { - file->flags |= XF_ERR; - goto exit; - } - offset += (unsigned)n; - } - dst += block; - } - - exit: - return i; -} - -PIC_INLINE long -xfseek(xFILE *file, long offset, int whence) -{ - file->ungot = -1; - return file->vtable.seek(file->vtable.cookie, offset, whence); -} - -PIC_INLINE long -xftell(xFILE *file) -{ - return xfseek(file, 0, SEEK_CUR); -} - -PIC_INLINE void -xrewind(xFILE *file) -{ - xfseek(file, 0, SEEK_SET); -} - -PIC_INLINE void -xclearerr(xFILE *file) -{ - file->flags = 0; -} - -PIC_INLINE int -xfeof(xFILE *file) -{ - return file->flags & XF_EOF; -} - -PIC_INLINE int -xferror(xFILE *file) -{ - return file->flags & XF_ERR; -} - -PIC_INLINE int -xfgetc(xFILE *file) -{ - char buf[1]; - - xfread(buf, 1, 1, file); - - if (xfeof(file) || xferror(file)) { - return EOF; - } - - return buf[0]; -} - -PIC_INLINE int -xgetc(xFILE *file) -{ - return xfgetc(file); -} - -PIC_INLINE char * -xfgets(char *str, int size, xFILE *file) -{ - int c = EOF, i; - - for (i = 0; i < size - 1 && c != '\n'; ++i) { - if ((c = xfgetc(file)) == EOF) { - break; - } - str[i] = (char)c; - } - if (i == 0 && c == EOF) { - return NULL; - } - if (xferror(file)) { - return NULL; - } - str[i] = '\0'; - - return str; -} - -PIC_INLINE int -xungetc(int c, xFILE *file) -{ - file->ungot = c; - if (c != EOF) { - file->flags &= ~XF_EOF; - } - return c; -} - -PIC_INLINE int -xgetchar(void) -{ - return xfgetc(xstdin); -} - -PIC_INLINE int -xfputc(int c, xFILE *file) -{ - char buf[1]; - - buf[0] = (char)c; - xfwrite(buf, 1, 1, file); - - if (xferror(file)) { - return EOF; - } - return buf[0]; -} - -PIC_INLINE int -xputc(int c, xFILE *file) -{ - return xfputc(c, file); -} - -PIC_INLINE int -xputchar(int c) -{ - return xfputc(c, xstdout); -} - -PIC_INLINE int -xfputs(const char *str, xFILE *file) -{ - size_t len; - - len = strlen(str); - xfwrite(str, len, 1, file); - - if (xferror(file)) { - return EOF; - } - return 0; -} - -PIC_INLINE int -xputs(const char *s) -{ - return xfputs(s, xstdout); -} - -PIC_INLINE int -xprintf(const char *fmt, ...) -{ - va_list ap; - int n; - - va_start(ap, fmt); - n = xvfprintf(xstdout, fmt, ap); - va_end(ap); - return n; -} - -PIC_INLINE int -xfprintf(xFILE *stream, const char *fmt, ...) -{ - va_list ap; - int n; - - va_start(ap, fmt); - n = xvfprintf(stream, fmt, ap); - va_end(ap); - return n; -} - -static void -xfile_printint(xFILE *stream, long x, int base) -{ - static char digits[] = "0123456789abcdef"; - char buf[20]; - int i, neg; - - neg = 0; - if (x < 0) { - neg = 1; - x = -x; - } - - i = 0; - do { - buf[i++] = digits[x % base]; - } while ((x /= base) != 0); - - if (neg) { - buf[i++] = '-'; - } - - while (i-- > 0) { - xputc(buf[i], stream); - } -} - -PIC_INLINE int -xvfprintf(xFILE *stream, const char *fmt, va_list ap) -{ - const char *p; - char *sval; - int ival; - double dval; - void *vp; - long seekr = xftell(stream); - - for (p = fmt; *p; p++) { - if (*p != '%') { - xputc(*p, stream); - continue; - } - switch (*++p) { - case 'd': - case 'i': - ival = va_arg(ap, int); - xfile_printint(stream, ival, 10); - break; - case 'f': - dval = va_arg(ap, double); - xfile_printint(stream, dval, 10); - xputc('.', stream); - xfile_printint(stream, fabs((dval - (int)dval) * 1e4), 10); - break; - case 's': - sval = va_arg(ap, char*); - xfputs(sval, stream); - break; - case 'p': - vp = va_arg(ap, void*); - xfputs("0x", stream); - xfile_printint(stream, (long)vp, 16); - break; - default: - xputc(*(p-1), stream); - break; - } - } - return xftell(stream) - seekr; -} +#define xclearerr(p) ((p)->flag &= ~(X_EOF | X_ERR)) +#define xfeof(p) (((p)->flag & X_EOF) != 0) +#define xferror(p) (((p)->flag & X_ERR) != 0) +#define xfileno(p) ((p)->fd) + +#define xgetc(p) \ + ((--(p)->cnt >= 0) \ + ? (unsigned char) *(p)->ptr++ \ + : x_fillbuf(p)) +#define xputc(x, p) \ + ((--(p)->cnt >= 0 && !(((p)->flag & X_LNBUF) && (x) == '\n')) \ + ? *(p)->ptr++ = (x) \ + : x_flushbuf(x, (p))) +#define xgetchar() xgetc(xstdin) +#define xputchar(x) xputc((x), xstdout) + +/* resource aquisition */ +xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*close)(void *)); +xFILE *xfopen(const char *, const char *); +int xfclose(xFILE *); + +/* buffer management */ +int x_fillbuf(xFILE *); +int x_flushbuf(int, xFILE *); +int xfflush(xFILE *); + +/* direct IO */ +size_t xfread(void *, size_t, size_t, xFILE *); +size_t xfwrite(const void *, size_t, size_t, xFILE *); + +enum { + XSEEK_CUR, + XSEEK_END, + XSEEK_SET +}; + +/* indicator positioning */ +long xfseek(xFILE *, long, int); +long xftell(xFILE *); +void xrewind(xFILE *); + +/* character IO */ +int xfputc(int, xFILE *); +int xfgetc(xFILE *); +int xfputs(const char *, xFILE *); +char *xfgets(char *, int, xFILE *); +int xputs(const char *); +int xungetc(int, xFILE *); + +/* formatted I/O */ +int xprintf(const char *, ...); +int xfprintf(xFILE *, const char *, ...); +int xvfprintf(xFILE *, const char *, va_list); #if defined(__cplusplus) } diff --git a/extlib/benz/port.c b/extlib/benz/port.c index df6a971c..20879173 100644 --- a/extlib/benz/port.c +++ b/extlib/benz/port.c @@ -68,7 +68,7 @@ struct strfile { }; static int -strfile_read(void *cookie, char *ptr, int size) +string_read(void *cookie, char *ptr, int size) { struct strfile *m = cookie; @@ -80,7 +80,7 @@ strfile_read(void *cookie, char *ptr, int size) } static int -strfile_write(void *cookie, const char *ptr, int size) +string_write(void *cookie, const char *ptr, int size) { struct strfile *m = cookie; @@ -96,18 +96,18 @@ strfile_write(void *cookie, const char *ptr, int size) } static long -strfile_seek(void *cookie, long pos, int whence) +string_seek(void *cookie, long pos, int whence) { struct strfile *m = cookie; switch (whence) { - case SEEK_SET: + case XSEEK_SET: m->pos = pos; break; - case SEEK_CUR: + case XSEEK_CUR: m->pos += pos; break; - case SEEK_END: + case XSEEK_END: m->pos = m->end + pos; break; } @@ -116,15 +116,7 @@ strfile_seek(void *cookie, long pos, int whence) } static int -strfile_flush(void *cookie) -{ - (void)cookie; - - return 0; -} - -static int -strfile_close(void *cookie) +string_close(void *cookie) { struct strfile *m = cookie; @@ -134,9 +126,8 @@ strfile_close(void *cookie) } static xFILE * -strfile_open(pic_state *pic) +string_open(pic_state *pic, const char *data, size_t size) { - static const size_t size = 128; struct strfile *m; xFILE *file; @@ -144,12 +135,19 @@ strfile_open(pic_state *pic) m->pic = pic; m->buf = pic_malloc(pic, size); m->pos = 0; - m->end = 0; + m->end = size; m->capa = size; - file = xfunopen(m, strfile_read, strfile_write, strfile_seek, strfile_flush, strfile_close); + memcpy(m->buf, data, size); + + if (data != NULL) { + file = xfunopen(m, string_read, NULL, string_seek, string_close); + } else { + file = xfunopen(m, NULL, string_write, string_seek, string_close); + } + if (file == NULL) { - strfile_close(m); + string_close(m); pic_error(pic, "could not open new output string/bytevector port", pic_nil_value()); } return file; @@ -161,14 +159,10 @@ pic_open_input_string(pic_state *pic, const char *str) struct pic_port *port; port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT); - port->file = strfile_open(pic); + port->file = string_open(pic, str, strlen(str)); port->flags = PIC_PORT_IN | PIC_PORT_TEXT; port->status = PIC_PORT_OPEN; - xfputs(str, port->file); - xfflush(port->file); - xrewind(port->file); - return port; } @@ -178,7 +172,7 @@ pic_open_output_string(pic_state *pic) struct pic_port *port; port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT); - port->file = strfile_open(pic); + port->file = string_open(pic, NULL, 0); port->flags = PIC_PORT_OUT | PIC_PORT_TEXT; port->status = PIC_PORT_OPEN; @@ -188,20 +182,17 @@ pic_open_output_string(pic_state *pic) struct pic_string * pic_get_output_string(pic_state *pic, struct pic_port *port) { - size_t size; - char *buf; + struct strfile *s; + + if (port->file->vtable.write != string_write) { + pic_errorf(pic, "get-output-string: port is not made by open-output-string"); + } - /* get endpos */ xfflush(port->file); - size = (size_t)xftell(port->file); - xrewind(port->file); - /* copy to buf */ - buf = (char *)pic_malloc(pic, size + 1); - buf[size] = 0; - xfread(buf, size, 1, port->file); + s = port->file->vtable.cookie; - return pic_make_str(pic, buf, size); + return pic_make_str(pic, s->buf, s->end); } void @@ -417,14 +408,10 @@ pic_port_open_input_blob(pic_state *pic) pic_get_args(pic, "b", &blob); port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT); - port->file = strfile_open(pic); + port->file = string_open(pic, (const char *)blob->data, blob->len); port->flags = PIC_PORT_IN | PIC_PORT_BINARY; port->status = PIC_PORT_OPEN; - xfwrite(blob->data, 1, blob->len, port->file); - xfflush(port->file); - xrewind(port->file); - return pic_obj_value(port); } @@ -436,7 +423,7 @@ pic_port_open_output_bytevector(pic_state *pic) pic_get_args(pic, ""); port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT); - port->file = strfile_open(pic); + port->file = string_open(pic, NULL, 0); port->flags = PIC_PORT_OUT | PIC_PORT_BINARY; port->status = PIC_PORT_OPEN; @@ -448,20 +435,22 @@ pic_port_get_output_bytevector(pic_state *pic) { struct pic_port *port = pic_stdout(pic); pic_blob *blob; - size_t size; + struct strfile *s; pic_get_args(pic, "|p", &port); assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "get-output-bytevector"); - /* get endpos */ - xfflush(port->file); - size = (size_t)xftell(port->file); - xrewind(port->file); + if (port->file->vtable.write != string_write) { + pic_errorf(pic, "get-output-bytevector: port is not made by open-output-bytevector"); + } - /* copy to buf */ - blob = pic_make_blob(pic, size); - xfread(blob->data, 1, size, port->file); + xfflush(port->file); + + s = port->file->vtable.cookie; + + blob = pic_make_blob(pic, s->end); + memcpy(blob->data, s->buf, s->end); return pic_obj_value(blob); } diff --git a/extlib/benz/read.c b/extlib/benz/read.c index d2300579..ce60a995 100644 --- a/extlib/benz/read.c +++ b/extlib/benz/read.c @@ -856,11 +856,14 @@ pic_read(pic_state *pic, struct pic_port *port) pic_value pic_read_cstr(pic_state *pic, const char *str) { - struct pic_port *port; + struct pic_port *port = pic_open_input_string(pic, str); + pic_value form; - port = pic_open_input_string(pic, str); + form = pic_read(pic, port); - return pic_read(pic, port); + pic_close_port(pic, port); + + return form; } static pic_value diff --git a/extlib/benz/state.c b/extlib/benz/state.c index efc8d2a8..571c5155 100644 --- a/extlib/benz/state.c +++ b/extlib/benz/state.c @@ -326,17 +326,17 @@ pic_open(int argc, char *argv[], char **envp, pic_allocf allocf) /* reader */ pic->reader = pic_reader_open(pic); + /* standard I/O */ + pic->xSTDIN = pic_make_standard_port(pic, xstdin, PIC_PORT_IN); + pic->xSTDOUT = pic_make_standard_port(pic, xstdout, PIC_PORT_OUT); + pic->xSTDERR = pic_make_standard_port(pic, xstderr, PIC_PORT_OUT); + /* standard libraries */ pic->PICRIN_BASE = pic_open_library(pic, pic_read_cstr(pic, "(picrin base)")); pic->PICRIN_USER = pic_open_library(pic, pic_read_cstr(pic, "(picrin user)")); pic->lib = pic->PICRIN_USER; pic->prev_lib = NULL; - /* standard I/O */ - pic->xSTDIN = pic_make_standard_port(pic, xstdin, PIC_PORT_IN); - pic->xSTDOUT = pic_make_standard_port(pic, xstdout, PIC_PORT_OUT); - pic->xSTDERR = pic_make_standard_port(pic, xstderr, PIC_PORT_OUT); - pic_gc_arena_restore(pic, ai); /* turn on GC */ diff --git a/extlib/benz/xfile.c b/extlib/benz/xfile.c new file mode 100644 index 00000000..d09bf9bf --- /dev/null +++ b/extlib/benz/xfile.c @@ -0,0 +1,472 @@ +#include "picrin.h" + +static int file_read(void *cookie, char *ptr, int size) { + FILE *file = cookie; + int r; + + size = 1; /* override size */ + + r = (int)fread(ptr, 1, (size_t)size, file); + if (r < size && ferror(file)) { + return -1; + } + if (r == 0 && feof(file)) { + clearerr(file); + } + return r; +} + +static int file_write(void *cookie, const char *ptr, int size) { + FILE *file = cookie; + int r; + + r = (int)fwrite(ptr, 1, (size_t)size, file); + if (r < size) { + return -1; + } + fflush(cookie); + return r; +} + +static long file_seek(void *cookie, long pos, int whence) { + switch (whence) { + case XSEEK_CUR: + whence = SEEK_CUR; + break; + case XSEEK_SET: + whence = SEEK_SET; + break; + case XSEEK_END: + whence = SEEK_END; + break; + } + return fseek(cookie, pos, whence); +} + +static int file_close(void *cookie) { + return fclose(cookie); +} + +xFILE *xfopen(const char *name, const char *mode) { + FILE *fp; + + if ((fp = fopen(name, mode)) == NULL) { + return NULL; + } + + switch (*mode) { + case 'r': + return xfunopen(fp, file_read, NULL, file_seek, file_close); + default: + return xfunopen(fp, NULL, file_write, file_seek, file_close); + } +} + +#define FILE_VTABLE { 0, file_read, file_write, file_seek, file_close } + +xFILE x_iob[XOPEN_MAX] = { + { { 0 }, 0, NULL, NULL, FILE_VTABLE, X_READ }, + { { 0 }, 0, NULL, NULL, FILE_VTABLE, X_WRITE | X_LNBUF }, + { { 0 }, 0, NULL, NULL, FILE_VTABLE, X_WRITE | X_UNBUF } +}; + +xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*close)(void *)) { + xFILE *fp; + + for (fp = x_iob; fp < x_iob + XOPEN_MAX; fp++) + if ((fp->flag & (X_READ | X_WRITE)) == 0) + break; /* found free slot */ + + if (fp >= x_iob + XOPEN_MAX) /* no free slots */ + return NULL; + + fp->cnt = 0; + fp->base = NULL; + fp->flag = read? X_READ : X_WRITE; + + fp->vtable.cookie = cookie; + fp->vtable.read = read; + fp->vtable.write = write; + fp->vtable.seek = seek; + fp->vtable.close = close; + + return fp; +} + +int xfclose(xFILE *fp) { + xfflush(fp); + fp->flag = 0; + if (fp->base != fp->buf) + free(fp->base); + return fp->vtable.close(fp->vtable.cookie); +} + +int x_fillbuf(xFILE *fp) { + int bufsize; + + if ((fp->flag & (X_READ|X_EOF|X_ERR)) != X_READ) + return EOF; + if (fp->base == NULL) { + if ((fp->flag & X_UNBUF) == 0) { + /* no buffer yet */ + if ((fp->base = malloc(XBUFSIZ)) == NULL) { + /* can't get buffer, try unbuffered */ + fp->flag |= X_UNBUF; + } + } + if (fp->flag & X_UNBUF) { + fp->base = fp->buf; + } + } + bufsize = (fp->flag & X_UNBUF) ? sizeof(fp->buf) : XBUFSIZ; + + fp->ptr = fp->base; + fp->cnt = fp->vtable.read(fp->vtable.cookie, fp->ptr, bufsize); + + if (--fp->cnt < 0) { + if (fp->cnt == -1) + fp->flag |= X_EOF; + else + fp->flag |= X_ERR; + fp->cnt = 0; + return EOF; + } + + return (unsigned char) *fp->ptr++; +} + +int x_flushbuf(int x, xFILE *fp) { + int num_written=0, bufsize=0; + char c = x; + + if ((fp->flag & (X_WRITE|X_EOF|X_ERR)) != X_WRITE) + return EOF; + if (fp->base == NULL && ((fp->flag & X_UNBUF) == 0)) { + /* no buffer yet */ + if ((fp->base = malloc(XBUFSIZ)) == NULL) { + /* couldn't allocate a buffer, so try unbuffered */ + fp->flag |= X_UNBUF; + } else { + fp->ptr = fp->base; + fp->cnt = XBUFSIZ - 1; + } + } + if (fp->flag & X_UNBUF) { + /* unbuffered write */ + fp->ptr = fp->base = NULL; + fp->cnt = 0; + if (x == EOF) + return EOF; + num_written = fp->vtable.write(fp->vtable.cookie, (const char *) &c, 1); + bufsize = 1; + } else { + /* buffered write */ + assert(fp->ptr); + if (x != EOF) { + *fp->ptr++ = (unsigned char) c; + } + bufsize = (int)(fp->ptr - fp->base); + while(bufsize - num_written > 0) { + int t; + t = fp->vtable.write(fp->vtable.cookie, fp->base + num_written, bufsize - num_written); + if (t < 0) + break; + num_written += t; + } + + fp->ptr = fp->base; + fp->cnt = BUFSIZ - 1; + } + + if (num_written == bufsize) { + return x; + } else { + fp->flag |= X_ERR; + return EOF; + } +} + +int xfflush(xFILE *f) { + int retval; + int i; + + retval = 0; + if (f == NULL) { + /* flush all output streams */ + for (i = 0; i < XOPEN_MAX; i++) { + if ((x_iob[i].flag & X_WRITE) && (xfflush(&x_iob[i]) == -1)) + retval = -1; + } + } else { + if ((f->flag & X_WRITE) == 0) + return -1; + x_flushbuf(EOF, f); + if (f->flag & X_ERR) + retval = -1; + } + return retval; +} + +int xfputc(int x, xFILE *fp) { + return xputc(x, fp); +} + +int xfgetc(xFILE *fp) { + return xgetc(fp); +} + +int xfputs(const char *s, xFILE *stream) { + const char *ptr = s; + while(*ptr != '\0') { + if (xputc(*ptr, stream) == EOF) + return EOF; + ++ptr; + } + return (int)(ptr - s); +} + +char *xfgets(char *s, int size, xFILE *stream) { + int c; + char *buf; + + xfflush(NULL); + + if (size == 0) { + return NULL; + } + buf = s; + while (--size > 0 && (c = xgetc(stream)) != EOF) { + if ((*buf++ = c) == '\n') + break; + } + *buf = '\0'; + + return (c == EOF && buf == s) ? NULL : s; +} + +int xputs(const char *s) { + int i = 1; + + while(*s != '\0') { + if (xputchar(*s++) == EOF) + return EOF; + i++; + } + if (xputchar('\n') == EOF) { + return EOF; + } + return i; +} + +char *xgets(char *s) { + int c; + char *buf; + + xfflush(NULL); + + buf = s; + while ((c = xgetchar()) != EOF && c != '\n') { + *buf++ = c; + } + *buf = '\0'; + + return (c == EOF && buf == s) ? NULL : s; +} + +int xungetc(int c, xFILE *fp) { + unsigned char uc = c; + + if (c == EOF || fp->base == fp->ptr) { + return EOF; + } + fp->cnt++; + return *--fp->ptr = uc; +} + +size_t xfread(void *ptr, size_t size, size_t count, xFILE *fp) { + long nbytes; + int c; + + nbytes = size * count; + while (nbytes > fp->cnt) { + memcpy((char *)ptr, fp->ptr, fp->cnt); + fp->ptr += fp->cnt; + ptr += fp->cnt; + nbytes -= fp->cnt; + if ((c = x_fillbuf(fp)) == EOF) { + return (size * count - nbytes) / size; + } else { + xungetc(c, fp); + } + } + memcpy((char *)ptr, fp->ptr, nbytes); + fp->ptr += nbytes; + fp->cnt -= nbytes; + return count; +} + +size_t xfwrite(const void *ptr, size_t size, size_t count, xFILE *fp) { + long nbytes; + + nbytes = size * count; + while (nbytes > fp->cnt) { + memcpy(fp->ptr, (char *)ptr, fp->cnt); + fp->ptr += fp->cnt; + ptr += fp->cnt; + nbytes -= fp->cnt; + if (x_flushbuf(EOF, fp) == EOF) { + return (size * count - nbytes) / size; + } + } + memcpy(fp->ptr, (char *)ptr, nbytes); + fp->ptr += nbytes; + fp->cnt -= nbytes; + return count; +} + +long xfseek(xFILE *fp, long offset, int whence) { + long s; + + xfflush(fp); + + fp->ptr = fp->base; + fp->cnt = 0; + + if ((s = fp->vtable.seek(fp->vtable.cookie, offset, whence)) != 0) + return s; + fp->flag &= ~X_EOF; + return 0; +} + +long xftell(xFILE *fp) { + return xfseek(fp, 0, XSEEK_CUR); +} + +void xrewind(xFILE *fp) { + xfseek(fp, 0, XSEEK_SET); + xclearerr(fp); +} + +int xprintf(const char *fmt, ...) { + va_list ap; + int n; + + va_start(ap, fmt); + n = xvfprintf(xstdout, fmt, ap); + va_end(ap); + return n; +} + +int xfprintf(xFILE *stream, const char *fmt, ...) { + va_list ap; + int n; + + va_start(ap, fmt); + n = xvfprintf(stream, fmt, ap); + va_end(ap); + return n; +} + +static int print_int(xFILE *stream, long x, int base) { + static char digits[] = "0123456789abcdef"; + char buf[20]; + int i, c, neg; + + neg = 0; + if (x < 0) { + neg = 1; + x = -x; + } + + i = 0; + do { + buf[i++] = digits[x % base]; + } while ((x /= base) != 0); + + if (neg) { + buf[i++] = '-'; + } + + c = i; + while (i-- > 0) { + xputc(buf[i], stream); + } + return c; +} + +int xvfprintf(xFILE *stream, const char *fmt, va_list ap) { + const char *p; + char *sval; + int ival; +#if PIC_ENABLE_FLOAT + double dval; +#endif + void *vp; + int cnt = 0; + + for (p = fmt; *p; p++) { + if (*p != '%') { + xputc(*p, stream); + cnt++; + continue; + } + switch (*++p) { + case 'd': + case 'i': + ival = va_arg(ap, int); + cnt += print_int(stream, ival, 10); + break; +#if PIC_ENABLE_FLOAT + case 'f': + dval = va_arg(ap, double); + cnt += print_int(stream, dval, 10); + xputc('.', stream); + cnt++; + if ((ival = fabs((dval - floor(dval)) * 1e4) + 0.5) == 0) { + cnt += xfputs("0000", stream); + } else { + int i; + for (i = 0; i < 3 - (int)log10(ival); ++i) { + xputc('0', stream); + cnt++; + } + cnt += print_int(stream, ival, 10); + } + break; +#endif + case 's': + sval = va_arg(ap, char*); + cnt += xfputs(sval, stream); + break; + case 'p': + vp = va_arg(ap, void*); + cnt += xfputs("0x", stream); + cnt += print_int(stream, (long)vp, 16); + break; + case '%': + xputc(*(p-1), stream); + cnt++; + break; + default: + xputc('%', stream); + xputc(*(p-1), stream); + cnt += 2; + break; + } + } + return cnt; +} + +#if 0 +int main() +{ + char buf[256]; + + xgets(buf); + + xprintf("%s\n", buf); + xprintf("hello\n"); + xprintf("hello\n"); + // xfflush(0); +} +#endif