/* * In-line data blocks are implemented as a here-document: * $FOO << EOD * data line 1 * data line 2 * ... * EOD * * The data block name must begin with $ followed by a letter. * The string EOD is arbitrary; lines of data will be read from the input stream * until the leading characters on the line match the given character string. * No attempt is made to parse the data at the time it is read in. */ void datablock_command() { FILE *fin; char *name, *eod; int nlines; int nsize = 4; struct udvt_entry *datablock; char dataline[MAX_LINE_LEN+1]; if (!isletter(c_token+1)) int_error(c_token, "illegal datablock name"); /* Create or recycle a datablock with the requested name */ name = parse_datablock_name(); datablock = add_udv_by_name(name); if (!datablock->udv_undef) gpfree_datablock(&datablock->udv_value); datablock->udv_undef = FALSE; datablock->udv_value.type = DATABLOCK; datablock->udv_value.v.data_array = NULL; if (!equals(c_token, "<<") || !isletter(c_token+1)) int_error(c_token, "data block name must be followed by << EODmarker"); c_token++; eod = gp_alloc(token[c_token].length +2, "datablock"); copy_str(&eod[0], c_token, token[c_token].length + 2); c_token++; /* Read in and store data lines until EOD */ fin = (lf_head == NULL) ? stdin : lf_head->fp; if (!fin) int_error(NO_CARET,"attempt to define data block from invalid context"); for (nlines = 0; fgets(dataline, MAX_LINE_LEN, fin); nlines++) { int n; if (!strncmp(eod, dataline, strlen(eod))) break; /* Allocate space for data lines plus at least 2 empty lines at the end. */ if (nlines >= nsize-4) { nsize *= 2; datablock->udv_value.v.data_array = gp_realloc( datablock->udv_value.v.data_array, nsize * sizeof(char *), "datablock"); memset(&datablock->udv_value.v.data_array[nlines], 0, (nsize - nlines) * sizeof(char *)); } /* Strip trailing newline character */ n = strlen(dataline); if (n > 0 && dataline[n - 1] == '\n') dataline[n - 1] = NUL; datablock->udv_value.v.data_array[nlines] = gp_strdup(dataline); } inline_num += nlines + 1; /* Update position in input file */ free(eod); return; }
/* 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; }