|
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 */