#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#ifndef unix
#include <stdarg.h>
#endif
#include "glepro.h"
#define false 0
#define true (!false)
#include "mygraph.h"
#include <math.h>
double emtof(char *s);
int font_reset_parskip(void);
int set_parskip(double v);
int set_lineskip(double v);
int ncat(char *a,char *b,int n);
int pp_fntchar(int f, int c,int32 *out, int *lout);
int polish_eval(char *s, double *x);
int cmd_token(uchar **in,char *cmdstr);
int set_base_size(void);
int find_primcmd(char *cmd);
int text_box(uchar *s,double width,int32 *tbuff, int32 *rplen);
int cmd_param(uchar **inp,uchar *pm[],int pmlen[],int npm);
int text_tomacro(uchar *in, uchar *out);
int texint(char *s, int *i);
int tex_presave(void);
int tex_preload(void);
int fsendstr(char *s, FILE *fout);
int text_gprint(int32 *in,int ilen);
int fftext_block(uchar *s,double width,int justify);
void font_load(void);
int tex_init(void);
int g_get_font(int *i);
int do_prim(uchar **in,int32 *out,int *lout);  /*  \frac{text}{text} */
#define dbg if ((gle_debug & 1024)>0)
extern int gle_debug;
double text_endx,text_endy;
/*----------------------------------------------------------------------*/
/*              TeX Emulation routines                                  */
/*----------------------------------------------------------------------*/
#define FONTDEF extern
#include "font.h"
#include "tex.h"
double linegap;
/*----------------------------------------------------------------------*/
struct def_table_struct {
	struct def_table_struct *next;
	char *name;
	char *defn;
	int npm;
};
typedef struct def_table_struct deftable;

/*----------------------------------------------------------------------*/
int tex_def(char *name, char *defn,int npm);
int tex_mathdef(char *name, int defn);
int *tex_findmathdef(char *s);
int tex_chardef(int c, char *defn);
char *tex_findchardef(int c);
deftable *tex_finddef(char *s) ;
/*----------------------------------------------------------------------*/
/*              Global variables for TEX emulation */

int fontfam[16][4];
double fontfamsz[16][4];        /* 1=text,  2=script, 3=scriptscript */
int famdef = -1;        /* dont use unless/until it is defined */

char *cdeftable[256];   /* Character macro's */
uchar chr_code[256];    /* Character codes 1..9  */
int chr_mathcode[256];  /* Character codes 1..9  */
int chr_val[256];       /* Character values, or macro numbers */
int chr_init;           /* Flag to initialize chr variables */

#define dp if (dont_print==false)
int dont_print=0;
int32 gt_pbuff[5000];
int gt_plen;
double gt_l,gt_r,gt_u,gt_d;

int tofont[9] = {0,2,2,1,1,0,0,0,0};

int p_fnt;
double p_hei;
double grphei[10];
int grpfnt[10];
int p_ngrp;

double base_size;
int curstyle=6;

double stretch_factor=1;
/*----------------------------------------------------------------------*/

union both {float f;int32 l;} bth;
#define outlong(v) *(out+((*lout)++)) = v
#define outfloat(v) bth.f = v; *(out+((*lout)++)) = bth.l
#define chrwidth(d) ((*(fnt[p_fnt].chr))[d].wx)
#define tofloat(fff) ((bth.l = fff),bth.f )
#define tolong(fff) ((bth.f = fff),bth.l )
#define checkfont if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt)

int set_stretch(double v);
set_stretch(double v)
{
	stretch_factor = v;
}
set_base_size()
{
	g_get_hei(&base_size);
}
text_topcode(uchar *in, int32 *out, int *lout)      /*  passed a paragraph  */
{
	int skip_space;
	float w;
	uchar c,d,c2,d2;

	outlong(8);     /* set font size */
	outfloat(p_hei);


	while (c = *(in++)) {
  dbg /* if (chr_code[c]>2) */ gprint("uchar %d, code %d  value %d \n",c,chr_code[c],chr_val[c]);
	  switch (chr_code[c]) {
	    case 10:
	    case 1: /* Normal character */
		d = chr_val[c];
		/* if next char is normal, then check for ligature and kern */
norm_again:
		w=0;
		checkfont;
		if (chr_code[*in]==1 || chr_code[*in]==10) {
			if (char_lig(p_fnt,&d,chr_val[*in])) {
				in++;
				goto norm_again;
			}
			char_kern(p_fnt,d,chr_val[*in],&w);
		}
		outlong(1);
		outlong(d | p_fnt*256);
		dbg gprint("==char width %d %f %f \n",d,chrwidth(d),w);
		if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt);              outfloat((chrwidth(d)+w)*p_hei);
		skip_space = false;
		break;
	    case 2: /* Single space */
		if (skip_space) break;
		skip_space = true;
		outlong(2);
		checkfont;
		outfloat(fnt[p_fnt].space*p_hei);
		outfloat(fnt[p_fnt].space_stretch*p_hei*10*stretch_factor);
		outfloat(fnt[p_fnt].space_shrink*p_hei*10);
		break;
	    case 3: /* Tab (for tabular) */
		break;
	    case 4: /* 8Tab (verbatim) */
		break;
	    case 5: /* \\ End of line */
		skip_space = false;
		outlong(5);
		outlong(0);             /* space for x,y to be put */
		outlong(0);
		break;
	    case 6: /* \ Primitive Command (macro's already done) */
		skip_space = false;
		do_prim(&in,out,lout);
		break;
	    case 7: /* { begin group */
		skip_space = false;
		grphei[++p_ngrp] = p_hei;
		grpfnt[p_ngrp] = p_fnt;
		break;
	    case 8: /* } end group */
		skip_space = false;
		if (p_ngrp<1) {
			gprint("%s\n",in);
			gprint("Too many end group brackets \n");
			return;
		}
		p_hei = grphei[p_ngrp];
		p_fnt = grpfnt[p_ngrp--];
		font_load_metric(p_fnt);

		outlong(8); outfloat(p_hei);
		break;
	    case 9: /* $^_ Macro (Done in macro expansion) */
		skip_space = false;
		break;
	    case 11: /* flag for end of paragraph */
			skip_space = false;
		outlong(10);
		outlong(0);     /* space for x,y to be put */
		outlong(0);
		break;
	    default:
		gprint("error, not valid character \n");
	  }
	}
}
/* cmd_param(uchar **inp,char *(*pm)[],int (*pmlen)[],int npm) */
int cmd_param(uchar **inp,uchar *pm[],int pmlen[],int npm)
{
	int gcnt=0,i;
	uchar *in = *inp;
	gcnt = 0;
	for (i=0;i<npm;i++) {
	 pm[i] = in;
	 pmlen[i] = 0;
	  if (chr_code[*in]==7) { /* begin group */
		pm[i] = ++in;
		for (;*in!=0;in++) {
			if (chr_code[*in]==7) gcnt++;
			if (chr_code[*in]==8) {
				if (gcnt==0) break;
				gcnt--;
			}
		}
		pmlen[i] = in - pm[i];
		in++;
	  } else {
		if (chr_code[*in]==6) { /* backslash look for non-alpha */
			pm[i] = ++in;
			if (isalpha(*pm[i])) {
				for (;*in!=0;in++) {
					if (!isalpha(*in)) {
						break;
					}
				}
				pmlen[i] = in - pm[i];
			} else {
				pm[i] = in;
				pmlen[i] = 1;
				in++;
			}
		} else {
			pm[i] = in;
			pmlen[i] = 1;
			in++;
		}
	  }
	}
	*inp = in;
}
text_box(uchar *s,double width,int32 *tbuff, int32 *rplen)
{
	uchar *t,*r,*m,*p;
	int i;
	int plen=0;
	char *workbuff;

	workbuff = myalloc(1000);
	if (s==NULL) return;
	if (*s==0) return;
	if (chr_init==false) tex_init();
	text_tomacro(s,UC workbuff);
	plen = 0;
	if (width==0) width = 400;
	text_topcode(UC workbuff,tbuff,&plen);
	text_wrapcode(tbuff,plen,width);
	*rplen = plen;
	myfree(workbuff);
}
topcode(char *s, int slen, double width, int32 **pbuff, int32 *plen, double *l,double *r,double *u,double *d)
{
	char schar;

	*pbuff = myalloc(1000);
	g_init_bounds();
	schar = s[slen];
	s[slen] = 0;
	text_box(UC s,width,*pbuff,plen);
	s[slen] = schar;
	g_get_bounds(l,d,r,u);
	if (*l > *r) {*l=0; *r=0; *u=0; *d=0;}

}

