ref: 8ef27e2fe652a8b29a8b57589863f2f2b45f9425
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 nalias; Rune **aliases; Stream *next; }; enum { TextStream, BinaryStream, }; enum { ReadStream, WriteStream, AppendStream }; static Stream *streams; static Stream *currentinput; static Stream *currentoutput; Stream *openstreamfd(int, Biobuf *, int, int); Stream *getstreambyfd(int); Stream *getstreambyalias(Rune *); Stream *getstream(Term *); 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, WriteStream); } 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); *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 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->nalias = 0; s->aliases = 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); Bungetrune(s->bio); return r; } void putchar(Term *t, Rune r) { Stream *s = getstream(t); Bprint(s->bio, "%C", r); Bflush(s->bio); }