2 static char *RCSid() { return RCSid("$Id: misc.c,v 1.81.2.4 2008/10/29 17:20:25 sfeam Exp $"); }
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
42 #include "parse.h" /* for const_express() */
49 #if defined(HAVE_DIRENT_H)
50 # include <sys/types.h>
52 #elif defined(_Windows)
56 /* name of command file; NULL if terminal */
57 char *infile_name = NULL;
59 static TBOOLEAN lf_pop __PROTO((void));
60 static void lf_push __PROTO((FILE *));
61 static void arrow_use_properties __PROTO((struct arrow_style_type *arrow, int tag));
62 static char *recursivefullname __PROTO((const char *path, const char *filename, TBOOLEAN recursive));
64 /* A copy of the declaration from set.c */
65 /* There should only be one declaration in a header file. But I do not know
67 /* void get_position __PROTO((struct position * pos)); */
69 /* State information for load_file(), to recover from errors
70 * and properly handle recursive load_file calls
72 LFS *lf_head = NULL; /* NULL if not in load_file */
74 /* these two could be in load_file, except for error recovery */
75 static TBOOLEAN do_load_arg_substitution = FALSE;
76 static char *call_args[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
79 * iso_alloc() allocates a iso_curve structure that can hold 'num'
86 ip = (struct iso_curve *) gp_alloc(sizeof(struct iso_curve), "iso curve");
87 ip->p_max = (num >= 0 ? num : 0);
89 ip->points = (struct coordinate GPHUGE *)
90 gp_alloc(num * sizeof(struct coordinate), "iso curve points");
92 ip->points = (struct coordinate GPHUGE *) NULL;
98 * iso_extend() reallocates a iso_curve structure to hold "num"
99 * points. This will either expand or shrink the storage.
102 iso_extend(struct iso_curve *ip, int num)
104 if (num == ip->p_max)
107 #if defined(DOS16) || defined(WIN16)
108 /* Make sure we do not allocate more than 64k points in msdos since
109 * indexing is done with 16-bit int
110 * Leave some bytes for malloc maintainance.
113 int_error(NO_CARET, "Array index must be less than 32k in msdos");
114 #endif /* 16bit (Win)Doze */
117 if (ip->points == NULL) {
118 ip->points = (struct coordinate GPHUGE *)
119 gp_alloc(num * sizeof(struct coordinate), "iso curve points");
121 ip->points = (struct coordinate GPHUGE *)
122 gp_realloc(ip->points, num * sizeof(struct coordinate), "expanding curve points");
126 if (ip->points != (struct coordinate GPHUGE *) NULL)
128 ip->points = (struct coordinate GPHUGE *) NULL;
134 * iso_free() releases any memory which was previously malloc()'d to hold
138 iso_free(struct iso_curve *ip)
142 free((char *) ip->points);
148 load_file(FILE *fp, char *name, TBOOLEAN can_do_args)
156 lf_push(fp); /* save state for errors and recursion */
157 do_load_arg_substitution = can_do_args;
159 if (fp == (FILE *) NULL) {
160 os_error(c_token, "Cannot open %s file '%s'",
161 can_do_args ? "call" : "load", name);
162 } else if (fp == stdin) {
163 /* DBT 10-6-98 go interactive if "-" named as load file */
167 /* go into non-interactive mode during load */
168 /* will be undone below, or in load_file_error */
169 int argc = 0; /* number arguments passed by "call" */
175 while (c_token < num_tokens && argc <= 9) {
176 if (isstring(c_token))
177 m_quote_capture(&call_args[argc++], c_token, c_token);
179 m_capture(&call_args[argc++], c_token, c_token);
182 /* Gnuplot "call" command can have up to 10 arguments named "$0"
183 to "$9". After reading the 10th argument (i.e., "$9") the
184 variable 'argc' equals 10.
185 Also, "call" must be the last command on the command line.
187 if (c_token < num_tokens)
188 int_error(++c_token, "too many arguments for 'call <file>'");
190 while (!stop) { /* read all commands in file */
191 /* read one command */
192 left = gp_input_line_len;
197 if (fgets(&(gp_input_line[start]), left, fp) == (char *) NULL) {
198 stop = TRUE; /* EOF in file */
199 gp_input_line[start] = '\0';
203 len = strlen(gp_input_line) - 1;
204 if (gp_input_line[len] == '\n') { /* remove any newline */
205 gp_input_line[len] = '\0';
206 /* Look, len was 1-1 = 0 before, take care here! */
209 if (gp_input_line[len] == '\r') { /* remove any carriage return */
210 gp_input_line[len] = NUL;
214 } else if (len + 2 >= left) {
216 left = gp_input_line_len - len - 1;
218 continue; /* don't check for '\' */
220 if (gp_input_line[len] == '\\') {
221 /* line continuation */
223 left = gp_input_line_len - start;
229 if (strlen(gp_input_line) > 0) {
233 char *raw_line = gp_strdup(gp_input_line);
236 *gp_input_line = '\0';
240 && ((aix = *(++rl)) != 0) /* HBB 980308: quiet BCC warning */
241 && ((aix >= '0' && aix <= '9') || aix == '#')) {
243 /* replace $# by number of passed arguments */
244 len = argc < 10 ? 1 : 2; /* argc can be 0 .. 10 */
245 while (gp_input_line_len - il < len + 1) {
248 sprintf(gp_input_line + il, "%i", argc);
251 if (call_args[aix -= '0']) {
252 /* replace $n for n=0..9 by the passed argument */
253 len = strlen(call_args[aix]);
254 while (gp_input_line_len - il < len + 1) {
257 strcpy(gp_input_line + il, call_args[aix]);
261 /* substitute for $<n> here */
262 if (il + 1 > gp_input_line_len) {
265 gp_input_line[il++] = *rl;
269 if (il + 1 > gp_input_line_len) {
272 gp_input_line[il] = '\0';
275 screen_ok = FALSE; /* make sure command line is
284 (void) lf_pop(); /* also closes file fp */
287 /* pop from load_file state stack
288 FALSE if stack was empty
289 called by load_file and load_file_error */
300 if (lf->fp != (FILE *) NULL && lf->fp != stdin) {
301 /* DBT 10-6-98 do not close stdin in the case
302 * that "-" is named as a load file
304 (void) fclose(lf->fp);
306 for (argindex = 0; argindex < 10; argindex++) {
307 if (call_args[argindex]) {
308 free(call_args[argindex]);
310 call_args[argindex] = lf->call_args[argindex];
312 do_load_arg_substitution = lf->do_load_arg_substitution;
313 interactive = lf->interactive;
314 inline_num = lf->inline_num;
315 infile_name = lf->name;
322 /* push onto load_file state stack
323 essentially, we save information needed to undo the load_file changes
324 called by load_file */
331 lf = (LFS *) gp_alloc(sizeof(LFS), (char *) NULL);
332 if (lf == (LFS *) NULL) {
333 if (fp != (FILE *) NULL)
334 (void) fclose(fp); /* it won't be otherwise */
335 int_error(c_token, "not enough memory to load file");
337 lf->fp = fp; /* save this file pointer */
338 lf->name = infile_name; /* save current name */
339 lf->interactive = interactive; /* save current state */
340 lf->inline_num = inline_num; /* save current line number */
341 lf->do_load_arg_substitution = do_load_arg_substitution;
342 for (argindex = 0; argindex < 10; argindex++) {
343 lf->call_args[argindex] = call_args[argindex];
344 call_args[argindex] = NULL; /* initially no args */
346 lf->prev = lf_head; /* link to stack */
350 /* used for reread vsnyder@math.jpl.nasa.gov */
354 if (lf_head == (LFS *) NULL)
355 return ((FILE *) NULL);
356 return (lf_head->fp);
359 /* called from main */
363 /* clean up from error in load_file */
364 /* pop off everything on stack */
368 /* find max len of keys and count keys with len > 0 */
370 /* FIXME HBB 2000508: by design, this one belongs into 'graphics', and the
371 * next to into 'graph3d'. Actually, the existence of a module like this
372 * 'misc' is almost always a sign of bad design, IMHO */
373 /* may return NULL */
375 loadpath_fopen(const char *filename, const char *mode)
380 if (*filename == '<') {
381 if ((fp = popen(filename + 1, "r")) == (FILE *) NULL)
385 if ((fp = fopen(filename, mode)) == (FILE *) NULL) {
386 /* try 'loadpath' variable */
387 char *fullname = NULL, *path;
389 while ((path = get_loadpath()) != NULL) {
390 /* length of path, dir separator, filename, \0 */
391 fullname = gp_realloc(fullname, strlen(path) + 1 + strlen(filename) + 1, "loadpath_fopen");
392 strcpy(fullname, path);
393 PATH_CONCAT(fullname, filename);
394 if ((fp = fopen(fullname, mode)) != NULL) {
397 /* reset loadpath internals!
398 * maybe this can be replaced by calling get_loadpath with
399 * a NULL argument and some loadpath_handler internal logic */
400 while (get_loadpath());
414 /* Harald Harders <h.harders@tu-bs.de> */
415 /* Thanks to John Bollinger <jab@bollingerbands.com> who has tested the
418 recursivefullname(const char *path, const char *filename, TBOOLEAN recursive)
420 char *fullname = NULL;
423 /* length of path, dir separator, filename, \0 */
424 fullname = gp_alloc(strlen(path) + 1 + strlen(filename) + 1,
425 "recursivefullname");
426 strcpy(fullname, path);
427 PATH_CONCAT(fullname, filename);
429 if ((fp = fopen(fullname, "r")) != NULL) {
440 struct dirent *direntry;
445 while ((direntry = readdir(dir)) != NULL) {
446 char *fulldir = gp_alloc(strlen(path) + 1 + strlen(direntry->d_name) + 1,
447 "fontpath_fullname");
448 strcpy(fulldir, path);
450 if (fulldir[strlen(fulldir) - 1] == ']')
451 fulldir[strlen(fulldir) - 1] = '\0';
452 strcpy(&(fulldir[strlen(fulldir)]), ".");
453 strcpy(&(fulldir[strlen(fulldir)]), direntry->d_name);
454 strcpy(&(fulldir[strlen(fulldir)]), "]");
456 PATH_CONCAT(fulldir, direntry->d_name);
459 if ((S_ISDIR(buf.st_mode)) &&
460 (strcmp(direntry->d_name, ".") != 0) &&
461 (strcmp(direntry->d_name, "..") != 0)) {
462 fullname = recursivefullname(fulldir, filename, TRUE);
463 if (fullname != NULL)
470 #elif defined(_Windows)
472 WIN32_FIND_DATA finddata;
473 char *pathwildcard = gp_alloc(strlen(path) + 2, "fontpath_fullname");
475 strcpy(pathwildcard, path);
476 PATH_CONCAT(pathwildcard, "*");
478 filehandle = FindFirstFile(pathwildcard, &finddata);
480 if (filehandle != INVALID_HANDLE_VALUE)
482 if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
483 (strcmp(finddata.cFileName, ".") != 0) &&
484 (strcmp(finddata.cFileName, "..") != 0)) {
485 char *fulldir = gp_alloc(strlen(path) + 1 + strlen(finddata.cFileName) + 1,
486 "fontpath_fullname");
487 strcpy(fulldir, path);
488 PATH_CONCAT(fulldir, finddata.cFileName);
490 fullname = recursivefullname(fulldir, filename, TRUE);
492 if (fullname != NULL)
495 } while (FindNextFile(filehandle, &finddata) != 0);
496 FindClose(filehandle);
499 int_warn(NO_CARET, "Recursive directory search not supported\n\t('%s!')", path);
506 /* may return NULL */
508 fontpath_fullname(const char *filename)
511 char *fullname = NULL;
514 if (*filename == '<') {
515 os_error(NO_CARET, "fontpath_fullname: No Pipe allowed");
518 if ((fp = fopen(filename, "r")) == (FILE *) NULL) {
519 /* try 'fontpath' variable */
520 char *tmppath, *path = NULL;
522 while ((tmppath = get_fontpath()) != NULL) {
523 TBOOLEAN subdirs = FALSE;
524 path = gp_strdup(tmppath);
525 if (path[strlen(path) - 1] == '!') {
526 path[strlen(path) - 1] = '\0';
529 fullname = recursivefullname(path, filename, subdirs);
530 if (fullname != NULL) {
531 while (get_fontpath());
539 fullname = gp_strdup(filename);
545 /* Push current terminal.
546 * Called 1. in main(), just after init_terminal(),
547 * 2. from load_rcfile(),
548 * 3. anytime by user command "set term push".
550 static char *push_term_name = NULL;
551 static char *push_term_opts = NULL;
554 push_terminal(int is_interactive)
557 free(push_term_name);
558 free(push_term_opts);
559 push_term_name = gp_strdup(term->name);
560 push_term_opts = gp_strdup(term_options);
562 fprintf(stderr, " pushed terminal %s %s\n", push_term_name, push_term_opts);
565 fputs("\tcurrent terminal type is unknown\n", stderr);
570 * Called anytime by user command "set term pop".
575 if (push_term_name != NULL) {
577 int i = strlen(push_term_name) + 11;
578 if (push_term_opts) {
579 /* do_string() does not like backslashes -- thus remove them */
580 for (s=push_term_opts; *s; s++)
581 if (*s=='\\' || *s=='\n') *s=' ';
582 i += strlen(push_term_opts);
584 s = gp_alloc(i, "pop");
587 sprintf(s,"set term %s %s", push_term_name, (push_term_opts ? push_term_opts : ""));
592 fprintf(stderr," restored terminal is %s %s\n", term->name, ((*term_options) ? term_options : ""));
594 fprintf(stderr,"No terminal has been pushed yet\n");
598 /* Parse a plot style. Used by 'set style {data|function}' and by
603 /* defined in plot.h */
608 ps = lookup_table(&plotstyle_tbl[0], c_token);
613 int_error(c_token, "\
614 expecting 'lines', 'points', 'linespoints', 'dots', 'impulses',\n\
615 \t'yerrorbars', 'xerrorbars', 'xyerrorbars', 'steps', 'fsteps',\n\
616 \t'histeps', 'filledcurves', 'boxes', 'boxerrorbars', 'boxxyerrorbars',\n\
617 \t'vectors', 'financebars', 'candlesticks', 'errorlines', 'xerrorlines',\n\
618 \t'yerrorlines', 'xyerrorlines', 'pm3d', 'labels', 'histograms'"
620 ",\n\t 'image', 'rgbimage'"
629 /* Parse options for style filledcurves and fill fco accordingly.
630 * If no option given, then set fco->opt_given to 0.
633 get_filledcurves_style_options(filledcurves_opts *fco)
637 p = lookup_table(&filledcurves_opts_tbl[0], c_token);
639 if (p == FILLEDCURVES_ABOVE) {
641 p = lookup_table(&filledcurves_opts_tbl[0], ++c_token);
642 } else if (p == FILLEDCURVES_BELOW) {
644 p = lookup_table(&filledcurves_opts_tbl[0], ++c_token);
650 return; /* no option given */
657 if (!equals(c_token, "="))
659 /* parameter required for filledcurves x1=... and friends */
660 if (p != FILLEDCURVES_ATXY)
663 fco->at = real(const_express(&a));
664 if (p != FILLEDCURVES_ATXY)
666 /* two values required for FILLEDCURVES_ATXY */
667 if (!equals(c_token, ","))
668 int_error(c_token, "syntax is xy=<x>,<y>");
670 fco->aty = real(const_express(&a));
674 /* Print filledcurves style options to a file (used by 'show' and 'save'
678 filledcurves_options_tofile(filledcurves_opts *fco, FILE *fp)
683 fputs(fco->oneside > 0 ? "above " : "below ", fp);
684 if (fco->closeto == FILLEDCURVES_CLOSED) {
688 if (fco->closeto <= FILLEDCURVES_Y2) {
689 fputs(filledcurves_opts_tbl[fco->closeto].key, fp);
692 if (fco->closeto <= FILLEDCURVES_ATY2) {
693 fprintf(fp, "%s=%g", filledcurves_opts_tbl[fco->closeto - 4].key, fco->at);
696 if (fco->closeto == FILLEDCURVES_ATXY) {
697 fprintf(fp, "xy=%g,%g", fco->at, fco->aty);
702 /* line/point parsing...
704 * allow_ls controls whether we are allowed to accept linestyle in
705 * the current context [ie not when doing a set linestyle command]
706 * allow_point is whether we accept a point command
707 * We assume compiler will optimise away if(0) or if(1)
711 lp_use_properties(struct lp_style_type *lp, int tag, int pointflag)
713 /* This function looks for a linestyle defined by 'tag' and copies
714 * its data into the structure 'lp'.
716 * If 'pointflag' equals ZERO, the properties belong to a linestyle
717 * used with arrows. In this case no point properties will be
718 * passed to the terminal (cf. function 'term_apply_lp_properties' below).
721 struct linestyle_def *this;
723 this = first_linestyle;
724 while (this != NULL) {
725 if (this->tag == tag) {
726 *lp = this->lp_properties;
727 /* FIXME - It would be nicer if this were always true already */
728 if (!lp->use_palette) {
729 lp->pm3d_color.type = TC_LT;
730 lp->pm3d_color.lt = lp->l_type;
732 lp->pointflag = pointflag;
740 /* Mar 2006 - This used to be a fatal error; now we fall back to line type */
741 lp->l_type = tag - 1;
742 lp->pm3d_color.type = TC_LT;
743 lp->pm3d_color.lt = lp->l_type;
744 lp->p_type = tag - 1;
748 /* allow any order of options - pm 24.11.2001 */
749 /* EAM Oct 2005 - Require that default values have been placed in lp by the caller */
751 lp_parse(struct lp_style_type *lp, TBOOLEAN allow_ls, TBOOLEAN allow_point)
756 (almost_equals(c_token, "lines$tyle") || equals(c_token, "ls"))) {
758 lp_use_properties(lp, (int) real(const_express(&t)), allow_point);
760 /* avoid duplicating options */
761 int set_lt = 0, set_pal = 0, set_lw = 0, set_pt = 0, set_ps = 0;
763 lp->pointflag = allow_point;
765 while (!END_OF_COMMAND) {
766 if (almost_equals(c_token, "linet$ype") || equals(c_token, "lt")) {
770 if (almost_equals(c_token, "rgb$color")) {
774 parse_colorspec(&lp->pm3d_color, TC_RGB);
777 /* both syntaxes allowed: 'with lt pal' as well as 'with pal' */
778 if (almost_equals(c_token, "pal$ette")) {
782 parse_colorspec(&lp->pm3d_color, TC_Z);
785 } else if (equals(c_token,"bgnd")) {
786 lp->l_type = LT_BACKGROUND;
790 int lt = real(const_express(&t));
792 /* user may prefer explicit line styles */
793 if (prefer_line_styles && allow_ls)
794 lp_use_properties(lp, lt, TRUE);
798 /* both syntaxes allowed: 'with lt pal' as well as 'with pal' */
799 if (almost_equals(c_token, "pal$ette")) {
803 parse_colorspec(&lp->pm3d_color, TC_Z);
808 if (equals(c_token,"lc") || almost_equals(c_token,"linec$olor")) {
813 if (almost_equals(c_token, "rgb$color")) {
815 parse_colorspec(&lp->pm3d_color, TC_RGB);
816 } else if (almost_equals(c_token, "pal$ette")) {
818 parse_colorspec(&lp->pm3d_color, TC_Z);
820 } else if (equals(c_token,"bgnd")) {
821 lp->pm3d_color.type = TC_LT;
822 lp->pm3d_color.lt = LT_BACKGROUND;
825 } else if (almost_equals(c_token, "var$iable")) {
827 lp->l_type = LT_COLORFROMCOLUMN;
828 lp->pm3d_color.type = TC_LINESTYLE;
830 lp->pm3d_color.type = TC_LT;
831 lp->pm3d_color.lt = (int) real(const_express(&t)) - 1;
836 if (almost_equals(c_token, "linew$idth") || equals(c_token, "lw")) {
840 lp->l_width = real(const_express(&t));
846 if (equals(c_token,"bgnd")) {
847 lp->l_type = LT_BACKGROUND;
853 /* HBB 20010622: restructured to allow for more descriptive
854 * error message, here. Would otherwise only print out
855 * 'undefined variable: pointtype' --- rather unhelpful. */
856 if (almost_equals(c_token, "pointt$ype") || equals(c_token, "pt")) {
861 lp->p_type = (int) real(const_express(&t)) - 1;
863 int_warn(c_token, "No pointtype specifier allowed, here");
869 if (almost_equals(c_token, "points$ize") || equals(c_token, "ps")) {
874 if (almost_equals(c_token, "var$iable")) {
875 lp->p_size = PTSZ_VARIABLE;
877 } else if (almost_equals(c_token, "def$ault")) {
878 lp->p_size = PTSZ_DEFAULT;
881 lp->p_size = real(const_express(&t));
886 int_warn(c_token, "No pointsize specifier allowed, here");
892 /* unknown option catched -> quit the while(1) loop */
896 if (set_lt > 1 || set_pal > 1 || set_lw > 1 || set_pt > 1 || set_ps > 1)
897 int_error(c_token, "duplicated arguments in style specification");
899 #if defined(__FILE__) && defined(__LINE__) && defined(DEBUG_LP)
901 "lp_properties at %s:%d : lt: %d, lw: %.3f, pt: %d, ps: %.3f\n",
902 __FILE__, __LINE__, lp->l_type, lp->l_width, lp->p_type,
908 /* <fillstyle> = {empty | solid {<density>} | pattern {<n>}} {noborder | border {<lt>}} */
910 parse_fillstyle(struct fill_style_type *fs, int def_style, int def_density, int def_pattern, int def_bordertype)
913 TBOOLEAN set_fill = FALSE;
914 TBOOLEAN set_param = FALSE;
917 fs->fillstyle = def_style;
918 fs->filldensity = def_density;
919 fs->fillpattern = def_pattern;
920 fs->border_linetype = def_bordertype;
924 if (!equals(c_token, "fs") && !almost_equals(c_token, "fill$style"))
928 while (!END_OF_COMMAND) {
929 if (almost_equals(c_token, "e$mpty")) {
930 fs->fillstyle = FS_EMPTY;
932 } else if (almost_equals(c_token, "s$olid")) {
933 fs->fillstyle = FS_SOLID;
936 } else if (almost_equals(c_token, "p$attern")) {
937 fs->fillstyle = FS_PATTERN;
944 else if (almost_equals(c_token, "bo$rder")) {
945 fs->border_linetype = LT_UNDEFINED;
947 /* FIXME EAM - isanumber really means `is a positive number` */
948 if (isanumber(c_token) ||
949 (equals(c_token, "-") && isanumber(c_token + 1))) {
950 fs->border_linetype = (int) real(const_express(&a)) - 1;
953 } else if (almost_equals(c_token, "nobo$rder")) {
954 fs->border_linetype = LT_NODRAW;
958 /* We hit something unexpected */
959 else if (!set_fill || !isanumber(c_token) || set_param)
962 if (fs->fillstyle == FS_SOLID) {
963 /* user sets 0...1, but is stored as an integer 0..100 */
964 fs->filldensity = 100.0 * real(const_express(&a)) + 0.5;
965 if (fs->filldensity < 0)
967 if (fs->filldensity > 100)
968 fs->filldensity = 100;
970 } else if (fs->fillstyle == FS_PATTERN) {
971 fs->fillpattern = real(const_express(&a));
972 if (fs->fillpattern < 0)
980 * Parse the sub-options of text color specification
981 * { def$ault | lt <linetype> | pal$ette { cb <val> | frac$tion <val> | z }
982 * The ordering of alternatives shown in the line above is kept in the symbol definitions
983 * TC_DEFAULT TC_LT TC_RGB TC_CB TC_FRAC TC_Z (0 1 2 3 4 5)
984 * and the "options" parameter to parse_colorspec limits legal input to the
985 * corresponding point in the series. So TC_LT allows only default or linetype
986 * coloring, while TC_Z allows all coloring options up to and including pal z
989 parse_colorspec(struct t_colorspec *tc, int options)
995 int_error(c_token, "expected colorspec");
996 if (almost_equals(c_token,"def$ault")) {
998 tc->type = TC_DEFAULT;
1000 } else if (equals(c_token,"bgnd")) {
1003 tc->lt = LT_BACKGROUND;
1005 } else if (equals(c_token,"lt")) {
1008 int_error(c_token, "expected linetype");
1010 tc->lt = (int)real(const_express(&a))-1;
1011 if (tc->lt < LT_BACKGROUND) {
1012 tc->type = TC_DEFAULT;
1013 int_warn(c_token,"illegal linetype");
1015 } else if (options <= TC_LT) {
1016 tc->type = TC_DEFAULT;
1017 int_error(c_token, "only tc lt <n> possible here");
1018 } else if (equals(c_token,"ls") || almost_equals(c_token,"lines$tyle")) {
1020 tc->type = TC_LINESTYLE;
1021 tc->lt = (int)real(const_express(&a));
1022 } else if (almost_equals(c_token,"rgb$color")) {
1027 if (almost_equals(c_token, "var$iable")) {
1028 /* Flag to indicate "variable", not currently checked anywhere */
1034 if (!(color = try_to_get_string()))
1035 int_error(c_token, "expected a color name or a string of form \"#RRGGBB\"");
1036 if ((rgbtriple = lookup_table_nth(pm3d_color_names_tbl, color)) >= 0)
1037 rgbtriple = pm3d_color_names_tbl[rgbtriple].value;
1039 sscanf(color,"#%x",&rgbtriple);
1042 int_error(c_token, "expected a known color name or a string of form \"#RRGGBB\"");
1045 } else if (almost_equals(c_token,"pal$ette")) {
1047 if (equals(c_token,"z")) {
1048 /* The actual z value is not yet known, fill it in later */
1049 if (options >= TC_Z) {
1052 tc->type = TC_DEFAULT;
1053 int_error(c_token, "palette z not possible here");
1056 } else if (equals(c_token,"cb")) {
1060 int_error(c_token, "expected cb value");
1061 tc->value = real(const_express(&a));
1062 } else if (almost_equals(c_token,"frac$tion")) {
1066 int_error(c_token, "expected palette fraction");
1067 tc->value = real(const_express(&a));
1068 if (tc->value < 0. || tc->value > 1.0)
1069 int_error(c_token, "palette fraction out of range");
1071 /* END_OF_COMMAND or palette <blank> */
1072 if (options >= TC_Z)
1076 int_error(c_token, "colorspec option not recognized");
1082 * allow_as controls whether we are allowed to accept arrowstyle in
1083 * the current context [ie not when doing a set style arrow command]
1087 arrow_use_properties(struct arrow_style_type *arrow, int tag)
1089 /* This function looks for an arrowstyle defined by 'tag' and
1090 * copies its data into the structure 'ap'. */
1091 struct arrowstyle_def *this;
1093 this = first_arrowstyle;
1094 while (this != NULL) {
1095 if (this->tag == tag) {
1096 *arrow = this->arrow_properties;
1103 /* tag not found: */
1104 int_error(NO_CARET,"arrowstyle not found", NO_CARET);
1109 struct arrow_style_type *arrow,
1114 if (allow_as && (almost_equals(c_token, "arrows$tyle") ||
1115 equals(c_token, "as"))) {
1117 arrow_use_properties(arrow, (int) real(const_express(&t)));
1119 /* avoid duplicating options */
1120 int set_layer=0, set_line=0, set_head=0;
1121 int set_headsize=0, set_headfilled=0;
1123 while (!END_OF_COMMAND) {
1124 if (equals(c_token, "nohead")) {
1128 arrow->head = NOHEAD;
1131 if (equals(c_token, "head")) {
1135 arrow->head = END_HEAD;
1138 if (equals(c_token, "backhead")) {
1142 arrow->head = BACKHEAD;
1145 if (equals(c_token, "heads")) {
1149 arrow->head = BACKHEAD | END_HEAD;
1153 if (almost_equals(c_token, "fill$ed")) {
1154 if (set_headfilled++)
1157 arrow->head_filled = 2;
1160 if (almost_equals(c_token, "empty")) {
1161 if (set_headfilled++)
1164 arrow->head_filled = 1;
1167 if (almost_equals(c_token, "nofill$ed")) {
1168 if (set_headfilled++)
1171 arrow->head_filled = 0;
1175 if (equals(c_token, "size")) {
1176 struct position hsize;
1179 hsize.scalex = hsize.scaley = hsize.scalez = first_axes;
1180 /* only scalex used; scaley is angle of the head in [deg] */
1183 int_error(c_token, "head size expected");
1184 get_position(&hsize);
1185 arrow->head_length = hsize.x;
1186 arrow->head_lengthunit = hsize.scalex;
1187 arrow->head_angle = hsize.y;
1188 arrow->head_backangle = hsize.z;
1189 /* invalid backangle --> default of 90.0° */
1190 if (arrow->head_backangle <= arrow->head_angle)
1191 arrow->head_backangle = 90.0;
1195 if (equals(c_token, "back")) {
1202 if (equals(c_token, "front")) {
1210 /* pick up a line spec - allow ls, but no point. */
1212 int stored_token = c_token;
1213 lp_parse(&arrow->lp_properties, TRUE, FALSE);
1214 if (stored_token == c_token || set_line++)
1219 /* unknown option caught -> quit the while(1) loop */
1223 if (set_layer>1 || set_line>1 || set_head>1 || set_headsize>1 || set_headfilled>1)
1224 int_error(c_token, "duplicated arguments in style specification");
1226 #if defined(__FILE__) && defined(__LINE__) && defined(DEBUG_LP)
1228 arrow->lp_properties = tmp_lp_style;
1230 arrow->head_length = 0.0;
1231 arrow->head_lengthunit = first_axes;
1232 arrow->head_angle = 15.0;
1233 arrow->head_backangle = 90.0;
1234 arrow->head_filled = 0;
1236 "arrow_properties at %s:%d : layer: %d, lt: %d, lw: %.3f, head: %d, headlength/unit: %.3f/%d, headangles: %.3f/%.3f, headfilled %d\n",
1237 __FILE__, __LINE__, arrow->layer, arrow->lp_properties.l_type,
1238 arrow->lp_properties.l_width, arrow->head, arrow->head_length,
1239 arrow->head_lengthunit, arrow->head_angle,
1240 arrow->head_backangle, arrow->head_filled);