#define p_sethei(hh) pp_sethei(hh,out,lout)
#define p_hfill(hh) pp_hfill(hh,out,lout)
#define p_move(x,y) pp_move(x,y,out,lout)
#define p_fntchar(ff,cc) pp_fntchar(ff,cc,out,lout)
#define p_mathchar(m) pp_mathchar(m,out,lout)
#define p_pcode(pbuff,plen) pp_pcode(pbuff,plen,out,lout)

pp_move(double x, double y, int32 *out,int *lout)
{
	outlong(4);
	outfloat(x);
	outfloat(y);
}
pp_sethei(double h, int32 *out,int *lout)
{
	outlong(8);
	outfloat(h);
	p_hei = h;
}
pp_hfill(double h, int32 *out,int *lout)
{
	outlong(2);
	outfloat(0.0);
	outfloat(h*p_hei);
	outfloat(h*p_hei);
}
int char_bbox_user(int p_fnt,int ix, double *x1,double *y1,double *x2,double *y2);
char_bbox_user(int p_fnt,int ix, double *x1,double *y1,double *x2,double *y2)
{
	char_bbox(p_fnt,ix,x1,y1,x2,y2);
	*x1 *= p_hei;
	*x2 *= p_hei;
	*y1 *= p_hei;
	*y2 *= p_hei;
}
pp_mathchar(int m, int32 *out, int *lout)
{
	int mchar,mfam,mtyp;
	int ix;
	double x1,y1,x2,y2,reqhi,yc;
	double oldhei;
	oldhei = p_hei;
	mchar = m & 0xff;
	mfam = (m & 0xf00) / 0x100;
	mtyp = (m & 0xf000) / 0x1000;
	if (mtyp == 7  && famdef>=0) mfam = famdef;
	if (mtyp == 7) mtyp = 0;
	ix = 'b'; /* center on letter b */
	char_bbox_user(p_fnt,ix,&x1,&y1,&x2,&y2);
	reqhi = y2/2;
	p_sethei(fontfamsz[mfam][tofont[curstyle]] * p_hei);
	char_bbox_user(fontfam[mfam][tofont[curstyle]],mchar,&x1,&y1,&x2,&y2);
	yc = (y2-y1)/2;
	if (mtyp==1) pp_move(0,reqhi+yc-y2,out,lout);
	p_fntchar(fontfam[mfam][tofont[curstyle]],mchar);
	if (mtyp==1) pp_move(0,-(reqhi+yc-y2),out,lout);
	p_sethei(oldhei);
}
#define mchrwidth(ddd) ((*(fnt[ff].chr))[ddd].wx)
pp_fntchar(int ff, int ch, int32 *out,int *lout)
{
	if (fnt[ff].chr==NULL) font_load_metric(ff);
	outlong(1);
	if (ch==0) ch = 254;
	outlong(ch | ff*256);
	outfloat((mchrwidth(ch))*p_hei);
}
pp_pcode(int32 *pbuff, int plen, int32 *out,int *lout)
{
	int i;
	out += *lout;
	for (i=0;i<plen;i++) *out++ = *pbuff++;
	*lout = *lout + plen;
}
cmd_param1(uchar **in,char *str1)
{
	union {char *s[4]; uchar *u[4];} pm;
	int pmlen[4];
	cmd_param(in,pm.u,pmlen,1);
	ncpy(str1,pm.s[0],pmlen[0]);
}
cmd_param2(uchar **in,char *str1,char *str2)
{
	union {char *s[4]; uchar *u[4];} pm;
	int pmlen[4];
	cmd_param(in,pm.u,pmlen,(int) 2);
	ncpy(str1,pm.s[0],pmlen[0]);
	ncpy(str2,pm.s[1],pmlen[1]);
}
cmd_param3(uchar **in,char *str1,char *str2,char *str3)
{
	union {char *s[5]; uchar *u[5];} pm;
	int pmlen[5];
	cmd_param(in,pm.u,pmlen,3);
	ncpy(str1,pm.s[0],pmlen[0]);
	ncpy(str2,pm.s[1],pmlen[1]);
	ncpy(str3,pm.s[2],pmlen[2]);
}

