DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T c

⟦ec4385bab⟧ TextFile

    Length: 37266 (0x9192)
    Types: TextFile
    Names: »command.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z« 
        └─⟦036c765ac⟧ 
            └─⟦this⟧ »TeX3.0/TeXcontrib/gnutex/command.c« 

TextFile

/*
 *
 *    G N U P L O T  --  command.c
 *
 *  Copyright (C) 1986 Thomas Williams, Colin Kelley
 *
 *  You may use this code as you wish if credit is given and this message
 *  is retained.
 *
 *  Please e-mail any useful additions to vu-vlsi!plot so they may be
 *  included in later releases.
 *
 *  This file should be edited with 4-column tabs!  (:set ts=4 sw=4 in vi)
 */
/*
 * Modifications for LaTeX and other support by David Kotz, 1988.
 * Department of Computer Science, Duke University, Durham, NC 27706.
 * Mail to dfk@cs.duke.edu.
 */

#include <stdio.h>
#include <math.h>
#include "plot.h"
#include "help.h"

#ifndef STDOUT
#define STDOUT 1
#endif

extern char *malloc();

/*
 * global variables to hold status of 'set' options
 *
 */
BOOLEAN			autoscale_x = TRUE;
BOOLEAN			autoscale_y = TRUE;
BOOLEAN			autoscale_lx = TRUE; /* local to this plot */
BOOLEAN			autoscale_ly = TRUE; /* local to this plot */
enum PLOT_STYLE data_style	= POINTS,
				func_style	= LINES;
BOOLEAN			log_x		= FALSE,
				log_y		= FALSE;
FILE*			outfile;
char			outstr[MAX_ID_LEN+1] = "STDOUT";
int				samples		= SAMPLES;
int				term		= 0;				/* unknown term is 0 */
double			xmin		= -10,
				xmax		= 10,
				ymin		= -10,
				ymax		= 10;
double			zero = ZERO;			/* zero threshold, not 0! */

BOOLEAN xtics = TRUE;
BOOLEAN ytics = TRUE;

BOOLEAN clipping = TRUE;

BOOLEAN screen_ok;
BOOLEAN term_init;
BOOLEAN undefined;

char title_string[MAX_LINE_LEN] = "";
char xlabel_string[MAX_LINE_LEN] = "";
char ylabel_string[MAX_LINE_LEN] = "";
char xformat[MAX_ID_LEN] = "";
char yformat[MAX_ID_LEN] = "";
int y_skip_factor = 0;
double plot_width = 4;		/* width  in inches, for latex */
double plot_height = 3;		/* height in inches, for latex */

/*
 * instead of <strings.h>
 */

char *gets(),*getenv();
char *strcpy(),*strcat();

double magnitude(),angle(),real(),imag();
struct value *const_express(), *pop(), *complex();


extern struct vt_entry vt[];
extern struct st_entry st[];
extern struct udft_entry udft[];
extern struct termentry term_tbl[];
extern int next_style;

char input_line[MAX_LINE_LEN],dummy_var[MAX_ID_LEN + 1];
struct at_type *curr_at;
int c_token;
int next_value = (int)NEXT_VALUE,next_function = 0,c_function = 0;
int num_tokens;

struct curve_points plot[MAX_PLOTS];

static char helpbuf[80];

#ifdef MSDOS
#include <process.h>
#endif /* MSDOS */

#ifdef vms
#include <descrip.h>
#include <rmsdef.h>
#include <errno.h>

extern lib$get_input(), lib$put_output();

int vms_len;

unsigned int status[2] = {1, 0};

$DESCRIPTOR(prompt_desc,PROMPT);
$DESCRIPTOR(line_desc,input_line);
$DESCRIPTOR(null_desc,"");

struct dsc$descriptor_s *cmd_ptr;

#endif

