shithub: pprolog

Download patch

ref: 1b73b6d1323c69c0086a41bf85a9b85003377a3b
parent: daadb2b174846cda95e51e0c4c94bcb748da4a69
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Mon Jul 19 08:44:08 EDT 2021

More work on streams

--- a/builtins.c
+++ b/builtins.c
@@ -63,6 +63,9 @@
 BuiltinProto(builtinchoicestacksize);
 BuiltinProto(builtincollectgarbage);
 BuiltinProto(builtinloadmodulefromfile);
+BuiltinProto(builtinflushoutput);
+BuiltinProto(builtinstreamproperties);
+BuiltinProto(builtinsetstreamposition);
 
 int compareterms(Term *, Term *);
 
@@ -178,6 +181,12 @@
 		return builtincollectgarbage;
 	if(Match(L"$load_module_from_file", 1))
 		return builtinloadmodulefromfile;
+	if(Match(L"flush_output", 1))
+		return builtinflushoutput;
+	if(Match(L"stream_properties", 1))
+		return builtinstreamproperties;
+	if(Match(L"set_stream_position", 2))
+		return builtinsetstreamposition;
 
 	return nil;
 }
@@ -1445,4 +1454,58 @@
 		return 1;
 	else
 		return 0;
+}
+
+int
+builtinflushoutput(Term *goal, Binding **bindings, Module *module)
+{
+	USED(bindings);
+	USED(module);
+	Term *s = goal->children;
+
+	if(s->tag == VariableTerm)
+		Throw(instantiationerror());
+	if(s->tag != IntegerTerm && s->tag != AtomTerm)
+		Throw(domainerror(L"stream_or_alias", s));
+	if(!isopenstream(s))
+		Throw(existenceerror(L"stream", s));
+	if(!isoutputstream(s))
+		Throw(permissionerror(L"output", L"stream", s));
+
+	flushstream(s);
+	return 1;
+}
+
+int
+builtinstreamproperties(Term *goal, Binding **bindings, Module *module)
+{
+	USED(module);
+	USED(bindings);
+	Term *props = goal->children;
+	Term *list = streamsproperties();
+	Term *realprops = mklist(list);
+	return unify(props, realprops, bindings);
+}
+
+int
+builtinsetstreamposition(Term *goal, Binding **bindings, Module *module)
+{
+	USED(module);
+	USED(bindings);
+	Term *s = goal->children;
+	Term *pos = s->next;
+
+	if(s->tag == VariableTerm || pos->tag == VariableTerm)
+		Throw(instantiationerror());
+	if(s->tag != IntegerTerm && s->tag != AtomTerm)
+		Throw(domainerror(L"stream_or_alias", s));
+	if(pos->tag != IntegerTerm || pos->ival < 0)
+		Throw(domainerror(L"stream_position", pos));
+	if(!isopenstream(s))
+		Throw(existenceerror(L"stream", s));
+	if(!canreposition(s))
+		Throw(permissionerror(L"reposition", L"stream", s));
+
+	reposition(s, pos->ival);
+	return 1;
 }
\ No newline at end of file
--- a/fns.h
+++ b/fns.h
@@ -57,11 +57,15 @@
 int isoutputstream(Term *);
 int istextstream(Term *);
 int isbinarystream(Term *);
+int canreposition(Term *);
 int readterm(Term *, Term **);
 void writeterm(Term *, Term *, Term *, Module *);
 Rune getchar(Term *);
 Rune peekchar(Term *);
 void putchar(Term *, Rune);
+void flushstream(Term *);
+Term *streamsproperties(void);
+void reposition(Term *, vlong);
 
 /* module.c */
 void initmodules(void);
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -110,6 +110,29 @@
 close(StreamOrAlias) :-
 	close(StreamOrAlias, []).
 
+flush_output :-
+	current_output(S),
+	flush_output(S).
+
+stream_property(S, P) :-
+	stream_properties(Props),
+	member(prop(S,P), Props).
+
+at_end_of_stream :-
+	current_input(S),
+	stream_property(S, end_of_stream(E)),
+	!,
+	(E = at ; E = past).
+
+at_end_of_stream(S_or_a) :-
+	( atom(S_or_a)
+	-> stream_property(S, alias(S_or_a))
+	; S = S_or_a
+	),
+	stream_property(S, end_of_stream(E)),
+	!,
+	(E = at; E = past).
+
 % Standard exceptions
 
 instantiation_error :-
--- a/streams.c
+++ b/streams.c
@@ -13,8 +13,11 @@
 	Biobuf *bio;
 	int type;
 	int mode;
+	int reposition;
+	int eofaction;
 	int nalias;
 	Rune **aliases;
+	Rune *filename;
 	Stream *next;
 };
 
@@ -26,9 +29,15 @@
 enum {
 	ReadStream,
 	WriteStream,
-	AppendStream
+	AppendStream,
 };
 
+enum {
+	EofActionError,
+	EofActionEof,
+	EofActionReset,
+};
+
 static Stream *streams;
 static Stream *currentinput;
 static Stream *currentoutput;
@@ -37,6 +46,8 @@
 Stream *getstreambyfd(int);
 Stream *getstreambyalias(Rune *);
 Stream *getstream(Term *);
+Term *streamproperties(Stream *);
+void addstreamalias(int, Rune *);
 
 void
 initstreams(void)
@@ -48,7 +59,10 @@
 	Biobuf *bioout = Bfdopen(outfd, OWRITE);
 	
 	currentinput = openstreamfd(infd, bioin, TextStream, ReadStream);
-	currentoutput = openstreamfd(outfd, bioout, TextStream, WriteStream);
+	currentoutput = openstreamfd(outfd, bioout, TextStream, AppendStream);
+
+	addstreamalias(infd, L"user_input");
+	addstreamalias(outfd, L"user_output");
 }
 
 int
@@ -84,6 +98,7 @@
 	}
 
 	Stream *s = openstreamfd(fd, bio, TextStream, smode);
+	s->filename = sourcesink;
 	*stream = mkinteger(s->fd);
 	return 0;
 }
@@ -192,6 +207,16 @@
 }
 
 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);
@@ -241,8 +266,11 @@
 	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;
@@ -304,5 +332,147 @@
 {
 	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);
+		Bungetrune(s->bio);
+		if(r == Beof)
+			arg = mkatom(L"at");
+		else
+			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;
+		}
+	}
 }
\ No newline at end of file