
/* An explanation of coding style is in order.  This program was first
   written in the late 1980s in pascal for compilation on an IBM VM/CMS
   system.  Parsing was automated using a custom parser-generator
   with table optimizations adapted from a compiler-compiler called
   BOBS-System, of a vintage similar to the original Yacc.  The program
   has migrated to several other operating systems since, including VMS
   and flavors of Unix, with debugging done using a variety of pascal
   compilers.  The result was a strict LALR(1) grammar and table-driven
   parser with a fully accessible stack of production attributes.

   For a while, dpic was distributed in C form by converting the
   pascal using p2c.  More recently, the pascal code was also included;
   consequently, the distribution had to contain versions of p2c and
   the custom parser generator.  To avoid requiring and maintaining the
   latter tools, it was decided to enter the world of Linux orthodoxy,
   provide the source in C, and use GNU bison to generate the parser.

   Dpic has been quite solid for a decade or more and in order not
   to introduce bugs, the C code has been altered very little.  As a
   result, there are few C idioms used but some p2c idiosyncracies
   (use of With, FORLIM ...) remain.  Starting from scratch would
   have resulted in cleaner code but bugs would have been introduced.
   The main program changes have resulted from going from parse code
   exploiting a completely accessible stack to the more implicit mode
   of bison. Error recovery and some error messages are also different.
   To avoid changing how dpic handles input, the original lexical analyser
   has been kept, controlled by tables now generated by an awk script.

   This file is the input to bison, except for the token definitions,
   which are generated by the awk script and inserted by the Makefile.
*/

%{
#include "dpic.h"
#define Rnd(x)	((long)floor(x + 0.5))
#define envinx(x)	Upr.UBLOCK.env[(int)(Rnd(x)-XLenvvar-1)]
#define envblockB	envblock->Upr.UBLOCK

int yyerror(char*);

boolean hasoutline(int, boolean);
boolean hasshade(int, boolean);
boolean isprint_(Char);
boolean teststflag(int, int);
double findvar(Char *, int);
double intpow(double, int);
double linlen(double, double);
double pheight(primitive *);
double pwidth(primitive *);
int bval(Char *);
int cmpstring(primitive *, primitive *);
int getstval(int);
int putstring(int, nametype *, Char *, chbufinx, chbufinx);
int varhash(Char *, chbufinx, chbufinx);
primitive *( findenv(primitive *));
primitive *( findplace(primitive *, Char *, chbufinx, chbufinx));
void addsuffix(Char *, chbufinx *, int *, double, int, double );
void appendthen(primitive **);
void appendstring(nametype *, Char *, chbufinx, chbufinx);
void attcopy(int,int);
void attreduce(int,int);
void checkjust(nametype *, boolean *, boolean *, boolean *, boolean *);
void clearchbuf(chbufinx, int);
void consoleflush(void);
void copyprim(primitive *, primitive **);
void copystr(nametype **, nametype *);
void corner(primitive *, int, double *, double *);
void deletefreeargs(arg **);
void deletefreeinbufs(fbuffer **);
void deletename(nametype **);
void deletestringbox(primitive **);
void deletetree(primitive **);
void dodefhead( attribute *);
void donamedobj(attribute *);
void dosprintf( attribute *, attribute *, attribute *, int );
void dostart(void);
void doundefine( attribute * );
void eqop(double *, int, double);
void FindExitPoint(primitive *, postype *);
void getnesw(primitive *);
void getscale(double, double, primitive *, double *, double *);
void inheritenv(primitive *);
void initnesw(void);
void inittwo(void);
void lineardir(primitive *, double, double, int *);
void makevar(Char *, int, double);
void markerror(int);
void marknotfound(int, Char *, chbufinx, chbufinx);
void nesw(primitive *);
void neswrec(primitive *);
void newbuf(fbuffer **);
void newprim(primitive **, int, primitive *);
void newstr(nametype **);
void putbval(Char *, int);
void queueprim( primitive *, primitive * );
void readfor(fbuffer *, int, fbuffer **, Char, boolean);

void resetenv(int, primitive *);
void resetscale(double, int, primitive *);
void scaleobj(primitive *, double);
void setangles(double *, double *, postype, double, double, double, double);
void setspec(int *, int);
void setstflag(int *, int);
void setstval(int *, int);
void setthen(int *);
void shift(primitive *, double, double);
void skipwhite(void);
void storestring(nametype *, Char *, chbufinx, chbufinx, int);
void wchar(FILE **, Char);
void wrbuf(fbuffer *, int, int);

#ifdef DDEBUG
int lspec(int);
void logaddr(fbuffer *);
void prattstack(attribute *);
void prattribute(char *, attribute *);
void printobject(primitive *);
void prvars(primitive *);
void snapname(Char *, chbufinx, chbufinx);
void wrbufaddr(fbuffer *, int);
extern int ordp(void *);
extern int odp(void *);
extern int ahnum(int);
extern void prtstval(int);
extern void snaptree(primitive *, int);
extern void snaptype(FILE **, int);
#endif

nametype *( findname(primitive *, Char *, chbufinx, chbufinx, nametype **,
  int *));
nametype *( glfindname(
  primitive *, Char *, chbufinx, chbufinx, nametype **, int *) );
primitive *( nthprimobj(primitive *, int, int) );

extern arg *(findmacro(arg *, Char *, chbufinx, chbufinx, arg **));
extern boolean isthen(primitive *);
extern double datan(double, double);
extern double Max(double, double);
extern double Min(double, double);
extern double principal(double, double);
extern int ahlex(int);
extern int eqstring(Char *, chbufinx, chbufinx, Char *, chbufinx, chbufinx);
extern int Floor(double);
extern int pahlex(int, int);
extern int pahnum(int, int);
extern int yylex(attribute *);
extern postype arcend(primitive *);
extern postype arcstart(primitive *);
extern void backup(void);
extern void copyleft(fbuffer *mac, fbuffer **buf, int attr);
extern void disposeargs(arg **);
extern void disposebufs(fbuffer **);
extern void drawtree(double, double, double, double, primitive *);
extern void fatal(int);
extern void inchar(void);
extern void newarg(arg **);
extern void pointinput(nametype *);
extern void pointoutput(boolean, nametype *, int *);
extern void setjust(nametype *, int);
extern void skipcontinue(boolean);
extern void skiptobrace(void);
extern void skiptoend(void);
extern void wcoord(FILE **, double, double);
extern void wfloat(FILE **, double);
extern void wpair(FILE **, double, double);
extern void wstring(FILE **, nametype *);

typedef double envarray[XLlastenv - XXenvvar];

%}

%define api.value.type { attribute }
%lex-param { attribute *pyylval }

%{
  nametype *lastvar, *namptr;
  fbuffer *lastm;
  arg *macp, *lastp;
  primitive *primp, *prp, *eb;
  int i, j, k, kk, lj, ll, nexprs, nwi;
  double r, s, t, x1, z1, dx, dy, ts;
  boolean bswitch;
  attribute *With, *With1;
  primitive *With2;
  nametype *With4;
  int FORLIM;
  char cy;
%}

%start input

							/* Tokens all have identifiers in order to preserve
							   their existing numerical values.
							   Do not change the following two lines: */
/* start tokens */

%token	XEOF 1
%token	XEMPTY 2
%token	XERROR 3
%token	XLT 4
%token	XLcw 5
%token	XLccw 6
%token	Xlparen 7
%token	Xrparen 8
%token	Xmult 9
%token	Xplus 10
%token	Xminus 11
%token	Xdiv 12
%token	Xpercent 13
%token	XNL 14
%token	Xcaret 15
%token	XNOT 16
%token	XANDAND 17
%token	XOROR 18
%token	Xcomma 19
%token	XCOLON 20
%token	XBRACKETL 21
%token	XBRACKETR 22
%token	XLBRACE 23
%token	XRBRACE 24
%token	Xdot 25
%token	XBLOCK 26
%token	XSLQ 27
%token	XSRQ 28
%token	XEQ 29
%token	XLcoloneq 30
%token	XLpluseq 31
%token	XLminuseq 32
%token	XLmulteq 33
%token	XLdiveq 34
%token	XLremeq 35
%token	XAND 36
%token	XLfloat 37
%token	XLname 38
%token	XLabel 39
%token	XLaTeX 40
%token	XLstring 41
%token	XCOMMENT 42
%token	XLarg 43
%token	XSTART 44
%token	XEND 45
%token	XLht 46
%token	XLwid 47
%token	XLrad 48
%token	XLdiam 49
%token	XLthick 50
%token	XLscaled 51
%token	XLfrom 52
%token	XLto 53
%token	XLat 54
%token	XLwith 55
%token	XLby 56
%token	XLthen 57
%token	XLcontinue 58
%token	XLchop 59
%token	XLsame 60
%token	XLof 61
%token	XLthe 62
%token	XLway 63
%token	XLbetween 64
%token	XLand 65
%token	XLHere 66
%token	XLnth 67
%token	XLlast 68
%token	XLfill 69
%token	XLdx 70
%token	XLdy 71
%token	XLprint 72
%token	XLcopy 73
%token	XLreset 74
%token	XLexec 75
%token	XLsh 76
%token	XLcommand 77
%token	XLdefine 78
%token	XLundefine 79
%token	XLrand 80
%token	XLif 81
%token	XLelse 82
%token	XFOR 83
%token	XLdo 84
%token	XLendfor 85
%token	XLsprintf 86
%token	XLcorner 87
%token	XDne 88
%token	XDse 89
%token	XDnw 90
%token	XDsw 91
%token	XDn 92
%token	XDs 93
%token	XDe 94
%token	XDw 95
%token	XDstart 96
%token	XDend 97
%token	XDc 98
%token	XLcompare 99
%token	XEQEQ 100
%token	XNEQ 101
%token	XGE 102
%token	XLE 103
%token	XGT 104
%token	XLparam 105
%token	XLheight 106
%token	XLwidth 107
%token	XLradius 108
%token	XLdiameter 109
%token	XLthickness 110
%token	XLlength 111
%token	XLfunc1 112
%token	XLabs 113
%token	XLacos 114
%token	XLasin 115
%token	XLcos 116
%token	XLexp 117
%token	XLexpe 118
%token	XLint 119
%token	XLlog 120
%token	XLloge 121
%token	XLsign 122
%token	XLsin 123
%token	XLsqrt 124
%token	XLtan 125
%token	XLfloor 126
%token	XLfunc2 127
%token	XLatan2 128
%token	XLmax 129
%token	XLmin 130
%token	XLpmod 131
%token	XLlinetype 132
%token	XLsolid 133
%token	XLdotted 134
%token	XLdashed 135
%token	XLinvis 136
%token	XLcolrspec 137
%token	XLcolour 138
%token	XLoutlined 139
%token	XLshaded 140
%token	XLtextpos 141
%token	XLcenter 142
%token	XLljust 143
%token	XLrjust 144
%token	XLabove 145
%token	XLbelow 146
%token	XLarrowhd 147
%token	XLEFTHEAD 148
%token	XRIGHTHEAD 149
%token	XDOUBLEHEAD 150
%token	XLdirecton 151
%token	XLup 152
%token	XLdown 153
%token	XLright 154
%token	XLleft 155
%token	XLprimitiv 156
%token	XLbox 157
%token	XLcircle 158
%token	XLellipse 159
%token	XLarc 160
%token	XLline 161
%token	XLarrow 162
%token	XLmove 163
%token	XLspline 164
%token	XLenvvar 165
%token	XLarcrad 166
%token	XLarrowht 167
%token	XLarrowwid 168
%token	XLboxht 169
%token	XLboxrad 170
%token	XLboxwid 171
%token	XLcirclerad 172
%token	XLdashwid 173
%token	XLellipseht 174
%token	XLellipsewid 175
%token	XLlineht 176
%token	XLlinewid 177
%token	XLmoveht 178
%token	XLmovewid 179
%token	XLtextht 180
%token	XLtextoffset 181
%token	XLtextwid 182
%token	XLarrowhead 183
%token	XLfillval 184
%token	XLlinethick 185
%token	XLmaxpsht 186
%token	XLmaxpswid 187
%token	XLscale 188
/* end tokens */

%% /* beginning of rules section */

input :                                                           /* input1 */

		| input picture NL                                        /* input2 */
		{ deletetree(&envblock);
    	  deletefreeargs(&freearg);
    	  deletefreeinbufs(&freeinbuf);
#ifdef DDEBUG
          if (debuglevel > 0) {
            fprintf(log_, "deletetree:\n");
	        fprintf(log_, "deletefreeargs: ");
	        fprintf(log_, "deletefreeinbufs: ");
	        fprintf(log_, "inittwo:\n"); }
#endif
    	  inittwo();
    	  if (envblock != NULL) { envblock->direction = XLright; }
		  }
		;

picture	:	start NL elementlist optnl XEND                     /* picture1 */
		{ if (envblock != NULL ) { getnesw(envblock->son);
#ifdef DDEBUG
	      if (debuglevel > 0) {
            snaptree(envblock->son,0);
		    fprintf(log_, " Global dimensions:\n");
            fprintf(log_, "(n,s)(e,w)=");
		    wpair(&log_, north, south); wpair(&log_, east, west);
		    fprintf(log_, " envblock<>nil:%s\n",
              (envblock != NULL) ? " TRUE" : "FALSE"); fflush(log_); }
#endif
		  envblock->aat.xpos = (east + west) * 0.5;
		  envblock->aat.ypos = (north + south) * 0.5;
		  envblock->Upr.UBLOCK.blockheight = north - south;
		  envblock->Upr.UBLOCK.blockwidth = east - west;
	      if (drawmode == xfig) {
		    shift(envblock, -west, -south);
		    north -= south;
		    east -= west;
		    west = 0.0;
		    south = 0.0; }
	      else if ((envblock != NULL) &&
	        ((drawmode == SVG) || (drawmode == PDF) || (drawmode == PS))) {
							/* linethick/2 in drawing units*/
		    r = (envblock->envinx(XLlinethick) / 2 / 72)
                * envblock->envinx(XLscale);
#ifdef DDEBUG
		    if (debuglevel > 0) {
			  fprintf(log_,     " west="); wfloat(&log_, west);
			  fprintf(log_,     " south="); wfloat(&log_, south);
			  fprintf(log_,     " r="); wfloat(&log_, r);
			  fprintf(log_,     " shift=("); wfloat(&log_, r-west);
              putc(',', log_);
			  wfloat(&log_,     r - south);
              fprintf(log_, ")\n"); fflush(log_); }
#endif
							/* shift .sw to (r,r) */
		      shift(envblock, (2 * r) - west, (2 * r) - south);
		      north += (3 * r) - south;
		      east += (3 * r) - west;
		      west = r;
		      south = r;
	          }
	        xfheight = north;
	        getscale($$.xval, $$.yval, envblock, &scale, &fsc);
#ifdef DDEBUG
	        if (debuglevel > 0) {
		      fprintf(log_, "After shift:\n");
		      fprintf(log_, "xfheight="); wfloat(&log_, xfheight);
              putc('\n', log_);
		      printobject(envblock);
		      printobject(envblock->son);
		      fprintf(log_, "\nStarting drawtree ================= ");
		      if (($$.xval > 0.0) && (east > west)) {
		        fprintf(log_, "fsc="); wfloat(&log_, fsc); }
		      putc('\n', log_);
		      snaptree(envblock, 0);
		      putc('\n', log_); fflush(log_); }
#endif
		    if ((drawmode == SVG) || (drawmode == PDF) || (drawmode == PS)) {
		      dptextratio = findvar("dptextratio", 11);
		      if (dptextratio == 0) { dptextratio = 1.0; }
		      dpPPI = findvar("dpPPI", 5); }
	        drawtree(north, south, east, west, envblock);
#ifdef DDEBUG
	        if (debuglevel > 0) {
		      fprintf(log_, " drawtree done ================= \n"); }
#endif
	        }
	      }
		;

NL	:	XNL                                                          /* NL1 */

		| error                                                      /* NL2 */
		{ yyerrok; yyclearin; }
		;

start	:	XSTART                                                /* start1 */
		{ dostart(); $$.xval = 0; $$.yval = 0;}

		| XSTART term                                             /* start2 */
		{ dostart(); $$.xval = $2.xval; $$.yval = 0; }

		| XSTART term term                                        /* start3 */
		{ dostart(); $$.xval = $2.xval; $$.yval = $3.xval; }
		;

elementlist	:                                               /* elementlist1 */

		| element                                           /* elementlist2 */
		{ if (($1.prim != NULL) && ($1.lexval != XLcontinue)) {
            queueprim( $1.prim, envblock ); }
#ifdef DDEBUG
          if (debuglevel > 0 ) { snaptree(envblock->son,0); }
#endif
    	  }

		| elementlist NL element                            /* elementlist3 */
		{ if (($3.prim != NULL) && ($3.lexval != XLcontinue)) {
            queueprim( $3.prim, envblock ); }
#ifdef DDEBUG
          if (debuglevel > 0 ) { snaptree(envblock->son,0); }
#endif
		  }
		;

term	:	factor                                                 /* term1 */

		| term Xmult factor                                        /* term2 */
		{ $$.xval = $1.xval * $3.xval; }

		| term Xdiv factor                                         /* term3 */
		{ if ($3.xval == 0.0) { markerror(852); $$.xval = 0.0; }
    		else { $$.xval = $1.xval / $3.xval; }
		  }

		| term Xpercent factor                                     /* term4 */
		{ i = Rnd($1.xval);
    	  j = Rnd($3.xval);
    	  if (j == 0) { markerror(852); $$.xval = 0.0; }
    	  else { $$.xval = i - ((i / j) * j); }
		  }
		;

element	:	namedobj /* chop operation for linear objects */    /* element1 */
		{ if ($$.prim != NULL) {
			prp = $$.prim;
			if ((prp->ptype == XLspline) || (prp->ptype == XLmove) ||
			    (prp->ptype == XLarrow) || (prp->ptype == XLline)) {
			  if ($$.startchop != 0.0) {
				dx = prp->Upr.Uline.endpos.xpos - prp->aat.xpos;
				dy = prp->Upr.Uline.endpos.ypos - prp->aat.ypos;
				s = linlen(dx, dy);
#ifdef DDEBUG
				if (debuglevel == 2) { fprintf(log_, " element1 startchop=");
				  wfloat(&log_, $$.startchop);
				  fprintf(log_, " (dx,dy)="); wpair(&log_, dx, dy);
				  fprintf(log_, " s="); wfloat(&log_, s); putc('\n', log_); }
#endif
				if (s != 0.0) {
				  t = $$.startchop / s;
				  prp->aat.xpos += t * dx;
				  prp->aat.ypos += t * dy; }
			    }
			  while (prp->son != NULL) { prp = prp->son; }
			  if ($$.endchop != 0.0) {
				dx = prp->Upr.Uline.endpos.xpos - prp->aat.xpos;
				dy = prp->Upr.Uline.endpos.ypos - prp->aat.ypos;
				s = linlen(dx, dy);
#ifdef DDEBUG
				if (debuglevel == 2) { fprintf(log_, " element1 endchop=");
				  wfloat(&log_, $$.endchop);
				  fprintf(log_, " (dx,dy)="); wpair(&log_, dx, dy);
				  fprintf(log_, " s="); wfloat(&log_, s); putc('\n', log_); }
#endif
				if (s != 0.0) {
				  t = $$.endchop / s;
				  prp->Upr.Uline.endpos.xpos -= t * dx;
				  prp->Upr.Uline.endpos.ypos -= t * dy; }
			    }
			  }
			FindExitPoint(prp, &envblockB.here); }
#ifdef DDEBUG
			if (debuglevel > 0) { prattribute("element1", &$$);
			  fprintf(log_, " element1 Here=");
			  wpair(&log_, envblock->Upr.UBLOCK.here.xpos,
				envblock->Upr.UBLOCK.here.ypos); putc('\n', log_);
			  printobject($$.prim); }
#endif
			}

		| XLabel suffix XCOLON position                         /* element2 */
		{ if ($2.lexval != XEMPTY) {
		    addsuffix(chbuf, &$1.chbufx,&$1.toklen, $2.xval,$2.lexval,$2.yval);}
		  prp = findplace(envblock->son, chbuf, $1.chbufx, $1.toklen);
		  if (prp == NULL) {
			newprim(&$$.prim, XLabel, envblock);
			newstr(&$$.prim->name);
			storestring($$.prim->name, chbuf, $1.chbufx, $1.toklen, 1);
			prp = $$.prim; }
		  else if (prp->ptype != XLabel) {
			newprim(&$$.prim, XLabel, envblock);
			$$.prim->name = prp->name;
			prp->name = NULL;
			prp = $$.prim; }
		  clearchbuf($1.chbufx, $1.toklen);
		  prp->aat.xpos = $4.xval;
		  prp->aat.ypos = $4.yval;
#ifdef DDEBUG
          if (debuglevel>1) {
            prattribute("element2", &$$);
            if ($$.prim != NULL) printobject($$.prim); }
#endif
		  }

		| assignlist                                            /* element3 */

		| XLdirecton                                            /* element4 */
			{ envblock->direction = $1.lexval; }

		| XLaTeX                                                /* element5 */
		{ newprim(&$$.prim, XLaTeX, envblock);
    	  newstr(&$$.prim->textp);
    	  storestring($$.prim->textp, chbuf, $1.chbufx, $1.toklen, 1);
		  clearchbuf($1.chbufx, $1.toklen);
		  }

		| command                                               /* element6 */

		| lbrace elementlist optnl XRBRACE                      /* element7 */
		{ envblockB.here.xpos = $1.xval;
    	  envblockB.here.ypos = $1.yval;
    	  if (($1.state == XLright) || ($1.state == XLleft) ||
			  ($1.state == XLdown) || ($1.state == XLup)) {
			envblock->direction = $1.state; }
#ifdef DDEBUG
          if (debuglevel>1) { prattribute("element7", &$$); }
#endif
		  }

		| ifpart                                                /* element8 */

		| elsehead elementlist optnl XRBRACE                    /* element9 */

		| for XRBRACE                                          /* element10 */

		| XLcommand stringexpr                                 /* element11 */
		{ if ($2.prim != NULL) {
			newprim(&$$.prim, XLaTeX, envblock);
			$$.prim->textp = $2.prim->textp;
			$2.prim->textp = NULL;
			if (envblock->son == $2.prim) { envblock->son = $$.prim; }
			deletestringbox(&$2.prim);
			}
		  }

		| XLexec stringexpr                                    /* element12 */
		{ if ($2.prim == NULL) { }
          else if ($2.prim->textp == NULL) { }
          else if ($2.prim->textp->segmnt != NULL) {
			With4 = $2.prim->textp;
			newbuf(&lastm);      /* Temp buffer; put nlch into inbuf */
			lastm->carray[1] = nlch;
			lastm->savedlen = 1;
			copyleft(lastm, &inbuf, -1);
			FORLIM = With4->len;
	                  /*  Copy string to lastm then to inbuf */
			for (i = 1; i <= FORLIM; i++) {
			  lastm->carray[i] = With4->segmnt[With4->seginx + i - 1]; }
			lastm->savedlen = With4->len;
			copyleft(lastm, &inbuf, -1);
						  /*  Add nlch in inbuf */
			lastm->carray[1] = nlch;
			lastm->savedlen = 1;
			copyleft(lastm, &inbuf, -1);
			deletestringbox(&$2.prim);
			disposebufs(&lastm); }
		  }
		;

lbrace	:	XLBRACE                                              /* lbrace1 */
		{ $$.xval = envblockB.here.xpos;
    	  $$.yval = envblockB.here.ypos;
    	  $$.state = envblock->direction; }
		;

namedobj:	object /* then, arc, and deferred shift */         /* namedobj1 */
		{ donamedobj(&$$); }

		| XLabel suffix XCOLON object                          /* namedobj2 */
		{ if ($4.prim != NULL) {
		    if ($2.lexval != XEMPTY) { addsuffix(chbuf, &$1.chbufx,
                  &$1.toklen, $2.xval,$2.lexval,$2.yval); }
			primp = findplace(envblock->son, chbuf, $1.chbufx, $1.toklen);
			if (primp != NULL) {
	    	  $4.prim->name = primp->name;
	    	  primp->name = NULL; }
			else {
	    	  With2 = $4.prim;
	    	  newstr(&With2->name);
	    	  storestring(With2->name, chbuf, $1.chbufx, $1.toklen, 1); }
			$$ = $4;
			donamedobj(&$$);
			}
		  clearchbuf($1.chbufx, $1.toklen);
		  }
		;

suffix	:                                                        /* suffix1 */
		{ $$.lexval = XEMPTY; }

		| XBRACKETL expression XBRACKETR                         /* suffix2 */
		{ if ($2.xval > maxint) { fatal(9); } else { $$.xval = $2.xval; } }

		| XBRACKETL position XBRACKETR                           /* suffix3 */
    	{ $$.lexval = Xcomma;
    	  $$.xval = $2.xval;
    	  $$.yval = $2.yval;
    	  if ((fabs($2.xval) > maxint) || (fabs($2.yval) > maxint)) {fatal(9);}
		  }
		;

position	:	pair                                           /* position1 */
			{ $$ = $1; }

		| expression XLbetween position XLand position         /* position2 */
		{ r = $1.xval;
    	  $$.xval = $3.xval + (r * ($5.xval - $3.xval));
    	  $$.yval = $3.yval + (r * ($5.yval - $3.yval)); }

		| expression XLof XLthe XLway XLbetween position XLand position
                                                               /* position3 */
		{
    	  r = $1.xval;
    	  $$.xval = $6.xval + (r * ($8.xval - $6.xval));
    	  $$.yval = $6.yval + (r * ($8.yval - $6.yval)); }

		| expression XLT position Xcomma position XLcompare shift
                                                               /* position4 */
		{ r = $1.xval;
    	  $$.xval = $3.xval + (r * ($5.xval - $3.xval));
    	  $$.yval = $3.yval + (r * ($5.yval - $3.yval));
		  if ($6.lexval != XGT) { markerror(869); }
		  else if ($7.lexval != XEMPTY) {
	   	    $$.xval += $7.xval;
	   	    $$.yval += $7.yval;
			}
		  }
		;

assignlist	:	assignment                                   /* assignlist1 */

		| assignlist Xcomma assignment                       /* assignlist2 */
		{ $$.xval = $3.xval; }
		;

command	:	XLprint expression redirect                         /* command1 */
		{ if ($3.lexval == XEMPTY) {
            wfloat(&errout, $2.xval); putc('\n', errout); }
    	  else if ($3.state == 0) {
#ifndef SAFE_MODE
	  		wfloat(&redirect, $2.xval); putc('\n', redirect);
			if (redirect != NULL) { fclose(redirect); }
			redirect = NULL;
#endif
			}
		  }

		| XLprint position redirect                             /* command2 */
		{ if ($3.lexval == XEMPTY) {
	  		wpair(&errout, $2.xval, $2.yval); putc('\n', errout); }
    	  else if ($3.state == 0) {
#ifndef SAFE_MODE
	  		wpair(&redirect, $2.xval, $2.yval);
			putc('\n', redirect);
			if (redirect != NULL) { fclose(redirect); }
			redirect = NULL;
#endif
			}
		  }

		| XLprint stringexpr redirect                           /* command3 */
		{ if ($3.lexval == XEMPTY) {
	      	wstring(&errout, $2.prim->textp);
			putc('\n', errout); }
    	  else if ($3.state == 0) {
#ifndef SAFE_MODE
	  		if ($2.prim != NULL) {
			  wstring(&redirect, $2.prim->textp); }
			putc('\n', redirect);
			if (redirect != NULL) { fclose(redirect); }
			redirect = NULL;
#endif
			}
		  deletestringbox(&$2.prim);
		  }

		| XLreset                                               /* command4 */
		{ resetenv(0, envblock); }

		| XLreset resetlist                                     /* command5 */

		| systemcmd                                             /* command6 */

		| XLcopy stringexpr                                     /* command7 */
		{ if ($2.prim != NULL) {
#ifdef SAFE_MODE
			markerror(901);
#else
			pointinput($2.prim->textp);
#endif
			deletestringbox(&$2.prim);
    		}
		  }

		| XLdefine XLname                                       /* command8 */
		{ currprod = 4;
          $$ = $2;
		  dodefhead( &$$ );
          }

		| XLdefine XLabel                                       /* command9 */
		{ currprod = 5;
          $$ = $2;
		  dodefhead( &$$ );
          }
		;

		| XLundefine XLname                                    /* command10 */
		{ $$ = $2; doundefine( &$2 );
		  clearchbuf($2.chbufx, $2.toklen); }

		| XLundefine XLabel                                    /* command11 */
		{ $$ = $2; doundefine( &$2 );
		  clearchbuf($2.chbufx, $2.toklen); }
		;

