#ifndef lint
static char *RCSid = "$Id: set.c,v 1.29 1995/12/20 22:39:36 drd Exp $";
#endif


/* GNUPLOT - set.c */
/*
 * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted, 
 * provided that the above copyright notice appear in all copies and 
 * that both that copyright notice and this permission notice appear 
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software is provided "as is" without express or implied warranty.
 * 
 *
 * AUTHORS
 * 
 *   Original Software:
 *     Thomas Williams,  Colin Kelley.
 * 
 *   Gnuplot 2.0 additions:
 *       Russell Lang, Dave Kotz, John Campbell.
 *
 *   Gnuplot 3.0 additions:
 *       Gershon Elber and many others.
 *
 * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
 * Added user-specified bases for log scaling.
 * 
 * There is a mailing list for gnuplot users. Note, however, that the
 * newsgroup 
 *	comp.graphics.gnuplot 
 * is identical to the mailing list (they
 * both carry the same set of messages). We prefer that you read the
 * messages through that newsgroup, to subscribing to the mailing list.
 * (If you can read that newsgroup, and are already on the mailing list,
 * please send a message info-gnuplot-request@dartmouth.edu, asking to be
 * removed from the mailing list.)
 *
 * The address for mailing to list members is
 *	   info-gnuplot@dartmouth.edu
 * and for mailing administrative requests is 
 *	   info-gnuplot-request@dartmouth.edu
 * The mailing list for bug reports is 
 *	   bug-gnuplot@dartmouth.edu
 * The list of those interested in beta-test versions is
 *	   info-gnuplot-beta@dartmouth.edu
 */

#include <math.h>
#include "plot.h"
#include "setshow.h"
#include "national.h"

#define DEF_FORMAT   "%g"	/* default format for tic mark labels */
#define SIGNIF (0.01)		/* less than one hundredth of a tic mark */

/*
 * global variables to hold status of 'set' options
 *
 * IMPORTANT NOTE:
 * ===============
 * If you change the default values of one of the variables below, or if
 * you add another global variable, make sure that the change you make is
 * done in reset_command() as well (if that makes sense).
 */

TBOOLEAN		autoscale_r	= DTRUE;
TBOOLEAN		autoscale_t	= DTRUE;
TBOOLEAN		autoscale_u	= DTRUE;
TBOOLEAN		autoscale_v	= DTRUE;
TBOOLEAN		autoscale_x	= DTRUE;
TBOOLEAN		autoscale_y	= DTRUE;
TBOOLEAN		autoscale_z	= DTRUE;
TBOOLEAN		autoscale_x2	= DTRUE;
TBOOLEAN		autoscale_y2	= DTRUE;
TBOOLEAN		autoscale_lt	= DTRUE;
TBOOLEAN		autoscale_lu	= DTRUE;
TBOOLEAN		autoscale_lv	= DTRUE;
TBOOLEAN		autoscale_lx	= DTRUE;
TBOOLEAN		autoscale_ly	= DTRUE;
TBOOLEAN		autoscale_lz	= DTRUE;
TBOOLEAN		multiplot		= FALSE;

double			boxwidth	= -1.0; /* box width (automatic) */
TBOOLEAN 		clip_points	= FALSE;
TBOOLEAN 		clip_lines1	= TRUE;
TBOOLEAN 		clip_lines2	= FALSE;
int			draw_border	= 31;
TBOOLEAN		draw_surface    = TRUE;
char			dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
char			default_font[MAX_ID_LEN+1] = "\0"; /* Entry font added by DJL */
char			xformat[MAX_ID_LEN+1] = DEF_FORMAT;
char			yformat[MAX_ID_LEN+1] = DEF_FORMAT;
char			zformat[MAX_ID_LEN+1] = DEF_FORMAT;
char			x2format[MAX_ID_LEN+1] = DEF_FORMAT;
char			y2format[MAX_ID_LEN+1] = DEF_FORMAT;
/* do formats look like times - use FIRST_X_AXIS etc as index
 * - never saved or shown ...
 */
#if AXIS_ARRAY_SIZE != 10
#error error in initialiser for format_is_numeric
#endif

int format_is_numeric[AXIS_ARRAY_SIZE] = { 1,1,1,1,1,1,1,1,1,1 };

enum PLOT_STYLE		data_style	= POINTSTYLE;
enum PLOT_STYLE		func_style	= LINES;
double		bar_size	= 1.0;
int			grid		= GRID_OFF;
int			grid_linetype   = -1;
int			mgrid_linetype   = -1;
double			polar_grid_angle= 0; /* nonzero means a polar grid */
int			key		= -1;	/* default position */
struct position key_user_pos;	/* user specified position for key */
TBOOLEAN		key_reverse	= FALSE;  /* reverse text & sample ? */
int			key_box		= -3; /* no linetype */
TBOOLEAN		is_log_x	= FALSE;
TBOOLEAN		is_log_y	= FALSE;
TBOOLEAN		is_log_z	= FALSE;
TBOOLEAN		is_log_x2	= FALSE;
TBOOLEAN		is_log_y2	= FALSE;
double			base_log_x	= 0.0;
double			base_log_y	= 0.0;
double			base_log_z	= 0.0;
double			base_log_x2	= 0.0;
double			base_log_y2	= 0.0;
double			log_base_log_x	= 0.0;
double			log_base_log_y	= 0.0;
double			log_base_log_z	= 0.0;
double			log_base_log_x2	= 0.0;
double			log_base_log_y2	= 0.0;
FILE*			outfile;
char			outstr[MAX_ID_LEN+1] = "STDOUT";
TBOOLEAN		parametric	= FALSE;
double			pointsize	= 1.0;
int			encoding;
char			*encoding_names[] =
				{"default", "iso_8859_1", "cp437", "cp850", NULL};
TBOOLEAN		polar		= FALSE;
TBOOLEAN		hidden3d	= FALSE;
TBOOLEAN		label_contours	= TRUE; /* different linestyles are used for contours when set */
char contour_format[32] = "%8.3g"; /* format for contour key entries */
int			angles_format	= ANGLES_RADIANS;
double			ang2rad		= 1.0;  /* 1 or pi/180, tracking angles_format */
int			mapping3d	= MAP3D_CARTESIAN;
int			samples		= SAMPLES; /* samples is always equal to samples_1 */
int			samples_1	= SAMPLES;
int			samples_2	= SAMPLES;
int			iso_samples_1	= ISO_SAMPLES;
int			iso_samples_2	= ISO_SAMPLES;
float			xsize		= 1.0;  /* scale factor for size */
float			ysize		= 1.0;  /* scale factor for size */
float			zsize		= 1.0;  /* scale factor for size */
float			xoffset	= 0.0;  /* x origin */
float			yoffset	= 0.0;  /* y origin */
TBOOLEAN    square   = FALSE; /* dont try to set aspect ratio to 1 */
float			surface_rot_z   = 30.0; /* Default 3d transform. */
float			surface_rot_x   = 60.0;
float			surface_scale   = 1.0;
float			surface_zscale  = 1.0;
struct termentry *term		= NULL;		/* unknown */
char			term_options[MAX_LINE_LEN+1] = "";
label_struct		title = { "", 0.0, 0.0, ""};
label_struct		timelabel = { "", 0.0, 0.0, ""};
label_struct		xlabel = {"", 0.0, 0.0, ""};
label_struct		ylabel = {"", 0.0, 0.0, ""};
label_struct		zlabel = {"", 0.0, 0.0, ""};
label_struct		x2label = {"", 0.0, 0.0, ""};
label_struct		y2label = {"", 0.0, 0.0, ""};

char			key_title[MAX_LINE_LEN+1] = "";
double			rmin		= -0.0;
double			rmax		=  10.0;
double			tmin		= -5.0;
double			tmax		=  5.0;
double			umin		= -5.0;
double			umax		= 5.0;
double			vmin		= -5.0;
double			vmax		= 5.0;
double			xmin		= -10.0;
double			xmax		= 10.0;
double			ymin		= -10.0;
double			ymax		= 10.0;
double			zmin		= -10.0;
double			zmax		= 10.0;
double			x2min		= -10.0;
double			x2max		= 10.0;
double			y2min		= -10.0;
double			y2max		= 10.0;
double			loff		= 0.0;
double			roff		= 0.0;
double			toff		= 0.0;
double			boff		= 0.0;
int			draw_contour	= CONTOUR_NONE;
int			contour_pts	= 5;
int			contour_kind	= CONTOUR_KIND_LINEAR;
int			contour_order	= 4;
int			contour_levels	= 5;
double			zero		= ZERO;	/* zero threshold, not 0! */
int			levels_kind	= LEVELS_AUTO;
double			levels_list[MAX_DISCRETE_LEVELS];  /* storage for z levels to draw contours at */

int			dgrid3d_row_fineness = 10;
int			dgrid3d_col_fineness = 10;
int			dgrid3d_norm_value = 1;
TBOOLEAN		dgrid3d		= FALSE;

int 		xzeroaxis	= -3;
int 		yzeroaxis	= -3;
int 		x2zeroaxis	= -3;
int 		y2zeroaxis	= -3;

/* perhaps make these into an array one day */

int 		xtics		= TICS_ON_BORDER | TICS_MIRROR;
int 		ytics		= TICS_ON_BORDER | TICS_MIRROR;
int 		ztics		= TICS_ON_BORDER; /* no mirror by default for ztics */
int 		x2tics		= NO_TICS;
int 		y2tics		= NO_TICS;

int range_flags[AXIS_ARRAY_SIZE]; /* = {0,0,...} */

int                mxtics          = MINI_DEFAULT;
int                mytics          = MINI_DEFAULT;
int                mztics          = MINI_DEFAULT;
int                mx2tics          = MINI_DEFAULT;
int                my2tics          = MINI_DEFAULT;

double                  mxtfreq         = 10; /* # intervals between major */
double                  mytfreq         = 10; /* tic marks */
double                  mztfreq         = 10;
double                  mx2tfreq         = 10;
double                  my2tfreq         = 10;

double                  ticscale        = 1.0; /* scale factor for tic mark */
double			miniticscale	= 0.5; /* and for minitics */

float 			ticslevel	= 0.5;

struct ticdef		xticdef		= {TIC_COMPUTED};
struct ticdef		yticdef		= {TIC_COMPUTED};
struct ticdef		zticdef		= {TIC_COMPUTED};
struct ticdef		x2ticdef		= {TIC_COMPUTED};
struct ticdef		y2ticdef		= {TIC_COMPUTED};

TBOOLEAN		tic_in		= TRUE;

struct text_label 	*first_label	= NULL;
struct arrow_def 	*first_arrow	= NULL;

int 			lmargin		= -1; /* space between left edge and xleft in chars (-1: computed) */ 
int 			bmargin		= -1; /* space between bottom and ybot in chars (-1: computed) */ 
int 			rmargin		= -1; /* space between right egde and xright in chars (-1: computed) */ 
int 			tmargin		= -1; /* space between top egde and ytop in chars (-1: computed) */ 

/* string representing missing values in ascii datafiles */
char *missing_val = NULL;

/* date&time language conversions */ 
extern struct dtconv *dtc;

/*** other things we need *****/

#if defined(unix)
extern FILE *popen();
#endif

/* input data, parsing variables */

extern TBOOLEAN is_3d_plot;

/* term in graphics mode */
extern TBOOLEAN term_graphics, term_suspended;

#ifdef _Windows
extern FILE * open_printer();
extern void close_printer();
#endif

int key_hpos = TRIGHT;  /* place for curve-labels, corner or outside */
int key_vpos = TTOP; /* place for curve-labels, corner or below */
int key_just = JRIGHT;  /* alignment of key labels, left or right */

#ifndef TIMEFMT
#define TIMEFMT "%d/%m/%y\n%H:%M"
#endif
/* format for date/time for reading time in datafile */
char timefmt[25] = TIMEFMT;

/* array of datatypes (x in 0,y in 1,z in 2,..(rtuv)) */
/* not sure how rtuv come into it ?
 * oh well, make first six compatible with FIRST_X_AXIS, etc
 */
int datatype[DATATYPE_ARRAY_SIZE];

char cur_locale[MAX_ID_LEN+1] = "";

/* not set or shown directly, but controlled by 'set locale'
 * defined in national.h
 */

char full_month_names[12][32] = { FMON01, FMON02, FMON03, FMON04, FMON05, FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12 };
char abbrev_month_names[12][8] ={ AMON01, AMON02, AMON03, AMON04, AMON05, AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12 };

char full_day_names[7][32] = { FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6, FDAY7 };
char abbrev_day_names[7][8] = { ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6, ADAY7 };