com_line()
{
#ifdef vms

	switch(status[1] = lib$get_input(&line_desc, &prompt_desc, &vms_len)){
		case RMS$_EOF:
			done(IO_SUCCESS);	/* ^Z isn't really an error */
			break;
		case RMS$_TNS:			/* didn't press return in time */
			vms_len--;		/* skip the last character */
			break;			/* and parse anyway */
		case RMS$_BES:			/* Bad Escape Sequence */
		case RMS$_PES:			/* Partial Escape Sequence */
			sys$putmsg(status);
			vms_len = 0;		/* ignore the line */
			break;
		case SS$_NORMAL:
			break;			/* everything's fine */
		default:
			done(status[1]);	/* give the error message */
	}

	if (vms_len && (input_line[0] == '!' || input_line[0] == '$')) {
		if (vms_len == 1)	/* spawn an interactive shell */
			cmd_ptr = &null_desc;
		else {
			cmd_ptr = &line_desc;
			input_line[0] = ' ';	/* an embarrassment, but... */
		}

		if ((status[1] = lib$spawn(cmd_ptr)) != SS$_NORMAL) {
			sys$putmsg(status);
		}
		(void) putchar('\n');

	} else {
		input_line[vms_len] = '\0';

#else
		/* not VMS */
	fprintf(stderr,PROMPT);
#ifdef MSDOS
	input_line[0] = MAX_LINE_LEN - 2;
	cgets(input_line);			/* console input so CED will work */
	(void) putc('\n',stderr);
	if (input_line[2] == 26) {
		(void) putc('\n',stderr);		/* end-of-file */
		done(IO_SUCCESS);
	}
	{
		register int i = -1;
		do				/* yuck!  move everything down two characters */
			i++;
		while (input_line[i] = input_line[i+2]);
	}

#else /* MSDOS */
		/* plain old Unix */
     {
	    int start = 0, left = MAX_LINE_LEN;
	    int more = TRUE;
	    int len;

	    while (more) {
		   if (!(int) fgets(&(input_line[start]), left, stdin)) {
			  (void) putc('\n',stderr);		/* end-of-file */
			  input_line[start] = '\0';
			  if (start > 0) /* don't quit yet - process what we have */
			    more = FALSE;
			  else
			    done(IO_SUCCESS);
		   } else {
			  len = strlen(input_line) - 1;
			  if (input_line[len] == '\n') { /* remove any newline */
				 input_line[len] = '\0';
				 len--;
			  } else if (len+1 >= left)
			    int_error("Input line too long",NO_CARET);
				 
			  if (input_line[len] == '\\') { /* line continuation */
				 start = len;
				 left -= len;
			  } else
			    more = FALSE;
		   }
	    }
	}
#endif /* MSDOS */

	screen_ok = TRUE; /* so we can flag any new output */

	if (input_line[0] == '!') {
		if (system(input_line + 1))
			os_error("system() failed",NO_CARET);
	} else {
#endif /* vms */
		do_line();
	}
}



do_line()  /* also used in load_file */
{
	num_tokens = scanner(input_line);
	c_token = 0;
	while(c_token < num_tokens) {
		command();
		if (c_token < num_tokens)	/* something after command */
			if (equals(c_token,";"))
				c_token++;
			else
				int_error("';' expected",c_token);
	}
}



command()
{
register int tsamp,len;
register FILE *f;
struct value a;
static char sv_file[MAX_ID_LEN+1];
int style;
register int i;

			/* string holding name of save or load file */

	dummy_var[0] = '\0';		/* no dummy variable */

	if (is_definition(c_token))
		define();
	else if (almost_equals(c_token,"h$elp") || equals(c_token,"?")) {
		c_token++;
		len = 0;
		while (!(END_OF_COMMAND)) {
			copy_str(helpbuf+len,c_token++);
			len = strlen(helpbuf);
			helpbuf[len++] = ' ';
			helpbuf[len] = '\0';
		}
		if (len > 0) {
		    helpbuf[len-1] = '\n';
		    lower_case(helpbuf);
		} else
		  sprintf(helpbuf, "\n");
		switch (help(helpbuf, HELPFILE)) {
		case H_FOUND:
			/* already printed the help info; do nothing */
			break;
		case H_NOTFOUND:
			printf("Sorry, no help for %s", helpbuf);
			break;
		case H_ERROR:
			perror(HELPFILE);
			break;
		default:	/* defensive programming */
			int_error("Impossible case in switch\n", NO_CARET);
			break;
		}

		screen_ok = FALSE;
		c_token++;
	}
	else if (almost_equals(c_token,"pr$int")) {
		c_token++;
		(void) const_express(&a);
		(void) putc('\t',stderr);
		show_value(stderr,&a);
		(void) putc('\n',stderr);
		screen_ok = FALSE;
	}
	else if (almost_equals(c_token,"p$lot")) {
		c_token++;
		plotrequest();
	}
	else if (almost_equals(c_token,"la$bel")) {
		c_token++;
		labelrequest();
	}
	else if (almost_equals(c_token,"k$ey")) {
		c_token++;
		keyrequest();
	}
	else if (almost_equals(c_token,"se$t")) {
		if (almost_equals(++c_token,"t$erminal")) {
			c_token++;
			if (END_OF_COMMAND)
				list_terms();
			else
				term = set_term(c_token);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"sa$mples")) {
			c_token++;
			tsamp = (int)magnitude(const_express(&a));
			if (tsamp < 1) 
				int_error("sampling rate must be > 0; sampling unchanged",
					c_token);
			else {
				samples = tsamp;		
				pointmem(samples);
			}
		}
		else if (almost_equals(c_token,"o$utput")) {
			c_token++;
			if (END_OF_COMMAND) {	/* no file specified */
				(void) fclose(outfile);
				outfile = fdopen(dup(STDOUT), "w");
				if (term != 0)
				  (*term_tbl[term].reset)();
				term_init = FALSE;
				(void) strcpy(outstr,"STDOUT");
			} else if (!isstring(c_token)) 
				int_error("expecting filename",c_token);
			else {
				quote_str(sv_file,c_token);
				if (!(f = fopen(sv_file,"w"))) {
				  os_error("cannot open file; output not changed",c_token);
				}
				if (term != 0)
				  (*term_tbl[term].reset)();
				term_init = FALSE;

				(void) fclose(outfile);
				outfile = f;

				outstr[0] = '\'';
				strcat(strcpy(outstr+1,sv_file),"'");
			} 
			c_token++;
		}
		else if (almost_equals(c_token,"a$utoscale")) {
		    c_token++;
		    if (END_OF_COMMAND) {
			   autoscale_x = autoscale_y = TRUE;
		    } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
			   autoscale_x = autoscale_y = TRUE;
			   c_token++;
		    } else if (equals(c_token, "x")) {
			   autoscale_x = TRUE;
			   c_token++;
		    } else if (equals(c_token, "y")) {
			   autoscale_y = TRUE;
			   c_token++;
		    }
		} 
		else if (almost_equals(c_token,"noa$utoscale")) {
		    c_token++;
		    if (END_OF_COMMAND) {
			   autoscale_x = autoscale_y = FALSE;
		    } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
			   autoscale_x = autoscale_y = 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 (almost_equals(c_token,"nol$ogscale")) {
			log_x = log_y = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"z$ero")) {
			c_token++;
			zero = magnitude(const_express(&a)); 
		}
		else if (almost_equals(c_token,"x$range")) {
			c_token++;
			if (!equals(c_token,"["))
				int_error("expecting '['",c_token);
			c_token++;
			load_range(&xmin,&xmax);
			autoscale_x = FALSE;
			if (!equals(c_token,"]"))
				int_error("expecting ']'",c_token);
			c_token++;
		}
		else if (almost_equals(c_token,"y$range")) {
			c_token++;
			if (!equals(c_token,"["))
				int_error("expecting '['",c_token);
			c_token++;
			load_range(&ymin,&ymax);
			autoscale_y = FALSE;
			if (!equals(c_token,"]"))
				int_error("expecting ']'",c_token);
			c_token++;
		}
		else if (almost_equals(c_token,"l$ogscale")) {
			c_token++;
			if (equals(c_token,"x")) {
				log_y = FALSE;
				log_x = TRUE;
				c_token++;
			}
			else if (equals(c_token,"y")) {
				log_x = FALSE;
				log_y = TRUE;
				c_token++;
			}
			else if (equals(c_token,"xy") || equals(c_token,"yx")) {
				log_x = log_y = TRUE;
				c_token++;
			}
			else
				int_error("expecting 'x', 'y', or 'xy'",c_token);
		}
		else if (almost_equals(c_token,"d$ata")) {
			c_token++;
			if (!almost_equals(c_token,"s$tyle")) 
				int_error("expecting keyword 'style'",c_token);
			c_token++;
			for (style = 0; style < next_style; style++) {
			    if (equals(c_token, st[style].st_name)) {
				   data_style = (enum PLOT_STYLE) style;
				   break;
			    }
			}
			if (style == next_style) 
			  int_error("unknown style - type 'show style'", c_token);
			c_token++;
		}
		else if (almost_equals(c_token,"f$unction")) {
			c_token++;
			if (!almost_equals(c_token,"s$tyle")) 
				int_error("expecting keyword 'style'",c_token);
			c_token++;
			for (style = 0; style < next_style; style++) {
			    if (equals(c_token, st[style].st_name)) {
				   func_style = (enum PLOT_STYLE) style;
				   break;
			    }
			}
			if (style == next_style) 
			  int_error("unknown style - type 'show style'", c_token);
			c_token++;
		}
		else if (almost_equals(c_token,"st$yle")) {
			c_token++;
			if (END_OF_COMMAND)
			  int_error("expecting name of new style", c_token);
			/* get the name and definition of the style and add to table  */
			c_token = add_style();
		}
		else if (almost_equals(c_token,"xl$abel")) {
		    c_token++;
		    if (!isstring(c_token)) 
			 int_error("expecting x label string",c_token);
		    else {
			   quote_str(xlabel_string,c_token);
		    }
		    c_token++;
		}
		else if (almost_equals(c_token,"xt$ics")) {
			xtics = TRUE;
			c_token++;
		} 
		else if (almost_equals(c_token,"noxt$ics")) {
			xtics = FALSE;
			c_token++;
		} 
		else if (almost_equals(c_token,"yl$abel")) {
		    c_token++;
		    if (!isstring(c_token)) {
			   int_error("expecting y label string",c_token);
		    } else {
			   quote_str(ylabel_string,c_token);
			   c_token++;
			   if (!END_OF_COMMAND) {  /* skip factor specified */
				  y_skip_factor = (int)magnitude(const_express(&a));
				  c_token++;
			   }
		    }
		}
		else if (almost_equals(c_token,"yt$ics")) {
			ytics = TRUE;
			c_token++;
		} 
		else if (almost_equals(c_token,"noyt$ics")) {
			ytics = FALSE;
			c_token++;
		} 
		else if (almost_equals(c_token,"fo$rmat")) {
			BOOLEAN setx, sety;
			c_token++;
			if (equals(c_token,"x")) {
			    setx = TRUE; sety = FALSE;
			    c_token++;
			}
			else if (equals(c_token,"y")) {
			    setx = FALSE; sety = TRUE;
			    c_token++;
			}
			else if (equals(c_token,"xy") || equals(c_token,"yx")) {
			    setx = sety = TRUE;
			    c_token++;
			}
			else if (isstring(c_token)) {
			    /* Assume he wants both */
			    setx = sety = TRUE;
			}
			else
				int_error("expecting 'x', 'y', or 'xy'",c_token);
			if (!isstring(c_token))
			  int_error("expecting format string",c_token);
			else {
			    if (setx)
				 quote_str(xformat,c_token);
			    if (sety)
				 quote_str(yformat,c_token);
			    c_token++;
			}
		}
		else if (almost_equals(c_token,"ti$tle")) {
		    c_token++;
		    if (!isstring(c_token)) 
			 int_error("expecting title string",c_token);
		    else {
			   quote_str(title_string,c_token);
		    }
		    c_token++;
		}
		else if (almost_equals(c_token,"si$ze")) {
		    c_token++;
		    plot_width = magnitude(const_express(&a));
		    c_token++;
		    plot_height = magnitude(const_express(&a));
		    c_token++;
		}
		else if (almost_equals(c_token,"cl$ip")) {
			clipping = TRUE;
			c_token++;
		} 
		else if (almost_equals(c_token,"nocl$ip")) {
			clipping = FALSE;
			c_token++;
		} 
		else
			int_error("unknown set option (try 'help set')",c_token);
	}
	else if (almost_equals(c_token,"sh$ow")) {
		if (almost_equals(++c_token,"f$unctions")) {
			c_token++;
			if (almost_equals(c_token,"s$tyle"))  {
				fprintf(stderr,"\nfunctions are plotted with %s\n\n",
					   st[(int)func_style].st_name);
				screen_ok = FALSE;
				c_token++;
			 }
			else 
				view_functions();
		}
		else if (almost_equals(c_token,"v$ariables")) {
			view_variables();
			c_token++;
		}
		else if (almost_equals(c_token,"ac$tion_table") ||
				 equals(c_token,"at") ) {
			c_token++;
			view_at();
			c_token++;
		} 
		else if (almost_equals(c_token,"d$ata")) {
			c_token++;
			if (!almost_equals(c_token,"s$tyle")) 
				int_error("expecting keyword 'style'",c_token);
			fprintf(stderr,"\ndata is plotted with %s\n\n",
				   st[(int) data_style].st_name);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"x$range")) {
			fprintf(stderr,"\nxrange is [%g : %g]\n\n",xmin,xmax);
			screen_ok = FALSE;
			c_token++;
		} 
		else if (almost_equals(c_token,"y$range")) {
			fprintf(stderr,"\nyrange is [%g : %g]\n\n",ymin,ymax);
			screen_ok = FALSE;
			c_token++;
		} 
		else if (almost_equals(c_token,"z$ero")) {
			fprintf(stderr,"\nzero is %g\n\n",zero);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"sa$mples")) {
			fprintf(stderr,"\nsampling rate is %d\n\n",samples);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"o$utput")) {
			fprintf(stderr,"\noutput is sent to %s\n\n",outstr);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"t$erminal")) {
			fprintf(stderr,"\nterminal type is %s\n\n",term_tbl[term].name);
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"au$toscale")) {
			fprintf(stderr,"\nx autoscaling is %s\n\n",(autoscale_x)? "ON" : "OFF");
			fprintf(stderr,"\ny autoscaling is %s\n\n",(autoscale_y)? "ON" : "OFF");
			screen_ok = FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"ve$rsion")) {
			(void) putc('\n',stderr);
			show_version(); 
			c_token++; 
		} 
		else if (almost_equals(c_token,"l$ogscale")) {
			if (log_x && log_y) 
				fprintf(stderr,"\nlogscaling both x and y axes\n\n");
			else if (log_x)
				fprintf(stderr,"\nlogscaling x axis\n\n");
			else if (log_y)
				fprintf(stderr,"\nlogscaling y axis\n\n");
			else 
				fprintf(stderr,"\nno logscaling\n\n");
			c_token++;
		}
		else if (almost_equals(c_token,"cl$ipping")) {
			fprintf(stderr, "clipping is %s\n", clipping ? "ON" : "OFF");
			c_token++;
		}
		else if (almost_equals(c_token,"xl$abel")) {
		    c_token++;
		    fprintf(stderr, "x axis label is '%s'\n", xlabel_string);
		}
		else if (almost_equals(c_token,"yl$abel")) {
		    c_token++;
		    fprintf(stderr, "y axis label is '%s', spacing factor %d\n",
				  ylabel_string, y_skip_factor);
		}
		else if (almost_equals(c_token,"fo$rmat")) {
			c_token++;
			fprintf(stderr, "x-axis tic format is \"%s\"\n", xformat);
			fprintf(stderr, "y-axis tic format is \"%s\"\n", yformat);
		}
		else if (almost_equals(c_token,"ti$tle")) {
		    c_token++;
		    fprintf(stderr, "title is '%s'\n", title_string);
		}
		else if (almost_equals(c_token,"si$ze")) {
		    c_token++;
		    fprintf(stderr, "plot size is %g\" width, %g\" high\n",
				  plot_width, plot_height);
		}
		else if (almost_equals(c_token,"st$yle")) {
		    c_token++;
		    if (END_OF_COMMAND) {
			   fprintf(stderr, "Available plot styles are:\n");
			   for (style = 0; style < next_style; style++) {
				  fprintf(stderr, "  %s\n", st[style].st_name);
			   }
			   fprintf(stderr, "For more info on style xxx type 'show style xxx'\n");
		    } else {
			   for (style = 0; style < next_style; style++) {
				  if (equals(c_token, st[style].st_name))
				    break;
			   }
			   if (style == next_style)
				fprintf(stderr, "That style is not defined.\n");
			   else {
				  fprintf(stderr, "Style '%s': ", st[style].st_name);
				  if (style <= FIXED_STYLES)
				    printf("Built-in style\n");
				  if (*st[style].st_point != '\0')
				    fprintf(stderr, "Point symbol '%s'\n", 
						  st[style].st_point);
				  if (st[style].st_length > 0) {
					 fprintf(stderr, "  Dot Sequence is ");
					 for (i = 0; i < st[style].st_length; i++) 
					   fprintf(stderr, "'%s', ", st[style].st_seq[i]);
    	   	  	 	    	 fprintf(stderr, "\n  Spacing %.1f points\n", 
    	   	  	 	    		    st[style].st_spacing);
    	   	  	 	  }
			   }
			   c_token++;
		    }
		}
		else if (almost_equals(c_token,"a$ll")) {
			c_token++;
			(void) putc('\n',stderr);
			show_version();
			fprintf(stderr,"functions are plotted with %s\n",
				   st[(int)func_style].st_name);
			fprintf(stderr,"data is plotted with %s\n",
				   st[(int)data_style].st_name);
			fprintf(stderr,"output is sent to %s\n",outstr);
			fprintf(stderr,"terminal type is %s\n",term_tbl[term].name);
			fprintf(stderr,"sampling rate is %d\n\n",samples);
			if (log_x && log_y) 
				fprintf(stderr,"logscaling both x and y axes\n");
			else if (log_x)
				fprintf(stderr,"logscaling x axis\n");
			else if (log_y)
				fprintf(stderr,"logscaling y axis\n");
			else 
				fprintf(stderr,"no logscaling\n");
			fprintf(stderr,"x autoscaling is %s\n",(autoscale_x)? "ON" : "OFF");
			fprintf(stderr,"y autoscaling is %s\n",(autoscale_y)? "ON" : "OFF");
			fprintf(stderr,"zero is %g\n",zero);
			fprintf(stderr,"xrange is [%g : %g]\n",xmin,xmax);
			fprintf(stderr,"yrange is [%g : %g]\n",ymin,ymax);
		    fprintf(stderr, "title is '%s'\n", title_string);
		    fprintf(stderr, "x axis label is '%s'\n", xlabel_string);
		    fprintf(stderr, "y axis label is '%s', spacing factor %d\n",
				  ylabel_string, y_skip_factor);
		    fprintf(stderr, "plot size is %g\" wide, %g\" high\n",
				  plot_width, plot_height);
			fprintf(stderr, "clipping is %s\n", clipping ? "ON" : "OFF");
			fprintf(stderr, "xtics are %s\n", xtics ? "ON" : "OFF");
			fprintf(stderr, "ytics are %s\n", ytics ? "ON" : "OFF");
			view_variables();
			view_functions();
			fprintf(stderr, "\nAvailable plot styles are:\n");
			for (style = 0; style < next_style; style++) {
			    fprintf(stderr, "  %s\n", st[style].st_name);
			}
			fprintf(stderr, "For more info on style xxx type 'show style xxx'\n");
			c_token++;
		}
		else
			int_error("unknown show option (try 'help show')",c_token);
	}
	else if (almost_equals(c_token,"cl$ear")) { /* now does clear screen! */
		if (!term_init) {
			(*term_tbl[term].init)();
			term_init = TRUE;
		}
		/* Below is a hack; no terminals but LATEX and IMAGEN uses all 
		 * these arguments, and calling this for them hardly 'clears'
		 * the screen.  (DFK 10/87)
		 */
		(*term_tbl[term].graphics)(plot_width, plot_height,
							  &(term_tbl[term]),
							  xlabel_string, ylabel_string, 
							  y_skip_factor,
							  title_string);
		(*term_tbl[term].text)();
		(void) fflush(outfile);
		screen_ok = FALSE;
		c_token++;
	}
	else if (almost_equals(c_token,"she$ll")) {
		do_shell();
		screen_ok = FALSE;
		c_token++;
	}
	else if (almost_equals(c_token,"sa$ve")) {
		if (almost_equals(++c_token,"f$unctions")) {
			if (!isstring(++c_token))
				int_error("expecting filename",c_token);
			else {
				quote_str(sv_file,c_token);
				save_functions(fopen(sv_file,"w"));
			}
		}
		else if (almost_equals(c_token,"v$ariables")) {
			if (!isstring(++c_token))
				int_error("expecting filename",c_token);
			else {
				quote_str(sv_file,c_token);
				save_variables(fopen(sv_file,"w"));
			}
		}
		else if (isstring(c_token)) {
				quote_str(sv_file,c_token);
				save_all(fopen(sv_file,"w"));
		}
		else {
			int_error(
		"filename or keyword 'functions' or 'variables' expected",c_token);
		}
		c_token++;
	}
	else if (almost_equals(c_token,"lo$ad")) {
		if (!isstring(++c_token))
			int_error("expecting filename",c_token);
		else {
			quote_str(sv_file,c_token);
			load_file(fopen(sv_file,"r"));	
		}
	/* input_line[] and token[] now destroyed! */
	}
	else if (almost_equals(c_token,"ex$it") ||
		almost_equals(c_token,"q$uit")) {
		done(IO_SUCCESS);
	}
	else if (!equals(c_token,";")) {		/* null statement */
		int_error("invalid command",c_token);
	}
}


