/******************************************************************************

			UNSW Prolog (version 4)

			Written by Claude Sammut
		     Department of Computer Science
		     University of New South Wales
		   (and St. Joseph's U., Philadelphia)

		   Copyright (c)  1983 - Claude Sammut

******************************************************************************/





/*		built-in predicates for I/O			*/


#include "pred.h"
#include "in.h"

#define MAXFILES _NFILE - 3	/* _NFILES is in stdio.h */
#define UNUSED	0
#define I_MODE	1
#define O_MODE	2


extern pval new();
extern compterm *record();
extern int bind(), unbind(), isbound(), prin(), _prin();

extern pval _input, _output;
extern FILE *prog_file, *output;
extern chartype chtype[];
extern integer *stack_int;

static
struct
{
	pval sname;
	FILE *file;
	char mode;
} stream [MAXFILES];

static short num_open = -1, onum = -1, inum = -1;
static pval ifile, ofile;

FILE *piport, *poport;


set_files()
{
	register i;

	for (i = 0; i < MAXFILES; i++)
		stream[i].mode = UNUSED;
	num_open = -1;
	piport = stdin;
	poport = stdout;
}


static
int get_stream()
{
	register i;

	for (i = 0; i <= num_open; i++)
		if (stream[i].mode == UNUSED) return(i);
	if (++num_open == MAXFILES) return(-1);
	else return(num_open);
}


int find_stream(name)
pval name;
{
	register i;

	for (i = 0; i <= num_open; i++)
		if (stream[i].sname == name) return(i);
	return(-1);
}


static
see PREDICATE
{
	register i;

	if (! isatom(arg[0]))
		fail("See - argument must be atomic")
	if ((i = find_stream(arg[0])) != -1)
	{
		if (stream[i].mode == O_MODE)
			fail("See - file already opened for output")
		if (i == inum) return(TRUE);
		input = piport = stream[i].file;
		inum = i;
		ifile = stream[i].sname;
		return(TRUE);
	}
	if ((i = get_stream()) == -1)
		fail("See - Too many open files")
	if ((piport = fopen(NAME(arg[0]), "r")) == NULL)
		fail("See - cannot open file")
	stream[i].sname = arg[0];
	stream[i].file = piport;
	stream[i].mode = I_MODE;
	inum = i;
	ifile = arg[0];
	input = piport;
	return(TRUE);
}


static
read_in PREDICATE
{
	input = piport = prog_file;
}


static
ptell PREDICATE
{
	register i;

	if (! isatom(arg[0]))
		fail("Tell - argument must be atomic")
	if ((i = find_stream(arg[0])) != -1)
	{
		if (stream[i].mode == I_MODE)
			fail("Tell - file already opened for input")
		if (i == onum) return(TRUE);
		output = poport = stream[i].file;
		onum = i;
		ofile = stream[i].sname;
		return(TRUE);
	}
	if ((i = get_stream()) == -1)
		fail("Tell - Too many open files")
	if ((poport = fopen(NAME(arg[0]), "w")) == NULL)
		fail("Tell - cannot open file")
	stream[i].sname = arg[0];
	stream[i].file = poport;
	stream[i].mode = O_MODE;
	onum = i;
	ofile = arg[0];
	output = poport;
	return(TRUE);
}


p_close PREDICATE
{
	register i;

	if (! isatom(arg[0]))
		fail("Close - argument must be atomic")
	if ((i = find_stream(arg[0])) == -1)
		fail("Close - file not open")
	if (stream[i].mode == I_MODE)
	{
		piport = input = prog_file;
		inum = -1;
		ifile = _input;
	}
	else {
		poport = output = stdout;
		onum = -1;
		ofile = _output;
	}
	fclose(stream[i].file);
	stream[i].mode = UNUSED;
	stream[i].sname = 0;
	return(TRUE);
}


static
seen PREDICATE
{
	if (inum == -1)
		fail("Seen - cannot close standard input")
	fclose(stream[inum].file);
	stream[inum].mode = UNUSED;
	stream[inum].sname = 0;
	piport = input = prog_file;
	inum = -1;
	ifile = _input;
	return(TRUE);
}


static
told PREDICATE
{
	if (onum == -1)
		fail("Told - cannot close standard output")
	fclose(stream[onum].file);
	stream[onum].mode = UNUSED;
	poport = output = stdout;
	onum = -1;
	ofile = _output;
	return(TRUE);
}


static
seeing PREDICATE
{
	if (isvariable(arg[0]))
	{
		if (inum == -1)
			bind(arg[0], frame[0], _input, 0);
		else bind(arg[0], frame[0], stream[inum].sname, 0);
		return(TRUE);
	}
	else fail("Seeing - argument must be unbound variable")
}


static
telling PREDICATE
{
	if (isvariable(arg[0]))
	{
		if (inum == -1)
			bind(arg[0], frame[0], _output, 0);
		else bind(arg[0], frame[0], stream[onum].sname, 0);
		return(TRUE);
	}
	else fail("Telling - argument must be unbound variable")
}


static
p_eof PREDICATE
{
	return(feof(input));
}



static
save PREDICATE
{
	FILE *old_output;
	extern FILE *output;

	if (isatom(arg[0]))
	{
		old_output = output;
		if ((output = fopen(NAME(arg[0]), "w")) == NULL)
			fail("Save - open failure")
		listing();
		fclose(output);
		output = old_output;
		return(TRUE);
	}
	else fail("Save - invalid file name")
}


infile(file_name, pname)
char *file_name;
char *pname;
{
	char old_interp;
	FILE *old_input;

	extern char interpret, *cur_file;
	extern FILE *input;
	extern int linen;
	
	old_input = input;
	if ((input = fopen(file_name, "r")) == NULL)
		fail("Consult - cannot open file")
	old_interp = interpret;
	interpret = isatty(fileno(input));
	linen = 1;
	if (pname == 0) cur_file = file_name;
	else cur_file = pname;
	prog_file = input;
	evloop();

	fclose(input);
	input = piport = old_input;
	interpret = old_interp;
	return(TRUE);
}


static
consult PREDICATE
{
	extern pval proc_list;
	extern atom *nil;
	pval prev_proc_list;

	prev_proc_list = proc_list;
	proc_list = (pval) nil;
	if (! isatom(arg[0]))
		fail("Consult - first argument must be an atom")
	else if (infile(NAME(arg[0]), 0))
	{
		add_file(arg[0], proc_list);
		proc_list = prev_proc_list;
		return(TRUE);
	}
	return(FALSE);
}




atom_table p_files =
{
	SET_PRED(FX, 700, 1, "save", save),
	SET_PRED(NONOP, 0, 1, "consult", consult),
	SET_PRED(NONOP, 0, 1, "see", see),
	SET_PRED(NONOP, 0, 0, "read_from_this_file", read_in),
	SET_PRED(NONOP, 0, 0, "eof", p_eof),
	SET_PRED(NONOP, 0, 1, "tell", ptell),
	SET_PRED(NONOP, 0, 1, "seeing", seeing),
	SET_PRED(NONOP, 0, 1, "telling", telling),
	SET_PRED(NONOP, 0, 0, "seen", seen),
	SET_PRED(NONOP, 0, 0, "told", told),
	SET_PRED(NONOP, 0, 1, "close", p_close),
	END_MARK
};