optnl	:                                                         /* optnl1 */

		| NL                                                      /* optnl2 */
		;

ifpart	:	ifhead elementlist optnl XRBRACE                     /* ifpart1 */
		;

elsehead:	ifpart XLelse XLBRACE                              /* elsehead1 */
		{ if ($1.xval == 1.0) { currprod = 1; skiptobrace(); } }
		;

for	:	forhead elementlist optnl                                   /* for1 */
		{ forattr = $$;
#ifdef DDEBUG
		  if (debuglevel>0) prattribute("for1",&$$);
#endif
		  }

		| for forincr elementlist optnl /* for2 */
		{ forattr = $$; }
		;

stringexpr:	string                                           /* stringexpr1 */
		{
#ifdef DDEBUG
		  if (debuglevel>0) {
			prattribute("stringexpr1",&$$);
            printobject($$.prim);
  			fflush(log_); }
#endif
		  }

		| stringexpr Xplus string                            /* stringexpr2 */
		{ if ($3.prim != NULL) { prp = $3.prim;
		  $$.prim->Upr.Ubox.boxwidth += prp->Upr.Ubox.boxwidth;
		  $$.prim->Upr.Ubox.boxheight = Max($1.prim->Upr.Ubox.boxheight,
			       prp->Upr.Ubox.boxheight);
		  if (prp->textp != NULL) {
    	    if ($1.prim->textp == NULL) {
			  $$.prim->textp = prp->textp; prp->textp = NULL; }
    		else if (($1.prim->textp->segmnt == prp->textp->segmnt) &&
	     		($1.prim->textp->seginx + $1.prim->textp->len ==
	      		  prp->textp->seginx)) {
			  $$.prim->textp->len += prp->textp->len;
			  putbval($$.prim->textp->segmnt,bval($1.prim->textp->segmnt)-1);
			  prp->textp->segmnt = NULL;
    		  }
    		else { appendstring($$.prim->textp, prp->textp->segmnt,
		        prp->textp->seginx, prp->textp->len); }
		  }
		deletetree(&$3.prim); }
		}
		;

string	:	XLstring                                             /* string1 */
		{ newprim(&$$.prim, XLstring, envblock);
		  eb = findenv(envblock);
		  With2 = $$.prim;
		  With2->Upr.Ubox.boxheight = eb->envinx(XLtextht);
		  With2->Upr.Ubox.boxwidth = eb->envinx(XLtextwid);
		  if (With2->Upr.Ubox.boxwidth == 0.0) {
			switch (drawmode) {
		  	  case xfig:
							/* To keep xfig from crashing, assume text height
							   is 0.1 and a character is 0.1*0.75 wide */
		  	  	if ($$.prim->Upr.Ubox.boxheight == 0.0) {
		  	      $$.prim->Upr.Ubox.boxheight = 0.1 * eb->envinx(XLscale); }
		  	  	$$.prim->Upr.Ubox.boxwidth =
				  $$.prim->Upr.Ubox.boxheight * $1.toklen * 0.75;
		  	  	break;
		  	  case PDF:
		  	  	$$.prim->Upr.Ubox.boxwidth =
				  $$.prim->Upr.Ubox.boxheight * $1.toklen * 0.6;
		  	  	break;
		  	  }
		    }
		  newstr(&With2->textp);
		  storestring(With2->textp, chbuf, $1.chbufx, $1.toklen, 1);
#ifdef DDEBUG
		  if (debuglevel>1) {
            prattribute("string1",&$$);
            printobject($$.prim);
  			fflush(log_); }
#endif
		  clearchbuf($1.chbufx, $1.toklen);
		  }

		| sprintf Xrparen                                        /* string2 */
		;

  /*      assignment = "<name>" suffix "=" assignrhs   */
assignment	:	XLname suffix XEQ assignrhs                  /* assignment1 */
		{ if ($2.lexval != XEMPTY) { addsuffix(chbuf, &$1.chbufx,
                &$1.toklen, $2.xval,$2.lexval,$2.yval); }
		    $$.varname = findname(envblock, chbuf, $1.chbufx, $1.toklen,
					     &lastvar, &k);
		    if (($$.varname == NULL) && ($3.lexval != XEQ)) {
			  $$.varname = glfindname(envblock->parent, chbuf,
				 $1.chbufx, $1.toklen, &namptr, &kk); }
		    if ($$.varname == NULL) {
			  newstr(&$$.varname);
			  j = varhash(chbuf, $1.chbufx, $1.toklen);
			  storestring($$.varname, chbuf, $1.chbufx, $1.toklen, 1);
		#ifdef DDEBUG
			if (debuglevel > 1) {
			    fprintf(log_, "assignment: j=%d envblock=%d eqstr=%d\n",
				    j,ordp(envblock), k);
			    fprintf(log_, " lastvar=%d", ordp(lastvar));
			    if (lastvar != NULL) {
				  snapname(lastvar->segmnt, lastvar->seginx, lastvar->len); }
			    putc('\n', log_);
			    fprintf(log_, " varname=%d\n", ordp($1.varname));
			    prvars(envblock);
			    }
		#endif
			With2 = envblock;
			if (lastvar == NULL) { With2->Upr.UBLOCK.vars[j] = $$.varname; }
			else if (k < 0) {
			  if (With2->Upr.UBLOCK.vars[j]->next_ == NULL) {
			    With2->Upr.UBLOCK.vars[j]->next_ = $$.varname; }
			  else {
				$$.varname->next_ = lastvar->next_;
				lastvar->next_ = $$.varname; }
			    }
			else if (lastvar == With2->Upr.UBLOCK.vars[j]) {
			  $$.varname->next_ = With2->Upr.UBLOCK.vars[j];
			  With2->Upr.UBLOCK.vars[j] = $$.varname; }
			else {
			  namptr = With2->Upr.UBLOCK.vars[j];
							/* while (namptr^.next<>nil) and
							   (namptr^.next<>lastvar) do */
			  while (namptr->next_ != lastvar) { namptr = namptr->next_; }
			  namptr->next_ = $$.varname;
			  $$.varname->next_ = lastvar;
			  }
			With2->Upr.UBLOCK.nvars[j]++;
			$$.varname->val = 0.0;
		    }
		  if ($3.lexval == XEQ) { $$.varname->val = $4.xval; }
		  else { eqop(&$$.varname->val, $3.lexval, $4.xval); }
		  $$.xval = $$.varname->val;

		  clearchbuf($1.chbufx, $1.toklen);
          }

		| XLenvvar XEQ assignrhs                             /* assignment2 */
		{ if (envblock != NULL) {
		    if (($1.lexval == XLarrowhead) && (drawmode == TeX) &&
		      ($3.xval == 0.0)) { markerror(858); }
		    else {
		      if (envblockB.env == NULL) { inheritenv(envblock); }
		      if ($1.lexval == XLscale) {
			    resetscale($3.xval, $2.lexval, envblock); }
		      else { eqop(&envblock->envinx($1.lexval), $2.lexval, $3.xval); }
		      }
		    $$.xval = envblock->envinx($1.lexval);
#ifdef DDEBUG
		    if (debuglevel > 0) {
		      fprintf(log_, " Assignment3or4 envblock[%d]: lexval=%d value=",
			    ordp(envblock), $1.lexval);
		      wfloat(&log_, envblock->envinx($1.lexval)); putc('\n', log_); }
#endif
		    $$.startchop = $$.lexval;
		    if (($$.lexval == XLdashwid) || ($$.lexval == XLlinethick)) {
		      newprim(&($$.prim), XLaTeX, envblock);
		      if ($1.lexval == XLlinethick) { $$.prim->lthick = $$.xval; }
		      else { $$.prim->lparam = $$.xval; }
		      }
	        }
		  }
		;

assignrhs : expression                                        /* assignrhs1 */

		| assignment                                          /* assignrhs2 */
		;

expression	:	term                                         /* expression1 */

		| Xplus term                                         /* expression2 */
		{ $$.xval = $2.xval; }

		| Xminus term                                        /* expression3 */
		{ $$.xval = -$2.xval; }

		| expression Xplus term                              /* expression4 */
		{ $$.xval = $1.xval + $3.xval; }

		| expression Xminus term                             /* expression5 */
		{ $$.xval = $1.xval - $3.xval; }
		;

ifhead	:	setlogic logexpr XLthen XLBRACE                      /* ifhead1 */
		{ inlogic = false;
    	  $$.xval = $2.xval;
    	  if ($$.xval == 0.0) {
		    currprod = 2 /* ifhead1 */;
		    skiptobrace();
    	    }
		  }
		;

setlogic:	XLif                                               /* setlogic1 */
		{ inlogic = true; }
		;

logexpr	:	logprod                                             /* logexpr1 */

		| logexpr XOROR logprod                                 /* logexpr2 */
		{ if (($1.xval != 0.0) || ($3.xval != 0.0)) { $$.xval = 1.0; }
    	  else { $$.xval = 0.0; }
		  }
		;

forhead	:	XFOR assignlist XLto expression do XLBRACE          /* forhead1 */
		{
		  $$.xval = $2.xval;                     /* initial value  */
		  $$.yval = $5.xval;                          /* increment */
		  $$.endchop = $4.xval;                     /* final value */
		  $$.toklen = 0;                                  /* flags */
		  if ($$.xval == $$.endchop) {
			$$.toklen = -1;
			$$.yval = 1.0; }
		  else if ($5.lexval == Xmult) {
			t = 0.0;
			if ($$.xval == 0.0) { $$.toklen = 860; }
			else { t = $$.endchop * $$.xval; }
			if (t < 0.0) { $$.toklen = 862; }
			else if ((t == 0.0) && (fabs($$.yval * $$.xval) != 0.0)) {
			  $$.toklen = 860; }
			else if (($$.yval == 0.0) && (t != 0.0)) { $$.toklen = 860; }
			else if ((fabs($$.yval) == 1) &&
				 (fabs($$.xval) != fabs($$.endchop))) { $$.toklen = 860; }
			else { $$.toklen = 1; }
		    }
		  else if ($$.yval == 0.0) { $$.toklen = 860; }
		  else if (($$.endchop - $$.xval) * $$.yval > 0) { $$.toklen = -1; }
		  if ($$.toklen > 800) { markerror($$.toklen); $$.toklen = 0; }
							/* store loop variable */
		  $$.startchop = $2.startchop;
		  if ($$.startchop == 0.0) {
			$$.varname = $2.varname;
			$$.varname->val = $$.xval; }
		  else if ((Rnd($$.startchop)) != XLscale) {
			if (envblockB.env == NULL) { inheritenv(envblock); }
			envblock->envinx($$.startchop) = $$.xval; }
		  else { resetscale($$.xval, XEQ, envblock); }

		  currprod = 3 /* forhead1 */ ;
		  if ($$.toklen == 0) { skiptobrace(); }
          else { readfor(NULL, 1, &inbuf, '}', true); }
#ifdef DDEBUG
    	  if (debuglevel > 0) {
            fprintf(log_," forhead:\n");
		    wrbufaddr(inbuf,0);
		    fprintf(log_, "for: initial="); wfloat(&log_, $$.xval);
		    fprintf(log_, " final="); wfloat(&log_, $$.endchop);
		    fprintf(log_, " incr="); wfloat(&log_, $$.yval);
		    putc('\n', log_); }
#endif
		  }
		;

forincr	: XLendfor                                              /* forincr1 */
		{ $$ = forattr;
	    With1 = &$$;
#ifdef DDEBUG
		if (debuglevel>1) prattribute("forincr1 $$",&$$);
#endif
	    if (With1->varname != NULL) { With1->xval = With1->varname->val; }
	    else { With1->xval = envblock->envinx(With1->startchop); }
	    bswitch = false;
	    if (With1->toklen < 0) {
		  if (With1->yval == 0) { bswitch = true; }
		  else {
		    With1->xval += With1->yval;
		    if (((With1->yval > 0) && (With1->xval > With1->endchop)) ||
			    ((With1->yval < 0) && (With1->xval < With1->endchop))) {
			  bswitch = true; }
		    }
	      }
	    else if (With1->xval == 0) { bswitch = true; }
	    else {
		  With1->xval *= With1->yval;
		  if (((fabs(With1->yval) >= 1.0) &&
		     (fabs(With1->xval) > fabs(With1->endchop))) ||
		    ((fabs(With1->yval) < 1.0) &&
		     (fabs(With1->xval) < fabs(With1->endchop)))) { bswitch= true; }
	      }
	    if (With1->varname != NULL) { With1->varname->val = With1->xval; }
	    else if ((Rnd(With1->startchop)) != XLscale) {
		  envblock->envinx(With1->startchop)= With1->xval; }
	    else { resetscale(With1->xval, XEQ, envblock); }
	    if (bswitch) {
		  while (inbuf->attrib < 0) {
		    lastm = inbuf;
		    inbuf = inbuf->higherb;
		    disposebufs(&lastm); }
		  lastm = inbuf;
		  inbuf = inbuf->higherb;
		  disposebufs(&lastm);
	      }
		}
		;

do	:	XLdo                                                         /* do1 */
		{ $$.xval = 1.0; }

		| by expression XLdo                                         /* do2 */
		{ $$.xval = $2.xval; }
		;

by	:	XLby                                                         /* by1 */

		| XLby Xmult                                                 /* by2 */
		{ $$.lexval = $2.lexval; }
		;

redirect:                                                      /* redirect1 */
		{ $$.lexval = XEMPTY; }

		| XLcompare stringexpr                                 /* redirect2 */
		{ With1 = &$2;
		  $$.state = 1;
		  bswitch = false;
		  if (With1->prim != NULL) {
			if (With1->prim->textp == NULL) { markerror(861); }
			else if ($1.lexval != XGT) { markerror(869); }
			else if (safemode) { markerror(901); }
			else { bswitch = true; }
		    }
#ifdef SAFE_MODE
		  if (bswitch) { markerror(901); }
#else
		  if (bswitch) { pointoutput(true,With1->prim->textp, &$$.state); }
#endif
		  deletestringbox(&With1->prim);
		  }

		| XLcompare XLcompare stringexpr                       /* redirect3 */
		{ With1 = &$3;
		  $$.state = 1;
		  bswitch = false;
		  if (With1->prim != NULL) {
			if (With1->prim->textp == NULL) { markerror(861); }
			else if (($1.lexval != XGT) || ($2.lexval != XGT)) {
			    markerror(869); }
			else if (safemode) { markerror(901); }
			else { bswitch = true; }
		    }
#ifdef SAFE_MODE
		  if (bswitch) { markerror(901); }
#else
		  if (bswitch) { pointoutput(false, With1->prim->textp, &$$.state); }
#endif
		  deletestringbox(&With1->prim);
		  }
		;

resetlist:	XLenvvar                                          /* resetlist1 */
		{ resetenv($1.lexval, envblock); }

		| resetlist Xcomma XLenvvar                           /* resetlist2 */
		{ resetenv($3.lexval, envblock); }
		;

systemcmd:	XLsh stringexpr                                   /* systemcmd1 */
		{ $$.xval = -1.0;
	      With1 = &$2;
	      if (With1->prim != NULL) {
		    if (With1->prim->textp != NULL) {
		      With4 = With1->prim->textp;
		      if (With4->segmnt != NULL) {
			    if (With4->seginx + With4->len >= CHBUFSIZ) {markerror(866); }
			    else if (safemode) { markerror(901); }
#ifndef SAFE_MODE
			    else {
			      With4->segmnt[With4->seginx + With4->len] = '\0';
			      $$.xval = system(&With4->segmnt[With4->seginx]); }
#endif
		        }
		      }
		    deletestringbox(&With1->prim);
	        }
#ifdef DDEBUG
		  if (debuglevel>1) { prattribute("systemcmd1",&$$); }
#endif
		  }
		;

sprintf	:	XLsprintf Xlparen stringexpr                        /* sprintf1 */
		{ dosprintf( &$$, &$3, &$3, 0 ); }

		| XLsprintf Xlparen stringexpr Xcomma exprlist          /* sprintf2 */
		{ dosprintf( &$$, &$3, &$5, $5.state ); }
		;

exprlist:	expression                                         /* exprlist1 */
		{ $$.state = 1; }

		| expression Xcomma exprlist                           /* exprlist2 */
		{ $$.state = $3.state + 1; }
		;

