ref: 0f347162b74d945f509955b6c57e506ab800db7b
dir: /streams.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "dat.h" #include "fns.h" typedef struct Stream Stream; struct Stream { ulong fd; Biobuf *bio; int type; int mode; int reposition; int eofaction; int nalias; Rune **aliases; Rune *filename; Stream *next; }; enum { TextStream, BinaryStream, }; enum { ReadStream, WriteStream, AppendStream, }; enum { EofActionError, EofActionEof, EofActionReset, }; static Stream *streams; static Stream *currentinput; static Stream *currentoutput; Stream *openstreamfd(int, Biobuf *, int, int); Stream *getstreambyfd(int); Stream *getstreambyalias(Rune *); Stream *getstream(Term *); Term *streamproperties(Stream *); void addstreamalias(int, Rune *); void initstreams(void) { int infd = dup(0, -1); int outfd = dup(1, -1); Biobuf *bioin = Bfdopen(infd, OREAD); Biobuf *bioout = Bfdopen(outfd, OWRITE); currentinput = openstreamfd(infd, bioin, TextStream, ReadStream); currentoutput = openstreamfd(outfd, bioout, TextStream, AppendStream); addstreamalias(infd, L"user_input"); addstreamalias(outfd, L"user_output"); } int openstream(Rune *sourcesink, Rune *mode, Term *options, Term **stream) { USED(options); int omode; int smode; if(runestrcmp(mode, L"read") == 0){ omode = OREAD; smode = ReadStream; }else if(runestrcmp(mode, L"write") == 0){ omode = OWRITE; smode = WriteStream; }else if(runestrcmp(mode, L"append") == 0){ omode = OWRITE; /* Is this correct? */ smode = AppendStream; }else{ *stream = existenceerror(L"source_sink", mkatom(sourcesink)); return 1; } char *filename = smprint("%S", sourcesink); int fd = open(filename, omode); if(fd < 0){ *stream = permissionerror(L"open", L"source_sink", mkatom(sourcesink)); return 1; } Biobuf *bio = Bfdopen(fd, omode); if(bio == nil){ *stream = permissionerror(L"open", L"source_sink", mkatom(sourcesink)); return 1; } Stream *s = openstreamfd(fd, bio, TextStream, smode); s->filename = sourcesink; *stream = mkinteger(s->fd); return 0; } void closestream(Term *t) { Stream *s = getstream(t); if(s == nil) return; Bterm(s->bio); close(s->fd); Stream *tmp; Stream *prev = nil; for(tmp = streams; tmp != nil; tmp = tmp->next){ if(tmp == s){ if(prev == nil) streams = tmp->next; else prev->next = tmp->next; break; } if(prev == nil) prev = tmp; } } Term * currentinputstream(void) { return mkinteger(currentinput->fd); } Term * currentoutputstream(void) { return mkinteger(currentoutput->fd); } void setcurrentinputstream(Term *t) { Stream *s = getstream(t); if(s) currentinput = s; } void setcurrentoutputstream(Term *t) { Stream *s = getstream(t); if(s) currentoutput = s; } int isopenstream(Term *t) { Stream *s = getstream(t); if(s) return 1; else return 0; } int isinputstream(Term *t) { Stream *s = getstream(t); if(s && s->mode == ReadStream) return 1; else return 0; } int isoutputstream(Term *t) { Stream *s = getstream(t); if(s && (s->mode == WriteStream || s->mode == AppendStream)) return 1; else return 0; } int istextstream(Term *t) { Stream *s = getstream(t); if(s && s->type == TextStream) return 1; else return 0; } int isbinarystream(Term *t) { Stream *s = getstream(t); if(s && s->type == BinaryStream) return 1; else return 0; } int canreposition(Term *t) { Stream *s = getstream(t); if(s && s->reposition) return 1; else return 0; } int readterm(Term *stream, Term **term) { Stream *s = getstream(stream); if(s == nil){ *term = existenceerror(L"stream", stream); return 1; } *term = parse(0, s->bio, 1); return 0; } void writeterm(Term *stream, Term *options, Term *term, Module *mod) { Stream *s = getstream(stream); if(s == nil) return; int quoted = 0; int ignoreops = 0; int numbervars = 0; Term *op; for(op = options; op->tag == CompoundTerm; op = op->children->next){ Term *opkey = op->children->children; Term *opval = opkey->next; if(runestrcmp(opkey->text, L"quoted") == 0) quoted = opval->ival; else if(runestrcmp(opkey->text, L"ignore_ops") == 0) ignoreops = opval->ival; else if(runestrcmp(opkey->text, L"numbervars") == 0) numbervars = opval->ival; } Rune *output = prettyprint(term, quoted, ignoreops, numbervars, mod); Bprint(s->bio, "%S", output); Bflush(s->bio); } Stream * openstreamfd(int fd, Biobuf *bio, int type, int mode) { /* streams are not garbage collected for now */ Stream *s = malloc(sizeof(Stream)); s->fd = fd; s->bio = bio; s->type = type; s->mode = mode; s->reposition = 0; s->eofaction = EofActionEof; s->nalias = 0; s->aliases = nil; s->filename = nil; s->next = streams; streams = s; return s; } Stream * getstreambyfd(int fd) { Stream *s; for(s = streams; s != nil; s = s->next) if(s->fd == fd) return s; return nil; } Stream * getstreambyalias(Rune *alias) { Stream *s; for(s = streams; s != nil; s = s->next){ int i; for(i = 0; i < s->nalias; i++){ if(runestrcmp(alias, s->aliases[i]) == 0) return s; } } return nil; } Stream * getstream(Term *t) { Stream *s = nil; if(t->tag == IntegerTerm) s = getstreambyfd(t->ival); else if(t->tag == AtomTerm) s = getstreambyalias(t->text); return s; } Rune getchar(Term *t) { Stream *s = getstream(t); return Bgetrune(s->bio); } Rune peekchar(Term *t) { Stream *s = getstream(t); Rune r = Bgetrune(s->bio); if(r != Beof) Bungetrune(s->bio); return r; } void putchar(Term *t, Rune r) { Stream *s = getstream(t); Bprint(s->bio, "%C", r); } void flushstream(Term *t) { Stream *s = getstream(t); Bflush(s->bio); } Term * streamsproperties(void) { Term *list = nil; Stream *s; for(s = streams; s != nil; s = s->next){ Term *props = streamproperties(s); list = appendterm(list, props); } return list; } Term *streamproperties(Stream *s) { Term *props = nil; Term *stream = mkinteger(s->fd); Term *arg = nil; Term *data; Term *prop; /* file_name(F) */ if(s->filename){ arg = mkatom(s->filename); data = copyterm(stream, nil); data->next = mkcompound(L"file_name", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); } /* mode(M) */ switch(s->mode){ case ReadStream: arg = mkatom(L"read"); break; case WriteStream: arg = mkatom(L"write"); break; case AppendStream: arg = mkatom(L"append"); break; } data = copyterm(stream, nil); data->next = mkcompound(L"mode", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); /* input or output */ data = copyterm(stream, nil); if(s->mode == ReadStream) data->next = mkatom(L"input"); else data->next = mkatom(L"output"); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); /* alias(A) */ int i; for(i = 0; i < s->nalias; i++){ arg = mkatom(s->aliases[i]); data = copyterm(stream, nil); data->next = mkcompound(L"alias", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); } /* position(P) */ if(s->reposition){ arg = mkinteger(Boffset(s->bio)); data = copyterm(stream, nil); data->next = mkcompound(L"position", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); } /* end_of_stream(E) */ if(s->mode == ReadStream){ Rune r = Bgetrune(s->bio); if(r == Beof) arg = mkatom(L"at"); else{ Bungetrune(s->bio); arg = mkatom(L"not"); } data = copyterm(stream, nil); data->next = mkcompound(L"end_of_stream", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); } /* eof_action(A) */ switch(s->eofaction){ case EofActionError: arg = mkatom(L"error"); break; case EofActionEof: arg = mkatom(L"eof_code"); break; case EofActionReset: arg = mkatom(L"reset"); break; } data = copyterm(stream, nil); data->next = mkcompound(L"eof_action", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); /* reposition(Bool) */ if(s->reposition) arg = mkatom(L"true"); else arg = mkatom(L"false"); data = copyterm(stream, nil); data->next = mkcompound(L"reposition", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); /* type(T) */ if(s->type == TextStream) arg = mkatom(L"text"); else arg = mkatom(L"binary"); data = copyterm(stream, nil); data->next = mkcompound(L"type", 1, arg); prop = mkcompound(L"prop", 2, data); props = appendterm(props, prop); return props; } void reposition(Term *t, vlong pos) { Stream *s = getstream(t); Bseek(s->bio, pos, 0); } void addstreamalias(int fd, Rune *alias) { Stream *s; for(s = streams; s != nil; s = s->next){ if(s->fd == fd){ s->nalias++; s->aliases = realloc(s->aliases, sizeof(Rune *) * s->nalias); s->aliases[s->nalias-1] = alias; } } }