This is command.c in view mode; [Download] [Up]
#ifndef lint static char *RCSid = "$Id: command.c%v 3.38.2.119 1993/04/26 00:02:13 woo Exp woo $"; #endif /* GNUPLOT - command.c */ /* * Copyright (C) 1986 - 1993 Thomas Williams, Colin Kelley * * Permission to use, copy, and distribute this software and its documentation * for any purpose with or without fee is hereby granted, provided that the * above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation. * * Permission to modify the software is granted, but not the right to distribute * the modified code. Modifications are to be distributed as patches to * released version. * * This software is provided "as is" without express or implied warranty. * * * AUTHORS * * Original Software: Thomas Williams, Colin Kelley. * * Gnuplot 2.0 additions: Russell Lang, Dave Kotz, John Campbell. * * Gnuplot 3.0 additions: Gershon Elber and many others. * * Changes: * * Feb 5, 1992 Jack Veenstra (veenstra@cs.rochester.edu) Added support to * filter data values read from a file through a user-defined function before * plotting. The keyword "thru" was added to the "plot" command. Example * syntax: f(x) = x / 100 plot "test.data" thru f(x) This example divides all * the y values by 100 before plotting. The filter function processes the * data before any log-scaling occurs. This capability should be generalized * to filter x values as well and a similar feature should be added to the * "splot" command. * * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu) * Added user-specified bases for log scaling. * * Send your comments or suggestions to info-gnuplot@dartmouth.edu. This is * a mailing list; to join it send a note to * info-gnuplot-request@dartmouth.edu. Send bug reports to * bug-gnuplot@dartmouth.edu. */ #include <stdio.h> #include <math.h> #include <ctype.h> #ifdef AMIGA_AC_5 #include <time.h> void sleep(); /* defined later */ #endif #ifdef OS2 #include <setjmp.h> extern jmp_buf env; /* from plot.c */ #endif #if defined(MSDOS) || defined(DOS386) #ifdef DJGPP #include <dos.h> #else #include <process.h> #endif #ifdef __ZTC__ #define P_WAIT 0 #include <time.h> /* usleep() */ #else #ifdef __TURBOC__ #ifndef _Windows #include <dos.h> /* sleep() */ #include <conio.h> #include <dir.h> /* setdisk() */ extern unsigned _stklen = 16394;/* increase stack size */ #endif #else /* must be MSC */ #if !defined(__EMX__) && !defined(DJGPP) #ifdef __MSC__ #include <direct.h> /* for _chdrive() */ #endif #include <time.h> /* kludge to provide sleep() */ void sleep(); /* defined later */ #endif /* !__EMX__ && !DJGPP */ #endif /* TURBOC */ #endif /* ZTC */ #endif /* MSDOS */ #ifdef ATARI #ifdef __PUREC__ #include <ext.h> #include <tos.h> #include <aes.h> #else #include <osbind.h> #include <aesbind.h> #endif /* __PUREC__ */ #endif /* ATARI */ #ifdef AMIGA_SC_6_1 #include <proto/dos.h> void sleep(); #endif /* AMIGA_SC_6_1 */ #include "plot.h" #include "setshow.h" #ifndef _Windows #include "help.h" #else #define MAXSTR 255 #endif #ifndef STDOUT #define STDOUT 1 #endif #ifndef HELPFILE #if defined( MSDOS ) || defined( OS2 ) || defined(DOS386) #define HELPFILE "gnuplot.gih" #else #ifdef AMIGA_SC_6_1 #define HELPFILE "S:gnuplot.gih" #else #define HELPFILE "docs/gnuplot.gih" /* changed by makefile */ #endif /* AMIGA_SC_6_1 */ #endif #endif /* HELPFILE */ #ifdef _Windows #include <windows.h> #include <setjmp.h> #ifdef __MSC__ #include <malloc.h> #else #include <alloc.h> #include <dir.h> /* setdisk() */ #endif #include "win/wgnuplib.h" void sleep(); extern TW textwin; extern jmp_buf FAR env; /* from plot.c */ extern LPSTR winhelpname; extern void screen_dump(void); /* in term/win.trm */ extern int Pause(LPSTR mess); /* in winmain.c */ #endif #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) ) /* * instead of <strings.h> */ #ifndef ATARI #ifdef _Windows #include <string.h> #include <stdlib.h> #else #ifndef AMIGA_SC_6_1 extern char *gets(), *getenv(); #ifdef sequent extern char *strcpy(), *strncpy(), *strcat(), *index(); #else extern char *strcpy(), *strncpy(), *strcat(), *strchr(); #endif extern int strlen(), strcmp(); extern double atof(); #endif /* !AMIGA_SC_6_1 */ #endif #else #ifdef __PUREC__ /* * a substitute for PureC's buggy sscanf. * this uses the normal sscanf and fixes the following bugs: * - whitespace in format matches whitespace in string, but doesn't * require any. ( "%f , %f" scans "1,2" correctly ) * - the ignore value feature works (*). this created an address error * in PureC. */ #include <stdarg.h> #include <string.h> int purec_sscanf( const char *string, const char *format, ... ) { va_list args; int cnt=0; char onefmt[256]; char buffer[256]; const char *f=format; const char *s=string; char *f2; char ch; int ignore; void *p; int *ip; int pos; va_start(args,format); while( *f && *s ) { ch=*f++; if( ch!='%' ) { if(isspace(ch)) { /* match any number of whitespace */ while(isspace(*s)) s++; } else { /* match exactly the character ch */ if( *s!=ch ) goto finish; s++; } } else { /* we have got a '%' */ ch=*f++; if( ch=='%' ) { /* match exactly % */ if( *s!=ch ) goto finish; s++; } else { f2=onefmt; *f2++='%'; *f2++=ch; ignore=0; if( ch=='*' ) { ignore=1; ch=f2[-1]=*f++; } while( isdigit(ch) ) { ch=*f2++=*f++; } if( ch=='l' || ch=='L' || ch=='h' ) { ch=*f2++=*f++; } switch(ch) { case '[': while( ch && ch!=']' ) { ch=*f2++=*f++; } if( !ch ) goto error; break; case 'e': case 'f': case 'g': case 'd': case 'o': case 'i': case 'u': case 'x': case 'c': case 's': case 'p': case 'n': /* special case handled below */ break; default: goto error; } if( ch!='n' ) { strcpy(f2,"%n"); if( ignore ) { p=buffer; } else { p=va_arg(args,void *); } switch( sscanf( s, onefmt, p, &pos ) ) { case EOF: goto error; case 0 : goto finish; } if( !ignore ) cnt++; s+=pos; } else { if( !ignore ) { ip=va_arg(args,int *); *ip=(int)(s-string); } } } } } if( !*f ) goto finish; error: cnt=EOF; finish: va_end(args); return cnt; } /* use the substitute now. I know this is dirty trick, but it works. */ #define sscanf purec_sscanf #endif /* __PUREC__ */ #endif /* ATARI */ /* * Only reference to contours library. */ extern struct gnuplot_contours *contour(); #ifdef OS2 /* emx has getcwd, chdir that can handle drive names */ #define getcwd _getcwd2 #define chdir _chdir2 #endif /* OS2 */ #if defined(unix) && !defined(hpux) #ifdef GETCWD extern char *getcwd(); /* some Unix's use getcwd */ #else extern char *getwd(); /* most Unix's use getwd */ #endif #else #ifdef DJGPP extern char *getwd(); /* DJGPP acts like Unix here */ #else extern char *getcwd(); /* Turbo C, MSC, EMX, OS2 and VMS use getcwd */ #endif #endif #ifdef vms int vms_vkid; /* Virtual keyboard id */ #endif static FILE *data_fp=NULL; /* != means file still open */ static TBOOLEAN more_data_fp=FALSE; /* And this explicitly says so. */ #if defined(unix) || defined(PIPES) extern FILE *popen(); static TBOOLEAN pipe_open = FALSE; #endif extern int chdir(); extern double magnitude(), angle(), real(), imag(); extern struct value *const_express(), *pop(), *Gcomplex(); extern struct at_type *temp_at(), *perm_at(); extern struct udft_entry *add_udf(); extern struct udvt_entry *add_udv(); extern void squash_spaces(); extern void lower_case(); /* local functions */ static enum coord_type adjustlog(); extern TBOOLEAN interactive; /* from plot.c */ /* input data, parsing variables */ struct lexical_unit token[MAX_TOKENS]; char input_line[MAX_LINE_LEN + 1] = ""; int num_tokens, c_token; int inline_num = 0; /* input line number */ char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1]; /* current dummy vars */ /* the curves/surfaces of the plot */ struct curve_points *first_plot = NULL; struct surface_points *first_3dplot = NULL; static struct udft_entry plot_func; struct udft_entry *dummy_func; /* jev -- for passing data thru user-defined function */ static struct udft_entry ydata_func; /* support for replot command */ char replot_line[MAX_LINE_LEN + 1] = ""; static int plot_token; /* start of 'plot' command */ /* If last plot was a 3d one. */ TBOOLEAN is_3d_plot = FALSE; com_line() { if (read_line(PROMPT)) return(1); /* So we can flag any new output: if false at time of error, */ /* we reprint the command line before printing caret. */ /* TRUE for interactive terminals, since the command line is typed. */ /* FALSE for non-terminal stdin, so command line is printed anyway. */ /* (DFK 11/89) */ screen_ok = interactive; if (do_line()) return(1); else return(0); } do_line() { /* also used in load_file */ if (is_system(input_line[0])) { do_system(); (void) fputs("!\n", stderr); return(0); } num_tokens = scanner(input_line); c_token = 0; while (c_token < num_tokens) { if (command()) return(1); if (c_token < num_tokens) /* something after command */ if (equals(c_token, ";")) c_token++; else int_error("';' expected", c_token); } return(0); } command() { FILE *fp, *lf_top(); int i; char sv_file[MAX_LINE_LEN + 1]; #if defined(__ZTC__) unsigned dummy; /* it's a parameter needed for dos_setdrive */ #endif /* string holding name of save or load file */ for (i = 0; i < MAX_NUM_VAR; i++) c_dummy_var[i][0] = '\0'; /* no dummy variables */ if (is_definition(c_token)) define(); else if (almost_equals(c_token, "h$elp") || equals(c_token, "?")) { c_token++; do_help(); } else if (almost_equals(c_token, "test")) { c_token++; test_term(); } else if (almost_equals(c_token, "scr$eendump")) { c_token++; #ifdef _Windows screen_dump(); #else fputs("screendump not implemented\n",stderr); #endif } else if (almost_equals(c_token, "pa$use")) { struct value a; int stime, text = 0; char buf[MAX_LINE_LEN + 1]; c_token++; stime = (int) real(const_express(&a)); buf[0]='\0'; if (!(END_OF_COMMAND)) { if (!isstring(c_token)) int_error("expecting string", c_token); else { quotel_str(buf, c_token); #ifdef _Windows if (stime>=0) #endif #ifdef OS2 if( strcmp(term_tbl[term].name, "pm" )!=0 || stime >=0 ) #endif (void) fprintf(stderr, "%s", buf); text = 1; } } if (stime < 0) #ifdef _Windows { if (!Pause(buf)) longjmp(env, TRUE); /* bail out to command line */ } #else #ifdef OS2 if( strcmp(term_tbl[term].name, "pm" )==0 && stime < 0 ) { int rc ; if( (rc=PM_pause( buf ))==0 ) longjmp(env,TRUE) ; else if( rc==2 ) { (void) fprintf(stderr, "%s", buf); text = 1; (void) fgets(buf, MAX_LINE_LEN, stdin); } } #else (void) fgets(buf, MAX_LINE_LEN, stdin); /* Hold until CR hit. */ #endif /*OS2*/ #endif #ifdef __ZTC__ if (stime > 0) usleep((unsigned long) stime); #else if (stime > 0) sleep((unsigned int) stime); #endif if (text != 0 && stime >= 0) (void) fprintf(stderr, "\n"); c_token++; screen_ok = FALSE; } else if (almost_equals(c_token, "pr$int")) { struct value a; c_token++; (void) const_express(&a); (void) putc('\t', stderr); disp_value(stderr, &a); (void) putc('\n', stderr); screen_ok = FALSE; } else if (almost_equals(c_token, "p$lot")) { plot_token = c_token++; #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); #endif plotrequest(); #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_ARROW)); #endif } else if (almost_equals(c_token, "sp$lot")) { plot_token = c_token++; #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); #endif plot3drequest(); #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_ARROW)); #endif } else if (almost_equals(c_token, "rep$lot")) { if (replot_line[0] == '\0') int_error("no previous plot", c_token); c_token++; #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT)); #endif replotrequest(); #ifdef _Windows SetCursor(LoadCursor((HINSTANCE)NULL, IDC_ARROW)); #endif } else if (almost_equals(c_token, "se$t")) set_command(); else if (almost_equals(c_token, "sh$ow")) show_command(); else if (almost_equals(c_token, "cl$ear")) { if (!term_init) { (*term_tbl[term].init) (); term_init = TRUE; } (*term_tbl[term].graphics) (); (*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 (almost_equals(c_token, "s$et")) { if (!isstring(++c_token)) int_error("expecting filename", c_token); else { quote_str(sv_file, c_token); save_set(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', 'variables', or 'set' expected", c_token); } c_token++; } else if (almost_equals(c_token, "l$oad")) { if (!isstring(++c_token)) int_error("expecting filename", c_token); else { quote_str(sv_file, c_token); load_file(fp=fopen(sv_file, "r"), sv_file); /* input_line[] and token[] now destroyed! */ c_token = num_tokens = 0; } } else if (almost_equals(c_token,"rer$ead")) { fp = lf_top(); if (fp != (FILE *)NULL) rewind(fp); c_token++; } else if (almost_equals(c_token, "cd")) { if (!isstring(++c_token)) int_error("expecting directory name", c_token); else { quotel_str(sv_file, c_token); #if defined(MSDOS) || defined(_Windows) || defined(ATARI) || defined(DOS386) if (!((strlen(sv_file)==2) && isalpha(sv_file[0]) && (sv_file[1]==':'))) #endif if (chdir(sv_file)) { int_error("Can't change to this directory", c_token); } #if defined(MSDOS) || defined(_Windows) || defined(ATARI) || defined(DOS386) if (isalpha(sv_file[0]) && (sv_file[1]==':')) { #ifdef ATARI (void)Dsetdrv(toupper(sv_file[0])-'A'); #endif #if defined(__ZTC__) (void)dos_setdrive(toupper(sv_file[0]) - 'A' + 1, &dummy); #endif #if defined(MSDOS) && defined(__EMX__) (void)_chdrive(toupper(sv_file[0])); #endif #if defined(__MSC__) (void)_chdrive(toupper(sv_file[0])-'A'); #endif #if (defined(MSDOS) || defined(_Windows)) && defined(__TURBOC__) (void) setdisk(toupper(sv_file[0])-'A'); #endif #ifdef DJGPP { union REGS r; r.h.ah = 0x0e; r.x.dx = toupper(sv_file[0])-'A'; intdos(&r, &r); } #endif } #endif c_token++; } } else if (almost_equals(c_token, "pwd")) { #if defined(unix) && !defined(hpux) #ifdef GETCWD (void) getcwd(sv_file, MAX_ID_LEN); /* some Unix's use getcwd */ #else (void) getwd(sv_file); /* most Unix's use getwd */ #endif #else #ifdef __EMX__ (void) _getcwd2(sv_file, MAX_ID_LEN); #else /* Turbo C and VMS have getcwd() */ (void) getcwd(sv_file, MAX_ID_LEN); #endif #endif #ifdef DJGPP { union REGS r; r.h.ah = 0x19; intdos(&r, &r); fprintf(stderr, "%c:", r.h.al + 'a'); } #endif fprintf(stderr, "%s\n", sv_file); c_token++; } else if (almost_equals(c_token, "ex$it") || almost_equals(c_token, "q$uit")) { return(1); } else if (!equals(c_token, ";")) { /* null statement */ int_error("invalid command", c_token); } return(0); } replotrequest() { char str[MAX_LINE_LEN + 1]; if (equals(c_token, "[")) int_error("cannot set range with replot", c_token); if (!END_OF_COMMAND) { capture(str, c_token, num_tokens - 1); if ((strlen(str) + strlen(replot_line)) <= MAX_LINE_LEN - 1) { (void) strcat(replot_line, ","); (void) strcat(replot_line, str); } else { int_error("plot line too long with replot arguments", c_token); } } (void) strcpy(input_line, replot_line); screen_ok = FALSE; num_tokens = scanner(input_line); c_token = 1; /* skip the 'plot' part */ is_3d_plot ? plot3drequest() : plotrequest(); } plotrequest() /* * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2 * while in the non-parametric case we would say only plot [b= -2:2] [-1:1] * sin(b) */ { TBOOLEAN changed; int dummy_token = -1; is_3d_plot = FALSE; if (parametric && strcmp(dummy_var[0], "u") == 0) strcpy(dummy_var[0], "t"); autoscale_lt = autoscale_t; autoscale_lx = autoscale_x; autoscale_ly = autoscale_y; if (!term) /* unknown */ int_error("use 'set term' to set terminal type first", c_token); if (equals(c_token, "[")) { c_token++; if (isletter(c_token)) { if (equals(c_token + 1, "=")) { dummy_token = c_token; c_token += 2; } else { /* oops; probably an expression with a variable. */ /* Parse it as an xmin expression. */ /* used to be: int_error("'=' expected",c_token); */ } } changed = parametric ? load_range(&tmin, &tmax) : load_range(&xmin, &xmax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) { if (parametric) autoscale_lt = FALSE; else autoscale_lx = FALSE; } } if (parametric && equals(c_token, "[")) { /* set optional x ranges */ c_token++; changed = load_range(&xmin, &xmax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) if(parametric) autoscale_lt = FALSE; else autoscale_lx = FALSE; } if (equals(c_token, "[")) { /* set optional y ranges */ c_token++; changed = load_range(&ymin, &ymax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) autoscale_ly = FALSE; } /* use the default dummy variable unless changed */ if (dummy_token >= 0) copy_str(c_dummy_var[0], dummy_token); else (void) strcpy(c_dummy_var[0], dummy_var[0]); eval_plots(); } plot3drequest() /* * in the parametric case we would say splot [u= -Pi:Pi] [v= 0:2*Pi] [-1:1] * [-1:1] [-1:1] sin(v)*cos(u),sin(v)*cos(u),sin(u) in the non-parametric * case we would say only splot [x= -2:2] [y= -5:5] sin(x)*cos(y) * */ { TBOOLEAN changed; int dummy_token0 = -1, dummy_token1 = -1; is_3d_plot = TRUE; if (parametric && strcmp(dummy_var[0], "t") == 0) { strcpy(dummy_var[0], "u"); strcpy(dummy_var[1], "v"); } autoscale_lx = autoscale_x; autoscale_ly = autoscale_y; autoscale_lz = autoscale_z; if (!term) /* unknown */ int_error("use 'set term' to set terminal type first", c_token); if (equals(c_token, "[")) { c_token++; if (isletter(c_token)) { if (equals(c_token + 1, "=")) { dummy_token0 = c_token; c_token += 2; } else { /* oops; probably an expression with a variable. */ /* Parse it as an xmin expression. */ /* used to be: int_error("'=' expected",c_token); */ } } changed = parametric ? load_range(&umin, &umax) : load_range(&xmin, &xmax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) if(parametric) autoscale_lu = FALSE; else autoscale_lx = FALSE; } if (equals(c_token, "[")) { c_token++; if (isletter(c_token)) { if (equals(c_token + 1, "=")) { dummy_token1 = c_token; c_token += 2; } else { /* oops; probably an expression with a variable. */ /* Parse it as an xmin expression. */ /* used to be: int_error("'=' expected",c_token); */ } } changed = parametric ? load_range(&vmin, &vmax) : load_range(&ymin, &ymax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) if(parametric) autoscale_lv = FALSE; else autoscale_ly = FALSE; } if (equals(c_token, "[")) { /* set optional x (parametric) or z ranges */ c_token++; changed = parametric ? load_range(&xmin, &xmax) : load_range(&zmin, &zmax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) if(parametric) autoscale_lx = FALSE; else autoscale_lz = FALSE; } if (equals(c_token, "[")) { /* set optional y ranges */ c_token++; changed = load_range(&ymin, &ymax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) autoscale_ly = FALSE; } if (equals(c_token, "[")) { /* set optional z ranges */ c_token++; changed = load_range(&zmin, &zmax); if (!equals(c_token, "]")) int_error("']' expected", c_token); c_token++; if (changed) autoscale_lz = FALSE; } /* use the default dummy variable unless changed */ if (dummy_token0 >= 0) copy_str(c_dummy_var[0], dummy_token0); else (void) strcpy(c_dummy_var[0], dummy_var[0]); if (dummy_token1 >= 0) copy_str(c_dummy_var[1], dummy_token1); else (void) strcpy(c_dummy_var[1], dummy_var[1]); eval_3dplots(); } define() { register int start_token;/* the 1st token in the function definition */ register struct udvt_entry *udv; register struct udft_entry *udf; if (equals(c_token + 1, "(")) { /* function ! */ int dummy_num = 0; start_token = c_token; do { c_token += 2; /* skip to the next dummy */ copy_str(c_dummy_var[dummy_num++], c_token); } while (equals(c_token + 1, ",") && (dummy_num < MAX_NUM_VAR)); if (equals(c_token + 1, ",")) int_error("function contains too many parameters", c_token + 2); c_token += 3; /* skip (, dummy, ) and = */ if (END_OF_COMMAND) int_error("function definition expected", c_token); udf = dummy_func = add_udf(start_token); if (udf->at) /* already a dynamic a.t. there */ free((char *) udf->at); /* so free it first */ if ((udf->at = perm_at()) == (struct at_type *) NULL) int_error("not enough memory for function", start_token); m_capture(&(udf->definition), start_token, c_token - 1); } else { /* variable ! */ start_token = c_token; c_token += 2; udv = add_udv(start_token); (void) const_express(&(udv->udv_value)); udv->udv_undef = FALSE; } } get_data(this_plot) struct curve_points *this_plot; { register int i, j, l_num, datum; int fcol[5], scol[5], ncol[5], prevmin, col; char format[MAX_LINE_LEN + 1], data_file[MAX_LINE_LEN + 1], line[MAX_LINE_LEN + 1]; /* conversion variables */ int n, m, linestat, using; char *s; double val[5], v[5]; float fval[5]; /* for use in sscanf */ /* close forgotten input file (in case of a syntax error) */ if( data_fp ) { #if defined(unix) || defined(PIPES) if (pipe_open) { (void) pclose(data_fp); pipe_open = FALSE; } else #endif /* unix || PIPES */ (void) fclose(data_fp); data_fp=NULL; } quotel_str(data_file, c_token); this_plot->plot_type = DATA; /* if (parametric) int_error("Parametric data files not yet implemented", NO_CARET); */ #if defined(unix) || defined(PIPES) if (*data_file == '<') { if ((data_fp = popen(data_file + 1, "r")) == (FILE *) NULL) os_error("cannot create pipe for data", c_token); else pipe_open = TRUE; } else #endif /* unix || PIPES */ if ((data_fp = fopen(data_file, "r")) == (FILE *) NULL) os_error("can't open data file", c_token); format[0] = '\0'; for (i=0; i<5; i++) fcol[i] = i+1; using = 0; c_token++; /* skip data file name */ /* jev -- support for passing data from file thru user function */ if (almost_equals(c_token, "thru$")) { c_token++; if (ydata_func.at) free(ydata_func.at); dummy_func = &ydata_func; ydata_func.at = perm_at(); } else { if (ydata_func.at) free(ydata_func.at); ydata_func.at = NULL; } if (almost_equals(c_token,"u$sing")) { using = 1; c_token++; /* skip "using" */ if (!END_OF_COMMAND && !isstring(c_token)) { struct value a; for (i=0; i<5; i++) fcol[i] = -1; fcol[0] = fcol[1] = (int)magnitude(const_express(&a)); for (i=1; equals(c_token,":") && i<5; i++) { c_token++; /* skip ":" */ fcol[i] = (int)magnitude(const_express(&a)); } if (i==1) /* only y column given */ fcol[0] = 1; } if (!END_OF_COMMAND && isstring(c_token)) { quotel_str(format, c_token); c_token++; /* skip format */ } } /* sort fcol[] into scol[] removing duplicates */ prevmin = 0; for (i=0; i<5; i++) { col = 10000; for (j=0; j<5; j++) if ((fcol[j]>prevmin) && (fcol[j]<col)) col = fcol[j]; if (col <10000) prevmin = scol[i] = col; else scol[i] = 0; } /* normalise fcol[] into ncol[] */ for (i=0; i<5; i++) { if (fcol[i] > 0) for (j=0; j<5; j++) { if (fcol[i] == scol[j]) ncol[i] = j+1; } else if (fcol[i] == 0) ncol[i] = 0; else ncol[i] = -1; } /* set col to highest column number */ col = 0; for (i=0; i<5; i++) if (fcol[i]>col) col=fcol[i]; l_num = 0; datum = 0; i = 0; while (fgets(line, MAX_LINE_LEN, data_fp) != (char *) NULL) { l_num++; if (is_comment(line[0])) continue; /* ignore comments */ if (i >= this_plot->p_max) { /* * overflow about to occur. Extend size of points[] array. We * either double the size, or add 1000 points, whichever is a * smaller increment. Note i=p_max. */ cp_extend(this_plot, i + (i < 1000 ? i : 1000)); } if (!line[1]) { /* is it blank line ? */ /* break in data, make next point undefined */ this_plot->points[i].type = UNDEFINED; i++; continue; } if (strlen(format) != 0) { /* use old sscanf if a format string was given */ m = sscanf(line, format, &fval[0], &fval[1], &fval[2], &fval[3], &fval[4]); for (n=0; n<5; n++) /* convert floats from sscanf to double */ val[n] = (double)fval[n]; for (j=0; j<5 && fcol[j]>=0 && fcol[j]-1<m ; j++) if (fcol[j]) v[j] = val[fcol[j]-1]; else v[j] = datum; /* using 0:n */ } else { /* implement our own sscanf that skips lines with invalid data * if a using statement was given */ /* convert the array to its constituents */ for(n=0; n<5; n++) /* wipe the array */ val[n] = 0.0; n=0; /* n is column number */ m=0; /* m is number of values read */ linestat = 1; /* linestat: 1 OK 2 bad value 0 EOL */ s = line; while ((linestat == 1) && (n<col)) { while (isspace(*s)) s++; if (*s == '\0') { linestat = 0; break; } n++; if (n == scol[m]) { if (isdigit(*s) || *s=='-' || *s=='+' || *s=='.') { val[m] = atof(s); m++; } else linestat = 2; /* abort the line non-digit in req loc */ } while ((!isspace(*s)) && (*s != '\0')) s++; } if (using && (linestat == 2)) continue; /* skip lines where a using pattern is present and not met */ for (j=0; j<5 && ncol[j]>=0 && ncol[j]-1<m ; j++) if (ncol[j]) v[j] = val[ncol[j]-1]; else v[j] = datum; /* using 0:n */ } switch (j) { case 1: { /* only one number */ /* x is index, assign number to y */ v[1]=v[0]; v[0]=datum; /* nobreak */ } case 2: { /* x, y */ /* ylow and yhigh are same as y */ datum++; store2d_point(this_plot, i++, v[0], v[1], v[1], v[1], -1.0); break; } case 3: { /* x, y, ydelta */ /* ydelta is in the ylow variable */ datum++; store2d_point(this_plot, i++, v[0], v[1], v[1]-v[2], v[1]+v[2], -1.0); break; } case 4: { /* x, y, ylow, yhigh */ datum++; store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], -1.0); break; } case 5: { /* x, y, ylow, yhigh, width */ datum++; store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4]); break; } default: { (void) sprintf(line, "bad data on line %d", l_num); /* close file before exiting to command level */ #if defined(unix) || defined(PIPES) if (pipe_open) { (void) pclose(data_fp); pipe_open = FALSE; } else #endif /* unix || PIPES */ (void) fclose(data_fp); data_fp=NULL; int_error(line, c_token); } } } this_plot->p_count = i; cp_extend(this_plot, i); /* shrink to fit */ #if defined(unix) || defined(PIPES) if (pipe_open) { (void) pclose(data_fp); pipe_open = FALSE; } else #endif /* unix || PIPES */ (void) fclose(data_fp); data_fp=NULL; } /* called by get_data for each point */ store2d_point(this_plot, i, x, y, ylow, yhigh, width) struct curve_points *this_plot; int i; /* point number */ double x, y; double ylow, yhigh; double width; { struct coordinate GPHUGE *cp = &(this_plot->points[i]); /* the easy part: */ cp->type = INRANGE; cp->x = x; cp->y = y; cp->ylow = ylow; cp->yhigh = yhigh; cp->z = width; /* jev -- pass data values thru user-defined function */ if (ydata_func.at) { struct value val; (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0); evaluate_at(ydata_func.at, &val); cp->y = real(&val); (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0); evaluate_at(ydata_func.at, &val); cp->ylow = real(&val); (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0); evaluate_at(ydata_func.at, &val); cp->yhigh = real(&val); } /* Adjust for log scale. */ if (is_log_x) { cp->type = adjustlog(cp->type, &(cp->x), log_base_log_x); (void) adjustlog(cp->type, &(cp->z), log_base_log_z); } if (is_log_y) { cp->type = adjustlog(cp->type, &(cp->y), log_base_log_y); /* Note ylow,yhigh can't affect cp->type. */ (void) adjustlog(cp->type, &(cp->ylow), log_base_log_y); (void) adjustlog(cp->type, &(cp->yhigh), log_base_log_y); } /* Now adjust the xrange, or declare the point out of range */ /* * The yrange is handled later, once we know whether to include ylow, * yhigh in the calculation. See adjust_yrange() */ if (cp->type == INRANGE) if (autoscale_lx || inrange(x, xmin, xmax)) { if (autoscale_lx) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; } } else { cp->type = OUTRANGE; } } /* * Adjust for log scale: take the log of the second parameter, in place, if * possible. If not possible, return new type for point; if possible, then * return old type for point. The log is taken to the base implicit in the * third parameter. */ static enum coord_type adjustlog(type, val, log_base_log) enum coord_type type; coordval *val; double log_base_log; { if (*val < 0.0) { return (UNDEFINED); } else if (*val == 0.0) { *val = -VERYLARGE; return (OUTRANGE); } else { *val = log(*val)/log_base_log; return (type); } } /* now adjust the yrange, or declare the point out of range */ /* this does all points in a curve */ adjust_yrange(curve) struct curve_points *curve; { TBOOLEAN ebars = (curve->plot_style == ERRORBARS); int npoints = curve->p_count; /* number of points */ coordval y, ylow, yhigh; /* one point value */ struct coordinate GPHUGE *cp; /* one coordinate */ int i; /* index into points */ for (i = 0; i < npoints; i++) { cp = &(curve->points[i]); if (cp->type == INRANGE) { y = is_log_y ? pow(base_log_y, cp->y) : cp->y; if ((autoscale_ly || /* * inrange((is_log_y ? pow(base_log_y, y) : y), ymin, ymax) || */ inrange((y), ymin, ymax) || polar)) { if (autoscale_ly) { if (y < ymin) ymin = y; if (y > ymax) ymax = y; if (ebars) { ylow = is_log_y ? pow(base_log_y, cp->ylow) : cp->ylow; yhigh = is_log_y ? pow(base_log_y, cp->yhigh) : cp->yhigh; if (ylow < ymin) ymin = ylow; if (ylow > ymax) ymax = ylow; if (yhigh < ymin) ymin = yhigh; if (yhigh > ymax) ymax = yhigh; } } } else { cp->type = OUTRANGE; } } } } grid_nongrid_data(this_plot) struct surface_points *this_plot; { int i, j, k; double x, y, z, w, dx, dy, xmin, xmax, ymin, ymax; struct iso_curve *old_iso_crvs = this_plot->iso_crvs; struct iso_curve *icrv, *oicrv, *oicrvs; /* Compute XY bounding box on the original data. */ xmin = xmax = old_iso_crvs->points[0].x; ymin = ymax = old_iso_crvs->points[0].y; for (icrv = old_iso_crvs; icrv != NULL; icrv = icrv->next) { struct coordinate GPHUGE *points = icrv->points; for (i = 0; i < icrv->p_count; i++, points++) { if (xmin > points->x) xmin = points->x; if (xmax < points->x) xmax = points->x; if (ymin > points->y) ymin = points->y; if (ymax < points->y) ymax = points->y; } } dx = (xmax - xmin) / (dgrid3d_row_fineness - 1); dy = (ymax - ymin) / (dgrid3d_row_fineness - 1); /* Create the new grid structure, and compute the low pass filtering from * non grid to grid structure. */ this_plot->iso_crvs = NULL; this_plot->num_iso_read = dgrid3d_col_fineness; this_plot->has_grid_topology = TRUE; for (i = 0, x = xmin; i < dgrid3d_col_fineness; i++, x += dx) { struct coordinate GPHUGE *points; icrv = iso_alloc(dgrid3d_row_fineness + 1); icrv->p_count = dgrid3d_row_fineness; icrv->next = this_plot->iso_crvs; this_plot->iso_crvs = icrv; points = icrv->points; for (j = 0, y = ymin; j < dgrid3d_row_fineness; j++, y += dy, points++) { z = w = 0.0; for (oicrv = old_iso_crvs; oicrv != NULL; oicrv = oicrv->next) { struct coordinate GPHUGE *opoints = oicrv->points; for (k = 0; k < oicrv->p_count; k++, opoints++) { double dist, dist_x = fabs( opoints->x - x ), dist_y = fabs( opoints->y - y ); switch (dgrid3d_norm_value) { case 1: dist = dist_x + dist_y; break; case 2: dist = dist_x * dist_x + dist_y * dist_y; break; case 4: dist = dist_x * dist_x + dist_y * dist_y; dist *= dist; break; case 8: dist = dist_x * dist_x + dist_y * dist_y; dist *= dist; dist *= dist; break; case 16: dist = dist_x * dist_x + dist_y * dist_y; dist *= dist; dist *= dist; dist *= dist; break; default: dist = pow( dist_x, dgrid3d_norm_value ) + pow( dist_y, dgrid3d_norm_value ); break; } /* The weight of this point is inverse proportional * to the distance. */ if ( dist == 0.0 ) #ifndef AMIGA_SC_6_1 dist = VERYLARGE; #else /* AMIGA_SC_6_1 */ /* Multiplying VERYLARGE by opoints->z below * might yield Inf (i.e. a number that can't * be represented on the machine). This will * result in points->z being set to NaN. It's * better to have a pretty large number that is * also on the safe side... The numbers that are * read by gnuplot are float values anyway, so * they can't be bigger than FLT_MAX. So setting * dist to FLT_MAX^2 will make dist pretty large * with respect to any value that has been read. */ dist = ((double)FLT_MAX)*((double)FLT_MAX); #endif /* AMIGA_SC_6_1 */ else dist = 1.0 / dist; z += opoints->z * dist; w += dist; } } points->x = x; points->y = y; points->z = z / w; points->type = INRANGE; } } /* Delete the old non grid data. */ for (oicrvs = old_iso_crvs; oicrvs != NULL;) { oicrv = oicrvs; oicrvs = oicrvs->next; iso_free(oicrv); } } get_3ddata(this_plot) struct surface_points *this_plot; { register int i, j, l_num, xdatum, ydatum; float x, y, z; char data_file[MAX_LINE_LEN + 1], line[MAX_LINE_LEN + 1]; char *float_format = "%f", *float_skip = "%*f"; static TBOOLEAN only_z = FALSE, using_format = FALSE; static int xcol = 1, ycol = 2, zcol = 3, index = -1; static char format[MAX_LINE_LEN + 1]; int pt_in_iso_crv = 0, maxcol, num_col; enum XYZ_order_type { XYZ, YXZ, ZXY, XZY, ZYX, YZX, XY, YX } xyz_order; struct iso_curve *this_iso; /* close forgotten file (in case of a syntax error) */ if (data_fp && !more_data_fp) { #if defined(unix) || defined(PIPES) if (pipe_open) { (void) pclose(data_fp); pipe_open = FALSE; } else #endif /* unix || PIPES */ (void) fclose(data_fp); data_fp=NULL; } quotel_str(data_file, c_token); this_plot->plot_type = DATA3D; this_plot->has_grid_topology = TRUE; if (!more_data_fp) { #if defined(unix) || defined(PIPES) if (*data_file == '<') { if ((data_fp = popen(data_file + 1, "r")) == (FILE *) NULL) os_error("cannot create pipe; output not changed", c_token); else pipe_open = TRUE; } else #endif /* unix || PIPES */ if ((data_fp = fopen(data_file, "r")) == (FILE *) NULL) os_error("can't open data file", c_token); /* Initialize defualt values. */ only_z = FALSE; using_format = FALSE; xcol = 1; ycol = 2; zcol = 3; index = -1; format[0] = '\0'; c_token++; /* skip data file name */ if (almost_equals(c_token, "i$ndex")) { struct value a; c_token++; /* skip "index" */ index = (int) magnitude(const_express(&a)); } if (almost_equals(c_token, "u$sing")) { c_token++; /* skip "using" */ if (!END_OF_COMMAND && !isstring(c_token)) { struct value a; zcol = (int) magnitude(const_express(&a)); only_z = TRUE; if (equals(c_token, ":")) { c_token++; /* skip ":" */ only_z = FALSE; ycol = zcol; zcol = (int) magnitude(const_express(&a)); if (equals(c_token, ":")) { c_token++; /* skip ":" */ xcol = ycol; ycol = zcol; zcol = (int) magnitude(const_express(&a)); } else { if (mapping3d == MAP3D_CARTESIAN) int_error("Must specify 1 or 3 columns", c_token); xcol = ycol; ycol = zcol; } } if (!only_z) if ((xcol == ycol) || (ycol == zcol) || (xcol == zcol)) int_error("Columns must be distinct", c_token); } if (!END_OF_COMMAND && isstring(c_token)) { quotel_str(format, c_token); using_format = TRUE; c_token++; /* skip format */ } } else { if ( (only_z = !parametric) != FALSE) zcol = 1; } } switch (mapping3d) { case MAP3D_CARTESIAN: maxcol = (xcol > ycol) ? xcol : ycol; maxcol = (maxcol > zcol) ? maxcol : zcol; if (!only_z) { /* Determine ordering of input columns */ if (zcol == maxcol) { if (xcol < ycol) xyz_order = XYZ; /* scanf(x,y,z) */ else xyz_order = YXZ; /* scanf(y,x,z) */ } else if (ycol == maxcol) { if (xcol < zcol) xyz_order = XZY; /* scanf(x,z,y) */ else xyz_order = ZXY; /* scanf(z,x,y) */ } else { if (ycol < zcol) xyz_order = YZX; /* scanf(y,z,x) */ else xyz_order = ZYX; /* scanf(z,y,x) */ } } if (strlen(format) == 0) { if (only_z) { for (i = 1; i <= zcol; i++) if (i == zcol) (void) strcat(format, float_format); else (void) strcat(format, float_skip); } else { for (i = 1; i <= maxcol; i++) if ((i == xcol) || (i == ycol) || (i == zcol)) (void) strcat(format, float_format); else (void) strcat(format, float_skip); } } break; case MAP3D_SPHERICAL: case MAP3D_CYLINDRICAL: if (only_z) int_error("Two or three columns for spherical/cylindrical coords.", c_token); maxcol = (xcol > ycol) ? xcol : ycol; maxcol = (maxcol > zcol) ? maxcol : zcol; xyz_order = (xcol < ycol) ? XY : YX; for (i = 1; i <= maxcol; i++) if ((i == xcol) || (i == ycol)) (void) strcat(format, float_format); else (void) strcat(format, float_skip); } l_num = 0; xdatum = 0; ydatum = 0; this_plot->num_iso_read = 0; this_plot->has_grid_topology = TRUE; if (this_plot->iso_crvs != NULL) { struct iso_curve *icrv, *icrvs = this_plot->iso_crvs; while (icrvs) { icrv = icrvs; icrvs = icrvs->next; iso_free(icrv); } this_plot->iso_crvs = NULL; } if (!more_data_fp && is_binary_file(data_fp)) { /* MOD--RKC */ #if defined(MSDOS)||defined(ATARI)||defined(OS2)||defined(_Windows)||defined(DOS386) /* file must be opened with binary flag. the old cr/lf problem again */ #ifdef PIPES if( pipe_open ) { pclose(data_fp); data_fp=NULL; pipe_open=FALSE; int_error("binary data from pipes is not implemented", NO_CARET); } #endif data_fp = freopen(data_file, "rb", data_fp); #endif xdatum = get_binary_data(this_plot, data_fp, &this_iso); } else { int last_line_blank = FALSE; more_data_fp = FALSE; this_iso = iso_alloc(samples); if (index > 0) { /* Skip data meshes until mesh index is reached. */ int i = index; while (i--) { while (fgets(line, MAX_LINE_LEN, data_fp) != (char *) NULL) { l_num++; if (!line[1]) { /* is it blank line ? */ if (last_line_blank) /* Two consecutive blanks. */ break; last_line_blank = TRUE; } else last_line_blank = FALSE; } if (feof(data_fp)) int_error("mesh index overflow", NO_CARET); } } /* end of index skip */ last_line_blank = FALSE; while (fgets(line, MAX_LINE_LEN, data_fp) != (char *) NULL) { l_num++; if (is_comment(line[0])) continue; /* ignore comments */ if (!line[1]) { /* is it blank line ? */ if (last_line_blank) { /* Two consecutive blank lines. */ more_data_fp = TRUE; break; } last_line_blank = TRUE; if (pt_in_iso_crv == 0) { if (xdatum == 0) continue; pt_in_iso_crv = xdatum; } if (xdatum > 0) { this_iso->p_count = xdatum; this_iso->next = this_plot->iso_crvs; this_plot->iso_crvs = this_iso; this_plot->num_iso_read++; if (xdatum != pt_in_iso_crv) this_plot->has_grid_topology = FALSE; this_iso = iso_alloc(pt_in_iso_crv); xdatum = 0; ydatum++; } continue; } last_line_blank = FALSE; if (xdatum >= this_iso->p_max) { /* * overflow about to occur. Extend size of points[] array. We * either double the size, or add 1000 points, whichever is a * smaller increment. Note i=p_max. */ iso_extend(this_iso, xdatum + (xdatum < 1000 ? xdatum : 1000)); } switch (num_col = sscanf(line, format, &x, &y, &z)) { case 3: /* All parameter are specified. */ if (!only_z || using_format) { switch (xyz_order) { case XYZ: /* scanf(x,y,z) */ this_iso->points[xdatum].x = x; this_iso->points[xdatum].y = y; this_iso->points[xdatum].z = z; break; case XZY: /* scanf(x,z,y) */ this_iso->points[xdatum].x = x; this_iso->points[xdatum].y = z; this_iso->points[xdatum].z = y; break; case YXZ: /* scanf(y,x,z) */ this_iso->points[xdatum].x = y; this_iso->points[xdatum].y = x; this_iso->points[xdatum].z = z; break; case ZXY: /* scanf(z,x,y) */ this_iso->points[xdatum].x = y; this_iso->points[xdatum].y = z; this_iso->points[xdatum].z = x; break; case YZX: /* scanf(y,z,x) */ this_iso->points[xdatum].x = z; this_iso->points[xdatum].y = x; this_iso->points[xdatum].z = y; break; case ZYX: /* scanf(z,y,x) */ this_iso->points[xdatum].x = z; this_iso->points[xdatum].y = y; this_iso->points[xdatum].z = x; break; } if (xyz_order != XYZ) { x = this_iso->points[xdatum].x; y = this_iso->points[xdatum].y; z = this_iso->points[xdatum].z; } if (!parametric) int_error("Must be in parametric mode.", NO_CARET); break; } case 1: /* only one number on the line */ if (!only_z && !using_format) int_error("3 columns expected, only 1 found", c_token); /* assign that number to z */ this_iso->points[xdatum].z = x; z = x; this_iso->points[xdatum].x = xdatum; x = this_iso->points[xdatum].x; this_iso->points[xdatum].y = ydatum; y = this_iso->points[xdatum].y; if (parametric) int_error("Must be in non parametric mode.", NO_CARET); break; case 2: switch (xyz_order) { case YX: z = x; /* Use z as temp */ x = y; y = z; break; default: break; } switch (mapping3d) { case MAP3D_CARTESIAN: int_error("2 columns found, 1 or 3 expected", c_token); break; case MAP3D_SPHERICAL: if (angles_format == ANGLES_DEGREES) { x *= DEG2RAD; /* Convert to radians. */ y *= DEG2RAD; } if( num_col == 2) z = 1.0; this_iso->points[xdatum].x = z*cos(x) * cos(y); this_iso->points[xdatum].y = z*sin(x) * cos(y); this_iso->points[xdatum].z = z*sin(y); break; case MAP3D_CYLINDRICAL: if (angles_format == ANGLES_DEGREES) x *= DEG2RAD; /* Convert to radians. */ if( num_col == 2) z = 1.0; this_iso->points[xdatum].x = z*cos(x); this_iso->points[xdatum].y = z*sin(x); this_iso->points[xdatum].z = y; break; } x = this_iso->points[xdatum].x; y = this_iso->points[xdatum].y; z = this_iso->points[xdatum].z; break; default: (void) sprintf(line, "bad data on line %d", l_num); int_error(line, c_token); } if (is_log_x) { if (x <= 0.0) int_error("X value must be above 0 for log scale!", NO_CARET); else this_iso->points[xdatum].x = log(this_iso->points[xdatum].x)/log_base_log_x; } if (is_log_y) { if (y <= 0.0) int_error("Y value must be above 0 for log scale!", NO_CARET); else this_iso->points[xdatum].y = log(this_iso->points[xdatum].y)/log_base_log_y; } if (is_log_z) { if (z <= 0.0) int_error("Z value must be above 0 for log scale!", NO_CARET); else this_iso->points[xdatum].z = log(this_iso->points[xdatum].z)/log_base_log_z; } 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; } if (autoscale_lz) { if (z < zmin) zmin = z; if (z > zmax) zmax = z; } xdatum++; } /* end of while loop */ if (xdatum > 0) { this_plot->num_iso_read++; /* Update last iso. */ this_iso->p_count = xdatum; this_iso->next = this_plot->iso_crvs; this_plot->iso_crvs = this_iso; if (xdatum != pt_in_iso_crv) this_plot->has_grid_topology = FALSE; } else { iso_free(this_iso); /* Free last allocation. */ } } /* MOD-RKC else of binary */ if (index >= 0) more_data_fp = FALSE; /* Only one data set please. */ if (!more_data_fp) { if (this_plot->num_iso_read <= 1) this_plot->has_grid_topology = FALSE; #if defined(unix) || defined(PIPES) if (pipe_open) { if (this_plot->has_grid_topology && !hidden3d) { (void) pclose(data_fp); pipe_open = FALSE; } } else #endif /* unix || PIPES */ { (void) fclose(data_fp); data_fp = NULL; } } if (dgrid3d) grid_nongrid_data(this_plot); if (this_plot->num_iso_read <= 1) this_plot->has_grid_topology = FALSE; if (this_plot->has_grid_topology && !hidden3d) { struct iso_curve *new_icrvs = NULL; int num_new_iso = this_plot->iso_crvs->p_count, len_new_iso = this_plot->num_iso_read; /* Now we need to set the other direction (pseudo) isolines. */ for (i = 0; i < num_new_iso; i++) { struct iso_curve *new_icrv = iso_alloc(len_new_iso); new_icrv->p_count = len_new_iso; for (j = 0, this_iso = this_plot->iso_crvs; this_iso != NULL; j++, this_iso = this_iso->next) { new_icrv->points[j].x = this_iso->points[i].x; new_icrv->points[j].y = this_iso->points[i].y; new_icrv->points[j].z = this_iso->points[i].z; } new_icrv->next = new_icrvs; new_icrvs = new_icrv; } /* Append the new iso curves after the read ones. */ for (this_iso = this_plot->iso_crvs; this_iso->next != NULL; this_iso = this_iso->next); this_iso->next = new_icrvs; } } /* * print_points: a debugging routine to print out the points of a curve, and * the curve structure. If curve<0, then we print the list of curves. */ static char *plot_type_names[4] = { "Function", "Data", "3D Function", "3d data" }; static char *plot_style_names[6] = { "Lines", "Points", "Impulses", "LinesPoints", "Dots", "Errorbars" }; print_points(curve) int curve; /* which curve to print */ { register struct curve_points *this_plot; int i; if (curve < 0) { for (this_plot = first_plot, i = 0; this_plot != NULL; i++, this_plot = this_plot->next_cp) { printf("Curve %d:\n", i); if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4) printf("Plot type %d: %s\n", (int) (this_plot->plot_type), plot_type_names[(int) (this_plot->plot_type)]); else printf("Plot type %d: BAD\n", (int) (this_plot->plot_type)); if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 6) printf("Plot style %d: %s\n", (int) (this_plot->plot_style), plot_style_names[(int) (this_plot->plot_style)]); else printf("Plot style %d: BAD\n", (int) (this_plot->plot_style)); printf("Plot title: '%s'\n", this_plot->title); printf("Line type %d\n", this_plot->line_type); printf("Point type %d\n", this_plot->point_type); printf("max points %d\n", this_plot->p_max); printf("current points %d\n", this_plot->p_count); printf("\n"); } } else { for (this_plot = first_plot, i = 0; i < curve && this_plot != NULL; i++, this_plot = this_plot->next_cp); if (this_plot == NULL) printf("Curve %d does not exist; list has %d curves\n", curve, i); else { printf("Curve %d, %d points\n", curve, this_plot->p_count); for (i = 0; i < this_plot->p_count; i++) { printf("%c x=%g y=%g z=%g ylow=%g yhigh=%g\n", this_plot->points[i].type == INRANGE ? 'i' : this_plot->points[i].type == OUTRANGE ? 'o' : 'u', this_plot->points[i].x, this_plot->points[i].y, this_plot->points[i].z, this_plot->points[i].ylow, this_plot->points[i].yhigh); } printf("\n"); } } } print_table() { register struct curve_points *this_plot; int i, curve; for (this_plot = first_plot, curve = 0; this_plot != NULL; curve++, this_plot = this_plot->next_cp) { fprintf(outfile, "Curve %d, %d points\n", curve, this_plot->p_count); for (i = 0; i < this_plot->p_count; i++) { fprintf(outfile, "%c x=%g y=%g\n", this_plot->points[i].type == INRANGE ? 'i' : this_plot->points[i].type == OUTRANGE ? 'o' : 'u', this_plot->points[i].x, this_plot->points[i].y); } fprintf(outfile, "\n"); } fflush(outfile); } print_3dtable() { register struct surface_points *this_3dplot; int i, curve; struct iso_curve *isocrv; for (this_3dplot = first_3dplot, curve = 0; this_3dplot != NULL; curve++, this_3dplot = this_3dplot->next_sp) { isocrv = this_3dplot->iso_crvs; fprintf(outfile, "Curve %d, %d points\n", curve, isocrv->p_count); for (i = 0; i < isocrv->p_count; i++) { fprintf(outfile, "%c x=%g y=%g z=%g\n", isocrv->points[i].type == INRANGE ? 'i' : isocrv->points[i].type == OUTRANGE ? 'o' : 'u', isocrv->points[i].x, isocrv->points[i].y, isocrv->points[i].z); } fprintf(outfile, "\n"); } fflush(outfile); } /* * 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; register struct curve_points *this_plot, **tp_ptr; register int start_token, end_token; register int begin_token; double x_min, x_max, y_min, y_max; register double x, xdiff, temp; static struct value a; TBOOLEAN ltmp, some_data_files = FALSE,is_log_func = FALSE; int plot_num, line_num, point_num, xparam = 0; char *xtitle; void parametric_fixup(); if (autoscale_ly) { ymin = VERYLARGE; ymax = -VERYLARGE; } else if (is_log_y && (ymin <= 0.0 || ymax <= 0.0)) int_error("y range must be above 0 for log scale!", NO_CARET); tp_ptr = &(first_plot); plot_num = 0; line_num = 0; /* default line type */ point_num = 0; /* default point type */ xtitle = NULL; 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); start_token = c_token; if (is_definition(c_token)) { define(); } else { plot_num++; if (isstring(c_token)) { /* data file to plot */ if (parametric && xparam) int_error("previous parametric function not fully specified", c_token); if (!some_data_files && autoscale_lx) { xmin = VERYLARGE; xmax = -VERYLARGE; } some_data_files = TRUE; if (*tp_ptr) this_plot = *tp_ptr; else { /* no memory malloc()'d there yet */ this_plot = cp_alloc(MIN_CRV_POINTS); *tp_ptr = this_plot; } this_plot->plot_type = DATA; this_plot->plot_style = data_style; end_token = c_token; get_data(this_plot); /* this also parses the using option */ } else { /* function to plot */ if (parametric) /* working on x parametric function */ xparam = 1 - xparam; if (*tp_ptr) { this_plot = *tp_ptr; cp_extend(this_plot, samples + 1); } else { /* no memory malloc()'d there yet */ this_plot = cp_alloc(samples + 1); *tp_ptr = this_plot; } this_plot->plot_type = FUNC; this_plot->plot_style = func_style; dummy_func = &plot_func; plot_func.at = temp_at(); /* ignore it for now */ end_token = c_token - 1; } if (almost_equals(c_token, "t$itle")) { if (parametric) { if (xparam) int_error( "\"title\" allowed only after parametric function fully specified", c_token); else if (xtitle != NULL) xtitle[0] = '\0'; /* Remove default title . */ } c_token++; if (isstring(c_token)) { m_quote_capture(&(this_plot->title), c_token, c_token); } else { int_error("expecting \"title\" for plot", c_token); } c_token++; } else if (almost_equals(c_token, "not$itle")) { c_token++; } else { m_capture(&(this_plot->title), start_token, end_token); if (xparam) xtitle = this_plot->title; } this_plot->line_type = line_num; this_plot->point_type = point_num; if (almost_equals(c_token, "w$ith")) { if (parametric && xparam) int_error("\"with\" allowed only after parametric function fully specified", c_token); this_plot->plot_style = get_style(); } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; this_plot->line_type = (int) real(const_express(&t)) - 1; } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; this_plot->point_type = (int) real(const_express(&t)) - 1; } if ((this_plot->plot_style == POINTSTYLE) || (this_plot->plot_style == LINESPOINTS) || (this_plot->plot_style == ERRORBARS)) if (!xparam) point_num++; if (!xparam) line_num++; if (this_plot->plot_type == DATA) /* now that we know the plot style, adjust the yrange */ adjust_yrange(this_plot); tp_ptr = &(this_plot->next_cp); } if (equals(c_token, ",")) c_token++; else break; } if (parametric && xparam) int_error("parametric function not fully specified", NO_CARET); if (parametric) { /* Swap t and x ranges for duration of these eval_plot computations. */ ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp; temp = xmin; xmin = tmin; tmin = temp; temp = xmax; xmax = tmax; tmax = temp; } /*** 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 (fabs(xmax - xmin) < zero) if (autoscale_lx) { fprintf(stderr, "Warning: empty %c range [%g:%g], ", parametric ? 't' : 'x', xmin, xmax); if (fabs(xmin) < zero) { /* completely arbitary */ xmin = -1.; xmax = 1.; } else { /* expand range by 10% in either direction */ xmin = xmin * 0.9; xmax = xmax * 1.1; } fprintf(stderr, "adjusting to [%g:%g]\n", xmin, xmax); } else { int_error("x range is less than `zero`", c_token); } /* give error if xrange badly set from missing datafile error */ if (xmin == VERYLARGE || xmax == -VERYLARGE) { int_error("x range is invalid", c_token); } if (is_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 = log(xmin)/log_base_log_x; x_max = log(xmax)/log_base_log_x; } else { x_min = xmin; x_max = xmax; } xdiff = (x_max - x_min) / (samples - 1); tp_ptr = &(first_plot); plot_num = 0; this_plot = first_plot; c_token = begin_token; /* start over */ /* Read through functions */ while (TRUE) { if (is_definition(c_token)) { define(); } else { plot_num++; if (isstring(c_token)) { /* data file to plot */ /* ignore this now */ c_token++; /* * jev -- support for passing data from file thru user * function */ if (almost_equals(c_token, "thru$")) { struct udft_entry tmp; c_token++; dummy_func = &tmp; (void) temp_at(); } if (almost_equals(c_token, "u$sing")) { c_token++; /* skip "using" */ if (!isstring(c_token)) { struct value a; (void) magnitude(const_express(&a)); /* skip xcol */ if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip ycol */ } if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip yemin */ } if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip yemax */ } if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip wcol */ } } if (isstring(c_token)) c_token++; /* skip format string */ } } else { /* function to plot */ if (parametric) /* working on x parametric function */ xparam = 1 - xparam; dummy_func = &plot_func; plot_func.at = temp_at(); /* reparse function */ is_log_func=parametric?(xparam?is_log_x:is_log_y):is_log_y; for (i = 0; i < samples; i++) { x = x_min + i * xdiff; /* if (is_log_x) PEM fix logscale x axis */ /* x = pow(base_log_x,x); 26-Sep-89 */ (void) Gcomplex(&plot_func.dummy_values[0], is_log_x ? pow(base_log_x, x) : x, 0.0); evaluate_at(plot_func.at, &a); if (undefined || (fabs(imag(&a)) > zero)) { this_plot->points[i].type = UNDEFINED; continue; } temp = real(&a); if (is_log_func && temp < 0.0) { this_plot->points[i].type = UNDEFINED; continue; } this_plot->points[i].x = x; this_plot->points[i].z = -1.0; /* width of box not specified */ if (is_log_func) { if (temp == 0.0) { this_plot->points[i].type = OUTRANGE; this_plot->points[i].y = -VERYLARGE; continue; } else { this_plot->points[i].y = log(temp)/log_base_log_y; } } else this_plot->points[i].y = temp; if (autoscale_ly || polar || inrange(temp, ymin, ymax)) { this_plot->points[i].type = INRANGE; /* When xparam is 1 we are not really computing y's! */ if (!xparam && autoscale_ly) { if (temp < ymin) ymin = temp; if (temp > ymax) ymax = temp; } } else this_plot->points[i].type = OUTRANGE; } this_plot->p_count = i; /* samples */ } /* title was handled above */ if (almost_equals(c_token, "t$itle")) { c_token++; c_token++; } else if (almost_equals(c_token, "not$itle")) { c_token++; } /* style was handled above */ if (almost_equals(c_token, "w$ith")) { c_token++; c_token++; } /* line and point types were handled above */ if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; (void) real(const_express(&t)); } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; (void) real(const_express(&t)); } tp_ptr = &(this_plot->next_cp); /* used below */ this_plot = this_plot->next_cp; } if (equals(c_token, ",")) c_token++; else break; } /* throw out all curve_points at end of list, that we don't need */ cp_free(*tp_ptr); *tp_ptr = NULL; if (fabs(ymax - ymin) < zero) /* if autoscale, widen range */ if (autoscale_ly) { fprintf(stderr, "Warning: empty y range [%g:%g], ", ymin, ymax); if (fabs(ymin) < zero) { ymin = -1.; ymax = 1.; } else { /* expand range by 10% in either direction */ ymin = ymin * 0.9; ymax = ymax * 1.1; } fprintf(stderr, "adjusting to [%g:%g]\n", ymin, ymax); } else { int_error("y range is less than `zero`", c_token); } /* Now we finally know the real ymin and ymax */ if (is_log_y) { y_min = log(ymin)/log_base_log_y; y_max = log(ymax)/log_base_log_y; } else { y_min = ymin; y_max = ymax; } capture(replot_line, plot_token, c_token); if (parametric) { /* Now put t and x ranges back before we actually plot anything. */ ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp; temp = xmin; xmin = tmin; tmin = temp; temp = xmax; xmax = tmax; tmax = temp; if (some_data_files && autoscale_lx) { /* * Stop any further autoscaling in this case (may be a mistake, * have to consider what is really wanted some day in the * future--jdc). */ autoscale_lx = 0; } /* Now actually fix the plot pairs to be single plots. */ parametric_fixup(first_plot, &plot_num, &x_min, &x_max); } if (strcmp(term_tbl[term].name, "table") == 0) print_table(); else do_plot(first_plot, plot_num, x_min, x_max, y_min, y_max); cp_free(first_plot); first_plot = NULL; } static void parse_title(crnt_param, start_token, end_token, xtitle, ytitle, this_plot, do_parse) int crnt_param, start_token, end_token; char **xtitle, **ytitle; struct surface_points *this_plot; TBOOLEAN do_parse; { static char title[256]; if (do_parse) { if (almost_equals(c_token, "t$itle")) { if (parametric) { if (crnt_param) int_error("\"title\" allowed only after parametric function fully specified", c_token); else { /* Remove default title */ if (*xtitle != NULL) (*xtitle)[0] = '\0'; if (*ytitle != NULL) (*ytitle)[0] = '\0'; } } c_token++; if (isstring(c_token)) { m_quote_capture(&(this_plot->title), c_token, c_token); } else { int_error("expecting \"title\" for plot", c_token); } c_token++; } else if (almost_equals(c_token, "not$itle")) { c_token++; } else { m_capture(&(this_plot->title), start_token, end_token); if (crnt_param == 1) *xtitle = this_plot->title; if (crnt_param == 2) *ytitle = this_plot->title; } strncpy(title, this_plot->title, 255); } else { this_plot->title = alloc(strlen(title) + 1); strcpy(this_plot->title, title); } } /* * This parses the splot command after any range specifications. To support * autoscaling on the x/z axis, we want any data files to define the x/y * 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_3dplots() { register int i, j; register struct surface_points *this_plot, **tp_3d_ptr; register int start_token, end_token; register int begin_token; double x_min, x_max, y_min, y_max, z_min, z_max; register double x, xdiff, xisodiff, y, ydiff, yisodiff, temp; static struct value a; TBOOLEAN ltmp, some_data_files = FALSE,is_log_func = FALSE; int plot_num, line_num, point_num, crnt_param = 0; /* 0=z, 1=x, 2=y */ char *xtitle; char *ytitle; void parametric_3dfixup(); if (autoscale_lz) { zmin = VERYLARGE; zmax = -VERYLARGE; } else if (is_log_z && (zmin <= 0.0 || zmax <= 0.0)) int_error("z range must be above 0 for log scale!", NO_CARET); tp_3d_ptr = &(first_3dplot); plot_num = 0; line_num = 0; /* default line type */ point_num = 0; /* default point type */ xtitle = NULL; ytitle = NULL; begin_token = c_token; /*** First Pass: Read through data files ***/ /* * This pass serves to set the x/yranges and to parse the command, as * well as filling in every thing except the function data. That is done * after the x/yrange is defined. */ while (TRUE) { if (END_OF_COMMAND) int_error("function to plt3d expected", c_token); start_token = c_token; if (is_definition(c_token)) { define(); } else { plot_num++; if (isstring(c_token)) { /* data file to plot */ int line_type = line_num, point_type = point_num, plot_style = data_style, first_mesh = TRUE; if (parametric && crnt_param != 0) int_error("previous parametric function not fully specified", c_token); if (!some_data_files) { if (autoscale_lx) { xmin = VERYLARGE; xmax = -VERYLARGE; } if (autoscale_ly) { ymin = VERYLARGE; ymax = -VERYLARGE; } } some_data_files = TRUE; do { if (*tp_3d_ptr) this_plot = *tp_3d_ptr; else { /* no memory malloc()'d there yet */ /* Allocate enough isosamples and samples */ this_plot = sp_alloc(0, 0, 0, 0); *tp_3d_ptr = this_plot; } this_plot->plot_type = DATA3D; end_token = c_token; /* this also parses index/using option */ get_3ddata(this_plot); parse_title(crnt_param, start_token, end_token, &xtitle, &ytitle, this_plot, first_mesh); if (!first_mesh) plot_num++; if (first_mesh) { if (almost_equals(c_token, "w$ith")) { plot_style = this_plot->plot_style = get_style(); } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; line_type = (int) real(const_express(&t)) - 1; } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; point_type = (int) real(const_express(&t)) - 1; } first_mesh = FALSE; } this_plot->line_type = line_type; this_plot->point_type = point_type; this_plot->plot_style = plot_style; tp_3d_ptr = &(this_plot->next_sp); } while (more_data_fp); } else { /* function to plot */ if (parametric) /* Rotate between x/y/z axes */ crnt_param = (crnt_param + 1) % 3; if (*tp_3d_ptr) { this_plot = *tp_3d_ptr; if (!hidden3d) sp_replace(this_plot, samples_1, iso_samples_1, samples_2, iso_samples_2); else sp_replace(this_plot, iso_samples_1, 0, 0, iso_samples_2); } else { /* no memory malloc()'d there yet */ /* Allocate enough isosamples and samples */ if (!hidden3d) this_plot = sp_alloc(samples_1, iso_samples_1, samples_2, iso_samples_2); else this_plot = sp_alloc(iso_samples_1, 0, 0, iso_samples_2); *tp_3d_ptr = this_plot; } this_plot->plot_type = FUNC3D; this_plot->has_grid_topology = TRUE; this_plot->plot_style = func_style; dummy_func = &plot_func; plot_func.at = temp_at(); /* ignore it for now */ end_token = c_token - 1; parse_title(crnt_param, start_token, end_token, &xtitle, &ytitle, this_plot, TRUE); this_plot->line_type = line_num; this_plot->point_type = point_num; if (almost_equals(c_token, "w$ith")) { this_plot->plot_style = get_style(); } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; this_plot->line_type = (int) real(const_express(&t)) - 1; } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; this_plot->point_type = (int) real(const_express(&t)) - 1; } tp_3d_ptr = &(this_plot->next_sp); } if ((this_plot->plot_style == POINTSTYLE) || (this_plot->plot_style == LINESPOINTS) || (this_plot->plot_style == ERRORBARS)) if (crnt_param == 0) point_num += 1 + (draw_contour != 0) + (hidden3d != 0); if (crnt_param == 0) line_num += 1 + (draw_contour != 0) + (hidden3d != 0); } if (equals(c_token, ",")) c_token++; else break; } if (parametric && crnt_param != 0) int_error("parametric function not fully specified", NO_CARET); if (parametric) { /* * Swap u/v and x/y ranges for duration of these eval_plot * computations. */ ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp; ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp; temp = xmin; xmin = umin; umin = temp; temp = xmax; xmax = umax; umax = temp; temp = ymin; ymin = vmin; vmin = temp; temp = ymax; ymax = vmax; vmax = temp; } /*** 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], ", xmin, xmax); if (xmin == 0.0) { /* completely arbitary */ xmin = -1.; xmax = 1.; } else { /* expand range by 10% in either direction */ xmin = xmin * 0.9; xmax = xmax * 1.1; } fprintf(stderr, "adjusting to [%g:%g]\n", xmin, xmax); } else { int_error("x range is empty", c_token); } if (ymin == ymax) if (autoscale_ly) { fprintf(stderr, "Warning: empty y range [%g:%g], ", ymin, ymax); if (ymin == 0.0) { /* completely arbitary */ ymin = -1.; ymax = 1.; } else { /* expand range by 10% in either direction */ ymin = ymin * 0.9; ymax = ymax * 1.1; } fprintf(stderr, "adjusting to [%g:%g]\n", ymin, ymax); } else { int_error("y range is empty", c_token); } /* give error if xrange badly set from missing datafile error */ if (xmin == VERYLARGE || xmax == -VERYLARGE) { int_error("x range is invalid", c_token); } if (is_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 = log(xmin)/log_base_log_x; x_max = log(xmax)/log_base_log_x; } else { x_min = xmin; x_max = xmax; } if (is_log_y) { if (ymin <= 0.0 || ymax <= 0.0) int_error("y range must be greater than 0 for log scale!", NO_CARET); y_min = log(ymin)/log_base_log_y; y_max = log(ymax)/log_base_log_y; } else { y_min = ymin; y_max = ymax; } if (samples_1 < 2 || samples_2 < 2 || iso_samples_1 < 2 || iso_samples_2 < 2) int_error("samples or iso_samples < 2. Must be at least 2.", NO_CARET); if (this_plot->has_grid_topology && hidden3d) { xdiff = (x_max - x_min) / (iso_samples_1 - 1); ydiff = (y_max - y_min) / (iso_samples_2 - 1); } else { xdiff = (x_max - x_min) / (samples_1 - 1); ydiff = (y_max - y_min) / (samples_2 - 1); } xisodiff = (x_max - x_min) / (iso_samples_1 - 1); yisodiff = (y_max - y_min) / (iso_samples_2 - 1); this_plot = first_3dplot; c_token = begin_token; /* start over */ /* Read through functions */ while (TRUE) { if (is_definition(c_token)) { define(); } else { if (isstring(c_token)) { /* data file to plot */ /* ignore this now */ c_token++; if (almost_equals(c_token, "i$ndex")) { struct value a; int index; c_token++; /* skip "index" */ index = (int) magnitude(const_express(&a)); } if (almost_equals(c_token, "u$sing")) { c_token++; /* skip "using" */ if (!isstring(c_token)) { struct value a; (void) magnitude(const_express(&a)); /* skip xcol */ if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip ycol */ if (equals(c_token, ":")) { c_token++; /* skip ":" */ (void) magnitude(const_express(&a)); /* skip zcol */ } } } if (isstring(c_token)) c_token++; /* skip format string */ } } else { /* function to plot */ struct iso_curve *this_iso = this_plot->iso_crvs; struct coordinate GPHUGE *points = this_iso->points; int num_sam_to_use, num_iso_to_use; if (parametric) crnt_param = (crnt_param + 1) % 3; dummy_func = &plot_func; plot_func.at = temp_at(); /* reparse function */ num_iso_to_use = iso_samples_2; if (!(this_plot->has_grid_topology && hidden3d)) num_sam_to_use = samples_1; else num_sam_to_use = iso_samples_1; is_log_func=(!parametric)||(crnt_param==0)?is_log_z:(crnt_param==1?is_log_x:is_log_y); for (j = 0; j < num_iso_to_use; j++) { y = y_min + j * yisodiff; /* if (is_log_y) PEM fix logscale y axis */ /* y = pow(log_base_log_y,y); 26-Sep-89 */ (void) Gcomplex(&plot_func.dummy_values[1], is_log_y ? pow(base_log_y, y) : y, 0.0); for (i = 0; i < num_sam_to_use; i++) { x = x_min + i * xdiff; /* if (is_log_x) PEM fix logscale x axis */ /* x = pow(base_log_x,x); 26-Sep-89 */ (void) Gcomplex(&plot_func.dummy_values[0], is_log_x ? pow(base_log_x, x) : x, 0.0); points[i].x = x; points[i].y = y; evaluate_at(plot_func.at, &a); if (undefined || (fabs(imag(&a)) > zero)) { points[i].type = UNDEFINED; continue; } temp = real(&a); if (is_log_func && temp < 0.0) { points[i].type = UNDEFINED; continue; } if (is_log_func) { if (temp == 0.0) { points[i].type = OUTRANGE; points[i].z = -VERYLARGE; continue; } else { points[i].z = log(temp)/log_base_log_z; } } else points[i].z = temp; if (autoscale_lz || inrange(temp, zmin, zmax)) { points[i].type = INRANGE; if (autoscale_lz) { if (temp < zmin) zmin = temp; if (temp > zmax) zmax = temp; } } else points[i].type = OUTRANGE; } this_iso->p_count = num_sam_to_use; this_iso = this_iso->next; points = this_iso? this_iso->points: NULL; } if (!(this_plot->has_grid_topology && hidden3d)) { num_iso_to_use = iso_samples_1; num_sam_to_use = samples_2; is_log_func=(!parametric)||(crnt_param==0)?is_log_z:(crnt_param==1?is_log_x:is_log_y); for (i = 0; i < num_iso_to_use; i++) { x = x_min + i * xisodiff; /* if (is_log_x) PEM fix logscale x axis */ /* x = pow(base_log_x,x); 26-Sep-89 */ (void) Gcomplex(&plot_func.dummy_values[0], is_log_x ? pow(base_log_x, x) : x, 0.0); for (j = 0; j < num_sam_to_use; j++) { y = y_min + j * ydiff; /* if (is_log_y) PEM fix logscale y axis */ /* y = pow(base_log_y,y); 26-Sep-89 */ (void) Gcomplex(&plot_func.dummy_values[1], is_log_y ? pow(base_log_y, y) : y, 0.0); points[j].x = x; points[j].y = y; evaluate_at(plot_func.at, &a); if (undefined || (fabs(imag(&a)) > zero)) { points[j].type = UNDEFINED; continue; } temp = real(&a); if (is_log_func && temp < 0.0) { points[j].type = UNDEFINED; continue; } if (is_log_func) { if (temp == 0.0) { points[j].type = OUTRANGE; points[j].z = -VERYLARGE; continue; } else { points[j].z = log(temp)/log_base_log_z; } } else points[j].z = temp; if (autoscale_lz || inrange(temp, zmin, zmax)) { points[j].type = INRANGE; if (autoscale_lz) { if (temp < zmin) zmin = temp; if (temp > zmax) zmax = temp; } } else points[j].type = OUTRANGE; } this_iso->p_count = num_sam_to_use; this_iso = this_iso->next; points = this_iso ? this_iso->points : NULL; } } } /* title was handled above */ if (almost_equals(c_token, "t$itle")) { c_token++; c_token++; } else if (almost_equals(c_token, "not$itle")) { c_token++; } /* style was handled above */ if (almost_equals(c_token, "w$ith")) { c_token++; c_token++; } /* line and point types were handled above */ if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; (void) real(const_express(&t)); } if (!equals(c_token, ",") && !END_OF_COMMAND) { struct value t; (void) real(const_express(&t)); } this_plot = this_plot->next_sp; } if (equals(c_token, ",")) c_token++; else break; } if (fabs(zmax - zmin) < zero) /* if autoscale, widen range */ if (autoscale_lz) { fprintf(stderr, "Warning: empty z range [%g:%g], ", zmin, zmax); if (fabs(zmin) < zero) { zmin = -1.; zmax = 1.; } else { /* expand range by 10% in either direction */ zmin = zmin * 0.9; zmax = zmax * 1.1; } fprintf(stderr, "adjusting to [%g:%g]\n", zmin, zmax); } else { int_error("z range is less than `zero`", c_token); } /* Now we finally know the real zmin and zmax */ if (is_log_z) { if (zmin <= 0.0 || zmax <= 0.0) int_error("z range must be greater than 0 for log scale!", NO_CARET); z_min = log(zmin)/log_base_log_z; z_max = log(zmax)/log_base_log_z; } else { z_min = zmin; z_max = zmax; } capture(replot_line, plot_token, c_token); if (parametric) { /* Now put u/v and x/y ranges back before we actually plot anything. */ ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp; ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp; temp = xmin; xmin = umin; umin = temp; temp = xmax; xmax = umax; umax = temp; temp = ymin; ymin = vmin; vmin = temp; temp = ymax; ymax = vmax; vmax = temp; /* Now actually fix the plot triplets to be single plots. */ parametric_3dfixup(first_3dplot, &plot_num, &x_min, &x_max, &y_min, &y_max, &z_min, &z_max); if (is_log_x) { if (x_min <= 0.0 || x_max <= 0.0) int_error("x range must be greater than 0 for log scale!", NO_CARET); x_min = log(x_min)/log_base_log_x; x_max = log(x_max)/log_base_log_x; } if (is_log_y) { if (y_min <= 0.0 || y_max <= 0.0) int_error("y range must be greater than 0 for log scale!", NO_CARET); y_min = log(y_min)/log_base_log_y; y_max = log(y_max)/log_base_log_y; } if (is_log_z) { if (z_min <= 0.0 || z_max <= 0.0) int_error("z range must be greater than 0 for log scale!", NO_CARET); z_min = log(z_min)/log_base_log_z; z_max = log(z_max)/log_base_log_z; } } /* Filter out empty meshes. */ while (first_3dplot && first_3dplot->num_iso_read == 0 && first_3dplot->plot_type == DATA3D) { struct surface_points *plt = first_3dplot->next_sp; first_3dplot->next_sp = NULL; sp_free(first_3dplot); plot_num--; first_3dplot = plt; } if (first_3dplot != NULL) { struct surface_points *plt1, *plt2; for (plt1 = first_3dplot, plt2 = plt1->next_sp; plt2 != NULL; ) { if (plt2->num_iso_read == 0 && plt2->plot_type == DATA3D) { plt2 = plt2->next_sp; plt1->next_sp->next_sp = NULL; sp_free(plt1->next_sp); plot_num--; plt1->next_sp = plt2; } else { plt1 = plt2; plt2 = plt2->next_sp; } } } if (first_3dplot == NULL) int_error("no data found in file", NO_CARET); /* Creates contours if contours are to be plotted as well. */ if (draw_contour) { for (this_plot = first_3dplot, i = 0; i < plot_num; this_plot = this_plot->next_sp, i++) { if (this_plot->contours) { struct gnuplot_contours *cntr, *cntrs = this_plot->contours; while (cntrs) { cntr = cntrs; cntrs = cntrs->next; gpfarfree(cntr->coords); free(cntr); } } /* Make sure this one can be contoured. */ if (!this_plot->has_grid_topology) { this_plot->contours = NULL; fprintf(stderr,"Notice: cannot contour non grid data!\n"); /* changed from int_error by recommendation of rkc@xn.ll.mit.edu */ } else if (this_plot->plot_type == DATA3D) this_plot->contours = contour( this_plot->num_iso_read, this_plot->iso_crvs, contour_levels, contour_pts, contour_kind, contour_order, levels_kind, levels_list); else this_plot->contours = contour(iso_samples_2, this_plot->iso_crvs, contour_levels, contour_pts, contour_kind, contour_order, levels_kind, levels_list); } } if (strcmp(term_tbl[term].name, "table") == 0) print_3dtable(); else do_3dplot(first_3dplot, plot_num, x_min, x_max, y_min, y_max, z_min, z_max); sp_free(first_3dplot); first_3dplot = NULL; } done(status) int status; { if (term && term_init) (*term_tbl[term].reset) (); #ifdef vms vms_reset(); #endif exit(status); } void parametric_fixup(start_plot, plot_num, x_min, x_max) struct curve_points *start_plot; int *plot_num; double *x_min, *x_max; /* * The hardest part of this routine is collapsing the FUNC plot types in the * list (which are gauranteed to occur in (x,y) pairs while preserving the * non-FUNC type plots intact. This means we have to work our way through * various lists. Examples (hand checked): start_plot:F1->F2->NULL ==> * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL * * Of course, the more interesting work is to move the y values of the x * function to become the x values of the y function (checking the mins and * maxs as we go along). */ { struct curve_points *xp, *new_list, *yp = start_plot, *tmp, *free_list, *free_head = NULL; int i, tlen, curve; char *new_title; double lxmin, lxmax, temp; if (autoscale_lx) { lxmin = VERYLARGE; lxmax = -VERYLARGE; } else { lxmin = xmin; lxmax = xmax; } /* * Ok, go through all the plots and move FUNC types together. Note: this * originally was written to look for a NULL next pointer, but gnuplot * wants to be sticky in grabbing memory and the right number of items in * the plot list is controlled by the plot_num variable. * * Since gnuplot wants to do this sticky business, a free_list of * curve_points is kept and then tagged onto the end of the plot list as * this seems more in the spirit of the original memory behavior than * simply freeing the memory. I'm personally not convinced this sort of * concern is worth it since the time spent computing points seems to * dominate any garbage collecting that might be saved here... */ new_list = xp = start_plot; yp = xp->next_cp; curve = 0; for (; curve < *plot_num; xp = xp->next_cp, yp = yp ? yp->next_cp : yp, curve++) { if (xp->plot_type != FUNC) { continue; } /* Here's a FUNC parametric function defined as two parts. */ --(*plot_num); /* * Go through all the points assigning the y's from xp to be the x's * for yp. Check max's and min's as you go. */ for (i = 0; i < yp->p_count; ++i) { /* * Throw away excess xp points, mark excess yp points as * OUTRANGE. */ if (i > xp->p_count) { yp->points[i].type = OUTRANGE; continue; } /* * Just as we had to do when we computed y values--now check that * x's (computed parametrically) are in the permitted ranges as * well. */ temp = xp->points[i].y; /* New x value for yp function. */ yp->points[i].x = temp; /* Handle undefined values differently from normal ranges. */ if (xp->points[i].type == UNDEFINED) yp->points[i].type = xp->points[i].type; if (autoscale_lx || polar || inrange(temp, lxmin, lxmax)) { if (autoscale_lx && temp < lxmin) lxmin = temp; if (autoscale_lx && temp > lxmax) lxmax = temp; } else yp->points[i].type = OUTRANGE; /* Due to x value. */ } /* Ok, fix up the title to include both the xp and yp plots. */ if (xp->title && xp->title[0] != '\0') { tlen = strlen(yp->title) + strlen(xp->title) + 3; new_title = alloc((unsigned long) tlen, "string"); strcpy(new_title, xp->title); strcat(new_title, ", "); /* + 2 */ strcat(new_title, yp->title); /* + 1 = + 3 */ free(yp->title); yp->title = new_title; } /* Eliminate the first curve (xparam) and just use the second. */ if (xp == start_plot) { /* Simply nip off the first element of the list. */ new_list = first_plot = yp; xp = xp->next_cp; if (yp->next_cp != NULL) yp = yp->next_cp; /* Add start_plot to the free_list. */ if (free_head == NULL) { free_list = free_head = start_plot; free_head->next_cp = NULL; } else { free_list->next_cp = start_plot; start_plot->next_cp = NULL; free_list = start_plot; } } else { /* Here, remove the xp node and replace it with the yp node. */ tmp = xp; /* Pass over any data files that might have been in place. */ while (new_list->next_cp && new_list->next_cp != xp) new_list = new_list->next_cp; new_list->next_cp = yp; new_list = new_list->next_cp; xp = xp->next_cp; if (yp->next_cp != NULL) yp = yp->next_cp; /* Add tmp to the free_list. */ tmp->next_cp = NULL; if (free_head == NULL) { free_list = free_head = tmp; } else { free_list->next_cp = tmp; free_list = tmp; } } } /* Ok, stick the free list at the end of the curve_points plot list. */ while (new_list->next_cp != NULL) new_list = new_list->next_cp; new_list->next_cp = free_head; /* Report the overall graph mins and maxs. */ *x_min = lxmin; *x_max = lxmax; } void parametric_3dfixup(start_plot, plot_num, x_min, x_max, y_min, y_max, z_min, z_max) struct surface_points *start_plot; int *plot_num; double *x_min, *x_max, *y_min, *y_max, *z_min, *z_max; /* * The hardest part of this routine is collapsing the FUNC plot types in the * list (which are gauranteed to occur in (x,y,z) triplets while preserving * the non-FUNC type plots intact. This means we have to work our way * through various lists. Examples (hand checked): * start_plot:F1->F2->F3->NULL ==> F3->NULL * start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F3->F6->NULL * start_plot:F1->F2->F3->D1->D2->F4->F5->F6->D3->NULL ==> * F3->D1->D2->F6->D3->NULL */ { struct surface_points *xp, *yp, *zp, *new_list, *tmp, *free_list, *free_head = NULL; struct iso_curve *icrvs, *xicrvs, *yicrvs, *zicrvs; int i, tlen, surface; char *new_title; double lxmin, lxmax, lymin, lymax, lzmin, lzmax; if (autoscale_lx) { lxmin = VERYLARGE; lxmax = -VERYLARGE; } else { lxmin = xmin; lxmax = xmax; } if (autoscale_ly) { lymin = VERYLARGE; lymax = -VERYLARGE; } else { lymin = ymin; lymax = ymax; } if (autoscale_lz) { lzmin = VERYLARGE; lzmax = -VERYLARGE; } else { lzmin = zmin; lzmax = zmax; } /* * Ok, go through all the plots and move FUNC3D types together. Note: * this originally was written to look for a NULL next pointer, but * gnuplot wants to be sticky in grabbing memory and the right number of * items in the plot list is controlled by the plot_num variable. * * Since gnuplot wants to do this sticky business, a free_list of * surface_points is kept and then tagged onto the end of the plot list * as this seems more in the spirit of the original memory behavior than * simply freeing the memory. I'm personally not convinced this sort of * concern is worth it since the time spent computing points seems to * dominate any garbage collecting that might be saved here... */ new_list = xp = start_plot; for (surface = 0; surface < *plot_num; surface++) { if (xp->plot_type != FUNC3D) { icrvs = xp->iso_crvs; while (icrvs) { struct coordinate GPHUGE *points = icrvs->points; for (i = 0; i < icrvs->p_count; ++i) { if (lxmin > points[i].x) lxmin = points[i].x; if (lxmax < points[i].x) lxmax = points[i].x; if (lymin > points[i].y) lymin = points[i].y; if (lymax < points[i].y) lymax = points[i].y; if (lzmin > points[i].z) lzmin = points[i].z; if (lzmax < points[i].z) lzmax = points[i].z; } icrvs = icrvs->next; } xp = xp->next_sp; continue; } yp = xp->next_sp; zp = yp->next_sp; /* Here's a FUNC3D parametric function defined as three parts. */ (*plot_num) -= 2; /* * Go through all the points and assign the x's and y's from xp and * yp to zp. Check max's and min's as you go. */ xicrvs = xp->iso_crvs; yicrvs = yp->iso_crvs; zicrvs = zp->iso_crvs; while (zicrvs) { struct coordinate GPHUGE *xpoints = xicrvs->points, GPHUGE *ypoints = yicrvs->points, GPHUGE *zpoints = zicrvs->points; for (i = 0; i < zicrvs->p_count; ++i) { zpoints[i].x = xpoints[i].z; zpoints[i].y = ypoints[i].z; if (lxmin > zpoints[i].x) lxmin = zpoints[i].x; if (lxmax < zpoints[i].x) lxmax = zpoints[i].x; if (lymin > zpoints[i].y) lymin = zpoints[i].y; if (lymax < zpoints[i].y) lymax = zpoints[i].y; if (lzmin > zpoints[i].z) lzmin = zpoints[i].z; if (lzmax < zpoints[i].z) lzmax = zpoints[i].z; } xicrvs = xicrvs->next; yicrvs = yicrvs->next; zicrvs = zicrvs->next; } /* Ok, fix up the title to include xp and yp plots. */ if ((xp->title && xp->title[0] != '\0') || (yp->title && yp->title[0] != '\0')) { tlen = (xp->title ? strlen(xp->title) : 0) + (yp->title ? strlen(yp->title) : 0) + (zp->title ? strlen(zp->title) : 0) + 5; new_title = alloc((unsigned long) tlen, "string"); new_title[0] = 0; if (xp->title) { strcat(new_title, xp->title); strcat(new_title, ", "); /* + 2 */ } if (yp->title) { strcat(new_title, yp->title); strcat(new_title, ", "); /* + 2 */ } if (zp->title) { strcat(new_title, zp->title); } free(zp->title); zp->title = new_title; } /* * Eliminate the first two surfaces (xp and yp) and just use the * third. */ if (xp == start_plot) { /* Simply nip off the first two elements of the list. */ new_list = first_3dplot = zp; xp = zp->next_sp; /* Add xp and yp to the free_list. */ if (free_head == NULL) { free_head = start_plot; } else { free_list->next_sp = start_plot; } free_list = start_plot->next_sp; free_list->next_sp = NULL; } else { /* * Here, remove the xp,yp nodes and replace them with the zp * node. */ tmp = xp; /* Pass over any data files that might have been in place. */ while (new_list->next_sp && new_list->next_sp != xp) new_list = new_list->next_sp; new_list->next_sp = zp; new_list = zp; xp = zp->next_sp; /* Add tmp to the free_list. */ if (free_head == NULL) { free_head = tmp; } else { free_list->next_sp = tmp; } free_list = tmp->next_sp; free_list->next_sp = NULL; } } /* Ok, stick the free list at the end of the surface_points plot list. */ while (new_list->next_sp != NULL) new_list = new_list->next_sp; new_list->next_sp = free_head; if (lxmax - lxmin < zero) { if (fabs(lxmax) < zero) { lxmin = -1.0; lxmax = 1.0; } else { lxmin *= 0.9; lxmax *= 1.1; } } if (lymax - lymin < zero) { if (fabs(lymax) < zero) { lymin = -1.0; lymax = 1.0; } else { lymin *= 0.9; lymax *= 1.1; } } if (lzmax - lzmin < zero) { if (fabs(lzmax) < zero) { lzmin = -1.0; lzmax = 1.0; } else { lzmin *= 0.9; lzmax *= 1.1; } } /* Report the overall graph mins and maxs. */ if (autoscale_lx) { *x_min = (is_log_x ? pow(base_log_x, lxmin) : lxmin); *x_max = (is_log_x ? pow(base_log_x, lxmax) : lxmax); } else { *x_min = xmin; *x_max = xmax; } if (autoscale_ly) { *y_min = (is_log_y ? pow(base_log_y, lymin) : lymin); *y_max = (is_log_y ? pow(base_log_y, lymax) : lymax); } else { *y_min = ymin; *y_max = ymax; } if (autoscale_lz) { *z_min = (is_log_z ? pow(base_log_z, lzmin) : lzmin); *z_max = (is_log_z ? pow(base_log_z, lzmax) : lzmax); } else { *z_min = zmin; *z_max = zmax; } } #ifdef AMIGA_SC_6_1 void sleep(delay) unsigned int delay; { Delay(50 * delay); } #endif #ifdef AMIGA_AC_5 void sleep(delay) unsigned int delay; { unsigned long time_is_up; time_is_up = time(NULL) + (unsigned long) delay; while (time(NULL) < time_is_up) /* wait */ ; } #endif #if defined(MSDOS) || defined(_Windows) || defined(DOS386) #if (!defined(__TURBOC__) && !defined(__EMX__) && !defined(DJGPP)) || defined(_Windows) /* Turbo C already has sleep() */ #ifndef __ZTC__ /* ZTC already has usleep() */ /* kludge to provide sleep() for msc 5.1 */ void sleep(delay) unsigned int delay; { unsigned long time_is_up; time_is_up = time(NULL) + (unsigned long) delay; while (time(NULL) < time_is_up) /* wait */ ; } #endif /* not ZTC */ #endif /* (!TURBOC && !__EMX__ && !DJGPP) or _Windows */ #endif /* MSDOS || _Windows*/ /* Support for input, shell, and help for various systems */ #ifdef vms #include <descrip.h> #include <rmsdef.h> #include <errno.h> #include <smgdef.h> #include <smgmsg.h> extern lib$get_input(), lib$put_output(); extern smg$read_composed_line(); int vms_len; unsigned int status[2] = {1, 0}; static char help[MAX_LINE_LEN + 1] = "gnuplot"; $DESCRIPTOR(prompt_desc, PROMPT); $DESCRIPTOR(line_desc, input_line); $DESCRIPTOR(help_desc, help); $DESCRIPTOR(helpfile_desc, "GNUPLOT$HELP"); read_line(prompt) char *prompt; { int more, start = 0; char expand_prompt[40]; prompt_desc.dsc$w_length = strlen(prompt); prompt_desc.dsc$a_pointer = prompt; (void) strcpy(expand_prompt, "_"); (void) strncat(expand_prompt, prompt, 38); do { line_desc.dsc$w_length = MAX_LINE_LEN - start; line_desc.dsc$a_pointer = &input_line[start]; switch (status[1] = smg$read_composed_line(&vms_vkid, 0, &line_desc, &prompt_desc, &vms_len)) { case SMG$_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 */ } start += vms_len; input_line[start] = '\0'; inline_num++; if (input_line[start - 1] == '\\') { /* Allow for a continuation line. */ prompt_desc.dsc$w_length = strlen(expand_prompt); prompt_desc.dsc$a_pointer = expand_prompt; more = 1; --start; } else { line_desc.dsc$w_length = strlen(input_line); line_desc.dsc$a_pointer = input_line; more = 0; } } while (more); return 0; } do_help() { help_desc.dsc$w_length = strlen(help); if ((vaxc$errno = lbr$output_help(lib$put_output, 0, &help_desc, &helpfile_desc, 0, lib$get_input)) != SS$_NORMAL) os_error("can't open GNUPLOT$HELP", NO_CARET); } do_shell() { if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) { os_error("spawn error", NO_CARET); } } do_system() { input_line[0] = ' '; /* an embarrassment, but... */ if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL) os_error("spawn error", NO_CARET); (void) putc('\n', stderr); } #else /* vms */ #ifdef _Windows do_help() { if (END_OF_COMMAND) WinHelp(textwin.hWndParent,(LPSTR)winhelpname,HELP_INDEX,(DWORD)NULL); else { char buf[128]; int start = c_token++; while (!(END_OF_COMMAND)) c_token++; capture(buf, start, c_token-1); WinHelp(textwin.hWndParent,(LPSTR)winhelpname,HELP_PARTIALKEY,(DWORD)buf); } } #else /* * do_help: (not VMS, although it would work) Give help to the user. It * parses the command line into helpbuf and supplies help for that string. * Then, if there are subtopics available for that key, it prompts the user * with this string. If more input is given, do_help is called recursively, * with the argument the index of null character in the string. Thus a more * specific help can be supplied. This can be done repeatedly. If null input * is given, the function returns, effecting a backward climb up the tree. * David Kotz (David.Kotz@Dartmouth.edu) 10/89 */ do_help() { static char *helpbuf = NULL; static char *prompt = NULL; int base; /* index of first char AFTER help string */ int len; /* length of current help string */ TBOOLEAN more_help; TBOOLEAN only; /* TRUE if only printing subtopics */ int subtopics; /* 0 if no subtopics for this topic */ int start; /* starting token of help string */ char *help_ptr; /* name of help file */ #ifdef ATARI static char help_fname[256]=""; /* keep helpfilename across calls */ #endif if ((help_ptr = getenv("GNUHELP")) == (char *) NULL) #ifndef ATARI /* if can't find environment variable then just use HELPFILE */ help_ptr = HELPFILE; #else /* try whether we can find the helpfile via shell_find. If not, just use the default. (tnx Andreas) */ #ifdef sequent if( !index( HELPFILE, ':' ) && !index( HELPFILE, '/' ) && !index( HELPFILE, '\\' ) ) { #else if( !strchr( HELPFILE, ':' ) && !strchr( HELPFILE, '/' ) && !strchr( HELPFILE, '\\' ) ) { #endif if( strlen(help_fname)==0 ) { strcpy( help_fname, HELPFILE ); if( shel_find( help_fname )==0 ) { strcpy( help_fname, HELPFILE ); } } help_ptr=help_fname; } else { help_ptr=HELPFILE; } #endif /* ATARI */ /* Since MSDOS DGROUP segment is being overflowed we can not allow such */ /* huge static variables (1k each). Instead we dynamically allocate them */ /* on the first call to this function... */ if (helpbuf == NULL) { helpbuf = alloc((unsigned long)MAX_LINE_LEN, "help buffer"); prompt = alloc((unsigned long)MAX_LINE_LEN, "help prompt"); helpbuf[0] = prompt[0] = 0; } len = base = strlen(helpbuf); /* find the end of the help command */ for (start = c_token; !(END_OF_COMMAND); c_token++); /* copy new help input into helpbuf */ if (len > 0) helpbuf[len++] = ' '; /* add a space */ capture(helpbuf + len, start, c_token - 1); squash_spaces(helpbuf + base); /* only bother with new stuff */ lower_case(helpbuf + base); /* only bother with new stuff */ len = strlen(helpbuf); /* now, a lone ? will print subtopics only */ if (strcmp(helpbuf + (base ? base + 1 : 0), "?") == 0) { /* subtopics only */ subtopics = 1; only = TRUE; helpbuf[base] = '\0'; /* cut off question mark */ } else { /* normal help request */ subtopics = 0; only = FALSE; } switch (help(helpbuf, help_ptr, &subtopics)) { case H_FOUND:{ /* already printed the help info */ /* subtopics now is true if there were any subtopics */ screen_ok = FALSE; do { if (subtopics && !only) { /* prompt for subtopic with current help string */ if (len > 0) (void) sprintf(prompt, "Subtopic of %s: ", helpbuf); else (void) strcpy(prompt, "Help topic: "); read_line(prompt); num_tokens = scanner(input_line); c_token = 0; more_help = !(END_OF_COMMAND); if (more_help) /* base for next level is all of current helpbuf */ do_help(); } else more_help = FALSE; } while (more_help); break; } case H_NOTFOUND:{ printf("Sorry, no help for '%s'\n", helpbuf); break; } case H_ERROR:{ perror(help_ptr); break; } default:{ /* defensive programming */ int_error("Impossible case in switch", NO_CARET); /* NOTREACHED */ } } helpbuf[base] = '\0'; /* cut it off where we started */ } #endif /* _Windows */ #ifdef AMIGA_AC_5 char strg0[256]; #endif do_system() { #ifdef AMIGA_AC_5 char *parms[80]; void getparms(); getparms(input_line + 1, parms); if (fexecv(parms[0], parms) < 0) #else #if defined(ATARI)&&defined(__GNUC__) /* use preloaded shell, if available */ short (*shell_p) (char *command); void *ssp; ssp = (void *) Super(NULL); shell_p = *(short (**) (char *)) 0x4f6; Super(ssp); /* this is a bit strange, but we have to have a single if */ if ((shell_p ? (*shell_p) (input_line + 1) : system(input_line + 1))) #else #ifdef _Windows if (winsystem(input_line + 1)) #else if (system(input_line + 1)) #endif #endif #endif os_error("system() failed", NO_CARET); } #ifdef AMIGA_AC_5 /******************************************************************************/ /* */ /* Parses the command string (for fexecv use) and converts the first token */ /* to lower case */ /* */ /******************************************************************************/ void getparms(command, parms) char *command; char **parms; { register int i = 0; /* A bunch of indices */ register int j = 0; register int k = 0; while (*(command + j) != '\0') { /* Loop on string characters */ parms[k++] = strg0 + i; while (*(command + j) == ' ') ++j; while (*(command + j) != ' ' && *(command + j) != '\0') { if (*(command + j) == '"') /* Get quoted string */ for (*(strg0 + (i++)) = *(command + (j++)); *(command + j) != '"'; *(strg0 + (i++)) = *(command + (j++))); *(strg0 + (i++)) = *(command + (j++)); } *(strg0 + (i++)) = '\0';/* NUL terminate every token */ } parms[k] = '\0'; for (k = strlen(strg0) - 1; k >= 0; --k) /* Convert to lower case */ *(strg0 + k) >= 'A' && *(strg0 + k) <= 'Z' ? *(strg0 + k) |= 32 : *(strg0 + k); } #endif /* AMIGA_AC_5 */ #ifdef READLINE char * rlgets(s, n, prompt) char *s; int n; char *prompt; { char *readline(); static char *line = (char *) NULL; /* If we already have a line, first free it */ if (line != (char *) NULL) free(line); line = readline((interactive) ? prompt : ""); /* If it's not an EOF */ if (line) { if (*line) add_history(line); strncpy(s, line, n); return s; } return line; } #endif /* READLINE */ #if defined(MSDOS) || defined(_Windows) || defined(DOS386) #ifndef _Windows #ifdef __TURBOC__ /* cgets implemented using dos functions */ /* Maurice Castro 22/5/91 */ char * doscgets(s) char *s; { long datseg; /* protect and preserve segments - call dos to do the dirty work */ datseg = _DS; _DX = FP_OFF(s); _DS = FP_SEG(s); _AH = 0x0A; geninterrupt(33); _DS = datseg; /* check for a carriage return and then clobber it with a null */ if (s[s[1] + 2] == '\r') s[s[1] + 2] = 0; /* return the input string */ return (&(s[2])); } #endif /* __TURBOC__ */ #endif /* !_Windows */ #ifdef __ZTC__ void cputs(char *s) { register int i = 0; while (s[i] != '\0') bdos(0x02, s[i++], NULL); } char *cgets(char *s) { bdosx(0x0A, s, NULL); if (s[s[1]+2] == '\r') s[s[1]+2] = 0; /* return the input string */ return(&(s[2])); } #endif /* __ZTC__ */ read_line(prompt) char *prompt; { register int i; int start = 0, ilen = 0; TBOOLEAN more; int last; char *p, *crnt_prompt = prompt; if (interactive) { /* if interactive use console IO so CED will * work */ #ifndef READLINE #if defined(_Windows) || defined(__EMX__) || defined(DJGPP) || defined(__ZTC__) printf("%s", prompt); #else cputs(prompt); #endif #endif /* READLINE */ do { ilen = MAX_LINE_LEN - start - 1; input_line[start] = ilen > 126 ? 126 : ilen; #ifdef READLINE input_line[start + 2] = 0; (void) rlgets(&(input_line[start + 2]), ilen, crnt_prompt); #ifdef sequent if ((p = index(&(input_line[start + 2]), '\r'))!=NULL) *p = 0; if ((p = index(&(input_line[start + 2]), '\n'))!=NULL) *p = 0; #else if ((p = strchr(&(input_line[start + 2]), '\r'))!=NULL) *p = 0; if ((p = strchr(&(input_line[start + 2]), '\n'))!=NULL) *p = 0; #endif input_line[start + 1] = strlen(&(input_line[start + 2])); #else /* READLINE */ #if defined(_Windows) || defined(__EMX__) || defined(DJGPP) (void) gets(&(input_line[start+2])); #else #ifdef __TURBOC__ (void) doscgets(&(input_line[start])); #else /* __TURBOC__ */ (void) cgets(&(input_line[start])); #endif /* __TURBOC__ */ #endif /* _Windows || __EMX__ || DJGPP*/ (void) putc('\n', stderr); #endif /* READLINE */ if (input_line[start + 2] == 26) { /* end-of-file */ (void) putc('\n', stderr); input_line[start] = '\0'; inline_num++; if (start > 0) /* don't quit yet - process what we have */ more = FALSE; else { (void) putc('\n', stderr); return(1); /* exit gnuplot */ /* NOTREACHED */ } } else { /* normal line input */ register i = start; while ((input_line[i] = input_line[i + 2]) != (char) NULL) i++; /* yuck! move everything down two characters */ inline_num++; last = strlen(input_line) - 1; if (last<0) last=0; /* stop UAE in Windows */ if (last + 1 >= MAX_LINE_LEN) int_error("Input line too long", NO_CARET); if (input_line[last] == '\\') { /* line continuation */ start = last; more = TRUE; } else more = FALSE; } #ifndef READLINE if (more) #if defined(_Windows) || defined(__EMX__) || defined(DJGPP) || defined(__ZTC__) printf("> "); #else cputs("> "); #endif #else crnt_prompt = "> "; #endif /* READLINE */ } while (more); } else { /* not interactive */ if (interactive) fputs(prompt, stderr); do { /* grab some input */ if (fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin) == (char *) NULL) { /* end-of-file */ if (interactive) (void) putc('\n', stderr); input_line[start] = '\0'; inline_num++; if (start > 0) /* don't quit yet - process what we have */ more = FALSE; else return(1); /* exit gnuplot */ } else { /* normal line input */ last = strlen(input_line) - 1; if (input_line[last] == '\n') { /* remove any newline */ input_line[last] = '\0'; /* Watch out that we don't backup beyond 0 (1-1-1) */ if (last > 0) --last; inline_num++; } else if (last + 1 >= MAX_LINE_LEN) int_error("Input line too long", NO_CARET); if (input_line[last] == '\\') { /* line continuation */ start = last; more = TRUE; } else more = FALSE; } if (more && interactive) fputs("> ", stderr); } while (more); } return(0); } do_shell() { register char *comspec; if ((comspec = getenv("COMSPEC")) == (char *) NULL) comspec = "\\command.com"; #ifdef _Windows if (WinExec(comspec, SW_SHOWNORMAL) <= 32) #else #ifdef DJGPP if (system(comspec) == -1) #else if (spawnl(P_WAIT, comspec, NULL) == -1) #endif #endif os_error("unable to spawn shell", NO_CARET); } #else /* MSDOS */ /* plain old Unix */ read_line(prompt) char *prompt; { int start = 0; TBOOLEAN more = FALSE; int last = 0; #ifndef READLINE if (interactive) fputs(prompt, stderr); #endif /* READLINE */ do { /* grab some input */ #ifdef READLINE if (((interactive) ? rlgets(&(input_line[start]), MAX_LINE_LEN - start, ((more) ? "> " : prompt)) : fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin)) == (char *) NULL) { #else if (fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin) == (char *) NULL) { #endif /* READLINE */ /* end-of-file */ if (interactive) (void) putc('\n', stderr); input_line[start] = '\0'; inline_num++; if (start > 0) /* don't quit yet - process what we have */ more = FALSE; else return(1); /* exit gnuplot */ } else { /* normal line input */ last = strlen(input_line) - 1; if (input_line[last] == '\n') { /* remove any newline */ input_line[last] = '\0'; /* Watch out that we don't backup beyond 0 (1-1-1) */ if (last > 0) --last; } else if (last + 1 >= MAX_LINE_LEN) int_error("Input line too long", NO_CARET); if (input_line[last] == '\\') { /* line continuation */ start = last; more = TRUE; } else more = FALSE; } #ifndef READLINE if (more && interactive) fputs("> ", stderr); #endif } while (more); return(0); } #ifdef VFORK do_shell() { register char *shell; register int p; static int execstat; if (!(shell = getenv("SHELL"))) shell = SHELL; #ifdef AMIGA_AC_5 execstat = fexecl(shell, shell, NULL); #else 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) #endif ; if (execstat == -1) os_error("shell exec failed", c_token); (void) putc('\n', stderr); } #else /* VFORK */ #ifdef AMIGA_SC_6_1 do_shell() { register char *shell; if (!(shell = getenv("SHELL"))) shell = SHELL; if (system(shell)) os_error("system() failed", NO_CARET); (void) putc('\n', stderr); } #else /* AMIGA_SC_6_1 */ #ifdef OS2 do_shell() { register char *shell; if (!(shell = getenv("COMSPEC"))) shell = SHELL; if (system(shell) == -1 ) os_error("system() failed", NO_CARET); (void) putc('\n', stderr); } #else /* ! OS2 */ #define EXEC "exec " do_shell() { static char exec[100] = EXEC; register char *shell; if (!(shell = getenv("SHELL"))) shell = SHELL; if (system(strncpy(&exec[sizeof(EXEC) - 1], shell, sizeof(exec) - sizeof(EXEC) - 1))) os_error("system() failed", NO_CARET); (void) putc('\n', stderr); } #endif /* OS2 */ #endif /* AMIGA_SC_6_1 */ #endif /* VFORK */ #endif /* MSDOS */ #endif /* vms */ #ifdef _Windows /* there is a system like call on MS Windows but it is a bit difficult to use, so we will invoke the command interpreter and use it to execute the commands */ int winsystem(s) char *s; { LPSTR comspec; LPSTR execstr; LPSTR p; /* get COMSPEC environment variable */ #ifdef WIN32 char envbuf[81]; GetEnvironmentVariable("COMSPEC", envbuf, 80); if (*envbuf == '\0'); comspec = "\\command.com"; else comspec = envbuf; #else p = GetDOSEnvironment(); comspec = "\\command.com"; while (*p) { if (!strncmp(p,"COMSPEC=",8)) { comspec=p+8; break; } p+=strlen(p)+1; } #endif /* if the command is blank we must use command.com */ p = s; while ((*p == ' ') || (*p == '\n') || (*p == '\r')) p++; if (*p == '\0') { WinExec(comspec, SW_SHOWNORMAL); } else { /* attempt to run the windows/dos program via windows */ if (WinExec(s, SW_SHOWNORMAL) <= 32) { /* attempt to run it as a dos program from command line */ execstr = (char *) malloc(strlen(s) + strlen(comspec) + 6); strcpy(execstr, comspec); strcat(execstr, " /c "); strcat(execstr, s); WinExec(execstr, SW_SHOWNORMAL); free(execstr); } } /* regardless of the reality return OK - the consequences of */ /* failure include shutting down Windows */ return(0); /* success */ } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.