object	:	block                                                /* object1 */

		| object XLht expression                                 /* object2 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			switch (With2->ptype) {
			  case XLbox:
			  case XBLOCK:
			    if (With2->ptype == XBLOCK) {
			      r = 0.5 * ($3.xval - With2->Upr.UBLOCK.blockheight);
			      With2->Upr.UBLOCK.blockheight = $3.xval; }
			    else {
			      r = 0.5 * ($3.xval - With2->Upr.Ubox.boxheight);
			      With2->Upr.Ubox.boxheight = $3.xval; }
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLleft:
			        case XLright:
				      break; /* blank case */
			        case XLup:
				      shift($1.prim, 0.0, r);
				      break;
			        case XLdown:
				      shift($1.prim, 0.0, -r);
				      break;
			        }
			      }
			    break;
			  case XLstring:
	  			With2->Upr.Ubox.boxheight = $3.xval;
	  			if ((drawmode == PDF) && (With2->textp != NULL)) {
	      		  With2->Upr.Ubox.boxwidth = With2->Upr.Ubox.boxheight *
					With2->textp->len * 0.6;
	  			  }
	  			break;
			  case XLcircle:
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLleft:
			        case XLright:
				      break; /* blank case */
			        case XLup:
				      With2->aat.ypos +=
				        (0.5 * $3.xval) - With2->Upr.Ucircle.radius;
				      break;
			        case XLdown:
				      With2->aat.ypos +=
				        With2->Upr.Ucircle.radius - (0.5 * $3.xval);
				      break;
			        }
			      }
			    With2->Upr.Ucircle.radius = $3.xval * 0.5;
			    break;
			  case XLellipse:
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLleft:
			        case XLright:
				      break; /* blank case */
			        case XLup:
				      With2->aat.ypos +=
				        0.5 * ($3.xval - With2->Upr.Uellipse.elheight);
				      break;
			        case XLdown:
				      With2->aat.ypos +=
				        0.5 * (With2->Upr.Uellipse.elheight - $3.xval);
				      break;
			        }
			      }
			    With2->Upr.Uellipse.elheight = $3.xval;
			    break;
			  case XLline:
			  case XLarrow:
			  case XLmove:
			  case XLarc:
			  case XLspline:
			    prp = $1.prim;
			    while (prp != NULL) {
			      prp->Upr.Uline.height = $3.xval;
			      if (isthen(prp)) { prp = prp->parent; } else { prp = NULL; }
			      }
			    break;
			  case XLabel:
			  case XLaTeX:
			    markerror(858);
			    break;
			    }
		      }
			}

		| object XLwid expression                                /* object3 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			switch (With2->ptype) {
			  case XLbox:
			  case XBLOCK:
			    if (With2->ptype == XBLOCK) {
			      r = 0.5 * ($3.xval - With2->Upr.UBLOCK.blockwidth);
			      With2->Upr.UBLOCK.blockwidth = $3.xval; }
			  else {
			      r = 0.5 * ($3.xval - With2->Upr.Ubox.boxwidth);
			      With2->Upr.Ubox.boxwidth = $3.xval; }
			  if (!teststflag($1.state, XLat)) {
			    switch (With2->direction) {
			      case XLup:
			      case XLdown:
				    break; /* blank case */
			      case XLright:
				    shift($1.prim, r, 0.0);
				    break;
			      case XLleft:
				    shift($1.prim, -r, 0.0);
				    break;
			      }
			    }
			  break;
			case XLstring:
			  With2->Upr.Ubox.boxwidth = $3.xval;
			  break;
			case XLcircle:
			  if (!teststflag($1.state, XLat)) {
			    switch (With2->direction) {
			      case XLup:
			      case XLdown:
				    break; /* blank case */
			      case XLright:
				    With2->aat.xpos +=
				      (0.5 * $3.xval) - With2->Upr.Ucircle.radius;
				    break;
			      case XLleft:
				    With2->aat.xpos +=
				      With2->Upr.Ucircle.radius - (0.5 * $3.xval);
				    break;
			      }
			    }
			  With2->Upr.Ucircle.radius = $3.xval * 0.5;
			  break;
			case XLellipse:
			  if (!teststflag($1.state, XLat)) {
			    switch (With2->direction) {
			      case XLup:
			      case XLdown:
				    break; /* blank case */
			      case XLright:
				    With2->aat.xpos +=
				      0.5 * ($3.xval - With2->Upr.Uellipse.elwidth);
				    break;
			      case XLleft:
				    With2->aat.xpos +=
				      0.5 * (With2->Upr.Uellipse.elwidth - $3.xval);
				    break;
			      }
			    }
			  With2->Upr.Uellipse.elwidth = $3.xval;
			  break;
			case XLline:
			case XLarrow:
			case XLmove:
			case XLarc:
			case XLspline:
			  prp = $1.prim;
			  while (prp != NULL) {
			    prp->Upr.Uline.width = $3.xval;
			    if (isthen(prp)) { prp = prp->parent; }
			      else { prp = NULL; }
			    }
			  break;
			case XLabel:
			case XLaTeX:
			  markerror(858);
			  break;
			  }
		    }
	 	  }

		| object XLrad expression                                /* object4 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			switch (With2->ptype) {
			  case XLbox:
			    With2->Upr.Ubox.boxradius = $3.xval;
			    break;
			  case XLarc:
			    t = $3.xval;
			    if (With2->direction == 0) {
			      $3.xval = With2->aat.xpos + (With2->Upr.Uline.aradius *
                    cos( With2->Upr.Uline.endpos.xpos +
                         With2->Upr.Uline.endpos.ypos));
			      $3.yval = With2->aat.ypos + (With2->Upr.Uline.aradius *
                    sin( With2->Upr.Uline.endpos.xpos +
                         With2->Upr.Uline.endpos.ypos));
			      r = cos(With2->Upr.Uline.endpos.xpos);
			      s = sin(With2->Upr.Uline.endpos.xpos);
			      With2->aat.xpos += With2->Upr.Uline.aradius * r;
			      With2->aat.ypos += With2->Upr.Uline.aradius * s;
			      With2->Upr.Uline.aradius = t;
			      With2->aat.xpos -= With2->Upr.Uline.aradius * r;
			      With2->aat.ypos -= With2->Upr.Uline.aradius * s;
			      setstflag(&$1.state, XLradius);
			      goto object_xx;
			      }
			    else {
			      r = cos(With2->Upr.Uline.endpos.xpos);
			      s = sin(With2->Upr.Uline.endpos.xpos);
			      $$.prim->aat.xpos += With2->Upr.Uline.aradius * r;
			      $$.prim->aat.ypos += With2->Upr.Uline.aradius * s;
			      $$.prim->Upr.Uline.aradius = t;
			      $$.prim->aat.xpos -= With2->Upr.Uline.aradius * r;
			      $$.prim->aat.ypos -= With2->Upr.Uline.aradius * s;
			      setstflag(&$$.state, XLradius);
				  }
			    break;
			  case XLcircle:
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLleft:
				      With2->aat.xpos += With2->Upr.Ucircle.radius - $3.xval;
				      break;
			        case XLright:
				      With2->aat.xpos += $3.xval - With2->Upr.Ucircle.radius;
				      break;
			        case XLup:
				      With2->aat.ypos += $3.xval - With2->Upr.Ucircle.radius;
				      break;
			        case XLdown:
				      With2->aat.ypos += With2->Upr.Ucircle.radius - $3.xval;
				      break;
			        }
			      }
			    With2->Upr.Ucircle.radius = $3.xval;
			    setstflag(&$1.state, XLradius);
			    break;
			  default:
			    markerror(858);
			    break;
			  }
		    }
		  }

		| object XLdiam expression                               /* object5 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			if (With2->ptype == XLcircle) {
			  r = 0.5 * $3.xval;
			  if (!teststflag($1.state, XLat)) {
				switch (With2->direction) {
				  case XLleft:
				    With2->aat.xpos += With2->Upr.Ucircle.radius - r;
				    break;
				  case XLright:
				    With2->aat.xpos += r - With2->Upr.Ucircle.radius;
				    break;
				  case XLup:
				    With2->aat.ypos += r - With2->Upr.Ucircle.radius;
				    break;
				  case XLdown:
				    With2->aat.ypos += With2->Upr.Ucircle.radius - r;
				    break;
				  }
			    }
			  With2->Upr.Ucircle.radius = r;
			  }
			else { markerror(858); }
		    }
		  }

		| object XLthick expression                              /* object6 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			if ($3.xval < 0.0) {
			  eb = findenv(envblock);
			  With2->lthick = eb->envinx(XLlinethick);
			  }
			else { With2->lthick = $3.xval; }
		    }
		  }

		| object XLscaled expression                             /* object7 */
		{ if (($1.prim != NULL) && ($3.lexval != XEMPTY)) {
			With2 = $$.prim;
			r = $3.xval - 1;
			corner($1.prim, XDc, &x1, &z1);
			switch (With2->ptype) {
			  case XLbox:
			  case XBLOCK:
			  case XLstring:
			    if (teststflag($1.state, XLat)) {
			      dx = 0.0;
			      dy = 0.0;
			      }
			    else if (With2->ptype == XBLOCK) {
			      dx = With2->Upr.UBLOCK.blockwidth * r / 2;
			      dy = With2->Upr.UBLOCK.blockheight * r / 2;
			      }
			    else {
			      dx = With2->Upr.Ubox.boxwidth * r / 2;
			      dy = With2->Upr.Ubox.boxheight * r / 2;
			      }
			    scaleobj($$.prim, $3.xval);
			    switch (With2->direction) {
			      case XLright: shift(
                    $$.prim, x1 - With2->aat.xpos + dx, z1 - With2->aat.ypos);
			        break;
			      case XLleft: shift(
                    $$.prim, x1 - With2->aat.xpos - dx, z1 - With2->aat.ypos);
			        break;
			      case XLup: shift(
                    $$.prim, x1 - With2->aat.xpos, z1 - With2->aat.ypos + dy);
			        break;
			      case XLdown: shift(
                    $$.prim, x1 - With2->aat.xpos, z1 - With2->aat.ypos - dy);
			        break;
			      }
			    break;
			  case XLcircle:
			    With2->Upr.Ucircle.radius = $3.xval * With2->Upr.Ucircle.radius;
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLup:
				      With2->aat.xpos = x1;
				      With2->aat.ypos = z1 + With2->Upr.Ucircle.radius;
				      break;
			        case XLdown:
				      With2->aat.xpos = x1;
				      With2->aat.ypos = z1 - With2->Upr.Ucircle.radius;
				      break;
			        case XLright:
				      With2->aat.xpos = x1 + With2->Upr.Ucircle.radius;
				      With2->aat.ypos = z1;
				      break;
			        case XLleft:
				      With2->aat.xpos = x1 - With2->Upr.Ucircle.radius;
				      With2->aat.ypos = z1;
				      break;
			        }
			      }
			    break;
			  case XLellipse:
			    With2->Upr.Uellipse.elwidth *= $3.xval;
			    With2->Upr.Uellipse.elheight *= $3.xval;
			    if (!teststflag($1.state, XLat)) {
			      switch (With2->direction) {
			        case XLup:
				      With2->aat.xpos = x1;
				      With2->aat.ypos = z1 + (With2->Upr.Uellipse.elheight / 2);
				      break;
			        case XLdown:
				      With2->aat.xpos = x1;
				      With2->aat.ypos = z1 - (With2->Upr.Uellipse.elheight / 2);
				      break;
			        case XLright:
				      With2->aat.xpos = x1 + (With2->Upr.Uellipse.elwidth / 2);
				      With2->aat.ypos = z1;
				      break;
			        case XLleft:
				      With2->aat.xpos = x1 - (With2->Upr.Uellipse.elwidth / 2);
				      With2->aat.ypos = z1;
				      break;
			        }
			      }
			    break;
			  case XLline:
			  case XLarrow:
			  case XLmove:
			  case XLarc:
			  case XLspline:
			    scaleobj($$.prim, $3.xval);
			    corner($$.prim, XDc, &r, &s);
			    shift($$.prim, x1 - r, z1 - s);
			    break;
			  case XLabel:
			  case XLaTeX:
			    markerror(858);
			    break;
			  }
		    }
		  }

		| object XLdirecton optexp                               /* object8 */
		{ if ($$.prim != NULL) {
			With2 = $$.prim;
			if ((With2->ptype == XLspline) || (With2->ptype == XLarrow) ||
			    (With2->ptype == XLmove) || (With2->ptype == XLline) ||
			    (With2->ptype == XLarc)) {
			  i = $2.lexval;
			  envblock->direction = i;
			  eb = findenv(envblock);
			  switch (With2->ptype) {
			    case XLarc:
			      r = cos(With2->Upr.Uline.endpos.xpos);
			      s = sin(With2->Upr.Uline.endpos.xpos);
			      With2->aat.xpos += With2->Upr.Uline.aradius * r;
			      With2->aat.ypos += With2->Upr.Uline.aradius * s;
				  nwi = With2->direction;
			      if (((nwi == XLup) && (i == XLleft)) ||
				      ((nwi == XLdown) && (i == XLright)) ||
				      ((nwi == XLright) && (i == XLup)) ||
				      ((nwi == XLleft) && (i == XLdown))) {
				    With2->Upr.Uline.endpos.ypos = pi * 0.5; }
			      else if (((nwi == XLup) && (i == XLright)) ||
				      ((nwi == XLdown) && (i == XLleft)) ||
				      ((nwi == XLright) && (i == XLdown)) ||
				      ((nwi == XLleft) && (i == XLup))) {
				    With2->Upr.Uline.endpos.ypos = (-pi) * 0.5; }
			      if ($3.lexval != XEMPTY) {
				    With2->Upr.Uline.aradius = $3.xval; }
			      With2->aat.xpos -= With2->Upr.Uline.aradius * r;
			      With2->aat.ypos -= With2->Upr.Uline.aradius * s;
			      With2->direction = i;
			      break;
			    case XLline:
			    case XLmove:
			    case XLarrow:
			    case XLspline:
			      With2->direction = i;
			      if ($3.lexval != XEMPTY) { r = $3.xval; s = r; }
			      else { switch (With2->ptype) {
				    case XLline:
				    case XLarrow:
				    case XLspline:
				      r = eb->envinx(XLlineht);
				      s = eb->envinx(XLlinewid);
				      break;
				    case XLmove:
				      r = eb->envinx(XLmoveht);
				      s = eb->envinx(XLmovewid);
				      break;
				      }
			        }
			      lineardir($$.prim, r, s, &$$.state);
			      break;
			      }
			  }
			else { markerror(858); }
		    }
#ifdef DDEBUG
	    if (debuglevel > 0) { printobject($$.prim); }
#endif
		  }

		| object XLlinetype optexp                               /* object9 */
		{ if ($1.prim != NULL) {
			setspec(&$$.prim->spec, $2.lexval);
			if ($3.lexval == XEMPTY) {
              if ($2.lexval == XLdashed) {
				eb = findenv(envblock);
                $$.prim->lparam = eb->envinx(XLdashwid); }
              }
            else if ((($2.lexval == XLsolid) || ($2.lexval == XLinvis))
               && (($1.prim->ptype == XLmove) || ($1.prim->ptype == XLspline)
                || ($1.prim->ptype == XLarrow) || ($1.prim->ptype == XLline))) {
			  lineardir($$.prim, $3.xval, $3.xval, &$$.state); }
			else if (($2.lexval == XLsolid) || ($2.lexval == XLinvis)) {
			  markerror(858); }
			else { $$.prim->lparam = $3.xval; }
		    }
#ifdef DDEBUG
	    if (debuglevel > 0) { printobject($$.prim); }
#endif
		  }

		| object XLchop optexp                                  /* object10 */
		{ if ($1.prim != NULL) {
			if (($1.prim->ptype != XLspline) &&
			    ($1.prim->ptype != XLmove) &&
			    ($1.prim->ptype != XLarrow) && ($1.prim->ptype != XLline)) {
			  markerror(858); }
			else {
			  With2 = $1.prim;
			  if ($3.lexval != XEMPTY) { r = $3.xval; }
			  else {
				eb = findenv(envblock);
				r = eb->envinx(XLcirclerad);
			    }
			  if (teststflag($$.state, XLchop)) { $$.endchop = r; }
			  else {
				$$.startchop = r;
				$$.endchop = r;
				setstflag(&$$.state, XLchop);
			    }
			  }
		    }
		  }

		| object XLfill optexp                                  /* object11 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			if ($3.lexval != XEMPTY) { s = $3.xval; }
			else {
			  eb = findenv(envblock);
			  s = eb->envinx(XLfillval);
			  }
			prp = $$.prim;
			while (prp != NULL) {
			  switch (With2->ptype) {
			    case XLbox:
			      prp->Upr.Ubox.boxfill = s;
			      break;
			    case XLcircle:
			      prp->Upr.Ucircle.cfill = s;
			      break;
			    case XLellipse:
			      prp->Upr.Uellipse.efill = s;
			      break;
			    default:
			      if ((drawmode >= 0) && (drawmode < 32) &&
				  (((1L << drawmode) &
				    ((1L << TeX) | (1L << tTeX) | (1L << Pict2e))) != 0)) {
				    markerror(858); }
			      else {
				    switch (With2->ptype) {
				      case XLline:
				      case XLarrow:
				      case XLmove:
				      case XLspline:
				      case XLarc:
				        prp->Upr.Uline.lfill = s;
				        break;
				      default:
				        markerror(858);
				        break;
				      }
			        }
			      break;
			    }
			  if (isthen(prp)) { prp = prp->parent; }
			  else { prp = NULL; }
			  }
		    }
		  }

		| object XLarrowhd optexp                               /* object12 */
		{ if ($$.prim != NULL) {
			With2 = $$.prim;
			if ((With2->ptype != XLspline) && (With2->ptype != XLarc) &&
			    (With2->ptype != XLarrow) && (With2->ptype != XLline)) {
			  markerror(858); }
			else {
			  With2->Upr.Uline.atype =
                pahlex(With2->Upr.Uline.atype,$2.lexval);
			  if ($3.lexval != XEMPTY) { lj = Rnd($3.xval); }
			  else {
				eb = findenv(envblock);
				lj = (long)floor(eb->envinx(XLarrowhead)+0.5);
			    }
			  With2->Upr.Uline.atype = pahnum(With2->Upr.Uline.atype, lj);
			  }
		    }
		  }

		| object XLthen                                         /* object13 */
		{ if ($1.prim != NULL) {
#ifdef DDEBUG
		    if (debuglevel > 0) {
	          fprintf(log_, "lexical \"then\" found, ");
	          prtstval($1.state); putc('\n', log_); }
#endif
			appendthen(&$$.prim);
			if ($1.prim->ptype != XLarc) { setstflag(&$$.state, XEMPTY); }
		    }
		  }

		| object XLcw                                           /* object14 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			if (With2->ptype != XLarc) { markerror(858); }
			else {
			  if ((With2->Upr.Uline.endpos.ypos > 0.0) &&
                  (With2->direction == 0)) {
				With2->Upr.Uline.endpos.ypos = -fabs(
				  principal((2.0 * pi) - With2->Upr.Uline.endpos.ypos,2.0*pi));}
			  else if (With2->direction != 0) {
				With2->aat = arcstart($$.prim);
				switch (With2->direction) {
				  case XLup:
				    With2->aat.xpos += With2->Upr.Uline.aradius;
				    break;
				  case XLdown:
				    With2->aat.xpos -= With2->Upr.Uline.aradius;
				    break;
				  case XLleft:
				    With2->aat.ypos += With2->Upr.Uline.aradius;
				    break;
				  case XLright:
				    With2->aat.ypos -= With2->Upr.Uline.aradius;
				    break;
				  }
				if (With2->Upr.Uline.endpos.ypos > 0.0) {
				    With2->Upr.Uline.endpos.xpos =
                      principal(With2->Upr.Uline.endpos.xpos + pi, pi); }
				With2->Upr.Uline.endpos.ypos =
                 -fabs(With2->Upr.Uline.endpos.ypos);
			    }
			  setstflag(&$$.state, XLcw);
			  }
		    }
		  }

		| object XLccw                                          /* object15 */
		{ if ($1.prim != NULL) {
			With2 = $1.prim;
			if (With2->ptype != XLarc) { markerror(858); }
			else {
			  if ((With2->Upr.Uline.endpos.ypos < 0.0) &&
                (With2->direction == 0)) {
				With2->Upr.Uline.endpos.ypos = fabs(
				  principal(With2->Upr.Uline.endpos.ypos - (2.0 * pi),2.0*pi));}
			  else if (With2->direction != 0) {
				With2->aat = arcstart($1.prim);
				switch (With2->direction) {
				  case XLup:
				    With2->aat.xpos -= With2->Upr.Uline.aradius;
				    break;
				  case XLdown:
				    With2->aat.xpos += With2->Upr.Uline.aradius;
				    break;
				  case XLleft:
				    With2->aat.ypos -= With2->Upr.Uline.aradius;
				    break;
				  case XLright:
				    With2->aat.ypos += With2->Upr.Uline.aradius;
				    break;
				  }
				if (With2->Upr.Uline.endpos.ypos < 0.0) {
				  With2->Upr.Uline.endpos.xpos =
                    principal( With2->Upr.Uline.endpos.xpos + pi, pi); }
				With2->Upr.Uline.endpos.ypos =
                  fabs(With2->Upr.Uline.endpos.ypos);
			    }
			  setstflag(&$1.state, XLccw);
			  }
		    }
		  }

		| object XLsame                                         /* object16 */
		{ if ($1.prim != NULL) {
			prp = nthprimobj(envblock->son, 0, $1.prim->ptype);
			if (prp == NULL) { markerror(857); }
			else {
			  With2 = $1.prim;
			  With2->lparam = prp->lparam;
			  With2->lthick = prp->lthick;
			  With2->direction = prp->direction;
			  With2->spec = prp->spec;
			  if (hasoutline($1.lexval, false)) {
				copystr(&With2->outlinep, prp->outlinep); }
			  if (hasshade($1.lexval, false)) {
				copystr(&With2->shadedp, prp->shadedp); }
			  }
			if (prp != NULL) {
			  With2 = $1.prim;
			  switch (With2->ptype) {
			    case XLbox:
			    case XLstring:
			      if (With2->ptype == XLbox) {
				    switch (With2->direction) {
				      case XLup:
				        With2->aat.ypos += 0.5 *
					    (prp->Upr.Ubox.boxheight - With2->Upr.Ubox.boxheight);
				        break;
				      case XLdown:
				        With2->aat.ypos -= 0.5 *
					    (prp->Upr.Ubox.boxheight - With2->Upr.Ubox.boxheight);
				        break;
				      case XLleft:
				        With2->aat.xpos -=
				          0.5 * (prp->Upr.Ubox.boxwidth -
						    With2->Upr.Ubox.boxwidth);
				        break;
				      case XLright:
				        With2->aat.xpos +=
				          0.5*(prp->Upr.Ubox.boxwidth-With2->Upr.Ubox.boxwidth);
				        break;
				      }
			        }
			      With2->Upr.Ubox.boxfill = prp->Upr.Ubox.boxfill;
			      With2->Upr.Ubox.boxheight = prp->Upr.Ubox.boxheight;
			      With2->Upr.Ubox.boxwidth = prp->Upr.Ubox.boxwidth;
			      With2->Upr.Ubox.boxradius = prp->Upr.Ubox.boxradius;
			      break;
			    case XBLOCK:
			      markerror(858);
			      break;
			    case XLcircle:
			      switch (With2->direction) {
			        case XLup:
				      With2->aat.ypos +=
                        prp->Upr.Ucircle.radius - With2->Upr.Ucircle.radius;
				      break;
			        case XLdown:
				      With2->aat.ypos +=
                        With2->Upr.Ucircle.radius - prp->Upr.Ucircle.radius;
				      break;
			        case XLleft:
				      With2->aat.xpos +=
                        With2->Upr.Ucircle.radius - prp->Upr.Ucircle.radius;
				      break;
			        case XLright:
				      With2->aat.xpos +=
                        prp->Upr.Ucircle.radius - With2->Upr.Ucircle.radius;
				      break;
			        }
			      With2->Upr.Ucircle.cfill = prp->Upr.Ucircle.cfill;
			      With2->Upr.Ucircle.radius = prp->Upr.Ucircle.radius;
			      break;
			    case XLellipse:
			      switch (With2->direction) {
			        case XLup:
				      With2->aat.ypos +=
				        0.5 * (prp->Upr.Uellipse.elheight -
                          With2->Upr.Uellipse.elheight);
				      break;
			        case XLdown:
				      With2->aat.ypos -=
				        0.5 * (prp->Upr.Uellipse.elheight -
                          With2->Upr.Uellipse.elheight);
				      break;
			        case XLleft:
				      With2->aat.xpos -=
				        0.5 * (prp->Upr.Uellipse.elwidth -
                          With2->Upr.Uellipse.elwidth);
				      break;
			        case XLright:
				      With2->aat.xpos +=
				        0.5 * (prp->Upr.Uellipse.elwidth -
                          With2->Upr.Uellipse.elwidth);
				      break;
			        }
			      With2->Upr.Uellipse.efill = prp->Upr.Uellipse.efill;
			      With2->Upr.Uellipse.elheight = prp->Upr.Uellipse.elheight;
			      With2->Upr.Uellipse.elwidth = prp->Upr.Uellipse.elwidth;
			      break;
			    case XLarc:
			      x1 = With2->aat.xpos + (With2->Upr.Uline.aradius *
                    cos(With2->Upr.Uline.endpos.xpos));
			      z1 = With2->aat.ypos + (With2->Upr.Uline.aradius *
                    sin(With2->Upr.Uline.endpos.xpos));
			      With2->Upr.Uline.aradius = prp->Upr.Uline.aradius;
			      With2->Upr.Uline.endpos.xpos = prp->Upr.Uline.endpos.xpos;
			      With2->aat.xpos = x1 - (With2->Upr.Uline.aradius *
						      cos(With2->Upr.Uline.endpos.xpos));
			      With2->aat.ypos = z1 - (With2->Upr.Uline.aradius *
						      sin(With2->Upr.Uline.endpos.xpos));
			      With2->Upr.Uline.endpos.ypos = prp->Upr.Uline.endpos.ypos;
			      break;
			    case XLline:
			    case XLarrow:
			    case XLmove:
			    case XLspline:
			      With2->Upr.Uline.endpos.xpos =
				    With2->aat.xpos + prp->Upr.Uline.endpos.xpos-prp->aat.xpos;
			      With2->Upr.Uline.endpos.ypos =
				    With2->aat.ypos + prp->Upr.Uline.endpos.ypos-prp->aat.ypos;
			      With2->Upr.Uline.height = prp->Upr.Uline.height;
			      With2->Upr.Uline.width = prp->Upr.Uline.width;
			      With2->Upr.Uline.atype = prp->Upr.Uline.atype;
			      break;
			    case XLabel:
			    case XLaTeX:
			      markerror(858);
			      break;
			    }
			  }
		    }
		  }

		| object stringexpr                                     /* object17 */
		{ if ($2.prim != NULL) {
			if ($1.prim != NULL) {
			  With2 = $1.prim;
			  if (With2->textp == NULL) { With2->textp = $2.prim->textp; }
			  else {
				namptr = With2->textp;
				i = 1;
				while (namptr->next_ != NULL) { namptr = namptr->next_; i++; }
				namptr->next_ = $2.prim->textp;
				if (With2->ptype == XLstring) {
				  if (drawmode == SVG) {
					eb = findenv(envblock);
					if (eb != NULL) {
					  r = findvar("dptextratio", 11);
					  if (r == 0) { r = 1.0; }
					  With2->Upr.Ubox.boxheight += eb->envinx(XLtextht) / r;
					  }
				    }
				  else { With2->Upr.Ubox.boxheight *= ((i + 1) / i); }
				  }
			    }
			  if ((drawmode == PS) || (drawmode == PDF) ||
			      (drawmode == PSfrag)) { /* output contains text */
				printstate = ((printstate >> 1) * 2) + 1;
			    }
			  }
			$2.prim->textp = NULL;
			deletestringbox(&$2.prim);
		    }
		  }

		| object XLby position                                  /* object18 */
		{ if ($1.prim != NULL) {
			$$  = $1;
			if (($1.prim->ptype == XLmove) || ($1.prim->ptype == XLspline) ||
			  ($1.prim->ptype == XLarrow) || ($1.prim->ptype == XLline) ||
			  ($1.prim->ptype == XLarc)) {
			    With2 = $1.prim;
			    x1 = $3.xval + With2->aat.xpos;
			    z1 = $3.yval + With2->aat.ypos;
			    if (With2->ptype == XLarc) {
				  x1 += With2->Upr.Uline.aradius *
                    cos(With2->Upr.Uline.endpos.xpos);
				  z1 += With2->Upr.Uline.aradius *
                    sin(With2->Upr.Uline.endpos.xpos);
			      }
			    $3.xval = x1;
			    $3.yval = z1;
                goto object_xx;
			    }
			  else { markerror(858); }
		    }
		  }

		| object XLfrom position                                /* object19 */
		{ if ($1.prim != NULL) {
			With2 = $$.prim;
			if ((With2->ptype == XLmove) || (With2->ptype == XLspline) ||
			  (With2->ptype == XLarrow) || (With2->ptype == XLline) ||
              (With2->ptype == XLarc)) {
			    if (With2->ptype == XLarc) {
				 r = $3.xval;
				 s = $3.yval;
				if (teststflag($1.state, XLto)) {
				  $3.xval = With2->aat.xpos + (With2->Upr.Uline.aradius *
                    cos( With2->Upr.Uline.endpos.xpos +
                        With2->Upr.Uline.endpos.ypos));
				  $3.yval = With2->aat.ypos + (With2->Upr.Uline.aradius *
                    sin( With2->Upr.Uline.endpos.xpos +
                         With2->Upr.Uline.endpos.ypos));
				  }
				With2->aat.xpos = r - (With2->Upr.Uline.aradius *
						       cos(With2->Upr.Uline.endpos.xpos));
				With2->aat.ypos = s - (With2->Upr.Uline.aradius *
						       sin(With2->Upr.Uline.endpos.xpos));
				if (teststflag($1.state, XLto)) { goto object_xx; }
			    }
			  else if (!teststflag($1.state, XLto)) {
				prp = $1.prim;
				while (isthen(prp)) { prp = prp->parent; }
				shift(prp, $3.xval - prp->aat.xpos, $3.yval - prp->aat.ypos);
			    }
			  else {
				With2->aat.xpos = $3.xval;
				With2->aat.ypos = $3.yval; }
			  setstflag(&$1.state, XLfrom);
			  }
			else { markerror(858); }
		    }
		  }

		| object XLto position                                  /* object20 */
		{
          object_xx:
    	    if ($1.prim != NULL) {
    	      if (($1.prim->ptype == XLmove) || ($1.prim->ptype == XLspline) ||
    	        ($1.prim->ptype == XLarrow) || ($1.prim->ptype == XLline) ||
    	        ($1.prim->ptype == XLarc)) {
    	        if (($1.prim->ptype != XLarc) & teststflag($1.state, XLto)) {
#ifdef DDEBUG
    	    	  if (debuglevel > 0) {
    	    	    fprintf(log_, "\"then\" inserted, \n");
    	    	    prtstval($1.state); putc('\n', log_); }
#endif
    	    	  appendthen(&$$.prim);
    	    	  setstflag(&$$.state, XEMPTY);
    	          }
    	        With2 = $$.prim;
    	        if (With2->ptype != XLarc) {
    	    	  With2->Upr.Uline.endpos.xpos = $3.xval;
    	    	  With2->Upr.Uline.endpos.ypos = $3.yval;
    	          }
    	        else {
    	    	  x1 = With2->aat.xpos + (With2->Upr.Uline.aradius *
                    cos(With2->Upr.Uline.endpos.xpos));
    	    	  z1 = With2->aat.ypos + (With2->Upr.Uline.aradius *
                    sin(With2->Upr.Uline.endpos.xpos));
    	    	  dx = $3.xval - x1;
    	    	  dy = $3.yval - z1;
    	    	  ts = (dx * dx) + (dy * dy);
    	    	  if (With2->direction != 0) { i = With2->direction; }
    	    	else { i = $$.toklen; }
#ifdef DDEBUG
    	    	if (debuglevel == 2) {
    	    	  fprintf(log_, " (x1,z1)="); wpair(&log_, x1, z1);
    	    	  fprintf(log_, " (dx,dy)="); wpair(&log_, dx, dy);
    	    	  fprintf(log_, " ts="); wfloat(&log_, ts);
    	    	  fprintf(log_, " i=%d", i); }
#endif
    	    	if (ts == 0.0) { With2->Upr.Uline.endpos.ypos = 0.0; }
    	    	else {
    	    	    t = sqrt(Max(0.0, (4.0 * With2->Upr.Uline.aradius * With2->
    	    				 Upr.Uline.aradius) - ts) / ts);
#ifdef DDEBUG
    	    	    if (debuglevel == 2) {
    	    		  fprintf(log_, " t="); wfloat(&log_, t);
    	    		  fprintf(log_, " |arcangle|=");
    	    		  wfloat(&log_, With2->Upr.Uline.endpos.ypos * 180 / pi);
    	    		  putc('\n', log_); }
#endif
    	    	    r = sqrt(ts);               /* t is always nonnegative  */
    	    	    if (t <= 0.0) { With2->Upr.Uline.aradius = 0.5 * r; }
    	    	    switch (i) {
							/* Determine which of the two default arcs to
							   draw: */
    	    	    case XLup:
    	    	      if (With2->Upr.Uline.endpos.ypos *
                        ((-dx) - (t * dy)) < 0.0) { t = -t; }
    	    	      break;
    	    	    case XLdown:
    	    	      if (With2->Upr.Uline.endpos.ypos *
                        ((-dx) - (t * dy)) > 0.0) { t = -t; }
    	    	      break;
    	    	    case XLright:
    	    	      if (With2->Upr.Uline.endpos.ypos *
                        (dy - (t * dx)) < 0.0) { t = -t; }
    	    	      break;
    	    	    case XLleft:
    	    	      if (With2->Upr.Uline.endpos.ypos *
                        (dy - (t * dx)) > 0.0) { t = -t; }
    	    	      break;
    	    	      }
    	    	    With2->aat.xpos = x1 + (0.5 * (dx + (t * dy)));
    	    	    With2->aat.ypos = z1 + (0.5 * (dy - (t * dx)));
#ifdef DDEBUG
    	    	    if (debuglevel == 2) {
    	    		  fprintf(log_, " t="); wfloat(&log_, t);
    	    		  fprintf(log_, " aradius=");
    	    		  wfloat(&log_, With2->Upr.Uline.aradius);
    	    		  fprintf(log_, " aat=");
    	    		  wpair(&log_, With2->aat.xpos, With2->aat.ypos);
    	    		  putc('\n', log_);
    	    	      }
#endif
    	    	    setangles(&With2->Upr.Uline.endpos.xpos,
    	    		      &With2->Upr.Uline.endpos.ypos, With2->aat, x1, z1,
    	    		      $3.xval, $3.yval);
    	    	}
							/* ratio centre-to-chord/half-chord */
    	    	    if (With2->direction != 0) { $$.toklen = With2->direction; }
    	    	    With2->direction = 0;
    	            }
    	          setstflag(&$$.state, XLto);
#ifdef DDEBUG
    	          if (debuglevel > 0) { printobject($$.prim); }
#endif
    	        }
    	      else { markerror(858); }
    	      }
		   }

		| object XLat position                                  /* object21 */
		{ if ($1.prim != NULL) {
			$$.xval = $3.xval;
			$$.yval = $3.yval;
			if ((drawmode != SVG) || (getstval($1.state) == 0)) {
			    setstval(&$$.state, XDc); }
			setstflag(&$$.state, XLat);
#ifdef DDEBUG
		    if (debuglevel > 0) {
	    	  fprintf(log_, " (xval,yval)=");
	    	  wpair(&log_, $$.xval, $$.yval);
	    	  fprintf(log_, " state=%d val=%d flag=%d\n",
		      $$.state, $$.state >> 8, $$.state & 255);
		      }
#endif
		    }
		  }

		| object XLtextpos                                      /* object22 */
		{ if ($1.prim != NULL) {
			namptr = $$.prim->textp;
			if (namptr != NULL) {
			  while (namptr->next_ != NULL) { namptr = namptr->next_; }
			  setjust(namptr, $2.lexval);
			  if (drawmode == SVG) {
				With2 = $$.prim;
				if (!teststflag($$.state, XLat)) {
				  $$.xval = With2->aat.xpos;
				  $$.yval = With2->aat.ypos;
				  setstflag(&$$.state, XLat); }
				setstflag(&$$.state, XLcw);
				i = getstval($$.state);
				if ((With2->ptype != XLmove) && (With2->ptype != XLspline) &&
				    (With2->ptype != XLarrow) && (With2->ptype != XLline)) {
				  switch ($2.lexval) {
				    case XLljust:
				      if (i == XDn) { setstval(&$$.state, XDnw); }
				      else if (i == XDs) { setstval(&$$.state, XDsw); }
				      else { setstval(&$$.state, XDw); }
				      break;
				    case XLrjust:
				      if (i == XDn) { setstval(&$$.state, XDne); }
				      else if (i == XDs) { setstval(&$$.state, XDse); }
				      else { setstval(&$$.state, XDe); }
				      break;
				    case XLbelow:
				      if (i == XDe) { setstval(&$$.state, XDne); }
				      else if (i == XDw) { setstval(&$$.state, XDnw); }
				      else { setstval(&$$.state, XDn); }
				      break;
				    case XLabove:
				      if (i == XDe) { setstval(&$$.state, XDse); }
				      else if (i == XDw) { setstval(&$$.state, XDsw); }
				      else { setstval(&$$.state, XDs); }
				      break;
				    }
				  }
			    }
			  }
			else { markerror(861); }
		    }
		  }

		| object XLcolrspec stringexpr                          /* object23 */
		{ if ((drawmode == Pict2e) || (drawmode == TeX) ||
		      (drawmode == tTeX) || (drawmode == xfig)) { markerror(858); }
		  else if (($3.prim != NULL) && ($1.prim != NULL)) {
			With2 = $$.prim;
			switch ($2.lexval) {
			case XLshaded:
			  if (hasshade($1.lexval, true)) {
			    deletename(&With2->shadedp);
			    With2->shadedp = $3.prim->textp;
			    $3.prim->textp = NULL;
			    }
			  break;
			case XLoutlined:
			  if (hasoutline($1.lexval, true)) {
			    deletename(&With2->outlinep);
			    With2->outlinep = $3.prim->textp;
			    $3.prim->textp = NULL;
			    }
			  break;
			case XLcolour:
			  if (hasoutline($1.lexval, true)) {
			    deletename(&With2->outlinep);
			    With2->outlinep = $3.prim->textp;
			    $3.prim->textp = NULL;
				i = With2->ptype;
			    if (((i != XLspline) && (i != XLarrow) && (i != XLline) &&
				   (i != XLarc)) & hasshade($1.lexval, false)) {
				  deletename(&With2->shadedp);
				  copystr(&With2->shadedp, With2->outlinep);
			      }
			    }
			  break;
			  }
		    }
		    deletestringbox(&$3.prim);
		  }

		| objectwith XLat position                              /* object24 */
		{ if ($1.prim != NULL) {
			$$.xval = $3.xval;
			$$.yval = $3.yval;
			setstval(&$$.state, XEMPTY);
			setstflag(&$$.state, XLat);
		    }
		  }

		| objectwith XLcorner XLat position                     /* object25 */
		{ if ($1.prim != NULL) {
			$$.xval = $4.xval;
			$$.yval = $4.yval;
			setstval(&$$.state, $2.lexval);
			setstflag(&$$.state, XLat);
		    }
		  }

		| objectwith pair XLat position                         /* object26 */
		{ if ($1.prim != NULL) {
			$$.xval = $4.xval;
			$$.yval = $4.yval;
            i = $$.prim->ptype;
			if ((i != XLarc) && (i != XLellipse) && (i != XLcircle) &&
			  (i != XBLOCK) && (i != XLstring) && (i != XLbox)){markerror(858);}
			else {
			  $$.startchop = $2.xval;
			  $$.endchop = $2.yval;
			  setstval(&$$.state, XLfloat);
			  }
			setstflag(&$$.state, XLat);
		    }
		  }

		| XLcontinue                                            /* object27 */
		{ primp = NULL;
	      prp = envblock->son;
	      while (prp != NULL) { i = prp->ptype;
		    if ( (i != XLaTeX) && (i != XLstring) && (i != XBLOCK)
			  && (i != XLabel) ) { primp = prp; }
		    prp = prp->next_; }
	      if (primp == NULL) { markerror(857); }
	      else {
		    while (primp->son != NULL) { primp = primp->son; }
		    $$.prim = primp;
		    if ($$.prim != NULL) {
			  appendthen(&$$.prim);
			  if ($$.prim->ptype != XLarc) { setstflag(&$$.state, XEMPTY); }
		      }
		    }
		  }
		;

