This is Status.m in view mode; [Download] [Up]
/* * Copyright (C) 1993 Robert Davis * * This program is free software; you can redistribute it and/or * modify it under the terms of Version 2, or any later version, of * the GNU General Public License as published by the Free Software * Foundation. */ static char RCSId[] = "$Id: Status.m,v 1.18 1993/05/30 09:10:15 davis Exp $"; #import <appkit/Font.h> #import <appkit/nextstd.h> /* NX_FREE */ #import <objc/hashtable.h> /* NXCopyStringBufferFromZone() */ #import <objc/List.h> #import <objc/zone.h> #import <ctype.h> /* isspace() */ #import <setjmp.h> /* setjmp() */ #import <stdio.h> #import <strings.h> /* strcat(), strcpy(), index() */ #import "FunctionObject.h" #import "GnuplotPlot.h" #import "Status.h" #import "StatusContour.h" /* Status categories */ #import "StatusTics.h" @interface Status (Private) - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond; - _buildPlotargs; - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction; - (const char *) _copyString:(const char *)source to:(char **)dest; - _doText:(const char *)theText; - _setText:(const char *) aString; @end /* * The class remembers which Status object was the last to issue a * plot command to Gnuplot. We need to know this when we set our * instance variables to the corresponding Gnuplot values -- see * -grabCurrent. */ static id lastplot = nil; #define MAX_LINE_LEN 1024 /* Same as in plot.h */ #define DEFAULT_FONT "Helvetica" #define POLAR 0 /* Two sets of range information */ #define CARTESIAN 1 /* * All instance variables begin with s_ to avoid confusion with the * variables defined in gnuplot .c files. * * gnuplot Variable (setshow.c) Status Instance Variable * ---------------------------- ------------------------ */ extern char nextfe_font[]; /* s_font */ extern int nextfe_fontsize; /* s_fontsize */ extern int nextfe_solid; // unused extern char title[]; /* s_title */ extern char xlabel[]; /* s_labelCoord[] */ extern char ylabel[]; extern char zlabel[]; extern char dummy_var[][51]; /* s_dummy_var[] */ extern int parametric; /* s_parametric */ extern int polar; /* s_polar */ extern int draw_border; /* s_border */ extern int draw_surface; /* s_draw_surface */ extern int grid; /* s_grid */ extern int xzeroaxis; /* s_zeroaxis[] */ extern int yzeroaxis; extern int is_log_x, is_log_y, is_log_z;/* s_isLogCoord[],s_isLogPol... */ extern double base_log_x, base_log_y, /* Currently unused by Status */ base_log_z; // extern double log_base_log_x, log_base_log_y, log_base_log_z; extern int key; /* s_key */ extern double key_x, key_y, key_z; /* s_keyCoord[] */ extern int timedate; /* s_time */ extern int time_xoffset, time_yoffset; /* s_timeCoord[] */ extern float xsize, ysize; /* s_xsize, s_ysize */ extern float surface_rot_x; /* s_rot_x */ extern float surface_rot_z; /* s_rot_z */ extern int hidden3d; /* s_hidden3d */ extern int autoscale_x; /* s_autoscaleCoord[][] */ extern int autoscale_y; extern int autoscale_z; extern int autoscale_r; extern double xmin, xmax; /* s_minCoord[][],s_maxCoord[][]*/ extern double ymin, ymax; extern double zmin, zmax; extern double rmin, rmax; extern int angles_format; /* degrees */ extern int samples; /* s_samples */ extern int samples_1; /* s_samplesCoord */ extern int samples_2; extern int iso_samples_1; /* s_iso_samplesCoord */ extern int iso_samples_2; extern char replot_line[]; /* s_plotargs */ extern NXStream *EPSStream; /* s_epsStream (terminal) */ extern int nextfe_halve; /* (GnuplotPlot preference) */ extern NEXTFE_reset(); /* Appends PS Trailer to stream */ /* * Removes leading blanks and tabs. */ static char *_removeLeadingBlanks (char *aString) { if (aString && *aString) { char *cur = aString; while (*cur && (isspace(*cur))) cur++; strcpy (aString, cur); } return aString; } /* * Stores the first line, up to max characters, from the multi-line * string source in dest and returns a pointer to it. It replaces * the newline with a null character. If the line was the last in * the string, it returns NULL. */ static char *_get_line (char *dest, int max, const char *source) { char *returnVal = dest; if (source && dest) { while ((*source != '\n') && (*source != '\0') && (max > 0)) { *dest = *source; dest++; source++; max--; } *dest = '\0'; if (*source == '\n') return returnVal; } /* NULL is returned if line is */ /* too long or end of source */ return NULL; /* or dest string is reached. */ } /* * Finds the end of the first function in string containing arguments * to gnuplot's plot command. */ static char *_endFunction(char *aString) { char delim[MAX_LINE_LEN]; char *cur = aString; int number = 0; while (cur && *cur) { switch (*cur) { case '\'': case '"': if (number && delim[number - 1] == *cur) number--; else delim[number++] = *cur; break; case '(': case ')': if (number && delim[number - 1] == ((*cur == '(')? ')' : '(')) number --; else delim[number++] = *cur; break; case ',': if (!number) return cur; } cur++; } return NULL; } const char *makeOneQuoteType (char *aString) { char *c, quote = '\0'; /* * Make sure at most one kind of quotation marks is used in the * string -- change all quotation marks to match the first one. */ for (c = aString; c && *c; c++) if ((*c == '\'') || (*c == '"')) { if (quote && (*c != quote)) *c = quote; else quote = *c; } return aString; } @implementation Status + lastplot { return lastplot; } + setHalvePlot:(BOOL)condition { nextfe_halve = condition; return self; } - init { int counter; [super init]; zone = [self zone]; report = YES; /* * Set all pointers to NULL or nil so -resetCurrent * doesn't try to free them. */ s_epsStream = NULL; text = s_title = s_plotargs = s_font = appendix = s_dummy_var[0] = s_dummy_var[1] = NULL; for (counter = 0 ; counter < 3 ; counter++) s_labelCoord[counter] = NULL; [self initTics]; [self initContour]; [self resetCurrent]; return self; } - free { int counter; if (s_epsStream) NXCloseMemory (s_epsStream, NX_FREEBUFFER); /* * NXZoneFree() doesn't bomb if you give it a NULL pointer, so we * don't bother to check the pointer. */ NXZoneFree (zone, text); NXZoneFree (zone, appendix); NXZoneFree (zone, s_title); NXZoneFree (zone, s_font); NXZoneFree (zone, s_dummy_var[X_TAG]); NXZoneFree (zone, s_dummy_var[Y_TAG]); for (counter = 0 ; counter < 3 ; counter++) NXZoneFree (zone, s_labelCoord[counter]); NXZoneFree (zone, s_plotargs); if (functions) [[functions freeObjects] free]; [self freeTics]; [self freeContour]; if (lastplot == self) lastplot = nil; return [super free]; } - setReport:(BOOL)cond { report = cond; return self; } - (BOOL)report { return report; } - setDelegate: anObject { if ([anObject respondsTo:@selector(settingsDidChange:)]) { delegate = anObject; return self; } else return nil; } - delegate { return delegate; } - (NXStream *)stream { return s_epsStream; } - (BOOL)canPlot { int count = 0, index; int total = [functions count]; /* Count the number of functions */ index = total; while (index--) count += ([[functions objectAt:index] isDataFile]) ? 0 : 1; /* * We can plot iff * * 1) there is an appendix * * or * * 2) there is at least one FunctionObject and * 3) if the plot is parametric then * a) we have pairs of functions (two-dimensional), * b) or we have triplets of functions (3-dimens.) * */ return ((appendix && *appendix) || (total && (s_parametric? (isThreeD? !(count % 3) : (!(count % 2) && (total == count))) :YES))); } - plot { [self applyCurrent]; lastplot = self; if (areSettingsEdited && !appendix) { [self _buildPlotargs]; [self _setText:s_plotargs]; areSettingsEdited = NO; } if (appendix && *appendix) [self _setText:appendix]; /* Appendix overrides current plot */ return [self _doText:text]; } - saveToFile:(const char *)filename { char *copy, *line, *cur; id returnVal; /* * Gnuplot sometimes drops characters off the end of long * pathnames given to the "save" command, a bug that seems to * have been introduced between 3.1 and 3.2. We work around it * by cd'ing to the directory first and then saving the file. */ copy = NXCopyStringBufferFromZone (filename, zone); if (cur = rindex (copy, '/')) { *(cur++) = '\0'; line = NXZoneMalloc (zone, 15 + strlen (filename)); sprintf (line, "cd '%s'\nsave '%s'\n", copy, cur); } else { line = NXZoneMalloc (zone, 9 + strlen (filename)); sprintf (line, "save '%s'\n", filename); } returnVal = [self _doText:line]? self : nil; NXZoneFree (zone, copy); NXZoneFree (zone, line); return returnVal; } - reportSettingsChange:sender { areSettingsEdited = YES; if (lastplot == self) lastplot = nil; /* Last valid plot is no longer valid */ if (delegate && report) [delegate settingsDidChange:self]; return self; } /* * Resets all the instance variables to their default values. */ - resetCurrent { int counter; if (functions) [functions freeObjects]; else functions = [[List allocFromZone:zone] init]; NXZoneFree (zone, text); text = NULL; NXZoneFree (zone, s_title); s_title = NULL; NXZoneFree (zone, s_dummy_var[0]); s_dummy_var[0] = NULL; NXZoneFree (zone, s_dummy_var[1]); s_dummy_var[1] = NULL; for (counter = 0 ; counter < 3 ; counter++) { NXZoneFree (zone, s_labelCoord[counter]); s_labelCoord[counter] = NULL; s_minCoord[counter][CARTESIAN] = -10.0; s_maxCoord[counter][CARTESIAN] = 10.0; s_minCoord[counter][POLAR] = -10.0; s_isLogCoord[counter][CARTESIAN] = NO; s_isLogCoord[counter][POLAR] = NO; } degrees = NO; /* These not set in for loop above */ s_minCoord[X_TAG][POLAR] = s_minCoord[R_TAG][POLAR] = 0.0; s_maxCoord[X_TAG][POLAR] = degrees? 360 :6.283186; s_maxCoord[Y_TAG][POLAR] = s_maxCoord[Z_TAG][POLAR] = s_maxCoord[R_TAG][POLAR] = 10.0; NXZoneFree (zone, s_plotargs); s_plotargs = NULL; NXZoneFree (zone, s_font); s_font = NULL; NXZoneFree (zone, appendix); appendix = NULL; s_fontsize = 16; isThreeD = NO; s_parametric = NO; s_polar = NO; s_border = YES; s_draw_surface = YES; [self resetCurrentContour]; [self resetCurrentTics]; s_hidden3d = NO; s_grid = NO; s_zeroaxis[X_TAG] = s_zeroaxis[Y_TAG] = YES; s_key = YES; /* Plot has a key, in default location */ s_key_default = YES; s_time = NO; /* Don't show time/date */ s_time_default = YES; for (counter = 0 ; counter < 4 ; counter++) { s_autoscaleCoord[counter][CARTESIAN] = 1; s_autoscaleCoord[counter][POLAR] = 1; } sizeProp = YES; /* Keep x, y, z proportional */ s_xsize = s_ysize = 1.0; s_samples = s_samplesCoord[X_TAG] = s_samplesCoord[Y_TAG] = 100; s_iso_samplesCoord[X_TAG] = s_iso_samplesCoord[Y_TAG] = 10; s_rotCoord[X_TAG] = 60.0; s_rotCoord[Z_TAG] = 30.0; areSettingsEdited = NO; return self; } /* Sets the current gnuplot settings to the Status instance variables. */ - applyCurrent { int type; nextfe_solid = NO;// if (s_font) strcpy (nextfe_font, s_font); else strcpy (nextfe_font, DEFAULT_FONT); nextfe_fontsize = s_fontsize; if (s_title) strcpy (title, s_title); else strcpy (title, ""); if (s_dummy_var[0]) strcpy (dummy_var[0], s_dummy_var[0]); else strcpy (dummy_var[0], "x"); if (s_dummy_var[1]) strcpy (dummy_var[1], s_dummy_var[1]); else strcpy (dummy_var[1], "y"); if (s_labelCoord[X_TAG]) strcpy (xlabel, s_labelCoord[X_TAG]); else strcpy (xlabel, ""); if (s_labelCoord[Y_TAG]) strcpy (ylabel, s_labelCoord[Y_TAG]); else strcpy (ylabel, ""); if (s_labelCoord[Z_TAG]) strcpy (zlabel, s_labelCoord[Z_TAG]); else strcpy (zlabel, ""); parametric = s_parametric; polar = s_polar; draw_border = s_border; draw_surface = s_draw_surface; [self applyCurrentContour]; [self applyCurrentTics]; hidden3d = s_hidden3d; grid = s_grid; xzeroaxis = s_zeroaxis[X_TAG]; yzeroaxis = s_zeroaxis[Y_TAG]; /* * We have to sets of ranges, depending on whether the plot is * cartesian or polar. Set the correct ones. */ type = s_polar? POLAR:CARTESIAN; xmin = s_minCoord[X_TAG][type]; xmax = s_maxCoord[X_TAG][type]; ymin = s_minCoord[Y_TAG][type]; ymax = s_maxCoord[Y_TAG][type]; zmin = s_minCoord[Z_TAG][type]; zmax = s_maxCoord[Z_TAG][type]; is_log_x = s_isLogCoord[X_TAG][type]; is_log_y = s_isLogCoord[Y_TAG][type]; is_log_z = s_isLogCoord[Z_TAG][type]; autoscale_x = s_autoscaleCoord[X_TAG][type]; autoscale_y = s_autoscaleCoord[Y_TAG][type]; autoscale_z = s_autoscaleCoord[Z_TAG][type]; autoscale_r = s_autoscaleCoord[R_TAG][type]; base_log_x = base_log_y = base_log_z = 10.0; log_base_log_x = log_base_log_y = log_base_log_z = log(10.0); angles_format = degrees? ANGLES_DEGREES :ANGLES_RADIANS; key = s_key? (s_key_default? -1 :1) :0; key_x = s_keyCoord[X_TAG]; key_y = s_keyCoord[Y_TAG]; key_z = s_keyCoord[Z_TAG]; timedate = s_time? 1 :0; time_xoffset = (s_time_default? 0 :s_timeCoord[X_TAG]); time_yoffset = (s_time_default? 0 :s_timeCoord[Y_TAG]); xsize = s_xsize; ysize = s_ysize; surface_rot_x = s_rotCoord[X_TAG]; surface_rot_z = s_rotCoord[Z_TAG]; samples = s_samples; samples_1 = s_samplesCoord[X_TAG]; samples_2 = s_samplesCoord[Y_TAG]; iso_samples_1 = s_iso_samplesCoord[X_TAG]; iso_samples_2 = s_iso_samplesCoord[Y_TAG]; return self; } /* * Resets all the instance variables to the current gnuplot settings, * all of which pertain to the most recent plot: */ - grabCurrent { char *cur; int type; NXZoneFree (zone, s_font); s_font = NXCopyStringBufferFromZone (nextfe_font, zone); s_fontsize = nextfe_fontsize; NXZoneFree (zone, s_title); s_title = NXCopyStringBufferFromZone (title, zone); NXZoneFree (zone, s_dummy_var[0]); s_dummy_var[0] = NXCopyStringBufferFromZone (dummy_var[0], zone); NXZoneFree (zone, s_dummy_var[1]); s_dummy_var[1] = NXCopyStringBufferFromZone (dummy_var[1], zone); NXZoneFree (zone, s_labelCoord[X_TAG]); s_labelCoord[X_TAG] = NXCopyStringBufferFromZone (xlabel, zone); NXZoneFree (zone, s_labelCoord[Y_TAG]); s_labelCoord[Y_TAG] = NXCopyStringBufferFromZone (ylabel, zone); NXZoneFree (zone, s_labelCoord[Z_TAG]); s_labelCoord[Z_TAG] = NXCopyStringBufferFromZone (zlabel, zone); /* * If the last plot command was "splot," as opposed to "plot," * it is three dimensional. */ isThreeD = (*(_removeLeadingBlanks(replot_line)) == 's'); s_parametric = parametric; s_polar = polar; s_border = draw_border; s_draw_surface = draw_surface; [self grabCurrentContour]; [self grabCurrentTics]; s_hidden3d = hidden3d; s_grid = grid; s_zeroaxis[X_TAG] = xzeroaxis; s_zeroaxis[Y_TAG] = yzeroaxis; type = polar? POLAR:CARTESIAN; s_minCoord[X_TAG][type] = xmin; s_maxCoord[X_TAG][type] = xmax; s_minCoord[Y_TAG][type] = ymin; s_maxCoord[Y_TAG][type] = ymax; s_minCoord[Z_TAG][type] = zmin; s_maxCoord[Z_TAG][type] = zmax; s_isLogCoord[X_TAG][type] = is_log_x; s_isLogCoord[Y_TAG][type] = is_log_y; s_isLogCoord[Z_TAG][type] = is_log_z; s_autoscaleCoord[X_TAG][type] = autoscale_x; s_autoscaleCoord[Y_TAG][type] = autoscale_y; s_autoscaleCoord[Z_TAG][type] = autoscale_z; s_autoscaleCoord[R_TAG][type] = autoscale_r; degrees = (angles_format == ANGLES_DEGREES); s_key = ((key == -1) || (key == 1)); s_key_default = (key == -1); s_keyCoord[X_TAG] = key_x; s_keyCoord[Y_TAG] = key_y; s_keyCoord[Z_TAG] = key_z; s_time = timedate; s_time_default = (time_xoffset == 0.0) && (time_yoffset == 0.0); s_timeCoord[X_TAG] = time_xoffset; s_timeCoord[Y_TAG] = time_yoffset; s_xsize = xsize; s_ysize = ysize; s_samples = samples; s_samplesCoord[X_TAG] = samples_1; s_samplesCoord[Y_TAG] = samples_2; s_iso_samplesCoord[X_TAG] = iso_samples_1; s_iso_samplesCoord[Y_TAG] = iso_samples_2; s_rotCoord[X_TAG] = surface_rot_x; s_rotCoord[Z_TAG] = surface_rot_z; NXZoneFree (zone, s_plotargs); if (cur = index (replot_line, ' ')) { /* todo What about tabs? */ s_plotargs = NXZoneMalloc (zone, strlen (replot_line) + 1); strcpy (s_plotargs, cur + 1); } else s_plotargs = NULL; /* Break plotargs into separate functions */ [self _grabFunctionsFrom:s_plotargs isThreeD:isThreeD]; [self _buildPlotargs]; [self _setText: s_plotargs]; areSettingsEdited = YES; return self; } - setThreeD:(BOOL) aCondition { if (isThreeD != aCondition) { int i; isThreeD = aCondition; for (i = [functions count] - 1; i >= 0; i--) [[functions objectAt:i] setThreeD:isThreeD]; if (s_parametric) { if (isThreeD) { [self _copyString:"u" to:&(s_dummy_var[X_TAG])]; [self _copyString:"v" to:&(s_dummy_var[Y_TAG])]; } else [self _copyString:"t" to:&(s_dummy_var[X_TAG])]; } [self reportSettingsChange:self]; } return self; } - (BOOL) isThreeD { return isThreeD; } - setParametric:(BOOL) cond { if (s_parametric != cond) { s_parametric = cond; if (cond) { if (isThreeD) { [self _copyString:"u" to:&(s_dummy_var[X_TAG])]; [self _copyString:"v" to:&(s_dummy_var[Y_TAG])]; } else [self _copyString:"t" to:&(s_dummy_var[X_TAG])]; } else { [self _copyString:"x" to:&(s_dummy_var[X_TAG])]; [self _copyString:"y" to:&(s_dummy_var[Y_TAG])]; } [self reportSettingsChange:self]; } return self; } - (BOOL) parametric { return s_parametric; } - setPolar:(BOOL) cond { if (s_polar != cond) { s_polar = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) isPolar { return s_polar; } - setBorder:(BOOL) cond { if (s_border != cond) { s_border = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) border { return s_border; } - setSurface:(BOOL) cond { if (s_draw_surface != cond) { s_draw_surface = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) surface { return s_draw_surface; } - setHiddenThreeD:(BOOL) cond { if (s_hidden3d != cond) { s_hidden3d = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) hiddenThreeD { return s_hidden3d; } - setGrid:(BOOL) cond { if (s_grid != cond) { s_grid = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) grid { return s_grid; } - setAxisCoord:(int)coord on:(BOOL)cond { if (s_zeroaxis[coord] != cond) { s_zeroaxis[coord] = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) axisCoord:(int)coord { return s_zeroaxis[coord]; } - setIsLogCoord:(int)coord isOn:(BOOL)isOn { int type = s_polar? POLAR:CARTESIAN; if (s_isLogCoord[coord][type] != isOn) { s_isLogCoord[coord][type] = isOn; [self reportSettingsChange:self]; } return self; } - (BOOL) isLogCoord:(int)coord { return s_isLogCoord[coord][s_polar? POLAR:CARTESIAN]; } - setTitle:(const char *) aString { [self _copyString:aString to:&s_title]; makeOneQuoteType (s_title); [self reportSettingsChange:self]; return self; } - (const char *) title { return s_title; } - setLabelCoord:(int)coord to:(const char *) aString { [self _copyString:aString to:&(s_labelCoord[coord])]; makeOneQuoteType (s_labelCoord[coord]); [self reportSettingsChange:self]; return self; } - (const char *) labelCoord:(int) coord { return s_labelCoord[coord]; } - setDummyVar:(int)coord to:(const char *)aString { [self _copyString:aString to:&(s_dummy_var[coord])]; [self reportSettingsChange:self]; return self; } - (const char *)dummyVar:(int)coord { if (!s_dummy_var[coord]) switch (coord) { case X_TAG: return "x"; break; case Y_TAG: return "y"; break; } return s_dummy_var[coord]; } - setAppendix: (const char *) aString { NXZoneFree (zone, appendix); if (aString) appendix = NXCopyStringBufferFromZone (aString, zone); else appendix = NULL; return self; } - setFontsize: (int) anInt; { if ((s_fontsize != anInt) && (anInt > 0)) { s_fontsize = anInt; [self reportSettingsChange:self]; return self; } else return nil; } - (int) fontsize { return s_fontsize; } - setFontname: (const char *) aString { [self _copyString:aString to:&s_font]; [self reportSettingsChange:self]; return self; } - (const char *) fontname { return s_font; } - setFont:aFont { if (aFont) { [self _copyString:[aFont name] to:&s_font]; s_fontsize = [aFont pointSize]; [self reportSettingsChange:self]; } return self; } - font { if (!s_font) return [Font newFont:DEFAULT_FONT size:s_fontsize]; return [Font newFont:s_font size:s_fontsize]; } - setKey:(BOOL) cond { if (s_key != cond) { s_key = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) key { return s_key; } - setKeyDefault:(BOOL) cond { if (s_key_default != cond) { s_key_default = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) keyDefault { return s_key_default; } - setKeyCoord:(int)coord to:(double)aDouble { if (s_keyCoord[coord] != aDouble) { s_keyCoord[coord] = aDouble; [self reportSettingsChange:self]; } return self; } - (double) keyCoord:(int)coord { return s_keyCoord[coord]; } - setTime:(BOOL) cond { if (s_time != cond) { s_time = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) time { return s_time; } - setTimeDefault:(BOOL) cond { if (s_time_default != cond) { s_time_default = cond; [self reportSettingsChange:self]; } return self; } - (BOOL) timeDefault { return s_time_default; } - setTimeCoord:(int)coord to:(int)aDouble { if (s_timeCoord[coord] != aDouble) { s_timeCoord[coord] = aDouble; [self reportSettingsChange:self]; } return self; } - (int) timeCoord:(int)coord { return s_timeCoord[coord]; } - setSizeProp:(BOOL) cond { sizeProp = cond; /* Don't do anything, just record status */ return self; } - (BOOL)sizeProp { return sizeProp; } /* * Size of zero means don't change... (e.g. if x=2 and y=0, we change * x but not y). */ - setSizeX:(float) xFloat Y:(float) yFloat { if ((xFloat != s_xsize) || (yFloat != s_ysize)) { if (xFloat) s_xsize = xFloat; if (yFloat) s_ysize = yFloat; [self reportSettingsChange:self]; } return self; } - (float) sizeX { return s_xsize; } - (float) sizeY { return s_ysize; } - setRotCoord:(int)coord to:(float)aFloat { if (s_rotCoord[coord] != aFloat) { s_rotCoord[coord] = aFloat; [self reportSettingsChange:self]; } return self; } - resetRotation { s_rotCoord[X_TAG] = 60.0; s_rotCoord[Z_TAG] = 30.0; [self reportSettingsChange:self]; return self; } - (float)rotCoord:(int)coord { return s_rotCoord[coord]; } - setSamplesCoord:(int)coord to:(int)anInt { if ((anInt >= 2) && (anInt != s_samplesCoord[coord])) { s_samplesCoord[coord] = anInt; if (coord == X_TAG) s_samples = anInt; } else return nil; [self reportSettingsChange:self]; return self; } - (int) samples:(int)coord { return s_samplesCoord[coord]; } - setIsoSamplesCoord:(int)coord to:(int)anInt { if ((anInt >= 2) && (anInt != s_iso_samplesCoord[coord])) s_iso_samplesCoord[coord] = anInt; else return nil; [self reportSettingsChange:self]; return self; } - (int) isoSamples:(int)coord { return s_iso_samplesCoord[coord]; } - setAutoscaleCoord:(int)coord isOn:(BOOL)cond { int type = s_polar? POLAR:CARTESIAN; if (s_autoscaleCoord[coord][type] != cond) { s_autoscaleCoord[coord][type] = cond; [self reportSettingsChange:self]; } return self; } - (BOOL)autoscaleCoord:(int)coord { return s_autoscaleCoord[coord][s_polar? POLAR:CARTESIAN]; } - setRangeCoord:(int)coord min:(double)min max:(double)max { int type = s_polar? POLAR:CARTESIAN; if ((s_maxCoord[coord][type] != max) || (s_minCoord[coord][type] != min)) { s_maxCoord[coord][type] = max; s_minCoord[coord][type] = min; [self reportSettingsChange:self]; } return self; } - (double)minCoord:(int)coord { return s_minCoord[coord][s_polar? POLAR:CARTESIAN]; } - (double)maxCoord:(int)coord { return s_maxCoord[coord][s_polar? POLAR:CARTESIAN]; } - setDegrees:(BOOL)cond; { if (degrees != cond) { degrees = cond; if (s_polar) if (degrees) { /* Convert radians to degrees */ s_maxCoord[X_TAG][POLAR] *= 57.2957795131; s_minCoord[X_TAG][POLAR] *= 57.2957795131; } else { /* Convert degrees to radians */ s_maxCoord[X_TAG][POLAR] /= 57.2957795131; s_minCoord[X_TAG][POLAR] /= 57.2957795131; } [self reportSettingsChange:self]; } return self; } - (BOOL)degrees { return degrees; } - (List *)functions { return functions; } // Shuts up the compiler about unused RCSId - (const char *) rcsid { return RCSId; } @end @implementation Status (Private) /* * We use a list of FunctionObjects to store each function (a * "function" is a mathematical expression that gnuplot will evaluate * at certain points or a file containing data that gnuplot will * plot.) We create these objects by parsing the plot arguments. */ - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond; { FunctionObject *aFunction; char *src; BOOL done; [functions freeObjects]; if (!aString) return nil; /* Skip any range specifications */ src = aString; while (isspace (*src)) src++; while (*src == '[') { while (*src != ']') src++; src++; while (isspace (*src)) src++; } /* Copy them to the strings list */ done = NO; while (!done) { char *end; if (end = _endFunction(src)) *end = '\0'; else done = YES; aFunction = [[FunctionObject allocFromZone:zone] initFromString: _removeLeadingBlanks (src) isThreeD:aCond]; [functions addObject:aFunction]; if (!done) { *end = ','; src = ++end; } } return self; } /* * We plot by assembling a Gnuplot "plot" command from the list of * FunctionObjects. */ - _buildPlotargs { int index = [functions count]; const char *aString; FunctionObject *function; int size = 0, counter, anInt, anInt2; /* * First, we calculate the total size that will be required for * the entire plot command, including commas, etc. */ if (counter = index) { size = isThreeD? 6 : 5; /* "splot" or "plot" */ while (counter--) { function = [functions objectAt:counter]; if (aString = [function stringValue]) size += strlen (aString); if ([function isDataFile]) size += 2; /* 2 quotation marks */ if (aString = [function title]) size += (strlen (aString) + 9); /* " title 'xxx'" */ if (aString = [function styleString]) size += (strlen (aString) + 12); /* " with ??? xx xx" */ size += 2; /* comma and space */ size += 255; /* "using" clause */ } /* * No comma or space after the last functions = -2 * Terminating ASCII NULL = +1 * ---- * Total = -1 */ size--; } /* Then we malloc enough space. */ NXZoneFree (zone, s_plotargs); s_plotargs = NXZoneMalloc (zone, size); /* And finally, assemble the pieces. */ if (index) { if (isThreeD) strcpy (s_plotargs, "splot "); else strcpy (s_plotargs, "plot "); counter = 0; while (counter != index) { function = [functions objectAt:counter++]; if ([function isDataFile]) { char using[255]; [self _buildUsing:using forFunction:function]; sprintf (index (s_plotargs, '\0'), "'%s' %s", [function stringValue], using); } else s_plotargs = strcat (s_plotargs, [function stringValue]); /* * We determine which kind of quotation marks to use for * the title by checking to see if the title itself * contains any quotation marks and using the opposite * kind. Assumption: that the title does not use both * kinds of quotation marks, single and double. */ if (aString = [function title]) { if (index (aString, '"')) sprintf (index (s_plotargs, '\0'), " title '%s'", aString); else sprintf(index(s_plotargs, '\0'), " title \"%s\"", aString); } if (aString = [function styleString]) { sprintf (index (s_plotargs, '\0'), " with %s", aString); /* * The following logical gymnastics are required * because the specific line and point styles may or * may not have been specified by the user and may or * may not be relevant. Plus, Gnuplot requires that * the line style be specified whenever the point * style is specified, even if the function has no * lines. Basically, we specify what we must (based * on the user's choices) and let the rest go to the * default. */ switch ([function style]) { case FUNCTION_LINES: if ((anInt = [function lineStyle]) != LINE_NOSTYLE) sprintf (index (s_plotargs, '\0'), " %d", anInt); break; case FUNCTION_POINTS: if ((anInt = [function pointsStyle]) != POINTS_NOSTYLE) sprintf (index (s_plotargs, '\0'), " 1 %d", anInt); break; case FUNCTION_LINESPOINTS: anInt2 = [function pointsStyle]; anInt = [function lineStyle]; if ((anInt != LINE_NOSTYLE) || (anInt2 != POINTS_NOSTYLE)) { sprintf (index (s_plotargs, '\0'), " %d", anInt); if (anInt2 != POINTS_NOSTYLE) sprintf (index (s_plotargs, '\0'), " %d", anInt2); } break; } } /* If there are more functions, we need a comma */ if (counter != index) s_plotargs = strcat (s_plotargs, ", "); } } return self; } - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction { struct coldat *d = [aFunction columnData]; *aString = '\0'; if (!d->isOn) /* No using clause */ return self; if (isThreeD) { if (d->useX) sprintf (aString, " using %d:%d:%d", d->x, d->y, d->z); else sprintf (aString, " using %d", d->z); } else { if (!d->useX) sprintf (aString, " using %d", d->y); else if (d->useX) { sprintf (aString, "using %d:%d", d->x, d->y); if (d->useYDelta) sprintf (aString, "%s:%d", aString, d->yDelta); else if (d->useYLow) { sprintf (aString, "%s:%d:%d", aString, d->yLow, d->yHigh); if (d->useBoxWidth) sprintf (aString, "%s:%d", aString, d->boxWidth); } else if (d->useBoxWidth) sprintf (aString, "%s:%d:%d:%d",aString,d->y,d->y,d->boxWidth); } } return self; } - (const char *) _copyString:(const char *)source to:(char **)dest { if (dest) { NXZoneFree (zone, *dest); if (source) *dest = NXCopyStringBufferFromZone (source, zone); else *dest = NULL; } return *dest; } /* * This method is nearly identical to load_file in misc.c, except * that instead of reading commands from a file, it reads from a * string, passing one line at a time to gnuplot. */ - _doText:(const char *)theText { extern char input_line[]; /* Line to be read by do_line() */ extern jmp_buf env; extern int do_line(); extern int interactive; int len; /* The length of a command */ int start, max; /* Indexes in input_line string */ BOOL more; /* Is there more of this line? */ BOOL stop; /* Are we done reading text? */ int inline_num; /* Text line number... */ int inline_index; /* ... which begins here */ if (setjmp(env)) { /* Gnuplot bails out to here */ /* in case of parse error, etc.*/ if (s_epsStream) { NXCloseMemory (s_epsStream, NX_FREEBUFFER); s_epsStream = NULL; } return nil; } else { interactive = 0; max = MAX_LINE_LEN; stop = NO; inline_num = inline_index = start = 0; if (s_epsStream) NXCloseMemory (s_epsStream, NX_FREEBUFFER); s_epsStream = NXOpenMemory(NULL, 0, NX_READWRITE); EPSStream = s_epsStream; while (!stop) { /* Read every line in theText */ more = YES; /* Read one command */ while (more) { if (!_get_line (&(input_line[start]), max, &theText[inline_index])) { stop = YES; /* End of string */ more = NO; } inline_num++; len = strlen (input_line); inline_index += (len + 1); if (len+1 >= max) { fprintf (stderr, "Input line too long\n"); /* todo Bring up a modal panel here or something */ } /* Continuation line */ if (input_line[len - 1] == '\\') { start = len - 1; max -= start; } else more = NO; } if (strlen (input_line) > 0) { do_line(); /* Parse input_line */ } } NEXTFE_reset(); return self; } } - _setText: (const char *) aString { NXZoneFree (zone, text); /* Magic number 100 -- todo be more accurate */ text = NXZoneMalloc (zone, strlen (aString) + 130); sprintf (text, "set term _nextfe '%s' %d\nset output '/dev/null'\n%s", s_font ? s_font : DEFAULT_FONT, s_fontsize, aString); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.