load_range(a,b)
double *a,*b;
{
struct value t;

	if (equals(c_token,"]"))
		return;
	if (END_OF_COMMAND) {
	    int_error("starting range value or 'to' expected",c_token);
	} else if (!equals(c_token,"to") && !equals(c_token,":"))  {
		*a = real(const_express(&t));
	}	
	if (!equals(c_token,"to") && !equals(c_token,":")) 
		int_error("Keyword 'to' or ':' expected",c_token);
	c_token++; 
	if (!equals(c_token,"]"))
		*b = real(const_express(&t));
}


plotrequest()
{
    autoscale_lx = autoscale_x;
    autoscale_ly = autoscale_y;

	dummy_var[0] = 'x';  /* default */
	dummy_var[1] = '\0'; 
	if (equals(c_token,"[")) {
		c_token++;
		if (isletter(c_token)) {
			copy_str(dummy_var,c_token++);
			if (equals(c_token,"="))
				c_token++;
			else
				int_error("'=' expected",c_token);
		}
		load_range(&xmin,&xmax);
		autoscale_lx = FALSE;
		if (!equals(c_token,"]"))
			int_error("']' expected",c_token);
		c_token++;
	}

	if (equals(c_token,"[")) { /* set optional y ranges */
		c_token++;
		load_range(&ymin,&ymax);
		autoscale_ly = FALSE;
		if (!equals(c_token,"]"))
			int_error("']' expected",c_token);
		c_token++;
	}

	eval_plots();
}

