home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / aa_Intel_Only / Gnuplot / GnuplotSource / Status.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  33.5 KB  |  1,732 lines

  1. /*
  2.  *  Copyright (C) 1993  Robert Davis
  3.  *
  4.  *  This program is free software; you can redistribute it and/or
  5.  *  modify it under the terms of Version 2, or any later version, of 
  6.  *  the GNU General Public License as published by the Free Software 
  7.  *  Foundation.
  8.  */
  9.  
  10. static char RCSId[] = "$Id: Status.m,v 1.18 1993/05/30 09:10:15 davis Exp $";
  11.  
  12.  
  13. #import <appkit/Font.h>
  14. #import <appkit/nextstd.h>    /* NX_FREE            */
  15.  
  16. #import <objc/hashtable.h>    /* NXCopyStringBufferFromZone()    */
  17. #import <objc/List.h>
  18. #import <objc/zone.h>
  19.  
  20. #import <ctype.h>        /* isspace()            */
  21. #import <setjmp.h>        /* setjmp()             */
  22. #import <stdio.h>
  23. #import <strings.h>        /* strcat(), strcpy(), index()    */
  24.  
  25. #import "FunctionObject.h"
  26. #import "GnuplotPlot.h"
  27. #import "Status.h"
  28.  
  29. #import "StatusContour.h"    /* Status categories        */
  30. #import "StatusTics.h"
  31.  
  32.  
  33. @interface Status (Private)
  34. - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond;
  35. - _buildPlotargs;
  36. - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction;
  37. - (const char *) _copyString:(const char *)source to:(char **)dest;
  38. - _doText:(const char *)theText;
  39. - _setText:(const char *) aString;
  40. @end
  41.  
  42.  
  43. /* 
  44.  *  The class remembers which Status object was the last to issue a 
  45.  *  plot command to Gnuplot.  We need to know this when we set our 
  46.  *  instance variables to the corresponding Gnuplot values -- see 
  47.  *  -grabCurrent.
  48.  */
  49. static id    lastplot = nil;
  50.  
  51.  
  52. #define MAX_LINE_LEN 1024    /* Same as in plot.h    */
  53. #define DEFAULT_FONT        "Helvetica"
  54.  
  55. #define POLAR        0    /* Two sets of range information    */
  56. #define CARTESIAN    1
  57.  
  58.  
  59. /*
  60.  *  All instance variables begin with s_ to avoid confusion with the 
  61.  *  variables defined in gnuplot .c files.
  62.  *
  63.  *  gnuplot Variable (setshow.c)       Status Instance Variable
  64.  *  ----------------------------       ------------------------
  65.  */
  66. extern char nextfe_font[];        /* s_font            */
  67. extern int nextfe_fontsize;        /* s_fontsize            */
  68. extern int nextfe_solid;        // unused
  69. extern char title[];            /* s_title            */
  70. extern char xlabel[];            /* s_labelCoord[]        */
  71. extern char ylabel[];
  72. extern char zlabel[];
  73. extern char dummy_var[][51];        /* s_dummy_var[]        */
  74. extern int parametric;            /* s_parametric            */
  75. extern int polar;            /* s_polar            */
  76. extern int draw_border;            /* s_border            */
  77. extern int draw_surface;        /* s_draw_surface        */
  78. extern int grid;            /* s_grid            */
  79. extern int xzeroaxis;            /* s_zeroaxis[]            */
  80. extern int yzeroaxis;
  81. extern int is_log_x, is_log_y, is_log_z;/* s_isLogCoord[],s_isLogPol...    */
  82.  
  83. extern double base_log_x, base_log_y,    /* Currently unused by Status    */
  84.           base_log_z;        //
  85. extern double log_base_log_x,
  86.           log_base_log_y,
  87.           log_base_log_z;
  88.  
  89. extern int key;                /* s_key            */
  90. extern double key_x, key_y, key_z;    /* s_keyCoord[]            */
  91. extern int timedate;            /* s_time            */
  92. extern int time_xoffset, time_yoffset;    /* s_timeCoord[]        */
  93. extern float xsize, ysize;        /* s_xsize, s_ysize        */
  94. extern float surface_rot_x;        /* s_rot_x            */
  95. extern float surface_rot_z;        /* s_rot_z            */
  96. extern int hidden3d;            /* s_hidden3d            */
  97. extern int autoscale_x;            /* s_autoscaleCoord[][]        */
  98. extern int autoscale_y;
  99. extern int autoscale_z;
  100. extern int autoscale_r;
  101. extern double xmin, xmax;        /* s_minCoord[][],s_maxCoord[][]*/
  102. extern double ymin, ymax;
  103. extern double zmin, zmax;
  104. extern double rmin, rmax;
  105. extern int angles_format;        /* degrees            */
  106. extern int samples;            /* s_samples            */
  107. extern int samples_1;            /* s_samplesCoord        */
  108. extern int samples_2;
  109. extern int iso_samples_1;        /* s_iso_samplesCoord        */
  110. extern int iso_samples_2;
  111. extern char replot_line[];        /* s_plotargs            */
  112. extern NXStream *EPSStream;        /* s_epsStream (terminal)    */
  113. extern int nextfe_halve;        /* (GnuplotPlot preference)    */
  114. extern NEXTFE_reset();            /* Appends PS Trailer to stream    */
  115.  
  116.  
  117. /*
  118.  *  Removes leading blanks and tabs.
  119.  */
  120. static char *_removeLeadingBlanks (char *aString)
  121. {
  122.     if (aString && *aString) {
  123.     char *cur = aString;
  124.  
  125.     while (*cur && (isspace(*cur)))
  126.         cur++;
  127.  
  128.     strcpy (aString, cur);
  129.     }
  130.  
  131.     return aString;
  132. }
  133.  
  134.  
  135. /*
  136.  *  Stores the first line, up to max characters,  from the multi-line 
  137.  *  string source in dest and returns a pointer to it.  It replaces 
  138.  *  the newline with a null character.  If the line was the last in 
  139.  *  the string, it returns NULL.
  140.  */
  141. static char *_get_line (char *dest, int max, const char *source)
  142. {
  143.     char *returnVal = dest;
  144.  
  145.     if (source && dest)  {
  146.     while ((*source != '\n') && (*source != '\0') && (max > 0)) {
  147.         *dest = *source;
  148.         dest++;
  149.         source++;
  150.         max--;
  151.     }
  152.  
  153.     *dest = '\0';
  154.  
  155.     if (*source == '\n')
  156.         return returnVal;
  157.     }                    /*  NULL is returned if line is    */
  158.                     /*  too long or end of source    */
  159.     return NULL;            /*  or dest string is reached.    */
  160. }
  161.     
  162.  
  163. /*  
  164.  *  Finds the end of the first function in string containing arguments 
  165.  *  to gnuplot's plot command.
  166.  */
  167. static char *_endFunction(char *aString)
  168. {
  169.     char delim[MAX_LINE_LEN];
  170.     char *cur = aString;
  171.     int number = 0;
  172.  
  173.     while (cur && *cur) {
  174.  
  175.     switch (*cur) {
  176.     case '\'':
  177.     case '"':
  178.         if (number && delim[number - 1] == *cur)
  179.         number--;
  180.         else
  181.         delim[number++] = *cur;
  182.         break;
  183.  
  184.     case '(':
  185.     case ')':
  186.         if (number && delim[number - 1] == ((*cur == '(')? ')' : '('))
  187.         number --;
  188.         else
  189.         delim[number++] = *cur;
  190.         break;
  191.  
  192.     case ',':
  193.         if (!number)
  194.         return cur;
  195.     }
  196.  
  197.     cur++;
  198.     }
  199.  
  200.     return NULL;
  201. }
  202.  
  203.  
  204. const char *makeOneQuoteType (char *aString)
  205. {
  206.     char    *c, quote = '\0';
  207.  
  208.     /*  
  209.      *  Make sure at most one kind of quotation marks is used in the 
  210.      *  string -- change all quotation marks to match the first one.
  211.      */
  212.     for (c = aString; c && *c; c++)
  213.     if ((*c == '\'') || (*c == '"')) {
  214.         if (quote && (*c != quote))
  215.         *c = quote;
  216.         else
  217.         quote = *c;
  218.     }
  219.  
  220.     return aString;
  221. }
  222.     
  223.  
  224.  
  225. @implementation Status
  226.  
  227. + lastplot
  228. {
  229.     return lastplot;
  230. }
  231.  
  232.  
  233. + setHalvePlot:(BOOL)condition
  234. {
  235.     nextfe_halve = condition;
  236.     return self;
  237. }
  238.  
  239.  
  240. - init
  241. {
  242.     int counter;
  243.  
  244.     [super init];
  245.     zone = [self zone];
  246.  
  247.     report = YES;
  248.  
  249.     /* 
  250.      *  Set all pointers to NULL or nil so -resetCurrent
  251.      *  doesn't try to free them.
  252.      */
  253.     s_epsStream = NULL;
  254.  
  255.     text = s_title = s_plotargs = s_font = appendix =
  256.     s_dummy_var[0] = s_dummy_var[1] = NULL;
  257.  
  258.     for (counter = 0 ; counter < 3 ; counter++)
  259.     s_labelCoord[counter] = NULL;
  260.  
  261.     [self initTics];
  262.     [self initContour];
  263.  
  264.     [self resetCurrent];
  265.  
  266.     return self;
  267. }
  268.  
  269.  
  270. - free
  271. {
  272.     int counter;
  273.  
  274.     if (s_epsStream)
  275.     NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  276.  
  277.     /*  
  278.      *  NXZoneFree() doesn't bomb if you give it a NULL pointer, so we 
  279.      *  don't bother to check the pointer.
  280.      */
  281.     NXZoneFree (zone, text);
  282.     NXZoneFree (zone, appendix);
  283.     NXZoneFree (zone, s_title);
  284.     NXZoneFree (zone, s_font);
  285.     NXZoneFree (zone, s_dummy_var[X_TAG]);
  286.     NXZoneFree (zone, s_dummy_var[Y_TAG]);
  287.  
  288.     for (counter = 0 ; counter < 3 ; counter++)
  289.     NXZoneFree (zone, s_labelCoord[counter]);
  290.  
  291.     NXZoneFree (zone, s_plotargs);
  292.  
  293.     if (functions)
  294.     [[functions freeObjects] free];
  295.  
  296.     [self freeTics];
  297.     [self freeContour];
  298.  
  299.     if (lastplot == self)
  300.     lastplot = nil;
  301.  
  302.     return [super free];
  303. }
  304.  
  305.  
  306. - setReport:(BOOL)cond
  307. {
  308.     report = cond;
  309.     return self;
  310. }
  311.  
  312.  
  313. - (BOOL)report
  314. {
  315.     return report;
  316. }
  317.  
  318.  
  319. - setDelegate: anObject
  320. {
  321.     if ([anObject respondsTo:@selector(settingsDidChange:)]) {
  322.     delegate = anObject;
  323.     return self;
  324.     } else
  325.     return nil;
  326. }
  327.  
  328.  
  329. - delegate
  330. {
  331.     return delegate;
  332. }
  333.  
  334.  
  335. - (NXStream *)stream
  336. {
  337.     return s_epsStream;
  338. }
  339.  
  340.  
  341.  
  342. - (BOOL)canPlot
  343. {
  344.     int count = 0, index;
  345.     int total = [functions count];
  346.  
  347.     /* Count the number of functions */
  348.     index = total;
  349.     while (index--)
  350.     count += ([[functions objectAt:index] isDataFile]) ? 0 : 1;
  351.  
  352.     /* 
  353.      *  We can plot iff
  354.      * 
  355.      *         1) there is an appendix
  356.      *         
  357.      *             or
  358.      *             
  359.      *         2) there is at least one FunctionObject and
  360.      *         3) if the plot is parametric then
  361.      *             a) we have pairs of functions (two-dimensional),
  362.      *             b) or we have triplets of functions (3-dimens.)
  363.      *
  364.      */
  365.     
  366.     return ((appendix && *appendix) ||
  367.         (total && 
  368.          (s_parametric? (isThreeD? !(count % 3)
  369.                      : (!(count % 2) && (total == count)))
  370.               :YES)));
  371.  
  372. }
  373.  
  374.  
  375. - plot
  376. {
  377.     [self applyCurrent];
  378.     lastplot = self;
  379.  
  380.     if (areSettingsEdited && !appendix)  {
  381.     [self _buildPlotargs];
  382.     [self _setText:s_plotargs];
  383.  
  384.     areSettingsEdited = NO;
  385.     }
  386.  
  387.     if (appendix && *appendix)
  388.     [self _setText:appendix];    /* Appendix overrides current plot */
  389.  
  390.     return [self _doText:text];
  391. }
  392.  
  393.  
  394.  
  395. - saveToFile:(const char *)filename
  396. {
  397.     char    *copy, *line, *cur;
  398.     id        returnVal;
  399.  
  400.     /* 
  401.      *  Gnuplot sometimes drops characters off the end of long 
  402.      *  pathnames given to the "save" command, a bug that seems to 
  403.      *  have been introduced between 3.1 and 3.2.  We work around it 
  404.      *  by cd'ing to the directory first and then saving the file.
  405.      */
  406.     copy = NXCopyStringBufferFromZone (filename, zone);
  407.  
  408.     if (cur = rindex (copy, '/')) {
  409.     *(cur++) = '\0';
  410.     line = NXZoneMalloc (zone, 15 + strlen (filename));
  411.     sprintf (line, "cd '%s'\nsave '%s'\n", copy, cur);
  412.     } else {
  413.     line = NXZoneMalloc (zone, 9 + strlen (filename));
  414.     sprintf (line, "save '%s'\n", filename);
  415.     }
  416.  
  417.     returnVal = [self _doText:line]? self : nil;
  418.     NXZoneFree (zone, copy);
  419.     NXZoneFree (zone, line);
  420.  
  421.     return returnVal;
  422. }
  423.  
  424.  
  425.  
  426. - reportSettingsChange:sender
  427. {
  428.     areSettingsEdited = YES;
  429.     if (lastplot == self)
  430.     lastplot = nil;        /* Last valid plot is no longer valid */
  431.  
  432.     if (delegate && report)
  433.     [delegate settingsDidChange:self];
  434.  
  435.     return self;
  436. }
  437.  
  438.  
  439.  
  440. /* 
  441.  *  Resets all the instance variables to their default values.
  442.  */
  443. - resetCurrent
  444. {
  445.     int counter;
  446.  
  447.     if (functions)
  448.     [functions freeObjects];
  449.     else
  450.     functions = [[List allocFromZone:zone] init];
  451.  
  452.     NXZoneFree (zone, text);
  453.     text = NULL;
  454.  
  455.     NXZoneFree (zone, s_title);
  456.     s_title = NULL;
  457.  
  458.     NXZoneFree (zone, s_dummy_var[0]);
  459.     s_dummy_var[0] = NULL;
  460.  
  461.     NXZoneFree (zone, s_dummy_var[1]);
  462.     s_dummy_var[1] = NULL;
  463.  
  464.     for (counter = 0 ; counter < 3 ; counter++)  {
  465.     NXZoneFree (zone, s_labelCoord[counter]);
  466.     s_labelCoord[counter] = NULL;
  467.     s_minCoord[counter][CARTESIAN] = -10.0;
  468.     s_maxCoord[counter][CARTESIAN] = 10.0;
  469.     s_minCoord[counter][POLAR] = -10.0;
  470.     s_isLogCoord[counter][CARTESIAN] = NO;
  471.     s_isLogCoord[counter][POLAR] = NO;
  472.     }
  473.  
  474.     degrees = NO;
  475.                     /* These not set in for loop above */
  476.     s_minCoord[X_TAG][POLAR] = s_minCoord[R_TAG][POLAR] = 0.0;
  477.     s_maxCoord[X_TAG][POLAR] = degrees? 360 :6.283186;
  478.     s_maxCoord[Y_TAG][POLAR] = s_maxCoord[Z_TAG][POLAR]
  479.     = s_maxCoord[R_TAG][POLAR] = 10.0;
  480.  
  481.     NXZoneFree (zone, s_plotargs);
  482.     s_plotargs = NULL;
  483.  
  484.     NXZoneFree (zone, s_font);
  485.     s_font = NULL;
  486.  
  487.     NXZoneFree (zone, appendix);
  488.     appendix = NULL;
  489.  
  490.     s_fontsize = 16;
  491.  
  492.     isThreeD = NO;
  493.     s_parametric = NO;
  494.     s_polar = NO;
  495.     s_border = YES;
  496.     s_draw_surface = YES;
  497.  
  498.     [self resetCurrentContour];
  499.     [self resetCurrentTics];
  500.  
  501.     s_hidden3d = NO;
  502.     s_grid = NO;
  503.     s_zeroaxis[X_TAG] = s_zeroaxis[Y_TAG] = YES;
  504.  
  505.     s_key = YES;        /* Plot has a key, in default location    */
  506.     s_key_default = YES;
  507.  
  508.     s_time = NO;        /* Don't show time/date            */
  509.     s_time_default = YES;
  510.  
  511.     for (counter = 0 ; counter < 4 ; counter++) {
  512.     s_autoscaleCoord[counter][CARTESIAN] = 1;
  513.     s_autoscaleCoord[counter][POLAR] = 1;
  514.     }
  515.  
  516.     sizeProp = YES;    /* Keep x, y, z proportional */
  517.     s_xsize = s_ysize = 1.0;
  518.     s_samples = s_samplesCoord[X_TAG] = s_samplesCoord[Y_TAG] = 100;
  519.     s_iso_samplesCoord[X_TAG] = s_iso_samplesCoord[Y_TAG] = 10;
  520.  
  521.     s_rotCoord[X_TAG] = 60.0;
  522.     s_rotCoord[Z_TAG] = 30.0;
  523.  
  524.     areSettingsEdited = NO;
  525.  
  526.     return self;
  527. }
  528.  
  529.  
  530.  
  531.  
  532.  
  533. /*  Sets the current gnuplot settings to the Status instance variables.  */
  534. - applyCurrent
  535. {
  536.     int        type;
  537.  
  538.     nextfe_solid = NO;//
  539.  
  540.     if (s_font)
  541.     strcpy (nextfe_font, s_font);
  542.     else
  543.     strcpy (nextfe_font, DEFAULT_FONT);
  544.  
  545.     nextfe_fontsize = s_fontsize;
  546.  
  547.     if (s_title)
  548.     strcpy (title, s_title);
  549.     else
  550.     strcpy (title, "");
  551.  
  552.     if (s_dummy_var[0])
  553.     strcpy (dummy_var[0], s_dummy_var[0]);
  554.     else
  555.     strcpy (dummy_var[0], "x");
  556.  
  557.     if (s_dummy_var[1])
  558.     strcpy (dummy_var[1], s_dummy_var[1]);
  559.     else
  560.     strcpy (dummy_var[1], "y");
  561.  
  562.     if (s_labelCoord[X_TAG])
  563.     strcpy (xlabel, s_labelCoord[X_TAG]);
  564.     else
  565.     strcpy (xlabel, "");
  566.  
  567.     if (s_labelCoord[Y_TAG])
  568.     strcpy (ylabel, s_labelCoord[Y_TAG]);
  569.     else
  570.     strcpy (ylabel, "");
  571.  
  572.     if (s_labelCoord[Z_TAG])
  573.     strcpy (zlabel, s_labelCoord[Z_TAG]);
  574.     else
  575.     strcpy (zlabel, "");
  576.  
  577.     parametric = s_parametric;
  578.     polar = s_polar;
  579.     draw_border = s_border;
  580.     draw_surface = s_draw_surface;
  581.  
  582.     [self applyCurrentContour];
  583.     [self applyCurrentTics];
  584.  
  585.     hidden3d = s_hidden3d;
  586.     grid = s_grid;
  587.     xzeroaxis = s_zeroaxis[X_TAG];
  588.     yzeroaxis = s_zeroaxis[Y_TAG];
  589.  
  590.     /*  
  591.      *  We have to sets of ranges, depending on whether the plot is 
  592.      *  cartesian or polar.  Set the correct ones.
  593.      */
  594.     type = s_polar? POLAR:CARTESIAN;
  595.  
  596.     xmin = s_minCoord[X_TAG][type];
  597.     xmax = s_maxCoord[X_TAG][type];
  598.     ymin = s_minCoord[Y_TAG][type];
  599.     ymax = s_maxCoord[Y_TAG][type];
  600.     zmin = s_minCoord[Z_TAG][type];
  601.     zmax = s_maxCoord[Z_TAG][type];
  602.     is_log_x = s_isLogCoord[X_TAG][type];
  603.     is_log_y = s_isLogCoord[Y_TAG][type];
  604.     is_log_z = s_isLogCoord[Z_TAG][type];
  605.     autoscale_x = s_autoscaleCoord[X_TAG][type];
  606.     autoscale_y = s_autoscaleCoord[Y_TAG][type];
  607.     autoscale_z = s_autoscaleCoord[Z_TAG][type];
  608.     autoscale_r = s_autoscaleCoord[R_TAG][type];
  609.  
  610.     base_log_x = base_log_y = base_log_z = 10.0;
  611.     log_base_log_x = log_base_log_y = log_base_log_z = log(10.0);
  612.  
  613.     angles_format = degrees? ANGLES_DEGREES :ANGLES_RADIANS;
  614.  
  615.     key = s_key? (s_key_default? -1 :1) :0;
  616.     key_x = s_keyCoord[X_TAG];
  617.     key_y = s_keyCoord[Y_TAG];
  618.     key_z = s_keyCoord[Z_TAG];
  619.  
  620.     timedate = s_time? 1 :0;
  621.     time_xoffset = (s_time_default? 0 :s_timeCoord[X_TAG]);
  622.     time_yoffset = (s_time_default? 0 :s_timeCoord[Y_TAG]);
  623.  
  624.     xsize = s_xsize;
  625.     ysize = s_ysize;
  626.  
  627.     surface_rot_x = s_rotCoord[X_TAG];
  628.     surface_rot_z = s_rotCoord[Z_TAG];
  629.  
  630.     samples = s_samples;
  631.     samples_1 = s_samplesCoord[X_TAG];
  632.     samples_2 = s_samplesCoord[Y_TAG];
  633.     iso_samples_1 = s_iso_samplesCoord[X_TAG];
  634.     iso_samples_2 = s_iso_samplesCoord[Y_TAG];
  635.  
  636.     return self;
  637. }
  638.  
  639.  
  640.  
  641. /* 
  642.  *  Resets all the instance variables to the current gnuplot settings, 
  643.  *  all of which pertain to the most recent plot:
  644.  */
  645. - grabCurrent
  646. {
  647.     char *cur;
  648.     int type;
  649.  
  650.     NXZoneFree (zone, s_font);
  651.     s_font = NXCopyStringBufferFromZone (nextfe_font, zone);
  652.  
  653.     s_fontsize = nextfe_fontsize;
  654.  
  655.     NXZoneFree (zone, s_title);
  656.     s_title = NXCopyStringBufferFromZone (title, zone);
  657.  
  658.     NXZoneFree (zone, s_dummy_var[0]);
  659.     s_dummy_var[0] = NXCopyStringBufferFromZone (dummy_var[0], zone);
  660.  
  661.     NXZoneFree (zone, s_dummy_var[1]);
  662.     s_dummy_var[1] = NXCopyStringBufferFromZone (dummy_var[1], zone);
  663.  
  664.     NXZoneFree (zone, s_labelCoord[X_TAG]);
  665.     s_labelCoord[X_TAG] = NXCopyStringBufferFromZone (xlabel, zone);
  666.  
  667.     NXZoneFree (zone, s_labelCoord[Y_TAG]);
  668.     s_labelCoord[Y_TAG] = NXCopyStringBufferFromZone (ylabel, zone);
  669.  
  670.     NXZoneFree (zone, s_labelCoord[Z_TAG]);
  671.     s_labelCoord[Z_TAG] = NXCopyStringBufferFromZone (zlabel, zone);
  672.  
  673.     /*  
  674.      *  If the last plot command was "splot," as opposed to "plot,"  
  675.      *  it is three dimensional.
  676.      */
  677.     isThreeD = (*(_removeLeadingBlanks(replot_line)) == 's');
  678.  
  679.     s_parametric = parametric;
  680.     s_polar = polar;
  681.     s_border = draw_border;
  682.     s_draw_surface = draw_surface;
  683.  
  684.     [self grabCurrentContour];
  685.     [self grabCurrentTics];
  686.  
  687.     s_hidden3d = hidden3d;
  688.     s_grid = grid;
  689.     s_zeroaxis[X_TAG] = xzeroaxis;
  690.     s_zeroaxis[Y_TAG] = yzeroaxis;
  691.  
  692.     type = polar? POLAR:CARTESIAN;
  693.     s_minCoord[X_TAG][type] = xmin;
  694.     s_maxCoord[X_TAG][type] = xmax;
  695.     s_minCoord[Y_TAG][type] = ymin;
  696.     s_maxCoord[Y_TAG][type] = ymax;
  697.     s_minCoord[Z_TAG][type] = zmin;
  698.     s_maxCoord[Z_TAG][type] = zmax;
  699.     s_isLogCoord[X_TAG][type] = is_log_x;
  700.     s_isLogCoord[Y_TAG][type] = is_log_y;
  701.     s_isLogCoord[Z_TAG][type] = is_log_z;
  702.     s_autoscaleCoord[X_TAG][type] = autoscale_x;
  703.     s_autoscaleCoord[Y_TAG][type] = autoscale_y;
  704.     s_autoscaleCoord[Z_TAG][type] = autoscale_z;
  705.     s_autoscaleCoord[R_TAG][type] = autoscale_r;
  706.  
  707.     degrees = (angles_format == ANGLES_DEGREES);
  708.  
  709.     s_key = ((key == -1) || (key == 1));
  710.     s_key_default = (key == -1);
  711.     s_keyCoord[X_TAG] = key_x;
  712.     s_keyCoord[Y_TAG] = key_y;
  713.     s_keyCoord[Z_TAG] = key_z;
  714.  
  715.     s_time = timedate;
  716.     s_time_default = (time_xoffset == 0.0) && (time_yoffset == 0.0);
  717.     s_timeCoord[X_TAG] = time_xoffset;
  718.     s_timeCoord[Y_TAG] = time_yoffset;
  719.  
  720.     s_xsize = xsize;
  721.     s_ysize = ysize;
  722.  
  723.     s_samples = samples;
  724.     s_samplesCoord[X_TAG] = samples_1;
  725.     s_samplesCoord[Y_TAG] = samples_2;
  726.     s_iso_samplesCoord[X_TAG] = iso_samples_1;
  727.     s_iso_samplesCoord[Y_TAG] = iso_samples_2;
  728.  
  729.     s_rotCoord[X_TAG] = surface_rot_x;
  730.     s_rotCoord[Z_TAG] = surface_rot_z;
  731.  
  732.     NXZoneFree (zone, s_plotargs);
  733.     if (cur = index (replot_line, ' ')) {    /* todo What about tabs? */
  734.     s_plotargs = NXZoneMalloc (zone, strlen (replot_line) + 1);
  735.     strcpy (s_plotargs, cur + 1);
  736.     } else
  737.     s_plotargs = NULL;
  738.  
  739.     /* Break plotargs into separate functions */
  740.     [self _grabFunctionsFrom:s_plotargs isThreeD:isThreeD];
  741.     [self _buildPlotargs];
  742.  
  743.     [self _setText: s_plotargs];
  744.     areSettingsEdited = YES;
  745.  
  746.     return self;
  747. }
  748.  
  749.  
  750. - setThreeD:(BOOL) aCondition
  751. {
  752.  
  753.     if (isThreeD != aCondition)  {
  754.     int i;
  755.  
  756.     isThreeD = aCondition;
  757.  
  758.     for (i = [functions count] - 1; i >= 0; i--)
  759.         [[functions objectAt:i] setThreeD:isThreeD];
  760.  
  761.     if (s_parametric) {
  762.         if (isThreeD) {
  763.         [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
  764.         [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
  765.         } else
  766.         [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
  767.     }
  768.  
  769.     [self reportSettingsChange:self];
  770.     }
  771.     return self;
  772. }
  773.  
  774.  
  775. - (BOOL) isThreeD
  776. {
  777.     return isThreeD;
  778. }
  779.  
  780.  
  781.  
  782. - setParametric:(BOOL) cond
  783. {
  784.     if (s_parametric != cond)  {
  785.  
  786.     s_parametric = cond;
  787.  
  788.     if (cond) {
  789.         if (isThreeD) {
  790.         [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
  791.         [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
  792.         } else
  793.         [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
  794.     } else {
  795.         [self _copyString:"x" to:&(s_dummy_var[X_TAG])];
  796.         [self _copyString:"y" to:&(s_dummy_var[Y_TAG])];
  797.     }
  798.  
  799.     [self reportSettingsChange:self];
  800.  
  801.     }
  802.     return self;
  803. }
  804.  
  805.  
  806. - (BOOL) parametric
  807. {
  808.     return s_parametric;
  809. }
  810.  
  811.  
  812.  
  813. - setPolar:(BOOL) cond
  814. {
  815.     if (s_polar != cond) {
  816.     s_polar = cond;
  817.     [self reportSettingsChange:self];
  818.     }
  819.  
  820.     return self;
  821. }
  822.  
  823.  
  824. - (BOOL) isPolar
  825. {
  826.     return s_polar;
  827. }
  828.  
  829.  
  830.  
  831. - setBorder:(BOOL) cond
  832. {
  833.     if (s_border != cond) {
  834.     s_border = cond;
  835.     [self reportSettingsChange:self];
  836.     }
  837.  
  838.     return self;
  839. }
  840.  
  841.  
  842. - (BOOL) border
  843. {
  844.     return s_border;
  845. }
  846.  
  847.  
  848.  
  849. - setSurface:(BOOL) cond
  850. {
  851.     if (s_draw_surface != cond) {
  852.     s_draw_surface = cond;
  853.     [self reportSettingsChange:self];
  854.     }
  855.  
  856.     return self;
  857. }
  858.  
  859.  
  860. - (BOOL) surface
  861. {
  862.     return s_draw_surface;
  863. }
  864.  
  865.  
  866.  
  867. - setHiddenThreeD:(BOOL) cond
  868. {
  869.     if (s_hidden3d != cond) {
  870.     s_hidden3d = cond;
  871.     [self reportSettingsChange:self];
  872.     }
  873.  
  874.     return self;
  875. }
  876.  
  877.  
  878. - (BOOL) hiddenThreeD
  879. {
  880.     return s_hidden3d;
  881. }
  882.  
  883.  
  884.  
  885. - setGrid:(BOOL) cond
  886. {
  887.     if (s_grid != cond) {
  888.     s_grid = cond;
  889.     [self reportSettingsChange:self];
  890.     }
  891.  
  892.     return self;
  893. }
  894.  
  895.  
  896. - (BOOL) grid
  897. {
  898.     return s_grid;
  899. }
  900.  
  901.  
  902.  
  903. - setAxisCoord:(int)coord on:(BOOL)cond
  904. {
  905.     if (s_zeroaxis[coord] != cond) {
  906.     s_zeroaxis[coord] = cond;
  907.     [self reportSettingsChange:self];
  908.     }
  909.  
  910.     return self;
  911. }
  912.  
  913.  
  914. - (BOOL) axisCoord:(int)coord
  915. {
  916.     return s_zeroaxis[coord];
  917. }
  918.  
  919.  
  920.  
  921. - setIsLogCoord:(int)coord isOn:(BOOL)isOn
  922. {
  923.     int type = s_polar? POLAR:CARTESIAN;
  924.  
  925.     if (s_isLogCoord[coord][type] != isOn) {
  926.     s_isLogCoord[coord][type] = isOn;
  927.     [self reportSettingsChange:self];
  928.     }
  929.  
  930.     return self;
  931. }
  932.  
  933.  
  934.  
  935. - (BOOL) isLogCoord:(int)coord
  936. {
  937.     return s_isLogCoord[coord][s_polar? POLAR:CARTESIAN];
  938. }
  939.  
  940.  
  941.  
  942. - setTitle:(const char *) aString
  943. {
  944.     [self _copyString:aString to:&s_title];
  945.     makeOneQuoteType (s_title);
  946.     [self reportSettingsChange:self];
  947.  
  948.     return self;
  949. }
  950.  
  951.  
  952. - (const char *) title
  953. {
  954.     return s_title;
  955. }
  956.  
  957.  
  958. - setLabelCoord:(int)coord to:(const char *) aString
  959. {
  960.     [self _copyString:aString to:&(s_labelCoord[coord])];
  961.     makeOneQuoteType (s_labelCoord[coord]);
  962.     [self reportSettingsChange:self];
  963.  
  964.     return self;
  965. }
  966.  
  967.  
  968.  
  969. - (const char *) labelCoord:(int) coord
  970. {
  971.     return s_labelCoord[coord];
  972. }
  973.  
  974.  
  975. - setDummyVar:(int)coord to:(const char *)aString
  976. {
  977.     [self _copyString:aString to:&(s_dummy_var[coord])];
  978.     [self reportSettingsChange:self];
  979.     return self;
  980. }
  981.  
  982.  
  983. - (const char *)dummyVar:(int)coord
  984. {
  985.     if (!s_dummy_var[coord])
  986.     switch (coord) {
  987.     case X_TAG:
  988.         return "x";
  989.         break;
  990.     case Y_TAG:
  991.         return "y";
  992.         break;
  993.     }
  994.  
  995.     return s_dummy_var[coord];
  996. }
  997.  
  998.  
  999. - setAppendix: (const char *) aString
  1000. {
  1001.     NXZoneFree (zone, appendix);
  1002.  
  1003.     if (aString)
  1004.     appendix = NXCopyStringBufferFromZone (aString, zone);
  1005.     else
  1006.     appendix = NULL;
  1007.  
  1008.     return self;
  1009. }
  1010.  
  1011.  
  1012. - setFontsize: (int) anInt;
  1013. {
  1014.     if ((s_fontsize != anInt) && (anInt > 0)) {
  1015.     s_fontsize = anInt;
  1016.     [self reportSettingsChange:self];
  1017.     return self;
  1018.     } else
  1019.     return nil;
  1020. }
  1021.  
  1022.  
  1023. - (int) fontsize
  1024. {
  1025.     return s_fontsize;
  1026. }
  1027.  
  1028.  
  1029.  
  1030. - setFontname: (const char *) aString
  1031. {
  1032.     [self _copyString:aString to:&s_font];
  1033.     [self reportSettingsChange:self];
  1034.  
  1035.     return self;
  1036. }
  1037.  
  1038.  
  1039. - (const char *) fontname
  1040. {
  1041.     return s_font;
  1042. }
  1043.  
  1044.  
  1045.  
  1046. - setFont:aFont
  1047. {
  1048.     if (aFont)  {
  1049.     [self _copyString:[aFont name] to:&s_font];
  1050.     s_fontsize = [aFont pointSize];
  1051.     [self reportSettingsChange:self];
  1052.     }
  1053.  
  1054.     return self;
  1055. }
  1056.  
  1057.  
  1058.  
  1059. - font
  1060. {
  1061.     if (!s_font)
  1062.     return [Font newFont:DEFAULT_FONT size:s_fontsize];
  1063.     return [Font newFont:s_font size:s_fontsize];
  1064. }
  1065.  
  1066.  
  1067.  
  1068. - setKey:(BOOL) cond
  1069. {
  1070.     if (s_key != cond) {
  1071.     s_key = cond;
  1072.     [self reportSettingsChange:self];
  1073.     }
  1074.  
  1075.     return self;
  1076. }
  1077.  
  1078.  
  1079.  
  1080. - (BOOL) key
  1081. {
  1082.     return s_key;
  1083. }
  1084.  
  1085.  
  1086. - setKeyDefault:(BOOL) cond
  1087. {
  1088.     if (s_key_default != cond) {
  1089.     s_key_default = cond;
  1090.     [self reportSettingsChange:self];
  1091.     }
  1092.  
  1093.     return self;
  1094. }
  1095.  
  1096.  
  1097.  
  1098. - (BOOL) keyDefault
  1099. {
  1100.     return s_key_default;
  1101. }
  1102.  
  1103.  
  1104. - setKeyCoord:(int)coord to:(double)aDouble
  1105. {
  1106.     if (s_keyCoord[coord] != aDouble) {
  1107.     s_keyCoord[coord] = aDouble;
  1108.     [self reportSettingsChange:self];
  1109.     }
  1110.     return self;
  1111. }
  1112.  
  1113.  
  1114. - (double) keyCoord:(int)coord
  1115. {
  1116.     return s_keyCoord[coord];
  1117. }
  1118.  
  1119.  
  1120.  
  1121. - setTime:(BOOL) cond
  1122. {
  1123.     if (s_time != cond) {
  1124.     s_time = cond;
  1125.     [self reportSettingsChange:self];
  1126.     }
  1127.  
  1128.     return self;
  1129. }
  1130.  
  1131.  
  1132.  
  1133. - (BOOL) time
  1134. {
  1135.     return s_time;
  1136. }
  1137.  
  1138.  
  1139. - setTimeDefault:(BOOL) cond
  1140. {
  1141.     if (s_time_default != cond) {
  1142.     s_time_default = cond;
  1143.     [self reportSettingsChange:self];
  1144.     }
  1145.  
  1146.     return self;
  1147. }
  1148.  
  1149.  
  1150.  
  1151. - (BOOL) timeDefault
  1152. {
  1153.     return s_time_default;
  1154. }
  1155.  
  1156.  
  1157. - setTimeCoord:(int)coord to:(int)aDouble
  1158. {
  1159.     if (s_timeCoord[coord] != aDouble) {
  1160.     s_timeCoord[coord] = aDouble;
  1161.     [self reportSettingsChange:self];
  1162.     }
  1163.     return self;
  1164. }
  1165.  
  1166.  
  1167. - (int) timeCoord:(int)coord
  1168. {
  1169.     return s_timeCoord[coord];
  1170. }
  1171.  
  1172.  
  1173.  
  1174. - setSizeProp:(BOOL) cond
  1175. {
  1176.     sizeProp = cond;        /* Don't do anything, just record status */
  1177.     return self;
  1178. }
  1179.  
  1180.  
  1181. - (BOOL)sizeProp
  1182. {
  1183.     return sizeProp;
  1184. }
  1185.  
  1186.  
  1187. /*
  1188.  *  Size of zero means don't change... (e.g. if x=2 and y=0, we change 
  1189.  *  x but not y).
  1190.  */
  1191. - setSizeX:(float) xFloat Y:(float) yFloat
  1192. {
  1193.     if ((xFloat != s_xsize) || (yFloat != s_ysize)) {
  1194.  
  1195.     if (xFloat)
  1196.         s_xsize = xFloat;
  1197.  
  1198.     if (yFloat)
  1199.         s_ysize = yFloat;
  1200.  
  1201.     [self reportSettingsChange:self];
  1202.     }
  1203.  
  1204.     return self;
  1205. }
  1206.  
  1207.  
  1208. - (float) sizeX
  1209. {
  1210.     return s_xsize;
  1211. }
  1212.  
  1213.  
  1214. - (float) sizeY
  1215. {
  1216.     return s_ysize;
  1217. }
  1218.  
  1219.  
  1220.  
  1221. - setRotCoord:(int)coord to:(float)aFloat
  1222. {
  1223.     if (s_rotCoord[coord] != aFloat) {
  1224.     s_rotCoord[coord] = aFloat;
  1225.     [self reportSettingsChange:self];
  1226.     }
  1227.     return self;
  1228. }
  1229.  
  1230.  
  1231.  
  1232. - resetRotation
  1233. {
  1234.     s_rotCoord[X_TAG] = 60.0;
  1235.     s_rotCoord[Z_TAG] = 30.0;
  1236.     [self reportSettingsChange:self];
  1237.     return self;
  1238. }
  1239.  
  1240.  
  1241.  
  1242. - (float)rotCoord:(int)coord
  1243. {
  1244.     return s_rotCoord[coord];
  1245. }
  1246.  
  1247.  
  1248.  
  1249. - setSamplesCoord:(int)coord to:(int)anInt
  1250. {
  1251.     if ((anInt >= 2) && (anInt != s_samplesCoord[coord])) {
  1252.     s_samplesCoord[coord] = anInt;
  1253.     if (coord == X_TAG)
  1254.         s_samples = anInt;
  1255.     } else
  1256.     return nil;
  1257.  
  1258.     [self reportSettingsChange:self];
  1259.     return self;
  1260. }
  1261.  
  1262.  
  1263. - (int) samples:(int)coord
  1264. {
  1265.     return s_samplesCoord[coord];
  1266. }
  1267.  
  1268.  
  1269.  
  1270. - setIsoSamplesCoord:(int)coord to:(int)anInt
  1271. {
  1272.     if ((anInt >= 2) && (anInt != s_iso_samplesCoord[coord]))
  1273.     s_iso_samplesCoord[coord] = anInt;
  1274.     else
  1275.     return nil;
  1276.  
  1277.     [self reportSettingsChange:self];
  1278.     return self;
  1279. }
  1280.  
  1281.  
  1282. - (int) isoSamples:(int)coord
  1283. {
  1284.     return s_iso_samplesCoord[coord];
  1285. }
  1286.  
  1287.  
  1288.  
  1289. - setAutoscaleCoord:(int)coord isOn:(BOOL)cond
  1290. {
  1291.     int type = s_polar? POLAR:CARTESIAN;
  1292.  
  1293.     if (s_autoscaleCoord[coord][type] != cond) {
  1294.     s_autoscaleCoord[coord][type] = cond;
  1295.     [self reportSettingsChange:self];
  1296.     }
  1297.  
  1298.     return self;
  1299. }
  1300.  
  1301.  
  1302. - (BOOL)autoscaleCoord:(int)coord
  1303. {
  1304.     return s_autoscaleCoord[coord][s_polar? POLAR:CARTESIAN];
  1305. }
  1306.  
  1307.  
  1308. - setRangeCoord:(int)coord min:(double)min max:(double)max
  1309. {
  1310.     int type = s_polar? POLAR:CARTESIAN;
  1311.  
  1312.     if ((s_maxCoord[coord][type] != max) || (s_minCoord[coord][type] != min)) {
  1313.  
  1314.     s_maxCoord[coord][type] = max;
  1315.     s_minCoord[coord][type] = min;
  1316.  
  1317.     [self reportSettingsChange:self];
  1318.  
  1319.     }
  1320.  
  1321.     return self;
  1322. }
  1323.  
  1324. - (double)minCoord:(int)coord
  1325. {
  1326.     return s_minCoord[coord][s_polar? POLAR:CARTESIAN];
  1327. }
  1328.  
  1329. - (double)maxCoord:(int)coord
  1330. {
  1331.     return s_maxCoord[coord][s_polar? POLAR:CARTESIAN];
  1332. }
  1333.  
  1334.  
  1335.  
  1336. - setDegrees:(BOOL)cond;
  1337. {
  1338.     if (degrees != cond) {
  1339.     degrees = cond;
  1340.     if (s_polar)
  1341.         if (degrees)  {        /* Convert radians to degrees    */
  1342.         s_maxCoord[X_TAG][POLAR] *= 57.2957795131;
  1343.         s_minCoord[X_TAG][POLAR] *= 57.2957795131;
  1344.         } else {            /* Convert degrees to radians    */
  1345.         s_maxCoord[X_TAG][POLAR] /= 57.2957795131;
  1346.         s_minCoord[X_TAG][POLAR] /= 57.2957795131;
  1347.         }    
  1348.  
  1349.     [self reportSettingsChange:self];
  1350.     }
  1351.     return self;
  1352. }
  1353.  
  1354.  
  1355. - (BOOL)degrees
  1356. {
  1357.     return degrees;
  1358. }
  1359.  
  1360.  
  1361.  
  1362. - (List *)functions
  1363. {
  1364.     return functions;
  1365. }
  1366.  
  1367.  
  1368. // Shuts up the compiler about unused RCSId
  1369. - (const char *) rcsid
  1370. {
  1371.     return RCSId;
  1372. }
  1373.  
  1374.  
  1375. @end
  1376.  
  1377.  
  1378. @implementation Status (Private)
  1379.  
  1380.  
  1381. /*  
  1382.  *  We use a list of FunctionObjects to store each function (a 
  1383.  *  "function" is a mathematical expression that gnuplot will evaluate
  1384.  *  at certain points or a file containing data that gnuplot will 
  1385.  *  plot.)  We create these objects by parsing the plot arguments.
  1386.  */
  1387. - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond;
  1388. {
  1389.     FunctionObject *aFunction;
  1390.     char *src;
  1391.     BOOL done;
  1392.  
  1393.     [functions freeObjects];
  1394.  
  1395.     if (!aString)
  1396.     return nil;
  1397.  
  1398.     /* Skip any range specifications */
  1399.     src = aString;
  1400.     while (isspace (*src))
  1401.     src++;
  1402.     while (*src == '[') {
  1403.     while (*src != ']')
  1404.         src++;
  1405.     src++;
  1406.     while (isspace (*src))
  1407.         src++;
  1408.     }
  1409.  
  1410.     /* Copy them to the strings list */
  1411.  
  1412.     done = NO;
  1413.     while (!done)  {
  1414.     char *end;
  1415.  
  1416.     if (end = _endFunction(src))
  1417.         *end = '\0';
  1418.     else
  1419.         done = YES;
  1420.  
  1421.     aFunction = [[FunctionObject allocFromZone:zone]
  1422.          initFromString: _removeLeadingBlanks (src) isThreeD:aCond];
  1423.     [functions addObject:aFunction];
  1424.  
  1425.     if (!done) {
  1426.         *end = ',';
  1427.         src = ++end;
  1428.     }
  1429.     }
  1430.  
  1431.     return self;
  1432. }
  1433.  
  1434.  
  1435.  
  1436.  
  1437. /*
  1438.  *  We plot by assembling a Gnuplot "plot" command from the list of
  1439.  *  FunctionObjects.
  1440.  */
  1441.  
  1442. - _buildPlotargs
  1443. {
  1444.     int        index = [functions count];
  1445.     const char    *aString;
  1446.     FunctionObject    *function;
  1447.     int        size = 0, counter, anInt, anInt2;
  1448.  
  1449.     /*  
  1450.      *  First, we calculate the total size that will be required for 
  1451.      *  the entire plot command, including commas, etc.
  1452.      */
  1453.     if (counter = index)  {
  1454.  
  1455.     size = isThreeD? 6 : 5;                /* "splot" or "plot" */
  1456.  
  1457.     while (counter--) {
  1458.         function = [functions objectAt:counter];
  1459.  
  1460.         if (aString = [function stringValue])
  1461.         size += strlen (aString);
  1462.  
  1463.         if ([function isDataFile])
  1464.         size += 2;                /* 2 quotation marks */
  1465.  
  1466.         if (aString = [function title])
  1467.         size += (strlen (aString) + 9);        /* " title 'xxx'"    */
  1468.  
  1469.         if (aString = [function styleString])
  1470.         size += (strlen (aString) + 12);    /* " with ??? xx xx" */
  1471.  
  1472.         size += 2;                    /* comma and space   */
  1473.         size += 255;                /* "using" clause    */
  1474.     }
  1475.  
  1476.     /* 
  1477.      *  No comma or space after the last functions    = -2
  1478.      *  Terminating ASCII NULL            = +1
  1479.      *                         ----
  1480.      *                 Total        = -1
  1481.      */
  1482.     
  1483.     size--;
  1484.     }
  1485.  
  1486.     /*  Then we malloc enough space.  */
  1487.  
  1488.     NXZoneFree (zone, s_plotargs);
  1489.     s_plotargs = NXZoneMalloc (zone, size);
  1490.  
  1491.  
  1492.     /*  And finally, assemble the pieces.  */
  1493.     if (index) {
  1494.     if (isThreeD)
  1495.         strcpy (s_plotargs, "splot ");
  1496.     else
  1497.         strcpy (s_plotargs, "plot ");
  1498.  
  1499.     counter = 0;
  1500.     while (counter != index)  {
  1501.         function = [functions objectAt:counter++];
  1502.  
  1503.         if ([function isDataFile]) {
  1504.         char using[255];
  1505.  
  1506.         [self _buildUsing:using forFunction:function];
  1507.         sprintf (index (s_plotargs, '\0'), "'%s' %s",
  1508.              [function stringValue], using);
  1509.         } else
  1510.         s_plotargs = strcat (s_plotargs, [function stringValue]);
  1511.  
  1512.         /* 
  1513.          *  We determine which kind of quotation marks to use for 
  1514.          *  the title by checking to see if the title itself 
  1515.          *  contains any quotation marks and using the opposite 
  1516.          *  kind.  Assumption:  that the title does not use both 
  1517.          *  kinds of quotation marks, single and double.
  1518.          */
  1519.         if (aString = [function title]) {
  1520.         if (index (aString, '"'))
  1521.             sprintf (index (s_plotargs, '\0'), " title '%s'", aString);
  1522.         else
  1523.             sprintf(index(s_plotargs, '\0'), " title \"%s\"", aString);
  1524.         }
  1525.  
  1526.         if (aString = [function styleString])  {
  1527.  
  1528.         sprintf (index (s_plotargs, '\0'), " with %s", aString);
  1529.  
  1530.         /* 
  1531.          *  The following logical gymnastics are required 
  1532.          *  because the specific line and point styles may or 
  1533.          *  may not have been specified by the user and may or 
  1534.          *  may not be relevant.  Plus, Gnuplot requires that 
  1535.          *  the line style be specified whenever the point 
  1536.          *  style is specified, even if the function has no 
  1537.          *  lines.  Basically, we specify what we must (based 
  1538.          *  on the user's choices) and let the rest go to the 
  1539.          *  default.
  1540.          */
  1541.         
  1542.         switch ([function style]) {
  1543.         case FUNCTION_LINES:
  1544.             if ((anInt = [function lineStyle]) != LINE_NOSTYLE)
  1545.             sprintf (index (s_plotargs, '\0'), " %d", anInt);
  1546.             break;
  1547.         case FUNCTION_POINTS:
  1548.             if ((anInt = [function pointsStyle]) != POINTS_NOSTYLE)
  1549.             sprintf (index (s_plotargs, '\0'), " 1 %d", anInt);
  1550.             break;
  1551.         case FUNCTION_LINESPOINTS:
  1552.             anInt2 = [function pointsStyle];
  1553.             anInt = [function lineStyle];
  1554.             if ((anInt != LINE_NOSTYLE) || 
  1555.             (anInt2 != POINTS_NOSTYLE)) {
  1556.             sprintf (index (s_plotargs, '\0'), " %d", anInt);
  1557.             if (anInt2 != POINTS_NOSTYLE)
  1558.                 sprintf (index (s_plotargs, '\0'), " %d", anInt2);
  1559.             }
  1560.             break;
  1561.         }
  1562.  
  1563.         }
  1564.         
  1565.         /* If there are more functions, we need a comma */
  1566.         if (counter != index)
  1567.             s_plotargs = strcat (s_plotargs, ", ");
  1568.     }
  1569.     }
  1570.  
  1571.     return self;
  1572. }
  1573.  
  1574.  
  1575. - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction
  1576. {
  1577.     struct coldat *d = [aFunction columnData];
  1578.  
  1579.     *aString = '\0';
  1580.  
  1581.     if (!d->isOn)        /* No using clause */
  1582.     return self;
  1583.  
  1584.     if (isThreeD) {
  1585.  
  1586.     if (d->useX)
  1587.         sprintf (aString, " using %d:%d:%d", d->x, d->y, d->z);
  1588.     else
  1589.         sprintf (aString, " using %d", d->z);
  1590.  
  1591.     } else {
  1592.  
  1593.     if (!d->useX)
  1594.         sprintf (aString, " using %d", d->y);
  1595.  
  1596.     else if (d->useX) {
  1597.  
  1598.         sprintf (aString, "using %d:%d", d->x, d->y);
  1599.         if (d->useYDelta)
  1600.         sprintf (aString, "%s:%d", aString, d->yDelta);
  1601.         else if (d->useYLow) {
  1602.         sprintf (aString, "%s:%d:%d", aString, d->yLow, d->yHigh);
  1603.  
  1604.         if (d->useBoxWidth)
  1605.             sprintf (aString, "%s:%d", aString, d->boxWidth);
  1606.         } else if (d->useBoxWidth)
  1607.         sprintf (aString, "%s:%d:%d:%d",aString,d->y,d->y,d->boxWidth);
  1608.  
  1609.     }
  1610.     }
  1611.  
  1612.     return self;
  1613. }
  1614.  
  1615.  
  1616.  
  1617. - (const char *) _copyString:(const char *)source to:(char **)dest
  1618. {
  1619.     if (dest)  {
  1620.     NXZoneFree (zone, *dest);
  1621.  
  1622.     if (source)
  1623.         *dest = NXCopyStringBufferFromZone (source, zone);
  1624.     else
  1625.         *dest = NULL;
  1626.     }
  1627.  
  1628.     return *dest;
  1629. }
  1630.  
  1631.  
  1632. /*
  1633.  *  This method is nearly identical to load_file in misc.c, except 
  1634.  *  that instead of reading commands from a file, it reads from a 
  1635.  *  string, passing one line at a time to gnuplot.
  1636.  */
  1637. - _doText:(const char *)theText
  1638. {
  1639.     extern char input_line[];        /* Line to be read by do_line()    */
  1640.     extern jmp_buf env;
  1641.     extern int do_line();
  1642.     extern int interactive;
  1643.  
  1644.     int len;                /* The length of a command    */
  1645.     int start, max;            /* Indexes in input_line string    */
  1646.     BOOL more;                /* Is there more of this line?    */
  1647.     BOOL stop;                /* Are we done reading text?    */
  1648.     int inline_num;            /* Text line number...        */
  1649.     int inline_index;            /* ... which begins here    */
  1650.  
  1651.  
  1652.     if (setjmp(env))  {            /*  Gnuplot bails out to here    */
  1653.                     /*  in case of parse error, etc.*/
  1654.     if (s_epsStream) {
  1655.  
  1656.         NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  1657.         s_epsStream = NULL;
  1658.  
  1659.     }
  1660.  
  1661.     return nil;
  1662.  
  1663.     } else {
  1664.  
  1665.     interactive = 0;
  1666.     max = MAX_LINE_LEN;
  1667.     stop = NO;
  1668.     inline_num = inline_index = start = 0;
  1669.  
  1670.     if (s_epsStream)
  1671.         NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  1672.     s_epsStream = NXOpenMemory(NULL, 0, NX_READWRITE);
  1673.  
  1674.     EPSStream = s_epsStream;
  1675.  
  1676.     while (!stop) {                  /* Read every line in theText    */
  1677.  
  1678.         more = YES;            /* Read one command        */
  1679.         while (more) {
  1680.         if (!_get_line (&(input_line[start]), max,
  1681.                 &theText[inline_index])) {
  1682.             stop = YES;        /* End of string        */
  1683.             more = NO;
  1684.         }
  1685.  
  1686.         inline_num++;
  1687.         len = strlen (input_line);
  1688.         inline_index += (len + 1);
  1689.         if (len+1 >= max) {
  1690.             fprintf (stderr, "Input line too long\n");
  1691.             /* todo Bring up a modal panel here or something */
  1692.         }
  1693.  
  1694.                                 /* Continuation line        */
  1695.         if (input_line[len - 1] == '\\') {
  1696.             start = len - 1;
  1697.             max -= start;
  1698.         } else
  1699.             more = NO;
  1700.         }
  1701.  
  1702.         if (strlen (input_line) > 0) {
  1703.         do_line();            /* Parse input_line    */
  1704.         }
  1705.  
  1706.     }
  1707.  
  1708.     NEXTFE_reset();
  1709.  
  1710.     return self;
  1711.     }
  1712. }
  1713.  
  1714.  
  1715.  
  1716. - _setText: (const char *) aString
  1717. {
  1718.     NXZoneFree (zone, text);
  1719.  
  1720.     /* Magic number 100 -- todo be more accurate */
  1721.     text = NXZoneMalloc (zone, strlen (aString) + 130);
  1722.     sprintf (text, "set term _nextfe '%s' %d\nset output '/dev/null'\n%s",
  1723.          s_font ? s_font : DEFAULT_FONT, s_fontsize, aString);
  1724.  
  1725.     return self;
  1726. }
  1727.  
  1728.  
  1729.  
  1730.  
  1731. @end
  1732.