1 // vim: noexpandtab tabstop=8 softtabstop=8 shiftwidth=8
2 /*
3 Gri - A language for scientific graphics programming
4 Copyright (C) 2010 Daniel Kelley
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <string>
22 #include <ctype.h>
23 #include <math.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "gr.hh"
27 #include "extern.hh"
28 #include "image_ex.hh"
29 #include "defaults.hh"
30 #include "files.hh"
31 #include "superus.hh"
32 #include "gr_coll.hh"
33 #include "GriState.hh"
34
35 static inline bool between(double x, double lim0, double lim1);
36 extern char _grTempString[];
37 void reset_top_of_plot(void);
38 bool ignore_initial_newline(void);
39 bool set_ignore_initial_newlineCmd(void);
40 bool set_image_colorscaleCmd(void);
41 bool set_image_grayscaleCmd(void);
42 bool set_image_grayscale_using_hist(void);
43 bool set_image_missingCmd(void);
44 bool set_image_rangeCmd(void);
45 bool set_grid_missingCmd(void);
46 bool set_grid_missing_curve(bool inside);
47 bool mask_an_island(double *x, double *y, unsigned int n);
48 bool set_y_axis_nameCmd(void);
49 // following shared with read.c
50 double _input_data_window_x_min = 1.0;
51 double _input_data_window_x_max = -1.0;
52 double _input_data_window_y_min = 1.0;
53 double _input_data_window_y_max = -1.0;
54 bool _input_data_window_x_exists = false;
55 bool _input_data_window_y_exists = false;
56 static bool already_landscape = false;
57 static double xleft, xright, xinc, ybottom, ytop, yinc;
58 static double tmp, tmp2;
59
between(double x,double lim0,double lim1)60 static inline bool between(double x, double lim0, double lim1)
61 {
62 if (lim0 <= x && x < lim1)
63 return true;
64 if (lim1 <= x && x < lim0)
65 return true;
66 return false;
67 }
68
69 void
reset_top_of_plot()70 reset_top_of_plot()
71 {
72 double margin, size;
73 get_var("..ymargin..", &margin);
74 get_var("..ysize..", &size);
75 _top_of_plot = margin + size;
76 }
77
78 static bool ignore_initial_newline_flag = false;
79 bool
set_ignore_initial_newlineCmd()80 set_ignore_initial_newlineCmd()
81 {
82 switch (_nword) {
83 case 4:
84 ignore_initial_newline_flag = true;
85 break;
86 case 5:
87 if (!strcmp(_word[4], "off")) {
88 ignore_initial_newline_flag = false;
89 return true;
90 } else {
91 demonstrate_command_usage();
92 return false;
93 }
94 default:
95 demonstrate_command_usage();
96 return false;
97 }
98 return false;
99 }
100 bool
ignore_initial_newline()101 ignore_initial_newline()
102 {
103 return ((ignore_initial_newline_flag) ? true : false);
104 }
105
106 bool
set_axes_styleCmd()107 set_axes_styleCmd()
108 {
109 if (_nword < 3) {
110 err("Too few words in `set axes'");
111 return false;
112 }
113 if (strcmp(_word[2], "style")) {
114 err("Third word of `set axes' must be \"style\".");
115 return false;
116 }
117 if (_nword < 4) {
118 err("`set axes style' to what?");
119 return false;
120 }
121 // `set axes style offset [.distance_cm.]'
122 if (_nword >= 4 && !strcmp(_word[3], "offset")) {
123 double tmp;
124 if (_nword == 5) {
125 if (!getdnum(_word[4], &tmp)) {
126 READ_WORD_ERROR(".distance_cm.");
127 return false;
128 }
129 _axes_offset = tmp;
130 } else if (!get_var("..tic_size..", &tmp)) {
131 err("Can't remember the tic size.");
132 return false;
133 }
134 _axes_offset = tmp;
135 return true;
136 }
137 switch (_nword) {
138 case 4:
139 // `set axes style .style.|rectangular|default|none'
140 if (!strcmp(_word[3], "default")) {
141 _axesStyle = 0;
142 _axes_offset = 0.0;
143 return true;
144 } else if (!strcmp(_word[3], "none")) {
145 _need_x_axis = false;
146 _need_y_axis = false;
147 } else if (!strcmp(_word[3], "rectangular")) {
148 // `set axes style rectangular'
149 _axesStyle = 0;
150 return true;
151 } else {
152 // `set axes style .style.'
153 if (!getdnum(_word[3], &tmp))
154 return false;
155 if (tmp < 0.0 || tmp > 2.0) {
156 err("Ignoring bad axes type <0 or >2");
157 return false;
158 }
159 _axesStyle = (int) floor(0.5 + tmp);
160 return true;
161 }
162 break;
163 default:
164 NUMBER_WORDS_ERROR;
165 return false;
166 }
167 return true;
168 }
169
170 // Set arrow head halfwidth into ..arrowsize..; a positive value indicates
171 // size in cm; a negative value
172 bool
set_arrow_sizeCmd()173 set_arrow_sizeCmd()
174 {
175 if (_nword < 3) {
176 err("`set arrow' what?");
177 return false;
178 }
179 if (!strcmp(_word[2], "size")) {
180 if (_nword < 4) {
181 err("`set arrow size' what?");
182 return false;
183 }
184 switch (_nword) {
185 case 4:
186 // set arrow size .size.|default
187 if (!strcmp(_word[3], "default")) {
188 PUT_VAR("..arrowsize..", ARROWSIZE_DEFAULT);
189 return true;
190 } else {
191 if (!getdnum(_word[3], &tmp)) {
192 err("Can't read arrow size");
193 return false;
194 }
195 if (tmp < 0.0) {
196 err("Ignoring bad (negative) arrow size.");
197 return false;
198 }
199 PUT_VAR("..arrowsize..", tmp);
200 return true;
201 }
202 // NOT REACHED
203 case 8:
204 // `set arrow size as .num. percent of length'
205 if (word_is(5, "percent") && word_is(6, "of") && word_is(7, "length")) {
206 Require(getdnum(_word[4], &tmp), err("Can't read percentage"));
207 Require(tmp >= 0.0, err("Ignoring bad (negative) percentage arrow size."));
208 PUT_VAR("..arrowsize..", -tmp / 100.0);
209 return true;
210 } else {
211 demonstrate_command_usage();
212 err("Cannot understand command");
213 return false;
214 }
215 // NOT REACHED
216 default:
217 demonstrate_command_usage();
218 NUMBER_WORDS_ERROR;
219 return false;
220 }
221 } else {
222 err("`set arrow' what?");
223 return false;
224 }
225 // NOT REACHED
226 }
227
228 bool
set_arrow_typeCmd()229 set_arrow_typeCmd()
230 {
231 if (_nword != 4) {
232 demonstrate_command_usage();
233 NUMBER_WORDS_ERROR;
234 return false;
235 }
236 double tmp;
237 if (!getdnum(_word[3], &tmp)) {
238 READ_WORD_ERROR(".which.");
239 return false;
240 }
241 _arrow_type = int(floor(0.5 + tmp));
242 if (_arrow_type != 0 && _arrow_type != 1 && _arrow_type != 2) {
243 err("Valid arrow types are 0, 1, and 2");
244 return false;
245 }
246 return true;
247 }
248
249 bool
set_beepCmd()250 set_beepCmd()
251 {
252 if (_nword == 2 || !strcmp(_word[2], "on"))
253 _gri_beep = true;
254 else if (!strcmp(_word[2], "off"))
255 _gri_beep = false;
256 else {
257 err("`set beep' what?");
258 return false;
259 }
260 return true;
261 }
262
263 //`set bounding box .xleft. .ybottom. .xright. .ytop. [cm|pt]'
264 bool
set_bounding_boxCmd()265 set_bounding_boxCmd()
266 {
267 // Set to _bounding_box_user
268 double ll_x, ll_y, ur_x, ur_y; // user-units
269 double ll_x_cm, ll_y_cm, ur_x_cm, ur_y_cm; // points
270 if (_nword == 7) { // user-units
271 if (!getdnum(_word[3], &ll_x)) {
272 demonstrate_command_usage();
273 err("Can't read .xleft. in `\\", _word[3], "'.", "\\");
274 return false;
275 }
276 if (!getdnum(_word[4], &ll_y)) {
277 demonstrate_command_usage();
278 err("Can't read .ybottom. in `\\", _word[4], "'.", "\\");
279 return false;
280 }
281 if (!getdnum(_word[5], &ur_x)) {
282 demonstrate_command_usage();
283 err("Can't read .xright. in `\\", _word[5], "'.", "\\");
284 return false;
285 }
286 if (!getdnum(_word[6], &ur_y)) {
287 demonstrate_command_usage();
288 err("Can't read .ytop. in `\\", _word[6], "'.", "\\");
289 return false;
290 }
291 double xmargin = XMARGIN_DEFAULT;
292 double ymargin = YMARGIN_DEFAULT;
293 double xsize = XSIZE_DEFAULT;
294 double ysize = YSIZE_DEFAULT;
295
296 if (!get_var("..xmargin..", &xmargin))
297 warning("(set_environment) ..xmargin.. undefined so using default");
298 if (!get_var("..ymargin..", &ymargin))
299 warning("(set_environment) ..ymargin.. undefined so using default");
300 if (!get_var("..xsize..", &xsize))
301 warning("(set_environment) ..xsize.. undefined so using default");
302 if (!get_var("..ysize..", &ysize))
303 warning("(set_environment) ..ysize.. undefined so using default");
304 gr_setxtransform(_xtype);
305 gr_setxscale(xmargin, xmargin + xsize, _xleft, _xright);
306 gr_setytransform(_ytype);
307 gr_setyscale(ymargin, ymargin + ysize, _ybottom, _ytop);
308
309 gr_usertocm(ll_x, ll_y, &ll_x_cm, &ll_y_cm);
310 gr_usertocm(ur_x, ur_y, &ur_x_cm, &ur_y_cm);
311
312 } else if (_nword == 8) {
313
314 bool in_pt = false;
315 if (word_is(7, "cm")) {
316 in_pt = false;
317 } else if (word_is(7, "pt")) {
318 in_pt = true;
319 } else {
320 err("`set bounding box ...' expecting keyword `pt' or `cm' but got `\\", _word[7], "'", "\\");
321 return false;
322 }
323
324 if (!getdnum(_word[3], &ll_x_cm)) {
325 demonstrate_command_usage();
326 err("Can't read .xleft. in `\\", _word[3], "'.", "\\");
327 return false;
328 }
329 if (!getdnum(_word[4], &ll_y_cm)) {
330 demonstrate_command_usage();
331 err("Can't read .ybottom. in `\\", _word[4], "'.", "\\");
332 return false;
333 }
334 if (!getdnum(_word[5], &ur_x_cm)) {
335 demonstrate_command_usage();
336 err("Can't read .xright. in `\\", _word[5], "'.", "\\");
337 return false;
338 }
339 if (!getdnum(_word[6], &ur_y_cm)) {
340 demonstrate_command_usage();
341 err("Can't read .ytop. in `\\", _word[6], "'.", "\\");
342 return false;
343 }
344 if (in_pt) {
345 ll_x_cm /= PT_PER_CM; // convert points to cm
346 ll_y_cm /= PT_PER_CM;
347 ur_x_cm /= PT_PER_CM;
348 ur_y_cm /= PT_PER_CM;
349 }
350
351 } else {
352 err("Must specify .xleft. .ybottom. .xright. .ytop. [cm]");
353 }
354 _bounding_box_user.set(ll_x_cm, ll_y_cm, ur_x_cm, ur_y_cm);
355 _user_gave_bounding_box = true;
356 return true;
357 }
358
359 // set clip to curve [4 words]
360 bool
set_clipCmd()361 set_clipCmd()
362 {
363 Require(_nword > 2, err("Must specify `set clip on' or `set clip off'"));
364 if (_nword == 4 && word_is(2, "to") && word_is(3, "curve")) {
365 unsigned int xlen = _colX.size();
366 if (xlen < 1) {
367 warning("`set clip to curve' noticed that no curve exists");
368 return true;
369 }
370 unsigned int ylen = _colY.size();
371 if (xlen != ylen) {
372 warning("`set clip to curve' noticed that curve's x and y lengths disagree");
373 return true;
374 }
375 double *xp = _colX.begin();
376 double *yp = _colY.begin();
377 gr_set_clip_ps_curve(xp, yp, xlen);
378 return true;
379 } else {
380 if (!strcmp(_word[2], "postscript")) {
381 // PostScript clipping
382 if (_nword < 4) {
383 err("`set clip postscript ...' needs >= 4 words.");
384 return false;
385 }
386 if (!strcmp(_word[3], "off")) {
387 gr_set_clip_ps_off();
388 return true;
389 } else if (!strcmp(_word[3], "on")) {
390 double xl, xr, yb, yt;
391 if (_nword == 4) { // set clip postscript on
392 xl = _xleft;
393 xr = _xright;
394 yb = _ybottom;
395 yt = _ytop;
396 /*DEK*/
397 // printf("DEBUG: will try to set clip to xl=%f xr=%f yb=%f yt=%f\n",xl,xr,yb,yt);
398 /*DEK*/
399 } else if (_nword == 8) { // set clip postscript on .llx. ...
400 if (!getdnum(_word[4], &xl)) {
401 demonstrate_command_usage();
402 err("Can't read .xleft. in `\\", _word[4], "'.", "\\");
403 return false;
404 }
405 if (!getdnum(_word[5], &xr)) {
406 demonstrate_command_usage();
407 err("Can't read .xright. in `\\", _word[5], "'.", "\\");
408 return false;
409 }
410 if (!getdnum(_word[6], &yb)) {
411 demonstrate_command_usage();
412 err("Can't read .ybottom. in `\\", _word[6], "'.", "\\");
413 return false;
414 }
415 if (!getdnum(_word[7], &yt)) {
416 demonstrate_command_usage();
417 err("Can't read .ytop. in `\\", _word[7], "'.", "\\");
418 return false;
419 }
420 } else {
421 NUMBER_WORDS_ERROR;
422 demonstrate_command_usage();
423 return false;
424 }
425 set_environment();
426 double llx, lly, urx, ury;
427 gr_usertopt(xl, yb, &llx, &lly);
428 gr_usertopt(xr, yt, &urx, &ury);
429 gr_set_clip_ps_rect(llx, lly, urx, ury);
430 return true;
431 }
432 } else if (!strcmp(_word[2], "on")) {
433 // Non-PostScript clipping
434 if (_nword == 3)
435 _clipData = -1;
436 else if (_nword == 7) {
437 if (!getdnum(_word[3], &tmp)) {
438 READ_WORD_ERROR(".xleft.");
439 _clipData = 0;
440 _clipxleft = _clipxright = _clipybottom = _clipytop = 0.0;
441 return false;
442 }
443 _clipxleft = tmp;
444 if (!getdnum(_word[4], &tmp)) {
445 READ_WORD_ERROR(".xright.");
446 _clipData = 0;
447 _clipxleft = _clipxright = _clipybottom = _clipytop = 0.0;
448 return false;
449 }
450 _clipxright = tmp;
451 if (!getdnum(_word[5], &tmp)) {
452 READ_WORD_ERROR(".ybottom.");
453 _clipData = 0;
454 _clipxleft = _clipxright = _clipybottom = _clipytop = 0.0;
455 return false;
456 }
457 _clipybottom = tmp;
458 if (!getdnum(_word[6], &tmp)) {
459 READ_WORD_ERROR(".ytop.");
460 _clipData = 0;
461 _clipxleft = _clipxright = _clipybottom = _clipytop = 0.0;
462 return false;
463 }
464 _clipytop = tmp;
465 _clipData = 1;
466 } else
467 err("`set clip on' takes 4 parameters");
468 } else if (!strcmp(_word[2], "off")) {
469 gr_set_clip_ps_off();
470 _clipData = 0;
471 } else {
472 err("Must specify `set clip on' or `set clip off'");
473 return false;
474 }
475 }
476 return true;
477 }
478
479 #define CHECK_RGB_RANGE(item) { \
480 if ((item) < 0.0) { \
481 warning("`set color rgb' value being clipped to range 0-1"); \
482 (item) = 0.0; \
483 } else if ((item) > 1.0) { \
484 warning("`set color rgb' value being clipped to range 0-1"); \
485 (item) = 1.0; \
486 } \
487 }
488 #define CHECK_HSB_RANGE(item) { \
489 if ((item) < 0.0) { \
490 warning("`set color hsb' value being clipped to range 0-1"); \
491 (item) = 0.0; \
492 } else if ((item) > 1.0) { \
493 warning("`set color hsb' value being clipped to range 0-1"); \
494 (item) = 1.0; \
495 } \
496 }
497 bool
set_colorCmd()498 set_colorCmd()
499 {
500 double red, green, blue;
501 std::string cname;
502 GriColor c;
503 switch (_nword) {
504 case 3:
505 cname.assign(_word[2]);
506 un_double_quote(cname);
507 if (!look_up_color(cname.c_str(), &red, &green, &blue)) {
508 unsigned int rhex, ghex, bhex;
509 if (cname.size() == 6
510 && 1 == sscanf(cname.substr(0,2).c_str(), "%x", &rhex)
511 && 1 == sscanf(cname.substr(2,2).c_str(), "%x", &ghex)
512 && 1 == sscanf(cname.substr(4,2).c_str(), "%x", &bhex)) {
513 red = rhex / 255.0;
514 green = ghex / 255.0;
515 blue = bhex / 255.0;
516 } else {
517 err("`set color' given unknown colorname `\\", cname.c_str(), "'. Use command `show colornames' to see available colors.", "\\");
518 return false;
519 }
520 }
521 PUT_VAR("..red..", red);
522 PUT_VAR("..green..", green);
523 PUT_VAR("..blue..", blue);
524 c.setRGB(red, green, blue);
525 _griState.set_color_line(c);
526 if (_griState.separate_text_color() == false)
527 _griState.set_color_text(c);
528 return true;
529 case 6:
530 if (!strcmp(_word[2], "rgb")) {
531 // `set color rgb .red. .green. .blue.'
532 Require(getdnum(_word[3], &red), READ_WORD_ERROR(".red."));
533 Require(getdnum(_word[4], &green), READ_WORD_ERROR(".green."));
534 Require(getdnum(_word[5], &blue), READ_WORD_ERROR(".blue."));
535 // Clip if necessary
536 CHECK_RGB_RANGE(red);
537 CHECK_RGB_RANGE(green);
538 CHECK_RGB_RANGE(blue);
539 PUT_VAR("..red..", red);
540 PUT_VAR("..green..", green);
541 PUT_VAR("..blue..", blue);
542 c.setRGB(red, green, blue);
543 _griState.set_color_line(c);
544 if (_griState.separate_text_color() == false)
545 _griState.set_color_text(c);
546 return true;
547 } else if (!strcmp(_word[2], "hsb")) {
548 // `set color hsb .hue. .saturation. .brightness.'
549 double hue, saturation, brightness;
550 Require(getdnum(_word[3], &hue), READ_WORD_ERROR(".hue."));
551 Require(getdnum(_word[4], &saturation), READ_WORD_ERROR(".saturation."));
552 Require(getdnum(_word[5], &brightness), READ_WORD_ERROR(".brightness."));
553 // Clip if necessary
554 CHECK_HSB_RANGE(hue);
555 CHECK_HSB_RANGE(saturation);
556 CHECK_HSB_RANGE(brightness);
557 gr_hsv2rgb(hue, saturation, brightness, &red, &green, &blue);
558 PUT_VAR("..red..", red);
559 PUT_VAR("..green..", green);
560 PUT_VAR("..blue..", blue);
561 c.setHSV(hue, saturation, brightness);
562 _griState.set_color_line(c);
563 if (_griState.separate_text_color() == false)
564 _griState.set_color_text(c);
565 return true;
566 } else {
567 err("Can't understand command.");
568 demonstrate_command_usage();
569 return false;
570 }
571 default:
572 NUMBER_WORDS_ERROR;
573 demonstrate_command_usage();
574 return false;
575 }
576 }
577
578
579 // `set colorname \name {rgb .red. .green. .blue.}|{hsb .hue. .saturation. .brightness.}
580 bool
set_colornameCmd()581 set_colornameCmd()
582 {
583 double red, green, blue;
584 switch (_nword) {
585 case 7:
586 if (strEQ(_word[3], "rgb")) {
587 Require(getdnum(_word[4], &red), READ_WORD_ERROR(".red."));
588 Require(getdnum(_word[5], &green), READ_WORD_ERROR(".green."));
589 Require(getdnum(_word[6], &blue), READ_WORD_ERROR(".blue."));
590 } else if (strEQ(_word[3], "hsb")) {
591 double hue, saturation, brightness;
592 Require(getdnum(_word[4], &hue), READ_WORD_ERROR(".hue."));
593 Require(getdnum(_word[5], &saturation), READ_WORD_ERROR(".saturation."));
594 Require(getdnum(_word[6], &brightness), READ_WORD_ERROR(".brightness."));
595 hue = pin0_1(hue);
596 saturation = pin0_1(saturation);
597 brightness = pin0_1(brightness);
598 gr_hsv2rgb(hue, saturation, brightness, &red, &green, &blue);
599 } else {
600 demonstrate_command_usage();
601 err("word must be `rgb' or `hsb', not `\\", _word[3], "' as given.", "\\");
602 return false;
603 }
604 red = pin0_1(red);
605 green = pin0_1(green);
606 blue = pin0_1(blue);
607 create_color(_word[2], red, green, blue);
608 //printf("set colorname '%s' %f %f %f\n", _word[2], red, green, blue);
609 break;
610 default:
611 NUMBER_WORDS_ERROR;
612 return false;
613 }
614 return true;
615 }
616
617 bool
set_x_typeCmd()618 set_x_typeCmd()
619 {
620 extern char _xtype_map;
621 switch (_nword) {
622 case 5:
623 if (word_is(3, "map")) {
624 if (word_is(4, "E")) {
625 _xtype_map = 'E';
626 } else if (word_is(4, "W")) {
627 _xtype_map = 'W';
628 } else if (word_is(4, "S")) {
629 _xtype_map = 'S';
630 } else if (word_is(4, "N")) {
631 _xtype_map = 'N';
632 } else {
633 err("X map type must be `E', `W', `S' or `N'");
634 return false;
635 }
636 } else {
637 err("Type must be `linear', `log', or `map'");
638 return false;
639 }
640 break;
641 case 4:
642 if (!strcmp(_word[3], "linear")) {
643 _xtype = gr_axis_LINEAR;
644 _xtype_map = ' ';
645 } else if (!strcmp(_word[3], "log")) {
646 _xtype_map = ' ';
647 if (_xtype == gr_axis_LOG) // only change if necessary
648 return true;
649 if (!_xscale_exists) {
650 _xtype = gr_axis_LOG;
651 gr_setxtransform(_xtype);
652 return true;
653 }
654 if ((_xright > _xleft) && (_xleft > 0.0) && (_xright > 0.0)) {
655 _xinc = 1;
656 PUT_VAR("..xleft..", _xleft = pow(10.0, floor(0.5 + log10(_xleft))));
657 PUT_VAR("..xright..", _xright = pow(10.0, floor(0.5 + log10(_xright))));
658 PUT_VAR("..xinc..", _xinc);
659 _xtype = gr_axis_LOG;
660 } else {
661 err("\
662 Can't convert from linear x axis, present x axis has numbers <= 0.\n\
663 First `delete x scale', then `set x type log'.");
664 }
665 } else {
666 err("Type must be `linear', `log', or `map'");
667 return false;
668 }
669 break;
670 default:
671 NUMBER_WORDS_ERROR;
672 return false;
673 }
674 gr_setxtransform(_xtype);
675 return true;
676 }
677
678 bool
set_y_typeCmd()679 set_y_typeCmd()
680 {
681 extern char _ytype_map;
682 switch (_nword) {
683 case 5:
684 if (word_is(3, "map")) {
685 if (word_is(4, "N")) {
686 _ytype_map = 'N';
687 } else if (word_is(4, "S")) {
688 _ytype_map = 'S';
689 } else if (word_is(4, "E")) {
690 _ytype_map = 'E';
691 } else if (word_is(4, "W")) {
692 _ytype_map = 'W';
693 } else {
694 err("Y map type must be `E', `W', `S' or `N'");
695 return false;
696 }
697 } else {
698 err("Type must be `linear', `log', or `map'");
699 return false;
700 }
701 break;
702 case 4:
703 if (!strcmp(_word[3], "linear")) {
704 _ytype_map = ' ';
705 _ytype = gr_axis_LINEAR;
706 } else if (!strcmp(_word[3], "log")) {
707 _ytype_map = ' ';
708 if (_ytype == gr_axis_LOG) { // only change if necessary
709 return true;
710 }
711 if (!_yscale_exists) {
712 _ytype = gr_axis_LOG;
713 gr_setytransform(_ytype);
714 return true;
715 }
716 if ((_ytop > _ybottom) && (_ytop > 0.0) && (_ybottom > 0.0)) {
717 _yinc = 1;
718 PUT_VAR("..ybottom..", _ybottom = pow(10.0, floor(0.5 + log10(_ybottom))));
719 PUT_VAR("..ytop..", _ytop = pow(10.0, floor(0.5 + log10(_ytop))));
720 PUT_VAR("..yinc..", _yinc);
721 _ytype = gr_axis_LOG;
722 } else {
723 err("\
724 Can't convert from linear y axis, present x axis has numbers <= 0.\n\
725 First `delete y scale', then `set y type log'.");
726 }
727 } else {
728 err("Type must be `linear', `log', or `map'");
729 return false;
730 }
731 break;
732 default:
733 NUMBER_WORDS_ERROR;
734 return false;
735 }
736 gr_setytransform(_ytype);
737 return true;
738 }
739
740 // `set z missing above|below .intercept. .slope.'
741 bool
set_z_missingCmd()742 set_z_missingCmd()
743 {
744 double slope, intercept;
745 typedef enum { above, below, dont_know } WHERE;
746 WHERE where = dont_know;
747 switch (_nword) {
748 case 6:
749 if (!getdnum(_word[4], &intercept))
750 return false;
751 if (!getdnum(_word[5], &slope))
752 return false;
753 if (word_is(3, "above"))
754 where = above;
755 else if (word_is(3, "below"))
756 where = below;
757 break;
758 default:
759 NUMBER_WORDS_ERROR;
760 return false;
761 }
762 if (_colX.size() < 1) {
763 err("First `read columns ... x'");
764 return false;
765 }
766 if (_colY.size() < 1) {
767 err("First `read columns ... y'");
768 return false;
769 }
770 if (_colZ.size() < 1) {
771 err("First `read columns ... z'");
772 return false;
773 }
774 double missing = gr_currentmissingvalue();
775 switch (where) {
776 case above:
777 for (unsigned int i = 0; i < _colX.size(); i++) {
778 if (_colY[i] > intercept + slope * _colX[i])
779 _colZ[i] = missing;
780 }
781 break;
782 case below:
783 for (unsigned int i = 0; i < _colX.size(); i++) {
784 if (_colY[i] < intercept + slope * _colX[i])
785 _colZ[i] = missing;
786 }
787 break;
788 default:
789 demonstrate_command_usage();
790 err("Fourth word must be `above' or `below'");
791 return false;
792 }
793
794 return true;
795 }
796
797
798
799 bool
set_font_colorCmd()800 set_font_colorCmd()
801 {
802 double red, green, blue;
803 GriColor c;
804 switch (_nword) {
805 case 4:
806 if (!look_up_color(_word[3], &red, &green, &blue)) {
807 err("`set font color' given unknown colorname `\\", _word[3], "'. Use command `show colornames' to see available colors.", "\\");
808 return false;
809 }
810 c.setRGB(red, green, blue);
811 _griState.set_color_text(c);
812 _griState.set_separate_text_color(true);
813 return true;
814 case 7:
815 if (strEQ(_word[3], "rgb")) {
816 // `set color rgb .red. .green. .blue.'
817 Require(getdnum(_word[4], &red), READ_WORD_ERROR(".red."));
818 Require(getdnum(_word[5], &green), READ_WORD_ERROR(".green."));
819 Require(getdnum(_word[6], &blue), READ_WORD_ERROR(".blue."));
820 // Clip if necessary
821 if (red < 0.0) {
822 warning("`set color rgb' value being clipped to 0");
823 red = 0.0;
824 } else if (red > 1.0) {
825 warning("`set color rgb' value being clipped to 0");
826 red = 1.0;
827 }
828 if (green < 0.0) {
829 warning("`set color rgb' .green. value being clipped to 0");
830 green = 0.0;
831 } else if (green > 1.0) {
832 warning("`set color rgb' value being clipped to 0");
833 green = 1.0;
834 }
835 if (blue < 0.0) {
836 warning("`set color rgb' value being clipped to 0");
837 blue = 0.0;
838 } else if (blue > 1.0) {
839 warning("`set color rgb' value being clipped to 0");
840 blue = 1.0;
841 }
842 _griState.set_separate_text_color(true);
843 c.setRGB(red, green, blue);
844 _griState.set_color_text(c);
845 return true;
846 } else if (strEQ(_word[3], "hsb")) {
847 // `set color hsb .hue. .saturation. .brightness.'
848 double hue, saturation, brightness;
849 Require(getdnum(_word[4], &hue), READ_WORD_ERROR(".hue."));
850 Require(getdnum(_word[5], &saturation), READ_WORD_ERROR(".saturation."));
851 Require(getdnum(_word[6], &brightness), READ_WORD_ERROR(".brightness."));
852 // Clip if necessary
853 if (hue < 0.0) {
854 warning("`set color hsb' value being clipped to 0");
855 hue = 0.0;
856 } else if (hue > 1.0) {
857 warning("`set color hsb' value being clipped to 0");
858 hue = 1.0;
859 }
860 if (saturation < 0.0) {
861 warning("`set color hsb' value being clipped to 0");
862 saturation = 0.0;
863 } else if (saturation > 1.0) {
864 warning("`set color hsb' value being clipped to 0");
865 saturation = 1.0;
866 }
867 if (brightness < 0.0) {
868 warning("`set color hsb' value being clipped to 0");
869 brightness = 0.0;
870 } else if (brightness > 1.0) {
871 warning("`set color hsb' value being clipped to 0");
872 brightness = 1.0;
873 }
874 c.setHSV(hue, saturation, brightness);
875 _griState.set_color_text(c);
876 _griState.set_separate_text_color(true);
877 return true;
878 } else {
879 err("Can't understand command.");
880 demonstrate_command_usage();
881 return false;
882 }
883 default:
884 NUMBER_WORDS_ERROR;
885 demonstrate_command_usage();
886 return false;
887 }
888 }
889
890 // set font encoding PostscriptStandard|isolatin1
891 bool
set_font_encodingCmd()892 set_font_encodingCmd()
893 {
894 if (_nword < 4) {
895 demonstrate_command_usage();
896 err("`set font encoding' needs to know which method to use ('PostscriptStandard' or 'isolatin1')");
897 return false;
898 }
899 if (!strcmp(_word[3], "PostscriptStandard")) {
900 gr_set_font_encoding(font_encoding_standard);
901 return true;
902 } else if (!strcmp(_word[3], "isolatin1")) {
903 gr_set_font_encoding(font_encoding_isolatin1);
904 return true;
905 } else if (!strcmp(_word[3], "isolatinl")) {
906 demonstrate_command_usage();
907 err("`set font encoding' spelling error. Did you mean `isolatin1' with a `one' at the end??");
908 return false;
909 } else {
910 demonstrate_command_usage();
911 err("`set font encoding' doesn't understand encoding method. Choices are `PostscriptStandard' and `isolatin1'");
912 return false;
913 }
914 }
915 bool
set_font_sizeCmd()916 set_font_sizeCmd()
917 {
918 if (_nword < 3) {
919 err("`set font' what?");
920 return false;
921 }
922 if (!strcmp(_word[2], "size")) {
923 if (_nword < 4) {
924 err("`set font size' what?");
925 return false;
926 }
927 if (_nword > 5) {
928 err("extra words in `set font size' command");
929 return false;
930 }
931 if (!strcmp(_word[3], "default")) {
932 PUT_VAR("..fontsize..", FONTSIZE_PT_DEFAULT);
933 gr_setfontsize_pt(FONTSIZE_PT_DEFAULT);
934 return false;
935 }
936 if (!getdnum(_word[3], &tmp))
937 return false;
938 if (_nword == 5) {
939 if (!strcmp(_word[4], "cm"))
940 tmp *= PT_PER_CM;
941 else {
942 err("last word in `set font size' unknown");
943 return false;
944 }
945 }
946 if (tmp < 0.0 || tmp > 200.0) {
947 err("ignoring bad font size <0 or >200 cm");
948 return false;
949 }
950 PUT_VAR("..fontsize..", tmp);
951 gr_setfontsize_pt(tmp);
952 } else {
953 err("`set font' what?");
954 return false;
955 }
956 return true;
957 }
958
959 bool
set_font_toCmd()960 set_font_toCmd()
961 {
962 if (_nword != 4) {
963 demonstrate_command_usage();
964 NUMBER_WORDS_ERROR;
965 return false;
966 }
967 if (!strcmp(_word[3], "Courier"))
968 gr_setfont(gr_font_Courier);
969 else if (!strcmp(_word[3], "Helvetica"))
970 gr_setfont(gr_font_Helvetica);
971 else if (!strcmp(_word[3], "HelveticaBold"))
972 gr_setfont(gr_font_HelveticaBold);
973 else if (!strcmp(_word[3], "Palatino") || !strcmp(_word[3], "PalatinoRoman"))
974 gr_setfont(gr_font_PalatinoRoman);
975 else if (!strcmp(_word[3], "Symbol"))
976 gr_setfont(gr_font_Symbol);
977 else if (!strcmp(_word[3], "Century"))
978 gr_setfont(gr_font_Century);
979 else if (!strcmp(_word[3], "Times"))
980 gr_setfont(gr_font_TimesRoman);
981 else if (!strcmp(_word[3], "TimesRoman"))
982 gr_setfont(gr_font_TimesRoman);
983 else if (!strcmp(_word[3], "TimesBold"))
984 gr_setfont(gr_font_TimesBold);
985
986 else if (*_word[3] == '\\') {
987 demonstrate_command_usage();
988 err("Font name, specified as `\\", _word[3], "' should not have a backslash at the start.", "\\");
989 return false;
990 } else {
991 demonstrate_command_usage();
992 err("Unknown font `\\", _word[3], "'.\n Available fonts: Courier, Helvetica, HelveticaBold, Palatino, PalatinoRoman, Symbol, Times, TimesRoman, TimesBold", "Century", "\\");
993 return false;
994 }
995 return true;
996 }
997
998 bool
set_dashCmd()999 set_dashCmd()
1000 {
1001 // Start by clearing existing dash list
1002 _dash.erase(_dash.begin(), _dash.end()); // go to solid
1003 // Solid line
1004 if (word_is(_nword - 1, "off")) { // solid line
1005 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1006 #if 0
1007 fprintf(_grPS, "[] 0 d\n");
1008 #endif
1009 return true; // solid line
1010 }
1011 if (_nword == 2) {
1012 // `set dash'
1013 _dash.push_back(0.2);
1014 _dash.push_back(0.1);
1015 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1016 return true;
1017 }
1018 if (_nword == 3) {
1019 // `set dash .num.'
1020 if (!getdnum(_word[2], &tmp)) {
1021 demonstrate_command_usage();
1022 READ_WORD_ERROR(".n.");
1023 return false;
1024 }
1025 switch ((int) (0.5 + fabs((double) tmp))) {
1026 case 0:
1027 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1028 case 1:
1029 _dash.push_back(0.2);
1030 _dash.push_back(0.1);
1031 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1032 case 2:
1033 _dash.push_back(0.4);
1034 _dash.push_back(0.1);
1035 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1036 case 3:
1037 _dash.push_back(0.6);
1038 _dash.push_back(0.1);
1039 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1040 case 4:
1041 _dash.push_back(0.8);
1042 _dash.push_back(0.1);
1043 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1044 case 5:
1045 _dash.push_back(1.0);
1046 _dash.push_back(0.1);
1047 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1048 case 10:
1049 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1050 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1051 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1052 case 11:
1053 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1054 _dash.push_back(2.0 * _griState.linewidth_line() / PT_PER_CM);
1055 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1056 case 12:
1057 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1058 _dash.push_back(3.0 * _griState.linewidth_line() / PT_PER_CM);
1059 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1060 case 13:
1061 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1062 _dash.push_back(4.0 * _griState.linewidth_line() / PT_PER_CM);
1063 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1064 case 14:
1065 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1066 _dash.push_back(5.0 * _griState.linewidth_line() / PT_PER_CM);
1067 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1068 case 15:
1069 _dash.push_back(_griState.linewidth_line() / PT_PER_CM);
1070 _dash.push_back(6.0 * _griState.linewidth_line() / PT_PER_CM);
1071 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1072 default:
1073 _dash.push_back(0.2);
1074 _dash.push_back(0.1);
1075 return gr_set_dash(_dash); // BUG: needed? (set in GriPath anyway)
1076 }
1077 return gr_set_dash(_dash); // BUG: need this? (set in GriPath anyway)
1078 } else {
1079 // Long list of values
1080 for (unsigned int i = 0; i < _nword - 2; i++) {
1081 double tmp;
1082 if (!getdnum(_word[2 + i], &tmp)) {
1083 demonstrate_command_usage();
1084 err("Cannot read all dash/blank values");
1085 return false;
1086 }
1087 _dash.push_back(tmp);
1088 }
1089 }
1090 #if 0
1091 fprintf(_grPS, "[");
1092 for (unsigned int i = 0; i < _dash.size(); i++)
1093 fprintf(_grPS, "%.3f ", _dash[i] * PT_PER_CM);
1094 fprintf(_grPS, "] %d d\n", int(_dash.size()));
1095 #endif
1096 return gr_set_dash(_dash); // BUG: need this? (set in GriPath anyway)
1097 }
1098 bool
gr_set_dash(const std::vector<double> dash)1099 gr_set_dash(const std::vector<double> dash)
1100 {
1101 extern FILE *_grPS;
1102 fprintf(_grPS, "[");
1103 for (unsigned int i = 0; i < dash.size(); i++)
1104 fprintf(_grPS, "%.3f ", dash[i] * PT_PER_CM);
1105 fprintf(_grPS, "] %d d\n", int(dash.size()));
1106 _griState.set_dash(dash);
1107 //printf("DEBUG: gr_set_dash() stored a dash of length %ud\n",dash.size());
1108 return true;
1109 }
1110
1111 bool
set_ignoreCmd()1112 set_ignoreCmd()
1113 {
1114 switch (_nword) {
1115 case 4:
1116 if (!strcmp(_word[1], "ignore")
1117 && !strcmp(_word[2], "error")
1118 && !strcmp(_word[3], "eof")) {
1119 _ignore_eof = true;
1120 } else {
1121 demonstrate_command_usage();
1122 err("Can't understand command.");
1123 }
1124 break;
1125 default:
1126 demonstrate_command_usage();
1127 NUMBER_WORDS_ERROR;
1128 break;
1129 }
1130 return false;
1131 }
1132
1133 bool
set_input_data_windowCmd()1134 set_input_data_windowCmd()
1135 {
1136 double minval, maxval;
1137 switch (_nword) {
1138 case 6: // set input data window x|y off
1139 if (strcmp(_word[5], "off")) {
1140 demonstrate_command_usage();
1141 err("In this context, the last word must be `off'.");
1142 return false;
1143 }
1144 if (!strcmp(_word[4], "x"))
1145 _input_data_window_x_exists = false;
1146 else if (!strcmp(_word[4], "y"))
1147 _input_data_window_y_exists = false;
1148 else {
1149 demonstrate_command_usage();
1150 err("In this context, the fifth word must be \"x\" or \"y\".");
1151 return false;
1152 }
1153 break;
1154 case 7:
1155 if (!strcmp(_word[4], "x")) {
1156 if (!getdnum(_word[5], &minval)) {
1157 demonstrate_command_usage();
1158 err("Can't read x window .min.");
1159 return false;
1160 }
1161 if (!getdnum(_word[6], &maxval)) {
1162 demonstrate_command_usage();
1163 err("Can't read x window .max.");
1164 return false;
1165 }
1166 if (minval == maxval) {
1167 demonstrate_command_usage();
1168 err("Can't have input data window of zero width.");
1169 return false;
1170 }
1171 if (minval < maxval) {
1172 _input_data_window_x_min = minval;
1173 _input_data_window_x_max = maxval;
1174 } else {
1175 _input_data_window_x_min = maxval;
1176 _input_data_window_x_max = minval;
1177 }
1178 _input_data_window_x_exists = true;
1179 } else if (!strcmp(_word[4], "y")) {
1180 if (!getdnum(_word[5], &minval)) {
1181 demonstrate_command_usage();
1182 err("Can't read y window .min.");
1183 return false;
1184 }
1185 if (!getdnum(_word[6], &maxval)) {
1186 demonstrate_command_usage();
1187 err("Can't read y window .max.");
1188 return false;
1189 }
1190 if (minval == maxval) {
1191 demonstrate_command_usage();
1192 err("Can't have input data window of zero width.");
1193 return false;
1194 }
1195 if (minval < maxval) {
1196 _input_data_window_y_min = minval;
1197 _input_data_window_y_max = maxval;
1198 } else {
1199 _input_data_window_y_min = maxval;
1200 _input_data_window_y_max = minval;
1201 }
1202 _input_data_window_y_exists = true;
1203 } else {
1204 demonstrate_command_usage();
1205 err("In this context, the fifth word must be \"x\" or \"y\".");
1206 return false;
1207 }
1208 break;
1209 default:
1210 demonstrate_command_usage();
1211 err("Can't understand command.");
1212 return false;
1213 }
1214 return true;
1215 }
1216
1217 bool
set_input_data_separatorCmd()1218 set_input_data_separatorCmd()
1219 {
1220 if (_nword < 5) {
1221 demonstrate_command_usage();
1222 err("Must specify an input separator (either `TAB' or `default').");
1223 return false;
1224 }
1225 if (_nword > 5) {
1226 demonstrate_command_usage();
1227 err("Too many words in `set input data separator' command");
1228 return false;
1229 }
1230 if (!strcmp(_word[4], "default")) {
1231 extern char _input_data_separator;
1232 _input_data_separator = ' ';
1233 return true;
1234 } else if (!strcmp(_word[4], "TAB")) {
1235 extern char _input_data_separator;
1236 _input_data_separator = '\t';
1237 return true;
1238 } else {
1239 demonstrate_command_usage();
1240 err("`set input data separator' only understands `TAB' and `default', not ``\\", _word[4], "' as given", "\\");
1241 return false;
1242 }
1243 }
1244 bool
set_contour_formatCmd()1245 set_contour_formatCmd()
1246 {
1247 if (_nword < 4) {
1248 err("Must specify a format for `set contour format'");
1249 return false;
1250 }
1251 if (!strcmp(_word[3], "default")) {
1252 _contourFmt.assign(CONTOUR_FMT_DEFAULT);
1253 } else {
1254 if (*_word[3] == '"') {
1255 int len = strlen(_word[3]);
1256 if (len <= 1) {
1257 _contourFmt.assign(CONTOUR_FMT_DEFAULT);
1258 } else {
1259 if (*(_word[3] + len - 1) == '"')
1260 _contourFmt.assign(_word[3] + 1, len - 2);
1261 else
1262 _contourFmt.assign(_word[3] + 1, len - 1);
1263 }
1264 } else {
1265 _contourFmt.assign(_word[3]);
1266 }
1267 }
1268 return true;
1269 }
1270
1271 // `set contour label position {.start_cm. .between_cm.}|default|centered'
1272 // 0 1 2 3 4 5 6
1273 // `set contour label for lines exceeding .x. cm'
1274 // 0 1 2 3 4 5 6 7
1275 bool
set_contour_labelCmd()1276 set_contour_labelCmd()
1277 {
1278 extern double _contour_space_first, _contour_space_later, _contour_minlength; // <-> draw.c
1279 extern bool _contour_space_centered; // <-> draw.c
1280 if (word_is(3, "for")) {
1281 // `set contour label for lines exceeding .x. cm'
1282 Require(_nword == 8, NUMBER_WORDS_ERROR);
1283 Require(getdnum(_word[6], &tmp), READ_WORD_ERROR(".x."));
1284 _contour_minlength = tmp;
1285 } else {
1286 // `set contour label position ...'
1287 switch (_nword) {
1288 case 5:
1289 if (word_is(4, "default")) {
1290 _contour_space_first = -1.0;
1291 _contour_space_later = -1.0;
1292 } else if (word_is(4, "centered") || word_is(4, "centred")) {
1293 _contour_space_centered = true;
1294 } else {
1295 demonstrate_command_usage();
1296 err("Expecting `default', not '\\", _word[4], "'", "\\");
1297 return false;
1298 }
1299 break;
1300 case 6:
1301 Require(getdnum(_word[4], &tmp), READ_WORD_ERROR(".start_cm."));
1302 Require(getdnum(_word[5], &tmp2), READ_WORD_ERROR(".between_cm."));
1303 _contour_space_first = tmp;
1304 _contour_space_later = tmp2;
1305 _contour_space_centered = false;
1306 break;
1307 default:
1308 demonstrate_command_usage();
1309 err("Can't understand command.");
1310 return false;
1311 }
1312 }
1313 return true;
1314 }
1315
1316 // `set contour labels rotated|horizontal'
1317 // `set contour labels whiteunder|nowhiteunder'
1318 // 0 1 2 3
1319 bool
set_contour_labelsCmd()1320 set_contour_labelsCmd()
1321 {
1322 extern bool _contour_label_rotated; // <-> draw.c startup.c
1323 extern bool _contour_label_whiteunder; // <-> grcntour.c startup.c
1324 Require(_nword == 4, NUMBER_WORDS_ERROR);
1325 if (word_is(3, "rotated"))
1326 _contour_label_rotated = true;
1327 else if (word_is(3, "horizontal"))
1328 _contour_label_rotated = false;
1329 else if (word_is(3, "whiteunder"))
1330 _contour_label_whiteunder = true;
1331 else if (word_is(3, "nowhiteunder"))
1332 _contour_label_whiteunder = false;
1333 else {
1334 err("Last word of `set contour labels' must be `rotated|horizontal|whiteunder|nowhiteunder'");
1335 return false;
1336 }
1337 return true;
1338 }
1339
1340 // Flags for `set flag'
1341 #define NFLAG 100
1342 typedef struct {
1343 std::string name;
1344 bool value;
1345 } FLAG;
1346 FLAG flag[NFLAG];
1347 unsigned int num_flags = 0;
1348 bool
set_flagCmd()1349 set_flagCmd()
1350 {
1351 if (_nword != 3 && _nword != 4) {
1352 demonstrate_command_usage();
1353 NUMBER_WORDS_ERROR;
1354 return false;
1355 }
1356 bool turn_on = true;
1357 if (_nword == 4 && word_is(3, "off"))
1358 turn_on = false;
1359 unsigned int i;
1360 for (i = 0; i < num_flags; i++) {
1361 if (flag[i].name == _word[2]) {
1362 flag[i].value = turn_on;
1363 return true;
1364 }
1365 }
1366 // It is a new flag
1367 if (i >= NFLAG) OUT_OF_MEMORY;
1368 num_flags = i;
1369 flag[num_flags].name = _word[2];
1370 flag[num_flags].value = turn_on;
1371 num_flags++;
1372 return true;
1373 }
1374
1375 bool
get_flag(const char * name)1376 get_flag(const char *name)
1377 {
1378 for (unsigned int i = 0; i < num_flags; i++)
1379 if (flag[i].name == name)
1380 return flag[i].value;
1381 return false; // unknown flag
1382 }
1383 void
show_flags()1384 show_flags()
1385 {
1386 extern char _grTempString[];
1387 if (num_flags) {
1388 for (unsigned int i = 0; i < num_flags; i++) {
1389 sprintf(_grTempString, "Flag `%s' is %d\n",
1390 flag[i].name.c_str(), flag[i].value);
1391 gr_textput(_grTempString);
1392 }
1393 } else {
1394 gr_textput("No flags exist\n");
1395 }
1396 }
1397
1398 // set error action ...
1399 bool
set_error_actionCmd()1400 set_error_actionCmd()
1401 {
1402 // set error action to core dump
1403 // 0 1 2 3 4 5
1404 if (_nword == 6
1405 && word_is(2, "action")
1406 && word_is(3, "to")
1407 && word_is(4, "core")
1408 && word_is(5, "dump")) {
1409 _error_action = 1;
1410 return true;
1411 } else {
1412 demonstrate_command_usage();
1413 err("Wrong syntax");
1414 return false;
1415 }
1416 }
1417
1418 bool
set_graylevelCmd()1419 set_graylevelCmd()
1420 {
1421 double tmp;
1422 if (_nword != 3) {
1423 err("`set graylevel' requires 1 parameter");
1424 return false;
1425 }
1426 if (word_is(2, "black")) {
1427 tmp = 0.0;
1428 } else if (word_is(2, "white")) {
1429 tmp = 1.0;
1430 } else if (!getdnum(_word[2], &tmp)) {
1431 READ_WORD_ERROR(".brightness.");
1432 return false;
1433 }
1434 if (tmp < 0.0 || tmp > 1.0) {
1435 err("Ignoring bad graylevel <0 or >1");
1436 return false;
1437 }
1438 PUT_VAR("..graylevel..", tmp);
1439 PUT_VAR("..red..", tmp);
1440 PUT_VAR("..green..", tmp);
1441 PUT_VAR("..blue..", tmp);
1442 GriColor c;
1443 c.setRGB(tmp, tmp, tmp);
1444 _griState.set_color_line(c);
1445 if (_griState.separate_text_color() == false)
1446 _griState.set_color_text(c);
1447 return true;
1448 }
1449
1450 // If x is very close to xmin or xmax, assign to same
1451 double
tweak_to_limit(double x,double xmin,double xmax)1452 tweak_to_limit(double x, double xmin, double xmax)
1453 {
1454 double range = fabs(xmax - xmin);
1455 if (fabs(x - xmin) < range / 1.0e4)
1456 return xmin;
1457 if (fabs(x - xmax) < range / 1.0e4)
1458 return xmax;
1459 return x;
1460 }
1461
1462 // set image colorscale hsb .h. .s. .b. .im_value. hsb .h. .s. .b. .im_value.
1463 // [increment .value.]
1464 //
1465 // set image colorscale rgb .r. .g. .b. .im_value. rgb .r. .g. .b. .im_value.
1466 // [increment .value.]
1467 //
1468 // set image colorscale \name .im_value. \name .im_value. [increment .im_value.]
1469 //
1470 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
1471 // 14
1472 bool
set_image_colorscaleCmd()1473 set_image_colorscaleCmd()
1474 {
1475 double rA, rB, gA, gB, bA, bB, hA, hB, sA, sB, brA, brB;
1476 double r, g, b, h, s, br;
1477 double valA, valB, indexA, indexB, inc, delta_image = 0.0;
1478 int i, levels = 0;
1479 GriColor::type color_model; // rgb hsv cmyk (GriColor.hh)
1480 bool gave_increment = false;
1481 // check number of words, for the 2 forms and with/without increment
1482 if (_nword != 13 && _nword != 15 && _nword != 7 && _nword != 9) {
1483 demonstrate_command_usage();
1484 NUMBER_WORDS_ERROR;
1485 return false;
1486 }
1487 if (!image_range_exists()) {
1488 err("First `set image range'");
1489 return false;
1490 }
1491 // Extract endpoint values.
1492 if (_nword == 7) {
1493 // `set image colorscale \name .im_value. \name .im_value.'
1494 if (!look_up_color(_word[3], &rA, &gA, &bA)) {
1495 err("Unknown colorname `\\", _word[3], "'. Use command `show colornames' to see available colors.", "\\");
1496 return false;
1497 }
1498 if (!getdnum(_word[4], &valA))
1499 return false;
1500 if (!look_up_color(_word[5], &rB, &gB, &bB)) {
1501 err("Unknown colorname `\\", _word[5], "'. Use command `show colornames' to see available colors.", "\\");
1502 return false;
1503 }
1504 if (!getdnum(_word[6], &valB))
1505 return false;
1506 gave_increment = false;
1507 color_model = GriColor::rgb; // default
1508 } else if (_nword == 9) {
1509 // `set image colorscale \name .im_value. \name .im_value. increment
1510 // .im_value.
1511 if (!look_up_color(_word[3], &rA, &gA, &bA)) {
1512 err("Unknown colorname `\\", _word[3], "'. Use command `show colornames' to see available colors.", "\\");
1513 return false;
1514 }
1515 if (!getdnum(_word[4], &valA))
1516 return false;
1517 if (!look_up_color(_word[5], &rB, &gB, &bB)) {
1518 err("Unknown colorname `\\", _word[5], "'. Use command `show colornames' to see available colors.", "\\");
1519 return false;
1520 }
1521 if (!getdnum(_word[6], &valB))
1522 return false;
1523 if (!getdnum(_word[8], &inc))
1524 return false;
1525 gave_increment = true;
1526 color_model = GriColor::rgb; // default
1527 } else { // BUG: will need to check word number if add cmyk
1528 // Didn't give named color. Must be rgb or hsb specification
1529 if (word_is(3, "rgb")) {
1530 if (!getdnum(_word[4], &rA))
1531 return false;
1532 if (!getdnum(_word[5], &gA))
1533 return false;
1534 if (!getdnum(_word[6], &bA))
1535 return false;
1536 if (!getdnum(_word[7], &valA))
1537 return false;
1538 color_model = GriColor::rgb;
1539 } else if (word_is(3, "hsb")) {
1540 if (!getdnum(_word[4], &hA))
1541 return false;
1542 if (!getdnum(_word[5], &sA))
1543 return false;
1544 if (!getdnum(_word[6], &brA))
1545 return false;
1546 if (!getdnum(_word[7], &valA))
1547 return false;
1548 color_model = GriColor::hsv;
1549 } else {
1550 err("Cannot understand first color specification `\\", _word[3], "'.", "\\");
1551 return false;
1552 }
1553 // Insist that rgb and hsb not be intermixed, since that's how to
1554 // decide on the blending algorithm
1555 if (word_is(8, "rgb")) {
1556 if (color_model != GriColor::rgb) {
1557 err("Cannot mix color specifications, e.g. `rgb' with `hsb'");
1558 return false;
1559 }
1560 if (!getdnum(_word[9], &rB))
1561 return false;
1562 if (!getdnum(_word[10], &gB))
1563 return false;
1564 if (!getdnum(_word[11], &bB))
1565 return false;
1566 if (!getdnum(_word[12], &valB))
1567 return false;
1568 if (rA < 0.0 || rA > 1.0
1569 || gA < 0.0 || gA > 1.0
1570 || bA < 0.0 || bA > 1.0) {
1571 err("Require all RGB values to be in range 0.0 to 1.0");
1572 return false;
1573 }
1574 } else if (word_is(8, "hsb")) {
1575 if (color_model != GriColor::hsv) {
1576 err("Cannot mix color specifications, e.g. `rgb' with `hsb'");
1577 return false;
1578 }
1579 if (!getdnum(_word[9], &hB))
1580 return false;
1581 if (!getdnum(_word[10], &sB))
1582 return false;
1583 if (!getdnum(_word[11], &brB))
1584 return false;
1585 if (!getdnum(_word[12], &valB))
1586 return false;
1587 if (hB < 0.0 || hB > 1.0
1588 || sB < 0.0 || sB > 1.0
1589 || brB < 0.0 || brB > 1.0) {
1590 err("Require all HSB values to be in range 0.0 to 1.0");
1591 return false;
1592 }
1593 } else {
1594 err("Cannot understand color specification `\\", _word[3], "'.", "\\");
1595 return false;
1596 }
1597 // Get increment value if it exists.
1598 if (word_is(13, "increment")) {
1599 // then last word is the increment value
1600 if (!getdnum(_word[14], &inc))
1601 return false;
1602 gave_increment = true;
1603 }
1604 }
1605 // Check that endpoints distinct
1606 if (valA == valB) {
1607 err("Can't have equal image values at endpoints of `set colorscale'");
1608 return false;
1609 }
1610 if (gave_increment) {
1611 if (!well_ordered(valA, valB, inc))
1612 inc = -inc;
1613 if (!gr_multiple(fabs(valB - valA), fabs(inc), fabs(0.001 * inc))) {
1614 err("\
1615 `set image colorscale ... requires range/increment to be integral to 0.1%");
1616 return false;
1617 }
1618 delta_image = 255.0 * fabs(inc / (valA - valB));
1619 levels = (int) floor(1.0e-5 + fabs((valA - valB) / inc));
1620 }
1621 // Calculate the transforms. NB: indexA and indexB are of the
1622 // indices of transform endpoints. Do RGB and HSB separately, each
1623 // interpolating linearly in its own space. (NB: a nonlinear transform
1624 // links RGB and HSB, so linear movement between equivalent endpoints in
1625 // these two spaces yields nonequivalent values.)
1626 //
1627 indexA = 255.0 * (valA - _image0) / (_image255 - _image0);
1628 indexB = 255.0 * (valB - _image0) / (_image255 - _image0);
1629 if (color_model == GriColor::rgb) {
1630 double delta_r = delta_image * fabs(rA - rB);
1631 double delta_g = delta_image * fabs(gA - gB);
1632 double delta_b = delta_image * fabs(bA - bB);
1633 // For each target imageTransform[], make a clipped, linear blend
1634 // from (rA,gA,bA) to (rB,gB,bB). Possibly pass this linear blend
1635 // to 'quantize', to make it into a staircase function.
1636 for (i = 0; i < 256; i++) {
1637 r = 255.0
1638 * (rA + (rB - rA) * pin0_1((i - indexA) / (indexB - indexA)));
1639 g = 255.0 *
1640 (gA + (gB - gA) * pin0_1((i - indexA) / (indexB - indexA)));
1641 b = 255.0 *
1642 (bA + (bB - bA) * pin0_1((i - indexA) / (indexB - indexA)));
1643 if (gave_increment) {
1644 r = quantize(r, levels, delta_r);
1645 g = quantize(g, levels, delta_g);
1646 b = quantize(b, levels, delta_b);
1647 }
1648 _imageTransform[i] = (unsigned char) pin0_255(r);
1649 _imageTransform[i + 256] = (unsigned char) pin0_255(g);
1650 _imageTransform[i + 512] = (unsigned char) pin0_255(b);
1651 }
1652 // Ensure that endpoints match (rgb)A or (rgb)B, as appropriate.
1653 if (indexA < indexB) {
1654 _imageTransform[0] = (unsigned char) (255.0 * rA);
1655 _imageTransform[256] = (unsigned char) (255.0 * gA);
1656 _imageTransform[512] = (unsigned char) (255.0 * bA);
1657 _imageTransform[0 + 255] = (unsigned char) (255.0 * rB);
1658 _imageTransform[256 + 255] = (unsigned char) (255.0 * gB);
1659 _imageTransform[512 + 255] = (unsigned char) (255.0 * bB);
1660 } else {
1661 _imageTransform[0] = (unsigned char) (255.0 * rB);
1662 _imageTransform[256] = (unsigned char) (255.0 * gB);
1663 _imageTransform[512] = (unsigned char) (255.0 * bB);
1664 _imageTransform[0 + 255] = (unsigned char) (255.0 * rA);
1665 _imageTransform[256 + 255] = (unsigned char) (255.0 * gA);
1666 _imageTransform[512 + 255] = (unsigned char) (255.0 * bA);
1667 }
1668 } else if (color_model == GriColor::hsv) {
1669 double delta_h = delta_image * fabs(hA - hB);
1670 double delta_s = delta_image * fabs(sA - sB);
1671 double delta_br = delta_image * fabs(brA - brB);
1672 // For each target imageTransform[], make a clipped, linear blend
1673 // from (hA,sA,brA) to (hB,sB,brB). Possibly pass this linear blend
1674 // to 'quantize', to make it into a staircase function.
1675 for (i = 0; i < 256; i++) {
1676 h = (hA + (hB - hA) * pin0_1((i - indexA) / (indexB - indexA)));
1677 s = (sA + (sB - sA) * pin0_1((i - indexA) / (indexB - indexA)));
1678 br = (brA + (brB - brA) * pin0_1((i - indexA) / (indexB - indexA)));
1679 if (gave_increment) {
1680 // Quantize HSB *before* conversion to RGB
1681 h = quantize(255.0 * h, levels, delta_h) / 255.0;
1682 s = quantize(255.0 * s, levels, delta_s) / 255.0;
1683 br = quantize(255.0 * br, levels, delta_br) / 255.0;
1684 }
1685 gr_hsv2rgb(h, s, br, &r, &g, &b);
1686 _imageTransform[i] = (unsigned char) pin0_255(255.0 * r);
1687 _imageTransform[i + 256] = (unsigned char) pin0_255(255.0 * g);
1688 _imageTransform[i + 512] = (unsigned char) pin0_255(255.0 * b);
1689 }
1690 // Ensure that endpoints match (rgb)A or (rgb)B, as appropriate.
1691 gr_hsv2rgb(hA, sA, brA, &rA, &gA, &bA);
1692 gr_hsv2rgb(hB, sB, brB, &rB, &gB, &bB);
1693 if (indexA < indexB) {
1694 _imageTransform[0] = (unsigned char) (255.0 * rA);
1695 _imageTransform[256] = (unsigned char) (255.0 * gA);
1696 _imageTransform[512] = (unsigned char) (255.0 * bA);
1697 _imageTransform[0 + 255] = (unsigned char) (255.0 * rB);
1698 _imageTransform[256 + 255] = (unsigned char) (255.0 * gB);
1699 _imageTransform[512 + 255] = (unsigned char) (255.0 * bB);
1700 } else {
1701 _imageTransform[0] = (unsigned char) (255.0 * rB);
1702 _imageTransform[256] = (unsigned char) (255.0 * gB);
1703 _imageTransform[512] = (unsigned char) (255.0 * bB);
1704 _imageTransform[0 + 255] = (unsigned char) (255.0 * rA);
1705 _imageTransform[256 + 255] = (unsigned char) (255.0 * gA);
1706 _imageTransform[512 + 255] = (unsigned char) (255.0 * bA);
1707 }
1708 } else {
1709 err("Cannot handle this color model. Only `rgb' and `hsb' are known at this time");
1710 return false;
1711 }
1712 // All done. Everything was OK.
1713 _imageTransform_exists = true;
1714 _image_color_model = rgb_model;
1715 return true;
1716 }
1717
1718 bool
set_image_grayscaleCmd()1719 set_image_grayscaleCmd()
1720 {
1721 int i;
1722 double indexA;
1723 if (_nword < 3) {
1724 err("`set image' what?");
1725 return false;
1726 }
1727 // Do a (redundant?) check
1728 if (!word_is(2, "grayscale") && !word_is(2, "greyscale")) {
1729 err("`set image' what?");
1730 return false;
1731 }
1732 if (!image_range_exists()) {
1733 err("First `set image range'");
1734 return false;
1735 }
1736 // `set image grayscale'
1737 if (_nword == 3) {
1738 if (!_image.storage_exists) {
1739 err("First, you must read or create an image");
1740 return false;
1741 }
1742 unsigned char valTmp;
1743 unsigned char valA = *(_image.image);
1744 unsigned char valB = valA;
1745 for (unsigned int ij = 1; ij < _image.ras_width * _image.ras_height; ij++) {
1746 valTmp = *(_image.image + ij);
1747 if (valTmp < valA)
1748 valA = valTmp;
1749 if (valTmp > valB)
1750 valB = valTmp;
1751 }
1752 indexA = pin0_255(255.0 * (valA - _image0) / (_image255 - _image0));
1753 double scale = 255 / (valB - valA);
1754 for (i = 0; i < 256; i++) {
1755 _imageTransform[i] = (unsigned char) floor(double(pin0_255((int) floor(scale * (i - indexA)))));
1756 }
1757 _imageTransform[0] = (_imageTransform[0] <= 128) ? 0 : 255;
1758 _imageTransform[255] = (_imageTransform[255] <= 128) ? 0 : 255;
1759 _imageTransform_exists = true;
1760 _image_color_model = bw_model;
1761 //printf("_image0 %f _image255 %f valA %d valB %d scale %f indexA %f\n", _image0, _image255, valA, valB, scale, indexA);
1762 return true;
1763 }
1764 // `set image grayscale [black .bl. white .wh. [increment .inc.]]'
1765 if (_nword > 3
1766 && (!strcmp(_word[3], "black")
1767 || !strcmp(_word[3], "white")
1768 || !strcmp(_word[3], "increment"))) {
1769 double inc = 0.0, valB, valA, scale;
1770 bool gave_increment = false;
1771 if (1 == get_cmd_values(_word, _nword, "black", 1, _dstack))
1772 valA = _dstack[0];
1773 else {
1774 err("Can't read .bl. in [white .wh. black .bl.]");
1775 return false;
1776 }
1777 if (1 == get_cmd_values(_word, _nword, "white", 1, _dstack))
1778 valB = _dstack[0];
1779 else {
1780 err("Can't read .wh. in [white .wh. black .bl.]");
1781 return false;
1782 }
1783 if (1 == get_cmd_values(_word, _nword, "increment", 1, _dstack)) {
1784 inc = _dstack[0];
1785 gave_increment = true;
1786 }
1787 indexA = 255.0 * (valA - _image0) / (_image255 - _image0);
1788 scale = (_image255 - _image0) / (valB - valA);
1789 if (gave_increment) {
1790 // Set up quantized gray levels. For example, `set image
1791 // grayscale white -1 black 1 increment 0.5' will set up 4 gray
1792 // levels; thus, _imageTransform[] will be set up with 4 bands,
1793 // containing the distinct values (1/5, 2/5, 3/5, 4/5) * 255.
1794 //
1795 // BUG -- this quantized graylevel code has had lots of bugs
1796 double delta_image; // image change per level
1797 int levels; // number of levels
1798 if (!well_ordered(valA, valB, inc))
1799 inc = -inc;
1800 if (!gr_multiple(valB - valA, inc, 0.001 * inc)) {
1801 err("\
1802 `set image grayscale black .bl. white .wh. increment .inc.'\n\
1803 has (.wh. - .bl.) not a multiple of .inc. to within 0.1%");
1804 return false;
1805 }
1806 if (valA == valB) {
1807 err("\
1808 `set image grayscale black .bl. white .wh. increment .inc.'\n\
1809 has .wh. = .bl., which is not allowed.");
1810 return false;
1811 }
1812 delta_image = 255.0 * fabs(inc / (valB - valA));
1813 levels = (int) floor(1.0e-5 + fabs((valB - valA) / inc));
1814 for (i = 0; i < 256; i++) {
1815 // The .001 below is to prevent rounding problems.
1816 _imageTransform[i] = (unsigned char)
1817 floor(double(pin0_255((int) floor(double(0.001 + quantize(scale * (i - indexA), levels, delta_image))))));
1818 }
1819 // BUG -- the following is a total kludge, because I could not
1820 // find an adequate rounding macro
1821 _imageTransform[0] = (_imageTransform[0] <= 128) ? 0 : 255;
1822 _imageTransform[255] = (_imageTransform[255] <= 128) ? 0 : 255;
1823 _imageTransform_exists = true;
1824 _image_color_model = bw_model;
1825 return true;
1826 } else {
1827 // Increment was not given.
1828 for (i = 0; i < 256; i++) {
1829 _imageTransform[i]
1830 = (unsigned char) floor(double(pin0_255((int) floor(scale * (i - indexA)))));
1831 }
1832 }
1833 _imageTransform_exists = true;
1834 _image_color_model = bw_model;
1835 return true;
1836 }
1837 demonstrate_command_usage();
1838 err("Can't understand command.");
1839 return false;
1840 }
1841
1842 bool
set_image_grayscale_using_hist()1843 set_image_grayscale_using_hist()
1844 {
1845 int i;
1846 double sum = 0.0, range;
1847 double wh, bl;
1848 if (!image_range_exists()) {
1849 err("First `set image range'");
1850 return false;
1851 }
1852 // Since parser got to this point, must at least match `set image
1853 // grayscale using histogram'
1854 if (_nword == 5) {
1855 // `set image grayscale using histogram'
1856 calculate_image_histogram();
1857 // The range is sum(255) - sum(0), but sum(255) is unity, because
1858 // _imageHist[] is defined that way, and sum(0) is _imageHist[0].
1859 range = 1.0 - _imageHist[0];
1860 if (range == 0.0)
1861 range = 1.0;
1862 for (i = 0; i < 256; i++) {
1863 _imageTransform[i] = (unsigned char) floor(pin0_255(255.0 * (1.0 - (sum - _imageHist[0]) / range)));
1864 sum += _imageHist[i];
1865 }
1866 _imageTransform_exists = true;
1867 } else if (_nword == 9) {
1868 // `set image grayscale using histogram black .bl. white .wh.'
1869 int start, end;
1870 double sum_to_end = 0.0, sum_to_start = 0.0;
1871 if (1 == get_cmd_values(_word, _nword, "black", 1, _dstack)) {
1872 bl = _dstack[0];
1873 } else {
1874 err("Can't read .bl. in [black .bl. white .wh.]");
1875 return false;
1876 }
1877 if (1 == get_cmd_values(_word, _nword, "white", 1, _dstack)) {
1878 wh = _dstack[0];
1879 } else {
1880 err("Can't read .wh. in [black .bl. white .wh.]");
1881 return false;
1882 }
1883 calculate_image_histogram();
1884 start = value_to_image(wh); // pixel
1885 end = value_to_image(bl); // pixel
1886 for (i = 0; i < start; i++)
1887 sum_to_start += _imageHist[i];
1888 for (i = 0; i < end; i++)
1889 sum_to_end += _imageHist[i];
1890 range = sum_to_end - sum_to_start;
1891 if (range == 0.0)
1892 range = 1.0;
1893 for (i = 0; i < 256; i++) {
1894 _imageTransform[i] = (unsigned char) floor(pin0_255(255.0 * (1.0 - (sum - sum_to_start) / range)));
1895 sum += _imageHist[i];
1896 }
1897 _imageTransform_exists = true;
1898 } else {
1899 demonstrate_command_usage();
1900 err("Can't understand command.");
1901 return false;
1902 }
1903 _image_color_model = bw_model;
1904 return true;
1905 }
1906
1907 // `set image missing value color to white|black|{graylevel .brightness.}'
1908 bool
set_image_missingCmd()1909 set_image_missingCmd()
1910 {
1911 if (!image_range_exists()) {
1912 err("First `set image range'");
1913 return false;
1914 }
1915 if (_nword == 7) { // `set image missing value color to white|black'
1916 if (word_is(6, "white")) {
1917 _image_missing_color_red = 1.0;
1918 _image_missing_color_green = 1.0;
1919 _image_missing_color_blue = 1.0;
1920 } else if (word_is(6, "black")) {
1921 _image_missing_color_red = 0.0;
1922 _image_missing_color_green = 0.0;
1923 _image_missing_color_blue = 0.0;
1924 } else {
1925 demonstrate_command_usage();
1926 err("Unknown color specified for image missing-value.");
1927 return false;
1928 }
1929 } else if (_nword == 10) {
1930 // `set image missing value color to rgb .red. .green. .blue.'
1931 if (!strcmp(_word[6], "rgb")) {
1932 double red, green, blue;
1933 Require(getdnum(_word[7], &red), READ_WORD_ERROR(".red."));
1934 Require(getdnum(_word[8], &green), READ_WORD_ERROR(".green."));
1935 Require(getdnum(_word[9], &blue), READ_WORD_ERROR(".blue."));
1936 // Clip if necessary
1937 CHECK_RGB_RANGE(red);
1938 CHECK_RGB_RANGE(green);
1939 CHECK_RGB_RANGE(blue);
1940 _image_missing_color_red = red;
1941 _image_missing_color_green = green;
1942 _image_missing_color_blue = blue;
1943 }
1944 } else {
1945 // `set image missing value color to {graylevel .brightness.}'
1946 if (1 == get_cmd_values(_word, _nword, "graylevel", 1, _dstack)
1947 || 1 ==get_cmd_values(_word, _nword, "greylevel", 1, _dstack)) {
1948 if (_dstack[0] < 0.0) {
1949 warning("`set image missing value color': clipping graylevel to 0.0");
1950 _image_missing_color_red = 0.0;
1951 _image_missing_color_green = 0.0;
1952 _image_missing_color_blue = 0.0;
1953 } else if (_dstack[0] > 1.0) {
1954 warning("`set image missing value color': clipping graylevel to 0.0");
1955 _image_missing_color_red = 1.0;
1956 _image_missing_color_green = 1.0;
1957 _image_missing_color_blue = 1.0;
1958 } else {
1959 _image_missing_color_red = _dstack[0];
1960 _image_missing_color_green = _dstack[0];
1961 _image_missing_color_blue = _dstack[0];
1962 }
1963 } else {
1964 demonstrate_command_usage();
1965 err("Can't understand color specification.");
1966 return false;
1967 }
1968 }
1969 return true;
1970 }
1971
1972 bool
set_image_rangeCmd()1973 set_image_rangeCmd()
1974 {
1975 double tmp1, tmp2;
1976 switch (_nword) {
1977 case 5:
1978 if (!getdnum(_word[3], &tmp1))
1979 return false;
1980 if (!getdnum(_word[4], &tmp2))
1981 return false;
1982 _image0 = tmp1;
1983 _image255 = tmp2;
1984 return true;
1985 default:
1986 demonstrate_command_usage();
1987 NUMBER_WORDS_ERROR;
1988 return false;
1989 }
1990 }
1991
1992 // `set grid missing inside|outside curve'
1993 // `set grid missing above|below .intercept. .slope'
1994 // 0 1 2 3 4 5
1995 bool
set_grid_missingCmd()1996 set_grid_missingCmd()
1997 {
1998 double intercept, slope;
1999 typedef enum { above, below, inside, outside, dont_know } WHERE;
2000 WHERE where = dont_know;
2001 switch(_nword) {
2002 case 5:
2003 if (word_is(3, "inside"))
2004 where = inside;
2005 else if (word_is(3, "outside"))
2006 where = outside;
2007 break;
2008 case 6:
2009 if (!getdnum(_word[4], &intercept))
2010 return false;
2011 if (!getdnum(_word[5], &slope))
2012 return false;
2013 if (word_is(3, "above"))
2014 where = above;
2015 else if (word_is(3, "below"))
2016 where = below;
2017 break;
2018 default:
2019 demonstrate_command_usage();
2020 NUMBER_WORDS_ERROR;
2021 return false;
2022 }
2023 if (!grid_exists())
2024 return false;
2025 unsigned int i, j;
2026 switch (where) {
2027 case above:
2028 for (i = 0; i < _num_xmatrix_data; i++)
2029 for (j = 0; j < _num_ymatrix_data; j++)
2030 if (_ymatrix[j] > intercept + slope * _xmatrix[i])
2031 _legit_xy(i, j) = false;
2032 return true; // ok
2033 case below:
2034 for (i = 0; i < _num_xmatrix_data; i++)
2035 for (j = 0; j < _num_ymatrix_data; j++)
2036 if (_ymatrix[j] < intercept + slope * _xmatrix[i])
2037 _legit_xy(i, j) = false;
2038 return true; // ok
2039 case inside:
2040 return set_grid_missing_curve(true);
2041 case outside:
2042 return set_grid_missing_curve(false);
2043 default:
2044 demonstrate_command_usage();
2045 err("Fourth word must be `above', `below', `inside' or `outside'");
2046 return false;
2047 }
2048 }
2049
2050 bool
set_grid_missing_curve(bool inside)2051 set_grid_missing_curve(bool inside)
2052 {
2053 if (!inside) {
2054 err("'set grid missing outside curve' not allowed");
2055 return false;
2056 }
2057 unsigned int imax = 0, start = 0;
2058 for (unsigned int i = 0; i < _colX.size(); i++) {
2059 imax = i;
2060 if (gr_missingx(_colX[i])
2061 || gr_missingy(_colY[i])
2062 || i > _colX.size() - 1) {
2063 if (!mask_an_island(_colX.begin() + start,
2064 _colY.begin() + start, i - start))
2065 return false; // problem
2066 while ((gr_missingx(_colX[i]) || gr_missingy(_colY[i]))
2067 && i < _colX.size())
2068 i++;
2069 start = i;
2070 }
2071 }
2072 if (imax <= _colX.size()) {
2073 mask_an_island(_colX.begin() + start,
2074 _colY.begin() + start,
2075 imax - start);
2076 }
2077 return true;
2078 }
2079
2080 bool
mask_an_island(double * x,double * y,unsigned int n)2081 mask_an_island(double *x, double *y, unsigned int n)
2082 {
2083 unsigned right_edge = 0;
2084 double xmax = x[0];
2085 unsigned int i;
2086 for (i = 1; i < n; i++) {
2087 if (x[i] > xmax) {
2088 xmax = x[i];
2089 right_edge = i;
2090 }
2091 }
2092 //DEBUG printf("\nIsland:\n");
2093 //DEBUG for (i = 0; i < n; i++) {
2094 //DEBUG printf(" %f %f\n", x[i], y[i]);
2095 //DEBUG }
2096 //DEBUG printf("Rotates to:\n");
2097 //DEBUG for (i = 0; i < n; i++) {
2098 //DEBUG int ii = (i + right_edge) % n;
2099 //DEBUG printf(" %f %f\n", x[ii], y[ii]);
2100 //DEBUG }
2101 for (i = 0; i < n; i++) {
2102 int ii = (i + right_edge) % n;
2103 for (unsigned int ixm = 0; ixm < _num_xmatrix_data; ixm++) {
2104 if (between(_xmatrix[ixm], x[(ii+1)%n], x[ii])) {
2105 //DEBUG printf("mask out ixm=%d at %f, bracketed by %f - %f\n", ixm, _xmatrix[ixm], x[(ii+1)%n],x[ii]);
2106 for (int iym = (int)_num_ymatrix_data - 1; iym > -1; iym--) {
2107 if (_ymatrix[iym] <=
2108 interpolate_linear(_xmatrix[ixm],
2109 x[ii], y[ii],
2110 x[(ii+1)%n], y[(ii+1)%n])) {
2111 // Reverse things below
2112 //DEBUG printf("reverse below y(%d)=%f\n", iym, _ymatrix[iym]);
2113 while (iym > -1) {
2114 _legit_xy(ixm, iym) = _legit_xy(ixm, iym) == true
2115 ? false : true;
2116 iym--;
2117 }
2118 //DEBUG printf("i=%d; grid=\n", i); show_grid_maskCmd();
2119 break; // just in case
2120 }
2121 }
2122 }
2123 }
2124 }
2125 return true;
2126 }
2127
2128 static bool
width_rapidograph(char * s,double * w)2129 width_rapidograph(char *s, double *w)
2130 {
2131 // Named pen sizes, following the notation of Rapidograph(TM)
2132 // technical drawing pens.
2133 #define NUM_RAPIDOGRAPH 16
2134 typedef struct {
2135 const char *name; // allow both 'X' and 'x' in names
2136 float width; // in points
2137 } r;
2138 r r_table[NUM_RAPIDOGRAPH] = {
2139 {"6x0", 0.369},
2140 {"6X0", 0.369},
2141 {"4x0", 0.510},
2142 {"4X0", 0.510},
2143 {"3x0", 0.709},
2144 {"3X0", 0.709},
2145 {"00", 0.850},
2146 {"0", 0.992},
2147 {"1", 1.417},
2148 {"2", 1.701},
2149 {"2.5", 1.984},
2150 {"3", 2.268},
2151 {"3.5", 2.835},
2152 {"4", 3.402},
2153 {"6", 3.969},
2154 {"7", 5.669}
2155 };
2156 std::string ss(s);
2157 un_double_quote(ss);
2158 for (int i = 0; i < NUM_RAPIDOGRAPH; i++)
2159 if (!strcmp(ss.c_str(), r_table[i].name)) {
2160 *w = r_table[i].width;
2161 return true;
2162 }
2163 err("Unknown rapidograph pen size `\\", s, "' requested.\n Permitted sizes: 6x0, 4x0, 3x0, 00, 0, 1, 2, 2.5, 3, 3.5, 4, 6, 7", "\\");
2164 return false;
2165 }
2166
2167 bool
set_line_capCmd()2168 set_line_capCmd()
2169 {
2170 if (_nword != 4) {
2171 err("`set line cap .type.' has wrong number of words on command line");
2172 return false;
2173 }
2174 double tmp;
2175 if (!getdnum(_word[3], &tmp)) {
2176 READ_WORD_ERROR(".type.");
2177 return false;
2178 }
2179 int t = int(floor(0.5 + tmp));
2180 if (t < 0 || t > 2) {
2181 err("`set line cap .type.' only permits types 0, 1 and 2");
2182 return false;
2183 }
2184 _griState.set_line_cap(t);
2185 return true;
2186 }
2187
2188 bool
set_line_joinCmd()2189 set_line_joinCmd()
2190 {
2191 if (_nword != 4) {
2192 err("`set line join .type.' has wrong number of words on command line");
2193 return false;
2194 }
2195 double tmp;
2196 if (!getdnum(_word[3], &tmp)) {
2197 READ_WORD_ERROR(".type.");
2198 return false;
2199 }
2200 int t = int(floor(0.5 + tmp));
2201 if (t < 0 || t > 2) {
2202 err("`set line join .type.' only permits types 0, 1 and 2");
2203 return false;
2204 }
2205 _griState.set_line_join(t);
2206 return true;
2207 }
2208
2209 bool
set_line_widthCmd()2210 set_line_widthCmd()
2211 {
2212 //show_words();
2213 double w; // the width, in pt
2214 unsigned int skip = 0;
2215 int what = 0; // -1=curve/rapido 0=curve 1=axis 2=symbol 3=all
2216 if (word_is(3, "axis")) {
2217 skip = 1;
2218 what = 1;
2219 } else if (word_is(3, "symbol")) {
2220 skip = 1;
2221 what = 2;
2222 } else if (word_is(3, "all")) {
2223 skip = 1;
2224 what = 3;
2225 } else if (word_is(3, "rapidograph")) {
2226 what = -1;
2227 } else {
2228 if (_nword > 4) {
2229 err("`set line width' found unexpected word `\\", _word[3], "'.", "\\");
2230 return false;
2231 }
2232 }
2233 // Check for 'set line width ...' with no width specification
2234 if (_nword <= (skip + 3)) {
2235 NUMBER_WORDS_ERROR;
2236 return false;
2237 }
2238 // Take care of 'default', simple, and 'rapidograph' styles
2239 if (word_is(3 + skip, "default")) {
2240 Require(_nword == (4 + skip), NUMBER_WORDS_ERROR);
2241 switch (what) {
2242 case 0:
2243 w = LINEWIDTH_DEFAULT;
2244 break;
2245 case 1:
2246 w = LINEWIDTHAXIS_DEFAULT;
2247 break;
2248 case 2:
2249 w = LINEWIDTHSYMBOL_DEFAULT;
2250 break;
2251 case 3:
2252 w = LINEWIDTH_DEFAULT;
2253 break;
2254 default:
2255 w = LINEWIDTHSYMBOL_DEFAULT;
2256 }
2257 } else if (_nword == (4 + skip) && !word_is(3, "rapidograph")) {
2258 // Simple case
2259 if (what == -1) {
2260 if (!width_rapidograph(_word[3 + skip], &w)) {
2261 err("`set line width' cannot understand rapidograph name");
2262 return false;
2263 }
2264 } else {
2265 if (!getdnum(_word[3 + skip], &w))
2266 return false;
2267 }
2268 } else if (_nword == (5 + skip)) {
2269 // Rapidograph style
2270 if (word_is(3 + skip, "rapidograph")) {
2271 if (!width_rapidograph(_word[4 + skip], &w)) {
2272 err("`set line width' cannot understand rapidograph name");
2273 return false;
2274 }
2275 } else {
2276 err("`set line width' expecting word `rapidograph'");
2277 return false;
2278 }
2279 } else {
2280 if (word_is(_nword - 1, "rapidograph")) {
2281 err("`set line width rapidograph' needs a pen-width name");
2282 } else {
2283 err("`set line width' cannot understand the width");
2284 }
2285 return false;
2286 }
2287 // check that w is not crazily small ... a common blunder. See if less
2288 // than 1 dot on a 600dpi printer.
2289 if (w != 0.0) {
2290 if (w / PT_PER_CM < 2.54 / 4800) {
2291 char msg[200];
2292 sprintf(msg,
2293 "a line width of %g points is barely resolved on a 4800 dpi printer",
2294 w);
2295 warning(msg);
2296 } else if (w / PT_PER_CM < 2.54 / 2400) {
2297 char msg[200];
2298 sprintf(msg,
2299 "a line width of %g points is barely resolved on a 2400 dpi printer",
2300 w);
2301 warning(msg);
2302 } else if (w / PT_PER_CM < 2.54 / 600) {
2303 char msg[200];
2304 sprintf(msg,
2305 "a line width of %g points is barely resolved on a 600 dpi printer",
2306 w);
2307 warning(msg);
2308 } else if (w / PT_PER_CM < 2.54 / 400) {
2309 char msg[200];
2310 sprintf(msg,
2311 "a line width of %g points is barely resolved on a 400 dpi printer",
2312 w);
2313 warning(msg);
2314 }
2315 }
2316 switch (what) {
2317 case -1:
2318 case 0:
2319 _griState.set_linewidth_line(w);
2320 PUT_VAR("..linewidth..", w);
2321 break;
2322 case 1:
2323 _griState.set_linewidth_axis(w);
2324 PUT_VAR("..linewidthaxis..", w);
2325 break;
2326 case 2:
2327 _griState.set_linewidth_symbol(w);
2328 PUT_VAR("..linewidthsymbol..", w);
2329 break;
2330 case 3:
2331 _griState.set_linewidth_line(w);
2332 PUT_VAR("..linewidth..", w);
2333 _griState.set_linewidth_axis(w);
2334 PUT_VAR("..linewidthaxis..", w);
2335 _griState.set_linewidth_symbol(w);
2336 PUT_VAR("..linewidthsymbol..", w);
2337 break;
2338 default:
2339 _griState.set_linewidth_line(w);
2340 PUT_VAR("..linewidthline..", w);
2341 }
2342 return true;
2343 }
2344
2345 bool
set_missing_valueCmd()2346 set_missing_valueCmd()
2347 {
2348 // `set missing value #|none'
2349 double tmp;
2350 if (_nword == 4) {
2351 if (!strcmp(_word[3], "none")) {
2352 gr_set_missing_value_none();
2353 } else if (getdnum(_word[3], &tmp)) {
2354 gr_set_missing_value(tmp);
2355 PUT_VAR("..missingvalue..", gr_currentmissingvalue());
2356 {
2357 char tmp[100];
2358 sprintf(tmp, "%f", gr_currentmissingvalue());
2359 put_syn("\\.missingvalue.", tmp, true);
2360 }
2361 } else {
2362 // Actually, can not reach this code, with current error checking
2363 // in getdnum().
2364 demonstrate_command_usage();
2365 READ_WORD_ERROR(".missing_value.");
2366 }
2367 } else {
2368 demonstrate_command_usage();
2369 NUMBER_WORDS_ERROR;
2370 return false;
2371 }
2372 return true;
2373 }
2374
2375 bool
set_page_sizeCmd()2376 set_page_sizeCmd()
2377 {
2378 Require(_nword == 4, err("`set page size' requires 1 parameter"));
2379 const char *s = _word[3]; // save typing
2380 extern rectangle _page_size;
2381 if (!strcmp(s, "letter")) {
2382 _page_size.set(0.0, 0.0, 8.5, 11.0);
2383 _page_size.scale(CM_PER_IN);
2384 } else if (!strcmp(s, "legal")) {
2385 _page_size.set(0.0, 0.0, 8.5, 14.0);
2386 _page_size.scale(CM_PER_IN);
2387 } else if (!strcmp(s, "folio")) {
2388 _page_size.set(0.0, 0.0, 8.5, 13.0);
2389 _page_size.scale(CM_PER_IN);
2390 } else if (!strcmp(s, "tabloid")) {
2391 _page_size.set(0.0, 0.0, 11.0, 17.0);
2392 _page_size.scale(CM_PER_IN);
2393 } else if (!strcmp(s, "A5")) {
2394 _page_size.set(0.0, 0.0, 14.8, 21.0);
2395 } else if (!strcmp(s, "A4")) {
2396 _page_size.set(0.0, 0.0, 21.0, 29.7);
2397 } else if (!strcmp(s, "A3")) {
2398 _page_size.set(0.0, 0.0, 29.7, 42.0);
2399 } else if (!strcmp(s, "A2")) {
2400 _page_size.set(0.0, 0.0, 42.0, 59.4);
2401 } else if (!strcmp(s, "A1")) {
2402 _page_size.set(0.0, 0.0, 59.4, 84.1);
2403 } else if (!strcmp(s, "A0")) {
2404 _page_size.set(0.0, 0.0, 84.1, 118.9);
2405 } else {
2406 demonstrate_command_usage();
2407 err("Unknown paper size `\\", s, "'.", "\\");
2408 return false;
2409 }
2410 return true;
2411 }
2412
2413 bool
set_pageCmd()2414 set_pageCmd()
2415 {
2416 extern rectangle _page_size;
2417 Require(_nword > 2, err("`set page' requires parameter(s)"));
2418 double mag, xcm, ycm;
2419 if (!strcmp(_word[2], "portrait")) {
2420 gr_setup_ps_portrait();
2421 } else if (!strcmp(_word[2], "landscape")) {
2422 if (!already_landscape) {
2423 if (_page_size.get_urx() == 0.0) {
2424 warning("Defaulting to page size US-letter; you should really do `set page size' before `set page landscape'");
2425 fprintf(gr_currentPSFILEpointer(),
2426 "%.2f 72 mul 0 translate 90 rotate %% Landscape\n",
2427 8.5);
2428 } else {
2429 fprintf(gr_currentPSFILEpointer(),
2430 "%.2f 72 mul 0 translate 90 rotate %% Landscape\n",
2431 _page_size.get_urx() / CM_PER_IN);
2432 }
2433 check_psfile();
2434 }
2435 already_landscape = true;
2436 PUT_VAR("..landscape..", 1.0);
2437 gr_setup_ps_landscape();
2438 } else if (!strcmp(_word[2], "factor")) {
2439 if (_nword != 4) {
2440 err("Must specify .mag. in `set page factor .mag.'");
2441 return false;
2442 }
2443 if (!getdnum(_word[3], &mag))
2444 return false;
2445 if (mag <= 0.0) {
2446 err("Can't use negative enlargement factor");
2447 return false;
2448 }
2449 gr_setscale(mag, mag);
2450 } else if (!strcmp(_word[2], "translate")) {
2451 if (_nword != 5) {
2452 err("Must specify .xcm. and .ycm. in `set page translate .xcm. .ycm.'");
2453 return false;
2454 }
2455 if (!getdnum(_word[3], &xcm))
2456 return false;
2457 if (!getdnum(_word[4], &ycm))
2458 return false;
2459 gr_settranslate(xcm, ycm);
2460 } else {
2461 err("Unknown `set page' parameter");
2462 return false;
2463 }
2464 return true;
2465 }
2466
2467 //`set path to "\path"|default for data|commands'
2468 bool
set_pathCmd()2469 set_pathCmd()
2470 {
2471 if (_nword != 6) {
2472 demonstrate_command_usage();
2473 NUMBER_WORDS_ERROR;
2474 return false;
2475 }
2476 if (strNE(_word[4], "for")) {
2477 err("Fourth word must be `for', not `\\", _word[4], "' as given.", "\\");
2478 return false;
2479 }
2480 char *which_path;
2481 if (strEQ(_word[5], "data"))
2482 which_path = (char *)"\\.path_data.";
2483 else if (strEQ(_word[5], "commands"))
2484 which_path = (char *)"\\.path_commands.";
2485 else {
2486 err("Sixth word must be `data' or `commands', not `\\", _word[5], "' as given.", "\\");
2487 return false;
2488 }
2489 if (strEQ(_word[3], "default")) {
2490 if (!put_syn(which_path, ".", true)) {
2491 err("Internal error in setting path to default.");
2492 return false;
2493 }
2494 } else {
2495 std::string unquoted;
2496 int ok = ExtractQuote(_word[3], unquoted);
2497 if (ok) {
2498 if (!put_syn(which_path, unquoted.c_str(), true)) {
2499 err("`set path' cannot save `\\", _word[2], "' in synonym", which_path, "\\");
2500 return false;
2501 }
2502 } else {
2503 err("`set path' cannot understand path `\\", _word[2], "'.", "\\");
2504 return false;
2505 }
2506 }
2507 return true;
2508 }
2509
2510 bool
set_postscript_filenameCmd()2511 set_postscript_filenameCmd()
2512 {
2513 if (_nword != 4) {
2514 demonstrate_command_usage();
2515 NUMBER_WORDS_ERROR;
2516 return false;
2517 }
2518 if (!gr_reopen_postscript(_word[3])) {
2519 demonstrate_command_usage();
2520 warning("Cannot open `\\", _word[3], "', so using old name.", "\\");
2521 }
2522 return true;
2523 }
2524
2525 bool
set_symbol_sizeCmd()2526 set_symbol_sizeCmd()
2527 {
2528 if (_nword < 3) {
2529 err("`set symbol' what?");
2530 return false;
2531 }
2532 if (!strcmp(_word[2], "size")) {
2533 if (!strcmp(_word[3], "default")) {
2534 tmp = SYMBOLSIZE_DEFAULT;
2535 PUT_VAR("..symbolsize..", tmp);
2536 gr_setsymbolsize_cm(SYMBOLSIZE_DEFAULT);
2537 return true;
2538 }
2539 if (!getdnum(_word[3], &tmp))
2540 return false;
2541 if (tmp < 0.0 || tmp > 20.0) {
2542 err("Ignoring bad symbol size <0 or >20 cm");
2543 return false;
2544 }
2545 PUT_VAR("..symbolsize..", tmp);
2546 gr_setsymbolsize_cm(tmp);
2547 } else {
2548 err("`set symbol' what?");
2549 return false;
2550 }
2551 return true;
2552 }
2553
2554 bool
set_tic_sizeCmd()2555 set_tic_sizeCmd()
2556 {
2557 if (_nword < 3) {
2558 err("`set tic' what?");
2559 return false;
2560 }
2561 if (!strcmp(_word[2], "size")) {
2562 if (_nword < 4) {
2563 err("`set tic size' what?");
2564 return false;
2565 }
2566 if (_nword > 4) {
2567 err("Extra words in `set tic size' command");
2568 return false;
2569 }
2570 if (!strcmp(_word[3], "default")) {
2571 tmp = TICSIZE_DEFAULT;
2572 PUT_VAR("..tic_size..", tmp);
2573 return true;
2574 }
2575 if (!getdnum(_word[3], &tmp))
2576 return false;
2577 if (tmp < 0.0 || tmp > 20.0) {
2578 err("Ignoring bad tic size <0 or >20 cm");
2579 return false;
2580 }
2581 PUT_VAR("..tic_size..", tmp);
2582 } else {
2583 err("`set tic' what?");
2584 return false;
2585 }
2586 return true;
2587 }
2588
2589 bool
set_ticsCmd()2590 set_ticsCmd()
2591 {
2592 if (_nword != 3) {
2593 demonstrate_command_usage();
2594 NUMBER_WORDS_ERROR;
2595 return false;
2596 }
2597 if (!strcmp(_word[2], "in")) {
2598 PUT_VAR("..tic_direction..", 1.0);
2599 } else if (!strcmp(_word[2], "out")) {
2600 PUT_VAR("..tic_direction..", 0.0);
2601 } else {
2602 demonstrate_command_usage();
2603 err("Third word must be \"in\" or \"out\".");
2604 return false;
2605 }
2606 return true;
2607 }
2608
2609 bool
set_transparencyCmd()2610 set_transparencyCmd()
2611 {
2612 if (_nword != 3) {
2613 err("`set transpancy' to what value?");
2614 return false;
2615 }
2616 double transparency;
2617 Require(getdnum(_word[2], &transparency), READ_WORD_ERROR(".transparency."));
2618 if (transparency < 0.0)
2619 transparency = 0.0;
2620 if (transparency > 1.0)
2621 transparency = 1.0;
2622 PUT_VAR("..transparency..", transparency);
2623 _griState.set_transparency_line(transparency);
2624 _griState.set_transparency_text(transparency);
2625 return true;
2626 }
2627
2628 bool
set_u_scaleCmd()2629 set_u_scaleCmd()
2630 {
2631 double xsize;
2632 if (_nword < 3) {
2633 demonstrate_command_usage();
2634 err("`set u' ?WHAT?");
2635 return false;
2636 }
2637 if (strcmp(_word[2], "scale")) {
2638 demonstrate_command_usage();
2639 err("`set u ?WHAT?' (try `set u scale ...'");
2640 return false;
2641 }
2642 switch (_nword) {
2643 case 4:
2644 // `set u scale .cm_per_unit.'
2645 if (!getdnum(_word[3], &tmp))
2646 return false;
2647 if (tmp != 0.0) {
2648 _cm_per_u = tmp;
2649 _uscale_exists = true;
2650 return true;
2651 } else {
2652 err("`set u scale 0' illegal");
2653 return false;
2654 }
2655 case 5:
2656 // `set u scale as x'
2657 if (strcmp(_word[3], "as") || strcmp(_word[4], "x")) {
2658 err("Correct usage `set u scale as x'");
2659 return false;
2660 }
2661 if (!_xscale_exists) {
2662 err("First `set x axis' or `read columns x ...'");
2663 return false;
2664 }
2665 if (_xtype != gr_axis_LINEAR) {
2666 err("Can only `set u scale as x' if x is LINEAR");
2667 return false;
2668 }
2669 if (!get_var("..xsize..", &xsize)) {
2670 err("Can't remember ..xsize..");
2671 return false;
2672 }
2673 _cm_per_u = xsize / (_xright - _xleft);
2674 _uscale_exists = true;
2675 return true;
2676 default:
2677 err("`set u' what?");
2678 return false;
2679 }
2680 }
2681
2682 bool
set_v_scaleCmd()2683 set_v_scaleCmd()
2684 {
2685 double ysize;
2686 if (_nword < 3) {
2687 err("`set v' ?WHAT?");
2688 return false;
2689 }
2690 if (strcmp(_word[2], "scale")) {
2691 err("`set v ?WHAT?' (try `set v scale ...'");
2692 return false;
2693 }
2694 switch (_nword) {
2695 case 4:
2696 // `set v scale .cm_per_unit.'
2697 if (!getdnum(_word[3], &tmp))
2698 return false;
2699 if (tmp != 0.0) {
2700 _cm_per_v = tmp;
2701 _vscale_exists = true;
2702 return true;
2703 } else {
2704 err("`set v scale 0' illegal");
2705 return false;
2706 }
2707 case 5:
2708 // `set v scale as y'
2709 if (strcmp(_word[3], "as") || strcmp(_word[4], "y")) {
2710 demonstrate_command_usage();
2711 err("Correct usage `set v scale as y'");
2712 return false;
2713 }
2714 if (!_yscale_exists) {
2715 demonstrate_command_usage();
2716 err("First `set y axis' or `read columns y ...'");
2717 return false;
2718 }
2719 if (_ytype != gr_axis_LINEAR) {
2720 demonstrate_command_usage();
2721 err("Can only `set u scale as y' if y is LINEAR");
2722 return false;
2723 }
2724 if (!get_var("..ysize..", &ysize)) {
2725 demonstrate_command_usage();
2726 err("Can't remember ..ysize..");
2727 return false;
2728 }
2729 _cm_per_v = ysize / (_ytop - _ybottom);
2730 _vscale_exists = true;
2731 return true;
2732 default:
2733 err("`set v' what?");
2734 return false;
2735 }
2736 }
2737
2738 bool
set_traceCmd()2739 set_traceCmd()
2740 {
2741 switch (_nword) {
2742 case 2:
2743 PUT_VAR("..trace..", 1.0);
2744 break;
2745 case 3:
2746 if (!strcmp(_word[2], "on")) {
2747 PUT_VAR("..trace..", 1.0);
2748 } else if (!strcmp(_word[2], "off")) {
2749 PUT_VAR("..trace..", 0.0);
2750 }
2751 break;
2752 default:
2753 break;
2754 }
2755 return true;
2756 }
2757
2758 bool
well_ordered(double min,double max,double inc)2759 well_ordered(double min, double max, double inc)
2760 {
2761 if (min < max)
2762 return ((inc > 0.0) ? true : false);
2763 else
2764 return ((inc < 0.0) ? true : false);
2765 }
2766 bool
inc_within_range(double min,double max,double inc)2767 inc_within_range(double min, double max, double inc)
2768 {
2769 if (min < max)
2770 return (min + inc < max);
2771 else
2772 return (min + inc > max);
2773 }
2774
2775 bool
set_x_axisCmd()2776 set_x_axisCmd()
2777 {
2778 _xatbottom = true;
2779 #if 1 // 2.9.x
2780 if (word_is(3, "labels")) {
2781 if (word_is(4, "automatic")) {
2782 _x_labels.erase(_x_labels.begin(), _x_labels.end());
2783 _x_label_positions.erase(_x_label_positions.begin(), _x_label_positions.end());
2784 return true;
2785 } else {
2786 unsigned int start = 4;
2787 if (word_is(start, "add")) {
2788 start++;
2789 } else {
2790 _x_labels.erase(_x_labels.begin(), _x_labels.end());
2791 _x_label_positions.erase(_x_label_positions.begin(), _x_label_positions.end());
2792 }
2793 for (unsigned int i = start; i < _nword; i++) {
2794 double tmp;
2795 if (!getdnum(_word[i], &tmp)) {
2796 READ_WORD_ERROR(".pos.");
2797 demonstrate_command_usage();
2798 return false;
2799 }
2800 _x_label_positions.push_back(tmp);
2801 if (i++ == _nword - 1) {
2802 err("Missing label to be applied at position \\", _word[i-1], "\\");
2803 demonstrate_command_usage();
2804 return false;
2805 }
2806 std::string l = _word[i];
2807 un_double_quote(l);
2808 _x_labels.push_back(l);
2809
2810 }
2811 return true;
2812 }
2813 }
2814 #endif // 2.9.x
2815 _x_gave_labelling = false;
2816 double labelling_value = 0.0;
2817 if (_nword > 6 && (!strcmp(_word[_nword - 2], "labelling") || !strcmp(_word[_nword - 2], "labeling"))) {
2818 if (_xtype == gr_axis_LOG) {
2819 err("cannot use a 'labelling' value with a logarithmic axis");
2820 return false;
2821 }
2822 if (!getdnum(_word[_nword - 1], &labelling_value)) {
2823 READ_WORD_ERROR("labelling .labelling_value.");
2824 return false;
2825 }
2826 _x_gave_labelling = true;
2827 _nword -= 2; // gobble last two words
2828 }
2829 if (!strcmp(_word[_nword - 1], "bottom")) {
2830 _xatbottom = true;
2831 if (_nword == 4) {
2832 _need_x_axis = true;
2833 _need_y_axis = true;
2834 return true;
2835 }
2836 _nword--;
2837 } else if (!strcmp(_word[_nword - 1], "top")) {
2838 _xatbottom = false;
2839 if (_nword == 4) {
2840 _need_x_axis = true;
2841 _need_y_axis = true;
2842 return true;
2843 }
2844 _nword--;
2845 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "increasing")) {
2846 _xincreasing = true;
2847 if (_xscale_exists && _xleft > _xright) {
2848 swap(_xleft, _xright);
2849 _xinc = -fabs(_xinc);
2850 _x_labelling = _x_gave_labelling ? labelling_value : _xleft; // FIXME
2851 PUT_VAR("..xleft..", _xleft);
2852 PUT_VAR("..xright..", _xright);
2853 PUT_VAR("..xinc..", _xinc);
2854 PUT_VAR("..xlabelling..", _x_labelling);
2855 }
2856 return true;
2857 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "decreasing")) {
2858 _xincreasing = false;
2859 if (_xscale_exists && _xleft < _xright) {
2860 swap(_xleft, _xright);
2861 _xinc = fabs(_xinc);
2862 _x_labelling = _x_gave_labelling ? labelling_value : _xleft;
2863 PUT_VAR("..xleft..", _xleft);
2864 PUT_VAR("..xright..", _xright);
2865 PUT_VAR("..xinc..", _xinc);
2866 PUT_VAR("..xlabelling..", _x_labelling);
2867 }
2868 return true;
2869 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "unknown")) {
2870 _xscale_exists = false;
2871 _need_x_axis = true;
2872 _user_set_x_axis = false;
2873 return true;
2874 }
2875 // ... specifying x axis
2876 // 'set x axis .left. .right.'
2877 if (_nword == 5) {
2878 if (!getdnum(_word[3], &xleft) || !getdnum(_word[4], &xright)) {
2879 READ_WORD_ERROR(".left. and .right.");
2880 return false;
2881 }
2882 if (_xtype == gr_axis_LOG) {
2883 Require(xleft > 0.0,
2884 err("`set x axis .left. .right.' cannot have non-positive .left. value for logarithmic axis"));
2885 Require(xright > 0.0,
2886 err("`set x axis .left. .right.' cannot have non-positive .right. value for logarithmic axis"));
2887 }
2888 _xleft = xleft;
2889 _xright = xright;
2890 if (_xtype == gr_axis_LOG)
2891 _xinc = 1.0;
2892 else
2893 _xinc = _xright - _xleft;
2894 _x_labelling = _x_gave_labelling ? labelling_value : _xleft;
2895 PUT_VAR("..xleft..", _xleft);
2896 PUT_VAR("..xright..", _xright);
2897 PUT_VAR("..xinc..", _xinc);
2898 PUT_VAR("..xlabelling..", _x_labelling);
2899 _xsubdiv = 1;
2900 _xscale_exists = true;
2901 _need_x_axis = true;
2902 _need_y_axis = true;
2903 _user_set_x_axis = true;
2904 return true;
2905 } else if (_nword == 6) { // 'set x axis .left. .right. .inc.'
2906 if (!getdnum(_word[3], &xleft)
2907 || !getdnum(_word[4], &xright)
2908 || !getdnum(_word[5], &xinc)) {
2909 // 'set x axis .left. .right. .incBig.'
2910 READ_WORD_ERROR(".left. .right. .incBig.");
2911 return false;
2912 }
2913 Require(well_ordered(xleft, xright, xinc),
2914 err("`set x axis .left. .right. .incBig.' has .incBig. of wrong sign"));
2915 SUGGEST(inc_within_range(xleft, xright, xinc),
2916 warning("`set x axis .left. .right. .incBig.' has .incBig. that goes outside range"));
2917 if (_xtype == gr_axis_LOG) {
2918 Require(xleft > 0.0,
2919 err("`set x axis .left. .right. .incBig.' cannot have non-positive .left. value for logarithmic axis"));
2920 Require(xright > 0.0,
2921 err("`set x axis .left. .right. .incBig.' cannot have non-positive .right. value for logarithmic axis"));
2922 Require(xinc > 0.0,
2923 err("`set x axis .left. .right. .incBig.' cannot have non-positive .incBig. value for logarithmic axis"));
2924 }
2925 _xleft = xleft;
2926 _xright = xright;
2927 if (_xtype == gr_axis_LOG) {
2928 _xinc = xinc;
2929 _xsubdiv = 1;
2930 } else {
2931 _xinc = xinc;
2932 _xsubdiv = 1;
2933 }
2934 _x_labelling = _x_gave_labelling ? labelling_value : _xleft;
2935 PUT_VAR("..xleft..", _xleft);
2936 PUT_VAR("..xright..", _xright);
2937 PUT_VAR("..xinc..", _xinc);
2938 PUT_VAR("..xlabelling..", _x_labelling);
2939 _xscale_exists = true;
2940 _need_x_axis = true;
2941 _need_y_axis = true;
2942 _user_set_x_axis = true;
2943 return true;
2944 } else if (_nword == 7) { // 'set x axis .left. .right. .incBig. .incSml.'
2945 if (!getdnum(_word[3], &xleft)
2946 || !getdnum(_word[4], &xright)
2947 || !getdnum(_word[5], &xinc)
2948 || !getdnum(_word[6], &tmp)) {
2949 READ_WORD_ERROR(".left. .right. .incBig. .incSml.");
2950 return false;
2951 }
2952 Require(well_ordered(xleft, xright, xinc),
2953 err("`set x axis .left. .right. .incBig. .incSml.' has .incBig. of wrong sign"));
2954 if (_xtype == gr_axis_LOG) {
2955 Require(xleft > 0.0,
2956 err("`set x axis .left. .right. .incBig. .incSml.' cannot have non-positive .left. value for logarithmic axis"));
2957 Require(xright > 0.0,
2958 err("`set x axis .left. .right. .incBig. .incSml.' cannot have non-positive .right. value for logarithmic axis"));
2959 Require(xinc > 0.0,
2960 err("`set x axis .left. .right. .incBig. .incSml.' cannot have non-positive .incBig. value for logarithmic axis"));
2961 }
2962 SUGGEST(inc_within_range(xleft, xright, xinc),
2963 warning("`set x axis .left. .right. .incBig.' has .incBig. that goes outside range"));
2964 _xleft = xleft;
2965 _xright = xright;
2966 if (_xtype == gr_axis_LOG) {
2967 _xinc = xinc;
2968 _xsubdiv = (tmp > 0) ? 1 : -1;
2969 } else {
2970 _xinc = xinc;
2971 _xsubdiv = int(floor(0.5 + fabs((double) (xinc / tmp))));
2972 }
2973 _x_labelling = _x_gave_labelling ? labelling_value : _xleft;
2974 PUT_VAR("..xleft..", _xleft);
2975 PUT_VAR("..xright..", _xright);
2976 PUT_VAR("..xinc..", _xinc);
2977 PUT_VAR("..xlabelling..", _xleft);
2978 _xscale_exists = true;
2979 _need_x_axis = true;
2980 _need_y_axis = true;
2981 _user_set_x_axis = true;
2982 return true;
2983 } else if (_nword == 8) { // 'set x axis .left. .right. .inc. labelling .xlabelling.'
2984 printf("HERE have 8 words\n");
2985 } else {
2986 err("`set x axis' may have only 2, 3 or 4 parameters");
2987 return false;
2988 }
2989 _user_set_x_axis = true;
2990 return true;
2991 }
2992
2993 bool
set_x_formatCmd()2994 set_x_formatCmd()
2995 {
2996 if (_nword < 4) {
2997 err("Must specify a format for `set x format'");
2998 return false;
2999 }
3000 if (!strcmp(_word[3], "off")) {
3001 _xFmt.assign("");
3002 } else if (!strcmp(_word[3], "default")){
3003 _xFmt.assign(X_FMT_DEFAULT);
3004 } else {
3005 if (*_word[3] == '"') {
3006 int len = strlen(_word[3]);
3007 if (len <= 1) {
3008 _xFmt.assign(X_FMT_DEFAULT);
3009 } else {
3010 if (*(_word[3] + len - 1) == '"')
3011 _xFmt.assign(_word[3] + 1, len - 2);
3012 else
3013 _xFmt.assign(_word[3] + 1, len - 1);
3014 }
3015 } else {
3016 _xFmt.assign(_word[3]);
3017 }
3018 }
3019 return true;
3020 }
3021
3022 bool
set_x_gridCmd()3023 set_x_gridCmd()
3024 {
3025 double x, xmin, xmax, xinc;
3026 int i, nx;
3027 // get numbers
3028 if (_nword != 6 && _nword != 7) {
3029 demonstrate_command_usage();
3030 NUMBER_WORDS_ERROR;
3031 return false;
3032 }
3033 Require(getdnum(_word[3], &xmin), READ_WORD_ERROR(".xmin."));
3034 Require(getdnum(_word[4], &xmax), READ_WORD_ERROR(".xmax."));
3035 if (*_word[5] == '/') {
3036 // kludge in case previous parsing didn't separate / from last number
3037 if (_nword == 6) {
3038 Require(getdnum(1 + _word[5], &xinc), err("Can't read /.numx."));
3039 } else if (_nword == 7) {
3040 Require(getdnum(_word[6], &xinc), err("Can't read /.numx."));
3041 } else {
3042 demonstrate_command_usage();
3043 NUMBER_WORDS_ERROR;
3044 return false;
3045 }
3046 Require(xinc >= 1.9, err("Bad /.x.; need >1"));
3047 nx = (int) floor(0.5 + xinc); // redefined below, using xinc
3048 xinc = (xmax - xmin) / (nx - 1);
3049 } else {
3050 Require(getdnum(_word[5], &xinc), READ_WORD_ERROR(".xinc."));
3051 }
3052 // check for stupidity
3053 Require(xinc != 0.0, err("Can't have .xinc.=0"));
3054 Require(xmin != xmax, err("Can't have .xmin. = .xmax."));
3055 Require(well_ordered(xmin, xmax, xinc),
3056 err("`set x grid .xmin. .xmax. .xinc.' has .xinc. of wrong sign"));
3057 SUGGEST(inc_within_range(xmin, xmax, xinc),
3058 warning("`set x grid .xmin. .xmax. .xinc.' has .xinc. that goes outside range"));
3059 nx = int(floor(1.5 + fabs((double) ((xmax - xmin) / xinc))));
3060 Require(nx > 0, err(".xinc. too big"));
3061 // check against existing matrix
3062 if (_grid_exists == true && nx != (int)_num_xmatrix_data) {
3063 sprintf(_errorMsg, "# intervals %d disagrees with existing grid size %d",
3064 nx, _num_xmatrix_data);
3065 err(_errorMsg);
3066 return false;
3067 }
3068 // get storage space
3069 Require(allocate_xmatrix_storage(nx), err("Insufficient space for grid x data"));
3070 // set up x grid
3071 for (i = 0, x = xmin; i < nx; i++, x += xinc)
3072 _xmatrix[i] = x;
3073 // Use grid for axis scale, if the latter does not exist yet
3074 if (!_xscale_exists) {
3075 _xleft = xmin;
3076 _xright = xmax;
3077 _xinc = xinc;
3078 _xscale_exists = true;
3079 //printf("creating x scale %f to %f by %f\n",_xleft, _xright, _xinc);
3080 }
3081 // Override any existing scale
3082 define_image_scales(_xmatrix[0], 0.0, _xmatrix[nx - 1], 0.0);
3083 _xgrid_exists = true;
3084 if (_xmatrix[1] > _xmatrix[0])
3085 _xgrid_increasing = true;
3086 else
3087 _xgrid_increasing = false;
3088 return true;
3089 } // end set_x_gridCmd()
3090
3091 bool
set_y_gridCmd()3092 set_y_gridCmd()
3093 {
3094 double y, ymin, ymax, yinc;
3095 int i, ny;
3096 if (_nword != 6 && _nword != 7) {
3097 demonstrate_command_usage();
3098 NUMBER_WORDS_ERROR;
3099 return false;
3100 }
3101 if (!getdnum(_word[3], &ymin)) {
3102 demonstrate_command_usage();
3103 READ_WORD_ERROR(".ymin.");
3104 return false;
3105 }
3106 if (!getdnum(_word[4], &ymax)) {
3107 demonstrate_command_usage();
3108 READ_WORD_ERROR(".ymax.");
3109 return false;
3110 }
3111 if (*_word[5] == '/') {
3112 // kludge in case previous parsing didn't separate / from last number
3113 if (_nword == 6) {
3114 Require(getdnum(1 + _word[5], &yinc), err("Can't read /.numy."));
3115 } else if (_nword == 7) {
3116 Require(getdnum(_word[6], &yinc), err("Can't read /.numy."));
3117 } else {
3118 demonstrate_command_usage();
3119 NUMBER_WORDS_ERROR;
3120 return false;
3121 }
3122 Require(yinc >= 1.9, err("Bad /.y.; need >1"));
3123 ny = int(floor(0.5 + yinc));
3124 yinc = (ymax - ymin) / (yinc - 1);
3125 } else {
3126 if (!getdnum(_word[5], &yinc)) {
3127 demonstrate_command_usage();
3128 READ_WORD_ERROR(".yinc.");
3129 return false;
3130 }
3131 }
3132 // check for stupidity
3133 Require(yinc != 0.0, err("Can't have .yinc.=0"));
3134 Require(ymin != ymax, err("Can't have .ymin.=.ymax."));
3135 Require(well_ordered(ymin, ymax, yinc),
3136 err("`set y grid .ymin. .ymax. .yinc.' has .yinc. of wrong sign"));
3137 SUGGEST(inc_within_range(ymin, ymax, yinc),
3138 warning("`set y grid .ymin. .ymax. .yinc.' has .yinc. that goes outside range"));
3139 ny = 1 + int(floor(0.5 + fabs((double) ((ymax - ymin) / yinc))));
3140 Require(ny > 0, err(".yinc. too big"));
3141 // check against existing matrix
3142 if (_grid_exists == true && ny != int(_num_ymatrix_data)) {
3143 demonstrate_command_usage();
3144 sprintf(_errorMsg,
3145 "# intervals %d disagrees with existing grid %d",
3146 ny, _num_ymatrix_data);
3147 err(_errorMsg);
3148 return false;
3149 }
3150 // get storage space
3151 Require(allocate_ymatrix_storage(ny), err("Insufficient space for grid y data."));
3152 // set up y grid
3153 for (i = 0, y = ymin; i < ny; i++, y += yinc)
3154 _ymatrix[i] = y;
3155 // Use grid for axis scale, if the latter does not exist yet
3156 if (!_yscale_exists) {
3157 _ybottom = ymin;
3158 _ytop = ymax;
3159 _yinc = yinc;
3160 _yscale_exists = true;
3161 //printf("creating y scale %f to %f by %f\n",_ybottom, _ytop, _yinc);
3162 }
3163 // Override any existing scale
3164 define_image_scales(0.0, _ymatrix[0], 0.0, _ymatrix[ny - 1]);
3165 _ygrid_exists = true;
3166 if (_ymatrix[1] > _ymatrix[0])
3167 _ygrid_increasing = true;
3168 else
3169 _ygrid_increasing = false;
3170 return true;
3171 } // end set_y_gridCmd()
3172
3173 bool
set_x_marginCmd()3174 set_x_marginCmd()
3175 {
3176 if (_nword == 4) {
3177 if (!strcmp(_word[3], "default")) {
3178 tmp = XMARGIN_DEFAULT;
3179 PUT_VAR("..xmargin..", tmp);
3180 _need_x_axis = true;
3181 _need_y_axis = true;
3182 return true;
3183 }
3184 if (!getdnum(_word[3], &tmp)) {
3185 err("Can't understand `set x margin' parameter.");
3186 return false;
3187 }
3188 PUT_VAR("..xmargin..", tmp);
3189 _need_x_axis = true;
3190 _need_y_axis = true;
3191 return true;
3192 } else if (_nword == 5) {
3193 double old = 0.0;
3194 if (!strcmp(_word[3], "bigger")) {
3195 if (!getdnum(_word[4], &tmp)) {
3196 err("can't understand `set x margin bigger' parameter");
3197 return false;
3198 }
3199 get_var("..xmargin..", &old);
3200 tmp = old + tmp;
3201 PUT_VAR("..xmargin..", tmp);
3202 _need_x_axis = true;
3203 _need_y_axis = true;
3204 return true;
3205 } else if (!strcmp(_word[3], "smaller")) {
3206 if (!getdnum(_word[4], &tmp)) {
3207 err("can't understand `set x margin smaller' parameter");
3208 return false;
3209 }
3210 get_var("..xmargin..", &old);
3211 tmp = old - tmp;
3212 PUT_VAR("..xmargin..", tmp);
3213 _need_x_axis = true;
3214 _need_y_axis = true;
3215 return true;
3216 } else {
3217 err("bad `set x margin' parameter\nvalid list: bigger/smaller");
3218 return false;
3219 }
3220 } else {
3221 err("Must specify margin in cm");
3222 return false;
3223 }
3224 }
3225
3226 bool
set_x_nameCmd()3227 set_x_nameCmd()
3228 {
3229 Require(_nword > 3, err("Must specify a name"));
3230 if (word_is(3, "default")) {
3231 _colX.setName("x");
3232 } else {
3233 std::string unquoted;
3234 int status = ExtractQuote(_cmdLine, unquoted);
3235 if (status == 0) {
3236 err("`set x name' needs a double-quoted string");
3237 return false;
3238 }
3239 if (status < 0) {
3240 err("`set x name' found starting double-quote but no ending double-quote");
3241 return false;
3242 }
3243 _colX.setName(unquoted.c_str());
3244 }
3245 return true;
3246 }
3247
3248 // set_x_sizeCmd() -- set width of plot
3249 bool
set_x_sizeCmd()3250 set_x_sizeCmd()
3251 {
3252 if (_nword != 4) {
3253 err("Must specify axis length in cm");
3254 return false;
3255 }
3256 if (!strcmp(_word[3], "default")) {
3257 tmp = XSIZE_DEFAULT;
3258 PUT_VAR("..xsize..", tmp);
3259 _need_x_axis = true;
3260 _need_y_axis = true;
3261 return true;
3262 }
3263 Require(getdnum(_word[3], &tmp), READ_WORD_ERROR(".width_cm."));
3264 Require(tmp >= 0.0, err("ignoring bad xsize <0"));
3265 PUT_VAR("..xsize..", tmp);
3266 _need_x_axis = true;
3267 _need_y_axis = true;
3268 return true;
3269 }
3270
3271 bool
set_y_axisCmd()3272 set_y_axisCmd()
3273 {
3274 _yatleft = true;
3275 #if 1 // 2.9.x
3276 if (word_is(3, "labels")) {
3277 if (word_is(4, "automatic")) {
3278 _y_labels.erase(_y_labels.begin(), _y_labels.end());
3279 _y_label_positions.erase(_y_label_positions.begin(), _y_label_positions.end());
3280 return true;
3281 } else {
3282 unsigned int start = 4;
3283 if (word_is(start, "add")) {
3284 start++;
3285 } else {
3286 _y_labels.erase(_y_labels.begin(), _y_labels.end());
3287 _y_label_positions.erase(_y_label_positions.begin(), _y_label_positions.end());
3288 }
3289 for (unsigned int i = start; i < _nword; i++) {
3290 double tmp;
3291 if (!getdnum(_word[i], &tmp)) {
3292 READ_WORD_ERROR(".pos.");
3293 demonstrate_command_usage();
3294 return false;
3295 }
3296 _y_label_positions.push_back(tmp);
3297 if (i++ == _nword - 1) {
3298 err("Missing label to be applied at position \\", _word[i-1], "\\");
3299 demonstrate_command_usage();
3300 return false;
3301 }
3302 std::string l = _word[i];
3303 un_double_quote(l);
3304 _y_labels.push_back(l);
3305 }
3306 return true;
3307 }
3308 }
3309 #endif // 2.9.x
3310 _y_gave_labelling = false;
3311 double labelling_value = 0.0;
3312 if (_nword > 6 && (!strcmp(_word[_nword - 2], "labelling") || !strcmp(_word[_nword - 2], "labeling"))) {
3313 if (_ytype == gr_axis_LOG) {
3314 err("cannot use a 'labelling' value with a logarithmic axis");
3315 return false;
3316 }
3317 if (!getdnum(_word[_nword - 1], &labelling_value)) {
3318 READ_WORD_ERROR("labelling .labelling_value.");
3319 return false;
3320 }
3321 _y_gave_labelling = true;
3322 _nword -= 2; // gobble last two words
3323 }
3324 if (!strcmp(_word[_nword - 1], "left")) {
3325 _yatleft = true;
3326 if (_nword == 4) {
3327 _need_x_axis = true;
3328 _need_y_axis = true;
3329 return true;
3330 }
3331 _nword--;
3332 } else if (!strcmp(_word[_nword - 1], "right")) {
3333 _yatleft = false;
3334 if (_nword == 4) {
3335 _need_x_axis = true;
3336 _need_y_axis = true;
3337 return true;
3338 }
3339 _nword--;
3340 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "increasing")) {
3341 _yincreasing = true;
3342 if (_yscale_exists && _ybottom > _ytop) {
3343 double tmp = _ybottom;
3344 _ybottom = _ytop;
3345 _ytop = tmp;
3346 _yinc = -_yinc;
3347 _y_labelling = _y_gave_labelling ? labelling_value : _ybottom;
3348 PUT_VAR("..ybottom..", _ybottom);
3349 PUT_VAR("..ytop..", _ytop);
3350 PUT_VAR("..yinc..", _yinc);
3351 PUT_VAR("..ylabelling..", _y_labelling);
3352 }
3353 return true;
3354 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "decreasing")) {
3355 _yincreasing = false;
3356 if (_yscale_exists && _ybottom < _ytop) {
3357 double tmp = _ybottom;
3358 _ybottom = _ytop;
3359 _ytop = tmp;
3360 _yinc = -_yinc;
3361 _y_labelling = _y_gave_labelling ? labelling_value : _ybottom;
3362 PUT_VAR("..ybottom..", _ybottom);
3363 PUT_VAR("..ytop..", _ytop);
3364 PUT_VAR("..yinc..", _yinc);
3365 PUT_VAR("..ylabelling..", _y_labelling);
3366 }
3367 return true;
3368 } else if (_nword == 4 && !strcmp(_word[_nword - 1], "unknown")) {
3369 _yscale_exists = false;
3370 _need_y_axis = true;
3371 _user_set_y_axis = false;
3372 return true;
3373 }
3374 // set y axis name ...
3375 if (_nword == 5 && word_is(3, "name")) {
3376 set_y_axis_nameCmd();
3377 return true;
3378 }
3379 if (_nword == 5 && word_is(3, "label")) {
3380 //printf("YA YA YA %f %f %d\n",_version,_version_expected,gri_version_exceeds(2,8,99));
3381 if (gri_version_exceeds(2, 8, 99)) {
3382 if (_version_expected != 0 && _version_expected < 2.0899) {
3383 warning("Using compatibility mode, interpreting `set y axis label'\n as if it were the newly-named command `set y axis name'.");
3384 set_y_axis_nameCmd();
3385 return true;
3386 } else {
3387 err("The `set y axis label' command is no longer available.\n Please use `set y axis name' instead, or use the `expecting'\n command with a version number lower than 2.9.0, to get\n backwards compatability.");
3388 return false;
3389 }
3390 } else {
3391 set_y_axis_nameCmd();
3392 return true;
3393 }
3394 }
3395 // ... specifying y axis
3396 if (_nword == 5) {
3397 // set y axis .bottom. .top.
3398 if (!getdnum(_word[3], &ybottom) || !getdnum(_word[4], &ytop)) {
3399 err("can't understand parameters");
3400 return false;
3401 }
3402 if (_ytype == gr_axis_LOG) {
3403 Require(ybottom > 0.0,
3404 err("`set y axis .bottom. .top.' cannot have non-positive .bottom. value for logarithmic axis"));
3405 Require(ytop > 0.0,
3406 err("`set y axis .bottom. .top.' cannot have non-positive .top. value for logarithmic axis"));
3407 }
3408 _ybottom = ybottom;
3409 _ytop = ytop;
3410 if (_ytype == gr_axis_LOG)
3411 _yinc = 1.0;
3412 else
3413 _yinc = _ytop - _ybottom;
3414 _y_labelling = _y_gave_labelling ? labelling_value : _ybottom;
3415 PUT_VAR("..ybottom..", _ybottom);
3416 PUT_VAR("..ytop..", _ytop);
3417 PUT_VAR("..yinc..", _yinc);
3418 PUT_VAR("..ylabelling..", _y_labelling);
3419 _ysubdiv = 1;
3420 _yscale_exists = true;
3421 _need_x_axis = true;
3422 _need_y_axis = true;
3423 reset_top_of_plot();
3424 _user_set_y_axis = true;
3425 return true;
3426 } else if (_nword == 6) {
3427 // set y axis .bottom. .top. .incBig.
3428 if (!getdnum(_word[3], &ybottom)
3429 || !getdnum(_word[4], &ytop)
3430 || !getdnum(_word[5], &yinc)) {
3431 err("can't understand parameters");
3432 return false;
3433 }
3434 Require(well_ordered(ybottom, ytop, yinc),
3435 err("`set y axis .bottom. .top. .incBig.' has .incBig. of wrong sign"));
3436 if (_ytype == gr_axis_LOG) {
3437 Require(ybottom > 0.0,
3438 err("`set y axis .bottom. .top. .incBig.' cannot have non-positive .bottom. value for logarithmic axis"));
3439 Require(ytop > 0.0,
3440 err("`set y axis .bottom. .top. .incBig.' cannot have non-positive .top. value for logarithmic axis"));
3441 Require(yinc > 0.0,
3442 err("`set y axis .bottom. .top. .incBig.' cannot have non-positive .incBig. value for logarithmic axis"));
3443 }
3444 SUGGEST(inc_within_range(ybottom, ytop, yinc),
3445 warning("`set y axis .bottom. .top. .incBig.' has .incBig. that goes outside range"));
3446 _ybottom = ybottom;
3447 _ytop = ytop;
3448 if (_ytype == gr_axis_LOG) {
3449 _yinc = yinc;
3450 _ysubdiv = 1;
3451 } else {
3452 _yinc = yinc;
3453 _ysubdiv = 1;
3454 }
3455 _y_labelling = _y_gave_labelling ? labelling_value : _ybottom;
3456 PUT_VAR("..ybottom..", _ybottom);
3457 PUT_VAR("..ytop..", _ytop);
3458 PUT_VAR("..yinc..", _yinc);
3459 PUT_VAR("..ylabelling..", _y_labelling);
3460 _yscale_exists = true;
3461 _need_x_axis = true;
3462 _need_y_axis = true;
3463 reset_top_of_plot();
3464 _user_set_y_axis = true;
3465 return true;
3466 } else if (_nword == 7) { // 'set y axis .bottom. .top. .incBig. .incSml.'
3467 if (!getdnum(_word[3], &ybottom)
3468 || !getdnum(_word[4], &ytop)
3469 || !getdnum(_word[5], &yinc)
3470 || !getdnum(_word[6], &tmp)) {
3471 err("can't understand parameters");
3472 return false;
3473 }
3474 Require(well_ordered(ybottom, ytop, yinc),
3475 err("`set y axis .bottom. .top. .incBig. .incSml.' has .incBig. of wrong sign"));
3476 if (_ytype == gr_axis_LOG) {
3477 Require(ybottom > 0.0,
3478 err("`set y axis .bottom. .top. .incBig. .incSml.' cannot have non-positive .bottom. value for logarithmic axis"));
3479 Require(ytop > 0.0,
3480 err("`set y axis .bottom. .top. .incBig. .incSml.' cannot have non-positive .top. value for logarithmic axis"));
3481 Require(yinc > 0.0,
3482 err("`set y axis .bottom. .top. .incBig. .incSml.' cannot have non-positive .incBig. value for logarithmic axis"));
3483 }
3484 SUGGEST(inc_within_range(ybottom, ytop, yinc),
3485 warning("`set y axis .bottom. .top. .incBig.' has .incBig. that goes outside range"));
3486 _ybottom = ybottom;
3487 _ytop = ytop;
3488 if (_ytype == gr_axis_LOG) {
3489 _yinc = yinc;
3490 _ysubdiv = (tmp > 0) ? 1 : -1;
3491 } else {
3492 _yinc = yinc;
3493 _ysubdiv = int(floor(0.5 + fabs((double) (yinc / tmp))));
3494 }
3495 _y_labelling = _y_gave_labelling ? labelling_value : _ybottom;
3496 PUT_VAR("..ybottom..", _ybottom);
3497 PUT_VAR("..ytop..", _ytop);
3498 PUT_VAR("..yinc..", _yinc);
3499 PUT_VAR("..ylaelled..", _y_labelling);
3500 _yscale_exists = true;
3501 _need_x_axis = true;
3502 _need_y_axis = true;
3503 reset_top_of_plot();
3504 _user_set_y_axis = true;
3505 return true;
3506 } else {
3507 //printf("_nword=%d\n",_nword); dandandan
3508 err("`set y axis' may have only 2, 3 or 4 parameters");
3509 return false;
3510 }
3511 _user_set_y_axis = true;
3512 return true;
3513 }
3514
3515 bool
set_y_axis_nameCmd()3516 set_y_axis_nameCmd()
3517 {
3518 if (_nword == 5 && !strcmp(_word[3], "label")) { // Syntax prior to version 2.9.0
3519 if (!strcmp(_word[4], "horizontal"))
3520 gr_setyaxisstyle(1);
3521 else if (!strcmp(_word[4], "vertical"))
3522 gr_setyaxisstyle(0);
3523 else {
3524 err("`set y axis name' expecting 'horizontal' or 'vertical', but got `\\", _word[4], "'", "\\");
3525 demonstrate_command_usage();
3526 return false;
3527 }
3528 } else if (_nword == 5 && !strcmp(_word[3], "name")) { // From version 2.9.0 onwards
3529 if (!strcmp(_word[4], "horizontal"))
3530 gr_setyaxisstyle(1);
3531 else if (!strcmp(_word[4], "vertical"))
3532 gr_setyaxisstyle(0);
3533 else {
3534 err("`set y axis name' expecting 'horizontal' or 'vertical', but got `\\", _word[4], "'", "\\");
3535 demonstrate_command_usage();
3536 return false;
3537 }
3538 }
3539 return true;
3540 }
3541
3542 bool
set_y_formatCmd()3543 set_y_formatCmd()
3544 {
3545 Require(_nword > 3, err("Must specify a format for `set y format'"));
3546 if (!strcmp(_word[3], "off")) {
3547 _yFmt.assign("");
3548 } else if (!strcmp(_word[3], "default")){
3549 _yFmt.assign(Y_FMT_DEFAULT);
3550 } else {
3551 if (*_word[3] == '"') {
3552 int len = strlen(_word[3]);
3553 if (len <= 1) {
3554 _yFmt.assign(Y_FMT_DEFAULT);
3555 } else {
3556 if (*(_word[3] + len - 1) == '"')
3557 _yFmt.assign(_word[3] + 1, len - 2);
3558 else
3559 _yFmt.assign(_word[3] + 1, len - 1);
3560 }
3561 } else {
3562 _yFmt.assign(_word[3]);
3563 }
3564 }
3565 return true;
3566 }
3567
3568 bool
set_y_marginCmd()3569 set_y_marginCmd()
3570 {
3571 if (_nword == 4) {
3572 if (!strcmp(_word[3], "default")) {
3573 tmp = YMARGIN_DEFAULT;
3574 PUT_VAR("..ymargin..", tmp);
3575 _need_x_axis = true;
3576 _need_y_axis = true;
3577 reset_top_of_plot();
3578 return true;
3579 }
3580 Require(getdnum(_word[3], &tmp), err("can't understand `set y margin' parameter"));
3581 PUT_VAR("..ymargin..", tmp);
3582 _need_x_axis = true;
3583 _need_y_axis = true;
3584 reset_top_of_plot();
3585 return true;
3586 } else if (_nword == 5) {
3587 double old = 0.0;
3588 if (!strcmp(_word[3], "bigger")) {
3589 Require(getdnum(_word[4], &tmp),
3590 err("can't understand `set y margin bigger' parameter"));
3591 get_var("..ymargin..", &old);
3592 tmp = old + tmp;
3593 PUT_VAR("..ymargin..", tmp);
3594 _need_x_axis = true;
3595 _need_y_axis = true;
3596 reset_top_of_plot();
3597 return true;
3598 } else if (!strcmp(_word[3], "smaller")) {
3599 Require(getdnum(_word[4], &tmp),
3600 err("can't understand `set y margin smaller' parameter"));
3601 get_var("..ymargin..", &old);
3602 tmp = old - tmp;
3603 PUT_VAR("..ymargin..", tmp);
3604 _need_x_axis = true;
3605 _need_y_axis = true;
3606 reset_top_of_plot();
3607 return true;
3608 } else {
3609 err("bad `set y margin' parameter\nvalid list: bigger/smaller");
3610 return false;
3611 }
3612 } else {
3613 err("Must specify margin in cm");
3614 return false;
3615 }
3616 }
3617
3618 bool
set_y_nameCmd()3619 set_y_nameCmd()
3620 {
3621 Require(_nword > 3, err("Must specify a name"));
3622 if (word_is(3, "default")) {
3623 _colY.setName("y");
3624 } else {
3625 std::string unquoted;
3626 int status = ExtractQuote(_cmdLine, unquoted);
3627 if (status == 0) {
3628 err("`set y name' needs a double-quoted string");
3629 return false;
3630 }
3631 if (status < 0) {
3632 err("`set y name' found starting double-quote but no ending double-quote");
3633 return false;
3634 }
3635 _colY.setName(unquoted.c_str());
3636 }
3637 return true;
3638 }
3639
3640 // set_y_sizeCmd() -- store height of plot
3641 bool
set_y_sizeCmd()3642 set_y_sizeCmd()
3643 {
3644 Require(_nword == 4, err("Must specify axis length in cm"));
3645 if (!strcmp(_word[3], "default")) {
3646 tmp = YSIZE_DEFAULT;
3647 PUT_VAR("..ysize..", tmp);
3648 reset_top_of_plot();
3649 _need_x_axis = true;
3650 _need_y_axis = true;
3651 return true;
3652 }
3653 Require(getdnum(_word[3], &tmp), READ_WORD_ERROR(".height_cm."));
3654 Require (tmp >= 0.0, err("ignoring bad ysize <0"));
3655 PUT_VAR("..ysize..", tmp);
3656 reset_top_of_plot();
3657 _need_x_axis = true;
3658 _need_y_axis = true;
3659 return true;
3660 }
3661
3662 // Possible calls are as follows; code below may
3663 // be in a different order though!
3664 // Type 1. \syn = word .n. of "string"
3665 // Type 2. \syn = system ...
3666 // Type 3. \syn = tmpname
3667 #if 0
3668 // Type 4. \syn = &.a_var.
3669 // Type 5. \syn = &\a_syn
3670 #endif
3671 // Type 6. \syn = "string"
3672 bool
assign_synonym()3673 assign_synonym()
3674 {
3675 #if 0
3676 printf("DEBUG %s:%d in assign_synonym. words: ", __FILE__,__LINE__);
3677 for (unsigned int iw = 0; iw < _nword; iw++)
3678 printf("<%s> ", _word[iw]);
3679 printf("\n");
3680 #endif
3681 Require (_nword > 2, err("Can't understand command."));
3682 if (!strncmp(_word[0], "\\@", 2)) {
3683 err("The purported alias `\\", _word[0], "' doesn't name any known variable or synonym.", "\\");
3684 return false;
3685 }
3686
3687 // If assigning as e.g.
3688 // \.word1. = 10
3689 // \.word1. = "hi"
3690 // then see if the calling-arg was a var/syn with an & to the left
3691 if (!strncmp(_word[0], "\\.word", 6) && *(_word[0] + strlen(_word[0]) - 1) == '.') {
3692 //printf("DEBUG %s:%d ASSIGNING to word[0] as '%s'\n",__FILE__,__LINE__,_word[0]);
3693 std::string value;
3694 if (!get_syn(_word[0], value, false)) {
3695 err("Cannot access \\.word0. synonym");
3696 return false;
3697 }
3698 //printf("DEBUG %s:%d value of '%s' is '%s'\n",__FILE__,__LINE__,_word[0],value.c_str());
3699 std::string coded_name;
3700 int coded_level = -1;
3701 if (is_coded_string(value, coded_name, &coded_level)) {
3702 //printf("DEBUG %s:%d '%s' was encoded `%s' at level %d\n",__FILE__,__LINE__, _word[0], coded_name.c_str(), coded_level);
3703 if (coded_name.c_str()[0] == '.') {
3704 int index = index_of_variable(coded_name.c_str(), coded_level);
3705 //printf("DEBUG %s:%d A VAR ... index %d. to assign '%s'\n",__FILE__,__LINE__,index,_word[2]);
3706 if (index < 0) {
3707 err("Cannot assign to non-existing variable `", coded_name.c_str(), "' as inferred from coded word `", value.c_str(), "'.", "\\");
3708 return false;
3709 }
3710 double rhs;
3711 if (!getdnum(_word[2], &rhs)) {
3712 err("cannot assign `", _word[2], "' to variable `", coded_name.c_str(), "'.", "\\");
3713 return false;
3714 }
3715 if (!strcmp(_word[1], "=")) {
3716 variableStack[index].set_value(rhs);
3717 } else {
3718 double oldValue = variableStack[index].get_value();
3719 if (strEQ(_word[1], "*="))
3720 variableStack[index].set_value(oldValue * rhs);
3721 else if (strEQ(_word[1], "/="))
3722 variableStack[index].set_value(oldValue / rhs);
3723 else if (strEQ(_word[1], "+="))
3724 variableStack[index].set_value(oldValue +rhs);
3725 else if (strEQ(_word[1], "-="))
3726 variableStack[index].set_value(oldValue - rhs);
3727 else if (strEQ(_word[1], "^="))
3728 variableStack[index].set_value(pow(oldValue, rhs));
3729 else if (strEQ(_word[1], "_=")) {
3730 if (oldValue < 0.0)
3731 variableStack[index].set_value(gr_currentmissingvalue());
3732 else
3733 variableStack[index].set_value(log(oldValue) / log(rhs));
3734 } else {
3735 err("`\\", _word[1], "' is not a known operator for variables", "'\\");
3736 return false;
3737 }
3738 }
3739 } else if (coded_name.c_str()[0] == '\\') {
3740 int index = index_of_synonym(coded_name.c_str(), coded_level);
3741 //printf("DEBUG %s:%d '%s' is syn index %d\n",__FILE__,__LINE__, coded_name.c_str(), index);
3742 std::string unquoted;
3743 int status = ExtractQuote(_word[2], unquoted);
3744 if (status == 0) {
3745 err("`\\synonym = \"value\" found no double-quoted string");
3746 return false;
3747 }
3748 //printf("BEFORE trying to insert at position %d.\n",index);
3749 //show_syn_stack();
3750 synonymStack[index].set_value(unquoted.c_str());
3751 //printf("AFTER.\n");
3752 //show_syn_stack();
3753 } else {
3754 err("Internal error in decoding &\\.word?. for assignment");
3755 return false;
3756 }
3757 return true;
3758 }
3759 }
3760
3761
3762 #if 0
3763 // Check for e.g
3764 // \syn = &.a_var.
3765 // \syn = &\a_syn
3766 if (_nword == 3 && *_word[2] == '&') {
3767 const char *name = 1 + _word[2];
3768 //printf("DEBUG %s:%d GOT A & and think name is <%s>\n",__FILE__,__LINE__,name);
3769 char coded_pointer[200]; // BUG: should be big enough. Jeeze!
3770 if (is_var(name)) {
3771 //printf("DEBUG: %s:%d & on a var named <%s>\n",__FILE__,__LINE__,name);
3772 int the_index = index_of_variable(name);
3773 sprintf(coded_pointer, "\\#v%d#", int(variablePointer.size()));
3774 //printf("DEBUG %s:%d pushing back %d into position %d of variablePointer list\n",__FILE__,__LINE__,the_index,int(variablePointer.size()));
3775 variablePointer.push_back(the_index);
3776 Require(put_syn(_word[0], coded_pointer, true),
3777 err("Cannot store synonym `\\", _word[0], "'", "\\"));
3778 } else if (is_syn(name)) {
3779 //printf("DEBUG: %s:%d & on a syn named <%s>\n",__FILE__,__LINE__,name);
3780 int the_index = index_of_synonym(name);
3781 //printf("DEBUG %s:%d pushing back %d into position %d of synonymPointer list\n",__FILE__,__LINE__,the_index,int(synonymPointer.size()));
3782 sprintf(coded_pointer, "\\#s%d#", int(synonymPointer.size()));
3783 synonymPointer.push_back(the_index);
3784 Require(put_syn(_word[0], coded_pointer, true),
3785 err("Cannot store synonym `\\", _word[0], "'", "\\"));
3786 return true;
3787 } else {
3788 err("Cannot do '&' unless item to right is name of variable or synonym");
3789 return false;
3790 }
3791 return true;
3792 }
3793 #endif
3794 // Following check should never be needed, but keep for possible future
3795 // changes.
3796 Require(is_syn(_word[0]), err("`\\", _word[0], "' must begin with `\\'", "\\"));
3797 // `\synonym = word .n. of "string"'
3798 if (_nword == 6
3799 && !strcmp(_word[1], "=")
3800 && !strcmp(_word[2], "word")
3801 && !strcmp(_word[4], "of")) {
3802 double tmp;
3803 if (!getdnum(_word[3], &tmp)) {
3804 READ_WORD_ERROR(".n. in e.g. `\\syn = word .n. of \"string\"'");
3805 return false;
3806 }
3807 int iwhich = int(floor(0.5 + tmp));
3808 if (iwhich < 0) {
3809 err("Cannot take a negatively-indexed word");
3810 return false;
3811 }
3812 unsigned int which = (unsigned int)(iwhich);
3813 std::string to_chop(_word[_nword - 1]);
3814 if (to_chop[0] == '"')
3815 to_chop.STRINGERASE(0, 1);
3816 if (to_chop[to_chop.size() - 1] == '"') {
3817 to_chop.STRINGERASE(to_chop.size() - 1, 1);
3818 } else {
3819 err("`\\syn = word N of \"string\" requires closing double-quote (\") sign");
3820 return false;
3821 }
3822 char *to_chop_in_C = strdup(to_chop.c_str());
3823 if (to_chop_in_C == NULL) {
3824 err("Out of memory while trying to assign synonym as n-th word of string");
3825 return false;
3826 }
3827 unsigned int max;
3828 chop_into_words(to_chop_in_C, _Words2, &max, MAX_nword);
3829 int i = strlen(_Words2[max - 1]);
3830 if (i > 2 && *(_Words2[max - 1] + i - 1) == '"')
3831 *(_Words2[max - 1] + i - 1) = '\0';
3832 if (which > (max - 1)) {
3833 err("The string \n`\\",
3834 _word[_nword - 1],
3835 "'\ndoes not have that many words. NOTE: the first word is counted as 0.",
3836 "\\");
3837 free(to_chop_in_C);
3838 return false;
3839 }
3840 Require(put_syn(_word[0], _Words2[which], true),
3841 err("Cannot store synonym `\\", _word[0], "'", "\\"));
3842 free(to_chop_in_C);
3843 return true;
3844 } else if (!strcmp(_word[1], "=") && !strcmp(_word[2], "tmpname")) {
3845 if (!put_syn(_word[0], tmp_file_name(), true))
3846 gr_Error("Ran out of storage");
3847 return true;
3848 } else if (!strcmp(_word[1], "=") && !strcmp(_word[2], "system")) {
3849 // `\synonym = system ...'
3850 #if !defined(HAVE_POPEN)
3851 err("\
3852 This computer can't `\\synonym = system ...' since no popen() subroutine.");
3853 return false;
3854 #else
3855 FILE *pipefile;
3856 // Much of following code duplicated in sytemCmd(), so if any
3857 // problems crop up, check there too.
3858 char * s = _cmdLine;
3859 s += skip_space(s); // skip any initial space
3860 s += skip_nonspace(s); // skip first word "\syn"
3861 s += skip_space(s); // skip space
3862 s += skip_nonspace(s); // skip "="
3863 s += skip_space(s); // skip space
3864 s += skip_nonspace(s); // skip "system"
3865 s += skip_space(s); // skip space
3866 if (*s == '\0' || *s == '\n') {
3867 err("`\\syn = system ...' needs a system command to do.");
3868 return false;
3869 }
3870
3871 // See if last word starts with "<<"; if so, then the stuff to be done
3872 // appears on the lines following, ended by whatever word follows the
3873 // "<<".
3874 // ... compare doline.cc near line 510.
3875 int i = strlen(s) - 2;
3876 std::string read_until;
3877 bool using_read_until = false;
3878 while (--i) {
3879 if (!strncmp((s + i), "<<", 2)) {
3880 bool quoted_end_string = false;
3881 int spaces = 0;
3882 while (isspace(*(s + i + 2 + spaces))) {
3883 spaces++;
3884 }
3885 if (*(s + i + 2 + spaces) == '"') {
3886 spaces++;
3887 quoted_end_string = true;
3888 }
3889 read_until.assign(s + i + 2 + spaces);
3890 using_read_until = true;
3891 // trim junk from end of the 'read until' string
3892 std::string::size_type cut_at;
3893 if (quoted_end_string)
3894 cut_at = read_until.find("\"");
3895 else
3896 cut_at = read_until.find(" ");
3897 //printf("READING UNTIL '%s' ... i.e.\n", read_until.c_str());
3898 if (cut_at != STRING_NPOS)
3899 read_until.STRINGERASE(cut_at, read_until.size() - cut_at);
3900 if (read_until.size() < 1) {
3901 err("`system ... <<STOP_STRING' found no STOP_STRING");
3902 return false;
3903 }
3904 //printf("reading until '%s'\n",read_until.c_str());
3905 break;
3906 }
3907 }
3908 static std::string cmd; // might save time in loops
3909 cmd.assign(s);
3910 if (using_read_until) {
3911 // It is of the <<WORD form
3912 #if 1
3913 cmd.append("\n");
3914 extern std::vector<BlockSource> bsStack;
3915 if (bsStack.size() == 0) {
3916 if (((unsigned) superuser()) & FLAG_SYS)printf("DEBUG %s:%d GOBBLE from a file\n",__FILE__,__LINE__);
3917 while (get_command_line()) {
3918 if (((unsigned) superuser()) & FLAG_SYS)printf("DEBUG %s:%d cmd line is [%s]\n",__FILE__,__LINE__,_cmdLine);
3919 // Trim filename/fileline indicator
3920 unsigned int l = strlen(_cmdLine);
3921 for (unsigned int ii = 0; ii < l; ii++) {
3922 if (_cmdLine[ii] == PASTE_CHAR) {
3923 _cmdLine[ii] = '\0';
3924 break;
3925 }
3926 }
3927 if (!strncmp(_cmdLine + skip_space(_cmdLine), read_until.c_str(), read_until.size())) {
3928 cmd.append(_cmdLine + skip_space(_cmdLine));
3929 cmd.append("\n");
3930 break;
3931 }
3932 cmd.append(_cmdLine);
3933 cmd.append("\n");
3934 }
3935 std::string cmd_sub;
3936 substitute_synonyms_cmdline(cmd.c_str(), cmd_sub, false);
3937 cmd = cmd_sub;
3938 } else {
3939 extern unsigned int chars_read;
3940 extern unsigned int offset_for_read;
3941 extern bool get_line_in_block(const char *block, unsigned int *offset);
3942 unsigned int offset = offset_for_read + chars_read;
3943 if (((unsigned) superuser()) & FLAG_SYS)printf("DEBUG %s:%d GOBBLE from block source\n",__FILE__,__LINE__);
3944 while (get_line_in_block(bsStack.back().get_start(), &offset)) {
3945 if (((unsigned) superuser()) & FLAG_SYS)printf("DEBUG %s:%d cmd line is [%s]\n",__FILE__,__LINE__,_cmdLine);
3946 bsStack.back().move_offset(strlen(_cmdLine) + 1);
3947 chars_read += strlen(_cmdLine) + 1;
3948 if (!strncmp(_cmdLine + skip_space(_cmdLine), read_until.c_str(), read_until.size())) {
3949 cmd.append(_cmdLine + skip_space(_cmdLine));
3950 cmd.append("\n");
3951 break;
3952 }
3953 cmd.append(_cmdLine);
3954 cmd.append("\n");
3955 }
3956 std::string cmd_sub;
3957 substitute_synonyms_cmdline(cmd.c_str(), cmd_sub, false);
3958 cmd = cmd_sub;
3959 }
3960 if (((unsigned) superuser()) & FLAG_SYS)printf("DEBUG %s:%d COMMAND START...\n%s\nDEBUG %s:%d ... COMMAND END\n",__FILE__,__LINE__,cmd.c_str(),__FILE__,__LINE__);
3961 #endif
3962 } else {
3963 // No, it is not of the <<WORD form
3964 std::string::size_type loc = 0;
3965 //printf("assigning synonym BEFORE [%s]\n",cmd.c_str());
3966 while (STRING_NPOS != (loc = cmd.find("\\\\", loc))) {
3967 cmd.STRINGERASE(loc, 2);
3968 cmd.insert(loc, "\\");
3969 }
3970 //printf("AFTER [%s]\n",cmd.c_str());
3971 }
3972 clean_blanks_quotes(cmd);
3973 cmd.append("\n");
3974 if (((unsigned) superuser()) & FLAG_SYS) {
3975 ShowStr("\n`\\synonym = system' sending the following command to the operating system:\n");
3976 ShowStr(cmd.c_str());
3977 ShowStr("\n");
3978 }
3979 pipefile = (FILE *) popen(cmd.c_str(), "r");
3980 if (pipefile) {
3981 std::string result;
3982 GriString this_line;
3983 //printf("START.\n");
3984 do {
3985 eof_status s = this_line.line_from_FILE(pipefile);
3986 //printf("<%s> %d (%d=eof_after %d=eofbeforedata, %d=no_eof)\n",this_line.getValue(),s,eof_after_data,eof_before_data,no_eof);
3987 if (s == eof_before_data)
3988 break;
3989 result.append(this_line.getValue());
3990 //printf("NOW <%s>\n",result.c_str());
3991 } while (1);
3992 pclose(pipefile);
3993 while (result[result.size() - 1] == '\n') {
3994 //printf("ERASING newline at end ....\n");
3995 result.STRINGERASE(result.size() - 1, 1);
3996 //printf("<%s>\n",result.c_str());
3997 }
3998 //printf("final <%s>\n",result.c_str());
3999 if (!put_syn(_word[0], result.c_str(), true)) OUT_OF_MEMORY;
4000 return true;
4001 } else {
4002 err("`\\",
4003 _word[0],
4004 " = system ...' can't access system",
4005 "\\");
4006 return false;
4007 }
4008 #endif
4009 } else {
4010 // Type 6. \syn = "string"
4011 std::string unquoted;
4012 int status = ExtractQuote(_cmdLine, unquoted);
4013 if (status == 0) {
4014 err("`\\synonym = \"value\" found no double-quoted string");
4015 return false;
4016 }
4017 if (status < 0) {
4018 err("`\\synonym = \"value\" found starting double-quote but no ending double-quote");
4019 return false;
4020 }
4021 //printf("%s:%d raw <%s> became <%s>\n",__FILE__,__LINE__,_cmdLine,unquoted.c_str());
4022 if (!put_syn(_word[0], unquoted.c_str(), true)) OUT_OF_MEMORY;
4023 }
4024 return true;
4025 }
4026
4027 // `set "\\syn" to "STRING"'
4028 // `set ".var." to NUMBER'
4029 bool
setCmd()4030 setCmd()
4031 {
4032 if (_nword != 4) {
4033 NUMBER_WORDS_ERROR;
4034 return false;
4035 }
4036 if (strNE(_word[2], "to")) {
4037 demonstrate_command_usage();
4038 err("Third word must be `to', not `\\", _word[2], "' as given.", "\\");
4039 return false;
4040 }
4041 std::string name(_word[1]);
4042 clean_blanks_quotes(name);
4043 //printf("<%s> ... <%s>>\n", _word[1], name.c_str());
4044 if (is_var(name.c_str())) {
4045 double value;
4046 if (!getdnum(_word[3], &value)) {
4047 demonstrate_command_usage();
4048 err("Cannot interpret `\\", _word[3], "' as a numerical value.", "\\");
4049 return false;
4050 }
4051 PUT_VAR(name.c_str(), value);
4052 } else if (is_syn(name.c_str())) {
4053 std::string value(_word[3]);
4054 if (value.size() < 2
4055 || (value[0] != '"' || value[-1 + value.size()] != '"')) {
4056 demonstrate_command_usage();
4057 err("Need a double-quoted string to set the synonym to");
4058 return false;
4059 }
4060 value.STRINGERASE(0, 1);
4061 value.STRINGERASE(-1 + value.size(), 1);
4062 put_syn(name.c_str(), value.c_str(), true);
4063 //printf("Assigned '%s' to synonym named '%s'\n", value.c_str(), name.c_str());
4064 } else {
4065 demonstrate_command_usage();
4066 err("Second word must be a variable name or a double-backslashed synonym name, in double quotes, not `\\", name.c_str(), "' as given.", "\\");
4067 return false;
4068 }
4069 return true;
4070 }
4071