/******** Local functions ********/
static enum position_type get_position __P((struct position *pos, enum position_type type));
static void get_position_type __P((enum position_type *type, int *axes));
static void set_xyzlabel __P((label_struct *label));
static void set_label __P((void));
static void set_nolabel __P((void));
static void set_arrow __P((void));
static void set_noarrow __P((void));
static void load_tics __P((int axis, struct ticdef *tdef));
static void load_tic_user __P((int axis, struct ticdef *tdef));
static void free_marklist __P((struct ticmark *list));
static void load_tic_series __P((int axis, struct ticdef *tdef));
static void load_offsets __P((double *a, double *b, double *c, double *d));
static void delete_label __P((struct text_label *prev, struct text_label *this));
static int assign_label_tag __P((void));
static void delete_arrow __P((struct arrow_def *prev, struct arrow_def *this));
static int assign_arrow_tag __P((void));
static TBOOLEAN set_one __P((void));
static TBOOLEAN set_two __P((void));
static TBOOLEAN set_three __P((void));
static int looks_like_numeric __P((char *));
static void set_locale __P((char *));

/* following code segment appears over and over again */
#define GET_NUM_OR_TIME(store,axis) \
do{if ( datatype[axis] == TIME && isstring(c_token) ) { \
    char ss[80]; struct tm tm; \
    quote_str(ss,c_token, 80); ++c_token; \
    if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); else store=0;\
   } else {\
    struct value value; \
    store = real(const_express(&value));\
  }}while(0)

/******** The 'reset' command ********/
void
reset_command()
{
  extern struct curve_points *first_plot;
  extern struct surface_points *first_3dplot;
  register struct curve_points *f_p = first_plot;
  register struct surface_points *f_3dp = first_3dplot;

  c_token++;
  first_plot = NULL;
  first_3dplot = NULL;
  cp_free(f_p);
  sp_free(f_3dp);
  /* delete arrows */
  while (first_arrow != NULL)
    delete_arrow((struct arrow_def *)NULL,first_arrow);
  /* delete labels */
  while (first_label != NULL)
    delete_label((struct text_label *)NULL,first_label);
  strcpy(dummy_var[0],"x");
  strcpy(dummy_var[1],"y");
  strcpy(title.text,"");
  strcpy(xlabel.text,"");
  strcpy(ylabel.text,"");
  strcpy(zlabel.text,"");
  strcpy(x2label.text, "");
  strcpy(y2label.text, "");
  *title.font = 0;
  *xlabel.font = 0;
  *ylabel.font = 0;
  *zlabel.font = 0;
  *x2label.font = 0;
  *y2label.font = 0;
  strcpy(key_title,"");
  strcpy(timefmt,TIMEFMT);
  strcpy(xformat,DEF_FORMAT);
  strcpy(yformat,DEF_FORMAT);
  strcpy(zformat,DEF_FORMAT);
  strcpy(x2format,DEF_FORMAT);
  strcpy(y2format,DEF_FORMAT);
  format_is_numeric[FIRST_X_AXIS]=format_is_numeric[SECOND_X_AXIS]=1;
  format_is_numeric[FIRST_Y_AXIS]=format_is_numeric[SECOND_Y_AXIS]=1;
  format_is_numeric[FIRST_Z_AXIS]=format_is_numeric[SECOND_Z_AXIS]=1;
  autoscale_r	 = DTRUE;
  autoscale_t	 = DTRUE;
  autoscale_u	 = DTRUE;
  autoscale_v	 = DTRUE;
  autoscale_x	 = DTRUE;
  autoscale_y	 = DTRUE;
  autoscale_z	 = DTRUE;
  autoscale_lt	 = DTRUE;
  autoscale_lu	 = DTRUE;
  autoscale_lv	 = DTRUE;
  autoscale_lx	 = DTRUE;
  autoscale_ly	 = DTRUE;
  autoscale_lz	 = DTRUE;
  boxwidth	 = -1.0;
  clip_points	 = FALSE;
  clip_lines1	 = TRUE;
  clip_lines2	 = FALSE;
  draw_border	 = 31;
  draw_surface	 = TRUE;
  data_style	 = POINTSTYLE;
  func_style	 = LINES;
  bar_size		= 1.0;
  grid		 = GRID_OFF;
  grid_linetype  = mgrid_linetype = -1;
  polar_grid_angle=0;
  key		 = -1;
  is_log_x	 = FALSE;
  is_log_y	 = FALSE;
  is_log_z	 = FALSE;
  is_log_x2	 = FALSE;
  is_log_y2	 = FALSE;
  base_log_x	 = 0.0;
  base_log_y	 = 0.0;
  base_log_z	 = 0.0;
  base_log_x2	 = 0.0;
  base_log_y2	 = 0.0;
  log_base_log_x = 0.0;
  log_base_log_y = 0.0;
  log_base_log_z = 0.0;
  log_base_log_x2 = 0.0;
  log_base_log_y2 = 0.0;
  parametric	 = FALSE;
  polar		 = FALSE;
  hidden3d	 = FALSE;
  label_contours = TRUE;
  strcpy(contour_format, "%8.3g");
  angles_format	 = ANGLES_RADIANS;
  ang2rad	 = 1.0; 
  mapping3d	 = MAP3D_CARTESIAN;
  samples	 = SAMPLES;
  samples_1	 = SAMPLES;
  samples_2	 = SAMPLES;
  iso_samples_1	 = ISO_SAMPLES;
  iso_samples_2	 = ISO_SAMPLES;
  xsize		 = 1.0;
  ysize		 = 1.0;
  zsize		 = 1.0;
  xoffset	= 0.0;
  yoffset	= 0.0;
  square     = FALSE;
  surface_rot_z	 = 30.0;
  surface_rot_x	 = 60.0;
  surface_scale	 = 1.0;
  surface_zscale = 1.0;
  *timelabel.text = 0;
  timelabel.xoffset	 = 0;
  timelabel.yoffset	 = 0;
  *timelabel.font = 0;
  title.xoffset	 = 0;
  title.yoffset	 = 0;
  xlabel.xoffset = 0;
  xlabel.yoffset = 0;
  ylabel.xoffset = 0;
  ylabel.yoffset = 0;
  zlabel.xoffset = 0;
  zlabel.yoffset = 0;
  x2label.xoffset = 0;
  x2label.yoffset = 0;
  y2label.xoffset = 0;
  y2label.yoffset = 0;
  rmin		 = -0.0;
  rmax		 =  10.0;
  tmin		 = -5.0;
  tmax		 =  5.0;
  umin		 = -5.0;
  umax		 = 5.0;
  vmin		 = -5.0;
  vmax		 = 5.0;
  xmin		 = -10.0;
  xmax		 = 10.0;
  ymin		 = -10.0;
  ymax		 = 10.0;
  zmin		 = -10.0;
  zmax		 = 10.0;
  memset(range_flags, 0, sizeof(range_flags)); /* all = 0 */
  
  loff		 = 0.0;
  roff		 = 0.0;
  toff		 = 0.0;
  boff		 = 0.0;
  draw_contour	 = CONTOUR_NONE;
  contour_pts	 = 5;
  contour_kind	 = CONTOUR_KIND_LINEAR;
  contour_order	 = 4;
  contour_levels = 5;
  zero		 = ZERO;
  levels_kind	 = LEVELS_AUTO;
  dgrid3d_row_fineness = 10;
  dgrid3d_col_fineness = 10;
  dgrid3d_norm_value   = 1;
  dgrid3d	 = FALSE;
  xzeroaxis	 =
  yzeroaxis	 =
  x2zeroaxis	 =
  y2zeroaxis	 = -3;
  xtics		 =
  ytics		 =
  ztics		 = TICS_ON_BORDER; /* no mirror by default */
  x2tics     = NO_TICS;
  y2tics     = NO_TICS;
  mxtics	 =
  mytics	 =
  mztics  =
  mx2tics =
  my2tics = MINI_DEFAULT;
  mxtfreq	 = 10.0;
  mytfreq	 = 10.0;
  mztfreq    = 10.0;
  mx2tfreq   = 10.0;
  my2tfreq   = 10.0;
  ticscale	 = 1.0;
  miniticscale	 = 0.5;
  ticslevel	 = 0.5;
  xticdef.type	 = TIC_COMPUTED;
  yticdef.type	 = TIC_COMPUTED;
  zticdef.type	 = TIC_COMPUTED;
  x2ticdef.type	 = TIC_COMPUTED;
  y2ticdef.type	 = TIC_COMPUTED;
  tic_in	 = TRUE;
  lmargin	 =
  bmargin	 =
  rmargin	 =
  tmargin	 = -1; /* autocomputed */
  key_hpos	 = TRIGHT;
  key_vpos	 = TTOP;
  key_just	 = JRIGHT;
  key_reverse	 = FALSE;
  key_box	 = -3;
  datatype[FIRST_X_AXIS]	 = FALSE;
  datatype[FIRST_Y_AXIS]	 = FALSE;
  datatype[FIRST_Z_AXIS]	 = FALSE;
  datatype[SECOND_X_AXIS]	 = FALSE;
  datatype[SECOND_Y_AXIS]	 = FALSE;
  datatype[SECOND_Z_AXIS]	 = FALSE;
  datatype[R_AXIS] = FALSE;
  datatype[T_AXIS] = FALSE;
  datatype[U_AXIS] = FALSE;
  datatype[V_AXIS] = FALSE;

  pointsize = 1.0;
  if (term_init && term->set_pointsize)
  	(*term->set_pointsize)(1.0);
  encoding = ENCODING_DEFAULT;

  set_locale(""); /* default */
}

/******** The 'set' command ********/
void
set_command()
{
static char GPFAR setmess[] ="\
valid set options:  [] = choose one, {} means optional\n\
\t'angles' '{no}arrow', {no}autoscale', 'bars', '{no}border',\n\
\t'boxwidth', '{no}clabel', '{no}clip', 'cntrparam', '{no}contour',\n\
\t'data style', '{no}dgrid3d', 'dummy', 'format',\n\
\t'function style', '{no}grid', '{no}hidden3d', 'isosamples', '{no}key',\n\
\t'keytitle','{no}label', 'locale', '{no}logscale', '[blrt]margin',\n\
\t'mapping', 'missing', 'offsets', 'origin', 'output', '{no}parametric',\n\
\t'pointsize', '{no}polar', '[rtuv]range', 'samples', 'size',\n\
\t'{no}surface', 'terminal', 'tics', 'ticscale', 'ticslevel',\n\
\t'{no}time', 'timefmt', 'title', 'view', '[xyz]{2}data', '[xyz]{2}label',\n\
\t'[xyz]{2}range', '{no}{m}[xyz]{2}tics','{no}[xyz]{2}[md]tics',\n\
\t'{no}[xyz]{2}zeroaxis', 'zero', '{no}zeroaxis'";


    c_token++;

    if (!set_one() && !set_two() && !set_three())
	int_error(setmess, c_token);
}