openblock	:	XBRACKETL                                     /* openblock1 */
		{ newprim(&$$.prim, XBLOCK, envblock);
		  $$.prim->Upr.UBLOCK.here.xpos = 0.0;
		  $$.prim->Upr.UBLOCK.here.ypos = 0.0;
		  envblock = $$.prim;
		  tail = NULL;
		  $$.lexval = 0;
		  }
		;

							/* position values for basic drawn object */
block	:	XLprimitiv optexp                                     /* block1 */
		{ if (($1.lexval > XLprimitiv) && ($1.lexval < XLenvvar)) {
			newprim(&$$.prim, $1.lexval, envblock);
			eb = findenv(envblock);
			if (( ($1.lexval != XLmove) && ((drawmode == MPost) ||
			      (drawmode == Pict2e) || (drawmode == PDF) ||
			      (drawmode == PS) || (drawmode == SVG) ||
			      (drawmode == PSfrag)) ) ||
			    ($1.lexval == XLarc)) {
			  $$.prim->lthick = eb->envinx(XLlinethick); }
			if (($2.lexval != XEMPTY) &&               /* check expr allowed */
			    ($1.lexval != XLmove) &&
			    ($1.lexval != XLspline) &&
			    ($1.lexval != XLarrow) &&
			    ($1.lexval != XLline)) { markerror(858); }
			With2 = $$.prim;
			switch ($1.lexval) {
			  case XLbox:
			    With2->Upr.Ubox.boxheight = eb->envinx(XLboxht);
			    With2->Upr.Ubox.boxwidth = eb->envinx(XLboxwid);
			    With2->Upr.Ubox.boxradius = eb->envinx(XLboxrad);
			    switch (With2->direction) {
			      case XLup:
			        With2->aat.ypos += With2->Upr.Ubox.boxheight * 0.5;
			        break;
			      case XLdown:
			        With2->aat.ypos -= With2->Upr.Ubox.boxheight * 0.5;
			        break;
			      case XLleft:
			        With2->aat.xpos -= With2->Upr.Ubox.boxwidth * 0.5;
			        break;
			      case XLright:
			        With2->aat.xpos += With2->Upr.Ubox.boxwidth * 0.5;
			        break;
			      }
			    break;
			  case XLcircle:
			    With2->Upr.Ucircle.radius = eb->envinx(XLcirclerad);
			    switch (With2->direction) {
			      case XLup:
			        With2->aat.ypos += With2->Upr.Ucircle.radius;
			        break;
			      case XLdown:
			        With2->aat.ypos -= With2->Upr.Ucircle.radius;
			        break;
			      case XLleft:
			        With2->aat.xpos -= With2->Upr.Ucircle.radius;
			        break;
			      case XLright:
			        With2->aat.xpos += With2->Upr.Ucircle.radius;
			        break;
			      }
			    break;
			  case XLellipse:
			    With2->Upr.Uellipse.elheight = eb->envinx(XLellipseht);
			    With2->Upr.Uellipse.elwidth = eb->envinx(XLellipsewid);
			    switch (With2->direction) {
			      case XLup:
			        With2->aat.ypos += With2->Upr.Uellipse.elheight * 0.5;
			        break;
			      case XLdown:
			        With2->aat.ypos -= With2->Upr.Uellipse.elheight * 0.5;
			        break;
			      case XLleft:
			        With2->aat.xpos -= With2->Upr.Uellipse.elwidth * 0.5;
			        break;
			      case XLright:
			        With2->aat.xpos += With2->Upr.Uellipse.elwidth * 0.5;
			        break;
			      }
			    break;
			  case XLarc:
			    With2->Upr.Uline.aradius =
                  eb->envinx(XLarcrad);
			    switch (With2->direction) {
			      case XLup:
			        With2->Upr.Uline.endpos.xpos = 0.0;
			        With2->aat.xpos -= With2->Upr.Uline.aradius;
			        break;
			      case XLdown:
			        With2->Upr.Uline.endpos.xpos = pi;
			        With2->aat.xpos += With2->Upr.Uline.aradius;
			        break;
			      case XLleft:
			        With2->Upr.Uline.endpos.xpos = 0.5 * pi;
			        With2->aat.ypos -= With2->Upr.Uline.aradius;
			        break;
			      case XLright:
			        With2->Upr.Uline.endpos.xpos = (-0.5) * pi;
			        With2->aat.ypos += With2->Upr.Uline.aradius;
			        break;
			      }
			    With2->Upr.Uline.height = eb->envinx(XLarrowht);
			    With2->Upr.Uline.width = eb->envinx(XLarrowwid);
			    With2->Upr.Uline.atype = pahnum(pahlex(0, XEMPTY),
			      Rnd(eb->envinx(XLarrowhead)));
			    With2->Upr.Uline.endpos.ypos = pi * 0.5;
			    break;
			  case XLline:
			  case XLarrow:
			  case XLspline:
			  case XLmove:
			    With2->Upr.Uline.endpos = With2->aat;
			    if ((With2->ptype == XLspline) && ($2.lexval != XEMPTY)) {
			      With2->Upr.Uline.aradius = $2.xval;
			      $2.lexval = XEMPTY; }
			    if ($2.lexval != XEMPTY) { r = $2.xval; }
			    else if (With2->ptype == XLmove) {
			      switch (With2->direction) {
			        case XLup:
			        case XLdown:
				      r = eb->envinx(XLmoveht);
				      break;
			        case XLleft:
			        case XLright:
				      r = eb->envinx(XLmovewid);
				      break;
			        }
			      }
			    else {
			      switch (With2->direction) {
			        case XLup:
			        case XLdown:
				      r = eb->envinx(XLlineht);
				      break;
			        case XLleft:
			        case XLright:
				      r = eb->envinx(XLlinewid);
				      break;
			        }
			      }
			    switch (With2->direction) {
			      case XLup:
			        With2->Upr.Uline.endpos.ypos = With2->aat.ypos + r;
			        break;
			      case XLdown:
			        With2->Upr.Uline.endpos.ypos = With2->aat.ypos - r;
			        break;
			      case XLleft:
			        With2->Upr.Uline.endpos.xpos = With2->aat.xpos - r;
			        break;
			      case XLright:
			        With2->Upr.Uline.endpos.xpos = With2->aat.xpos + r;
			        break;
			      }
			    With2->Upr.Uline.height = eb->envinx(XLarrowht);
			    With2->Upr.Uline.width = eb->envinx(XLarrowwid);
			    if (With2->ptype == XLarrow) {
			      With2->Upr.Uline.atype = pahlex(0, XRIGHTHEAD); }
			    else { With2->Upr.Uline.atype = pahlex(0, XEMPTY); }
			  With2->Upr.Uline.atype = pahnum(With2->Upr.Uline.atype,
			    Rnd(eb->envinx(XLarrowhead)));
			  break;
			  }
		    }
#ifdef DDEBUG
			if (debuglevel > 0) { printobject($$.prim); }
#endif
		  }

		| stringexpr                                              /* block2 */
		{ if ((drawmode == PS) || (drawmode == PDF) || (drawmode == PSfrag)) {
			printstate = ((printstate >> 1) * 2) + 1; }
		  }

		| openblock closeblock XBRACKETR                          /* block3 */
		{ if ($1.prim != NULL) {
			envblock = $1.prim->parent;
			tail = NULL;
			getnesw($1.prim->son);
			With2 = $1.prim;
			With2->Upr.UBLOCK.blockwidth = east - west;
			With2->Upr.UBLOCK.blockheight = north - south;
			With2->aat.xpos = (east + west) * 0.5;
			With2->aat.ypos = (north + south) * 0.5;
			dx = envblockB.here.xpos - With2->aat.xpos;
			dy = envblockB.here.ypos - With2->aat.ypos;
			switch (envblock->direction) {
			  case XLright: dx += With2->Upr.UBLOCK.blockwidth * 0.5; break;
			  case XLleft: dx -= With2->Upr.UBLOCK.blockwidth * 0.5; break;
			  case XLup: dy += With2->Upr.UBLOCK.blockheight * 0.5; break;
			  case XLdown: dy -= With2->Upr.UBLOCK.blockheight * 0.5; break;
			  }
			With2->direction = envblock->direction;
#ifdef DDEBUG
			if ((debuglevel > 0) && ($1.prim->son != NULL)) {
			  printobject($1.prim->son);
			  if ($1.prim->son->next_ != NULL) {
                printobject($1.prim->son->next_); }
			  }
#endif
			shift($1.prim, dx, dy);
#ifdef DDEBUG
			if (debuglevel > 0) {
			  With2 = $1.prim;
			  fprintf(log_, "Block3: (north,south),(west,east)");
			  wpair(&log_,With2->aat.ypos + (With2->Upr.UBLOCK.blockheight*0.5),
				  With2->aat.ypos - (With2->Upr.UBLOCK.blockheight * 0.5));
			  wpair(&log_,With2->aat.xpos -(With2->Upr.UBLOCK.blockwidth*0.5),
				  With2->aat.xpos + (With2->Upr.UBLOCK.blockwidth * 0.5));
			  fprintf(log_, " here=");
			  wpair(&log_,
				  With2->Upr.UBLOCK.here.xpos, With2->Upr.UBLOCK.here.ypos);
			  putc('\n', log_);
			  if ($1.prim->son != NULL) {
				printobject($1.prim->son);
				if ($1.prim->son->next_ != NULL) {
				  printobject($$.prim->son->next_); }
			    }
			  $$.prim = $1.prim;
			  snaptree($$.prim, 0);
			  putc('\n', log_);
			  }
#endif
		    }
		  }

		| XBLOCK                                                  /* block4 */
		{ newprim(&$$.prim, XBLOCK, envblock);
		  $$.prim->Upr.UBLOCK.here.xpos = 0.0;
		  $$.prim->Upr.UBLOCK.here.ypos = 0.0;
		  $$.lexval = 0;
		  }
		;

optexp	:                                                        /* optexp1 */
			{ $$.lexval = XEMPTY; }

		| expression                                             /* optexp2 */
		;

closeblock	:	elementlist optnl                            /* closeblock1 */
		{ if (envblockB.env != NULL) {
			eb = findenv(envblock->parent);
			if (envblock->envinx(XLlinethick) != eb->envinx(XLlinethick)) {
		      newprim(&prp, XLaTeX, envblock);
			  prp->lthick = eb->envinx(XLlinethick);
              queueprim( prp, envblock );
              }
		    }
		  }
		;

objectwith	:	object XLwith                                /* objectwith1 */

		| objectwith Xdot XLabel suffix                      /* objectwith2 */
		{ if ($1.prim != NULL) {
			if ($4.lexval != XEMPTY) {
			  With1 = &$3;
			  addsuffix(chbuf, &With1->chbufx, &With1->toklen,
			    $4.xval,$4.lexval,$4.yval); }
			if ($$.internal == NULL) { prp = $$.prim; }
			else { prp = $$.internal; }
			$$.internal = findplace(prp->son, chbuf, $3.chbufx, $3.toklen);
			if ($$.internal == NULL) {
			  marknotfound(855, chbuf, $3.chbufx, $3.toklen);
			  deletetree(&$$.prim); }
		    }
		  clearchbuf($3.chbufx, $3.toklen);
		  }

		| objectwith Xdot nth primobj                        /* objectwith3 */
		{ if ($1.prim != NULL) {
			if ($1.internal == NULL) { prp = $1.prim; }
			else { prp = $1.internal; }
			$$.internal = nthprimobj(prp->son, $3.toklen, $4.lexval);
			if ($$.internal == NULL) { markerror(857); deletetree(&$$.prim); }
		    }
		  }
		;

pair	:	expression Xcomma expression                           /* pair1 */
		{ $$.yval = $3.xval;
#ifdef DDEBUG
			if (debuglevel>1) prattribute("pair1",&$$);
#endif
			}

		| location shift                                           /* pair2 */
		{ if ($2.lexval != XEMPTY) {
			$$.xval += $2.xval;
			$$.yval += $2.yval; }
		  }
		;

nth	:	ncount XLnth                                                /* nth1 */
		{ if ($1.xval <= 0.0) { markerror(856); }
		  else { $$.toklen = Rnd($1.xval); }
		  }

		| ncount XLnth XLlast                                       /* nth2 */
		{ if ($1.xval <= 0.0) { markerror(856); }
		  else { $$.toklen = -Rnd($1.xval); }
		  }

		| XLlast                                                    /* nth3 */
		{ $$.toklen = 0; }
		;

primobj	: XLprimitiv                                            /* primobj1 */

		| XBLOCK                                                /* primobj2 */

		| XLstring                                              /* primobj3 */

		| XBRACKETL XBRACKETR                                   /* primobj4 */
		{ $$.lexval = XBLOCK; }
		;

shift	: /* empty */                                             /* shift1 */
		{ $$.xval = 0.0;
		  $$.yval = 0.0;
		  $$.lexval = XEMPTY;
		  }

		| shift Xplus location                                    /* shift2 */
		{ $$.xval += $3.xval;
		  $$.yval += $3.yval;
		  $$.lexval = XLfloat;
		  }

		| shift Xminus location                                   /* shift3 */
		{ $$.xval -= $3.xval;
		  $$.yval -= $3.yval;
		  $$.lexval = XLfloat;
		  }
		;

location	:	Xlparen position Xrparen                       /* location1 */
		{ $$ = $2; }

		| Xlparen position Xcomma position Xrparen             /* location2 */
		{ $$.xval = $2.xval;
		  $$.yval = $4.yval;
		  }

		| place                                                /* location3 */

		| location Xmult factor                                /* location4 */
		{ $$.xval *= $3.xval;
		  $$.yval *= $3.xval;
		  }

		| location Xdiv factor                                 /* location5 */
		{ if ($3.xval == 0.0) { markerror(852); }
		  else {
			$$.xval /= $3.xval;
			$$.yval /= $3.xval;
		    }
		  }
		;

place	:	placename                                             /* place1 */
		{ corner($1.prim, XEMPTY, &$$.xval, &$$.yval); }

		| placename XLcorner                                      /* place2 */
		{ corner($1.prim, $2.lexval, &$$.xval, &$$.yval); }

		| XLcorner placename                                      /* place3 */
		{ corner($2.prim, $1.lexval, &$2.xval, &$2.yval);
 		  $$ = $2; }

		| XLcorner XLof placename                                 /* place4 */
		{ corner($3.prim, $1.lexval, &$3.xval, &$3.yval);
 		  $$ = $3; }

		| XLHere                                                  /* place5 */
		{ $$.xval = envblockB.here.xpos;
		  $$.yval = envblockB.here.ypos;
		  }
		;

factor	:	primary                                              /* factor1 */

		| XNOT primary                                           /* factor2 */
		{ if ($2.xval == 0.0) { $$.xval = 1.0; }
    	  else { $$.xval = 0.0; }
		  }

		| primary Xcaret factor                                  /* factor3 */
		{ if (($1.xval == 0.0) && ($3.xval < 0.0)) { markerror(852); }
		  else {
			j = Rnd($3.xval);
			r = j;
			if (r == $3.xval) { $$.xval = intpow($1.xval, j); }
			else if ($1.xval < 0.0) { markerror(863); $$.xval = 0.0; }
			else if ($1.xval != 0.0) { $$.xval = exp($3.xval * log($1.xval));}
			}
    	  }
		;

placename	:	XLabel suffix                                 /* placename1 */
		{ if ($2.lexval != XEMPTY) { addsuffix(chbuf, &$1.chbufx, &$1.toklen,
                $2.xval,$2.lexval,$2.yval); }
		  prp = NULL;
		  primp = envblock;
		  while (primp != prp) {
		    prp = findplace(primp->son, chbuf, $1.chbufx, $1.toklen);
			if (prp != NULL) { primp = prp; }
			else { primp = primp->parent; }
		    }
		  if (prp == NULL) {
			marknotfound(854, chbuf, $1.chbufx, $1.toklen); }
		  clearchbuf($1.chbufx, $1.toklen);
		  $$.prim = prp;
		  }

		| nth primobj                                         /* placename2 */
		{ $$.prim = nthprimobj(envblock->son, $1.toklen, $2.lexval);
		  if ($$.prim == NULL) { markerror(857); }
#ifdef DDEBUG
		  if (debuglevel > 0) {
            fprintf(log_, "\n placename2 %dth location:",$1.toklen);
	        wpair(&log_, $$.prim->aat.xpos, $$.prim->aat.ypos);
            putc('\n', log_); fflush(log_);
            }
#endif
		  }

		| placename Xdot XLabel suffix                        /* placename3 */
		{ if ($1.prim != NULL) {
			if ($4.lexval != XEMPTY) { addsuffix(chbuf, &$3.chbufx,
              &$3.toklen, $4.xval,$4.lexval,$4.yval); }
			primp = findplace($$.prim->son, chbuf, $3.chbufx, $3.toklen);
			if (primp == NULL) { marknotfound(855, chbuf, $3.chbufx,$3.toklen);}
			$$.prim = primp;
		    }
		  clearchbuf($3.chbufx, $3.toklen);
		  }

		| placename Xdot nth primobj                          /* placename4 */
		{ if ($1.prim != NULL) {
			$$.prim = nthprimobj($1.prim->son, $3.toklen, $4.lexval);
			if ($$.prim == NULL) { markerror(857); }
		    }
		  }
		;

ncount	:	XLfloat                                              /* ncount1 */

		| XSLQ expression XSRQ                                   /* ncount2 */
		{ $$.xval = $2.xval; }

		| XLBRACE expression XRBRACE                             /* ncount3 */
		{ $$.xval = $2.xval; }
		;

logprod	:	logval                                              /* logprod1 */

		| logprod XANDAND logval                                /* logprod2 */
		{ if (($1.xval == 0.0) || ($3.xval == 0.0)) { $$.xval = 0.0; }
		  else { $$.xval = 1.0; }
		  }
		;

logval	:	lcompare                                             /* logval1 */
		{ if ($1.lexval == XLstring) {
			markerror(869);
			$$.lexval = XLfloat;
			deletestringbox(&$1.prim);
		    }
		  }

		| stringexpr XLT stringexpr                              /* logval2 */
		{ i = cmpstring($1.prim, $3.prim);
		  if (i < 0) { $$.xval = 1.0; }
		  else { $$.xval = 0.0; }
		  $$.lexval = XLfloat;
		  deletestringbox(&$3.prim);
		  deletestringbox(&$1.prim);
		  }

		| expression XLT expression                              /* logval3 */
		{ if ($1.xval < $3.xval) { $$.xval = 1.0; }
		  else { $$.xval = 0.0; }
		  }
		;

lcompare:	expression                                         /* lcompare1 */

		| stringexpr                                           /* lcompare2 */

		| lcompare XLcompare expression                        /* lcompare3 */
		{ if ($1.lexval == XLstring) {
			markerror(869);
			bswitch = false;
			deletestringbox(&$1.prim);
		    }
		  else {
#ifdef DDEBUG
			if (debuglevel > 0) { fprintf(log_," compare %g %d %g\n",
              $1.xval,$2.lexval-XLcompare,$3.xval); }
#endif
			switch ($2.lexval - XLcompare) {
			  case 0: bswitch = ($1.xval < $3.xval); break;
			  case 1: bswitch = ($1.xval == $3.xval); break;
			  case 2: bswitch = ($1.xval != $3.xval); break;
			  case 3: bswitch = ($1.xval >= $3.xval); break;
			  case 4: bswitch = ($1.xval <= $3.xval); break;
			  case 5: bswitch = ($1.xval > $3.xval); break;
			  default: bswitch = false; break;
			  }
		    }
		  if (bswitch) { $$.xval = 1.0; } else { $$.xval = 0.0; }
		  }

		| lcompare XLcompare stringexpr                        /* lcompare4 */
		{ if ($1.lexval != XLstring) { markerror(869); bswitch = false; }
		  else {
			i = cmpstring($1.prim, $3.prim);
			switch ($2.lexval - XLcompare) {
			  case 0: bswitch = (i < 0); break;
			  case 1: bswitch = (i == 0); break;
			  case 2: bswitch = (i != 0); break;
			  case 3: bswitch = (i >= 0); break;
			  case 4: bswitch = (i <= 0); break;
			  case 5: bswitch = (i > 0); break;
			  default: bswitch = false; break;
			  }
			deletestringbox(&$$.prim);
		    }
		  if (bswitch) { $$.xval = 1.0; } else { $$.xval = 0.0; }
		  $$.lexval = XLfloat;
		  deletestringbox(&$3.prim);
		  }
		;

primary	:	XLenvvar                                            /* primary1 */
		{ if (envblock != NULL) {
			eb = findenv(envblock);
			$$.xval = eb->envinx($1.lexval);
		    }
		  }

		| XLname suffix                                         /* primary2 */
		{ if ($2.lexval != XEMPTY) { addsuffix(chbuf,
		    &$1.chbufx, &$1.toklen, $2.xval,$2.lexval,$2.yval); }
    	  namptr = glfindname(envblock,chbuf,$1.chbufx,$1.toklen, &lastvar, &k);
    	  if (namptr == NULL) { $$.xval = 0.0; }
    	  else { $$.xval = namptr->val; }
		  clearchbuf($1.chbufx, $1.toklen);
		  }

		| XLfloat                                               /* primary3 */

		| Xlparen logexpr Xrparen                               /* primary4 */
		{ $$.xval = $2.xval; }

		| location XLdx                                         /* primary5 */

		| location XLdy                                         /* primary6 */
		{ $$.xval = $1.yval; }

		| placename XLparam                                     /* primary7 */
		{ if ($1.prim != NULL) {
			switch ($2.lexval) {
			  case XLheight:
			    $$.xval = pheight($$.prim);
			    break;
			  case XLwidth:
			    $$.xval = pwidth($$.prim);
			    break;
			  case XLradius:
			    With2 = $$.prim;
			    if (With2->ptype == XLcircle) {
			      $$.xval = With2->Upr.Ucircle.radius; }
			    else if (With2->ptype == XLarc) {
			      $$.xval = With2->Upr.Uline.aradius; }
			    else if (With2->ptype == XLbox) {
			      $$.xval = With2->Upr.Ubox.boxradius; }
			    else {
			      $$.xval = 0.0;
			      markerror(858); }
			    break;
			case XLdiameter:
			  With2 = $1.prim;
			  if (With2->ptype == XLcircle) {
			    $$.xval = With2->Upr.Ucircle.radius * 2; }
			  else if (With2->ptype == XLarc) {
			    $$.xval = With2->Upr.Uline.aradius * 2; }
			  else {
			    $$.xval = 0.0;
			    markerror(858); }
			  break;
			case XLthickness:
			  With2 = $1.prim; j = With2->ptype;
			  if ((j == XLarc) || (j == XLspline) || (j == XLarrow) ||
                (j == XLline) || (j == XLcircle) || (j == XLellipse) ||
			      (j == XLbox)) { $$.xval = With2->lthick; }
			  else {
			    $$.xval = 0.0;
			    markerror(858); }
			  break;
			case XLlength:
			  With2 = $1.prim; j = With2->ptype;
			  if ((j == XLspline) || (j == XLmove) || (j == XLarrow) ||
                (j == XLline)) {
			    primp = $1.prim;
			    while (primp->son != NULL) { primp = primp->son; }
			    r = fabs(primp->Upr.Uline.endpos.xpos - With2->aat.xpos);
			    s = fabs(primp->Upr.Uline.endpos.ypos - With2->aat.ypos);
			    if (r == 0.0) { $$.xval = s; }
			    else if (s == 0.0) { $$.xval = r; }
			    else { $$.xval = sqrt((r * r) + (s * s)); }
			    }
			  else {
			    $$.xval = 0.0;
			    markerror(858); }
			  break;
			  }
		    }
		  }

		| XLrand Xlparen Xrparen                                /* primary8 */
		{ $$.xval = ((double)random()) / randmax; }

		| XLrand Xlparen expression Xrparen                     /* primary9 */
		{ srandom(Rnd($3.xval));
		  $$.xval = ((double)random()) / randmax;
		  }

		| XLfunc1 Xlparen expression Xrparen                   /* primary10 */
		{ switch ($$.lexval) {
		    case XLabs: $$.xval = fabs($3.xval);
		      break;
		    case XLacos:
		      t = $3.xval;
		      if (fabs(t) > 1.0) { markerror(868); }
		      else { $$.xval = datan(sqrt(1 - (t * t)), t); }
		      break;
		    case XLasin:
		      t = $3.xval;
		      if (fabs(t) > 1.0) { markerror(868); }
		      else { $$.xval = datan(t, sqrt(1 - (t * t))); }
		      break;
		    case XLcos: $$.xval = cos($3.xval);
		      break;
		    case XLexp: $$.xval = exp(log(10.0) * $3.xval);
		      break;
		    case XLexpe: $$.xval = exp($3.xval);
		      break;
		    case XLint: $$.xval = (long)$3.xval;
		      break;
		    case XLlog:
		      if ($3.xval <= 0.0) { markerror(867); }
		      else { $$.xval = log($3.xval) / log(10.0); }
		      break;
		    case XLloge:
		      if ($3.xval <= 0.0) { markerror(867); }
		      else { $$.xval = log($3.xval); }
		      break;
		    case XLsign:
		      if ($3.xval >= 0.0) { $$.xval = 1.0; }
		      else { $$.xval = -1.0; }
		      break;
		    case XLsin: $$.xval = sin($3.xval);
		      break;
		    case XLsqrt:
		      if ($3.xval < 0.0) { markerror(867); }
		      else { $$.xval = sqrt($3.xval); }
		      break;
		    case XLtan:
		      t = cos($3.xval);
		      if (t == 0.0) { markerror(868); $$.xval = distmax; }
		      else { $$.xval = sin($3.xval) / t; }
		      break;
		    case XLfloor: $$.xval = Floor($3.xval);
		      break;
		    }
		  }

		| XLfunc2 Xlparen expression Xcomma expression Xrparen /* primary11 */
		{ switch ($1.lexval) {
		    case XLatan2: $$.xval = datan($3.xval, $5.xval);
		      break;
		    case XLmax: $$.xval = Max($3.xval, $5.xval);
		      break;
		    case XLmin: $$.xval = Min($3.xval, $5.xval);
		      break;
		    case XLpmod:
		      t = $3.xval;
		      s = $5.xval;
		      if (s == 0) { markerror(871); }
		      else {
			    $$.xval = t - (s * Floor(t / s));
			    if ($$.xval < 0) { $$.xval += fabs(s); }
		        }
		      break;
		    }
		  }

		| Xlparen assignlist Xrparen                           /* primary12 */
		{ $$.xval = $2.xval; }

		| Xlparen systemcmd Xrparen                            /* primary13 */
		{ $$.xval = $2.xval; }
		;

