/*
	This is version 4.  The input language is:

Cmd	Abbrev	Operands / Comments
comment	#		only at start of line
blank	b	s <vnum>	start blanking; erase commands follow
		e <vnum>	end blanking current view
click	c	<clicknum>
define	d	v <number> <viewname> xmin ymin xmax ymax
		c <number> <clickname>
		p e	pragma -- end of defs at front of file
			Other possible ``pragmas'':			???
				Number of views, clicks
				Number of (lines, bytes) in file
erase	e	<line repeated here, except for leading g>
			Object is deletable
geom	g	<slotn>	l <vnum> <opts> <x1> <y1> <x2> <y2>	line
			b <vnum> <opts> <x1> <y1> <x2> <y2>	box
			c <vnum> <opts> <x> <y> <rad>		circle
			t <vnum> <opts> <x> <y> <text string>	text
				one separating blank; string unquoted
			    <opts> format: string of characters, in order
			    <slotn> == 0 => line never erased

At beginning of file:
	d v <number> <view name>
	d c <number> <click name>
	d p <various pragmas here>
	d p e

 */

#include <stdio.h>
#include "anim.h"

#define	sendpoint(p)	{ sendint(p.x); sendint(p.y); }
#define	sendpair(x,y)	{ sendint(x); sendint(y); }
#define	eq(s, t)	(strcmp(s,t) == 0)
#define	FATAL	1

char	*cmdname;
char	*emalloc();

#ifdef BLIT
long	memsize	= 65000;	/* memory allocation */
#endif
#ifdef X11
long	memsize	= 200000;	/* X11 memory allocation */
#endif

int	dbg	= 0;
int	lineno	= 1;	/* ? */

char	*zload	= "";	/* will be -z for load and hang on blit */
char	*termld = TERMLD;	/* will be "32ld" or "dmdld" */
int	nterm	= 0;	/* number of bytes needed in terminal */

main(argc, argv)
	char *argv[];
{
	FILE *fp;
	char *term_process = ANIMTERM;	/* typically "./animterm" */
	char buf[100];
	int i, c, bootstat;

	cmdname = argv[0];
	while (argc > 1 && argv[1][0] == '-') {
		switch (argv[1][1]) {
		case 'd':
			dbg = !dbg;
			break;
		case 'z':
			zload = "-z";
			break;
		case 't':
			term_process = argv[2];
			argc--;
			argv++;
			break;
		case 'm':
			memsize = atoi(&argv[1][2]);
			if (memsize <= 0) {
				memsize = atoi(argv[2]);
				if (memsize <= 0)
					error(FATAL, "memory size must be positive.  use -mN");
				argc--;
				argv++;
			}
			break;
		}
		argc--;
		argv++;
	}
	if (argc <= 1)
		error(FATAL, "no input file");
	if ((fp = fopen(argv[1], "r")) == NULL)
		error(FATAL, "can't open %s\n", argv[1]);
	if (!dbg) {
		bootstat = bootterm(term_process);
		set_tty();
	}
	if (bootstat || dbg)
		send_data(fp);
	if (dbg) {
		printf("\nterminal bytes needed: %d\n", nterm);
		exit(0);
	}
	while ((c = readchar()) != P_QUIT) {
		if (c == P_FILE) {	/* rest of line is a filename */
			readstring(buf);
			if ((fp = fopen(buf, "r")) == NULL)
				send1char(P_ERROR);
			else {
				send1char(P_FILE);	/* ack */
				send_data(fp);
			}
		} else
			send1char(P_ERROR);
	}
	reset_tty();
}