/* return TRUE if a command match, FALSE if not */
static TBOOLEAN
set_one()
{
	if (almost_equals(c_token,"ar$row")) {
		c_token++;
		set_arrow();
	}
	else if (almost_equals(c_token,"noar$row")) {
		c_token++;
		set_noarrow();
	}

/* save on replication with a macro */
#define PROCESS_AUTO_LETTER(AUTO, STRING,MIN,MAX) \
else if (equals(c_token, STRING))       { AUTO = DTRUE; ++c_token; } \
else if (almost_equals(c_token, MIN)) { AUTO |= 1;    ++c_token; } \
else if (almost_equals(c_token, MAX)) { AUTO |= 2;    ++c_token; }

     else if (almost_equals(c_token,"au$toscale")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		   autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = DTRUE;
	    } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
		   autoscale_x = autoscale_y = DTRUE;
		   c_token++;
	    }
	    PROCESS_AUTO_LETTER(autoscale_r, "r", "rmi$n", "rma$x")
	    PROCESS_AUTO_LETTER(autoscale_t, "t", "tmi$n", "tma$x")
	    PROCESS_AUTO_LETTER(autoscale_u, "u", "umi$n", "uma$x")
	    PROCESS_AUTO_LETTER(autoscale_v, "v", "vmi$n", "vma$x")
	    PROCESS_AUTO_LETTER(autoscale_x, "x", "xmi$n", "xma$x")
	    PROCESS_AUTO_LETTER(autoscale_y, "y", "ymi$n", "yma$x")
	    PROCESS_AUTO_LETTER(autoscale_z, "z", "zmi$n", "zma$x")
	    PROCESS_AUTO_LETTER(autoscale_x2, "x2", "x2mi$n", "x2ma$x")
	    PROCESS_AUTO_LETTER(autoscale_y2, "y2", "y2mi$n", "y2ma$x")
	    else
		int_error("Invalid range", c_token);
	} 
	else if (almost_equals(c_token,"noau$toscale")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		   autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
	    } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
		   autoscale_x = autoscale_y = FALSE;
		   c_token++;
	    } else if (equals(c_token, "r")) {
		   autoscale_r = FALSE;
		   c_token++;
	    } else if (equals(c_token, "t")) {
		   autoscale_t = FALSE;
		   c_token++;
	    } else if (equals(c_token, "u")) {
		   autoscale_u = FALSE;
		   c_token++;
	    } else if (equals(c_token, "v")) {
		   autoscale_v = FALSE;
		   c_token++;
	    } else if (equals(c_token, "x")) {
		   autoscale_x = FALSE;
		   c_token++;
	    } else if (equals(c_token, "y")) {
		   autoscale_y = FALSE;
		   c_token++;
	    } else if (equals(c_token, "z")) {
		   autoscale_z = FALSE;
		   c_token++;
	    }
	} 
	else if (almost_equals(c_token,"nobor$der")) {
	    draw_border = 0;
	    c_token++;
	}
	else if (almost_equals(c_token,"box$width")) {
		struct value a;
		c_token++;
	    if (END_OF_COMMAND)
	    	boxwidth = -1.0;
	    else
/*              if((boxwidth = real(const_express(&a))) != -2.0)*/
/*                      boxwidth = magnitude(const_express(&a));*/
                boxwidth = real(const_express(&a));
	}
	else if (almost_equals(c_token,"c$lip")) {
	    c_token++;
	    if (END_OF_COMMAND)
		 /* assuming same as points */
		 clip_points = TRUE;
	    else if (almost_equals(c_token, "p$oints"))
		 clip_points = TRUE;
	    else if (almost_equals(c_token, "o$ne"))
		 clip_lines1 = TRUE;
	    else if (almost_equals(c_token, "t$wo"))
		 clip_lines2 = TRUE;
	    else
		 int_error("expecting 'points', 'one', or 'two'", c_token);
	    c_token++;
	}
	else if (almost_equals(c_token,"noc$lip")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		   /* same as all three */
		   clip_points = FALSE;
		   clip_lines1 = FALSE;
		   clip_lines2 = FALSE;
	    } else if (almost_equals(c_token, "p$oints"))
		 clip_points = FALSE;
	    else if (almost_equals(c_token, "o$ne"))
		 clip_lines1 = FALSE;
	    else if (almost_equals(c_token, "t$wo"))
		 clip_lines2 = FALSE;
	    else
		 int_error("expecting 'points', 'one', or 'two'", c_token);
	    c_token++;
	}
	else if (almost_equals(c_token,"hi$dden3d")) {
#ifdef LITE
		printf(" Hidden Line Removal Not Supported in LITE version\n");
#else
	    hidden3d = TRUE;
#endif /* LITE */
	    c_token++;
	}
	else if (almost_equals(c_token,"nohi$dden3d")) {
#ifdef LITE
		printf(" Hidden Line Removal Not Supported in LITE version\n");
#else
	    hidden3d = FALSE;
#endif /* LITE */
	    c_token++;
	}
 	else if (almost_equals(c_token,"cla$bel")) {
 		label_contours = TRUE;
 		c_token++;
 		if (isstring(c_token))
 			quote_str(contour_format, c_token++, 30);
 	}
 	else if (almost_equals(c_token,"nocla$bel")) {
 		label_contours = FALSE;
 		c_token++;
  	}
	else if (almost_equals(c_token,"ma$pping3d")) {
	    c_token++;
	    if (END_OF_COMMAND)
		 /* assuming same as points */
		 mapping3d = MAP3D_CARTESIAN;
	    else if (almost_equals(c_token, "ca$rtesian"))
		 mapping3d = MAP3D_CARTESIAN;
	    else if (almost_equals(c_token, "s$pherical"))
		 mapping3d = MAP3D_SPHERICAL;
	    else if (almost_equals(c_token, "cy$lindrical"))
		 mapping3d = MAP3D_CYLINDRICAL;
	    else
		 int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
	    c_token++;
	}
	else if (almost_equals(c_token,"co$ntour")) {
	  c_token++;
	  if (END_OF_COMMAND)
		 /* assuming same as points */
		 draw_contour = CONTOUR_BASE;
	  else {
	    if (almost_equals(c_token, "ba$se"))
		 draw_contour = CONTOUR_BASE;
	    else if (almost_equals(c_token, "s$urface"))
		 draw_contour = CONTOUR_SRF;
	    else if (almost_equals(c_token, "bo$th"))
		 draw_contour = CONTOUR_BOTH;
	    else
		 int_error("expecting 'base', 'surface', or 'both'", c_token);
	    c_token++;
	  }
	}
	else if (almost_equals(c_token,"noco$ntour")) {
	    c_token++;
	    draw_contour = CONTOUR_NONE;
	}
	else if (almost_equals(c_token,"cntrp$aram")) {
	    struct value a;

	    c_token++;
	    if (END_OF_COMMAND) {
		 /* assuming same as defaults */
		 contour_pts = 5;
		 contour_kind = CONTOUR_KIND_LINEAR;
		 contour_order = 4;
		 contour_levels = 5;
 		 levels_kind = LEVELS_AUTO;
	    }
	    else if (almost_equals(c_token, "p$oints")) {
		 c_token++;
		 contour_pts = (int) real(const_express(&a));
	    }
	    else if (almost_equals(c_token, "li$near")) {
		 c_token++;
		 contour_kind = CONTOUR_KIND_LINEAR;
	    }
	    else if (almost_equals(c_token, "c$ubicspline")) {
		 c_token++;
		 contour_kind = CONTOUR_KIND_CUBIC_SPL;
	    }
	    else if (almost_equals(c_token, "b$spline")) {
		 c_token++;
		 contour_kind = CONTOUR_KIND_BSPLINE;
	    }

   		else if (almost_equals(c_token, "le$vels")) {
   			int i=0;  /* local counter */
   			c_token++;
			/*  RKC: I have modified the next two:
			 *   to use commas to separate list elements as in xtics
 			 *   so that incremental lists start,incr[,end]as in "
 			 */
   			if (almost_equals(c_token, "di$screte")) {
   			   levels_kind = LEVELS_DISCRETE;
   			   c_token++;
 			   if(END_OF_COMMAND)
			     int_error("expecting discrete level", c_token);
 			   else
 			     levels_list[i++] = real(const_express(&a));
 			   while(!END_OF_COMMAND){
 			     if (!equals(c_token, ","))
 			       int_error("expecting comma to separate discrete levels", c_token);
 			     c_token++;
 			     levels_list[i++] =  real(const_express(&a));
 			   }
   			   contour_levels = i;
   			}
   			else if (almost_equals(c_token, "in$cremental")) {
   			   levels_kind = LEVELS_INCREMENTAL;
   			   c_token++;
 			   levels_list[i++] =  real(const_express(&a));
 			   if (!equals(c_token, ","))
 			     int_error("expecting comma to separate start,incr levels", c_token);
 			   c_token++;
 			   if((levels_list[i++] = real(const_express(&a)))==0)
 			     int_error("increment cannot be 0", c_token);
  			   if(!END_OF_COMMAND){
 			     if (!equals(c_token, ","))
 			       int_error("expecting comma to separate incr,stop levels", c_token);
 			     c_token++;
			     contour_levels = (real(const_express(&a))-levels_list[0])/levels_list[1];
 			     }
   			}
   			else if (almost_equals(c_token, "au$to")) {
   				levels_kind = LEVELS_AUTO;
 				c_token++;
 				if(!END_OF_COMMAND)
 					contour_levels = (int) real(const_express(&a));
 			}
 			else {
			  if(levels_kind == LEVELS_DISCRETE)
			    int_error("Levels type is discrete, ignoring new number of contour levels", c_token);
			    contour_levels = (int) real(const_express(&a));
			}
 		}
	    else if (almost_equals(c_token, "o$rder")) {
		 int order;
		 c_token++;
		 order = (int) real(const_express(&a));
		 if ( order < 2 || order > 10 )
		     int_error("bspline order must be in [2..10] range.", c_token);
		 contour_order = order;
	    }
	    else
		 int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
	    c_token++;
	}
	else if (almost_equals(c_token,"da$ta")) {
		c_token++;
		if (!almost_equals(c_token,"s$tyle"))
			int_error("expecting keyword 'style'",c_token);
		data_style = get_style();
	}
	else if (almost_equals(c_token,"dg$rid3d")) {
		int i;
		TBOOLEAN was_comma = TRUE;
		int local_vals[3];
		struct value a;

		local_vals[0] = dgrid3d_row_fineness;
		local_vals[1] = dgrid3d_col_fineness;
		local_vals[2] = dgrid3d_norm_value;
		c_token++;
		for (i = 0; i < 3 && !(END_OF_COMMAND);) {
			if (equals(c_token,",")) {
				if (was_comma) i++;
				was_comma = TRUE;
				c_token++;
			}
			else {
				if (!was_comma)
					int_error("',' expected",c_token);
				local_vals[i] = real(const_express(&a));
				i++;
				was_comma = FALSE;
			}
		}


		if (local_vals[0] < 2 || local_vals[0] > 1000)
			int_error("Row size must be in [2:1000] range; size unchanged",
				  c_token);
		if (local_vals[1] < 2 || local_vals[1] > 1000)
			int_error("Col size must be in [2:1000] range; size unchanged",
				  c_token);
		if (local_vals[2] < 1 || local_vals[2] > 100)
			int_error("Norm must be in [1:100] range; norm unchanged", c_token);

		dgrid3d_row_fineness = local_vals[0];
		dgrid3d_col_fineness = local_vals[1];
		dgrid3d_norm_value = local_vals[2];
		dgrid3d = TRUE;
	}
	else if (almost_equals(c_token,"nodg$rid3d")) {
		c_token++;
		dgrid3d = FALSE;
	}
	else if (almost_equals(c_token,"mis$sing")) {
		c_token++;
		if (END_OF_COMMAND) {
			if (missing_val)
				free(missing_val);
			missing_val = NULL;
		} else {
			if (!isstring(c_token))
				int_error("Expected missing-value string", c_token);
			m_quote_capture(&missing_val, c_token, c_token);
			c_token++;
		}
	}
	else if (almost_equals(c_token,"nomis$sing")) {
		++c_token;
		if (missing_val)
			free(missing_val);
		missing_val = NULL;
	}
	else if (almost_equals(c_token,"du$mmy")) {
		c_token++;
		if (END_OF_COMMAND)
			int_error("expecting dummy variable name", c_token);
		else {
			if (!equals(c_token,","))
				copy_str(dummy_var[0],c_token++, MAX_ID_LEN);
			if (!END_OF_COMMAND && equals(c_token,",")) {
				c_token++;
				if (END_OF_COMMAND)
					int_error("expecting second dummy variable name", c_token);
				copy_str(dummy_var[1],c_token++, MAX_ID_LEN);
		    	}
		}
	}
	else if (almost_equals(c_token,"fo$rmat")) {
		TBOOLEAN setx=FALSE, sety=FALSE, setz=FALSE;
		TBOOLEAN setx2=FALSE, sety2=FALSE;
		c_token++;
		if (equals(c_token,"x")) {
			setx = TRUE;
			c_token++;
		}
		else if (equals(c_token,"y")) {
			sety = TRUE;
			c_token++;
		}
		else if (equals(c_token,"x2")) {
			setx2 = TRUE;
			c_token++;
		}
		else if (equals(c_token,"y2")) {
			sety2 = TRUE;
			c_token++;
		}
		else if (equals(c_token,"z")) {
			setz = TRUE;
			c_token++;
		}
		else if (equals(c_token,"xy") || equals(c_token,"yx")) {
			setx = sety = TRUE;
			c_token++;
		}
		else if (isstring(c_token) || END_OF_COMMAND) {
			/* Assume he wants all */
			setx = sety = setz = setx2 = sety2 = TRUE;
		}
		if (END_OF_COMMAND) {
			if (setx) {
				(void) strcpy(xformat,DEF_FORMAT);
				format_is_numeric[FIRST_X_AXIS]=1;
			}
			if (sety) {
				(void) strcpy(yformat,DEF_FORMAT);
				format_is_numeric[FIRST_Y_AXIS]=1;
			}
			if (setz) {
				(void) strcpy(zformat,DEF_FORMAT);
				format_is_numeric[FIRST_Z_AXIS]=1;
			}
			if (setx2) {
				(void) strcpy(x2format,DEF_FORMAT);
				format_is_numeric[SECOND_X_AXIS]=1;
			}
			if (sety2) {
				(void) strcpy(y2format,DEF_FORMAT);
				format_is_numeric[SECOND_Y_AXIS]=1;
			}
		}
		else {
			if (!isstring(c_token))
			  int_error("expecting format string",c_token);
			else {
				if (setx) {
				 quote_str(xformat,c_token, MAX_ID_LEN);
				 format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(xformat);
				}
				if (sety) {
				 quote_str(yformat,c_token, MAX_ID_LEN);
				 format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(yformat);
				}
				if (setz) {
				 quote_str(zformat,c_token, MAX_ID_LEN);
				 format_is_numeric[FIRST_X_AXIS]=looks_like_numeric(zformat);
				}
				if (setx2) {
				 quote_str(x2format,c_token, MAX_ID_LEN);
				 format_is_numeric[SECOND_X_AXIS]=looks_like_numeric(x2format);
				}
				if (sety2) {
				 quote_str(y2format,c_token, MAX_ID_LEN);
				 format_is_numeric[SECOND_Y_AXIS]=looks_like_numeric(y2format);
				}
				c_token++;
			}
		}
	}
	else if (almost_equals(c_token,"fu$nction")) {
		c_token++;
		if (!almost_equals(c_token,"s$tyle"))
			int_error("expecting keyword 'style'",c_token);
		func_style = get_style();
	}
	else if (almost_equals(c_token,"la$bel")) {
		c_token++;
		set_label();
	}
	else if (almost_equals(c_token,"nola$bel")) {
		c_token++;
		set_nolabel();
	}
	else if (almost_equals(c_token,"lo$gscale")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = TRUE;
		base_log_x = base_log_y = base_log_z = base_log_x2 = base_log_y2 = 10.0;
		log_base_log_x = log_base_log_y = log_base_log_z = log_base_log_x2 = log_base_log_y2 = log(10.0);
	    } else {
		TBOOLEAN change_x = FALSE;
		TBOOLEAN change_y = FALSE;
		TBOOLEAN change_z = FALSE;
		TBOOLEAN change_x2 = FALSE;
		TBOOLEAN change_y2 = FALSE;
		double newbase=10, log_newbase;

		if (equals(c_token, "x2"))
			change_x2 = TRUE;
		else if (equals(c_token, "y2"))
			change_y2 = TRUE;
		else { /* must not see x when x2, etc */
		    if (chr_in_str(c_token, 'x'))
			change_x = TRUE;
		    if (chr_in_str(c_token, 'y'))
			change_y = TRUE;
		    if (chr_in_str(c_token, 'z'))
			change_z = TRUE;
		}
		c_token++;
                if (!END_OF_COMMAND) {
			struct value a;
			newbase = magnitude(const_express(&a));
			if (newbase < 1.1)
			    int_error("log base must be >= 1.1; logscale unchanged",
				c_token);
		}

		log_newbase = log(newbase);

			if (change_x) {
			    is_log_x = TRUE;
			    base_log_x = newbase;
			    log_base_log_x = log_newbase;
			}
			if (change_y) {
			    is_log_y = TRUE;
			    base_log_y = newbase;
			    log_base_log_y = log_newbase;
			}
			if (change_z) {
			    is_log_z = TRUE;
			    base_log_z = newbase;
			    log_base_log_z = log_newbase;
			}
			if (change_x2) {
			    is_log_x2 = TRUE;
			    base_log_x2 = newbase;
			    log_base_log_x2 = log_newbase;
			}
			if (change_y2) {
			    is_log_y2 = TRUE;
			    base_log_y2 = newbase;
			    log_base_log_y2 = log_newbase;
			}
	    }
	}
	else if (almost_equals(c_token,"nolo$gscale")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		is_log_x = is_log_y = is_log_z = is_log_x2 = is_log_y2 = FALSE;
	    } else if (equals(c_token, "x2")) {
		is_log_x2=FALSE; ++c_token;
	    } else if (equals(c_token, "y2")) {
		is_log_y2=FALSE; ++c_token;
	    } else {
		if (chr_in_str(c_token, 'x')) {
		    is_log_x = FALSE;
		    base_log_x = 0.0;
		    log_base_log_x = 0.0;
                }
		if (chr_in_str(c_token, 'y')) {
		    is_log_y = FALSE;
		    base_log_y = 0.0;
		    log_base_log_y = 0.0;
                }
		if (chr_in_str(c_token, 'z')) {
		    is_log_z = FALSE;
		    base_log_z = 0.0;
		    log_base_log_z = 0.0;
                }
		c_token++;
	    }
	} 
	else if (almost_equals(c_token,"of$fsets")) {
		c_token++;
		if (END_OF_COMMAND) {
			loff = roff = toff = boff = 0.0;  /* Reset offsets */
		}
		else {
			load_offsets (&loff,&roff,&toff,&boff);
		}
	}
	else if (almost_equals(c_token, "noof$fsets")) {
		loff = roff = toff = boff = 0.0;
		++c_token;
	}
        else if(almost_equals(c_token,"b$ars")){
           c_token++;
           if(END_OF_COMMAND){
           		bar_size=1.0;
           } else if(almost_equals(c_token,"s$mall")){
              bar_size=0.0;
              ++c_token;
           } else if(almost_equals(c_token,"l$arge")){
              bar_size=1.0;
              ++c_token;
           } else {
           		struct value a;
           		bar_size=real(const_express(&a));
           }
        } else if (almost_equals(c_token, "nob$ars")){
        		++c_token;
        		bar_size=0.0;
        } else if (almost_equals(c_token, "enco$ding")){
	    c_token++;
	    if(END_OF_COMMAND) {
		encoding = ENCODING_DEFAULT;
	    }
	    else if (almost_equals(c_token,"def$ault")) {
		c_token++;
		encoding = ENCODING_DEFAULT;
	    }
            else if (almost_equals(c_token,"iso$_8859_1")) {
		c_token++;
		encoding = ENCODING_ISO_8859_1;
	    }
	    else if (almost_equals(c_token,"cp4$37")) {
		c_token++;
		encoding = ENCODING_CP_437;
	    }
	    else if (almost_equals(c_token,"cp8$50")) {
		c_token++;
		encoding = ENCODING_CP_850;
	    }
	    else {
	       int_error("expecting one of 'default', 'iso_8859_1', 'cp437' or 'cp850'",
			c_token);
	    }
        } else return(FALSE);  /* no command match */
	return(TRUE);
}