%% /* start of programs */

int
yyerror(char *s)
{
  markerror(799);
  return 0;
  }

							/* Get and initialize a buffer from the
							   old-buffer stack or make a new one */
void
newbuf(fbuffer **buf)
{ fbuffer *With;
#ifdef DDEBUG
  if (debuglevel > 0) { fprintf(log_, " newbuf"); }
#endif
  if (freeinbuf == NULL) {
    *buf = malloc(sizeof(fbuffer));
    (*buf)->carray = malloc(sizeof(chbufarray));
    }
  else {
#ifdef DDEBUG
    if (debuglevel > 0) { fprintf(log_, " f"); }
#endif
    *buf = freeinbuf;
    freeinbuf = freeinbuf->nextb;
    }
  With = *buf;
  With->savedlen = 0;
  With->carray[0] = ' ';
  With->readx = 1;
  With->attrib = 0;
  With->higherb = NULL;
  With->prevb = NULL;
  With->nextb = NULL;
#ifdef DDEBUG
  if (debuglevel > 0) { logaddr(*buf); putc('\n', log_); }
#endif
}


							/* Clearing memory at end of diagram */
void
deletefreeargs(arg **a)
{ arg *na;

  while ((*a) != NULL) {
      na = (*a)->nexta;
      disposebufs(&(*a)->argbody);
      Free(*a);
      *a = na;
  }
}


							/* Clearing memory at end of diagram */
void
deletefreeinbufs(fbuffer **p)
{ fbuffer *q;

  while ((*p) != NULL) {
      q = (*p)->nextb;
      Free((*p)->carray);
      Free(*p);
      *p = q;
  }
}


							/* performed for each input diagram: */
void
inittwo(void)
{ freeinbuf = NULL;
  freeseg = NULL;
  freex = 0;
  freearg = NULL;
  lastfillval = mdistmax;
  gslinethick = mdistmax;
  newprim(&envblock, XBLOCK, NULL);
  globalenv = envblock;
  tail = NULL;
  resetenv(0, envblock);
#ifdef DDEBUG
  if (debuglevel > 0) { printobject(envblock); }
#endif
  pyylval = &yylval;
}

void
preproduce(int p)
{
  switch (p) {
  case -2:
    inittwo();
    break;
  case -1:
    if (envblock != NULL) { envblock->direction = XLright; }
    inlogic = false;
    inbuf = NULL;
    break;
	}
  }

							/* Compute integer power of x */
double
intpow(double x, int k)
{ /* 0^(-k) does not occur */
  /* 0^0 returns 1.0 */
  if (k == 0) { x = 1.0; return x; }
  if ((x == 0.0) || (k == 1)) { return x; }
  if (k < 0) { x = intpow(1.0 / x, -k); return x; }
							/* common enough to test for it */
  if (k == 2) { x *= x; return x; }
  if (k & 1) { x *= intpow(x, k - 1); }
  else { x = intpow(x, k >> 1); x *= x; }
  return x;
}

							/* error message strings for lexical terminals */
static const char *const lexterms[] = {
" EOF",
#include "lxerr.h"
};

							/* Write error message with symbol found
							   and symbol expected if possible */
void
markerror(int emi) {
  int inx, j, k;
  fbuffer *thisbuf, *lastbuf;
							/* Do not count warnings */
  if (emi < 900) { errcount++; }
#ifdef DDEBUG
  fbuffer *With;
  if (debuglevel > 0) {
    fprintf(log_, "*** markerror");
    wrbufaddr(inbuf, 0);
    fprintf(log_, " emi=%d, lexsymb=%d:\n", emi, lexsymb);
    if (currentmacro == NULL) {}
	else if (currentmacro->argbody == NULL) { }
	else if (currentmacro->argbody->carray != NULL) {
	  With = currentmacro->argbody;
	  fprintf(errout, "In macro ");
	  FORLIM = -With->attrib;
	  for (j = 1; j <= FORLIM; j++) { wchar(&errout, With->carray[j]); }
      fprintf(errout, ":\n");
	  }
    }
#endif

  fprintf(errout, "\n*** dpic ");
  if (emi < 900) { fprintf(errout, "ERROR"); }
  else { fprintf(errout, "WARNING"); }
  fprintf(errout, " line %d:\n", lineno);

  if (emi < 903) {          /* Write out the input buffer */
      thisbuf = inbuf;
      lastbuf = NULL;
      inx = 1;
      while (thisbuf != NULL) { /* Skip back over white space */
	    lastbuf = thisbuf;
	    j = 0;
	    if (thisbuf->readx > thisbuf->savedlen) { inx = thisbuf->savedlen; }
	    else { inx = thisbuf->readx - 1; }
	    if (thisbuf->readx - 1 < thisbuf->savedlen) { j = thisbuf->readx - 1; }
	    else { j = thisbuf->savedlen; }
	    while (inx > j) {
	      if ( (thisbuf->carray[inx] == etxch)
            || (thisbuf->carray[inx] == tabch)
            || (thisbuf->carray[inx] == ' ')
            || (thisbuf->carray[inx] == crch)
            || (thisbuf->carray[inx] == nlch) ) { inx--; }
	      else { j = inx; }
	      }
	    j = 0;              /* Skip back over code or tabs */
	    while (inx > j) {
	      if (isprint_(thisbuf->carray[inx])
		    || (thisbuf->carray[inx] == tabch)) { inx--; }
	      else { j = inx; }
	      }
	    if (inx == 0) { thisbuf = thisbuf->prevb; }
	    else { thisbuf = NULL; }
        }
      while (lastbuf != NULL) { /* Write out the line or lines */
	    if (lastbuf == inbuf) { k = lastbuf->readx - 1; }
	    else { k = lastbuf->savedlen; }
	  if (inx < 1) { inx = 1; }
	  for (j = inx; j <= k; j++) { wchar(&errout, lastbuf->carray[j]); }
	  if (lastbuf != inbuf) { lastbuf = lastbuf->nextb; }
	  else { lastbuf = NULL; }
	  if (lastbuf != NULL) { inx = lastbuf->readx; }
      }
    putc('\n',errout);
    }

  switch (emi) {
  case 799:                                           /* syntax error */
    fprintf(errout, "Syntax error at or before");
    if ((lexsymb < 0) || (lexsymb > lxmax)) {
      fprintf(errout, " unknown symbol\n"); }
      else { fprintf(errout, " %s\n",lexterms[lexsymb]); }
    if ((newsymb == XLname) || (newsymb == XLabel)) {
      for (i=yylval.chbufx; i<(yylval.chbufx+yylval.toklen); i++) {
        wchar(&errout, chbuf[i]); } }
    break;
							/* lexical error messages */
  case 800:
    fprintf(errout, "Character not recognized: ignored\n");
    break;

  case 802:
    fprintf(errout, "Invalid exponent character after e in a number\n");
    break;

  case 804:
  case 807:
    fprintf(errout, "End of file while reading ");
    if (emi == 807) { fprintf(errout, "string in "); }
    switch (currprod) {
      case 1 /* elsehead1 */:
        fprintf(errout, "else");
        break;
      case 2 /* ifhead1 */:
        fprintf(errout, "if");
        break;
      case 3 /* forhead1 */:
        fprintf(errout, "for");
        break;
      case 4 /* defhead1 */:
      case 5 /* defhead2 */:
        fprintf(errout, "define");
        break;
      }
    fprintf(errout, " {...} contents\n");
    break;

  case 805:
    fprintf(errout, "Bad macro argument number\n");
    break;

  case 806:
    fprintf(errout, "End of file while evaluating macro argument\n");
    break;

							/* context error messages */
  case 851:
    fprintf(errout, "Variable not found\n");
    break;

  case 852:
    fprintf(errout, "Zero divisor not allowed\n");
    break;

  case 853:
    fprintf(errout, "Only one copy file may be open at any time\n");
    break;

  case 854:
    fprintf(errout, "Place name not found\n");
    break;

  case 855:
    fprintf(errout, "Internal name not found\n");
    break;

  case 856:
    fprintf(errout, "Invalid non-positive value for object count\n");
    break;

  case 857:
    fprintf(errout, "Enumerated or previous object not found\n");
    break;

  case 858:
    fprintf(errout, "This usage is inapplicable in this context\n");
    break;

  case 859:
    fprintf(errout, "File not readable\n");
    break;

  case 860:
    fprintf(errout, "Infinite looping not allowed\n");
    break;

  case 861:
    fprintf(errout, "Missing or blank string\n");
    break;

  case 862:
    fprintf(errout, "For ... by *() limits must have the same sign\n");
    break;

  case 863:
    fprintf(errout, "Non-integer power of negative value\n");
    break;

  case 864:
    fprintf(errout, "Incorrect number of sprintf arguments\n");
    break;

  case 865:
    fprintf(errout, "Bad sprintf format; only e, f, g allowed\n");
    break;

  case 866:
    fprintf(errout, "String exceeds max length of 4095 characters\n");
    break;

  case 867:
    fprintf(errout, "Invalid log or sqrt argument\n");
    break;

  case 868:
    fprintf(errout, "Function argument out of range\n");
    break;

  case 869:
    fprintf(errout, "Improper use of logical operator\n");
    break;

  case 870:
    fprintf(errout, "Zero value of scale not allowed\n");
    break;

  case 871:
    fprintf(errout, "Zero second argument of pmod not allowed\n");
    break;

  case 872:
    fprintf(errout, "Buffer overflow while defining macro argument\n");
    break;

  case 873:
    fprintf(errout, "Format width too large\n");
    break;

  case 874:
    fprintf(errout, "System routine snprintf error: bad formatted value\n");
    break;

							/* warning messages */
  case 901:
    fprintf(errout, "Safe mode: sh, copy, and print to file disallowed\n");
    break;

  case 903:
    fprintf(errout, "Picture size adjusted to maxpswid value\n");
    break;

  case 904:
    fprintf(errout, "Picture size adjusted to maxpsht value\n");
    break;

  default:
    fprintf(errout, "Unknown error\n");
    break;
  }

  consoleflush();
  if (errcount > MAXERRCOUNT) { fatal(3); }
}  /* markerror */


							/* Flag an object not found and complain to
							   stderr */
void
marknotfound(int eno, Char *chb, chbufinx inx, chbufinx len)
{ int i;
#ifdef DDEBUG
  if (debuglevel > 0) {
    fprintf(log_, "Search failure %d", eno);
    if (chb != NULL) {
	  fprintf(log_, " for \"");
	  for (i = inx; i < (inx + len); i++) { putc(chb[i], log_); }
	  putc('"', log_);
      }
    putc('\n', log_);
    }
#endif
  markerror(eno);
  fprintf(errout, "\nSearch failure");
  if (chb != NULL) {
      fprintf(errout, " for \"");
      for (i = inx; i < (inx + len); i++) {
	  putc(chb[i], errout);
      }
      putc('"', errout);
  }
  putc('\n', errout);
}

							/* Hash of variable name:
   							   (ord(chr(1))+ord(chr(n-1))) mod 10 */
int
varhash(Char *chb, chbufinx chbufx, chbufinx toklen)
{ int idx;

  if (chb == NULL) {
      idx = 0;
      return (idx - ((idx / (HASHLIM + 1)) * (HASHLIM + 1)));
  }
  idx = chb[chbufx];
  if (toklen > 2) {
      idx += chb[chbufx + toklen - 2];
  }
  return (idx - ((idx / (HASHLIM + 1)) * (HASHLIM + 1)));
}

							/* Binary search for name in chain of stored
							   names */
nametype *(
findname(primitive *eb, Char *chb, chbufinx chbufx, chbufinx toklen,
	 nametype **last, int *k))
{ nametype *leftptr;
  nametype *rightptr = NULL;
  int left = 0, right = 0;
  int midpt, i, idx;
  nametype *With;
  idx = varhash(chb, chbufx, toklen);
#ifdef DDEBUG
  if (debuglevel > 0) {
    fprintf(log_, " findname|");
    for (i = chbufx; i < (chbufx + toklen); i++) { putc(chb[i], log_); }
    fprintf(log_, "|:");
    if (eb == NULL) { fprintf(log_, " eb=nil"); }
    else { fprintf(log_, " nvars[%d]=%d", idx, eb->Upr.UBLOCK.nvars[idx]); }
    if (debuglevel > 1) { putc('\n', log_); }
    }
#endif
  *k = 1;
  *last = NULL;
  if (eb == NULL) { leftptr = NULL; }
  else {
#ifdef DDEBUG
    if (debuglevel > 0) { fprintf(log_, " eb!=NULL: k=%d idx=%d ", *k,idx); }
#endif
    leftptr = eb->Upr.UBLOCK.vars[idx];
    *last = leftptr; }
#ifdef DDEBUG
    if (debuglevel > 0) {
      if (leftptr==NULL) { fprintf(log_," leftptr == NULL "); }
      else { fprintf(log_, "leftptr!=NULL[%d] k=%d", ordp(leftptr), *k); } }
#endif
							/* Check the first (highest) name */
  if (leftptr != NULL) {
    *k = eqstring(chb, chbufx, toklen, leftptr->segmnt, leftptr->seginx,
		    leftptr->len);
#ifdef DDEBUG
    if (debuglevel > 0) { fprintf(log_, "leftptr!=NULL: k=%d", *k); }
#endif
    if ((*k) < 0) {
	  left = 2;
	  leftptr = leftptr->next_;
	  right = eb->Upr.UBLOCK.nvars[idx] + 1; }
    else { rightptr = leftptr; }
    }
#ifdef DDEBUG
    if (debuglevel > 0) { fprintf(log_, "leftptr!=rightptr: %d",
      (int) (leftptr!=rightptr)); }
#endif
  while (leftptr != rightptr) {
    midpt = (left + right) >> 1;
    *last = leftptr;
    for (i = left + 1; i <= midpt; i++) { *last = (*last)->next_; }
    With = *last;
    *k = eqstring(chb, chbufx, toklen, With->segmnt, With->seginx,With->len);
#ifdef DDEBUG
    if (debuglevel > 0) { fprintf(log_, "while: k=%d", *k); }
#endif
    if ((*k) < 0) {
	  left = midpt + 1;
	  leftptr = (*last)->next_;
	  continue; }
    if ((*k) == 0) {
	  leftptr = *last;
	  rightptr = leftptr; }
    else {
	  right = midpt;
	  rightptr = *last; }
    }
#ifdef DDEBUG
  if (debuglevel > 0) {
    if ((*k) == 0) { fprintf(log_," return leftptr;\n"); }
    else { fprintf(log_," return NULL;\n"); } }
#endif
  if ((*k) == 0) { return leftptr; }
  else { return NULL; }
}

							/* A minimal set of debug routines has been kept: */
#ifdef DDEBUG
void
logchar(Char c)
{ fprintf(log_, "ch(%d)=\"", c);
  wchar(&log_, c);
  putc('"', log_);
}


void
wlogfl(Char *nm, double v, int cr)
{
  fprintf(log_, " %s=", nm);
  if (MaxReal - fabs(v) < MaxReal * 1e-6) {
    if (v < 0) { fprintf(log_, "-MaxReal"); }
    else { fprintf(log_, "MaxReal"); }
    }
  else { wfloat(&log_, v); }
  if (cr != 0) { putc('\n', log_); }
}

void
logaddr(fbuffer *b)
{
  putc('[', log_);
  if (b != NULL) { fprintf(log_, "%d", odp(b)); }
  else { fprintf(log_, "nil"); }
  fprintf(log_, "]\n");
}

void
wrbufaddr(fbuffer *q, int job)
{ fbuffer *r;
  boolean difa = false;
  if (q == NULL) { fprintf(log_, "[nil]"); return; }
  r = q;
  while (r->nextb != NULL) { r = r->nextb; }
  while (r->prevb != NULL) {
    difa = (difa || (r->attrib != r->prevb->attrib));
    r = r->prevb; }
  if (job <= 0) {
    r = q;
    while (r->prevb != NULL) { r = r->prevb; }
    while (r != q) {
	  fprintf(log_, "[%d", odp(r));
	  if (difa) { fprintf(log_, ":%d", r->attrib); }
	  r = r->nextb; }
    }
  fprintf(log_, "[%d:%d]", odp(q), q->attrib);
  if (job < 0) { return; }
  while (q->nextb != NULL) {
    q = q->nextb;
    fprintf(log_, "%d", odp(q));
    if (difa) { fprintf(log_, ":%d", q->attrib); }
    putc(']', log_);
    }
}

void
wrbuf(fbuffer *p, int job, int r)
{ int i, j, k, m;
  fbuffer *With;
  if (p == NULL) { fprintf(log_, " nil buffer "); return; }
  while (p != NULL) {
    With = p;
    if (job > 2) { fprintf(log_, " buf"); wrbufaddr(p, 0); }
    if (job > 1) {
	  fprintf(log_, " readx=%d savedlen=%d attrib=%d",
		  With->readx, With->savedlen, With->attrib); }
    if (r == 0) { j = 1; }
    else if (r < 0) { j = -r; }
    else { j = With->readx; }
    if (job > 0) { fprintf(log_, "(%d,%d)", j, With->savedlen); }
    fprintf(log_, "\n|");
    if (With->carray == NULL) { fprintf(log_, "nil"); }
    else {
	  i = j;
	  while (i <= With->savedlen) {
	    if (With->carray[i] != 0) { wchar(&log_, With->carray[i]); }
	    else {
		  m = i;
		  k = With->savedlen + 1;
		  while (i < k) {
		    if (With->carray[i] == 0) { i++; }
		    else { k = i; }
		    }
		  fprintf(log_, "(%d)x", i - m);
		  wchar(&log_, '\0');
		  i--;
	      }
	    i++;
	    }
      }
    fprintf(log_, "|\n");
    p = p->nextb;
    }
  }


void
prtstval(int st)
{ fprintf(log_, "state=%d", st);
  if ((st & 3) != 0) {
    switch (st & 3) {
      case 1: fprintf(log_, ",XLto"); break;
      case 2: fprintf(log_, ",XLfrom"); break;
      case 3: fprintf(log_, ",XLat"); break;
      }
    }
  if ((st >> 2) & 1) { fprintf(log_, ",XLchop"); }
  if ((st >> 3) & 1) { fprintf(log_, ",XLdirecton"); }
}


void
snapname(Char *chbu, chbufinx inx, chbufinx ll)
{ int j;
  fprintf(log_, " (%d inx=%d len=%d)|", ordp(chbu), inx, ll);
  if (chbu == NULL) { fprintf(log_, "**nil string pointer**"); }
  else { for (j = inx; j < (inx + ll); j++) { putc(chbu[j], log_); } }
  putc('|', log_);
  fflush(log_);
}


void
snaptype(FILE **iou, int p)
{ switch (p) {
    case XLbox: fprintf(*iou, "<box>"); break;
    case XBLOCK: fprintf(*iou, "<[]>"); break;
    case XLellipse: fprintf(*iou, "<ellipse>"); break;
    case XLcircle: fprintf(*iou, "<circle>"); break;
    case XLline: fprintf(*iou, "<line>"); break;
    case XLarrow: fprintf(*iou, "<arrow>"); break;
    case XLmove: fprintf(*iou, "<move>"); break;
    case XLspline: fprintf(*iou, "<spline>"); break;
    case XLarc: fprintf(*iou, "<arc>"); break;
    case XLstring: fprintf(*iou, "<<string>>"); break;
    case XLaTeX: fprintf(*iou, "<<LaTeX>>"); break;
    case XLabel: fprintf(*iou, "<<Label>>"); break;
    default: fprintf(*iou, "Unknown type %3d", p); break;
    }
  fflush(*iou);
}


void
snaptree(primitive *pr, int indent)
{ int i, j = /* 6 */ 0;
  while ((pr != NULL) && (indent <= 240)) {
    snaptype(&log_, pr->ptype);
	/* fprintf(log_,"[%d]",odp(pr)); */
    switch (pr->ptype) {
      case XBLOCK: i = 4; break;
      case XLbox:
      case XLarc: i = 5; break;
      case XLline:
      case XLmove: i = 6; break;
      case XLarrow: i = 7; break;
      case XLcircle:
      case XLspline: i = 8; break;
      case XLellipse:
      case XLaTeX: i = 9; break;
      case XLstring: i = 10; break;
      case XLabel: i = 12; break;
      default: i = 3; break;
      }
    snaptree(pr->next_, indent + i + j);
    j = 0;
    if (pr->son != NULL) { fprintf(log_, "\n%*c", indent, ' '); }
    pr = pr->son;
    }
}

void
printtext(nametype *namptr)
{ nametype *With;

  while (namptr != NULL) {
      With = namptr;
      putc(' ', log_);
      wpair(&log_, ordp(namptr), ordp(With->next_));
      fprintf(log_, " val=");
      wfloat(&log_, With->val);
      fflush(log_);
      snapname(With->segmnt, With->seginx, With->len);
      namptr = With->next_;
      putc('\n', log_);
  }
}

void
printobject(primitive *primp)
{ double xx, yy;
  int i;
  primitive *With;

  if (debuglevel != 0) {
    if (primp == NULL) { fprintf(log_, "Object is nil\n"); }
    else {
	  while (primp != NULL) {
	    With = primp;
	    fprintf(log_, "Object(%d) type=", ordp(primp));
	    snaptype(&log_, With->ptype);
	    fprintf(log_, "(%d)\n", With->ptype);
	    fprintf(log_, " Parent(%d", ordp(With->parent));
	    if (With->parent != NULL) {
		  fprintf(log_, ") Parent^.son(%d", ordp(With->parent->son)); }
	    fprintf(log_, ") Son(%d) Next(%d)\n",
		      ordp(With->son), ordp(With->next_));
	    if (With->name != NULL) {
		  fprintf(log_, " name: ");
		  printtext(With->name); }
	    if (With->outlinep != NULL) {
		  fprintf(log_, " outline:");
		  printtext(With->outlinep); }
	    if (With->shadedp != NULL) {
		  fprintf(log_, " shaded:");
		  printtext(With->shadedp); }
	    if (With->textp != NULL) { printtext(With->textp); }
	    fprintf(log_, " aat");
	    wpair(&log_, With->aat.xpos, With->aat.ypos);
	    wlogfl("lparam", With->lparam, 0);
	    wlogfl("lthick", With->lthick, 0);
	    switch (With->direction) {
	      case XLup: fprintf(log_, " <up>"); break;
	      case XLdown: fprintf(log_, " <down>"); break;
	      case XLleft: fprintf(log_, " <left>"); break;
	      case XLright: fprintf(log_, " <right>"); break;
	      default: fprintf(log_, " dir =%d", With->direction); break;
	      }
	    fprintf(log_, " spec=%d\n", With->spec);
	    fflush(log_);
	    switch (With->ptype) {
	      case XLbox:
	      case XLstring:
		    wlogfl("boxfill", With->Upr.Ubox.boxfill, 0);
		    wlogfl("boxheight", With->Upr.Ubox.boxheight, 0);
		    wlogfl("boxwidth", With->Upr.Ubox.boxwidth, 0);
		    wlogfl("boxrad", With->Upr.Ubox.boxradius, 0);
		    break;
	      case XBLOCK:
		    wlogfl("blockheight", With->Upr.UBLOCK.blockheight, 0);
		    wlogfl("blockwidth", With->Upr.UBLOCK.blockwidth, 0);
		    fprintf(log_, " here=");
		    wpair(&log_, With->Upr.UBLOCK.here.xpos,
			  With->Upr.UBLOCK.here.ypos);
		    fprintf(log_, " vars=");
		    for (i = 0; i <= HASHLIM; i++) {
		      if (With->Upr.UBLOCK.vars[i] == NULL) {
				 fprintf(log_, " %d nil;", i);}
		      else {
				fprintf(log_, " %d %d;", i, ordp(With->Upr.UBLOCK.vars[i])); }
		      }
		    fprintf(log_, "\n env=");
		    if (With->Upr.UBLOCK.env == NULL) { fprintf(log_, "nil"); }
		    else { fprintf(log_, "%d", ordp(With->Upr.UBLOCK.env)); }
		    break;
	      case XLcircle:
		    wlogfl("cfill", With->Upr.Ucircle.cfill, 0);
		    wlogfl("radius", With->Upr.Ucircle.radius, 0);
		    break;
	      case XLellipse:
		    wlogfl("efill", With->Upr.Uellipse.efill, 0);
		    wlogfl("elheight", With->Upr.Uellipse.elheight, 0);
		    wlogfl("elwidth", With->Upr.Uellipse.elwidth, 0);
		    break;
	      case XLline:
	      case XLarrow:
	      case XLmove:
	      case XLspline:
		    fprintf(log_, " endpos=");
		    wpair(&log_, With->Upr.Uline.endpos.xpos,
		      With->Upr.Uline.endpos.ypos);
		    wlogfl("height", With->Upr.Uline.height, 0);
		    wlogfl("width", With->Upr.Uline.width, 0);
		    wlogfl("lfill", With->Upr.Uline.lfill, 0);
		    wlogfl("aradius", With->Upr.Uline.aradius, 0);
		    fprintf(log_, "\n ahlex(atype)=%d",
			    ahlex(With->Upr.Uline.atype));
		    fprintf(log_, " ahnum(atype)=%d", ahnum(With->Upr.Uline.atype));
		    break;
	      case XLarc:
		    fprintf(log_, " lspec=%d", lspec(With->spec));
		    wlogfl("lfill", With->Upr.Uline.lfill, 0);
		    wlogfl("aradius", With->Upr.Uline.aradius, 0);
		    fprintf(log_, " (|startangle|,|arcangle|)(deg)=");
		    wpair(&log_, With->Upr.Uline.endpos.xpos * 180.0 / pi,
		      With->Upr.Uline.endpos.ypos * 180.0 / pi);
		    fprintf(log_, "\n (from)=");
		    xx = With->aat.xpos +
		     (With->Upr.Uline.aradius * cos(With->Upr.Uline.endpos.xpos));
		    yy = With->aat.ypos +
		     (With->Upr.Uline.aradius * sin(With->Upr.Uline.endpos.xpos));
		    wpair(&log_, xx, yy);
		    fprintf(log_, " (to)=");
		    xx = With->aat.xpos + (With->Upr.Uline.aradius * cos(
			 With->Upr.Uline.endpos.xpos + With->Upr.Uline.endpos.ypos));
		    yy = With->aat.ypos + (With->Upr.Uline.aradius * sin(
			 With->Upr.Uline.endpos.xpos + With->Upr.Uline.endpos.ypos));
		    wpair(&log_, xx, yy);
		    fprintf(log_, " ahlex(atype)=%d", ahlex(With->Upr.Uline.atype));
		    fprintf(log_, " ahnum(atype)=%d", ahnum(With->Upr.Uline.atype));
		    break;
	      case XLaTeX:
	      case XLabel:
			/* blank case */
		    break;
	      default:
		    fprintf(log_, " Bad case in printobject; this cannot happen\n");
		    break;
	      }
	    putc('\n', log_);
	    fflush(log_);
	    if (With->ptype == XBLOCK) { primp = NULL; }
	    else { primp = With->son; }
	    }
      }
  }
  putc('\n', log_);
  fflush(log_);
}

