1 /* GNUPLOT - set.c */
2
3 /*[
4 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
5 *
6 * Permission to use, copy, and distribute this software and its
7 * documentation for any purpose with or without fee is hereby granted,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation.
11 *
12 * Permission to modify the software is granted, but not the right to
13 * distribute the complete modified source code. Modifications are to
14 * be distributed as patches to the released version. Permission to
15 * distribute binaries produced by compiling modified sources is granted,
16 * provided you
17 * 1. distribute the corresponding source modifications from the
18 * released version in the form of a patch file along with the binaries,
19 * 2. add special version identification to distinguish your version
20 * in addition to the base release version number,
21 * 3. provide your name and address as the primary contact for the
22 * support of your modified version, and
23 * 4. retain our contact information in regard to use of the base
24 * software.
25 * Permission to distribute the released version of the source code along
26 * with corresponding source modifications in the form of a patch file is
27 * granted with same provisions 2 through 4 for binary distributions.
28 *
29 * This software is provided "as is" without express or implied warranty
30 * to the extent permitted by applicable law.
31 ]*/
32
33
34 /*
35 * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
36 * Added user-specified bases for log scaling.
37 */
38
39 #include "setshow.h"
40
41 #include "alloc.h"
42 #include "axis.h"
43 #include "command.h"
44 #include "contour.h"
45 #include "datafile.h"
46 #include "datablock.h"
47 #include "fit.h"
48 #include "gp_hist.h"
49 #include "gp_time.h"
50 #include "hidden3d.h"
51 #include "jitter.h"
52 #include "misc.h"
53 #include "plot.h"
54 #include "plot2d.h"
55 #include "plot3d.h"
56 #include "tables.h"
57 #include "tabulate.h"
58 #include "term_api.h"
59 #include "util.h"
60 #include "variable.h"
61 #include "pm3d.h"
62 #include "getcolor.h"
63 #include <ctype.h>
64 #ifdef HAVE_ICONV
65 #include <iconv.h>
66 #endif
67 #ifdef HAVE_LANGINFO_H
68 #include <langinfo.h>
69 #endif
70
71 static palette_color_mode pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_NONE;
72
73 static void set_angles __PROTO((void));
74 static void set_arrow __PROTO((void));
75 static int assign_arrow_tag __PROTO((void));
76 static void set_autoscale __PROTO((void));
77 static void set_bars __PROTO((void));
78 static void set_border __PROTO((void));
79 static void set_boxplot __PROTO((void));
80 static void set_boxwidth __PROTO((void));
81 static void set_clabel __PROTO((void));
82 static void set_clip __PROTO((void));
83 static void set_cntrparam __PROTO((void));
84 static void set_cntrlabel __PROTO((void));
85 static void set_contour __PROTO((void));
86 static void set_dashtype __PROTO((void));
87 static void set_dgrid3d __PROTO((void));
88 static void set_decimalsign __PROTO((void));
89 static void set_degreesign __PROTO((char *));
90 static void set_dummy __PROTO((void));
91 static void set_encoding __PROTO((void));
92 static void set_fit __PROTO((void));
93 static void set_grid __PROTO((void));
94 static void set_hidden3d __PROTO((void));
95 static void set_history __PROTO((void));
96 static void set_isosamples __PROTO((void));
97 static void set_key __PROTO((void));
98 static void set_label __PROTO((void));
99 static int assign_label_tag __PROTO((void));
100 static void set_loadpath __PROTO((void));
101 static void set_fontpath __PROTO((void));
102 static void set_locale __PROTO((void));
103 static void set_logscale __PROTO((void));
104 static void set_mapping __PROTO((void));
105 static void set_margin __PROTO((t_position *));
106 static void set_minus_sign __PROTO((void));
107 static void set_micro __PROTO((void));
108 static void set_missing __PROTO((void));
109 static void set_separator __PROTO((char **));
110 static void set_datafile_commentschars __PROTO((void));
111 static void set_monochrome __PROTO((void));
112 static void set_mouse __PROTO((void));
113 static void set_offsets __PROTO((void));
114 static void set_origin __PROTO((void));
115 static void set_output __PROTO((void));
116 static void set_parametric __PROTO((void));
117 static void set_pm3d __PROTO((void));
118 static void set_palette __PROTO((void));
119 static void set_colorbox __PROTO((void));
120 static void set_pointsize __PROTO((void));
121 static void set_pointintervalbox __PROTO((void));
122 static void set_polar __PROTO((void));
123 static void set_print __PROTO((void));
124 #ifdef EAM_OBJECTS
125 static void set_object __PROTO((void));
126 static void set_obj __PROTO((int, int));
127 #endif
128 static void set_psdir __PROTO((void));
129 static void set_rgbmax __PROTO((void));
130 static void set_samples __PROTO((void));
131 static void set_size __PROTO((void));
132 static void set_style __PROTO((void));
133 static void set_surface __PROTO((void));
134 static void set_table __PROTO((void));
135 static void set_terminal __PROTO((void));
136 static void set_termoptions __PROTO((void));
137 static void set_theta __PROTO((void));
138 static void set_tics __PROTO((void));
139 static void set_ticscale __PROTO((void));
140 static void set_timefmt __PROTO((void));
141 static void set_timestamp __PROTO((void));
142 static void set_view __PROTO((void));
143 static void set_zero __PROTO((void));
144 static void set_timedata __PROTO((struct axis *));
145 static void set_range __PROTO((struct axis *));
146 static void set_paxis __PROTO((void));
147 static void set_raxis __PROTO((void));
148 static void set_xyplane __PROTO((void));
149 static void set_ticslevel __PROTO((void));
150 static void set_zeroaxis __PROTO((AXIS_INDEX));
151 static void set_allzeroaxis __PROTO((void));
152
153
154 /******** Local functions ********/
155
156 static void set_xyzlabel __PROTO((text_label * label));
157 static void load_tics __PROTO((struct axis * axis));
158 static void load_tic_user __PROTO((struct axis * axis));
159 static void load_tic_series __PROTO((struct axis * axis));
160
161 static void set_linestyle __PROTO((struct linestyle_def **head, lp_class destination_class));
162 static void set_arrowstyle __PROTO((void));
163 static int assign_arrowstyle_tag __PROTO((void));
164 static int set_tic_prop __PROTO((struct axis *));
165 static void set_mttics __PROTO((struct axis *this_axis));
166
167 static void check_palette_grayscale __PROTO((void));
168 static int set_palette_defined __PROTO((void));
169 static void set_palette_file __PROTO((void));
170 static void set_palette_function __PROTO((void));
171 static void parse_histogramstyle __PROTO((histogram_style *hs,
172 t_histogram_type def_type, int def_gap));
173 static void set_style_parallel __PROTO((void));
174 static void parse_lighting_options __PROTO((void));
175
176 static const char *encoding_micro __PROTO((void));
177 static const char *encoding_minus __PROTO((void));
178
179 static const struct position default_position
180 = {first_axes, first_axes, first_axes, 0., 0., 0.};
181 static const struct position default_offset
182 = {character, character, character, 0., 0., 0.};
183
184 static lp_style_type default_hypertext_point_style
185 = {1, LT_BLACK, 4, DASHTYPE_SOLID, 0, 0, 1.0, PTSZ_DEFAULT, DEFAULT_P_CHAR, {TC_RGB, 0x000000, 0.0}, DEFAULT_DASHPATTERN};
186
187 /******** The 'set' command ********/
188 void
set_command()189 set_command()
190 {
191 c_token++;
192
193 /* Mild form of backwards compatibility */
194 /* Allow "set no{foo}" rather than "unset foo" */
195 if (gp_input_line[token[c_token].start_index] == 'n' &&
196 gp_input_line[token[c_token].start_index+1] == 'o' &&
197 gp_input_line[token[c_token].start_index+2] != 'n') {
198 if (interactive)
199 int_warn(c_token, "deprecated syntax, use \"unset\"");
200 token[c_token].start_index += 2;
201 token[c_token].length -= 2;
202 c_token--;
203 unset_command();
204 } else {
205
206 int save_token = c_token;
207 set_iterator = check_for_iteration();
208 if (empty_iteration(set_iterator)) {
209 /* Skip iteration [i=start:end] where start > end */
210 while (!END_OF_COMMAND) c_token++;
211 set_iterator = cleanup_iteration(set_iterator);
212 return;
213 }
214 if (forever_iteration(set_iterator)) {
215 set_iterator = cleanup_iteration(set_iterator);
216 int_error(save_token, "unbounded iteration");
217 }
218 save_token = c_token;
219 ITERATE:
220
221 switch(lookup_table(&set_tbl[0],c_token)) {
222 case S_ANGLES:
223 set_angles();
224 break;
225 case S_ARROW:
226 set_arrow();
227 break;
228 case S_AUTOSCALE:
229 set_autoscale();
230 break;
231 case S_BARS:
232 set_bars();
233 break;
234 case S_BORDER:
235 set_border();
236 break;
237 case S_BOXWIDTH:
238 set_boxwidth();
239 break;
240 case S_CLABEL:
241 set_clabel();
242 break;
243 case S_CLIP:
244 set_clip();
245 break;
246 case S_COLOR:
247 unset_monochrome();
248 c_token++;
249 break;
250 case S_COLORSEQUENCE:
251 set_colorsequence(0);
252 break;
253 case S_CNTRPARAM:
254 set_cntrparam();
255 break;
256 case S_CNTRLABEL:
257 set_cntrlabel();
258 break;
259 case S_CONTOUR:
260 set_contour();
261 break;
262 case S_DASHTYPE:
263 set_dashtype();
264 break;
265 case S_DGRID3D:
266 set_dgrid3d();
267 break;
268 case S_DECIMALSIGN:
269 set_decimalsign();
270 break;
271 case S_DUMMY:
272 set_dummy();
273 break;
274 case S_ENCODING:
275 set_encoding();
276 break;
277 case S_FIT:
278 set_fit();
279 break;
280 case S_FONTPATH:
281 set_fontpath();
282 break;
283 case S_FORMAT:
284 set_format();
285 break;
286 case S_GRID:
287 set_grid();
288 break;
289 case S_HIDDEN3D:
290 set_hidden3d();
291 break;
292 case S_HISTORYSIZE: /* Deprecated in favor of "set history size" */
293 case S_HISTORY:
294 set_history();
295 break;
296 case S_ISOSAMPLES:
297 set_isosamples();
298 break;
299 case S_JITTER:
300 set_jitter();
301 break;
302 case S_KEY:
303 set_key();
304 break;
305 case S_LINESTYLE:
306 set_linestyle(&first_linestyle, LP_STYLE);
307 break;
308 case S_LINETYPE:
309 if (equals(c_token+1,"cycle")) {
310 c_token += 2;
311 linetype_recycle_count = int_expression();
312 } else
313 set_linestyle(&first_perm_linestyle, LP_TYPE);
314 break;
315 case S_LABEL:
316 set_label();
317 break;
318 case S_LINK:
319 case S_NONLINEAR:
320 link_command();
321 break;
322 case S_LOADPATH:
323 set_loadpath();
324 break;
325 case S_LOCALE:
326 set_locale();
327 break;
328 case S_LOGSCALE:
329 set_logscale();
330 break;
331 case S_MACROS:
332 /* Aug 2013 - macros are always enabled */
333 c_token++;
334 break;
335 case S_MAPPING:
336 set_mapping();
337 break;
338 case S_MARGIN:
339 /* Jan 2015: CHANGE to order <left>,<right>,<bottom>,<top> */
340 set_margin(&lmargin);
341 if (!equals(c_token,","))
342 break;
343 set_margin(&rmargin);
344 if (!equals(c_token,","))
345 break;
346 set_margin(&bmargin);
347 if (!equals(c_token,","))
348 break;
349 set_margin(&tmargin);
350 break;
351 case S_BMARGIN:
352 set_margin(&bmargin);
353 break;
354 case S_LMARGIN:
355 set_margin(&lmargin);
356 break;
357 case S_RMARGIN:
358 set_margin(&rmargin);
359 break;
360 case S_TMARGIN:
361 set_margin(&tmargin);
362 break;
363 case S_MICRO:
364 set_micro();
365 break;
366 case S_MINUS_SIGN:
367 set_minus_sign();
368 break;
369 case S_DATAFILE:
370 if (almost_equals(++c_token,"miss$ing"))
371 set_missing();
372 else if (almost_equals(c_token,"sep$arators"))
373 set_separator(&df_separators);
374 else if (almost_equals(c_token,"com$mentschars"))
375 set_datafile_commentschars();
376 else if (almost_equals(c_token,"bin$ary"))
377 df_set_datafile_binary();
378 else if (almost_equals(c_token,"fort$ran")) {
379 df_fortran_constants = TRUE;
380 c_token++;
381 } else if (almost_equals(c_token,"nofort$ran")) {
382 df_fortran_constants = FALSE;
383 c_token++;
384 } else if (almost_equals(c_token,"fpe_trap")) {
385 df_nofpe_trap = FALSE;
386 c_token++;
387 } else if (almost_equals(c_token,"nofpe_trap")) {
388 df_nofpe_trap = TRUE;
389 c_token++;
390 } else
391 int_error(c_token,"expecting datafile modifier");
392 break;
393 case S_MOUSE:
394 set_mouse();
395 break;
396 case S_MONOCHROME:
397 set_monochrome();
398 break;
399 case S_MULTIPLOT:
400 term_start_multiplot();
401 break;
402 case S_OFFSETS:
403 set_offsets();
404 break;
405 case S_ORIGIN:
406 set_origin();
407 break;
408 case SET_OUTPUT:
409 set_output();
410 break;
411 case S_PARAMETRIC:
412 set_parametric();
413 break;
414 case S_PM3D:
415 set_pm3d();
416 break;
417 case S_PALETTE:
418 set_palette();
419 break;
420 case S_COLORBOX:
421 set_colorbox();
422 break;
423 case S_POINTINTERVALBOX:
424 set_pointintervalbox();
425 break;
426 case S_POINTSIZE:
427 set_pointsize();
428 break;
429 case S_POLAR:
430 set_polar();
431 break;
432 case S_PRINT:
433 set_print();
434 break;
435 case S_PSDIR:
436 set_psdir();
437 break;
438 #ifdef EAM_OBJECTS
439 case S_OBJECT:
440 set_object();
441 break;
442 #endif
443 case S_SAMPLES:
444 set_samples();
445 break;
446 case S_RGBMAX:
447 set_rgbmax();
448 break;
449 case S_SIZE:
450 set_size();
451 break;
452 case S_STYLE:
453 set_style();
454 break;
455 case S_SURFACE:
456 set_surface();
457 break;
458 case S_TABLE:
459 set_table();
460 break;
461 case S_TERMINAL:
462 set_terminal();
463 break;
464 case S_TERMOPTIONS:
465 set_termoptions();
466 break;
467 case S_THETA:
468 set_theta();
469 break;
470 case S_TICS:
471 set_tics();
472 break;
473 case S_TICSCALE:
474 set_ticscale();
475 break;
476 case S_TIMEFMT:
477 set_timefmt();
478 break;
479 case S_TIMESTAMP:
480 set_timestamp();
481 break;
482 case S_TITLE:
483 set_xyzlabel(&title);
484 title.rotate = 0.0;
485 break;
486 case S_VIEW:
487 set_view();
488 break;
489 case S_ZERO:
490 set_zero();
491 break;
492
493 case S_MXTICS:
494 case S_NOMXTICS:
495 case S_XTICS:
496 case S_NOXTICS:
497 case S_XDTICS:
498 case S_NOXDTICS:
499 case S_XMTICS:
500 case S_NOXMTICS:
501 set_tic_prop(&axis_array[FIRST_X_AXIS]);
502 break;
503 case S_MYTICS:
504 case S_NOMYTICS:
505 case S_YTICS:
506 case S_NOYTICS:
507 case S_YDTICS:
508 case S_NOYDTICS:
509 case S_YMTICS:
510 case S_NOYMTICS:
511 set_tic_prop(&axis_array[FIRST_Y_AXIS]);
512 break;
513 case S_MX2TICS:
514 case S_NOMX2TICS:
515 case S_X2TICS:
516 case S_NOX2TICS:
517 case S_X2DTICS:
518 case S_NOX2DTICS:
519 case S_X2MTICS:
520 case S_NOX2MTICS:
521 set_tic_prop(&axis_array[SECOND_X_AXIS]);
522 break;
523 case S_MY2TICS:
524 case S_NOMY2TICS:
525 case S_Y2TICS:
526 case S_NOY2TICS:
527 case S_Y2DTICS:
528 case S_NOY2DTICS:
529 case S_Y2MTICS:
530 case S_NOY2MTICS:
531 set_tic_prop(&axis_array[SECOND_Y_AXIS]);
532 break;
533 case S_MZTICS:
534 case S_NOMZTICS:
535 case S_ZTICS:
536 case S_NOZTICS:
537 case S_ZDTICS:
538 case S_NOZDTICS:
539 case S_ZMTICS:
540 case S_NOZMTICS:
541 set_tic_prop(&axis_array[FIRST_Z_AXIS]);
542 break;
543 case S_MCBTICS:
544 case S_NOMCBTICS:
545 case S_CBTICS:
546 case S_NOCBTICS:
547 case S_CBDTICS:
548 case S_NOCBDTICS:
549 case S_CBMTICS:
550 case S_NOCBMTICS:
551 set_tic_prop(&axis_array[COLOR_AXIS]);
552 break;
553 case S_RTICS:
554 case S_MRTICS:
555 set_tic_prop(&axis_array[POLAR_AXIS]);
556 break;
557 case S_TTICS:
558 set_tic_prop(&THETA_AXIS);
559 break;
560 case S_MTTICS:
561 set_mttics(&THETA_AXIS);
562 break;
563 case S_XDATA:
564 set_timedata(&axis_array[FIRST_X_AXIS]);
565 axis_array[T_AXIS].datatype
566 = axis_array[U_AXIS].datatype
567 = axis_array[FIRST_X_AXIS].datatype;
568 break;
569 case S_YDATA:
570 set_timedata(&axis_array[FIRST_Y_AXIS]);
571 axis_array[V_AXIS].datatype
572 = axis_array[FIRST_X_AXIS].datatype;
573 break;
574 case S_ZDATA:
575 set_timedata(&axis_array[FIRST_Z_AXIS]);
576 break;
577 case S_CBDATA:
578 set_timedata(&axis_array[COLOR_AXIS]);
579 break;
580 case S_X2DATA:
581 set_timedata(&axis_array[SECOND_X_AXIS]);
582 break;
583 case S_Y2DATA:
584 set_timedata(&axis_array[SECOND_Y_AXIS]);
585 break;
586 case S_XLABEL:
587 set_xyzlabel(&axis_array[FIRST_X_AXIS].label);
588 break;
589 case S_YLABEL:
590 set_xyzlabel(&axis_array[FIRST_Y_AXIS].label);
591 break;
592 case S_ZLABEL:
593 set_xyzlabel(&axis_array[FIRST_Z_AXIS].label);
594 break;
595 case S_CBLABEL:
596 set_xyzlabel(&axis_array[COLOR_AXIS].label);
597 break;
598 case S_RLABEL:
599 set_xyzlabel(&axis_array[POLAR_AXIS].label);
600 break;
601 case S_X2LABEL:
602 set_xyzlabel(&axis_array[SECOND_X_AXIS].label);
603 break;
604 case S_Y2LABEL:
605 set_xyzlabel(&axis_array[SECOND_Y_AXIS].label);
606 break;
607 case S_XRANGE:
608 set_range(&axis_array[FIRST_X_AXIS]);
609 break;
610 case S_X2RANGE:
611 set_range(&axis_array[SECOND_X_AXIS]);
612 break;
613 case S_YRANGE:
614 set_range(&axis_array[FIRST_Y_AXIS]);
615 break;
616 case S_Y2RANGE:
617 set_range(&axis_array[SECOND_Y_AXIS]);
618 break;
619 case S_ZRANGE:
620 set_range(&axis_array[FIRST_Z_AXIS]);
621 break;
622 case S_CBRANGE:
623 set_range(&axis_array[COLOR_AXIS]);
624 break;
625 case S_RRANGE:
626 set_range(&axis_array[POLAR_AXIS]);
627 if (polar)
628 rrange_to_xy();
629 break;
630 case S_TRANGE:
631 set_range(&axis_array[T_AXIS]);
632 break;
633 case S_URANGE:
634 set_range(&axis_array[U_AXIS]);
635 break;
636 case S_VRANGE:
637 set_range(&axis_array[V_AXIS]);
638 break;
639 case S_PAXIS:
640 set_paxis();
641 break;
642 case S_RAXIS:
643 set_raxis();
644 break;
645 case S_XZEROAXIS:
646 set_zeroaxis(FIRST_X_AXIS);
647 break;
648 case S_YZEROAXIS:
649 set_zeroaxis(FIRST_Y_AXIS);
650 break;
651 case S_ZZEROAXIS:
652 set_zeroaxis(FIRST_Z_AXIS);
653 break;
654 case S_X2ZEROAXIS:
655 set_zeroaxis(SECOND_X_AXIS);
656 break;
657 case S_Y2ZEROAXIS:
658 set_zeroaxis(SECOND_Y_AXIS);
659 break;
660 case S_ZEROAXIS:
661 set_allzeroaxis();
662 break;
663 case S_XYPLANE:
664 set_xyplane();
665 break;
666 case S_TICSLEVEL:
667 set_ticslevel();
668 break;
669 default:
670 int_error(c_token, "unrecognized option - see 'help set'.");
671 break;
672 }
673
674 if (next_iteration(set_iterator)) {
675 c_token = save_token;
676 goto ITERATE;
677 }
678
679 }
680
681 update_gpval_variables(0);
682
683 set_iterator = cleanup_iteration(set_iterator);
684 }
685
686
687 /* process 'set angles' command */
688 static void
set_angles()689 set_angles()
690 {
691 c_token++;
692 if (END_OF_COMMAND) {
693 /* assuming same as defaults */
694 ang2rad = 1;
695 } else if (almost_equals(c_token, "r$adians")) {
696 c_token++;
697 ang2rad = 1;
698 } else if (almost_equals(c_token, "d$egrees")) {
699 c_token++;
700 ang2rad = DEG2RAD;
701 } else
702 int_error(c_token, "expecting 'radians' or 'degrees'");
703
704 if (polar && axis_array[T_AXIS].set_autoscale) {
705 /* set trange if in polar mode and no explicit range */
706 axis_array[T_AXIS].set_min = 0;
707 axis_array[T_AXIS].set_max = 2 * M_PI / ang2rad;
708 }
709 }
710
711
712 /* process a 'set arrow' command */
713 /* set arrow {tag} {from x,y} {to x,y} {{no}head} ... */
714 /* allow any order of options - pm 25.11.2001 */
715 static void
set_arrow()716 set_arrow()
717 {
718 struct arrow_def *this_arrow = NULL;
719 struct arrow_def *new_arrow = NULL;
720 struct arrow_def *prev_arrow = NULL;
721 TBOOLEAN duplication = FALSE;
722 TBOOLEAN set_start = FALSE;
723 TBOOLEAN set_end = FALSE;
724 int save_token;
725 int tag;
726
727 c_token++;
728
729 /* get tag */
730 if (almost_equals(c_token, "back$head") || equals(c_token, "front")
731 || equals(c_token, "from") || equals(c_token, "at")
732 || equals(c_token, "to") || equals(c_token, "rto")
733 || equals(c_token, "size")
734 || equals(c_token, "filled") || equals(c_token, "empty")
735 || equals(c_token, "as") || equals(c_token, "arrowstyle")
736 || almost_equals(c_token, "head$s") || equals(c_token, "nohead")
737 || almost_equals(c_token, "nobo$rder")) {
738 tag = assign_arrow_tag();
739
740 } else
741 tag = int_expression();
742
743 if (tag <= 0)
744 int_error(c_token, "tag must be > 0");
745
746 /* OK! add arrow */
747 if (first_arrow != NULL) { /* skip to last arrow */
748 for (this_arrow = first_arrow; this_arrow != NULL;
749 prev_arrow = this_arrow, this_arrow = this_arrow->next)
750 /* is this the arrow we want? */
751 if (tag <= this_arrow->tag)
752 break;
753 }
754 if (this_arrow == NULL || tag != this_arrow->tag) {
755 new_arrow = gp_alloc(sizeof(struct arrow_def), "arrow");
756 if (prev_arrow == NULL)
757 first_arrow = new_arrow;
758 else
759 prev_arrow->next = new_arrow;
760 new_arrow->tag = tag;
761 new_arrow->next = this_arrow;
762 this_arrow = new_arrow;
763
764 this_arrow->start = default_position;
765 this_arrow->end = default_position;
766 this_arrow->angle = 0.0;
767 this_arrow->type = arrow_end_undefined;
768
769 default_arrow_style(&(new_arrow->arrow_properties));
770 }
771
772 while (!END_OF_COMMAND) {
773
774 /* get start position */
775 if (equals(c_token, "from") || equals(c_token,"at")) {
776 if (set_start) { duplication = TRUE; break; }
777 c_token++;
778 if (END_OF_COMMAND)
779 int_error(c_token, "start coordinates expected");
780 /* get coordinates */
781 get_position(&this_arrow->start);
782 set_start = TRUE;
783 continue;
784 }
785
786 /* get end or relative end position */
787 if (equals(c_token, "to") || equals(c_token,"rto")) {
788 if (set_end) { duplication = TRUE; break; }
789 if (equals(c_token,"rto"))
790 this_arrow->type = arrow_end_relative;
791 else
792 this_arrow->type = arrow_end_absolute;
793 c_token++;
794 if (END_OF_COMMAND)
795 int_error(c_token, "end coordinates expected");
796 /* get coordinates */
797 get_position(&this_arrow->end);
798 set_end = TRUE;
799 continue;
800 }
801
802 /* get end position specified as length + orientation angle */
803 if (almost_equals(c_token, "len$gth")) {
804 if (set_end) { duplication = TRUE; break; }
805 this_arrow->type = arrow_end_oriented;
806 c_token++;
807 get_position_default(&this_arrow->end, first_axes, 1);
808 set_end = TRUE;
809 continue;
810 }
811 if (almost_equals(c_token,"ang$le")) {
812 c_token++;
813 this_arrow->angle = real_expression();
814 continue;
815 }
816
817 /* Allow interspersed style commands */
818 save_token = c_token;
819 arrow_parse(&this_arrow->arrow_properties, TRUE);
820 if (save_token != c_token)
821 continue;
822
823 if (!END_OF_COMMAND)
824 int_error(c_token, "wrong argument in set arrow");
825
826 } /* while (!END_OF_COMMAND) */
827
828 if (duplication)
829 int_error(c_token, "duplicate or contradictory arguments");
830
831 }
832
833
834 /* assign a new arrow tag
835 * arrows are kept sorted by tag number, so this is easy
836 * returns the lowest unassigned tag number
837 */
838 static int
assign_arrow_tag()839 assign_arrow_tag()
840 {
841 struct arrow_def *this_arrow;
842 int last = 0; /* previous tag value */
843
844 for (this_arrow = first_arrow; this_arrow != NULL;
845 this_arrow = this_arrow->next)
846 if (this_arrow->tag == last + 1)
847 last++;
848 else
849 break;
850
851 return (last + 1);
852 }
853
854 /* helper routine for 'set autoscale' on a single axis */
855 static TBOOLEAN
set_autoscale_axis(struct axis * this)856 set_autoscale_axis(struct axis *this)
857 {
858 char keyword[16];
859 char *name = (char *) &(axis_name(this->index)[0]);
860
861 if (equals(c_token, name)) {
862 this->set_autoscale = AUTOSCALE_BOTH;
863 this->min_constraint = CONSTRAINT_NONE;
864 this->max_constraint = CONSTRAINT_NONE;
865 ++c_token;
866 return TRUE;
867 }
868 sprintf(keyword, "%smi$n", name);
869 if (almost_equals(c_token, keyword)) {
870 this->set_autoscale |= AUTOSCALE_MIN;
871 this->min_constraint = CONSTRAINT_NONE;
872 ++c_token;
873 return TRUE;
874 }
875 sprintf(keyword, "%sma$x", name);
876 if (almost_equals(c_token, keyword)) {
877 this->set_autoscale |= AUTOSCALE_MAX;
878 this->max_constraint = CONSTRAINT_NONE;
879 ++c_token;
880 return TRUE;
881 }
882 sprintf(keyword, "%sfix", name);
883 if (equals(c_token, keyword)) {
884 this->set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX;
885 ++c_token;
886 return TRUE;
887 }
888 sprintf(keyword, "%sfixmi$n", name);
889 if (almost_equals(c_token, keyword)) {
890 this->set_autoscale |= AUTOSCALE_FIXMIN;
891 ++c_token;
892 return TRUE;
893 }
894 sprintf(keyword, "%sfixma$x", name);
895 if (almost_equals(c_token, keyword)) {
896 this->set_autoscale |= AUTOSCALE_FIXMAX;
897 ++c_token;
898 return TRUE;
899 }
900
901 return FALSE;
902 }
903
904 /* process 'set autoscale' command */
905 static void
set_autoscale()906 set_autoscale()
907 {
908 int axis;
909
910 c_token++;
911 if (END_OF_COMMAND) {
912 for (axis=0; axis<AXIS_ARRAY_SIZE; axis++)
913 axis_array[axis].set_autoscale = AUTOSCALE_BOTH;
914 for (axis=0; axis<num_parallel_axes; axis++)
915 parallel_axis[axis].set_autoscale = AUTOSCALE_BOTH;
916 return;
917 } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
918 axis_array[FIRST_X_AXIS].set_autoscale =
919 axis_array[FIRST_Y_AXIS].set_autoscale = AUTOSCALE_BOTH;
920 axis_array[FIRST_X_AXIS].min_constraint =
921 axis_array[FIRST_X_AXIS].max_constraint =
922 axis_array[FIRST_Y_AXIS].min_constraint =
923 axis_array[FIRST_Y_AXIS].max_constraint = CONSTRAINT_NONE;
924 c_token++;
925 return;
926 } else if (equals(c_token, "fix") || almost_equals(c_token, "noext$end")) {
927 for (axis=0; axis<AXIS_ARRAY_SIZE; axis++)
928 axis_array[axis].set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX;
929 for (axis=0; axis<num_parallel_axes; axis++)
930 parallel_axis[axis].set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX;
931 c_token++;
932 return;
933 } else if (almost_equals(c_token, "ke$epfix")) {
934 for (axis=0; axis<AXIS_ARRAY_SIZE; axis++)
935 axis_array[axis].set_autoscale |= AUTOSCALE_BOTH;
936 for (axis=0; axis<num_parallel_axes; axis++)
937 parallel_axis[axis].set_autoscale |= AUTOSCALE_BOTH;
938 c_token++;
939 return;
940 }
941
942 if (set_autoscale_axis(&axis_array[FIRST_X_AXIS])) return;
943 if (set_autoscale_axis(&axis_array[FIRST_Y_AXIS])) return;
944 if (set_autoscale_axis(&axis_array[FIRST_Z_AXIS])) return;
945 if (set_autoscale_axis(&axis_array[SECOND_X_AXIS])) return;
946 if (set_autoscale_axis(&axis_array[SECOND_Y_AXIS])) return;
947 if (set_autoscale_axis(&axis_array[COLOR_AXIS])) return;
948 if (set_autoscale_axis(&axis_array[POLAR_AXIS])) return;
949 /* FIXME: Do these commands make any sense? */
950 if (set_autoscale_axis(&axis_array[T_AXIS])) return;
951 if (set_autoscale_axis(&axis_array[U_AXIS])) return;
952 if (set_autoscale_axis(&axis_array[V_AXIS])) return;
953
954 /* come here only if nothing found: */
955 int_error(c_token, "Invalid range");
956 }
957
958
959 /* process 'set bars' command */
960 static void
set_bars()961 set_bars()
962 {
963 int save_token;
964
965 c_token++;
966
967 if (END_OF_COMMAND)
968 reset_bars();
969
970 while (!END_OF_COMMAND) {
971
972 if (equals(c_token,"default")) {
973 reset_bars();
974 ++c_token;
975 return;
976 }
977
978 /* Jul 2015 - allow a separate line type for error bars */
979 save_token = c_token;
980 lp_parse(&bar_lp, LP_ADHOC, FALSE);
981 if (c_token != save_token) {
982 bar_lp.flags = LP_ERRORBAR_SET;
983 continue;
984 }
985
986 if (almost_equals(c_token,"s$mall")) {
987 bar_size = 0.0;
988 ++c_token;
989 } else if (almost_equals(c_token,"l$arge")) {
990 bar_size = 1.0;
991 ++c_token;
992 } else if (almost_equals(c_token,"full$width")) {
993 bar_size = -1.0;
994 ++c_token;
995 } else if (equals(c_token,"front")) {
996 bar_layer = LAYER_FRONT;
997 ++c_token;
998 } else if (equals(c_token,"back")) {
999 bar_layer = LAYER_BACK;
1000 ++c_token;
1001 } else {
1002 bar_size = real_expression();
1003 }
1004 }
1005 }
1006
1007
1008 /* process 'set border' command */
1009 static void
set_border()1010 set_border()
1011 {
1012 c_token++;
1013 if (END_OF_COMMAND){
1014 draw_border = 31;
1015 border_layer = LAYER_FRONT;
1016 border_lp = default_border_lp;
1017 }
1018
1019 while (!END_OF_COMMAND) {
1020 if (equals(c_token,"front")) {
1021 border_layer = LAYER_FRONT;
1022 c_token++;
1023 } else if (equals(c_token,"back")) {
1024 border_layer = LAYER_BACK;
1025 c_token++;
1026 } else if (equals(c_token,"behind")) {
1027 border_layer = LAYER_BEHIND;
1028 c_token++;
1029 } else if (equals(c_token,"polar")) {
1030 draw_border |= 0x1000;
1031 c_token++;
1032 } else {
1033 int save_token = c_token;
1034 lp_parse(&border_lp, LP_ADHOC, FALSE);
1035 if (save_token != c_token)
1036 continue;
1037 draw_border = int_expression();
1038 }
1039 }
1040
1041 /* This is the only place the user can change the border */
1042 /* so remember what he set. If draw_border is later changed*/
1043 /* internally, we can still recover the user's preference. */
1044 user_border = draw_border;
1045 }
1046
1047
1048 /* process 'set style boxplot' command */
1049 static void
set_boxplot()1050 set_boxplot()
1051 {
1052 c_token++;
1053 if (END_OF_COMMAND) {
1054 boxplot_style defstyle = DEFAULT_BOXPLOT_STYLE;
1055 boxplot_opts = defstyle;
1056 }
1057 while (!END_OF_COMMAND) {
1058 if (almost_equals(c_token, "noout$liers")) {
1059 boxplot_opts.outliers = FALSE;
1060 c_token++;
1061 }
1062 else if (almost_equals(c_token, "out$liers")) {
1063 boxplot_opts.outliers = TRUE;
1064 c_token++;
1065 }
1066 else if (almost_equals(c_token, "point$type") || equals (c_token, "pt")) {
1067 c_token++;
1068 boxplot_opts.pointtype = int_expression()-1;
1069 }
1070 else if (equals(c_token,"range")) {
1071 c_token++;
1072 boxplot_opts.limit_type = 0;
1073 boxplot_opts.limit_value = real_expression();
1074 }
1075 else if (almost_equals(c_token,"frac$tion")) {
1076 c_token++;
1077 boxplot_opts.limit_value = real_expression();
1078 if (boxplot_opts.limit_value < 0 || boxplot_opts.limit_value > 1)
1079 int_error(c_token-1,"fraction must be less than 1");
1080 boxplot_opts.limit_type = 1;
1081 }
1082 else if (almost_equals(c_token,"candle$sticks")) {
1083 c_token++;
1084 boxplot_opts.plotstyle = CANDLESTICKS;
1085 }
1086 else if (almost_equals(c_token,"finance$bars")) {
1087 c_token++;
1088 boxplot_opts.plotstyle = FINANCEBARS;
1089 }
1090 else if (almost_equals(c_token,"sep$aration")) {
1091 c_token++;
1092 boxplot_opts.separation = real_expression();
1093 if (boxplot_opts.separation < 0)
1094 int_error(c_token-1,"separation must be > 0");
1095 }
1096 else if (almost_equals(c_token,"lab$els")) {
1097 c_token++;
1098 if (equals(c_token, "off")) {
1099 boxplot_opts.labels = BOXPLOT_FACTOR_LABELS_OFF;
1100 }
1101 else if (equals(c_token, "x")) {
1102 boxplot_opts.labels = BOXPLOT_FACTOR_LABELS_X;
1103 }
1104 else if (equals(c_token, "x2")) {
1105 boxplot_opts.labels = BOXPLOT_FACTOR_LABELS_X2;
1106 }
1107 else if (equals(c_token, "auto")) {
1108 boxplot_opts.labels = BOXPLOT_FACTOR_LABELS_AUTO;
1109 }
1110 else
1111 int_error(c_token-1,"expecting 'x', 'x2', 'auto' or 'off'");
1112 c_token++;
1113 }
1114 else if (almost_equals(c_token, "median$linewidth")) {
1115 c_token++;
1116 boxplot_opts.median_linewidth = real_expression();
1117 }
1118 else if (almost_equals(c_token, "so$rted")) {
1119 boxplot_opts.sort_factors = TRUE;
1120 c_token++;
1121 }
1122 else if (almost_equals(c_token, "un$sorted")) {
1123 boxplot_opts.sort_factors = FALSE;
1124 c_token++;
1125 }
1126 else
1127 int_error(c_token,"unrecognized option");
1128 }
1129
1130 }
1131
1132
1133 /* process 'set boxwidth' command */
1134 static void
set_boxwidth()1135 set_boxwidth()
1136 {
1137 c_token++;
1138 if (END_OF_COMMAND) {
1139 boxwidth = -1.0;
1140 boxwidth_is_absolute = TRUE;
1141 } else {
1142 boxwidth = real_expression();
1143 }
1144 if (END_OF_COMMAND)
1145 return;
1146 else {
1147 if (almost_equals(c_token, "a$bsolute"))
1148 boxwidth_is_absolute = TRUE;
1149 else if (almost_equals(c_token, "r$elative"))
1150 boxwidth_is_absolute = FALSE;
1151 else
1152 int_error(c_token, "expecting 'absolute' or 'relative' ");
1153 }
1154 c_token++;
1155 }
1156
1157 /* process 'set clabel' command */
1158 static void
set_clabel()1159 set_clabel()
1160 {
1161 char *new_format;
1162
1163 c_token++;
1164 clabel_onecolor = FALSE;
1165 if ((new_format = try_to_get_string())) {
1166 safe_strncpy(contour_format, new_format, sizeof(contour_format));
1167 free(new_format);
1168 }
1169 }
1170
1171
1172 /* process 'set clip' command */
1173 static void
set_clip()1174 set_clip()
1175 {
1176 c_token++;
1177 if (END_OF_COMMAND) {
1178 /* assuming same as points */
1179 clip_points = TRUE;
1180 } else if (almost_equals(c_token, "p$oints")) {
1181 clip_points = TRUE;
1182 c_token++;
1183 } else if (almost_equals(c_token, "o$ne")) {
1184 clip_lines1 = TRUE;
1185 c_token++;
1186 } else if (almost_equals(c_token, "t$wo")) {
1187 clip_lines2 = TRUE;
1188 c_token++;
1189 } else
1190 int_error(c_token, "expecting 'points', 'one', or 'two'");
1191 }
1192
1193
1194 /* process 'set cntrparam' command */
1195 static void
set_cntrparam()1196 set_cntrparam()
1197 {
1198 c_token++;
1199 if (END_OF_COMMAND) {
1200 /* assuming same as defaults */
1201 contour_pts = DEFAULT_NUM_APPROX_PTS;
1202 contour_kind = CONTOUR_KIND_LINEAR;
1203 contour_order = DEFAULT_CONTOUR_ORDER;
1204 contour_levels = DEFAULT_CONTOUR_LEVELS;
1205 contour_levels_kind = LEVELS_AUTO;
1206 contour_firstlinetype = 0;
1207 return;
1208 }
1209
1210 while (!END_OF_COMMAND) {
1211 if (almost_equals(c_token, "p$oints")) {
1212 c_token++;
1213 contour_pts = int_expression();
1214 } else if (almost_equals(c_token, "first$linetype")) {
1215 c_token++;
1216 contour_firstlinetype = int_expression();
1217 } else if (almost_equals(c_token, "sort$ed")) {
1218 c_token++;
1219 contour_sortlevels = TRUE;
1220 } else if (almost_equals(c_token, "unsort$ed")) {
1221 c_token++;
1222 contour_sortlevels = FALSE;
1223 } else if (almost_equals(c_token, "li$near")) {
1224 c_token++;
1225 contour_kind = CONTOUR_KIND_LINEAR;
1226 } else if (almost_equals(c_token, "c$ubicspline")) {
1227 c_token++;
1228 contour_kind = CONTOUR_KIND_CUBIC_SPL;
1229 } else if (almost_equals(c_token, "b$spline")) {
1230 c_token++;
1231 contour_kind = CONTOUR_KIND_BSPLINE;
1232 } else if (almost_equals(c_token, "le$vels")) {
1233 c_token++;
1234
1235 if (!(set_iterator && set_iterator->iteration)) {
1236 free_dynarray(&dyn_contour_levels_list);
1237 init_dynarray(&dyn_contour_levels_list, sizeof(double), 5, 10);
1238 }
1239
1240 /* RKC: I have modified the next two:
1241 * to use commas to separate list elements as in xtics
1242 * so that incremental lists start,incr[,end]as in "
1243 */
1244 if (almost_equals(c_token, "di$screte")) {
1245 contour_levels_kind = LEVELS_DISCRETE;
1246 c_token++;
1247 if (END_OF_COMMAND)
1248 int_error(c_token, "expecting discrete level");
1249 else
1250 *(double *)nextfrom_dynarray(&dyn_contour_levels_list) =
1251 real_expression();
1252
1253 while(!END_OF_COMMAND) {
1254 if (!equals(c_token, ","))
1255 int_error(c_token,
1256 "expecting comma to separate discrete levels");
1257 c_token++;
1258 *(double *)nextfrom_dynarray(&dyn_contour_levels_list) =
1259 real_expression();
1260 }
1261 contour_levels = dyn_contour_levels_list.end;
1262 } else if (almost_equals(c_token, "in$cremental")) {
1263 int i = 0; /* local counter */
1264
1265 contour_levels_kind = LEVELS_INCREMENTAL;
1266 c_token++;
1267 contour_levels_list[i++] = real_expression();
1268 if (!equals(c_token, ","))
1269 int_error(c_token,
1270 "expecting comma to separate start,incr levels");
1271 c_token++;
1272 if ((contour_levels_list[i++] = real_expression()) == 0)
1273 int_error(c_token, "increment cannot be 0");
1274 if (!END_OF_COMMAND) {
1275 if (!equals(c_token, ","))
1276 int_error(c_token,
1277 "expecting comma to separate incr,stop levels");
1278 c_token++;
1279 /* need to round up, since 10,10,50 is 5 levels, not four,
1280 * but 10,10,49 is four
1281 */
1282 dyn_contour_levels_list.end = i;
1283 contour_levels = (int) ( (real_expression()-contour_levels_list[0])/contour_levels_list[1] + 1.0);
1284 }
1285 } else if (almost_equals(c_token, "au$to")) {
1286 contour_levels_kind = LEVELS_AUTO;
1287 c_token++;
1288 if (!END_OF_COMMAND)
1289 contour_levels = int_expression();
1290 } else {
1291 if (contour_levels_kind == LEVELS_DISCRETE)
1292 int_error(c_token, "Levels type is discrete, ignoring new number of contour levels");
1293 contour_levels = int_expression();
1294 }
1295 } else if (almost_equals(c_token, "o$rder")) {
1296 int order;
1297 c_token++;
1298 order = int_expression();
1299 if ( order < 2 || order > MAX_BSPLINE_ORDER )
1300 int_error(c_token, "bspline order must be in [2..10] range.");
1301 contour_order = order;
1302 } else
1303 int_error(c_token, "expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'");
1304 }
1305 }
1306
1307 /* process 'set cntrlabel' command */
1308 static void
set_cntrlabel()1309 set_cntrlabel()
1310 {
1311 c_token++;
1312 if (END_OF_COMMAND) {
1313 strcpy(contour_format, "%8.3g");
1314 clabel_onecolor = FALSE;
1315 return;
1316 }
1317 while (!END_OF_COMMAND) {
1318 if (almost_equals(c_token, "form$at")) {
1319 char *new;
1320 c_token++;
1321 if ((new = try_to_get_string()))
1322 safe_strncpy(contour_format,new,sizeof(contour_format));
1323 free(new);
1324 } else if (equals(c_token, "font")) {
1325 char *ctmp;
1326 c_token++;
1327 if ((ctmp = try_to_get_string())) {
1328 free(clabel_font);
1329 clabel_font = ctmp;
1330 }
1331 } else if (almost_equals(c_token, "one$color")) {
1332 c_token++;
1333 clabel_onecolor = TRUE;
1334 } else if (equals(c_token, "start")) {
1335 c_token++;
1336 clabel_start = int_expression();
1337 if (clabel_start <= 0)
1338 clabel_start = 5;
1339 } else if (almost_equals(c_token, "int$erval")) {
1340 c_token++;
1341 clabel_interval = int_expression();
1342 } else {
1343 int_error(c_token, "unrecognized option");
1344 }
1345 }
1346 }
1347
1348 /* process 'set contour' command */
1349 static void
set_contour()1350 set_contour()
1351 {
1352 c_token++;
1353 if (END_OF_COMMAND)
1354 /* assuming same as points */
1355 draw_contour = CONTOUR_BASE;
1356 else {
1357 if (almost_equals(c_token, "ba$se"))
1358 draw_contour = CONTOUR_BASE;
1359 else if (almost_equals(c_token, "s$urface"))
1360 draw_contour = CONTOUR_SRF;
1361 else if (almost_equals(c_token, "bo$th"))
1362 draw_contour = CONTOUR_BOTH;
1363 else
1364 int_error(c_token, "expecting 'base', 'surface', or 'both'");
1365 c_token++;
1366 }
1367 }
1368
1369 /* process 'set colorsequence command */
1370 void
set_colorsequence(int option)1371 set_colorsequence(int option)
1372 {
1373 unsigned long default_colors[] = DEFAULT_COLOR_SEQUENCE;
1374 unsigned long podo_colors[] = PODO_COLOR_SEQUENCE;
1375
1376 if (option == 0) { /* Read option from command line */
1377 if (equals(++c_token, "default"))
1378 option = 1;
1379 else if (equals(c_token, "podo"))
1380 option = 2;
1381 else if (equals(c_token, "classic"))
1382 option = 3;
1383 else
1384 int_error(c_token, "unrecognized color set");
1385 }
1386
1387 if (option == 1 || option == 2) {
1388 int i;
1389 char *command;
1390 char *command_template = "set linetype %2d lc rgb 0x%06x";
1391 unsigned long *colors = default_colors;
1392 if (option == 2)
1393 colors = podo_colors;
1394 linetype_recycle_count = 8;
1395 for (i = 1; i <= 8; i++) {
1396 command = gp_alloc(strlen(command_template)+8, "dynamic command");
1397 sprintf(command, command_template, i, colors[i-1]);
1398 do_string_and_free(command);
1399 }
1400
1401 } else if (option == 3) {
1402 struct linestyle_def *this;
1403 for (this = first_perm_linestyle; this != NULL; this = this->next) {
1404 this->lp_properties.pm3d_color.type = TC_LT;
1405 this->lp_properties.pm3d_color.lt = this->tag-1;
1406 }
1407 linetype_recycle_count = 0;
1408
1409 } else {
1410 int_error(c_token, "Expecting 'classic' or 'default'");
1411 }
1412 c_token++;
1413 }
1414
1415 /* process 'set dashtype' command */
1416 static void
set_dashtype()1417 set_dashtype()
1418 {
1419 struct custom_dashtype_def *this_dashtype = NULL;
1420 struct custom_dashtype_def *new_dashtype = NULL;
1421 struct custom_dashtype_def *prev_dashtype = NULL;
1422 int tag, is_new = FALSE;
1423
1424 c_token++;
1425
1426 /* get tag */
1427 if (END_OF_COMMAND || ((tag = int_expression()) <= 0))
1428 int_error(c_token, "tag must be > zero");
1429
1430 /* Check if dashtype is already defined */
1431 for (this_dashtype = first_custom_dashtype; this_dashtype != NULL;
1432 prev_dashtype = this_dashtype, this_dashtype = this_dashtype->next)
1433 if (tag <= this_dashtype->tag)
1434 break;
1435
1436 if (this_dashtype == NULL || tag != this_dashtype->tag) {
1437 struct t_dashtype loc_dt = DEFAULT_DASHPATTERN;
1438 new_dashtype = gp_alloc(sizeof(struct custom_dashtype_def), "dashtype");
1439 if (prev_dashtype != NULL)
1440 prev_dashtype->next = new_dashtype; /* add it to end of list */
1441 else
1442 first_custom_dashtype = new_dashtype; /* make it start of list */
1443 new_dashtype->tag = tag;
1444 new_dashtype->d_type = DASHTYPE_SOLID;
1445 new_dashtype->next = this_dashtype;
1446 new_dashtype->dashtype = loc_dt;
1447 this_dashtype = new_dashtype;
1448 is_new = TRUE;
1449 }
1450
1451 if (almost_equals(c_token, "def$ault")) {
1452 delete_dashtype(prev_dashtype, this_dashtype);
1453 is_new = FALSE;
1454 c_token++;
1455 } else {
1456 /* FIXME: Maybe this should reject return values > 0 because */
1457 /* otherwise we have potentially recursive definitions. */
1458 this_dashtype->d_type = parse_dashtype(&this_dashtype->dashtype);
1459 }
1460
1461 if (!END_OF_COMMAND) {
1462 if (is_new)
1463 delete_dashtype(prev_dashtype, this_dashtype);
1464 int_error(c_token,"Extraneous arguments to set dashtype");
1465 }
1466 }
1467
1468 /*
1469 * Delete dashtype from linked list.
1470 */
1471 void
delete_dashtype(struct custom_dashtype_def * prev,struct custom_dashtype_def * this)1472 delete_dashtype(struct custom_dashtype_def *prev, struct custom_dashtype_def *this)
1473 {
1474 if (this != NULL) { /* there really is something to delete */
1475 if (this == first_custom_dashtype)
1476 first_custom_dashtype = this->next;
1477 else
1478 prev->next = this->next;
1479 free(this);
1480 }
1481 }
1482
1483 /* process 'set dgrid3d' command */
1484 static void
set_dgrid3d()1485 set_dgrid3d()
1486 {
1487 int token_cnt = 0; /* Number of comma-separated values read in */
1488
1489 int gridx = dgrid3d_row_fineness;
1490 int gridy = dgrid3d_col_fineness;
1491 int normval = dgrid3d_norm_value;
1492 double scalex = dgrid3d_x_scale;
1493 double scaley = dgrid3d_y_scale;
1494
1495 /* dgrid3d has two different syntax alternatives: classic and new.
1496 If there is a "mode" keyword, the syntax is new, otherwise it is classic.*/
1497 dgrid3d_mode = DGRID3D_DEFAULT;
1498
1499 dgrid3d_kdensity = FALSE;
1500
1501 c_token++;
1502 while ( !(END_OF_COMMAND) ) {
1503 int tmp_mode = lookup_table(&dgrid3d_mode_tbl[0],c_token);
1504 if (tmp_mode != DGRID3D_OTHER) {
1505 dgrid3d_mode = tmp_mode;
1506 c_token++;
1507 }
1508
1509 switch (tmp_mode) {
1510 case DGRID3D_QNORM:
1511 if (!(END_OF_COMMAND)) normval = int_expression();
1512 break;
1513 case DGRID3D_SPLINES:
1514 break;
1515 case DGRID3D_GAUSS:
1516 case DGRID3D_CAUCHY:
1517 case DGRID3D_EXP:
1518 case DGRID3D_BOX:
1519 case DGRID3D_HANN:
1520 if (!(END_OF_COMMAND) && almost_equals( c_token, "kdens$ity2d" )) {
1521 dgrid3d_kdensity = TRUE;
1522 c_token++;
1523 }
1524 if (!(END_OF_COMMAND)) {
1525 scalex = real_expression();
1526 scaley = scalex;
1527 if (equals(c_token, ",")) {
1528 c_token++;
1529 scaley = real_expression();
1530 }
1531 }
1532 break;
1533
1534 default: /* {rows}{,cols{,norm}}} */
1535
1536 if ( equals( c_token, "," )) {
1537 c_token++;
1538 token_cnt++;
1539 } else if (token_cnt == 0) {
1540 gridx = int_expression();
1541 gridy = gridx; /* gridy defaults to gridx, unless overridden below */
1542 } else if (token_cnt == 1) {
1543 gridy = int_expression();
1544 } else if (token_cnt == 2) {
1545 normval = int_expression();
1546 } else
1547 int_error(c_token,"Unrecognized keyword or unexpected value");
1548 break;
1549 }
1550
1551 }
1552
1553 /* we could warn here about floating point values being truncated... */
1554 if (gridx < 2 || gridx > 1000 || gridy < 2 || gridy > 1000)
1555 int_error( NO_CARET,
1556 "Number of grid points must be in [2:1000] - not changed!");
1557
1558 /* no mode token found: classic format */
1559 if (dgrid3d_mode == DGRID3D_DEFAULT)
1560 dgrid3d_mode = DGRID3D_QNORM;
1561
1562 if (scalex < 0.0 || scaley < 0.0)
1563 int_error( NO_CARET,
1564 "Scale factors must be greater than zero - not changed!" );
1565
1566 dgrid3d_row_fineness = gridx;
1567 dgrid3d_col_fineness = gridy;
1568 dgrid3d_norm_value = normval;
1569 dgrid3d_x_scale = scalex;
1570 dgrid3d_y_scale = scaley;
1571 dgrid3d = TRUE;
1572 }
1573
1574
1575 /* process 'set decimalsign' command */
1576 static void
set_decimalsign()1577 set_decimalsign()
1578 {
1579 c_token++;
1580
1581 /* Clear current setting */
1582 free(decimalsign);
1583 decimalsign=NULL;
1584
1585 if (END_OF_COMMAND) {
1586 reset_numeric_locale();
1587 free(numeric_locale);
1588 numeric_locale = NULL;
1589 #ifdef HAVE_LOCALE_H
1590 } else if (equals(c_token,"locale")) {
1591 char *newlocale = NULL;
1592 c_token++;
1593 newlocale = try_to_get_string();
1594 if (!newlocale)
1595 newlocale = gp_strdup(setlocale(LC_NUMERIC,""));
1596 if (!newlocale)
1597 newlocale = gp_strdup(getenv("LC_ALL"));
1598 if (!newlocale)
1599 newlocale = gp_strdup(getenv("LC_NUMERIC"));
1600 if (!newlocale)
1601 newlocale = gp_strdup(getenv("LANG"));
1602 if (!setlocale(LC_NUMERIC, newlocale ? newlocale : ""))
1603 int_error(c_token-1, "Could not find requested locale");
1604 decimalsign = gp_strdup(get_decimal_locale());
1605 fprintf(stderr,"decimal_sign in locale is %s\n", decimalsign);
1606 /* Save this locale for later use, but return to "C" for now */
1607 free(numeric_locale);
1608 numeric_locale = newlocale;
1609 setlocale(LC_NUMERIC,"C");
1610 #endif
1611 } else if (!(decimalsign = try_to_get_string()))
1612 int_error(c_token, "expecting string");
1613 }
1614
1615 /* process 'set dummy' command */
1616 static void
set_dummy()1617 set_dummy()
1618 {
1619 int i;
1620 c_token++;
1621 for (i=0; i<MAX_NUM_VAR; i++) {
1622 if (END_OF_COMMAND)
1623 return;
1624 if (isalpha((unsigned char)gp_input_line[token[c_token].start_index]))
1625 copy_str(set_dummy_var[i],c_token++, MAX_ID_LEN);
1626 if (equals(c_token,","))
1627 c_token++;
1628 else
1629 break;
1630 }
1631 if (!END_OF_COMMAND)
1632 int_error(c_token,"unrecognized syntax");
1633 }
1634
1635
1636 /* process 'set encoding' command */
1637 static void
set_encoding()1638 set_encoding()
1639 {
1640 char *l = NULL;
1641 c_token++;
1642
1643 if (END_OF_COMMAND) {
1644 encoding = S_ENC_DEFAULT;
1645 #ifdef HAVE_LOCALE_H
1646 } else if (equals(c_token, "locale")) {
1647 enum set_encoding_id newenc = encoding_from_locale();
1648
1649 l = setlocale(LC_CTYPE, "");
1650 if (newenc == S_ENC_DEFAULT)
1651 int_warn(NO_CARET, "Locale not supported by gnuplot: %s", l);
1652 if (newenc == S_ENC_INVALID)
1653 int_warn(NO_CARET, "Error converting locale \"%s\" to codepage number", l);
1654 else
1655 encoding = newenc;
1656 c_token++;
1657 #endif
1658 } else {
1659 int temp = lookup_table(&set_encoding_tbl[0],c_token);
1660 char *senc;
1661
1662 /* allow string variables as parameter */
1663 if ((temp == S_ENC_INVALID) && isstringvalue(c_token) && (senc = try_to_get_string())) {
1664 int i;
1665 for (i = 0; encoding_names[i] != NULL; i++)
1666 if (strcmp(encoding_names[i], senc) == 0)
1667 temp = i;
1668 free(senc);
1669 } else {
1670 c_token++;
1671 }
1672
1673 if (temp == S_ENC_INVALID)
1674 int_error(c_token, "unrecognized encoding specification; see 'help encoding'.");
1675 encoding = temp;
1676 }
1677
1678 init_special_chars();
1679 }
1680
1681 static void
set_degreesign(char * locale)1682 set_degreesign(char *locale)
1683 {
1684 #if defined(HAVE_ICONV) && !(defined _WIN32)
1685 char degree_utf8[3] = {'\302', '\260', '\0'};
1686 size_t lengthin = 3;
1687 size_t lengthout = 8;
1688 char *in = degree_utf8;
1689 char *out = degree_sign;
1690 iconv_t cd;
1691
1692 if (locale) {
1693 /* This should work even if gnuplot doesn't understand the encoding */
1694 #ifdef HAVE_LANGINFO_H
1695 char *cencoding = nl_langinfo(CODESET);
1696 #else
1697 char *cencoding = strchr(locale, '.');
1698 if (cencoding) cencoding++; /* Step past the dot in, e.g., ja_JP.EUC-JP */
1699 #endif
1700 if (cencoding) {
1701 if (strcmp(cencoding,"UTF-8") == 0)
1702 strcpy(degree_sign,degree_utf8);
1703 else if ((cd = iconv_open(cencoding, "UTF-8")) == (iconv_t)(-1))
1704 int_warn(NO_CARET, "iconv_open failed for %s",cencoding);
1705 else {
1706 if (iconv(cd, &in, &lengthin, &out, &lengthout) == (size_t)(-1))
1707 int_warn(NO_CARET, "iconv failed to convert degree sign");
1708 iconv_close(cd);
1709 }
1710 }
1711 return;
1712 }
1713 #else
1714 (void)locale; /* -Wunused argument */
1715 #endif
1716
1717 /* These are the internally-known encodings */
1718 memset(degree_sign, 0, sizeof(degree_sign));
1719 switch (encoding) {
1720 case S_ENC_UTF8: degree_sign[0] = '\302'; degree_sign[1] = '\260'; break;
1721 case S_ENC_KOI8_R:
1722 case S_ENC_KOI8_U: degree_sign[0] = '\234'; break;
1723 case S_ENC_CP437:
1724 case S_ENC_CP850:
1725 case S_ENC_CP852: degree_sign[0] = '\370'; break;
1726 case S_ENC_SJIS: break; /* should be 0x818B */
1727 case S_ENC_CP950: break; /* should be 0xA258 */
1728 /* default applies at least to:
1729 ISO8859-1, -2, -9, -15,
1730 CP1250, CP1251, CP1252, CP1254
1731 */
1732 default: degree_sign[0] = '\260'; break;
1733 }
1734 }
1735
1736 /* Encoding-specific character enabled by "set micro" */
1737 static const char *
encoding_micro()1738 encoding_micro()
1739 {
1740 static const char micro_utf8[4] = {0xC2, 0xB5, 0x0, 0x0};
1741 static const char micro_437[2] = {0xE6, 0x0};
1742 static const char micro_latin1[2] = {0xB5, 0x0};
1743 static const char micro_default[2] = {'u', 0x0};
1744 switch (encoding) {
1745 case S_ENC_UTF8: return micro_utf8;
1746 case S_ENC_CP1250:
1747 case S_ENC_CP1251:
1748 case S_ENC_CP1252:
1749 case S_ENC_CP1254:
1750 case S_ENC_ISO8859_1:
1751 case S_ENC_ISO8859_9:
1752 case S_ENC_ISO8859_15: return micro_latin1;
1753 case S_ENC_CP437:
1754 case S_ENC_CP850: return micro_437;
1755 default: return micro_default;
1756 }
1757 }
1758
1759 /* process 'set fit' command */
1760 /* Encoding-specific character enabled by "set minussign" */
1761 static const char *
encoding_minus()1762 encoding_minus()
1763 {
1764 static const char minus_utf8[4] = {0xE2, 0x88, 0x92, 0x0};
1765 static const char minus_1252[2] = {0x96, 0x0};
1766 /* NB: This SJIS character is correct, but produces bad spacing if used */
1767 /* static const char minus_sjis[4] = {0x81, 0x7c, 0x0, 0x0}; */
1768 switch (encoding) {
1769 case S_ENC_UTF8: return minus_utf8;
1770 case S_ENC_CP1252: return minus_1252;
1771 case S_ENC_SJIS:
1772 default: return NULL;
1773 }
1774 }
1775
1776
1777 void
init_special_chars(void)1778 init_special_chars(void)
1779 {
1780 /* Set degree sign to match encoding */
1781 char * l = NULL;
1782 #ifdef HAVE_LOCALE_H
1783 l = setlocale(LC_CTYPE, "");
1784 #endif
1785 set_degreesign(l);
1786
1787 /* Set minus sign to match encoding */
1788 minus_sign = encoding_minus();
1789
1790 /* Set micro character to match encoding */
1791 micro = encoding_micro();
1792 }
1793
1794
1795 /* process 'set fit' command */
1796 static void
set_fit()1797 set_fit()
1798 {
1799 c_token++;
1800
1801 while (!END_OF_COMMAND) {
1802 if (almost_equals(c_token, "log$file")) {
1803 char *tmp;
1804
1805 c_token++;
1806 fit_suppress_log = FALSE;
1807 if (END_OF_COMMAND) {
1808 free(fitlogfile);
1809 fitlogfile = NULL;
1810 } else if (equals(c_token, "default")) {
1811 c_token++;
1812 free(fitlogfile);
1813 fitlogfile = NULL;
1814 } else if ((tmp = try_to_get_string()) != NULL) {
1815 free(fitlogfile);
1816 fitlogfile = tmp;
1817 } else {
1818 int_error(c_token, "expecting string");
1819 }
1820 } else if (almost_equals(c_token, "nolog$file")) {
1821 fit_suppress_log = TRUE;
1822 c_token++;
1823 } else if (almost_equals(c_token, "err$orvariables")) {
1824 fit_errorvariables = TRUE;
1825 c_token++;
1826 } else if (almost_equals(c_token, "noerr$orvariables")) {
1827 fit_errorvariables = FALSE;
1828 c_token++;
1829 } else if (almost_equals(c_token, "cov$ariancevariables")) {
1830 fit_covarvariables = TRUE;
1831 c_token++;
1832 } else if (almost_equals(c_token, "nocov$ariancevariables")) {
1833 fit_covarvariables = FALSE;
1834 c_token++;
1835 } else if (almost_equals(c_token, "errors$caling")) {
1836 fit_errorscaling = TRUE;
1837 c_token++;
1838 } else if (almost_equals(c_token, "noerrors$caling")) {
1839 fit_errorscaling = FALSE;
1840 c_token++;
1841 } else if (equals(c_token, "quiet")) {
1842 fit_verbosity = QUIET;
1843 c_token++;
1844 } else if (equals(c_token, "noquiet")) {
1845 fit_verbosity = BRIEF;
1846 c_token++;
1847 } else if (equals(c_token, "results")) {
1848 fit_verbosity = RESULTS;
1849 c_token++;
1850 } else if (equals(c_token, "brief")) {
1851 fit_verbosity = BRIEF;
1852 c_token++;
1853 } else if (equals(c_token, "verbose")) {
1854 fit_verbosity = VERBOSE;
1855 c_token++;
1856 } else if (equals(c_token, "prescale")) {
1857 fit_prescale = TRUE;
1858 c_token++;
1859 } else if (equals(c_token, "noprescale")) {
1860 fit_prescale = FALSE;
1861 c_token++;
1862 } else if (equals(c_token, "limit")) {
1863 /* preserve compatibility with FIT_LIMIT user variable */
1864 struct udvt_entry *v;
1865 double value;
1866
1867 c_token++;
1868 if (equals(c_token, "default")) {
1869 c_token++;
1870 value = 0.;
1871 } else
1872 value = real_expression();
1873 if ((value > 0.) && (value < 1.)) {
1874 v = add_udv_by_name((char *)FITLIMIT);
1875 Gcomplex(&v->udv_value, value, 0);
1876 } else {
1877 del_udv_by_name((char *)FITLIMIT, FALSE);
1878 }
1879 } else if (equals(c_token, "limit_abs")) {
1880 double value;
1881 c_token++;
1882 value = real_expression();
1883 epsilon_abs = (value > 0.) ? value : 0.;
1884 } else if (equals(c_token, "maxiter")) {
1885 /* preserve compatibility with FIT_MAXITER user variable */
1886 struct udvt_entry *v;
1887 int maxiter;
1888
1889 c_token++;
1890 if (equals(c_token, "default")) {
1891 c_token++;
1892 maxiter = 0;
1893 } else
1894 maxiter = int_expression();
1895 if (maxiter > 0) {
1896 v = add_udv_by_name((char *)FITMAXITER);
1897 Ginteger(&v->udv_value, maxiter);
1898 } else {
1899 del_udv_by_name((char *)FITMAXITER, FALSE);
1900 }
1901 } else if (equals(c_token, "start_lambda")) {
1902 /* preserve compatibility with FIT_START_LAMBDA user variable */
1903 struct udvt_entry *v;
1904 double value;
1905
1906 c_token++;
1907 if (equals(c_token, "default")) {
1908 c_token++;
1909 value = 0.;
1910 } else
1911 value = real_expression();
1912 if (value > 0.) {
1913 v = add_udv_by_name((char *)FITSTARTLAMBDA);
1914 Gcomplex(&v->udv_value, value, 0);
1915 } else {
1916 del_udv_by_name((char *)FITSTARTLAMBDA, FALSE);
1917 }
1918 } else if (equals(c_token, "lambda_factor")) {
1919 /* preserve compatibility with FIT_LAMBDA_FACTOR user variable */
1920 struct udvt_entry *v;
1921 double value;
1922
1923 c_token++;
1924 if (equals(c_token, "default")) {
1925 c_token++;
1926 value = 0.;
1927 } else
1928 value = real_expression();
1929 if (value > 0.) {
1930 v = add_udv_by_name((char *)FITLAMBDAFACTOR);
1931 Gcomplex(&v->udv_value, value, 0);
1932 } else {
1933 del_udv_by_name((char *)FITLAMBDAFACTOR, FALSE);
1934 }
1935 } else if (equals(c_token, "script")) {
1936 char *tmp;
1937
1938 c_token++;
1939 if (END_OF_COMMAND) {
1940 free(fit_script);
1941 fit_script = NULL;
1942 } else if (equals(c_token, "default")) {
1943 c_token++;
1944 free(fit_script);
1945 fit_script = NULL;
1946 } else if ((tmp = try_to_get_string())) {
1947 free(fit_script);
1948 fit_script = tmp;
1949 } else {
1950 int_error(c_token, "expecting string");
1951 }
1952 } else if (equals(c_token, "wrap")) {
1953 c_token++;
1954 fit_wrap = int_expression();
1955 if (fit_wrap < 0) fit_wrap = 0;
1956 } else if (equals(c_token, "nowrap")) {
1957 c_token++;
1958 fit_wrap = 0;
1959 } else if (equals(c_token, "v4")) {
1960 c_token++;
1961 fit_v4compatible = TRUE;
1962 } else if (equals(c_token, "v5")) {
1963 c_token++;
1964 fit_v4compatible = FALSE;
1965 } else {
1966 int_error(c_token, "unrecognized option --- see `help set fit`");
1967 }
1968 } /* while (!end) */
1969 }
1970
1971
1972 /* process 'set format' command */
1973 void
set_format()1974 set_format()
1975 {
1976 TBOOLEAN set_for_axis[AXIS_ARRAY_SIZE] = AXIS_ARRAY_INITIALIZER(FALSE);
1977 AXIS_INDEX axis;
1978 char *format;
1979 td_type tictype = DT_UNINITIALIZED;
1980
1981 c_token++;
1982 if ((axis = lookup_table(axisname_tbl, c_token)) >= 0) {
1983 set_for_axis[axis] = TRUE;
1984 c_token++;
1985 } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
1986 set_for_axis[FIRST_X_AXIS] = set_for_axis[FIRST_Y_AXIS] = TRUE;
1987 c_token++;
1988 } else {
1989 /* Set all of them */
1990 for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)
1991 set_for_axis[axis] = TRUE;
1992 }
1993
1994 if (END_OF_COMMAND) {
1995 for (axis = FIRST_AXES; axis <= POLAR_AXIS; axis++) {
1996 if (set_for_axis[axis]) {
1997 free(axis_array[axis].formatstring);
1998 axis_array[axis].formatstring = gp_strdup(DEF_FORMAT);
1999 axis_array[axis].tictype = DT_NORMAL;
2000 }
2001 }
2002 return;
2003 }
2004
2005 if (!(format = try_to_get_string()))
2006 int_error(c_token, "expecting format string");
2007
2008 if (almost_equals(c_token,"time$date")) {
2009 tictype = DT_TIMEDATE;
2010 c_token++;
2011 } else if (almost_equals(c_token,"geo$graphic")) {
2012 tictype = DT_DMS;
2013 c_token++;
2014 } else if (almost_equals(c_token,"num$eric")) {
2015 tictype = DT_NORMAL;
2016 c_token++;
2017 }
2018
2019 for (axis = FIRST_AXES; axis <= POLAR_AXIS; axis++) {
2020 if (set_for_axis[axis]) {
2021 free(axis_array[axis].formatstring);
2022 axis_array[axis].formatstring = gp_strdup(format);
2023 if (tictype != DT_UNINITIALIZED)
2024 axis_array[axis].tictype = tictype;
2025 }
2026 }
2027 free(format);
2028 }
2029
2030
2031 /* process 'set grid' command */
2032
2033 static void
set_grid()2034 set_grid()
2035 {
2036 TBOOLEAN explicit_change = FALSE;
2037 c_token++;
2038 #define GRID_MATCH(axis, string) \
2039 if (almost_equals(c_token, string+2)) { \
2040 if (string[2] == 'm') \
2041 axis_array[axis].gridminor = TRUE; \
2042 else \
2043 axis_array[axis].gridmajor = TRUE; \
2044 explicit_change = TRUE; \
2045 ++c_token; \
2046 } else if (almost_equals(c_token, string)) { \
2047 if (string[2] == 'm') \
2048 axis_array[axis].gridminor = FALSE; \
2049 else \
2050 axis_array[axis].gridmajor = FALSE; \
2051 explicit_change = TRUE; \
2052 ++c_token; \
2053 }
2054 while (!END_OF_COMMAND) {
2055 GRID_MATCH(FIRST_X_AXIS, "nox$tics")
2056 else GRID_MATCH(FIRST_Y_AXIS, "noy$tics")
2057 else GRID_MATCH(FIRST_Z_AXIS, "noz$tics")
2058 else GRID_MATCH(SECOND_X_AXIS, "nox2$tics")
2059 else GRID_MATCH(SECOND_Y_AXIS, "noy2$tics")
2060 else GRID_MATCH(FIRST_X_AXIS, "nomx$tics")
2061 else GRID_MATCH(FIRST_Y_AXIS, "nomy$tics")
2062 else GRID_MATCH(FIRST_Z_AXIS, "nomz$tics")
2063 else GRID_MATCH(SECOND_X_AXIS, "nomx2$tics")
2064 else GRID_MATCH(SECOND_Y_AXIS, "nomy2$tics")
2065 else GRID_MATCH(COLOR_AXIS, "nocb$tics")
2066 else GRID_MATCH(COLOR_AXIS, "nomcb$tics")
2067 else GRID_MATCH(POLAR_AXIS, "nor$tics")
2068 else GRID_MATCH(POLAR_AXIS, "nomr$tics")
2069 else if (almost_equals(c_token,"po$lar")) {
2070 /* Dec 2016 - zero or negative disables radial grid lines */
2071 axis_array[POLAR_AXIS].gridmajor = TRUE; /* Enable both circles and radii */
2072 polar_grid_angle = 30*DEG2RAD;
2073 c_token++;
2074 if (might_be_numeric(c_token)) {
2075 double ang = real_expression();
2076 polar_grid_angle = (ang > 2.*M_PI) ? DEG2RAD*ang : ang2rad*ang;
2077 }
2078 } else if (almost_equals(c_token,"nopo$lar")) {
2079 polar_grid_angle = 0; /* not polar grid */
2080 c_token++;
2081 } else if (equals(c_token,"back")) {
2082 grid_layer = LAYER_BACK;
2083 c_token++;
2084 } else if (equals(c_token,"front")) {
2085 grid_layer = LAYER_FRONT;
2086 c_token++;
2087 } else if (almost_equals(c_token,"vert$ical")) {
2088 grid_vertical_lines = TRUE;
2089 c_token++;
2090 } else if (almost_equals(c_token,"novert$ical")) {
2091 grid_vertical_lines = FALSE;
2092 c_token++;
2093 } else if (almost_equals(c_token,"layerd$efault")
2094 || equals(c_token, "behind")) {
2095 grid_layer = LAYER_BEHIND;
2096 c_token++;
2097 } else { /* only remaining possibility is a line type */
2098 int save_token = c_token;
2099 lp_parse(&grid_lp, LP_ADHOC, FALSE);
2100 if (equals(c_token,",")) {
2101 c_token++;
2102 lp_parse(&mgrid_lp, LP_ADHOC, FALSE);
2103 } else if (save_token != c_token)
2104 mgrid_lp = grid_lp;
2105 if (save_token == c_token)
2106 break;
2107 }
2108 }
2109
2110 if (!explicit_change && !some_grid_selected()) {
2111 /* no axis specified, thus select default grid */
2112 if (polar) {
2113 axis_array[POLAR_AXIS].gridmajor = TRUE;
2114 polar_grid_angle = 30.*DEG2RAD;
2115 } else {
2116 axis_array[FIRST_X_AXIS].gridmajor = TRUE;
2117 axis_array[FIRST_Y_AXIS].gridmajor = TRUE;
2118 }
2119 }
2120 }
2121
2122
2123 /* process 'set hidden3d' command */
2124 static void
set_hidden3d()2125 set_hidden3d()
2126 {
2127 c_token++;
2128 set_hidden3doptions();
2129 hidden3d = TRUE;
2130 SET_REFRESH_OK(E_REFRESH_NOT_OK,0);
2131 }
2132
2133
2134 static void
set_history()2135 set_history()
2136 {
2137 c_token++;
2138
2139 while (!END_OF_COMMAND) {
2140 if (equals(c_token, "quiet")) {
2141 c_token++;
2142 history_quiet = TRUE;
2143 continue;
2144 } else if (almost_equals(c_token, "num$bers")) {
2145 c_token++;
2146 history_quiet = FALSE;
2147 continue;
2148 } else if (equals(c_token, "full")) {
2149 c_token++;
2150 history_full = TRUE;
2151 continue;
2152 } else if (equals(c_token, "trim")) {
2153 c_token++;
2154 history_full = FALSE;
2155 continue;
2156 } else if (almost_equals(c_token, "def$ault")) {
2157 c_token++;
2158 history_quiet = FALSE;
2159 history_full = TRUE;
2160 gnuplot_history_size = HISTORY_SIZE;
2161 continue;
2162 } else if (equals(c_token, "size")) {
2163 c_token++;
2164 /* fall through */
2165 }
2166 /* Catches both the deprecated "set historysize" and "set history size" */
2167 gnuplot_history_size = int_expression();
2168 #ifndef GNUPLOT_HISTORY
2169 int_warn(NO_CARET, "This copy of gnuplot was built without support for command history.");
2170 #endif
2171 }
2172 }
2173
2174
2175 /* process 'set isosamples' command */
2176 static void
set_isosamples()2177 set_isosamples()
2178 {
2179 int tsamp1, tsamp2;
2180
2181 c_token++;
2182 tsamp1 = abs(int_expression());
2183 tsamp2 = tsamp1;
2184 if (!END_OF_COMMAND) {
2185 if (!equals(c_token,","))
2186 int_error(c_token, "',' expected");
2187 c_token++;
2188 tsamp2 = abs(int_expression());
2189 }
2190 if (tsamp1 < 2 || tsamp2 < 2)
2191 int_error(c_token, "sampling rate must be > 1; sampling unchanged");
2192 else {
2193 struct curve_points *f_p = first_plot;
2194 struct surface_points *f_3dp = first_3dplot;
2195
2196 first_plot = NULL;
2197 first_3dplot = NULL;
2198 cp_free(f_p);
2199 sp_free(f_3dp);
2200
2201 iso_samples_1 = tsamp1;
2202 iso_samples_2 = tsamp2;
2203 }
2204 }
2205
2206
2207 /* When plotting an external key, the margin and l/r/t/b/c are
2208 used to determine one of twelve possible positions. They must
2209 be defined appropriately in the case where stack direction
2210 determines exact position. */
2211 static void
set_key_position_from_stack_direction(legend_key * key)2212 set_key_position_from_stack_direction(legend_key *key)
2213 {
2214 if (key->stack_dir == GPKEY_VERTICAL) {
2215 switch(key->hpos) {
2216 case LEFT:
2217 key->margin = GPKEY_LMARGIN;
2218 break;
2219 case CENTRE:
2220 if (key->vpos == JUST_TOP)
2221 key->margin = GPKEY_TMARGIN;
2222 else
2223 key->margin = GPKEY_BMARGIN;
2224 break;
2225 case RIGHT:
2226 key->margin = GPKEY_RMARGIN;
2227 break;
2228 }
2229 } else {
2230 switch(key->vpos) {
2231 case JUST_TOP:
2232 key->margin = GPKEY_TMARGIN;
2233 break;
2234 case JUST_CENTRE:
2235 if (key->hpos == LEFT)
2236 key->margin = GPKEY_LMARGIN;
2237 else
2238 key->margin = GPKEY_RMARGIN;
2239 break;
2240 case JUST_BOT:
2241 key->margin = GPKEY_BMARGIN;
2242 break;
2243 }
2244 }
2245 }
2246
2247
2248 /* process 'set key' command */
2249 static void
set_key()2250 set_key()
2251 {
2252 TBOOLEAN vpos_set = FALSE, hpos_set = FALSE, reg_set = FALSE, sdir_set = FALSE;
2253 char *vpos_warn = "Multiple vertical position settings";
2254 char *hpos_warn = "Multiple horizontal position settings";
2255 char *reg_warn = "Multiple location region settings";
2256 char *sdir_warn = "Multiple stack direction settings";
2257 legend_key *key = &keyT;
2258
2259 /* Only for backward compatibility with deprecated "set keytitle foo" */
2260 if (almost_equals(c_token,"keyt$itle"))
2261 goto S_KEYTITLE;
2262
2263 c_token++;
2264 key->visible = TRUE;
2265
2266 while (!END_OF_COMMAND) {
2267 switch(lookup_table(&set_key_tbl[0],c_token)) {
2268 case S_KEY_ON:
2269 key->visible = TRUE;
2270 break;
2271 case S_KEY_OFF:
2272 key->visible = FALSE;
2273 break;
2274 case S_KEY_DEFAULT:
2275 reset_key();
2276 break;
2277 case S_KEY_TOP:
2278 if (vpos_set)
2279 int_warn(c_token, vpos_warn);
2280 key->vpos = JUST_TOP;
2281 vpos_set = TRUE;
2282 break;
2283 case S_KEY_BOTTOM:
2284 if (vpos_set)
2285 int_warn(c_token, vpos_warn);
2286 key->vpos = JUST_BOT;
2287 vpos_set = TRUE;
2288 break;
2289 case S_KEY_LEFT:
2290 if (hpos_set)
2291 int_warn(c_token, hpos_warn);
2292 key->hpos = LEFT;
2293 hpos_set = TRUE;
2294 break;
2295 case S_KEY_RIGHT:
2296 if (hpos_set)
2297 int_warn(c_token, hpos_warn);
2298 key->hpos = RIGHT;
2299 hpos_set = TRUE;
2300 break;
2301 case S_KEY_CENTER:
2302 if (!vpos_set) key->vpos = JUST_CENTRE;
2303 if (!hpos_set) key->hpos = CENTRE;
2304 if (vpos_set || hpos_set)
2305 vpos_set = hpos_set = TRUE;
2306 break;
2307 case S_KEY_VERTICAL:
2308 if (sdir_set)
2309 int_warn(c_token, sdir_warn);
2310 key->stack_dir = GPKEY_VERTICAL;
2311 sdir_set = TRUE;
2312 break;
2313 case S_KEY_HORIZONTAL:
2314 if (sdir_set)
2315 int_warn(c_token, sdir_warn);
2316 key->stack_dir = GPKEY_HORIZONTAL;
2317 sdir_set = TRUE;
2318 break;
2319 case S_KEY_OVER:
2320 if (reg_set)
2321 int_warn(c_token, reg_warn);
2322 /* Fall through */
2323 case S_KEY_ABOVE:
2324 if (!hpos_set)
2325 key->hpos = CENTRE;
2326 if (!sdir_set)
2327 key->stack_dir = GPKEY_HORIZONTAL;
2328 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2329 key->margin = GPKEY_TMARGIN;
2330 reg_set = TRUE;
2331 break;
2332 case S_KEY_UNDER:
2333 if (reg_set)
2334 int_warn(c_token, reg_warn);
2335 /* Fall through */
2336 case S_KEY_BELOW:
2337 if (!hpos_set)
2338 key->hpos = CENTRE;
2339 if (!sdir_set)
2340 key->stack_dir = GPKEY_HORIZONTAL;
2341 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2342 key->margin = GPKEY_BMARGIN;
2343 reg_set = TRUE;
2344 break;
2345 case S_KEY_INSIDE:
2346 if (reg_set)
2347 int_warn(c_token, reg_warn);
2348 key->region = GPKEY_AUTO_INTERIOR_LRTBC;
2349 key->fixed = FALSE;
2350 reg_set = TRUE;
2351 break;
2352 case S_KEY_OUTSIDE:
2353 if (reg_set)
2354 int_warn(c_token, reg_warn);
2355 key->region = GPKEY_AUTO_EXTERIOR_LRTBC;
2356 reg_set = TRUE;
2357 break;
2358 case S_KEY_FIXED:
2359 if (reg_set)
2360 int_warn(c_token, reg_warn);
2361 key->region = GPKEY_AUTO_INTERIOR_LRTBC;
2362 key->fixed = TRUE;
2363 reg_set = TRUE;
2364 break;
2365 case S_KEY_TMARGIN:
2366 if (reg_set)
2367 int_warn(c_token, reg_warn);
2368 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2369 key->margin = GPKEY_TMARGIN;
2370 reg_set = TRUE;
2371 break;
2372 case S_KEY_BMARGIN:
2373 if (reg_set)
2374 int_warn(c_token, reg_warn);
2375 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2376 key->margin = GPKEY_BMARGIN;
2377 reg_set = TRUE;
2378 break;
2379 case S_KEY_LMARGIN:
2380 if (reg_set)
2381 int_warn(c_token, reg_warn);
2382 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2383 key->margin = GPKEY_LMARGIN;
2384 reg_set = TRUE;
2385 break;
2386 case S_KEY_RMARGIN:
2387 if (reg_set)
2388 int_warn(c_token, reg_warn);
2389 key->region = GPKEY_AUTO_EXTERIOR_MARGIN;
2390 key->margin = GPKEY_RMARGIN;
2391 reg_set = TRUE;
2392 break;
2393 case S_KEY_LLEFT:
2394 key->just = GPKEY_LEFT;
2395 break;
2396 case S_KEY_RRIGHT:
2397 key->just = GPKEY_RIGHT;
2398 break;
2399 case S_KEY_REVERSE:
2400 key->reverse = TRUE;
2401 break;
2402 case S_KEY_NOREVERSE:
2403 key->reverse = FALSE;
2404 break;
2405 case S_KEY_INVERT:
2406 key->invert = TRUE;
2407 break;
2408 case S_KEY_NOINVERT:
2409 key->invert = FALSE;
2410 break;
2411 case S_KEY_ENHANCED:
2412 key->enhanced = TRUE;
2413 break;
2414 case S_KEY_NOENHANCED:
2415 key->enhanced = FALSE;
2416 break;
2417 case S_KEY_BOX:
2418 c_token++;
2419 key->box.l_type = LT_BLACK;
2420 if (!END_OF_COMMAND) {
2421 int old_token = c_token;
2422 lp_parse(&key->box, LP_ADHOC, FALSE);
2423 if (old_token == c_token && isanumber(c_token)) {
2424 key->box.l_type = int_expression() - 1;
2425 c_token++;
2426 }
2427 }
2428 c_token--; /* is incremented after loop */
2429 break;
2430 case S_KEY_NOBOX:
2431 key->box.l_type = LT_NODRAW;
2432 break;
2433 case S_KEY_SAMPLEN:
2434 c_token++;
2435 key->swidth = real_expression();
2436 c_token--; /* it is incremented after loop */
2437 break;
2438 case S_KEY_SPACING:
2439 c_token++;
2440 key->vert_factor = real_expression();
2441 if (key->vert_factor < 0.0)
2442 key->vert_factor = 0.0;
2443 c_token--; /* it is incremented after loop */
2444 break;
2445 case S_KEY_WIDTH:
2446 c_token++;
2447 key->width_fix = real_expression();
2448 c_token--; /* it is incremented after loop */
2449 break;
2450 case S_KEY_HEIGHT:
2451 c_token++;
2452 key->height_fix = real_expression();
2453 c_token--; /* it is incremented after loop */
2454 break;
2455 case S_KEY_AUTOTITLES:
2456 if (almost_equals(++c_token, "col$umnheader"))
2457 key->auto_titles = COLUMNHEAD_KEYTITLES;
2458 else {
2459 key->auto_titles = FILENAME_KEYTITLES;
2460 c_token--;
2461 }
2462 break;
2463 case S_KEY_NOAUTOTITLES:
2464 key->auto_titles = NOAUTO_KEYTITLES;
2465 break;
2466 case S_KEY_TITLE:
2467 S_KEYTITLE:
2468 key->title.pos = CENTRE;
2469 set_xyzlabel( &key->title );
2470 c_token--;
2471 break;
2472 case S_KEY_NOTITLE:
2473 free(key->title.text);
2474 key->title.text = NULL;
2475 break;
2476 case S_KEY_FONT:
2477 c_token++;
2478 /* Make sure they've specified a font */
2479 if (!isstringvalue(c_token))
2480 int_error(c_token,"expected font");
2481 else {
2482 char *tmp = try_to_get_string();
2483 if (tmp) {
2484 free(key->font);
2485 key->font = tmp;
2486 }
2487 c_token--;
2488 }
2489 break;
2490 case S_KEY_TEXTCOLOR:
2491 {
2492 struct t_colorspec lcolor = DEFAULT_COLORSPEC;
2493 parse_colorspec(&lcolor, TC_VARIABLE);
2494 /* Only for backwards compatibility */
2495 if (lcolor.type == TC_RGB && lcolor.value == -1.0)
2496 lcolor.type = TC_VARIABLE;
2497 key->textcolor = lcolor;
2498 }
2499 c_token--;
2500 break;
2501 case S_KEY_MAXCOLS:
2502 c_token++;
2503 if (END_OF_COMMAND || almost_equals(c_token, "a$utomatic"))
2504 key->maxcols = 0;
2505 else
2506 key->maxcols = int_expression();
2507 if (key->maxcols < 0)
2508 key->maxcols = 0;
2509 c_token--; /* it is incremented after loop */
2510 break;
2511 case S_KEY_MAXROWS:
2512 c_token++;
2513 if (END_OF_COMMAND || almost_equals(c_token, "a$utomatic"))
2514 key->maxrows = 0;
2515 else
2516 key->maxrows = int_expression();
2517 if (key->maxrows < 0)
2518 key->maxrows = 0;
2519 c_token--; /* it is incremented after loop */
2520 break;
2521
2522 case S_KEY_FRONT:
2523 key->front = TRUE;
2524 break;
2525 case S_KEY_NOFRONT:
2526 key->front = FALSE;
2527 break;
2528
2529 case S_KEY_MANUAL:
2530 c_token++;
2531 if (reg_set)
2532 int_warn(c_token, reg_warn);
2533 get_position(&key->user_pos);
2534 key->region = GPKEY_USER_PLACEMENT;
2535 reg_set = TRUE;
2536 c_token--; /* will be incremented again soon */
2537 break;
2538
2539 case S_KEY_INVALID:
2540 default:
2541 int_error(c_token, "unknown key option");
2542 break;
2543 }
2544 c_token++;
2545 }
2546
2547 if (key->region == GPKEY_AUTO_EXTERIOR_LRTBC)
2548 set_key_position_from_stack_direction(key);
2549 else if (key->region == GPKEY_AUTO_EXTERIOR_MARGIN) {
2550 if (vpos_set && (key->margin == GPKEY_TMARGIN || key->margin == GPKEY_BMARGIN))
2551 int_warn(NO_CARET,
2552 "ignoring top/center/bottom; incompatible with tmargin/bmargin.");
2553 else if (hpos_set && (key->margin == GPKEY_LMARGIN || key->margin == GPKEY_RMARGIN))
2554 int_warn(NO_CARET,
2555 "ignoring left/center/right; incompatible with lmargin/tmargin.");
2556 }
2557 }
2558
2559
2560 /* process 'set label' command */
2561 /* set label {tag} {"label_text"{,<value>{,...}}} {<label options>} */
2562 /* EAM Mar 2003 - option parsing broken out into separate routine */
2563 static void
set_label()2564 set_label()
2565 {
2566 struct text_label *this_label = NULL;
2567 struct text_label *new_label = NULL;
2568 struct text_label *prev_label = NULL;
2569 struct value a;
2570 int save_token;
2571 int tag = -1;
2572
2573 c_token++;
2574 if (END_OF_COMMAND)
2575 return;
2576
2577 /* The first item must be either a tag or the label text */
2578 save_token = c_token;
2579 if (isletter(c_token) && type_udv(c_token) == 0) {
2580 tag = assign_label_tag();
2581 } else {
2582 const_express(&a);
2583 if (a.type == STRING) {
2584 c_token = save_token;
2585 tag = assign_label_tag();
2586 gpfree_string(&a);
2587 } else {
2588 tag = (int) real(&a);
2589 }
2590 }
2591
2592 if (tag <= 0)
2593 int_error(c_token, "tag must be > zero");
2594
2595 if (first_label != NULL) { /* skip to last label */
2596 for (this_label = first_label; this_label != NULL;
2597 prev_label = this_label, this_label = this_label->next)
2598 /* is this the label we want? */
2599 if (tag <= this_label->tag)
2600 break;
2601 }
2602 /* Insert this label into the list if it is a new one */
2603 if (this_label == NULL || tag != this_label->tag) {
2604 new_label = new_text_label(tag);
2605 new_label->offset = default_offset;
2606 if (prev_label == NULL)
2607 first_label = new_label;
2608 else
2609 prev_label->next = new_label;
2610 new_label->next = this_label;
2611 this_label = new_label;
2612 }
2613
2614 if (!END_OF_COMMAND) {
2615 char* text;
2616 parse_label_options(this_label, 0);
2617 text = try_to_get_string();
2618 if (text) {
2619 free(this_label->text);
2620 this_label->text = text;
2621 }
2622
2623 }
2624
2625 /* Now parse the label format and style options */
2626 parse_label_options(this_label, 0);
2627 }
2628
2629
2630 /* assign a new label tag
2631 * labels are kept sorted by tag number, so this is easy
2632 * returns the lowest unassigned tag number
2633 */
2634 static int
assign_label_tag()2635 assign_label_tag()
2636 {
2637 struct text_label *this_label;
2638 int last = 0; /* previous tag value */
2639
2640 for (this_label = first_label; this_label != NULL;
2641 this_label = this_label->next)
2642 if (this_label->tag == last + 1)
2643 last++;
2644 else
2645 break;
2646
2647 return (last + 1);
2648 }
2649
2650
2651 /* process 'set loadpath' command */
2652 static void
set_loadpath()2653 set_loadpath()
2654 {
2655 /* We pick up all loadpath elements here before passing
2656 * them on to set_var_loadpath()
2657 */
2658 char *collect = NULL;
2659
2660 c_token++;
2661 if (END_OF_COMMAND) {
2662 clear_loadpath();
2663 } else while (!END_OF_COMMAND) {
2664 char *ss;
2665 if ((ss = try_to_get_string())) {
2666 int len = (collect? strlen(collect) : 0);
2667 gp_expand_tilde(&ss);
2668 collect = gp_realloc(collect, len+1+strlen(ss)+1, "tmp loadpath");
2669 if (len != 0) {
2670 strcpy(collect+len+1,ss);
2671 *(collect+len) = PATHSEP;
2672 }
2673 else
2674 strcpy(collect,ss);
2675 free(ss);
2676 } else {
2677 int_error(c_token, "expected string");
2678 }
2679 }
2680 if (collect) {
2681 set_var_loadpath(collect);
2682 free(collect);
2683 }
2684 }
2685
2686
2687 /* process 'set fontpath' command */
2688 static void
set_fontpath()2689 set_fontpath()
2690 {
2691 /* We pick up all fontpath elements here before passing
2692 * them on to set_var_fontpath()
2693 */
2694 char *collect = NULL;
2695
2696 c_token++;
2697 if (END_OF_COMMAND) {
2698 clear_fontpath();
2699 } else while (!END_OF_COMMAND) {
2700 char *ss;
2701 if ((ss = try_to_get_string())) {
2702 int len = (collect? strlen(collect) : 0);
2703 gp_expand_tilde(&ss);
2704 collect = gp_realloc(collect, len+1+strlen(ss)+1, "tmp fontpath");
2705 if (len != 0) {
2706 strcpy(collect+len+1,ss);
2707 *(collect+len) = PATHSEP;
2708 }
2709 else
2710 strcpy(collect,ss);
2711 free(ss);
2712 } else {
2713 int_error(c_token, "expected string");
2714 }
2715 }
2716 if (collect) {
2717 set_var_fontpath(collect);
2718 free(collect);
2719 }
2720 }
2721
2722
2723 /* process 'set locale' command */
2724 static void
set_locale()2725 set_locale()
2726 {
2727 char *s;
2728
2729 c_token++;
2730 if (END_OF_COMMAND) {
2731 init_locale();
2732 } else if ((s = try_to_get_string())) {
2733 set_var_locale(s);
2734 free(s);
2735 } else
2736 int_error(c_token, "expected string");
2737 }
2738
2739
2740 /* process 'set logscale' command */
2741 static void
set_logscale()2742 set_logscale()
2743 {
2744 TBOOLEAN set_for_axis[AXIS_ARRAY_SIZE] = AXIS_ARRAY_INITIALIZER(FALSE);
2745 int axis;
2746 double newbase = 10;
2747 c_token++;
2748
2749 if (END_OF_COMMAND) {
2750 for (axis = 0; axis < POLAR_AXIS; axis++)
2751 set_for_axis[axis] = TRUE;
2752 } else {
2753 /* do reverse search because of "x", "x1", "x2" sequence in axisname_tbl */
2754 int i = 0;
2755 while (i < token[c_token].length) {
2756 axis = lookup_table_nth_reverse(axisname_tbl, NUMBER_OF_MAIN_VISIBLE_AXES,
2757 gp_input_line + token[c_token].start_index + i);
2758 if (axis < 0) {
2759 token[c_token].start_index += i;
2760 int_error(c_token, "invalid axis");
2761 }
2762 set_for_axis[axisname_tbl[axis].value] = TRUE;
2763 i += strlen(axisname_tbl[axis].key);
2764 }
2765 c_token++;
2766
2767 if (!END_OF_COMMAND) {
2768 newbase = fabs(real_expression());
2769 if (newbase <= 1.0)
2770 int_error(c_token,
2771 "log base must be > 1.0; logscale unchanged");
2772 }
2773 }
2774
2775 #if defined(NONLINEAR_AXES) && (NONLINEAR_AXES > 0)
2776 for (axis = 0; axis < NUMBER_OF_MAIN_VISIBLE_AXES; axis++) {
2777 if (set_for_axis[axis]) {
2778 static char command[128];
2779 char *dummy;
2780 if (!isalpha(axis_name(axis)[0]))
2781 continue;
2782 switch (axis) {
2783 case FIRST_Y_AXIS:
2784 case SECOND_Y_AXIS:
2785 dummy = "y"; break;
2786 case FIRST_Z_AXIS:
2787 case COLOR_AXIS:
2788 dummy = "z"; break;
2789 case POLAR_AXIS:
2790 dummy = "r"; break;
2791 default:
2792 dummy = "x"; break;
2793 }
2794
2795 /* Avoid a warning message triggered by default axis range [-10:10] */
2796 if (axis_array[axis].set_min <= 0 && axis_array[axis].set_max > 0)
2797 axis_array[axis].set_min = 0.1;
2798
2799 /* Also forgive negative axis limits if we are currently autoscaling */
2800 if ((axis_array[axis].set_autoscale != AUTOSCALE_NONE)
2801 && (axis_array[axis].set_min <= 0 || axis_array[axis].set_max <= 0)) {
2802 axis_array[axis].set_min = 0.1;
2803 axis_array[axis].set_max = 10.;
2804 }
2805
2806 if (newbase == 10.) {
2807 sprintf(command, "set nonlinear %s via log10(%s) inv 10**%s",
2808 axis_name(axis), dummy, dummy);
2809 } else {
2810 sprintf(command, "set nonlinear %s via log(%s)/log(%g) inv (%g)**%s",
2811 axis_name(axis), dummy, newbase, newbase, dummy);
2812 }
2813 do_string(command);
2814 axis_array[axis].ticdef.logscaling = TRUE;
2815 axis_array[axis].base = newbase;
2816 axis_array[axis].log_base = log(newbase);
2817 axis_array[axis].linked_to_primary->base = newbase;
2818 axis_array[axis].linked_to_primary->log_base = log(newbase);
2819
2820 /* do_string("set nonlinear") cleared the log flags */
2821 axis_array[axis].log = TRUE;
2822 axis_array[axis].linked_to_primary->log = TRUE;
2823 }
2824 }
2825
2826 #else
2827 for (axis = 0; axis < NUMBER_OF_MAIN_VISIBLE_AXES; axis++) {
2828 if (set_for_axis[axis]) {
2829 axis_array[axis].log = TRUE;
2830 axis_array[axis].base = newbase;
2831 axis_array[axis].log_base = log(newbase);
2832 if ((axis == POLAR_AXIS) && polar)
2833 rrange_to_xy();
2834 }
2835 }
2836
2837 /* Because the log scaling is applied during data input, a quick refresh */
2838 /* using existing stored data will not work if the log setting changes. */
2839 SET_REFRESH_OK(E_REFRESH_NOT_OK, 0);
2840 #endif
2841
2842 }
2843
2844 /* process 'set mapping3d' command */
2845 static void
set_mapping()2846 set_mapping()
2847 {
2848 c_token++;
2849 if (END_OF_COMMAND)
2850 /* assuming same as points */
2851 mapping3d = MAP3D_CARTESIAN;
2852 else if (almost_equals(c_token, "ca$rtesian"))
2853 mapping3d = MAP3D_CARTESIAN;
2854 else if (almost_equals(c_token, "s$pherical"))
2855 mapping3d = MAP3D_SPHERICAL;
2856 else if (almost_equals(c_token, "cy$lindrical"))
2857 mapping3d = MAP3D_CYLINDRICAL;
2858 else
2859 int_error(c_token,
2860 "expecting 'cartesian', 'spherical', or 'cylindrical'");
2861 c_token++;
2862 }
2863
2864
2865 /* process 'set {blrt}margin' command */
2866 static void
set_margin(t_position * margin)2867 set_margin(t_position *margin)
2868 {
2869 margin->scalex = character;
2870 margin->x = -1;
2871 c_token++;
2872
2873 if (END_OF_COMMAND)
2874 return;
2875
2876 if (equals(c_token,"at") && !almost_equals(++c_token,"sc$reen"))
2877 int_error(c_token,"expecting 'screen <fraction>'");
2878 if (almost_equals(c_token,"sc$reen")) {
2879 margin->scalex = screen;
2880 c_token++;
2881 }
2882
2883 margin->x = real_expression();
2884 if (margin->x < 0)
2885 margin->x = -1;
2886
2887 if (margin->scalex == screen) {
2888 if (margin->x < 0)
2889 margin->x = 0;
2890 if (margin->x > 1)
2891 margin->x = 1;
2892 }
2893
2894 }
2895
2896 /* process 'set micro' command */
2897 static void
set_micro()2898 set_micro()
2899 {
2900 c_token++;
2901 use_micro = TRUE;
2902 }
2903
2904 /* process 'set minus_sign' command */
2905 static void
set_minus_sign()2906 set_minus_sign()
2907 {
2908 c_token++;
2909 use_minus_sign = TRUE;
2910 }
2911
2912 static void
set_separator(char ** xx_separators)2913 set_separator(char **xx_separators)
2914 {
2915 c_token++;
2916 free(*xx_separators);
2917 *xx_separators = NULL;
2918
2919 if (END_OF_COMMAND)
2920 return;
2921
2922 if (almost_equals(c_token, "white$space")) {
2923 c_token++;
2924 } else if (equals(c_token, "comma")) {
2925 *xx_separators = gp_strdup(",");
2926 c_token++;
2927 } else if (equals(c_token, "tab") || equals(c_token, "\'\\t\'")) {
2928 *xx_separators = gp_strdup("\t");
2929 c_token++;
2930 } else if (!(*xx_separators = try_to_get_string())) {
2931 int_error(c_token, "expected \"<separator_char>\"");
2932 }
2933 }
2934
2935 static void
set_datafile_commentschars()2936 set_datafile_commentschars()
2937 {
2938 char *s;
2939
2940 c_token++;
2941
2942 if (END_OF_COMMAND) {
2943 free(df_commentschars);
2944 df_commentschars = gp_strdup(DEFAULT_COMMENTS_CHARS);
2945 } else if ((s = try_to_get_string())) {
2946 free(df_commentschars);
2947 df_commentschars = s;
2948 } else /* Leave it the way it was */
2949 int_error(c_token, "expected string with comments chars");
2950 }
2951
2952 /* process 'set datafile missing' command */
2953 static void
set_missing()2954 set_missing()
2955 {
2956 c_token++;
2957 free(missing_val);
2958 missing_val = NULL;
2959 if (END_OF_COMMAND)
2960 return;
2961 if (equals(c_token,"NaN") || equals(c_token,"nan")) {
2962 missing_val = strdup("NaN");
2963 c_token++;
2964 } else if (!(missing_val = try_to_get_string()))
2965 int_error(c_token, "expected missing-value string");
2966 }
2967
2968 /* (version 5) 'set monochrome' command */
2969 static void
set_monochrome()2970 set_monochrome()
2971 {
2972 monochrome = TRUE;
2973 if (!END_OF_COMMAND)
2974 c_token++;
2975
2976 if (almost_equals(c_token, "def$ault")) {
2977 c_token++;
2978 while (first_mono_linestyle)
2979 delete_linestyle(&first_mono_linestyle, first_mono_linestyle, first_mono_linestyle);
2980 }
2981
2982 init_monochrome();
2983
2984 if (almost_equals(c_token, "linet$ype") || equals(c_token, "lt")) {
2985 /* we can pass this off to the generic "set linetype" code */
2986 if (equals(c_token+1,"cycle")) {
2987 c_token += 2;
2988 mono_recycle_count = int_expression();
2989 } else
2990 set_linestyle(&first_mono_linestyle, LP_TYPE);
2991 }
2992
2993 if (!END_OF_COMMAND)
2994 int_error(c_token, "unrecognized option");
2995 }
2996
2997 static void
set_mouse()2998 set_mouse()
2999 {
3000 #ifdef USE_MOUSE
3001 char *ctmp;
3002
3003 c_token++;
3004 mouse_setting.on = 1;
3005
3006 while (!END_OF_COMMAND) {
3007 if (almost_equals(c_token, "do$ubleclick")) {
3008 ++c_token;
3009 mouse_setting.doubleclick = real_expression();
3010 if (mouse_setting.doubleclick < 0)
3011 mouse_setting.doubleclick = 0;
3012 } else if (almost_equals(c_token, "nodo$ubleclick")) {
3013 mouse_setting.doubleclick = 0; /* double click off */
3014 ++c_token;
3015 } else if (almost_equals(c_token, "zoomco$ordinates")) {
3016 mouse_setting.annotate_zoom_box = 1;
3017 ++c_token;
3018 } else if (almost_equals(c_token, "nozoomco$ordinates")) {
3019 mouse_setting.annotate_zoom_box = 0;
3020 ++c_token;
3021 } else if (almost_equals(c_token, "po$lardistancedeg")) {
3022 mouse_setting.polardistance = 1;
3023 UpdateStatusline();
3024 ++c_token;
3025 } else if (almost_equals(c_token, "polardistancet$an")) {
3026 mouse_setting.polardistance = 2;
3027 UpdateStatusline();
3028 ++c_token;
3029 } else if (almost_equals(c_token, "nopo$lardistance")) {
3030 mouse_setting.polardistance = 0;
3031 UpdateStatusline();
3032 ++c_token;
3033 } else if (almost_equals(c_token, "label$s")) {
3034 mouse_setting.label = 1;
3035 ++c_token;
3036 /* check if the optional argument "<label options>" is present */
3037 if (isstringvalue(c_token) && (ctmp = try_to_get_string())) {
3038 free(mouse_setting.labelopts);
3039 mouse_setting.labelopts = ctmp;
3040 }
3041 } else if (almost_equals(c_token, "nola$bels")) {
3042 mouse_setting.label = 0;
3043 ++c_token;
3044 } else if (almost_equals(c_token, "ve$rbose")) {
3045 mouse_setting.verbose = 1;
3046 ++c_token;
3047 } else if (almost_equals(c_token, "nove$rbose")) {
3048 mouse_setting.verbose = 0;
3049 ++c_token;
3050 } else if (almost_equals(c_token, "zoomju$mp")) {
3051 mouse_setting.warp_pointer = 1;
3052 ++c_token;
3053 } else if (almost_equals(c_token, "nozoomju$mp")) {
3054 mouse_setting.warp_pointer = 0;
3055 ++c_token;
3056 } else if (almost_equals(c_token, "fo$rmat")) {
3057 ++c_token;
3058 if (isstringvalue(c_token) && (ctmp = try_to_get_string())) {
3059 if (mouse_setting.fmt != mouse_fmt_default)
3060 free(mouse_setting.fmt);
3061 mouse_setting.fmt = ctmp;
3062 } else
3063 mouse_setting.fmt = mouse_fmt_default;
3064 } else if (almost_equals(c_token, "mo$useformat")) {
3065 ++c_token;
3066 if (isstringvalue(c_token) && (ctmp = try_to_get_string())) {
3067 free(mouse_alt_string);
3068 mouse_alt_string = ctmp;
3069 if (!strlen(mouse_alt_string)) {
3070 free(mouse_alt_string);
3071 mouse_alt_string = NULL;
3072 if (MOUSE_COORDINATES_ALT == mouse_mode)
3073 mouse_mode = MOUSE_COORDINATES_REAL;
3074 } else {
3075 mouse_mode = MOUSE_COORDINATES_ALT;
3076 }
3077 c_token++;
3078 } else {
3079 int itmp = int_expression();
3080 if (itmp >= MOUSE_COORDINATES_REAL
3081 && itmp <= MOUSE_COORDINATES_ALT) {
3082 if (MOUSE_COORDINATES_ALT == itmp && !mouse_alt_string) {
3083 fprintf(stderr,
3084 "please 'set mouse mouseformat <fmt>' first.\n");
3085 } else {
3086 mouse_mode = itmp;
3087 }
3088 } else {
3089 fprintf(stderr, "should be: %d <= mouseformat <= %d\n",
3090 MOUSE_COORDINATES_REAL, MOUSE_COORDINATES_ALT);
3091 }
3092 }
3093 } else if (almost_equals(c_token, "noru$ler")) {
3094 c_token++;
3095 set_ruler(FALSE, -1, -1);
3096 } else if (almost_equals(c_token, "ru$ler")) {
3097 c_token++;
3098 if (END_OF_COMMAND || !equals(c_token, "at")) {
3099 set_ruler(TRUE, -1, -1);
3100 } else { /* set mouse ruler at ... */
3101 struct position where;
3102 int x, y;
3103 c_token++;
3104 if (END_OF_COMMAND)
3105 int_error(c_token, "expecting ruler coordinates");
3106 get_position(&where);
3107 map_position(&where, &x, &y, "ruler at");
3108 set_ruler(TRUE, (int)x, (int)y);
3109 }
3110 } else if (almost_equals(c_token, "zoomfac$tors")) {
3111 double x = 1.0, y = 1.0;
3112 c_token++;
3113 if (!END_OF_COMMAND) {
3114 x = real_expression();
3115 if (equals(c_token,",")) {
3116 c_token++;
3117 y = real_expression();
3118 }
3119 }
3120 mouse_setting.xmzoom_factor = x;
3121 mouse_setting.ymzoom_factor = y;
3122 } else {
3123 if (!END_OF_COMMAND)
3124 int_error(c_token, "wrong option");
3125 break;
3126 }
3127 }
3128 #ifdef OS2
3129 PM_update_menu_items();
3130 #endif
3131 #else /* USE_MOUSE */
3132 c_token++;
3133 int_warn(NO_CARET, "this copy of gnuplot has no mouse support");
3134 #endif /* USE_MOUSE */
3135 }
3136
3137 /* process 'set offsets' command */
3138 static void
set_offsets()3139 set_offsets()
3140 {
3141 c_token++;
3142 if (END_OF_COMMAND) {
3143 loff.x = roff.x = toff.y = boff.y = 0.0;
3144 return;
3145 }
3146
3147 loff.scalex = first_axes;
3148 if (almost_equals(c_token,"gr$aph")) {
3149 loff.scalex = graph;
3150 c_token++;
3151 }
3152 loff.x = real_expression();
3153 if (!equals(c_token, ","))
3154 return;
3155
3156 roff.scalex = first_axes;
3157 if (almost_equals(++c_token,"gr$aph")) {
3158 roff.scalex = graph;
3159 c_token++;
3160 }
3161 roff.x = real_expression();
3162 if (!equals(c_token, ","))
3163 return;
3164
3165 toff.scaley = first_axes;
3166 if (almost_equals(++c_token,"gr$aph")) {
3167 toff.scaley = graph;
3168 c_token++;
3169 }
3170 toff.y = real_expression();
3171 if (!equals(c_token, ","))
3172 return;
3173
3174 boff.scaley = first_axes;
3175 if (almost_equals(++c_token,"gr$aph")) {
3176 boff.scaley = graph;
3177 c_token++;
3178 }
3179 boff.y = real_expression();
3180 }
3181
3182
3183 /* process 'set origin' command */
3184 static void
set_origin()3185 set_origin()
3186 {
3187 c_token++;
3188 if (END_OF_COMMAND) {
3189 xoffset = 0.0;
3190 yoffset = 0.0;
3191 } else {
3192 xoffset = real_expression();
3193 if (!equals(c_token,","))
3194 int_error(c_token, "',' expected");
3195 c_token++;
3196 yoffset = real_expression();
3197 }
3198 }
3199
3200
3201 /* process 'set output' command */
3202 static void
set_output()3203 set_output()
3204 {
3205 char *testfile;
3206
3207 c_token++;
3208 if (multiplot)
3209 int_error(c_token, "you can't change the output in multiplot mode");
3210
3211 if (END_OF_COMMAND) { /* no file specified */
3212 term_set_output(NULL);
3213 if (outstr) {
3214 free(outstr);
3215 outstr = NULL; /* means STDOUT */
3216 }
3217 } else if ((testfile = try_to_get_string())) {
3218 gp_expand_tilde(&testfile);
3219 term_set_output(testfile);
3220 if (testfile != outstr) {
3221 if (testfile)
3222 free(testfile);
3223 testfile = outstr;
3224 }
3225 /* if we get here then it worked, and outstr now = testfile */
3226 } else
3227 int_error(c_token, "expecting filename");
3228
3229 /* Invalidate previous palette */
3230 invalidate_palette();
3231
3232 }
3233
3234
3235 /* process 'set print' command */
3236 static void
set_print()3237 set_print()
3238 {
3239 TBOOLEAN append_p = FALSE;
3240 char *testfile = NULL;
3241
3242 c_token++;
3243 if (END_OF_COMMAND) { /* no file specified */
3244 print_set_output(NULL, FALSE, append_p);
3245 } else if (equals(c_token, "$") && isletter(c_token + 1)) { /* datablock */
3246 /* NB: has to come first because try_to_get_string will choke on the datablock name */
3247 char * datablock_name = strdup(parse_datablock_name());
3248 if (!END_OF_COMMAND) {
3249 if (equals(c_token, "append")) {
3250 append_p = TRUE;
3251 c_token++;
3252 } else {
3253 int_error(c_token, "expecting keyword \'append\'");
3254 }
3255 }
3256 print_set_output(datablock_name, TRUE, append_p);
3257 } else if ((testfile = try_to_get_string())) { /* file name */
3258 gp_expand_tilde(&testfile);
3259 if (!END_OF_COMMAND) {
3260 if (equals(c_token, "append")) {
3261 append_p = TRUE;
3262 c_token++;
3263 } else {
3264 int_error(c_token, "expecting keyword \'append\'");
3265 }
3266 }
3267 print_set_output(testfile, FALSE, append_p);
3268 } else
3269 int_error(c_token, "expecting filename or datablock");
3270 }
3271
3272 /* process 'set psdir' command */
3273 static void
set_psdir()3274 set_psdir()
3275 {
3276 c_token++;
3277 if (END_OF_COMMAND) { /* no file specified */
3278 free(PS_psdir);
3279 PS_psdir = NULL;
3280 } else if ((PS_psdir = try_to_get_string())) {
3281 gp_expand_tilde(&PS_psdir);
3282 } else
3283 int_error(c_token, "expecting filename");
3284 }
3285
3286 /* process 'set parametric' command */
3287 static void
set_parametric()3288 set_parametric()
3289 {
3290 c_token++;
3291
3292 if (!parametric) {
3293 parametric = TRUE;
3294 if (!polar) { /* already done for polar */
3295 strcpy (set_dummy_var[0], "t");
3296 strcpy (set_dummy_var[1], "y");
3297 if (interactive)
3298 (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
3299 }
3300 }
3301 }
3302
3303
3304 /* is resetting palette enabled?
3305 * note: reset_palette() is disabled within 'test palette'
3306 */
3307 int enable_reset_palette = 1;
3308
3309 /* default settings for palette */
3310 void
reset_palette()3311 reset_palette()
3312 {
3313 if (!enable_reset_palette) return;
3314 free(sm_palette.gradient);
3315 free(sm_palette.color);
3316 free_at(sm_palette.Afunc.at);
3317 free_at(sm_palette.Bfunc.at);
3318 free_at(sm_palette.Cfunc.at);
3319 init_color();
3320 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_NONE;
3321 }
3322
3323
3324
3325 /* Process 'set palette defined' gradient specification */
3326 /* Syntax
3327 * set palette defined --> use default palette
3328 * set palette defined ( <pos1> <colorspec1>, ... , <posN> <colorspecN> )
3329 * <posX> gray value, automatically rescaled to [0, 1]
3330 * <colorspecX> := { "<color_name>" | "<X-style-color>" | <r> <g> <b> }
3331 * <color_name> predefined colors (see below)
3332 * <X-style-color> "#rrggbb" with 2char hex values for red, green, blue
3333 * <r> <g> <b> three values in [0, 1] for red, green and blue
3334 * return 1 if named colors where used, 0 otherwise
3335 */
3336 static int
set_palette_defined()3337 set_palette_defined()
3338 {
3339 double p=0, r=0, g=0, b=0;
3340 int num, named_colors=0;
3341 int actual_size=8;
3342
3343 /* Invalidate previous gradient */
3344 invalidate_palette();
3345
3346 free( sm_palette.gradient );
3347 sm_palette.gradient = gp_alloc( actual_size*sizeof(gradient_struct), "pm3d gradient" );
3348 sm_palette.smallest_gradient_interval = 1;
3349
3350 if (END_OF_COMMAND) {
3351 /* lets use some default gradient */
3352 double pal[][4] = { {0.0, 0.05, 0.05, 0.2}, {0.1, 0, 0, 1},
3353 {0.25, 0.7, 0.85, 0.9}, {0.4, 0, 0.75, 0},
3354 {0.5, 1, 1, 0}, {0.7, 1, 0, 0},
3355 {0.9, 0.6, 0.6, 0.6}, {1.0, 0.95, 0.95, 0.95} };
3356 int i;
3357 for (i=0; i<8; i++) {
3358 sm_palette.gradient[i].pos = pal[i][0];
3359 sm_palette.gradient[i].col.r = pal[i][1];
3360 sm_palette.gradient[i].col.g = pal[i][2];
3361 sm_palette.gradient[i].col.b = pal[i][3];
3362 }
3363 sm_palette.gradient_num = 8;
3364 sm_palette.cmodel = C_MODEL_RGB;
3365 sm_palette.smallest_gradient_interval = 0.1; /* From pal[][] */
3366 c_token--; /* Caller will increment! */
3367 return 0;
3368 }
3369
3370 if ( !equals(c_token,"(") )
3371 int_error( c_token, "expected ( to start gradient definition" );
3372
3373 ++c_token;
3374 num = -1;
3375
3376 while (!END_OF_COMMAND) {
3377 char *col_str;
3378 p = real_expression();
3379 col_str = try_to_get_string();
3380 if (col_str) {
3381 /* either color name or X-style rgb value "#rrggbb" */
3382 if (col_str[0] == '#' || col_str[0] == '0') {
3383 /* X-style specifier */
3384 int rr,gg,bb;
3385 if ((sscanf( col_str, "#%2x%2x%2x", &rr, &gg, &bb ) != 3 )
3386 && (sscanf( col_str, "0x%2x%2x%2x", &rr, &gg, &bb ) != 3 ))
3387 int_error( c_token-1,
3388 "Unknown color specifier. Use '#RRGGBB' of '0xRRGGBB'." );
3389 r = (double)(rr)/255.;
3390 g = (double)(gg)/255.;
3391 b = (double)(bb)/255.;
3392 }
3393 else { /* some predefined names */
3394 /* Maybe we could scan the X11 rgb.txt file to look up color
3395 * names? Or at least move these definitions to some file
3396 * which is included somehow during compilation instead
3397 * hardcoding them. */
3398 /* Can't use lookupt_table() as it works for tokens only,
3399 so we'll do it manually */
3400 const struct gen_table *tbl = pm3d_color_names_tbl;
3401 while (tbl->key) {
3402 if (!strcmp(col_str, tbl->key)) {
3403 r = (double)((tbl->value >> 16 ) & 255) / 255.;
3404 g = (double)((tbl->value >> 8 ) & 255) / 255.;
3405 b = (double)(tbl->value & 255) / 255.;
3406 break;
3407 }
3408 tbl++;
3409 }
3410 if (!tbl->key)
3411 int_error( c_token-1, "Unknown color name." );
3412 named_colors = 1;
3413 }
3414 free(col_str);
3415 } else {
3416 /* numerical rgb, hsv, xyz, ... values [0,1] */
3417 r = real_expression();
3418 if (r<0 || r>1 ) int_error(c_token-1,"Value out of range [0,1].");
3419 g = real_expression();
3420 if (g<0 || g>1 ) int_error(c_token-1,"Value out of range [0,1].");
3421 b = real_expression();
3422 if (b<0 || b>1 ) int_error(c_token-1,"Value out of range [0,1].");
3423 }
3424 ++num;
3425
3426 if ( num >= actual_size ) {
3427 /* get more space for the gradient */
3428 actual_size += 10;
3429 sm_palette.gradient = gp_realloc( sm_palette.gradient,
3430 actual_size*sizeof(gradient_struct),
3431 "pm3d gradient" );
3432 }
3433 sm_palette.gradient[num].pos = p;
3434 sm_palette.gradient[num].col.r = r;
3435 sm_palette.gradient[num].col.g = g;
3436 sm_palette.gradient[num].col.b = b;
3437 if (equals(c_token,")") ) break;
3438 if ( !equals(c_token,",") )
3439 int_error( c_token, "expected comma" );
3440 ++c_token;
3441
3442 }
3443
3444 sm_palette.gradient_num = num + 1;
3445 check_palette_grayscale();
3446
3447 return named_colors;
3448 }
3449
3450
3451 /* process 'set palette file' command
3452 * load a palette from file, honor datafile modifiers
3453 */
3454 static void
set_palette_file()3455 set_palette_file()
3456 {
3457 int specs;
3458 double v[4];
3459 int i, j, actual_size;
3460 char *file_name;
3461
3462 ++c_token;
3463
3464 /* get filename */
3465 if (!(file_name = try_to_get_string()))
3466 int_error(c_token, "missing filename");
3467
3468 df_set_plot_mode(MODE_QUERY); /* Needed only for binary datafiles */
3469 specs = df_open(file_name, 4, NULL);
3470 free(file_name);
3471
3472 if (specs > 0 && specs < 3)
3473 int_error( c_token, "Less than 3 using specs for palette");
3474
3475 if (sm_palette.gradient) {
3476 free( sm_palette.gradient );
3477 sm_palette.gradient = 0;
3478 }
3479 actual_size = 10;
3480 sm_palette.gradient =
3481 gp_alloc( actual_size*sizeof(gradient_struct), "gradient" );
3482
3483 i = 0;
3484
3485 /* values are simply clipped to [0,1] without notice */
3486 while ((j = df_readline(v, 4)) != DF_EOF) {
3487 if (i >= actual_size) {
3488 actual_size += 10;
3489 sm_palette.gradient = (gradient_struct*)
3490 gp_realloc( sm_palette.gradient,
3491 actual_size*sizeof(gradient_struct),
3492 "pm3d gradient" );
3493 }
3494 switch (j) {
3495 case 3:
3496 sm_palette.gradient[i].col.r = clip_to_01(v[0]);
3497 sm_palette.gradient[i].col.g = clip_to_01(v[1]);
3498 sm_palette.gradient[i].col.b = clip_to_01(v[2]);
3499 sm_palette.gradient[i].pos = i ;
3500 break;
3501 case 4:
3502 sm_palette.gradient[i].col.r = clip_to_01(v[1]);
3503 sm_palette.gradient[i].col.g = clip_to_01(v[2]);
3504 sm_palette.gradient[i].col.b = clip_to_01(v[3]);
3505 sm_palette.gradient[i].pos = v[0];
3506 break;
3507 default:
3508 df_close();
3509 int_error(c_token, "Bad data on line %d", df_line_number);
3510 break;
3511 }
3512 ++i;
3513 }
3514 df_close();
3515 if (i==0)
3516 int_error( c_token, "No valid palette found" );
3517
3518 sm_palette.gradient_num = i;
3519 check_palette_grayscale();
3520
3521 }
3522
3523
3524 /* Process a 'set palette function' command.
3525 * Three functions with fixed dummy variable gray are registered which
3526 * map gray to the different color components.
3527 * If ALLOW_DUMMY_VAR_FOR_GRAY is set:
3528 * A different dummy variable may proceed the formulae in quotes.
3529 * This syntax is different from the usual '[u=<start>:<end>]', but
3530 * as <start> and <end> are fixed to 0 and 1 you would have to type
3531 * always '[u=]' which looks strange, especially as just '[u]'
3532 * wouldn't work.
3533 * If unset: dummy variable is fixed to 'gray'.
3534 */
3535 static void
set_palette_function()3536 set_palette_function()
3537 {
3538 int start_token;
3539 char saved_dummy_var[MAX_ID_LEN+1];
3540
3541 ++c_token;
3542 strncpy( saved_dummy_var, c_dummy_var[0], MAX_ID_LEN );
3543
3544 /* set dummy variable */
3545 #ifdef ALLOW_DUMMY_VAR_FOR_GRAY
3546 if (isstring(c_token)) {
3547 quote_str( c_dummy_var[0], c_token, MAX_ID_LEN );
3548 ++c_token;
3549 }
3550 else
3551 #endif /* ALLOW_DUMMY_VAR_FOR_GRAY */
3552 strncpy( c_dummy_var[0], "gray", MAX_ID_LEN );
3553
3554
3555 /* Afunc */
3556 start_token = c_token;
3557 if (sm_palette.Afunc.at) {
3558 free_at( sm_palette.Afunc.at );
3559 sm_palette.Afunc.at = NULL;
3560 }
3561 dummy_func = &sm_palette.Afunc;
3562 sm_palette.Afunc.at = perm_at();
3563 if (! sm_palette.Afunc.at)
3564 int_error(start_token, "not enough memory for function");
3565 m_capture(&(sm_palette.Afunc.definition), start_token, c_token-1);
3566 dummy_func = NULL;
3567 if (!equals(c_token,","))
3568 int_error(c_token,"expected comma" );
3569 ++c_token;
3570
3571 /* Bfunc */
3572 start_token = c_token;
3573 if (sm_palette.Bfunc.at) {
3574 free_at( sm_palette.Bfunc.at );
3575 sm_palette.Bfunc.at = NULL;
3576 }
3577 dummy_func = &sm_palette.Bfunc;
3578 sm_palette.Bfunc.at = perm_at();
3579 if (! sm_palette.Bfunc.at)
3580 int_error(start_token, "not enough memory for function");
3581 m_capture(&(sm_palette.Bfunc.definition), start_token, c_token-1);
3582 dummy_func = NULL;
3583 if (!equals(c_token,","))
3584 int_error(c_token,"expected comma" );
3585 ++c_token;
3586
3587 /* Cfunc */
3588 start_token = c_token;
3589 if (sm_palette.Cfunc.at) {
3590 free_at( sm_palette.Cfunc.at );
3591 sm_palette.Cfunc.at = NULL;
3592 }
3593 dummy_func = &sm_palette.Cfunc;
3594 sm_palette.Cfunc.at = perm_at();
3595 if (! sm_palette.Cfunc.at)
3596 int_error(start_token, "not enough memory for function");
3597 m_capture(&(sm_palette.Cfunc.definition), start_token, c_token-1);
3598 dummy_func = NULL;
3599
3600 strncpy( c_dummy_var[0], saved_dummy_var, MAX_ID_LEN );
3601 }
3602
3603
3604 /*
3605 * Normalize gray scale of gradient to fill [0,1] and
3606 * complain if gray values are not strictly increasing.
3607 * Maybe automatic sorting of the gray values could be a
3608 * feature.
3609 */
3610 static void
check_palette_grayscale()3611 check_palette_grayscale()
3612 {
3613 int i;
3614 double off, f;
3615 gradient_struct *gradient = sm_palette.gradient;
3616
3617 /* check if gray values are sorted */
3618 for (i=0; i<sm_palette.gradient_num-1; ++i ) {
3619 if (gradient[i].pos > gradient[i+1].pos) {
3620 int_error( c_token, "Gray scale not sorted in gradient." );
3621 }
3622 }
3623
3624 /* fit gray axis into [0:1]: subtract offset and rescale */
3625 off = gradient[0].pos;
3626 f = 1.0 / ( gradient[sm_palette.gradient_num-1].pos-off );
3627 for (i=1; i<sm_palette.gradient_num-1; ++i ) {
3628 gradient[i].pos = f*(gradient[i].pos-off);
3629 }
3630
3631 /* paranoia on the first and last entries */
3632 gradient[0].pos = 0.0;
3633 gradient[sm_palette.gradient_num-1].pos = 1.0;
3634
3635 /* save smallest interval */
3636 sm_palette.smallest_gradient_interval = 1.0;
3637 for (i=1; i<sm_palette.gradient_num-1; ++i ) {
3638 if (((gradient[i].pos - gradient[i-1].pos) > 0)
3639 && (sm_palette.smallest_gradient_interval > (gradient[i].pos - gradient[i-1].pos)))
3640 sm_palette.smallest_gradient_interval = (gradient[i].pos - gradient[i-1].pos);
3641 }
3642 }
3643
3644 #define CHECK_TRANSFORM do { \
3645 if (transform_defined) \
3646 int_error(c_token, "inconsistent palette options" ); \
3647 transform_defined = 1; \
3648 } while(0)
3649
3650 /* Process 'set palette' command */
3651 static void
set_palette()3652 set_palette()
3653 {
3654 int transform_defined = 0;
3655 int named_color = 0;
3656
3657 c_token++;
3658
3659 if (END_OF_COMMAND) /* reset to default settings */
3660 reset_palette();
3661 else { /* go through all options of 'set palette' */
3662 for ( ; !END_OF_COMMAND; c_token++ ) {
3663 switch (lookup_table(&set_palette_tbl[0],c_token)) {
3664 /* positive and negative picture */
3665 case S_PALETTE_POSITIVE: /* "pos$itive" */
3666 sm_palette.positive = SMPAL_POSITIVE;
3667 continue;
3668 case S_PALETTE_NEGATIVE: /* "neg$ative" */
3669 sm_palette.positive = SMPAL_NEGATIVE;
3670 continue;
3671 /* Now the options that determine the palette of smooth colours */
3672 /* gray or rgb-coloured */
3673 case S_PALETTE_GRAY: /* "gray" */
3674 sm_palette.colorMode = SMPAL_COLOR_MODE_GRAY;
3675 continue;
3676 case S_PALETTE_GAMMA: /* "gamma" */
3677 ++c_token;
3678 sm_palette.gamma = real_expression();
3679 --c_token;
3680 continue;
3681 case S_PALETTE_COLOR: /* "col$or" */
3682 if (pm3d_last_set_palette_mode != SMPAL_COLOR_MODE_NONE) {
3683 sm_palette.colorMode = pm3d_last_set_palette_mode;
3684 } else {
3685 sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
3686 }
3687 continue;
3688 /* rgb color mapping formulae: rgb$formulae r,g,b (3 integers) */
3689 case S_PALETTE_RGBFORMULAE: { /* "rgb$formulae" */
3690 int i;
3691 char * formerr = "color formula out of range (use `show palette rgbformulae' to display the range)";
3692
3693 CHECK_TRANSFORM;
3694 c_token++;
3695 i = int_expression();
3696 if (abs(i) >= sm_palette.colorFormulae)
3697 int_error(c_token, formerr);
3698 sm_palette.formulaR = i;
3699 if (!equals(c_token--,","))
3700 continue;
3701 c_token += 2;
3702 i = int_expression();
3703 if (abs(i) >= sm_palette.colorFormulae)
3704 int_error(c_token, formerr);
3705 sm_palette.formulaG = i;
3706 if (!equals(c_token--,","))
3707 continue;
3708 c_token += 2;
3709 i = int_expression();
3710 if (abs(i) >= sm_palette.colorFormulae)
3711 int_error(c_token, formerr);
3712 sm_palette.formulaB = i;
3713 c_token--;
3714 sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
3715 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_RGB;
3716 continue;
3717 } /* rgbformulae */
3718 /* rgb color mapping based on the "cubehelix" scheme proposed by */
3719 /* D A Green (2011) http://arxiv.org/abs/1108.5083 */
3720 case S_PALETTE_CUBEHELIX: { /* cubehelix */
3721 TBOOLEAN done = FALSE;
3722 CHECK_TRANSFORM;
3723 sm_palette.colorMode = SMPAL_COLOR_MODE_CUBEHELIX;
3724 sm_palette.cubehelix_start = 0.5;
3725 sm_palette.cubehelix_cycles = -1.5;
3726 sm_palette.cubehelix_saturation = 1.0;
3727 c_token++;
3728 do {
3729 if (equals(c_token,"start")) {
3730 c_token++;
3731 sm_palette.cubehelix_start = real_expression();
3732 }
3733 else if (almost_equals(c_token,"cyc$les")) {
3734 c_token++;
3735 sm_palette.cubehelix_cycles = real_expression();
3736 }
3737 else if (almost_equals(c_token, "sat$uration")) {
3738 c_token++;
3739 sm_palette.cubehelix_saturation = real_expression();
3740 }
3741 else
3742 done = TRUE;
3743 } while (!done);
3744 --c_token;
3745 continue;
3746 } /* cubehelix */
3747 case S_PALETTE_DEFINED: { /* "def$ine" */
3748 CHECK_TRANSFORM;
3749 ++c_token;
3750 named_color = set_palette_defined();
3751 sm_palette.colorMode = SMPAL_COLOR_MODE_GRADIENT;
3752 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_GRADIENT;
3753 continue;
3754 }
3755 case S_PALETTE_FILE: { /* "file" */
3756 CHECK_TRANSFORM;
3757 set_palette_file();
3758 sm_palette.colorMode = SMPAL_COLOR_MODE_GRADIENT;
3759 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_GRADIENT;
3760 --c_token;
3761 continue;
3762 }
3763 case S_PALETTE_FUNCTIONS: { /* "func$tions" */
3764 CHECK_TRANSFORM;
3765 set_palette_function();
3766 sm_palette.colorMode = SMPAL_COLOR_MODE_FUNCTIONS;
3767 pm3d_last_set_palette_mode = SMPAL_COLOR_MODE_FUNCTIONS;
3768 --c_token;
3769 continue;
3770 }
3771 case S_PALETTE_MODEL: { /* "mo$del" */
3772 int model;
3773 ++c_token;
3774 if (END_OF_COMMAND)
3775 int_error( c_token, "expected color model" );
3776 model = lookup_table(&color_model_tbl[0],c_token);
3777 if (model == -1)
3778 int_error(c_token,"unknown color model");
3779 if (model == C_MODEL_XYZ)
3780 int_warn(c_token,"CIE/XYZ not supported");
3781 sm_palette.cmodel = model;
3782 continue;
3783 }
3784 /* ps_allcF: write all rgb formulae into PS file? */
3785 case S_PALETTE_NOPS_ALLCF: /* "nops_allcF" */
3786 sm_palette.ps_allcF = FALSE;
3787 continue;
3788 case S_PALETTE_PS_ALLCF: /* "ps_allcF" */
3789 sm_palette.ps_allcF = TRUE;
3790 continue;
3791 /* max colors used */
3792 case S_PALETTE_MAXCOLORS: { /* "maxc$olors" */
3793 int i;
3794
3795 c_token++;
3796 i = int_expression();
3797 if (i<0 || i==1)
3798 int_warn(c_token,"maxcolors must be > 1");
3799 else
3800 sm_palette.use_maxcolors = i;
3801 --c_token;
3802 continue;
3803 }
3804 } /* switch over palette lookup table */
3805 int_error(c_token,"invalid palette option");
3806 } /* end of while !end of command over palette options */
3807 } /* else(arguments found) */
3808
3809 if (named_color && sm_palette.cmodel != C_MODEL_RGB && interactive)
3810 int_warn(NO_CARET,
3811 "Named colors will produce strange results if not in color mode RGB." );
3812
3813 /* Invalidate previous palette */
3814 invalidate_palette();
3815 }
3816
3817 #undef CHECK_TRANSFORM
3818
3819 /* process 'set colorbox' command */
3820 static void
set_colorbox()3821 set_colorbox()
3822 {
3823 c_token++;
3824
3825 if (END_OF_COMMAND) /* reset to default position */
3826 color_box.where = SMCOLOR_BOX_DEFAULT;
3827 else { /* go through all options of 'set colorbox' */
3828 for ( ; !END_OF_COMMAND; c_token++ ) {
3829 switch (lookup_table(&set_colorbox_tbl[0],c_token)) {
3830 /* vertical or horizontal color gradient */
3831 case S_COLORBOX_VERTICAL: /* "v$ertical" */
3832 color_box.rotation = 'v';
3833 continue;
3834 case S_COLORBOX_HORIZONTAL: /* "h$orizontal" */
3835 color_box.rotation = 'h';
3836 continue;
3837 /* color box where: default position */
3838 case S_COLORBOX_DEFAULT: /* "def$ault" */
3839 color_box.where = SMCOLOR_BOX_DEFAULT;
3840 continue;
3841 /* color box where: position by user */
3842 case S_COLORBOX_USER: /* "u$ser" */
3843 color_box.where = SMCOLOR_BOX_USER;
3844 continue;
3845 /* color box layer: front or back */
3846 case S_COLORBOX_FRONT: /* "fr$ont" */
3847 color_box.layer = LAYER_FRONT;
3848 continue;
3849 case S_COLORBOX_BACK: /* "ba$ck" */
3850 color_box.layer = LAYER_BACK;
3851 continue;
3852 /* border of the color box */
3853 case S_COLORBOX_BORDER: /* "bo$rder" */
3854
3855 color_box.border = 1;
3856 c_token++;
3857
3858 if (!END_OF_COMMAND) {
3859 /* expecting a border line type */
3860 color_box.border_lt_tag = int_expression();
3861 if (color_box.border_lt_tag <= 0) {
3862 color_box.border_lt_tag = 0;
3863 int_error(c_token, "tag must be strictly positive (see `help set style line')");
3864 }
3865 --c_token;
3866 }
3867 continue;
3868 case S_COLORBOX_BDEFAULT: /* "bd$efault" */
3869 color_box.border_lt_tag = -1; /* use default border */
3870 continue;
3871 case S_COLORBOX_NOBORDER: /* "nobo$rder" */
3872 color_box.border = 0;
3873 continue;
3874 /* colorbox origin */
3875 case S_COLORBOX_ORIGIN: /* "o$rigin" */
3876 c_token++;
3877 if (END_OF_COMMAND) {
3878 int_error(c_token, "expecting screen value [0 - 1]");
3879 } else {
3880 /* FIXME: should be 2 but old save files may have 3 */
3881 get_position_default(&color_box.origin, screen, 3);
3882 }
3883 c_token--;
3884 continue;
3885 /* colorbox size */
3886 case S_COLORBOX_SIZE: /* "s$ize" */
3887 c_token++;
3888 if (END_OF_COMMAND) {
3889 int_error(c_token, "expecting screen value [0 - 1]");
3890 } else {
3891 /* FIXME: should be 2 but old save files may have 3 */
3892 get_position_default(&color_box.size, screen, 3);
3893 }
3894 c_token--;
3895 continue;
3896 case S_COLORBOX_INVERT: /* Flip direction of color gradient + cbaxis */
3897 c_token++;
3898 color_box.invert = TRUE;
3899 continue;
3900 case S_COLORBOX_NOINVERT: /* Flip direction of color gradient + cbaxis */
3901 c_token++;
3902 color_box.invert = FALSE;
3903 continue;
3904 } /* switch over colorbox lookup table */
3905 int_error(c_token,"invalid colorbox option");
3906 } /* end of while !end of command over colorbox options */
3907 if (color_box.where == SMCOLOR_BOX_NO) /* default: draw at default position */
3908 color_box.where = SMCOLOR_BOX_DEFAULT;
3909 }
3910 }
3911
3912
3913 /* process 'set pm3d' command */
3914 static void
set_pm3d()3915 set_pm3d()
3916 {
3917 int c_token0 = ++c_token;
3918
3919 if (END_OF_COMMAND) { /* assume default settings */
3920 pm3d_reset(); /* sets pm3d.implicit to PM3D_EXPLICIT and pm3d.where to "s" */
3921 pm3d.implicit = PM3D_IMPLICIT; /* for historical reasons */
3922 }
3923 else { /* go through all options of 'set pm3d' */
3924 for ( ; !END_OF_COMMAND; c_token++ ) {
3925 switch (lookup_table(&set_pm3d_tbl[0],c_token)) {
3926 /* where to plot */
3927 case S_PM3D_AT: /* "at" */
3928 c_token++;
3929 if (get_pm3d_at_option(&pm3d.where[0]))
3930 return; /* error */
3931 c_token--;
3932 #if 1
3933 if (c_token == c_token0+1)
3934 /* for historical reasons: if "at" is the first option of pm3d,
3935 * like "set pm3d at X other_opts;", then implicit is switched on */
3936 pm3d.implicit = PM3D_IMPLICIT;
3937 #endif
3938 continue;
3939 case S_PM3D_INTERPOLATE: /* "interpolate" */
3940 c_token++;
3941 if (END_OF_COMMAND) {
3942 int_error(c_token, "expecting step values i,j");
3943 } else {
3944 pm3d.interp_i = int_expression();
3945 if (!equals(c_token,","))
3946 int_error(c_token, "',' expected");
3947 c_token++;
3948 pm3d.interp_j = int_expression();
3949 c_token--;
3950 }
3951 continue;
3952 /* forward and backward drawing direction */
3953 case S_PM3D_SCANSFORWARD: /* "scansfor$ward" */
3954 pm3d.direction = PM3D_SCANS_FORWARD;
3955 continue;
3956 case S_PM3D_SCANSBACKWARD: /* "scansback$ward" */
3957 pm3d.direction = PM3D_SCANS_BACKWARD;
3958 continue;
3959 case S_PM3D_SCANS_AUTOMATIC: /* "scansauto$matic" */
3960 pm3d.direction = PM3D_SCANS_AUTOMATIC;
3961 continue;
3962 case S_PM3D_DEPTH: /* "dep$thorder" */
3963 pm3d.direction = PM3D_DEPTH;
3964 if (equals(c_token+1, "base")) {
3965 pm3d.base_sort = TRUE;
3966 c_token++;
3967 } else {
3968 pm3d.base_sort = FALSE;
3969 }
3970 continue;
3971 /* flush scans: left, right or center */
3972 case S_PM3D_FLUSH: /* "fl$ush" */
3973 c_token++;
3974 if (almost_equals(c_token, "b$egin"))
3975 pm3d.flush = PM3D_FLUSH_BEGIN;
3976 else if (almost_equals(c_token, "c$enter"))
3977 pm3d.flush = PM3D_FLUSH_CENTER;
3978 else if (almost_equals(c_token, "e$nd"))
3979 pm3d.flush = PM3D_FLUSH_END;
3980 else
3981 int_error(c_token,"expecting flush 'begin', 'center' or 'end'");
3982 continue;
3983 /* clipping method */
3984 case S_PM3D_CLIP_1IN: /* "clip1$in" */
3985 pm3d.clip = PM3D_CLIP_1IN;
3986 continue;
3987 case S_PM3D_CLIP_4IN: /* "clip4$in" */
3988 pm3d.clip = PM3D_CLIP_4IN;
3989 continue;
3990 case S_PM3D_CLIPCB:
3991 pm3d.no_clipcb = FALSE;
3992 continue;
3993 case S_PM3D_NOCLIPCB:
3994 pm3d.no_clipcb = TRUE;
3995 continue;
3996 /* setup everything for plotting a map */
3997 case S_PM3D_MAP: /* "map" */
3998 pm3d.where[0] = 'b'; pm3d.where[1] = 0; /* set pm3d at b */
3999 data_style = PM3DSURFACE;
4000 func_style = PM3DSURFACE;
4001 splot_map = TRUE;
4002 continue;
4003 /* flushing triangles */
4004 case S_PM3D_FTRIANGLES: /* "ftr$iangles" */
4005 pm3d.ftriangles = 1;
4006 continue;
4007 case S_PM3D_NOFTRIANGLES: /* "noftr$iangles" */
4008 pm3d.ftriangles = 0;
4009 continue;
4010 /* deprecated pm3d "hidden3d" option, now used for borders */
4011 case S_PM3D_HIDDEN:
4012 if (isanumber(c_token+1)) {
4013 c_token++;
4014 load_linetype(&pm3d.border, int_expression());
4015 c_token--;
4016 continue;
4017 }
4018 /* fall through */
4019 case S_PM3D_BORDER: /* border {linespec} */
4020 c_token++;
4021 pm3d.border = default_pm3d_border;
4022 lp_parse(&pm3d.border, LP_ADHOC, FALSE);
4023 c_token--;
4024 continue;
4025 case S_PM3D_NOHIDDEN:
4026 case S_PM3D_NOBORDER:
4027 pm3d.border.l_type = LT_NODRAW;
4028 continue;
4029 case S_PM3D_SOLID: /* "so$lid" */
4030 case S_PM3D_NOTRANSPARENT: /* "notr$ansparent" */
4031 case S_PM3D_NOSOLID: /* "noso$lid" */
4032 case S_PM3D_TRANSPARENT: /* "tr$ansparent" */
4033 if (interactive)
4034 int_warn(c_token, "Deprecated syntax --- ignored");
4035 case S_PM3D_IMPLICIT: /* "i$mplicit" */
4036 case S_PM3D_NOEXPLICIT: /* "noe$xplicit" */
4037 pm3d.implicit = PM3D_IMPLICIT;
4038 continue;
4039 case S_PM3D_NOIMPLICIT: /* "noi$mplicit" */
4040 case S_PM3D_EXPLICIT: /* "e$xplicit" */
4041 pm3d.implicit = PM3D_EXPLICIT;
4042 continue;
4043
4044 case S_PM3D_WHICH_CORNER: /* "corners2color" */
4045 c_token++;
4046 if (equals(c_token, "mean"))
4047 pm3d.which_corner_color = PM3D_WHICHCORNER_MEAN;
4048 else if (equals(c_token, "geomean"))
4049 pm3d.which_corner_color = PM3D_WHICHCORNER_GEOMEAN;
4050 else if (equals(c_token, "harmean"))
4051 pm3d.which_corner_color = PM3D_WHICHCORNER_HARMEAN;
4052 else if (equals(c_token, "median"))
4053 pm3d.which_corner_color = PM3D_WHICHCORNER_MEDIAN;
4054 else if (equals(c_token, "min"))
4055 pm3d.which_corner_color = PM3D_WHICHCORNER_MIN;
4056 else if (equals(c_token, "max"))
4057 pm3d.which_corner_color = PM3D_WHICHCORNER_MAX;
4058 else if (equals(c_token, "rms"))
4059 pm3d.which_corner_color = PM3D_WHICHCORNER_RMS;
4060 else if (equals(c_token, "c1"))
4061 pm3d.which_corner_color = PM3D_WHICHCORNER_C1;
4062 else if (equals(c_token, "c2"))
4063 pm3d.which_corner_color = PM3D_WHICHCORNER_C2;
4064 else if (equals(c_token, "c3"))
4065 pm3d.which_corner_color = PM3D_WHICHCORNER_C3;
4066 else if (equals(c_token, "c4"))
4067 pm3d.which_corner_color = PM3D_WHICHCORNER_C4;
4068 else
4069 int_error(c_token,"expecting 'mean', 'geomean', 'harmean', 'median', 'min', 'max', 'c1', 'c2', 'c3' or 'c4'");
4070 continue;
4071
4072 case S_PM3D_NOLIGHTING_MODEL:
4073 pm3d_shade.strength = 0.0;
4074 continue;
4075
4076 case S_PM3D_LIGHTING_MODEL:
4077 parse_lighting_options();
4078 continue;
4079
4080 } /* switch over pm3d lookup table */
4081 int_error(c_token,"invalid pm3d option");
4082 } /* end of while !end of command over pm3d options */
4083 if (PM3D_SCANS_AUTOMATIC == pm3d.direction
4084 && PM3D_FLUSH_BEGIN != pm3d.flush) {
4085 pm3d.direction = PM3D_SCANS_FORWARD;
4086 /* FIXME: Why isn't this combination supported? */
4087 FPRINTF((stderr, "pm3d: `scansautomatic' and `flush %s' are incompatible\n",
4088 PM3D_FLUSH_END == pm3d.flush ? "end": "center"));
4089 }
4090 }
4091 }
4092
4093
4094 /* process 'set pointintervalbox' command */
4095 static void
set_pointintervalbox()4096 set_pointintervalbox()
4097 {
4098 c_token++;
4099 if (END_OF_COMMAND)
4100 pointintervalbox = 1.0;
4101 else
4102 pointintervalbox = real_expression();
4103 if (pointintervalbox <= 0)
4104 pointintervalbox = 1.0;
4105 }
4106
4107 /* process 'set pointsize' command */
4108 static void
set_pointsize()4109 set_pointsize()
4110 {
4111 c_token++;
4112 if (END_OF_COMMAND)
4113 pointsize = 1.0;
4114 else
4115 pointsize = real_expression();
4116 if (pointsize <= 0)
4117 pointsize = 1.0;
4118 }
4119
4120
4121 /* process 'set polar' command */
4122 static void
set_polar()4123 set_polar()
4124 {
4125 c_token++;
4126
4127 if (polar)
4128 return;
4129
4130 polar = TRUE;
4131 raxis = TRUE;
4132
4133 if (!parametric) {
4134 if (interactive)
4135 (void) fprintf(stderr,"\n\tdummy variable is t for curves\n");
4136 strcpy (set_dummy_var[0], "t");
4137 }
4138 if (axis_array[T_AXIS].set_autoscale) {
4139 /* only if user has not set a range manually */
4140 axis_array[T_AXIS].set_min = 0.0;
4141 /* 360 if degrees, 2pi if radians */
4142 axis_array[T_AXIS].set_max = 2 * M_PI / ang2rad;
4143 }
4144 if (axis_array[POLAR_AXIS].set_autoscale != AUTOSCALE_BOTH)
4145 rrange_to_xy();
4146 }
4147
4148 #ifdef EAM_OBJECTS
4149 /*
4150 * Process command 'set object <tag> {rectangle|ellipse|circle|polygon}'
4151 * set object {tag} rectangle {from <bottom_left> {to|rto} <top_right>}
4152 * {{at|center} <xcen>,<ycen> size <w>,<h>}
4153 * {fc|fillcolor <colorspec>} {lw|linewidth <lw>}
4154 * {fs <fillstyle>} {front|back|behind}
4155 * {default}
4156 * EAM Jan 2005
4157 */
4158
4159 static void
set_object()4160 set_object()
4161 {
4162 int tag;
4163
4164 /* The next token must either be a tag or the object type */
4165 c_token++;
4166 if (almost_equals(c_token, "rect$angle") || almost_equals(c_token, "ell$ipse")
4167 || almost_equals(c_token, "circ$le") || almost_equals(c_token, "poly$gon"))
4168 tag = -1; /* We'll figure out what it really is later */
4169 else {
4170 tag = int_expression();
4171 if (tag <= 0)
4172 int_error(c_token, "tag must be > zero");
4173 }
4174
4175 if (almost_equals(c_token, "rect$angle")) {
4176 set_obj(tag, OBJ_RECTANGLE);
4177
4178 } else if (almost_equals(c_token, "ell$ipse")) {
4179 set_obj(tag, OBJ_ELLIPSE);
4180
4181 } else if (almost_equals(c_token, "circ$le")) {
4182 set_obj(tag, OBJ_CIRCLE);
4183
4184 } else if (almost_equals(c_token, "poly$gon")) {
4185 set_obj(tag, OBJ_POLYGON);
4186
4187 } else if (tag > 0) {
4188 /* Look for existing object with this tag */
4189 t_object *this_object = first_object;
4190 for (; this_object != NULL; this_object = this_object->next)
4191 if (tag == this_object->tag)
4192 break;
4193 if (this_object && tag == this_object->tag) {
4194 c_token--;
4195 set_obj(tag, this_object->object_type);
4196 } else
4197 int_error(c_token, "unknown object");
4198
4199 } else
4200 int_error(c_token, "unrecognized object type");
4201
4202 }
4203
4204 static t_object *
new_object(int tag,int object_type,t_object * new)4205 new_object(int tag, int object_type, t_object *new)
4206 {
4207 t_object def_rect = DEFAULT_RECTANGLE_STYLE;
4208 t_object def_ellipse = DEFAULT_ELLIPSE_STYLE;
4209 t_object def_circle = DEFAULT_CIRCLE_STYLE;
4210 t_object def_polygon = DEFAULT_POLYGON_STYLE;
4211
4212 if (!new)
4213 new = gp_alloc(sizeof(struct object), "object");
4214 else if (new->object_type == OBJ_POLYGON)
4215 free(new->o.polygon.vertex);
4216
4217 if (object_type == OBJ_RECTANGLE) {
4218 *new = def_rect;
4219 new->lp_properties.l_type = LT_DEFAULT; /* Use default rectangle color */
4220 new->fillstyle.fillstyle = FS_DEFAULT; /* and default fill style */
4221 } else if (object_type == OBJ_ELLIPSE)
4222 *new = def_ellipse;
4223 else if (object_type == OBJ_CIRCLE)
4224 *new = def_circle;
4225 else if (object_type == OBJ_POLYGON)
4226 *new = def_polygon;
4227 else
4228 int_error(NO_CARET,"object initialization failure");
4229
4230 new->tag = tag;
4231 new->object_type = object_type;
4232
4233 return new;
4234 }
4235
4236 static void
set_obj(int tag,int obj_type)4237 set_obj(int tag, int obj_type)
4238 {
4239 t_rectangle *this_rect = NULL;
4240 t_ellipse *this_ellipse = NULL;
4241 t_circle *this_circle = NULL;
4242 t_polygon *this_polygon = NULL;
4243 t_object *this_object = NULL;
4244 t_object *new_obj = NULL;
4245 t_object *prev_object = NULL;
4246 TBOOLEAN got_fill = FALSE;
4247 TBOOLEAN got_lt = FALSE;
4248 TBOOLEAN got_fc = FALSE;
4249 TBOOLEAN got_corners = FALSE;
4250 TBOOLEAN got_center = FALSE;
4251 TBOOLEAN got_origin = FALSE;
4252
4253 c_token++;
4254
4255 /* We are setting the default, not any particular rectangle */
4256 if (tag < -1) {
4257 c_token--;
4258 if (obj_type == OBJ_RECTANGLE) {
4259 this_object = &default_rectangle;
4260 this_rect = &this_object->o.rectangle;
4261 } else
4262 int_error(c_token, "Unknown object type");
4263
4264 } else {
4265 /* Look for existing object with this tag */
4266 for (this_object = first_object; this_object != NULL;
4267 prev_object = this_object, this_object = this_object->next)
4268 /* is this the one we want? */
4269 if (0 < tag && tag <= this_object->tag)
4270 break;
4271
4272 /* Insert this rect into the list if it is a new one */
4273 if (this_object == NULL || tag != this_object->tag) {
4274 if (tag == -1)
4275 tag = (prev_object) ? prev_object->tag+1 : 1;
4276 new_obj = new_object(tag, obj_type, NULL);
4277 if (prev_object == NULL)
4278 first_object = new_obj;
4279 else
4280 prev_object->next = new_obj;
4281 new_obj->next = this_object;
4282 this_object = new_obj;
4283 /* V5 CHANGE: Apply default rectangle style now rather than later */
4284 if (obj_type == OBJ_RECTANGLE) {
4285 this_object->fillstyle = default_rectangle.fillstyle;
4286 this_object->lp_properties = default_rectangle.lp_properties;
4287 }
4288 }
4289
4290 /* Over-write old object if the type has changed */
4291 else if (this_object->object_type != obj_type) {
4292 t_object *save_link = this_object->next;
4293 new_obj = new_object(tag, obj_type, this_object);
4294 this_object->next = save_link;
4295 }
4296
4297 this_rect = &this_object->o.rectangle;
4298 this_ellipse = &this_object->o.ellipse;
4299 this_circle = &this_object->o.circle;
4300 this_polygon = &this_object->o.polygon;
4301
4302 }
4303
4304 while (!END_OF_COMMAND) {
4305 int save_token = c_token;
4306
4307 switch (obj_type) {
4308 case OBJ_RECTANGLE:
4309 if (equals(c_token,"from")) {
4310 /* Read in the bottom left and upper right corners */
4311 c_token++;
4312 get_position(&this_rect->bl);
4313 if (equals(c_token,"to")) {
4314 c_token++;
4315 get_position(&this_rect->tr);
4316 } else if (equals(c_token,"rto")) {
4317 c_token++;
4318 get_position_default(&this_rect->tr, this_rect->bl.scalex, 2);
4319 if (this_rect->bl.scalex != this_rect->tr.scalex
4320 || this_rect->bl.scaley != this_rect->tr.scaley)
4321 int_error(c_token,"relative coordinates must match in type");
4322 this_rect->tr.x += this_rect->bl.x;
4323 this_rect->tr.y += this_rect->bl.y;
4324 } else
4325 int_error(c_token,"Expecting to or rto");
4326 got_corners = TRUE;
4327 this_rect->type = 0;
4328 continue;
4329
4330 } else if (equals(c_token,"at") || almost_equals(c_token,"cen$ter")) {
4331 /* Read in the center position */
4332 c_token++;
4333 get_position(&this_rect->center);
4334 got_center = TRUE;
4335 this_rect->type = 1;
4336 continue;
4337
4338 } else if (equals(c_token,"size")) {
4339 /* Read in the width and height */
4340 c_token++;
4341 get_position(&this_rect->extent);
4342 got_center = TRUE;
4343 this_rect->type = 1;
4344 continue;
4345 }
4346 break;
4347
4348 case OBJ_CIRCLE:
4349 if (equals(c_token,"at") || almost_equals(c_token,"cen$ter")) {
4350 /* Read in the center position */
4351 c_token++;
4352 get_position(&this_circle->center);
4353 continue;
4354
4355 } else if (equals(c_token,"size") || equals(c_token,"radius")) {
4356 /* Read in the radius */
4357 c_token++;
4358 get_position(&this_circle->extent);
4359 continue;
4360
4361 } else if (equals(c_token, "arc")) {
4362 /* Start and end angle for arc */
4363 if (equals(++c_token,"[")) {
4364 double arc;
4365 c_token++;
4366 arc = real_expression();
4367 if (fabs(arc) > 1000.)
4368 int_error(c_token-1,"Angle out of range");
4369 else
4370 this_circle->arc_begin = arc;
4371 if (equals(c_token++, ":")) {
4372 arc = real_expression();
4373 if (fabs(arc) > 1000.)
4374 int_error(c_token-1,"Angle out of range");
4375 else
4376 this_circle->arc_end = arc;
4377 if (equals(c_token++,"]"))
4378 continue;
4379 }
4380 }
4381 int_error(--c_token, "Expecting arc [<begin>:<end>]");
4382 } else if (equals(c_token, "wedge")) {
4383 c_token++;
4384 this_circle->wedge = TRUE;
4385 continue;
4386 } else if (equals(c_token, "nowedge")) {
4387 c_token++;
4388 this_circle->wedge = FALSE;
4389 continue;
4390 }
4391 break;
4392
4393 case OBJ_ELLIPSE:
4394 if (equals(c_token,"at") || almost_equals(c_token,"cen$ter")) {
4395 /* Read in the center position */
4396 c_token++;
4397 get_position(&this_ellipse->center);
4398 continue;
4399
4400 } else if (equals(c_token,"size")) {
4401 /* Read in the width and height */
4402 c_token++;
4403 get_position(&this_ellipse->extent);
4404 continue;
4405
4406 } else if (almost_equals(c_token,"ang$le")) {
4407 c_token++;
4408 this_ellipse->orientation = real_expression();
4409 continue;
4410
4411 } else if (almost_equals(c_token,"unit$s")) {
4412 c_token++;
4413 if (equals(c_token,"xy") || END_OF_COMMAND) {
4414 this_ellipse->type = ELLIPSEAXES_XY;
4415 } else if (equals(c_token,"xx")) {
4416 this_ellipse->type = ELLIPSEAXES_XX;
4417 } else if (equals(c_token,"yy")) {
4418 this_ellipse->type = ELLIPSEAXES_YY;
4419 } else {
4420 int_error(c_token, "expecting 'xy', 'xx' or 'yy'" );
4421 }
4422 c_token++;
4423 continue;
4424
4425 }
4426 break;
4427
4428 case OBJ_POLYGON:
4429 if (equals(c_token,"from")) {
4430 c_token++;
4431 this_polygon->vertex = gp_realloc(this_polygon->vertex,
4432 sizeof(struct position),
4433 "polygon vertex");
4434 get_position(&this_polygon->vertex[0]);
4435 this_polygon->type = 1;
4436 got_origin = TRUE;
4437 continue;
4438 }
4439 if (!got_corners && (equals(c_token,"to") || equals(c_token,"rto"))) {
4440 while (equals(c_token,"to") || equals(c_token,"rto")) {
4441 if (!got_origin)
4442 goto polygon_error;
4443 this_polygon->vertex = gp_realloc(this_polygon->vertex,
4444 (this_polygon->type+1) * sizeof(struct position),
4445 "polygon vertex");
4446 if (equals(c_token++,"to")) {
4447 get_position(&this_polygon->vertex[this_polygon->type]);
4448 } else /* "rto" */ {
4449 int v = this_polygon->type;
4450 get_position_default(&this_polygon->vertex[v],
4451 this_polygon->vertex->scalex, 2);
4452 if (this_polygon->vertex[v].scalex != this_polygon->vertex[v-1].scalex
4453 || this_polygon->vertex[v].scaley != this_polygon->vertex[v-1].scaley)
4454 int_error(c_token,"relative coordinates must match in type");
4455 this_polygon->vertex[v].x += this_polygon->vertex[v-1].x;
4456 this_polygon->vertex[v].y += this_polygon->vertex[v-1].y;
4457 }
4458 this_polygon->type++;
4459 got_corners = TRUE;
4460 }
4461 if (got_corners && memcmp(&this_polygon->vertex[this_polygon->type-1],
4462 &this_polygon->vertex[0],sizeof(struct position))) {
4463 fprintf(stderr,"Polygon is not closed - adding extra vertex\n");
4464 this_polygon->vertex = gp_realloc(this_polygon->vertex,
4465 (this_polygon->type+1) * sizeof(struct position),
4466 "polygon vertex");
4467 this_polygon->vertex[this_polygon->type] = this_polygon->vertex[0];
4468 this_polygon->type++;
4469 }
4470 continue;
4471 }
4472 break;
4473 polygon_error:
4474 free(this_polygon->vertex);
4475 this_polygon->vertex = NULL;
4476 this_polygon->type = 0;
4477 int_error(c_token, "Unrecognized polygon syntax");
4478 /* End of polygon options */
4479
4480 default:
4481 int_error(c_token, "unrecognized object type");
4482 } /* End of object-specific options */
4483
4484 /* The rest of the options apply to any type of object */
4485
4486 if (equals(c_token,"front")) {
4487 this_object->layer = LAYER_FRONT;
4488 c_token++;
4489 continue;
4490 } else if (equals(c_token,"back")) {
4491 this_object->layer = LAYER_BACK;
4492 c_token++;
4493 continue;
4494 } else if (equals(c_token,"behind")) {
4495 this_object->layer = LAYER_BEHIND;
4496 c_token++;
4497 continue;
4498 } else if (almost_equals(c_token,"def$ault")) {
4499 if (tag < 0) {
4500 int_error(c_token,
4501 "Invalid command - did you mean 'unset style rectangle'?");
4502 } else {
4503 this_object->lp_properties.l_type = LT_DEFAULT;
4504 this_object->fillstyle.fillstyle = FS_DEFAULT;
4505 }
4506 got_fill = got_lt = TRUE;
4507 c_token++;
4508 continue;
4509 } else if (equals(c_token, "clip")) {
4510 this_object->clip = OBJ_CLIP;
4511 c_token++;
4512 continue;
4513 } else if (equals(c_token, "noclip")) {
4514 this_object->clip = OBJ_NOCLIP;
4515 c_token++;
4516 continue;
4517 }
4518
4519 /* Now parse the style options; default to whatever the global style is */
4520 if (!got_fill) {
4521 fill_style_type *default_style;
4522 if (this_object->object_type == OBJ_RECTANGLE)
4523 default_style = &default_rectangle.fillstyle;
4524 else
4525 default_style = &default_fillstyle;
4526
4527 if (new_obj)
4528 parse_fillstyle(&this_object->fillstyle, default_style->fillstyle,
4529 default_style->filldensity, default_style->fillpattern,
4530 default_style->border_color);
4531 else
4532 parse_fillstyle(&this_object->fillstyle, this_object->fillstyle.fillstyle,
4533 this_object->fillstyle.filldensity, this_object->fillstyle.fillpattern,
4534 this_object->fillstyle.border_color);
4535 if (c_token != save_token) {
4536 got_fill = TRUE;
4537 continue;
4538 }
4539 }
4540
4541 /* Parse the colorspec */
4542 if (!got_fc) {
4543 if (equals(c_token,"fc") || almost_equals(c_token,"fillc$olor")) {
4544 this_object->lp_properties.l_type = LT_BLACK; /* Anything but LT_DEFAULT */
4545 parse_colorspec(&this_object->lp_properties.pm3d_color, TC_FRAC);
4546 if (this_object->lp_properties.pm3d_color.type == TC_DEFAULT)
4547 this_object->lp_properties.l_type = LT_DEFAULT;
4548 }
4549
4550 if (c_token != save_token) {
4551 got_fc = TRUE;
4552 continue;
4553 }
4554 }
4555
4556 /* Line properties (will be used for the object border if the fillstyle has one. */
4557 /* LP_NOFILL means don't eat fillcolor here since at is set separately with "fc". */
4558 if (!got_lt) {
4559 lp_style_type lptmp = this_object->lp_properties;
4560 lp_parse(&lptmp, LP_NOFILL, FALSE);
4561 if (c_token != save_token) {
4562 this_object->lp_properties.l_width = lptmp.l_width;
4563 this_object->lp_properties.d_type = lptmp.d_type;
4564 this_object->lp_properties.custom_dash_pattern = lptmp.custom_dash_pattern;
4565 got_lt = TRUE;
4566 continue;
4567 }
4568 }
4569
4570 int_error(c_token, "Unrecognized or duplicate option");
4571 }
4572
4573 if (got_center && got_corners)
4574 int_error(NO_CARET,"Inconsistent options");
4575
4576 }
4577 #endif
4578
4579 static void
set_rgbmax()4580 set_rgbmax()
4581 {
4582 c_token++;
4583 if (END_OF_COMMAND)
4584 rgbmax = 255;
4585 else
4586 rgbmax = real_expression();
4587 if (rgbmax <= 0)
4588 rgbmax = 255;
4589 }
4590
4591 /* process 'set samples' command */
4592 static void
set_samples()4593 set_samples()
4594 {
4595 int tsamp1, tsamp2;
4596
4597 c_token++;
4598 tsamp1 = abs(int_expression());
4599 tsamp2 = tsamp1;
4600 if (!END_OF_COMMAND) {
4601 if (!equals(c_token,","))
4602 int_error(c_token, "',' expected");
4603 c_token++;
4604 tsamp2 = abs(int_expression());
4605 }
4606 if (tsamp1 < 2 || tsamp2 < 2)
4607 int_error(c_token, "sampling rate must be > 1; sampling unchanged");
4608 else {
4609 struct surface_points *f_3dp = first_3dplot;
4610
4611 first_3dplot = NULL;
4612 sp_free(f_3dp);
4613
4614 samples_1 = tsamp1;
4615 samples_2 = tsamp2;
4616 }
4617 }
4618
4619
4620 /* process 'set size' command */
4621 static void
set_size()4622 set_size()
4623 {
4624 c_token++;
4625 if (END_OF_COMMAND) {
4626 xsize = 1.0;
4627 ysize = 1.0;
4628 } else {
4629 if (almost_equals(c_token, "sq$uare")) {
4630 aspect_ratio = 1.0;
4631 ++c_token;
4632 } else if (almost_equals(c_token,"ra$tio")) {
4633 ++c_token;
4634 aspect_ratio = real_expression();
4635 } else if (almost_equals(c_token, "nora$tio") || almost_equals(c_token, "nosq$uare")) {
4636 aspect_ratio = 0.0;
4637 ++c_token;
4638 }
4639
4640 if (!END_OF_COMMAND) {
4641 xsize = real_expression();
4642 if (equals(c_token,",")) {
4643 c_token++;
4644 ysize = real_expression();
4645 } else {
4646 ysize = xsize;
4647 }
4648 }
4649 }
4650 if (xsize <= 0 || ysize <=0) {
4651 xsize = ysize = 1.0;
4652 int_error(NO_CARET,"Illegal value for size");
4653 }
4654 }
4655
4656
4657 /* process 'set style' command */
4658 static void
set_style()4659 set_style()
4660 {
4661 c_token++;
4662
4663 switch(lookup_table(&show_style_tbl[0],c_token)){
4664 case SHOW_STYLE_DATA:
4665 data_style = get_style();
4666 if (data_style == FILLEDCURVES) {
4667 get_filledcurves_style_options(&filledcurves_opts_data);
4668 if (!filledcurves_opts_data.opt_given) /* default value */
4669 filledcurves_opts_data.closeto = FILLEDCURVES_CLOSED;
4670 }
4671 break;
4672 case SHOW_STYLE_FUNCTION:
4673 {
4674 enum PLOT_STYLE temp_style = get_style();
4675
4676 if ((temp_style & PLOT_STYLE_HAS_ERRORBAR)
4677 || (temp_style == LABELPOINTS) || (temp_style == HISTOGRAMS)
4678 || (temp_style == IMAGE) || (temp_style == RGBIMAGE) || (temp_style == RGBA_IMAGE)
4679 || (temp_style == PARALLELPLOT))
4680 int_error(c_token, "style not usable for function plots, left unchanged");
4681 else
4682 func_style = temp_style;
4683 if (func_style == FILLEDCURVES) {
4684 get_filledcurves_style_options(&filledcurves_opts_func);
4685 if (!filledcurves_opts_func.opt_given) /* default value */
4686 filledcurves_opts_func.closeto = FILLEDCURVES_CLOSED;
4687 }
4688 break;
4689 }
4690 case SHOW_STYLE_LINE:
4691 set_linestyle(&first_linestyle, LP_STYLE);
4692 break;
4693 case SHOW_STYLE_FILLING:
4694 parse_fillstyle( &default_fillstyle,
4695 default_fillstyle.fillstyle,
4696 default_fillstyle.filldensity,
4697 default_fillstyle.fillpattern,
4698 default_fillstyle.border_color);
4699 break;
4700 case SHOW_STYLE_ARROW:
4701 set_arrowstyle();
4702 break;
4703 #ifdef EAM_OBJECTS
4704 case SHOW_STYLE_RECTANGLE:
4705 c_token++;
4706 set_obj(-2, OBJ_RECTANGLE);
4707 break;
4708 case SHOW_STYLE_CIRCLE:
4709 c_token++;
4710 while (!END_OF_COMMAND) {
4711 if (almost_equals(c_token,"r$adius")) {
4712 c_token++;
4713 get_position(&default_circle.o.circle.extent);
4714 } else if (almost_equals(c_token, "wedge$s")) {
4715 c_token++;
4716 default_circle.o.circle.wedge = TRUE;
4717 } else if (almost_equals(c_token, "nowedge$s")) {
4718 c_token++;
4719 default_circle.o.circle.wedge = FALSE;
4720 } else if (equals(c_token, "clip")) {
4721 c_token++;
4722 default_circle.clip = OBJ_CLIP;
4723 } else if (equals(c_token, "noclip")) {
4724 c_token++;
4725 default_circle.clip = OBJ_NOCLIP;
4726 } else
4727 int_error(c_token, "unrecognized style option" );
4728 }
4729 break;
4730 case SHOW_STYLE_ELLIPSE:
4731 c_token++;
4732 while (!END_OF_COMMAND) {
4733 if (equals(c_token,"size")) {
4734 c_token++;
4735 get_position(&default_ellipse.o.ellipse.extent);
4736 c_token--;
4737 } else if (almost_equals(c_token,"ang$le")) {
4738 c_token++;
4739 if (might_be_numeric(c_token)) {
4740 default_ellipse.o.ellipse.orientation = real_expression();
4741 c_token--;
4742 }
4743 } else if (almost_equals(c_token,"unit$s")) {
4744 c_token++;
4745 if (equals(c_token,"xy") || END_OF_COMMAND) {
4746 default_ellipse.o.ellipse.type = ELLIPSEAXES_XY;
4747 } else if (equals(c_token,"xx")) {
4748 default_ellipse.o.ellipse.type = ELLIPSEAXES_XX;
4749 } else if (equals(c_token,"yy")) {
4750 default_ellipse.o.ellipse.type = ELLIPSEAXES_YY;
4751 } else {
4752 int_error(c_token, "expecting 'xy', 'xx' or 'yy'" );
4753 }
4754 } else if (equals(c_token, "clip")) {
4755 c_token++;
4756 default_ellipse.clip = OBJ_CLIP;
4757 } else if (equals(c_token, "noclip")) {
4758 c_token++;
4759 default_ellipse.clip = OBJ_NOCLIP;
4760 } else
4761 int_error(c_token, "expecting 'units {xy|xx|yy}', 'angle <number>' or 'size <position>'" );
4762
4763 c_token++;
4764 }
4765 break;
4766 #endif
4767 case SHOW_STYLE_HISTOGRAM:
4768 parse_histogramstyle(&histogram_opts,HT_CLUSTERED,histogram_opts.gap);
4769 break;
4770 #ifdef EAM_BOXED_TEXT
4771 case SHOW_STYLE_TEXTBOX:
4772 c_token++;
4773 while (!END_OF_COMMAND) {
4774 if (almost_equals(c_token,"op$aque")) {
4775 textbox_opts.opaque = TRUE;
4776 c_token++;
4777 } else if (almost_equals(c_token,"trans$parent")) {
4778 textbox_opts.opaque = FALSE;
4779 c_token++;
4780 } else if (almost_equals(c_token,"mar$gins")) {
4781 struct value a;
4782 c_token++;
4783 if (END_OF_COMMAND) {
4784 textbox_opts.xmargin = 1.;
4785 textbox_opts.ymargin = 1.;
4786 break;
4787 }
4788 textbox_opts.xmargin = real(const_express(&a));
4789 if (textbox_opts.xmargin < 0)
4790 textbox_opts.xmargin = 0;
4791 if (!equals(c_token++,",") || END_OF_COMMAND)
4792 break;
4793 textbox_opts.ymargin = real(const_express(&a));
4794 if (textbox_opts.ymargin < 0)
4795 textbox_opts.ymargin = 0;
4796 } else if (almost_equals(c_token,"fillc$olor") || equals(c_token,"fc")) {
4797 parse_colorspec(&textbox_opts.fillcolor, TC_RGB);
4798 } else if (almost_equals(c_token,"nobo$rder")) {
4799 c_token++;
4800 textbox_opts.noborder = TRUE;
4801 textbox_opts.border_color.type = TC_LT;
4802 textbox_opts.border_color.lt = LT_NODRAW;
4803 } else if (almost_equals(c_token,"bo$rdercolor")) {
4804 c_token++;
4805 textbox_opts.noborder = FALSE;
4806 textbox_opts.border_color.type = TC_LT;
4807 textbox_opts.border_color.lt = LT_BLACK;
4808 if (END_OF_COMMAND)
4809 continue;
4810 if (equals(c_token,"lt"))
4811 c_token--;
4812 parse_colorspec(&textbox_opts.border_color, TC_RGB);
4813 } else if (almost_equals(c_token,"linew$idth") || equals(c_token,"lw")) {
4814 c_token++;
4815 textbox_opts.linewidth = real_expression();
4816 if (textbox_opts.linewidth < 0)
4817 textbox_opts.linewidth = 1.0;
4818 } else
4819 int_error(c_token,"unrecognized option");
4820 }
4821 break;
4822 #endif
4823 case SHOW_STYLE_INCREMENT:
4824 #if TRUE || defined(BACKWARDS_COMPATIBLE)
4825 c_token++;
4826 if (END_OF_COMMAND || almost_equals(c_token,"def$ault"))
4827 prefer_line_styles = FALSE;
4828 else if (almost_equals(c_token,"u$serstyles"))
4829 prefer_line_styles = TRUE;
4830 else
4831 int_error(c_token,"unrecognized option");
4832 c_token++;
4833 #endif
4834 break;
4835 case SHOW_STYLE_BOXPLOT:
4836 set_boxplot();
4837 break;
4838 case SHOW_STYLE_PARALLEL:
4839 set_style_parallel();
4840 break;
4841 default:
4842 int_error(c_token, "unrecognized option - see 'help set style'");
4843 }
4844 }
4845
4846
4847 /* process 'set surface' command */
4848 static void
set_surface()4849 set_surface()
4850 {
4851 c_token++;
4852 draw_surface = TRUE;
4853 implicit_surface = TRUE;
4854 if (!END_OF_COMMAND) {
4855 if (equals(c_token, "implicit"))
4856 ;
4857 else if (equals(c_token, "explicit"))
4858 implicit_surface = FALSE;
4859 c_token++;
4860 }
4861 }
4862
4863
4864 /* process 'set table' command */
4865 static void
set_table()4866 set_table()
4867 {
4868 char *tablefile;
4869 int filename_token = ++c_token;
4870 TBOOLEAN append = FALSE;
4871
4872 if (table_outfile) {
4873 fclose(table_outfile);
4874 table_outfile = NULL;
4875 }
4876 table_var = NULL;
4877
4878 if (equals(c_token, "$") && isletter(c_token + 1)) { /* datablock */
4879 /* NB: has to come first because try_to_get_string will choke on the datablock name */
4880 table_var = add_udv_by_name(parse_datablock_name());
4881 if (table_var == NULL)
4882 int_error(c_token, "Error allocating datablock");
4883 if (equals(c_token, "append")) {
4884 c_token++;
4885 append = TRUE;
4886 }
4887 if (!append || table_var->udv_value.type != DATABLOCK) {
4888 gpfree_datablock(&table_var->udv_value);
4889 gpfree_string(&table_var->udv_value);
4890 table_var->udv_value.type = DATABLOCK;
4891 table_var->udv_value.v.data_array = NULL;
4892 }
4893
4894 } else if ((tablefile = try_to_get_string())) { /* file name */
4895 /* 'set table "foo"' creates a new output file */
4896 /* 'set table "foo" append' writes to the end of an existing output file */
4897 gp_expand_tilde(&tablefile);
4898 if (equals(c_token, "append")) {
4899 c_token++;
4900 append = TRUE;
4901 }
4902 if (!(table_outfile = fopen(tablefile, (append ? "a" : "w"))))
4903 os_error(filename_token, "cannot open table output file");
4904 free(tablefile);
4905 }
4906
4907 if (almost_equals(c_token,"sep$arator")) {
4908 set_separator(&table_sep);
4909 }
4910
4911 table_mode = TRUE;
4912 }
4913
4914
4915 /* process 'set terminal' comamnd */
4916 static void
set_terminal()4917 set_terminal()
4918 {
4919 c_token++;
4920
4921 if (multiplot)
4922 int_error(c_token, "You can't change the terminal in multiplot mode");
4923
4924 if (END_OF_COMMAND) {
4925 list_terms();
4926 screen_ok = FALSE;
4927 return;
4928 }
4929
4930 /* `set term push' */
4931 if (equals(c_token,"push")) {
4932 push_terminal(interactive);
4933 c_token++;
4934 return;
4935 } /* set term push */
4936
4937 #ifdef USE_MOUSE
4938 event_reset((void *)1); /* cancel zoombox etc. */
4939 #endif
4940 term_reset();
4941
4942 /* `set term pop' */
4943 if (equals(c_token,"pop")) {
4944 pop_terminal();
4945 c_token++;
4946 return;
4947 } /* set term pop */
4948
4949 /* `set term <normal terminal>' */
4950 /* NB: if set_term() exits via int_error() then term will not be changed */
4951 term = set_term();
4952
4953 /* get optional mode parameters
4954 * not all drivers reset the option string before
4955 * strcat-ing to it, so we reset it for them
4956 */
4957 *term_options = 0;
4958 term->options();
4959 if (interactive && *term_options)
4960 fprintf(stderr,"Options are '%s'\n",term_options);
4961 if ((term->flags & TERM_MONOCHROME))
4962 init_monochrome();
4963 }
4964
4965
4966 /*
4967 * Accept a single terminal option to apply to the current terminal if possible.
4968 * If the current terminal cannot support this option, we silently ignore it.
4969 * Only reasonably common terminal options are supported.
4970 *
4971 * If necessary, the code in term->options() can detect that it was called
4972 * from here because in this case almost_equals(c_token-1, "termopt$ion");
4973 */
4974
4975 static void
set_termoptions()4976 set_termoptions()
4977 {
4978 TBOOLEAN ok_to_call_terminal = FALSE;
4979 int save_end_of_line = num_tokens;
4980 c_token++;
4981
4982 if (END_OF_COMMAND || !term)
4983 return;
4984
4985 if (almost_equals(c_token,"enh$anced")
4986 || almost_equals(c_token,"noenh$anced")) {
4987 num_tokens = GPMIN(num_tokens,c_token+1);
4988 if (term->enhanced_open)
4989 ok_to_call_terminal = TRUE;
4990 else
4991 c_token++;
4992 } else if (equals(c_token,"font") || equals(c_token,"fname")) {
4993 num_tokens = GPMIN(num_tokens,c_token+2);
4994 ok_to_call_terminal = TRUE;
4995 } else if (equals(c_token,"fontscale")) {
4996 num_tokens = GPMIN(num_tokens,c_token+2);
4997 if (term->flags & TERM_FONTSCALE)
4998 ok_to_call_terminal = TRUE;
4999 else {
5000 c_token++;
5001 real_expression(); /* Silently ignore the request */
5002 }
5003 } else if (equals(c_token,"pointscale") || equals(c_token,"ps")) {
5004 num_tokens = GPMIN(num_tokens,c_token+2);
5005 if (term->flags & TERM_POINTSCALE)
5006 ok_to_call_terminal = TRUE;
5007 else {
5008 c_token++;
5009 real_expression(); /* Silently ignore the request */
5010 }
5011 } else if (equals(c_token,"lw") || almost_equals(c_token,"linew$idth")) {
5012 num_tokens = GPMIN(num_tokens,c_token+2);
5013 if (term->flags & TERM_LINEWIDTH)
5014 ok_to_call_terminal = TRUE;
5015 else {
5016 c_token++;
5017 real_expression(); /* Silently ignore the request */
5018 }
5019 } else if (almost_equals(c_token,"dash$ed") || equals(c_token,"solid")) {
5020 /* Silently ignore the request */
5021 num_tokens = GPMIN(num_tokens,++c_token);
5022 } else if (almost_equals(c_token,"dashl$ength") || equals(c_token,"dl")) {
5023 num_tokens = GPMIN(num_tokens,c_token+2);
5024 if (term->flags & TERM_CAN_DASH)
5025 ok_to_call_terminal = TRUE;
5026 else
5027 c_token+=2;
5028 } else if (!strcmp(term->name,"gif") && equals(c_token,"delay") && num_tokens==4) {
5029 ok_to_call_terminal = TRUE;
5030 } else {
5031 int_error(c_token,"This option cannot be changed using 'set termoption'");
5032 }
5033 if (ok_to_call_terminal) {
5034 *term_options = 0;
5035 (term->options)();
5036 }
5037 num_tokens = save_end_of_line;
5038 }
5039
5040 /* Various properties of the theta axis in polar mode */
5041 static void
set_theta()5042 set_theta()
5043 {
5044 c_token++;
5045 while (!END_OF_COMMAND) {
5046 if (almost_equals(c_token, "r$ight"))
5047 theta_origin = 0.0;
5048 else if (almost_equals(c_token, "t$op"))
5049 theta_origin = 90.0;
5050 else if (almost_equals(c_token, "l$eft"))
5051 theta_origin = 180.0;
5052 else if (almost_equals(c_token, "b$ottom"))
5053 theta_origin = -90.;
5054 else if (equals(c_token, "clockwise") || equals(c_token, "cw"))
5055 theta_direction = -1;
5056 else if (equals(c_token, "counterclockwise") || equals(c_token, "ccw"))
5057 theta_direction = 1;
5058 else
5059 int_error(c_token,"unrecognized option");
5060 c_token++;
5061 }
5062 }
5063
5064 /* process 'set tics' command */
5065 static void
set_tics()5066 set_tics()
5067 {
5068 unsigned int i = 0;
5069 TBOOLEAN axisset = FALSE;
5070 TBOOLEAN mirror_opt = FALSE; /* set to true if (no)mirror option specified) */
5071
5072 ++c_token;
5073
5074 if (END_OF_COMMAND) {
5075 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5076 axis_array[i].tic_in = TRUE;
5077 }
5078
5079 while (!END_OF_COMMAND) {
5080 if (almost_equals(c_token, "ax$is")) {
5081 axisset = TRUE;
5082 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5083 axis_array[i].ticmode &= ~TICS_ON_BORDER;
5084 axis_array[i].ticmode |= TICS_ON_AXIS;
5085 }
5086 ++c_token;
5087 } else if (almost_equals(c_token, "bo$rder")) {
5088 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5089 axis_array[i].ticmode &= ~TICS_ON_AXIS;
5090 axis_array[i].ticmode |= TICS_ON_BORDER;
5091 }
5092 ++c_token;
5093 } else if (almost_equals(c_token, "mi$rror")) {
5094 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5095 axis_array[i].ticmode |= TICS_MIRROR;
5096 mirror_opt = TRUE;
5097 ++c_token;
5098 } else if (almost_equals(c_token, "nomi$rror")) {
5099 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5100 axis_array[i].ticmode &= ~TICS_MIRROR;
5101 mirror_opt = TRUE;
5102 ++c_token;
5103 } else if (almost_equals(c_token,"in$wards")) {
5104 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5105 axis_array[i].tic_in = TRUE;
5106 ++c_token;
5107 } else if (almost_equals(c_token,"out$wards")) {
5108 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5109 axis_array[i].tic_in = FALSE;
5110 ++c_token;
5111 } else if (almost_equals(c_token, "sc$ale")) {
5112 set_ticscale();
5113 } else if (almost_equals(c_token, "ro$tate")) {
5114 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5115 axis_array[i].tic_rotate = TEXT_VERTICAL;
5116 }
5117 ++c_token;
5118 if (equals(c_token, "by")) {
5119 int langle;
5120 ++c_token;
5121 langle = int_expression();
5122 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5123 axis_array[i].tic_rotate = langle;
5124 }
5125 } else if (almost_equals(c_token, "noro$tate")) {
5126 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5127 axis_array[i].tic_rotate = 0;
5128 ++c_token;
5129 } else if (almost_equals(c_token, "l$eft")) {
5130 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5131 axis_array[i].tic_pos = LEFT;
5132 axis_array[i].manual_justify = TRUE;
5133 }
5134 c_token++;
5135 } else if (almost_equals(c_token, "c$entre")
5136 || almost_equals(c_token, "c$enter")) {
5137 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5138 axis_array[i].tic_pos = CENTRE;
5139 axis_array[i].manual_justify = TRUE;
5140 }
5141 c_token++;
5142 } else if (almost_equals(c_token, "ri$ght")) {
5143 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5144 axis_array[i].tic_pos = RIGHT;
5145 axis_array[i].manual_justify = TRUE;
5146 }
5147 c_token++;
5148 } else if (almost_equals(c_token, "autoj$ustify")) {
5149 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5150 axis_array[i].manual_justify = FALSE;
5151 c_token++;
5152 } else if (almost_equals(c_token, "off$set")) {
5153 struct position lpos;
5154 ++c_token;
5155 get_position_default(&lpos, character, 3);
5156 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5157 axis_array[i].ticdef.offset = lpos;
5158 } else if (almost_equals(c_token, "nooff$set")) {
5159 ++c_token;
5160 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5161 axis_array[i].ticdef.offset = default_offset;
5162 } else if (almost_equals(c_token, "format")) {
5163 set_format();
5164 } else if (almost_equals(c_token, "enh$anced")) {
5165 ++c_token;
5166 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5167 axis_array[i].ticdef.enhanced = TRUE;
5168 } else if (almost_equals(c_token, "noenh$anced")) {
5169 ++c_token;
5170 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5171 axis_array[i].ticdef.enhanced = FALSE;
5172 } else if (almost_equals(c_token, "f$ont")) {
5173 ++c_token;
5174 /* Make sure they've specified a font */
5175 if (!isstringvalue(c_token))
5176 int_error(c_token,"expected font");
5177 else {
5178 char *lfont = try_to_get_string();
5179 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5180 free(axis_array[i].ticdef.font);
5181 axis_array[i].ticdef.font = gp_strdup(lfont);
5182 }
5183 free(lfont);
5184 }
5185 } else if (equals(c_token,"tc") ||
5186 almost_equals(c_token,"text$color")) {
5187 struct t_colorspec lcolor;
5188 parse_colorspec(&lcolor, TC_FRAC);
5189 for (i = 0; i < AXIS_ARRAY_SIZE; ++i)
5190 axis_array[i].ticdef.textcolor = lcolor;
5191 } else if (equals(c_token,"front")) {
5192 grid_tics_in_front = TRUE;
5193 ++c_token;
5194 } else if (equals(c_token,"back")) {
5195 grid_tics_in_front = FALSE;
5196 ++c_token;
5197 } else if (!END_OF_COMMAND) {
5198 int_error(c_token, "extraneous arguments in set tics");
5199 }
5200 }
5201
5202 /* if tics are off and not set by axis, reset to default (border) */
5203 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5204 if (((axis_array[i].ticmode & TICS_MASK) == NO_TICS) && (!axisset)) {
5205 if ((i == SECOND_X_AXIS) || (i == SECOND_Y_AXIS))
5206 continue; /* don't switch on secondary axes by default */
5207 axis_array[i].ticmode = TICS_ON_BORDER;
5208 if ((mirror_opt == FALSE) && ((i == FIRST_X_AXIS) || (i == FIRST_Y_AXIS) || (i == COLOR_AXIS))) {
5209 axis_array[i].ticmode |= TICS_MIRROR;
5210 }
5211 }
5212 }
5213 }
5214
5215
5216 /* process 'set ticscale' command */
5217 static void
set_ticscale()5218 set_ticscale()
5219 {
5220 int i, ticlevel;
5221
5222 ++c_token;
5223 if (almost_equals(c_token, "def$ault")) {
5224 ++c_token;
5225 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5226 axis_array[i].ticscale = 1.0;
5227 axis_array[i].miniticscale = 0.5;
5228 }
5229 ticscale[0] = 1.0;
5230 ticscale[1] = 0.5;
5231 for (ticlevel = 2; ticlevel < MAX_TICLEVEL; ticlevel++)
5232 ticscale[ticlevel] = 1.0;
5233 } else {
5234 double lticscale, lminiticscale;
5235 lticscale = real_expression();
5236 if (equals(c_token, ",")) {
5237 ++c_token;
5238 lminiticscale = real_expression();
5239 } else {
5240 lminiticscale = 0.5 * lticscale;
5241 }
5242 for (i = 0; i < AXIS_ARRAY_SIZE; ++i) {
5243 axis_array[i].ticscale = lticscale;
5244 axis_array[i].miniticscale = lminiticscale;
5245 }
5246 ticlevel = 2;
5247 while (equals(c_token, ",")) {
5248 ++c_token;
5249 ticscale[ticlevel++] = real_expression();
5250 if (ticlevel >= MAX_TICLEVEL)
5251 break;
5252 }
5253 }
5254 }
5255
5256
5257 /* process 'set ticslevel' command */
5258 /* is datatype 'time' relevant here ? */
5259 static void
set_ticslevel()5260 set_ticslevel()
5261 {
5262 c_token++;
5263 xyplane.z = real_expression();
5264 xyplane.absolute = FALSE;
5265 }
5266
5267
5268 /* process 'set xyplane' command */
5269 /* is datatype 'time' relevant here ? */
5270 static void
set_xyplane()5271 set_xyplane()
5272 {
5273 if (equals(++c_token, "at")) {
5274 c_token++;
5275 xyplane.z = real_expression();
5276 xyplane.absolute = TRUE;
5277 return;
5278 } else if (!almost_equals(c_token,"rel$ative")) {
5279 c_token--;
5280 /* int_warn(NO_CARET, "deprecated syntax"); */
5281 }
5282 set_ticslevel();
5283 }
5284
5285
5286 /* Process 'set timefmt' command */
5287 /* HBB 20000507: changed this to a per-axis setting. I.e. you can now
5288 * have separate timefmt parse strings, different axes */
5289 /* V5 Oct 2014: But that was never documented, and makes little sense since
5290 * the input format is a property of the data file, not the graph axis.
5291 * Revert to a single global default timefmt as documented.
5292 * If the default is not sufficient, use timecolumn(N,"format") on input.
5293 * Use "set {axis}tics format" to control the output format.
5294 */
5295 static void
set_timefmt()5296 set_timefmt()
5297 {
5298 char *ctmp;
5299 c_token++;
5300
5301 if ((ctmp = try_to_get_string())) {
5302 free(timefmt);
5303 timefmt = ctmp;
5304 } else {
5305 free(timefmt);
5306 timefmt = gp_strdup(TIMEFMT);
5307 }
5308 }
5309
5310
5311 /* process 'set timestamp' command */
5312 static void
set_timestamp()5313 set_timestamp()
5314 {
5315 TBOOLEAN got_format = FALSE;
5316 char *new;
5317
5318 c_token++;
5319
5320 while (!END_OF_COMMAND) {
5321
5322 if (almost_equals(c_token,"t$op")) {
5323 timelabel_bottom = FALSE;
5324 c_token++;
5325 continue;
5326 } else if (almost_equals(c_token, "b$ottom")) {
5327 timelabel_bottom = TRUE;
5328 c_token++;
5329 continue;
5330 }
5331
5332 if (almost_equals(c_token,"r$otate")) {
5333 timelabel.rotate = TEXT_VERTICAL;
5334 c_token++;
5335 continue;
5336 } else if (almost_equals(c_token, "n$orotate")) {
5337 timelabel.rotate = 0;
5338 c_token++;
5339 continue;
5340 }
5341
5342 if (almost_equals(c_token,"off$set")) {
5343 c_token++;
5344 get_position_default(&(timelabel.offset), character, 3);
5345 continue;
5346 }
5347
5348 if (equals(c_token,"font")) {
5349 c_token++;
5350 new = try_to_get_string();
5351 free(timelabel.font);
5352 timelabel.font = new;
5353 continue;
5354 }
5355
5356 if (equals(c_token,"tc") || almost_equals(c_token,"text$color")) {
5357 parse_colorspec(&(timelabel.textcolor), TC_VARIABLE);
5358 continue;
5359 }
5360
5361 if (!got_format && ((new = try_to_get_string()))) {
5362 /* we have a format string */
5363 free(timelabel.text);
5364 timelabel.text = new;
5365 got_format = TRUE;
5366 continue;
5367 }
5368
5369 int_error(c_token,"unrecognized option");
5370
5371 }
5372
5373 if (!(timelabel.text))
5374 timelabel.text = gp_strdup(DEFAULT_TIMESTAMP_FORMAT);
5375 if (timelabel.rotate && !timelabel_bottom)
5376 timelabel.pos = RIGHT;
5377 else
5378 timelabel.pos = LEFT;
5379 }
5380
5381
5382 /* process 'set view' command */
5383 static void
set_view()5384 set_view()
5385 {
5386 int i;
5387 TBOOLEAN was_comma = TRUE;
5388 static const char errmsg1[] = "rot_%c must be in [0:%d] degrees range; view unchanged";
5389 static const char errmsg2[] = "%sscale must be > 0; view unchanged";
5390 double local_vals[4];
5391
5392 c_token++;
5393 if (equals(c_token,"map")) {
5394 splot_map = TRUE;
5395 mapview_scale = 1.0;
5396 c_token++;
5397 if (equals(c_token,"scale")) {
5398 c_token++;
5399 mapview_scale = real_expression();
5400 }
5401 if (aspect_ratio_3D != 0) {
5402 aspect_ratio = -1;
5403 aspect_ratio_3D = 0;
5404 }
5405 return;
5406 };
5407
5408 if (splot_map == TRUE)
5409 splot_map = FALSE; /* default is no map */
5410
5411 if (almost_equals(c_token,"equal$_axes")) {
5412 c_token++;
5413 if (END_OF_COMMAND || equals(c_token,"xy")) {
5414 aspect_ratio_3D = 2;
5415 c_token++;
5416 } else if (equals(c_token,"xyz")) {
5417 aspect_ratio_3D = 3;
5418 c_token++;
5419 }
5420 return;
5421 } else if (almost_equals(c_token,"noequal$_axes")) {
5422 aspect_ratio_3D = 0;
5423 c_token++;
5424 return;
5425 }
5426
5427 if (equals(c_token,"azimuth")) {
5428 c_token++;
5429 azimuth = real_expression();
5430 return;
5431 }
5432
5433 local_vals[0] = surface_rot_x;
5434 local_vals[1] = surface_rot_z;
5435 local_vals[2] = surface_scale;
5436 local_vals[3] = surface_zscale;
5437 for (i = 0; i < 4 && !(END_OF_COMMAND);) {
5438 if (equals(c_token,",")) {
5439 if (was_comma) i++;
5440 was_comma = TRUE;
5441 c_token++;
5442 } else {
5443 if (!was_comma)
5444 int_error(c_token, "',' expected");
5445 local_vals[i] = real_expression();
5446 i++;
5447 was_comma = FALSE;
5448 }
5449 }
5450
5451 if (local_vals[0] < 0 || local_vals[0] > 360)
5452 int_error(c_token, errmsg1, 'x', 360);
5453 if (local_vals[1] < 0 || local_vals[1] > 360)
5454 int_error(c_token, errmsg1, 'z', 360);
5455 if (local_vals[2] < 1e-6)
5456 int_error(c_token, errmsg2, "");
5457 if (local_vals[3] < 1e-6)
5458 int_error(c_token, errmsg2, "z");
5459
5460 surface_rot_x = local_vals[0];
5461 surface_rot_z = local_vals[1];
5462 surface_scale = local_vals[2];
5463 surface_zscale = local_vals[3];
5464 surface_lscale = log(surface_scale);
5465 }
5466
5467
5468 /* process 'set zero' command */
5469 static void
set_zero()5470 set_zero()
5471 {
5472 struct value a;
5473 c_token++;
5474 zero = magnitude(const_express(&a));
5475 }
5476
5477
5478 /* process 'set {x|y|z|x2|y2}data' command */
5479 static void
set_timedata(struct axis * this_axis)5480 set_timedata(struct axis *this_axis)
5481 {
5482 c_token++;
5483 this_axis->datatype = DT_NORMAL;
5484 if (almost_equals(c_token,"t$ime")) {
5485 this_axis->datatype = DT_TIMEDATE;
5486 c_token++;
5487 } else if (almost_equals(c_token,"geo$graphic")) {
5488 this_axis->datatype = DT_DMS;
5489 c_token++;
5490 }
5491 /* FIXME: this provides approximate backwards compatibility */
5492 /* but may be more trouble to explain than it's worth */
5493 this_axis->tictype = this_axis->datatype;
5494 }
5495
5496
5497 static void
set_range(struct axis * this_axis)5498 set_range(struct axis *this_axis)
5499 {
5500 c_token++;
5501
5502 if (almost_equals(c_token,"re$store")) {
5503 c_token++;
5504 this_axis->set_min = this_axis->writeback_min;
5505 this_axis->set_max = this_axis->writeback_max;
5506 this_axis->set_autoscale = AUTOSCALE_NONE;
5507 } else {
5508 if (!equals(c_token,"["))
5509 int_error(c_token, "expecting '[' or 'restore'");
5510 c_token++;
5511 this_axis->set_autoscale =
5512 load_range(this_axis,
5513 &this_axis->set_min, &this_axis->set_max,
5514 this_axis->set_autoscale);
5515 if (!equals(c_token,"]"))
5516 int_error(c_token, "expecting ']'");
5517 c_token++;
5518 while (!END_OF_COMMAND) {
5519 if (almost_equals(c_token, "rev$erse")) {
5520 ++c_token;
5521 this_axis->range_flags |= RANGE_IS_REVERSED;
5522 } else if (almost_equals(c_token, "norev$erse")) {
5523 ++c_token;
5524 this_axis->range_flags &= ~RANGE_IS_REVERSED;
5525 } else if (almost_equals(c_token, "wr$iteback")) {
5526 ++c_token;
5527 this_axis->range_flags |= RANGE_WRITEBACK;
5528 } else if (almost_equals(c_token, "nowri$teback")) {
5529 ++c_token;
5530 this_axis->range_flags &= ~RANGE_WRITEBACK;
5531 } else if (almost_equals(c_token, "ext$end")) {
5532 ++c_token;
5533 this_axis->set_autoscale &= ~(AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX);
5534 } else if (almost_equals(c_token, "noext$end")) {
5535 ++c_token;
5536 this_axis->set_autoscale |= AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX;
5537 } else
5538 int_error(c_token,"unrecognized option");
5539 }
5540 }
5541
5542 /* If this is one end of a linked axis pair, replicate the new range to the */
5543 /* linked axis, possibly via a mapping function. */
5544 if (this_axis->linked_to_secondary)
5545 clone_linked_axes(this_axis, this_axis->linked_to_secondary);
5546 else if (this_axis->linked_to_primary)
5547 clone_linked_axes(this_axis, this_axis->linked_to_primary);
5548 }
5549
5550 /*
5551 * set paxis <axis> {range <range-options> | tics <tic-options> }
5552 */
5553 static void
set_paxis()5554 set_paxis()
5555 {
5556 int p;
5557 c_token++;
5558 p = int_expression();
5559
5560 if (p <= 0 || p > MAX_PARALLEL_AXES)
5561 int_error(c_token-1, "illegal paxis");
5562 if (p > num_parallel_axes)
5563 extend_parallel_axis(p);
5564
5565 if (equals(c_token, "range"))
5566 set_range( ¶llel_axis[p-1] );
5567 else if (almost_equals(c_token, "tic$s"))
5568 set_tic_prop( ¶llel_axis[p-1] );
5569 else
5570 int_error(c_token, "expecting 'range' or 'tics'");
5571 }
5572
5573 static void
set_raxis()5574 set_raxis()
5575 {
5576 raxis = TRUE;
5577 c_token++;
5578 }
5579
5580 /* process 'set {xyz}zeroaxis' command */
5581 static void
set_zeroaxis(AXIS_INDEX axis)5582 set_zeroaxis(AXIS_INDEX axis)
5583 {
5584 c_token++;
5585 if (axis_array[axis].zeroaxis != (void *)(&default_axis_zeroaxis))
5586 free(axis_array[axis].zeroaxis);
5587 if (END_OF_COMMAND)
5588 axis_array[axis].zeroaxis = (void *)(&default_axis_zeroaxis);
5589 else {
5590 /* Some non-default style for the zeroaxis */
5591 axis_array[axis].zeroaxis = gp_alloc(sizeof(lp_style_type), "zeroaxis");
5592 *(axis_array[axis].zeroaxis) = default_axis_zeroaxis;
5593 lp_parse(axis_array[axis].zeroaxis, LP_ADHOC, FALSE);
5594 }
5595 }
5596
5597 /* process 'set zeroaxis' command */
5598 static void
set_allzeroaxis()5599 set_allzeroaxis()
5600 {
5601 int save_token = c_token;
5602 set_zeroaxis(FIRST_X_AXIS);
5603 c_token = save_token;
5604 set_zeroaxis(FIRST_Y_AXIS);
5605 c_token = save_token;
5606 set_zeroaxis(FIRST_Z_AXIS);
5607 }
5608
5609 /* Implements 'set tics' 'set xtics' 'set ytics' etc */
5610 static int
set_tic_prop(struct axis * this_axis)5611 set_tic_prop(struct axis *this_axis)
5612 {
5613 int match = 0; /* flag, set by matching a tic command */
5614 char nocmd[12]; /* fill w/ "no"+axis_name+suffix */
5615 char *cmdptr = NULL, *sfxptr = NULL;
5616 AXIS_INDEX axis = this_axis->index;
5617
5618 if (axis < NUMBER_OF_MAIN_VISIBLE_AXES) {
5619 (void) strcpy(nocmd, "no");
5620 cmdptr = &nocmd[2];
5621 (void) strcpy(cmdptr, axis_name(axis));
5622 sfxptr = &nocmd[strlen(nocmd)];
5623 (void) strcpy(sfxptr, "t$ics"); /* STRING */
5624 }
5625 if (axis == THETA_AXIS.index)
5626 cmdptr = "ttics";
5627
5628 if (almost_equals(c_token, cmdptr) || axis >= PARALLEL_AXES) {
5629 TBOOLEAN axisset = FALSE;
5630 TBOOLEAN mirror_opt = FALSE; /* set to true if (no)mirror option specified) */
5631 this_axis->ticdef.def.mix = FALSE;
5632 match = 1;
5633 ++c_token;
5634 do {
5635 if (almost_equals(c_token, "ax$is")) {
5636 axisset = TRUE;
5637 this_axis->ticmode &= ~TICS_ON_BORDER;
5638 this_axis->ticmode |= TICS_ON_AXIS;
5639 ++c_token;
5640 } else if (almost_equals(c_token, "bo$rder")) {
5641 this_axis->ticmode &= ~TICS_ON_AXIS;
5642 this_axis->ticmode |= TICS_ON_BORDER;
5643 ++c_token;
5644 } else if (almost_equals(c_token, "mi$rror")) {
5645 this_axis->ticmode |= TICS_MIRROR;
5646 mirror_opt = TRUE;
5647 ++c_token;
5648 } else if (almost_equals(c_token, "nomi$rror")) {
5649 this_axis->ticmode &= ~TICS_MIRROR;
5650 mirror_opt = TRUE;
5651 ++c_token;
5652 } else if (almost_equals(c_token, "in$wards")) {
5653 this_axis->tic_in = TRUE;
5654 ++c_token;
5655 } else if (almost_equals(c_token, "out$wards")) {
5656 this_axis->tic_in = FALSE;
5657 ++c_token;
5658 } else if (almost_equals(c_token, "sc$ale")) {
5659 ++c_token;
5660 if (almost_equals(c_token, "def$ault")) {
5661 this_axis->ticscale = 1.0;
5662 this_axis->miniticscale = 0.5;
5663 ++c_token;
5664 } else {
5665 this_axis->ticscale = real_expression();
5666 if (equals(c_token, ",")) {
5667 ++c_token;
5668 this_axis->miniticscale = real_expression();
5669 } else
5670 this_axis->miniticscale = 0.5 * this_axis->ticscale;
5671 }
5672 } else if (almost_equals(c_token, "ro$tate")) {
5673 this_axis->tic_rotate = TEXT_VERTICAL;
5674 ++c_token;
5675 if (equals(c_token, "by")) {
5676 c_token++;
5677 this_axis->tic_rotate = int_expression();
5678 }
5679 } else if (almost_equals(c_token, "noro$tate")) {
5680 this_axis->tic_rotate = 0;
5681 ++c_token;
5682 } else if (almost_equals(c_token, "off$set")) {
5683 ++c_token;
5684 get_position_default(&this_axis->ticdef.offset,
5685 character, 3);
5686 } else if (almost_equals(c_token, "nooff$set")) {
5687 ++c_token;
5688 this_axis->ticdef.offset = default_offset;
5689 } else if (almost_equals(c_token, "l$eft")) {
5690 this_axis->tic_pos = LEFT;
5691 this_axis->manual_justify = TRUE;
5692 c_token++;
5693 } else if (almost_equals(c_token, "c$entre")
5694 || almost_equals(c_token, "c$enter")) {
5695 this_axis->tic_pos = CENTRE;
5696 this_axis->manual_justify = TRUE;
5697 c_token++;
5698 } else if (almost_equals(c_token, "ri$ght")) {
5699 this_axis->tic_pos = RIGHT;
5700 this_axis->manual_justify = TRUE;
5701 c_token++;
5702 } else if (almost_equals(c_token, "autoj$ustify")) {
5703 this_axis->manual_justify = FALSE;
5704 c_token++;
5705 } else if (almost_equals(c_token,"range$limited")) {
5706 this_axis->ticdef.rangelimited = TRUE;
5707 ++c_token;
5708 } else if (almost_equals(c_token,"norange$limited")) {
5709 this_axis->ticdef.rangelimited = FALSE;
5710 ++c_token;
5711 } else if (almost_equals(c_token, "f$ont")) {
5712 ++c_token;
5713 /* Make sure they've specified a font */
5714 if (!isstringvalue(c_token))
5715 int_error(c_token,"expected font");
5716 else {
5717 free(this_axis->ticdef.font);
5718 this_axis->ticdef.font = NULL;
5719 this_axis->ticdef.font = try_to_get_string();
5720 }
5721
5722 /* The geographic/timedate/numeric options are new in version 5 */
5723 } else if (almost_equals(c_token,"geo$graphic")) {
5724 ++c_token;
5725 this_axis->tictype = DT_DMS;
5726 } else if (almost_equals(c_token,"time$date")) {
5727 ++c_token;
5728 this_axis->tictype = DT_TIMEDATE;
5729 } else if (almost_equals(c_token,"numeric")) {
5730 ++c_token;
5731 this_axis->tictype = DT_NORMAL;
5732
5733 } else if (equals(c_token,"format")) {
5734 char *format;
5735 ++c_token;
5736 if (END_OF_COMMAND)
5737 format = gp_strdup(DEF_FORMAT);
5738 else if (!((format = try_to_get_string())))
5739 int_error(c_token,"expected format");
5740 free(this_axis->formatstring);
5741 this_axis->formatstring = format;
5742 } else if (almost_equals(c_token, "enh$anced")) {
5743 ++c_token;
5744 this_axis->ticdef.enhanced = TRUE;
5745 } else if (almost_equals(c_token, "noenh$anced")) {
5746 ++c_token;
5747 this_axis->ticdef.enhanced = FALSE;
5748 } else if (equals(c_token,"tc") ||
5749 almost_equals(c_token,"text$color")) {
5750 parse_colorspec(&this_axis->ticdef.textcolor,
5751 axis == FIRST_Z_AXIS ? TC_Z : TC_FRAC);
5752 } else if (almost_equals(c_token, "au$tofreq")) {
5753 /* auto tic interval */
5754 ++c_token;
5755 if (!this_axis->ticdef.def.mix) {
5756 free_marklist(this_axis->ticdef.def.user);
5757 this_axis->ticdef.def.user = NULL;
5758 }
5759 this_axis->ticdef.type = TIC_COMPUTED;
5760 #ifdef NONLINEAR_AXES
5761 } else if (almost_equals(c_token, "log$scale")) {
5762 ++c_token;
5763 this_axis->ticdef.logscaling = TRUE;
5764 } else if (almost_equals(c_token, "nolog$scale")) {
5765 ++c_token;
5766 this_axis->ticdef.logscaling = FALSE;
5767 #endif
5768 } else if (equals(c_token,"add")) {
5769 ++c_token;
5770 this_axis->ticdef.def.mix = TRUE;
5771 } else if (!END_OF_COMMAND) {
5772 load_tics(this_axis);
5773 }
5774 } while (!END_OF_COMMAND);
5775
5776 /* if tics are off and not set by axis, reset to default (border) */
5777 if (((this_axis->ticmode & TICS_MASK) == NO_TICS) && (!axisset)) {
5778 if (axis >= PARALLEL_AXES)
5779 this_axis->ticmode |= TICS_ON_AXIS;
5780 else
5781 this_axis->ticmode |= TICS_ON_BORDER;
5782 if ((mirror_opt == FALSE) && ((axis == FIRST_X_AXIS) || (axis == FIRST_Y_AXIS) || (axis == COLOR_AXIS))) {
5783 this_axis->ticmode |= TICS_MIRROR;
5784 }
5785 }
5786
5787 }
5788
5789 /* The remaining command options cannot work for parametric or parallel axes */
5790 if (axis >= NUMBER_OF_MAIN_VISIBLE_AXES)
5791 return match;
5792
5793 if (almost_equals(c_token, nocmd)) { /* NOSTRING */
5794 this_axis->ticmode &= ~TICS_MASK;
5795 c_token++;
5796 match = 1;
5797 }
5798
5799 /* other options */
5800
5801 (void) strcpy(sfxptr, "m$tics"); /* MONTH */
5802 if (almost_equals(c_token, cmdptr)) {
5803 if (!this_axis->ticdef.def.mix) {
5804 free_marklist(this_axis->ticdef.def.user);
5805 this_axis->ticdef.def.user = NULL;
5806 }
5807 this_axis->ticdef.type = TIC_MONTH;
5808 ++c_token;
5809 match = 1;
5810 }
5811 if (almost_equals(c_token, nocmd)) { /* NOMONTH */
5812 this_axis->ticdef.type = TIC_COMPUTED;
5813 ++c_token;
5814 match = 1;
5815 }
5816 (void) strcpy(sfxptr, "d$tics"); /* DAYS */
5817 if (almost_equals(c_token, cmdptr)) {
5818 match = 1;
5819 if (!this_axis->ticdef.def.mix) {
5820 free_marklist(this_axis->ticdef.def.user);
5821 this_axis->ticdef.def.user = NULL;
5822 }
5823 this_axis->ticdef.type = TIC_DAY;
5824 ++c_token;
5825 }
5826 if (almost_equals(c_token, nocmd)) { /* NODAYS */
5827 this_axis->ticdef.type = TIC_COMPUTED;
5828 ++c_token;
5829 match = 1;
5830 }
5831 *cmdptr = 'm';
5832 (void) strcpy(cmdptr + 1, axis_name(axis));
5833 (void) strcat(cmdptr, "t$ics"); /* MINISTRING */
5834
5835 if (almost_equals(c_token, cmdptr)) {
5836 c_token++;
5837 match = 1;
5838 if (END_OF_COMMAND) {
5839 this_axis->minitics = MINI_AUTO;
5840 } else if (almost_equals(c_token, "def$ault")) {
5841 this_axis->minitics = MINI_DEFAULT;
5842 ++c_token;
5843 } else {
5844 int freq = int_expression();
5845 if (freq > 0 && freq < 101) {
5846 this_axis->mtic_freq = freq;
5847 this_axis->minitics = MINI_USER;
5848 } else {
5849 this_axis->minitics = MINI_DEFAULT;
5850 int_warn(c_token-1,"Expecting number of intervals");
5851 }
5852 }
5853 }
5854 if (almost_equals(c_token, nocmd)) { /* NOMINI */
5855 this_axis->minitics = MINI_OFF;
5856 c_token++;
5857 match = 1;
5858 }
5859 return (match);
5860 }
5861
5862 /*
5863 * minor tics around perimeter of polar grid circle (theta).
5864 * This version works like other axes (parameter is # of subintervals)
5865 * but it might be more reasonable to simply take increment in degress.
5866 */
5867 static void
set_mttics(struct axis * this_axis)5868 set_mttics(struct axis *this_axis)
5869 {
5870 c_token++;
5871
5872 if (END_OF_COMMAND) {
5873 this_axis->minitics = MINI_AUTO;
5874 ++c_token;
5875 } else {
5876 int freq = int_expression();
5877 if (freq > 0 && freq < 361) {
5878 this_axis->mtic_freq = freq;
5879 this_axis->minitics = MINI_USER;
5880 } else {
5881 this_axis->minitics = MINI_AUTO;
5882 int_warn(c_token-1,"Expecting number of intervals");
5883 }
5884 }
5885 }
5886
5887 /* process a 'set {x/y/z}label command */
5888 /* set {x/y/z}label {label_text} {offset {x}{,y}} {<fontspec>} {<textcolor>} */
5889 static void
set_xyzlabel(text_label * label)5890 set_xyzlabel(text_label *label)
5891 {
5892 char *text = NULL;
5893
5894 c_token++;
5895 if (END_OF_COMMAND) { /* no label specified */
5896 free(label->text);
5897 label->text = NULL;
5898 return;
5899 }
5900
5901 parse_label_options(label, 0);
5902
5903 if (!END_OF_COMMAND) {
5904 text = try_to_get_string();
5905 if (text) {
5906 free(label->text);
5907 label->text = text;
5908 }
5909 }
5910
5911 parse_label_options(label, 0);
5912
5913 }
5914
5915
5916 /*
5917 * Change or insert a new linestyle in a list of line styles.
5918 * Supports the old 'set linestyle' command (backwards-compatible)
5919 * and the new "set style line" and "set linetype" commands.
5920 * destination_class is either LP_STYLE or LP_TYPE.
5921 */
5922 static void
set_linestyle(struct linestyle_def ** head,lp_class destination_class)5923 set_linestyle(struct linestyle_def **head, lp_class destination_class)
5924 {
5925 struct linestyle_def *this_linestyle = NULL;
5926 struct linestyle_def *new_linestyle = NULL;
5927 struct linestyle_def *prev_linestyle = NULL;
5928 int tag;
5929
5930 c_token++;
5931
5932 /* get tag */
5933 if (END_OF_COMMAND || ((tag = int_expression()) <= 0))
5934 int_error(c_token, "tag must be > zero");
5935
5936 /* Check if linestyle is already defined */
5937 for (this_linestyle = *head; this_linestyle != NULL;
5938 prev_linestyle = this_linestyle, this_linestyle = this_linestyle->next)
5939 if (tag <= this_linestyle->tag)
5940 break;
5941
5942 if (this_linestyle == NULL || tag != this_linestyle->tag) {
5943 /* Default style is based on linetype with the same tag id */
5944 struct lp_style_type loc_lp = DEFAULT_LP_STYLE_TYPE;
5945 loc_lp.l_type = tag - 1;
5946 loc_lp.p_type = tag - 1;
5947 loc_lp.d_type = DASHTYPE_SOLID;
5948 loc_lp.pm3d_color.type = TC_LT;
5949 loc_lp.pm3d_color.lt = tag - 1;
5950
5951 new_linestyle = gp_alloc(sizeof(struct linestyle_def), "linestyle");
5952 if (prev_linestyle != NULL)
5953 prev_linestyle->next = new_linestyle; /* add it to end of list */
5954 else
5955 *head = new_linestyle; /* make it start of list */
5956 new_linestyle->tag = tag;
5957 new_linestyle->next = this_linestyle;
5958 new_linestyle->lp_properties = loc_lp;
5959 this_linestyle = new_linestyle;
5960 }
5961
5962 if (almost_equals(c_token, "def$ault")) {
5963 delete_linestyle(head, prev_linestyle, this_linestyle);
5964 c_token++;
5965 } else
5966 /* pick up a line spec; dont allow ls, do allow point type */
5967 lp_parse(&this_linestyle->lp_properties, destination_class, TRUE);
5968
5969 if (!END_OF_COMMAND)
5970 int_error(c_token,"Extraneous arguments to set %s",
5971 head == &first_perm_linestyle ? "linetype" : "style line");
5972 }
5973
5974 /*
5975 * Delete linestyle from linked list.
5976 * Called with pointers to the head of the list,
5977 * to the previous linestyle (not strictly necessary),
5978 * and to the linestyle to delete.
5979 */
5980 void
delete_linestyle(struct linestyle_def ** head,struct linestyle_def * prev,struct linestyle_def * this)5981 delete_linestyle(struct linestyle_def **head, struct linestyle_def *prev, struct linestyle_def *this)
5982 {
5983 if (this != NULL) { /* there really is something to delete */
5984 if (this == *head)
5985 *head = this->next;
5986 else
5987 prev->next = this->next;
5988 free(this);
5989 }
5990 }
5991
5992
5993 /* ======================================================== */
5994 /* process a 'set arrowstyle' command */
5995 /* set style arrow {tag} {nohead|head|backhead|heads} {size l,a{,b}} {{no}filled} {linestyle...} {layer n}*/
5996 static void
set_arrowstyle()5997 set_arrowstyle()
5998 {
5999 struct arrowstyle_def *this_arrowstyle = NULL;
6000 struct arrowstyle_def *new_arrowstyle = NULL;
6001 struct arrowstyle_def *prev_arrowstyle = NULL;
6002 struct arrow_style_type loc_arrow;
6003 int tag;
6004
6005 default_arrow_style(&loc_arrow);
6006
6007 c_token++;
6008
6009 /* get tag */
6010 if (!END_OF_COMMAND) {
6011 /* must be a tag expression! */
6012 tag = int_expression();
6013 if (tag <= 0)
6014 int_error(c_token, "tag must be > zero");
6015 } else
6016 tag = assign_arrowstyle_tag(); /* default next tag */
6017
6018 /* search for arrowstyle */
6019 if (first_arrowstyle != NULL) { /* skip to last arrowstyle */
6020 for (this_arrowstyle = first_arrowstyle; this_arrowstyle != NULL;
6021 prev_arrowstyle = this_arrowstyle,
6022 this_arrowstyle = this_arrowstyle->next)
6023 /* is this the arrowstyle we want? */
6024 if (tag <= this_arrowstyle->tag)
6025 break;
6026 }
6027
6028 if (this_arrowstyle == NULL || tag != this_arrowstyle->tag) {
6029 /* adding the arrowstyle */
6030 new_arrowstyle = (struct arrowstyle_def *)
6031 gp_alloc(sizeof(struct arrowstyle_def), "arrowstyle");
6032 default_arrow_style(&(new_arrowstyle->arrow_properties));
6033 if (prev_arrowstyle != NULL)
6034 prev_arrowstyle->next = new_arrowstyle; /* add it to end of list */
6035 else
6036 first_arrowstyle = new_arrowstyle; /* make it start of list */
6037 new_arrowstyle->arrow_properties.tag = tag;
6038 new_arrowstyle->tag = tag;
6039 new_arrowstyle->next = this_arrowstyle;
6040 this_arrowstyle = new_arrowstyle;
6041 }
6042
6043 if (END_OF_COMMAND)
6044 this_arrowstyle->arrow_properties = loc_arrow;
6045 else if (almost_equals(c_token, "def$ault")) {
6046 this_arrowstyle->arrow_properties = loc_arrow;
6047 c_token++;
6048 } else
6049 /* pick up a arrow spec : dont allow arrowstyle */
6050 arrow_parse(&this_arrowstyle->arrow_properties, FALSE);
6051
6052 if (!END_OF_COMMAND)
6053 int_error(c_token, "extraneous or out-of-order arguments in set arrowstyle");
6054
6055 }
6056
6057 /* assign a new arrowstyle tag
6058 * arrowstyles are kept sorted by tag number, so this is easy
6059 * returns the lowest unassigned tag number
6060 */
6061 static int
assign_arrowstyle_tag()6062 assign_arrowstyle_tag()
6063 {
6064 struct arrowstyle_def *this;
6065 int last = 0; /* previous tag value */
6066
6067 for (this = first_arrowstyle; this != NULL; this = this->next)
6068 if (this->tag == last + 1)
6069 last++;
6070 else
6071 break;
6072
6073 return (last + 1);
6074 }
6075
6076 /* For set [xy]tics... command */
6077 static void
load_tics(struct axis * this_axis)6078 load_tics(struct axis *this_axis)
6079 {
6080 if (equals(c_token, "(")) { /* set : TIC_USER */
6081 c_token++;
6082 load_tic_user(this_axis);
6083 } else { /* series : TIC_SERIES */
6084 load_tic_series(this_axis);
6085 }
6086 }
6087
6088 /* load TIC_USER definition */
6089 /* (tic[,tic]...)
6090 * where tic is ["string"] value [level]
6091 * Left paren is already scanned off before entry.
6092 */
6093 static void
load_tic_user(struct axis * this_axis)6094 load_tic_user(struct axis *this_axis)
6095 {
6096 char *ticlabel;
6097 double ticposition;
6098
6099 /* Free any old tic labels */
6100 if (!this_axis->ticdef.def.mix && !(set_iterator && set_iterator->iteration)) {
6101 free_marklist(this_axis->ticdef.def.user);
6102 this_axis->ticdef.def.user = NULL;
6103 }
6104
6105 /* Mark this axis as user-generated ticmarks only, unless the */
6106 /* mix flag indicates that both user- and auto- tics are OK. */
6107 if (!this_axis->ticdef.def.mix)
6108 this_axis->ticdef.type = TIC_USER;
6109
6110 while (!END_OF_COMMAND && !equals(c_token,")")) {
6111 int ticlevel=0;
6112 int save_token;
6113 /* syntax is ( {'format'} value {level} {, ...} )
6114 * but for timedata, the value itself is a string, which
6115 * complicates things somewhat
6116 */
6117
6118 /* has a string with it? */
6119 save_token = c_token;
6120 ticlabel = try_to_get_string();
6121 if (ticlabel && this_axis->datatype == DT_TIMEDATE
6122 && (equals(c_token,",") || equals(c_token,")"))) {
6123 c_token = save_token;
6124 free(ticlabel);
6125 ticlabel = NULL;
6126 }
6127
6128 /* in any case get the value */
6129 ticposition = get_num_or_time(this_axis);
6130
6131 if (!END_OF_COMMAND &&
6132 !equals(c_token, ",") &&
6133 !equals(c_token, ")")) {
6134 ticlevel = int_expression(); /* tic level */
6135 }
6136
6137 /* add to list */
6138 add_tic_user(this_axis, ticlabel, ticposition, ticlevel);
6139 free(ticlabel);
6140
6141 /* expect "," or ")" here */
6142 if (!END_OF_COMMAND && equals(c_token, ","))
6143 c_token++; /* loop again */
6144 else
6145 break; /* hopefully ")" */
6146 }
6147
6148 if (END_OF_COMMAND || !equals(c_token, ")")) {
6149 free_marklist(this_axis->ticdef.def.user);
6150 this_axis->ticdef.def.user = NULL;
6151 int_error(c_token, "expecting right parenthesis )");
6152 }
6153 c_token++;
6154 }
6155
6156 void
free_marklist(struct ticmark * list)6157 free_marklist(struct ticmark *list)
6158 {
6159 while (list != NULL) {
6160 struct ticmark *freeable = list;
6161 list = list->next;
6162 if (freeable->label != NULL)
6163 free(freeable->label);
6164 free(freeable);
6165 }
6166 }
6167
6168 /* Remove tic labels that were read from a datafile during a previous plot
6169 * via the 'using xtics(n)' mechanism. These have tick level < 0.
6170 */
6171 struct ticmark *
prune_dataticks(struct ticmark * list)6172 prune_dataticks(struct ticmark *list)
6173 {
6174 struct ticmark a = {0.0,NULL,0,NULL};
6175 struct ticmark *b = &a;
6176 struct ticmark *tmp;
6177
6178 while (list) {
6179 if (list->level < 0) {
6180 free(list->label);
6181 tmp = list->next;
6182 free(list);
6183 list = tmp;
6184 } else {
6185 b->next = list;
6186 b = list;
6187 list = list->next;
6188 }
6189 }
6190 b->next = NULL;
6191 return a.next;
6192 }
6193
6194 /* load TIC_SERIES definition */
6195 /* [start,]incr[,end] */
6196 static void
load_tic_series(struct axis * this_axis)6197 load_tic_series(struct axis *this_axis)
6198 {
6199 double start, incr, end;
6200 int incr_token;
6201 struct ticdef *tdef = &(this_axis->ticdef);
6202
6203 start = get_num_or_time(this_axis);
6204
6205 if (!equals(c_token, ",")) {
6206 /* only step specified */
6207 incr_token = c_token;
6208 incr = start;
6209 start = -VERYLARGE;
6210 end = VERYLARGE;
6211 } else {
6212 c_token++;
6213 incr_token = c_token;
6214 incr = get_num_or_time(this_axis);
6215
6216 if (!equals(c_token, ",")) {
6217 /* only step and increment specified */
6218 end = VERYLARGE;
6219 } else {
6220 c_token++;
6221 end = get_num_or_time(this_axis);
6222 }
6223 }
6224
6225 if (start < end && incr <= 0)
6226 int_error(incr_token, "increment must be positive");
6227 if (start > end && incr >= 0)
6228 int_error(incr_token, "increment must be negative");
6229 if (start > end) {
6230 /* put in order */
6231 double numtics = floor((end * (1 + SIGNIF) - start) / incr);
6232
6233 end = start;
6234 start = end + numtics * incr;
6235 incr = -incr;
6236 }
6237
6238 if (!tdef->def.mix) { /* remove old list */
6239 free_marklist(tdef->def.user);
6240 tdef->def.user = NULL;
6241 }
6242 tdef->type = TIC_SERIES;
6243 tdef->def.series.start = start;
6244 tdef->def.series.incr = incr;
6245 tdef->def.series.end = end;
6246 }
6247
6248 /*
6249 * new_text_label() allocates and initializes a text_label structure.
6250 * This routine is also used by the plot and splot with labels commands.
6251 */
6252 struct text_label *
new_text_label(int tag)6253 new_text_label(int tag)
6254 {
6255 struct text_label *new;
6256
6257 new = gp_alloc( sizeof(struct text_label), "text_label");
6258 memset(new, 0, sizeof(struct text_label));
6259 new->tag = tag;
6260 new->place = default_position;
6261 new->pos = LEFT;
6262 new->textcolor.type = TC_DEFAULT;
6263 new->lp_properties.p_type = 1;
6264 new->offset = default_offset;
6265
6266 return(new);
6267 }
6268
6269 /*
6270 * Parse the sub-options for label style and placement.
6271 * This is called from set_label, and from plot2d and plot3d
6272 * to handle options for 'plot with labels'
6273 * Note: ndim = 2 means we are inside a plot command,
6274 * ndim = 3 means we are inside an splot command
6275 * ndim = 0 in a set command
6276 */
6277 void
parse_label_options(struct text_label * this_label,int ndim)6278 parse_label_options( struct text_label *this_label, int ndim)
6279 {
6280 struct position pos;
6281 char *font = NULL;
6282 enum JUSTIFY just = LEFT;
6283 int rotate = 0;
6284 TBOOLEAN set_position = FALSE, set_just = FALSE, set_point = FALSE,
6285 set_rot = FALSE, set_font = FALSE, set_offset = FALSE,
6286 set_layer = FALSE, set_textcolor = FALSE, set_hypertext = FALSE;
6287 int layer = LAYER_BACK;
6288 TBOOLEAN axis_label = (this_label->tag <= NONROTATING_LABEL_TAG);
6289 TBOOLEAN hypertext = FALSE;
6290 struct position offset = default_offset;
6291 t_colorspec textcolor = {TC_DEFAULT,0,0.0};
6292 struct lp_style_type loc_lp = DEFAULT_LP_STYLE_TYPE;
6293 loc_lp.flags = LP_NOT_INITIALIZED;
6294
6295 /* Now parse the label format and style options */
6296 while (!END_OF_COMMAND) {
6297 /* get position */
6298 if ((ndim == 0) && !set_position && equals(c_token, "at") && !axis_label) {
6299 c_token++;
6300 get_position(&pos);
6301 set_position = TRUE;
6302 continue;
6303 }
6304
6305 /* get justification */
6306 if (! set_just) {
6307 if (almost_equals(c_token, "l$eft")) {
6308 just = LEFT;
6309 c_token++;
6310 set_just = TRUE;
6311 continue;
6312 } else if (almost_equals(c_token, "c$entre")
6313 || almost_equals(c_token, "c$enter")) {
6314 just = CENTRE;
6315 c_token++;
6316 set_just = TRUE;
6317 continue;
6318 } else if (almost_equals(c_token, "r$ight")) {
6319 just = RIGHT;
6320 c_token++;
6321 set_just = TRUE;
6322 continue;
6323 }
6324 }
6325
6326 /* get rotation (added by RCC) */
6327 if (almost_equals(c_token, "rot$ate")) {
6328 c_token++;
6329 set_rot = TRUE;
6330 rotate = this_label->rotate;
6331 if (equals(c_token, "by")) {
6332 c_token++;
6333 rotate = int_expression();
6334 if (this_label->tag == ROTATE_IN_3D_LABEL_TAG)
6335 this_label->tag = NONROTATING_LABEL_TAG;
6336 } else if (almost_equals(c_token,"para$llel")) {
6337 if (this_label->tag >= 0)
6338 int_error(c_token,"invalid option");
6339 c_token++;
6340 this_label->tag = ROTATE_IN_3D_LABEL_TAG;
6341 } else if (almost_equals(c_token,"var$iable")) {
6342 if (ndim == 2) /* only in 2D plot with labels */
6343 this_label->tag = VARIABLE_ROTATE_LABEL_TAG;
6344 else
6345 set_rot = FALSE;
6346 c_token++;
6347 } else
6348 rotate = TEXT_VERTICAL;
6349 continue;
6350 } else if (almost_equals(c_token, "norot$ate")) {
6351 rotate = 0;
6352 c_token++;
6353 set_rot = TRUE;
6354 if (this_label->tag == ROTATE_IN_3D_LABEL_TAG)
6355 this_label->tag = NONROTATING_LABEL_TAG;
6356 continue;
6357 }
6358
6359 /* get font (added by DJL) */
6360 if (! set_font && equals(c_token, "font")) {
6361 c_token++;
6362 if ((font = try_to_get_string())) {
6363 set_font = TRUE;
6364 continue;
6365 } else
6366 int_error(c_token, "'fontname,fontsize' expected");
6367 }
6368
6369 /* Flag this as hypertext rather than a normal label */
6370 if (!set_hypertext && almost_equals(c_token,"hyper$text")) {
6371 c_token++;
6372 hypertext = TRUE;
6373 set_hypertext = TRUE;
6374 if (!set_point)
6375 loc_lp = default_hypertext_point_style;
6376 continue;
6377 } else if (!set_hypertext && almost_equals(c_token,"nohyper$text")) {
6378 c_token++;
6379 hypertext = FALSE;
6380 set_hypertext = TRUE;
6381 continue;
6382 }
6383
6384 /* get front/back (added by JDP) */
6385 if ((ndim == 0) && !set_layer && !axis_label) {
6386 if (equals(c_token, "back")) {
6387 layer = LAYER_BACK;
6388 c_token++;
6389 set_layer = TRUE;
6390 continue;
6391 } else if (equals(c_token, "front")) {
6392 layer = LAYER_FRONT;
6393 c_token++;
6394 set_layer = TRUE;
6395 continue;
6396 }
6397 }
6398
6399 #ifdef EAM_BOXED_TEXT
6400 if (equals(c_token, "boxed")) {
6401 this_label->boxed = 1;
6402 c_token++;
6403 continue;
6404 } else if (equals(c_token, "noboxed")) {
6405 this_label->boxed = 0;
6406 c_token++;
6407 continue;
6408 }
6409 #endif
6410
6411 if (!axis_label && (loc_lp.flags == LP_NOT_INITIALIZED || set_hypertext)) {
6412 if (almost_equals(c_token, "po$int")) {
6413 int stored_token = ++c_token;
6414 struct lp_style_type tmp_lp;
6415 loc_lp.flags = LP_SHOW_POINTS;
6416 tmp_lp = loc_lp;
6417 lp_parse(&tmp_lp, LP_ADHOC, TRUE);
6418 if (stored_token != c_token)
6419 loc_lp = tmp_lp;
6420 set_point = TRUE;
6421 continue;
6422 } else if (almost_equals(c_token, "nopo$int")) {
6423 loc_lp.flags = 0;
6424 c_token++;
6425 continue;
6426 }
6427 }
6428
6429 if (! set_offset && almost_equals(c_token, "of$fset")) {
6430 c_token++;
6431 get_position_default(&offset, character, ndim);
6432 set_offset = TRUE;
6433 continue;
6434 }
6435
6436 if ((equals(c_token,"tc") || almost_equals(c_token,"text$color"))
6437 && ! set_textcolor ) {
6438 parse_colorspec( &textcolor, TC_VARIABLE );
6439 set_textcolor = TRUE;
6440 continue;
6441 }
6442
6443 if (almost_equals(c_token,"noenh$anced")) {
6444 this_label->noenhanced = TRUE;
6445 c_token++;
6446 continue;
6447 } else if (almost_equals(c_token,"enh$anced")) {
6448 this_label->noenhanced = FALSE;
6449 c_token++;
6450 continue;
6451 }
6452
6453 /* Coming here means that none of the previous 'if's struck
6454 * its "continue" statement, i.e. whatever is in the command
6455 * line is forbidden by the 'set label' command syntax.
6456 * On the other hand, 'plot with labels' may have additional stuff coming up.
6457 */
6458 break;
6459
6460 } /* while(!END_OF_COMMAND) */
6461
6462 /* HBB 20011120: this chunk moved here, behind the while()
6463 * loop. Only after all options have been parsed it's safe to
6464 * overwrite the position if none has been specified. */
6465 if (!set_position)
6466 pos = default_position;
6467
6468 /* OK! copy the requested options into the label */
6469 if (set_position)
6470 this_label->place = pos;
6471 if (set_just)
6472 this_label->pos = just;
6473 if (set_rot)
6474 this_label->rotate = rotate;
6475 if (set_layer)
6476 this_label->layer = layer;
6477 if (set_font) {
6478 free(this_label->font);
6479 this_label->font = font;
6480 }
6481 if (set_textcolor)
6482 this_label->textcolor = textcolor;
6483 if ((loc_lp.flags & LP_NOT_INITIALIZED) == 0)
6484 this_label->lp_properties = loc_lp;
6485 if (set_offset)
6486 this_label->offset = offset;
6487 if (set_hypertext)
6488 this_label->hypertext = hypertext;
6489
6490 /* Make sure the z coord and the z-coloring agree */
6491 if (this_label->textcolor.type == TC_Z)
6492 this_label->textcolor.value = this_label->place.z;
6493 if (this_label->lp_properties.pm3d_color.type == TC_Z)
6494 this_label->lp_properties.pm3d_color.value = this_label->place.z;
6495 }
6496
6497
6498 /* <histogramstyle> = {clustered {gap <n>} | rowstacked | columnstacked */
6499 /* errorbars {gap <n>} {linewidth <lw>}} */
6500 /* {title <title_options>} */
6501 static void
parse_histogramstyle(histogram_style * hs,t_histogram_type def_type,int def_gap)6502 parse_histogramstyle( histogram_style *hs,
6503 t_histogram_type def_type,
6504 int def_gap)
6505 {
6506 text_label title_specs = EMPTY_LABELSTRUCT;
6507
6508 /* Set defaults */
6509 hs->type = def_type;
6510 hs->gap = def_gap;
6511
6512 if (END_OF_COMMAND)
6513 return;
6514 if (!equals(c_token,"hs") && !almost_equals(c_token,"hist$ogram"))
6515 return;
6516 c_token++;
6517
6518 while (!END_OF_COMMAND) {
6519 if (almost_equals(c_token, "clust$ered")) {
6520 hs->type = HT_CLUSTERED;
6521 c_token++;
6522 } else if (almost_equals(c_token, "error$bars")) {
6523 hs->type = HT_ERRORBARS;
6524 c_token++;
6525 } else if (almost_equals(c_token, "rows$tacked")) {
6526 hs->type = HT_STACKED_IN_LAYERS;
6527 c_token++;
6528 } else if (almost_equals(c_token, "columns$tacked")) {
6529 hs->type = HT_STACKED_IN_TOWERS;
6530 c_token++;
6531 } else if (equals(c_token, "gap")) {
6532 if (isanumber(++c_token))
6533 hs->gap = int_expression();
6534 else
6535 int_error(c_token,"expected gap value");
6536 } else if (almost_equals(c_token, "ti$tle")) {
6537 title_specs.offset = hs->title.offset;
6538 set_xyzlabel(&title_specs);
6539 free(title_specs.text);
6540 title_specs.text = NULL;
6541 if (hs->title.font) {
6542 free(hs->title.font);
6543 hs->title.font = NULL;
6544 }
6545 hs->title = title_specs;
6546 } else if ((equals(c_token,"lw") || almost_equals(c_token,"linew$idth"))
6547 && (hs->type == HT_ERRORBARS)) {
6548 c_token++;
6549 hs->bar_lw = real_expression();
6550 if (hs->bar_lw <= 0)
6551 hs->bar_lw = 1;
6552 } else
6553 /* We hit something unexpected */
6554 break;
6555 }
6556 }
6557
6558 /*
6559 * set pm3d lighting {primary <fraction>} {specular <fraction>}
6560 */
6561 static void
parse_lighting_options()6562 parse_lighting_options()
6563 {
6564 c_token++;
6565
6566 /* TODO: Add separate "set" commands for these */
6567 pm3d_shade.ambient = 1.0;
6568 pm3d_shade.Phong = 5.0; /* Phong exponent */
6569 pm3d_shade.rot_x = 45; /* illumination angle */
6570 pm3d_shade.rot_z = -45; /* illumination angle */
6571 pm3d_shade.fixed = TRUE; /* TRUE means the light does not rotate */
6572
6573 /* This is what you get from simply "set pm3d lighting" */
6574 pm3d_shade.strength = 0.5; /* contribution of primary light source */
6575 pm3d_shade.spec = 0.2; /* contribution of specular highlights */
6576
6577 while (!END_OF_COMMAND) {
6578 if (almost_equals(c_token,"primary")) {
6579 c_token++;
6580 pm3d_shade.strength = real_expression();
6581 pm3d_shade.strength = clip_to_01(pm3d_shade.strength);
6582 continue;
6583 }
6584
6585 if (almost_equals(c_token,"spec$ular")) {
6586 c_token++;
6587 pm3d_shade.spec = real_expression();
6588 pm3d_shade.spec = clip_to_01(pm3d_shade.spec);
6589 continue;
6590 }
6591
6592 break;
6593 }
6594
6595 c_token--;
6596 }
6597
6598 /* process 'set style parallelaxis' command */
6599 static void
set_style_parallel()6600 set_style_parallel()
6601 {
6602 c_token++;
6603 while (!END_OF_COMMAND) {
6604 int save_token = c_token;
6605 lp_parse( ¶llel_axis_style.lp_properties, LP_ADHOC, FALSE );
6606 if (save_token != c_token)
6607 continue;
6608 if (equals(c_token, "front"))
6609 parallel_axis_style.layer = LAYER_FRONT;
6610 else if (equals(c_token, "back"))
6611 parallel_axis_style.layer = LAYER_BACK;
6612 else
6613 int_error(c_token, "unrecognized option");
6614 c_token++;
6615 }
6616 }
6617
6618 /* Utility routine to propagate rrange into corresponding x and y ranges */
6619 void
rrange_to_xy()6620 rrange_to_xy()
6621 {
6622 double min;
6623
6624 /* An inverted R axis makes no sense in most cases.
6625 * One reasonable use is to project altitude/azimuth spherical coordinates
6626 * so that the zenith (azimuth = 90) is in the center and the horizon
6627 * (azimuth = 0) is at the perimeter.
6628 */
6629 if (R_AXIS.set_min > R_AXIS.set_max) {
6630 if (nonlinear(&R_AXIS))
6631 int_error(NO_CARET, "cannot invert nonlinear R axis");
6632 inverted_raxis = TRUE;
6633 } else {
6634 inverted_raxis = FALSE;
6635 }
6636
6637 if (R_AXIS.set_autoscale & AUTOSCALE_MIN)
6638 min = 0;
6639 else
6640 min = R_AXIS.set_min;
6641 if (R_AXIS.set_autoscale & AUTOSCALE_MAX) {
6642 X_AXIS.set_autoscale = AUTOSCALE_BOTH;
6643 Y_AXIS.set_autoscale = AUTOSCALE_BOTH;
6644 } else {
6645 X_AXIS.set_autoscale = AUTOSCALE_NONE;
6646 Y_AXIS.set_autoscale = AUTOSCALE_NONE;
6647 if (nonlinear(&R_AXIS))
6648 X_AXIS.set_max = eval_link_function(R_AXIS.linked_to_primary, R_AXIS.set_max)
6649 - eval_link_function(R_AXIS.linked_to_primary, min);
6650 else if (R_AXIS.log)
6651 /* NB: Can't get here if "set log" is implemented as nonlinear */
6652 X_AXIS.set_max = AXIS_DO_LOG(POLAR_AXIS, R_AXIS.set_max)
6653 - AXIS_DO_LOG(POLAR_AXIS, min);
6654 else
6655 X_AXIS.set_max = fabs(R_AXIS.set_max - min);
6656
6657 Y_AXIS.set_max = X_AXIS.set_max;
6658 Y_AXIS.set_min = X_AXIS.set_min = -X_AXIS.set_max;
6659 }
6660 }
6661
6662