long parse_color_name() { char *string; long color = -2; /* Terminal drivers call this after seeing a "background" option */ if (almost_equals(c_token,"rgb$color") && almost_equals(c_token-1,"back$ground")) c_token++; if ((string = try_to_get_string())) { int iret; iret = lookup_table_nth(pm3d_color_names_tbl, string); if (iret >= 0) color = pm3d_color_names_tbl[iret].value; else if (string[0] == '#') iret = sscanf(string,"#%lx",&color); else if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) iret = sscanf(string,"%lx",&color); free(string); if (color == -2) int_error(c_token, "unrecognized color name and not a string \"#AARRGGBB\" or \"0xAARRGGBB\""); } else { color = int_expression(); } return (unsigned int)(color); }
/* Look for an iterate-over-plot construct, of the form * {s}plot for [<var> = <start> : <end> { : <increment>}] ... */ void check_for_iteration() { char *errormsg = "Expecting iterator \tfor [<var> = <start> : <end>]\n\t\t\tor\tfor [<var> in \"string of words\"]"; iteration_udv = NULL; free(iteration_string); iteration_string = NULL; iteration_increment = 1; iteration = 0; if (!equals(c_token, "for")) return; c_token++; if (!equals(c_token++, "[") || !isletter(c_token)) int_error(c_token-1, errormsg); iteration_udv = add_udv(c_token++); if (equals(c_token, "=")) { c_token++; iteration_start = int_expression(); if (!equals(c_token++, ":")) int_error(c_token-1, errormsg); iteration_end = int_expression(); if (equals(c_token,":")) { c_token++; iteration_increment = int_expression(); } if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); if (iteration_udv->udv_undef == FALSE) gpfree_string(&iteration_udv->udv_value); Ginteger(&(iteration_udv->udv_value), iteration_start); iteration_udv->udv_undef = FALSE; } else if (equals(c_token++, "in")) { iteration_string = try_to_get_string(); if (!iteration_string) int_error(c_token-1, errormsg); if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); iteration_start = 1; iteration_end = gp_words(iteration_string); if (iteration_udv->udv_undef == FALSE) gpfree_string(&iteration_udv->udv_value); Gstring(&(iteration_udv->udv_value), gp_word(iteration_string, 1)); iteration_udv->udv_undef = FALSE; } else /* Neither [i=B:E] or [s in "foo"] */ int_error(c_token-1, errormsg); iteration_current = iteration_start; }
/* Used by plot2d/plot3d/fit: * Parse an expression that may return a string or may return a constant or may * be a dummy function using dummy variables x, y, ... * If any dummy variables are present, set (*atptr) to point to an action table * corresponding to the parsed expression, and return NULL. * Otherwise evaluate the expression and return a string if there is one. * The return value "str" and "*atptr" both point to locally-managed memory, * which must not be freed by the caller! */ char* string_or_express(struct at_type **atptr) { int i; TBOOLEAN has_dummies; static char* str = NULL; free(str); str = NULL; if (atptr) *atptr = NULL; if (END_OF_COMMAND) int_error(c_token, "expression expected"); /* parsing for datablocks */ if (equals(c_token,"$")) return parse_datablock_name(); if (isstring(c_token)) { str = try_to_get_string(); return str; } /* parse expression */ temp_at(); /* check if any dummy variables are used */ has_dummies = FALSE; for (i = 0; i < at->a_count; i++) { enum operators op_index = at->actions[i].index; if ( op_index == PUSHD1 || op_index == PUSHD2 || op_index == PUSHD || op_index == SUM ) { has_dummies = TRUE; break; } } if (!has_dummies) { /* no dummy variables: evaluate expression */ struct value val; evaluate_at(at, &val); if (!undefined && val.type == STRING) str = val.v.string_val; } /* prepare return */ if (atptr) *atptr = at; return str; }
long parse_color_name() { char *string; long color = -1; if (almost_equals(c_token,"rgb$color")) c_token++; if ((string = try_to_get_string())) { color = lookup_table_nth(pm3d_color_names_tbl, string); if (color >= 0) color = pm3d_color_names_tbl[color].value; else sscanf(string,"#%lx",&color); free(string); } if (color == -1) int_error(c_token, "not recognized as a color name or a string of form \"#RRGGBB\""); return (unsigned int)(color); }
/* Look for iterate-over-plot constructs, of the form * for [<var> = <start> : <end> { : <increment>}] ... * If one (or more) is found, an iterator structure is allocated and filled * and a pointer to that structure is returned. * The pointer is NULL if no "for" statements are found. */ t_iterator * check_for_iteration() { char *errormsg = "Expecting iterator \tfor [<var> = <start> : <end> {: <incr>}]\n\t\t\tor\tfor [<var> in \"string of words\"]"; int nesting_depth = 0; t_iterator *iter = NULL; t_iterator *this_iter = NULL; /* Now checking for iteration parameters */ /* Nested "for" statements are supported, each one corresponds to a node of the linked list */ while (equals(c_token, "for")) { struct udvt_entry *iteration_udv = NULL; char *iteration_string = NULL; int iteration_start; int iteration_end; int iteration_increment = 1; int iteration_current; int iteration = 0; TBOOLEAN empty_iteration; TBOOLEAN just_once = FALSE; c_token++; if (!equals(c_token++, "[") || !isletter(c_token)) int_error(c_token-1, errormsg); iteration_udv = add_udv(c_token++); if (equals(c_token, "=")) { c_token++; iteration_start = int_expression(); if (!equals(c_token++, ":")) int_error(c_token-1, errormsg); iteration_end = int_expression(); if (equals(c_token,":")) { c_token++; iteration_increment = int_expression(); if (iteration_increment == 0) int_error(c_token-1, errormsg); } if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); if (iteration_udv->udv_undef == FALSE) gpfree_string(&(iteration_udv->udv_value)); Ginteger(&(iteration_udv->udv_value), iteration_start); iteration_udv->udv_undef = FALSE; } else if (equals(c_token++, "in")) { iteration_string = try_to_get_string(); if (!iteration_string) int_error(c_token-1, errormsg); if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); iteration_start = 1; iteration_end = gp_words(iteration_string); if (iteration_udv->udv_undef == FALSE) gpfree_string(&(iteration_udv->udv_value)); Gstring(&(iteration_udv->udv_value), gp_word(iteration_string, 1)); iteration_udv->udv_undef = FALSE; } else /* Neither [i=B:E] or [s in "foo"] */ int_error(c_token-1, errormsg); iteration_current = iteration_start; empty_iteration = FALSE; if ( (iteration_udv != NULL) && ((iteration_end > iteration_start && iteration_increment < 0) || (iteration_end < iteration_start && iteration_increment > 0))) { empty_iteration = TRUE; FPRINTF((stderr,"Empty iteration\n")); } /* Allocating a node of the linked list nested iterations. */ /* Iterating just once is the same as not iterating at all */ /* so we skip building the node in that case. */ if (iteration_start == iteration_end) just_once = TRUE; if (iteration_start < iteration_end && iteration_end < iteration_start + iteration_increment) just_once = TRUE; if (iteration_start > iteration_end && iteration_end > iteration_start + iteration_increment) just_once = TRUE; if (!just_once) { this_iter = gp_alloc(sizeof(t_iterator), "iteration linked list"); this_iter->iteration_udv = iteration_udv; this_iter->iteration_string = iteration_string; this_iter->iteration_start = iteration_start; this_iter->iteration_end = iteration_end; this_iter->iteration_increment = iteration_increment; this_iter->iteration_current = iteration_current; this_iter->iteration = iteration; this_iter->done = FALSE; this_iter->really_done = FALSE; this_iter->empty_iteration = empty_iteration; this_iter->next = NULL; this_iter->prev = NULL; if (nesting_depth == 0) { /* first "for" statement: this will be the listhead */ iter = this_iter; } else { /* not the first "for" statement: attach the newly created node to the end of the list */ iter->prev->next = this_iter; /* iter->prev points to the last node of the list */ this_iter->prev = iter->prev; } iter->prev = this_iter; /* a shortcut: making the list circular */ /* if one iteration in the chain is empty, the subchain of nested iterations is too */ if (!iter->empty_iteration) iter->empty_iteration = empty_iteration; nesting_depth++; } } return iter; }
void multiplot_start() { TBOOLEAN set_spacing = FALSE; TBOOLEAN set_margins = FALSE; c_token++; /* Only a few options are possible if we are already in multiplot mode */ /* So far we have "next". Maybe also "previous", "clear"? */ if (multiplot) { if (equals(c_token, "next")) { c_token++; if (!mp_layout.auto_layout) int_error(c_token, "only valid inside an auto-layout multiplot"); multiplot_next(); return; } else if (almost_equals(c_token, "prev$ious")) { c_token++; if (!mp_layout.auto_layout) int_error(c_token, "only valid inside an auto-layout multiplot"); multiplot_previous(); return; } else { term_end_multiplot(); } } /* FIXME: more options should be reset/initialized each time */ mp_layout.auto_layout = FALSE; mp_layout.auto_layout_margins = FALSE; mp_layout.current_panel = 0; mp_layout.title.noenhanced = FALSE; free(mp_layout.title.text); mp_layout.title.text = NULL; free(mp_layout.title.font); mp_layout.title.font = NULL; /* Parse options */ while (!END_OF_COMMAND) { if (almost_equals(c_token, "ti$tle")) { c_token++; mp_layout.title.text = try_to_get_string(); continue; } if (equals(c_token, "font")) { c_token++; mp_layout.title.font = try_to_get_string(); continue; } if (almost_equals(c_token,"enh$anced")) { mp_layout.title.noenhanced = FALSE; c_token++; continue; } if (almost_equals(c_token,"noenh$anced")) { mp_layout.title.noenhanced = TRUE; c_token++; continue; } if (almost_equals(c_token, "lay$out")) { if (mp_layout.auto_layout) int_error(c_token, "too many layout commands"); else mp_layout.auto_layout = TRUE; c_token++; if (END_OF_COMMAND) { int_error(c_token,"expecting '<num_cols>,<num_rows>'"); } /* read row,col */ mp_layout.num_rows = int_expression(); if (END_OF_COMMAND || !equals(c_token,",") ) int_error(c_token, "expecting ', <num_cols>'"); c_token++; if (END_OF_COMMAND) int_error(c_token, "expecting <num_cols>"); mp_layout.num_cols = int_expression(); /* remember current values of the plot size and the margins */ mp_layout.prev_xsize = xsize; mp_layout.prev_ysize = ysize; mp_layout.prev_xoffset = xoffset; mp_layout.prev_yoffset = yoffset; mp_layout.prev_lmargin = lmargin; mp_layout.prev_rmargin = rmargin; mp_layout.prev_bmargin = bmargin; mp_layout.prev_tmargin = tmargin; mp_layout.act_row = 0; mp_layout.act_col = 0; continue; } /* The remaining options are only valid for auto-layout mode */ if (!mp_layout.auto_layout) int_error(c_token, "only valid in the context of an auto-layout command"); switch(lookup_table(&set_multiplot_tbl[0],c_token)) { case S_MULTIPLOT_COLUMNSFIRST: mp_layout.row_major = TRUE; c_token++; break; case S_MULTIPLOT_ROWSFIRST: mp_layout.row_major = FALSE; c_token++; break; case S_MULTIPLOT_DOWNWARDS: mp_layout.downwards = TRUE; c_token++; break; case S_MULTIPLOT_UPWARDS: mp_layout.downwards = FALSE; c_token++; break; case S_MULTIPLOT_SCALE: c_token++; mp_layout.xscale = real_expression(); mp_layout.yscale = mp_layout.xscale; if (!END_OF_COMMAND && equals(c_token,",") ) { c_token++; if (END_OF_COMMAND) { int_error(c_token, "expecting <yscale>"); } mp_layout.yscale = real_expression(); } break; case S_MULTIPLOT_OFFSET: c_token++; mp_layout.xoffset = real_expression(); mp_layout.yoffset = mp_layout.xoffset; if (!END_OF_COMMAND && equals(c_token,",") ) { c_token++; if (END_OF_COMMAND) { int_error(c_token, "expecting <yoffset>"); } mp_layout.yoffset = real_expression(); } break; case S_MULTIPLOT_MARGINS: c_token++; if (END_OF_COMMAND) int_error(c_token,"expecting '<left>,<right>,<bottom>,<top>'"); mp_layout.lmargin.scalex = screen; mp_layout_set_margin_or_spacing(&(mp_layout.lmargin)); if (!END_OF_COMMAND && equals(c_token,",") ) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expecting <right>"); mp_layout.rmargin.scalex = mp_layout.lmargin.scalex; mp_layout_set_margin_or_spacing(&(mp_layout.rmargin)); } else { int_error(c_token, "expecting <right>"); } if (!END_OF_COMMAND && equals(c_token,",") ) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expecting <top>"); mp_layout.bmargin.scalex = mp_layout.rmargin.scalex; mp_layout_set_margin_or_spacing(&(mp_layout.bmargin)); } else { int_error(c_token, "expecting <bottom>"); } if (!END_OF_COMMAND && equals(c_token,",") ) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expecting <bottom>"); mp_layout.tmargin.scalex = mp_layout.bmargin.scalex; mp_layout_set_margin_or_spacing(&(mp_layout.tmargin)); } else { int_error(c_token, "expection <top>"); } set_margins = TRUE; break; case S_MULTIPLOT_SPACING: c_token++; if (END_OF_COMMAND) int_error(c_token,"expecting '<xspacing>,<yspacing>'"); mp_layout.xspacing.scalex = screen; mp_layout_set_margin_or_spacing(&(mp_layout.xspacing)); mp_layout.yspacing = mp_layout.xspacing; if (!END_OF_COMMAND && equals(c_token, ",")) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expecting <yspacing>"); mp_layout_set_margin_or_spacing(&(mp_layout.yspacing)); } set_spacing = TRUE; break; default: int_error(c_token,"invalid or duplicate option"); break; } } if (set_spacing || set_margins) { if (set_spacing && set_margins) { if (mp_layout.lmargin.x >= 0 && mp_layout.rmargin.x >= 0 && mp_layout.tmargin.x >= 0 && mp_layout.bmargin.x >= 0 && mp_layout.xspacing.x >= 0 && mp_layout.yspacing.x >= 0) mp_layout.auto_layout_margins = TRUE; else int_error(NO_CARET, "must give positive margin and spacing values"); } else if (set_spacing) { int_warn(NO_CARET, "must give margins and spacing, continue with auto margins."); } else if (set_margins) { mp_layout.auto_layout_margins = TRUE; mp_layout.xspacing.scalex = screen; mp_layout.xspacing.x = 0.05; mp_layout.yspacing.scalex = screen; mp_layout.yspacing.x = 0.05; int_warn(NO_CARET, "must give margins and spacing, continue with spacing of 0.05"); } /* Sanity check that screen tmargin is > screen bmargin */ if (mp_layout.bmargin.scalex == screen && mp_layout.tmargin.scalex == screen) if (mp_layout.bmargin.x > mp_layout.tmargin.x) { double tmp = mp_layout.bmargin.x; mp_layout.bmargin.x = mp_layout.tmargin.x; mp_layout.tmargin.x = tmp; } } /* If we reach here, then the command has been successfully parsed. * Aug 2013: call term_start_plot() before setting multiplot so that * the wxt and qt terminals will reset the plot count to 0 before * ignoring subsequent TERM_LAYER_RESET requests. */ term_start_plot(); multiplot = TRUE; fill_gpval_integer("GPVAL_MULTIPLOT", 1); /* Place overall title before doing anything else */ if (mp_layout.title.text) { double tmpx, tmpy; unsigned int x, y; char *p = mp_layout.title.text; map_position_r(&(mp_layout.title.offset), &tmpx, &tmpy, "mp title"); x = term->xmax / 2 + tmpx; y = term->ymax - term->v_char + tmpy;; ignore_enhanced(mp_layout.title.noenhanced); apply_pm3dcolor(&(mp_layout.title.textcolor)); write_multiline(x, y, mp_layout.title.text, CENTRE, JUST_TOP, 0, mp_layout.title.font); reset_textcolor(&(mp_layout.title.textcolor)); ignore_enhanced(FALSE); /* Calculate fractional height of title compared to entire page */ /* If it would fill the whole page, forget it! */ for (y=1; *p; p++) if (*p == '\n') y++; /* Oct 2012 - v_char depends on the font used */ if (mp_layout.title.font && *mp_layout.title.font) term->set_font(mp_layout.title.font); mp_layout.title_height = (double)(y * term->v_char) / (double)term->ymax; if (mp_layout.title.font && *mp_layout.title.font) term->set_font(""); if (mp_layout.title_height > 0.9) mp_layout.title_height = 0.05; } else { mp_layout.title_height = 0.0; } if (mp_layout.auto_layout_margins) mp_layout_margins_and_spacing(); else mp_layout_size_and_offset(); }
// Called when terminal type is selected. // This procedure should parse options on the command line. // A list of the currently selected options should be stored in term_options[], // in a form suitable for use with the set term command. // term_options[] is used by the save command. Use options_null() if no options are available." * void qt_options() { char *s = NULL; QString fontSettings; bool duplication = false; bool set_enhanced = false, set_font = false; bool set_persist = false, set_number = false; bool set_raise = false, set_ctrl = false; bool set_title = false, set_close = false; bool set_size = false; bool set_widget = false; bool set_dash = false; if (term_interlock != NULL && term_interlock != (void *)qt_init) { term = NULL; int_error(NO_CARET, "The qt terminal cannot be used in a wxt session"); } #define SETCHECKDUP(x) { c_token++; if (x) duplication = true; x = true; } while (!END_OF_COMMAND) { FPRINTF((stderr, "processing token\n")); switch (lookup_table(&qt_opts[0], c_token)) { case QT_WIDGET: SETCHECKDUP(set_widget); if (!(s = try_to_get_string())) int_error(c_token, "widget: expecting string"); if (*s) qt_optionWidget = QString(s); free(s); break; case QT_FONT: SETCHECKDUP(set_font); if (!(s = try_to_get_string())) int_error(c_token, "font: expecting string"); if (*s) { fontSettings = QString(s); QStringList list = fontSettings.split(','); if ((list.size() > 0) && !list[0].isEmpty()) qt_optionFontName = list[0]; if ((list.size() > 1) && (list[1].toInt() > 0)) qt_optionFontSize = list[1].toInt(); } free(s); break; case QT_ENHANCED: SETCHECKDUP(set_enhanced); qt_optionEnhanced = true; term->flags |= TERM_ENHANCED_TEXT; break; case QT_NOENHANCED: SETCHECKDUP(set_enhanced); qt_optionEnhanced = false; term->flags &= ~TERM_ENHANCED_TEXT; break; case QT_SIZE: SETCHECKDUP(set_size); if (END_OF_COMMAND) int_error(c_token, "size requires 'width,heigth'"); qt_optionWidth = real_expression(); if (!equals(c_token++, ",")) int_error(c_token, "size requires 'width,heigth'"); qt_optionHeight = real_expression(); if (qt_optionWidth < 1 || qt_optionHeight < 1) int_error(c_token, "size is out of range"); break; case QT_PERSIST: SETCHECKDUP(set_persist); qt_optionPersist = true; break; case QT_NOPERSIST: SETCHECKDUP(set_persist); qt_optionPersist = false; break; case QT_RAISE: SETCHECKDUP(set_raise); qt_optionRaise = true; break; case QT_NORAISE: SETCHECKDUP(set_raise); qt_optionRaise = false; break; case QT_CTRL: SETCHECKDUP(set_ctrl); qt_optionCtrl = true; break; case QT_NOCTRL: SETCHECKDUP(set_ctrl); qt_optionCtrl = false; break; case QT_TITLE: SETCHECKDUP(set_title); if (!(s = try_to_get_string())) int_error(c_token, "title: expecting string"); if (*s) qt_optionTitle = qt_codec->toUnicode(s); free(s); break; case QT_CLOSE: SETCHECKDUP(set_close); break; case QT_DASH: SETCHECKDUP(set_dash); qt_optionDash = true; break; case QT_SOLID: SETCHECKDUP(set_dash); qt_optionDash = false; break; case QT_OTHER: default: qt_optionWindowId = int_expression(); qt_optionWidget = ""; if (set_number) duplication = true; set_number = true; break; } if (duplication) int_error(c_token-1, "Duplicated or contradicting arguments in qt term options."); } // Save options back into options string in normalized format QString termOptions = QString::number(qt_optionWindowId); /* Initialize user-visible font setting */ fontSettings = qt_optionFontName + "," + QString::number(qt_optionFontSize); if (set_title) { termOptions += " title \"" + qt_optionTitle + '"'; if (qt_initialized) qt_out << GETitle << qt_optionTitle; } if (set_size) { termOptions += " size " + QString::number(qt_optionWidth) + ", " + QString::number(qt_optionHeight); qt_setSize = true; qt_setWidth = qt_optionWidth; qt_setHeight = qt_optionHeight; } if (set_enhanced) termOptions += qt_optionEnhanced ? " enhanced" : " noenhanced"; termOptions += " font \"" + fontSettings + '"'; if (set_dash) termOptions += qt_optionDash ? " dashed" : " solid"; if (set_widget) termOptions += " widget \"" + qt_optionWidget + '"'; if (set_persist) termOptions += qt_optionPersist ? " persist" : " nopersist"; if (set_raise) termOptions += qt_optionRaise ? " raise" : " noraise"; if (set_ctrl) termOptions += qt_optionCtrl ? " ctrl" : " noctrl"; if (set_close && qt_initialized) qt_out << GECloseWindow << qt_optionWindowId; /// @bug change Utf8 to local encoding strncpy(term_options, termOptions.toUtf8().data(), MAX_LINE_LEN); }
/* * destination_class tells us whether we are filling in a line style ('set style line'), * a persistant linetype ('set linetype') or an ad hoc set of properties for a single * use ('plot ... lc foo lw baz'). * allow_point controls whether we accept a point attribute in this lp_style. */ int lp_parse(struct lp_style_type *lp, lp_class destination_class, TBOOLEAN allow_point) { /* keep track of which options were set during this call */ int set_lt = 0, set_pal = 0, set_lw = 0; int set_pt = 0, set_ps = 0, set_pi = 0; int set_dt = 0; int new_lt = 0; /* EAM Mar 2010 - We don't want properties from a user-defined default * linetype to override properties explicitly set here. So fill in a * local lp_style_type as we go and then copy over the specifically * requested properties on top of the default ones. */ struct lp_style_type newlp = *lp; if ((destination_class == LP_ADHOC) && (almost_equals(c_token, "lines$tyle") || equals(c_token, "ls"))) { c_token++; lp_use_properties(lp, int_expression()); } while (!END_OF_COMMAND) { /* This special case is to flag an attemp to "set object N lt <lt>", * which would otherwise be accepted but ignored, leading to confusion * FIXME: Couldn't this be handled at a higher level? */ if ((destination_class == LP_NOFILL) && (equals(c_token,"lt") || almost_equals(c_token,"linet$ype"))) { int_error(c_token, "object linecolor must be set using fillstyle border"); } if (almost_equals(c_token, "linet$ype") || equals(c_token, "lt")) { if (set_lt++) break; if (destination_class == LP_TYPE) int_error(c_token, "linetype definition cannot use linetype"); c_token++; if (almost_equals(c_token, "rgb$color")) { if (set_pal++) break; c_token--; parse_colorspec(&(newlp.pm3d_color), TC_RGB); } else /* both syntaxes allowed: 'with lt pal' as well as 'with pal' */ if (almost_equals(c_token, "pal$ette")) { if (set_pal++) break; c_token--; parse_colorspec(&(newlp.pm3d_color), TC_Z); } else if (equals(c_token,"bgnd")) { *lp = background_lp; c_token++; } else if (equals(c_token,"black")) { *lp = default_border_lp; c_token++; } else if (equals(c_token,"nodraw")) { lp->l_type = LT_NODRAW; c_token++; } else { /* These replace the base style */ new_lt = int_expression(); lp->l_type = new_lt - 1; /* user may prefer explicit line styles */ if (prefer_line_styles && (destination_class != LP_STYLE)) lp_use_properties(lp, new_lt); else load_linetype(lp, new_lt); } } /* linetype, lt */ /* both syntaxes allowed: 'with lt pal' as well as 'with pal' */ if (almost_equals(c_token, "pal$ette")) { if (set_pal++) break; c_token--; parse_colorspec(&(newlp.pm3d_color), TC_Z); continue; } /* This is so that "set obj ... lw N fc <colorspec>" doesn't eat up the * fc colorspec as a line property. We need to parse it later as a * _fill_ property. Also prevents "plot ... fc <col1> fs <foo> lw <baz>" * from generating an error claiming redundant line properties. */ if ((destination_class == LP_NOFILL || destination_class == LP_ADHOC) && (equals(c_token,"fc") || almost_equals(c_token,"fillc$olor"))) break; if (equals(c_token,"lc") || almost_equals(c_token,"linec$olor") || equals(c_token,"fc") || almost_equals(c_token,"fillc$olor") ) { if (set_pal++) break; c_token++; if (almost_equals(c_token, "rgb$color") || isstring(c_token)) { c_token--; parse_colorspec(&(newlp.pm3d_color), TC_RGB); } else if (almost_equals(c_token, "pal$ette")) { c_token--; parse_colorspec(&(newlp.pm3d_color), TC_Z); } else if (equals(c_token,"bgnd")) { newlp.pm3d_color.type = TC_LT; newlp.pm3d_color.lt = LT_BACKGROUND; c_token++; } else if (equals(c_token,"black")) { newlp.pm3d_color.type = TC_LT; newlp.pm3d_color.lt = LT_BLACK; c_token++; } else if (almost_equals(c_token, "var$iable")) { c_token++; newlp.l_type = LT_COLORFROMCOLUMN; newlp.pm3d_color.type = TC_LINESTYLE; } else { /* Pull the line colour from a default linetype, but */ /* only if we are not in the middle of defining one! */ if (destination_class != LP_STYLE) { struct lp_style_type temp; load_linetype(&temp, int_expression()); newlp.pm3d_color = temp.pm3d_color; } else { newlp.pm3d_color.type = TC_LT; newlp.pm3d_color.lt = int_expression() - 1; } } continue; } if (almost_equals(c_token, "linew$idth") || equals(c_token, "lw")) { if (set_lw++) break; c_token++; newlp.l_width = real_expression(); if (newlp.l_width < 0) newlp.l_width = 0; continue; } if (equals(c_token,"bgnd")) { if (set_lt++) break;; c_token++; *lp = background_lp; continue; } if (equals(c_token,"black")) { if (set_lt++) break;; c_token++; *lp = default_border_lp; continue; } if (almost_equals(c_token, "pointt$ype") || equals(c_token, "pt")) { if (allow_point) { char *symbol; if (set_pt++) break; c_token++; if ((symbol = try_to_get_string())) { newlp.p_type = PT_CHARACTER; /* An alternative mechanism would be to use * utf8toulong(&newlp.p_char, symbol); */ strncpy((char *)(&newlp.p_char), symbol, 3); /* Truncate ascii text to single character */ if ((((char *)&newlp.p_char)[0] & 0x80) == 0) ((char *)&newlp.p_char)[1] = '\0'; /* UTF-8 characters may use up to 3 bytes */ ((char *)&newlp.p_char)[3] = '\0'; free(symbol); } else { newlp.p_type = int_expression() - 1; } } else { int_warn(c_token, "No pointtype specifier allowed, here"); c_token += 2; } continue; } if (almost_equals(c_token, "points$ize") || equals(c_token, "ps")) { if (allow_point) { if (set_ps++) break; c_token++; if (almost_equals(c_token, "var$iable")) { newlp.p_size = PTSZ_VARIABLE; c_token++; } else if (almost_equals(c_token, "def$ault")) { newlp.p_size = PTSZ_DEFAULT; c_token++; } else { newlp.p_size = real_expression(); if (newlp.p_size < 0) newlp.p_size = 0; } } else { int_warn(c_token, "No pointsize specifier allowed, here"); c_token += 2; } continue; } if (almost_equals(c_token, "pointi$nterval") || equals(c_token, "pi")) { c_token++; if (allow_point) { newlp.p_interval = int_expression(); set_pi = 1; } else { int_warn(c_token, "No pointinterval specifier allowed, here"); int_expression(); } continue; } if (almost_equals(c_token, "dasht$ype") || equals(c_token, "dt")) { int tmp; if (set_dt++) break; c_token++; tmp = parse_dashtype(&newlp.custom_dash_pattern); /* Pull the dashtype from the list of already defined dashtypes, */ /* but only if it we didn't get an explicit one back from parse_dashtype */ if (tmp == DASHTYPE_AXIS) lp->l_type = LT_AXIS; if (tmp >= 0) tmp = load_dashtype(&newlp.custom_dash_pattern, tmp + 1); newlp.d_type = tmp; continue; } /* caught unknown option -> quit the while(1) loop */ break; } if (set_lt > 1 || set_pal > 1 || set_lw > 1 || set_pt > 1 || set_ps > 1 || set_dt > 1) int_error(c_token, "duplicated arguments in style specification"); if (set_pal) { lp->pm3d_color = newlp.pm3d_color; /* hidden3d uses this to decide that a single color surface is wanted */ lp->flags |= LP_EXPLICIT_COLOR; } else { lp->flags &= ~LP_EXPLICIT_COLOR; } if (set_lw) lp->l_width = newlp.l_width; if (set_pt) { lp->p_type = newlp.p_type; lp->p_char = newlp.p_char; } if (set_ps) lp->p_size = newlp.p_size; if (set_pi) lp->p_interval = newlp.p_interval; if (newlp.l_type == LT_COLORFROMCOLUMN) lp->l_type = LT_COLORFROMCOLUMN; if (set_dt) { lp->d_type = newlp.d_type; lp->custom_dash_pattern = newlp.custom_dash_pattern; } return new_lt; }
int parse_dashtype(struct t_dashtype *dt) { int res = DASHTYPE_SOLID; int j = 0; int k = 0; char *dash_str = NULL; /* Erase any previous contents */ memset(dt, 0, sizeof(struct t_dashtype)); /* Fill in structure based on keyword ... */ if (equals(c_token, "solid")) { res = DASHTYPE_SOLID; c_token++; /* Or numerical pattern consisting of pairs solid,empty,solid,empty... */ } else if (equals(c_token, "(")) { c_token++; while (!END_OF_COMMAND) { if (j >= DASHPATTERN_LENGTH) { int_error(c_token, "too many pattern elements"); } dt->pattern[j++] = real_expression(); /* The solid portion */ if (!equals(c_token++, ",")) int_error(c_token, "expecting comma"); dt->pattern[j++] = real_expression(); /* The empty portion */ if (equals(c_token, ")")) break; if (!equals(c_token++, ",")) int_error(c_token, "expecting comma"); } if (!equals(c_token, ")")) int_error(c_token, "expecting , or )"); c_token++; res = DASHTYPE_CUSTOM; /* Or string representing pattern elements ... */ } else if ((dash_str = try_to_get_string())) { #define DSCALE 10. while (dash_str[j] && (k < DASHPATTERN_LENGTH || dash_str[j] == ' ')) { /* . Dot with short space * - Dash with regular space * _ Long dash with regular space * space Don't add new dash, just increase last space */ switch (dash_str[j]) { case '.': dt->pattern[k++] = 0.2 * DSCALE; dt->pattern[k++] = 0.5 * DSCALE; break; case '-': dt->pattern[k++] = 1.0 * DSCALE; dt->pattern[k++] = 1.0 * DSCALE; break; case '_': dt->pattern[k++] = 2.0 * DSCALE; dt->pattern[k++] = 1.0 * DSCALE; break; case ' ': if (k > 0) dt->pattern[k-1] += 1.0 * DSCALE; break; default: int_error(c_token - 1, "expecting one of . - _ or space"); } j++; #undef DSCALE } /* truncate dash_str if we ran out of space in the array representation */ dash_str[j] = '\0'; strncpy(dt->dstring, dash_str, sizeof(dt->dstring)-1); free(dash_str); res = DASHTYPE_CUSTOM; /* Or index of previously defined dashtype */ /* FIXME: Is the index enough or should we copy its contents into this one? */ /* FIXME: What happens if there is a recursive definition? */ } else { res = int_expression(); if (res < 0) int_error(c_token - 1, "dashtype must be non-negative"); if (res == 0) res = DASHTYPE_AXIS; else res = res - 1; } return res; }
static void prepare_call(int calltype) { struct udvt_entry *udv; int argindex; if (calltype == 2) { call_argc = 0; while (!END_OF_COMMAND && call_argc <= 9) { call_args[call_argc] = try_to_get_string(); if (!call_args[call_argc]) { int save_token = c_token; /* This catches call "file" STRINGVAR (expression) */ if (type_udv(c_token) == STRING) { call_args[call_argc] = gp_strdup(add_udv(c_token)->udv_value.v.string_val); c_token++; /* Evaluates a parenthesized expression and store the result in a string */ } else if (equals(c_token, "(")) { char val_as_string[32]; struct value a; const_express(&a); switch(a.type) { case CMPLX: /* FIXME: More precision? Some way to provide a format? */ sprintf(val_as_string, "%g", a.v.cmplx_val.real); call_args[call_argc] = gp_strdup(val_as_string); break; default: int_error(save_token, "Unrecognized argument type"); break; case INTGR: sprintf(val_as_string, "%d", a.v.int_val); call_args[call_argc] = gp_strdup(val_as_string); break; } /* old (pre version 5) style wrapping of bare tokens as strings */ /* is still useful for passing unquoted numbers */ } else { m_capture(&call_args[call_argc], c_token, c_token); c_token++; } } call_argc++; } lf_head->c_token = c_token; if (!END_OF_COMMAND) int_error(++c_token, "too many arguments for 'call <file>'"); } else if (calltype == 5) { /* lf_push() moved our call arguments from call_args[] to lf->call_args[] */ /* call_argc was determined at program entry */ for (argindex = 0; argindex < 10; argindex++) { call_args[argindex] = lf_head->call_args[argindex]; lf_head->call_args[argindex] = NULL; /* just to be safe */ } } else { /* "load" command has no arguments */ call_argc = 0; } /* Old-style "call" arguments were referenced as $0 ... $9 and $# */ /* New-style has ARG0 = script-name, ARG1 ... ARG9 and ARGC */ /* FIXME: If we defined these on entry, we could use get_udv* here */ udv = add_udv_by_name("ARGC"); Ginteger(&(udv->udv_value), call_argc); udv->udv_undef = FALSE; udv = add_udv_by_name("ARG0"); gpfree_string(&(udv->udv_value)); Gstring(&(udv->udv_value), gp_strdup(lf_head->name)); udv->udv_undef = FALSE; for (argindex = 1; argindex <= 9; argindex++) { char *arg = gp_strdup(call_args[argindex-1]); udv = add_udv_by_name(argname[argindex]); gpfree_string(&(udv->udv_value)); Gstring(&(udv->udv_value), arg ? arg : gp_strdup("")); udv->udv_undef = FALSE; } }
void statsrequest(void) { int i; int columns; int columnsread; double v[2]; static char *file_name = NULL; /* Vars to hold data and results */ long n; /* number of records retained */ long max_n; static double *data_x = NULL; static double *data_y = NULL; /* values read from file */ long invalid; /* number of missing/invalid records */ long blanks; /* number of blank lines */ long doubleblanks; /* number of repeated blank lines */ long out_of_range; /* number pts rejected, because out of range */ struct file_stats res_file; struct sgl_column_stats res_x, res_y; struct two_column_stats res_xy; float *matrix; /* matrix data. This must be float. */ int nc, nr; /* matrix dimensions. */ int index; /* Vars for variable handling */ static char *prefix = NULL; /* prefix for user-defined vars names */ /* Vars that control output */ TBOOLEAN do_output = TRUE; /* Generate formatted output */ c_token++; /* Parse ranges */ AXIS_INIT2D(FIRST_X_AXIS, 0); AXIS_INIT2D(FIRST_Y_AXIS, 0); parse_range(FIRST_X_AXIS); parse_range(FIRST_Y_AXIS); /* Initialize */ columnsread = 2; invalid = 0; /* number of missing/invalid records */ blanks = 0; /* number of blank lines */ doubleblanks = 0; /* number of repeated blank lines */ out_of_range = 0; /* number pts rejected, because out of range */ n = 0; /* number of records retained */ nr = 0; /* Matrix dimensions */ nc = 0; max_n = INITIAL_DATA_SIZE; free(data_x); free(data_y); data_x = vec(max_n); /* start with max. value */ data_y = vec(max_n); if ( !data_x || !data_y ) int_error( NO_CARET, "Internal error: out of memory in stats" ); n = invalid = blanks = doubleblanks = out_of_range = nr = 0; /* Get filename */ free ( file_name ); file_name = try_to_get_string(); if ( !file_name ) int_error(c_token, "missing filename"); /* =========================================================== v923z: insertion for treating matrices EAM: only handles ascii matrix with uniform grid, and fails to apply any input data transforms =========================================================== */ if ( almost_equals(c_token, "mat$rix") ) { df_open(file_name, 3, NULL); index = df_num_bin_records - 1; /* We take these values as set by df_determine_matrix_info See line 1996 in datafile.c */ nc = df_bin_record[index].scan_dim[0]; nr = df_bin_record[index].scan_dim[1]; n = nc * nr; matrix = (float *)df_bin_record[index].memory_data; /* Fill up a vector, so that we can use the existing code. */ if ( !redim_vec(&data_x, n ) ) { int_error( NO_CARET, "Out of memory in stats: too many datapoints (%d)?", n ); } for( i=0; i < n; i++ ) { data_y[i] = (double)matrix[i]; } /* We can close the file here, there is nothing else to do */ df_close(); /* We will invoke single column statistics for the matrix */ columns = 1; } else { /* Not a matrix */ columns = df_open(file_name, 2, NULL); /* up to 2 using specs allowed */ if (columns < 0) int_error(NO_CARET, "Can't read data file"); if (columns > 2 ) int_error(c_token, "Need 0 to 2 using specs for stats command"); /* If the user has set an explicit locale for numeric input, apply it here so that it affects data fields read from the input file. */ /* v923z: where exactly should this be? here or before the matrix case? * I think, we should move everything here to before trying to open the file. * There is no point in trying to read anything, if the axis is logarithmic, e.g. */ set_numeric_locale(); /* For all these below: we could save the state, switch off, then restore */ if ( axis_array[FIRST_X_AXIS].log || axis_array[FIRST_Y_AXIS].log ) int_error( NO_CARET, "Stats command not available with logscale active"); if ( axis_array[FIRST_X_AXIS].datatype == DT_TIMEDATE || axis_array[FIRST_Y_AXIS].datatype == DT_TIMEDATE ) int_error( NO_CARET, "Stats command not available in timedata mode"); if ( polar ) int_error( NO_CARET, "Stats command not available in polar mode" ); if ( parametric ) int_error( NO_CARET, "Stats command not available in parametric mode" ); /* The way readline and friends work is as follows: - df_open will return the number of columns requested in the using spec so that "columns" will be 0, 1, or 2 (no using, using 1, using 1:2) - readline always returns the same number of columns (for us: 1 or 2) - using 1:2 = return two columns, skipping lines w/ bad data - using 1 = return sgl column (supply zeros (0) for the second col) - no using = return two columns (first two), fail on bad data We need to know how many columns to process. If columns==1 or ==2 (that is, if there was a using spec), all is clear and we use the value of columns. But: if columns is 0, then we need to figure out the number of cols read from the return value of readline. If readline ever returns 1, we take that; only if it always returns 2 do we assume two cols. */ while( (i = df_readline(v, 2)) != DF_EOF ) { columnsread = ( i > columnsread ? i : columnsread ); if ( n >= max_n ) { max_n = (max_n * 3) / 2; /* increase max_n by factor of 1.5 */ /* Some of the reallocations went bad: */ if ( 0 || !redim_vec(&data_x, max_n) || !redim_vec(&data_y, max_n) ) { df_close(); int_error( NO_CARET, "Out of memory in stats: too many datapoints (%d)?", max_n ); } } /* if (need to extend storage space) */ switch (i) { case DF_MISSING: case DF_UNDEFINED: /* Invalids are only recognized if the syntax is like this: stats "file" using ($1):($2) If the syntax is simply: stats "file" using 1:2 then df_readline simply skips invalid records (does not return anything!) Status: 2009-11-02 */ invalid += 1; continue; case DF_FIRST_BLANK: blanks += 1; continue; case DF_SECOND_BLANK: blanks += 1; doubleblanks += 1; continue; case 0: int_error( NO_CARET, "bad data on line %d of file %s", df_line_number, df_filename ? df_filename : "" ); break; case 1: /* Read single column successfully */ if ( validate_data(v[0], FIRST_Y_AXIS) ) { data_y[n] = v[0]; n++; } else { out_of_range++; } break; case 2: /* Read two columns successfully */ if ( validate_data(v[0], FIRST_X_AXIS) && validate_data(v[1], FIRST_Y_AXIS) ) { data_x[n] = v[0]; data_y[n] = v[1]; n++; } else { out_of_range++; } break; } } /* end-while : done reading file */ df_close(); /* now resize fields to actual length: */ redim_vec(&data_x, n); redim_vec(&data_y, n); /* figure out how many columns where really read... */ if ( columns == 0 ) columns = columnsread; } /* end of case when the data file is not a matrix */ /* Now finished reading user input; return to C locale for internal use*/ reset_numeric_locale(); /* PKJ - TODO: similar for logscale, polar/parametric, timedata */ /* No data! Try to explain why. */ if ( n == 0 ) { if ( out_of_range > 0 ) int_error( NO_CARET, "All points out of range" ); else int_error( NO_CARET, "No valid data points found in file" ); } /* Parse the remainder of the command line: 0 to 2 tokens possible */ while( !(END_OF_COMMAND) ) { if ( almost_equals( c_token, "out$put" ) ) { do_output = TRUE; c_token++; } else if ( almost_equals( c_token, "noout$put" ) ) { do_output = FALSE; c_token++; } else if ( almost_equals(c_token, "pre$fix") || equals(c_token, "name")) { c_token++; free ( prefix ); prefix = try_to_get_string(); if (!legal_identifier(prefix) || !strcmp ("GPVAL_", prefix)) int_error( --c_token, "illegal prefix" ); } else { int_error( c_token, "Expecting [no]output or prefix"); } } /* Set defaults if not explicitly set by user */ if (!prefix) prefix = gp_strdup("STATS_"); i = strlen(prefix); if (prefix[i-1] != '_') { prefix = gp_realloc(prefix, i+2, "prefix"); strcat(prefix,"_"); } /* Do the actual analysis */ res_file = analyze_file( n, out_of_range, invalid, blanks, doubleblanks ); if ( columns == 1 ) { res_y = analyze_sgl_column( data_y, n, nr ); } if ( columns == 2 ) { /* If there are two columns, then the data file is not a matrix */ res_x = analyze_sgl_column( data_x, n, 0 ); res_y = analyze_sgl_column( data_y, n, 0 ); res_xy = analyze_two_columns( data_x, data_y, res_x, res_y, n ); } /* Store results in user-accessible variables */ /* Clear out any previous use of these variables */ del_udv_by_name( prefix, TRUE ); file_variables( res_file, prefix ); if ( columns == 1 ) { sgl_column_variables( res_y, prefix, "" ); } if ( columns == 2 ) { sgl_column_variables( res_x, prefix, "_x" ); sgl_column_variables( res_y, prefix, "_y" ); two_column_variables( res_xy, prefix ); } /* Output */ if ( do_output ) { file_output( res_file ); if ( columns == 1 ) sgl_column_output( res_y, res_file.records ); else two_column_output( res_x, res_y, res_xy, res_file.records ); } /* Cleanup */ free(data_x); free(data_y); data_x = NULL; data_y = NULL; free( file_name ); file_name = NULL; free( prefix ); prefix = NULL; }
/* * Parse the sub-options of text color specification * { def$ault | lt <linetype> | pal$ette { cb <val> | frac$tion <val> | z } * The ordering of alternatives shown in the line above is kept in the symbol definitions * TC_DEFAULT TC_LT TC_RGB TC_CB TC_FRAC TC_Z (0 1 2 3 4 5) * and the "options" parameter to parse_colorspec limits legal input to the * corresponding point in the series. So TC_LT allows only default or linetype * coloring, while TC_Z allows all coloring options up to and including pal z */ void parse_colorspec(struct t_colorspec *tc, int options) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expected colorspec"); if (almost_equals(c_token,"def$ault")) { c_token++; tc->type = TC_DEFAULT; #ifdef KEYWORD_BGND } else if (equals(c_token,"bgnd")) { c_token++; tc->type = TC_LT; tc->lt = LT_BACKGROUND; #endif } else if (equals(c_token,"lt")) { c_token++; if (END_OF_COMMAND) int_error(c_token, "expected linetype"); tc->type = TC_LT; tc->lt = int_expression()-1; if (tc->lt < LT_BACKGROUND) { tc->type = TC_DEFAULT; int_warn(c_token,"illegal linetype"); } } else if (options <= TC_LT) { tc->type = TC_DEFAULT; int_error(c_token, "only tc lt <n> possible here"); } else if (equals(c_token,"ls") || almost_equals(c_token,"lines$tyle")) { c_token++; tc->type = TC_LINESTYLE; tc->lt = real_expression(); } else if (almost_equals(c_token,"rgb$color")) { char *color; int rgbtriple; c_token++; tc->type = TC_RGB; if (almost_equals(c_token, "var$iable")) { tc->value = -1.0; c_token++; return; } else tc->value = 0.0; if (!(color = try_to_get_string())) int_error(c_token, "expected a color name or a string of form \"#RRGGBB\""); if ((rgbtriple = lookup_table_nth(pm3d_color_names_tbl, color)) >= 0) rgbtriple = pm3d_color_names_tbl[rgbtriple].value; else sscanf(color,"#%x",&rgbtriple); free(color); if (rgbtriple < 0) int_error(c_token, "expected a known color name or a string of form \"#RRGGBB\""); tc->type = TC_RGB; tc->lt = rgbtriple; } else if (almost_equals(c_token,"pal$ette")) { c_token++; if (equals(c_token,"z")) { /* The actual z value is not yet known, fill it in later */ if (options >= TC_Z) { tc->type = TC_Z; } else { tc->type = TC_DEFAULT; int_error(c_token, "palette z not possible here"); } c_token++; } else if (equals(c_token,"cb")) { tc->type = TC_CB; c_token++; if (END_OF_COMMAND) int_error(c_token, "expected cb value"); tc->value = real_expression(); } else if (almost_equals(c_token,"frac$tion")) { tc->type = TC_FRAC; c_token++; if (END_OF_COMMAND) int_error(c_token, "expected palette fraction"); tc->value = real_expression(); if (tc->value < 0. || tc->value > 1.0) int_error(c_token, "palette fraction out of range"); } else { /* END_OF_COMMAND or palette <blank> */ if (options >= TC_Z) tc->type = TC_Z; } } else { int_error(c_token, "colorspec option not recognized"); } }