#include "all.h"

#include "global.h"
#include "proto.h"

int32 gt_index(OPKEY lkey,char *s);
int include_file(char *s);
int var_set_local(void);
int var_set_global(void);
int var_clear_local(void);
int get_cap(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen);
int get_join(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen);
int g_marker_def(char *s1, char *s2);
char *mixed_case(char *s);
extern int this_line;

#define true (!false)
#define false 0
#define tok(n)  (*tk)[n]
extern int gle_debug;

struct sub_st {char name[40];int typ; int np
		; int ptyp[20]; char *pname[20]; }  ;
struct sub_st *psub;
/*---------------------------------------------------------------------------*/
#define no_more()  if (curtok<=*ntok) gprint("Unexpected text on end of command {%s}\n",tok(curtok));
#define lkeypos(i)  (pcode + *plen + (*lkey)[i].pos - 1);
#define dup_err if (*pt!=0) gprint("Duplicate or illegal combination of qualifiers \n");
#define get_xy() gt_xy(&curtok,tk,ntok,pcode,plen)
#define get_first(key) gt_first((OPKEY) key,&curtok,(TOKENS) tk,ntok,pcode,plen)
#define get_optional(key) gt_optional((OPKEY) key,&curtok,(TOKENS) tk,ntok,pcode,plen)
#define skip_space  if (*tok(curtok)==' ') {curtok++;}
#define get_anyexp() {etype=0;polish(tok(curtok++),(char *) pcode,plen,&etype);}
#define get_exp() {etype=1;polish(tok(curtok++),(char *) pcode,plen,&etype);}
#define get_strexp() {etype=2;polish(tok(curtok++),(char *) pcode,plen,&etype);}
#define get_token(t) if (strcmp(t,tok(curtok))!=0) gprint("Expecting {%s} found {%s} %d \n",t,tok(curtok),curtok); curtok += 1
#define dbg if ((gle_debug & 8)>0)