/* Parse the definition of a style and add to table */
int add_style()
{
    register int i;
    int style = -1;				/* the new style number */
    struct value a;
    register struct st_entry *stp;	/* quick access to new entry */
    int null_definition = TRUE; /* watch out for missing definitions */

	/* check if it's already in the table... */

    style = -1;
	for (i = 0; i < next_value; i++) {
		if (equals(c_token,st[i].st_name))
			style = i;
	}
    /* Not found - assign a new one */
    if (style < 0)
	 style = next_style;
    /* Found - redefine it */
    if (style <= FIXED_STYLES)
	 int_error("cannot redefine this style", c_token);
    if (style == MAX_STYLES)
	 int_error("user defined style space full",NO_CARET);
    else
	 next_style++;

    stp = &st[style];

    /* Copy in the name of the style */
    copy_str(stp->st_name,c_token);
    stp->st_undef = TRUE;
    c_token++;

    /* Point type */
    if(!isstring(c_token)) {
	   *stp->st_point = '\0'; /* null point definition */
    } else {
	   quote_str(stp->st_point, c_token);
	   c_token++;
	   null_definition = FALSE;
    }

     /* Spacing */
    if(END_OF_COMMAND) {
	   stp->st_spacing = 0;
	   stp->st_length = 0;
    } else {
	   /* read dot spacing */
	   if (!isnumber(c_token)) {
		  next_value--;
		  int_error("expecting spacing (in points) for style", c_token);
	   }
	   convert(&a, c_token);
	   stp->st_spacing = magnitude(&a);
	   if (stp->st_spacing < 0.1) {
		  next_value--;
		  int_error("unreasonable spacing value", c_token);
	   }
	   c_token++;

	   /* build dot sequence */
	   stp->st_length = 0;
	   
	   while(!(END_OF_COMMAND)) {
		  if (!isstring(c_token))
		    int_error("expecting a string defining a sequence style", c_token);
		  quote_str(stp->st_seq[stp->st_length++], c_token);
		  c_token++;
		  if (stp->st_length >= MAX_STYLE_SEQ_LENGTH)
		    int_error("style sequence too long", c_token);
	   }
	   null_definition = FALSE;

	   if (stp->st_length == 0)
		int_error("expecting dot sequence", c_token);
    }

    if (null_definition)
	 int_error("expecting definition of style", c_token);

    return(++c_token);
}