do_prim(uchar **in,int32 *out,int *lout)  /*  \frac{text}{text} */
{
	int ci;
	int ix,savefnt,newfnt;
	static char cmdstr[20];
	char str1[100],str2[100],str3[100];
	double lef,wid,hei,dep,savehei,x;
	int32 *pbuff=0;
	int32 plen;
	union {char *s[10]; uchar *u[10];} pm;
	int pmlen[10];
	int *m,i,k,j,n,npm;

	k = 0;

	cmd_token(in,cmdstr);   /* finds command name and parameters */
	ci = find_primcmd(cmdstr);
	if (ci==0) { /* then maybe its a mathchar */
		m = tex_findmathdef(cmdstr);
		if (m!=0) {
			p_mathchar(*m);
		} else {
			gprint("Unrecognised control sequence {%s} \n",cmdstr);
		}
		return;
	}
	switch (ci) {
	  case tp_sup: /* \superscript{exp} */
		cmd_param(in,pm.u,pmlen,1);
		savehei = p_hei;
		p_hei = p_hei * .7;
		topcode(pm.s[0],pmlen[0],0.0,&pbuff,&plen,&lef,&wid,&hei,&dep);
		p_move(0,0.8*p_hei);
		p_pcode(pbuff,plen);
		p_move(0,-0.8*p_hei);
		myfree(pbuff);
		p_sethei(savehei);
		break;
	  case tp_sub:
		cmd_param(in,pm.u,pmlen,1);
		savehei = p_hei;
		p_hei = p_hei * .7;
		topcode(pm.s[0],pmlen[0],0.0,&pbuff,&plen,&lef,&wid,&hei,&dep);
		p_move(0,-0.3*p_hei);
		p_pcode(pbuff,plen);
		p_move(0,0.3*p_hei);
		myfree(pbuff);
		p_sethei(savehei);
		break;
	  case tp_sethei: /* \sethei{exp} */
		cmd_param1(in,str1);
		p_sethei(emtof(str1));
		break;
	  case tp_hfill: /* \sethei{exp} */
		p_hfill(10.0);
		break;
	  case tp_char:
		cmd_param1(in,str1);
		texint(str1,&ix);
		p_fntchar(p_fnt,ix);
		break;
	  case tp_chardef:  /* /chardef{a}{xxxxx} */
		cmd_param2(in,str1,str2);
		tex_chardef(str1[0],str2);
		break;
	  case tp_ssfont:
		k++;
	  case tp_sfont:
		k++;
	  case tp_tfont:  /* \tfont{0}{cmr10}{.5}  */
		cmd_param3(in,str1,str2,str3);
		i = atoi(str1);  if (i>15) i = 1;
		fontfam[i][k] = pass_font(str2);
		fontfamsz[i][k] = emtof(str3);
		break;
	  case tp_accent:  /* accent{texcmr}{123}{a} */
	    {
		double wid2,hei2,lef2,dep2,ww,hh,h=0,cwid,cwid2;
		int ix2;

		cmd_param3(in,str1,str2,str3);
		savefnt = p_fnt;
		newfnt = pass_font(str1);
		texint(str2,&ix);
		ix2 = str3[0];
		char_bbox(newfnt,ix,&lef,&dep,&wid,&hei);
		cwid = p_hei * ((*(fnt[newfnt].chr))[ix].wx);
		char_bbox(p_fnt,ix2,&lef2,&dep2,&wid2,&hei2);
		cwid2 = p_hei * ((*(fnt[p_fnt].chr))[ix2].wx);

		wid *= p_hei;  wid2 *= p_hei; hei *= p_hei; hei2 *= p_hei;
		lef *= p_hei;  dep *= p_hei;
		lef2 *= p_hei;  dep2 *= p_hei;
		if (hei2>p_hei*(3.6/8.0)) h = hei2-p_hei*(3.6/8.0);

		ww = lef2+wid2;
		p_fntchar(p_fnt,ix2);
		p_move(-cwid2 + lef2 + wid2/2 -wid/2,h);  /* cwid2/2 - cwid/2 */
		p_fntchar(newfnt,ix);        /* cwid2/2 + cwid/2 */
		p_move(-cwid + cwid2 - lef2 - wid2/2 + wid/2,-h);
		p_fnt = savefnt;
		font_load_metric(p_fnt);
		break;
	    }
	  case tp_def:
		cmd_param1(in,str1); /* finds everything up to the #1#2 */
		npm = 0;
		while (**in == '#') {
			(*in)++;
			n = (*(*in)++) - '0';
			if (n>0 && n<9) if (npm<n) npm=n;
		}
		cmd_param1(in,str2);
		tex_def(str1,str2,npm);
		break;
	  case tp_mathchardef:  /* /mathchardef */
		cmd_param2(in,str1,str2);
		texint(str2,&ix);
		tex_mathdef(str1+1,ix);
		break;
	  case tp_movexy:
		cmd_param2(in,str1,str2);
		p_move(emtof(str1),emtof(str2));
		break;
	  case tp_rule:
		cmd_param2(in,str1,str2);
		outlong(6);
		outfloat(emtof(str1));
		outfloat(emtof(str2));
		break;
	  case tp_mathchar:
		cmd_param1(in,str1);
		texint(str1,&ix);
		p_mathchar(ix);
		break;
	  case tp_mathcode:
		cmd_param2(in,str1,str2);
		texint(str2,&ix);
		chr_mathcode[*str1] = ix;
		break;
	  case tp_delcode:
		cmd_param2(in,str1,str2);
		texint(str2,&ix);
		chr_mathcode[*str1] = ix;
		break;
	  case tp_setfont:
		cmd_param1(in,str1);
		p_fnt = pass_font(str1);
		font_load_metric(p_fnt);

		if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt);
		break;
	  case tp_presave:
		gprint("Saving definitions\n");
		tex_presave();
		break;
	  case tp_newline:
		outlong(5);
		outlong(0);             /* space for x,y to be put */
		outlong(0);
		break;
	  case tp_parskip:
		cmd_param1(in,str1);
		set_parskip(emtof(str1));
		break;
	  case tp_setstretch:
		cmd_param1(in,str1);
		set_stretch(emtof(str1));
		break;
	  case tp_lineskip:
		cmd_param1(in,str1);
		set_lineskip(emtof(str1));
		break;
	  case tp_linegap:
		cmd_param1(in,str1);
		linegap = emtof(str1);
		break;
	  case tp_frac:
	  case tp_delimiter:
	  case tp_left:
	  case tp_right:
	  case tp_defbegin:
	  case tp_nolimits:

	  case tp_overbrace:
	  case tp_overline:
	  case tp_underbrace:
	  case tp_underline:
	    gprint("A valid GLE-TEX primitive which isn't implemented yet %d \n",ci);
		break;
	  default:
	    gprint("An invalid GLE-TEX primitive %d \n",ci);
	    break;
	}
}
#ifndef DJ
double emtof(char *s)
{       /* same as ATOF but if it sees EM then it multiplies by FONT HEI */
	if (strstr(s,"sp")!=NULL) {
		return atof(s)*fnt[p_fnt].space*p_hei;
	}
	if (strstr(s,"em")!=NULL) {
		return atof(s)*p_hei*.75;
	}
	return atof(s);
}
#else
double emtof(char *s)
{       /* same as ATOF but if it sees EM then it multiplies by FONT HEI */
	/* GLE32 doesn't interpret "-1em" but "-1 em"  a.r. */
	char *ss;       /* is it allowed to overwrite s? */
	double ret;

	ss = (char *) malloc((strlen(s)+1)*sizeof(char));
	strcpy(ss,s);
	if (strstr(ss,"sp")!=NULL) {
		*strstr(ss,"sp") = '\0';
		ret = atof(ss)*fnt[p_fnt].space*p_hei;
		free(ss);
		return ret;
	}
	if (strstr(ss,"em")!=NULL) {
		*strstr(ss,"em") = '\0';
		ret = atof(ss)*p_hei*.75;
		free(ss);
		return ret;
	}
	ret = atof(ss);
	free(ss);
	return ret;
}
#endif

