Charles.Forsyth20060303a828770d19 years agoHistory
244 lines · 4.4 KB · Brainfuck
RawDownload
implement Shellbuiltin; # parse/generate comma-separated values. include "sys.m";	sys: Sys;include "draw.m";include "sh.m";	sh: Sh;	Listnode, Context: import sh;	myself: Shellbuiltin;include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; initbuiltin(ctxt: ref Context, shmod: Sh): string{	sys = load Sys Sys->PATH;	sh = shmod;	myself = load Shellbuiltin "$self";	if (myself == nil)		ctxt.fail("bad module", sys->sprint("csv: cannot load self: %r"));	bufio = load Bufio Bufio->PATH;	if (bufio == nil)		ctxt.fail("bad module",			sys->sprint("csv: cannot load: %s: %r", Bufio->PATH));	ctxt.addbuiltin("getcsv", myself);	ctxt.addsbuiltin("csv", myself);	return nil;} whatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string{	return nil;} getself(): Shellbuiltin{	return myself;} runbuiltin(c: ref Sh->Context, nil: Sh,			cmd: list of ref Sh->Listnode, last: int): string{	return builtin_getcsv(c, cmd, last);} runsbuiltin(c: ref Sh->Context, nil: Sh,			cmd: list of ref Sh->Listnode): list of ref Listnode{	return sbuiltin_csv(c, cmd);} builtin_getcsv(ctxt: ref Context, argv: list of ref Listnode, nil: int) : string{	n := len argv;	if (n != 2 || !iscmd(hd tl argv))		builtinusage(ctxt, "getcsv {cmd}");	cmd := hd tl argv :: ctxt.get("*");	stdin := bufio->fopen(sys->fildes(0), Sys->OREAD);	if (stdin == nil)		ctxt.fail("bad input", sys->sprint("getcsv: cannot open stdin: %r"));	status := "";	ctxt.push();	for(;;){		{			for (;;) {				line: list of ref Listnode = nil;				sl := readcsvline(stdin);				if (sl == nil)					break;				for (; sl != nil; sl = tl sl)					line = ref Listnode(nil, hd sl) :: line;				ctxt.setlocal("line", line);				status = setstatus(ctxt, ctxt.run(cmd, 0));			}			ctxt.pop();			return status;		}		exception e{			"fail:*" =>				ctxt.pop();				if (loopexcept(e) == BREAK)					return status;				ctxt.push();		}	}} CONTINUE, BREAK: con iota;loopexcept(ename: string): int{	case ename[5:] {	"break" =>		return BREAK;	"continue" =>		return CONTINUE;	* =>		raise ename;	}	return 0;} iscmd(n: ref Listnode): int{	return n.cmd != nil || (n.word != nil && n.word[0] == '{');}	builtinusage(ctxt: ref Context, s: string){	ctxt.fail("usage", "usage: " + s);} setstatus(ctxt: ref Context, val: string): string{	ctxt.setlocal("status", ref Listnode(nil, val) :: nil);	return val;} # in csv format, is it possible to distinguish between a line containing# one empty field and a line containing no fields at all?# what does each one look like?readcsvline(iob: ref Iobuf): list of string{	sl: list of string; 	for(;;) {		(s, eof) := readcsvword(iob);		if (sl == nil && s == nil && eof)			return nil; 		c := Bufio->EOF;		if (!eof)			c = iob.getc();		sl = s :: sl;		if (c == '\n' || c == Bufio->EOF)			return sl;	}} sbuiltin_csv(nil: ref Context, val: list of ref Listnode): list of ref Listnode{	val = tl val;	if (val == nil)		return nil;	s := s2qv(word(hd val));	for (val = tl val; val != nil; val = tl val)		s += "," + s2qv(word(hd val));	return ref Listnode(nil, s) :: nil;} s2qv(s: string): string{	needquote := 0;	needscan := 0;	for (i := 0; i < len s; i++) {		c := s[i];		if (c == '\n' || c == ',')			needquote = 1;		else if (c == '"') {			needquote = 1;			needscan = 1;		}	}	if (!needquote)		return s;	if (!needscan)		return "\"" + s + "\"";	r := "\"";	for (i = 0; i < len s; i++) {		c := s[i];		if (c == '"')			r[len r] = c;		r[len r] = c;	}	r[len r] = '"';	return r;} readcsvword(iob: ref Iobuf): (string, int){	s := "";	case c := iob.getc() {	'"' =>		for (;;) {			case c = iob.getc() {			Bufio->EOF =>				return (s, 1);			'"' =>				case c = iob.getc() {				'"' =>					s[len s] = '"';				'\n' or				',' =>					iob.ungetc();					return (s, 0);				Bufio->EOF =>					return (s, 1);				* =>					# illegal					iob.ungetc();					(t, eof) := readcsvword(iob);					return (s + t, eof);				}			* =>				s[len s] = c;			}		}	',' or	'\n' =>		iob.ungetc();		return (s, 0);	Bufio->EOF =>		return (nil, 1);	* =>		s[len s] = c;		for (;;) {			case c = iob.getc() {			',' or			'\n' =>				iob.ungetc();				return (s, 0);			'"' =>				# illegal				iob.ungetc();				(t, eof) := readcsvword(iob);				return (s + t, eof);			Bufio->EOF =>				return (s, 1);			* =>				s[len s] = c;			}		}	}} word(n: ref Listnode): string{	if (n.word != nil)		return n.word;	if (n.cmd != nil)		n.word = sh->cmd2string(n.cmd);	return n.word;}