labelrequest()
{
    struct value a;
    double x,y;			/* the point */
    char pos[MAX_ID_LEN+1];	/* optional argument */
    char text[MAX_ID_LEN+1];	/* text of the label */
    double length = 0;		/* length of arrow */
    int dx = 0, dy = 0;		/* slope of arrow */

    /* x coordinate */
    const_express(&a);
    x = real(&a);
    if (log_x)		/* handle coords on logscale plot. PEM 01/17/89 */
	x = log10(x);

    if (!equals(c_token, ","))
	 int_error("comma expected", c_token);
    c_token++;

    /* y coordinate */
    const_express(&a);
    y = real(&a);
    if (log_y)		/* handle coords on logscale plot. PEM 01/17/89 */
	y = log10(y);

    /* text */
    if (isstring(c_token))
	 quote_str(text, c_token++);
    else
	 int_error("expecting text of the label", c_token);

    /* optional pos */
    pos[0] = '\0';
    if (!(END_OF_COMMAND)) {
	   copy_str(pos, c_token++);
	   
	   /* optional length for optional arrow  */
	   if (!(END_OF_COMMAND)) {
		  const_express(&a);
		  length = real(&a);

		  if (!(END_OF_COMMAND)) {
			 if (!equals(c_token, ","))
			   int_error("comma expected", c_token);
			 c_token++;
		  
			 const_express(&a);
			 dx = (int) real(&a);

			 if (!equals(c_token, ","))
			   int_error("comma expected", c_token);
			 c_token++;

			 const_express(&a);
			 dy = (int) real(&a);
		  }
	   }
    }

    do_label(x,y, text, pos, length, dx, dy);
}

