shithub: pprolog

ref: 0c45e33c1b8d094353a5585c44179d1818ff6e1e
dir: pprolog/streams.c

View raw version
#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 *options, Term **term)
{
	USED(options);

	Stream *s = getstream(stream);
	if(s == nil){
		*term = existenceerror(L"stream", stream);
		return 1;
	}
	print(": ");
	*term = parse(0, s->bio, 1);

	return 0;
}

void
writeterm(Term *stream, Term *options, Term *term)
{
	USED(options);
	
	Stream *s = getstream(stream);
	if(s == nil)
		return;

	int quoted = 0;
	int ignoreops = 0;
	int numbervars = 0;

	Rune *output = prettyprint(term, quoted, ignoreops, numbervars);
	Bprint(s->bio, "%S", output);
	Bflush(s->bio);
}

Stream *
openstreamfd(int fd, Biobuf *bio, int type, int mode)
{
	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;
}