texint(char *s, int *i) /* Reads an integer, or hex string (if $) */
{
	int32 j;
	if (*s=='$') {
		sscanf(s+1,"%lx",&j);
		*i = j;
	} else *i = atoi(s);
}
/*
	Character Codes

	a..z            1       normal character
	space           2       single space
	<TAB>,&         3       Tab (as in tabular)
	<8TAB>          4       TAB (as in verbatim)
	<LF>,\\         5       End of line
	\               6       Macro or command
	{               7       Begin group
	}               8       end group
	$_^             9       Macro call
			10      null
	255             11      end of paragraph (crcr)
	end of command, = first non alpha character
*/




/*      Bounding Box ??

	1=char  font+char,x
	2=move  x,stret,shrink                  throw away after cr
	3=MOVE  x,0,0                           glue which has been set
	4=MOVE  x,y                             solid move
	5=newline,x,y
	6=rule  x,y
	10=color color
	8=fontsz   fontsz
	9=font   i
	15=null
*/
#define infloat(fff) ((bth.l = fff),bth.f)


text_wrapcode(int32 *in,int ilen,double width)
{
	double cx=0,cy=0,p_hei,ax=0,x,y,cdep=0,chei=0;
	int i,j,eat_glue,c,p_fnt,si,skline,saveii;
	double totstretch=0,totshrink=0,ls=0,gap=0
		,last_y,last_x,lastdep,last_stret,last_shrink;
	int32 *pcr=0,last_space=0;
	double setlen;
	dbg text_gprint(in,ilen);
	ls = 0;
	last_x = 0;
	gap = 0;
	last_y = 0;
	lastdep = 0;
	last_stret = 0;
	last_shrink = 0;
	dbg gprint("==wrap pcode, ilen = %d \n",ilen);

	dbg gprint("wrap pcode ilen=%d \n",ilen);
	p_hei = 1;
	si = 0;
	for (i=0;i<ilen;i++) {
	  switch (*(in+i)) {
	    case 1: /* char     font+char,wx    */
		eat_glue = false;
		p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
		font_load_metric(p_fnt);

		c = *(in+i) & 0x00ff;
		if (cdep>cy+p_hei*((*(fnt[p_fnt].chr))[c].y1))
			cdep=cy+p_hei*((*(fnt[p_fnt].chr))[c].y1);
		if (chei<cy+p_hei*((*(fnt[p_fnt].chr))[c].y2))
			chei=cy+p_hei*((*(fnt[p_fnt].chr))[c].y2);
/*              gprint("chei=%f, cdep=%f \n",chei,cdep);   */

		cx += tofloat(*(in+ ++i));
		ax = cx;
		if (cx>width) {
		  if (last_space>si) {
			dbg gprint("Call SET_GLUE  from %d, to %d \n",si,last_space);
			set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
			i = last_space;
			*(in+i++) = 4;
			*(in+i++) = tolong(-setlen);
			if (pcr!=NULL) { /* put in last line feed now */
				y = last_y-ls;
				if ((y+chei+gap)>lastdep)
					y = lastdep-chei-gap;
				cy = y;
				*pcr = tolong(y);
			}
			font_get_lineskip(&ls,&gap);
			pcr = (in+i++);   /* place to put line feed */
			*(in+i) = 20;           /* null */
			last_stret = 0;
			last_shrink = 0;
			totstretch = 0;
			totshrink = 0;
			lastdep = cdep;
			last_y = cy;
			cx = 0;
			cy = 0;
			si = i;
			eat_glue = true;
		  }
		}
		break;
	    case 2: /* move     x,stretch,shrink */
		last_space = i;
		last_x = ax;
		last_y = cy;
		last_stret = totstretch;
		last_shrink = totshrink;
		if (eat_glue) {*(in+i)=3; *(in+ ++i)=tolong(0);i+=2;break;}
		cx += tofloat(*(in+ ++i));
		totstretch += tofloat(*(in+ ++i));
		totshrink += tofloat(*(in+ ++i));
		dbg gprint("total stretch %f, shrink %f \n",totstretch,totshrink);
		break;
	    case 3: /* move     x,0,0   SOLID   */
		cx += tofloat(*(in+ ++i));
		i += 2;
		ax = cx;
		eat_glue = false;
		break;
	    case 4: /* move     x,y     SOLID   */
		eat_glue = false;
		cx += tofloat(*(in+ ++i));
		cy += tofloat(*(in+ ++i));
		ax = cx;
		break;
	    case 5: /* Newline  x,y     (0,0 at moment) */
	    case 10:
		if (*(in+i)==5) skline = true; else skline = false;
		*(in+i) = 0;
/*              last_space = i;
		last_x = ax;
		last_y = cy;
		last_stret = totstretch;
		last_shrink = totshrink;
*/
		  if (last_space<=si || ax==cx) {
			last_x = ax;
			last_y = cy;
			last_stret = totstretch;
			last_shrink = totshrink;
			last_space = i;
		  }
			dbg gprint("Call SET_GLUE  from %d, to %d \n",si,last_space);
			set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
			saveii = i;
			i = last_space;
			while (i < saveii) *(in+i++) = 20; /* nop */
			*(in+i++) = 4;
			*(in+i++) = tolong(-setlen);
			if (pcr!=NULL) { /* put in last line feed now */
				y = last_y-ls;
				if ((y+chei+gap)>lastdep)
					y = lastdep-chei-gap;
				cy = y;
				*pcr = tolong(y);
			}
			if (skline)
				font_get_lineskip(&ls,&gap);
			else    font_get_parskip(&ls,&gap);
			pcr = (in+i);   /* place to put line feed */
			last_stret = 0;
			last_shrink = 0;
			totstretch = 0;
			totshrink = 0;
			lastdep = cdep;
			last_y = cy;
			cx = 0;
			cy = 0;
			si = i+1;
			eat_glue = true;
			break;
/*              eat_glue = true;
		i += 2;
		break; */
	    case 6: /* rule     x,y             */
		i += 2;
		eat_glue = false;
		break;
	    case 7: /* color    color           */
		g_set_color(tofloat(*(in+ ++i)));
		break;
	    case 8: /* fontsz   sz              */
		p_hei = tofloat(*(in+ ++i));
		g_set_hei(p_hei);
		break;
	    case 9: /* font     p_fnt   */
		p_fnt = *(in+ ++i);
		font_load_metric(p_fnt);

		break;
	    case 20: /*  nop  */
		break;
	    default:
		gprint("dud pcode in wrap pcode %d   i=%d \n",*(in+i),i);
		break;
	  }
	}

	if (last_space==0) last_space = ilen;
	dbg gprint("Exiting call to SET_GLUE  from %d, to %d \n",si,last_space);
	set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
	if (pcr!=NULL) { /* put in last line feed now */
		y = last_y-ls;
		if ((y+chei+gap)>lastdep)
			y = lastdep-chei-gap;
		cy = y;
		*pcr = tolong(y);
	}
	dbg text_gprint(in,ilen);
}
set_glue(int32 *in,int ilen,double actual,double width,double stretch,double
	shrink,double *setlen)
{
	double mst=0,msh=0;
	float s1,s2,x,y;
	int i=0;

	dbg gprint("===set glue \n");
	dbg text_gprint(in,ilen);
	dbg gprint("set glue ilen=%d actual=%f, width=%f, stretch=%f shrink=%f \n"
			,ilen,actual,width,stretch,shrink);
/*      if (actual<0) get_natural(in,ilen,&actual); */
	if (actual<width) {
		if (stretch>0.0000001) mst = (width-actual)/stretch;
		msh = 0;
		if (mst>1) mst=0;
	} else {
		mst = 0;
		if (shrink>0) msh = (actual-width)/shrink;
		if (msh>1) msh=0;
	}
	*setlen = actual+stretch*mst+shrink*msh;
	dbg gprint("SETTing glue to  %f  %f  actual %f, setto %f\n",mst,msh,actual,*setlen);

	for (i=0;i<ilen;i++) {
	  switch (*(in+i)) {
	    case 1: /* char     font+char,wx    */
		i += 2;
		break;
	    case 2: /* move     x,stretch,shrink */
		x = tofloat(*(in+i+1));
		s1 = tofloat(*(in+i+2));
		s2 = tofloat(*(in+i+3));
		*(in+i) = 3;
		*(in+i+1) = tolong(x + s1*mst+s2*msh);
		i += 3;
		break;
	    case 3: /* move     x,0,0   SOLID   */
		i += 3;
		break;
	    case 4: /* move     x,y     SOLID   */
		i += 2;
		break;
	    case 5: /* Newline  x,y     (0,0 at moment) */
		i += 2;
		break;
	    case 6: /* rule     x,y             */
		i += 2;
		break;
	    case 7: /* color    color           */
		i += 1;
		break;
	    case 8: /* fontsz   sz              */
		i += 1;
		break;
	    case 9: /* font     p_fnt   */
		i += 1;
		break;
	    case 10: /* Newparagraph x,y        (0,0 at moment) */
		i += 2;
		break;
	    case 20: /*  nop  */
		break;
	    default:
		gprint("dud (in set glue) pcode in text pcode %d i=%d\n",*(in+i),i);
		break;
	  }
	}
	dbg printf("=== Result after setting \n");
	dbg text_gprint(in,ilen);
	dbg printf("===+++++ END OF SET GLUE  =============== \n");
}