void
prattribute(char *label, attribute *a)
{
  fprintf(log_, "attribute %s[%d]:", label, ordp(a));
  fprintf(log_, "\n lexval %4d", a->lexval);
  fprintf(log_, "  state %4d", a->state);
  fprintf(log_, "  chbufx %4d", a->chbufx);
  fprintf(log_, "  toklen %4d\n", a->toklen);
  if (a->varname != NULL) {
    fprintf(log_, " varname "); printtext(a->varname); }
  fprintf(log_, " xval %g", a->xval);
  fprintf(log_, " yval %g\n", a->yval);
  if (a->prim != NULL) {
    fprintf(log_, " prim[%d]",ordp(a->prim));
    fprintf(log_, " ptype : %4d ", a->prim->ptype);
    snaptype(&log_,a->prim->ptype); }
  putc('\n', log_);
  if (a->internal != NULL) {
    fprintf(log_, "intrtype: ");
    fprintf(log_, "%4d", a->internal->ptype);
    putc('\n', log_); }
}

void
prvars(primitive *eb)
{ nametype *lv;
  int i = 0, x = HASHLIM + 1;
  if (eb == NULL) { fprintf(log_, "vars=nil: nil envblock"); return; }
  while (i < x) { if (eb->Upr.UBLOCK.vars[i] != NULL) { x = i; } else { i++; } }
  fprintf(log_, "vars=\n");
  if (x > HASHLIM) { fprintf(log_, "  None set\n"); return; }
  for (i = 0; i <= HASHLIM; i++) {
    fprintf(log_, "%d", i);
    lv = eb->Upr.UBLOCK.vars[i];
    if (lv == NULL) { fprintf(log_, " nil\n"); }
    while (lv != NULL) {
	  fprintf(log_, " (%d,%d)=", ordp(lv), ordp(lv->next_));
	  snapname(lv->segmnt, lv->seginx, lv->len);
	  putc('=', log_);
	  wfloat(&log_, lv->val);
	  putc('\n', log_);
	  lv = lv->next_;
      }
    }
  putc('\n', log_);
}
#endif

							/* Dispose of a tree of 1 or more objects */
void
deletetree(primitive **p)
{ primitive *r;
  int i;
  primitive *With;
  if ((*p) != NULL) { (*p)->parent = NULL; }
  while ((*p) != NULL) {
    while (((*p)->next_ != NULL) || ((*p)->son != NULL)) {
	  r = *p;
	  if ((*p)->next_ != NULL) { *p = (*p)->next_; r->next_ = NULL; }
	  else { *p = (*p)->son; r->son = NULL; }
	  (*p)->parent = r;
      }
    r = (*p)->parent;
    deletename(&(*p)->shadedp);
    deletename(&(*p)->outlinep);
    deletename(&(*p)->textp);
    deletename(&(*p)->name);
    With = *p;
    if ((With->ptype) == XBLOCK) {
	  for (i = HASHLIM; i >= 0; i--) { deletename(&With->Upr.UBLOCK.vars[i]);}
	  if (With->Upr.UBLOCK.env != NULL) { Free(With->Upr.UBLOCK.env); }
      }
    else { Free(*p); }
    *p = r;
    }
  }


							/* Store arc strtang and arcang parameters */
void
setangles(double *strtang, double *arcang, postype ctr, double xs, double ys,
	  double xf, double yf)
{ double ra;                       /* set arc angles given centre, start, end */

  *strtang = datan(ys - ctr.ypos, xs - ctr.xpos);
  ra = principal(datan(yf - ctr.ypos, xf - ctr.xpos) - (*strtang), pi);
  if ((ra < 0.0) && ((*arcang) > 0.0)) {
      ra += 2.0 * pi;
  }
  else if ((ra > 0.0) && ((*arcang) < 0.0)) {
      ra -= 2.0 * pi;
  }
  *arcang = ra;
}


							/* Perform assignment operator */
void
eqop(double *x, int op, double y)
{ int i, j;

  switch (op) {

  case XEQ:
  case XLcoloneq:
    *x = y;
    break;

  case XLpluseq:
    *x += y;
    break;

  case XLminuseq:
    *x -= y;
    break;

  case XLmulteq:
    *x *= y;
    break;

  case XLdiveq:
    if (y == 0) {
	markerror(852);
    }
    else {
	*x /= y;
    }
    break;

  case XLremeq:
    i = Rnd((*x));
    j = Rnd(y);
    if (j == 0) {
	markerror(852);
	*x = 0.0;
    }
    else {
	*x = i - ((i / j) * j);
    }
    break;
  }
}

							/* Store int value in bits 9 and above */
void
setstval(int *st, int value)
{ *st = (value * 256) + ((*st) & 255);
}

							/* Recover int value from bits 9 and above */
int
getstval(int st)
{ return (st >> 8);
}

							/* Record application of object attribute */
void
setstflag(int *st, int value)
{ switch (value) {

  case XEMPTY:
    *st = ((*st) >> 6) * 64;
    break;

  case XLto:
    *st = (((*st) >> 1) * 2) + 1;
    break;

  case XLfrom:
    *st = (((*st) >> 2) * 4) + ((*st) & 1) + 2;
    break;

  case XLat:
    *st = (((*st) >> 3) * 8) + ((*st) & 3) + 4;
    break;

  case XLradius:
    *st = (((*st) >> 4) * 16) + ((*st) & 7) + 8;
    break;

  case XLcw:
    *st = (((*st) >> 5) * 32) + ((*st) & 15) + 16;
    break;

  case XLccw:
    *st = (((*st) >> 6) * 64) + ((*st) & 31) + 32;
    break;

  case XLchop:
    *st = (((*st) >> 7) * 128) + ((*st) & 63) + 64;
    break;

  case XLdirecton:
    *st = (((*st) >> 8) * 256) + ((*st) & 127) + 128;
    break;
  }
}


							/* Test if attribute has been applied */
boolean
teststflag(int st, int value)
{ boolean b = false;

  switch (value) {

  case XLto:
    b = st & 1;
    break;

  case XLfrom:
    b = (st >> 1) & 1;
    break;

  case XLat:
    b = (st >> 2) & 1;
    break;

  case XLradius:
    b = (st >> 3) & 1;
    break;

  case XLcw:
    b = (st >> 4) & 1;
    break;

  case XLccw:
    b = (st >> 5) & 1;
    break;

  case XLchop:
    b = (st >> 6) & 1;
    break;

  case XLdirecton:
    b = (st >> 7) & 1;
    break;
  }
  return b;
}

							/* String equality of primitives */
int
cmpstring(primitive *p1, primitive *p2)
{ if ((p1 == NULL) || (p2 == NULL)) {
      return maxint;
  }
  else if (p1->textp == NULL) {
      return maxint;
  }
  else if (p2->textp == NULL) {
      return (-maxint);
  }
  else {
      return (eqstring(p1->textp->segmnt, p1->textp->seginx, p1->textp->len,
		       p2->textp->segmnt, p2->textp->seginx, p2->textp->len));
  }
}


							/* Match place name with stored places */
primitive *(
findplace(primitive *p, Char *chb, chbufinx inx, chbufinx toklen))
{ primitive *pj = NULL;
  nametype *With;

  while (p != pj) {
      if (p->name == NULL) {
	  p = p->next_;
      }
      else {
	  With = p->name;
	  if (eqstring(With->segmnt, With->seginx, With->len, chb, inx,
		       toklen) == 0) {
	      pj = p;
	  }
	  else {
	      p = p->next_;
	  }
      }
  }
  return p;
}

							/* Get the value of a global variable */
double
findvar(Char *s, int ln)
{ int i, k;
  nametype *last, *np;

  if (tmpfmt == NULL) {
      tmpfmt = malloc(sizeof(chbufarray));
  }
  for (i = 1; i <= ln; i++) {
      tmpfmt[i] = s[i-1];
  }
  np = findname(globalenv, tmpfmt, 1, ln, &last, &k);
  if (np == NULL) {
      return 0.0;
  }
  else {
      return (np->val);
  }
}

							/* Search for variable in this and higer scope*/
nametype *(
glfindname(primitive *eb, Char *chb, chbufinx chbufx, chbufinx toklen,
	   nametype **last, int *k))
{ nametype *np = NULL;
  primitive *pp = NULL;
  *k = 1;
  while (eb != pp) {
    np = findname(eb, chb, chbufx, toklen, last, k);
    if (np != NULL) { pp = eb; }
    else { eb = eb->parent; }
    }
  if (eb == NULL) { marknotfound(851, chb, chbufx, toklen); }
  return np;
}


							/* Append the int string to the name string*/
void
appendsuff(Char *buf, chbufinx inx, int *len, double x)
{ int i, j, k;
  i = Rnd(x);
  if (i < 0) { buf[inx + (*len)] = '-'; (*len)++; i = -i; }
  k = i;
  do {
    (*len)++;
    k /= 10;
    } while (k != 0);
  if (inx + (*len) - 1 > CHBUFSIZ) { fatal(4); }
  j = (*len) - 1;
  do {
    k = i / 10;
    buf[inx + j] = i - (k * 10) + '0';
    i = k;
    j--;
    } while (i != 0);
}

							/* Append the suffix string to the name string
							   for one or two integers */
void
addsuffix(Char *buf, chbufinx *inx, int *len, double x, int lx, double y)
{ int i, FORLIM;
  if (chbufi + (*len) - 1 > CHBUFSIZ) { fatal(4); }
  if ((*inx) + (*len) != chbufi) {
    FORLIM = *len;
    for (i = 0; i < FORLIM; i++) {
      buf[chbufi + i] = buf[(*inx) + i];
      buf[(*inx) + i] = '\0'; }
    *inx = chbufi; }
  if ((*inx) + (*len) + 2 > CHBUFSIZ) { fatal(4); }
  buf[(*inx) + (*len)] = '[';
  (*len)++;
  appendsuff(buf, *inx, len, x);
  if (lx == Xcomma) {
    buf[(*inx) + (*len)] = ',';
    (*len)++;
    appendsuff(buf, *inx, len, y); }
  buf[(*inx) + (*len)] = ']';
  (*len)++;
  chbufi = (*inx) + (*len);
}  /* addsuffix */


							/* Implement "then" or the "to" special case */
void
appendthen(primitive **pr)
{ primitive *prp, *prq;
  for (prq=(*pr); prq->son != NULL; prq = prq->son) {}
  copyprim(prq, &prp);
  prp->parent = prq;
  prp->son = NULL;
  prp->next_ = NULL;
  prp->name = NULL;
  prp->textp = NULL;
  prp->shadedp = NULL;
  if (prp->outlinep != NULL) {  /* We have to duplicate the stored string */
    copystr(&prp->outlinep, prq->outlinep); }
  FindExitPoint(prq, &prp->aat);
  prq->son = prp;
  setthen(&prp->spec);
  *pr = prp;
}

							/* Attribute up, down, left, right */
void
lineardir(primitive *pr, double dy, double dx, int *state)
{ if (!(teststflag(*state, XLto) | teststflag(*state, XLdirecton))) {
      pr->Upr.Uline.endpos = pr->aat; }
  switch (pr->direction) {
  case XLup:
    pr->Upr.Uline.endpos.ypos += dy;
    break;
  case XLdown:
    pr->Upr.Uline.endpos.ypos -= dy;
    break;
  case XLleft:
    pr->Upr.Uline.endpos.xpos -= dx;
    break;
  case XLright:
    pr->Upr.Uline.endpos.xpos += dx;
    break;
  }
  setstflag(state, XLdirecton);
}

							/* Test for outline for outlined "string" */
boolean
hasoutline(int lx, boolean warn)
{ boolean hs;
  hs = ((lx == XLspline) || (lx == XLarrow) || (lx == XLline) ||
	(lx == XLarc) || (lx == XLellipse) ||
	(lx == XLcircle) || (lx == XLbox));
  if (drawmode == SVG) { hs = (hs || (lx == XLstring)); }
  if ((!hs) && warn) { markerror(858); }
  return hs;
}


							/* Test for shade for shaded "string" */
boolean
hasshade(int lx, boolean warn)
{ boolean hs;
  if ((lx == XLellipse) || (lx == XLcircle) || (lx == XLbox)) { hs = true; }
  else if ((drawmode >= 0) && (drawmode < 32) &&
	   (((1L << drawmode) & ((1L << Pict2e) | (1L << TeX) | (1L << tTeX) |
				 (1L << xfig))) != 0)) {
      hs = false; }
  else { hs = ((lx == XLspline) || (lx == XLarrow) || (lx == XLline) ||
	    (lx == XLarc)); }
  if (drawmode == SVG) { hs = (hs || (lx == XLstring)); }
  if ((!hs) && warn) { markerror(858); }
  return hs;
}


							/* Create a string struct */
void
newstr(nametype **sp)
{
  nametype *With;
  *sp = malloc(sizeof(nametype));
  With = *sp;
  With->val = 0.0;
  With->segmnt = NULL;
  With->seginx = 0;
  With->len = 0;
  With->next_ = NULL;
#ifdef DDEBUG
  if (debuglevel > 0) { fprintf(log_, "newstr[%d]\n", ordp(*sp)); }
#endif
}


							/* Copy a string into freeseg */
void
storestring(nametype *outstr,Char *srcbuf,chbufinx psrc,chbufinx lsrc,int job)
{ int i, j;
  boolean newseg;
  if ((freeseg == NULL) || (lsrc > (CHBUFSIZ - freex + 1))) { newseg = true; }
  else { newseg = false; }
  if (newseg) {
    freeseg = malloc(sizeof(chbufarray));
#ifdef DDEBUG
    if (debuglevel>0) { fprintf(log_, "storestring new[%d]\n", ordp(freeseg));}
#endif
    putbval(freeseg, 0);
    freex = 3; }
  for (i = 0; i < lsrc; i++) { freeseg[freex + i] = srcbuf[psrc + i]; }
  outstr->segmnt = freeseg;
  outstr->seginx = freex;
  outstr->len = lsrc;
  j = bval(freeseg);
  putbval(freeseg, j + 1);
  freex += lsrc;
#ifdef DDEBUG
  if (debuglevel > 0) {
  fprintf(log_,
	  "storestring to strptr %d: segmnt=%d seginx=%d links=%d freex=%d\n",
	  ordp(outstr), ordp(freeseg), outstr->seginx, bval(freeseg), freex);
  snapname(freeseg, outstr->seginx, outstr->len);
  fprintf(log_, " from:");
  snapname(srcbuf, psrc, lsrc);
  putc('\n', log_); }
#endif
  if (job != 0) { clearchbuf(psrc, lsrc); }
  }

							/* Duplicate a strptr and copy the body */
void
copystr(nametype **sp, nametype *ip)
{ if (ip == NULL) {
      *sp = NULL;
  }
  else {
      newstr(sp);
      storestring(*sp, ip->segmnt, ip->seginx, ip->len, 0);
  }
}


							/* Append buf to *sp */
void
appendstring(nametype *sp, Char *buf, chbufinx px, chbufinx ll)
{
  int i;
  int j;
  Char *tmpseg;
  int FORLIM;
  if ((sp == NULL) || (buf == NULL)) { return; }
  if ((sp->segmnt == freeseg) && (sp->seginx + sp->len == freex) &&
      (freex + ll - 1 <= CHBUFSIZ)) {
    for (i = 0; i < ll; i++) { freeseg[freex + i] = buf[px + i]; }
    sp->len += ll;
    freex += ll;
    return;
    }
  if (sp->len + ll + 2 > CHBUFSIZ) { markerror(866); return; }
  tmpseg = malloc(sizeof(chbufarray));
  FORLIM = sp->len;
  for (i = 0; i < FORLIM; i++) { tmpseg[i+3] = sp->segmnt[sp->seginx + i]; }
  j = bval(sp->segmnt);
  if (j > 1) {
    putbval(sp->segmnt, j - 1);
    if ((sp->segmnt == freeseg) && (sp->seginx + sp->len == freex)) {
	  freex = sp->seginx;
	  j = 3;
	  while (freex > j) {
	    if (sp->segmnt[freex-1] == nlch) { freex--; }
	    else { j = freex; }
	    }
      }
    else {
	  FORLIM = sp->seginx + sp->len;
	  for (i = sp->seginx; i < FORLIM; i++) { sp->segmnt[i] = nlch; }
      }
    }
  else {
    if (sp->segmnt == freeseg) { freeseg = NULL; }
    Free(sp->segmnt);
    }
  for (i = 0; i < ll; i++) { tmpseg[sp->len + i + 3] = buf[px + i]; }
  freeseg = tmpseg;
  freex = sp->len + ll + 3;
  putbval(freeseg, 1);
  sp->segmnt = freeseg;
  sp->seginx = 3;
  sp->len += ll;
}


							/* Store or append string */
int
putstring(int ix, nametype *sp, Char *buf, chbufinx px, chbufinx ll)
{ if (ix <= 0) {
      storestring(sp, buf, px, ll, 0);
  }
  else {
      appendstring(sp, buf, px, ll);
  }
  return (ix + 1);
}


							/* Height of a primitive object */
double
pheight(primitive *pr)
{ double ph;

  if (pr == NULL) {
      ph = 0.0;
      return ph;
  }
  switch (pr->ptype) {

  case XLbox:
    ph = pr->Upr.Ubox.boxheight;
    break;

  case XLstring:
    ph = pr->Upr.Ubox.boxheight;
    break;

  case XBLOCK:
    ph = pr->Upr.UBLOCK.blockheight;
    break;

  case XLellipse:
    ph = pr->Upr.Uellipse.elheight;
    break;

  case XLcircle:
    ph = 2.0 * pr->Upr.Ucircle.radius;
    break;

  case XLline:
  case XLarrow:
  case XLmove:
  case XLspline:
    ph = pr->Upr.Uline.height;
    break;

  default:
    ph = 0.0;
    break;
  }
  return ph;
}


							/* Width of a primitive object */
double
pwidth(primitive *pr)
{ double pw;

  if (pr == NULL) {
      pw = 0.0;
      return pw;
  }
  switch (pr->ptype) {

  case XLbox:
  case XLstring:
    pw = pr->Upr.Ubox.boxwidth;
    break;

  case XBLOCK:
    pw = pr->Upr.UBLOCK.blockwidth;
    break;

  case XLellipse:
    pw = pr->Upr.Uellipse.elwidth;
    break;

  case XLcircle:
    pw = 2.0 * pr->Upr.Ucircle.radius;
    break;

  case XLline:
  case XLarrow:
  case XLmove:
  case XLspline:
    pw = pr->Upr.Uline.width;
    break;

  default:
    pw = 0.0;
    break;
  }
  return pw;
}


							/* The n, s, e, w values of a drawing tree */
void
neswrec(primitive *ptm)
{ while (ptm != NULL) {
    nesw(ptm);
    if (ptm->ptype != XBLOCK) { neswrec(ptm->son); }
    ptm = ptm->next_;
    }
  }


							/* Bounding box of a drawing tree */
void
getnesw(primitive *ptm)
{ initnesw();
  neswrec(ptm);
  if (south > north) {
    south = 0.0;
    north = 0.0;
    }
  if (west > east) {
    west = 0.0;
    east = 0.0;
    }
}


							/* Test and return A(bove), B(elow),
							                   L(eft), R(ight) */
void
checkjust(nametype *tp, boolean *A, boolean *B, boolean *L, boolean *R)
{ int i;

  if (tp == NULL) {
    *A = false;
    *B = false;
    *L = false;
    *R = false;
    return;
    }
  i = Rnd(tp->val);
  *R = i & 1;
  *L = (i >> 1) & 1;
  *B = (i >> 2) & 1;
  *A = (i >> 3) & 1;
}

							/* Return linespec, i.e.,
							   <solid>, <dotted>, <dashed>, <invis>
							   from lowest 3 bits */
int
lspec(int n)
{ /* if ((n div 16) mod 2) <> 0 then lspec := XLsolid
  else */
  return ((n & 7) + XLlinetype);
}

							/* Find the lowest block with environment
							   variables defined */
primitive *(
findenv(primitive *p))
{ primitive *q = NULL;

  while (p != q) {
      if (p->ptype != XBLOCK) {
	  p = p->parent;
      }
      else if (p->Upr.UBLOCK.env == NULL) {
	  p = p->parent;
      }
      else {
	  q = p;
      }
  }
  return p;
}


							/* Get the value of an environment variable */
double
venv(primitive *p, int ind)
{ double v = 0.0;
  if ((ind <= XXenvvar) || (ind > XLlastenv)) { return v; }
  p = findenv(p);
  if (p != NULL) { v = p->Upr.UBLOCK.env[ind - XXenvvar - 1]; }
  return v;
}


							/* Get the value of an environment variable
							   if it has not been set locally */
double
qenv(primitive *p, int ind, double localval)
{ double noval;
  switch (ind) {
    case XLfillval: noval = -1.0; break;
    case XLlinethick: noval = mdistmax; break;
    case XLdashwid: noval = mdistmax; break;
    default: noval = 0.0; break;
    }
  if (localval != noval) { return localval; }
  else { return (venv(p, ind)); }
}


							/* Position from an affine transformation
							   orig + mat(cs) * [x,y]
							   Position cs is (cos t, sin t) */
postype
affine(double x, double y, postype orig, postype cs)
{ postype tpos;

  tpos.xpos = orig.xpos + (cs.xpos * x) - (cs.ypos * y);
  tpos.ypos = orig.ypos + (cs.ypos * x) + (cs.xpos * y);
  return tpos;
}


							/* Get (cos t, sin t) of point wrt shaft */
postype
affang(postype point, postype shaft)
{ double lgth;
  postype tpos;

  lgth = linlen(shaft.xpos - point.xpos, shaft.ypos - point.ypos);
  if (lgth == 0.0) {
      tpos.xpos = 1.0;
      tpos.ypos = 0.0;
  }
  else {
      tpos.xpos = (point.xpos - shaft.xpos) / lgth;
      tpos.ypos = (point.ypos - shaft.ypos) / lgth;
  }
  return tpos;
}

							/* Initialize parameters for routine nesw */
void
initnesw(void)
{ south = distmax;
  north = -south;
  west = south;
  east = -west;
}


							/* Values north, south, west, east for a string
							   accounting for ljust rjust above below */
void
neswstring(primitive *pmp, double ht, double wd)
{ boolean A, B, L, R;
  double x, y, offst;
  if (pmp == NULL) { return; }
  checkjust(pmp->textp, &A, &B, &L, &R);
  offst = venv(pmp, XLtextoffset);
  y = pmp->aat.ypos;
  if (A) { y += (ht * 0.5) + offst; }
  else if (B) { y += ((-ht) * 0.5) - offst; }
  x = pmp->aat.xpos;
  if (R) { x += ((-wd) * 0.5) - offst; }
  else if (L) { x += (wd * 0.5) + offst; }
  north = Max(north, y + (ht * 0.5));
  south = Min(south, y - (ht * 0.5));
  west = Min(west, x - (wd * 0.5));
  east = Max(east, x + (wd * 0.5));
#ifdef DDEBUG
  if (debuglevel > 0) {
    fprintf(log_, " neswstring:");
    wlogfl("aat.xpos", pmp->aat.xpos, 0);
    wlogfl("x", x, 0);
    wlogfl("y", y, 1);
    wlogfl("east", east, 0);
    wlogfl("west", west, 0);
    wlogfl("wd", wd, 1);
    wlogfl("north", north, 0);
    wlogfl("south", south, 0);
    wlogfl("ht", ht, 1); }
#endif
}


							/* Values north, south, west, east for a line
							   or arrow */
void
neswline(primitive *pmp)
{ double aht, awd;
  postype cs, cc, cd;
  int TEMP;

  if (pmp == NULL) {
      return;
  }
  west = Min(west, Min(pmp->aat.xpos, pmp->Upr.Uline.endpos.xpos));
  east = Max(east, Max(pmp->aat.xpos, pmp->Upr.Uline.endpos.xpos));
  south = Min(south, Min(pmp->aat.ypos, pmp->Upr.Uline.endpos.ypos));
  north = Max(north, Max(pmp->aat.ypos, pmp->Upr.Uline.endpos.ypos));
  TEMP = ahlex(pmp->Upr.Uline.atype);
  if ((TEMP == XLEFTHEAD) || (TEMP == XDOUBLEHEAD)) {
      cs = affang(pmp->Upr.Uline.endpos, pmp->aat);
      awd = qenv(pmp, XLarrowht, pmp->Upr.Uline.width);
      aht = qenv(pmp, XLarrowwid, pmp->Upr.Uline.height);
      cc = affine(aht, awd / 2, pmp->aat, cs);
      cd = affine(aht, awd / (-2), pmp->aat, cs);
      west = Min(west, Min(cc.xpos, cd.xpos));
      east = Max(east, Max(cc.xpos, cd.xpos));
      south = Min(south, Min(cc.ypos, cd.ypos));
      north = Max(north, Max(cc.ypos, cd.ypos));
  }
  TEMP = ahlex(pmp->Upr.Uline.atype);
  if (!((TEMP == XRIGHTHEAD) || (TEMP == XDOUBLEHEAD))) {
      return;
  }
  cs = affang(pmp->aat, pmp->Upr.Uline.endpos);
  awd = qenv(pmp, XLarrowht, pmp->Upr.Uline.width);
  aht = qenv(pmp, XLarrowwid, pmp->Upr.Uline.height);
  cc = affine(aht, awd / 2, pmp->Upr.Uline.endpos, cs);
  cd = affine(aht, awd / (-2), pmp->Upr.Uline.endpos, cs);
  west = Min(west, Min(cc.xpos, cd.xpos));
  east = Max(east, Max(cc.xpos, cd.xpos));
  south = Min(south, Min(cc.ypos, cd.ypos));
  north = Max(north, Max(cc.ypos, cd.ypos));
}


							/* Test if angle is within an arc segment */
boolean
inarc(double strt, double fin, double ang, double arcang)
{ boolean inarctmp;

  if (arcang >= 0.0) {
      while (fin < strt) {
	  fin += 2.0 * pi;
      }
      while (ang < strt) {
	  ang += 2.0 * pi;
      }
      if (ang <= fin) {
	  inarctmp = true;
      }
      else {
	  inarctmp = false;
      }
      return inarctmp;
  }
  while (fin > strt) {
      fin -= 2.0 * pi;
  }
  while (ang > strt) {
      ang -= 2.0 * pi;
  }
  if (ang >= fin) {
      inarctmp = true;
  }
  else {
      inarctmp = false;
  }
  return inarctmp;
}


							/* Values north, south, east, west of an obj */
