2000-06-27 18:15:43 +02:00
|
|
|
/**********
|
|
|
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
|
|
|
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|
|
|
|
**********/
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
|
#include "ngspice/bool.h"
|
|
|
|
|
#include "ngspice/wordlist.h"
|
|
|
|
|
#include "ngspice/defines.h"
|
|
|
|
|
#include "ngspice/macros.h"
|
|
|
|
|
#include "ngspice/cpdefs.h"
|
|
|
|
|
#include "ngspice/memory.h"
|
|
|
|
|
#include "ngspice/inpdefs.h"
|
|
|
|
|
#include "ngspice/fteext.h"
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
#include "circuits.h"
|
|
|
|
|
#include "com_history.h"
|
* frontend/Makefile.am: Updates for new files.
* frontend/breakp2.c, frontend/newcoms.c, frontend/postcoms.c,
frontend/resource.c, frontend/terminal.h, frontend/variable.c,
frontend/variable.h, frontend/com_compose.c,
frontend/com_display.c, frontend/com_setscale.c,
frontend/com_strcmp.c: Include files update.
* parser/var2.c, parser/var2.h: Empty files, removed.
* parser/Makefile.am: Updates for removed files.
* parser/lexical.c: Small adjustments
* parser/input.c, parser/input.h: Input, output and error streams
handled in the frontend. Moved to the frontend directory.
* frontend/streams.c: Its new home.
2000-07-07 16:09:06 +02:00
|
|
|
#include "quote.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/cpextern.h"
|
* frontend/Makefile.am: Updates for new files.
* frontend/breakp2.c, frontend/newcoms.c, frontend/postcoms.c,
frontend/resource.c, frontend/terminal.h, frontend/variable.c,
frontend/variable.h, frontend/com_compose.c,
frontend/com_display.c, frontend/com_setscale.c,
frontend/com_strcmp.c: Include files update.
* parser/var2.c, parser/var2.h: Empty files, removed.
* parser/Makefile.am: Updates for removed files.
* parser/lexical.c: Small adjustments
* parser/input.c, parser/input.h: Input, output and error streams
handled in the frontend. Moved to the frontend directory.
* frontend/streams.c: Its new home.
2000-07-07 16:09:06 +02:00
|
|
|
#include "variable.h"
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cp_noglob = TRUE;
|
|
|
|
|
bool cp_nonomatch = FALSE;
|
|
|
|
|
bool cp_noclobber = FALSE;
|
|
|
|
|
bool cp_ignoreeof = FALSE;
|
2001-12-14 19:29:08 +01:00
|
|
|
bool cp_echo = FALSE; /* CDHW */
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
struct variable *variables = NULL;
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
wordlist *
|
|
|
|
|
cp_varwl(struct variable *var)
|
|
|
|
|
{
|
|
|
|
|
wordlist *wl = NULL, *w, *wx = NULL;
|
2015-03-28 20:10:29 +01:00
|
|
|
char *buf;
|
2000-06-27 18:15:43 +02:00
|
|
|
struct variable *vt;
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
switch (var->va_type) {
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_BOOL:
|
2012-08-05 12:04:06 +02:00
|
|
|
/* Can't ever be FALSE. */
|
2015-03-28 20:10:29 +01:00
|
|
|
buf = copy(var->va_bool ? "TRUE" : "FALSE");
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_NUM:
|
2015-03-28 20:10:29 +01:00
|
|
|
buf = tprintf("%d", var->va_num);
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_REAL:
|
2012-08-05 12:04:06 +02:00
|
|
|
/* This is a case where printnum isn't too good... */
|
2015-03-28 20:10:29 +01:00
|
|
|
buf = tprintf("%G", var->va_real);
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_STRING:
|
2015-03-28 20:10:29 +01:00
|
|
|
buf = cp_unquote(var->va_string);
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_LIST: /* The tricky case. */
|
2012-08-05 12:04:06 +02:00
|
|
|
for (vt = var->va_vlist; vt; vt = vt->va_next) {
|
|
|
|
|
w = cp_varwl(vt);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (wl == NULL) {
|
2012-08-05 12:04:06 +02:00
|
|
|
wl = wx = w;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2012-08-05 12:04:06 +02:00
|
|
|
wx->wl_next = w;
|
|
|
|
|
w->wl_prev = wx;
|
|
|
|
|
wx = w;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (wl);
|
2000-06-27 18:15:43 +02:00
|
|
|
default:
|
2012-08-05 12:04:06 +02:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"cp_varwl: Internal Error: bad variable type %d\n",
|
|
|
|
|
var->va_type);
|
|
|
|
|
return (NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2015-03-28 20:10:29 +01:00
|
|
|
return wl_cons(buf, NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set a variable. */
|
|
|
|
|
void
|
2010-07-20 21:19:51 +02:00
|
|
|
cp_vset(char *varname, enum cp_types type, void *value)
|
2000-06-27 18:15:43 +02:00
|
|
|
{
|
|
|
|
|
struct variable *v, *u, *w;
|
|
|
|
|
int i;
|
2009-03-29 18:58:44 +02:00
|
|
|
bool alreadythere = FALSE, v_free = FALSE;
|
2012-08-05 12:04:06 +02:00
|
|
|
char *copyvarname;
|
|
|
|
|
|
2000-11-01 22:21:21 +01:00
|
|
|
/* varname = cp_unquote(varname); DG: Memory leak old varname is lost*/
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-11-01 22:21:21 +01:00
|
|
|
copyvarname = cp_unquote(varname);
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
w = NULL;
|
|
|
|
|
for (v = variables; v; v = v->va_next) {
|
2000-11-01 22:21:21 +01:00
|
|
|
if (eq(copyvarname, v->va_name)) {
|
2000-06-27 18:15:43 +02:00
|
|
|
alreadythere = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
w = v;
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-14 20:22:13 +02:00
|
|
|
|
|
|
|
|
if (alreadythere) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (v->va_type == CP_LIST)
|
2012-08-14 20:22:13 +02:00
|
|
|
free_struct_variable(v->va_vlist);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (v->va_type == CP_STRING)
|
2012-08-14 20:22:13 +02:00
|
|
|
tfree(v->va_string);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
if (!v) {
|
2016-03-25 15:39:27 +01:00
|
|
|
v = var_alloc(copy(copyvarname), NULL);
|
2009-03-29 18:58:44 +02:00
|
|
|
v_free = TRUE;
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
switch (type) {
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_BOOL:
|
2000-06-27 18:15:43 +02:00
|
|
|
if (* ((bool *) value) == FALSE) {
|
2000-11-01 22:21:21 +01:00
|
|
|
cp_remvar(copyvarname);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (v_free) {
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(v->va_name);
|
|
|
|
|
tfree(v);
|
2009-03-29 18:58:44 +02:00
|
|
|
}
|
2012-04-05 21:25:04 +02:00
|
|
|
tfree(copyvarname);
|
2000-06-27 18:15:43 +02:00
|
|
|
return;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2016-03-25 15:42:24 +01:00
|
|
|
var_set_bool(v, TRUE);
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_NUM:
|
2016-03-25 15:42:24 +01:00
|
|
|
var_set_num(v, * (int *) value);
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_REAL:
|
2016-03-25 15:42:24 +01:00
|
|
|
var_set_real(v, * (double *) value);
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_STRING:
|
2016-03-25 15:42:24 +01:00
|
|
|
var_set_string(v, copy((char*) value));
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
2010-07-17 22:48:20 +02:00
|
|
|
case CP_LIST:
|
2016-03-25 15:42:24 +01:00
|
|
|
var_set_vlist(v, (struct variable *) value);
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2012-08-05 12:04:06 +02:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"cp_vset: Internal Error: bad variable type %d.\n",
|
2000-06-27 18:15:43 +02:00
|
|
|
type);
|
2012-04-05 21:25:04 +02:00
|
|
|
tfree(copyvarname);
|
2000-06-27 18:15:43 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
/* Now, see if there is anything interesting going on. We
|
|
|
|
|
* recognise these special variables: noglob, nonomatch, history,
|
|
|
|
|
* echo, noclobber, prompt, and verbose. cp_remvar looks for these
|
|
|
|
|
* variables too. The host program will get any others. */
|
2000-11-01 22:21:21 +01:00
|
|
|
if (eq(copyvarname, "noglob"))
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_noglob = TRUE;
|
2000-11-01 22:21:21 +01:00
|
|
|
else if (eq(copyvarname, "nonomatch"))
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_nonomatch = TRUE;
|
2010-07-17 22:48:20 +02:00
|
|
|
else if (eq(copyvarname, "history") && (type == CP_NUM))
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_maxhistlength = v->va_num;
|
2010-07-17 22:48:20 +02:00
|
|
|
else if (eq(copyvarname, "history") && (type == CP_REAL))
|
2011-06-23 20:01:40 +02:00
|
|
|
cp_maxhistlength = (int)floor(v->va_real + 0.5);
|
2000-11-01 22:21:21 +01:00
|
|
|
else if (eq(copyvarname, "noclobber"))
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_noclobber = TRUE;
|
2004-01-10 22:39:36 +01:00
|
|
|
else if (eq(varname, "echo")) /*CDHW*/
|
2012-08-05 12:04:06 +02:00
|
|
|
cp_echo = TRUE; /*CDHW*/
|
2019-11-30 05:32:13 +01:00
|
|
|
else if (eq(copyvarname, "prompt")) {
|
|
|
|
|
if (type == CP_STRING) {
|
|
|
|
|
cp_promptstring = v->va_string;
|
|
|
|
|
}
|
|
|
|
|
else { /* use a default string since prompt is not a string */
|
|
|
|
|
cp_promptstring = "-> ";
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-11-01 22:21:21 +01:00
|
|
|
else if (eq(copyvarname, "ignoreeof"))
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_ignoreeof = TRUE;
|
2000-11-01 22:21:21 +01:00
|
|
|
else if (eq(copyvarname, "cpdebug")) {
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_debug = TRUE;
|
|
|
|
|
#ifndef CPDEBUG
|
2012-08-05 12:04:06 +02:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: program not compiled with cshpar debug messages\n");
|
2000-06-27 18:15:43 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (i = cp_usrset(v, TRUE)) {
|
|
|
|
|
|
|
|
|
|
case US_OK:
|
|
|
|
|
/* Normal case. */
|
|
|
|
|
if (!alreadythere) {
|
|
|
|
|
v->va_next = variables;
|
|
|
|
|
variables = v;
|
|
|
|
|
}
|
2016-07-24 18:05:48 +02:00
|
|
|
else if (v_free)
|
|
|
|
|
free_struct_variable(v);
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case US_DONTRECORD:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* 'curplot' 'curplotname' 'curplottitle' 'curplotdate' */
|
2000-06-27 18:15:43 +02:00
|
|
|
/* Do nothing... */
|
|
|
|
|
if (alreadythere) {
|
2012-09-20 20:30:53 +02:00
|
|
|
fprintf(cp_err, "cp_vset: Internal Error: "
|
2012-08-05 12:04:06 +02:00
|
|
|
"%s already there, but 'dont record'\n", v->va_name);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2016-07-24 18:05:48 +02:00
|
|
|
if (v_free)
|
|
|
|
|
free_struct_variable(v);
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
case US_READONLY:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* 'plots' and any var in plot_cur->pl_env */
|
2000-06-27 18:15:43 +02:00
|
|
|
fprintf(cp_err, "Error: %s is a read-only variable.\n", v->va_name);
|
|
|
|
|
if (alreadythere)
|
2012-09-20 20:30:53 +02:00
|
|
|
fprintf(cp_err, "cp_vset: Internal Error: "
|
2012-08-05 12:04:06 +02:00
|
|
|
"it was already there too!!\n");
|
2000-06-27 18:15:43 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case US_SIMVAR:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* variables processed by if_option(ft_curckt->ci_ckt, ...) */
|
2012-08-05 12:04:06 +02:00
|
|
|
if (alreadythere) {
|
|
|
|
|
/* somehow it got into the front-end list of variables */
|
|
|
|
|
if (w) {
|
|
|
|
|
w->va_next = v->va_next;
|
|
|
|
|
} else {
|
|
|
|
|
variables = v->va_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
alreadythere = FALSE;
|
|
|
|
|
if (ft_curckt) {
|
|
|
|
|
for (u = ft_curckt->ci_vars; u; u = u->va_next)
|
|
|
|
|
if (eq(copyvarname, u->va_name)) {
|
|
|
|
|
alreadythere = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!alreadythere) {
|
|
|
|
|
v->va_next = ft_curckt->ci_vars;
|
|
|
|
|
ft_curckt->ci_vars = v;
|
|
|
|
|
} else {
|
|
|
|
|
if (u->va_type == CP_STRING)
|
|
|
|
|
tfree(u->va_string);
|
|
|
|
|
else if (u->va_type == CP_LIST)
|
|
|
|
|
tfree(u->va_vlist);
|
2003-07-23 21:36:39 +02:00
|
|
|
u->va_V = v->va_V;
|
|
|
|
|
u->va_type = v->va_type;
|
2016-07-24 18:05:48 +02:00
|
|
|
/* va_name is the same string */
|
|
|
|
|
tfree(u->va_name);
|
|
|
|
|
u->va_name = v->va_name;
|
2003-07-23 21:36:39 +02:00
|
|
|
/* va_next left unchanged */
|
|
|
|
|
tfree(v);
|
2012-08-05 12:04:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
case US_NOSIMVAR:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* variables processed by if_option(NULL, ...) */
|
2012-08-05 12:04:06 +02:00
|
|
|
/* What do you do? */
|
2016-07-24 18:05:48 +02:00
|
|
|
free_struct_variable(v);
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-11-01 22:21:21 +01:00
|
|
|
tfree(copyvarname);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2019-03-31 14:41:14 +02:00
|
|
|
/* Read a wordlist, e.g. from the options or set commands
|
|
|
|
|
e.g. set myvar=myval or set myvar="myval" or myvar=( "myval1" myval2 ) or
|
|
|
|
|
set myvar1=myval1 myvar2=myval2 myvar3="myval3"
|
|
|
|
|
Separate into name and value(s)
|
|
|
|
|
Generate variables (real, string or list)
|
|
|
|
|
Value in double quotes will always become string variable.
|
|
|
|
|
Without quotes tokens like 2N5401_C will be evaluated as real number 2n, i.e. 2e-9 */
|
2000-06-27 18:15:43 +02:00
|
|
|
struct variable *
|
|
|
|
|
cp_setparse(wordlist *wl)
|
|
|
|
|
{
|
2012-08-05 12:04:06 +02:00
|
|
|
char *name = NULL, *val, *copyval, *s, *ss;
|
2000-06-27 18:15:43 +02:00
|
|
|
double *td;
|
|
|
|
|
struct variable *listv = NULL, *vv, *lv = NULL;
|
|
|
|
|
struct variable *vars = NULL;
|
|
|
|
|
int balance;
|
2019-11-30 05:32:13 +01:00
|
|
|
/* Step through the list of words. Words may be various combinations of
|
|
|
|
|
* the information needed to set a variable. For example, to set x to
|
|
|
|
|
* the value 3, the data could be supplied as one word x=3, two words
|
|
|
|
|
* x= 3 or x =3 or three words x = 3. Additionally words may be quoted
|
|
|
|
|
* or unquoted. Each iteration through the loop handles one variable */
|
2000-06-27 18:15:43 +02:00
|
|
|
while (wl) {
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2019-05-29 22:57:40 +02:00
|
|
|
if (name) {
|
|
|
|
|
txfree(name);
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
name = cp_unquote(wl->wl_word);
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
wl = wl->wl_next;
|
2012-08-05 12:04:06 +02:00
|
|
|
if ((!wl || (*wl->wl_word != '=')) && !strchr(name, '=')) {
|
2019-11-30 05:32:13 +01:00
|
|
|
vars = var_alloc_bool(name, TRUE, vars);
|
|
|
|
|
name = (char *) NULL; /* Given to variable vars */
|
2000-06-27 18:15:43 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
if (wl && eq(wl->wl_word, "=")) {
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
if (wl == NULL) {
|
|
|
|
|
fprintf(cp_err, "Error: bad set form.\n");
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(name); /*DG: cp_unquote Memory leak*/
|
2012-11-04 14:16:27 +01:00
|
|
|
if (ft_stricterror)
|
|
|
|
|
controlled_exit(EXIT_BAD);
|
2012-11-07 19:38:28 +01:00
|
|
|
return (NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
val = wl->wl_word;
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
} else if (wl && (*wl->wl_word == '=')) {
|
|
|
|
|
val = wl->wl_word + 1;
|
|
|
|
|
wl = wl->wl_next;
|
2012-08-05 12:04:06 +02:00
|
|
|
} else if ((s = strchr(name, '=')) != NULL) {
|
2000-06-27 18:15:43 +02:00
|
|
|
val = s + 1;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
if (*val == '\0') {
|
|
|
|
|
if (!wl) {
|
2004-01-10 22:39:36 +01:00
|
|
|
fprintf(cp_err, "Error: %s equals what?.\n", name);
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(name); /*DG: cp_unquote Memory leak: free name before exiting*/
|
2012-11-04 14:16:27 +01:00
|
|
|
if (ft_stricterror)
|
|
|
|
|
controlled_exit(EXIT_BAD);
|
2012-11-07 19:38:28 +01:00
|
|
|
return (NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
} else {
|
|
|
|
|
val = wl->wl_word;
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(cp_err, "Error: bad set form.\n");
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(name); /*DG: cp_unquote Memory leak: free name befor exiting */
|
2012-11-04 14:16:27 +01:00
|
|
|
if (ft_stricterror)
|
|
|
|
|
controlled_exit(EXIT_BAD);
|
2012-11-07 19:38:28 +01:00
|
|
|
return (NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2019-03-31 14:41:14 +02:00
|
|
|
/* if val is in double quotes, treat as string */
|
|
|
|
|
copyval = cp_unquote(val);
|
|
|
|
|
if (!eq(val, copyval)) {
|
|
|
|
|
vars = var_alloc_string(copy(name), copy(copyval), vars);
|
|
|
|
|
tfree(name);
|
|
|
|
|
tfree(copyval);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
strcpy(val, copyval);
|
|
|
|
|
tfree(copyval);
|
|
|
|
|
|
2015-09-22 21:12:31 +02:00
|
|
|
if (eq(val, "(")) {
|
2000-06-27 18:15:43 +02:00
|
|
|
/* The beginning of a list... We have to walk down the
|
|
|
|
|
* list until we find a close paren... If there are nested
|
|
|
|
|
* ()'s, treat them as tokens... */
|
|
|
|
|
balance = 1;
|
|
|
|
|
while (wl && wl->wl_word) {
|
|
|
|
|
if (eq(wl->wl_word, "(")) {
|
|
|
|
|
balance++;
|
|
|
|
|
} else if (eq(wl->wl_word, ")")) {
|
|
|
|
|
if (!--balance)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-12-08 17:58:47 +01:00
|
|
|
copyval = ss = cp_unquote(wl->wl_word);
|
2019-03-31 14:41:14 +02:00
|
|
|
/* if val is in double quotes, treat as string */
|
|
|
|
|
if (!eq(wl->wl_word, copyval)) {
|
2016-03-25 15:40:38 +01:00
|
|
|
vv = var_alloc_string(NULL, copy(ss), NULL);
|
2019-03-31 14:41:14 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
td = ft_numparse(&ss, FALSE);
|
|
|
|
|
if (td)
|
|
|
|
|
vv = var_alloc_real(NULL, *td, NULL);
|
|
|
|
|
else
|
|
|
|
|
vv = var_alloc_string(NULL, copy(ss), NULL);
|
|
|
|
|
}
|
|
|
|
|
tfree(copyval);
|
2000-06-27 18:15:43 +02:00
|
|
|
if (listv) {
|
|
|
|
|
lv->va_next = vv;
|
|
|
|
|
lv = vv;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2000-06-27 18:15:43 +02:00
|
|
|
listv = lv = vv;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
wl = wl->wl_next;
|
|
|
|
|
}
|
|
|
|
|
if (balance && !wl) {
|
|
|
|
|
fprintf(cp_err, "Error: bad set form.\n");
|
2004-01-10 22:39:36 +01:00
|
|
|
tfree(name); /* va: cp_unquote memory leak: free name before exiting */
|
2012-11-04 14:16:27 +01:00
|
|
|
if (ft_stricterror)
|
|
|
|
|
controlled_exit(EXIT_BAD);
|
2012-11-07 19:38:28 +01:00
|
|
|
return (NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2016-03-25 15:41:12 +01:00
|
|
|
vars = var_alloc_vlist(copy(name), listv, vars);
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
wl = wl->wl_next;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-09 20:46:36 +01:00
|
|
|
copyval = ss = cp_unquote(val);
|
2019-03-31 14:41:14 +02:00
|
|
|
/* if val is in double quotes, treat as string */
|
|
|
|
|
if (!eq(val, copyval)) {
|
|
|
|
|
vars = var_alloc_string(copy(name), copy(copyval), vars);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
td = ft_numparse(&ss, FALSE);
|
|
|
|
|
if (td) {
|
|
|
|
|
/*** We should try to get CP_NUM's... */
|
2019-11-30 05:32:13 +01:00
|
|
|
vars = var_alloc_real(name, *td, vars);
|
2019-03-31 14:41:14 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-11-30 05:32:13 +01:00
|
|
|
vars = var_alloc_string(name, copy(val), vars);
|
2019-03-31 14:41:14 +02:00
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2019-11-30 05:32:13 +01:00
|
|
|
name = (char *) NULL; /* name given to variable via var_alloc_* */
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak */
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2019-11-30 05:32:13 +01:00
|
|
|
if (name) {
|
2003-07-23 21:36:39 +02:00
|
|
|
tfree(name);
|
2019-11-30 05:32:13 +01:00
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
return (vars);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-04-05 10:02:03 +02:00
|
|
|
/* free the struct variable. The type of the union is given by va_type */
|
|
|
|
|
void
|
|
|
|
|
free_struct_variable(struct variable *v)
|
|
|
|
|
{
|
2012-09-20 20:30:53 +02:00
|
|
|
while (v) {
|
2012-08-05 12:01:11 +02:00
|
|
|
struct variable *next_v = v->va_next;
|
2016-01-02 14:04:31 +01:00
|
|
|
if (v->va_name)
|
|
|
|
|
tfree(v->va_name);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (v->va_type == CP_LIST)
|
2012-08-05 12:01:11 +02:00
|
|
|
free_struct_variable(v->va_vlist);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (v->va_type == CP_STRING)
|
2012-08-05 12:01:11 +02:00
|
|
|
tfree(v->va_string);
|
|
|
|
|
tfree(v);
|
|
|
|
|
v = next_v;
|
2012-08-05 12:04:06 +02:00
|
|
|
}
|
2009-04-05 10:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
void
|
|
|
|
|
cp_remvar(char *varname)
|
|
|
|
|
{
|
2016-08-03 21:25:37 +02:00
|
|
|
struct variable *v, **p;
|
2016-08-03 20:49:57 +02:00
|
|
|
struct variable *uv1;
|
2016-08-05 20:48:13 +02:00
|
|
|
int i;
|
2007-10-09 09:19:45 +02:00
|
|
|
|
2016-08-03 20:23:58 +02:00
|
|
|
uv1 = cp_usrvars();
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2016-08-03 21:12:31 +02:00
|
|
|
for (p = &variables; *p; p = &(*p)->va_next)
|
2016-08-03 21:25:37 +02:00
|
|
|
if (eq((*p)->va_name, varname))
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2016-08-03 21:18:44 +02:00
|
|
|
|
|
|
|
|
if (*p == NULL)
|
2016-08-03 21:12:31 +02:00
|
|
|
for (p = &uv1; *p; p = &(*p)->va_next)
|
2016-08-03 21:25:37 +02:00
|
|
|
if (eq((*p)->va_name, varname))
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2016-08-03 21:18:44 +02:00
|
|
|
|
2016-08-05 21:44:46 +02:00
|
|
|
if (*p == NULL && plot_cur)
|
|
|
|
|
for (p = &plot_cur->pl_env; *p; p = &(*p)->va_next)
|
|
|
|
|
if (eq((*p)->va_name, varname))
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-03 21:18:44 +02:00
|
|
|
if (*p == NULL && ft_curckt)
|
2016-08-03 21:12:31 +02:00
|
|
|
for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next)
|
2016-08-03 21:25:37 +02:00
|
|
|
if (eq((*p)->va_name, varname))
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2016-08-03 21:18:44 +02:00
|
|
|
|
2016-08-03 21:25:37 +02:00
|
|
|
v = *p;
|
2016-08-03 21:18:44 +02:00
|
|
|
|
|
|
|
|
/* make up an auxiliary struct variable for cp_usrset() */
|
|
|
|
|
if (!v)
|
2016-03-25 15:40:38 +01:00
|
|
|
v = var_alloc_num(copy(varname), 0, NULL);
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
/* Note that 'unset history' doesn't do anything here... Causes
|
|
|
|
|
* trouble... */
|
|
|
|
|
if (eq(varname, "noglob"))
|
|
|
|
|
cp_noglob = FALSE;
|
|
|
|
|
else if (eq(varname, "nonomatch"))
|
|
|
|
|
cp_nonomatch = FALSE;
|
|
|
|
|
else if (eq(varname, "noclobber"))
|
|
|
|
|
cp_noclobber = FALSE;
|
2001-12-14 19:29:08 +01:00
|
|
|
else if (eq(varname, "echo")) /*CDHW*/
|
|
|
|
|
cp_echo = FALSE; /*CDHW*/
|
2012-09-15 14:58:39 +02:00
|
|
|
else if (eq(varname, "prompt"))
|
|
|
|
|
cp_promptstring = NULL;
|
2000-06-27 18:15:43 +02:00
|
|
|
else if (eq(varname, "cpdebug"))
|
|
|
|
|
cp_debug = FALSE;
|
|
|
|
|
else if (eq(varname, "ignoreeof"))
|
|
|
|
|
cp_ignoreeof = FALSE;
|
2012-09-15 14:58:39 +02:00
|
|
|
else if (eq(varname, "program"))
|
|
|
|
|
cp_program = "";
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
switch (i = cp_usrset(v, FALSE)) {
|
|
|
|
|
|
|
|
|
|
case US_OK:
|
|
|
|
|
/* Normal case. */
|
2016-08-03 21:25:37 +02:00
|
|
|
if (*p) {
|
2016-08-05 20:48:13 +02:00
|
|
|
*p = v->va_next;
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case US_DONTRECORD:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* 'curplot' 'curplotname' 'curplottitle' 'curplotdate' */
|
2000-06-27 18:15:43 +02:00
|
|
|
/* Do nothing... */
|
2016-08-03 21:25:37 +02:00
|
|
|
if (*p)
|
2000-06-27 18:15:43 +02:00
|
|
|
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
|
|
|
|
|
break;
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
case US_READONLY:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* 'plots' and any var in plot_cur->pl_env */
|
2000-06-27 18:15:43 +02:00
|
|
|
/* Badness... */
|
|
|
|
|
fprintf(cp_err, "Error: %s is read-only.\n", v->va_name);
|
2016-08-03 21:25:37 +02:00
|
|
|
if (*p)
|
2000-06-27 18:15:43 +02:00
|
|
|
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case US_SIMVAR:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* variables processed by if_option(ft_curckt->ci_ckt, ...) */
|
2012-08-05 12:04:06 +02:00
|
|
|
fprintf(stderr, "it's a US_SIMVAR!\n");
|
|
|
|
|
if (ft_curckt) {
|
2016-08-03 21:12:31 +02:00
|
|
|
for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next)
|
2016-08-03 21:25:37 +02:00
|
|
|
if (eq(varname, (*p)->va_name))
|
2012-08-05 12:04:06 +02:00
|
|
|
break;
|
2016-08-03 21:25:37 +02:00
|
|
|
if (*p) {
|
|
|
|
|
struct variable *u = *p;
|
2016-08-05 20:48:13 +02:00
|
|
|
*p = u->va_next;
|
2012-08-05 12:04:06 +02:00
|
|
|
tfree(u);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2016-08-03 20:36:23 +02:00
|
|
|
case US_NOSIMVAR:
|
2000-06-27 18:15:43 +02:00
|
|
|
default:
|
2016-08-03 20:36:23 +02:00
|
|
|
/* variables processed by if_option(NULL, ...) */
|
2000-06-27 18:15:43 +02:00
|
|
|
fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2012-08-14 20:22:13 +02:00
|
|
|
v->va_next = NULL;
|
|
|
|
|
free_struct_variable(v);
|
2016-08-04 21:57:44 +02:00
|
|
|
|
2009-04-05 10:02:03 +02:00
|
|
|
free_struct_variable(uv1);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Determine the value of a variable. Fail if the variable is unset,
|
|
|
|
|
* and if the type doesn't match, try and make it work... */
|
|
|
|
|
bool
|
2018-07-21 18:22:18 +02:00
|
|
|
cp_getvar(char *name, enum cp_types type, void *retval, size_t rsize)
|
2000-06-27 18:15:43 +02:00
|
|
|
{
|
|
|
|
|
struct variable *v;
|
2016-08-03 20:49:57 +02:00
|
|
|
struct variable *uv1;
|
2007-10-09 09:19:45 +02:00
|
|
|
|
2016-08-03 20:23:58 +02:00
|
|
|
uv1 = cp_usrvars();
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
#ifdef TRACE
|
|
|
|
|
/* SDB debug statement */
|
2012-09-20 20:30:53 +02:00
|
|
|
fprintf(stderr, "in cp_getvar, trying to get value of variable %s.\n", name);
|
2004-01-10 22:39:36 +01:00
|
|
|
#endif
|
|
|
|
|
|
2016-08-05 21:28:53 +02:00
|
|
|
for (v = variables; v; v = v->va_next)
|
|
|
|
|
if (eq(name, v->va_name))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!v)
|
|
|
|
|
for (v = uv1; v; v = v->va_next)
|
|
|
|
|
if (eq(name, v->va_name))
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-05 21:44:46 +02:00
|
|
|
if (!v && plot_cur)
|
|
|
|
|
for (v = plot_cur->pl_env; v; v = v->va_next)
|
|
|
|
|
if (eq(name, v->va_name))
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-05 21:28:53 +02:00
|
|
|
if (!v && ft_curckt)
|
|
|
|
|
for (v = ft_curckt->ci_vars; v; v = v->va_next)
|
|
|
|
|
if (eq(name, v->va_name))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!v) {
|
2010-07-20 20:41:25 +02:00
|
|
|
if (type == CP_BOOL && retval)
|
2016-08-05 21:28:53 +02:00
|
|
|
*(bool *) retval = FALSE;
|
2009-03-28 21:06:38 +01:00
|
|
|
free_struct_variable(uv1);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
if (v->va_type == type) {
|
2016-08-05 21:28:53 +02:00
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
|
switch (type) {
|
|
|
|
|
case CP_BOOL:
|
|
|
|
|
*(bool *) retval = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
case CP_NUM:
|
|
|
|
|
*(int *) retval = v->va_num;
|
|
|
|
|
break;
|
|
|
|
|
case CP_REAL:
|
|
|
|
|
*(double *) retval = v->va_real;
|
|
|
|
|
break;
|
|
|
|
|
case CP_STRING: { /* Gotta be careful to have room. */
|
|
|
|
|
char *s = cp_unquote(v->va_string);
|
|
|
|
|
cp_wstrip(s);
|
2018-07-21 18:22:18 +02:00
|
|
|
if (strlen(s) >= rsize - 1) {
|
2018-08-22 14:19:12 +02:00
|
|
|
fprintf(stderr, "Internal Error: string length for variable %s is limited to %zu chars\n", v->va_name, rsize);
|
2018-07-21 18:22:18 +02:00
|
|
|
controlled_exit(EXIT_BAD);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
strcpy((char*) retval, s);
|
2016-08-05 21:28:53 +02:00
|
|
|
tfree(s);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CP_LIST: /* Funny case... */
|
|
|
|
|
*(struct variable **) retval = v->va_vlist;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"cp_getvar: Internal Error: bad var type %d.\n", type);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
free_struct_variable(uv1);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (TRUE);
|
2016-08-05 21:28:53 +02:00
|
|
|
}
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2016-08-05 21:28:53 +02:00
|
|
|
/* Try to coerce it.. */
|
|
|
|
|
if ((type == CP_NUM) && (v->va_type == CP_REAL)) {
|
|
|
|
|
*(int *) retval = (int) v->va_real;
|
|
|
|
|
} else if ((type == CP_REAL) && (v->va_type == CP_NUM)) {
|
|
|
|
|
*(double *) retval = (double) v->va_num;
|
|
|
|
|
} else if ((type == CP_STRING) && (v->va_type == CP_NUM)) {
|
|
|
|
|
sprintf((char*) retval, "%d", v->va_num);
|
|
|
|
|
} else if ((type == CP_STRING) && (v->va_type == CP_REAL)) {
|
|
|
|
|
sprintf((char*) retval, "%f", v->va_real);
|
2000-06-27 18:15:43 +02:00
|
|
|
} else {
|
2012-08-05 12:04:06 +02:00
|
|
|
free_struct_variable(uv1);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2016-08-05 21:28:53 +02:00
|
|
|
|
|
|
|
|
free_struct_variable(uv1);
|
|
|
|
|
return (TRUE);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* A variable substitution is indicated by a $, and the variable name
|
|
|
|
|
* is the following string of non-special characters. All variable
|
|
|
|
|
* values are inserted as a single word, except for lists, which are a
|
|
|
|
|
* list of words. A routine cp_usrset must be supplied by the host
|
|
|
|
|
* program to deal with variables that aren't used by cshpar -- it
|
|
|
|
|
* should be cp_usrset(var, isset), where var is a variable *, and
|
|
|
|
|
* isset is TRUE if the variable is being set, FALSE if unset. Also
|
|
|
|
|
* required is a routine cp_enqvar(name) which returns a struct
|
|
|
|
|
* variable *, which allows the host program to provide values for
|
|
|
|
|
* non-cshpar variables. */
|
|
|
|
|
|
|
|
|
|
char cp_dol = '$';
|
|
|
|
|
|
|
|
|
|
/* Non-alphanumeric characters that may appear in variable names. < is very
|
|
|
|
|
* special...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define VALIDCHARS "$-_<#?@.()[]&"
|
|
|
|
|
|
2013-08-27 14:28:59 +02:00
|
|
|
char *
|
|
|
|
|
span_var_expr(char *t)
|
|
|
|
|
{
|
|
|
|
|
int parenthesis = 0;
|
|
|
|
|
int brackets = 0;
|
|
|
|
|
|
2016-03-08 21:20:11 +01:00
|
|
|
while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
|
2013-08-27 14:28:59 +02:00
|
|
|
switch (*t++)
|
|
|
|
|
{
|
|
|
|
|
case '[':
|
|
|
|
|
brackets++;
|
|
|
|
|
break;
|
|
|
|
|
case '(':
|
|
|
|
|
parenthesis++;
|
|
|
|
|
break;
|
|
|
|
|
case ']':
|
|
|
|
|
if (brackets <= 0)
|
|
|
|
|
return t-1;
|
|
|
|
|
if (--brackets <= 0)
|
|
|
|
|
return t;
|
|
|
|
|
break;
|
|
|
|
|
case ')':
|
|
|
|
|
if (parenthesis <= 0)
|
|
|
|
|
return t-1;
|
|
|
|
|
if (--parenthesis <= 0)
|
|
|
|
|
return t;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-01-04 15:42:57 +01:00
|
|
|
/* Substitute variable name by its value and restore to wordlist */
|
2000-06-27 18:15:43 +02:00
|
|
|
wordlist *
|
|
|
|
|
cp_variablesubst(wordlist *wlist)
|
|
|
|
|
{
|
2014-11-30 20:58:29 +01:00
|
|
|
wordlist *wl;
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
for (wl = wlist; wl; wl = wl->wl_next) {
|
2014-11-30 20:58:29 +01:00
|
|
|
|
|
|
|
|
char *s_dollar;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
while ((s_dollar = strchr(wl->wl_word + i, cp_dol)) != NULL) {
|
|
|
|
|
|
|
|
|
|
int prefix_len = (int) (s_dollar - wl->wl_word);
|
|
|
|
|
|
|
|
|
|
char *tail = span_var_expr(s_dollar + 1);
|
|
|
|
|
char *var = copy_substring(s_dollar + 1, tail);
|
|
|
|
|
|
|
|
|
|
wordlist *nwl = vareval(var);
|
|
|
|
|
tfree(var);
|
|
|
|
|
|
|
|
|
|
if (nwl) {
|
|
|
|
|
char *x = nwl->wl_word;
|
|
|
|
|
char *tail_ = copy(tail);
|
|
|
|
|
nwl->wl_word = tprintf("%.*s%s", prefix_len, wl->wl_word, nwl->wl_word);
|
2018-07-21 12:19:05 +02:00
|
|
|
tfree(x);
|
2014-11-30 20:58:29 +01:00
|
|
|
if (wlist == wl)
|
|
|
|
|
wlist = nwl;
|
|
|
|
|
wl = wl_splice(wl, nwl);
|
2015-01-04 20:37:16 +01:00
|
|
|
i = (int) strlen(wl->wl_word);
|
2014-11-30 20:58:29 +01:00
|
|
|
x = wl->wl_word;
|
|
|
|
|
wl->wl_word = tprintf("%s%s", wl->wl_word, tail_);
|
2018-07-21 12:19:05 +02:00
|
|
|
tfree(x);
|
|
|
|
|
tfree(tail_);
|
2014-11-30 20:58:29 +01:00
|
|
|
} else if (prefix_len || *tail) {
|
|
|
|
|
char *x = wl->wl_word;
|
|
|
|
|
wl->wl_word = tprintf("%.*s%s", prefix_len, wl->wl_word, tail);
|
|
|
|
|
i = prefix_len;
|
2018-07-21 12:19:05 +02:00
|
|
|
tfree(x);
|
2014-11-30 20:58:29 +01:00
|
|
|
} else {
|
|
|
|
|
wordlist *next = wl->wl_next;
|
|
|
|
|
if (wlist == wl)
|
|
|
|
|
wlist = next;
|
|
|
|
|
wl_delete_slice(wl, next);
|
|
|
|
|
if (!next)
|
|
|
|
|
return wlist;
|
|
|
|
|
wl = next;
|
|
|
|
|
i = 0;
|
2009-04-05 10:02:03 +02:00
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-03-29 18:58:44 +02:00
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wlist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Evaluate a variable. */
|
|
|
|
|
wordlist *
|
|
|
|
|
vareval(char *string)
|
|
|
|
|
{
|
2018-08-07 22:46:26 +02:00
|
|
|
struct variable *v, *vfree = NULL;
|
2000-06-27 18:15:43 +02:00
|
|
|
wordlist *wl;
|
|
|
|
|
char buf[BSIZE_SP], *s;
|
|
|
|
|
char *oldstring = copy(string);
|
|
|
|
|
char *range = NULL;
|
2018-10-07 14:52:52 +02:00
|
|
|
int i, up, low, tbfreed;
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2018-08-07 22:46:26 +02:00
|
|
|
/* usage of vfree: variable v has to be freed only if created by cp_enqvar()! */
|
|
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
cp_wstrip(string);
|
2012-08-05 12:04:06 +02:00
|
|
|
if ((s = strchr(string, '[')) != NULL) {
|
2000-06-27 18:15:43 +02:00
|
|
|
*s = '\0';
|
|
|
|
|
range = s + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (*string) {
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
case '$':
|
2015-03-28 20:10:29 +01:00
|
|
|
wl = wl_cons(tprintf("%d", getpid()), NULL);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
case '<':
|
2000-06-27 18:15:43 +02:00
|
|
|
(void) fflush(cp_out);
|
|
|
|
|
if (!fgets(buf, BSIZE_SP, cp_in)) {
|
|
|
|
|
clearerr(cp_in);
|
|
|
|
|
(void) strcpy(buf, "EOF");
|
|
|
|
|
}
|
|
|
|
|
for (s = buf; *s && (*s != '\n'); s++)
|
|
|
|
|
;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
wl = cp_lexer(buf);
|
|
|
|
|
/* This is a hack. */
|
|
|
|
|
if (!wl->wl_word)
|
|
|
|
|
wl->wl_word = copy("");
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
2012-08-05 12:04:06 +02:00
|
|
|
|
|
|
|
|
case '?':
|
2000-06-27 18:15:43 +02:00
|
|
|
string++;
|
|
|
|
|
for (v = variables; v; v = v->va_next)
|
|
|
|
|
if (eq(v->va_name, string))
|
|
|
|
|
break;
|
2018-10-07 14:52:52 +02:00
|
|
|
if (!v) {
|
|
|
|
|
v = cp_enqvar(string, &tbfreed);
|
|
|
|
|
if (tbfreed)
|
|
|
|
|
vfree = v;
|
|
|
|
|
}
|
2012-07-14 10:23:51 +02:00
|
|
|
wl = wl_cons(copy(v ? "1" : "0"), NULL);
|
2018-08-07 22:46:26 +02:00
|
|
|
free_struct_variable(vfree);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
2012-08-05 12:04:06 +02:00
|
|
|
|
|
|
|
|
case '#':
|
2000-06-27 18:15:43 +02:00
|
|
|
string++;
|
|
|
|
|
for (v = variables; v; v = v->va_next)
|
|
|
|
|
if (eq(v->va_name, string))
|
|
|
|
|
break;
|
2018-10-07 14:52:52 +02:00
|
|
|
if (!v) {
|
|
|
|
|
v = cp_enqvar(string, &tbfreed);
|
|
|
|
|
if (tbfreed)
|
|
|
|
|
vfree = v;
|
|
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
if (!v) {
|
2012-08-05 12:04:06 +02:00
|
|
|
fprintf(cp_err, "Error: %s: no such variable.\n", string);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (NULL);
|
|
|
|
|
}
|
2010-07-17 22:48:20 +02:00
|
|
|
if (v->va_type == CP_LIST)
|
2000-06-27 18:15:43 +02:00
|
|
|
for (v = v->va_vlist, i = 0; v; v = v->va_next)
|
|
|
|
|
i++;
|
|
|
|
|
else
|
2010-07-17 22:48:20 +02:00
|
|
|
i = (v->va_type != CP_BOOL);
|
2015-03-28 20:10:29 +01:00
|
|
|
wl = wl_cons(tprintf("%d", i), NULL);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2018-08-07 22:46:26 +02:00
|
|
|
free_struct_variable(vfree);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
|
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
case '\0':
|
2012-07-14 10:23:51 +02:00
|
|
|
wl = wl_cons(copy("$"), NULL);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-07 22:46:26 +02:00
|
|
|
vfree = NULL; //just in case ...
|
2000-06-27 18:15:43 +02:00
|
|
|
/* The notation var[stuff] has two meanings... If this is a real
|
|
|
|
|
* variable, then the [] denotes range, but if this is a strange
|
|
|
|
|
* (e.g, device parameter) variable, it could be anything...
|
|
|
|
|
*/
|
|
|
|
|
for (v = variables; v; v = v->va_next)
|
|
|
|
|
if (eq(v->va_name, string))
|
|
|
|
|
break;
|
2016-03-08 21:20:11 +01:00
|
|
|
if (!v && isdigit_c(*string)) {
|
2000-06-27 18:15:43 +02:00
|
|
|
for (v = variables; v; v = v->va_next)
|
|
|
|
|
if (eq(v->va_name, "argv"))
|
|
|
|
|
break;
|
|
|
|
|
range = string;
|
|
|
|
|
}
|
|
|
|
|
if (!v) {
|
|
|
|
|
range = NULL;
|
|
|
|
|
string = oldstring;
|
2018-10-07 14:52:52 +02:00
|
|
|
v = cp_enqvar(string, &tbfreed);
|
|
|
|
|
if (tbfreed)
|
|
|
|
|
vfree = v;
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2010-11-19 19:52:44 +01:00
|
|
|
if (!v && (s = getenv(string)) != NULL) {
|
2012-07-14 10:23:51 +02:00
|
|
|
wl = wl_cons(copy(s), NULL);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
|
|
|
|
}
|
|
|
|
|
if (!v) {
|
|
|
|
|
fprintf(cp_err, "Error: %s: no such variable.\n", string);
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
wl = cp_varwl(v);
|
2018-08-07 22:46:26 +02:00
|
|
|
free_struct_variable(vfree);
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
/* Now parse and deal with 'range' ... */
|
|
|
|
|
if (range) {
|
2013-07-30 21:36:37 +02:00
|
|
|
/* rather crude fix when range itself is a $expression */
|
|
|
|
|
wordlist *r = NULL;
|
|
|
|
|
if (*range == '$') {
|
|
|
|
|
char *t = ++range;
|
|
|
|
|
if (*t == '&')
|
|
|
|
|
t++;
|
2016-03-08 21:20:11 +01:00
|
|
|
while (isalnum_c(*t))
|
2013-07-30 21:36:37 +02:00
|
|
|
t++;
|
|
|
|
|
*t = '\0';
|
|
|
|
|
r = vareval(range);
|
|
|
|
|
if (!r || r->wl_next) {
|
|
|
|
|
fprintf(cp_err, "Error: %s: illegal index.\n", string);
|
|
|
|
|
tfree(oldstring);
|
|
|
|
|
wl_free(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
range = r->wl_word;
|
|
|
|
|
}
|
2016-03-08 21:20:11 +01:00
|
|
|
for (low = 0; isdigit_c(*range); range++)
|
2000-06-27 18:15:43 +02:00
|
|
|
low = low * 10 + *range - '0';
|
2016-03-08 21:20:11 +01:00
|
|
|
if ((*range == '-') && isdigit_c(range[1]))
|
|
|
|
|
for (up = 0, range++; isdigit_c(*range); range++)
|
2000-06-27 18:15:43 +02:00
|
|
|
up = up * 10 + *range - '0';
|
|
|
|
|
else if (*range == '-')
|
|
|
|
|
up = wl_length(wl);
|
|
|
|
|
else
|
|
|
|
|
up = low;
|
|
|
|
|
up--, low--;
|
|
|
|
|
wl = wl_range(wl, low, up);
|
2013-07-30 21:36:37 +02:00
|
|
|
wl_free(r);
|
2000-06-27 18:15:43 +02:00
|
|
|
}
|
2009-03-29 18:58:44 +02:00
|
|
|
tfree(oldstring);
|
2000-06-27 18:15:43 +02:00
|
|
|
return (wl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-07-31 17:31:31 +02:00
|
|
|
struct xxx {
|
|
|
|
|
struct variable *x_v;
|
|
|
|
|
char x_char;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2000-06-27 18:15:43 +02:00
|
|
|
static int
|
|
|
|
|
vcmp(const void *a, const void *b)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct xxx *v1 = (struct xxx *) a;
|
|
|
|
|
struct xxx *v2 = (struct xxx *) b;
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2010-11-19 19:51:03 +01:00
|
|
|
if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)) != 0)
|
2000-06-27 18:15:43 +02:00
|
|
|
return (i);
|
|
|
|
|
else
|
|
|
|
|
return (v1->x_char - v2->x_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Print the values of currently defined variables. */
|
|
|
|
|
void
|
|
|
|
|
cp_vprint(void)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v;
|
2016-08-03 20:49:57 +02:00
|
|
|
struct variable *uv1;
|
2000-06-27 18:15:43 +02:00
|
|
|
wordlist *wl;
|
|
|
|
|
int i, j;
|
|
|
|
|
char *s;
|
|
|
|
|
struct xxx *vars;
|
|
|
|
|
|
2016-08-03 20:23:58 +02:00
|
|
|
uv1 = cp_usrvars();
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2016-08-05 22:03:45 +02:00
|
|
|
for (v = variables, i = 0; v; v = v->va_next)
|
|
|
|
|
i++;
|
|
|
|
|
for (v = uv1; v; v = v->va_next)
|
2000-06-27 18:15:43 +02:00
|
|
|
i++;
|
2016-08-05 21:44:46 +02:00
|
|
|
if (plot_cur)
|
|
|
|
|
for (v = plot_cur->pl_env; v; v = v->va_next)
|
|
|
|
|
i++;
|
2016-08-03 20:49:57 +02:00
|
|
|
if (ft_curckt)
|
|
|
|
|
for (v = ft_curckt->ci_vars; v; v = v->va_next)
|
|
|
|
|
i++;
|
2012-08-05 12:04:06 +02:00
|
|
|
|
2010-10-28 21:32:34 +02:00
|
|
|
vars = TMALLOC(struct xxx, i);
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
out_init();
|
|
|
|
|
for (v = variables, i = 0; v; v = v->va_next, i++) {
|
|
|
|
|
vars[i].x_v = v;
|
|
|
|
|
vars[i].x_char = ' ';
|
|
|
|
|
}
|
|
|
|
|
for (v = uv1; v; v = v->va_next, i++) {
|
|
|
|
|
vars[i].x_v = v;
|
|
|
|
|
vars[i].x_char = '*';
|
|
|
|
|
}
|
2016-08-05 21:44:46 +02:00
|
|
|
if (plot_cur)
|
|
|
|
|
for (v = plot_cur->pl_env; v; v = v->va_next, i++) {
|
|
|
|
|
vars[i].x_v = v;
|
|
|
|
|
vars[i].x_char = '*';
|
|
|
|
|
}
|
2016-08-03 20:49:57 +02:00
|
|
|
if (ft_curckt)
|
|
|
|
|
for (v = ft_curckt->ci_vars; v; v = v->va_next, i++) {
|
|
|
|
|
vars[i].x_v = v;
|
|
|
|
|
vars[i].x_char = '+';
|
|
|
|
|
}
|
2000-06-27 18:15:43 +02:00
|
|
|
|
2012-08-05 12:04:06 +02:00
|
|
|
qsort(vars, (size_t) i, sizeof(*vars), vcmp);
|
2000-06-27 18:15:43 +02:00
|
|
|
|
|
|
|
|
for (j = 0; j < i; j++) {
|
2012-08-05 12:04:06 +02:00
|
|
|
if (j && eq(vars[j].x_v->va_name, vars[j-1].x_v->va_name))
|
2000-06-27 18:15:43 +02:00
|
|
|
continue;
|
|
|
|
|
v = vars[j].x_v;
|
2010-07-17 22:48:20 +02:00
|
|
|
if (v->va_type == CP_BOOL) {
|
2012-08-18 18:27:13 +02:00
|
|
|
out_printf("%c %s\n", vars[j].x_char, v->va_name);
|
2000-06-27 18:15:43 +02:00
|
|
|
} else {
|
|
|
|
|
out_printf("%c %s\t", vars[j].x_char, v->va_name);
|
|
|
|
|
wl = vareval(v->va_name);
|
|
|
|
|
s = wl_flatten(wl);
|
2012-08-05 12:04:06 +02:00
|
|
|
if (v->va_type == CP_LIST)
|
2000-06-27 18:15:43 +02:00
|
|
|
out_printf("( %s )\n", s);
|
2012-08-05 12:04:06 +02:00
|
|
|
else
|
2000-06-27 18:15:43 +02:00
|
|
|
out_printf("%s\n", s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-05 21:45:22 +02:00
|
|
|
free_struct_variable(uv1);
|
2000-06-27 18:15:43 +02:00
|
|
|
tfree(vars);
|
|
|
|
|
}
|
2016-03-25 15:42:15 +01:00
|
|
|
|
2016-03-25 15:38:31 +01:00
|
|
|
struct variable *
|
|
|
|
|
var_alloc(char *name, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = TMALLOC(struct variable, 1);
|
|
|
|
|
ZERO(v, struct variable);
|
|
|
|
|
v -> va_name = name;
|
|
|
|
|
v -> va_next = next;
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-25 15:40:21 +01:00
|
|
|
struct variable *
|
|
|
|
|
var_alloc_bool(char *name, bool value, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = var_alloc(name, next);
|
|
|
|
|
var_set_bool(v, value);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct variable *
|
|
|
|
|
var_alloc_num(char *name, int value, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = var_alloc(name, next);
|
|
|
|
|
var_set_num(v, value);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct variable *
|
|
|
|
|
var_alloc_real(char *name, double value, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = var_alloc(name, next);
|
|
|
|
|
var_set_real(v, value);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct variable *
|
|
|
|
|
var_alloc_string(char *name, char * value, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = var_alloc(name, next);
|
|
|
|
|
var_set_string(v, value);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct variable *
|
|
|
|
|
var_alloc_vlist(char *name, struct variable * value, struct variable *next)
|
|
|
|
|
{
|
|
|
|
|
struct variable *v = var_alloc(name, next);
|
|
|
|
|
var_set_vlist(v, value);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-25 15:42:15 +01:00
|
|
|
void
|
|
|
|
|
var_set_bool(struct variable *v, bool value)
|
|
|
|
|
{
|
|
|
|
|
v->va_type = CP_BOOL;
|
|
|
|
|
v->va_bool = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
var_set_num(struct variable *v, int value)
|
|
|
|
|
{
|
|
|
|
|
v->va_type = CP_NUM;
|
|
|
|
|
v->va_num = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
var_set_real(struct variable *v, double value)
|
|
|
|
|
{
|
|
|
|
|
v->va_type = CP_REAL;
|
|
|
|
|
v->va_real = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
var_set_string(struct variable *v, char *value)
|
|
|
|
|
{
|
|
|
|
|
v->va_type = CP_STRING;
|
|
|
|
|
v->va_string = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
var_set_vlist(struct variable *v, struct variable *value)
|
|
|
|
|
{
|
|
|
|
|
v->va_type = CP_LIST;
|
|
|
|
|
v->va_vlist = value;
|
|
|
|
|
}
|