keyrequest()
{
    struct value a;
    double x,y;			/* the point */
    int styles[MAX_KEYS+1];	/* the style for each plot */
    char *text[MAX_KEYS+1];	/* text of each key entry */
    int style;
    int curve = 0;			/* index of the entry */

    /* x coordinate */
    const_express(&a);
    x = real(&a);

    if (!equals(c_token, ","))
	 int_error("comma expected", c_token);
    c_token++;

    /* y coordinate */
    const_express(&a);
    y = real(&a);

    do {					/* scan the entries in the key */
	   /* text */
	   if (isstring(c_token)) {
		  text[curve] = (char *) malloc(MAX_ID_LEN);
		  quote_str(text[curve], c_token++);
	   } else
		int_error("expecting text of the key entry", c_token);
	   
	   if (almost_equals(c_token, "w$ith"))
		c_token++;
	   else
		int_error("expecting 'with' style for key entry", c_token);

	   for (style = 0; style < next_style; style++)
		if (equals(c_token, st[style].st_name))
		  break;
	   if (style == next_style)
		int_error("unknown plot style; type 'show style'", 
				c_token);
	   else
		styles[curve] = style;
	   c_token++;

	   if (!END_OF_COMMAND)
		if (!equals(c_token, ","))
		  int_error("expecting ',' between key entries", c_token);
		else
		  c_token++;

	   curve++;
	   if (curve > MAX_KEYS)
		int_error("too many lines in the key", c_token);
    } while (!END_OF_COMMAND);

    text[curve] = NULL;		/* acts as terminator */

    do_key (x,y, styles, text);

    for (curve--; curve >= 0; curve--)
	 free(text[curve]);

}