text_draw(int32 *in,int ilen)
{
	double cx,cy,p_hei,x,y;
	int i,c,p_fnt;

	dbg gprint("---TEXT DRAW, ilen = %d \n",ilen);
	dbg text_gprint(in,ilen);
	cx = 0;
	cy = 0;
	dp g_get_xy(&cx,&cy);
	dbg printf("Current x y, %g %g \n",cx,cy);
	p_hei = 1;

	for (i=0;i<ilen;i++) {
	  switch (*(in+i)) {
	    case 1: /* char     font+char,wx    */
		p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
		font_load_metric(p_fnt);

		c = *(in+i) & 0x00ff;
		g_set_bounds(cx+p_hei*((*(fnt[p_fnt].chr))[c].x1),cy+p_hei*((*(fnt[p_fnt].chr))[c].y1));
		g_set_bounds(cx+p_hei*((*(fnt[p_fnt].chr))[c].x2),cy+p_hei*((*(fnt[p_fnt].chr))[c].y2));
		dp {
			g_move(cx,cy);
			g_char(p_fnt,c);
		}
		cx += tofloat(*(in+ ++i));
		break;
	    case 2: /* move     x,stretch,shrink */
		cx += tofloat(*(in+ ++i));
		i += 2;         /* glue is already set */
		break;
	    case 3: /* move     x,0,0   SOLID   */
		cx += tofloat(*(in+ ++i));
		i += 2;
		break;
	    case 4: /* move     x,y     SOLID   */
		cx += tofloat(*(in+ ++i));
		cy += tofloat(*(in+ ++i));
		break;
	    case 5: /* Newline  x,y     (turned into a move) */
		i += 2;
		break;
	    case 6: /* rule     x,y             */
		x = tofloat(*(in+ ++i));
		y = tofloat(*(in+ ++i));
		g_set_bounds(cx,cy);
		g_set_bounds(cx+x,cy+y);
		if (x>0) g_box_fill(cx,cy,cx+x,cy+y);
		break;
	    case 7: /* color    color           */
/*              dp g_set_color(tofloat(*(in+ ++i)));*/
		break;
	    case 8: /* fontsz   sz              */
		p_hei = tofloat(*(in+ ++i));
		g_set_hei(p_hei);
		break;
	    case 9: /* font     p_fnt   */
		p_fnt = *(in+ ++i);
		font_load_metric(p_fnt);

		break;
	    case 10: /* Newline  x,y    (turned into a move) */
		i += 2;
		break;
	    case 20: /*  nop  */
		break;
	    case 0:
		dbg gprint("zero");
		break;
	    default:
		gprint("dud3 pcode in text pcode %d %d \n",*(in+i),i);
		break;
	  }
	}
	text_endx = cx;
	text_endy = cy;
	dbg gprint("---TEXT DRAW, DONE. %g %g \n",cx,cy);
}
double tex_xend(void)
{
	return text_endx;
}
double tex_yend(void)
{
	return text_endy;
}
text_gprint(int32 *in,int ilen)
{
	double cx,cy,p_hei,x,y;
	int i,c,p_fnt,z;

	for (i=0;i<ilen;i++) printf("%lx ",*(in+i));
	printf("\n");
	z=0;
	printf("# ");
	for (i=0;i<ilen;i++) {
	  switch (*(in+i)) {
	    case 1: /* char     font+char,wx    */
		p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
		font_load_metric(p_fnt);

		c = *(in+i) & 0x00ff;
		x = tofloat(*(in+ ++i));
		printf("%c[%3.3h]",c,x);
	/*      printf("%c{%d %3.3f} ",c,p_fnt,tofloat(*(in+ ++i)));  */
		break;
	    case 2: /* move     x,stretch,shrink */
		printf("[sp %3.3f %3.3f %3.3f] \n# ",tofloat(*(in+1+i))
				,tofloat(*(in+2+i)),tofloat(*(in+3+i)));
		i += 3;
		break;
	    case 3: /* move     x,0,0   SOLID   */
		printf("(3 %3.3f %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
				,tofloat(*(in+2+i)),tofloat(*(in+3+i)));
		i += 3;
		break;
	    case 4: /* move     x,y     SOLID   */
		printf("(4 %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
				,tofloat(*(in+2+i)));
		i += 2;
		break;
	    case 5: /* Newline  x,y     (turned into a move) */
		i += 2;
		printf("5 \n# ");
		break;
	    case 6: /* rule     x,y             */
		printf("(rule %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
				,tofloat(*(in+2+i)));
		i += 2;
		break;
	    case 7: /* color    color           */
		printf("(color %x) \n# ",(*(in+ ++i)));
		break;
	    case 8: /* fontsz   sz              */
		printf("(p_hei %3.3f) \n# ",tofloat(*(in+ ++i)));
		break;
	    case 9: /* font     p_fnt   */
		printf("(font %d) \n",(*(in+ ++i)));
		break;
	    case 10: /* Newline  x,y    (turned into a move) */
		i += 2;
		printf("\n10(paragraph)\n# ");
		break;
	    case 20: /*  nop  */
		printf("NOP ");
		break;
	    default:
		printf("(err=%4x pos=%d)\n ",*(in+i),i);
		break;
	  }
	}
	printf("\n");
}
double lineskip1,parskip1;
font_reset_parskip()
{
	lineskip1 = 1.0;
	parskip1 = 2.5;
}
set_parskip(double v)
{
	parskip1 = v;
}
set_lineskip(double v)
{
	lineskip1 = v;
}
font_get_lineskip(double *ls,double *gap)
{
	*ls = p_hei * lineskip1;
	*gap = *ls * .1 + linegap;
}
font_get_parskip(double *ls,double *gap)
{
	*ls = p_hei * parskip1;
	*gap = *ls * .1;
}