send_data(fp)
	FILE *fp;
{
	char text[100], buf[100], opts[100], *p;
	int c, x1, y1, x2, y2, i, v, slot;
	int ntext;

	sendint(memsize);
	send1char(P_INIT);
	send1char(P_PRINT);
	sendstring("here comes the data!");
	while ((c = getc(fp)) != EOF) {
		switch (c) {
		case ' ':
		case '\t':
			break;
		case '\n':
			lineno++;	/* this should be the only increment */
			break;
		case '#':		/* comments */
			skipline(fp);
			break;
		case 'b':	/* blank.  ignore for now */
			skipline(fp);
			break;
		case 'c':		/* click */
			if (fscanf(fp, "%d", &i) != 1)
				return badfile(fp);
			send1char(P_OBJECT);
			send1char(c);
			sendint(i);
			skipline(fp);
			nterm += 3;
			break;
		case 'e':		/* erase */
			if (fscanf(fp, "%d", &i) != 1)
				return badfile(fp);
			send1char(P_OBJECT);
			send1char(c);
			sendint(i);
			skipline(fp);
			nterm += 6;
			break;
		case 'g':		/* geom:  draw line, box, circle, ... */
			if (fscanf(fp, "%d", &slot) != 1)
				return badfile(fp);
			switch (c = skipbl(fp)) {
			case 'l':
			case 'b':
				if (fscanf(fp, "%d %s %d %d %d %d", &v, opts, &x1, &y1, &x2, &y2) != 6)
					return badfile(fp);
				send1char(P_OBJECT);
				send1char(c);
				sendint(slot);
				sendint(v);
				sendopt(c=='b' ? boxops : lineops, opts);
				sendpair(x1, y1);
				sendpair(x2, y2);
				nterm += 12;
				break;
			case 'c':	/* circle */
				if (fscanf(fp, "%d %s %d %d %d", &v, opts, &x1, &y1, &x2) != 5)
					return badfile(fp);;
				send1char(P_OBJECT);
				send1char('o');	/* 'o' is for circle */
				sendint(slot);
				sendint(v);
				sendopt(circops, opts);
				sendpair(x1, y1);
				sendint(x2);
				nterm += 10;
				break;
			case 't':	/* text */
				if (fscanf(fp, "%d %s %d %d", &v, opts, &x1, &y1) != 4)
					return badfile(fp);
				send1char(P_OBJECT);
				send1char('t');
				sendint(slot);
				sendint(v);
				sendopt(textops, opts);
				sendpair(x1, y1);
				getc(fp);	/* skip 1 separator; no quotes */
				for (p = text; (c = getc(fp)) != '\n'; )
					*p++ = c;
				*p = 0;
				ungetc('\n', fp);
				ntext = 1;
				/* slow... */
				if (eq(text, "bullet"))
					sendstring("*");
				else if (eq(text, "dot"))
					sendstring(".");
				else if (eq(text, "circle"))
					sendstring("o");
				else if (eq(text, "times"))
					sendstring("x");
				else {
					sendstring(text);
					ntext = strlen(text);
				}
				nterm += 10 + ntext;
				break;
			default:
				return badfile(fp);
			}
			break;
		case 'd':	/* definition of some sort */
			switch (c = skipbl(fp)) {
			case 'v':	/* view */
				if (fscanf(fp, "%d %s", &i, text) != 2)
					return badfile(fp);
				send1char(P_DEFINE);
				send1char('v');
				sendint(i);
				sendstring(text);
				skipline(fp);	/* might be a title there */
				break;
			case 'c':	/* click */
				if (fscanf(fp, "%d %s", &i, text) != 2)
					return badfile(fp);
				send1char(P_DEFINE);
				send1char('c');
				sendint(i);
				sendstring(text);
				break;
			case 'p':
				skipline(fp);
				break;
			default:
				return badfile(fp);
			}
			break;
		default:
			return badfile(fp);
		}
	}
	send1char(P_ENDFILE);
	fclose(fp);
	flushproto();
	return 1;
}

badfile(fp)
	FILE *fp;
{
	send1char(P_ERRPRINT);
	sendstring("file is not in .i format");
	send1char(P_ENDFILE);
	while (getc(fp) != EOF)
		;
	fclose(fp);
	flushproto();
	return 0;
}

sendopt(optvals, opts)
	int optvals[];
	char *opts;
{
	int i, n;

	n = 0;
	for (i = 0; optvals[i] && opts; i += 2)
		if (*opts == optvals[i]) {
			n += optvals[i+1];
			opts++;
		}
	sendint(n);
}

skipbl(fp)
	FILE *fp;
{
	int c;

	while ((c = getc(fp)) == ' ' || c == '\t')
		;
	return c;
}

skipline(fp)
	FILE *fp;
{
	int c;

	while ((c = getc(fp)) != '\n')
		;
	ungetc('\n', fp);
}

error(f, s, a1, a2, a3, a4, a5, a6, a7)
{
	extern char *cmdname;
	extern int dbg;

	fprintf(stderr, "%s: ", cmdname);
	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
	fprintf(stderr, "\n");
	if (lineno)
		fprintf(stderr, " source line number %d\n", lineno);
	if (f) {
		if (dbg)
			abort();
		exit(2);
	}
}

#ifndef X11

bootterm(procname)
	char *procname;
{
	char buf[100];

	sprintf(buf, "%s %s %s </dev/tty", termld, zload, procname);
	if (system(buf) != 0) {
		fprintf(stderr,
			"anim: can't create pipe to terminal process\n");
		return 0;
	}
	return 1;
}

#endif

#ifdef X11

bootterm(procname)
	char *procname;
{
	int afildes[2], bfildes[2], pid;
	if((pipe(afildes)==-1)||(pipe(bfildes)==-1)){
		fprintf(stderr,
			"anim: can't create pipe to terminal process\n");
		return 0;
	}
	if((pid=fork())==0){
		close(0);
		dup(afildes[0]);
		close(1);
		dup(bfildes[1]);
		execl(procname, "animterm", 0);
		exit(127);
	}
	if(pid==-1){
		fprintf(stderr,"anim: can't fork %s\n", procname);
		return 0;
	}
	close(0);
	dup(bfildes[0]);
	close(1);
	dup(afildes[1]);
	return 1;
}

#endif