/* pos=   Offset to find the data			*/
/* idx=   For switches, which can only have one value. 	*/
/* The pos is the order the items will be placed in the pcode */
/*---------------------------------------------------------------------------*/
/* Input is gle command (tokized) , output is pcode */
static int cur_mode=0;  /* 0 = normal, 1 = external begin...end */
pass_checkmode()
{
	if (cur_mode!=0) gprint("END OF FILE while in block type %d \n",cur_mode);
	cur_mode = 0; /* reset it */
}
passt(int srclin,char *source,TOKENS tk,int *ntok,int32 *pcode,int *plen)
{
		/* Source line number */
		/* a pointer to the original string */
		/* a pointer to an array of 500 pointers to char tokens */
		/* pinter to number of tokens */
		/* a pointer to the pcode output buffer */
		/* a pointer to the length of the pcode output */
int etype;
static int sdx;
static int sub_start,sub_end;
static char tempstr[300];
static char *sp;
static int *savep;
static int i,f,vtyp,v,sl,np,in_sub,vidx,vtype;
	int ix;
	int curtok=1;

	vtype = 0;
	this_line = srclin;
	etype = 1;
	curtok = 1;
	if (cur_mode!=0) {goto text_mode;}

	dbg for (i=1;i<= *ntok; i++) gprint("{%s}%d ",tok(i),strlen(tok(i)));
	dbg gprint("\n");

	if (*ntok==0) { /* blank line */
		*(pcode+(*plen)++) = 0;
		return;
	}
	find_mkey(tok(1),&ix);
	if (ix==0) {
		if (*tok(1)=='@') { /* call subroutine */
			char tmpexp[232];
			*(pcode+(*plen)++) = 52;
			curtok = 2;
			strcpy(tmpexp,tok(1)+1);
			strcat(tmpexp,"(");
			if (curtok > *ntok) strcat(tmpexp,",");
			while (curtok <= *ntok) {
				strcat(tmpexp,tok(curtok++));
				strcat(tmpexp,",");
			}
			tmpexp[strlen(tmpexp)-1] = ')';
			etype = 0;
			polish(tmpexp,(char *) pcode,plen,&etype);
			return ;
		}
		if (strcmp(tok(2),"=")==0) {  /* variable = expression */
			*(pcode+(*plen)++) = 51;
			var_find(tok(1),&vidx,&vtype);
			if (vidx<0) var_add(tok(1),&vidx,&vtype);
			*(pcode+(*plen)++) = vidx;
			curtok = 3;
			polish(tok(curtok++),(char *) pcode,plen,&vtype);
			if (*ntok >= curtok)  gprint("Remove spaces from expression \n");
			return ;
		}
		sp = strchr(tok(curtok),'=');
		if (sp!=NULL) {
			*sp = 0;
			var_findadd(tok(curtok),&vidx,&vtype);
			tok(curtok) = sp + 1;
			*(pcode+(*plen)++) = 51;
			*(pcode+(*plen)++) = vidx;
			curtok = 1;
			polish(tok(curtok++),(char *) pcode,plen,&vtype);
			if (*ntok >= curtok)  gprint("No spaces in expressions\n");
			return ;
		}
	}
	*(pcode+(*plen)++) = ix;
	curtok = 2;
	switch (ix) {
	  case 1:  /* ALINE */
		get_xy();
		get_optional(op_line);
		break;
	  case 2: /* AMOVE */
		get_xy();
		break;
	  case 3: /* ARC r a1 a2  */
		get_exp();
		get_xy();
		get_optional(op_arc);
		no_more();
		break;
	  case 4: /* ARCTO x1 y1 x2 y2 r */
		get_xy();
		get_xy();
		get_exp();
		no_more();
		break;
	  case 5: /* BEGIN  "PATH"  "BOX"  "SCALE"  "ROTATE"  "TRANSLATE" shear */
		f = get_first(op_begin);
		*(pcode+(*plen)++) = f;
		spush(51);
		/*------------------------------------------*/
		/*       Check if begin variable matches    */
		/*------------------------------------------*/
		switch (f) {
		  case 1: /* path */
			get_optional(op_begin_path);
			break;
		  case 2: /* box */
			get_optional(op_begin_box);
			break;
		  case 3: /* scale */
			get_xy();
			/* get_optional(op_begin_scale); */
			no_more();
			break;
		  case 21: /* shear */
			get_xy();
			/* get_optional(op_begin_scale); */
			no_more();
			break;
		  case 4: /* rotate */
			get_exp();
			/* get_optional(op_begin_scale); */
			no_more();
			break;
		  case 5: /* translate */
			get_xy();
/*			get_optional(op_begin_scale); */
			no_more();
			break;
		  case 19: /* clip */
		  case 17: /* origin */
			break;
		  case 6: /* if */
			break;
		  case 7: /* sub */
			gprint("Not a valid begin option\n");
			break;
		  case 8: /* name joe */
			get_strexp();
			break;
		  case 9: /* text */
			cur_mode = 9;
			get_optional(op_begin_text);
			break;
		  case 10: /* graph */
			cur_mode = 10;
			break;
		  case 11: /* xaxis */
			cur_mode = 11;
			break;
		  case 12: /* yaxis */
			cur_mode = 12;
			break;
		  case 13: /* x2axis */
			cur_mode = 13;
			break;
		  case 14: /* y2axis */
			cur_mode = 14;
			break;
		  case 15: /* curve */
			break;
		  case 16: /* KEY */
			cur_mode = 16;
			break;
		  case 18: /* table */
			cur_mode = 18;
			break;
		}
		/* here should copy source line across for "begin width 3 */
		if (cur_mode>0)	*(pcode+(*plen)++) = 0;
		break;
	  case 6: /* BEZIER x1 y1 x2 y2 x3 y3 */
		get_xy();
		get_xy();
		get_xy();
		no_more();
		break;
	  case 7 :	/* box x y  [left | center | right]  [fill xxx] name*/
		get_xy();
		get_optional(op_box);
		break;
	  case 52: /* call subroutine */
		{
			char tmpexp[232];
			strcpy(tmpexp,tok(curtok++));
			strcat(tmpexp,"(");
			while (curtok <= *ntok) {
				strcat(tmpexp,tok(curtok++));
				strcat(tmpexp,",");
			}
			tmpexp[strlen(tmpexp)-1] = ')';
			etype = 0;
			polish(tmpexp,(char *) pcode,plen,&etype);
		}
		break;
	  case 8 :	/* circle rad fill */
		get_exp();
		get_optional(op_circle);
		break;
	  case 9 : /* close */
		get_exp();
		no_more();
		break;
	  case 53: /* comment !  or blank line */
		break;
	  case 10 : /* curve sx sy x y x y x y ... ex ey */
		while (*ntok>curtok) {
			*(pcode+(*plen)++) = 111;
			get_xy();
		}
		*(pcode+(*plen)++) = 999;
		break;
	  case 60 : /* defmarker xyz rm 33 1 -.4 -.2 */
		g_defmarker(tok(curtok),tok(curtok+1),atoi(tok(curtok+2))
			,atof(tok(curtok+4)),atof(tok(curtok+5))
			,atof(tok(curtok+3)),true);
		break;
	  case 11 :  /* define marker jj subname */
		get_token("MARKER");
		g_marker_def(tok(curtok),tok(curtok+1));
		curtok+=2;
		no_more();
		break;
	  case 12 :
		sl = strlen(source)+1;
		sl = ((sl + 3) & 0xfffc);
		sl = sl/4;
		/* copy source string to pcode., add null, round upp. 	 */
		strcpy((char *) (pcode+*plen),source);
		*plen = *plen + sl;
		break;
	  case 13 :/* ELSE ... */
		scheck(50);
		no_more();
		break;
	  case 14 : /* END if, sub, path, box, scale,translate,rotate */
		i = get_optional(op_begin);
		if (i==7) {
			sub_end = srclin;
			sub_set_startend(sdx,sub_start,sub_end);
			var_clear_local();
			in_sub = false;
		}
		if (i==0) gprint("Type of END missing, e.g. end if, end sub\n");
		spop(i+50);	/* Check if begin variable matches */
		break;
	  case 16 : /* FILL (fillpath) */
		no_more();
		break;
	  case 15 : /* FCLOSE inchan */
		get_exp();
		break;
	  case 17: /* fopen "a.a" inchan read|write */
		get_strexp();
		var_findadd(tok(curtok),&v,&vtyp);
		curtok++;
		*(pcode+(*plen)++) = v;
		if (strcmp(tok(curtok),"WRITE")==0) *(pcode+(*plen)++) = 1;
		else {
			get_token("READ");
			*(pcode+(*plen)++) = 0;
		}
	  case 61 : /* fread CHAN a$ x   */
	  case 62 : /* freadln */
		while (curtok<=*ntok) {
			var_findadd(tok(curtok),&v,&vtyp); curtok++;
			*(pcode+(*plen)++) = 49;
			*(pcode+(*plen)++) = v;
			*(pcode+(*plen)++) = vtyp;
			skip_space;
		}
		break;
	  case 63 : /* fwrite */
	  case 64 : /* fwriteln */
		while (curtok<=*ntok) {
			*(pcode+(*plen)++) = 49;
			*(pcode+(*plen)) = 0;
			savep = (int *) (pcode+(*plen)++);
			get_anyexp();
			*savep = etype;
			skip_space;
		}
		break;
	  case 18 :  /* for var = exp1 to exp2 [step exp3] */
		sp = strchr(tok(curtok),'=');
		if (sp!=NULL) {
			*sp = 0;
			var_findadd(tok(curtok),&v,&vtyp);
			tok(curtok) = sp + 1;
			*(pcode+(*plen)++) = v;
			spush(v+100);	/* Remeber we started a loop with variable v*/
		} else {
			var_findadd(tok(curtok++),&v,&vtyp);
			*(pcode+(*plen)++) = v;
			spush(v+100);	/* Remeber we started a loop with variable v*/
			get_token("=");
		}
		get_exp();
		get_token("TO");
		get_exp();
		get_optional(op_for_step);
		break;
	  case 19 :/* goto */
		gprint("Goto IS NOT implemented, being kept or a future release.\n");
		break;
	  case 20 : /* gsave */
		no_more();
		break;
	  case 54 : /* grestore */
		no_more();
		break;
	  case 21 : /* icon x y */
		get_xy();
		no_more();
		break;
	  case 22 :  /* IF exp THEN ...  */
		get_exp();
		get_token("THEN");
		no_more();
		spush(50);	/* Check if endif or else matches */
		break;
	  case 55 : /* postscript file$  width  height */
		get_strexp();
		get_xy();
		no_more();
		break;
	  case 56 : /* draw file$, nope, not a good idea. begin..end text */
		get_strexp();
		no_more();
		break;
	  case 57 : /* plotter fonts */
		get_token("FONTS");
		no_more();
		break;
	  case 23 : /* include "string" */
		include_file(mixed_case(tok(curtok++)));
		no_more();
		break;
	  case 58 : /* bigfile "string" This waits until 'run' to read the file*/
		get_strexp();
		no_more();
		break;
	  case 24 : /* input 1 a$=20,fill$=10,j=6 prompt "Age and name " */
	  		/* input 1 a$,yval prompt "Age and name " */
	  case 25 : /* join a.tl->b.br   ,   string, arrows&line, string */
		get_strexp();
		*(pcode+(*plen)++) = get_first(op_joinname);
		get_strexp();
		break;
	  case 26 : /* marker square [2.2] */
		get_marker(tk,ntok,&curtok,pcode,plen);
		if (*ntok<curtok) {
			*(pcode+(*plen)++) = 0;
		} else {
			get_exp();
		}
		break;
	  case 27 : /* MOVE name */
		get_strexp();
		no_more();
		break;
	  case 28 : /* narc, Arc in clockwise direction */
		get_exp();
		get_xy();
		get_optional(op_arc);
		no_more();
		break;
	  case 29 : /* newpath */
		no_more();
		break;
	  case 30 : /* next */
		if (curtok<=*ntok) get_exp();
		spop(v+100);	/* Check if loop variable matches */
		no_more();
		break;
	  case 31 : /* pie r a1 a2 fill pattern */
		get_exp();
		get_xy();
		get_optional(op_fill);
		break;
	  case 32 : /*print 0 "Working..." */
	  case 33 :
		get_xy();
		get_xy();
		get_xy();
		no_more();
		break;
	  case 34 : /* region */
		gprint("Region IS NOT implemented, complain to your local MP   \n");
		break;
	  case 50 : /* Return EXP */
		if (curtok<=*ntok) {
			get_exp();
		} else {		
		  etype=1;polish("0",(char *) pcode,plen,&etype);
		}
		break;
	  case 35 : /* Reverse the current path */
		no_more();
		break;
	  case 36 : /* rline */
		get_xy();
		get_optional(op_line);
		break;
	  case 37 : /* rmove */
		get_xy();
		no_more();
		break;
	  case 38 : /* rotate */
		get_exp();
		no_more();
		break;
	  case 39 : /* save joe */
		get_strexp();
		no_more();
		break;
	  case 40 : /* scale x y */
		get_xy();
		no_more();
		break;
	  case 41 : /* SET color font hei just lwidth lstyle ldist */
		while (curtok<=*ntok) {
		 dbg gprint(" set ntok= %d  curtok= %d \n",curtok,*ntok);
		 f = get_first(op_set);
		 *(pcode+(*plen)++) = 500+f;
		 switch (f) {
		  case 1: /* height */
			get_exp();
			break;
		  case 2: /* font */
			get_font(tk,ntok,&curtok,pcode,plen);
			break;
		  case 3: /* justify */
			get_justify(tk,ntok,&curtok,pcode,plen);
			break;
		  case 4: /* color */
			get_color(tk,ntok,&curtok,pcode,plen);
			break;
		  case 5: /* dashlen */
			get_exp();
			break;
		  case 6: /* dash */
			get_exp();
			break;
		  case 7: /* lwidth */
			get_exp();
			break;
		  case 8: /* join */
			/* get_join(); */
			get_join(tk,ntok,&curtok,pcode,plen);
			break;
		  case 9: /* cap */
			/* get_cap(); */
			get_cap(tk,ntok,&curtok,pcode,plen);
			break;
		  case 10: /* fontlwidth */
			get_exp();
			break;
		  }
		}
		break;
	  case 42 : /* size */
		get_xy();
		get_optional(op_size);
		break;
	  case 43 : /* STROKE */
		no_more();
		break;
	  case 44 : /* SUB JOE X Y$ Z   ... END SUB  */
		if (in_sub) {gprint("Cannot define a subroutine within a sub "); break;}
		in_sub = true;
		spush(51);		/* to check structure */
		sdx = sub_def(tok(curtok++));
		var_set_local();
		if (!valid_var(psub->name)) {
			gprint("Invalid subroutine name ");
		}
		for (np=0; curtok<=*ntok; np++) {
			sub_param(sdx,tok(curtok));
			if (!valid_var(tok(curtok))) {
				gprint("Invalid subroutine parameter");
			}
			curtok++;
		}
		*(pcode+(*plen)++) = sdx; /* put sub number in pcode */
		sub_start = srclin;
		var_set_global();
		break;
	  case 45 :
		/* char *source;	a pointer to the original string */
		/* produce captilized string				 */
		for (i=0; *(source+i)!=0; i++)
			tempstr[i] = toupper(*(source+i));
		/* find word TEXT 					 */
		sp = strstr(tempstr,"TEXT");
		if (sp==NULL) {gprint("what the shit \n"); break;}
						/* sp = &tempstr;    */
		sp = (sp-&tempstr[0])+source;	/* switch to lowercase str */
		sp = sp + 5;
		sl = strlen(sp)+1;
		sl = ((sl + 3) & 0xfffc);
		sl = sl/4;
		/* copy rest of string to pcode., add null, round upp. 	 */
		strcpy((char *) (pcode+*plen),sp);
		*plen = *plen + sl;
		break;
	  case 59 : /* textdef */
		/* char *source;	a pointer to the original string */
		/* produce captilized string				 */
		for (i=0; *(source+i)!=0; i++)
			tempstr[i] = toupper(*(source+i));
		/* find word TEXT 					 */
		sp = strstr(tempstr,"TEXTDEF");
		if (sp==NULL) {gprint("what the shit \n"); break;}
						/* sp = &tempstr;    */
		sp = (sp-&tempstr[0])+source;	/* switch to lowercase str */
		sp = sp + 8;
		sl = strlen(sp)+1;
		sl = ((sl + 3) & 0xfffc);
		sl = sl/4;
		/* copy rest of string to pcode., add null, round upp. 	 */
		strcpy((char *) (pcode+*plen),sp);
		*plen = *plen + sl;
		break;
	  case 46 : /* translate x y */
		get_xy();
		no_more();
		break;
	  case 47 : /* until */
		get_exp();
		spush(50+20);
		break;
	  case 48 : /* while */
		gprint("While IS NOT implemented, complain to your local MP   \n");
		break;
	  case 49 : /* write numexp,strexp,strexp */
		while (curtok<=*ntok) {
			*(pcode+(*plen)++) = 49;
			*(pcode+(*plen)) = 0;
			savep = (int *) (pcode+(*plen)++);
			get_anyexp();
			*savep = etype;
			skip_space;
		}
		break;
	  default:
		gprint("Unrecognised command verb {%s}   %d \n",tok(1),ix);
		if (strchr(tok(1),'=')!=NULL)
			gprint("There should be a space on either side of an equals sign \n");

	}
return;

/*------------*/
text_mode: /* Inside a begin, don't interpret, just pass "as is" */
	*(pcode+(*plen)++) = 5;		/* begin */
	if (strcmp(tok(1),"END")==0) {
	  i = gt_index((OPKEY) op_begin,tok(2));
	  if (i==cur_mode) {
		*(pcode+(*plen)++) = 0;		/* END XXXX */
		cur_mode = 0;
		return;
	  }
	}
	*(pcode+(*plen)++) = cur_mode;	/* begin_type (e.g. text, graph, xaxis */

	sl = strlen(source)+1;
	*(pcode+*plen) = 0;
	sl = ((sl + 3) & 0xfffc);
	sl = sl/4;
	/* copy source string to pcode., add null, round upp. 	 */
	strcpy((char *) (pcode+*plen),source);
	*plen = *plen + sl;
}
/*--------------------------------------------------------------------------*/
gt_xy(int *curtok, char (*(*tk)[500]), int *ntok,
	int32 *pcode, int *plen)
{
	int etype;
	etype = 1;
	if (*ntok < *curtok) {
		gprint("Expecting x expression on end of line\n");
	}
	polish(tok((*curtok)++),(char *) pcode,plen,&etype);
	etype = 1;
	if (*ntok < *curtok) {
		gprint("Expecting y expression on end of line\n");
	}
	polish(tok((*curtok)++),(char *) pcode,plen,&etype);
}
/*--------------------------------------------------------------------------*/
int32 gt_first(OPKEY lkey, int *curtok, TOKENS tk, int *ntok, int32 *pcode, int *plen)
{
	int nk,i,width=0,p;
	for (i=0; (*lkey)[i].typ!=typ_end; i++) {
		p = (*lkey)[i].pos;
		if (p>width) width = p ;
	}
	nk = i;
	for (i=0; i<nk; i++) {
		if (strcmp((*lkey)[i].name,tok(*curtok))==0) {
			(*curtok)++;
			return (*lkey)[i].idx;
		}
	}
	gprint("Found {%s} expecting one of: \n",tok(*curtok));
	gprint("		");
	for (i=0; i<nk; i++) {
		gprint("%s, ",(*lkey)[i].name);
		if ( (i+1)/3 == (i+1)/3.0 ) gprint("\n		");
	}
	if ( (i)/3 != (i+1)/3.0 ) gprint("\n");
	(*curtok)++;

}
int32 gt_firstval(OPKEY lkey,char *s)
{
	int nk,i,width=0,p;
	for (i=0; (*lkey)[i].typ!=typ_end; i++) {
		p = (*lkey)[i].pos;
		if (p>width) width = p ;
	}
	nk = i;
	for (i=0; i<nk; i++) {
		if (strcmp((*lkey)[i].name,s)==0) {
			dbg gprint("Got match {%s} \n",s);
			return (*lkey)[i].idx;
		}
	}
	gprint("Found {%s} expecting one of: \n",s);
	for (i=0; i<nk; i++) gprint("		%s \n",(*lkey)[i].name);
}