/* return TRUE if a command match, FALSE if not */
static TBOOLEAN
set_two()
{
     char testfile[MAX_LINE_LEN+1];
#if defined(unix) || defined(PIPES)
     static TBOOLEAN pipe_open = FALSE;
#endif /* unix || PIPES */

	if (almost_equals(c_token,"o$utput")) {
	 if (multiplot) {
 	    fprintf(stderr,"In multiplotmode you can't change the output\n");
 	  } else {
		register FILE *f;

		c_token++;
		if (term && term_init) {
			(*term->reset)();
			term_init=FALSE;
		}
		if (END_OF_COMMAND) {	/* no file specified */
 			UP_redirect (4);
			if (outfile != stdout) { /* Never close stdout */
#if defined(unix) || defined(PIPES)
				if ( pipe_open ) {
					(void) pclose(outfile);
					pipe_open = FALSE;
				} else
#endif /* unix || PIPES */
#ifdef _Windows
				  if ( !stricmp(outstr,"'PRN'") )
					close_printer();
				  else
#endif
					(void) fclose(outfile);
			}
			outfile = stdout; /* Don't dup... */
			term_init = FALSE;
			(void) strcpy(outstr,"STDOUT");
		} else if (!isstring(c_token))
			int_error("expecting filename",c_token);
		else {
			quote_str(testfile,c_token, MAX_LINE_LEN);
#if defined(unix) || defined(PIPES)
			if ( *testfile == '|' ) {
			  if ((f = popen(testfile+1,"w")) == (FILE *)NULL)
			    os_error("cannot create pipe; output not changed",c_token);
			  else
			    pipe_open = TRUE;
			} else
#endif /* unix || PIPES */
#ifdef _Windows
			if ( !stricmp(outstr,"'PRN'") ) {
				/* we can't call open_printer() while printer is open, so */
				close_printer();	/* close printer immediately if open */
			    outfile = stdout;	/* and reset output to stdout */
			    term_init = FALSE;
				(void) strcpy(outstr,"STDOUT");
			}
			if ( !stricmp(testfile,"PRN") ) {
			  if ((f = open_printer()) == (FILE *)NULL)
			    os_error("cannot open printer temporary file; output may have changed",c_token);
			} else
#endif
			  if ((f = fopen(testfile,"w")) == (FILE *)NULL)
			    os_error("cannot open file; output not changed",c_token);
			if (outfile != stdout) /* Never close stdout */
#if defined(unix) || defined(PIPES)
			    if( pipe_open ) {
				(void) pclose(outfile);
				pipe_open=FALSE;
			    } else
#endif /* unix || PIPES */
				(void) fclose(outfile);
			outfile = f;
			term_init = FALSE;
			outstr[0] = '\'';
			(void) strcat(strcpy(outstr+1,testfile),"'");
 			UP_redirect (1);
			c_token++;
		}
	  }
		/* c_token++; */
	}
     else if (almost_equals(c_token,"origin")) {
 		struct value s;
 		c_token++;
 		if (END_OF_COMMAND) {
 			xoffset = 0.0;
 			yoffset = 0.0;
 		} 
 		else {
 				xoffset=real(const_express(&s));
 				if (!equals(c_token,","))
 					int_error("',' expected",c_token);
 				c_token++;
 				yoffset=real(const_express(&s));
 		} 
 	} 
	else if (almost_equals(c_token,"tit$le")) {
		set_xyzlabel(&title);
	}
	else if (almost_equals(c_token,"xl$abel")) {
		set_xyzlabel(&xlabel);
	}
	else if (almost_equals(c_token,"yl$abel")) {
		set_xyzlabel(&ylabel);
	}
	else if (almost_equals(c_token,"zl$abel")) {
		set_xyzlabel(&zlabel);
	}
	else if (almost_equals(c_token,"x2l$abel")) {
		set_xyzlabel(&x2label);
	}
	else if (almost_equals(c_token,"y2l$abel")) {
		set_xyzlabel(&y2label);
	}
	else if (almost_equals(c_token,"keyt$itle")) {
		c_token++;
		if (END_OF_COMMAND) {	/* set to default */
			key_title[0] = '\0';
		} else {
			if (isstring(c_token)) {
				/* We have string specified - grab it. */
				quote_str(key_title,c_token, MAX_LINE_LEN);
				c_token++;
			}
			/* c_token++; */
		}
	}
	else if (almost_equals(c_token, "nokeyt$itle")) {
		++c_token;
		*key_title=0;
	}
	else if (almost_equals(c_token,"timef$mt")) {
		c_token++;
		if (END_OF_COMMAND) {	/* set to default */
			strcpy(timefmt,TIMEFMT);
		} else {
			if (isstring(c_token)) {
				/* We have string specified - grab it. */
				quote_str(timefmt,c_token, 25);
			}
			c_token++;
		}
	}
	else if (almost_equals(c_token,"loc$ale")) {
		c_token++;
		if (END_OF_COMMAND) {
			set_locale("");
		} else if (isstring(c_token)) {
			char ss[MAX_ID_LEN+1];
			quote_str(ss,c_token,MAX_ID_LEN);
			set_locale(ss);
			++c_token;
		} else {
			int_error("Expected string", c_token);
		}
	}

#define DO_ZEROAX(variable, string,neg) \
else if (almost_equals(c_token, string)) { \
   ++c_token; if (END_OF_COMMAND) variable=-1; \
   else { struct value a; variable=real(const_express(&a))-1; }\
} else if (almost_equals(c_token, neg)) { \
   ++c_token; variable=-3; \
}


	DO_ZEROAX(xzeroaxis, "xzero$axis", "noxzero$axis")
	DO_ZEROAX(yzeroaxis, "yzero$axis", "noyzero$axis")
	DO_ZEROAX(x2zeroaxis, "x2zero$axis", "nox2zero$axis")
	DO_ZEROAX(y2zeroaxis, "y2zero$axis", "noy2zero$axis")

	else if (almost_equals(c_token,"zeroa$xis")) {
		int line=-1;
		c_token++;
		if (!END_OF_COMMAND) {
			struct value a;
			line=real(const_express(&a))-1;
		}
		xzeroaxis =
		yzeroaxis = line;
	}
	else if (almost_equals(c_token,"nozero$axis")) {
		c_token++;
		xzeroaxis = -3;
		yzeroaxis = -3;
		x2zeroaxis = -3;
		y2zeroaxis = -3;
	} else if (almost_equals(c_token,"par$ametric")) {
		if (!parametric) {
		   parametric = TRUE;
		   if (!polar) { /* already done for polar */
			   strcpy (dummy_var[0], "t");
			   strcpy (dummy_var[1], "y");
			   if (interactive)
			     (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
			}
	    }
	    c_token++;
	}
	else if (almost_equals(c_token,"nopar$ametric")) {
		if (parametric) {
		   parametric = FALSE;
		   if (!polar) { /* keep t for polar */
			   strcpy (dummy_var[0], "x");
			   strcpy (dummy_var[1], "y");
			   if (interactive)
			     (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
			}
	    }
	    c_token++;
	}
	else if (almost_equals(c_token, "poi$ntsize")) {
		struct value a;
		c_token++;
		if (END_OF_COMMAND)
		    pointsize = 1.0;
		else
		    pointsize = real(const_express(&a));
		if(pointsize<=0) pointsize=1;
		if (term_init && term->set_pointsize)
			(*term->set_pointsize)(pointsize);
	}
	else if (almost_equals(c_token,"pol$ar")) {
	    if (!polar) {
			if (!parametric) {
				if (interactive)
					(void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
				strcpy (dummy_var[0], "t");
			}
			polar = TRUE;
			if (autoscale_t) {
				/* only if user has not set a range manually */
				tmin = 0.0;
				tmax = 2*Pi / ang2rad;  /* 360 if degrees, 2pi if radians */
			}
	    }
	    c_token++;
	}
	else if (almost_equals(c_token,"nopo$lar")) {
	    if (polar) {
			polar = FALSE;
			if (parametric && autoscale_t) {
				/* only if user has not set an explicit range */
				tmin = -5.0;
				tmax = 5.0;
			}
			if (!parametric) {
				strcpy (dummy_var[0], "x");
				if (interactive)
					(void) fprintf(stderr,"\n\tdummy variable is x for curves\n");
			}
		

	    }
	    c_token++;
	}
	else if (almost_equals(c_token,"an$gles")) {
	    c_token++;
	    if (END_OF_COMMAND) {
		/* assuming same as defaults */
		angles_format = ANGLES_RADIANS;
		ang2rad=1;
	    }
	    else if (almost_equals(c_token, "r$adians")) {
		angles_format = ANGLES_RADIANS;
		c_token++;
		ang2rad=1;
	    }
	    else if (almost_equals(c_token, "d$egrees")) {
		angles_format = ANGLES_DEGREES;
		c_token++;
		ang2rad=DEG2RAD;
	    }
	    else
		 int_error("expecting 'radians' or 'degrees'", c_token);

	    if (polar && autoscale_t) {
		/* set trange if in polar mode and no explicit range */
		tmin=0;
		tmax=2*Pi/ang2rad;
	    }
	}

#define GRID_MATCH(string, neg, mask) \
if (almost_equals(c_token, string)) { grid |= mask; ++c_token; } \
else if (almost_equals(c_token, neg)) { grid &= ~(mask); ++c_token; }

	else if (almost_equals(c_token,"g$rid")) {
                c_token++;
		if (END_OF_COMMAND && !grid)
			grid = GRID_X|GRID_Y;
                else while (!END_OF_COMMAND){
			GRID_MATCH("x$tics", "nox$tics", GRID_X)
			else GRID_MATCH("y$tics", "noy$tics", GRID_Y)
			else GRID_MATCH("z$tics", "noz$tics", GRID_Z)
			else GRID_MATCH("x2$tics", "nox2$tics", GRID_X2)
			else GRID_MATCH("y2$tics", "noy2$tics", GRID_Y2)
			else GRID_MATCH("mx$tics", "nomx$tics", GRID_MX)
			else GRID_MATCH("my$tics", "nomy$tics", GRID_MY)
			else GRID_MATCH("mz$tics", "nomz$tics", GRID_MZ)
			else GRID_MATCH("mx2$tics", "nomx2$tics", GRID_MX2)
			else GRID_MATCH("my2$tics", "nomy2$tics", GRID_MY2)
			else if (almost_equals(c_token,"po$lar")){
				if (!grid) grid=GRID_X;
                                c_token++;
                                if (END_OF_COMMAND) {
                                	polar_grid_angle=30*DEG2RAD;
                                } else {
					/* get radial interval */
                                	struct value a;
                                	polar_grid_angle=ang2rad*real(const_express(&a));
                                }
			} else if (almost_equals(c_token,"nopo$lar")){
                                polar_grid_angle=0; /* not polar grid */
                                c_token++;
			} else break; /* might be a linetype */
		}
		if (!END_OF_COMMAND) {
			struct value a;
			grid_linetype=real(const_express(&a))-1;
			if (!grid) grid = GRID_X|GRID_Y;
				/* probably just  set grid <linetype> */

			if (END_OF_COMMAND) {
				mgrid_linetype=grid_linetype;
			} else {
				mgrid_linetype=real(const_express(&a))-1;
			}

			if (!grid) grid = GRID_X|GRID_Y;
				/* probably just  set grid <linetype> */
		}

		
        }
	else if (almost_equals(c_token,"nog$rid")) {
		grid = GRID_OFF;
		c_token++;
	}
	else if (almost_equals(c_token,"su$rface")) {
		draw_surface = TRUE;
		c_token++;
	}
	else if (almost_equals(c_token,"nosu$rface")) {
		draw_surface = FALSE;
		c_token++;
	}
	else if (almost_equals(c_token,"bor$der")) {
		struct value a;
		c_token++;
		if(END_OF_COMMAND){
			draw_border = 31;
		} else {
			draw_border = (int)real(const_express(&a));
		}
	}
	else if (almost_equals(c_token,"k$ey")) {
		struct value a;
		c_token++;
		if (END_OF_COMMAND) {
			key = -1;
			key_vpos = TTOP;
			key_hpos = TRIGHT;
			key_just = JRIGHT;
		} 
		else {
			enum position_type default_scale=first_axes;
			while (!END_OF_COMMAND) {
				if (almost_equals(c_token,"t$op")) {
					key_vpos = TTOP;
					key = -1;
				} else if (almost_equals(c_token,"b$ottom")) {
					key_vpos = TBOTTOM;
					key = -1;
				} else if (almost_equals(c_token,"l$eft")) {
					key_hpos = TLEFT;
					/* key_just = TRIGHT; */
					key = -1;
				} else if (almost_equals(c_token,"r$ight")) {
					key_hpos = TRIGHT;
					key = -1;
				} else if (almost_equals(c_token,"u$nder") ||
				    almost_equals(c_token,"be$low")) {
					key_vpos = TUNDER;
					if (key_hpos == TOUT) key_hpos--;
					key = -1;
				} else if (almost_equals(c_token,"o$utside")) {
					key_hpos = TOUT;
					if (key_vpos == TUNDER) key_vpos--;
					key = -1;
				} else if (almost_equals(c_token,"L$eft")) {
					/* key_hpos = TLEFT; */
					key_just = JLEFT;
					/* key = -1; */
				} else if (almost_equals(c_token,"R$ight")) {
					/* key_hpos = TLEFT; */
					key_just = JRIGHT;
					/* key = -1; */
				} else if (almost_equals(c_token,"rev$erse")) {
					key_reverse=TRUE;
				} else if (almost_equals(c_token,"norev$erse")) {
					key_reverse=FALSE;
				} else if (almost_equals(c_token,"b$ox")) {
					++c_token;
					if (END_OF_COMMAND)
						key_box=-2;
					else
						key_box=real(const_express(&a))-1;
					--c_token;  /* is incremented after loop */
				} else if (almost_equals(c_token,"nob$ox")) {
					key_box=-3;
				} else if (almost_equals(c_token,"ti$tle")) {
					if (isstring(c_token+1)) {
						/* We have string specified - grab it. */
						quote_str(key_title,++c_token, MAX_LINE_LEN);
					}
					else
						key_title[0]=0;
				} else {
					default_scale = get_position(&key_user_pos, default_scale);
					key = 1;
					--c_token;  /* will be incremented again soon */
				} 
				c_token++;
 			} 
		}
	}
	else if (almost_equals(c_token,"nok$ey")) {
		key = 0;
		c_token++;
	}
	else if (almost_equals(c_token,"tic$s")) {
		tic_in = TRUE;
		c_token++;
		if (almost_equals(c_token,"i$n")) {
			tic_in = TRUE;
			c_token++;
		}
		else if (almost_equals(c_token,"o$ut")) {
			tic_in = FALSE;
			c_token++;
		}
	}
     else if (almost_equals(c_token,"xda$ta")) {
	 c_token++;
	 if(END_OF_COMMAND) {
		datatype[FIRST_X_AXIS] = FALSE;
		/* eh ? - t and u have nothing to do with x */
		datatype[T_AXIS] = FALSE;
		datatype[U_AXIS] = FALSE;
	 } else {
		if (almost_equals(c_token,"t$ime")) {
			datatype[FIRST_X_AXIS] = TIME;
			datatype[T_AXIS] = TIME;
			datatype[U_AXIS] = TIME;
		} else {
			datatype[FIRST_X_AXIS] = FALSE;
			datatype[T_AXIS] = FALSE;
			datatype[U_AXIS] = FALSE;
		}
		c_token++;
	 }
     }
     else if (almost_equals(c_token,"yda$ta")) {
	 c_token++;
	 if(END_OF_COMMAND) {
		datatype[FIRST_Y_AXIS] = FALSE;
		datatype[V_AXIS] = FALSE;
	 } else {
		if (almost_equals(c_token,"t$ime")) {
			datatype[FIRST_Y_AXIS] = TIME;
			datatype[V_AXIS] = TIME;
		} else {
			datatype[FIRST_Y_AXIS] = FALSE;
			datatype[V_AXIS] = FALSE;
		}
		c_token++;
	 }
     }
     else if (almost_equals(c_token,"zda$ta")) {
	 c_token++;
	 if(END_OF_COMMAND) {
		datatype[FIRST_Z_AXIS] = FALSE;
	 } else {
		if (almost_equals(c_token,"t$ime")) {
			datatype[FIRST_Z_AXIS] = TIME;
		} else {
			datatype[FIRST_Z_AXIS] = FALSE;
		}
		c_token++;
	 }
     }
     else if (almost_equals(c_token,"x2da$ta")) {
	 c_token++;
	 if(END_OF_COMMAND) {
		datatype[SECOND_X_AXIS] = FALSE;
	 } else {
		if (almost_equals(c_token,"t$ime")) {
			datatype[SECOND_X_AXIS] = TIME;
		} else {
			datatype[SECOND_X_AXIS] = FALSE;
		}
		c_token++;
	 }
     }
     else if (almost_equals(c_token,"y2da$ta")) {
	 c_token++;
	 if(END_OF_COMMAND) {
		datatype[SECOND_Y_AXIS] = FALSE;
	 } else {
		if (almost_equals(c_token,"t$ime")) {
			datatype[SECOND_Y_AXIS] = TIME;
		} else {
			datatype[SECOND_Y_AXIS] = FALSE;
		}
		c_token++;
	 }
     }

/* to save duplicating code for x/y/z/x2/y2, make a macro
 * (should perhaps be a function ?)
 * unfortunately, string concatenation is not supported on all compilers :-(
 */

#define PROCESS_TIC_COMMANDS(TICS, MTICS, FREQ, TICDEF, AXIS, STRING, NOSTRING, MONTH, DAY, MINISTRING, NOMINI) \
else if (almost_equals(c_token, STRING)) { \
 if (almost_equals(++c_token, "ax$is")) {\
  TICS &= ~TICS_ON_BORDER; TICS |= TICS_ON_AXIS; ++c_token;\
   /* set tics to border if border specified or they were off, else leave (maybe axis) */\
 } else if ( (almost_equals(c_token, "bo$rder") && ++c_token) || !TICS) { \
  TICS &= ~TICS_ON_AXIS; TICS |= TICS_ON_BORDER;\
 }\
 if (almost_equals(c_token, "mi$rror")) {\
  TICS |= TICS_MIRROR; ++c_token; \
 } else if (almost_equals(c_token, "nomi$rror")) {\
  TICS &= ~TICS_MIRROR; ++c_token; \
 }\
 if (END_OF_COMMAND) { /* reset to default */\
  if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  TICDEF.type = TIC_COMPUTED;\
 } else load_tics(AXIS,&TICDEF);\
} else if (almost_equals(c_token,NOSTRING)) {\
 TICS = NO_TICS; c_token++;\
} else if (almost_equals(c_token,MONTH)) {\
  if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  TICDEF.type = TIC_MONTH; ++c_token;\
} else if (almost_equals(c_token,DAY)) {\
  if (TICDEF.type == TIC_USER) { free_marklist(TICDEF.def.user); TICDEF.def.user = NULL; }\
  TICDEF.type = TIC_DAY; ++c_token; \
} else if (almost_equals(c_token,MINISTRING)) { /* eg mxtics */\
 struct value freq;\
 c_token++; \
 if (END_OF_COMMAND) { MTICS=MINI_AUTO; }\
 else if (almost_equals(c_token, "def$ault")) {\
  MTICS=MINI_DEFAULT; ++c_token; \
 } else { \
  FREQ=real(const_express(&freq)); FREQ=floor(FREQ);\
  MTICS=MINI_USER; \
}} else if (almost_equals(c_token,NOMINI)) {\
  MTICS = FALSE;  c_token++;\
}


PROCESS_TIC_COMMANDS(x2tics,mx2tics,mx2tfreq,x2ticdef,SECOND_X_AXIS,"x2t$ics","nox2t$ics","x2m$tics","x2d$tics","mx2t$ics","nomx2t$ics")
PROCESS_TIC_COMMANDS(y2tics,my2tics,my2tfreq,y2ticdef,SECOND_Y_AXIS,"y2t$ics","noy2t$ics","y2m$tics","y2d$tics","my2t$ics","nomy2t$ics" )
PROCESS_TIC_COMMANDS(xtics, mxtics, mxtfreq, xticdef, FIRST_X_AXIS,"xt$ics","noxt$ics","xm$tics","xd$tics","mxt$ics","nomxt$ics")
PROCESS_TIC_COMMANDS(ytics, mytics, mytfreq, yticdef, FIRST_Y_AXIS,"yt$ics","noyt$ics","ym$tics","yd$tics","myt$ics","nomyt$ics")
PROCESS_TIC_COMMANDS(ztics, mztics, mztfreq, zticdef, FIRST_Z_AXIS,"zt$ics","nozt$ics","zm$tics","zd$tics","mzt$ics","nomzt$ics")

    else if (almost_equals(c_token,"ticsl$evel")) {
		double tlvl;
		struct value a;

		c_token++;
		/* is datatype 'time' relevant here ? */
		tlvl = real(const_express(&a));
		ticslevel = tlvl;
    }

#define PROCESS_MARGIN(variable, string) \
else if (almost_equals(c_token,string)) {\
 ++c_token; if (END_OF_COMMAND) variable=-1;\
 else { struct value a; variable=real(const_express(&a)); } \
}

	PROCESS_MARGIN(lmargin, "lmar$gin")
	PROCESS_MARGIN(bmargin, "bmar$gin")
	PROCESS_MARGIN(rmargin, "rmar$gin")
	PROCESS_MARGIN(tmargin, "tmar$gin")

    else
	return(FALSE);	/* no command match */

    return(TRUE);
}
 


/* return TRUE if a command match, FALSE if not */
static TBOOLEAN
set_three()
{
     if (almost_equals(c_token,"sa$mples")) {
		register int tsamp1, tsamp2;
		struct value a;

		c_token++;
		tsamp1 = (int)magnitude(const_express(&a));
		tsamp2 = tsamp1;
		if (!END_OF_COMMAND) {
			if (!equals(c_token,","))
				int_error("',' expected",c_token);
			c_token++;
			tsamp2 = (int)magnitude(const_express(&a));
		}
		if (tsamp1 < 2 || tsamp2 < 2)
			int_error("sampling rate must be > 1; sampling unchanged",
				c_token);
		else {
		        extern struct surface_points *first_3dplot;
			register struct surface_points *f_3dp = first_3dplot;

			first_3dplot = NULL;
			sp_free(f_3dp);

			samples = tsamp1;
			samples_1 = tsamp1;
			samples_2 = tsamp2;
		}
    }
    else if (almost_equals(c_token,"isosa$mples")) {
		register int tsamp1, tsamp2;
		struct value a;

		c_token++;
		tsamp1 = (int)magnitude(const_express(&a));
		tsamp2 = tsamp1;
		if (!END_OF_COMMAND) {
			if (!equals(c_token,","))
				int_error("',' expected",c_token);
			c_token++;
			tsamp2 = (int)magnitude(const_express(&a));
		}
		if (tsamp1 < 2 || tsamp2 < 2)
			int_error("sampling rate must be > 1; sampling unchanged",
				c_token);
		else {
		        extern struct curve_points *first_plot;
		        extern struct surface_points *first_3dplot;
			register struct curve_points *f_p = first_plot;
			register struct surface_points *f_3dp = first_3dplot;

			first_plot = NULL;
			first_3dplot = NULL;
			cp_free(f_p);
			sp_free(f_3dp);

			iso_samples_1 = tsamp1;
			iso_samples_2 = tsamp2;
		}
    }
    else if (almost_equals(c_token,"si$ze")) {
		struct value s;
		c_token++;
		if (END_OF_COMMAND) {
			xsize = 1.0;
			ysize = 1.0;
		} else {
				if (almost_equals(c_token, "sq$uare")) {
					square=TRUE;
					++c_token;
				} else if (almost_equals(c_token,"nosq$uare")) {
					square=FALSE;
					++c_token;
				}
				if (!END_OF_COMMAND) {
					xsize=real(const_express(&s));
					if (equals(c_token,",")) {
						c_token++;
						ysize=real(const_express(&s));
					} else {
						ysize=xsize;
					}
				}
			}
		} 
      else if (almost_equals(c_token,"ticsc$ale")) {
                struct value tscl;
                c_token++;
                if (END_OF_COMMAND) {
                        ticscale = 1.0;
			miniticscale = 0.5;
                } else {
                        ticscale=real(const_express(&tscl));
			if (END_OF_COMMAND) {
				miniticscale=ticscale*0.5;
			} else {
				miniticscale=real(const_express(&tscl));
			}
                }
        }
	else if (almost_equals(c_token,"t$erminal")) {
	 if (multiplot) {
 	    fprintf(stderr,"You can't change the terminal in multiplotmode\n");
 	    c_token++;
 	  } else {
		c_token++;
		if (END_OF_COMMAND) {
			list_terms();
			screen_ok = FALSE;
		}
		else {
			if (term && term_init) {
				(*term->reset)();
				(void) fflush(outfile);
				term=0; term_init=0; /* in case set_term() fails */
			}
			term = set_term(c_token);
			c_token++;

			/* get optional mode parameters */
			if (term)
				(*term->options)();
			if (interactive && *term_options)
				fprintf(stderr,"Options are '%s'\n",term_options);
		}
	}
	}
	else if (almost_equals(c_token,"tim$estamp")) {
		c_token++;
		if (END_OF_COMMAND || !isstring(c_token))
			strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);

		if (!END_OF_COMMAND) {
			struct value a;

			if (isstring(c_token)) {
				/* we have a format string */
				quote_str(timelabel.text, c_token, MAX_LINE_LEN);
				++c_token;
			} else {
				strcpy(timelabel.text, DEFAULT_TIMESTAMP_FORMAT);
			}
			/* We have x,y offsets specified */
			if (!END_OF_COMMAND && !equals(c_token,","))
			    timelabel.xoffset = real(const_express(&a));
			if (!END_OF_COMMAND && equals(c_token,",")) {
				c_token++;
				timelabel.yoffset = real(const_express(&a));
			}
			if (!END_OF_COMMAND && isstring(c_token)) {
				quote_str(timelabel.font, c_token, MAX_LINE_LEN);
				++c_token;
			} else {
				*timelabel.font = 0;
			}
		}
	}
	else if (almost_equals(c_token,"not$ime")) {
		*timelabel.text = 0;
		c_token++;
	}
	else if (almost_equals(c_token,"vi$ew")) {
		int i;
		TBOOLEAN was_comma = TRUE;
		double local_vals[4];
		struct value a;

		local_vals[0] = surface_rot_x;
		local_vals[1] = surface_rot_z;
		local_vals[2] = surface_scale;
		local_vals[3] = surface_zscale;
		c_token++;
		for (i = 0; i < 4 && !(END_OF_COMMAND);) {
			if (equals(c_token,",")) {
				if (was_comma) i++;
				was_comma = TRUE;
				c_token++;
			}
			else {
				if (!was_comma)
					int_error("',' expected",c_token);
				local_vals[i] = real(const_express(&a));
				i++;
				was_comma = FALSE;
			}
		}

		if (local_vals[0] < 0 || local_vals[0] > 180)
			int_error("rot_x must be in [0:180] degrees range; view unchanged",
				  c_token);
		if (local_vals[1] < 0 || local_vals[1] > 360)
			int_error("rot_z must be in [0:360] degrees range; view unchanged",
				  c_token);
		if (local_vals[2] < 1e-6)
			int_error("scale must be > 0; view unchanged", c_token);
		if (local_vals[3] < 1e-6)
			int_error("zscale must be > 0; view unchanged", c_token);

		surface_rot_x = local_vals[0];
		surface_rot_z = local_vals[1];
		surface_scale = local_vals[2];
		surface_zscale = local_vals[3];
	}

/* to save replicated code, define a macro */
#define PROCESS_RANGE(AXIS,STRING, MIN, MAX, AUTO) \
else if (almost_equals(c_token, STRING)) { \
 if (!equals(++c_token,"[")) int_error("expecting '['",c_token); \
 c_token++; \
 AUTO = load_range(AXIS,&MIN,&MAX,AUTO); \
 if (!equals(c_token,"]")) int_error("expecting ']'",c_token); \
 c_token++; \
 if (almost_equals(c_token, "rev$erse")) { \
   ++c_token; range_flags[AXIS] |= RANGE_REVERSE;\
 } else if (almost_equals(c_token, "norev$erse")) { \
   ++c_token; range_flags[AXIS] &= ~RANGE_REVERSE;\
 } if (almost_equals(c_token, "wr$iteback")) { \
   ++c_token; range_flags[AXIS] |= RANGE_WRITEBACK;\
 } else if (almost_equals(c_token, "nowri$teback")) { \
   ++c_token; range_flags[AXIS] &= ~RANGE_WRITEBACK;\
}}
	PROCESS_RANGE(R_AXIS, "rr$ange", rmin, rmax, autoscale_r)
	PROCESS_RANGE(T_AXIS, "tr$ange", tmin, tmax, autoscale_t)
	PROCESS_RANGE(U_AXIS, "ur$ange", umin, umax, autoscale_u)
	PROCESS_RANGE(V_AXIS, "vr$ange", vmin, vmax, autoscale_v)
	PROCESS_RANGE(FIRST_X_AXIS, "xr$ange", xmin, xmax, autoscale_x)
	PROCESS_RANGE(FIRST_Y_AXIS, "yr$ange", ymin, ymax, autoscale_y)
	PROCESS_RANGE(FIRST_Z_AXIS, "zr$ange", zmin, zmax, autoscale_z)
	PROCESS_RANGE(SECOND_X_AXIS, "x2r$ange", x2min, x2max, autoscale_x2)
	PROCESS_RANGE(SECOND_Y_AXIS, "y2r$ange", y2min, y2max, autoscale_y2)

	else if (almost_equals(c_token,"z$ero")) {
		struct value a;
		c_token++;
		zero = magnitude(const_express(&a));
	}
	else if (almost_equals(c_token,"multi$plot")) {
	  if (multiplot && term_graphics) {
	    (*term->text)();
	    term_graphics = FALSE;
	    (void) fflush(outfile);
	  } else {	    
	    multiplot = TRUE;
	    if (!term_init) {
	      (*term->init)();
	      term_init = TRUE;
	    }
	    (*term->graphics)();
	    term_graphics=TRUE;
	  }
	  c_token++;
	}
	else if (almost_equals(c_token,"nomulti$plot")) {
	  if (term_graphics) {
	  	 if (term_suspended && term->resume)
	  	 	(*term->resume)();
	  	 term_suspended = FALSE;
	    (*term->text)();
	    (void) fflush(outfile);
	    term_graphics=FALSE;
	  }
	    multiplot = FALSE;
	    c_token++;
	}
	else
		return(FALSE);	/* no command match */
	return(TRUE);
}

/*********** Support functions for set_command ***********/

/* process a 'set {x/y/z}label command */
/* set {x/y/z}label {label_text} {x}{,y} */
static void set_xyzlabel(label)
label_struct *label;
{
	c_token++;
	if (END_OF_COMMAND) {	/* no label specified */
		*label->text = '\0';
		return;
	}
	
	if (isstring(c_token)) {
		/* We have string specified - grab it. */
		quote_str(label->text,c_token, MAX_LINE_LEN);
		c_token++;
	}

	if (END_OF_COMMAND)
		return;

	if (!isstring(c_token)) {
		/* We have x,y offsets specified */
		struct value a;
		if (!equals(c_token,","))
		    label->xoffset = real(const_express(&a));

		if (END_OF_COMMAND)
			return;

		if (equals(c_token,",")) {
				c_token++;
				label->yoffset = real(const_express(&a));
		}
	}

	if (END_OF_COMMAND)
		return;

	if (!isstring(c_token))
		int_error("Expected font", c_token);

	quote_str(label->font,c_token, MAX_LINE_LEN);
	c_token++;
}

/* process a 'set label' command */
/* set label {tag} {label_text} {at x,y} {pos} {font name,size} */
/* Entry font added by DJL */
static void
set_label()
{
    struct value a;
    struct text_label *this_label = NULL;
    struct text_label *new_label = NULL;
    struct text_label *prev_label = NULL;
    struct position pos;
    char text[MAX_LINE_LEN+1],font[MAX_LINE_LEN+1];
    enum JUSTIFY just=LEFT;
    int tag;
    TBOOLEAN set_text, set_position, set_just=FALSE, set_font;

    /* get tag */
    if (!END_OF_COMMAND 
	   && !isstring(c_token) 
	   && !equals(c_token, "at")
	   && !equals(c_token, "left")
	   && !equals(c_token, "center")
	   && !equals(c_token, "centre")
	   && !equals(c_token, "right")
	   && !equals(c_token, "font")) {
	   /* must be a tag expression! */
	   tag = (int)real(const_express(&a));
	   if (tag <= 0)
		int_error("tag must be > zero", c_token);
    } else
	 tag = assign_label_tag(); /* default next tag */
	 
    /* get text */
    if (!END_OF_COMMAND && isstring(c_token)) {
	   /* get text */
	   quote_str(text, c_token, MAX_LINE_LEN);
	   c_token++;
	   set_text = TRUE;
    } else {
	   text[0] = '\0';		/* default no text */
	   set_text = FALSE;
    }
	 
    /* get justification - what the heck, let him put it here */
    if (!END_OF_COMMAND && !equals(c_token, "at") && !equals(c_token, "font")) {
	   if (almost_equals(c_token,"l$eft")) {
		  just = LEFT;
	   }
	   else if (almost_equals(c_token,"c$entre")
			  || almost_equals(c_token,"c$enter")) {
		  just = CENTRE;
	   }
	   else if (almost_equals(c_token,"r$ight")) {
		  just = RIGHT;
	   }
	   else
		int_error("bad syntax in set label", c_token);
	   c_token++;
	   set_just = TRUE;
    }

    /* get position */
    if (!END_OF_COMMAND && equals(c_token, "at")) {
	   c_token++;

		get_position(&pos, first_axes);
	   set_position = TRUE;
    } else {
		pos.x = pos.y = pos.z = 0;
		pos.scalex=pos.scaley=pos.scalez=first_axes;
	   set_position = FALSE;
    }

    /* get justification */
    if (!END_OF_COMMAND && !equals(c_token, "font")) {
	   if (set_just)
		int_error("only one justification is allowed", c_token);
	   if (almost_equals(c_token,"l$eft")) {
		  just = LEFT;
	   }
	   else if (almost_equals(c_token,"c$entre")
			  || almost_equals(c_token,"c$enter")) {
		  just = CENTRE;
	   }
	   else if (almost_equals(c_token,"r$ight")) {
		  just = RIGHT;
	   }
	   else
		int_error("bad syntax in set label", c_token);
	   c_token++;
	   set_just = TRUE;
    } 

    /* get font */
    font[0]='\0'; set_font = FALSE;
    if (!END_OF_COMMAND && equals(c_token, "font")) {
	   c_token++;
	   if (END_OF_COMMAND)
		int_error("font name and size expected", c_token);
           if (isstring(c_token)) {
	        quote_str(font, c_token, MAX_ID_LEN);
                /* get 'name,size', no further check */
                set_font = TRUE;
           }
	   else
		int_error("'fontname,fontsize' expected", c_token);
           c_token++;
    } /* Entry font added by DJL */

    if (!END_OF_COMMAND)
	 int_error("extraenous or out-of-order arguments in set label", c_token);

    /* OK! add label */
    if (first_label != NULL) { /* skip to last label */
	   for (this_label = first_label; this_label != NULL ; 
		   prev_label = this_label, this_label = this_label->next)
		/* is this the label we want? */
		if (tag <= this_label->tag)
		  break;
    }
    if (this_label != NULL && tag == this_label->tag) {
	   /* changing the label */
	   if (set_position) {
		  this_label->place=pos;
	   }
	   if (set_text)
		(void) strcpy(this_label->text, text);
	   if (set_just)
		this_label->pos = just;
	   if (set_font)
                (void) strcpy(this_label->font, font);
    } else {
	   /* adding the label */
	   new_label = (struct text_label *) 
		alloc ( (unsigned long) sizeof(struct text_label), "label");
	   if (prev_label != NULL)
		prev_label->next = new_label; /* add it to end of list */
	   else 
		first_label = new_label; /* make it start of list */
	   new_label->tag = tag;
	   new_label->next = this_label;
	   new_label->place=pos;
	   (void) strcpy(new_label->text, text);
	   new_label->pos = just;
           (void) strcpy(new_label->font, font);
    }
} /* Entry font added by DJL */

/* process 'set nolabel' command */
/* set nolabel {tag} */
static void
set_nolabel()
{
    struct value a;
    struct text_label *this_label;
    struct text_label *prev_label; 
    int tag;

    if (END_OF_COMMAND) {
	   /* delete all labels */
	   while (first_label != NULL)
		delete_label((struct text_label *)NULL,first_label);
    }
    else {
	   /* get tag */
	   tag = (int)real(const_express(&a));
	   if (!END_OF_COMMAND)
		int_error("extraneous arguments to set nolabel", c_token);
	   for (this_label = first_label, prev_label = NULL;
		   this_label != NULL;
		   prev_label = this_label, this_label = this_label->next) {
		  if (this_label->tag == tag) {
			 delete_label(prev_label,this_label);
			 return;		/* exit, our job is done */
		  }
	   }
	   int_error("label not found", c_token);
    }
}

/* assign a new label tag */
/* labels are kept sorted by tag number, so this is easy */
static int				/* the lowest unassigned tag number */
assign_label_tag()
{
    struct text_label *this_label;
    int last = 0;			/* previous tag value */

    for (this_label = first_label; this_label != NULL;
	    this_label = this_label->next)
	 if (this_label->tag == last+1)
	   last++;
	 else
	   break;
    
    return (last+1);
}

/* delete label from linked list started by first_label.
 * called with pointers to the previous label (prev) and the 
 * label to delete (this).
 * If there is no previous label (the label to delete is
 * first_label) then call with prev = NULL.
 */
static void
delete_label(prev,this)
	struct text_label *prev, *this;
{
    if (this!=NULL)	{		/* there really is something to delete */
	   if (prev!=NULL)		/* there is a previous label */
		prev->next = this->next; 
	   else				/* this = first_label so change first_label */
		first_label = this->next;
	   free((char *)this);
    }
}


/* process a 'set arrow' command */
/* set arrow {tag} {from x,y} {to x,y} {{no}head} */
static void
set_arrow()
{
    struct value a;
    struct arrow_def *this_arrow = NULL;
    struct arrow_def *new_arrow = NULL;
    struct arrow_def *prev_arrow = NULL;
    struct position spos, epos;
    int axes=FIRST_AXES;
    int linetype=1;
    int tag;
    TBOOLEAN set_start, set_end, head = 1, set_axes=0, set_line=0;
    enum position_type pos_type=first_axes;

    /* get tag */
    if (!END_OF_COMMAND 
	   && !equals(c_token, "from")
	   && !equals(c_token, "to")
	   && !equals(c_token, "first")
	   && !equals(c_token, "second")) {
	   /* must be a tag expression! */
	   tag = (int)real(const_express(&a));
	   if (tag <= 0)
		int_error("tag must be > zero", c_token);
    } else
	 tag = assign_arrow_tag(); /* default next tag */

	if (!END_OF_COMMAND && equals(c_token, "first")) {
		++c_token;
		axes=FIRST_AXES;
		set_axes=1;
	} else if (!END_OF_COMMAND && equals(c_token, "second")) {
		++c_token;
		axes=SECOND_AXES;
		set_axes=1;
	}
    /* get start position */
    if (!END_OF_COMMAND && equals(c_token, "from")) {
	   c_token++;
	   if (END_OF_COMMAND)
		int_error("start coordinates expected", c_token);
	   /* get coordinates */
		pos_type=get_position(&spos, pos_type);
	   set_start = TRUE;
    } else {
		spos.x=spos.y=spos.z=0;
		spos.scalex=spos.scaley=spos.scalez=first_axes;
	   set_start = FALSE;
    }

    /* get end position */
    if (!END_OF_COMMAND && equals(c_token, "to")) {
	   c_token++;
	   if (END_OF_COMMAND)
		int_error("end coordinates expected", c_token);
	   /* get coordinates */
		pos_type=get_position(&epos, pos_type);
	   set_end = TRUE;
    } else {
    	epos.x=epos.y=epos.z=0;
    	epos.scalex=epos.scaley=epos.scalez=first_axes;
	   set_end = FALSE;
    }

    /* get start position - what the heck, either order is ok */
    if (!END_OF_COMMAND && equals(c_token, "from")) {
	   if (set_start)
		int_error("only one 'from' is allowed", c_token);
	   c_token++;
	   if (END_OF_COMMAND)
		int_error("start coordinates expected", c_token);
	   /* get coordinates */
		pos_type=get_position(&spos,pos_type);
	   set_start = TRUE;
    }

    if (!END_OF_COMMAND && equals(c_token, "nohead")) {
	   c_token++;
           head = 0;
    }

    if (!END_OF_COMMAND && equals(c_token, "head")) {
	   c_token++;
           head = 1;
    }

    if (!END_OF_COMMAND) {
    	struct value a;
    	linetype=real(const_express(&a));
    	set_line=1;
    }
    
    if (!END_OF_COMMAND)
	 int_error("extraneous or out-of-order arguments in set arrow", c_token);

    /* OK! add arrow */
    if (first_arrow != NULL) { /* skip to last arrow */
	   for (this_arrow = first_arrow; this_arrow != NULL ; 
		   prev_arrow = this_arrow, this_arrow = this_arrow->next)
		/* is this the arrow we want? */
		if (tag <= this_arrow->tag)
		  break;
    }
    if (this_arrow != NULL && tag == this_arrow->tag) {
	   /* changing the arrow */
	   if (set_start) {
		  this_arrow->start=spos;
	   }
	   if (set_end) {
		  this_arrow->end=epos;
	   }
	   this_arrow->head = head;
	   if (set_line) this_arrow->line=linetype;
    } else {
	   /* adding the arrow */
	   new_arrow = (struct arrow_def *) 
		alloc ( (unsigned long) sizeof(struct arrow_def), "arrow");
	   if (prev_arrow != NULL)
		prev_arrow->next = new_arrow; /* add it to end of list */
	   else 
		first_arrow = new_arrow; /* make it start of list */
	   new_arrow->tag = tag;
	   new_arrow->next = this_arrow;
	   new_arrow->start=spos;
	   new_arrow->end=epos;
	   new_arrow->head = head;
	   new_arrow->line=linetype;
    }
}

/* process 'set noarrow' command */
/* set noarrow {tag} */
static void
set_noarrow()
{
    struct value a;
    struct arrow_def *this_arrow;
    struct arrow_def *prev_arrow; 
    int tag;

    if (END_OF_COMMAND) {
	   /* delete all arrows */
	   while (first_arrow != NULL)
		delete_arrow((struct arrow_def *)NULL,first_arrow);
    }
    else {
	   /* get tag */
	   tag = (int)real(const_express(&a));
	   if (!END_OF_COMMAND)
		int_error("extraneous arguments to set noarrow", c_token);
	   for (this_arrow = first_arrow, prev_arrow = NULL;
		   this_arrow != NULL;
		   prev_arrow = this_arrow, this_arrow = this_arrow->next) {
		  if (this_arrow->tag == tag) {
			 delete_arrow(prev_arrow,this_arrow);
			 return;		/* exit, our job is done */
		  }
	   }
	   int_error("arrow not found", c_token);
    }
}

/* assign a new arrow tag */
/* arrows are kept sorted by tag number, so this is easy */
static int				/* the lowest unassigned tag number */
assign_arrow_tag()
{
    struct arrow_def *this_arrow;
    int last = 0;			/* previous tag value */

    for (this_arrow = first_arrow; this_arrow != NULL;
	    this_arrow = this_arrow->next)
	 if (this_arrow->tag == last+1)
	   last++;
	 else
	   break;

    return (last+1);
}

/* delete arrow from linked list started by first_arrow.
 * called with pointers to the previous arrow (prev) and the 
 * arrow to delete (this).
 * If there is no previous arrow (the arrow to delete is
 * first_arrow) then call with prev = NULL.
 */
static void
delete_arrow(prev,this)
	struct arrow_def *prev, *this;
{
    if (this!=NULL)	{		/* there really is something to delete */
	   if (prev!=NULL)		/* there is a previous arrow */
		prev->next = this->next; 
	   else				/* this = first_arrow so change first_arrow */
		first_arrow = this->next;
	   free((char *)this);
    }
}


enum PLOT_STYLE			/* not static; used by command.c */
get_style()
{
register enum PLOT_STYLE ps;

	c_token++;
	if (almost_equals(c_token,"l$ines"))
		ps = LINES;
	else if (almost_equals(c_token,"i$mpulses"))
		ps = IMPULSES;
	else if (almost_equals(c_token,"p$oints"))
		ps = POINTSTYLE;
	else if (almost_equals(c_token,"linesp$oints"))
		ps = LINESPOINTS;
	else if (almost_equals(c_token,"d$ots"))
		ps = DOTS;
        else if (almost_equals(c_token,"ye$rrorbars"))
                ps = YERRORBARS;
	else if (almost_equals(c_token,"e$rrorbars"))
                ps = YERRORBARS;
        else if (almost_equals(c_token,"xe$rrorbars"))
                ps = XERRORBARS;
        else if (almost_equals(c_token,"xye$rrorbars"))
                ps = XYERRORBARS;
        else if (almost_equals(c_token,"boxes"))
		ps = BOXES;
	else if (almost_equals(c_token,"boxer$rorbars"))
		ps = BOXERROR;
        else if (almost_equals(c_token,"boxx$yerrorbars"))
                ps = BOXXYERROR;
        else if (almost_equals(c_token,"st$eps"))
		ps = STEPS;
	else if (almost_equals(c_token,"fs$teps"))
		ps = FSTEPS;
else if (almost_equals(c_token,"vec$tor"))
ps = VECTOR;
	else {
		int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses', \n\
        'yerrorbars', 'xerrorbars', 'xyerrorbars', 'steps', 'fsteps', 'boxes', \n\
        'boxerrorbars', 'boxxyerrorbars', 'vector'",c_token);
      return 0; /* keep gcc -Wuninitialised happy */
   }
	c_token++;
	return(ps);
}

/* For set [xy]tics... command*/
#ifdef ANSI_C
static void load_tics(int axis, struct ticdef *tdef)
#else
static void
load_tics(axis,tdef)
	int axis;
	struct ticdef *tdef;	/* change this ticdef */
#endif
{
    if (equals(c_token,"(")) { /* set : TIC_USER */
	   c_token++;
	   load_tic_user(axis,tdef);
    } else {				/* series : TIC_SERIES */
	   load_tic_series(axis,tdef);
    }
}

/* load TIC_USER definition */
/* (tic[,tic]...)
 * where tic is ["string"] value
 * Left paren is already scanned off before entry.
 */
static void
load_tic_user(axis,tdef)
	int axis;
	struct ticdef *tdef;
{
    struct ticmark *list = NULL; /* start of list */
    struct ticmark *last = NULL; /* end of list */
    struct ticmark *tic = NULL; /* new ticmark */
    char temp_string[MAX_LINE_LEN];

    while (!END_OF_COMMAND) {
	   /* parse a new ticmark */
	   tic = (struct ticmark *)alloc((unsigned long)sizeof(struct ticmark), (char *)NULL);
	   if (tic == (struct ticmark *)NULL) {
		  free_marklist(list);
		  int_error("out of memory for tic mark", c_token);
	   }

	   /* has a string with it? */
	   if (isstring(c_token)) {
		  quote_str(temp_string,c_token, MAX_LINE_LEN);
		  tic->label = alloc((unsigned long)strlen(temp_string)+1, "tic label");
		  (void) strcpy(tic->label, temp_string);
		  c_token++;
	   } else
		tic->label = NULL;

	   /* in any case get the value */
		GET_NUM_OR_TIME(tic->position, axis);
	   tic->next = NULL;

	   /* append to list */
	   if (list == NULL)
		last = list = tic;	/* new list */
	   else {				/* append to list */
		  last->next = tic;
		  last = tic;
	   }

	   /* expect "," or ")" here */
	   if (!END_OF_COMMAND && equals(c_token, ","))
		c_token++;		/* loop again */
	   else
		break;			/* hopefully ")" */
    }
    
    if (END_OF_COMMAND || !equals(c_token, ")")) {
	   free_marklist(list);
	   int_error("expecting right parenthesis )", c_token);
    }
    c_token++;
    
    /* successful list */
    if (tdef->type == TIC_USER) {
	   /* remove old list */
		/* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
	   free_marklist(tdef->def.user);
	   tdef->def.user = NULL;
    }
    tdef->type = TIC_USER;
    tdef->def.user = list;
}

static void
free_marklist(list)
	struct ticmark *list;
{
    register struct ticmark *freeable;

    while (list != NULL) {
	   freeable = list;
	   list = list->next;
	   if (freeable->label != NULL)
		free( (char *)freeable->label );
	   free( (char *)freeable );
    }
}

/* load TIC_SERIES definition */
/* [start,]incr[,end] */
static void
load_tic_series(axis,tdef)
	int axis;
	struct ticdef *tdef;
{
  double start, incr, end;
  int incr_token;

  GET_NUM_OR_TIME(start,axis);

  if (!equals(c_token, ",")) {
    	/* only step specified */
    	incr = start;
    	start = -VERYLARGE;
    	end = VERYLARGE;
  } else {

    c_token++;

    incr_token = c_token;
	 GET_NUM_OR_TIME(incr, axis);

    if (END_OF_COMMAND)
	 end = VERYLARGE;
    else {
	   if (!equals(c_token, ","))
		int_error("expecting comma to separate incr,end", c_token);
	   c_token++;
		GET_NUM_OR_TIME(end, axis);
    }
    if (!END_OF_COMMAND)
	 int_error("tic series is defined by [start,]increment[,end]", 
			 c_token);
    
    if (start < end && incr <= 0)
	 int_error("increment must be positive", incr_token);
    if (start > end && incr >= 0)
	 int_error("increment must be negative", incr_token);
    if (start > end) {
	   /* put in order */
		double numtics;
		numtics = floor( (end*(1+SIGNIF) - start)/incr );
		end = start;
		start = end + numtics*incr;
		incr = -incr;
/*
	   double temp = start;
	   start = end;
	   end = temp;
	   incr = -incr;
 */
    }
  }

    if (tdef->type == TIC_USER) {
	   /* remove old list */
		/* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
	   free_marklist(tdef->def.user);
	   tdef->def.user = NULL;
    }
    tdef->type = TIC_SERIES;
    tdef->def.series.start = start;
    tdef->def.series.incr = incr;
    tdef->def.series.end = end;
}

static void
load_offsets (a, b, c, d)
double *a,*b, *c, *d;
{
struct value t;

	*a = real (const_express(&t));  /* loff value */
	if (!equals(c_token,","))
		return;

	c_token++;
	*b = real (const_express(&t));  /* roff value */
	if (!equals(c_token,","))
	    return;

	c_token++;
	*c = real (const_express(&t));  /* toff value */
	if (!equals(c_token,","))
	    return;

	c_token++;
	*d = real (const_express(&t));  /* boff value */
}

TBOOLEAN				/* new value for autosc */
load_range(axis,a,b,autosc)		/* also used by command.c */
int axis;
double *a,*b;
TBOOLEAN autosc;
{
	if (equals(c_token,"]"))
		return(autosc);
	if (END_OF_COMMAND) {
	    int_error("starting range value or ':' or 'to' expected",c_token);
	} else if (!equals(c_token,"to") && !equals(c_token,":"))  {
		if (equals(c_token,"*")) {
			autosc |= 1;
			c_token++;
		} else {
			GET_NUM_OR_TIME(*a, axis);
			autosc &= 2;
		}
	}	
	if (!equals(c_token,"to") && !equals(c_token,":"))
		int_error("':' or keyword 'to' expected",c_token);
	c_token++;
	if (!equals(c_token,"]")) {
		if (equals(c_token,"*")) {
			autosc |= 2;
			c_token++;
		} else {
			GET_NUM_OR_TIME(*b, axis);
			autosc &= 1;
		}
	}
     return(autosc);
}

/* return 1 if format looks like a numeric format
 * ie more than one %{efg}, or %something-else
 */ 

static int looks_like_numeric(format)
char *format;
{
	if (!(format=strchr(format,'%'))) return 0;
	
	while ( ++format, (*format >= '0' && *format <= '9') || *format=='.')
		;

	return ( *format == 'f' || *format == 'g' || *format == 'e' );
}


/* parse a position of the form
 *    [coords] x, [coords] y {,[coords] z}
 * where coords is one of first,second.graph,screen
 * if first or second, we need to take datatype into account
 * mixed co-ordinates are for specialists, but it's not particularly
 * hard to implement...
 */

#define GET_NUMBER_OR_TIME(store,axes,axis) \
do{if (axes>=0 && datatype[axes+axis] == TIME && isstring(c_token) ) { \
    char ss[80]; struct tm tm; \
    quote_str(ss,c_token, 80); ++c_token; \
    if (gstrptime(ss,timefmt,&tm)) store = (double) gtimegm(&tm); \
   } else {\
    struct value value; \
    store = real(const_express(&value));\
  }}while(0)



static void get_position_type(type, axes)
enum position_type *type;
int *axes;
{ 
	if (almost_equals(c_token, "fir$st")) {
		++c_token;
		*type=first_axes;
	} else if (almost_equals(c_token, "sec$ond")) {
		++c_token;
		*type=second_axes;
	} else if (almost_equals(c_token, "gr$aph")) {
		++c_token;
		*type=graph;
	} else if (almost_equals(c_token, "sc$reen")) {
		++c_token;
		*type=screen;
	}

	switch(*type) {
		case first_axes: *axes=FIRST_AXES; return;
		case second_axes: *axes=SECOND_AXES; return;
		default: *axes = (-1); return;
	}
}

static enum position_type get_position(pos,type)
struct position *pos;
enum position_type type;
{
	int axes;

	get_position_type(&type, &axes);
	pos->scalex = type;
	GET_NUMBER_OR_TIME(pos->x, axes, FIRST_X_AXIS);
	if (!equals(c_token++, ","))
		int_error("Expected comma", c_token);

	get_position_type(&type, &axes);
	pos->scaley = type;
	GET_NUMBER_OR_TIME(pos->y, axes, FIRST_Y_AXIS);

	/* z is not really allowed for a screen co-ordinate, but keep it simple ! */
	if (equals(c_token, ",")) {
		++c_token;
		get_position_type(&type, &axes);
		pos->scalez = type;
		GET_NUMBER_OR_TIME(pos->z, axes, FIRST_Z_AXIS);
	}
	else {
		pos->z=0;
		pos->scalez = type; /* same as y */
	}

	return type; /* so co-ordinates can propagate */
}

static void set_locale(lcl)
char *lcl;
{
	int i;

#ifdef HAVE_LOCALE
	if (setlocale(LC_TIME, lcl))
		strcpy(cur_locale, lcl);
	else
		int_error("Locale not available", c_token);

	/* we can do a *lot* better than this ; eg use system functions
	 * where available; create values on first use, etc
	 */
	 
	for (i=0; i<7; ++i)
	{
		struct tm tm;
		tm.tm_wday = i;  /* hope this enough */
		strftime(full_day_names[i], sizeof(full_day_names[i]), "%a", &tm);
		strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%A", &tm);
	}
	for (i=0; i<12; ++i)
	{
		struct tm tm;
		tm.tm_mon = i;  /* hope this enough */
		strftime(full_day_names[i], sizeof(full_day_names[i]), "%b", &tm);
		strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%B", &tm);
	}
#else
	strcpy(cur_locale, lcl);
#endif /* HAVE_LOCALE */
}
