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);
}