int pass_font(char *p)
{
	int i,f=0,etype=1;
	int32 j;
	char u[90];
	char vv[80],*s;
	double xx;

	s = &u[0];
	strncpy(u,p,90);
	strupr(u);
	if ( (*s=='"')  || (strchr(s,'$') != NULL)) {
		strcpy(vv,"cvtfont(");
		strcat(vv,s); strcat(vv,")");
		polish_eval(vv,&xx);
		memcpy(&j,&xx,sizeof(int32));
		return j;  /* actyally is an int */
	} else {
		if (nfnt==0) font_load();
		for (i=1; i<=nfnt; i++) {
			if (fnt[i].name!=NULL) if (strcmp(fnt[i].name,u)==0) {
			  return i;
			}
		}
		gprint("Invalid font name {%s}, NFNT %d expecting one of: \n    ",u,nfnt);
		for (i=1;i<=nfnt; i++) {
			if (fnt[i].name!=NULL)
				gprint("  {%s} ",fnt[i++].name);
			if (fnt[i].name!=NULL)
				gprint("  {%s} ",fnt[i++].name);
			if (fnt[i].name!=NULL)
				gprint("  {%s} ",fnt[i++].name);
			if (fnt[i].name!=NULL)
				gprint("  {%s} \n",fnt[i].name);
		}
		return 1;       /* default font number */
	}
}
#define get_exps(ss) polish(ss,(char *) pcode,plen,&etype)
#define tok(n)  (*tk)[n]
get_font(char (*(*tk)[500]),int *ntok,int *curtok,int32 *pcode,int *plen)
{
	int i,f=0,etype=1;
	char vv[80];
	char *p;
	if (nfnt==0) font_load();

	if ( (*tok(*curtok)=='"') ||  (strchr(tok(*curtok),'$') != NULL) ) {
		strcpy(vv,"cvtfont(");
		strcat(vv,tok(*curtok)); strcat(vv,")");
		get_exps(vv);
		(*curtok)++;
		return;
	}

	p = (*tk)[*curtok];
	(*curtok)++;
	*(pcode+(*plen)++) = 8;
	for (i=1; i<=nfnt; i++) {
		if (fnt[i].name!=NULL) if (strcmp(fnt[i].name,p)==0) {
		  *(pcode+(*plen)++) = i;       /* font number */
		  return;
		}
	}
	gprint("Invalid font name {%s}, expecting one of: \n    ",p);
	for (i=1;i<=nfnt; i++) {
		if (fnt[i].name!=NULL)
			gprint("  {%s} ",fnt[i++].name);
		if (fnt[i].name!=NULL)
			gprint("  {%s} ",fnt[i++].name);
		if (fnt[i].name!=NULL)
			gprint("  {%s} ",fnt[i++].name);
		if (fnt[i].name!=NULL)
			gprint("  {%s} \n",fnt[i].name);
	}
	*(pcode+(*plen)++) = 1;         /* default font number */
}
text_block(uchar *s,double width,int justify)
{
	double ox,oy,x,y,ll,rr,uu,dd;
	double a,b,c,d;

	set_base_size();
	g_get_bounds(&a,&b,&c,&d);
	g_init_bounds();
	dont_print = true;
	fftext_block(s,width,justify);
	dont_print = false;
	g_get_bounds(&ll,&dd,&rr,&uu);
	if (ll > rr) {ll=0; rr=0; uu=0; dd=0;}
	g_get_xy(&ox,&oy);
	x = ox; y = oy;
	g_dotjust(&x,&y,ll,rr,uu,dd,justify);
	g_move(x,y);
	g_init_bounds();
	if (a<=c) {
		g_set_bounds(a,b);
		g_set_bounds(c,d);
	}
	g_get_bounds(&a,&b,&c,&d);
	text_draw(gt_pbuff,gt_plen);
	g_get_bounds(&a,&b,&c,&d);
	g_move(ox,oy);
}
/*----------------------------------------------------------------------*/
/* Searches CMD and replaces #n's with parameters */
char *tex_replace(char *cmd,char *pm[],int pmlen[],int npm)
{
	char *r,*s,*o;
	int n,i;

/*      printf("replace {%s} \n",cmd);
	for (i=0;i<npm;i++) {
		printf("pm[%d] = {%s} %d \n",i,pm[i],pmlen[i]);
	}
*/
	if (strchr(cmd,'#')==0) return sdup(cmd);
	r = myalloc(1000);
	o = r;
	for (s=cmd; *s!=0; s++) {
		if (*s=='#') {
			n = *(++s) - '0';
			if (n>0 && n<=npm) {
				strncpy(o,pm[n-1],pmlen[n-1]);
				o += pmlen[n-1];
			}
		} else *o++ = *s;
	}
	*o++ = 0;
	return r;
}

