ref: cf3f244661f70421b8c266b3670a8481835d604e
dir: /iostream.c/
#include "llt.h" #include "flisp.h" #include "cvalues.h" #include "types.h" #include "print.h" #include "read.h" static value_t iostreamsym, rdsym, wrsym, apsym, crsym, truncsym; static value_t instrsym, outstrsym; fltype_t *iostreamtype; void print_iostream(value_t v, ios_t *f) { USED(v); fl_print_str("#<io stream>", f); } void free_iostream(value_t self) { ios_t *s = value2c(ios_t*, self); ios_close(s); } void relocate_iostream(value_t oldv, value_t newv) { ios_t *olds = value2c(ios_t*, oldv); ios_t *news = value2c(ios_t*, newv); if(news->buf == &olds->local[0]) news->buf = &news->local[0]; } static cvtable_t iostream_vtable = { print_iostream, relocate_iostream, free_iostream, nil }; int fl_isiostream(value_t v) { return iscvalue(v) && cv_class(ptr(v)) == iostreamtype; } BUILTIN("iostream?", iostreamp) { argcount(nargs, 1); return fl_isiostream(args[0]) ? FL_T : FL_F; } BUILTIN("eof-object", eof_object) { USED(args); argcount(nargs, 0); return FL_EOF; } BUILTIN("eof-object?", eof_objectp) { argcount(nargs, 1); return args[0] == FL_EOF ? FL_T : FL_F; } ios_t * fl_toiostream(value_t v) { if(!fl_isiostream(v)) type_error("iostream", v); return value2c(ios_t*, v); } BUILTIN("file", file) { if(nargs < 1) argcount(nargs, 1); int i, r = 0, w = 0, c = 0, t = 0, a = 0; for(i = 1; i < nargs; i++){ if(args[i] == rdsym) r = 1; else if(args[i] == wrsym) w = 1; else if(args[i] == apsym) a = w = 1; else if(args[i] == crsym) c = w = 1; else if(args[i] == truncsym) t = w = 1; } if((r|w|c|t|a) == 0) r = 1; // default to reading value_t f = cvalue(iostreamtype, sizeof(ios_t)); char *fname = tostring(args[0]); ios_t *s = value2c(ios_t*, f); if(ios_file(s, fname, r, w, c, t) == nil) lerrorf(IOError, "could not open \"%s\"", fname); if(a) ios_seek_end(s); return f; } BUILTIN("buffer", buffer) { argcount(nargs, 0); USED(args); value_t f = cvalue(iostreamtype, sizeof(ios_t)); ios_t *s = value2c(ios_t*, f); if(ios_mem(s, 0) == nil) lerrorf(MemoryError, "could not allocate stream"); return f; } BUILTIN("read", read) { value_t arg = 0; if(nargs > 1) argcount(nargs, 1); else if(nargs == 0) arg = symbol_value(instrsym); else arg = args[0]; ios_t *s = fl_toiostream(arg); fl_gc_handle(&arg); value_t v = fl_read_sexpr(arg); fl_free_gc_handles(1); if(ios_eof(s)) return FL_EOF; return v; } BUILTIN("io.getc", io_getc) { argcount(nargs, 1); ios_t *s = fl_toiostream(args[0]); Rune r; int res; if((res = ios_getutf8(s, &r)) == IOS_EOF) //lerrorf(IOError, "end of file reached"); return FL_EOF; if(res == 0) lerrorf(IOError, "invalid UTF-8 sequence"); return mk_rune(r); } BUILTIN("io.putc", io_putc) { argcount(nargs, 2); ios_t *s = fl_toiostream(args[0]); if(!iscprim(args[1]) || ((cprim_t*)ptr(args[1]))->type != runetype) type_error("rune", args[1]); Rune r = *(Rune*)cp_data((cprim_t*)ptr(args[1])); return fixnum(ios_pututf8(s, r)); } BUILTIN("io.skip", io_skip) { argcount(nargs, 2); ios_t *s = fl_toiostream(args[0]); off_t off = tooffset(args[1]); off_t res = ios_skip(s, off); if(res < 0) return FL_F; return sizeof(res) == sizeof(int64_t) ? mk_int64(res) : mk_int32(res); } BUILTIN("io.flush", io_flush) { argcount(nargs, 1); return ios_flush(fl_toiostream(args[0])) == 0 ? FL_T : FL_F; } BUILTIN("io.close", io_close) { argcount(nargs, 1); ios_close(fl_toiostream(args[0])); return FL_T; } BUILTIN("io.discardbuffer", io_discardbuffer) { argcount(nargs, 1); ios_purge(fl_toiostream(args[0])); return FL_T; } BUILTIN("io.eof?", io_eofp) { argcount(nargs, 1); return ios_eof(fl_toiostream(args[0])) ? FL_T : FL_F; } BUILTIN("io.seek", io_seek) { argcount(nargs, 2); ios_t *s = fl_toiostream(args[0]); size_t pos = toulong(args[1]); off_t res = ios_seek(s, (off_t)pos); if(res == -1) return FL_F; return FL_T; } BUILTIN("io.pos", io_pos) { argcount(nargs, 1); ios_t *s = fl_toiostream(args[0]); off_t res = ios_pos(s); if(res == -1) return FL_F; return size_wrap((size_t)res); } BUILTIN("write", write) { if(nargs < 1 || nargs > 2) argcount(nargs, 1); ios_t *s; s = nargs == 2 ? fl_toiostream(args[1]) : fl_toiostream(symbol_value(outstrsym)); fl_print(s, args[0]); return args[0]; } BUILTIN("io.read", io_read) { if(nargs != 3) argcount(nargs, 2); ios_t *s = fl_toiostream(args[0]); size_t n; fltype_t *ft; if(nargs == 3){ // form (io.read s type count) ft = get_array_type(args[1]); n = toulong(args[2]) * ft->elsz; }else{ ft = get_type(args[1]); if(ft->eltype != nil && !iscons(cdr_(cdr_(args[1])))) lerrorf(ArgError, "incomplete type"); n = ft->size; } value_t cv = cvalue(ft, n); char *data; if(iscvalue(cv)) data = cv_data(ptr(cv)); else data = cp_data(ptr(cv)); size_t got = ios_read(s, data, n); if(got < n) //lerrorf(IOError, "end of input reached"); return FL_EOF; return cv; } // args must contain data[, offset[, count]] static void get_start_count_args(value_t *args, uint32_t nargs, size_t sz, size_t *offs, size_t *nb) { if(nargs > 1){ *offs = toulong(args[1]); *nb = nargs > 2 ? toulong(args[2]) : sz - *offs; if(*offs >= sz || *offs + *nb > sz) bounds_error(args[0], args[1]); } } BUILTIN("io.write", io_write) { if(nargs < 2 || nargs > 4) argcount(nargs, 2); ios_t *s = fl_toiostream(args[0]); if(iscprim(args[1]) && ((cprim_t*)ptr(args[1]))->type == runetype){ if(nargs > 2) lerrorf(ArgError, "offset argument not supported for characters"); Rune r = *(Rune*)cp_data(ptr(args[1])); return fixnum(ios_pututf8(s, r)); } char *data; size_t sz, offs = 0; to_sized_ptr(args[1], &data, &sz); size_t nb = sz; if(nargs > 2){ get_start_count_args(&args[1], nargs-1, sz, &offs, &nb); data += offs; } return size_wrap(ios_write(s, data, nb)); } BUILTIN("dump", dump) { if(nargs < 1 || nargs > 3) argcount(nargs, 1); ios_t *s = fl_toiostream(symbol_value(outstrsym)); char *data; size_t sz, offs = 0; to_sized_ptr(args[0], &data, &sz); size_t nb = sz; if(nargs > 1){ get_start_count_args(args, nargs, sz, &offs, &nb); data += offs; } hexdump(s, data, nb, offs); return FL_T; } static char get_delim_arg(value_t arg) { size_t uldelim = toulong(arg); if(uldelim > 0x7f){ // runes > 0x7f, or anything else > 0xff, are out of range if((iscprim(arg) && cp_class(ptr(arg)) == runetype) || uldelim > 0xff) lerrorf(ArgError, "delimiter out of range"); } return (char)uldelim; } BUILTIN("io.readuntil", io_readuntil) { argcount(nargs, 2); value_t str = cvalue_string(80); cvalue_t *cv = ptr(str); char *data = cv_data(cv); ios_t dest; ios_mem(&dest, 0); ios_setbuf(&dest, data, 80, 0); char delim = get_delim_arg(args[1]); ios_t *src = fl_toiostream(args[0]); size_t n = ios_copyuntil(&dest, src, delim); cv->len = n; if(dest.buf != data){ // outgrew initial space size_t sz; cv->data = ios_takebuf(&dest, &sz); #ifndef BOEHM_GC cv_autorelease(cv); #endif }else{ ((char*)cv->data)[n] = '\0'; } if(n == 0 && ios_eof(src)) return FL_EOF; return str; } BUILTIN("io.copyuntil", io_copyuntil) { argcount(nargs, 3); ios_t *dest = fl_toiostream(args[0]); ios_t *src = fl_toiostream(args[1]); char delim = get_delim_arg(args[2]); return size_wrap(ios_copyuntil(dest, src, delim)); } BUILTIN("io.copy", io_copy) { if(nargs < 2 || nargs > 3) argcount(nargs, 2); ios_t *dest = fl_toiostream(args[0]); ios_t *src = fl_toiostream(args[1]); if(nargs == 3) return size_wrap(ios_copy(dest, src, toulong(args[2]))); return size_wrap(ios_copyall(dest, src)); } value_t stream_to_string(value_t *ps) { value_t str; size_t n; ios_t *st = value2c(ios_t*, *ps); if(st->buf == &st->local[0]){ n = st->size; str = cvalue_string(n); memmove(cvalue_data(str), st->buf, n); ios_trunc(st, 0); }else{ char *b = ios_takebuf(st, &n); n--; b[n] = '\0'; str = cvalue_from_ref(stringtype, b, n, FL_NIL); #ifndef BOEHM_GC cv_autorelease(ptr(str)); #endif } return str; } BUILTIN("io.tostring!", io_tostring) { argcount(nargs, 1); ios_t *src = fl_toiostream(args[0]); if(src->bm != bm_mem) lerrorf(ArgError, "requires memory stream"); return stream_to_string(&args[0]); } void iostream_init(void) { iostreamsym = symbol("iostream"); rdsym = symbol(":read"); wrsym = symbol(":write"); apsym = symbol(":append"); crsym = symbol(":create"); truncsym = symbol(":truncate"); instrsym = symbol("*input-stream*"); outstrsym = symbol("*output-stream*"); iostreamtype = define_opaque_type(iostreamsym, sizeof(ios_t), &iostream_vtable, nil); setc(symbol("*stdout*"), cvalue_from_ref(iostreamtype, ios_stdout, sizeof(ios_t), FL_NIL)); setc(symbol("*stderr*"), cvalue_from_ref(iostreamtype, ios_stderr, sizeof(ios_t), FL_NIL)); setc(symbol("*stdin*" ), cvalue_from_ref(iostreamtype, ios_stdin, sizeof(ios_t), FL_NIL)); }