Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / plot2d.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: plot2d.c,v 1.133.2.17 2009/07/21 18:16:11 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - plot2d.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 #include "gp_types.h"
38 #include "plot2d.h"
39
40 #include "alloc.h"
41 #include "axis.h"
42 #include "binary.h"
43 #include "command.h"
44 #include "datafile.h"
45 #include "eval.h"
46 #include "fit.h"
47 #include "graphics.h"
48 #include "interpol.h"
49 #include "misc.h"
50 #include "parse.h"
51 #include "setshow.h"
52 #include "tables.h"
53 #include "term_api.h"
54 #include "util.h"
55 #ifdef BINARY_DATA_FILE
56 #include "plot.h"
57 #endif
58
59 #ifndef _Windows
60 # include "help.h"
61 #endif
62
63 /* minimum size of points[] in curve_points */
64 #define MIN_CRV_POINTS 100
65
66 /* static prototypes */
67
68 static struct curve_points * cp_alloc __PROTO((int num));
69 static int get_data __PROTO((struct curve_points *));
70 static void store2d_point __PROTO((struct curve_points *, int i, double x, double y, double xlow, double xhigh, double ylow, double yhigh, double width));
71 static void print_table __PROTO((struct curve_points * first_plot, int plot_num));
72 static void eval_plots __PROTO((void));
73 static void parametric_fixup __PROTO((struct curve_points * start_plot, int *plot_num));
74 #ifdef EAM_HISTOGRAMS
75 static void histogram_range_fiddling __PROTO((struct curve_points *plot));
76 #endif
77
78 /* internal and external variables */
79
80 /* the curves/surfaces of the plot */
81 struct curve_points *first_plot = NULL;
82 static struct udft_entry plot_func;
83
84 /* box width (automatic) */
85 double   boxwidth              = -1.0;
86 /* whether box width is absolute (default) or relative */
87 TBOOLEAN boxwidth_is_absolute  = TRUE;
88
89 #ifdef EAM_HISTOGRAMS
90 static double histogram_rightmost = 0.0;        /* Highest x-coord of histogram so far */
91 static char *histogram_title = NULL;            /* Subtitle for this histogram */
92 static struct coordinate GPHUGE *stackheight = NULL; /* Scratch space for y autoscale */
93 static int stack_count = 0;                     /* counter for stackheight */
94 #endif
95
96 /* function implementations */
97
98 /* HBB 20000508: moved cp_alloc() &friends to the main module using them, and
99  * made cp_alloc 'static'.
100  */
101 /*
102  * cp_alloc() allocates a curve_points structure that can hold 'num'
103  * points.   Initialize all fields to NULL.
104  */
105 static struct curve_points *
106 cp_alloc(int num)
107 {
108     struct curve_points *cp;
109     struct lp_style_type default_lp_properties = DEFAULT_LP_STYLE_TYPE;
110
111     cp = (struct curve_points *) gp_alloc(sizeof(struct curve_points), "curve");
112     memset(cp,0,sizeof(struct curve_points));
113
114     cp->p_max = (num >= 0 ? num : 0);
115     if (num > 0)
116         cp->points = (struct coordinate GPHUGE *)
117             gp_alloc(num * sizeof(struct coordinate), "curve points");
118
119     /* Initialize various fields */
120     cp->lp_properties = default_lp_properties;
121     default_arrow_style(&(cp->arrow_properties));
122     cp->fill_properties = default_fillstyle;
123
124     return (cp);
125 }
126
127
128 /*
129  * cp_extend() reallocates a curve_points structure to hold "num"
130  * points. This will either expand or shrink the storage.
131  */
132 void
133 cp_extend(struct curve_points *cp, int num)
134 {
135
136 #if defined(DOS16) || defined(WIN16)
137     /* Make sure we do not allocate more than 64k points in msdos since
138      * indexing is done with 16-bit int
139      * Leave some bytes for malloc maintainance.
140      */
141     if (num > 32700)
142         int_error(NO_CARET, "Array index must be less than 32k in msdos");
143 #endif /* MSDOS */
144
145     if (num == cp->p_max)
146         return;
147
148     if (num > 0) {
149         if (cp->points == NULL) {
150             cp->points = gp_alloc(num * sizeof(cp->points[0]),
151                                   "curve points");
152         } else {
153             cp->points = gp_realloc(cp->points, num * sizeof(cp->points[0]),
154                                     "expanding curve points");
155         }
156         cp->p_max = num;
157     } else {
158         if (cp->points != NULL)
159             free(cp->points);
160         cp->points = NULL;
161         cp->p_max = 0;
162     }
163 }
164
165 /*
166  * cp_free() releases any memory which was previously malloc()'d to hold
167  *   curve points (and recursively down the linked list).
168  */
169 /* HBB 20000506: instead of risking stack havoc by recursion, operate
170  * iteratively */
171 void
172 cp_free(struct curve_points *cp)
173 {
174     while (cp) {
175         struct curve_points *next = cp->next;
176
177         if (cp->title)
178             free(cp->title);
179         if (cp->points)
180             free(cp->points);
181 #ifdef EAM_DATASTRINGS
182         if (cp->labels) {
183             free_labels(cp->labels);
184             cp->labels = (struct text_label *)NULL;
185         }
186 #endif
187         free(cp);
188         cp = next;
189     }
190 }
191
192 /*
193  * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
194  * while in the non-parametric case we would say only plot [b= -2:2] [-1:1]
195  * sin(b)
196  */
197 void
198 plotrequest()
199 {
200     int dummy_token = -1;
201     int t_axis;
202
203     if (!term)                  /* unknown */
204         int_error(c_token, "use 'set term' to set terminal type first");
205
206     is_3d_plot = FALSE;
207 #ifdef WITH_IMAGE
208     is_cb_plot = FALSE;
209 #endif
210
211     /* Deactivate if 'set view map' is still running after the previous 'splot': */
212     splot_map_deactivate();
213
214     if (parametric && strcmp(set_dummy_var[0], "u") == 0)
215         strcpy(set_dummy_var[0], "t");
216
217     /* initialise the arrays from the 'set' scalars */
218
219     AXIS_INIT2D(FIRST_X_AXIS, 0);
220     AXIS_INIT2D(FIRST_Y_AXIS, 1);
221     AXIS_INIT2D(SECOND_X_AXIS, 0);
222     AXIS_INIT2D(SECOND_Y_AXIS, 1);
223     AXIS_INIT2D(T_AXIS, 0);
224     AXIS_INIT2D(R_AXIS, 1);
225     AXIS_INIT2D(COLOR_AXIS, 1);
226
227     t_axis = (parametric || polar) ? T_AXIS : FIRST_X_AXIS;
228
229     PARSE_NAMED_RANGE(t_axis, dummy_token);
230     if (parametric || polar)    /* set optional x ranges */
231         PARSE_RANGE(FIRST_X_AXIS);
232
233     /* possible reversal of x range *does* matter, even in parametric
234      * or polar mode */
235     CHECK_REVERSE(FIRST_X_AXIS);
236
237     PARSE_RANGE(FIRST_Y_AXIS);
238     CHECK_REVERSE(FIRST_Y_AXIS);
239     PARSE_RANGE(SECOND_X_AXIS);
240     CHECK_REVERSE(SECOND_X_AXIS);
241     PARSE_RANGE(SECOND_Y_AXIS);
242     CHECK_REVERSE(SECOND_Y_AXIS);
243
244     /* Clear out any tick labels read from data files in previous plot */
245     for (t_axis=0; t_axis<AXIS_ARRAY_SIZE; t_axis++) {
246         struct ticdef *ticdef = &axis_array[t_axis].ticdef;
247         if (ticdef->def.user)
248             ticdef->def.user = prune_dataticks(ticdef->def.user);
249         if (!ticdef->def.user && ticdef->type == TIC_USER)
250             ticdef->type = TIC_COMPUTED;
251     }
252
253     /* use the default dummy variable unless changed */
254     if (dummy_token >= 0)
255         copy_str(c_dummy_var[0], dummy_token, MAX_ID_LEN);
256     else
257         (void) strcpy(c_dummy_var[0], set_dummy_var[0]);
258
259     eval_plots();
260 }
261
262 /* A quick note about boxes style. For boxwidth auto, we cannot
263  * calculate widths yet, since it may be sorted, etc. But if
264  * width is set, we must do it now, before logs of xmin/xmax
265  * are taken.
266  * We store -1 in point->z as a marker to mean width needs to be
267  * calculated, or 0 to mean that xmin/xmax are set correctly
268  */
269 /* current_plot->token is after datafile spec, for error reporting
270  * it will later be moved passed title/with/linetype/pointtype
271  */
272 static int
273 get_data(struct curve_points *current_plot)
274 {
275     int i /* num. points ! */ , j;
276     int max_cols, min_cols;    /* allowed range of column numbers */
277     double v[MAXDATACOLS];
278     int storetoken = current_plot->token;
279 #ifdef WITH_IMAGE
280     struct coordinate GPHUGE *cp;
281 #endif
282
283     TBOOLEAN variable_color = FALSE;
284     double   variable_color_value;
285     if ((current_plot->lp_properties.pm3d_color.type == TC_RGB)
286     &&  (current_plot->lp_properties.pm3d_color.value < 0))
287         variable_color = TRUE;
288     if (current_plot->lp_properties.pm3d_color.type == TC_Z)
289         variable_color = TRUE;
290
291     /* eval_plots has already opened file */
292
293     /* HBB 2000504: For most plot styles, the 'z' coordinate is
294      * unused.  set it to -1, to account for that. For styles that use
295      * the z coordinate as a real coordinate (i.e. not a width or
296      * 'delta' component, change the setting inside the switch: */
297     current_plot->z_axis = -1;
298
299     /* HBB NEW 20060427: if there's only one, explicit using column,
300      * it's y data.  df_axis[] has to reflect that, so df_readline()
301      * will expect time/date input. */
302     if (df_no_use_specs == 1)
303         df_axis[0] = df_axis[1];
304
305     switch (current_plot->plot_style) { /* set maximum columns to scan */
306     case XYERRORLINES:
307     case XYERRORBARS:
308     case BOXXYERROR:
309         min_cols = 4;
310         max_cols = 7;           /* HBB FIXME 20060427: what's 7th? */
311
312         if (df_no_use_specs >= 6) {
313             /* HBB 20060427: signal 3rd and 4th column are absolute x
314              * data --- needed so time/date parsing works */
315             df_axis[2] = df_axis[3] = df_axis[0];
316             /* and 5th and 6th are absolute y data */
317             df_axis[4] = df_axis[5] = df_axis[1];
318         }
319         
320         break;
321
322     case FINANCEBARS:
323     case CANDLESTICKS:
324         /* HBB 20000504: use 'z' coordinate for y-axis quantity */
325         current_plot->z_axis = current_plot->y_axis;
326         min_cols = max_cols = 5;
327         /* HBB 20060427: signal 3rd and 4th column are absolute y data
328          * --- needed so time/date parsing works */
329         df_axis[2] = df_axis[3] = df_axis[4] = df_axis[1];
330         break;
331
332     case BOXERROR:
333         min_cols = 3;           /* HBB 20040520: fixed, was 4 */
334         max_cols = 5;
335
336         /* There are four(!) possible cases: */
337         /* 3 cols --> (x,y,dy), auto dx */
338         /* 4 cols, boxwidth==-2 --> (x,y,ylow,yhigh), auto dx */
339         /* 4 cols, boxwidth!=-2 --> (x,y,dy,dx) */
340         /* 5 cols --> (x,y,ylow,yhigh,dx) */
341         if ((df_no_use_specs == 4 && boxwidth == -2)
342             || df_no_use_specs == 5)
343             /* HBB 20060427: signal 3rd and 4th column are absolute y
344              * data --- needed so time/date parsing works */
345             df_axis[2] = df_axis[3] = df_axis[1];
346         break;
347
348     case VECTOR:        /* x, y, dx, dy, variable_color */
349         min_cols = 4;
350         max_cols = 5;
351         break;
352
353     case XERRORLINES:
354     case XERRORBARS:
355         min_cols = 3;
356         max_cols = 4;
357         if (df_no_use_specs == 4)
358             /* HBB 20060427: signal 3rd and 4th column are absolute x
359              * data --- needed so time/date parsing works */
360             df_axis[2] = df_axis[3] = df_axis[0];
361         break;
362
363     case YERRORLINES:
364     case YERRORBARS:
365         min_cols = 3;
366         max_cols = 4;
367         if (df_no_use_specs == 4)
368             /* HBB 20060427: signal 3rd and 4th column are absolute y
369              * data --- needed so time/date parsing works */
370             df_axis[2] = df_axis[3] = df_axis[1];
371         break;
372
373 #ifdef EAM_HISTOGRAMS
374     case HISTOGRAMS:
375         min_cols = 1;
376         max_cols = 2;
377         break;
378 #endif
379
380     case BOXES:
381         min_cols = 1;
382         max_cols = 4;
383         
384         break;
385
386     case FILLEDCURVES:
387     case IMPULSES:      /* 2 + possible variable color */
388     case LINES:
389     case DOTS:
390         min_cols = 1;
391         max_cols = 3;
392         break;
393
394 #ifdef EAM_DATASTRINGS
395     case LABELPOINTS:
396         /* 3 column data: X Y Label */
397         /* 4th column allows rgb variable */
398         min_cols = 3;
399         max_cols = 4;
400         expect_string( 3 );
401         break;
402 #endif
403
404 #ifdef WITH_IMAGE
405     case IMAGE:
406         min_cols = 3;
407         max_cols = 3;
408         break;
409
410     case RGBIMAGE:
411         min_cols = 5;
412         max_cols = 5;
413         break;
414 #endif
415
416     case POINTSTYLE:
417         /* Allow 3rd column because of 'pointsize variable' */
418         /* Allow 4th column because of 'lc rgb variable' */
419         min_cols = 1;
420         max_cols = 4;
421         break;
422
423     default:
424         min_cols = 1;
425         max_cols = 2;
426         break;
427     }
428
429     if (current_plot->plot_smooth == SMOOTH_ACSPLINES) {
430         max_cols = 3;
431         current_plot->z_axis = FIRST_Z_AXIS;
432         df_axis[2] = FIRST_Z_AXIS;
433     }
434
435     if (df_no_use_specs > max_cols)
436         int_error(NO_CARET, "Too many using specs for this style");
437
438     if (df_no_use_specs > 0 && df_no_use_specs < min_cols)
439         int_error(NO_CARET, "Not enough columns for this style");
440
441     i = 0;
442
443 #ifdef EAM_HISTOGRAMS
444     /* EAM FIXME - There are places in df_readline where it would be really */
445     /* nice to know what kind of plot we are making, so I think that        */
446     /* current_plot should be a parameter to df_readline. For now, however, */
447     /* I am using a global variable, and only for HISTOGRAMS.               */
448     df_current_plot = (current_plot->plot_style == HISTOGRAMS)
449         ? current_plot : NULL;
450 #endif
451
452     while ((j = df_readline(v, max_cols)) != DF_EOF) {
453         /* j <= max_cols */
454
455         if (i >= current_plot->p_max) {
456             /* overflow about to occur. Extend size of points[]
457              * array. Double the size, and add 1000 points, to avoid
458              * needlessly small steps. */
459             cp_extend(current_plot, i + i + 1000);
460         }
461
462         /* Allow for optional columns.  Currently only used for BOXES, but */
463         /* should be extended to a more general mechanism.                 */
464         variable_color_value = 0;
465         if (variable_color) {
466             int style = current_plot->plot_style;
467             if ((style == BOXES  && j >= 3)
468             ||  (style == VECTOR && j >= 5))
469                 variable_color_value = v[--j];
470         }
471
472         switch (j) {
473         default:
474             {
475                 df_close();
476                 int_error(c_token, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
477             }
478
479         case DF_MISSING:
480             /* Plot type specific handling of missing points goes here. */
481 #ifdef EAM_HISTOGRAMS
482             if (current_plot->plot_style == HISTOGRAMS) {
483                 current_plot->points[i].type = UNDEFINED;
484                 i++;
485                 continue;
486             }
487 #endif
488             /* Jun 2006 - Return to behavior of 3.7 and current docs:
489              *            do not interrupt plotted line because of missing data
490              */
491             FPRINTF((stderr,"Missing datum %d\n", i));
492             continue;
493
494         case DF_UNDEFINED:
495             /* NaN or bad result from extended using expression */
496             current_plot->points[i].type = UNDEFINED;
497             i++;
498             continue;
499
500         case DF_FIRST_BLANK:
501 #if defined(WITH_IMAGE) && defined(BINARY_DATA_FILE)
502             /* The binary input routines generate DF_FIRST_BLANK at the end
503              * of scan lines, so that the data may be used for the isometric
504              * splots.  Rather than turning that off inside the binary
505              * reading routine based upon the plot mode, DF_FIRST_BLANK is
506              * ignored for certain plot types requiring 3D coordinates in
507              * MODE_PLOT.
508              */
509             if ((current_plot->plot_style == IMAGE) || (current_plot->plot_style == RGBIMAGE))
510                 continue;
511 #endif
512             /* break in data, make next point undefined */
513             /* FIXME: We really should distinguish between a blank      */
514             /*        line and an undefined value on a non-blank line.  */
515             current_plot->points[i].type = UNDEFINED;
516             i++;
517             continue;
518
519         case DF_SECOND_BLANK:
520             /* second blank line. We dont do anything
521              * (we did everything when we got FIRST one)
522              */
523             continue;
524
525 #ifdef EAM_DATASTRINGS
526         case DF_FOUND_KEY_TITLE:
527             df_set_key_title(current_plot);
528             continue;
529         case DF_KEY_TITLE_MISSING:
530             fprintf(stderr,"get_data: key title not found in requested column\n");
531             continue;
532 #endif
533         case 0:         /* not blank line, but df_readline couldn't parse it */
534             {
535                 df_close();
536                 int_error(current_plot->token,
537                           "Bad data on line %d", df_line_number);
538             }
539
540         case 1:
541             {                   /* only one number */
542                 /* x is index, assign number to y */
543                 v[1] = v[0];
544                 v[0] = df_datum;
545                 /* nobreak */
546             }
547
548         case 2:
549 #ifdef EAM_HISTOGRAMS
550             if (current_plot->plot_style == HISTOGRAMS) {
551                 if (histogram_opts.type == HT_ERRORBARS) {
552                     if (j == 1)
553                         int_error(c_token, "Not enough columns in using specification");
554                     v[2] = v[1];
555                     v[1] = v[0];
556                     v[0] = df_datum;
557                 } else if (j == 2)
558                     int_error(c_token, "Too many columns in using specification");
559                 else v[2] = 0.0;
560
561                 if (histogram_opts.type == HT_STACKED_IN_TOWERS) {
562                     histogram_rightmost = current_plot->histogram_sequence
563                         + current_plot->histogram->start;
564                     current_plot->histogram->end = histogram_rightmost;
565                 } else if (v[0] + current_plot->histogram->start > histogram_rightmost) {
566                     histogram_rightmost = v[0] + current_plot->histogram->start;
567                     current_plot->histogram->end = histogram_rightmost;
568                 }
569                 /* Histogram boxwidths are always absolute */
570                 if (boxwidth > 0)
571                     store2d_point(current_plot, i++, v[0], v[1],
572                                   v[0] - boxwidth / 2, v[0] + boxwidth / 2,
573                                   v[1]-v[2], v[1]+v[2], 0.0);
574                 else
575                     store2d_point(current_plot, i++, v[0], v[1], 
576                                   v[0] - 0.5, v[0] + 0.5,
577                                   v[1]-v[2], v[1]+v[2], 0.0);       /* EAM DEBUG -1.0 ?? */
578             } else
579 #endif
580                 /* x, y */
581                 /* ylow and yhigh are same as y */
582
583                 if ( (current_plot->plot_style == BOXES)
584                      && boxwidth > 0 && boxwidth_is_absolute) {
585                     /* calculate width now */
586                     if (axis_array[current_plot->x_axis].log) {
587                         double base = axis_array[current_plot->x_axis].base;
588                         store2d_point(current_plot, i++, v[0], v[1],
589                                       v[0] * pow(base, -boxwidth/2.), v[0] * pow(base, boxwidth/2.),
590                                       v[1], variable_color_value, 0.0);
591                     } else
592                         store2d_point(current_plot, i++, v[0], v[1],
593                                       v[0] - boxwidth / 2, v[0] + boxwidth / 2,
594                                       v[1], variable_color_value, 0.0);
595                 } else {
596                     if (current_plot->plot_style == CANDLESTICKS
597                         || current_plot->plot_style == FINANCEBARS) {
598                         int_warn(storetoken, "This plot style does not work with 1 or 2 cols. Setting to points");
599                         current_plot->plot_style = POINTSTYLE;
600                     }
601                     /* xlow and xhigh are same as x */
602                     /* auto width if boxes, else ignored */
603                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[1],
604                                   v[1], -1.0);
605                 }
606             break;
607
608
609         case 3:
610             /* x, y, ydelta OR x, y, xdelta OR x, y, width */
611             if (current_plot->plot_smooth == SMOOTH_ACSPLINES)
612                 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[1],
613                               v[1], v[2]);
614             else
615                 switch (current_plot->plot_style) {
616                 default:
617                     int_warn(storetoken, "This plot style does not work with 3 cols. Setting to yerrorbars");
618                     current_plot->plot_style = YERRORBARS;
619                     /* fall through */
620
621                 case FILLEDCURVES:
622                     current_plot->filledcurves_options.closeto = FILLEDCURVES_BETWEEN;
623                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
624                                   v[1], v[2], -1.0);
625                     break;
626
627                 case YERRORLINES:
628                 case YERRORBARS:
629                 case BOXERROR:  /* x, y, dy */
630                     /* auto width if boxes, else ignored */
631                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
632                                   v[1] - v[2], v[1] + v[2], -1.0);
633                     break;
634
635                 case XERRORLINES:
636                 case XERRORBARS:
637                     store2d_point(current_plot, i++, v[0], v[1], v[0] - v[2],
638                                   v[0] + v[2], v[1], v[1], 0.0);
639                     break;
640
641                 case BOXES:
642                     /* calculate xmin and xmax here, so that logs are taken if if necessary */
643                     store2d_point(current_plot, i++, v[0], v[1],
644                                   v[0] - v[2] / 2, v[0] + v[2] / 2,
645                                   v[1], variable_color_value, 0.0);
646                     break;
647
648 #ifdef EAM_DATASTRINGS
649                 case LABELPOINTS:
650                     /* Load the coords just as we would have for a point plot */
651                     store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
652                                   v[1], -1.0);
653                     /* Allocate and fill in a text_label structure to match it */
654                     store_label(current_plot->labels,
655                                 &(current_plot->points[i]), i, df_tokens[2], 0.0);
656                     i++;
657                     break;
658 #endif
659
660 #ifdef WITH_IMAGE
661                 case IMAGE:  /* x_center y_center z_value */
662                     store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
663                                   v[1], v[2]);
664                     cp = &(current_plot->points[i]);
665                     COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[2], cp->type,
666                                                           COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
667                     i++;
668                     break;
669 #endif
670
671                 case POINTSTYLE: /* x, y, variable point size or variable color */
672                 case IMPULSES:
673                 case LINES:
674                 case DOTS:
675                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], 
676                                   v[1], v[2], v[2]);
677                     break;
678
679                 }               /*inner switch */
680
681             break;
682
683
684
685         case 4:
686             /* x, y, ylow, yhigh OR
687              * x, y, xlow, xhigh OR
688              * x, y, xdelta, ydelta OR
689              * x, y, ydelta, width
690              */
691
692             switch (current_plot->plot_style) {
693             default:
694                 int_warn(storetoken, "This plot style does not work with 4 cols. Setting to yerrorbars");
695                 current_plot->plot_style = YERRORBARS;
696                 /* fall through */
697
698             case YERRORLINES:
699             case YERRORBARS:
700                 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], v[2],
701                               v[3], -1.0);
702                 break;
703
704             case BOXXYERROR:    /* x, y, dx, dy */
705             case XYERRORLINES:
706             case XYERRORBARS:
707                 store2d_point(current_plot, i++, v[0], v[1],
708                               v[0] - v[2], v[0] + v[2],
709                               v[1] - v[3], v[1] + v[3], 0.0);
710                 break;
711
712
713             case BOXES:
714                 /* x, y, xmin, xmax */
715                 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3],
716                               v[1], variable_color_value, 0.0);
717                 break;
718
719             case XERRORLINES:
720             case XERRORBARS:
721                 /* x, y, xmin, xmax */
722                 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3],
723                               v[1], v[1], 0.0);
724                 break;
725
726             case BOXERROR:
727                 if (boxwidth == -2)
728                     /* x,y, ylow, yhigh --- width automatic */
729                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
730                                   v[2], v[3], -1.0);
731                 else
732                     /* x, y, dy, width */
733                     store2d_point(current_plot, i++, v[0], v[1],
734                                   v[0] - v[3] / 2, v[0] + v[3] / 2,
735                                   v[1] - v[2], v[1] + v[2], 0.0);
736                 break;
737
738             case VECTOR:
739                 /* x,y,dx,dy */
740                 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0] + v[2],
741                               v[1], v[1] + v[3], variable_color_value);
742                 break;
743
744             case POINTSTYLE: /* x, y, variable point size and variable color */
745                 store2d_point(current_plot, i++, v[0], v[1], v[0], v[0], 
746                                   v[1], v[3], v[2]);
747                 break;
748
749 #ifdef EAM_DATASTRINGS
750             case LABELPOINTS:
751                 /* Load the coords just as we would have for a point plot */
752                 store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1],
753                               v[1], -1.0);
754                 /* Allocate and fill in a text_label structure to match it */
755                 store_label(current_plot->labels,
756                             &(current_plot->points[i]), i, df_tokens[2], v[3]);
757                 i++;
758                 break;
759 #endif
760
761             }                   /*inner switch */
762
763             break;
764
765
766         case 5:
767             {   /* x, y, ylow, yhigh, width  or  x open low high close */
768                 switch (current_plot->plot_style) {
769                 default:
770 #ifdef WITH_IMAGE
771                     int_warn(storetoken, "Five col. plot style must be boxerrorbars, financebars, candlesticks, or rgbimage. Setting to boxerrorbars");
772 #else
773                     int_warn(storetoken, "Five col. plot style must be boxerrorbars, financebars or candlesticks. Setting to boxerrorbars");
774 #endif
775                     current_plot->plot_style = BOXERROR;
776                     /*fall through */
777
778                 case BOXERROR:  /* x, y, ylow, yhigh, width */
779                     store2d_point(current_plot, i++, v[0], v[1],
780                                   v[0] - v[4] / 2, v[0] + v[4] / 2,
781                                   v[2], v[3], 0.0);
782                     break;
783
784                 case FINANCEBARS: /* x yopen ylow yhigh yclose */
785                 case CANDLESTICKS:
786                     store2d_point(current_plot, i++, v[0], v[1], v[0], v[0],
787                                   v[2], v[3], v[4]);
788                     break;
789
790 #ifdef WITH_IMAGE
791                 case RGBIMAGE:  /* x_center y_center r_value g_value b_value (rgb) */
792                     store2d_point(current_plot, i, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
793                     /* A slight kludge, but it does in fact do what it is supposed to.
794                      * There is only one color axis, but we are storing components in
795                      * different variables.  Place all components on the same axis.
796                      * (That will maintain a consistent mapping amongst the components.)
797                      * But then retrieve what was stored and break it back into its
798                      * components storing without updating any axes.
799                      */
800                     cp = &(current_plot->points[i]);
801                     COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[2], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
802                     v[2] = cp->CRD_COLOR;
803                     COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[3], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
804                     v[3] = cp->CRD_COLOR;
805                     COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(cp->CRD_COLOR, v[4], cp->type, COLOR_AXIS, NOOP, cp->CRD_COLOR=-VERYLARGE);
806                     v[4] = cp->CRD_COLOR;
807                     cp->z = v[2];
808                     cp->xlow = v[3];
809                     cp->ylow = v[4];
810                     i++;
811                     break;
812 #endif
813                 }
814                 break;
815             }
816
817         case 7:
818             /* same as six columns. Width ignored */
819             /* eh ? - fall through */
820         case 6:
821             /* x, y, xlow, xhigh, ylow, yhigh */
822             switch (current_plot->plot_style) {
823             default:
824                 int_warn(storetoken, "This plot style not work with 6 cols. Setting to xyerrorbars");
825                 current_plot->plot_style = XYERRORBARS;
826                 /*fall through */
827             case XYERRORLINES:
828             case XYERRORBARS:
829             case BOXXYERROR:
830                 store2d_point(current_plot, i++, v[0], v[1], v[2], v[3], v[4],
831                               v[5], 0.0);
832                 break;
833             }
834
835         }                       /*switch */
836
837     }                           /*while */
838
839     current_plot->p_count = i;
840     cp_extend(current_plot, i); /* shrink to fit */
841
842     df_close();
843
844     return i;                   /* i==0 indicates an 'empty' file */
845 }
846
847 /* called by get_data for each point */
848 static void
849 store2d_point(
850     struct curve_points *current_plot,
851     int i,                      /* point number */
852     double x, double y,
853     double xlow, double xhigh,
854     double ylow, double yhigh,
855     double width)               /* BOXES widths: -1 -> autocalc, 0 ->  use xlow/xhigh */
856 {
857     struct coordinate GPHUGE *cp = &(current_plot->points[i]);
858     int dummy_type = INRANGE;   /* sometimes we dont care about outranging */
859
860     /* jev -- pass data values thru user-defined function */
861     /* div -- y is dummy variable 2 - copy value there */
862     if (ydata_func.at) {
863         struct value val;
864
865         (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
866         ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
867         evaluate_at(ydata_func.at, &val);
868         y = undefined ? 0.0 : real(&val);
869
870         (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
871         ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
872         evaluate_at(ydata_func.at, &val);
873         ylow = undefined ? 0 : real(&val);
874
875         (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
876         ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
877         evaluate_at(ydata_func.at, &val);
878         yhigh = undefined ? 0 : real(&val);
879     }
880     dummy_type = cp->type = INRANGE;
881
882     if (polar) {
883         double newx, newy;
884         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && y > axis_array[R_AXIS].max) {
885             cp->type = OUTRANGE;
886         }
887         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
888             /* we store internally as if plotting r(t)-rmin */
889             y -= axis_array[R_AXIS].min;
890         }
891         newx = y * cos(x * ang2rad);
892         newy = y * sin(x * ang2rad);
893 #if 0                           /* HBB 981118: added polar errorbars */
894         /* only lines and points supported with polar */
895         y = ylow = yhigh = newy;
896         x = xlow = xhigh = newx;
897 #else
898         y = newy;
899         x = newx;
900
901         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && yhigh > axis_array[R_AXIS].max) {
902             cp->type = OUTRANGE;
903         }
904         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
905             /* we store internally as if plotting r(t)-rmin */
906             yhigh -= axis_array[R_AXIS].min;
907         }
908         newx = yhigh * cos(xhigh * ang2rad);
909         newy = yhigh * sin(xhigh * ang2rad);
910         yhigh = newy;
911         xhigh = newx;
912
913         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && ylow > axis_array[R_AXIS].max) {
914             cp->type = OUTRANGE;
915         }
916         if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
917             /* we store internally as if plotting r(t)-rmin */
918             ylow -= axis_array[R_AXIS].min;
919         }
920         newx = ylow * cos(xlow * ang2rad);
921         newy = ylow * sin(xlow * ang2rad);
922         ylow = newy;
923         xlow = newx;
924 #endif
925     }
926     /* return immediately if x or y are undefined
927      * we dont care if outrange for high/low.
928      * BUT if high/low undefined (ie log( < 0 ), no number is stored,
929      * but graphics.c doesn't know.
930      * explicitly store -VERYLARGE;
931      */
932     STORE_WITH_LOG_AND_UPDATE_RANGE(cp->x, x, cp->type, current_plot->x_axis, NOOP, return);
933     STORE_WITH_LOG_AND_UPDATE_RANGE(cp->y, y, cp->type, current_plot->y_axis, NOOP, return);
934
935     switch (current_plot->plot_style) {
936     case POINTSTYLE:            /* Only x and y are relevant to axis scaling */
937     case LINES:
938     case LINESPOINTS:
939     case LABELPOINTS:
940     case DOTS:
941     case IMPULSES:
942         cp->xlow = xlow;
943         cp->xhigh = xhigh;
944         cp->ylow = ylow;
945         cp->yhigh = yhigh;
946         break;
947     case BOXES:                 /* auto-scale to xlow xhigh ylow yhigh */
948         cp->ylow = y;
949         cp->yhigh = yhigh;      /* really variable_color_data */
950         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xlow, xlow, dummy_type, 
951                                         current_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
952         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xhigh, xhigh, dummy_type,
953                                         current_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
954         break;
955     default:                    /* auto-scale to xlow xhigh ylow yhigh */
956         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xlow, xlow, dummy_type, 
957                                         current_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
958         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->xhigh, xhigh, dummy_type,
959                                         current_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
960         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->ylow, ylow, dummy_type,
961                                         current_plot->y_axis, NOOP, cp->ylow = -VERYLARGE);
962         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->yhigh, yhigh, dummy_type,
963                                         current_plot->y_axis, NOOP, cp->yhigh = -VERYLARGE);
964         break;
965     }
966
967     /* HBB 20010214: if z is not used for some actual value, just
968      * store 'width' to that axis and be done with it */
969     if ((int)current_plot->z_axis != -1)
970         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->z, width, dummy_type, current_plot->z_axis, NOOP, cp->z = -VERYLARGE);
971     else
972         cp->z = width;
973
974     /* If we have variable color corresponding to a z-axis value, use it to autoscale */
975     if (current_plot->lp_properties.pm3d_color.type == TC_Z)
976         STORE_WITH_LOG_AND_UPDATE_RANGE(cp->z, cp->z, dummy_type, COLOR_AXIS, 
977                                         NOOP, NOOP);
978
979 }                               /* store2d_point */
980
981 #ifdef EAM_HISTOGRAMS
982 /* Since the stored x values for histogrammed data do not correspond exactly */
983 /* to the eventual x coordinates, we need to modify the x axis range bounds. */
984 /* Also the two stacked histogram modes need adjustment of the y axis bounds.*/
985 static void
986 histogram_range_fiddling(struct curve_points *plot)
987 {
988     double xlow, xhigh;
989     int i;
990     /*
991      * EAM FIXME - HT_STACKED_IN_TOWERS forcibly resets xmin, which is only
992      *   correct if no other plot came first.
993      */
994     switch (histogram_opts.type) {
995         case HT_STACKED_IN_LAYERS:
996             if (axis_array[plot->y_axis].autoscale & AUTOSCALE_MAX) {
997                 if (plot->histogram_sequence == 0) {
998                     if (stackheight)
999                         free(stackheight);
1000                     stackheight = gp_alloc( plot->p_count * sizeof(struct coordinate GPHUGE),
1001                                             "stackheight array");
1002                     for (stack_count=0; stack_count < plot->p_count; stack_count++) {
1003                         stackheight[stack_count].yhigh = 0;
1004                         stackheight[stack_count].ylow = 0;
1005                     }
1006                 } else if (plot->p_count > stack_count) {
1007                     stackheight = gp_realloc( stackheight,
1008                                             plot->p_count * sizeof(struct coordinate GPHUGE),
1009                                             "stackheight array");
1010                     for ( ; stack_count < plot->p_count; stack_count++) {
1011                         stackheight[stack_count].yhigh = 0;
1012                         stackheight[stack_count].ylow = 0;
1013                     }
1014                 }
1015                 for (i=0; i<stack_count; i++) {
1016                     if (plot->points[i].type == UNDEFINED)
1017                         continue;
1018                     if (plot->points[i].y >= 0)
1019                         stackheight[i].yhigh += plot->points[i].y;
1020                     else
1021                         stackheight[i].ylow += plot->points[i].y;
1022
1023                     if (axis_array[plot->y_axis].max < stackheight[i].yhigh)
1024                         axis_array[plot->y_axis].max = stackheight[i].yhigh;
1025                     if (axis_array[plot->y_axis].min > stackheight[i].ylow)
1026                         axis_array[plot->y_axis].min = stackheight[i].ylow;
1027
1028                 }
1029             }
1030                 /* fall through to checks on x range */
1031         case HT_CLUSTERED:      
1032         case HT_ERRORBARS:      
1033                 if (!axis_array[FIRST_X_AXIS].autoscale)
1034                     break;
1035                 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN) {
1036                     xlow = plot->histogram->start - 1.0;
1037                     if (axis_array[FIRST_X_AXIS].min > xlow)
1038                         axis_array[FIRST_X_AXIS].min = xlow;
1039                 }
1040                 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX) {
1041                     /* FIXME - why did we increment p_count on UNDEFINED points? */
1042                     while (plot->points[plot->p_count-1].type == UNDEFINED) {
1043                         plot->p_count--;
1044                         if (!plot->p_count)
1045                             int_error(NO_CARET,"All points in histogram UNDEFINED");
1046                     }
1047                     xhigh = plot->points[plot->p_count-1].x;
1048                     xhigh += plot->histogram->start + 1.0;
1049                     if (axis_array[FIRST_X_AXIS].max < xhigh)
1050                         axis_array[FIRST_X_AXIS].max = xhigh;
1051                 }
1052                 break;
1053         case HT_STACKED_IN_TOWERS:
1054                 if (axis_array[FIRST_X_AXIS].set_autoscale) {
1055                     xlow = -1.0;
1056                     xhigh = plot->histogram_sequence;
1057                     xhigh += plot->histogram->start + 1.0;
1058                     if (axis_array[FIRST_X_AXIS].min > xlow)
1059                         axis_array[FIRST_X_AXIS].min = xlow;
1060                     if (axis_array[FIRST_X_AXIS].max != xhigh)
1061                         axis_array[FIRST_X_AXIS].max  = xhigh;
1062                 }
1063                 if (axis_array[FIRST_Y_AXIS].set_autoscale) {
1064                     double ylow, yhigh;
1065                     for (i=0, yhigh=ylow=0.0; i<plot->p_count; i++)
1066                         if (plot->points[i].type != UNDEFINED) {
1067                             if (plot->points[i].y >= 0)
1068                                 yhigh += plot->points[i].y;
1069                             else
1070                                 ylow += plot->points[i].y;
1071                         }
1072                     if (axis_array[FIRST_Y_AXIS].set_autoscale & AUTOSCALE_MAX)
1073                         if (axis_array[plot->y_axis].max < yhigh)
1074                             axis_array[plot->y_axis].max = yhigh;
1075                     if (axis_array[FIRST_Y_AXIS].set_autoscale & AUTOSCALE_MIN)
1076                         if (axis_array[plot->y_axis].min > ylow)
1077                             axis_array[plot->y_axis].min = ylow;
1078                 }
1079                 break;
1080     }
1081 }
1082 #endif
1083
1084 #ifdef EAM_DATASTRINGS
1085 /* store_label() is called by get_data for each point */
1086 /* This routine is exported so it can be shared by plot3d */
1087 void
1088 store_label(
1089     struct text_label *listhead,
1090     struct coordinate *cp,
1091     int i,                      /* point number */
1092     char *string,               /* start of label string */
1093     double colorval)            /* used if text color derived from palette */
1094 {
1095     struct text_label *tl = listhead;
1096     int textlen;
1097
1098     /* Walk through list to get to the end. Yes I know this is inefficient */
1099     /* but is anyone really going to plot so many labels that it matters?  */
1100     if (!tl) int_error(NO_CARET,"text_label list was not initialized");
1101     while (tl->next) tl = tl->next;
1102
1103     /* Allocate a new label structure and fill it in */
1104     tl->next = gp_alloc(sizeof(struct text_label),"labelpoint label");
1105     memcpy(tl->next,tl,sizeof(text_label));
1106     tl = tl->next;
1107     tl->next = (text_label *)NULL;
1108     tl->tag = i;
1109     tl->place.x = cp->x;
1110     tl->place.y = cp->y;
1111     tl->place.z = cp->z;
1112
1113     /* Check for optional (textcolor palette ...) */
1114     if (tl->textcolor.type == TC_Z)
1115         tl->textcolor.value = colorval;
1116     else if (tl->textcolor.type == TC_RGB && tl->textcolor.value < 0)
1117         tl->textcolor.lt = colorval;
1118
1119     /* Check for null string (no label) */
1120     if (!string)
1121         string = "";
1122
1123     textlen = 0;
1124     /* FIXME EAM - this code is ugly but seems to work */
1125     /* We need to handle quoted separators and quoted quotes */
1126     if (df_separator) {
1127         TBOOLEAN in_quote = FALSE;
1128         while (string[textlen]) {
1129             if (string[textlen] == '"')
1130                 in_quote = !in_quote;
1131             else if (string[textlen] == df_separator && !in_quote)
1132                 break;
1133             textlen++;
1134         }
1135         while (textlen > 0 && isspace(string[textlen-1]))
1136             textlen--;
1137     } else {
1138     /* This is the normal case (no special separator character) */
1139         if (*string == '"') {
1140             for (textlen=1; string[textlen] && string[textlen] != '"'; textlen++);
1141         }
1142         while (string[textlen] && !isspace(string[textlen]))
1143             textlen++;
1144     }
1145
1146     /* Strip double quote from both ends */
1147     if (string[0] == '"' && string[textlen-1] == '"')
1148         textlen -= 2, string++;
1149
1150     tl->text = gp_alloc(textlen+1,"labelpoint text");
1151     strncpy( tl->text, string, textlen );
1152     tl->text[textlen] = '\0';
1153     parse_esc(tl->text);
1154
1155     FPRINTF((stderr,"LABELPOINT %f %f \"%s\" \n", tl->place.x, tl->place.y, tl->text));
1156 }
1157
1158 #endif
1159
1160 /*
1161  * print_points: a debugging routine to print out the points of a curve, and
1162  * the curve structure. If curve<0, then we print the list of curves.
1163  */
1164
1165 #if 0                           /* not used */
1166 static char *plot_type_names[] =
1167 {
1168     "Function", "Data", "3D Function", "3d data"
1169 };
1170 static char *plot_style_names[] =
1171 {
1172     "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
1173     "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
1174     "FSteps", "Vector",
1175     "XErrorlines", "YErrorlines", "XYErrorlines"
1176 };
1177 static char *plot_smooth_names[] =
1178 {
1179     "None", "Unique", "Frequency", "CSplines", "ACSplines", "Bezier", "SBezier"
1180 };
1181
1182 static void
1183 print_points(int curve)
1184 {
1185     struct curve_points *this_plot;
1186     int i;
1187
1188     if (curve < 0) {
1189         for (this_plot = first_plot, i = 0;
1190              this_plot != NULL;
1191              i++, this_plot = this_plot->next) {
1192             printf("Curve %d:\n", i);
1193             if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
1194                 printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
1195                        plot_type_names[(int) (this_plot->plot_type)]);
1196             else
1197                 printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
1198             if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
1199                 printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
1200                        plot_style_names[(int) (this_plot->plot_style)]);
1201             else
1202                 printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
1203             if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
1204                 printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
1205                        plot_smooth_names[(int) (this_plot->plot_smooth)]);
1206             else
1207                 printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
1208             printf("\
1209 Plot title: '%s'\n\
1210 Line type %d\n\
1211 Point type %d\n\
1212 max points %d\n\
1213 current points %d\n\n",
1214                    this_plot->title,
1215                    this_plot->line_type,
1216                    this_plot->point_type,
1217                    this_plot->p_max,
1218                    this_plot->p_count);
1219         }
1220     } else {
1221         for (this_plot = first_plot, i = 0;
1222              i < curve && this_plot != NULL;
1223              i++, this_plot = this_plot->next);
1224         if (this_plot == NULL)
1225             printf("Curve %d does not exist; list has %d curves\n", curve, i);
1226         else {
1227             printf("Curve %d, %d points\n", curve, this_plot->p_count);
1228             for (i = 0; i < this_plot->p_count; i++) {
1229                 printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
1230                        this_plot->points[i].type == INRANGE ? 'i'
1231                        : this_plot->points[i].type == OUTRANGE ? 'o'
1232                        : 'u',
1233                        this_plot->points[i].x,
1234                        this_plot->points[i].y,
1235                        this_plot->points[i].z,
1236                        this_plot->points[i].xlow,
1237                        this_plot->points[i].xhigh,
1238                        this_plot->points[i].ylow,
1239                        this_plot->points[i].yhigh);
1240             }
1241             printf("\n");
1242         }
1243     }
1244 }
1245 #endif /* not used */
1246
1247
1248
1249 static void
1250 print_table(struct curve_points *current_plot, int plot_num)
1251 {
1252     int i, curve;
1253     char *buffer = gp_alloc(150, "print_table: output buffer");
1254     FILE *outfile = (table_outfile) ? table_outfile : gpoutfile;
1255
1256     for (curve = 0; curve < plot_num;
1257          curve++, current_plot = current_plot->next) {
1258         struct coordinate GPHUGE *point = NULL;
1259
1260         /* two blank lines between plots in table output by prepending
1261          * a \n here */
1262         fprintf(outfile, "\n#Curve %d of %d, %d points\n#x y",
1263                 curve, plot_num, current_plot->p_count);
1264         switch (current_plot->plot_style) {
1265         case BOXES:
1266         case XERRORBARS:
1267             fputs(" xlow xhigh", outfile);
1268             break;
1269         case BOXERROR:
1270         case YERRORBARS:
1271             fputs(" ylow yhigh", outfile);
1272             break;
1273         case BOXXYERROR:
1274         case XYERRORBARS:
1275             fputs(" xlow xhigh ylow yhigh", outfile);
1276             break;
1277         case FINANCEBARS:
1278         case CANDLESTICKS:
1279             fputs("open ylow yhigh yclose", outfile);
1280         default:
1281             /* ? */
1282             break;
1283         }
1284
1285         fputs(" type\n", outfile);
1286         for (i = 0, point = current_plot->points;
1287              i < current_plot->p_count;
1288              i++, point++) {
1289             /* HBB 20020405: new macro to use the 'set format' string
1290              * specifiers, as it has been documented for ages, but
1291              * never actually done. */
1292 #define OUTPUT_NUMBER(field, axis)                              \
1293             gprintf(buffer, 150, axis_array[axis].formatstring, \
1294                     1.0, point->field);                         \
1295             fputs(buffer, outfile);                             \
1296             fputc(' ', outfile);
1297
1298             /* FIXME HBB 20020405: had better use the real x/x2 axes
1299                of this plot */
1300             OUTPUT_NUMBER(x, current_plot->x_axis);
1301             OUTPUT_NUMBER(y, current_plot->y_axis);
1302
1303             switch (current_plot->plot_style) {
1304             case BOXES:
1305             case XERRORBARS:
1306                 OUTPUT_NUMBER(xlow, current_plot->x_axis);
1307                 OUTPUT_NUMBER(xhigh, current_plot->x_axis);
1308                 /* Hmmm... shouldn't this write out width field of box
1309                  * plots, too, if stored? */
1310                 break;
1311             case BOXXYERROR:
1312             case XYERRORBARS:
1313                 OUTPUT_NUMBER(xlow, current_plot->x_axis);
1314                 OUTPUT_NUMBER(xhigh, current_plot->x_axis);
1315                 /* FALLTHROUGH */
1316             case BOXERROR:
1317             case YERRORBARS:
1318                 OUTPUT_NUMBER(ylow, current_plot->y_axis);
1319                 OUTPUT_NUMBER(yhigh, current_plot->y_axis);
1320                 break;
1321             case FINANCEBARS:
1322             case CANDLESTICKS:
1323                 OUTPUT_NUMBER(ylow, current_plot->y_axis);
1324                 OUTPUT_NUMBER(yhigh, current_plot->y_axis);
1325                 OUTPUT_NUMBER(z, current_plot->y_axis);
1326             default:
1327                 /* ? */
1328                 break;
1329             } /* switch(plot type) */
1330             fprintf(outfile, " %c\n",
1331                     current_plot->points[i].type == INRANGE
1332                     ? 'i' : current_plot->points[i].type == OUTRANGE
1333                     ? 'o' : 'u');
1334         } /* for(point i) */
1335
1336         putc('\n', outfile);
1337     } /* for(curve) */
1338
1339     fflush(outfile);
1340     free(buffer);
1341 }
1342 #undef OUTPUT_NUMBER
1343
1344 /* HBB 20010610: mnemonic names for the bits stored in 'uses_axis' */
1345 typedef enum e_uses_axis {
1346     USES_AXIS_FOR_DATA = 1,
1347     USES_AXIS_FOR_FUNC = 2
1348 } t_uses_axis;
1349
1350 /*
1351  * This parses the plot command after any range specifications. To support
1352  * autoscaling on the x axis, we want any data files to define the x range,
1353  * then to plot any functions using that range. We thus parse the input
1354  * twice, once to pick up the data files, and again to pick up the functions.
1355  * Definitions are processed twice, but that won't hurt.
1356  * div - okay, it doesn't hurt, but every time an option as added for
1357  * datafiles, code to parse it has to be added here. Change so that
1358  * we store starting-token in the plot structure.
1359  */
1360 static void
1361 eval_plots()
1362 {
1363     int i;
1364     struct curve_points *this_plot, **tp_ptr;
1365     t_uses_axis uses_axis[AXIS_ARRAY_SIZE];
1366     int some_functions = 0;
1367     int plot_num, line_num, point_num, xparam = 0;
1368     int pattern_num;
1369     char *xtitle = NULL;
1370     int begin_token = c_token;  /* so we can rewind for second pass */
1371     legend_key *key = &keyT;
1372
1373 #ifdef EAM_HISTOGRAMS
1374     double newhist_start = 0.0;
1375     int histogram_sequence = -1;
1376     int newhist_color = 0;
1377     int newhist_pattern = LT_UNDEFINED;
1378     histogram_rightmost = 0.0;
1379     free_histlist(&histogram_opts);
1380     init_histogram(NULL,NULL);
1381 #endif
1382
1383     uses_axis[FIRST_X_AXIS] =
1384         uses_axis[FIRST_Y_AXIS] =
1385         uses_axis[SECOND_X_AXIS] =
1386         uses_axis[SECOND_Y_AXIS] = 0;
1387
1388     /* Reset first_plot. This is usually done at the end of this function.
1389      * If there is an error within this function, the memory is left allocated,
1390      * since we cannot call cp_free if the list is incomplete. Making sure that
1391      * the list structure is always vaild requires some rewriting */
1392     first_plot = NULL;
1393
1394     tp_ptr = &(first_plot);
1395     plot_num = 0;
1396     line_num = 0;               /* default line type */
1397     point_num = 0;              /* default point type */
1398     pattern_num = default_fillstyle.fillpattern;        /* default fill pattern */
1399
1400     xtitle = NULL;
1401
1402     /* ** First Pass: Read through data files ***
1403      * This pass serves to set the xrange and to parse the command, as well
1404      * as filling in every thing except the function data. That is done after
1405      * the xrange is defined.
1406      */
1407     while (TRUE) {
1408         if (END_OF_COMMAND)
1409             int_error(c_token, "function to plot expected");
1410
1411 #ifdef EAM_HISTOGRAMS
1412         if (almost_equals(c_token,"newhist$ogram")) {
1413             struct lp_style_type lp = DEFAULT_LP_STYLE_TYPE;
1414             struct fill_style_type fs;
1415             int previous_token;
1416             c_token++;
1417             histogram_sequence = -1;
1418             free(histogram_title);
1419             histogram_title = NULL;
1420
1421             if (histogram_rightmost > 0)
1422                 newhist_start = histogram_rightmost + 2;
1423
1424             lp.l_type = LT_UNDEFINED;
1425             fs.fillpattern = LT_UNDEFINED;
1426
1427             do {
1428                 previous_token = c_token;
1429
1430                 if (equals(c_token,"at")) {
1431                     struct value a;
1432                     c_token++;
1433                     newhist_start = real(const_express(&a));
1434                 }
1435
1436                 /* Store title in temporary variable and then copy into the */
1437                 /* new histogram structure when it is allocated.            */
1438                 if (!histogram_title && isstringvalue(c_token))
1439                     histogram_title = try_to_get_string();
1440
1441                 /* Allow explicit starting color or pattern for this histogram */
1442                 lp_parse(&lp, FALSE, FALSE);
1443                 parse_fillstyle(&fs, FS_SOLID, 100, fs.fillpattern, -1); 
1444
1445                 } while (c_token != previous_token);
1446
1447             newhist_color = lp.l_type;
1448             newhist_pattern = fs.fillpattern;
1449         } else
1450 #endif /* EAM_DATASTRINGS */
1451         if (is_definition(c_token)) {
1452             define();
1453         } else {
1454             int specs = 0;
1455
1456             /* for datafile plot, record datafile spec for title */
1457             int start_token = c_token, end_token;
1458             char* name_str;
1459
1460             TBOOLEAN duplication = FALSE;
1461             TBOOLEAN set_smooth = FALSE, set_axes = FALSE, set_title = FALSE;
1462             TBOOLEAN set_with = FALSE, set_lpstyle = FALSE;
1463             TBOOLEAN set_fillstyle = FALSE;
1464 #ifdef EAM_DATASTRINGS
1465             TBOOLEAN set_labelstyle = FALSE;
1466 #endif
1467
1468             plot_num++;
1469
1470             dummy_func = &plot_func;
1471             /* should this be saved in "this_plot"? */
1472             name_str = string_or_express(NULL);
1473             dummy_func = NULL;
1474
1475             if (name_str) { /* data file to plot */
1476                 if (parametric && xparam)
1477                     int_error(c_token, "previous parametric function not fully specified");
1478
1479                 if (*tp_ptr)
1480                     this_plot = *tp_ptr;
1481                 else {          /* no memory malloc()'d there yet */
1482                     this_plot = cp_alloc(MIN_CRV_POINTS);
1483                     *tp_ptr = this_plot;
1484                 }
1485                 this_plot->plot_type = DATA;
1486                 this_plot->plot_style = data_style;
1487                 this_plot->plot_smooth = SMOOTH_NONE;
1488                 this_plot->filledcurves_options.opt_given = 0;
1489                 /* default no palette */
1490                 this_plot->lp_properties.use_palette = 0;
1491
1492                 /* up to MAXDATACOLS cols */
1493                 df_set_plot_mode(MODE_PLOT);    /* Needed for binary datafiles */
1494                 specs = df_open(name_str, MAXDATACOLS);
1495
1496 #ifndef BINARY_DATA_FILE
1497                 /* this parses data-file-specific modifiers only */
1498                 /* we'll sort points when we know style, if necessary */
1499                 if (df_binary)
1500                     int_error(c_token, "This copy of gnuplot was not built with support for 2d binary files");
1501 #endif
1502                 /* include modifiers in default title */
1503                 this_plot->token = end_token = c_token - 1;
1504
1505             } else {
1506
1507                 /* function to plot */
1508
1509                 some_functions = 1;
1510                 if (parametric) /* working on x parametric function */
1511                     xparam = 1 - xparam;
1512                 if (*tp_ptr) {
1513                     this_plot = *tp_ptr;
1514                     cp_extend(this_plot, samples_1 + 1);
1515                 } else {        /* no memory malloc()'d there yet */
1516                     this_plot = cp_alloc(samples_1 + 1);
1517                     *tp_ptr = this_plot;
1518                 }
1519                 this_plot->plot_type = FUNC;
1520                 this_plot->plot_style = func_style;
1521                 this_plot->filledcurves_options.opt_given = 0;
1522                 /* default no palette */
1523                 this_plot->lp_properties.use_palette = 0;
1524                 end_token = c_token - 1;
1525             }                   /* end of IS THIS A FILE OR A FUNC block */
1526
1527             /* axis defaults */
1528             x_axis = FIRST_X_AXIS;
1529             y_axis = FIRST_Y_AXIS;
1530
1531             /* pm 25.11.2001 allow any order of options */
1532             while (!END_OF_COMMAND) {
1533
1534                 /*  deal with smooth */
1535                 if (almost_equals(c_token, "s$mooth")) {
1536                     int found_token;
1537
1538                     if (set_smooth) {
1539                         duplication=TRUE;
1540                         break;
1541                     }
1542                     found_token = lookup_table(plot_smooth_tbl, ++c_token);
1543
1544                     switch(found_token) {
1545                     case SMOOTH_ACSPLINES:
1546                     case SMOOTH_BEZIER:
1547                     case SMOOTH_CSPLINES:
1548                     case SMOOTH_SBEZIER:
1549                     case SMOOTH_UNIQUE:
1550                     case SMOOTH_FREQUENCY:
1551                         this_plot->plot_smooth = found_token;
1552                         break;
1553                     case SMOOTH_NONE:
1554                     default:
1555                         int_error(c_token, "expecting 'unique', 'frequency', 'acsplines', 'csplines', 'bezier' or 'sbezier'");
1556                         break;
1557                     }
1558                     this_plot->plot_style = LINES;
1559                     c_token++;      /* skip format */
1560                     set_smooth = TRUE;
1561                     continue;
1562                 }
1563
1564                 /* look for axes/axis */
1565                 if (almost_equals(c_token, "ax$es")
1566                     || almost_equals(c_token, "ax$is")) {
1567                     if (set_axes) {
1568                         duplication=TRUE;
1569                         break;
1570                     }
1571                     if (parametric && xparam)
1572                         int_error(c_token, "previous parametric function not fully specified");
1573
1574                     c_token++;
1575                     switch(lookup_table(&plot_axes_tbl[0],c_token)) {
1576                     case AXES_X1Y1:
1577                         x_axis = FIRST_X_AXIS;
1578                         y_axis = FIRST_Y_AXIS;
1579                         ++c_token;
1580                         break;
1581                     case AXES_X2Y2:
1582                         x_axis = SECOND_X_AXIS;
1583                         y_axis = SECOND_Y_AXIS;
1584                         ++c_token;
1585                         break;
1586                     case AXES_X1Y2:
1587                         x_axis = FIRST_X_AXIS;
1588                         y_axis = SECOND_Y_AXIS;
1589                         ++c_token;
1590                         break;
1591                     case AXES_X2Y1:
1592                         x_axis = SECOND_X_AXIS;
1593                         y_axis = FIRST_Y_AXIS;
1594                         ++c_token;
1595                         break;
1596                     case AXES_NONE:
1597                     default:
1598                         int_error(c_token, "axes must be x1y1, x1y2, x2y1 or x2y2");
1599                         break;
1600                     }
1601                     set_axes = TRUE;
1602                     continue;
1603                 }
1604
1605                 /* deal with title */
1606                 if (almost_equals(c_token, "t$itle")) {
1607                     if (set_title) {
1608                         duplication=TRUE;
1609                         break;
1610                     }
1611                     this_plot->title_no_enhanced = !key->enhanced;
1612                         /* title can be enhanced if not explicitly disabled */
1613                     if (parametric) {
1614                         if (xparam)
1615                             int_error(c_token, "\"title\" allowed only after parametric function fully specified");
1616                         else if (xtitle != NULL)
1617                             xtitle[0] = '\0';       /* Remove default title . */
1618                     }
1619                     c_token++;
1620                     if (!(this_plot->title = try_to_get_string()))
1621                         int_error(c_token, "expecting \"title\" for plot");
1622                     set_title = TRUE;
1623                     continue;
1624                 }
1625
1626                 if (almost_equals(c_token, "not$itle")) {
1627                     if (set_title) {
1628                         duplication=TRUE;
1629                         break;
1630                     }
1631                     c_token++;
1632                     if (isstringvalue(c_token))
1633                         try_to_get_string(); /* ignore optionally given title string */
1634                     this_plot->title_is_suppressed = TRUE;
1635                     if (xtitle != NULL)
1636                         xtitle[0] = '\0';
1637                     set_title = TRUE;
1638                     continue;
1639                 }
1640
1641                 /* deal with style */
1642                 if (almost_equals(c_token, "w$ith")) {
1643                     if (set_with) {
1644                         duplication=TRUE;
1645                         break;
1646                     }
1647                     if (parametric && xparam)
1648                         int_error(c_token, "\"with\" allowed only after parametric function fully specified");
1649                     this_plot->plot_style = get_style();
1650                     if (this_plot->plot_style == FILLEDCURVES) {
1651                         /* read a possible option for 'with filledcurves' */
1652                         get_filledcurves_style_options(&this_plot->filledcurves_options);
1653                     }
1654                     if ((this_plot->plot_type == FUNC) &&
1655                         ((this_plot->plot_style & PLOT_STYLE_HAS_ERRORBAR)
1656 #ifdef EAM_DATASTRINGS
1657                         || (this_plot->plot_style == LABELPOINTS)
1658 #endif
1659                         ))
1660                         {
1661                             int_warn(c_token, "This plot style is only for datafiles, reverting to \"points\"");
1662                             this_plot->plot_style = POINTSTYLE;
1663                         }
1664                     set_with = TRUE;
1665                     continue;
1666                 }
1667
1668 #ifdef EAM_DATASTRINGS
1669                 /* Labels can have font and text property info as plot options */
1670                 /* In any case we must allocate one instance of the text style */
1671                 /* that all labels in the plot will share.                     */
1672                 if (this_plot->plot_style == LABELPOINTS) {
1673                     int stored_token = c_token;
1674                     
1675                     if (this_plot->labels == NULL) {
1676                         this_plot->labels = new_text_label(-1);
1677                         this_plot->labels->pos = JUST_CENTRE;
1678                         this_plot->labels->layer = LAYER_PLOTLABELS;
1679                     }
1680                     parse_label_options(this_plot->labels);
1681                     if (stored_token != c_token) {
1682                         if (set_labelstyle) {
1683                             duplication = TRUE;
1684                             break;
1685                         } else {
1686                             set_labelstyle = TRUE;
1687                             continue;
1688                         }
1689                     }
1690                 }
1691 #endif /* EAM_DATASTRINGS */
1692
1693                 /* pick up line/point specs and other style-specific keywords
1694                  * - point spec allowed if style uses points, ie style&2 != 0
1695                  * - keywords for lt and pt are optional
1696                  */
1697                 if (this_plot->plot_style == CANDLESTICKS) {
1698                     if (almost_equals(c_token,"whisker$bars")) {
1699                         struct value a;
1700                         this_plot->arrow_properties.head = BOTH_HEADS;
1701                         c_token++;
1702                         if (isanumber(c_token) || type_udv(c_token) == INTGR || type_udv(c_token) == CMPLX)
1703                             this_plot->arrow_properties.head_length = real(const_express(&a));
1704                     }
1705                 }
1706
1707                 if (this_plot->plot_style == VECTOR) {
1708                     int stored_token = c_token;
1709                     
1710                     if (!set_lpstyle) {
1711                         default_arrow_style(&(this_plot->arrow_properties));
1712                         if (prefer_line_styles)
1713                             lp_use_properties(&(this_plot->arrow_properties.lp_properties),
1714                                                 line_num+1, FALSE);
1715                         else
1716                             this_plot->arrow_properties.lp_properties.l_type = line_num;
1717                     }
1718
1719                     arrow_parse(&(this_plot->arrow_properties), TRUE);
1720                     if (stored_token != c_token) {
1721                         if (set_lpstyle) {
1722                             duplication=TRUE;
1723                             break;
1724                         } else {
1725                             set_lpstyle = TRUE;
1726                             continue;
1727                         }
1728                     }
1729                 } else {
1730                     int stored_token = c_token;
1731                     struct lp_style_type lp = DEFAULT_LP_STYLE_TYPE;
1732
1733                     lp.l_type = line_num;
1734                     lp.p_type = point_num;
1735
1736                     /* user may prefer explicit line styles */
1737                     if (prefer_line_styles)
1738                         lp_use_properties(&lp, line_num+1, TRUE);
1739
1740                     lp_parse(&lp, TRUE,
1741                              this_plot->plot_style & PLOT_STYLE_HAS_POINT);
1742                     if (stored_token != c_token) {
1743                         if (set_lpstyle) {
1744                             duplication=TRUE;
1745                             break;
1746                         } else {
1747                             this_plot->lp_properties = lp;
1748                             set_lpstyle = TRUE;
1749                             continue;
1750                         }
1751                     }
1752                 }
1753
1754                 /* Some plots have a fill style as well */
1755                 if (this_plot->plot_style & PLOT_STYLE_HAS_FILL){
1756                     if (equals(c_token,"fs") || equals(c_token,"fill")) {
1757                         int stored_token = c_token;
1758                         parse_fillstyle(&this_plot->fill_properties,
1759                                 default_fillstyle.fillstyle,
1760                                 default_fillstyle.filldensity,
1761                                 pattern_num,
1762                                 default_fillstyle.border_linetype);
1763                         if (this_plot->plot_style == FILLEDCURVES 
1764                         && this_plot->fill_properties.fillstyle == FS_EMPTY)
1765                             this_plot->fill_properties.fillstyle = FS_SOLID;
1766                         set_fillstyle = TRUE;
1767                         if (stored_token != c_token)
1768                             continue;
1769                     }
1770                 }
1771
1772                 break; /* unknown option */
1773
1774             } /* while (!END_OF_COMMAND) */
1775
1776             if (duplication)
1777                 int_error(c_token, "duplicated or contradicting arguments in plot options");
1778
1779             /* set default values for title if this has not been specified */
1780             this_plot->title_is_filename = FALSE;
1781             if (!set_title) {
1782                 this_plot->title_no_enhanced = TRUE; /* filename or function cannot be enhanced */
1783                 if (key->auto_titles == FILENAME_KEYTITLES) {
1784                     m_capture(&(this_plot->title), start_token, end_token);
1785                     if (xparam)
1786                         xtitle = this_plot->title;
1787                     this_plot->title_is_filename = TRUE;
1788                 } else if (xtitle != NULL)
1789                     xtitle[0] = '\0';
1790             }
1791
1792             /* Vectors will be drawn using linetype from arrow style, so we
1793              * copy this to overall plot linetype so that the key sample matches */
1794             if (this_plot->plot_style == VECTOR) {
1795                 if (!set_lpstyle) {
1796                     if (prefer_line_styles)
1797                         lp_use_properties(&(this_plot->arrow_properties.lp_properties),
1798                                         line_num+1, FALSE);
1799                     else
1800                         this_plot->arrow_properties.lp_properties.l_type = line_num;
1801                     arrow_parse(&this_plot->arrow_properties, TRUE);
1802                 }
1803                 this_plot->lp_properties = this_plot->arrow_properties.lp_properties;
1804                 set_lpstyle = TRUE;
1805             }
1806             /* No line/point style given. As lp_parse also supplies
1807              * the defaults for linewidth and pointsize, call it now
1808              * to define them. */
1809             if (! set_lpstyle) {
1810                 this_plot->lp_properties.l_type = line_num;
1811                 this_plot->lp_properties.l_width = 1.0;
1812                 this_plot->lp_properties.p_type = point_num;
1813                 this_plot->lp_properties.p_size = pointsize;
1814                 this_plot->lp_properties.use_palette = 0;
1815
1816                 /* user may prefer explicit line styles */
1817                 if (prefer_line_styles)
1818                     lp_use_properties(&this_plot->lp_properties, line_num+1, TRUE);
1819
1820                 lp_parse(&this_plot->lp_properties, TRUE,
1821                          this_plot->plot_style & PLOT_STYLE_HAS_POINT);
1822
1823 #ifdef BACKWARDS_COMPATIBLE
1824                 /* allow old-style syntax - ignore case lt 3 4 for example */
1825                 if (!END_OF_COMMAND && isanumber(c_token)) {
1826                     struct value t;
1827                     this_plot->lp_properties.l_type =
1828                         this_plot->lp_properties.p_type =
1829                         (int) real(const_express(&t)) - 1;
1830
1831                     if (isanumber(c_token))
1832                         this_plot->lp_properties.p_type =
1833                             (int) real(const_express(&t)) - 1;
1834                 }
1835 #endif /* BACKWARDS_COMPATIBLE */
1836
1837             }
1838
1839             /* Rule out incompatible line/point/style options */
1840             if (this_plot->plot_type == FUNC) {
1841                 if ((this_plot->plot_style & PLOT_STYLE_HAS_POINT) 
1842                 &&  (this_plot->lp_properties.p_size == PTSZ_VARIABLE))
1843                     this_plot->lp_properties.p_size = 1;
1844             }
1845
1846             /* Similar argument for check that all fill styles were set */
1847             if (this_plot->plot_style & PLOT_STYLE_HAS_FILL) {
1848                 if (! set_fillstyle)
1849                     parse_fillstyle(&this_plot->fill_properties,
1850                                 default_fillstyle.fillstyle,
1851                                 default_fillstyle.filldensity,
1852                                 pattern_num,
1853                                 default_fillstyle.border_linetype);
1854                 if (this_plot->fill_properties.fillstyle == FS_PATTERN)
1855                     pattern_num = this_plot->fill_properties.fillpattern + 1;
1856                 if (this_plot->plot_style == FILLEDCURVES
1857                 && this_plot->fill_properties.fillstyle == FS_EMPTY)
1858                     this_plot->fill_properties.fillstyle = FS_SOLID;
1859             }
1860
1861 #ifdef EAM_DATASTRINGS
1862             /* If we got this far without initializing the label list, do it now */
1863             if (this_plot->plot_style == LABELPOINTS) {
1864                 if (this_plot->labels == NULL) {
1865                     this_plot->labels = new_text_label(-1);
1866                     this_plot->labels->pos = JUST_CENTRE;
1867                     this_plot->labels->layer = LAYER_PLOTLABELS;
1868                 }
1869                 this_plot->labels->place.scalex =
1870                     (x_axis == SECOND_X_AXIS) ? second_axes : first_axes;
1871                 this_plot->labels->place.scaley =
1872                     (y_axis == SECOND_Y_AXIS) ? second_axes : first_axes;
1873             }
1874 #endif /* EAM_DATASTRINGS */
1875
1876             this_plot->x_axis = x_axis;
1877             this_plot->y_axis = y_axis;
1878
1879 #ifdef EAM_HISTOGRAMS
1880             /* Initialize histogram data structure */
1881             if (this_plot->plot_style == HISTOGRAMS) {
1882                 if (axis_array[x_axis].log)
1883                     int_error(c_token, "Log scale on X is incompatible with histogram plots\n");
1884
1885                 if ((histogram_opts.type == HT_STACKED_IN_LAYERS
1886                 ||   histogram_opts.type == HT_STACKED_IN_TOWERS)
1887                 &&  axis_array[y_axis].log)
1888                     int_error(c_token, "Log scale on Y is incompatible with stacked histogram plot\n");
1889                 this_plot->histogram_sequence = ++histogram_sequence;
1890                 /* Current histogram always goes at the front of the list */
1891                 if (this_plot->histogram_sequence == 0) {
1892                     this_plot->histogram = gp_alloc(sizeof(struct histogram_style), "New histogram");
1893                     init_histogram(this_plot->histogram,histogram_title);
1894                     histogram_title = NULL;
1895                     this_plot->histogram->start = newhist_start;
1896                     this_plot->histogram->startcolor = newhist_color;
1897                     this_plot->histogram->startpattern = newhist_pattern;
1898                 } else {
1899                     this_plot->histogram = histogram_opts.next;
1900                     this_plot->histogram->clustersize++;
1901                 }
1902
1903                 /* Normally each histogram gets a new set of colors, but in */
1904                 /* 'newhistogram' you can force a starting color instead.   */
1905                 if (!set_lpstyle && this_plot->histogram->startcolor != LT_UNDEFINED)
1906                     this_plot->lp_properties.l_type = this_plot->histogram_sequence
1907                                                     + this_plot->histogram->startcolor;
1908                 if (this_plot->histogram->startpattern != LT_UNDEFINED)
1909                     this_plot->fill_properties.fillpattern = this_plot->histogram_sequence
1910                                                     + this_plot->histogram->startpattern;
1911             }
1912 #endif /* EAM_HISTOGRAMS */
1913
1914 #ifdef WITH_IMAGE
1915             /* Styles that use palette */
1916             if (this_plot->plot_style == IMAGE)
1917                 this_plot->lp_properties.use_palette = 1;
1918             /* Styles that use colorbus */
1919             if (this_plot->plot_style == IMAGE || this_plot->plot_style == RGBIMAGE)
1920                 is_cb_plot = TRUE;
1921 #endif /* WITH_IMAGE */
1922
1923             /* we can now do some checks that we deferred earlier */
1924
1925             if (this_plot->plot_type == DATA) {
1926                 if (specs < 0) {
1927                     /* Error check to handle missing or unreadable file */
1928                     if (this_plot->plot_style & PLOT_STYLE_HAS_POINT)
1929                         ++point_num;
1930                     ++line_num;
1931                     this_plot->plot_type = NODATA;
1932                     goto SKIPPED_EMPTY_FILE;
1933                 }
1934                 if (! (uses_axis[x_axis] & USES_AXIS_FOR_DATA)
1935                     && X_AXIS.autoscale) {
1936                     if (X_AXIS.autoscale & AUTOSCALE_MIN)
1937                         X_AXIS.min = VERYLARGE;
1938                     if (X_AXIS.autoscale & AUTOSCALE_MAX)
1939                         X_AXIS.max = -VERYLARGE;
1940                 }
1941                 if (X_AXIS.is_timedata) {
1942                     if (specs < 2)
1943                         int_error(c_token, "Need full using spec for x time data");
1944                 }
1945                 if (Y_AXIS.is_timedata) {
1946                     if (specs < 1)
1947                         int_error(c_token, "Need using spec for y time data");
1948                 }
1949                 /* need other cols, but I'm lazy */
1950                 df_axis[0] = x_axis;
1951                 df_axis[1] = y_axis;
1952
1953                 /* separate record of datafile and func */
1954                 uses_axis[x_axis] |= USES_AXIS_FOR_DATA;
1955                 uses_axis[y_axis] |= USES_AXIS_FOR_DATA;
1956             } else if (!parametric || !xparam) {
1957                 /* for x part of a parametric function, axes are
1958                  * possibly wrong */
1959                 /* separate record of data and func */
1960                 uses_axis[x_axis] |= USES_AXIS_FOR_FUNC;
1961                 uses_axis[y_axis] |= USES_AXIS_FOR_FUNC;
1962             }
1963
1964             if (!xparam
1965 #ifdef WITH_IMAGE
1966                 && this_plot->plot_style != IMAGE
1967                 && this_plot->plot_style != RGBIMAGE
1968                 /* don't increment the default line/point properties if
1969                  * this_plot is an image */
1970 #endif /* WITH_IMAGE */
1971             ) {
1972                 if (this_plot->plot_style & PLOT_STYLE_HAS_POINT)
1973                     ++point_num;
1974                 ++line_num;
1975             }
1976             if (this_plot->plot_type == DATA) {
1977                 /* actually get the data now */
1978                 if (get_data(this_plot) == 0) {
1979                     /* EAM 2005 - warn, but keep going */
1980                     int_warn(c_token-1,"Skipping data file with no valid points");
1981                     this_plot->plot_type = NODATA;
1982                     goto SKIPPED_EMPTY_FILE;
1983                 }
1984
1985 #ifdef EAM_HISTOGRAMS
1986                 /* Fiddle the auto-scaling data for histograms */
1987                 if (this_plot->plot_style == HISTOGRAMS)
1988                     histogram_range_fiddling(this_plot);
1989 #endif /* EAM_HISTOGRAMS */
1990
1991                 /* sort */
1992                 switch (this_plot->plot_smooth) {
1993                 /* sort and average, if the style requires */
1994                 case SMOOTH_UNIQUE:
1995                 case SMOOTH_FREQUENCY:
1996                 case SMOOTH_CSPLINES:
1997                 case SMOOTH_ACSPLINES:
1998                 case SMOOTH_SBEZIER:
1999                     sort_points(this_plot);
2000                     cp_implode(this_plot);
2001                 case SMOOTH_NONE:
2002                 case SMOOTH_BEZIER:
2003                 default:
2004                     break;
2005                 }
2006                 switch (this_plot->plot_smooth) {
2007                 /* create new data set by evaluation of
2008                  * interpolation routines */
2009                 case SMOOTH_FREQUENCY:
2010                     gen_interp_frequency(this_plot);
2011                     break;
2012                 case SMOOTH_CSPLINES:
2013                 case SMOOTH_ACSPLINES:
2014                 case SMOOTH_BEZIER:
2015                 case SMOOTH_SBEZIER:
2016                     gen_interp(this_plot);
2017                 case SMOOTH_NONE:
2018                 case SMOOTH_UNIQUE:
2019                 default:
2020                     break;
2021                 }
2022
2023                 /* now that we know the plot style, adjust the x- and yrange */
2024                 /* adjust_range(this_plot); no longer needed */
2025
2026 #ifdef WITH_IMAGE
2027                 /* Images are defined by a grid representing centers of pixels.
2028                  * Compensate for extent of the image so `set autoscale fix`
2029                  * uses outer edges of outer pixels in axes adjustment.
2030                  */
2031                 if ((this_plot->plot_style == IMAGE || this_plot->plot_style == RGBIMAGE))
2032                     UPDATE_AXES_FOR_PLOT_IMAGE(this_plot, IC_PALETTE);
2033 #endif
2034
2035             }
2036
2037             SKIPPED_EMPTY_FILE:
2038             /* Note position in command line for second pass */
2039                 this_plot->token = c_token;
2040                 tp_ptr = &(this_plot->next);
2041
2042         } /* !is_defn */
2043
2044         if (equals(c_token, ","))
2045             c_token++;
2046         else
2047             break;
2048     }
2049
2050     if (parametric && xparam)
2051         int_error(NO_CARET, "parametric function not fully specified");
2052
2053
2054 /*** Second Pass: Evaluate the functions ***/
2055     /*
2056      * Everything is defined now, except the function data. We expect
2057      * no syntax errors, etc, since the above parsed it all. This
2058      * makes the code below simpler. If y is autoscaled, the yrange
2059      * may still change.  we stored last token of each plot, so we
2060      * dont need to do everything again */
2061
2062     /* parametric or polar fns can still affect x ranges */
2063     if (!parametric && !polar) {
2064         /* If we were expecting to autoscale on X but found no usable
2065          * points in the data files, then the axis limits are still sitting
2066          * at +/- VERYLARGE.  The default range for bare functions is [-10:10].
2067          * Or we could give up and fall through to "x range invalid".
2068          */
2069         if (some_functions && uses_axis[FIRST_X_AXIS])
2070             if (axis_array[FIRST_X_AXIS].max == -VERYLARGE ||
2071                 axis_array[FIRST_X_AXIS].min == VERYLARGE) {
2072                     axis_array[FIRST_X_AXIS].min = -10;
2073                     axis_array[FIRST_X_AXIS].max = 10;
2074         }
2075
2076         /* check that xmin -> xmax is not too small */
2077         axis_checked_extend_empty_range(FIRST_X_AXIS, "x range is invalid");
2078
2079         if (uses_axis[SECOND_X_AXIS] & USES_AXIS_FOR_DATA) {
2080             /* check that x2min -> x2max is not too small */
2081             axis_checked_extend_empty_range(SECOND_X_AXIS, "x2 range is invalid");
2082         } else if (axis_array[SECOND_X_AXIS].autoscale) {
2083             /* copy x1's range */
2084             if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2085                 axis_array[SECOND_X_AXIS].min = axis_array[FIRST_X_AXIS].min;
2086             if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2087                 axis_array[SECOND_X_AXIS].max = axis_array[FIRST_X_AXIS].max;
2088         }
2089     }
2090     if (some_functions) {
2091
2092         /* call the controlled variable t, since x_min can also mean
2093          * smallest x */
2094         double t_min = 0., t_max = 0., t_step = 0.;
2095
2096         if (parametric || polar) {
2097             if (! (uses_axis[FIRST_X_AXIS] & USES_AXIS_FOR_DATA)) {
2098                 /* these have not yet been set to full width */
2099                 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN)
2100                     axis_array[FIRST_X_AXIS].min = VERYLARGE;
2101                 if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX)
2102                     axis_array[FIRST_X_AXIS].max = -VERYLARGE;
2103             }
2104             if (! (uses_axis[SECOND_X_AXIS] & USES_AXIS_FOR_DATA)) {
2105                 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2106                     axis_array[SECOND_X_AXIS].min = VERYLARGE;
2107                 if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2108                     axis_array[SECOND_X_AXIS].max = -VERYLARGE;
2109             }
2110         }
2111
2112         /* FIXME HBB 20000430: here and elsewhere, the code explicitly
2113          * assumes that the dummy variables (t, u, v) cannot possibly
2114          * be logscaled in parametric or polar mode. Does this
2115          * *really* hold? */
2116         if (parametric || polar) {
2117             t_min = axis_array[T_AXIS].min;
2118             t_max = axis_array[T_AXIS].max;
2119             t_step = (t_max - t_min) / (samples_1 - 1);
2120         }
2121         /* else we'll do it on each plot (see below) */
2122
2123         tp_ptr = &(first_plot);
2124         plot_num = 0;
2125         this_plot = first_plot;
2126         c_token = begin_token;  /* start over */
2127
2128         /* Read through functions */
2129         while (TRUE) {
2130             if (is_definition(c_token)) {
2131                 define();
2132             } else {
2133                 struct at_type *at_ptr;
2134                 char *name_str;
2135
2136                 /* HBB 20000820: now globals in 'axis.c' */
2137                 x_axis = this_plot->x_axis;
2138                 y_axis = this_plot->y_axis;
2139
2140                 plot_num++;
2141
2142                 dummy_func = &plot_func;
2143                 /* WARNING: do NOT free name_str */
2144                 /* FIXME: should this be saved in "this_plot"? */
2145                 name_str = string_or_express(&at_ptr);
2146
2147                 if (!name_str) {            /* function to plot */
2148                     if (parametric) {   /* toggle parametric axes */
2149                         xparam = 1 - xparam;
2150                     }
2151                     plot_func.at = at_ptr;
2152
2153                     if (!parametric && !polar) {
2154                         t_min = X_AXIS.min;
2155                         t_max = X_AXIS.max;
2156                         axis_unlog_interval(x_axis, &t_min, &t_max, 1);
2157                         t_step = (t_max - t_min) / (samples_1 - 1);
2158                     }
2159                     for (i = 0; i < samples_1; i++) {
2160                         double temp;
2161                         struct value a;
2162                         double t = t_min + i * t_step;
2163                         /* parametric/polar => NOT a log quantity */
2164                         double x = (!parametric && !polar)
2165                             ? AXIS_DE_LOG_VALUE(x_axis, t) : t;
2166
2167                         (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
2168                         evaluate_at(plot_func.at, &a);
2169
2170                         if (undefined || (fabs(imag(&a)) > zero)) {
2171                             this_plot->points[i].type = UNDEFINED;
2172                             continue;
2173                         }
2174                         temp = real(&a);
2175
2176                         /* width of box not specified */
2177                         this_plot->points[i].z = -1.0;
2178                         /* for the moment */
2179                         this_plot->points[i].type = INRANGE;
2180
2181                         if (parametric) {
2182                             /* we cannot do range-checking now, since for
2183                              * the x function we did not know which axes
2184                              * we were using
2185                              * DO NOT TAKE LOGS YET - do it in parametric_fixup
2186                              */
2187                             /* ignored, actually... */
2188                             this_plot->points[i].x = t;
2189                             this_plot->points[i].y = temp;
2190                             if (boxwidth >= 0 && boxwidth_is_absolute )
2191                                 this_plot->points[i].z = 0;
2192                         } else if (polar) {
2193                             double y;
2194                             if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && temp > axis_array[R_AXIS].max)
2195                                 this_plot->points[i].type = OUTRANGE;
2196                             if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN))
2197                                 temp -= axis_array[R_AXIS].min;
2198                             y = temp * sin(x * ang2rad);
2199                             x = temp * cos(x * ang2rad);
2200                             if (boxwidth >= 0 &&  boxwidth_is_absolute) {
2201                                 double xlow, xhigh;
2202                                 int dmy_type = INRANGE;
2203                                 this_plot->points[i].z = 0;
2204                                 if (axis_array[this_plot->x_axis].log) {
2205                                     double base = axis_array[this_plot->x_axis].base;
2206                                     xlow = x * pow(base, -boxwidth/2.);
2207                                     xhigh = x * pow(base, boxwidth/2.);
2208                                 } else {
2209                                     xlow = x - boxwidth/2;
2210                                     xhigh = x + boxwidth/2;
2211                                 }
2212                                 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xlow, xlow, dmy_type, x_axis, NOOP, NOOP );
2213                                 dmy_type = INRANGE;
2214                                 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xhigh, xhigh, dmy_type, x_axis, NOOP, NOOP );
2215                             }
2216                             temp = y;
2217                             STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].x, x, this_plot->points[i].type, x_axis, NOOP, goto come_here_if_undefined);
2218                             STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].y, y, this_plot->points[i].type, y_axis, NOOP, goto come_here_if_undefined);
2219                         } else {        /* neither parametric or polar */
2220                             /* If non-para, it must be INRANGE */
2221                             /* logscale ? log(x) : x */
2222                             this_plot->points[i].x = t;
2223                             if (boxwidth >= 0 && boxwidth_is_absolute) {
2224                                 double xlow, xhigh;
2225                                 int dmy_type = INRANGE;
2226                                 this_plot->points[i].z = 0;
2227                                 if (axis_array[this_plot->x_axis].log) {
2228                                     double base = axis_array[this_plot->x_axis].base;
2229                                     xlow = x * pow(base, -boxwidth/2.);
2230                                     xhigh = x * pow(base, boxwidth/2.);
2231                                 } else {
2232                                     xlow = x - boxwidth/2;
2233                                     xhigh = x + boxwidth/2;
2234                                 }
2235                                 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xlow, xlow, dmy_type, x_axis, NOOP, NOOP );
2236                                 dmy_type = INRANGE;
2237                                 STORE_WITH_LOG_AND_UPDATE_RANGE( this_plot->points[i].xhigh, xhigh, dmy_type, x_axis, NOOP, NOOP );
2238                             }
2239                             STORE_WITH_LOG_AND_UPDATE_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type, y_axis + (x_axis - y_axis) * xparam, NOOP, goto come_here_if_undefined);
2240
2241                             /* could not use a continue in this case */
2242                           come_here_if_undefined:
2243                             ;   /* ansi requires a statement after a label */
2244                         }
2245
2246                     }   /* loop over samples_1 */
2247                     this_plot->p_count = i;     /* samples_1 */
2248                 }
2249                 /* skip all modifers func / whole of data plots */
2250                 c_token = this_plot->token;
2251
2252                 /* used below */
2253                 tp_ptr = &(this_plot->next);
2254                 this_plot = this_plot->next;
2255             }
2256
2257             if (equals(c_token, ","))
2258                 c_token++;
2259             else
2260                 break;
2261         }
2262         /* when step debugging, set breakpoint here to get through
2263          * the 'read function' loop above quickly */
2264         if (parametric) {
2265             /* Now actually fix the plot pairs to be single plots
2266              * also fixes up polar&&parametric fn plots */
2267             parametric_fixup(first_plot, &plot_num);
2268             /* we omitted earlier check for range too small */
2269             axis_checked_extend_empty_range(FIRST_X_AXIS, NULL);
2270             if (uses_axis[SECOND_X_AXIS]) {
2271                 axis_checked_extend_empty_range(SECOND_X_AXIS, NULL);
2272             }
2273         }
2274     }   /* some_functions */
2275     /* throw out all curve_points at end of list, that we don't need  */
2276     cp_free(*tp_ptr);
2277     *tp_ptr = NULL;
2278
2279
2280     /* if first_plot is NULL, we have no functions or data at all. This can
2281      * happen, if you type "plot x=5", since x=5 is a variable assignment */
2282
2283     if (plot_num == 0 || first_plot == NULL) {
2284         int_error(c_token, "no functions or data to plot");
2285     }
2286
2287     if (!uses_axis[FIRST_X_AXIS] && !uses_axis[SECOND_X_AXIS])
2288         if (first_plot->plot_type == NODATA)
2289             int_error(NO_CARET,"No data in plot");
2290
2291     if (uses_axis[FIRST_X_AXIS]) {
2292         if (axis_array[FIRST_X_AXIS].max == -VERYLARGE ||
2293             axis_array[FIRST_X_AXIS].min == VERYLARGE)
2294             int_error(NO_CARET, "all points undefined!");
2295         axis_revert_and_unlog_range(FIRST_X_AXIS);
2296     }
2297     if (uses_axis[SECOND_X_AXIS]) {
2298         if (axis_array[SECOND_X_AXIS].max == -VERYLARGE ||
2299             axis_array[SECOND_X_AXIS].min == VERYLARGE)
2300             int_error(NO_CARET, "all points undefined!");
2301         axis_revert_and_unlog_range(SECOND_X_AXIS);
2302     } else {
2303         assert(uses_axis[FIRST_X_AXIS]);
2304         if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MIN)
2305             axis_array[SECOND_X_AXIS].min = axis_array[FIRST_X_AXIS].min;
2306         if (axis_array[SECOND_X_AXIS].autoscale & AUTOSCALE_MAX)
2307             axis_array[SECOND_X_AXIS].max = axis_array[FIRST_X_AXIS].max;
2308         if (! axis_array[SECOND_X_AXIS].autoscale)
2309             axis_revert_and_unlog_range(SECOND_X_AXIS);
2310     }
2311     if (! uses_axis[FIRST_X_AXIS]) {
2312         assert(uses_axis[SECOND_X_AXIS]);
2313         if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MIN)
2314             axis_array[FIRST_X_AXIS].min = axis_array[SECOND_X_AXIS].min;
2315         if (axis_array[FIRST_X_AXIS].autoscale & AUTOSCALE_MAX)
2316             axis_array[FIRST_X_AXIS].max = axis_array[SECOND_X_AXIS].max;
2317     }
2318
2319
2320     if (uses_axis[FIRST_Y_AXIS]) {
2321         axis_checked_extend_empty_range(FIRST_Y_AXIS, "all points y value undefined!");
2322         axis_revert_and_unlog_range(FIRST_Y_AXIS);
2323     }
2324     if (uses_axis[SECOND_Y_AXIS]) {
2325         axis_checked_extend_empty_range(SECOND_Y_AXIS, "all points y2 value undefined!");
2326         axis_revert_and_unlog_range(SECOND_Y_AXIS);
2327     } else {
2328         /* else we want to copy y2 range */
2329         assert(uses_axis[FIRST_Y_AXIS]);
2330         if (axis_array[SECOND_Y_AXIS].autoscale & AUTOSCALE_MIN)
2331             axis_array[SECOND_Y_AXIS].min = axis_array[FIRST_Y_AXIS].min;
2332         if (axis_array[SECOND_Y_AXIS].autoscale & AUTOSCALE_MAX)
2333             axis_array[SECOND_Y_AXIS].max = axis_array[FIRST_Y_AXIS].max;
2334         /* Log() fixup is only necessary if the range was *not* copied from
2335          * the (already logarithmized) yrange */
2336         if (! axis_array[SECOND_Y_AXIS].autoscale)
2337             axis_revert_and_unlog_range(SECOND_Y_AXIS);
2338     }
2339     if (! uses_axis[FIRST_Y_AXIS]) {
2340         assert(uses_axis[SECOND_Y_AXIS]);
2341         if (axis_array[FIRST_Y_AXIS].autoscale & AUTOSCALE_MIN)
2342             axis_array[FIRST_Y_AXIS].min = axis_array[SECOND_Y_AXIS].min;
2343         if (axis_array[FIRST_Y_AXIS].autoscale & AUTOSCALE_MAX)
2344             axis_array[FIRST_Y_AXIS].max = axis_array[SECOND_Y_AXIS].max;
2345     }
2346
2347 #if 0
2348     /* FIXME HBB 20000502: this seems to have been replaced by newer code,
2349      * in the meantime? --> disable it */
2350     AXIS_WRITEBACK(FIRST_X_AXIS);
2351     AXIS_WRITEBACK(FIRST_Y_AXIS);
2352     AXIS_WRITEBACK(SECOND_X_AXIS);
2353     AXIS_WRITEBACK(SECOND_Y_AXIS);
2354 #endif
2355
2356
2357     /* the following ~5 lines were moved from the end of the
2358      * function to here, as do_plot calles term->text, which
2359      * itself might process input events in mouse enhanced
2360      * terminals. For redrawing to work, line capturing and
2361      * setting the plot_num must already be done before
2362      * entering do_plot(). Thu Jan 27 23:56:24 2000 (joze) */
2363     /* if we get here, all went well, so record this line for replot */
2364     if (plot_token != -1) {
2365         /* note that m_capture also frees the old replot_line */
2366         m_capture(&replot_line, plot_token, c_token - 1);
2367         plot_token = -1;
2368     }
2369
2370     if (table_mode)
2371         print_table(first_plot, plot_num);
2372     else {
2373         START_LEAK_CHECK();     /* check for memory leaks in this routine */
2374
2375         /* do_plot now uses axis_array[] */
2376         do_plot(first_plot, plot_num);
2377
2378         END_LEAK_CHECK();
2379
2380         /* after do_plot(), axis_array[].min and .max
2381          * contain the plotting range actually used (rounded
2382          * to tic marks, not only the min/max data values)
2383          *  --> save them now for writeback if requested
2384          */
2385         SAVE_WRITEBACK_ALL_AXES;
2386         /* update GPVAL_ variables available to user */
2387         update_gpval_variables(1);
2388     }
2389
2390     cp_free(first_plot);
2391     first_plot = NULL;
2392 }                               /* eval_plots */
2393
2394
2395 /*
2396  * The hardest part of this routine is collapsing the FUNC plot types in the
2397  * list (which are garanteed to occur in (x,y) pairs while preserving the
2398  * non-FUNC type plots intact.  This means we have to work our way through
2399  * various lists.  Examples (hand checked): start_plot:F1->F2->NULL ==>
2400  * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
2401  * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
2402  *
2403  */
2404 static void
2405 parametric_fixup(struct curve_points *start_plot, int *plot_num)
2406 {
2407     struct curve_points *xp, *new_list = NULL, *free_list = NULL;
2408     struct curve_points **last_pointer = &new_list;
2409     size_t tlen;
2410     int i, curve;
2411     char *new_title;
2412
2413     /*
2414      * Ok, go through all the plots and move FUNC types together.  Note: this
2415      * originally was written to look for a NULL next pointer, but gnuplot
2416      * wants to be sticky in grabbing memory and the right number of items in
2417      * the plot list is controlled by the plot_num variable.
2418      *
2419      * Since gnuplot wants to do this sticky business, a free_list of
2420      * curve_points is kept and then tagged onto the end of the plot list as
2421      * this seems more in the spirit of the original memory behavior than
2422      * simply freeing the memory.  I'm personally not convinced this sort of
2423      * concern is worth it since the time spent computing points seems to
2424      * dominate any garbage collecting that might be saved here...
2425      */
2426     new_list = xp = start_plot;
2427     curve = 0;
2428
2429     while (++curve <= *plot_num) {
2430         if (xp->plot_type == FUNC) {
2431             /* Here's a FUNC parametric function defined as two parts. */
2432             struct curve_points *yp = xp->next;
2433
2434             --(*plot_num);
2435
2436             assert(xp->p_count == yp->p_count);
2437
2438             /* because syntax is   plot x(t), y(t) axes ..., only
2439              * the y function axes are correct
2440              */
2441
2442
2443             /*
2444              * Go through all the points assigning the y's from xp to be
2445              * the x's for yp. In polar mode, we need to check max's and
2446              * min's as we go.
2447              */
2448
2449             for (i = 0; i < yp->p_count; ++i) {
2450                 if (polar) {
2451                     double r = yp->points[i].y;
2452                     double t = xp->points[i].y * ang2rad;
2453                     double x, y;
2454                     if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MAX) && r > axis_array[R_AXIS].max)
2455                         yp->points[i].type = OUTRANGE;
2456                     if (!(axis_array[R_AXIS].autoscale & AUTOSCALE_MIN)) {
2457                         /* store internally as if plotting r(t)-rmin */
2458                         r -= axis_array[R_AXIS].min;
2459                     }
2460                     x = r * cos(t);
2461                     y = r * sin(t);
2462                     if (boxwidth >= 0 && boxwidth_is_absolute) {
2463                         int dmy_type = INRANGE;
2464                         STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xlow, x - boxwidth/2, dmy_type, xp->x_axis, NOOP, NOOP );
2465                         dmy_type = INRANGE;
2466                         STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xhigh, x + boxwidth/2, dmy_type, xp->x_axis, NOOP, NOOP );
2467                     }
2468                     /* we hadn't done logs when we stored earlier */
2469                     STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].x, x, yp->points[i].type, xp->x_axis, NOOP, NOOP);
2470                     STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].y, y, yp->points[i].type, xp->y_axis, NOOP, NOOP);
2471                 } else {
2472                     double x = xp->points[i].y;
2473                     double y = yp->points[i].y;
2474
2475                     if (boxwidth >= 0 && boxwidth_is_absolute) {
2476                         int dmy_type = INRANGE;
2477                         STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xlow, x - boxwidth/2, dmy_type, yp->x_axis, NOOP, NOOP );
2478                         dmy_type = INRANGE;
2479                         STORE_WITH_LOG_AND_UPDATE_RANGE( yp->points[i].xhigh, x + boxwidth/2, dmy_type, yp->x_axis, NOOP, NOOP );
2480                     }
2481                     STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].x, x, yp->points[i].type, yp->x_axis, NOOP, NOOP);
2482                     STORE_WITH_LOG_AND_UPDATE_RANGE(yp->points[i].y, y, yp->points[i].type, yp->y_axis, NOOP, NOOP);
2483                 }
2484             }
2485
2486             /* Ok, fix up the title to include both the xp and yp plots. */
2487             if (xp->title && xp->title[0] != '\0' && yp->title) {
2488                 tlen = strlen(yp->title) + strlen(xp->title) + 3;
2489                 new_title = gp_alloc(tlen, "string");
2490                 strcpy(new_title, xp->title);
2491                 strcat(new_title, ", ");
2492                 strcat(new_title, yp->title);
2493                 free(yp->title);
2494                 yp->title = new_title;
2495             }
2496             /* move xp to head of free list */
2497             xp->next = free_list;
2498             free_list = xp;
2499
2500             /* append yp to new_list */
2501             *last_pointer = yp;
2502             last_pointer = &(yp->next);
2503             xp = yp->next;
2504
2505         } else {                /* data plot */
2506             assert(*last_pointer == xp);
2507             last_pointer = &(xp->next);
2508             xp = xp->next;
2509         }
2510     }                           /* loop over plots */
2511
2512     first_plot = new_list;
2513
2514     /* Ok, stick the free list at the end of the curve_points plot list. */
2515     *last_pointer = free_list;
2516 }