void
nesw(primitive *ptmp)
{ double hight, wdth, sang, eang;
  if (ptmp == NULL) { return; }
  switch (ptmp->ptype) {
    case XLstring:
      hight = ptmp->Upr.Ubox.boxheight;
      wdth = ptmp->Upr.Ubox.boxwidth;
      break;
    case XLbox:
      hight = ptmp->Upr.Ubox.boxheight;
      wdth = ptmp->Upr.Ubox.boxwidth;
      break;
    case XBLOCK:
      hight = ptmp->Upr.UBLOCK.blockheight;
      wdth = ptmp->Upr.UBLOCK.blockwidth;
      break;
    case XLcircle:
      hight = 2.0 * ptmp->Upr.Ucircle.radius;
      wdth = hight;
      break;
    case XLellipse:
      hight = ptmp->Upr.Uellipse.elheight;
      wdth = ptmp->Upr.Uellipse.elwidth;
      break;
    default:
      hight = 0.0;
      wdth = 0.0;
      break;
    }
  switch (ptmp->ptype) {
  case XLbox:
  case XBLOCK:
  case XLcircle:
  case XLellipse:
    north = Max(north, ptmp->aat.ypos + (hight * 0.5));
    south = Min(south, ptmp->aat.ypos - (hight * 0.5));
    west = Min(west, ptmp->aat.xpos - (wdth * 0.5));
    east = Max(east, ptmp->aat.xpos + (wdth * 0.5));
    break;
  case XLstring:
    if (drawmode == SVG) {
	north = Max(north, ptmp->aat.ypos + (hight * 0.5));
	south = Min(south, ptmp->aat.ypos - (hight * 0.5));
	west = Min(west, ptmp->aat.xpos - (wdth * 0.5));
	east = Max(east, ptmp->aat.xpos + (wdth * 0.5));
    }
    else {
	neswstring(ptmp, hight, wdth);
    }
    break;
  case XLline:
  case XLarrow:
  case XLmove:
  case XLspline:
    neswline(ptmp);
    break;
  case XLaTeX:
  case XLabel:
	/* blank case */
    break;
  case XLarc:
    sang = principal(ptmp->Upr.Uline.endpos.xpos, pi);
    eang = ptmp->Upr.Uline.endpos.xpos + ptmp->Upr.Uline.endpos.ypos;
    if (inarc(sang, eang, 0.5 * pi, ptmp->Upr.Uline.endpos.ypos)) {
	  north = Max(north, ptmp->aat.ypos + ptmp->Upr.Uline.aradius); }
    else { north = Max(north,
	  ptmp->aat.ypos + (ptmp->Upr.Uline.aradius * Max(sin(sang), sin(eang)))); }
    if (inarc(sang, eang, (-0.5) * pi, ptmp->Upr.Uline.endpos.ypos)) {
	  south = Min(south, ptmp->aat.ypos - ptmp->Upr.Uline.aradius); }
    else { south = Min(south,
	  ptmp->aat.ypos + (ptmp->Upr.Uline.aradius * Min(sin(sang), sin(eang)))); }
    if (inarc(sang, eang, pi, ptmp->Upr.Uline.endpos.ypos)) {
	  west = Min(west, ptmp->aat.xpos - ptmp->Upr.Uline.aradius); }
    else { west = Min(west,
	  ptmp->aat.xpos + (ptmp->Upr.Uline.aradius * Min(cos(sang),cos(eang)))); }
    if (inarc(sang, eang, 0.0, ptmp->Upr.Uline.endpos.ypos)) {
	  east = Max(east, ptmp->aat.xpos + ptmp->Upr.Uline.aradius); }
    else { east = Max(east,
	  ptmp->aat.xpos + (ptmp->Upr.Uline.aradius * Max(cos(sang),cos(eang)))); }
    break;
  }
#ifdef DDEBUG
  if (debuglevel > 0) {
    fprintf(log_, "nesw(%d) ptype=%d", odp(ptmp), ptmp->ptype);
    wlogfl("W", west, 0); wlogfl("S", south, 0);
    wlogfl("E", east, 0); wlogfl("N", north, 1); }
#endif
}

							/* Exit point of a primitive object */
void
FindExitPoint(primitive *pr, postype *pe)
{ if (pr == NULL) {
      pe->xpos = 0.0;
      pe->ypos = 0.0;
      return;
  }
  if ((pr->ptype != XBLOCK) && (pr->son != NULL)) {
      FindExitPoint(pr->son, pe);
      return;
  }
  *pe = pr->aat;
  switch (pr->ptype) {

  case XLbox:
    switch (pr->direction) {

    case XLup:
      pe->ypos = pr->aat.ypos + (pr->Upr.Ubox.boxheight * 0.5);
      break;

    case XLdown:
      pe->ypos = pr->aat.ypos - (pr->Upr.Ubox.boxheight * 0.5);
      break;

    case XLleft:
      pe->xpos = pr->aat.xpos - (pr->Upr.Ubox.boxwidth * 0.5);
      break;

    case XLright:
      pe->xpos = pr->aat.xpos + (pr->Upr.Ubox.boxwidth * 0.5);
      break;
    }
    break;

  case XLstring:
    switch (pr->direction) {

    case XLup:
      pe->ypos = pr->aat.ypos + (pr->Upr.Ubox.boxheight * 0.5);
      break;

    case XLdown:
      pe->ypos = pr->aat.ypos - (pr->Upr.Ubox.boxheight * 0.5);
      break;

    case XLleft:
      pe->xpos = pr->aat.xpos - (pr->Upr.Ubox.boxwidth * 0.5);
      break;

    case XLright:
      pe->xpos = pr->aat.xpos + (pr->Upr.Ubox.boxwidth * 0.5);
      break;
    }
    break;

  case XBLOCK:
    switch (pr->direction) {

    case XLup:
      pe->ypos = pr->aat.ypos + (pr->Upr.UBLOCK.blockheight * 0.5);
      break;

    case XLdown:
      pe->ypos = pr->aat.ypos - (pr->Upr.UBLOCK.blockheight * 0.5);
      break;

    case XLleft:
      pe->xpos = pr->aat.xpos - (pr->Upr.UBLOCK.blockwidth * 0.5);
      break;

    case XLright:
      pe->xpos = pr->aat.xpos + (pr->Upr.UBLOCK.blockwidth * 0.5);
      break;
    }
    break;

  case XLcircle:
    switch (pr->direction) {

    case XLup:
      pe->ypos = pr->aat.ypos + pr->Upr.Ucircle.radius;
      break;

    case XLdown:
      pe->ypos = pr->aat.ypos - pr->Upr.Ucircle.radius;
      break;

    case XLleft:
      pe->xpos = pr->aat.xpos - pr->Upr.Ucircle.radius;
      break;

    case XLright:
      pe->xpos = pr->aat.xpos + pr->Upr.Ucircle.radius;
      break;
    }
    break;

  case XLellipse:
    switch (pr->direction) {

    case XLup:
      pe->ypos = pr->aat.ypos + (pr->Upr.Uellipse.elheight * 0.5);
      break;

    case XLdown:
      pe->ypos = pr->aat.ypos - (pr->Upr.Uellipse.elheight * 0.5);
      break;

    case XLleft:
      pe->xpos = pr->aat.xpos - (pr->Upr.Uellipse.elwidth * 0.5);
      break;

    case XLright:
      pe->xpos = pr->aat.xpos + (pr->Upr.Uellipse.elwidth * 0.5);
      break;
    }
    break;

  case XLarc:
    *pe = arcend(pr);
    break;

  case XLline:
  case XLarrow:
  case XLmove:
  case XLspline:
    *pe = pr->Upr.Uline.endpos;
    break;

  case XLabel:
  case XLaTeX:
	/* blank case */
    break;
  }
}

							/* Retrieve integer in first two buffer bytes */
int
bval(Char *buf)
{ return (((int) buf[0]) << 7) + (int) buf[1] ;
}

							/* Store integer in first two buffer bytes */
void
putbval(Char *buf, int n)
{
  buf[0] = (Char)(n>>7); buf[1] = (Char)(n % 128);
}

							/* Free the space used by the name string */
void
deletename(nametype **head)
{ /*F(var head: strptr)F*/
  nametype *pn, *r;
  int j, FORLIM;
  while ((*head) != NULL) {
    pn = *head;
    r = pn;
    while (pn->next_ != NULL) { r = pn; pn = pn->next_; }
    r->next_ = NULL;
    if (pn == (*head)) { *head = NULL; }
    if (pn->segmnt != NULL) {
	  if (bval(pn->segmnt) > 1) {
	    j = bval(pn->segmnt);
	    putbval(pn->segmnt, j - 1);
	    if ((pn->segmnt == freeseg) && (pn->seginx + pn->len == freex)) {
		  freex = pn->seginx;
		  j = 3;
		  while (freex > j) {
		    if (pn->segmnt[freex-1] == nlch) { freex--; }
		    else { j = freex; }
		    }
	      }
	    else {
		  FORLIM = pn->seginx + pn->len;
		  for (j = pn->seginx; j < FORLIM; j++) { pn->segmnt[j] = nlch; }
	      }
	    }
	  else if ((pn->segmnt == freeseg) && (freeseg != NULL)) {
	    Free(freeseg);
	    freeseg = NULL;
	    }
	  else {
	    Free(pn->segmnt);
        pn->segmnt = NULL;
	    }
      }
    Free(pn);
    }
}


							/* Store svalue in low 3 bits */
void
setspec(int *specv, int svalue)
{ *specv = (((*specv) >> 3) * 8) + svalue - XLlinetype;
							/* if svalue = XLsolid then
						     specv := (specv div 32)*32 + 16 + (specv mod 16) */
}

							/* Store svalue only in low 3 bits */
void
resetspec(int *specv, int svalue)
{ *specv = 0;
  setspec(specv, svalue);
}


							/* Set bit 4 to flag a segment with a parent */
void
setthen(int *specv)
{ *specv = (((*specv) >> 4) * 16) + ((*specv) & 7) + 8;
}

							/* Create and initialize a primitive object */
void
newprim(primitive **pr, int primtype, primitive *envblk)
{ int i;
  primitive *With;
  switch (primtype) {
    case XLbox:
    case XLstring:
      *pr = malloc(sizeof(XLboxprimitive));
      break;
    case XBLOCK:
      *pr = malloc(sizeof(primitive));
      break;
    case XLcircle:
      *pr = malloc(sizeof(XLcircleprimitive));
      break;
    case XLellipse:
      *pr = malloc(sizeof(XLellipseprimitive));
      break;
    case XLline:
    case XLarc:
    case XLarrow:
    case XLmove:
    case XLspline:
      *pr = malloc(sizeof(XLlineprimitive));
      break;
    case XLabel:
    case XLaTeX:
      *pr = malloc(sizeof(XLabelprimitive));
      break;
    }

#ifdef DDEBUG
  if (debuglevel > 0) {fprintf(log_, "newprim");
  snaptype(&log_,primtype); fprintf(log_,"[%d]\n", ordp(*pr));
  }
#endif

  With = *pr;
  With->name = NULL;
  With->textp = NULL;
  With->outlinep = NULL;
  With->shadedp = NULL;
  With->son = NULL;
  With->next_ = NULL;
  if (envblk == NULL) {
    With->parent = NULL;
    With->aat.xpos = 0.0;
    With->aat.ypos = 0.0;
    With->direction = XLright;
    }
  else {
    With->parent = envblk;
    With->aat = envblk->Upr.UBLOCK.here;
    With->direction = envblk->direction;
    }
  With->lparam = mdistmax;
  With->lthick = mdistmax;
  if ((primtype == XLstring) || (primtype == XLspline) ||
    (primtype == XLarc) || (primtype == XLarrow) || (primtype == XLline) ||
    (primtype == XLellipse) || (primtype == XLcircle) ||
    (primtype == XLbox)) { resetspec(&With->spec, XLsolid); }
  else { resetspec(&With->spec, XLinvis); }
  With->ptype = primtype;
  switch (primtype) {
    case XLbox:
    case XLstring:
      With->Upr.Ubox.boxfill = -1.0;
      With->Upr.Ubox.boxheight = 0.0;
      With->Upr.Ubox.boxwidth = 0.0;
      With->Upr.Ubox.boxradius = 0.0;
      break;
    case XBLOCK:
      With->Upr.UBLOCK.blockheight = 0.0;
      With->Upr.UBLOCK.blockwidth = 0.0;
      With->Upr.UBLOCK.here = With->aat;
      for (i = 0; i <= HASHLIM; i++) {
	    With->Upr.UBLOCK.vars[i]   = NULL;
	    With->Upr.UBLOCK.nvars[i]   = 0; }
      With->Upr.UBLOCK.env = NULL;
      break;
    case XLcircle:
      With->Upr.Ucircle.cfill = -1.0;
      With->Upr.Ucircle.radius = 0.0;
      break;
    case XLellipse:
      With->Upr.Uellipse.efill = -1.0;
      With->Upr.Uellipse.elheight = 0.0;
      With->Upr.Uellipse.elwidth = 0.0;
      break;
    case XLline:
    case XLarrow:
    case XLmove:
    case XLarc:
    case XLspline:
      With->Upr.Uline.endpos.xpos = 0.0;
      With->Upr.Uline.endpos.ypos = 0.0;
      With->Upr.Uline.height = 0.0;
      With->Upr.Uline.width = 0.0;
      With->Upr.Uline.lfill = -1.0;
      With->Upr.Uline.aradius = mdistmax;
      With->Upr.Uline.atype = pahlex(0, XEMPTY);
      break;
    case XLabel:
    case XLaTeX:
	/* blank case */
      break;
    }
}  /* newprim */

							/* Determine drawing direction at arc end */
void
arcenddir(primitive *pr)
{ if (pr->Upr.Uline.endpos.ypos > 0.0) {
      switch (pr->direction) {

      case 0:
	/* blank case */
	break;

      case XLup:
	envblock->direction = XLleft;
	break;

      case XLdown:
	envblock->direction = XLright;
	break;

      case XLleft:
	envblock->direction = XLdown;
	break;

      case XLright:
	envblock->direction = XLup;
	break;
      }
      return;
  }
  switch (pr->direction) {

  case 0:
	/* blank case */
    break;

  case XLup:
    envblock->direction = XLright;
    break;

  case XLdown:
    envblock->direction = XLleft;
    break;

  case XLleft:
    envblock->direction = XLup;
    break;

  case XLright:
    envblock->direction = XLdown;
    break;
  }
}


#ifdef DDEBUG
primitive *(node[10001]);
int ijx;

int
scantree(primitive *p, primitive *r)
{
int j,k;
  while ( r != NULL) {
    j = 0; k = ijx;
    node[ijx] = r;
    while (j < k) { if (r==node[j]) { k = j; } else { j++; } }
    if ( j < k ) { return 0; }
    else {
      if ( scantree(p, r->next_) == 0) { return 0; }
      if (ijx > 10000) { return 0; }
      r = r->son;
      ijx++;
      }
    }
  return 1;
  }

int
checktree( primitive *p )
{
  int ok;
  ijx = 0;
  node[ijx] = p;
  ok = scantree(p,p);
  fprintf(log_,"ok=%d ijx=%d\n",ok,ijx);
  return ok;
  }
#endif

							/* Shift a tree by (x,y) */
void
shift(primitive *pr, double x, double y)
{
#ifdef DDEBUG
  if (debuglevel > 0) { fprintf(log_,"\nshift[%d]=",ordp(pr));
    wpair(&log_, x, y); putc('\n', log_);
    snaptree(pr,0);
    fflush(log_); }
#endif
  if ((x == 0) && (y == 0)) { return; }
  while (pr != NULL) {
    pr->aat.xpos += x;
    pr->aat.ypos += y;
    if ((pr->ptype == XLspline) || (pr->ptype == XLmove) ||
	    (pr->ptype == XLarrow) || (pr->ptype == XLline)) {
	  pr->Upr.Uline.endpos.xpos += x;
	  pr->Upr.Uline.endpos.ypos += y; }
    if (pr->son != NULL) { shift(pr->son, x, y); }
    pr = pr->next_;
    }
}


							/* Scale an object */
void
scaleobj(primitive *pr, double s)
{ primitive *With;

  while (pr != NULL) {
      With = pr;
      With->aat.xpos *= s;
      With->aat.ypos *= s;
      if (With->ptype == XLbox) {
	  With->Upr.Ubox.boxheight *= s;
	  With->Upr.Ubox.boxwidth *= s;
	  With->Upr.Ubox.boxradius *= s;
      }
      else if (With->ptype == XBLOCK) {
	  With->Upr.UBLOCK.blockheight *= s;
	  With->Upr.UBLOCK.blockwidth *= s;
      }
      else if (With->ptype == XLcircle) {
	  With->Upr.Ucircle.radius *= s;
      }
      else if (With->ptype == XLellipse) {
	  With->Upr.Uellipse.elheight *= s;
	  With->Upr.Uellipse.elwidth *= s;
      }
      else if (With->ptype == XLarc) {
	  With->Upr.Uline.aradius *= s;
      }
      else if ((With->ptype == XLspline) || (With->ptype == XLmove) ||
	       (With->ptype == XLarrow) || (With->ptype == XLline)) {
	  With->Upr.Uline.endpos.xpos *= s;
	  With->Upr.Uline.endpos.ypos *= s;
      }
      if (With->son != NULL) {
	  scaleobj(With->son, s);
      }
      pr = With->next_;
  }
}


							/* corner(prim,<corner>,xval,yval); Put the
							   named-corner coordinates into xval,yval   */
void
corner(primitive *pr, int lexv, double *x, double *y)
{ primitive *pe;
  boolean sb, A, B, L, R;
  if (pr == NULL) { return; }
  *x = pr->aat.xpos;
  *y = pr->aat.ypos;
  pe = pr;
  if ((lexv == XEMPTY) &&
      ((pr->ptype == XLspline) || (pr->ptype == XLmove) ||
       (pr->ptype == XLarrow) || (pr->ptype == XLline))) {
    while (pe->son != NULL) { pe = pe->son; }
    *x = 0.5 * (pr->aat.xpos + pe->Upr.Uline.endpos.xpos);
    *y = 0.5 * (pr->aat.ypos + pe->Upr.Uline.endpos.ypos);
    return;
    }
  if ((lexv == XEMPTY) && (pr->ptype != XLstring) && (pr->ptype != XLaTeX)) {
      return; }
  switch (pr->ptype) {
    case XLbox:
    case XLstring:
    case XBLOCK:
    case XLcircle:
    case XLellipse:
    case XLarc:
      *x = pr->aat.xpos;
      *y = pr->aat.ypos;
      initnesw();
      nesw(pr);
							/* Compass corners of justified strings not
							   implemented: */
		/* if ptype = XLstring then begin
         checkjust(textp,A,B,L,R);
         offst := venv(pr,XLtextoffset);
         if L then x := x+boxwidth/2 + offst
         else if R then x := x-boxwidth/2 - offst;
         if A then y := y+boxheight/2 + offst
         else if B then y := y-boxheight/2 - offst;
         end; */
      if ((pr->ptype == XLstring) && (drawmode == SVG)) {
	    switch (lexv) {

	case XDn:
	  *y = north;
	  break;

	case XDs:
	  *y = south;
	  break;

	case XDe:
	  *x = east;
	  break;

	case XDw:
	  *x = west;
	  break;

	case XDne:
	  *y = north;
	  *x = east;
	  break;

	case XDse:
	  *y = south;
	  *x = east;
	  break;

	case XDsw:
	  *y = south;
	  *x = west;
	  break;

	case XDnw:
	  *y = north;
	  *x = west;
	  break;

	case XDc:
	  *y = pr->aat.ypos;
	  *x = pr->aat.xpos;
	  break;

	case XDstart:
	case XDend:
	  markerror(858);
	  break;
	}
	checkjust(pr->textp, &A, &B, &L, &R);
	if (L) { pr->Upr.Ubox.boxradius = (west - east) / 2; }
	else if (R) { pr->Upr.Ubox.boxradius = (east - west) / 2; }
    }
    else if (((pr->ptype == XLarc) || (pr->ptype == XLcircle) ||
	      (pr->ptype == XLellipse) || (pr->ptype == XLbox)) &&
	     ((lexv == XDnw) || (lexv == XDsw) || (lexv == XDse) ||
	      (lexv == XDne))) {
	switch (pr->ptype) {

	case XLbox:
	  *y = Min(pr->Upr.Ubox.boxradius,
		   Min(fabs(pr->Upr.Ubox.boxheight),
		       fabs(pr->Upr.Ubox.boxwidth)) / 2) * (1 - (1 / sqrt(2.0)));
	  *x = (pr->Upr.Ubox.boxwidth / 2) - (*y);
	  *y = (pr->Upr.Ubox.boxheight / 2) - (*y);
	  break;

	case XLellipse:
	  *x = pr->Upr.Uellipse.elwidth * (0.5 / sqrt(2.0));
	  *y = pr->Upr.Uellipse.elheight * (0.5 / sqrt(2.0));
	  break;

	case XLarc:
	  *x = pr->Upr.Uline.aradius / sqrt(2.0);
	  *y = *x;
	  break;

	case XLcircle:
	  *x = pr->Upr.Ucircle.radius / sqrt(2.0);
	  *y = *x;
	  break;
	}
	switch (lexv) {

	case XDne:
	/* blank case */
	  break;

	case XDse:
	  *y = -*y;
	  break;

	case XDnw:
	  *x = -*x;
	  break;

	case XDsw:
	  *x = -*x;
	  *y = -*y;
	  break;
	}
	*x = pr->aat.xpos + (*x);
	*y = pr->aat.ypos + (*y);
    }
    else if (pr->ptype == XLarc) {
	switch (lexv) {

	case XDn:
	  *y = pr->aat.ypos + pr->Upr.Uline.aradius;
	  break;

	case XDs:
	  *y = pr->aat.ypos - pr->Upr.Uline.aradius;
	  break;

	case XDe:
	  *x = pr->aat.xpos + pr->Upr.Uline.aradius;
	  break;

	case XDw:
	  *x = pr->aat.xpos - pr->Upr.Uline.aradius;
	  break;

	case XDc:
	/* blank case */
	  break;

	case XDstart:
	  *x = pr->aat.xpos + (pr->Upr.Uline.aradius * cos(pr->Upr.Uline.endpos.xpos));
	  *y = pr->aat.ypos + (pr->Upr.Uline.aradius * sin(pr->Upr.Uline.endpos.xpos));
	  break;

	case XDend:
	  *x = pr->aat.xpos + (pr->Upr.Uline.aradius *
		 cos(pr->Upr.Uline.endpos.xpos + pr->Upr.Uline.endpos.ypos));
	  *y = pr->aat.ypos + (pr->Upr.Uline.aradius *
		 sin(pr->Upr.Uline.endpos.xpos + pr->Upr.Uline.endpos.ypos));
	  break;
	}
    }
    else {
	switch (lexv) {

	case XDn:
	  *y = north;
	  break;

	case XDs:
	  *y = south;
	  break;

	case XDe:
	  *x = east;
	  break;

	case XDw:
	  *x = west;
	  break;

	case XDne:
	  *y = north;
	  *x = east;
	  break;

	case XDse:
	  *y = south;
	  *x = east;
	  break;

	case XDsw:
	  *y = south;
	  *x = west;
	  break;

	case XDnw:
	  *y = north;
	  *x = west;
	  break;

	case XDc:
	  *y = pr->aat.ypos;
	  *x = pr->aat.xpos;
	  break;

	case XDstart:
	case XDend:
	  markerror(858);
	  break;
	}
    }
    break;

  case XLline:
  case XLarrow:
  case XLmove:
  case XLspline:
    if (lexv != XDstart) {
	if (lexv == XDend) {
	    while (pe->son != NULL) {
		pe = pe->son;
	    }
	    *x = pe->Upr.Uline.endpos.xpos;
	    *y = pe->Upr.Uline.endpos.ypos;
	}
	else if (lexv == XDc) {
	    while (pe->son != NULL) {
		pe = pe->son;
	    }
	    *x = 0.5 * ((*x) + pe->Upr.Uline.endpos.xpos);
	    *y = 0.5 * ((*y) + pe->Upr.Uline.endpos.ypos);
	}
	else {
	    do {
		sb = false;
		switch (lexv) {

		case XDn:
		  sb = (pe->Upr.Uline.endpos.ypos > (*y));
		  break;

		case XDs:
		  sb = (pe->Upr.Uline.endpos.ypos < (*y));
		  break;

		case XDe:
		  sb = (pe->Upr.Uline.endpos.xpos > (*x));
		  break;

		case XDw:
		  sb = (pe->Upr.Uline.endpos.xpos < (*x));
		  break;

		case XDne:
		  sb = (((pe->Upr.Uline.endpos.ypos > (*y)) &&
			 (pe->Upr.Uline.endpos.xpos >= (*x))) ||
			((pe->Upr.Uline.endpos.ypos >= (*y)) &&
			 (pe->Upr.Uline.endpos.xpos > (*x))));
		  break;

		case XDse:
		  sb = (((pe->Upr.Uline.endpos.ypos < (*y)) &&
			 (pe->Upr.Uline.endpos.xpos >= (*x))) ||
			((pe->Upr.Uline.endpos.ypos <= (*y)) &&
			 (pe->Upr.Uline.endpos.xpos > (*x))));
		  break;

		case XDsw:
		  sb = (((pe->Upr.Uline.endpos.ypos < (*y)) &&
			 (pe->Upr.Uline.endpos.xpos <= (*x))) ||
			((pe->Upr.Uline.endpos.ypos <= (*y)) &&
			 (pe->Upr.Uline.endpos.xpos < (*x))));
		  break;

		case XDnw:
		  sb = (((pe->Upr.Uline.endpos.ypos > (*y)) &&
			 (pe->Upr.Uline.endpos.xpos <= (*x))) ||
			((pe->Upr.Uline.endpos.ypos >= (*y)) &&
			 (pe->Upr.Uline.endpos.xpos < (*x))));
		  break;
		}
		if (sb) {
		    *x = pe->Upr.Uline.endpos.xpos;
		    *y = pe->Upr.Uline.endpos.ypos;
		}
		pe = pe->son;
	    } while (pe != NULL);
	}
    }
    break;

  case XLabel:
	/* blank case */
    break;

  case XLaTeX:
    markerror(858);
    break;
  }
}


							/* The nth (or nth last) enumerated object */
primitive *(
nthprimobj(primitive *primp, int nth, int objtype))
{ primitive *prp = NULL;
  primitive *pp;
#ifdef DDEBUG
  if (debuglevel == 2) {
    fprintf(log_, "nthprimobj in [%s] nth=%d type=%d\n",
      (primp==NULL)?"NULL":"!NULL", nth, objtype);
	snaptree(primp,0); }
#endif
  if (nth == 0) { pp = primp;
    while (pp != NULL) {
	  if ((pp->ptype) == objtype) { prp = pp; }
	  pp = pp->next_;
      }
    }
  else { pp = primp; i = 0;
    if (nth < 0) {
      while (pp != NULL) {
	    if (pp->ptype == objtype) { i++; }
	    pp = pp->next_; }
      nth += i + 1;
      }
#ifdef DDEBUG
    if (debuglevel > 1) { fprintf(log_," nth=%d",nth); }
#endif
    pp = primp; i = 0; prp = NULL;
    while (pp != prp) {
      if (pp->ptype == objtype) { i++; }
      if (i == nth) { prp = pp; } else { pp = pp->next_; }
      }
    }
  return prp;
  }


							/* Reset environment vars:
							   n=0: all
							   n<0: scaled variables only
							   n>0: one var given by its lexical val*/
