diff --git a/lib/ext/file.c b/lib/ext/file.c index 4dc55229..69826ccd 100644 --- a/lib/ext/file.c +++ b/lib/ext/file.c @@ -123,6 +123,34 @@ pic_file_open_output_file(pic_state *pic) return pic_fopen(pic, fp, "w"); } +pic_value +pic_file_open_binary_input_file(pic_state *pic) +{ + const char *fname; + FILE *fp; + + pic_get_args(pic, "z", &fname); + + if ((fp = fopen(fname, "rb")) == NULL) { + file_error(pic, "could not open file", 1, pic_cstr_value(pic, fname)); + } + return pic_fopen(pic, fp, "rb"); +} + +pic_value +pic_file_open_binary_output_file(pic_state *pic) +{ + const char *fname; + FILE *fp; + + pic_get_args(pic, "z", &fname); + + if ((fp = fopen(fname, "wb")) == NULL) { + file_error(pic, "could not open file", 1, pic_cstr_value(pic, fname)); + } + return pic_fopen(pic, fp, "wb"); +} + pic_value pic_file_exists_p(pic_state *pic) { @@ -154,13 +182,21 @@ pic_file_delete(pic_state *pic) void pic_init_file(pic_state *pic) { - pic_defvar(pic, "current-input-port", pic_fopen(pic, stdin, "r")); - pic_defvar(pic, "current-output-port", pic_fopen(pic, stdout, "w")); - pic_defvar(pic, "current-error-port", pic_fopen(pic, stdout, "w")); + pic_value i, o, e; + + i = pic_fopen(pic, stdin, "r"); + o = pic_fopen(pic, stdout, "w"); + e = pic_fopen(pic, stderr, "w"); + pic_setvbuf(pic, i, NULL, PIC_IOLBF, 0); + pic_setvbuf(pic, o, NULL, PIC_IOLBF, 0); + pic_defvar(pic, "current-input-port", i); + pic_defvar(pic, "current-output-port", o); + pic_defvar(pic, "current-error-port", e); + pic_defun(pic, "open-input-file", pic_file_open_input_file); pic_defun(pic, "open-output-file", pic_file_open_output_file); - pic_defun(pic, "open-binary-input-file", pic_file_open_input_file); - pic_defun(pic, "open-binary-output-file", pic_file_open_output_file); + pic_defun(pic, "open-binary-input-file", pic_file_open_binary_input_file); + pic_defun(pic, "open-binary-output-file", pic_file_open_binary_output_file); pic_defun(pic, "file-exists?", pic_file_exists_p); pic_defun(pic, "delete-file", pic_file_delete); } diff --git a/lib/ext/main.c b/lib/ext/main.c index acb17dda..dc2d2952 100644 --- a/lib/ext/main.c +++ b/lib/ext/main.c @@ -17,10 +17,12 @@ main(int argc, char *argv[]) if (argc == 1) { /* repl */ while (1) { pic_printf(pic, "> "); + pic_fflush(pic, pic_stdout(pic)); e = pic_funcall(pic, "read", 0); if (pic_eof_p(pic, e)) break; - pic_printf(pic, "~s\n", pic_funcall(pic, "eval", 1, e)); + pic_funcall(pic, "write", 1, pic_funcall(pic, "eval", 1, e)); + pic_printf(pic, "\n"); } } else if (argc == 2) { /* load file */ FILE *file = fopen(argv[1], "r"); diff --git a/lib/include/picrin.h b/lib/include/picrin.h index 4e6f71a2..2d075897 100644 --- a/lib/include/picrin.h +++ b/lib/include/picrin.h @@ -258,6 +258,10 @@ typedef struct { #define PIC_SEEK_END 1 #define PIC_SEEK_SET 2 +#define PIC_IONBF 0 +#define PIC_IOLBF 1 +#define PIC_IOFBF 2 + #define pic_stdin(pic) pic_funcall(pic, "current-input-port", 0) #define pic_stdout(pic) pic_funcall(pic, "current-output-port", 0) #define pic_stderr(pic) pic_funcall(pic, "current-error-port", 0) @@ -281,13 +285,11 @@ int pic_fputs(pic_state *, const char *s, pic_value port); char *pic_fgets(pic_state *, char *s, int size, pic_value port); int pic_ungetc(pic_state *, int c, pic_value port); int pic_fflush(pic_state *, pic_value port); +int pic_setvbuf(pic_state *, pic_value port, char *buf, int mode, size_t size); /* formatted output */ int pic_printf(pic_state *, const char *fmt, ...); int pic_fprintf(pic_state *, pic_value port, const char *fmt, ...); int pic_vfprintf(pic_state *, pic_value port, const char *fmt, va_list ap); -/* string buffer */ -pic_value pic_fmemopen(pic_state *, const char *buf, int len, const char *mode); /* deprecated */ -int pic_fgetbuf(pic_state *, pic_value port, const char **buf, int *len); /* deprecated */ /* diff --git a/lib/object.h b/lib/object.h index 9507e376..bbe14d73 100644 --- a/lib/object.h +++ b/lib/object.h @@ -129,12 +129,13 @@ struct proc { }; enum { - FILE_READ = 01, - FILE_WRITE = 02, - FILE_UNBUF = 04, - FILE_EOF = 010, - FILE_ERR = 020, - FILE_LNBUF = 040 + FILE_READ = 01, + FILE_WRITE = 02, + FILE_UNBUF = 04, + FILE_EOF = 010, + FILE_ERR = 020, + FILE_LNBUF = 040, + FILE_SETBUF = 0100 }; struct port { diff --git a/lib/port.c b/lib/port.c index e4dca466..21feada1 100644 --- a/lib/port.c +++ b/lib/port.c @@ -35,13 +35,13 @@ pic_fclose(pic_state *pic, pic_value port) return 0; pic_fflush(pic, port); fp->flag = 0; - if (fp->base != fp->buf) + if (fp->base != fp->buf && (fp->flag & FILE_SETBUF) == 0) pic_free(pic, fp->base); return fp->vtable->close(pic, fp->cookie); } void -pic_clearerr(pic_state *PIC_UNUSED(pic), pic_value port) +pic_clearerr(pic_state *pic, pic_value port) { struct file *fp = &port_ptr(pic, port)->file; @@ -49,7 +49,7 @@ pic_clearerr(pic_state *PIC_UNUSED(pic), pic_value port) } int -pic_feof(pic_state *PIC_UNUSED(pic), pic_value port) +pic_feof(pic_state *pic, pic_value port) { struct file *fp = &port_ptr(pic, port)->file; @@ -57,13 +57,36 @@ pic_feof(pic_state *PIC_UNUSED(pic), pic_value port) } int -pic_ferror(pic_state *PIC_UNUSED(pic), pic_value port) +pic_ferror(pic_state *pic, pic_value port) { struct file *fp = &port_ptr(pic, port)->file; return (fp->flag & FILE_ERR) != 0; } +int +pic_setvbuf(pic_state *pic, pic_value port, char *buf, int mode, size_t size) +{ + struct file *fp = &port_ptr(pic, port)->file; + + fp->flag &= ~(FILE_UNBUF | FILE_LNBUF); + if (mode == PIC_IOLBF) { + fp->flag |= FILE_LNBUF; + } else if (mode == PIC_IONBF) { + fp->flag |= FILE_UNBUF; + } + + if (buf == NULL) { + return 0; + } + if (size != PIC_BUFSIZ) { + return EOF; + } + fp->base = buf; + fp->flag |= FILE_SETBUF; + return 0; +} + static int fillbuf(pic_state *pic, struct file *fp) { @@ -230,7 +253,7 @@ pic_fgets(pic_state *pic, char *s, int size, pic_value port) } int -pic_ungetc(pic_state *PIC_UNUSED(pic), int c, pic_value port) +pic_ungetc(pic_state *pic, int c, pic_value port) { struct file *fp = &port_ptr(pic, port)->file; unsigned char uc = c; @@ -311,79 +334,7 @@ pic_fseek(pic_state *pic, pic_value port, long offset, int whence) int pic_vfprintf(pic_state *pic, pic_value port, const char *fmt, va_list ap) { - const char *p; - long start = pic_fseek(pic, port, 0, PIC_SEEK_CUR); - - for (p = fmt; *p; p++) { - if (*p == '~') { - switch (*++p) { - default: - pic_fputc(pic, *(p-1), port); - break; - case '%': - pic_fputc(pic, '\n', port); - break; - case 'a': - pic_void(pic, pic_funcall(pic, "display", 2, va_arg(ap, pic_value), port)); - break; - case 's': - pic_void(pic, pic_funcall(pic, "write", 2, va_arg(ap, pic_value), port)); - break; - } - continue; - } - if (*p == '%') { - switch (*++p) { - case 'd': - case 'i': { - int ival = va_arg(ap, int); - pic_value str = pic_funcall(pic, "number->string", 1, pic_int_value(pic, ival)); - pic_fputs(pic, pic_cstr(pic, str, 0), port); - break; - } - case 'f': { - double f = va_arg(ap, double); - pic_value str = pic_funcall(pic, "number->string", 1, pic_float_value(pic, f)); - pic_fputs(pic, pic_cstr(pic, str, 0), port); - break; - } - case 'c': { - int ival = va_arg(ap, int); - pic_fputc(pic, ival, port); - break; - } - case 's': { - char *sval = va_arg(ap, char*); - pic_fputs(pic, sval, port); - break; - } - case 'p': { - static const char digits[] = "0123456789abcdef"; - unsigned long vp = (unsigned long) va_arg(ap, void*); - char buf[sizeof vp * CHAR_BIT / 4 + 1]; - size_t i; - for (i = 0; i < sizeof buf - 1; ++i) { - buf[sizeof buf - i - 2] = digits[vp % 16]; - vp /= 16; - } - buf[i] = '\0'; - pic_fputs(pic, "0x", port); - pic_fputs(pic, buf, port); - break; - } - case '%': - pic_fputc(pic, *(p-1), port); - break; - default: - pic_fputc(pic, '%', port); - pic_fputc(pic, *(p-1), port); - break; - } - continue; - } - pic_fputc(pic, *p, port); - } - return pic_fseek(pic, port, 0, PIC_SEEK_CUR) - start; + return pic_fputs(pic, pic_cstr(pic, pic_vstrf_value(pic, fmt, ap), NULL), port); } int diff --git a/lib/string.c b/lib/string.c index b59a7551..04012876 100644 --- a/lib/string.c +++ b/lib/string.c @@ -229,24 +229,67 @@ pic_strf_value(pic_state *pic, const char *fmt, ...) va_start(ap, fmt); str = pic_vstrf_value(pic, fmt, ap); va_end(ap); - return str; } pic_value pic_vstrf_value(pic_state *pic, const char *fmt, va_list ap) { - pic_value str, port; - const char *buf; - int len; + pic_value str, str2; + const char *p; - port = pic_fmemopen(pic, NULL, 0, "w"); - - pic_vfprintf(pic, port, fmt, ap); - pic_fgetbuf(pic, port, &buf, &len); - str = pic_str_value(pic, buf, len); - pic_fclose(pic, port); - return str; + for (p = fmt; *p; p++) { + if (*p == '%') + break; + } + str = pic_str_value(pic, fmt, p - fmt); + if (*p == 0) { + return str; + } + p++; /* skip '%' */ + switch (*p++) { + case '\0': + return pic_str_value(pic, fmt, p - fmt - 1); + case 'd': + case 'i': { + int i = va_arg(ap, int); + str2 = pic_funcall(pic, "number->string", 1, pic_int_value(pic, i)); + break; + } + case 'f': { + double f = va_arg(ap, double); + str2 = pic_funcall(pic, "number->string", 1, pic_float_value(pic, f)); + break; + } + case 'c': { + char c = (char) va_arg(ap, int); + str2 = pic_str_value(pic, &c, 1); + break; + } + case 's': { + char *sval = va_arg(ap, char*); + str2 = pic_cstr_value(pic, sval); + break; + } + case 'p': { + static const char digits[] = "0123456789abcdef"; + static const size_t bufsiz = sizeof(long) * CHAR_BIT / 4; + unsigned long vp = (unsigned long) va_arg(ap, void*); + char buf[2 + bufsiz + 1] = "0x", *p = buf + 2; + size_t i; + for (i = 0; i < bufsiz; ++i) { + p[bufsiz - i - 2] = digits[vp % 16]; + vp /= 16; + } + p[i] = '\0'; + str2 = pic_cstr_value(pic, buf); + break; + } + case '%': + str2 = pic_str_value(pic, &p[-1], 1); + break; + } + return pic_str_cat(pic, str, pic_str_cat(pic, str2, pic_vstrf_value(pic, p, ap))); } int