define()
{
register int value,start_token;  /* start_token is the 1st token in the	*/
								/* function definition.			*/

	if (equals(c_token+1,"(")) {
		/* function ! */
		start_token = c_token;
		copy_str(dummy_var, c_token + 2);
		c_token += 5; /* skip (, dummy, ) and = */
		value = c_function = user_defined(start_token);
		build_at(&(udft[value].at));
				/* define User Defined Function (parse.c)*/
		capture(udft[value].definition,start_token,c_token-1);
	}
	else {
		/* variable ! */
		c_token +=2;
		(void) const_express(&vt[value = add_value(c_token - 2) ].vt_value);
		vt[value].vt_undef = FALSE;
	}
}


#define iscomment(c) (c == '!' || c == '#')

get_data(plot_num)
int plot_num;
{
static char data_file[MAX_ID_LEN+1], line[MAX_LINE_LEN+1];
register int i, l_num, datum;
register FILE *fp;
float x, y;

	quote_str(data_file, c_token);
	plot[plot_num].plot_type = DATA;
	if (!(fp = fopen(data_file, "r")))
		os_error("can't open data file", c_token);

	l_num = 0;
     datum = 0;
	i = 0;
	while (fgets(line, MAX_LINE_LEN, fp)) {
		l_num++;
		if (iscomment(line[0]) || ! line[1])	/* line[0] will be '\n' */
			continue;		/* ignore comments  and blank lines */
		if (i > samples) {
		    fprintf(stderr, 
				  "Too many data points (limit is %d) in file '%s'\n",
				  samples, data_file);
		    fprintf(stderr, " To change limit, use 'set samples <limit>'\n");
		    break;
		}
		switch (sscanf(line, "%f %f", &x, &y)) {
			case 1:			/* only one number on the line */
				y = x;		/* assign that number to y */
				x = datum;	/* and make the index into x */
			/* no break; !!! */
			case 2:
				datum++;
				plot[plot_num].points[i].undefined = FALSE;
				if (   (autoscale_lx || (x >= xmin && x <= xmax))
				    && (autoscale_ly || (y >= ymin && y <= ymax))) {
					if (log_x) {
						if (x <= 0.0)
						  plot[plot_num].points[i].undefined = TRUE;
						else
						  plot[plot_num].points[i].x = log10(x);
					} else
						plot[plot_num].points[i].x = x;
					if (log_y) {
						if (y <= 0.0)
						  plot[plot_num].points[i].undefined = TRUE;
						else
						  plot[plot_num].points[i].y = log10(y);
					} else
						plot[plot_num].points[i].y = y;
					if (plot[plot_num].points[i].undefined == FALSE) {
					    if (autoscale_lx) {
						   if (x < xmin) xmin = x;
						   if (x > xmax) xmax = x;
					    }
					    if (autoscale_ly) {
						   if (y < ymin) ymin = y;
						   if (y > ymax) ymax = y;
					    }
					}
				} else
				  plot[plot_num].points[i].undefined = TRUE;
				i++;
				break;
			default:
				(void) sprintf(line, "bad data on line %d", l_num);
				int_error(line,c_token);
		}
	}
	plot[plot_num].count = i;

     fclose(fp);			/* DFK 6/8/87 Bugfix: never closed file! */
}

/* This parses the plot command after any range specifications. 
 * To support autoscaling on the x axis, we want any data files to 
 * define the x range, then to plot any functions using that range. 
 * We thus parse the input twice, once to pick up the data files, 
 * and again to pick up the functions. Definitions are processed 
 * twice, but that won't hurt.
 */
