|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 37266 (0x9192)
Types: TextFile
Names: »command.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z«
└─⟦036c765ac⟧
└─⟦this⟧ »TeX3.0/TeXcontrib/gnutex/command.c«
/*
*
* 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 */