int32 gt_index(OPKEY lkey,char *s)
{
	int nk,i,p;
	for (i=0; (*lkey)[i].typ!=typ_end; i++) {
		if (strcmp((*lkey)[i].name,s)==0) {
			return (*lkey)[i].idx;
		}
	}
	return 0;
}
/*--------------------------------------------------------------------------*/
gt_optional(OPKEY lkey, int *curtok, TOKENS tk, int *ntok, int32 *pcode, int *plen)
{
	int rval=0;
	int xlen,*pt;
	int etype,f;
	int nk,i,width=0,p,tt,pidx,prest;

	for (i=0; (*lkey)[i].typ!=typ_end; i++) {
		p = (*lkey)[i].pos;
		if (p>width) width = p ;
	}
	nk = i;
	/* zero all the optional parameters. */
	for (i=0; i<width+1; i++) {
		*(pcode + i + *plen) = 0;
	}
	dbg gprint("The number of flags %d first token {%s} %d \n",nk,tok(*curtok),*curtok);
	prest = *plen + nk;	/*remeber where the END OF exp'S are */
	for (tt = *curtok; tt<= *ntok; ) {
	  for (i=0; i<nk; i++) {
		if (strcmp((*lkey)[i].name,tok(tt))==0) {
			tt++;
			goto found_word;
		}
	  }
	*plen = prest;
	  gprint("Found {%s} (%d) expecting one of: \n",tok(tt),tt);
	  for (i=0; i<nk; i++) gprint("		%s \n",(*lkey)[i].name);
	  *curtok = tt;
	  return 0;
found_word:
/*----------------------------------------*/
/* switches 	int 	placed in directly, 1 present, 0 not present
/* expressions 	LONG* 	pointed to, 0 if not present.
/* color/fill	LONG* 	Pointer to exp 0 if not present.
/* marker	LONG*	Pointer to exp 0 if not present.
/* lstyle 	LONG*	Pointer to exp 0 if not present.
/* font 	int32* 	Pointer to string expression.
/* justify 	int32
*/

	  switch ((*lkey)[i].typ) {
	    case typ_val:
		etype = 1;
		pt = (int *)  (pcode + *plen + (*lkey)[i].pos - 1);
		if (*pt!=0) gprint("Duplicate or illegal combination of qualifiers ");
		*pt = prest-*plen-(*lkey)[i].pos+1;
		polish(tok(tt++),(char *) pcode,&prest,&etype);
		dbg gprint("val Returned,  curtok=%d prest=%d type %d \n",tt,prest,etype);
	 	break;
	    case typ_val2:
		etype = 1;
		pt = (int *) (pcode + *plen + (*lkey)[i].pos - 1);
		if (*pt!=0) gprint("Duplicate or illegal combination of qualifiers ");
		*pt = prest-*plen-(*lkey)[i].pos+1 ;
		polish(tok(tt++),(char *) pcode,&prest,&etype);
		dbg gprint("val Returned,  curtok=%d prest=%d type %d \n",tt,prest,etype);
		/* tt++; */	/* step over space between expressions */
		etype = 1;
		pt = pt + 1;
		if (*pt!=0) gprint("Duplicate or illegal combination of qualifiers ");
		*pt = prest-*plen-(*lkey)[i].pos+1 ;
		polish(tok(tt++),(char *) pcode,&prest,&etype);
		dbg gprint("val Returned,  curtok=%d prest=%d type %d \n",tt,prest,etype);
		break;
	    case typ_str: /* string constant,  used for NAMEs, */
		etype = 2;
		pt = (int *) (pcode + *plen + (*lkey)[i].pos - 1);
		if (*pt!=0) gprint("Duplicate or illegal combination of qualifiers %ld %p \n",*pt,pt);
		*pt = prest-*plen-(*lkey)[i].pos+1;
		polish(tok(tt++),(char *) pcode,&prest,&etype);
	 	break;
	    case typ_switch:
		pt = (int *) (pcode + *plen + (*lkey)[i].pos - 1);
		dup_err;
		*pt = (*lkey)[i].idx;
		rval = *pt;
		break;
	    case typ_color: /* blue green red, or exp. */
	    case typ_fill:
		pt = (int *) lkeypos(i);
		dup_err;
		*pt = prest-*plen-(*lkey)[i].pos+1 ;
		get_fill(tk,ntok,&tt,pcode,&prest);
		break;
	    case typ_marker:
		pt = (int *) lkeypos(i);
		dup_err;
		*pt = prest-*plen-(*lkey)[i].pos+1 ;
		get_marker(tk,ntok,&tt,pcode,&prest);
		break;
	    case typ_lstyle:
		pt = (int *) lkeypos(i);
		dup_err;
		*pt = prest-*plen-(*lkey)[i].pos+1 ;
		etype = 1;
		polish(tok(tt++),(char *) pcode,&prest,&etype);
		break;
	    case typ_justify:
		pt = (int *) lkeypos(i);
		dup_err;
		*pt = gt_first((OPKEY) op_justify,&tt,(TOKENS) tk,ntok,pcode,&prest);
		dbg gprint("setting justify flag %d \n",*pt);
		break;
	    case typ_arrow:
		f = gt_first((OPKEY) op_arrow,&tt,(TOKENS) tk,ntok,pcode,&prest);
		pt = (int *) lkeypos(i);
		*pt = f;
		break;
	    default :
		gprint("***errrorororororor non existent type ***");
		break;
	  }
/*----------------------------------------*/
	}
	*plen = prest;
	*curtok = tt;
	return rval;
}
/*--------------------------------------------------------------------------*/