/*----------------------------------------------------------------------*/
/*              tex_chardef                                             */
/*----------------------------------------------------------------------*/
tex_chardef(int c, char *defn)  /* Defines single char as string */
{
	if (c<0 || c>255) return;
	if (cdeftable[c]!=NULL) myfree(cdeftable[c]);
	cdeftable[c] = sdup(defn);
}
char *tex_findchardef(int c)
{
	return cdeftable[c];
}

/*----------------------------------------------------------------------*/
/*              Hashing table code for \def                             */
/*----------------------------------------------------------------------*/
#define HASHSIZE 101

static deftable  *def_hashtab[HASHSIZE];

unsigned hash_str(char *s);
unsigned hash_str(char *s)
{
	unsigned hashval;

	for (hashval=0; *s != 0; s++)
		hashval = *s + 31*hashval;
	return hashval % HASHSIZE ;
}

deftable *tex_finddef(char *s)
{
	deftable  *np;

	for (np = def_hashtab[hash_str(s)]; np != NULL; np = np->next)
		if (strcmp(s, np->name) == 0) {
			return np;
		}
	return NULL;
}

tex_def(char *name, char *defn,int npm)
{
	deftable  *np;
	char **s;
	unsigned hashval;

	if ((np = tex_finddef(name)) == NULL) { /* not found */
		np = (deftable  *) myalloc(sizeof(*np));
		if ((np == NULL) || (np->name = sdup(name)) == NULL)
			return NULL;
		hashval = hash_str(name);
		np->next = def_hashtab[hashval];
		def_hashtab[hashval] = np;
		np->npm = npm;
		if ((np->defn = sdup(defn)) == NULL) return NULL;
	} else {
		myfree(np->defn);
		if ((np->defn = sdup(defn)) == NULL) return NULL;
	}
	return true;
}
/*----------------------------------------------------------------------*/
/*              Hashing table code for \mathchardef                     */
/*----------------------------------------------------------------------*/
struct mdef_table_struct {
	struct mdef_table_struct  *next;
	char *name;
	int defn;
};
typedef struct mdef_table_struct mdeftable;

static mdeftable  *mdef_hashtab[HASHSIZE];

int *tex_findmathdef(char *s)
{
	mdeftable  *np;

	for (np = mdef_hashtab[hash_str(s)]; np != NULL; np = np->next)
		if (strcmp(s, np->name) == 0) {
			return &np->defn;
		}
	return NULL;
}

