2 static char *RCSid() { return RCSid("$Id: set.c,v 1.236.2.20 2009/09/01 16:38:55 sfeam Exp $"); }
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
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.
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,
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
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.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
39 * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
40 * Added user-specified bases for log scaling.
56 /* #include "parse.h" */
68 static palette_color_mode pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_NONE;
70 static void set_angles __PROTO((void));
71 static void set_arrow __PROTO((void));
72 static int assign_arrow_tag __PROTO((void));
73 static void set_autoscale __PROTO((void));
74 static void set_bars __PROTO((void));
75 static void set_border __PROTO((void));
76 static void set_boxwidth __PROTO((void));
77 static void set_clabel __PROTO((void));
78 static void set_clip __PROTO((void));
79 static void set_cntrparam __PROTO((void));
80 static void set_contour __PROTO((void));
81 static void set_dgrid3d __PROTO((void));
82 static void set_decimalsign __PROTO((void));
83 static void set_dummy __PROTO((void));
84 static void set_encoding __PROTO((void));
85 static void set_fit __PROTO((void));
86 static void set_format __PROTO((void));
87 static void set_grid __PROTO((void));
88 static void set_hidden3d __PROTO((void));
89 #ifdef GNUPLOT_HISTORY
90 static void set_historysize __PROTO((void));
92 static void set_isosamples __PROTO((void));
93 static void set_key __PROTO((void));
94 static void set_keytitle __PROTO((void));
95 static void set_label __PROTO((void));
96 static int assign_label_tag __PROTO((void));
97 static void set_loadpath __PROTO((void));
98 static void set_fontpath __PROTO((void));
99 static void set_locale __PROTO((void));
100 static void set_logscale __PROTO((void));
102 static void set_macros __PROTO((void));
104 static void set_mapping __PROTO((void));
105 static void set_margin __PROTO((t_position *));
106 static void set_missing __PROTO((void));
107 static void set_separator __PROTO((void));
108 static void set_datafile_commentschars __PROTO((void));
110 static void set_mouse __PROTO((void));
112 static void set_offsets __PROTO((void));
113 static void set_origin __PROTO((void));
114 static void set_output __PROTO((void));
115 static void set_parametric __PROTO((void));
116 static void set_pm3d __PROTO((void));
117 static void set_palette __PROTO((void));
118 static void set_colorbox __PROTO((void));
119 static void set_pointsize __PROTO((void));
120 static void set_polar __PROTO((void));
121 static void set_print __PROTO((void));
123 static void set_object __PROTO((void));
124 static void set_rectangle __PROTO((int));
126 static void set_samples __PROTO((void));
127 static void set_size __PROTO((void));
128 static void set_style __PROTO((void));
129 static void set_surface __PROTO((void));
130 static void set_table __PROTO((void));
131 static void set_terminal __PROTO((void));
132 static void set_termoptions __PROTO((void));
133 static void set_tics __PROTO((void));
134 static void set_ticscale __PROTO((void));
135 static void set_ticslevel __PROTO((void));
136 static void set_timefmt __PROTO((void));
137 static void set_timestamp __PROTO((void));
138 static void set_view __PROTO((void));
139 static void set_zero __PROTO((void));
140 static void set_timedata __PROTO((AXIS_INDEX));
141 static void set_range __PROTO((AXIS_INDEX));
142 static void set_zeroaxis __PROTO((AXIS_INDEX));
143 static void set_allzeroaxis __PROTO((void));
146 /******** Local functions ********/
148 static void set_xyzlabel __PROTO((text_label * label));
149 static void load_tics __PROTO((AXIS_INDEX axis));
150 static void load_tic_user __PROTO((AXIS_INDEX axis));
151 static void load_tic_series __PROTO((AXIS_INDEX axis));
152 static void load_offsets __PROTO((double *a, double *b, double *c, double *d));
154 static void set_linestyle __PROTO((void));
155 static int assign_linestyle_tag __PROTO((void));
156 static void set_arrowstyle __PROTO((void));
157 static int assign_arrowstyle_tag __PROTO((void));
158 static int looks_like_numeric __PROTO((char *));
159 static int set_tic_prop __PROTO((AXIS_INDEX));
160 static char *fill_numbers_into_string __PROTO((char *pattern));
162 static void check_palette_grayscale __PROTO((void));
163 static int set_palette_defined __PROTO((void));
164 static void set_palette_file __PROTO((void));
165 static void set_palette_function __PROTO((void));
166 #ifdef EAM_HISTOGRAMS
167 static void parse_histogramstyle __PROTO((histogram_style *hs,
168 t_histogram_type def_type, int def_gap));
171 static struct position default_position
172 = {first_axes, first_axes, first_axes, 0., 0., 0.};
174 /* Backwards compatibility ... */
175 static void set_nolinestyle __PROTO((void));
177 /******** The 'set' command ********/
181 static char GPFAR setmess[] =
182 "valid set options: [] = choose one, {} means optional\n\n\
183 \t'angles', 'arrow', 'autoscale', 'bars', 'border', 'boxwidth',\n\
184 \t'clabel', 'clip', 'cntrparam', 'colorbox', 'contour', 'decimalsign',\n\
185 \t'dgrid3d', 'dummy', 'encoding', 'fit', 'format', 'grid',\n\
186 \t'hidden3d', 'historysize', 'isosamples', 'key', 'label', 'locale',\n\
187 \t'logscale', 'macros', '[blrt]margin', 'mapping', 'mouse', 'multiplot',\n\
188 \t'offsets', 'origin', 'output', 'palette', 'parametric', 'pm3d',\n\
189 \t'pointsize', 'polar', 'print', '[rtuv]range', 'samples', 'size',\n\
190 \t'style', 'surface', 'terminal', 'tics', 'ticscale', 'ticslevel',\n\
191 \t'timestamp', 'timefmt', 'title', 'view', 'xyplane', '[xyz]{2}data',\n\
192 \t'[xyz]{2}label', '[xyz]{2}range', '{no}{m}[xyz]{2}tics',\n\
193 \t'[xyz]{2}[md]tics', '{[xyz]{2}}zeroaxis', 'zero'";
197 #ifdef BACKWARDS_COMPATIBLE
199 /* retain backwards compatibility to the old syntax for now
200 * Oh, such ugliness ...
203 if (almost_equals(c_token,"da$ta")) {
205 int_warn(c_token, "deprecated syntax, use \"set style data\"");
206 if (!almost_equals(++c_token,"s$tyle"))
207 int_error(c_token,"expecting keyword 'style'");
209 data_style = get_style();
210 } else if (almost_equals(c_token,"fu$nction")) {
212 int_warn(c_token, "deprecated syntax, use \"set style function\"");
213 if (!almost_equals(++c_token,"s$tyle"))
214 int_error(c_token,"expecting keyword 'style'");
216 enum PLOT_STYLE temp_style = get_style();
218 if (temp_style & PLOT_STYLE_HAS_ERRORBAR)
219 int_error(c_token, "style not usable for function plots, left unchanged");
220 #ifdef EAM_HISTOGRAMS
221 else if (temp_style == HISTOGRAMS)
222 int_error(c_token, "style not usable for function plots, left unchanged");
225 func_style = temp_style;
227 } else if (almost_equals(c_token,"li$nestyle") || equals(c_token, "ls" )) {
229 int_warn(c_token, "deprecated syntax, use \"set style line\"");
232 } else if (almost_equals(c_token,"noli$nestyle") || equals(c_token, "nols" )) {
235 } else if (gp_input_line[token[c_token].start_index] == 'n' &&
236 gp_input_line[token[c_token].start_index+1] == 'o') {
238 int_warn(c_token, "deprecated syntax, use \"unset\"");
239 token[c_token].start_index += 2;
240 token[c_token].length -= 2;
243 } else if (almost_equals(c_token,"miss$ing")) {
245 int_warn(c_token, "deprecated syntax, use \"set datafile missing\"");
249 #endif /* BACKWARDS_COMPATIBLE */
251 switch(lookup_table(&set_tbl[0],c_token)) {
310 #ifdef GNUPLOT_HISTORY
313 int_error(c_token, "Command 'set historysize' requires history support.");
346 set_margin(&bmargin);
349 set_margin(&lmargin);
352 set_margin(&rmargin);
355 set_margin(&tmargin);
358 if (almost_equals(++c_token,"miss$ing"))
360 else if (almost_equals(c_token,"sep$arator"))
362 else if (almost_equals(c_token,"com$mentschars"))
363 set_datafile_commentschars();
364 #ifdef BINARY_DATA_FILE
365 else if (almost_equals(c_token,"bin$ary"))
366 df_set_datafile_binary();
368 else if (almost_equals(c_token,"fort$ran")) {
369 df_fortran_constants = TRUE;
371 } else if (almost_equals(c_token,"nofort$ran")) {
372 df_fortran_constants = FALSE;
375 int_error(c_token,"expecting datafile modifier");
383 term_start_multiplot();
457 set_xyzlabel(&title);
474 set_tic_prop(FIRST_X_AXIS);
484 set_tic_prop(FIRST_Y_AXIS);
494 set_tic_prop(SECOND_X_AXIS);
504 set_tic_prop(SECOND_Y_AXIS);
514 set_tic_prop(FIRST_Z_AXIS);
524 set_tic_prop(COLOR_AXIS);
527 set_timedata(FIRST_X_AXIS);
528 /* HBB 20000506: the old cod this this, too, although it
529 * serves no useful purpose, AFAICS */
530 /* HBB 20010201: Changed implementation to fix bug
531 * (c_token advanced too far) */
532 axis_array[T_AXIS].is_timedata
533 = axis_array[U_AXIS].is_timedata
534 = axis_array[FIRST_X_AXIS].is_timedata;
537 set_timedata(FIRST_Y_AXIS);
539 axis_array[V_AXIS].is_timedata
540 = axis_array[FIRST_X_AXIS].is_timedata;
543 set_timedata(FIRST_Z_AXIS);
546 set_timedata(COLOR_AXIS);
549 set_timedata(SECOND_X_AXIS);
552 set_timedata(SECOND_Y_AXIS);
555 set_xyzlabel(&axis_array[FIRST_X_AXIS].label);
558 set_xyzlabel(&axis_array[FIRST_Y_AXIS].label);
561 set_xyzlabel(&axis_array[FIRST_Z_AXIS].label);
564 set_xyzlabel(&axis_array[COLOR_AXIS].label);
567 set_xyzlabel(&axis_array[SECOND_X_AXIS].label);
570 set_xyzlabel(&axis_array[SECOND_Y_AXIS].label);
573 set_range(FIRST_X_AXIS);
576 set_range(SECOND_X_AXIS);
579 set_range(FIRST_Y_AXIS);
582 set_range(SECOND_Y_AXIS);
585 set_range(FIRST_Z_AXIS);
588 set_range(COLOR_AXIS);
603 set_zeroaxis(FIRST_X_AXIS);
606 set_zeroaxis(FIRST_Y_AXIS);
609 set_zeroaxis(FIRST_Z_AXIS);
612 set_zeroaxis(SECOND_X_AXIS);
615 set_zeroaxis(SECOND_Y_AXIS);
621 int_error(c_token, setmess);
625 #ifdef BACKWARDS_COMPATIBLE
628 update_gpval_variables(0); /* update GPVAL_ inner variables */
633 /* process 'set angles' command */
638 if (END_OF_COMMAND) {
639 /* assuming same as defaults */
641 } else if (almost_equals(c_token, "r$adians")) {
644 } else if (almost_equals(c_token, "d$egrees")) {
648 int_error(c_token, "expecting 'radians' or 'degrees'");
650 if (polar && axis_array[T_AXIS].set_autoscale) {
651 /* set trange if in polar mode and no explicit range */
652 axis_array[T_AXIS].set_min = 0;
653 axis_array[T_AXIS].set_max = 2 * M_PI / ang2rad;
658 /* process a 'set arrow' command */
659 /* set arrow {tag} {from x,y} {to x,y} {{no}head} ... */
660 /* allow any order of options - pm 25.11.2001 */
664 struct arrow_def *this_arrow = NULL;
665 struct arrow_def *new_arrow = NULL;
666 struct arrow_def *prev_arrow = NULL;
667 TBOOLEAN duplication = FALSE;
668 TBOOLEAN set_start = FALSE;
669 TBOOLEAN set_end = FALSE;
677 if (almost_equals(c_token, "back$head") || equals(c_token, "front")
678 || equals(c_token, "from") || equals(c_token, "size")
679 || equals(c_token, "to") || equals(c_token, "rto")
680 || equals(c_token, "filled") || equals(c_token, "empty")
681 || equals(c_token, "as") || equals(c_token, "arrowstyle")
682 || almost_equals(c_token, "head$s") || equals(c_token, "nohead")) {
683 tag = assign_arrow_tag();
686 tag = (int) real(const_express(&a));
689 int_error(c_token, "tag must be > 0");
692 if (first_arrow != NULL) { /* skip to last arrow */
693 for (this_arrow = first_arrow; this_arrow != NULL;
694 prev_arrow = this_arrow, this_arrow = this_arrow->next)
695 /* is this the arrow we want? */
696 if (tag <= this_arrow->tag)
699 if (this_arrow == NULL || tag != this_arrow->tag) {
700 new_arrow = gp_alloc(sizeof(struct arrow_def), "arrow");
701 if (prev_arrow == NULL)
702 first_arrow = new_arrow;
704 prev_arrow->next = new_arrow;
705 new_arrow->tag = tag;
706 new_arrow->next = this_arrow;
707 this_arrow = new_arrow;
709 this_arrow->start = default_position;
710 this_arrow->end = default_position;
712 default_arrow_style(&(new_arrow->arrow_properties));
715 while (!END_OF_COMMAND) {
717 /* get start position */
718 if (equals(c_token, "from")) {
719 if (set_start) { duplication = TRUE; break; }
722 int_error(c_token, "start coordinates expected");
723 /* get coordinates */
724 get_position(&this_arrow->start);
729 /* get end or relative end position */
730 if (equals(c_token, "to") || equals(c_token,"rto")) {
731 if (set_end) { duplication = TRUE; break; }
732 this_arrow->relative = (equals(c_token,"rto")) ? TRUE : FALSE;
735 int_error(c_token, "end coordinates expected");
736 /* get coordinates */
737 get_position(&this_arrow->end);
742 /* Allow interspersed style commands */
743 save_token = c_token;
744 arrow_parse(&this_arrow->arrow_properties, TRUE);
745 if (save_token != c_token)
749 int_error(c_token, "wrong argument in set arrow");
751 } /* while (!END_OF_COMMAND) */
754 int_error(c_token, "duplicate or contradictory arguments");
759 /* assign a new arrow tag
760 * arrows are kept sorted by tag number, so this is easy
761 * returns the lowest unassigned tag number
766 struct arrow_def *this_arrow;
767 int last = 0; /* previous tag value */
769 for (this_arrow = first_arrow; this_arrow != NULL;
770 this_arrow = this_arrow->next)
771 if (this_arrow->tag == last + 1)
780 /* process 'set autoscale' command */
784 char min_string[20], max_string[20];
787 if (END_OF_COMMAND) {
788 INIT_AXIS_ARRAY(set_autoscale , AUTOSCALE_BOTH);
790 } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
791 axis_array[FIRST_X_AXIS].set_autoscale =
792 axis_array[FIRST_Y_AXIS].set_autoscale = AUTOSCALE_BOTH;
795 } else if (equals(c_token, "fix")) {
797 while (a < AXIS_ARRAY_SIZE) {
798 axis_array[a].set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX;
803 } else if (almost_equals(c_token, "ke$epfix")) {
805 while (a < AXIS_ARRAY_SIZE)
806 axis_array[a++].set_autoscale |= AUTOSCALE_BOTH;
811 /* save on replication with a macro */
812 #define PROCESS_AUTO_LETTER(axis) \
814 AXIS *this = axis_array + axis; \
816 if (equals(c_token, axis_defaults[axis].name)) { \
817 this->set_autoscale = AUTOSCALE_BOTH; \
821 sprintf(min_string, "%smi$n", axis_defaults[axis].name); \
822 if (almost_equals(c_token, min_string)) { \
823 this->set_autoscale |= AUTOSCALE_MIN; \
827 sprintf(max_string, "%sma$x", axis_defaults[axis].name); \
828 if (almost_equals(c_token, max_string)) { \
829 this->set_autoscale |= AUTOSCALE_MAX; \
833 sprintf(min_string, "%sfix", axis_defaults[axis].name); \
834 if (equals(c_token, min_string)) { \
835 this->set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX; \
839 sprintf(min_string, "%sfixmi$n", axis_defaults[axis].name); \
840 if (almost_equals(c_token, min_string)) { \
841 this->set_autoscale |= AUTOSCALE_FIXMIN; \
845 sprintf(max_string, "%sfixma$x", axis_defaults[axis].name); \
846 if (almost_equals(c_token, max_string)) { \
847 this->set_autoscale |= AUTOSCALE_FIXMAX; \
853 PROCESS_AUTO_LETTER(R_AXIS);
854 PROCESS_AUTO_LETTER(T_AXIS);
855 PROCESS_AUTO_LETTER(U_AXIS);
856 PROCESS_AUTO_LETTER(V_AXIS);
857 PROCESS_AUTO_LETTER(FIRST_X_AXIS);
858 PROCESS_AUTO_LETTER(FIRST_Y_AXIS);
859 PROCESS_AUTO_LETTER(FIRST_Z_AXIS);
860 PROCESS_AUTO_LETTER(SECOND_X_AXIS);
861 PROCESS_AUTO_LETTER(SECOND_Y_AXIS);
862 PROCESS_AUTO_LETTER(COLOR_AXIS);
863 /* came here only if nothing found: */
864 int_error(c_token, "Invalid range");
868 /* process 'set bars' command */
877 } else if(almost_equals(c_token,"s$mall")) {
880 } else if(almost_equals(c_token,"l$arge")) {
883 } else if(almost_equals(c_token,"full$width")) {
887 bar_size = real(const_express(&a));
892 /* process 'set border' command */
902 border_lp = default_border_lp;
905 while (!END_OF_COMMAND) {
906 if (equals(c_token,"front")) {
909 } else if (equals(c_token,"back")) {
913 int save_token = c_token;
914 lp_parse(&border_lp, TRUE, FALSE);
915 if (save_token != c_token)
917 draw_border = (int)real(const_express(&a));
923 /* process 'set boxwidth' command */
930 if (END_OF_COMMAND) {
932 boxwidth_is_absolute = TRUE;
934 boxwidth = real(const_express(&a));
939 if (almost_equals(c_token, "a$bsolute"))
940 boxwidth_is_absolute = TRUE;
941 else if (almost_equals(c_token, "r$elative"))
942 boxwidth_is_absolute = FALSE;
944 int_error(c_token, "expecting 'absolute' or 'relative' ");
949 /* process 'set clabel' command */
956 label_contours = TRUE;
957 if ((new_format = try_to_get_string())) {
958 strncpy(contour_format, new_format, sizeof(contour_format));
964 /* process 'set clip' command */
970 /* assuming same as points */
972 else if (almost_equals(c_token, "p$oints"))
974 else if (almost_equals(c_token, "o$ne"))
976 else if (almost_equals(c_token, "t$wo"))
979 int_error(c_token, "expecting 'points', 'one', or 'two'");
984 /* process 'set cntrparam' command */
991 if (END_OF_COMMAND) {
992 /* assuming same as defaults */
993 contour_pts = DEFAULT_NUM_APPROX_PTS;
994 contour_kind = CONTOUR_KIND_LINEAR;
995 contour_order = DEFAULT_CONTOUR_ORDER;
996 contour_levels = DEFAULT_CONTOUR_LEVELS;
997 contour_levels_kind = LEVELS_AUTO;
998 } else if (almost_equals(c_token, "p$oints")) {
1000 contour_pts = (int) real(const_express(&a));
1001 } else if (almost_equals(c_token, "li$near")) {
1003 contour_kind = CONTOUR_KIND_LINEAR;
1004 } else if (almost_equals(c_token, "c$ubicspline")) {
1006 contour_kind = CONTOUR_KIND_CUBIC_SPL;
1007 } else if (almost_equals(c_token, "b$spline")) {
1009 contour_kind = CONTOUR_KIND_BSPLINE;
1010 } else if (almost_equals(c_token, "le$vels")) {
1013 free_dynarray(&dyn_contour_levels_list);
1014 init_dynarray(&dyn_contour_levels_list, sizeof(double), 5, 10);
1016 /* RKC: I have modified the next two:
1017 * to use commas to separate list elements as in xtics
1018 * so that incremental lists start,incr[,end]as in "
1020 if (almost_equals(c_token, "di$screte")) {
1021 contour_levels_kind = LEVELS_DISCRETE;
1024 int_error(c_token, "expecting discrete level");
1026 *(double *)nextfrom_dynarray(&dyn_contour_levels_list) =
1027 real(const_express(&a));
1029 while(!END_OF_COMMAND) {
1030 if (!equals(c_token, ","))
1032 "expecting comma to separate discrete levels");
1034 *(double *)nextfrom_dynarray(&dyn_contour_levels_list) =
1035 real(const_express(&a));
1037 contour_levels = dyn_contour_levels_list.end;
1038 } else if (almost_equals(c_token, "in$cremental")) {
1039 int i = 0; /* local counter */
1041 contour_levels_kind = LEVELS_INCREMENTAL;
1043 contour_levels_list[i++] = real(const_express(&a));
1044 if (!equals(c_token, ","))
1046 "expecting comma to separate start,incr levels");
1048 if((contour_levels_list[i++] = real(const_express(&a))) == 0)
1049 int_error(c_token, "increment cannot be 0");
1050 if(!END_OF_COMMAND) {
1051 if (!equals(c_token, ","))
1053 "expecting comma to separate incr,stop levels");
1055 /* need to round up, since 10,10,50 is 5 levels, not four,
1056 * but 10,10,49 is four
1058 dyn_contour_levels_list.end = i;
1059 contour_levels = (int) ( (real(const_express(&a))-contour_levels_list[0])/contour_levels_list[1] + 1.0);
1061 } else if (almost_equals(c_token, "au$to")) {
1062 contour_levels_kind = LEVELS_AUTO;
1065 contour_levels = (int) real(const_express(&a));
1067 if(contour_levels_kind == LEVELS_DISCRETE)
1068 int_error(c_token, "Levels type is discrete, ignoring new number of contour levels");
1069 contour_levels = (int) real(const_express(&a));
1071 } else if (almost_equals(c_token, "o$rder")) {
1074 order = (int) real(const_express(&a));
1075 if ( order < 2 || order > MAX_BSPLINE_ORDER )
1076 int_error(c_token, "bspline order must be in [2..10] range.");
1077 contour_order = order;
1079 int_error(c_token, "expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'");
1083 /* process 'set contour' command */
1089 /* assuming same as points */
1090 draw_contour = CONTOUR_BASE;
1092 if (almost_equals(c_token, "ba$se"))
1093 draw_contour = CONTOUR_BASE;
1094 else if (almost_equals(c_token, "s$urface"))
1095 draw_contour = CONTOUR_SRF;
1096 else if (almost_equals(c_token, "bo$th"))
1097 draw_contour = CONTOUR_BOTH;
1099 int_error(c_token, "expecting 'base', 'surface', or 'both'");
1105 /* process 'set dgrid3d' command */
1112 TBOOLEAN was_comma = TRUE;
1115 local_vals[0] = dgrid3d_row_fineness;
1116 local_vals[1] = dgrid3d_col_fineness;
1117 local_vals[2] = dgrid3d_norm_value;
1119 for (i = 0; i < 3 && !(END_OF_COMMAND);) {
1120 if (equals(c_token,",")) {
1126 int_error(c_token, "',' expected");
1127 local_vals[i] = real(const_express(&a));
1133 if (local_vals[0] < 2 || local_vals[0] > 1000)
1134 int_error(c_token, "Row size must be in [2:1000] range; size unchanged");
1135 if (local_vals[1] < 2 || local_vals[1] > 1000)
1136 int_error(c_token, "Col size must be in [2:1000] range; size unchanged");
1137 if (local_vals[2] < 1 || local_vals[2] > 100)
1138 int_error(c_token, "Norm must be in [1:100] range; norm unchanged");
1140 dgrid3d_row_fineness = local_vals[0];
1141 dgrid3d_col_fineness = local_vals[1];
1142 dgrid3d_norm_value = local_vals[2];
1147 /* process 'set decimalsign' command */
1153 /* Clear current setting */
1157 if (END_OF_COMMAND) {
1158 #ifdef HAVE_LOCALE_H
1159 setlocale(LC_NUMERIC,"C");
1160 } else if (equals(c_token,"locale")) {
1161 char *newlocale = NULL;
1163 newlocale = try_to_get_string();
1165 newlocale = gp_strdup(getenv("LC_ALL"));
1167 newlocale = gp_strdup(getenv("LC_NUMERIC"));
1169 newlocale = gp_strdup(getenv("LANG"));
1170 if (!setlocale(LC_NUMERIC, newlocale ? newlocale : ""))
1171 int_error(c_token-1, "Could not find requested locale");
1172 decimalsign = gp_strdup(localeconv()->decimal_point);
1173 fprintf(stderr,"decimal_sign in locale is %s\n", decimalsign);
1176 } else if (!(decimalsign = try_to_get_string()))
1177 int_error(c_token, "expecting string");
1180 /* process 'set dummy' command */
1186 int_error(c_token, "expecting dummy variable name");
1188 if (!equals(c_token,","))
1189 copy_str(set_dummy_var[0],c_token++, MAX_ID_LEN);
1190 if (!END_OF_COMMAND && equals(c_token,",")) {
1193 int_error(c_token, "expecting second dummy variable name");
1194 copy_str(set_dummy_var[1],c_token++, MAX_ID_LEN);
1200 /* process 'set encoding' command */
1209 temp = S_ENC_DEFAULT;
1211 temp = lookup_table(&set_encoding_tbl[0],c_token);
1213 if (temp == S_ENC_INVALID)
1214 int_error(c_token, "expecting one of 'default', 'iso_8859_1', 'iso_8859_2', 'iso_8859_15', 'cp437', 'cp850', 'cp852', 'koi8r' or 'koi8u'");
1221 /* process 'set fit' command */
1227 while (!END_OF_COMMAND) {
1228 if (almost_equals(c_token, "log$file")) {
1230 if (END_OF_COMMAND) {
1231 if (fitlogfile != NULL)
1234 } else if (!(fitlogfile = try_to_get_string()))
1235 int_error(c_token, "expecting string");
1237 } else if (almost_equals(c_token, "err$orvariables")) {
1238 fit_errorvariables = TRUE;
1240 } else if (almost_equals(c_token, "noerr$orvariables")) {
1241 fit_errorvariables = FALSE;
1243 #endif /* GP_FIT_ERRVARS */
1246 "unknown --- expected 'logfile' or [no]errorvariables");
1248 } /* while (!end) */
1252 /* process 'set format' command */
1256 TBOOLEAN set_for_axis[AXIS_ARRAY_SIZE] = AXIS_ARRAY_INITIALIZER(FALSE);
1260 if ((axis = lookup_table(axisname_tbl, c_token)) >= 0) {
1261 set_for_axis[axis] = TRUE;
1263 } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
1264 set_for_axis[FIRST_X_AXIS]
1265 = set_for_axis[FIRST_Y_AXIS]
1269 /* Assume he wants all */
1270 for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)
1271 set_for_axis[axis] = TRUE;
1274 if (END_OF_COMMAND) {
1275 SET_DEFFORMAT(FIRST_X_AXIS , set_for_axis);
1276 SET_DEFFORMAT(FIRST_Y_AXIS , set_for_axis);
1277 SET_DEFFORMAT(FIRST_Z_AXIS , set_for_axis);
1278 SET_DEFFORMAT(SECOND_X_AXIS, set_for_axis);
1279 SET_DEFFORMAT(SECOND_Y_AXIS, set_for_axis);
1280 SET_DEFFORMAT(COLOR_AXIS , set_for_axis);
1282 char *format = try_to_get_string();
1284 int_error(c_token, "expecting format string");
1287 #define SET_FORMATSTRING(axis) \
1288 if (set_for_axis[axis]) { \
1289 strncpy(axis_array[axis].formatstring, format, MAX_ID_LEN); \
1290 axis_array[axis].format_is_numeric = looks_like_numeric(format);\
1292 SET_FORMATSTRING(FIRST_X_AXIS);
1293 SET_FORMATSTRING(FIRST_Y_AXIS);
1294 SET_FORMATSTRING(FIRST_Z_AXIS);
1295 SET_FORMATSTRING(SECOND_X_AXIS);
1296 SET_FORMATSTRING(SECOND_Y_AXIS);
1297 SET_FORMATSTRING(COLOR_AXIS);
1298 #undef SET_FORMATSTRING
1306 /* process 'set grid' command */
1311 TBOOLEAN explicit_change = FALSE;
1313 #define GRID_MATCH(axis, string) \
1314 if (almost_equals(c_token, string+2)) { \
1315 if (string[2] == 'm') \
1316 axis_array[axis].gridminor = TRUE; \
1318 axis_array[axis].gridmajor = TRUE; \
1319 explicit_change = TRUE; \
1321 } else if (almost_equals(c_token, string)) { \
1322 if (string[2] == 'm') \
1323 axis_array[axis].gridminor = FALSE; \
1325 axis_array[axis].gridmajor = FALSE; \
1326 explicit_change = TRUE; \
1329 while (!END_OF_COMMAND) {
1330 GRID_MATCH(FIRST_X_AXIS, "nox$tics")
1331 else GRID_MATCH(FIRST_Y_AXIS, "noy$tics")
1332 else GRID_MATCH(FIRST_Z_AXIS, "noz$tics")
1333 else GRID_MATCH(SECOND_X_AXIS, "nox2$tics")
1334 else GRID_MATCH(SECOND_Y_AXIS, "noy2$tics")
1335 else GRID_MATCH(FIRST_X_AXIS, "nomx$tics")
1336 else GRID_MATCH(FIRST_Y_AXIS, "nomy$tics")
1337 else GRID_MATCH(FIRST_Z_AXIS, "nomz$tics")
1338 else GRID_MATCH(SECOND_X_AXIS, "nomx2$tics")
1339 else GRID_MATCH(SECOND_Y_AXIS, "nomy2$tics")
1340 else GRID_MATCH(COLOR_AXIS, "nocb$tics")
1341 else GRID_MATCH(COLOR_AXIS, "nomcb$tics")
1342 else if (almost_equals(c_token,"po$lar")) {
1343 if (!some_grid_selected()) {
1344 /* grid_selection = GRID_X; */
1345 axis_array[FIRST_X_AXIS].gridmajor = TRUE;
1348 if (END_OF_COMMAND) {
1349 polar_grid_angle = 30*DEG2RAD;
1351 /* get radial interval */
1353 polar_grid_angle = ang2rad*real(const_express(&a));
1355 } else if (almost_equals(c_token,"nopo$lar")) {
1356 polar_grid_angle = 0; /* not polar grid */
1358 } else if (equals(c_token,"back")) {
1361 } else if (equals(c_token,"front")) {
1364 } else if (almost_equals(c_token,"layerd$efault")) {
1368 break; /* might be a linetype */
1371 if (!END_OF_COMMAND) {
1373 int old_token = c_token;
1375 lp_parse(&grid_lp, TRUE, FALSE);
1376 if (c_token == old_token) { /* nothing parseable found... */
1377 grid_lp.l_type = real(const_express(&a)) - 1;
1380 /* probably just set grid <linetype> */
1382 if (END_OF_COMMAND) {
1383 memcpy(&mgrid_lp,&grid_lp,sizeof(struct lp_style_type));
1385 if (equals(c_token,","))
1387 old_token = c_token;
1388 lp_parse(&mgrid_lp, TRUE, FALSE);
1389 if (c_token == old_token) {
1390 mgrid_lp.l_type = real(const_express(&a)) -1;
1395 if (!explicit_change && !some_grid_selected()) {
1396 /* no axis specified, thus select default grid */
1397 axis_array[FIRST_X_AXIS].gridmajor = TRUE;
1398 axis_array[FIRST_Y_AXIS].gridmajor = TRUE;
1403 /* process 'set hidden3d' command */
1409 printf(" Hidden Line Removal Not Supported in LITE version\n");
1411 /* HBB 970618: new parsing engine for hidden3d options */
1412 set_hidden3doptions();
1418 #ifdef GNUPLOT_HISTORY
1419 /* process 'set historysize' command */
1427 gnuplot_history_size = (int) real(const_express(&a));
1428 if (gnuplot_history_size < 0) {
1429 gnuplot_history_size = 0;
1435 /* process 'set isosamples' command */
1443 tsamp1 = (int)magnitude(const_express(&a));
1445 if (!END_OF_COMMAND) {
1446 if (!equals(c_token,","))
1447 int_error(c_token, "',' expected");
1449 tsamp2 = (int)magnitude(const_express(&a));
1451 if (tsamp1 < 2 || tsamp2 < 2)
1452 int_error(c_token, "sampling rate must be > 1; sampling unchanged");
1454 struct curve_points *f_p = first_plot;
1455 struct surface_points *f_3dp = first_3dplot;
1458 first_3dplot = NULL;
1462 iso_samples_1 = tsamp1;
1463 iso_samples_2 = tsamp2;
1468 /* When plotting an external key, the margin and l/r/t/b/c are
1469 used to determine one of twelve possible positions. They must
1470 be defined appropriately in the case where stack direction
1471 determines exact position. */
1473 set_key_position_from_stack_direction(legend_key *key)
1475 if (key->stack_dir == GPKEY_VERTICAL) {
1478 key->margin = GPKEY_LMARGIN;
1481 if (key->vpos == JUST_TOP)
1482 key->margin = GPKEY_TMARGIN;
1484 key->margin = GPKEY_BMARGIN;
1487 key->margin = GPKEY_RMARGIN;
1493 key->margin = GPKEY_TMARGIN;
1496 if (key->hpos == LEFT)
1497 key->margin = GPKEY_LMARGIN;
1499 key->margin = GPKEY_RMARGIN;
1502 key->margin = GPKEY_BMARGIN;
1509 /* process 'set key' command */
1513 TBOOLEAN vpos_set = FALSE, hpos_set = FALSE, reg_set = FALSE, sdir_set = FALSE;
1514 char *vpos_warn = "Multiple vertical position settings";
1515 char *hpos_warn = "Multiple horizontal position settings";
1516 char *reg_warn = "Multiple location region settings";
1517 char *sdir_warn = "Multiple stack direction settings";
1519 legend_key *key = &keyT;
1522 key->visible = TRUE;
1524 #ifdef BACKWARDS_COMPATIBLE
1525 if (END_OF_COMMAND) {
1527 key->title[0] = '\0';
1529 int_warn(c_token, "deprecated syntax, use \"set key default\"");
1533 while (!END_OF_COMMAND) {
1534 switch(lookup_table(&set_key_tbl[0],c_token)) {
1536 key->visible = TRUE;
1539 key->visible = FALSE;
1543 key->title[0] = '\0';
1547 int_warn(c_token, vpos_warn);
1548 key->vpos = JUST_TOP;
1553 int_warn(c_token, vpos_warn);
1554 key->vpos = JUST_BOT;
1559 int_warn(c_token, hpos_warn);
1565 int_warn(c_token, hpos_warn);
1570 if (!vpos_set) key->vpos = JUST_CENTRE;
1571 if (!hpos_set) key->hpos = CENTRE;
1572 if (vpos_set || hpos_set)
1573 vpos_set = hpos_set = TRUE;
1575 case S_KEY_VERTICAL:
1577 int_warn(c_token, sdir_warn);
1578 key->stack_dir = GPKEY_VERTICAL;
1581 case S_KEY_HORIZONTAL:
1583 int_warn(c_token, sdir_warn);
1584 key->stack_dir = GPKEY_HORIZONTAL;
1589 int_warn(c_token, reg_warn);
1595 key->stack_dir = GPKEY_HORIZONTAL;
1596 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1597 key->margin = GPKEY_TMARGIN;
1602 int_warn(c_token, reg_warn);
1608 key->stack_dir = GPKEY_HORIZONTAL;
1609 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1610 key->margin = GPKEY_BMARGIN;
1615 int_warn(c_token, reg_warn);
1616 key->region = GPKEY_AUTO_INTERIOR_LRTBC;
1620 #ifdef BACKWARDS_COMPATIBLE
1624 key->stack_dir = GPKEY_VERTICAL;
1627 int_warn(c_token, reg_warn);
1628 key->region = GPKEY_AUTO_EXTERIOR_LRTBC;
1633 int_warn(c_token, reg_warn);
1634 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1635 key->margin = GPKEY_TMARGIN;
1640 int_warn(c_token, reg_warn);
1641 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1642 key->margin = GPKEY_BMARGIN;
1647 int_warn(c_token, reg_warn);
1648 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1649 key->margin = GPKEY_LMARGIN;
1654 int_warn(c_token, reg_warn);
1655 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
1656 key->margin = GPKEY_RMARGIN;
1660 key->just = GPKEY_LEFT;
1663 key->just = GPKEY_RIGHT;
1666 key->reverse = TRUE;
1668 case S_KEY_NOREVERSE:
1669 key->reverse = FALSE;
1674 case S_KEY_NOINVERT:
1675 key->invert = FALSE;
1677 case S_KEY_ENHANCED:
1678 key->enhanced = TRUE;
1680 case S_KEY_NOENHANCED:
1681 key->enhanced = FALSE;
1685 key->box.l_type = LT_BLACK;
1686 if (!END_OF_COMMAND) {
1687 int old_token = c_token;
1688 lp_parse(&key->box, TRUE, FALSE);
1689 if (old_token == c_token && isanumber(c_token)) {
1690 key->box.l_type = real(const_express(&a)) - 1;
1694 c_token--; /* is incremented after loop */
1697 key->box.l_type = LT_NODRAW;
1701 key->swidth = real(const_express(&a));
1702 c_token--; /* it is incremented after loop */
1706 key->vert_factor = real(const_express(&a));
1707 if (key->vert_factor < 0.0)
1708 key->vert_factor = 0.0;
1709 c_token--; /* it is incremented after loop */
1713 key->width_fix = real(const_express(&a));
1714 c_token--; /* it is incremented after loop */
1718 key->height_fix = real(const_express(&a));
1719 c_token--; /* it is incremented after loop */
1721 case S_KEY_AUTOTITLES:
1722 if (almost_equals(++c_token, "col$umnheader"))
1723 key->auto_titles = COLUMNHEAD_KEYTITLES;
1725 key->auto_titles = FILENAME_KEYTITLES;
1729 case S_KEY_NOAUTOTITLES:
1730 key->auto_titles = NOAUTO_KEYTITLES;
1736 if ((s = try_to_get_string())) {
1737 strncpy(key->title,s,sizeof(key->title));
1740 key->title[0] = '\0';
1746 #ifdef BACKWARDS_COMPATIBLE
1751 int_warn(c_token, reg_warn);
1752 get_position(&key->user_pos);
1753 key->region = GPKEY_USER_PLACEMENT;
1755 c_token--; /* will be incremented again soon */
1757 #ifndef BACKWARDS_COMPATIBLE
1760 int_error(c_token, "unknown key option");
1767 if (key->region == GPKEY_AUTO_EXTERIOR_LRTBC)
1768 set_key_position_from_stack_direction(key);
1769 else if (key->region == GPKEY_AUTO_EXTERIOR_MARGIN) {
1770 if (vpos_set && (key->margin == GPKEY_TMARGIN || key->margin == GPKEY_BMARGIN))
1772 "ignoring top/center/bottom; incompatible with tmargin/bmargin.");
1773 else if (hpos_set && (key->margin == GPKEY_LMARGIN || key->margin == GPKEY_RMARGIN))
1775 "ignoring left/center/right; incompatible with lmargin/tmargin.");
1780 /* process 'set keytitle' command */
1784 legend_key *key = &keyT;
1787 if (END_OF_COMMAND) { /* set to default */
1788 key->title[0] = NUL;
1791 if ((s = try_to_get_string())) {
1792 strncpy(key->title,s,sizeof(key->title));
1798 /* process 'set label' command */
1799 /* set label {tag} {"label_text"{,<value>{,...}}} {<label options>} */
1800 /* EAM Mar 2003 - option parsing broken out into separate routine */
1804 struct text_label *this_label = NULL;
1805 struct text_label *new_label = NULL;
1806 struct text_label *prev_label = NULL;
1814 /* FIXME - Are these tests really still needed? */
1815 && !isstringvalue(c_token)
1816 && !equals(c_token, "at")
1817 && !equals(c_token, "left")
1818 && !equals(c_token, "center")
1819 && !equals(c_token, "centre")
1820 && !equals(c_token, "right")
1821 && !equals(c_token, "front")
1822 && !equals(c_token, "back")
1823 && !almost_equals(c_token, "rot$ate")
1824 && !almost_equals(c_token, "norot$ate")
1825 && !equals(c_token, "lt")
1826 && !almost_equals(c_token, "linet$ype")
1827 && !equals(c_token, "pt")
1828 && !almost_equals(c_token, "pointt$ype")
1829 && !equals(c_token, "tc")
1830 && !almost_equals(c_token, "text$color")
1831 && !equals(c_token, "font")) {
1833 /* must be an expression, but is it a tag or is it the label itself? */
1834 #ifdef GP_STRING_VARS
1835 int save_token = c_token;
1837 if (a.type == STRING) {
1838 c_token = save_token;
1839 tag = assign_label_tag();
1842 tag = (int) real(&a);
1844 tag = (int) real(const_express(&a));
1848 tag = assign_label_tag(); /* default next tag */
1851 int_error(c_token, "tag must be > zero");
1853 if (first_label != NULL) { /* skip to last label */
1854 for (this_label = first_label; this_label != NULL;
1855 prev_label = this_label, this_label = this_label->next)
1856 /* is this the label we want? */
1857 if (tag <= this_label->tag)
1860 /* Insert this label into the list if it is a new one */
1861 if (this_label == NULL || tag != this_label->tag) {
1862 struct position default_offset = { character, character, character,
1864 new_label = new_text_label(tag);
1865 new_label->offset = default_offset;
1866 if (prev_label == NULL)
1867 first_label = new_label;
1869 prev_label->next = new_label;
1870 new_label->next = this_label;
1871 this_label = new_label;
1874 #ifdef GP_STRING_VARS
1875 if (!END_OF_COMMAND) {
1877 parse_label_options( this_label );
1878 text = try_to_get_string();
1880 free(this_label->text);
1881 this_label->text = text;
1884 /* get text from string */
1885 if (!END_OF_COMMAND && isstring(c_token)) {
1886 char *text = gp_alloc (token_len(c_token), "text_label->text");
1887 quote_str(text, c_token, token_len(c_token));
1889 this_label->text = text;
1891 /* HBB 20001021: new functionality. If next token is a ','
1892 * treat it as a numeric expression whose value is to be
1893 * sprintf()ed into the label string (which contains an
1894 * appropriate %f format string) */
1895 /* EAM Oct 2004 - this is superseded by general string variable
1896 * handling, but left in for backward compatibility */
1897 if (!END_OF_COMMAND && equals(c_token, ","))
1898 this_label->text = fill_numbers_into_string(this_label->text);
1901 /* Now parse the label format and style options */
1902 parse_label_options( this_label );
1906 /* assign a new label tag
1907 * labels are kept sorted by tag number, so this is easy
1908 * returns the lowest unassigned tag number
1913 struct text_label *this_label;
1914 int last = 0; /* previous tag value */
1916 for (this_label = first_label; this_label != NULL;
1917 this_label = this_label->next)
1918 if (this_label->tag == last + 1)
1927 /* process 'set loadpath' command */
1931 /* We pick up all loadpath elements here before passing
1932 * them on to set_var_loadpath()
1934 char *collect = NULL;
1937 if (END_OF_COMMAND) {
1939 } else while (!END_OF_COMMAND) {
1940 if (isstring(c_token)) {
1942 char *ss = gp_alloc(token_len(c_token), "tmp storage");
1943 len = (collect? strlen(collect) : 0);
1944 quote_str(ss,c_token,token_len(c_token));
1945 collect = gp_realloc(collect, len+1+strlen(ss)+1, "tmp loadpath");
1947 strcpy(collect+len+1,ss);
1948 *(collect+len) = PATHSEP;
1955 int_error(c_token, "expected string");
1959 set_var_loadpath(collect);
1965 /* process 'set fontpath' command */
1969 /* We pick up all fontpath elements here before passing
1970 * them on to set_var_fontpath()
1972 char *collect = NULL;
1975 if (END_OF_COMMAND) {
1977 } else while (!END_OF_COMMAND) {
1978 if (isstring(c_token)) {
1980 char *ss = gp_alloc(token_len(c_token), "tmp storage");
1981 len = (collect? strlen(collect) : 0);
1982 quote_str(ss,c_token,token_len(c_token));
1983 collect = gp_realloc(collect, len+1+strlen(ss)+1, "tmp fontpath");
1985 strcpy(collect+len+1,ss);
1986 *(collect+len) = PATHSEP;
1993 int_error(c_token, "expected string");
1997 set_var_fontpath(collect);
2003 /* process 'set locale' command */
2010 if (END_OF_COMMAND) {
2012 } else if ((s = try_to_get_string())) {
2016 int_error(c_token, "expected string");
2020 /* process 'set logscale' command */
2025 if (END_OF_COMMAND) {
2026 INIT_AXIS_ARRAY(log,TRUE);
2027 INIT_AXIS_ARRAY(base, 10.0);
2029 TBOOLEAN set_for_axis[AXIS_ARRAY_SIZE] = AXIS_ARRAY_INITIALIZER(FALSE);
2031 double newbase = 10;
2033 /* do reverse search because of "x", "x1", "x2" sequence in axisname_tbl */
2035 while (i < token[c_token].length) {
2036 axis = lookup_table_nth_reverse(axisname_tbl, AXIS_ARRAY_SIZE,
2037 gp_input_line + token[c_token].start_index + i);
2039 token[c_token].start_index += i;
2040 int_error(c_token, "unknown axis");
2042 set_for_axis[axisname_tbl[axis].value] = TRUE;
2043 i += strlen(axisname_tbl[axis].key);
2047 if (!END_OF_COMMAND) {
2049 newbase = magnitude(const_express(&a));
2052 "log base must be >= 1.1; logscale unchanged");
2055 for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)
2056 if (set_for_axis[axis]) {
2057 axis_array[axis].log = TRUE;
2058 axis_array[axis].base = newbase;
2068 expand_macros = TRUE;
2072 /* process 'set mapping3d' command */
2078 /* assuming same as points */
2079 mapping3d = MAP3D_CARTESIAN;
2080 else if (almost_equals(c_token, "ca$rtesian"))
2081 mapping3d = MAP3D_CARTESIAN;
2082 else if (almost_equals(c_token, "s$pherical"))
2083 mapping3d = MAP3D_SPHERICAL;
2084 else if (almost_equals(c_token, "cy$lindrical"))
2085 mapping3d = MAP3D_CYLINDRICAL;
2088 "expecting 'cartesian', 'spherical', or 'cylindrical'");
2093 /* process 'set {blrt}margin' command */
2095 set_margin(t_position *margin)
2099 margin->scalex = character;
2106 if (equals(c_token,"at") && !almost_equals(++c_token,"sc$reen"))
2107 int_error(c_token,"expecting 'screen <fraction>'");
2108 if (almost_equals(c_token,"sc$reen")) {
2109 margin->scalex = screen;
2113 margin->x = real(const_express(&a));
2122 if (END_OF_COMMAND) {
2123 df_separator = '\0';
2126 if (almost_equals(c_token, "white$space"))
2127 df_separator = '\0';
2128 else if (!isstring(c_token))
2129 int_error(c_token, "expected \"<separator_char>\"");
2130 else if (equals(c_token, "\"\\t\"") || equals(c_token, "\'\\t\'"))
2131 df_separator = '\t';
2132 else if (gp_input_line[token[c_token].start_index]
2133 != gp_input_line[token[c_token].start_index + 2])
2134 int_error(c_token, "extra chars after <separation_char>");
2136 df_separator = gp_input_line[token[c_token].start_index + 1];
2141 set_datafile_commentschars()
2147 if (END_OF_COMMAND) {
2148 free(df_commentschars);
2149 df_commentschars = gp_strdup(DEFAULT_COMMENTS_CHARS);
2150 } else if ((s = try_to_get_string())) {
2151 free(df_commentschars);
2152 df_commentschars = s;
2153 } else /* Leave it the way it was */
2154 int_error(c_token, "expected string with comments chars");
2157 /* process 'set missing' command */
2162 if (END_OF_COMMAND) {
2165 } else if (!(missing_val = try_to_get_string()))
2166 int_error(c_token, "expected missing-value string");
2174 mouse_setting.on = 1;
2176 while (!END_OF_COMMAND) {
2177 if (almost_equals(c_token, "do$ubleclick")) {
2180 mouse_setting.doubleclick = real(const_express(&a));
2181 if (mouse_setting.doubleclick < 0)
2182 mouse_setting.doubleclick = 0;
2183 } else if (almost_equals(c_token, "nodo$ubleclick")) {
2184 mouse_setting.doubleclick = 0; /* double click off */
2186 } else if (almost_equals(c_token, "zoomco$ordinates")) {
2187 mouse_setting.annotate_zoom_box = 1;
2189 } else if (almost_equals(c_token, "nozoomco$ordinates")) {
2190 mouse_setting.annotate_zoom_box = 0;
2192 } else if (almost_equals(c_token, "po$lardistancedeg")) {
2193 mouse_setting.polardistance = 1;
2196 } else if (almost_equals(c_token, "polardistancet$an")) {
2197 mouse_setting.polardistance = 2;
2200 } else if (almost_equals(c_token, "nopo$lardistance")) {
2201 mouse_setting.polardistance = 0;
2204 } else if (equals(c_token, "labels")) {
2205 mouse_setting.label = 1;
2207 /* check if the optional argument "<label options>" is present */
2208 if (isstring(c_token)) {
2209 if (token_len(c_token) >= sizeof(mouse_setting.labelopts)) {
2210 int_error(c_token, "option string too long");
2212 quote_str(mouse_setting.labelopts,
2213 c_token, token_len(c_token));
2217 } else if (almost_equals(c_token, "nola$bels")) {
2218 mouse_setting.label = 0;
2220 } else if (almost_equals(c_token, "ve$rbose")) {
2221 mouse_setting.verbose = 1;
2223 } else if (almost_equals(c_token, "nove$rbose")) {
2224 mouse_setting.verbose = 0;
2226 } else if (almost_equals(c_token, "zoomju$mp")) {
2227 mouse_setting.warp_pointer = 1;
2229 } else if (almost_equals(c_token, "nozoomju$mp")) {
2230 mouse_setting.warp_pointer = 0;
2232 } else if (almost_equals(c_token, "fo$rmat")) {
2234 if (isstring(c_token)) {
2235 if (token_len(c_token) >= sizeof(mouse_setting.fmt)) {
2236 int_error(c_token, "format string too long");
2238 quote_str(mouse_setting.fmt, c_token, token_len(c_token));
2241 int_error(c_token, "expecting string format");
2244 } else if (almost_equals(c_token, "cl$ipboardformat")) {
2246 if (isstring(c_token)) {
2247 if (clipboard_alt_string)
2248 free(clipboard_alt_string);
2249 clipboard_alt_string = gp_alloc
2250 (token_len(c_token), "set->mouse->clipboardformat");
2251 quote_str(clipboard_alt_string, c_token, token_len(c_token));
2252 if (clipboard_alt_string && !strlen(clipboard_alt_string)) {
2253 free(clipboard_alt_string);
2254 clipboard_alt_string = (char*) 0;
2255 if (MOUSE_COORDINATES_ALT == mouse_mode) {
2256 mouse_mode = MOUSE_COORDINATES_REAL;
2259 clipboard_mode = MOUSE_COORDINATES_ALT;
2264 int itmp = (int) real(const_express(&a));
2265 if (itmp >= MOUSE_COORDINATES_REAL
2266 && itmp <= MOUSE_COORDINATES_XDATETIME) {
2267 if (MOUSE_COORDINATES_ALT == itmp
2268 && !clipboard_alt_string) {
2270 "please 'set mouse clipboard <fmt>' first.\n");
2272 clipboard_mode = itmp;
2275 fprintf(stderr, "should be: %d <= clipboardformat <= %d\n",
2276 MOUSE_COORDINATES_REAL, MOUSE_COORDINATES_XDATETIME);
2279 } else if (almost_equals(c_token, "mo$useformat")) {
2281 if (isstring(c_token)) {
2282 if (mouse_alt_string)
2283 free(mouse_alt_string);
2284 mouse_alt_string = gp_alloc
2285 (token_len(c_token), "set->mouse->mouseformat");
2286 quote_str(mouse_alt_string, c_token, token_len(c_token));
2287 if (mouse_alt_string && !strlen(mouse_alt_string)) {
2288 free(mouse_alt_string);
2289 mouse_alt_string = (char*) 0;
2290 if (MOUSE_COORDINATES_ALT == mouse_mode) {
2291 mouse_mode = MOUSE_COORDINATES_REAL;
2294 mouse_mode = MOUSE_COORDINATES_ALT;
2299 int itmp = (int) real(const_express(&a));
2300 if (itmp >= MOUSE_COORDINATES_REAL
2301 && itmp <= MOUSE_COORDINATES_XDATETIME) {
2302 if (MOUSE_COORDINATES_ALT == itmp && !mouse_alt_string) {
2304 "please 'set mouse mouseformat <fmt>' first.\n");
2309 fprintf(stderr, "should be: %d <= mouseformat <= %d\n",
2310 MOUSE_COORDINATES_REAL, MOUSE_COORDINATES_XDATETIME);
2313 } else if (almost_equals(c_token, "noru$ler")) {
2315 set_ruler(FALSE, -1, -1);
2316 } else if (almost_equals(c_token, "ru$ler")) {
2318 if (END_OF_COMMAND || !equals(c_token, "at")) {
2319 set_ruler(TRUE, -1, -1);
2320 } else { /* set mouse ruler at ... */
2321 struct position where;
2325 int_error(c_token, "expecting ruler coordinates");
2326 get_position(&where);
2327 map_position(&where, &x, &y, "ruler at");
2328 set_ruler(TRUE, (int)x, (int)y);
2331 if (!END_OF_COMMAND)
2332 int_error(c_token, "wrong option");
2337 PM_update_menu_items();
2342 /* process 'set offsets' command */
2347 if (END_OF_COMMAND) {
2348 loff = roff = toff = boff = 0.0; /* Reset offsets */
2350 load_offsets (&loff,&roff,&toff,&boff);
2355 /* process 'set origin' command */
2362 if (END_OF_COMMAND) {
2366 xoffset = real(const_express(&a));
2367 if (!equals(c_token,","))
2368 int_error(c_token, "',' expected");
2370 yoffset = real(const_express(&a));
2375 /* process 'set output' command */
2383 int_error(c_token, "you can't change the output in multiplot mode");
2385 if (END_OF_COMMAND) { /* no file specified */
2386 term_set_output(NULL);
2389 outstr = NULL; /* means STDOUT */
2391 } else if ((testfile = try_to_get_string())) {
2392 gp_expand_tilde(&testfile);
2393 term_set_output(testfile);
2394 if (testfile != outstr) {
2399 /* if we get here then it worked, and outstr now = testfile */
2401 int_error(c_token, "expecting filename");
2403 /* Invalidate previous palette */
2404 invalidate_palette();
2409 /* process 'set print' command */
2413 TBOOLEAN append_p = FALSE;
2414 char *testfile = NULL;
2417 if (END_OF_COMMAND) { /* no file specified */
2418 print_set_output(NULL, append_p);
2419 } else if ((testfile = try_to_get_string())) {
2420 gp_expand_tilde(&testfile);
2421 if (!END_OF_COMMAND) {
2422 if (equals(c_token, "append")) {
2426 int_error(c_token, "expecting keyword \'append\'");
2429 print_set_output(testfile, append_p);
2431 int_error(c_token, "expecting filename");
2435 /* process 'set parametric' command */
2443 if (!polar) { /* already done for polar */
2444 strcpy (set_dummy_var[0], "t");
2445 strcpy (set_dummy_var[1], "y");
2447 (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
2453 /* is resetting palette enabled?
2454 * note: reset_palette() is disabled within 'test palette'
2456 int enable_reset_palette = 1;
2458 /* default settings for palette */
2462 if (!enable_reset_palette) return;
2463 sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
2464 sm_palette.formulaR = 7; sm_palette.formulaG = 5;
2465 sm_palette.formulaB = 15;
2466 sm_palette.positive = SMPAL_POSITIVE;
2467 sm_palette.ps_allcF = 0;
2468 sm_palette.use_maxcolors = 0;
2469 sm_palette.gradient_num = 0;
2470 free(sm_palette.gradient);
2471 sm_palette.gradient = NULL;
2472 free(sm_palette.color);
2473 sm_palette.color = NULL;
2474 sm_palette.cmodel = C_MODEL_RGB;
2475 sm_palette.gamma = 1.5;
2476 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_NONE;
2481 /* Process 'set palette defined' gradient specification */
2483 * set palette defined --> use default palette
2484 * set palette defined ( <pos1> <colorspec1>, ... , <posN> <colorspecN> )
2485 * <posX> gray value, automatically rescaled to [0, 1]
2486 * <colorspecX> := { "<color_name>" | "<X-style-color>" | <r> <g> <b> }
2487 * <color_name> predefined colors (see below)
2488 * <X-style-color> "#rrggbb" with 2char hex values for red, green, blue
2489 * <r> <g> <b> three values in [0, 1] for red, green and blue
2490 * return 1 if named colors where used, 0 otherwise
2493 set_palette_defined()
2496 double p=0, r=0, g=0, b=0;
2497 int num, named_colors=0;
2500 /* Invalidate previous gradient */
2501 invalidate_palette();
2503 free( sm_palette.gradient );
2504 sm_palette.gradient = gp_alloc( actual_size*sizeof(gradient_struct), "pm3d gradient" );
2506 if (END_OF_COMMAND) {
2507 /* lets use some default gradient */
2508 double pal[][4] = { {0.0, 0.05, 0.05, 0.2}, {0.1, 0, 0, 1},
2509 {0.25, 0.7, 0.85, 0.9}, {0.4, 0, 0.75, 0},
2510 {0.5, 1, 1, 0}, {0.7, 1, 0, 0},
2511 {0.9, 0.6, 0.6, 0.6}, {1.0, 0.95, 0.95, 0.95} };
2513 for( i=0; i<8; ++i ) {
2514 sm_palette.gradient[i].pos = pal[i][0];
2515 sm_palette.gradient[i].col.r = pal[i][1];
2516 sm_palette.gradient[i].col.g = pal[i][2];
2517 sm_palette.gradient[i].col.b = pal[i][3];
2519 sm_palette.gradient_num = 8;
2520 sm_palette.cmodel = C_MODEL_RGB;
2524 if ( !equals(c_token,"(") )
2525 int_error( c_token, "Expected ( to start gradient definition." );
2530 while (!END_OF_COMMAND) {
2532 p = real(const_express(&a));
2533 col_str = try_to_get_string();
2535 /* either color name or X-style rgb value "#rrggbb" */
2536 if (col_str[0] == '#') {
2537 /* X-style specifier */
2539 if (sscanf( col_str, "#%2x%2x%2x", &rr, &gg, &bb ) != 3 )
2540 int_error( c_token-1,
2541 "Unknown color specifier. Use '#rrggbb'." );
2542 r = (double)(rr)/255.;
2543 g = (double)(gg)/255.;
2544 b = (double)(bb)/255.;
2546 else { /* some predefined names */
2547 /* Maybe we could scan the X11 rgb.txt file to look up color
2548 * names? Or at least move these definitions to some file
2549 * which is included somehow during compilation instead
2550 * hardcoding them. */
2551 /* Can't use lookupt_table() as it works for tokens only,
2552 so we'll do it manually */
2553 const struct gen_table *tbl = pm3d_color_names_tbl;
2555 if (!strcmp(col_str, tbl->key)) {
2556 r = (double)((tbl->value >> 16 ) & 255) / 255.;
2557 g = (double)((tbl->value >> 8 ) & 255) / 255.;
2558 b = (double)(tbl->value & 255) / 255.;
2564 int_error( c_token-1, "Unknown color name." );
2569 /* numerical rgb, hsv, xyz, ... values [0,1] */
2570 r = real(const_express(&a));
2571 if (r<0 || r>1 ) int_error(c_token-1,"Value out of range [0,1].");
2572 g = real(const_express(&a));
2573 if (g<0 || g>1 ) int_error(c_token-1,"Value out of range [0,1].");
2574 b = real(const_express(&a));
2575 if (b<0 || b>1 ) int_error(c_token-1,"Value out of range [0,1].");
2579 if ( num >= actual_size ) {
2580 /* get more space for the gradient */
2582 sm_palette.gradient = gp_realloc( sm_palette.gradient,
2583 actual_size*sizeof(gradient_struct),
2586 sm_palette.gradient[num].pos = p;
2587 sm_palette.gradient[num].col.r = r;
2588 sm_palette.gradient[num].col.g = g;
2589 sm_palette.gradient[num].col.b = b;
2590 if (equals(c_token,")") ) break;
2591 if ( !equals(c_token,",") )
2592 int_error( c_token, "Expected comma." );
2597 sm_palette.gradient_num = num + 1;
2598 check_palette_grayscale();
2600 return named_colors;
2604 /* process 'set palette file' command
2605 * load a palette from file, honor datafile modifiers
2612 int i, j, actual_size;
2618 if (!(file_name = try_to_get_string()))
2619 int_error(c_token, "missing filename");
2621 df_set_plot_mode(MODE_QUERY); /* Needed only for binary datafiles */
2622 specs = df_open(file_name, 4);
2625 if (specs > 0 && specs < 3)
2626 int_error( c_token, "Less than 3 using specs for palette");
2628 if (sm_palette.gradient) {
2629 free( sm_palette.gradient );
2630 sm_palette.gradient = 0;
2633 sm_palette.gradient =
2634 gp_alloc( actual_size*sizeof(gradient_struct), "gradient" );
2638 #define VCONSTRAIN(x) ( (x)<0 ? 0 : ( (x)>1 ? 1: (x) ) )
2639 /* values are simply clipped to [0,1] without notice */
2640 while ((j = df_readline(v, 4)) != DF_EOF) {
2641 if (i >= actual_size) {
2643 sm_palette.gradient = (gradient_struct*)
2644 gp_realloc( sm_palette.gradient,
2645 actual_size*sizeof(gradient_struct),
2650 sm_palette.gradient[i].col.r = VCONSTRAIN(v[0]);
2651 sm_palette.gradient[i].col.g = VCONSTRAIN(v[1]);
2652 sm_palette.gradient[i].col.b = VCONSTRAIN(v[2]);
2653 sm_palette.gradient[i].pos = i ;
2656 sm_palette.gradient[i].col.r = VCONSTRAIN(v[1]);
2657 sm_palette.gradient[i].col.g = VCONSTRAIN(v[2]);
2658 sm_palette.gradient[i].col.b = VCONSTRAIN(v[3]);
2659 sm_palette.gradient[i].pos = v[0];
2663 int_error(c_token, "Bad data on line %d", df_line_number);
2671 int_error( c_token, "No valid palette found" );
2673 sm_palette.gradient_num = i;
2674 check_palette_grayscale();
2679 /* Process a 'set palette function' command.
2680 * Three functions with fixed dummy variable gray are registered which
2681 * map gray to the different color components.
2682 * If ALLOW_DUMMY_VAR_FOR_GRAY is set:
2683 * A different dummy variable may proceed the formulae in quotes.
2684 * This syntax is different from the usual '[u=<start>:<end>]', but
2685 * as <start> and <end> are fixed to 0 and 1 you would have to type
2686 * always '[u=]' which looks strange, especially as just '[u]'
2688 * If unset: dummy variable is fixed to 'gray'.
2691 set_palette_function()
2694 char saved_dummy_var[MAX_ID_LEN+1];
2697 strncpy( saved_dummy_var, c_dummy_var[0], MAX_ID_LEN );
2699 /* set dummy variable */
2700 #ifdef ALLOW_DUMMY_VAR_FOR_GRAY
2701 if (isstring(c_token)) {
2702 quote_str( c_dummy_var[0], c_token, MAX_ID_LEN );
2706 #endif /* ALLOW_DUMMY_VAR_FOR_GRAY */
2707 strncpy( c_dummy_var[0], "gray", MAX_ID_LEN );
2711 start_token = c_token;
2712 if (sm_palette.Afunc.at) {
2713 free_at( sm_palette.Afunc.at );
2714 sm_palette.Afunc.at = NULL;
2716 dummy_func = &sm_palette.Afunc;
2717 sm_palette.Afunc.at = perm_at();
2718 if (! sm_palette.Afunc.at)
2719 int_error(start_token, "not enough memory for function");
2720 m_capture(&(sm_palette.Afunc.definition), start_token, c_token-1);
2722 if (!equals(c_token,","))
2723 int_error(c_token,"Expected comma" );
2727 start_token = c_token;
2728 if (sm_palette.Bfunc.at) {
2729 free_at( sm_palette.Bfunc.at );
2730 sm_palette.Bfunc.at = NULL;
2732 dummy_func = &sm_palette.Bfunc;
2733 sm_palette.Bfunc.at = perm_at();
2734 if (! sm_palette.Bfunc.at)
2735 int_error(start_token, "not enough memory for function");
2736 m_capture(&(sm_palette.Bfunc.definition), start_token, c_token-1);
2738 if (!equals(c_token,","))
2739 int_error(c_token,"Expected comma" );
2743 start_token = c_token;
2744 if (sm_palette.Cfunc.at) {
2745 free_at( sm_palette.Cfunc.at );
2746 sm_palette.Cfunc.at = NULL;
2748 dummy_func = &sm_palette.Cfunc;
2749 sm_palette.Cfunc.at = perm_at();
2750 if (! sm_palette.Cfunc.at)
2751 int_error(start_token, "not enough memory for function");
2752 m_capture(&(sm_palette.Cfunc.definition), start_token, c_token-1);
2755 strncpy( c_dummy_var[0], saved_dummy_var, MAX_ID_LEN );
2760 * Normalize gray scale of gradient to fill [0,1] and
2761 * complain if gray values are not strictly increasing.
2762 * Maybe automatic sorting of the gray values could be a
2766 check_palette_grayscale()
2771 /* check if gray values are sorted */
2772 for (i=0; i<sm_palette.gradient_num-1; ++i ) {
2773 if (sm_palette.gradient[i].pos > sm_palette.gradient[i+1].pos) {
2774 int_error( c_token, "Gray scale not sorted in gradient." );
2778 /* fit gray axis into [0:1]: subtract offset and rescale */
2779 off = sm_palette.gradient[0].pos;
2780 f = 1.0 / ( sm_palette.gradient[sm_palette.gradient_num-1].pos-off );
2781 for (i=1; i<sm_palette.gradient_num-1; ++i ) {
2782 sm_palette.gradient[i].pos = f*(sm_palette.gradient[i].pos-off);
2785 /* paranoia on the first and last entries */
2786 sm_palette.gradient[0].pos = 0.0;
2787 sm_palette.gradient[sm_palette.gradient_num-1].pos = 1.0;
2791 #define SCAN_RGBFORMULA(formula) do { \
2793 i = (int) real(const_express(&a)); \
2794 if (abs(i) >= sm_palette.colorFormulae) \
2795 int_error(c_token, \
2796 "color formula out of range (use `show palette rgbformulae' to display the range)"); \
2800 #define CHECK_TRANSFORM do { \
2801 if (transform_defined) \
2802 int_error(c_token, \
2803 "Use either `rgbformulae`, `defined`, `file` or `formulae`." ); \
2804 transform_defined = 1; \
2807 /* Process 'set palette' command */
2812 int transform_defined, named_color;
2813 transform_defined = named_color = 0;
2816 if (END_OF_COMMAND) /* reset to default settings */
2818 else { /* go through all options of 'set palette' */
2819 for ( ; !END_OF_COMMAND; c_token++ ) {
2820 switch (lookup_table(&set_palette_tbl[0],c_token)) {
2821 /* positive and negative picture */
2822 case S_PALETTE_POSITIVE: /* "pos$itive" */
2823 sm_palette.positive = SMPAL_POSITIVE;
2825 case S_PALETTE_NEGATIVE: /* "neg$ative" */
2826 sm_palette.positive = SMPAL_NEGATIVE;
2828 /* Now the options that determine the palette of smooth colours */
2829 /* gray or rgb-coloured */
2830 case S_PALETTE_GRAY: /* "gray" */
2831 sm_palette.colorMode = SMPAL_COLOR_MODE_GRAY;
2833 case S_PALETTE_GAMMA: /* "gamma" */
2835 sm_palette.gamma = real(const_express(&a));
2838 case S_PALETTE_COLOR: /* "col$or" */
2839 if (pm3d_last_set_palette_mode != SMPAL_COLOR_MODE_NONE) {
2840 sm_palette.colorMode = pm3d_last_set_palette_mode;
2842 sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
2845 /* rgb color mapping formulae: rgb$formulae r,g,b (3 integers) */
2846 case S_PALETTE_RGBFORMULAE: { /* "rgb$formulae" */
2850 SCAN_RGBFORMULA( sm_palette.formulaR );
2851 if (!equals(c_token,",")) { c_token--; continue; }
2852 SCAN_RGBFORMULA( sm_palette.formulaG );
2853 if (!equals(c_token,",")) { c_token--; continue; }
2854 SCAN_RGBFORMULA( sm_palette.formulaB );
2856 sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
2857 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_RGB;
2860 case S_PALETTE_DEFINED: { /* "def$ine" */
2863 named_color = set_palette_defined();
2864 sm_palette.colorMode = SMPAL_COLOR_MODE_GRADIENT;
2865 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_GRADIENT;
2868 case S_PALETTE_FILE: { /* "file" */
2871 sm_palette.colorMode = SMPAL_COLOR_MODE_GRADIENT;
2872 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_GRADIENT;
2876 case S_PALETTE_FUNCTIONS: { /* "func$tions" */
2878 set_palette_function();
2879 sm_palette.colorMode = SMPAL_COLOR_MODE_FUNCTIONS;
2880 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_FUNCTIONS;
2884 case S_PALETTE_MODEL: { /* "mo$del" */
2889 int_error( c_token, "Expected color model." );
2890 model = lookup_table(&color_model_tbl[0],c_token);
2892 int_error(c_token,"Unknown color model.");
2893 sm_palette.cmodel = model;
2896 /* ps_allcF: write all rgb formulae into PS file? */
2897 case S_PALETTE_NOPS_ALLCF: /* "nops_allcF" */
2898 sm_palette.ps_allcF = 0;
2900 case S_PALETTE_PS_ALLCF: /* "ps_allcF" */
2901 sm_palette.ps_allcF = 1;
2903 /* max colors used */
2904 case S_PALETTE_MAXCOLORS: { /* "maxc$olors" */
2909 i = (int)real(const_express(&a));
2910 if (i<0) int_error(c_token,"non-negative number required");
2911 sm_palette.use_maxcolors = i;
2915 } /* switch over palette lookup table */
2916 int_error(c_token,"invalid palette option");
2917 } /* end of while !end of command over palette options */
2918 } /* else(arguments found) */
2920 if (named_color && sm_palette.cmodel != C_MODEL_RGB && interactive)
2922 "Named colors will produce strange results if not in color mode RGB." );
2924 /* Invalidate previous palette */
2925 invalidate_palette();
2928 #undef CHECK_TRANSFORM
2929 #undef SCAN_RGBFORMULA
2931 /* process 'set colorbox' command */
2937 if (END_OF_COMMAND) /* reset to default position */
2938 color_box.where = SMCOLOR_BOX_DEFAULT;
2939 else { /* go through all options of 'set colorbox' */
2940 for ( ; !END_OF_COMMAND; c_token++ ) {
2941 switch (lookup_table(&set_colorbox_tbl[0],c_token)) {
2942 /* vertical or horizontal color gradient */
2943 case S_COLORBOX_VERTICAL: /* "v$ertical" */
2944 color_box.rotation = 'v';
2946 case S_COLORBOX_HORIZONTAL: /* "h$orizontal" */
2947 color_box.rotation = 'h';
2949 /* color box where: default position */
2950 case S_COLORBOX_DEFAULT: /* "def$ault" */
2951 color_box.where = SMCOLOR_BOX_DEFAULT;
2953 /* color box where: position by user */
2954 case S_COLORBOX_USER: /* "u$ser" */
2955 color_box.where = SMCOLOR_BOX_USER;
2957 /* color box layer: front or back */
2958 case S_COLORBOX_FRONT: /* "fr$ont" */
2959 color_box.layer = LAYER_FRONT;
2961 case S_COLORBOX_BACK: /* "ba$ck" */
2962 color_box.layer = LAYER_BACK;
2964 /* border of the color box */
2965 case S_COLORBOX_BORDER: /* "bo$rder" */
2967 color_box.border = 1;
2970 if (!END_OF_COMMAND) {
2971 /* expecting a border line type */
2973 color_box.border_lt_tag = real(const_express(&a));
2974 if (color_box.border_lt_tag <= 0) {
2975 color_box.border_lt_tag = 0;
2976 int_error(c_token, "tag must be strictly positive (see `help set style line')");
2981 case S_COLORBOX_BDEFAULT: /* "bd$efault" */
2982 color_box.border_lt_tag = -1; /* use default border */
2984 case S_COLORBOX_NOBORDER: /* "nobo$rder" */
2985 color_box.border = 0;
2987 /* colorbox origin */
2988 case S_COLORBOX_ORIGIN: /* "o$rigin" */
2990 if (END_OF_COMMAND) {
2991 int_error(c_token, "expecting screen value [0 - 1]");
2993 get_position_default(&color_box.origin, screen);
2998 case S_COLORBOX_SIZE: /* "s$ize" */
3000 if (END_OF_COMMAND) {
3001 int_error(c_token, "expecting screen value [0 - 1]");
3003 get_position_default(&color_box.size, screen);
3007 } /* switch over colorbox lookup table */
3008 int_error(c_token,"invalid colorbox option");
3009 } /* end of while !end of command over colorbox options */
3010 if (color_box.where == SMCOLOR_BOX_NO) /* default: draw at default position */
3011 color_box.where = SMCOLOR_BOX_DEFAULT;
3016 /* process 'set pm3d' command */
3020 int c_token0 = ++c_token;
3022 if (END_OF_COMMAND) { /* assume default settings */
3023 pm3d_reset(); /* sets pm3d.implicit to PM3D_IMPLICIT and pm3d.where to "s" */
3024 pm3d.implicit = PM3D_IMPLICIT; /* for historical reasons */
3026 else { /* go through all options of 'set pm3d' */
3027 for ( ; !END_OF_COMMAND; c_token++ ) {
3028 switch (lookup_table(&set_pm3d_tbl[0],c_token)) {
3030 case S_PM3D_AT: /* "at" */
3032 if (get_pm3d_at_option(&pm3d.where[0]))
3036 if (c_token == c_token0+1)
3037 /* for historical reasons: if "at" is the first option of pm3d,
3038 * like "set pm3d at X other_opts;", then implicit is switched on */
3039 pm3d.implicit = PM3D_IMPLICIT;
3042 case S_PM3D_INTERPOLATE: /* "interpolate" */
3044 if (END_OF_COMMAND) {
3045 int_error(c_token, "expecting step values i,j");
3048 pm3d.interp_i = real(const_express(&a));
3049 if(pm3d.interp_i < 1)
3051 if (!equals(c_token,","))
3052 int_error(c_token, "',' expected");
3054 pm3d.interp_j = real(const_express(&a));
3055 if (pm3d.interp_j < 1)
3060 /* forward and backward drawing direction */
3061 case S_PM3D_SCANSFORWARD: /* "scansfor$ward" */
3062 pm3d.direction = PM3D_SCANS_FORWARD;
3064 case S_PM3D_SCANSBACKWARD: /* "scansback$ward" */
3065 pm3d.direction = PM3D_SCANS_BACKWARD;
3067 case S_PM3D_SCANS_AUTOMATIC: /* "scansauto$matic" */
3068 pm3d.direction = PM3D_SCANS_AUTOMATIC;
3070 case S_PM3D_DEPTH: /* "dep$thorder" */
3071 pm3d.direction = PM3D_DEPTH;
3073 /* flush scans: left, right or center */
3074 case S_PM3D_FLUSH: /* "fl$ush" */
3076 if (almost_equals(c_token, "b$egin"))
3077 pm3d.flush = PM3D_FLUSH_BEGIN;
3078 else if (almost_equals(c_token, "c$enter"))
3079 pm3d.flush = PM3D_FLUSH_CENTER;
3080 else if (almost_equals(c_token, "e$nd"))
3081 pm3d.flush = PM3D_FLUSH_END;
3083 int_error(c_token,"expecting flush 'begin', 'center' or 'end'");
3085 /* clipping method */
3086 case S_PM3D_CLIP_1IN: /* "clip1$in" */
3087 pm3d.clip = PM3D_CLIP_1IN;
3089 case S_PM3D_CLIP_4IN: /* "clip4$in" */
3090 pm3d.clip = PM3D_CLIP_4IN;
3092 /* setup everything for plotting a map */
3093 case S_PM3D_MAP: /* "map" */
3094 pm3d.where[0] = 'b'; pm3d.where[1] = 0; /* set pm3d at b */
3095 data_style = PM3DSURFACE;
3096 func_style = PM3DSURFACE;
3099 /* flushing triangles */
3100 case S_PM3D_FTRIANGLES: /* "ftr$iangles" */
3101 pm3d.ftriangles = 1;
3103 case S_PM3D_NOFTRIANGLES: /* "noftr$iangles" */
3104 pm3d.ftriangles = 0;
3106 /* pm3d-specific hidden line overwrite */
3107 case S_PM3D_HIDDEN: { /* "hi$dden3d" */
3110 pm3d.hidden3d_tag = real(const_express(&a));
3112 if (pm3d.hidden3d_tag <= 0) {
3113 pm3d.hidden3d_tag = 0;
3114 int_error(c_token,"tag must be strictly positive (see `help set style line')");
3118 case S_PM3D_NOHIDDEN: /* "nohi$dden3d" */
3119 pm3d.hidden3d_tag = 0;
3121 case S_PM3D_SOLID: /* "so$lid" */
3122 case S_PM3D_NOTRANSPARENT: /* "notr$ansparent" */
3128 int_warn(c_token, "Deprecated syntax --- ignored");
3131 case S_PM3D_NOSOLID: /* "noso$lid" */
3132 case S_PM3D_TRANSPARENT: /* "tr$ansparent" */
3138 int_warn(c_token, "Deprecated syntax --- ignored");
3140 case S_PM3D_IMPLICIT: /* "i$mplicit" */
3141 case S_PM3D_NOEXPLICIT: /* "noe$xplicit" */
3142 pm3d.implicit = PM3D_IMPLICIT;
3144 case S_PM3D_NOIMPLICIT: /* "noi$mplicit" */
3145 case S_PM3D_EXPLICIT: /* "e$xplicit" */
3146 pm3d.implicit = PM3D_EXPLICIT;
3148 case S_PM3D_WHICH_CORNER: /* "corners2color" */
3150 if (equals(c_token, "mean"))
3151 pm3d.which_corner_color = PM3D_WHICHCORNER_MEAN;
3152 else if (equals(c_token, "geomean"))
3153 pm3d.which_corner_color = PM3D_WHICHCORNER_GEOMEAN;
3154 else if (equals(c_token, "median"))
3155 pm3d.which_corner_color = PM3D_WHICHCORNER_MEDIAN;
3156 else if (equals(c_token, "min"))
3157 pm3d.which_corner_color = PM3D_WHICHCORNER_MIN;
3158 else if (equals(c_token, "max"))
3159 pm3d.which_corner_color = PM3D_WHICHCORNER_MAX;
3160 else if (equals(c_token, "c1"))
3161 pm3d.which_corner_color = PM3D_WHICHCORNER_C1;
3162 else if (equals(c_token, "c2"))
3163 pm3d.which_corner_color = PM3D_WHICHCORNER_C2;
3164 else if (equals(c_token, "c3"))
3165 pm3d.which_corner_color = PM3D_WHICHCORNER_C3;
3166 else if (equals(c_token, "c4"))
3167 pm3d.which_corner_color = PM3D_WHICHCORNER_C4;
3169 int_error(c_token,"expecting 'mean', 'geomean', 'median', 'c1', 'c2', 'c3' or 'c4'");
3171 } /* switch over pm3d lookup table */
3172 int_error(c_token,"invalid pm3d option");
3173 } /* end of while !end of command over pm3d options */
3174 if (PM3D_SCANS_AUTOMATIC == pm3d.direction
3175 && PM3D_FLUSH_BEGIN != pm3d.flush) {
3176 pm3d.direction = PM3D_SCANS_FORWARD;
3178 /* be silent, don't print this warning */
3179 /* Rather FIXME that this combination is supported? Shouldn't be
3180 so big problem, I guess, just it is not implemented. */
3181 fprintf(stderr, "pm3d: `scansautomatic' and `flush %s' are incompatible\n",
3182 PM3D_FLUSH_END == pm3d.flush ? "end": "center");
3183 fputs(" => setting `scansforward'\n", stderr);
3190 /* process 'set pointsize' command */
3200 pointsize = real(const_express(&a));
3201 if(pointsize <= 0) pointsize = 1;
3205 /* process 'set polar' command */
3214 (void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
3215 strcpy (set_dummy_var[0], "t");
3218 if (axis_array[T_AXIS].set_autoscale) {
3219 /* only if user has not set a range manually */
3220 axis_array[T_AXIS].set_min = 0.0;
3221 /* 360 if degrees, 2pi if radians */
3222 axis_array[T_AXIS].set_max = 2 * M_PI / ang2rad;
3229 * Process 'set object <tag> rectangle' command
3230 * set object {tag} rectangle {from <bottom_left> {to|rto} <top_right>}
3231 * {{at|center} <xcen>,<ycen> size <w>,<h>}
3232 * {fc|fillcolor <colorspec>} {lw|linewidth <lw>}
3233 * {fs <fillstyle>} {front|back|behind}
3244 /* The next token must either be a tag or the object type */
3246 if (almost_equals(c_token, "rect$angle"))
3247 tag = -1; /* We'll figure out what it really is later */
3249 tag = (int) real(const_express(&a));
3251 int_error(c_token, "tag must be > zero");
3254 if (almost_equals(c_token, "rect$angle")) {
3257 } else if (tag > 0) {
3258 /* Look for existing object with this tag */
3259 t_object *this_object = first_object;
3260 for (; this_object != NULL; this_object = this_object->next)
3261 if (tag == this_object->tag)
3263 if (this_object && tag == this_object->tag
3264 && this_object->object_type == OBJ_RECTANGLE) {
3268 int_error(c_token, "unknown object");
3271 int_error(c_token, "unrecognized object type");
3276 new_object(int tag, int object_type)
3278 t_object *new = gp_alloc(sizeof(struct object), "object");
3279 if (object_type == OBJ_RECTANGLE) {
3280 t_object def = DEFAULT_RECTANGLE_STYLE;
3283 new->object_type = object_type;
3284 new->lp_properties.l_type = LT_DEFAULT; /* Use default rectangle color */
3285 new->fillstyle.fillstyle = FS_DEFAULT; /* and default fill style */
3287 fprintf(stderr,"object initialization failure\n");
3292 set_rectangle(int tag)
3294 t_rectangle *this_rect = NULL;
3295 t_object *this_object = NULL;
3296 t_object *new_obj = NULL;
3297 t_object *prev_object = NULL;
3299 TBOOLEAN got_fill = FALSE;
3300 TBOOLEAN got_lt = FALSE;
3301 TBOOLEAN got_lw = FALSE;
3302 TBOOLEAN got_corners = FALSE;
3303 TBOOLEAN got_center = FALSE;
3308 /* We are setting the default, not any particular rectangle */
3310 this_object = &default_rectangle;
3311 this_rect = &default_rectangle.o.rectangle;
3315 /* Look for existing rectangle with this tag */
3316 for (this_object = first_object; this_object != NULL;
3317 prev_object = this_object, this_object = this_object->next)
3318 /* is this the rect we want? */
3319 if (0 < tag && tag <= this_object->tag)
3322 /* Insert this rect into the list if it is a new one */
3323 if (this_object == NULL || tag != this_object->tag) {
3325 tag = (prev_object) ? prev_object->tag+1 : 1;
3326 new_obj = new_object(tag, OBJ_RECTANGLE);
3327 if (prev_object == NULL)
3328 first_object = new_obj;
3330 prev_object->next = new_obj;
3331 new_obj->next = this_object;
3332 this_object = new_obj;
3334 this_rect = &this_object->o.rectangle;
3337 while (!END_OF_COMMAND) {
3338 int save_token = c_token;
3340 if (equals(c_token,"from")) {
3341 /* Read in the bottom left and upper right corners */
3343 get_position(&this_rect->bl);
3344 if (equals(c_token,"to")) {
3346 get_position(&this_rect->tr);
3347 } else if (equals(c_token,"rto")) {
3349 get_position_default(&this_rect->tr,this_rect->bl.scalex);
3350 if (this_rect->bl.scalex != this_rect->tr.scalex
3351 || this_rect->bl.scaley != this_rect->tr.scaley)
3352 int_error(c_token,"relative coordinates must match in type");
3353 this_rect->tr.x += this_rect->bl.x;
3354 this_rect->tr.y += this_rect->bl.y;
3356 int_error(c_token,"Expecting to or rto");
3358 this_rect->type = 0;
3361 } else if (equals(c_token,"at") || almost_equals(c_token,"cen$ter")) {
3362 /* Read in the center position */
3364 get_position(&this_rect->center);
3366 this_rect->type = 1;
3368 } else if (equals(c_token,"size")) {
3369 /* Read in the width and height */
3371 get_position(&this_rect->extent);
3373 this_rect->type = 1;
3376 } else if (equals(c_token,"front")) {
3377 this_object->layer = 1;
3380 } else if (equals(c_token,"back")) {
3381 this_object->layer = 0;
3384 } else if (equals(c_token,"behind")) {
3385 this_object->layer = -1;
3388 } else if (almost_equals(c_token,"def$ault")) {
3391 "Invalid command - did you mean 'unset style rectangle'?");
3393 this_object->lp_properties.l_type = LT_DEFAULT;
3394 this_object->fillstyle.fillstyle = FS_DEFAULT;
3396 got_fill = got_lt = TRUE;
3401 /* Now parse the style options; default to whatever the global style is */
3404 parse_fillstyle(&this_object->fillstyle, default_rectangle.fillstyle.fillstyle,
3405 default_rectangle.fillstyle.filldensity, default_rectangle.fillstyle.fillpattern,
3406 default_rectangle.fillstyle.border_linetype);
3408 parse_fillstyle(&this_object->fillstyle, this_object->fillstyle.fillstyle,
3409 this_object->fillstyle.filldensity, this_object->fillstyle.fillpattern,
3410 this_object->fillstyle.border_linetype);
3411 if (c_token != save_token) {
3417 /* Parse the colorspec */
3419 if (equals(c_token,"fc") || almost_equals(c_token,"fillc$olor")) {
3420 this_object->lp_properties.use_palette = TRUE;
3421 this_object->lp_properties.l_type = LT_BLACK; /* Anything but LT_DEFAULT */
3422 parse_colorspec(&this_object->lp_properties.pm3d_color, TC_FRAC);
3423 if (this_object->lp_properties.pm3d_color.type == TC_DEFAULT)
3424 this_object->lp_properties.l_type = LT_DEFAULT;
3427 if (c_token != save_token) {
3435 if (equals(c_token,"lw") || almost_equals(c_token,"linew$idth")) {
3437 lw = real(const_express(&a));
3439 if (c_token != save_token) {
3445 int_error(c_token, "Unrecognized or duplicate option");
3449 this_object->lp_properties.l_width = lw;
3451 if (got_center && got_corners)
3452 int_error(NO_CARET,"Inconsistent options");
3457 /* process 'set samples' command */
3465 tsamp1 = (int)magnitude(const_express(&a));
3467 if (!END_OF_COMMAND) {
3468 if (!equals(c_token,","))
3469 int_error(c_token, "',' expected");
3471 tsamp2 = (int)magnitude(const_express(&a));
3473 if (tsamp1 < 2 || tsamp2 < 2)
3474 int_error(c_token, "sampling rate must be > 1; sampling unchanged");
3476 struct surface_points *f_3dp = first_3dplot;
3478 first_3dplot = NULL;
3487 /* process 'set size' command */
3494 if (END_OF_COMMAND) {
3498 if (almost_equals(c_token, "sq$uare")) {
3501 } else if (almost_equals(c_token,"ra$tio")) {
3503 aspect_ratio = real(const_express(&s));
3504 } else if (almost_equals(c_token, "nora$tio") || almost_equals(c_token, "nosq$uare")) {
3509 if (!END_OF_COMMAND) {
3510 xsize = real(const_express(&s));
3511 if (equals(c_token,",")) {
3513 ysize = real(const_express(&s));
3519 if (xsize <= 0 || ysize <=0) {
3520 xsize = ysize = 1.0;
3521 int_error(NO_CARET,"Illegal value for size");
3526 /* process 'set style' command */
3532 switch(lookup_table(&show_style_tbl[0],c_token)){
3533 case SHOW_STYLE_DATA:
3534 data_style = get_style();
3535 if (data_style == FILLEDCURVES) {
3536 get_filledcurves_style_options(&filledcurves_opts_data);
3537 if (!filledcurves_opts_data.opt_given) /* default value */
3538 filledcurves_opts_data.closeto = FILLEDCURVES_CLOSED;
3541 case SHOW_STYLE_FUNCTION:
3543 enum PLOT_STYLE temp_style = get_style();
3545 if (temp_style & PLOT_STYLE_HAS_ERRORBAR
3546 #ifdef EAM_DATASTRINGS
3547 || (temp_style == LABELPOINTS)
3549 #ifdef EAM_HISTOGRAMS
3550 || (temp_style == HISTOGRAMS)
3553 int_error(c_token, "style not usable for function plots, left unchanged");
3555 func_style = temp_style;
3556 if (func_style == FILLEDCURVES) {
3557 get_filledcurves_style_options(&filledcurves_opts_func);
3558 if (!filledcurves_opts_func.opt_given) /* default value */
3559 filledcurves_opts_func.closeto = FILLEDCURVES_CLOSED;
3563 case SHOW_STYLE_LINE:
3566 case SHOW_STYLE_FILLING:
3567 parse_fillstyle( &default_fillstyle,
3568 default_fillstyle.fillstyle,
3569 default_fillstyle.filldensity,
3570 default_fillstyle.fillpattern,
3571 default_fillstyle.border_linetype);
3573 case SHOW_STYLE_ARROW:
3577 case SHOW_STYLE_RECTANGLE:
3582 #ifdef EAM_HISTOGRAMS
3583 case SHOW_STYLE_HISTOGRAM:
3584 parse_histogramstyle(&histogram_opts,HT_CLUSTERED,histogram_opts.gap);
3587 case SHOW_STYLE_INCREMENT:
3589 if (END_OF_COMMAND || almost_equals(c_token,"def$ault"))
3590 prefer_line_styles = FALSE;
3591 else if (almost_equals(c_token,"u$serstyles"))
3592 prefer_line_styles = TRUE;
3597 "expecting 'data', 'function', 'line', 'fill' or 'arrow'" );
3602 /* process 'set surface' command */
3607 draw_surface = TRUE;
3611 /* process 'set table' command */
3619 if (table_outfile) {
3620 fclose(table_outfile);
3621 table_outfile = NULL;
3624 if ((tablefile = try_to_get_string())) {
3625 /* 'set table "foo"' creates a new output file */
3626 if (!(table_outfile = fopen(tablefile, "w")))
3627 os_error(c_token, "cannot open table output file");
3636 /* process 'set terminal' comamnd */
3643 int_error(c_token, "You can't change the terminal in multiplot mode");
3645 if (END_OF_COMMAND) {
3651 #ifdef BACKWARDS_COMPATIBLE
3652 if (equals(c_token,"table")) {
3655 int_warn(NO_CARET,"The command 'set term table' is deprecated.\n\t Please use 'set table \"outfile\"' instead.\n");
3661 /* `set term push' */
3662 if (equals(c_token,"push")) {
3663 push_terminal(interactive);
3666 } /* set term push */
3668 #ifdef EXTENDED_COLOR_SPECS
3669 /* each terminal is supposed to turn this on, probably
3670 * somewhere when the graphics is initialized */
3671 supply_extended_color_specs = 0;
3674 event_reset((void *)1); /* cancel zoombox etc. */
3678 /* `set term pop' */
3679 if (equals(c_token,"pop")) {
3683 } /* set term pop */
3685 /* `set term <normal terminal>' */
3686 term = 0; /* in case set_term() fails */
3687 term = set_term(c_token);
3689 /* get optional mode parameters
3690 * not all drivers reset the option string before
3691 * strcat-ing to it, so we reset it for them
3696 if (interactive && *term_options)
3697 fprintf(stderr,"Options are '%s'\n",term_options);
3702 * Accept a single terminal option to apply to the current terminal if
3703 * possible. The options are intended to be limited to those which apply
3704 * to a large number of terminals. It would be nice also to limit it to
3705 * options for which we can test in advance to see if the terminal will
3706 * support it; that allows us to silently ignore the command rather than
3707 * issuing an error when the current terminal would not be affected anyhow.
3709 * If necessary, the code in term->options() can detect that it was called
3710 * from here because in this case (c_token == 2), whereas when called from
3711 * 'set term foo ...' it will see (c_token == 3).
3717 int save_end_of_line = num_tokens;
3720 if (END_OF_COMMAND || !term) {
3722 } else if (almost_equals(c_token,"enh$anced")
3723 || almost_equals(c_token,"noenh$anced")) {
3724 num_tokens = GPMIN(num_tokens,c_token+1);
3725 if (term->enhanced_open) {
3730 } else if (almost_equals(c_token,"font")
3731 || almost_equals(c_token,"fname")) {
3732 num_tokens = GPMIN(num_tokens,c_token+2);
3733 if (term->set_font) {
3738 } else if (!strcmp(term->name,"gif") && equals(c_token,"delay") && num_tokens==4) {
3742 int_error(c_token,"This option cannot be changed using 'set termoption'");
3744 num_tokens = save_end_of_line;
3748 /* process 'set tics' command */
3753 TBOOLEAN axisset = FALSE;
3754 TBOOLEAN mirror_opt = FALSE; /* set to true if (no)mirror option specified) */
3758 if (END_OF_COMMAND) {
3759 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3760 axis_array[i].tic_in = TRUE;
3763 while (!END_OF_COMMAND) {
3764 if (almost_equals(c_token, "ax$is")) {
3766 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3767 axis_array[i].ticmode &= ~TICS_ON_BORDER;
3768 axis_array[i].ticmode |= TICS_ON_AXIS;
3771 } else if (almost_equals(c_token, "bo$rder")) {
3772 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3773 axis_array[i].ticmode &= ~TICS_ON_AXIS;
3774 axis_array[i].ticmode |= TICS_ON_BORDER;
3777 } else if (almost_equals(c_token, "mi$rror")) {
3778 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3779 axis_array[i].ticmode |= TICS_MIRROR;
3782 } else if (almost_equals(c_token, "nomi$rror")) {
3783 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3784 axis_array[i].ticmode &= ~TICS_MIRROR;
3787 } else if (almost_equals(c_token,"in$wards")) {
3788 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3789 axis_array[i].tic_in = TRUE;
3791 } else if (almost_equals(c_token,"out$wards")) {
3792 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3793 axis_array[i].tic_in = FALSE;
3795 } else if (almost_equals(c_token, "sc$ale")) {
3798 if (almost_equals(c_token, "def$ault")) {
3799 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3800 axis_array[i].ticscale = 1.0;
3801 axis_array[i].miniticscale = 0.5;
3805 double lticscale, lminiticscale;
3806 lticscale = real(const_express(&a));
3807 if (equals(c_token, ",")) {
3809 lminiticscale = real(const_express(&a));
3811 lminiticscale = 0.5 * lticscale;
3812 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3813 axis_array[i].ticscale = lticscale;
3814 axis_array[i].miniticscale = lminiticscale;
3817 } else if (almost_equals(c_token, "ro$tate")) {
3818 axis_array[i].tic_rotate = TEXT_VERTICAL;
3820 if (equals(c_token, "by")) {
3824 langle = (int)real(const_express(&a));
3825 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3826 axis_array[i].tic_rotate = langle;
3828 } else if (almost_equals(c_token, "noro$tate")) {
3829 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3830 axis_array[i].tic_rotate = 0;
3832 } else if (almost_equals(c_token, "off$set")) {
3833 struct position lpos;
3835 get_position_default(&lpos, character);
3836 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3837 axis_array[i].ticdef.offset = lpos;
3838 } else if (almost_equals(c_token, "nooff$set")) {
3839 struct position tics_nooffset =
3840 { character, character, character, 0., 0., 0.};
3842 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3843 axis_array[i].ticdef.offset = tics_nooffset;
3844 } else if (almost_equals(c_token, "format")) {
3846 } else if (almost_equals(c_token, "f$ont")) {
3848 /* Make sure they've specified a font */
3849 if (!isstringvalue(c_token))
3850 int_error(c_token,"expected font");
3852 char *lfont = try_to_get_string();
3853 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3854 free(axis_array[i].ticdef.font);
3855 axis_array[i].ticdef.font = gp_strdup(lfont);
3859 } else if (equals(c_token,"tc") ||
3860 almost_equals(c_token,"text$color")) {
3861 struct t_colorspec lcolor;
3862 parse_colorspec(&lcolor, TC_FRAC);
3863 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
3864 axis_array[i].ticdef.textcolor = lcolor;
3865 } else if (equals(c_token,"front")) {
3868 } else if (equals(c_token,"back")) {
3871 } else if (!END_OF_COMMAND) {
3872 int_error(c_token, "extraneous arguments in set tics");
3876 /* if tics are off and not set by axis, reset to default (border) */
3877 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3878 if (((axis_array[i].ticmode & TICS_MASK) == NO_TICS) && (!axisset)) {
3879 if ((i == SECOND_X_AXIS) || (i == SECOND_Y_AXIS))
3880 continue; /* don't switch on secondary axes by default */
3881 axis_array[i].ticmode = TICS_ON_BORDER;
3882 if ((mirror_opt == FALSE) && ((i == FIRST_X_AXIS) || (i == FIRST_Y_AXIS) || (i == COLOR_AXIS))) {
3883 axis_array[i].ticmode |= TICS_MIRROR;
3890 /* process 'set ticscale' command */
3895 double lticscale, lminiticscale;
3899 "Deprecated syntax - please use 'set tics scale' keyword");
3902 if (END_OF_COMMAND) {
3904 lminiticscale = 0.5;
3906 lticscale = real(const_express(&tscl));
3907 if (END_OF_COMMAND) {
3908 lminiticscale = lticscale*0.5;
3910 if (equals(c_token, ","))
3912 lminiticscale = real(const_express(&tscl));
3915 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
3916 axis_array[i].ticscale = lticscale;
3917 axis_array[i].miniticscale = lminiticscale;
3922 /* process 'set ticslevel' or 'set xyplane' command */
3923 /* is datatype 'time' relevant here ? */
3929 if (equals(++c_token, "at")) {
3931 xyplane.xyplane_z = real(const_express(&a));
3932 xyplane.absolute = TRUE;
3934 xyplane.ticslevel = real(const_express(&a));
3935 xyplane.absolute = FALSE;
3940 /* Process 'set timefmt' command */
3941 /* HBB 20000507: changed this to a per-axis setting. I.e. you can now
3942 * have separate timefmt parse strings, different axes */
3949 if (END_OF_COMMAND) {
3950 /* set all axes to default */
3951 for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)
3952 strcpy(axis_array[axis].timefmt,TIMEFMT);
3954 if ((axis = lookup_table(axisname_tbl, c_token)) >= 0) {
3956 if (isstring(c_token)) {
3957 quote_str(axis_array[axis].timefmt,c_token, MAX_ID_LEN);
3960 int_error(c_token, "time format string expected");
3962 } else if (isstring(c_token)) {
3963 /* set the given parse string for all current timedata axes: */
3964 for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)
3965 quote_str(axis_array[axis].timefmt, c_token, MAX_ID_LEN);
3968 int_error(c_token, "time format string expected");
3974 /* process 'set timestamp' command */
3978 TBOOLEAN got_format = FALSE;
3983 while (!END_OF_COMMAND) {
3985 if (almost_equals(c_token,"t$op")) {
3986 timelabel_bottom = FALSE;
3989 } else if (almost_equals(c_token, "b$ottom")) {
3990 timelabel_bottom = TRUE;
3995 if (almost_equals(c_token,"r$otate")) {
3996 timelabel_rotate = TRUE;
3999 } else if (almost_equals(c_token, "n$orotate")) {
4000 timelabel_rotate = FALSE;
4005 if (almost_equals(c_token,"off$set")) {
4007 get_position_default(&(timelabel.offset),character);
4011 if (equals(c_token,"font")) {
4013 new = try_to_get_string();
4014 free(timelabel.font);
4015 timelabel.font = new;
4019 if (!got_format && ((new = try_to_get_string()))) {
4020 /* we have a format string */
4021 free(timelabel.text);
4022 timelabel.text = new;
4027 #ifdef BACKWARDS_COMPATIBLE
4028 /* The "font" keyword is new (v4.1), for backward compatibility we don't enforce it */
4029 if (!END_OF_COMMAND && ((new = try_to_get_string()))) {
4030 free(timelabel.font);
4031 timelabel.font = new;
4034 /* The "offset" keyword is new (v4.1); for backward compatibility we don't enforce it */
4035 get_position_default(&(timelabel.offset),character);
4037 int_error(c_token,"unrecognized option");
4042 if (!(timelabel.text))
4043 timelabel.text = gp_strdup(DEFAULT_TIMESTAMP_FORMAT);
4048 /* process 'set view' command */
4053 TBOOLEAN was_comma = TRUE;
4054 static const char errmsg1[] = "rot_%c must be in [0:%d] degrees range; view unchanged";
4055 static const char errmsg2[] = "%sscale must be > 0; view unchanged";
4056 double local_vals[4];
4060 if (equals(c_token,"map")) {
4066 if (splot_map == TRUE) {
4067 splot_map_deactivate();
4068 splot_map = FALSE; /* default is no map */
4071 if (almost_equals(c_token,"equal$_axes")) {
4073 if (END_OF_COMMAND || equals(c_token,"xy")) {
4074 aspect_ratio_3D = 2;
4076 } else if (equals(c_token,"xyz")) {
4077 aspect_ratio_3D = 3;
4081 } else if (almost_equals(c_token,"noequal$_axes")) {
4082 aspect_ratio_3D = 0;
4087 local_vals[0] = surface_rot_x;
4088 local_vals[1] = surface_rot_z;
4089 local_vals[2] = surface_scale;
4090 local_vals[3] = surface_zscale;
4091 for (i = 0; i < 4 && !(END_OF_COMMAND);) {
4092 if (equals(c_token,",")) {
4098 int_error(c_token, "',' expected");
4099 local_vals[i] = real(const_express(&a));
4105 if (local_vals[0] < 0 || local_vals[0] > 180)
4106 int_error(c_token, errmsg1, 'x', 180);
4107 if (local_vals[1] < 0 || local_vals[1] > 360)
4108 int_error(c_token, errmsg1, 'z', 360);
4109 if (local_vals[2] < 1e-6)
4110 int_error(c_token, errmsg2, "");
4111 if (local_vals[3] < 1e-6)
4112 int_error(c_token, errmsg2, "z");
4114 surface_rot_x = local_vals[0];
4115 surface_rot_z = local_vals[1];
4116 surface_scale = local_vals[2];
4117 surface_zscale = local_vals[3];
4122 /* process 'set zero' command */
4128 zero = magnitude(const_express(&a));
4132 /* process 'set {x|y|z|x2|y2}data' command */
4134 set_timedata(AXIS_INDEX axis)
4137 if(END_OF_COMMAND) {
4138 axis_array[axis].is_timedata = FALSE;
4140 if ((axis_array[axis].is_timedata = almost_equals(c_token,"t$ime")))
4147 set_range(AXIS_INDEX axis)
4152 splot_map_deactivate();
4154 if(almost_equals(c_token,"re$store")) { /* ULIG */
4156 axis_array[axis].set_min = get_writeback_min(axis);
4157 axis_array[axis].set_max = get_writeback_max(axis);
4158 axis_array[axis].set_autoscale = AUTOSCALE_NONE;
4160 if (!equals(c_token,"["))
4161 int_error(c_token, "expecting '[' or 'restore'");
4163 axis_array[axis].set_autoscale =
4165 &axis_array[axis].set_min,&axis_array[axis].set_max,
4166 axis_array[axis].set_autoscale);
4167 if (!equals(c_token,"]"))
4168 int_error(c_token, "expecting ']'");
4170 if (almost_equals(c_token, "rev$erse")) {
4172 axis_array[axis].range_flags |= RANGE_REVERSE;
4173 } else if (almost_equals(c_token, "norev$erse")) {
4175 axis_array[axis].range_flags &= ~RANGE_REVERSE;
4177 if (almost_equals(c_token, "wr$iteback")) {
4179 axis_array[axis].range_flags |= RANGE_WRITEBACK;
4180 } else if (almost_equals(c_token, "nowri$teback")) {
4182 axis_array[axis].range_flags &= ~RANGE_WRITEBACK;
4186 splot_map_activate();
4189 /* process 'set {xyz}zeroaxis' command */
4191 set_zeroaxis(AXIS_INDEX axis)
4196 axis_array[axis].zeroaxis.l_type = -1;
4199 int old_token = c_token;
4200 axis_array[axis].zeroaxis.l_type = LT_AXIS;
4201 lp_parse(&axis_array[axis].zeroaxis, TRUE, FALSE);
4202 if (old_token == c_token)
4203 axis_array[axis].zeroaxis.l_type = real(const_express(&a)) - 1;
4208 /* process 'set zeroaxis' command */
4212 set_zeroaxis(FIRST_X_AXIS);
4213 axis_array[FIRST_Y_AXIS].zeroaxis = axis_array[FIRST_X_AXIS].zeroaxis;
4214 #ifndef BACKWARDS_COMPATIBLE
4215 axis_array[FIRST_Z_AXIS].zeroaxis = axis_array[FIRST_X_AXIS].zeroaxis;
4219 /*********** Support functions for set_command ***********/
4222 * The set.c PROCESS_TIC_PROP macro has the following characteristics:
4223 * (a) options must in the correct order
4224 * (b) 'set xtics' (no option) resets only the interval (FREQ)
4225 * {it will also negate NO_TICS, see (d)}
4226 * (c) changing any property also resets the interval to automatic
4227 * (d) set no[xy]tics; set [xy]tics changes border to nomirror, rather
4228 * than to the default, mirror.
4229 * (e) effect of 'set no[]tics; set []tics border ...' is compiler
4230 * dependent; if '!(TICS)' is evaluated first, 'border' is an
4231 * undefined variable :-(
4233 * This function replaces the macro, and introduces a new option
4234 * 'au$tofreq' to give somewhat different behaviour:
4236 * (b) 'set xtics' (no option) only affects NO_TICS; 'autofreq' resets
4237 * the interval calulation to automatic
4238 * (c) the interval mode is not affected by changing some other option
4239 * (d) if NO_TICS, set []tics will restore defaults (borders, mirror
4240 * where appropriate)
4241 * (e) if (NO_TICS), border option is processed.
4243 * A 'default' option could easily be added to reset all options to
4244 * the initial values - mostly book-keeping.
4246 * To retain tic properties after setting no[]tics may also be
4247 * straightforward (save value as negative), but requires changes
4248 * in other code ( e.g. for 'if (xtics)', use 'if (xtics > 0)'
4251 /* generates PROCESS_TIC_PROP strings from tic_side, e.g. "x2"
4252 * STRING, NOSTRING, MONTH, NOMONTH, DAY, NODAY, MINISTRING, NOMINI
4253 * "nox2t$ics" "nox2m$tics" "nox2d$tics" "nomx2t$ics"
4257 set_tic_prop(AXIS_INDEX axis)
4259 int match = 0; /* flag, set by matching a tic command */
4260 char nocmd[12]; /* fill w/ "no"+axis_name+suffix */
4261 char *cmdptr, *sfxptr;
4263 (void) strcpy(nocmd, "no");
4265 (void) strcpy(cmdptr, axis_defaults[axis].name);
4266 sfxptr = &nocmd[strlen(nocmd)];
4267 (void) strcpy(sfxptr, "t$ics"); /* STRING */
4269 if (almost_equals(c_token, cmdptr)) {
4270 TBOOLEAN axisset = FALSE;
4271 TBOOLEAN mirror_opt = FALSE; /* set to true if (no)mirror option specified) */
4272 axis_array[axis].ticdef.def.mix = FALSE;
4276 if (almost_equals(c_token, "ax$is")) {
4278 axis_array[axis].ticmode &= ~TICS_ON_BORDER;
4279 axis_array[axis].ticmode |= TICS_ON_AXIS;
4281 } else if (almost_equals(c_token, "bo$rder")) {
4282 axis_array[axis].ticmode &= ~TICS_ON_AXIS;
4283 axis_array[axis].ticmode |= TICS_ON_BORDER;
4285 } else if (almost_equals(c_token, "mi$rror")) {
4286 axis_array[axis].ticmode |= TICS_MIRROR;
4289 } else if (almost_equals(c_token, "nomi$rror")) {
4290 axis_array[axis].ticmode &= ~TICS_MIRROR;
4293 } else if (almost_equals(c_token, "in$wards")) {
4294 axis_array[axis].tic_in = TRUE;
4296 } else if (almost_equals(c_token, "out$wards")) {
4297 axis_array[axis].tic_in = FALSE;
4299 } else if (almost_equals(c_token, "sc$ale")) {
4302 if (almost_equals(c_token, "def$ault")) {
4303 axis_array[axis].ticscale = 1.0;
4304 axis_array[axis].miniticscale = 0.5;
4307 axis_array[axis].ticscale = real(const_express(&a));
4308 if (equals(c_token, ",")) {
4310 axis_array[axis].miniticscale =
4311 real(const_express(&a));
4313 axis_array[axis].miniticscale =
4314 0.5 * axis_array[axis].ticscale;
4316 } else if (almost_equals(c_token, "ro$tate")) {
4317 axis_array[axis].tic_rotate = TEXT_VERTICAL;
4319 if (equals(c_token, "by")) {
4322 axis_array[axis].tic_rotate =
4323 (int)real(const_express(&a));
4325 } else if (almost_equals(c_token, "noro$tate")) {
4326 axis_array[axis].tic_rotate = 0;
4328 } else if (almost_equals(c_token, "off$set")) {
4330 get_position_default(&axis_array[axis].ticdef.offset,
4332 } else if (almost_equals(c_token, "nooff$set")) {
4333 struct position tics_nooffset =
4334 { character, character, character, 0., 0., 0.};
4336 axis_array[axis].ticdef.offset = tics_nooffset;
4337 } else if (almost_equals(c_token,"range$limited")) {
4338 axis_array[axis].ticdef.rangelimited = TRUE;
4340 } else if (almost_equals(c_token,"norange$limited")) {
4341 axis_array[axis].ticdef.rangelimited = FALSE;
4343 } else if (almost_equals(c_token, "f$ont")) {
4345 /* Make sure they've specified a font */
4346 if (!isstringvalue(c_token))
4347 int_error(c_token,"expected font");
4349 free(axis_array[axis].ticdef.font);
4350 axis_array[axis].ticdef.font = NULL;
4351 axis_array[axis].ticdef.font = try_to_get_string();
4353 } else if (equals(c_token,"format")) {
4356 if (!((format = try_to_get_string())))
4357 int_error(c_token,"expected format");
4358 strncpy(axis_array[axis].formatstring, format,
4359 sizeof(axis_array[axis].formatstring));
4361 axis_array[axis].format_is_numeric =
4362 looks_like_numeric(axis_array[axis].formatstring);
4363 } else if (equals(c_token,"tc") ||
4364 almost_equals(c_token,"text$color")) {
4365 parse_colorspec(&axis_array[axis].ticdef.textcolor, TC_FRAC);
4366 } else if (almost_equals(c_token, "au$tofreq")) {
4367 /* auto tic interval */
4369 if (!axis_array[axis].ticdef.def.mix) {
4370 free_marklist(axis_array[axis].ticdef.def.user);
4371 axis_array[axis].ticdef.def.user = NULL;
4373 axis_array[axis].ticdef.type = TIC_COMPUTED;
4374 } else if (equals(c_token,"add")) {
4376 axis_array[axis].ticdef.def.mix = TRUE;
4377 } else if (!END_OF_COMMAND) {
4380 } while (!END_OF_COMMAND);
4382 /* if tics are off and not set by axis, reset to default (border) */
4383 if (((axis_array[axis].ticmode & TICS_MASK) == NO_TICS) && (!axisset)) {
4384 axis_array[axis].ticmode |= TICS_ON_BORDER;
4385 if ((mirror_opt == FALSE) && ((axis == FIRST_X_AXIS) || (axis == FIRST_Y_AXIS) || (axis == COLOR_AXIS))) {
4386 axis_array[axis].ticmode |= TICS_MIRROR;
4392 if (almost_equals(c_token, nocmd)) { /* NOSTRING */
4393 axis_array[axis].ticmode &= ~TICS_MASK;
4399 (void) strcpy(sfxptr, "m$tics"); /* MONTH */
4400 if (almost_equals(c_token, cmdptr)) {
4401 if (!axis_array[axis].ticdef.def.mix) {
4402 free_marklist(axis_array[axis].ticdef.def.user);
4403 axis_array[axis].ticdef.def.user = NULL;
4405 axis_array[axis].ticdef.type = TIC_MONTH;
4409 if (almost_equals(c_token, nocmd)) { /* NOMONTH */
4410 axis_array[axis].ticdef.type = TIC_COMPUTED;
4414 (void) strcpy(sfxptr, "d$tics"); /* DAYS */
4415 if (almost_equals(c_token, cmdptr)) {
4417 if (!axis_array[axis].ticdef.def.mix) {
4418 free_marklist(axis_array[axis].ticdef.def.user);
4419 axis_array[axis].ticdef.def.user = NULL;
4421 axis_array[axis].ticdef.type = TIC_DAY;
4424 if (almost_equals(c_token, nocmd)) { /* NODAYS */
4425 axis_array[axis].ticdef.type = TIC_COMPUTED;
4430 (void) strcpy(cmdptr + 1, axis_defaults[axis].name);
4431 (void) strcat(cmdptr, "t$ics"); /* MINISTRING */
4433 if (almost_equals(c_token, cmdptr)) {
4437 if (END_OF_COMMAND) {
4438 axis_array[axis].minitics = MINI_AUTO;
4439 } else if (almost_equals(c_token, "def$ault")) {
4440 axis_array[axis].minitics = MINI_DEFAULT;
4443 axis_array[axis].mtic_freq = floor(real(const_express(&freq)));
4444 axis_array[axis].minitics = MINI_USER;
4447 if (almost_equals(c_token, nocmd)) { /* NOMINI */
4448 axis_array[axis].minitics = FALSE;
4455 /* process a 'set {x/y/z}label command */
4456 /* set {x/y/z}label {label_text} {offset {x}{,y}} {<fontspec>} {<textcolor>} */
4458 set_xyzlabel(text_label *label)
4463 if (END_OF_COMMAND) { /* no label specified */
4469 parse_label_options(label);
4471 if (!END_OF_COMMAND) {
4472 text = try_to_get_string();
4477 #ifdef BACKWARDS_COMPATIBLE
4478 if (isanumber(c_token) || equals(c_token, "-")) {
4479 /* Parse offset with missing keyword "set xlabel 'foo' 1,2 "*/
4480 get_position_default(&(label->offset),character);
4485 parse_label_options(label);
4491 /* 'set style line' command */
4492 /* set style line {tag} {linetype n} {linewidth x} {pointtype n} {pointsize x} */
4497 struct linestyle_def *this_linestyle = NULL;
4498 struct linestyle_def *new_linestyle = NULL;
4499 struct linestyle_def *prev_linestyle = NULL;
4500 struct lp_style_type loc_lp = DEFAULT_LP_STYLE_TYPE;
4506 if (!END_OF_COMMAND) {
4507 /* must be a tag expression! */
4508 tag = (int) real(const_express(&a));
4510 int_error(c_token, "tag must be > zero");
4512 tag = assign_linestyle_tag(); /* default next tag */
4514 /* Default style is based on linetype with the same tag id */
4515 loc_lp.l_type = tag - 1;
4516 loc_lp.p_type = tag - 1;
4518 /* Check if linestyle is already defined */
4519 if (first_linestyle != NULL) { /* skip to last linestyle */
4520 for (this_linestyle = first_linestyle; this_linestyle != NULL;
4521 prev_linestyle = this_linestyle,
4522 this_linestyle = this_linestyle->next)
4523 /* is this the linestyle we want? */
4524 if (tag <= this_linestyle->tag)
4528 if (this_linestyle == NULL || tag != this_linestyle->tag) {
4529 new_linestyle = gp_alloc(sizeof(struct linestyle_def), "linestyle");
4530 if (prev_linestyle != NULL)
4531 prev_linestyle->next = new_linestyle; /* add it to end of list */
4533 first_linestyle = new_linestyle; /* make it start of list */
4534 new_linestyle->tag = tag;
4535 new_linestyle->next = this_linestyle;
4536 new_linestyle->lp_properties = loc_lp;
4537 this_linestyle = new_linestyle;
4540 /* Reset to default values */
4542 this_linestyle->lp_properties = loc_lp;
4543 else if (almost_equals(c_token, "def$ault")) {
4544 this_linestyle->lp_properties = loc_lp;
4547 /* pick up a line spec; dont allow ls, do allow point type */
4548 lp_parse(&this_linestyle->lp_properties, FALSE, TRUE);
4550 if (!END_OF_COMMAND)
4551 int_error(c_token,"Extraneous arguments to set style line");
4555 /* assign a new linestyle tag
4556 * linestyles are kept sorted by tag number, so this is easy
4557 * returns the lowest unassigned tag number
4560 assign_linestyle_tag()
4562 struct linestyle_def *this;
4563 int last = 0; /* previous tag value */
4565 for (this = first_linestyle; this != NULL; this = this->next)
4566 if (this->tag == last + 1)
4574 /* delete linestyle from linked list started by first_linestyle.
4575 * called with pointers to the previous linestyle (prev) and the
4576 * linestyle to delete (this).
4577 * If there is no previous linestyle (the linestyle to delete is
4578 * first_linestyle) then call with prev = NULL.
4581 delete_linestyle(struct linestyle_def *prev, struct linestyle_def *this)
4583 if (this != NULL) { /* there really is something to delete */
4584 if (prev != NULL) /* there is a previous linestyle */
4585 prev->next = this->next;
4586 else /* this = first_linestyle so change first_linestyle */
4587 first_linestyle = this->next;
4593 /* ======================================================== */
4594 /* process a 'set arrowstyle' command */
4595 /* set style arrow {tag} {nohead|head|backhead|heads} {size l,a{,b}} {{no}filled} {linestyle...} {layer n}*/
4600 struct arrowstyle_def *this_arrowstyle = NULL;
4601 struct arrowstyle_def *new_arrowstyle = NULL;
4602 struct arrowstyle_def *prev_arrowstyle = NULL;
4603 struct arrow_style_type loc_arrow;
4606 default_arrow_style(&loc_arrow);
4611 if (!END_OF_COMMAND) {
4612 /* must be a tag expression! */
4613 tag = (int) real(const_express(&a));
4615 int_error(c_token, "tag must be > zero");
4617 tag = assign_arrowstyle_tag(); /* default next tag */
4619 /* search for arrowstyle */
4620 if (first_arrowstyle != NULL) { /* skip to last arrowstyle */
4621 for (this_arrowstyle = first_arrowstyle; this_arrowstyle != NULL;
4622 prev_arrowstyle = this_arrowstyle,
4623 this_arrowstyle = this_arrowstyle->next)
4624 /* is this the arrowstyle we want? */
4625 if (tag <= this_arrowstyle->tag)
4629 if (this_arrowstyle == NULL || tag != this_arrowstyle->tag) {
4630 /* adding the arrowstyle */
4631 new_arrowstyle = (struct arrowstyle_def *)
4632 gp_alloc(sizeof(struct arrowstyle_def), "arrowstyle");
4633 default_arrow_style(&(new_arrowstyle->arrow_properties));
4634 if (prev_arrowstyle != NULL)
4635 prev_arrowstyle->next = new_arrowstyle; /* add it to end of list */
4637 first_arrowstyle = new_arrowstyle; /* make it start of list */
4638 new_arrowstyle->tag = tag;
4639 new_arrowstyle->next = this_arrowstyle;
4640 this_arrowstyle = new_arrowstyle;
4644 this_arrowstyle->arrow_properties = loc_arrow;
4645 else if (almost_equals(c_token, "def$ault")) {
4646 this_arrowstyle->arrow_properties = loc_arrow;
4649 /* pick up a arrow spec : dont allow arrowstyle */
4650 arrow_parse(&this_arrowstyle->arrow_properties, FALSE);
4652 if (!END_OF_COMMAND)
4653 int_error(c_token, "extraneous or out-of-order arguments in set arrowstyle");
4657 /* assign a new arrowstyle tag
4658 * arrowstyles are kept sorted by tag number, so this is easy
4659 * returns the lowest unassigned tag number
4662 assign_arrowstyle_tag()
4664 struct arrowstyle_def *this;
4665 int last = 0; /* previous tag value */
4667 for (this = first_arrowstyle; this != NULL; this = this->next)
4668 if (this->tag == last + 1)
4676 /* For set [xy]tics... command */
4678 load_tics(AXIS_INDEX axis)
4680 if (equals(c_token, "(")) { /* set : TIC_USER */
4681 if (equals(++c_token, ")"))
4684 load_tic_user(axis);
4685 } else { /* series : TIC_SERIES */
4686 load_tic_series(axis);
4690 /* load TIC_USER definition */
4692 * where tic is ["string"] value [level]
4693 * Left paren is already scanned off before entry.
4696 load_tic_user(AXIS_INDEX axis)
4701 /* Free any old tic labels */
4702 if (!axis_array[axis].ticdef.def.mix) {
4703 free_marklist(axis_array[axis].ticdef.def.user);
4704 axis_array[axis].ticdef.def.user = NULL;
4707 while (!END_OF_COMMAND) {
4710 /* syntax is ( {'format'} value {level} {, ...} )
4711 * but for timedata, the value itself is a string, which
4712 * complicates things somewhat
4715 /* has a string with it? */
4716 save_token = c_token;
4717 ticlabel = try_to_get_string();
4718 if (ticlabel && axis_array[axis].is_timedata
4719 && (equals(c_token,",") || equals(c_token,")"))) {
4720 c_token = save_token;
4725 /* in any case get the value */
4726 GET_NUM_OR_TIME(ticposition, axis);
4728 if (!END_OF_COMMAND &&
4729 !equals(c_token, ",") &&
4730 !equals(c_token, ")")) {
4732 ticlevel = (int) real(const_express(&value)); /* tic level */
4736 add_tic_user(axis, ticlabel, ticposition, ticlevel);
4739 /* expect "," or ")" here */
4740 if (!END_OF_COMMAND && equals(c_token, ","))
4741 c_token++; /* loop again */
4743 break; /* hopefully ")" */
4746 if (END_OF_COMMAND || !equals(c_token, ")")) {
4747 free_marklist(axis_array[axis].ticdef.def.user);
4748 axis_array[axis].ticdef.def.user = NULL;
4749 int_error(c_token, "expecting right parenthesis )");
4755 free_marklist(struct ticmark *list)
4757 while (list != NULL) {
4758 struct ticmark *freeable = list;
4760 if (freeable->label != NULL)
4761 free(freeable->label);
4766 /* Remove tic labels that were read from a datafile during a previous plot
4767 * via the 'using xtics(n)' mechanism. These have tick level < 0.
4770 prune_dataticks(struct ticmark *list)
4772 struct ticmark a = {0.0,NULL,0,NULL};
4773 struct ticmark *b = &a;
4774 struct ticmark *tmp;
4777 if (list->level < 0) {
4792 /* load TIC_SERIES definition */
4793 /* [start,]incr[,end] */
4795 load_tic_series(AXIS_INDEX axis)
4797 double start, incr, end;
4800 struct ticdef *tdef = &axis_array[axis].ticdef;
4802 GET_NUM_OR_TIME(start, axis);
4804 if (!equals(c_token, ",")) {
4805 /* only step specified */
4811 incr_token = c_token;
4812 GET_NUM_OR_TIME(incr, axis);
4814 if (!equals(c_token, ",")) {
4815 /* only step and increment specified */
4819 GET_NUM_OR_TIME(end, axis);
4822 if (start < end && incr <= 0)
4823 int_error(incr_token, "increment must be positive");
4824 if (start > end && incr >= 0)
4825 int_error(incr_token, "increment must be negative");
4828 double numtics = floor((end * (1 + SIGNIF) - start) / incr);
4831 start = end + numtics * incr;
4836 if (!tdef->def.mix) { /* remove old list */
4837 free_marklist(tdef->def.user);
4838 tdef->def.user = NULL;
4840 tdef->type = TIC_SERIES;
4841 tdef->def.series.start = start;
4842 tdef->def.series.incr = incr;
4843 tdef->def.series.end = end;
4847 load_offsets(double *a, double *b, double *c, double *d)
4851 *a = real(const_express(&t)); /* loff value */
4852 if (!equals(c_token, ","))
4856 *b = real(const_express(&t)); /* roff value */
4857 if (!equals(c_token, ","))
4861 *c = real(const_express(&t)); /* toff value */
4862 if (!equals(c_token, ","))
4866 *d = real(const_express(&t)); /* boff value */
4869 /* return 1 if format looks like a numeric format
4870 * ie more than one %{efg}, or %something-else
4872 /* FIXME HBB 20000430: as coded, this will only check the *first*
4873 * format string, not all of them. */
4875 looks_like_numeric(char *format)
4877 if (!(format = strchr(format, '%')))
4880 while (++format && (*format == ' '
4886 while (isdigit((unsigned char) *format)
4890 return (*format == 'f' || *format == 'g' || *format == 'e');
4895 * Backwards compatibility ...
4897 static void set_nolinestyle()
4900 struct linestyle_def *this, *prev;
4903 if (END_OF_COMMAND) {
4904 /* delete all linestyles */
4905 while (first_linestyle != NULL)
4906 delete_linestyle((struct linestyle_def *) NULL, first_linestyle);
4909 tag = (int) real(const_express(&a));
4910 if (!END_OF_COMMAND)
4911 int_error(c_token, "extraneous arguments to set nolinestyle");
4912 for (this = first_linestyle, prev = NULL;
4914 prev = this, this = this->next) {
4915 if (this->tag == tag) {
4916 delete_linestyle(prev, this);
4917 return; /* exit, our job is done */
4920 int_error(c_token, "linestyle not found");
4925 /* HBB 20001021: new function: make label texts decoratable with numbers */
4927 fill_numbers_into_string(char *pattern)
4929 size_t pattern_length = strlen(pattern) + 1;
4930 size_t newlen = pattern_length;
4931 char *output = gp_alloc(newlen, "fill_numbers output buffer");
4932 size_t output_end = 0;
4934 do { /* loop over string/value pairs */
4938 if (isstring(++c_token)) {
4941 int_error(c_token, "constant expression expected");
4944 /* assume it's a numeric expression, concatenate it to output
4945 * string: parse value, enlarge output buffer, and gprintf()
4947 value = real(const_express(&a));
4948 newlen += pattern_length + 30;
4949 output = gp_realloc(output, newlen, "fill_numbers next number");
4950 gprintf(output + output_end, newlen - output_end,
4951 pattern, 1.0, value);
4952 output_end += strlen(output + output_end);
4954 /* allow a string to follow, after another comma: */
4955 if (END_OF_COMMAND || !equals(c_token, ",")) {
4956 /* no comma followed the number --> we're done. Jump out
4957 * directly, as falling out of the while loop means
4958 * something slightly different. */
4964 if (!END_OF_COMMAND && isstring(c_token)) {
4965 size_t length = token_len(c_token);
4967 if (length >= pattern_length)
4968 pattern = gp_realloc(pattern, pattern_length = length,
4969 "fill_numbers resize pattern");
4970 quote_str(pattern, c_token, length);
4975 int_error(c_token, "string expected");
4976 } /* if (string after comma) */
4977 } while (!END_OF_COMMAND && equals(c_token, ","));
4979 /* came out here --> the last element was a string, not a number.
4980 * that means that there is a string in pattern which was not yet
4981 * copied to 'output' */
4982 output = gp_realloc(output, newlen += pattern_length,
4983 "fill_numbers closing");
4984 strcpy(output + output_end, pattern);
4990 * new_text_label() allocates and initializes a text_label structure.
4991 * This routine is also used by the plot and splot with labels commands.
4994 new_text_label(int tag)
4996 struct text_label *new;
4997 struct position default_offset = { character, character, character,
5000 new = gp_alloc( sizeof(struct text_label), "text_label");
5003 new->place = default_position;
5007 new->text = (char *)NULL;
5008 new->font = (char *)NULL;
5009 new->textcolor.type = TC_DEFAULT;
5010 new->lp_properties.pointflag = 0;
5011 new->lp_properties.p_type = 1;
5012 new->offset = default_offset;
5013 new->noenhanced = FALSE;
5019 * Parse the sub-options for label style and placement.
5020 * This is called from set_label, and from plot2d and plot3d
5021 * to handle options for 'plot with labels'
5024 parse_label_options( struct text_label *this_label )
5027 struct position pos;
5029 enum JUSTIFY just = LEFT;
5031 TBOOLEAN set_position = FALSE, set_just = FALSE,
5032 set_rot = FALSE, set_font = FALSE, set_offset = FALSE,
5033 set_layer = FALSE, set_textcolor = FALSE;
5035 TBOOLEAN axis_label = (this_label->tag == -2);
5036 struct position offset = { character, character, character, 0., 0., 0. };
5037 t_colorspec textcolor = {TC_DEFAULT,0,0.0};
5038 struct lp_style_type loc_lp = DEFAULT_LP_STYLE_TYPE;
5039 loc_lp.pointflag = -2;
5041 /* Now parse the label format and style options */
5042 while (!END_OF_COMMAND) {
5044 if (! set_position && equals(c_token, "at") && !axis_label) {
5047 set_position = TRUE;
5051 /* get justification */
5053 if (almost_equals(c_token, "l$eft")) {
5058 } else if (almost_equals(c_token, "c$entre")
5059 || almost_equals(c_token, "c$enter")) {
5064 } else if (almost_equals(c_token, "r$ight")) {
5072 /* get rotation (added by RCC) */
5074 if (almost_equals(c_token, "rot$ate")) {
5075 rotate = TEXT_VERTICAL;
5078 if (equals(c_token, "by")) {
5080 rotate = (int)real(const_express(&a));
5083 } else if (almost_equals(c_token, "norot$ate")) {
5091 /* get font (added by DJL) */
5092 if (! set_font && equals(c_token, "font")) {
5094 if ((font = try_to_get_string())) {
5098 int_error(c_token, "'fontname,fontsize' expected");
5101 /* get front/back (added by JDP) */
5102 if (! set_layer && !axis_label) {
5103 if (equals(c_token, "back")) {
5108 } else if (equals(c_token, "front")) {
5116 if (loc_lp.pointflag == -2 && !axis_label) {
5117 if (almost_equals(c_token, "po$int")) {
5118 int stored_token = ++c_token;
5119 struct lp_style_type tmp_lp;
5120 loc_lp.pointflag = 1;
5122 lp_parse(&tmp_lp, TRUE, TRUE);
5123 if (stored_token != c_token)
5126 } else if (almost_equals(c_token, "nopo$int")) {
5127 loc_lp.pointflag = 0;
5133 if (! set_offset && almost_equals(c_token, "of$fset")) {
5135 get_position_default(&offset,character);
5140 if ((equals(c_token,"tc") || almost_equals(c_token,"text$color"))
5141 && ! set_textcolor ) {
5142 parse_colorspec( &textcolor, TC_Z );
5143 set_textcolor = TRUE;
5147 /* EAM FIXME: Option to disable enhanced text processing currently not */
5148 /* documented for ordinary labels. */
5149 if (almost_equals(c_token,"noenh$anced")) {
5150 this_label->noenhanced = TRUE;
5153 } else if (almost_equals(c_token,"enh$anced")) {
5154 this_label->noenhanced = FALSE;
5159 /* Coming here means that none of the previous 'if's struck
5160 * its "continue" statement, i.e. whatever is in the command
5161 * line is forbidden by the 'set label' command syntax.
5162 * On the other hand, 'plot with labels' may have additional stuff coming up.
5164 #ifdef GP_STRING_VARS
5167 if (this_label->tag == -1 || this_label->tag == -2)
5170 int_error(c_token, "extraneous or contradicting arguments in label options");
5173 } /* while(!END_OF_COMMAND) */
5175 /* HBB 20011120: this chunk moved here, behind the while()
5176 * loop. Only after all options have been parsed it's safe to
5177 * overwrite the position if none has been specified. */
5179 pos = default_position;
5181 /* OK! copy the requested options into the label */
5183 this_label->place = pos;
5185 this_label->pos = just;
5187 this_label->rotate = rotate;
5189 this_label->layer = layer;
5191 this_label->font = font;
5193 memcpy(&(this_label->textcolor), &textcolor, sizeof(t_colorspec));
5194 if (loc_lp.pointflag >= 0)
5195 memcpy(&(this_label->lp_properties), &loc_lp, sizeof(loc_lp));
5197 this_label->offset = offset;
5199 /* Make sure the z coord and the z-coloring agree */
5200 if (this_label->textcolor.type == TC_Z)
5201 this_label->textcolor.value = this_label->place.z;
5205 #ifdef EAM_HISTOGRAMS
5206 /* <histogramstyle> = {clustered {gap <n>} | rowstacked | columnstacked */
5207 /* errorbars {gap <n>} {linewidth <lw>}} */
5208 /* {title <title_options>} */
5210 parse_histogramstyle( histogram_style *hs,
5211 t_histogram_type def_type,
5215 text_label title_specs = EMPTY_LABELSTRUCT;
5218 hs->type = def_type;
5223 if (!equals(c_token,"hs") && !almost_equals(c_token,"hist$ogram"))
5227 while (!END_OF_COMMAND) {
5228 if (almost_equals(c_token, "clust$ered")) {
5229 hs->type = HT_CLUSTERED;
5231 } else if (almost_equals(c_token, "error$bars")) {
5232 hs->type = HT_ERRORBARS;
5234 } else if (almost_equals(c_token, "rows$tacked")) {
5235 hs->type = HT_STACKED_IN_LAYERS;
5237 } else if (almost_equals(c_token, "columns$tacked")) {
5238 hs->type = HT_STACKED_IN_TOWERS;
5240 } else if (equals(c_token, "gap")) {
5241 if (isanumber(++c_token))
5242 hs->gap = (int)real(const_express(&a));
5244 int_error(c_token,"expected gap value");
5245 } else if (almost_equals(c_token, "ti$tle")) {
5246 title_specs.offset = hs->title.offset;
5247 set_xyzlabel(&title_specs);
5248 memcpy(&hs->title.textcolor,&title_specs.textcolor,sizeof(t_colorspec));
5249 hs->title.offset = title_specs.offset;
5250 /* EAM FIXME - could allocate space and copy parsed font instead */
5251 hs->title.font = axis_array[FIRST_X_AXIS].label.font;
5252 } else if ((equals(c_token,"lw") || almost_equals(c_token,"linew$idth"))
5253 && (hs->type == HT_ERRORBARS)) {
5255 hs->bar_lw = real(const_express(&a));
5259 /* We hit something unexpected */
5263 #endif /* EAM_HISTOGRAMS */