ref: 24cdc7adf5611d536403ae625414bb10f3bc4f93
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;
}
}
}