Sigrid Solveig Haflínudóttirfile: avoid GC issuesc9a23e52 months agoHistory
693 lines · 16.0 KB · C
RawDownload
#include "inc/priv.h"#include "inc/cvalues.h"#include "inc/types.h"#include "inc/print.h"#include "inc/read.h"#include "inc/io.h" static sl_v iosym, rdsym, wrsym, apsym, crsym, truncsym, exclsym, rclosesym;static sl_v linesym, blocksym, memorysym;static sl_v ioinsym, wssym, startsym, endsym, bendiansym, lendiansym;sl_v sl_iooutsym, sl_iodeffilemodesym, sl_iodefdirmodesym;const sl_type *sl_iotype; static voidprint_io(sl_v v){	ios *s = value2c(ios*, v);	sl_print_str("#<io", true);	if(*s->filename != 0){		sl_print_str(" \"", true);		sl_print_str(s->filename, false);		sl_print_str("\" ", true);		sl_print(fixnum(s->loc.lineno));		sl_print_chr(' ');		sl_print(fixnum(s->loc.colno));	}	sl_print_chr('>');} static voidrelocate_io(sl_v oldv, sl_v newv){	ios *olds = value2c(ios*, oldv);	ios *news = value2c(ios*, newv);	if(news->data != sl_nil){		news->data = sl_relocate(news->data);		usize sz, esz;		news->buf = to_sized_ptr(news->data, &sz, &esz, &news->tmp);		news->buf += news->start;	}else if(news->buf == &olds->local[0])		news->buf = &news->local[0];} voidfree_io(sl_v self){	ios *s = value2c(ios*, self);	ios_close(s);	ios_free(s);} static sl_cvtable io_vtable = {	print_io,	relocate_io,	free_io,	nil,	nil}; boolisio(sl_v v){	return iscvalue(v) && cvalue_class(v) == sl_iotype;} static boolisflipped(sl_v v){	bool little;	if(v == lendiansym)		little = true;	else if(v == bendiansym)		little = false;	else		cthrow(error(sl_errarg, "invalid endian specifier"), v);#if BYTE_ORDER == LITTLE_ENDIAN	return !little;#else	return little;#endif} BUILTIN("io?", iop){	argcount(1);	return isio(args[0]) ? sl_t : sl_nil;} BUILTIN("eof?", eofp){	argcount(1);	return args[0] == sl_eof ? sl_t : sl_nil;} ios *toio(sl_v v, bool open, bool rd, bool wr){	if(sl_unlikely(!isio(v)))		cthrow(type_error(nil, "io", v), v);	ios *s = value2c(ios*, v);	if(sl_likely(open)){		if(sl_unlikely(s->state == IOS_STATE_CLOSED))			cthrow(error(sl_errio, "closed file"), v);		if(wr && sl_unlikely((s->flags & IOS_FL_RDONLY) != 0))			cthrow(error(sl_errio, "read-only file"), v);		if(rd && sl_unlikely((s->flags & IOS_FL_WRONLY) != 0))			cthrow(error(sl_errio, "write-only file"), v);	}	return s;} BUILTIN("file", file){	argcount_least(1);	(void)tostr(args[0]);	ios_flags flags = 0;	usize mode = tofixnum(sym_value(sl_iodeffilemodesym));	int wmode = 0, wrd = 0, wwr = 0, wap = 0, wcr = 0, wtrunc = 0, wexcl = 0, wrclose = 0;	for(int i = 1; i < nargs; i++){		if(isfixnum(args[i]) && !wmode++)			mode = tosize(args[i]);		else if(args[i] == rdsym && !wrd++)			flags |= IOS_READ;		else if(args[i] == wrsym && !wwr++)			flags |= IOS_WRITE;		else if(args[i] == apsym && !wap++)			flags |= IOS_WRITE | IOS_APPEND;		else if(args[i] == crsym && !wcr++)			flags |= IOS_WRITE | IOS_CREATE;		else if(args[i] == truncsym && !wtrunc++)			flags |= IOS_WRITE | IOS_TRUNC;		else if(args[i] == exclsym && !wexcl++)			flags |= IOS_EXCL;		else if(args[i] == rclosesym && !wrclose++)			flags |= IOS_RCLOSE;		else			bthrow(error(sl_errarg, "invalid arguments"));	}	if(flags == 0)		flags = IOS_READ;	u8int *heap = slvm.curheap;	sl_v f = cvalue(sl_iotype, sizeof(ios));	ios *s = value2c(ios*, f);	const char *fname = tostr(args[0]);	if(ios_file(s, fname, flags, mode) == nil){		slvm.curheap = heap;		bthrow(error(sl_errio, "could not open \"%s\"", fname));	}	return f;} BUILTIN("io-buffer-mode", io_buffer_mode){	argcount(1);	switch(toio(args[0], true, false, false)->bm){	case IOS_BUF_NONE: return sl_nil;	case IOS_BUF_LINE: return linesym;	case IOS_BUF_BLOCK: return blocksym;	case IOS_BUF_MEM: return memorysym;	default: abort();	}} BUILTIN("io-buffer-mode!", io_buffer_mode_q){	argcount(2);	sl_v m = args[1];	int bm;	if(m == sl_nil)		bm = IOS_BUF_NONE;	else if(m == linesym)		bm = IOS_BUF_LINE;	else if(m == blocksym)		bm = IOS_BUF_BLOCK;	else if(m == memorysym)		bm = IOS_BUF_MEM;	else		bthrow(error(sl_errarg, "invalid buffer mode"));	if(ios_bufmode(toio(args[0], true, false, false), bm) != 0)		bthrow(error(sl_errarg, "invalid buffer mode for this io"));	return args[1];} BUILTIN("buffer", buffer){	sl_v keys[] = {startsym, endsym}, values[nelem(keys)];	if(sl_unlikely(nargs > 0)){		nargs = sl_process_args(args, 1, nargs, keys, nelem(keys), values);		argcount(1);	}	sl_v f;	if(sl_unlikely(nargs > 0)){		usize sz, esz;		u64int tmp;		u8int *p = to_sized_ptr(args[0], &sz, &esz, &tmp);		usize start = nonnil(values[0]) ? tosize(values[0]) : 0;		usize end = nonnil(values[1]) ? tosize(values[1]) : sz;		if(sl_unlikely(start > sz || start > end || end > sz))			bthrow(error(sl_errarg, "limits out of range"));		f = cvalue(sl_iotype, sizeof(ios));		ios *s = value2c(ios*, f);		ios_static_buffer(s, p+start, end-start);		s->start = start;		s->end = end;		s->data = args[0];	}else{		f = cvalue(sl_iotype, sizeof(ios));		ios *s = value2c(ios*, f);		if(sl_unlikely(ios_mem(s, 0) == nil))			bthrow(error(sl_errmem, "could not allocate in-memory io"));	}	return f;} BUILTIN("read", read){	sl_v keys[] = {wssym}, values[nelem(keys)];	nargs = sl_process_args(args, 0, nargs, keys, nelem(keys), values);	if(sl_unlikely(nargs > 1))		bthrow(error(sl_errarg, "extra arguments"));	bool ws = nonnil(values[0]);	sl_v a = nargs == 0 ? sym_value(ioinsym) : args[0];	USED(toio(a, true, true, false));	return sl_read_sexpr(a, sl_nil, SL_EXPR_S, ws);} BUILTIN("read-list-until", read_list_until){	argcount_least(1);	argcount_most(2);	sl_v a = nargs == 1 ? sym_value(ioinsym) : args[1];	USED(toio(a, true, true, false));	return sl_read_sexpr(a, args[0], SL_EXPR_LIST, false);} static sl_vfetch_data(sl_v *args, int nargs, bool peek){	ios *s = toio(args[0], true, true, false);	const sl_type *ft;	usize n, nem, emsz;	bool isrune, isutf8, flip = false;	if(nargs >= 3 && iskeysym(args[nargs-1]))		flip = isflipped(args[--nargs]);	if(nargs == 3){		// form (io-* s type count)		ft = get_arr_type(args[1]);		nem = tosize(args[2]);		emsz = ft->elsz;		n = nem * emsz;		isrune = ft->eltype == sl_runetype;		isutf8 = ft->eltype == sl_utf8type;	}else{		ft = get_type(args[1], 0);		if(ft->eltype != nil && !iscons(cdr_(cdr_(args[1]))))			bthrow(error(sl_errarg, "incomplete type"));		nem = 1;		emsz = n = ft->size;		isrune = ft == sl_runetype;		isutf8 = ft == sl_utf8type;	}	if(isutf8){		ft = sl_strtype;		n *= 4;	}	// give it double the space if we need to peek for runes	// it will get cut down later on	sl_v cv = cvalue(ft, (isrune && peek) ? n*2 : n);	u8int *buf = cvalue_data(cv), *buf0 = buf;	usize got;	if(!isrune && !isutf8){		got = (peek ? ios_peek : ios_read)(s, buf, n);		nem = got/emsz;		got = nem*emsz;		buf += got;	}else if(peek){		char *data = (char*)(isrune ? buf+n : buf);		Rune r;		if(nem > 0)			got = ios_peek(s, (u8int*)data, n);		else if((got = ios_peekrune(s, &r)) == 1)			got = runetochar(data, &r);		usize nr, nb, left = got;		for(nr = nb = 0; left > 0 && nr < nem; nr++){			if(!fullrune(data, left))				break;			int bc = chartorune(&r, data);			if(r == Runeerror)				bthrow(error(sl_errio, "invalid rune"));			if(isrune){				if(ft == sl_runetype)					return mk_rune(r);				*(Rune*)buf = r;				buf += sizeof(Rune);			}else{				memcpy(buf, data, bc);				buf += bc;			}			data += bc;			left -= bc;			nb += bc;		}		got = isutf8 ? nb : nr*sizeof(Rune);	}else{		usize nr;		for(got = nr = 0; nr < nem; nr++){			Rune r;			int rc = ios_getrune(s, &r);			if(rc == 0)				bthrow(error(sl_errio, "invalid rune"));			if(rc != 1)				break;			if(isrune){				if(ft == sl_runetype)					return mk_rune(r);				*(Rune*)buf = r;				buf += sizeof(Rune);				got += sizeof(Rune);			}else{				int bc = runetochar((char*)buf, &r);				buf += bc;				got += bc;			}		}	}	if((nem > 0 && got < 1) || (nem == 0 && (s->flags & IOS_FL_EOF) != 0))		//bthrow(error(sl_errio, "end of input reached"));		return sl_eof;	cvalue_cutdown(cv, got);	if(flip && emsz > 1){		int half = emsz >> 1;		for(; buf0 < buf; buf0 += emsz){			for(int j = 0; j < half; j++){				u8int x = buf0[j];				buf0[j] = buf0[emsz-1-j];				buf0[emsz-1-j] = x;			}		}	}	return cv;} BUILTIN("io-peek", io_peek){	argcount_least(2);	argcount_most(4);	return fetch_data(args, nargs, true);} BUILTIN("io-skip", io_skip){	sl_v keys[] = {endsym}, values[nelem(keys)];	nargs = sl_process_args(args, 2, nargs, keys, nelem(keys), values);	bool end = nonnil(values[0]);	argcount(2);	ios *s = toio(args[0], true, false, false);	soffset off = tooffset(args[1]);	soffset res = ios_skip(s, off, end);	if(res < 0)		return sl_nil;	return size_wrap((usize)res);} BUILTIN("io-flush", io_flush){	argcount(1);	return ios_flush(toio(args[0], true, false, false)) == 0 ? sl_t : sl_nil;} BUILTIN("io-close", io_close){	argcount(1);	ios_close(toio(args[0], false, false, false));	return sl_void;} BUILTIN("io-truncate", io_truncate){	argcount(2);	ios *s = toio(args[0], true, false, true);	if(ios_trunc(s, tooffset(args[1])) < 0)		bthrow(error(sl_errio, "truncation failed"));	return sl_void;} BUILTIN("io-discard-buffer", io_discard_buffer){	argcount(1);	ios_purge(toio(args[0], true, false, false));	return sl_void;} BUILTIN("io-eof?", io_eofp){	argcount(1);	return (toio(args[0], true, false, false)->flags & IOS_FL_EOF) != 0 ? sl_t : sl_nil;} BUILTIN("io-pos", io_pos){	argcount(1);	ios *s = toio(args[0], true, false, false);	soffset res = ios_skip(s, 0, false);	return res < 0 ? sl_nil : size_wrap((usize)res);} BUILTIN("io-pos!", io_pos_q){	argcount(2);	ios *s = toio(args[0], true, false, false);	soffset pos = tosize(args[1]);	soffset res = (s->flags & IOS_FL_REREADABLE) != 0 ? ios_seek(s, pos) : ios_skip(s, 0, false);	return res < 0 ? sl_nil : size_wrap((usize)res);} BUILTIN("write", write){	argcount_least(1);	argcount_most(2);	ios *s;	s = toio(		nargs == 2 && args[1] != sl_nil ? args[1] : sym_value(sl_iooutsym),		true, false, true	);	sl.pr.f = s;	sl_print(args[0]);	return args[0];} BUILTIN("io-read", io_read){	argcount_least(2);	argcount_most(4);	return fetch_data(args, nargs, false);} BUILTIN("io-write", io_write){	argcount_least(2);	argcount_most(3);	ios *s = toio(args[0], true, false, true);	sl_v v = args[1];	bool flip = nargs > 2 && isflipped(args[2]);	if(sl_unlikely(sl_isrune(v)))		return fixnum(ios_putrune(s, torune(v)));	u64int tmp;	usize sz, esz, nb = 0;	const u8int *data = to_sized_ptr(v, &sz, &esz, &tmp);	if(!iscvalue(v) || cvalue_class(v) != sl_runetype->artype){		if(sl_likely(!flip || esz == 1))			nb = ios_write(s, data, sz);		else{			u8int f[8];			assert(esz <= sizeof(f));			for(usize i = 0; i < sz; i += esz){				for(usize j = 0; j < esz; j++)					f[esz-j-1] = data[i+j];				usize r = ios_write(s, f, esz);				if(r != esz)					break;				nb += r;			}		}	}else{		sz /= sizeof(Rune);		for(usize i = 0; i < sz; i++){			int r = ios_putrune(s, ((Rune*)data)[i]);			if(r <= 0)				break;			nb += r;		}	}	return size_wrap(nb);} static Runeget_delim_arg(sl_v arg){	return sl_isrune(arg) ? torune(arg) : tosize(arg);} BUILTIN("io-read-until", io_read_until){	argcount(2);	ios *src = toio(args[0], true, true, false);	sl_v str = cvalue_str(80);	sl_cv *cv = ptr(sl_cv, str);	u8int *data = cv_data(cv);	ios dest;	ios_mem(&dest, 0);	ios_setbuf(&dest, data, 80, 0);	Rune delim = get_delim_arg(args[1]);	usize n = ios_copyuntil(&dest, src, delim);	cv->len = n;	if(dest.buf != data){		// outgrew initial space		usize sz;		cv->data = ios_takebuf(&dest, &sz);		cv_autorelease(cv);	}else{

Lines 1–500 of 693.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t