#undef get_first
#define get_first(key) gt_first(&key,curtok,tk,ntok,pcode,plen)

/*--------------------------------------------------------------------------*/
mystrcpy(char **d,char *s)
{
	if (*d!=0) myfree(*d);
	*d = 0;
	*d = myallocz(strlen(s)+1);
	strcpy(*d,s);
}
#undef get_exp
#define get_exp() polish(tok((*curtok)++),(char *) pcode,plen,&etype)
/* pos=   Offset to find the data			*/
/* idx=   For switches, which can only have one value. 	*/
/*--------------------------------------------------------------------------*/
int pass_justify(char *s)
{
	return gt_firstval((OPKEY) op_justify,s);
}
int polish_eval(char *s, double *x);
int32 pass_color(char *s)
{
	double xx;
	int32 j;
	int i;
	char vv[80];
	if (strstr(s,"CVTRGB")!=NULL) {
		polish_eval(s,&xx);
	} else if (*s=='.' || *s=='(' || isdigit(*s)) {
		strcpy(vv,"cvtgrey(");
		strcat(vv,s); strcat(vv,")");
		polish_eval(vv,&xx);
	} else	if (strchr(s,'$') != NULL) {
		strcpy(vv,"cvtcolor(");
		strcat(vv,s); strcat(vv,")");
		polish_eval(vv,&xx);
	} else {
		return 	gt_firstval((OPKEY) op_color_typ,s);
	}
	memcpy(&j,&xx,sizeof(int32));
	return j;
}
#define get_exps(ss) polish(ss,(char *) pcode,plen,&etype)
get_color(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	int i,etype=1;
	char vv[80];

	if (strstr(tok(*curtok),"CVTRGB")!=NULL) {
		get_exps(tok(*curtok));
	} else if (*tok(*curtok)=='(' || isdigit(*tok(*curtok))) {
		strcpy(vv,"cvtgrey(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else	if (strchr(tok(*curtok),'$') != NULL) {
		strcpy(vv,"cvtcolor(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else {
		*(pcode+(*plen)++) = 8;
		*(pcode+(*plen)++) = get_first(op_color_typ);
		return;
	}
	(*curtok)++;
}
get_fill(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	int i,etype=1;
	char vv[80];
	if (strstr(tok(*curtok),"CVTRGB")!=NULL) {
		get_exps(tok(*curtok));
	} else if (*tok(*curtok)=='(' || isdigit(*tok(*curtok))) {
		strcpy(vv,"cvtgrey(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else	if (strchr(tok(*curtok),'$') != NULL) {
		strcpy(vv,"cvtcolor(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else {
		*(pcode+(*plen)++) = 8;
		*(pcode+(*plen)++) = get_first(op_color_typ);
		return;
	}
	(*curtok)++;
}
get_justify(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	*(pcode+(*plen)++) = get_first(op_justify);
}
get_join(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	*(pcode+(*plen)++) = get_first(op_join);
}
get_cap(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	*(pcode+(*plen)++) = get_first(op_cap);
}

struct mark_struct { char *name; char *font; int cc; double rx; double ry; double scl;};
struct mark_struct stdmark[] = {
		"DOT","RM",46,-.125,-.0435,3.0,		/* dot */
		"CROSS","TEXSY",2,-.375,-.24,1.0,	/* cross */
		"FCIRCLE","GLEMARK",4,-.5,-.5,0.7,	/* fcircle */
		"FSQUARE","GLEMARK",6,-.5,-.5,0.7,	/* fsquare */
		"FTRIANGLE","GLEMARK",5,-.5,-.433,0.7,	/* ftriangle */
		"FDIAMOND","GLEMARK",7,-.5,-.7,0.7,	/* fdiamond */
		"CIRCLE","GLEMARK",12,-.5,-.5,0.7,	/* circle */
		"SQUARE","GLEMARK",2,-.5,-.5,0.7,	/* square */
		"TRIANGLE","GLEMARK",1,-.5,-.433,0.7,	/* triangle */
		"DIAMOND","GLEMARK",3,-.5,-.7,0.7,	/* diamond */
		/*"PLUS","TEXMI",43,-.375,-.24,1.0,*/	/* plus, needs fixing ("+" unavailable in that font) */
		"PLUS","TEXCMR",43,-.375,-.24,1.0,	/* plus, fixed */
		"CLUB","TEXSY",124,-.38,-.3,1.0,	/* club */
		"HEART","TEXSY",126,-.38,-.34,1.0,	/* heart */
		"DIAMONDZ","TEXSY",125,-.38,-.26,1.0,	/* diamondz */
		"SPADE","TEXSY",127,-.375,-.24,1.0,	/* spade (needs fixing) */
		"STAR","TEXMI",63,-.25,-.21,1.0,	/* star */
		"SNAKE","TEXSY",120,-.21,-.22,1.0,	/* snake */
		"DAG","TEXSY",121,-.21,-.22,1.0,	/* dag */
		"DDAG","TEXSY",122,-.21,-.22,1.0,	/* dagg */
		"ASTERIX","TEXSY",3,-.25,-.24,1.0,	/* asterix */
		"ASTERISK","TEXSY",3,-.25,-.24,1.0,	/* asterix */
		"OPLUS","TEXSY",8,-.40,-.24,1.0,	/* oplus */
		"OMINUS","TEXSY",9,-.40,-.24,1.0,	/* ominus */
		"OTIMES","TEXSY",10,-.40,-.24,1.0,	/* otimes */
		"ODOT","TEXSY",12,-.40,-.24,1.0,	/* odot */
		"TRIANGLEZ","TEXSY",52,-.44,-.26,1.0,	/* trianglez */
		"DIAMONDZ","TEXSY",125,-.38,-.26,1.0,	/* diamondz */
		"WCIRCLE","GLEMARK",8,-.5,-.5,0.7,	/* wcircle */
		"WTRIANGLE","GLEMARK",9,-.5,-.433,0.7,	/* wtriangle */
		"WSQUARE","GLEMARK",10,-.5,-.5,0.7,	/* wsquare */
		"WDIAMOND","GLEMARK",11,-.5,-.7,0.7,	/* wdiamond */
		"PLANE","PSZD",40,0.0,0.0,1.0,		/* ZapDingbats */
		"HANDPEN","PSZD",45,0.0,0.0,1.0,	/* ZapDingbats */
		"SCIRCLE","PSZD",109,0.0,0.0,1.0,	/* ZapDingbats */
		"SSQUARE","PSZD",111,0.0,0.0,1.0,	/* ZapDingbats */
		"PHONE","PSZD",37,0.0,0.0,1.0,		/* ZapDingbats */
		"LETTER","PSZD",41,0.0,0.0,1.0,		/* ZapDingbats */
		"STAR2","PSZD",69,0.0,0.0,1.0,		/* ZapDingbats */
		"STAR3","PSZD",79,0.0,0.0,1.0,		/* ZapDingbats */
		"STAR4","PSZD",98,0.0,0.0,1.0,		/* ZapDingbats */
		"FLOWER","PSZD",96,0.0,0.0,1.0,		/* ZapDingbats */
		NULL,NULL,0,0,0,0
};	/* change range check below when adding markers */



char *mark_name[30];
char *mrk_fname[61];
char *mrk_name[61];
char *mark_sub[30];
int mark_subp[30];
int nmark;
int nmrk;
int std_nmrk;
void mark_clear(void)
{
	int i,fg;
	struct mark_struct *p;
	if (std_nmrk==0) {
		for (i=0; stdmark[i].name !=NULL; i++) {
			p = &stdmark[i];
			fg = false;
			if (p->rx==0) fg = true;
			g_defmarker(p->name,p->font,p->cc,p->rx,p->ry
				,p->scl,fg);
		}
		std_nmrk = nmrk;
	}
	for (i=0; i<nmark; i++) {
	  if (mark_sub[i]!=NULL) { myfree(mark_sub[i]); mark_sub[i]=NULL;}
	  if (mark_name[i]!=NULL) { myfree(mark_name[i]); mark_name[i]=NULL;}
	}
	for (i=std_nmrk; i<nmrk; i++) {
	  if (mrk_name[i]!=NULL) { myfree(mrk_name[i]); mrk_name[i]=NULL;}
	  if (mrk_fname[i]!=NULL) { myfree(mrk_fname[i]); mrk_fname[i]=NULL;}
	}
	nmrk = std_nmrk;
	nmark = 0;
}
get_marker(TOKENS tk,int *ntok,int *curtok,int32 *pcode,int *plen)
{
	int i,etype=1;
	char vv[80];
	if (*tok(*curtok)=='(' || isdigit(*tok(*curtok))) {
		strcpy(vv,"cvtint(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else	if (strchr(tok(*curtok),'$') != NULL) {
		strcpy(vv,"cvtmarker(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
	} else {
		*(pcode+(*plen)++) = 8;
		*(pcode+(*plen)++) = pass_marker(tok(*curtok));
	}
	(*curtok)++;
}
pass_marker(char *s)
{
	int i;
	int32 f=0;
	/* if 0, maybe its a user defined marker, ie a subroutine */
	/* Use -ve to signify subroutine instead of normal marker */
	for (i=0; i<nmark; i++) {
		if (strcmp(mark_name[i],s)==0) {
			f = -(++i);
			break;
		}
	}
	if (f==0)  {
		for (i=nmrk-1; i>=0; i--) {
			if (strcmp(mrk_name[i],s)==0) {
				f = ++i;
				break;
			}
		}
	}
	if (f==0) gprint("Invalid marker name {%s} \n",s);
	return f;
}


spop(int v)
{
}
spush(int v)
{
}
scheck(int v)
{
}

char *mixed_case(char *s)
{
	if (*s == '"') {
		s[strlen(s)-1] = 0;
		return s+1;
	}
	return strlwr(s);
}