void
resetenv(int envval, primitive *envbl)
{ environx i, last;

  if (envbl == NULL) { return; }
  if (envval == 0) {
    envval = XXenvvar + 1;
    last = XLlastenv;
    }
  else if (envval < 0) {
    envval = XXenvvar + 1;
    last = XLlastsc;
    }
  else { last = envval; }
  if (envbl->Upr.UBLOCK.env == NULL) {
    envbl->Upr.UBLOCK.env = malloc(sizeof(envarray));
#ifdef DDEBUG
    if (debuglevel > 0) {
	  fprintf(log_, "resetenv envarray[%d]\n", ordp(envbl->Upr.UBLOCK.env)); }
#endif
    }
  for (i = envval - 1; i <= (last - 1); i++) {
    switch (i + 1) {
							/* scaled environment vars (in) */
      case XLarcrad: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.25;
	    break;
      case XLarrowht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.1;
	    break;
      case XLarrowwid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.05;
	    break;
      case XLboxht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLboxrad: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.0;
	    break;
      case XLboxwid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.75;
	    break;
      case XLcirclerad: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.25;
	    break;
      case XLdashwid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.05;
	    break;
      case XLellipseht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLellipsewid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.75;
	    break;
      case XLlineht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLlinewid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLmoveht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLmovewid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLtextht:
	    switch (drawmode) {
	      case PDF: envbl->Upr.UBLOCK.env[i - XXenvvar] = DFONT / 72.0;
	        break;
	      case SVG:
	        envbl->Upr.UBLOCK.env[i - XXenvvar] = (DFONT / 72.0) * 0.66;
	        break;
	      default:
	        envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.0;
	        break;
	      }
	    break;
      case XLtextoffset: envbl->Upr.UBLOCK.env[i - XXenvvar] = 2.0 / 72;
	    break;
      case XLtextwid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.0;
	    break;
							/* The following are unscaled */
      case XLarrowhead: envbl->Upr.UBLOCK.env[i - XXenvvar] = 1.0;
	    break;
      case XLfillval: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.5;
	    break;
      case XLlinethick: envbl->Upr.UBLOCK.env[i - XXenvvar] = 0.8;
	    break;
      case XLmaxpsht: envbl->Upr.UBLOCK.env[i - XXenvvar] = 11.0;
	    break;
      case XLmaxpswid: envbl->Upr.UBLOCK.env[i - XXenvvar] = 8.5;
	    break;
      case XLscale: envbl->Upr.UBLOCK.env[i - XXenvvar] = 1.0;
	    break;
      }
    }
}


							/* Copy env vars to current scope */
void
inheritenv(primitive *envbl)
{ environx i;
  primitive *pr;

  pr = findenv(envbl);
  if (pr == NULL) { resetenv(0, envbl); return; }
  envbl->Upr.UBLOCK.env = malloc(sizeof(envarray));
  for (i = XXenvvar; i <= (XLlastenv - 1); i++) {
      envbl->Upr.UBLOCK.env[i - XXenvvar] = pr->Upr.UBLOCK.env[i - XXenvvar];
  }
}


							/* Execute scale = x */
void
resetscale(double x, int opr, primitive *envbl)
{ double r, s;
  int i;

  resetenv(-1, envbl);
  r = envbl->Upr.UBLOCK.env[XLscale - XXenvvar - 1];
  eqop(&envbl->Upr.UBLOCK.env[XLscale - XXenvvar - 1], opr, x);
  s = envbl->Upr.UBLOCK.env[XLscale - XXenvvar - 1];
  if (s == 0.0) {
      envbl->Upr.UBLOCK.env[XLscale - XXenvvar - 1] = r;
      s = 1.0;
      markerror(870);
  }
  else if (r == 0.0) {
      markerror(852);
  }
  else {
      s /= r;
  }
  for (i = XXenvvar; i < XLlastsc; i++) {
      eqop(&envbl->Upr.UBLOCK.env[i - XXenvvar], XLmulteq, s);
  }
}


							/* .PS xv yv
							   sfact = nominal scale factor set by scale = ...
							   xsc = effective scale factor to achieve correct
  							   max picture size
							   ie (size in inches)/(desired size in inches) */
void
getscale(double xv, double yv, primitive *lp, double *sfact, double *xsc)
{ double gs = 1.0;
  int erno = 0;
  primitive *qp;

  *sfact = gs;
  if (lp != NULL) {
      if (lp->ptype == XBLOCK) {
	  qp = findenv(lp);
	  if (qp->Upr.UBLOCK.env[XLscale - XXenvvar - 1] > 0.0) {
	      *sfact = qp->Upr.UBLOCK.env[XLscale - XXenvvar - 1];
	  }
	  if ((east > west) &&
	      ((east - west) / (*sfact) >
	       qp->Upr.UBLOCK.env[XLmaxpswid - XXenvvar - 1]) &&
	      (qp->Upr.UBLOCK.env[XLmaxpswid - XXenvvar - 1] > 0.0)) {
	      erno = 903;
	      gs = (east - west) / qp->Upr.UBLOCK.env[XLmaxpswid - XXenvvar - 1];
	  }
	  if ((north > south) &&
	      ((north - south) / (*sfact) >
	       qp->Upr.UBLOCK.env[XLmaxpsht - XXenvvar - 1]) &&
	      (qp->Upr.UBLOCK.env[XLmaxpsht - XXenvvar - 1] > 0.0)) {
	      erno = 904;
	      gs = Max(gs,
		  (north - south) / qp->Upr.UBLOCK.env[XLmaxpsht - XXenvvar - 1]);
	  }
      }
  }
  if ((xv > 0.0) && (east > west)) {
      erno = 0;
      gs = (east - west) / (*sfact) / xv;
  }
  if ((yv > 0.0) && (north > south) &&
      ((xv == 0.0) || ((north - south) / gs > yv * (*sfact)))) {
      erno = 0;
      gs = (north - south) / (*sfact) / yv;
  }
  if (erno != 0) {
      markerror(erno);
  }
  *xsc = gs * (*sfact);
}

							/* Copy primitive for use by then or same */
void
copyprim(primitive *prin, primitive **prout)
{ /* Needed because assignment of variant records is unreliable */
  int i;
  if (prin == NULL) { return; }
  newprim(prout, prin->ptype, NULL);
  (*prout)->name = prin->name;
  (*prout)->textp = prin->textp;
  (*prout)->outlinep = prin->outlinep;
  (*prout)->shadedp = prin->shadedp;
  (*prout)->parent = prin->parent;
  (*prout)->son = prin->son;
  (*prout)->next_ = prin->next_;
  (*prout)->aat = prin->aat;
  (*prout)->lparam = prin->lparam;
  (*prout)->lthick = prin->lthick;
  (*prout)->direction = prin->direction;
  (*prout)->spec = prin->spec;
  (*prout)->ptype = prin->ptype;
  switch (prin->ptype) {
  case XLbox:
  case XLstring:
    (*prout)->Upr.Ubox.boxfill = prin->Upr.Ubox.boxfill;
    (*prout)->Upr.Ubox.boxheight = prin->Upr.Ubox.boxheight;
    (*prout)->Upr.Ubox.boxwidth = prin->Upr.Ubox.boxwidth;
    (*prout)->Upr.Ubox.boxradius = prin->Upr.Ubox.boxradius;
    break;
  case XBLOCK:
    (*prout)->Upr.UBLOCK.blockheight = prin->Upr.UBLOCK.blockheight;
    (*prout)->Upr.UBLOCK.blockwidth = prin->Upr.UBLOCK.blockwidth;
    (*prout)->Upr.UBLOCK.here = prin->Upr.UBLOCK.here;
    for (i = 0; i <= HASHLIM; i++) {
	  (*prout)->Upr.UBLOCK.vars[i] = prin->Upr.UBLOCK.vars[i];
	  (*prout)->Upr.UBLOCK.nvars[i] = prin->Upr.UBLOCK.nvars[i]; }
    if (prin->Upr.UBLOCK.env != NULL) {
	  (*prout)->Upr.UBLOCK.env = malloc(sizeof(envarray));
	  for (i = XXenvvar; i < XLlastenv; i++) {
	    (*prout)->Upr.UBLOCK.env[i - XXenvvar] =
          prin->Upr.UBLOCK.env[i - XXenvvar];
	    }
      }
    break;
  case XLcircle:
    (*prout)->Upr.Ucircle.cfill = prin->Upr.Ucircle.cfill;
    (*prout)->Upr.Ucircle.radius = prin->Upr.Ucircle.radius;
    break;
  case XLellipse:
    (*prout)->Upr.Uellipse.efill = prin->Upr.Uellipse.efill;
    (*prout)->Upr.Uellipse.elheight = prin->Upr.Uellipse.elheight;
    (*prout)->Upr.Uellipse.elwidth = prin->Upr.Uellipse.elwidth;
    break;
  case XLline:
  case XLarrow:
  case XLmove:
  case XLarc:
  case XLspline:
    (*prout)->Upr.Uline.endpos = prin->Upr.Uline.endpos;
    (*prout)->Upr.Uline.height = prin->Upr.Uline.height;
    (*prout)->Upr.Uline.width = prin->Upr.Uline.width;
    (*prout)->Upr.Uline.lfill = prin->Upr.Uline.lfill;
    (*prout)->Upr.Uline.aradius = prin->Upr.Uline.aradius;
    (*prout)->Upr.Uline.atype = prin->Upr.Uline.atype;
    break;
  case XLabel:
  case XLaTeX:
	/* blank case */
    break;
  }
}


							/* Delete temporary string */
void
deletestringbox(primitive **pr)
{
  primitive *prx;
  if ((*pr) == NULL) { }
  else if ((*pr)->parent == NULL) { }
  else if ((*pr)->parent->son != NULL) {
	if ((*pr)->parent->son == (*pr)) { (*pr)->parent->son = NULL; }
	else {
	  prx = (*pr)->parent->son;
	  while ((prx->next_ != NULL) && (prx->next_ != (*pr))) { prx = prx->next_;}
	  prx->next_ = NULL; }
    }
  deletetree(pr);
}

void
dostart(void)
{
    makevar("dpicopt", 7, drawmode);
    if (safemode) { i = 1; } else { i = 0; }
    makevar("optsafe", 7, i);
    makevar("optMFpic", 8, MFpic);
    makevar("optMpost", 8, MPost);
    makevar("optPDF", 6, PDF);
    makevar("optPGF", 6, PGF);
    makevar("optPict2e", 9, Pict2e);
    makevar("optPS", 5, PS);
    makevar("optPSfrag", 9, PSfrag);
    makevar("optPSTricks", 11, PSTricks);
    makevar("optSVG", 6, SVG);
    makevar("optTeX", 6, TeX);
    makevar("opttTeX", 7, tTeX);
    makevar("optxfig", 7, xfig);
    if ((drawmode == SVG) || (drawmode == PDF) || (drawmode == PS)) {
	  makevar("dptextratio", 11, 0.66);
	  makevar("dpPPI", 5, 96.0);
      }
}

							/* The program equivalent of var = number */
void
makevar(Char *s, int ln, double varval)
{ nametype *vn, *lastvar, *namptr;
  int j, k;
  primitive *With;
  for (j = 0; j < ln; j++) { chbuf[chbufi + j] = s[j]; }
  vn = findname(envblock, chbuf, chbufi, ln, &lastvar, &k);
  newstr(&vn);
  j = varhash(chbuf, chbufi, ln);
  storestring(vn, chbuf, chbufi, ln, 1);
#ifdef DDEBUG
  if (debuglevel > 1) {
    fprintf(log_, "makevar: envblock=%d eqstr val=%d\n", ordp(envblock), k);
    fprintf(log_, " lastvar=%d", ordp(lastvar));
    if (lastvar != NULL) {
	  snapname(lastvar->segmnt, lastvar->seginx, lastvar->len); }
    putc('\n', log_);
    }
#endif
  With = envblock;
#ifdef DDEBUG
  if (debuglevel > 1) { fprintf(log_, " vn=%d\n", ordp(vn)); }
#endif
  if (lastvar == NULL) { With->Upr.UBLOCK.vars[j] = vn; }
  else if (k < 0) {
    if (With->Upr.UBLOCK.vars[j]->next_ == NULL) {
	  With->Upr.UBLOCK.vars[j]->next_ = vn; }
    else {
	  vn->next_ = lastvar->next_;
	  lastvar->next_ = vn; }
    }
  else if (lastvar == With->Upr.UBLOCK.vars[j]) {
    vn->next_ = With->Upr.UBLOCK.vars[j];
    With->Upr.UBLOCK.vars[j] = vn;
    }
  else {
    namptr = With->Upr.UBLOCK.vars[j];
    while (namptr->next_ != lastvar) { namptr = namptr->next_; }
    namptr->next_ = vn;
    vn->next_ = lastvar;
    }
  With->Upr.UBLOCK.nvars[j]++;
  vn->val = varval;
}

void                                       /* then, arc, deferred shift */
donamedobj(attribute *a1)
{
  if (a1->prim != NULL) {
	prp = a1->prim;
	while (isthen(a1->prim)) { a1->prim = a1->prim->parent; }
#ifdef DDEBUG
	if (debuglevel < 0) { fprintf(log_," donamedobj(%d):\n",ordp(a1->prim));
      if (checktree(envblock->son) == 0) {
        fprintf(errout," checktree failure ijx=%d\n",ijx);
        return; }
	  snaptree(a1->prim,0); }
#endif
	if (prp == a1->prim) { }
	else if ((a1->prim->name == NULL) && (prp->name != NULL)) {
	  a1->prim->name = prp->name;
	  prp->name = NULL; }
	if (a1->prim->ptype == XLarc) { arcenddir(prp); }
	if (teststflag(a1->state, XLat)) {    /* deferred shift */
	    With2 = a1->prim;
	    i = getstval(a1->state);
	    if (i == XLfloat) {  /* pair at */
		  getnesw(a1->prim);
		  dx = west + a1->startchop;
		  dy = south + a1->endchop;
	      }
	    else if (a1->internal != NULL) { corner(a1->internal, i, &dx, &dy); }
	    else { corner(a1->prim, i, &dx, &dy); }
	    a1->internal = NULL;
	    if ((drawmode == SVG) && (With2->ptype == XLstring)) {
		  ts = venv(a1->prim, XLtextoffset);
		  if (teststflag(a1->state, XLcw)) {    /* shift by arg2,arg3 */
		    switch (i) {                                   /* textpos */
		      case XDe:  dx += ts; break;
		      case XDne: dx += ts; dy += ts; break;
		      case XDn:  dy += ts; break;
		      case XDnw: dx -= ts; dy += ts; break;
		      case XDw:  dx -= ts; break;
		      case XDsw: dx -= ts; dy -= ts; break;
		      case XDs:  dy -= ts; break;
		      case XDse: dx += ts; dy -= ts; break;
		      }
		    }
		  shift(a1->prim, a1->xval - dx, a1->yval - dy);
	      }
	    else if (With2->ptype != XLarc) {
		  shift(a1->prim, a1->xval - dx, a1->yval - dy); }
	    else {
		  x1 = With2->aat.xpos +
		     (With2->Upr.Uline.aradius * cos(With2->Upr.Uline.endpos.xpos));
							/* from */
		  z1 = With2->aat.ypos +
		     (With2->Upr.Uline.aradius * sin(With2->Upr.Uline.endpos.xpos));
		  if (teststflag(a1->state, XLto)) {
							/* to X from Here|Y implied */
		    if ((i != XEMPTY) && (i != XDc)) { markerror(858); }
		    r = With2->aat.xpos + (With2->Upr.Uline.aradius * cos(
			    With2->Upr.Uline.endpos.xpos + With2->Upr.Uline.endpos.ypos));
		    s = With2->aat.ypos + (With2->Upr.Uline.aradius * sin(
			    With2->Upr.Uline.endpos.xpos + With2->Upr.Uline.endpos.ypos));
		    With2->aat.xpos = a1->xval;
		    With2->aat.ypos = a1->yval;
		    With2->Upr.Uline.aradius = linlen(r - With2->aat.xpos,
						    s - With2->aat.ypos);
		    setangles(&With2->Upr.Uline.endpos.xpos,
			      &With2->Upr.Uline.endpos.ypos, With2->aat, x1, z1, r, s);
		    }
		  else if (teststflag(a1->state, XLfrom)) {
		    if ((i != XEMPTY) && (i != XDc)) { markerror(858); }
		    With2->aat.xpos = a1->xval;
		    With2->aat.ypos = a1->yval;
		    t = datan(z1 - With2->aat.ypos, x1 - With2->aat.xpos);
		    r = With2->aat.xpos + (With2->Upr.Uline.aradius * cos(
					     t + With2->Upr.Uline.endpos.ypos));
		    s = With2->aat.ypos + (With2->Upr.Uline.aradius * sin(
					     t + With2->Upr.Uline.endpos.ypos));
		    With2->Upr.Uline.aradius = linlen(x1 - With2->aat.xpos,
						    z1 - With2->aat.ypos);
		    setangles(&With2->Upr.Uline.endpos.xpos,
			      &With2->Upr.Uline.endpos.ypos, With2->aat, x1, z1, r, s);
			}
		  else { shift(a1->prim, With->xval - dx, With->yval - dy); }
	    }
	  }
    }
}

void
doundefine( attribute *a2 )
{
    macp = findmacro(macros, chbuf, a2->chbufx, a2->toklen, &lastp);
    if (macp != NULL) {
	  if (lastp != NULL) { lastp->nexta = macp->nexta; }
	  if (macp == macros) { macros = macp->nexta; }
	  disposebufs(&macp->argbody);
	  free(macp);
	  macp = NULL; }
}

							/* Stuff the body of a for loop or a macro body
							   into p2 */
void
readfor(fbuffer *p0, int attx, fbuffer **p2, Char endch, boolean isfor)
{ /* attx: -(name length)
     p0 <> nil: append the output to this buffer. */
  int j;
  int bracelevel = 1;
  fbuffer *p;
  fbuffer *p1 = NULL;
  boolean instring = false, moreinput = true;
  Char prevch = ' ';

#ifdef DDEBUG
  if (debuglevel > 0) {
    fprintf(log_, "readfor: p0");
    if (p0 == NULL) { fprintf(log_, "=nil"); } else { fprintf(log_, "<>nil");}
    fprintf(log_, " attx(");
    if (attx < 0) { fprintf(log_, "-length)="); }
    else { fprintf(log_, "attx should be -ve):"); }
    fprintf(log_, "%5d\n", attx);
    fprintf(log_, "         p2");
    if ((*p2) == NULL) { fprintf(log_, "=nil"); }
    else { fprintf(log_, "<>nil"); }
    fprintf(log_, " endch=\"%c\" ch=\"%c\"\n", endch, ch);
  }
#endif
  if (!isfor) { inchar(); }
  while (moreinput) {
    if (p0 == NULL) { newbuf(&p); } else { p = p0; p0 = NULL; }
    p->attrib = attx;                   /* attstack index or -(name length) */
    if (p1 != NULL) { p1->nextb = p; p->prevb = p1; }
    p->higherb = inbuf;
    p1 = p;
    j = CHBUFSIZ;
    if (endch == '}') { do { /* lbrace ... rbrace */
	  if (ch == bslch) { skipcontinue(instring); }
	  if (instring) {  /* do not check braces in strings */
		if ((ch == '"') && (prevch != bslch)) { instring = false; }
	    }
	  else if (ch == '#') { skiptoend(); ch = nlch; }
	  else if (ch == '{') { bracelevel++; }
	  else if (ch == '}') { bracelevel--; }
	  else if (ch == '"') { instring = true; }
	  if (bracelevel <= 0) {
		moreinput = false;
		j = p1->savedlen + 1;
		ch = nlch;
	    }
	  p1->savedlen++;
	  p1->carray[p1->savedlen] = ch;
	  prevch = ch;
	  if (moreinput) { inchar(); }
	  if (inputeof) {
        if (instring) { markerror(807); } else { markerror(804); }
		j = p1->savedlen;
		moreinput = false;
	    }
	  } while (p1->savedlen != j);
      }
    else { do { /* X ... X */
	  if (ch == bslch) { skipcontinue(instring); }
	  if (instring) {
	    if ((ch == '"') && (prevch != bslch)) { instring = false; }
	    }
	  else if (ch == endch) {
        moreinput = false; j = p1->savedlen + 1; ch = nlch; }
	  else if (ch == '#') { skiptoend(); ch = nlch; }
	  else if (ch == '"') { instring = true; }
	  p1->savedlen++;
	  p1->carray[p1->savedlen] = ch;
	  prevch = ch;
	  if (moreinput) { inchar(); }
	  if (inputeof) {
        if (instring) { markerror(807); } else { markerror(804); }
	    j = p1->savedlen;
	    moreinput = false;
	    }
      } while (p1->savedlen != j);
      }
    }
  while (p1->prevb != NULL) { p1 = p1->prevb; }
  if (isfor) { backup(); }
#ifdef DDEBUG
  if (debuglevel > 0) {
      fprintf(log_, "\nreadfor done: for/macro buffer"); wrbuf(p1, 3, 0); }
#endif
  *p2 = p1;
}

void
queueprim(primitive *pr, primitive *envblk)
{ primitive *pp;
  if (envblk->son == NULL) { envblk->son = pr; }
  else if (tail != NULL ) { tail->next_ = pr; }
  else {
    pp = envblk->son;
    while (pp->next_ != NULL) { pp = pp->next_; }
    pp->next_ = pr;
    }
  tail = pr;
  }


void
clearchbuf(chbufinx bi, int ln)
{
  int i,j;
  if ((bi+ln) == chbufi) {
    i = bi-1; j = -1;
    while (i > j) { if (chbuf[i] == '\0') { i--; } else { j = i; } }
    chbufi = i+1; }
  else { for (i=0; i<ln; i++) { chbuf[bi+i] = '\0'; } }
  }

void
dodefhead( attribute *a0 )
{ fbuffer *Withargbody;
  Char lastc;
  macp = findmacro(macros, chbuf, a0->chbufx, a0->toklen, &lastp);
  if (macp == NULL) {
	newarg(&macp);
	if (lastp == NULL) { macros = macp; } else { lastp->nexta = macp; }
    }
  disposebufs(&(macp->argbody));
  newbuf(&(macp->argbody));
  Withargbody = macp->argbody;
							/* copy the macro name */
  FORLIM = a0->toklen;
  for (i = 1; i <= FORLIM; i++) {
    Withargbody->carray[i] = chbuf[a0->chbufx + i - 1]; }
  Withargbody->savedlen = a0->toklen;
  Withargbody->readx = a0->toklen + 1;
  clearchbuf(a0->chbufx, a0->toklen);
  skipwhite();
  if (ch == '{') { lastc = '}'; } else { lastc = ch; }
							/* append the body */
  readfor(macp->argbody, -(a0->toklen), &macp->argbody, lastc, false);
  lastm = macp->argbody;
  while (lastm->nextb != NULL) { lastm = lastm->nextb; }
  lastm->carray[lastm->savedlen] = etxch;
#ifdef DDEBUG
  if (debuglevel > 1) { putc('\n', log_);
	if (currprod == 4 /* defhead1 */) { fprintf(log_, "defhead1"); }
	else { fprintf(log_, "defhead2"); }
	wrbuf(macp->argbody, 3, 0); }
#endif
  }

void
dosprintf( attribute *a0, attribute *a3, attribute *a5, int nexprs )
{ newprim(&a0->prim, XLstring, envblock);
  With2 = a0->prim;
  eb = findenv(envblock);
#ifdef DDEBUG
  if (debuglevel > 0) {
	fprintf(log_,"sprintf nexprs=%d\n",nexprs);
	printobject(a3->prim);
	if (eb == NULL) { fprintf(log_, " ! sprintf_i: eb=nil\n"); }
	else if (eb->Upr.UBLOCK.env == NULL) {
	    fprintf(log_, " ! sprintf_i: env=nil\n"); } }
#endif
  With2->Upr.Ubox.boxheight = eb->envinx(XLtextht);
  With2->Upr.Ubox.boxwidth = eb->envinx(XLtextwid);
  With2->Upr.Ubox.boxradius = 0.0;
  newstr(&With2->textp);
  if (tmpbuf == NULL) { tmpbuf = malloc(sizeof(chbufarray)); }
  if (tmpfmt == NULL) { tmpfmt = malloc(sizeof(chbufarray)); }
  i = 0;                                        /* expression count */
  j = 0;                                /* end of current substring */
  lj = j;                             /* start of current substring */
  kk = 0;                                        /* substring count */
  if (a3->prim == NULL) { /* nil */ }
  else if (a3->prim->textp == NULL) { /* nil */ }
  else {  /*-- */
	With4 = a3->prim->textp;
	while (j < With4->len) {
#ifdef DDEBUG
	  if (debuglevel > 0) {
        fprintf(log_,
                  " nexprs=%d expr no i=%d string start=%d len=%d\n",
          nexprs,i,lj,With4->len);
		fprintf(log_," sprintf looping, j=%4d c=\"%c\"\n",
		  j, With4->segmnt[With4->seginx + j]);
	  fflush(log_); }
#endif
      if (With4->segmnt[With4->seginx + j] != '%') {
        j++;
        if (j == With4->len) { kk = putstring(kk, a0->prim->textp,
      	  With4->segmnt, With4->seginx + lj, j - lj); }
        continue;
        }
      if (With4->segmnt[With4->seginx + j + 1] == '%') {/* %% prints %*/
        kk = putstring(kk, a0->prim->textp, With4->segmnt,
      	  With4->seginx + lj, j - lj + 1);
        j += 2;
        lj = j;
        continue;
        }
      if (i >= nexprs) {  /* not enough exprs */
        markerror(864); j = With4->len; continue; }
      if (j > lj) {
        kk = putstring(kk, a0->prim->textp, With4->segmnt,
      	  With4->seginx + lj, j - lj);
        lj = j; }
      k = With4->len;
      j++;
      if (With4->segmnt[With4->seginx + j] == '-') { j++; }
      while (j < k) {
	    cy = With4->segmnt[With4->seginx + j];
        if ((cy=='g') || (cy=='f') || (cy=='e')) { k = j; }
        else if ((cy=='.') || isdigit(cy)) { j++; }
        else { j = k; }
        }
      ts = a5->xval;
	  a5++; a5++;
      if (k == With4->len) { markerror(865); continue; }
      j++;
#ifdef DDEBUG
      if (debuglevel > 0) { int kv;
        fprintf(log_, "format=\"");
        for (kv = lj; kv < j; kv++) {
          putc(With4->segmnt[With4->seginx + kv], log_); }
        fprintf(log_, "\" nexprs=%2d Numerical print value=", nexprs);
        wfloat(&log_, ts); putc('\n', log_); fflush(log_); }
#endif
      if (j - lj + 1 > CHBUFSIZ) {
        markerror(873); ll = 0; j = With4->len; }
      else {
        for (ll = lj; ll <= (j - 2); ll++) {
          tmpfmt[ll - lj] = With4->segmnt[With4->seginx + ll]; }
        tmpfmt[j - lj - 1] = 'L';
        tmpfmt[j - lj] = With4->segmnt[With4->seginx + j - 1];
        tmpfmt[j - lj + 1] = '\0';
        ll = snprintf(tmpbuf,CHBUFSIZ,tmpfmt, (long double) ts);
        }
      if (ll < 0) { markerror(874); j = With4->len; }
      else if (ll > CHBUFSIZ) { markerror(874);
                ll = CHBUFSIZ; j = With4->len; }
#ifdef DDEBUG
      if (debuglevel > 0) { int kv;
        fprintf(log_, " ll=%d", ll);
        if (ll > 0) {
          fprintf(log_, " tmpbuf(0:%d)=", ll - 1);
          for (kv = 0; kv < ll; kv++) { putc(tmpbuf[kv], log_); } }
        putc('\n', log_); fflush(log_); }
#endif
							/* Copy tmpbuf to the string */
      if (ll > 0) { kk = putstring(kk, a0->prim->textp, tmpbuf, 0, ll);}
      i++;
      lj = j;
	  }
    } /*  --*/
  if (nexprs > i) { markerror(864); }               /* Too many exprs */
  if (drawmode == xfig) {
	With2 = a0->prim;
	if (With2->Upr.Ubox.boxwidth == 0.0) {
	  if (With2->Upr.Ubox.boxheight == 0.0) {
		With2->Upr.Ubox.boxheight =
		  0.1 * eb->envinx(XLscale); }
	  if (With2->textp != NULL) {
		With2->Upr.Ubox.boxwidth = With2->Upr.Ubox.boxheight *
					  With2->textp->len * 0.75; }
	  }
    }
  else if ((drawmode == PDF) && (With2->textp != NULL)) {
	  With2->Upr.Ubox.boxwidth = With2->Upr.Ubox.boxheight *
				      With2->textp->len * 0.6; }
  if (envblock->son == a3->prim) { envblock->son = a0->prim; }
  deletestringbox(&(a3->prim));
}

#ifdef DDEBUG
int ordp(void *p)       { return (p==NULL)?(int) 0 : (int) abs((long)p); }
#endif