eval_plots()
{
register int i, plot_num, start_token, mysamples;
register int begin_token;
register double x_min, x_max, y_min, y_max, x;
register double xdiff, temp;
struct value a;
int style;
BOOLEAN some_data_files = FALSE;

	/* don't sample higher than output device can handle! */
	mysamples = (samples <= term_tbl[term].xmax) ?samples :term_tbl[term].xmax;

	if (autoscale_ly) {
		ymin = HUGE;
		ymax = -HUGE;
	} else if (log_y && (ymin <= 0.0 || ymax <= 0.0))
			int_error("y range must be greater than 0 for log scale!",
				NO_CARET);

	c_function = MAX_UDFS;		/* last udft[] entry used for plots */

	plot_num = 0;

     begin_token = c_token;

/*** First Pass: Read through data files ***/
/* This pass serves to set the xrange and to parse the command, as well 
 * as filling in every thing except the function data. That is done after
 * the xrange is defined.
 */
	while (TRUE) {
		if (END_OF_COMMAND)
			int_error("function to plot expected",c_token);
		if (plot_num == MAX_PLOTS || plot[plot_num].points == NULL)
			int_error("maximum number of plots exceeded",NO_CARET);

		start_token = c_token;

		if (is_definition(c_token)) {
			define();
		} else {
			if (isstring(c_token)) {			/* data file to plot */
				if (!some_data_files && autoscale_lx) {
				    xmin = HUGE;
				    xmax = -HUGE;
				}
				some_data_files = TRUE;

				plot[plot_num].plot_type = DATA;
				plot[plot_num].plot_style = (int)data_style;
				get_data(plot_num);
				c_token++;
			} 
			else {							/* function to plot */
				plot[plot_num].plot_type = FUNC;
				plot[plot_num].plot_style = (int)func_style;
				build_at(&udft[MAX_UDFS].at);
				/* ignore it for now */
			}
			capture(plot[plot_num].title,start_token,c_token-1);
			if (almost_equals(c_token,"w$ith")) {
				c_token++;
				for (style = 0; style < next_style; style++)
				  if (equals(c_token, st[style].st_name))
				    break;
				if (style == next_style)
				  int_error("unknown plot style; type 'show style'", 
						  c_token);
				else
				  plot[plot_num].plot_style = style;
				c_token++;
			}
			plot_num++;
		}

		if (equals(c_token,",")) 
			c_token++;
		else  
			break;
	}

/*** Second Pass: Evaluate the functions ***/
/* Everything is defined now, except the function data. We expect
 * no syntax errors, etc, since the above parsed it all. This makes 
 * the code below simpler. If autoscale_ly, the yrange may still change.
 */
     if (xmin == xmax)
	  if (autoscale_lx) {
		 fprintf(stderr,
			    "Warning: empty x range [%g:%g], adjusting to [%g:%g]\n",
			    xmin,xmax, xmin*0.9, xmax*1.1);
		 xmin = xmin * 0.9;	/* expand range by 10% in either direction */
		 xmax = xmax * 1.1;
	  } else {
		 int_error("x range is empty", c_token);
	  }

    if (log_x) {
	   if (xmin < 0.0 || xmax < 0.0)
		int_error("x range must be greater than 0 for log scale!",NO_CARET);
	   x_min = log10(xmin);
	   x_max = log10(xmax);
    } else {
	   x_min = xmin;
	   x_max = xmax;
    }
    
    xdiff = (x_max - x_min) / mysamples;
    
    c_function = MAX_UDFS;		/* last udft[] entry used for plots */
    plot_num = 0;
    c_token = begin_token;	/* start over */

    /* Read through data files */
	while (TRUE) {
		if (is_definition(c_token)) {
			define();
		} else {
			if (isstring(c_token)) {			/* data file to plot */
			    /* ignore this now */
				c_token++;
			} 
			else {							/* function to plot */
				build_at(&udft[MAX_UDFS].at);
    
				for (i = 0; i <= mysamples; i++) {
				    if (i == samples+1)
					 int_error("number of points exceeded samples",
							 NO_CARET);
				    x = x_min + i*xdiff;
				    if (log_x)
					 x = pow(10.0,x);
				    (void) complex(&udft[MAX_UDFS].dummy_value, x, 0.0);
				    
				    evaluate_at(&udft[MAX_UDFS].at,&a);
				    
				    if (plot[plot_num].points[i].undefined =
					   undefined || (fabs(imag(&a)) > zero))
					 continue;
				    
				    temp = real(&a);
				    
				    if (log_y && temp <= 0.0) {
					   plot[plot_num].points[i].undefined = TRUE;
					   continue;
				    }

				    if (autoscale_ly) {
					   if (temp < ymin) ymin = temp;
					   if (temp > ymax) ymax = temp;
				    } else if (temp < ymin || temp > ymax) {
					   plot[plot_num].points[i].undefined = TRUE;
					   continue;
				    }

				    plot[plot_num].points[i].x = x;
				    plot[plot_num].points[i].y = 
					 log_y ? log10(temp) : temp;
				}
				plot[plot_num].count = i; /* mysamples + 1 */
			 }
			
			/* style was handled above */
			if (almost_equals(c_token,"w$ith")) {
			    c_token++;
			    c_token++;
			}
			plot_num++;
		 }
		
		if (equals(c_token,",")) 
		  c_token++;
		else  
		  break;
	 }

    if (ymin == ymax)
	 if (autoscale_ly) {
		fprintf(stderr,
			   "Warning: empty y range [%g:%g], adjusting to [%g:%g]\n",
			   ymin,ymax, ymin*0.9, ymax*1.1);
		ymin = ymin * 0.9;	/* expand range by 10% in either direction */
		ymax = ymax * 1.1;
	 } else {
		int_error("y range is empty", c_token);
	 }

/* Now we finally know the real ymin and ymax */
	if (log_y) {
		y_min = log10(ymin);
		y_max = log10(ymax);
	} else {
		y_min = ymin;
		y_max = ymax;
	}
	do_plot(plot,plot_num,x_min,x_max,y_min,y_max);
}



done(status)
int status;
{
	if (term)
		(*term_tbl[term].reset)();
	exit(status);
}

#ifdef vms
do_shell()
{
	if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
		os_error("spawn error");
	}
}

#else /* vms */

#ifdef MSDOS

do_shell()
{
register char *comspec;
	if (!(comspec = getenv("COMSPEC")))
		comspec = "\command.com";
	if (spawnl(P_WAIT,comspec,NULL))
		os_error("unable to spawn shell");
}

#else /* MSDOS */

#ifdef VFORK

do_shell()
{
register char *shell;
register int p;
static int execstat;
	if (!(shell = getenv("SHELL")))
		shell = SHELL;
	if ((p = vfork()) == 0) {
		execstat = execl(shell,shell,NULL);
		_exit(1);
	} else if (p == -1)
		os_error("vfork failed",c_token);
	else
		while (wait(NULL) != p)
			;
	if (execstat == -1)
		os_error("shell exec failed",c_token);
	(void) putc('\n',stderr);
}
#else /* VFORK */

#define EXEC "exec "
do_shell()
{
static char exec[100] = EXEC;
register char *shell;
	if (!(shell = getenv("SHELL")))
		shell = SHELL;

	if (system(strcpy(&exec[sizeof(EXEC)-1],shell)))
		os_error("system() failed",NO_CARET);

	(void) putc('\n',stderr);
}
#endif /* VFORK */
#endif /* MSDOS */
#endif /* vms */