tex_mathdef(char *name, int defn)
{
	mdeftable  *np;
	int *d;
	unsigned hashval;

	if ((d = tex_findmathdef(name)) == NULL ) { /* not found */
		np = (mdeftable  *) myalloc(sizeof(*np));
		if ((np == NULL) || (np->name = sdup(name)) == NULL)
			return NULL;
		hashval = hash_str(name);
		np->next = mdef_hashtab[hashval];
		mdef_hashtab[hashval] = np;
		np->defn = defn;
	} else {
		*d = defn;
	}
	return true;
}
tex_init()
{
	int i;
	for (i=0;i<256;i++) chr_val[i]=i;
	for (i=0;i<256;i++) chr_code[i]=10;     /* other */
	for (i=65;i<91;i++) chr_code[i]=1;      /* alpha */
	for (i=97;i<123;i++) chr_code[i]=1;
	chr_code[0] = 2; /* maybe should be 0,  this is only tested in lig*/
	chr_code[' '] = 2;
	chr_code[9] = 2;
	chr_code['\n'] = 2;
	chr_code['\\'] = 6;
	chr_code['{'] = 7;
	chr_code['}'] = 8;
	chr_code[255] = 11;     /* flag for end of paragraph, unless verbatim */
	chr_init = true;
	tex_preload();
	tex_def(" ","\\movexy{1sp}{}",0);
	tex_def("\\","\\newline",0);
	tex_def("{","\\char{123}",0);
	tex_def("}","\\char{125}",0);
	tex_def("_","\\char{95}",0);
	/* tex_def("^","\\char{94}",0); */
	tex_def("$","\\char{36}",0);
}
tex_clear()
{
	/* clear CHARDEF table before each redraw */

	int c;
	for (c=1;c<255;c++) {
		if (cdeftable[c]!=NULL) {
			myfree(cdeftable[c]);
			cdeftable[c] = NULL;
		}
	}
	tex_chardef('^',"\\sup ");
	tex_chardef('_',"\\sub ");
}
g_measure(char *s, double *l, double *r, double *u, double *d)
{
	double sa,sb,sc,sd;
	g_get_bounds(&sa,&sb,&sc,&sd);
	set_base_size();
	g_init_bounds();
	dont_print = true;
	fftext_block(UC s,0.0,0);
	dont_print = false;
	g_get_bounds(l,d,r,u);
	if (*l > *r) {*l=0; *r=0; *u=0; *d=0;}
	gt_l = *l;
	gt_r = *r;
	gt_u = *u;
	gt_d = *d;
	g_init_bounds();
	if (sa>sc) return;
	g_set_bounds(sa,sb);
	g_set_bounds(sc,sd);
}
g_textfindend(char *s, double *cx, double *cy)
{
	double sa,sb,sc,sd;
	set_base_size();
	g_get_bounds(&sa,&sb,&sc,&sd);
	dont_print = true;
	fftext_block(UC s,0.0,0);
	*cx = text_endx;
	*cy = text_endy;
	dont_print = false;
	g_init_bounds();
	if (sa>sc) return;
	g_set_bounds(sa,sb);
	g_set_bounds(sc,sd);
}
g_jtext(int just)
{
	double ox,oy,x,y;
	g_get_xy(&ox,&oy);
	x = ox; y = oy;
	g_dotjust(&x,&y,gt_l,gt_r,gt_u,gt_d,just);
	g_move(x,y);
	text_draw(gt_pbuff,gt_plen);
	g_move(ox,oy);
}
static uchar tbuff[8000];
text_def(uchar *s)
{
	gt_plen = 0;
	if (chr_init==false) tex_init();
	text_topcode(s,gt_pbuff,&gt_plen);
}
fftext_block(uchar *s,double width,int justify)
{
	uchar *t,*r,*m,*p;
	int i;

	g_get_font(&p_fnt);
	font_load_metric(p_fnt);

	g_get_hei(&p_hei);
	font_reset_parskip();
	gt_plen = 0;
	if (s==NULL) {
		dbg gprint("TEXT_BLOCK, Passed NULL pointer \n");
		return;
	}
	if (*s==0) {
		/* gprint("TEXT_BLOCK, Passed empty string \n"); */
		return;
	}
	if (chr_init==false) tex_init();
lp:

	t = UC strstr(SC s,"\n\n");     /* search for cr,cr                     */
	if (t!=NULL) {
		*(t+1) = 255;   /* flag end of paragraph */
		goto lp;
	}
	text_tomacro(s,tbuff);
	gt_plen = 0;
	if (width==0) {
		width = 400;
		chr_code['\n'] = 5;
	} else chr_code['\n'] = 2;
	text_topcode(tbuff,gt_pbuff,&gt_plen);
	text_wrapcode(gt_pbuff,gt_plen,width);
	text_draw(gt_pbuff,gt_plen);


	g_set_font(p_fnt);
	g_set_hei(p_hei);


/*      dbg gprint("text to macro {%s} {%s} \n",s,tbuff);
	dbg gprint("============topcode \n");
	dbg gprint("P: ");
	for (i=0;i<plen;i++) {
		dbg gprint("%4x ",pbuff[i]);
		if ((i+1)/10==(i+1)/10.0) dbg gprint("\nP: ");
	}
	dbg gprint("\n");
	dbg text_gprint(pbuff,plen);
	dbg gprint("\n");
	dbg gprint("==== ====       ==== ==== wrapcode \n");
	dbg gprint("\n");
	dbg gprint("==== ====       ==== ==== draw \n");
*/
}
cmd_token(uchar **in,char *cmdstr)
{
	int gcnt,i;
	char *s;
	s = cmdstr;
	i=0;
	if ( (!isalpha(**in)) && (**in != 0)) {
		*cmdstr++ = *(*in)++;
	} else {
		for (; chr_code[**in]==1 && **in != 0 && i<20;(*in)++,i++)  {
			*cmdstr++ = **in;
		}
	}
	*cmdstr = 0;
	cmdstr -= 1;
	if (chr_code[*cmdstr]==1) {
		for (;(**in != 0) && (chr_code[**in]==2);) (*in)++;
	}
}
text_tomacro(uchar *in, uchar *out)
{
	/* find /cmdname  or defined characters */
	static char macroname[30];
	uchar *s,*dfn,*r,*saves;
	int changed,dlen;
	int nrep,j;
	deftable  *np;
	static union {char *s[10]; uchar *u[10];} pm;
	static int pmlen[10];

	nrep = 0;
	strcpy(SC out,SC in);
	for (s=out; *s != 0;s++)  {
	  if (nrep>300) gle_abort("Loop in text macros\n");
	  if (chr_code[*s]==6) {        /* backslash, begining of macro? */
		saves = s;
		s++;
		cmd_token(&s,macroname);
		np = tex_finddef(macroname);
		if (np != NULL) {
			nrep++;
			dfn = UC np->defn;
			dbg printf("Found macro {%s} = {%s} \n",macroname,dfn);
			cmd_param(&s,pm.u,pmlen,np->npm);
			dlen = s-saves;
			r = UC tex_replace(SC dfn,pm.s,pmlen,np->npm);
			s = saves;
			memmove(SC s+strlen(SC r),SC s+dlen,strlen(SC s)+1);
			strncpy(SC s,SC r,strlen(SC r));
			myfree(r);
			s--;
		}
		s = saves;
	  }
	  if (cdeftable[*s]!=0) {
		dbg printf("Found char definition %d  {%s} \n",*s,s);
		nrep++;
		dfn = UC tex_findchardef(*s);
		memmove(s+strlen(SC dfn)-1,s,strlen(SC s)+1);
		strncpy(SC s,SC dfn,strlen(SC dfn));
		s--;
	  }
	}
	dbg printf("MACOR IN {%s} \n",in);
	dbg printf("MACOR CODE {%s} \n",out);
}
tex_presave()
{
	int i;
	deftable *dt;
	FILE *fout;
	mdeftable *mdt;
	char *workarea;
	/* Save all defined features possible */
	fout = fopen(gledir("inittex.ini"),WRITE_BIN);
	if (fout==NULL) gprint("Could not open inittex.ini file \n");
	fwrite(fontfam,sizeof(int),16*4,fout);
	fwrite(fontfamsz,sizeof(double),16*4,fout);
	fwrite(chr_mathcode,sizeof(char),256,fout);

	for (i=0;i<HASHSIZE;i++) {
	  for (dt = def_hashtab[i]; dt != NULL; dt = dt->next) {
		fwrite(&i,sizeof(i),1,fout);
		fwrite(&dt->npm,sizeof(i),1,fout);
		fsendstr(dt->name,fout);
		fsendstr(dt->defn,fout);
	  }
	}
	i = 0x0fff; fwrite(&i,sizeof(i),1,fout);
	for (i=0;i<HASHSIZE;i++) {
	  for (mdt = mdef_hashtab[i]; mdt != NULL; mdt = mdt->next) {
		fwrite(&i,sizeof(i),1,fout);
		fwrite(&mdt->defn,sizeof(i),1,fout);
		fsendstr(mdt->name,fout);
	  }
	}
	i = 0x0fff; fwrite(&i,sizeof(i),1,fout);
	for (i=0;i<256;i++)  fsendstr(cdeftable[i],fout);
	fclose(fout);
}
/*----------------------------------------------------------------------*/
fgetvstr(char **s,FILE *fmt)
{
	int i;
	i = fgetc(fmt);
	if (i==0) return;
	*s = myalloc(i+1);
	fread(*s,1,i,fmt);
	*(*s+i) = 0;
}
fgetcstr(char s[],FILE *fmt)
{
	int i;
	i = fgetc(fmt);
	if (i==0) return;
	fread(s,1,i,fmt);
	s[i] = 0;
}
fsendstr(char *s,FILE *fout)
{
	if (s==NULL) {
		fputc(0,fout);
		return;
	}
	fputc(strlen(s),fout);
	fwrite(s,1,strlen(s),fout);
}
tex_preload()
{
	int i,j;
	deftable *dt;
	FILE *fout;
	mdeftable *mdt;
	char *workarea;
	char str1[80],str2[80];
	/* reload all defined features */
	fout = fopen(gledir("inittex.ini"),READ_BIN);
	if (fout==NULL) {gprint("Could not open inittex.ini file \n"); return;}
	fread(fontfam,sizeof(int),16*4,fout);
	fread(fontfamsz,sizeof(double),16*4,fout);
	fread(chr_mathcode,sizeof(char),256,fout);

	for (;  (fread(&i,sizeof(i),1,fout)), i != 0x0fff;) {
		fread(&j,sizeof(j),1,fout);
		fgetcstr(str1,fout); fgetcstr(str2,fout);
		tex_def(str1,str2,j);
	}
	for (;  (fread(&i,sizeof(i),1,fout)), i != 0x0fff;) {
		fread(&j,sizeof(j),1,fout);
		fgetcstr(str1,fout);
		tex_mathdef(str1,j);
	}

	for (i=0;i<256;i++)  fgetvstr(&cdeftable[i],fout);
	fclose(fout);
}
