Fix variables so that they behave as described (or intended) in the ngspice-26plus manual.

This commit is contained in:
mhx 2016-01-01 20:32:22 +01:00 committed by rlar
parent 9d32a0a5a9
commit ee2eb66c45
2 changed files with 252 additions and 189 deletions

View File

@ -33,23 +33,26 @@ wordlist *
cp_varwl(struct variable *var) cp_varwl(struct variable *var)
{ {
wordlist *wl = NULL, *w, *wx = NULL; wordlist *wl = NULL, *w, *wx = NULL;
char *buf; char buf[BSIZE_SP], *copystring;
struct variable *vt; struct variable *vt;
switch (var->va_type) { switch (var->va_type) {
case CP_BOOL: case CP_BOOL:
/* Can't ever be FALSE. */ /* Can't ever be FALSE. */
buf = copy(var->va_bool ? "TRUE" : "FALSE"); sprintf(buf, "%s", var->va_bool ? "TRUE" : "FALSE");
break; break;
case CP_NUM: case CP_NUM:
buf = tprintf("%d", var->va_num); sprintf(buf, "%d", var->va_num);
break; break;
case CP_REAL: case CP_REAL:
/* This is a case where printnum isn't too good... */ /* This is a case where printnum isn't too good... */
buf = tprintf("%G", var->va_real); sprintf(buf, "%G", var->va_real);
break; break;
case CP_STRING: case CP_STRING:
buf = cp_unquote(var->va_string); /*strcpy(buf, cp_unquote(var->va_string)); DG: memory leak here*/
copystring = cp_unquote(var->va_string); /*DG*/
strcpy(buf, copystring);
tfree(copystring);
break; break;
case CP_LIST: /* The tricky case. */ case CP_LIST: /* The tricky case. */
for (vt = var->va_vlist; vt; vt = vt->va_next) { for (vt = var->va_vlist; vt; vt = vt->va_next) {
@ -65,12 +68,13 @@ cp_varwl(struct variable *var)
return (wl); return (wl);
default: default:
fprintf(cp_err, fprintf(cp_err,
"cp_varwl: Internal Error: bad variable type %d\n", "cp_varwl: INTERNAL ERROR: bad variable type %d\n",
var->va_type); var->va_type);
return (NULL); return (NULL);
} }
return wl_cons(buf, NULL); wl = wl_cons(copy(buf), NULL);
return wl;
} }
@ -143,7 +147,7 @@ cp_vset(char *varname, enum cp_types type, void *value)
default: default:
fprintf(cp_err, fprintf(cp_err,
"cp_vset: Internal Error: bad variable type %d.\n", "cp_vset: INTERNAL ERROR: bad variable type %d.\n",
type); type);
tfree(copyvarname); tfree(copyvarname);
return; return;
@ -152,7 +156,7 @@ cp_vset(char *varname, enum cp_types type, void *value)
v->va_type = type; v->va_type = type;
/* Now, see if there is anything interesting going on. We /* Now, see if there is anything interesting going on. We
* recognise these special variables: noglob, nonomatch, history, * recognize these special variables: noglob, nonomatch, history,
* echo, noclobber, prompt, and verbose. cp_remvar looks for these * echo, noclobber, prompt, and verbose. cp_remvar looks for these
* variables too. The host program will get any others. */ * variables too. The host program will get any others. */
if (eq(copyvarname, "noglob")) if (eq(copyvarname, "noglob"))
@ -165,18 +169,14 @@ cp_vset(char *varname, enum cp_types type, void *value)
cp_maxhistlength = (int)floor(v->va_real + 0.5); cp_maxhistlength = (int)floor(v->va_real + 0.5);
else if (eq(copyvarname, "noclobber")) else if (eq(copyvarname, "noclobber"))
cp_noclobber = TRUE; cp_noclobber = TRUE;
else if (eq(varname, "echo")) /*CDHW*/ else if (eq(varname, "echo"))
cp_echo = TRUE; /*CDHW*/ cp_echo = TRUE;
else if (eq(copyvarname, "prompt") && (type == CP_STRING)) else if (eq(copyvarname, "prompt") && (type == CP_STRING))
cp_promptstring = v->va_string; cp_promptstring = v->va_string;
else if (eq(copyvarname, "ignoreeof")) else if (eq(copyvarname, "ignoreeof"))
cp_ignoreeof = TRUE; cp_ignoreeof = TRUE;
else if (eq(copyvarname, "cpdebug")) { else if (eq(copyvarname, "cpdebug")) {
cp_debug = TRUE; cp_debug = TRUE;
#ifndef CPDEBUG
fprintf(cp_err,
"Warning: program not compiled with cshpar debug messages\n");
#endif
} }
switch (i = cp_usrset(v, TRUE)) { switch (i = cp_usrset(v, TRUE)) {
@ -192,15 +192,15 @@ cp_vset(char *varname, enum cp_types type, void *value)
case US_DONTRECORD: case US_DONTRECORD:
/* Do nothing... */ /* Do nothing... */
if (alreadythere) { if (alreadythere) {
fprintf(cp_err, "cp_vset: Internal Error: " fprintf(cp_err, "cp_vset: INTERNAL ERROR: "
"%s already there, but 'dont record'\n", v->va_name); "%s already there, but `don't record'\n", v->va_name);
} }
break; break;
case US_READONLY: case US_READONLY:
fprintf(cp_err, "Error: %s is a read-only variable.\n", v->va_name); fprintf(cp_err, "ERROR: %s is a read-only variable.\n", v->va_name);
if (alreadythere) if (alreadythere)
fprintf(cp_err, "cp_vset: Internal Error: " fprintf(cp_err, "cp_vset: INTERNAL ERROR: "
"it was already there too!!\n"); "it was already there too!!\n");
break; break;
@ -230,16 +230,8 @@ cp_vset(char *varname, enum cp_types type, void *value)
else if (u->va_type == CP_LIST) else if (u->va_type == CP_LIST)
tfree(u->va_vlist); tfree(u->va_vlist);
u->va_V = v->va_V; u->va_V = v->va_V;
/* va_name is the same string */
u->va_type = v->va_type; u->va_type = v->va_type;
/* va_next left unchanged */
// tfree(v->va_name);
tfree(v); tfree(v);
/* va: old version with memory leaks
w = u->va_next;
bcopy(v, u, sizeof(*u));
u->va_next = w;
*/
} }
} }
break; break;
@ -251,24 +243,28 @@ cp_vset(char *varname, enum cp_types type, void *value)
break; break;
default: default:
fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i); fprintf(cp_err, "cp_vset: INTERNAL ERROR: bad US val %d\n", i);
break; break;
} }
/* if (v_free) {
tfree(v->va_name);
tfree(v);
} */
tfree(copyvarname); tfree(copyvarname);
} }
/*CDHW This needs leak checking carefully CDHW*/ /* CDHW This needs leak checking carefully CDHW */
/* mhx: Uses ft_numparse, which interprets SPICE numbers. Therefore it worked incorrectly
for com_set: it prevented e.g. set ape="1MEG" (ape became CP_NUM 1e6 instead of CP_STRING '1meg').
Therefore I changed the function to FIRST check if the rhs is a string (look for quotes), and only
if it is not, continue with ft_numparse.
Note: cp_setparse is used by com_set and com_option, where this new behavior should be ok.
cp_setparse is used in inp.c (4) for .option scale=xxx. Assumed new behavior will be ok.
cp_setparse is used in rawfile.c (2) to parse "option: xxx". Assumed new behavior will be ok.
*/
struct variable * struct variable *
cp_setparse(wordlist *wl) cp_setparse(wordlist *wl)
{ {
char *name = NULL, *val, *copyval, *s, *ss; char *name = NULL, *val, *copyval, *s, *ss;
double *td; double *td;
bool isstring;
struct variable *listv = NULL, *vv, *lv = NULL; struct variable *listv = NULL, *vv, *lv = NULL;
struct variable *vars = NULL; struct variable *vars = NULL;
int balance; int balance;
@ -281,7 +277,7 @@ cp_setparse(wordlist *wl)
name = cp_unquote(wl->wl_word); name = cp_unquote(wl->wl_word);
wl = wl->wl_next; wl = wl->wl_next;
if ((!wl || (*wl->wl_word != '=')) && !strchr(name, '=')) { if ((!wl || (*wl->wl_word != '=')) && !strchr(name, '=')) { /* 'name ccccc' */
vv = alloc(struct variable); vv = alloc(struct variable);
vv->va_name = copy(name); vv->va_name = copy(name);
vv->va_type = CP_BOOL; vv->va_type = CP_BOOL;
@ -292,10 +288,10 @@ cp_setparse(wordlist *wl)
continue; continue;
} }
if (wl && eq(wl->wl_word, "=")) { if (wl && eq(wl->wl_word, "=")) { /* 'name =' */
wl = wl->wl_next; wl = wl->wl_next;
if (wl == NULL) { if (wl == NULL) {
fprintf(cp_err, "Error: bad set form.\n"); fprintf(cp_err, "ERROR: bad set form.\n");
tfree(name); /*DG: cp_unquote Memory leak*/ tfree(name); /*DG: cp_unquote Memory leak*/
if (ft_stricterror) if (ft_stricterror)
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
@ -303,7 +299,7 @@ cp_setparse(wordlist *wl)
} }
val = wl->wl_word; val = wl->wl_word;
wl = wl->wl_next; wl = wl->wl_next;
} else if (wl && (*wl->wl_word == '=')) { } else if (wl && (*wl->wl_word == '=')) { /* name =' */
val = wl->wl_word + 1; val = wl->wl_word + 1;
wl = wl->wl_next; wl = wl->wl_next;
} else if ((s = strchr(name, '=')) != NULL) { } else if ((s = strchr(name, '=')) != NULL) {
@ -311,7 +307,7 @@ cp_setparse(wordlist *wl)
*s = '\0'; *s = '\0';
if (*val == '\0') { if (*val == '\0') {
if (!wl) { if (!wl) {
fprintf(cp_err, "Error: %s equals what?.\n", name); fprintf(cp_err, "ERROR: %s equals what?\n", name);
tfree(name); /*DG: cp_unquote Memory leak: free name before exiting*/ tfree(name); /*DG: cp_unquote Memory leak: free name before exiting*/
if (ft_stricterror) if (ft_stricterror)
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
@ -322,7 +318,7 @@ cp_setparse(wordlist *wl)
} }
} }
} else { } else {
fprintf(cp_err, "Error: bad set form.\n"); fprintf(cp_err, "ERROR: bad set form\n");
tfree(name); /*DG: cp_unquote Memory leak: free name befor exiting */ tfree(name); /*DG: cp_unquote Memory leak: free name befor exiting */
if (ft_stricterror) if (ft_stricterror)
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
@ -330,6 +326,7 @@ cp_setparse(wordlist *wl)
} }
/* val = cp_unquote(val); DG: bad old val is lost*/ /* val = cp_unquote(val); DG: bad old val is lost*/
isstring = (*val == '"'); /* mhx: is this sufficient? */
copyval = cp_unquote(val); /*DG*/ copyval = cp_unquote(val); /*DG*/
strcpy(val, copyval); strcpy(val, copyval);
tfree(copyval); tfree(copyval);
@ -340,6 +337,7 @@ cp_setparse(wordlist *wl)
* ()'s, treat them as tokens... */ * ()'s, treat them as tokens... */
balance = 1; balance = 1;
while (wl && wl->wl_word) { while (wl && wl->wl_word) {
bool isstringc;
if (eq(wl->wl_word, "(")) { if (eq(wl->wl_word, "(")) {
balance++; balance++;
} else if (eq(wl->wl_word, ")")) { } else if (eq(wl->wl_word, ")")) {
@ -348,7 +346,12 @@ cp_setparse(wordlist *wl)
} }
vv = alloc(struct variable); vv = alloc(struct variable);
vv->va_next = NULL; vv->va_next = NULL;
isstringc = (*wl->wl_word == '"'); /* mhx: is this sufficient? */
copyval = ss = cp_unquote(wl->wl_word); copyval = ss = cp_unquote(wl->wl_word);
if (isstringc) {
vv->va_type = CP_STRING;
vv->va_string = copy(ss);
} else {
td = ft_numparse(&ss, FALSE); td = ft_numparse(&ss, FALSE);
if (td) { if (td) {
vv->va_type = CP_REAL; vv->va_type = CP_REAL;
@ -356,6 +359,8 @@ cp_setparse(wordlist *wl)
} else { } else {
vv->va_type = CP_STRING; vv->va_type = CP_STRING;
vv->va_string = copy(ss); vv->va_string = copy(ss);
fprintf(cp_err, "cp_setparse() :: ft_numparse() didn't recognize `%s' for assignment to `%s' as CP_REAL, using CP_STRING.\n", ss, name);
}
} }
tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak*/ tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak*/
if (listv) { if (listv) {
@ -367,7 +372,7 @@ cp_setparse(wordlist *wl)
wl = wl->wl_next; wl = wl->wl_next;
} }
if (balance && !wl) { if (balance && !wl) {
fprintf(cp_err, "Error: bad set form.\n"); fprintf(cp_err, "ERROR: bad set form\n");
tfree(name); /* va: cp_unquote memory leak: free name before exiting */ tfree(name); /* va: cp_unquote memory leak: free name before exiting */
if (ft_stricterror) if (ft_stricterror)
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
@ -385,19 +390,26 @@ cp_setparse(wordlist *wl)
continue; continue;
} }
copyval = ss = cp_unquote(val); /* there shouldn't be quotes around val at this point? */
td = ft_numparse(&ss, FALSE); if (*val == '"')
isstring |= TRUE; /* mhx: is this sufficient? */
copyval = ss = cp_unquote(val); /* 'name = ccccc' */
vv = alloc(struct variable); vv = alloc(struct variable);
vv->va_name = copy(name); vv->va_name = copy(name);
vv->va_next = vars; vv->va_next = vars;
vars = vv; vars = vv;
if (td) { if (isstring) {
/*** We should try to get CP_NUM's... */
vv->va_type = CP_REAL;
vv->va_real = *td;
} else {
vv->va_type = CP_STRING; vv->va_type = CP_STRING;
vv->va_string = copy(val); vv->va_string = copy(val);
} else {
td = ft_numparse(&ss, FALSE); /* FALSE: because set x=1umeter should work and 'meter' ignored */
if (td) {
vv->va_type = CP_REAL;
vv->va_real = *td;
} else {
vv->va_type = CP_STRING;
vv->va_string = copy(val);
}
} }
tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak */ tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak */
tfree(name); /* va: cp_unquote memory leak: free name for every loop */ tfree(name); /* va: cp_unquote memory leak: free name for every loop */
@ -477,8 +489,8 @@ cp_remvar(char *varname)
cp_nonomatch = FALSE; cp_nonomatch = FALSE;
else if (eq(varname, "noclobber")) else if (eq(varname, "noclobber"))
cp_noclobber = FALSE; cp_noclobber = FALSE;
else if (eq(varname, "echo")) /*CDHW*/ else if (eq(varname, "echo"))
cp_echo = FALSE; /*CDHW*/ cp_echo = FALSE;
else if (eq(varname, "prompt")) else if (eq(varname, "prompt"))
cp_promptstring = NULL; cp_promptstring = NULL;
else if (eq(varname, "cpdebug")) else if (eq(varname, "cpdebug"))
@ -510,14 +522,14 @@ cp_remvar(char *varname)
case US_DONTRECORD: case US_DONTRECORD:
/* Do nothing... */ /* Do nothing... */
if (found) if (found)
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname); fprintf(cp_err, "cp_remvar: INTERNAL ERROR: var %d\n", *varname);
break; break;
case US_READONLY: case US_READONLY:
/* Badness... */ /* Badness... */
fprintf(cp_err, "Error: %s is read-only.\n", v->va_name); fprintf(cp_err, "ERROR: %s is read-only.\n", v->va_name);
if (found) if (found)
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname); fprintf(cp_err, "cp_remvar: INTERNAL ERROR: var %d\n", *varname);
break; break;
case US_SIMVAR: case US_SIMVAR:
@ -540,7 +552,7 @@ cp_remvar(char *varname)
break; break;
default: default:
fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i); fprintf(cp_err, "cp_remvar: INTERNAL ERROR: US val %d\n", i);
break; break;
} }
@ -551,8 +563,10 @@ cp_remvar(char *varname)
} }
/* Determine the value of a variable. Fail if the variable is unset, /*
* and if the type doesn't match, try and make it work... */ * 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 bool
cp_getvar(char *name, enum cp_types type, void *retval) cp_getvar(char *name, enum cp_types type, void *retval)
{ {
@ -561,11 +575,6 @@ cp_getvar(char *name, enum cp_types type, void *retval)
cp_usrvars(&uv1, &uv2); cp_usrvars(&uv1, &uv2);
#ifdef TRACE
/* SDB debug statement */
fprintf(stderr, "in cp_getvar, trying to get value of variable %s.\n", name);
#endif
for (v = variables; v && !eq(name, v->va_name); v = v->va_next) for (v = variables; v && !eq(name, v->va_name); v = v->va_next)
; ;
if (v == NULL) if (v == NULL)
@ -616,11 +625,10 @@ cp_getvar(char *name, enum cp_types type, void *retval)
} }
default: default:
fprintf(cp_err, fprintf(cp_err,
"cp_getvar: Internal Error: bad var type %d.\n", type); "cp_getvar: INTERNAL ERROR: bad var type %d.\n", type);
break; break;
} }
free_struct_variable(uv1); free_struct_variable(uv1);
// tfree(uv2);
return (TRUE); return (TRUE);
} else { } else {
@ -678,7 +686,7 @@ span_var_expr(char *t)
int parenthesis = 0; int parenthesis = 0;
int brackets = 0; int brackets = 0;
while (*t && (isalphanum(*t) || strchr(VALIDCHARS, *t))) while (*t && (isalphanum((int)*t) || strchr(VALIDCHARS, *t)))
switch (*t++) switch (*t++)
{ {
case '[': case '[':
@ -707,55 +715,59 @@ span_var_expr(char *t)
} }
/* Substitute variable name by its value and restore to wordlist */
wordlist * wordlist *
cp_variablesubst(wordlist *wlist) cp_variablesubst(wordlist *wlist)
{ {
wordlist *wl; wordlist *wl, *nwl;
char *s, *t, buf[BSIZE_SP], wbuf[BSIZE_SP], tbuf[BSIZE_SP];
/* MW. tbuf holds current word after wl_splice() calls free() on it */
int i;
for (wl = wlist; wl; wl = wl->wl_next) { for (wl = wlist; wl; wl = wl->wl_next) {
char *s_dollar; t = wl->wl_word;
int i = 0; i = 0;
while ((s = strchr(t, cp_dol)) != NULL) {
while ((s_dollar = strchr(wl->wl_word + i, cp_dol)) != NULL) { while (t < s)
wbuf[i++] = *t++;
int prefix_len = (int) (s_dollar - wl->wl_word); wbuf[i] = '\0';
t++;
char *tail = span_var_expr(s_dollar + 1); s = buf;
char *var = copy_substring(s_dollar + 1, tail); /* Get s and t past the end of the var name. */
{
wordlist *nwl = vareval(var); char *end = span_var_expr(t);
tfree(var); while (t < end)
*s++ = *t++;
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);
free(x);
if (wlist == wl)
wlist = nwl;
wl = wl_splice(wl, nwl);
i = (int) strlen(wl->wl_word);
x = wl->wl_word;
wl->wl_word = tprintf("%s%s", wl->wl_word, tail_);
free(x);
free(tail_);
} 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;
free(x);
} else {
wordlist *next = wl->wl_next;
if (wlist == wl)
wlist = next;
wl_delete_slice(wl, next);
if (!next)
return wlist;
wl = next;
i = 0;
} }
*s = '\0';
nwl = vareval(buf);
if (i) {
(void) strcpy(buf, wbuf);
if (nwl) {
(void) strcat(buf, nwl->wl_word);
tfree(nwl->wl_word);
nwl->wl_word = copy(buf);
} else {
nwl = wl_cons(copy(buf), NULL);
}
}
(void) strcpy(tbuf, t); /* MW. Save t*/
if ((wl = wl_splice(wl, nwl)) == NULL) {/*CDHW this frees wl CDHW*/
wl_free(nwl);
return NULL;
}
/* This is bad... */
for (wlist = wl; wlist->wl_prev; wlist = wlist->wl_prev)
;
(void) strcpy(buf, wl->wl_word);
i = (int) strlen(buf);
(void) strcat(buf, tbuf); /* MW. tbuf is used here only */
tfree(wl->wl_word);
wl->wl_word = copy(buf);
t = &wl->wl_word[i];
s = wl->wl_word;
for (i = 0; s < t; s++)
wbuf[i++] = *s;
} }
} }
@ -783,7 +795,8 @@ vareval(char *string)
switch (*string) { switch (*string) {
case '$': case '$':
wl = wl_cons(tprintf("%d", getpid()), NULL); (void) sprintf(buf, "%d", getpid());
wl = wl_cons(copy(buf), NULL);
tfree(oldstring); tfree(oldstring);
return (wl); return (wl);
@ -822,7 +835,7 @@ vareval(char *string)
if (!v) if (!v)
v = cp_enqvar(string); v = cp_enqvar(string);
if (!v) { if (!v) {
fprintf(cp_err, "Error: %s: no such variable.\n", string); fprintf(cp_err, "ERROR: %s: no such variable.\n", string);
tfree(oldstring); tfree(oldstring);
return (NULL); return (NULL);
} }
@ -831,7 +844,8 @@ vareval(char *string)
i++; i++;
else else
i = (v->va_type != CP_BOOL); i = (v->va_type != CP_BOOL);
wl = wl_cons(tprintf("%d", i), NULL); (void) sprintf(buf, "%d", i);
wl = wl_cons(copy(buf), NULL);
tfree(oldstring); tfree(oldstring);
return (wl); return (wl);
@ -848,14 +862,14 @@ vareval(char *string)
for (v = variables; v; v = v->va_next) for (v = variables; v; v = v->va_next)
if (eq(v->va_name, string)) if (eq(v->va_name, string))
break; break;
if (!v && isdigit(*string)) { if (!v && isdigit((int)*string)) {
for (v = variables; v; v = v->va_next) for (v = variables; v; v = v->va_next)
if (eq(v->va_name, "argv")) if (eq(v->va_name, "argv"))
break; break;
range = string; range = string;
} }
if (!v) { if (!v) {
range = NULL; // ? range = NULL;
string = oldstring; string = oldstring;
v = cp_enqvar(string); v = cp_enqvar(string);
} }
@ -865,7 +879,7 @@ vareval(char *string)
return (wl); return (wl);
} }
if (!v) { if (!v) {
fprintf(cp_err, "Error: %s: no such variable.\n", string); fprintf(cp_err, "ERROR: %s: no such variable.\n", string);
tfree(oldstring); tfree(oldstring);
return (NULL); return (NULL);
} }
@ -879,22 +893,22 @@ vareval(char *string)
char *t = ++range; char *t = ++range;
if (*t == '&') if (*t == '&')
t++; t++;
while (isalphanum(*t)) while (isalphanum((int)*t))
t++; t++;
*t = '\0'; *t = '\0';
r = vareval(range); r = vareval(range);
if (!r || r->wl_next) { if (!r || r->wl_next) {
fprintf(cp_err, "Error: %s: illegal index.\n", string); fprintf(cp_err, "ERROR: %s: illegal index.\n", string);
tfree(oldstring); tfree(oldstring);
wl_free(r); wl_free(r);
return NULL; return NULL;
} }
range = r->wl_word; range = r->wl_word;
} }
for (low = 0; isdigit(*range); range++) for (low = 0; isdigit((int)*range); range++)
low = low * 10 + *range - '0'; low = low * 10 + *range - '0';
if ((*range == '-') && isdigit(range[1])) if ((*range == '-') && isdigit((int)range[1]))
for (up = 0, range++; isdigit(*range); range++) for (up = 0, range++; isdigit((int)*range); range++)
up = up * 10 + *range - '0'; up = up * 10 + *range - '0';
else if (*range == '-') else if (*range == '-')
up = wl_length(wl); up = wl_length(wl);

View File

@ -22,11 +22,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
#include "ngspice/dstring.h" #include "ngspice/dstring.h"
#include "plotting/plotting.h" #include "plotting/plotting.h"
#ifdef XSPICE
/* gtri - begin - add function prototype for EVTfindvec */
struct dvec *EVTfindvec(char *node); struct dvec *EVTfindvec(char *node);
/* gtri - end - add function prototype for EVTfindvec */
#endif
static void static void
@ -180,14 +176,9 @@ findvec(char *word, struct plot *pl)
spice_dstring_free(&dbuf); spice_dstring_free(&dbuf);
#ifdef XSPICE
/* gtri - begin - Add processing for getting event-driven vector */
if (!d) if (!d)
d = EVTfindvec(word); d = EVTfindvec(word);
/* gtri - end - Add processing for getting event-driven vector */
#endif
if (d && d->v_link2) { if (d && d->v_link2) {
d = vec_copy(d); d = vec_copy(d);
vec_new(d); vec_new(d);
@ -209,18 +200,18 @@ namecmp(const void *a, const void *b)
const char *t = (const char *) b; const char *t = (const char *) b;
for (;;) { for (;;) {
while ((*s == *t) && !isdigit(*s) && *s) while ((*s == *t) && !isdigit((int)*s) && *s)
s++, t++; s++, t++;
if (!*s) if (!*s)
return (0); return (0);
if ((*s != *t) && (!isdigit(*s) || !isdigit(*t))) if ((*s != *t) && (!isdigit((int)*s) || !isdigit((int)*t)))
return (*s - *t); return (*s - *t);
/* The beginning of a number... Grab the two numbers and then /* The beginning of a number... Grab the two numbers and then
* compare them... */ * compare them... */
for (i = 0; isdigit(*s); s++) for (i = 0; isdigit((int)*s); s++)
i = i * 10 + *s - '0'; i = i * 10 + *s - '0';
for (j = 0; isdigit(*t); t++) for (j = 0; isdigit((int)*t); t++)
j = j * 10 + *t - '0'; j = j * 10 + *t - '0';
if (i != j) if (i != j)
@ -383,11 +374,11 @@ vec_fromplot(char *word, struct plot *plot)
} }
/* scanf("%c(%s)" doesn't do what it should do. ) */ /* scanf("%c(%s)" doesn't do what it should do. ) */
if (!d && (sscanf(word, "%c(%s", &cc, buf) == 2) && if (!d && (sscanf(word, "%c(%s", /* ) */ &cc, buf) == 2) &&
((s = strrchr(buf, ')')) != NULL) && /* ( */ ((s = strrchr(buf, ')')) != NULL) &&
(s[1] == '\0')) { (s[1] == '\0')) {
*s = '\0'; *s = '\0';
if (prefix("i(", word) || prefix("I(", word)) { if (prefix("i(", /* ) */ word) || prefix("I(", /* ) */ word)) {
/* Spice dependency... */ /* Spice dependency... */
(void) sprintf(buf2, "%s#branch", buf); (void) sprintf(buf2, "%s#branch", buf);
(void) strcpy(buf, buf2); (void) strcpy(buf, buf2);
@ -422,9 +413,23 @@ vec_get(const char *vec_name)
char buf[BSIZE_SP], *s, *wd, *word, *whole, *name = NULL, *param; char buf[BSIZE_SP], *s, *wd, *word, *whole, *name = NULL, *param;
int i = 0; int i = 0;
struct variable *vv; struct variable *vv;
int indexvar; /* mhx */
wd = word = copy(vec_name); /* Gets mangled below... */ wd = word = copy(vec_name); /* Gets mangled below... */
if (*word != SPECCHAR) { /* mhx: eventually replace atoi() by full evaluate */
char *ps = strchr(wd, '['), *pe = strchr(wd, ']');
if (ps && pe && pe > ps) {
whole = copy(word);
*ps = '\0';
*pe = '\0';
indexvar = atoi(++ps);
} else {
whole = NULL;
indexvar = -1;
}
}
if (strchr(word, '.')) { if (strchr(word, '.')) {
/* Snag the plot... */ /* Snag the plot... */
for (i = 0, s = word; *s != '.'; i++, s++) for (i = 0, s = word; *s != '.'; i++, s++)
@ -470,18 +475,34 @@ vec_get(const char *vec_name)
d = newv; d = newv;
if (!d) { if (!d) {
fprintf(cp_err, fprintf(cp_err,
"Error: plot wildcard (name %s) matches nothing\n", "ERROR: plot wildcard (name %s) matches nothing\n",
word); word);
tfree(wd); /* MW. I don't want core leaks here */ tfree(wd);
return (NULL); return (NULL);
} }
} }
/* In case of data[ix] we must return a SINGLE value
(vector of length 1) instead of the vector.
Duplicates a lot of code that still follows :-( */
if (d && indexvar != -1) {
struct dvec *ad;
ad = alloc(struct dvec);
ZERO(ad, struct dvec);
ad->v_name = copy(whole); /* so the name could be data[2] or data[expression] :-) */
ad->v_type = d->v_type;
ad->v_flags = d->v_flags; /* VF_REAL; or complex? */
ad->v_length = 1;
ad->v_realdata = TMALLOC(double, 1);
*ad->v_realdata = *d->v_realdata;
tfree(whole);
}
if (!d && (*word == SPECCHAR)) { if (!d && (*word == SPECCHAR)) {
/* This is a special quantity... */ /* This is a special quantity... */
if (ft_nutmeg) { if (ft_nutmeg) {
fprintf(cp_err, fprintf(cp_err,
"Error: circuit parameters only available with spice\n"); "ERROR: circuit parameters only available with spice\n");
tfree(wd); /* MW. Memory leak fixed again */ tfree(wd); /* MW. Memory leak fixed again */
return (NULL); /* va: use NULL */ return (NULL); /* va: use NULL */
} }
@ -516,16 +537,19 @@ vec_get(const char *vec_name)
return (NULL); return (NULL);
} }
} else { } else {
fprintf(cp_err, "Error: No circuit loaded.\n"); fprintf(cp_err, "ERROR: No circuit loaded.\n");
tfree(whole); tfree(whole);
tfree(wd); tfree(wd);
return (NULL); return (NULL);
} }
d = dvec_alloc(copy(whole), /* MW. The same as word before */ d = alloc(struct dvec);
SV_NOTYPE, ZERO(d, struct dvec);
VF_REAL, /* No complex values yet... */ d->v_name = copy(whole); /* MW. The same as word before */
1, NULL); d->v_type = SV_NOTYPE;
d->v_flags |= VF_REAL; /* No complex values yet... */
d->v_realdata = TMALLOC(double, 1);
d->v_length = 1;
/* In case the represented variable is a REAL vector this takes /* In case the represented variable is a REAL vector this takes
* the actual value of the first element of the linked list which * the actual value of the first element of the linked list which
@ -538,8 +562,8 @@ vec_get(const char *vec_name)
* defined as IF_INTEGER are not given their value when using * defined as IF_INTEGER are not given their value when using
* print @pot[pos_node] * print @pot[pos_node]
* To fix this, it is necessary to define: * To fix this, it is necessary to define:
* OPU( "pos_node", POT_QUEST_POS_NODE, IF_REAL,"Positive node of potenciometer"), * OPU( "pos_node", POT_QUEST_POS_NODE, IF_REAL,"Positive node of potentiometer"),
* int POTnegNode; // number of negative node of potenciometer (Nodo_3) * int POTnegNode; // number of negative node of potentiometer (Node_3)
* case POT_QUEST_POS_NODE: * case POT_QUEST_POS_NODE:
* value->rValue = (double)fast->POTposNode; * value->rValue = (double)fast->POTposNode;
* return (OK); * return (OK);
@ -562,7 +586,7 @@ vec_get(const char *vec_name)
* CP_REAL, * CP_REAL,
* CP_STRING, * CP_STRING,
* CP_LIST * CP_LIST
° }; * };
*/ */
/* The variable is a vector */ /* The variable is a vector */
@ -572,16 +596,20 @@ vec_get(const char *vec_name)
*/ */
struct variable *nv; struct variable *nv;
i = 0; double *list;
for (nv = vv->va_vlist; nv; nv = nv->va_next) list = TMALLOC(double, 1);
i++; nv = alloc(struct variable);
dvec_realloc(d, i, NULL);
i = 0;
for (nv = vv->va_vlist; nv; nv = nv->va_next)
d->v_realdata[i++] = nv->va_real;
nv = vv->va_vlist;
for (i = 1; ; i++) {
list = TREALLOC(double, list, i);
list[i-1] = nv->va_real;
nv = nv->va_next;
if (!nv)
break;
}
d->v_realdata = list;
d->v_length = i;
/* To be able to identify the vector to represent /* To be able to identify the vector to represent
* belongs to a special "conunto" and should be printed in a * belongs to a special "conunto" and should be printed in a
* special way. * special way.
@ -681,22 +709,28 @@ vec_copy(struct dvec *v)
if (!v) if (!v)
return (NULL); return (NULL);
nv = dvec_alloc(copy(v->v_name), nv = alloc(struct dvec);
v->v_type, nv->v_name = copy(v->v_name);
v->v_flags & ~VF_PERMANENT, nv->v_type = v->v_type;
v->v_length, NULL); nv->v_flags = v->v_flags & ~VF_PERMANENT;
if (isreal(v)) if (isreal(v)) {
nv->v_realdata = TMALLOC(double, v->v_length);
bcopy(v->v_realdata, nv->v_realdata, bcopy(v->v_realdata, nv->v_realdata,
sizeof(double) * (size_t) v->v_length); sizeof(double) * (size_t) v->v_length);
else nv->v_compdata = NULL;
} else {
nv->v_realdata = NULL;
nv->v_compdata = TMALLOC(ngcomplex_t, v->v_length);
bcopy(v->v_compdata, nv->v_compdata, bcopy(v->v_compdata, nv->v_compdata,
sizeof(ngcomplex_t) * (size_t) v->v_length); sizeof(ngcomplex_t) * (size_t) v->v_length);
}
nv->v_minsignal = v->v_minsignal; nv->v_minsignal = v->v_minsignal;
nv->v_maxsignal = v->v_maxsignal; nv->v_maxsignal = v->v_maxsignal;
nv->v_gridtype = v->v_gridtype; nv->v_gridtype = v->v_gridtype;
nv->v_plottype = v->v_plottype; nv->v_plottype = v->v_plottype;
nv->v_length = v->v_length;
/* Modified to copy the rlength of origin to destination vecor /* Modified to copy the rlength of origin to destination vecor
* instead of always putting it to 0. * instead of always putting it to 0.
@ -764,13 +798,10 @@ plot_alloc(char *name)
void void
vec_new(struct dvec *d) vec_new(struct dvec *d)
{ {
#ifdef FTEDEBUG
if (ft_vecdb)
fprintf(cp_err, "new vector %s\n", d->v_name);
#endif
/* Note that this can't happen. */ /* Note that this can't happen. */
if (plot_cur == NULL) { if (plot_cur == NULL) {
fprintf(cp_err, "vec_new: Internal Error: no cur plot\n"); fprintf(cp_err, "vec_new: INTERNAL ERROR: no cur plot\n");
controlled_exit(1);
} }
plot_cur->pl_lookup_valid = FALSE; plot_cur->pl_lookup_valid = FALSE;
if ((d->v_flags & VF_PERMANENT) && (plot_cur->pl_scale == NULL)) if ((d->v_flags & VF_PERMANENT) && (plot_cur->pl_scale == NULL))
@ -849,7 +880,7 @@ vec_free_x(struct dvec *v)
lv->v_next = v->v_next; lv->v_next = v->v_next;
else else
fprintf(cp_err, fprintf(cp_err,
"vec_free: Internal Error: %s not in plot\n", "vec_free: INTERNAL ERROR: %s not in plot\n",
v->v_name); v->v_name);
} }
if (pl->pl_scale == v) { if (pl->pl_scale == v) {
@ -860,7 +891,13 @@ vec_free_x(struct dvec *v)
} }
} }
dvec_free(v); if (v->v_name)
tfree(v->v_name);
if (v->v_realdata)
tfree(v->v_realdata);
if (v->v_compdata)
tfree(v->v_compdata);
tfree(v);
} }
@ -868,7 +905,7 @@ vec_free_x(struct dvec *v)
* return TRUE if every vector element is zero * return TRUE if every vector element is zero
*/ */
bool BOOL
vec_iszero(struct dvec *v) vec_iszero(struct dvec *v)
{ {
int i; int i;
@ -937,12 +974,12 @@ vec_basename(struct dvec *v)
} }
strtolower(buf); strtolower(buf);
for (t = buf; isspace(*t); t++) for (t = buf; isspace((int)*t); t++)
; ;
s = t; s = t;
for (t = s; *t; t++) for (t = s; *t; t++)
; ;
while ((t > s) && isspace(t[-1])) while ((t > s) && isspace((int)t[-1]))
*--t = '\0'; *--t = '\0';
return (copy(s)); return (copy(s));
} }
@ -972,7 +1009,7 @@ plot_setcur(char *name)
if (plot_prefix(name, pl->pl_typename)) if (plot_prefix(name, pl->pl_typename))
break; break;
if (!pl) { if (!pl) {
fprintf(cp_err, "Error: no such plot named %s\n", name); fprintf(cp_err, "ERROR: no such plot named %s\n", name);
return; return;
} }
/* va: we skip cp_kwswitch, because it confuses the keyword-tree management for /* va: we skip cp_kwswitch, because it confuses the keyword-tree management for
@ -1053,7 +1090,8 @@ vec_transpose(struct dvec *v)
} }
koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */ koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */
} }
dvec_realloc(v, v->v_length, newreal); tfree(oldreal);
v->v_realdata = newreal;
} else { } else {
newcomp = TMALLOC(ngcomplex_t, v->v_length); newcomp = TMALLOC(ngcomplex_t, v->v_length);
oldcomp = v->v_compdata; oldcomp = v->v_compdata;
@ -1062,14 +1100,17 @@ vec_transpose(struct dvec *v)
joffset = 0; joffset = 0;
for (j = 0; j < dim0; j++) { for (j = 0; j < dim0; j++) {
for (i = 0; i < dim1; i++) { for (i = 0; i < dim1; i++) {
newcomp[ koffset + joffset + i ] = realpart(newcomp[ koffset + joffset + i ]) =
oldcomp[ koffset + i*dim0 + j ]; realpart(oldcomp[ koffset + i*dim0 + j ]);
imagpart(newcomp[ koffset + joffset + i ]) =
imagpart(oldcomp[ koffset + i*dim0 + j ]);
} }
joffset += dim1; /* joffset = j*dim0 */ joffset += dim1; /* joffset = j*dim0 */
} }
koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */ koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */
} }
dvec_realloc(v, v->v_length, newcomp); tfree(oldcomp);
v->v_compdata = newcomp;
} }
} }
@ -1082,9 +1123,9 @@ vec_transpose(struct dvec *v)
struct dvec * struct dvec *
vec_mkfamily(struct dvec *v) vec_mkfamily(struct dvec *v)
{ {
int size, numvecs, i, count[MAXDIMS]; int size, numvecs, i, j, count[MAXDIMS];
struct dvec *vecs, *d, **t; struct dvec *vecs, *d;
char buf2[BSIZE_SP]; char buf[BSIZE_SP], buf2[BSIZE_SP];
if (v->v_numdims < 2) if (v->v_numdims < 2)
return (v); return (v);
@ -1092,16 +1133,25 @@ vec_mkfamily(struct dvec *v)
size = v->v_dims[v->v_numdims - 1]; size = v->v_dims[v->v_numdims - 1];
for (i = 0, numvecs = 1; i < v->v_numdims - 1; i++) for (i = 0, numvecs = 1; i < v->v_numdims - 1; i++)
numvecs *= v->v_dims[i]; numvecs *= v->v_dims[i];
for (i = 0, vecs = d = NULL; i < numvecs; i++) {
if (vecs) {
d = d->v_link2 = alloc(struct dvec);
ZERO(d, struct dvec);
} else {
d = vecs = alloc(struct dvec);
ZERO(d, struct dvec);
}
}
for (i = 0; i < MAXDIMS; i++) for (i = 0; i < MAXDIMS; i++)
count[i] = 0; count[i] = 0;
for (t = &vecs, i = 0; i < numvecs; i++) { for (d = vecs, j = 0; d; j++, d = d->v_link2) {
indexstring(count, v->v_numdims - 1, buf2); indexstring(count, v->v_numdims - 1, buf2);
d = dvec_alloc(tprintf("%s%s", v->v_name, buf2), (void) sprintf(buf, "%s%s", v->v_name, buf2);
v->v_type, d->v_name = copy(buf);
v->v_flags, d->v_type = v->v_type;
size, NULL); d->v_flags = v->v_flags;
d->v_minsignal = v->v_minsignal; d->v_minsignal = v->v_minsignal;
d->v_maxsignal = v->v_maxsignal; d->v_maxsignal = v->v_maxsignal;
@ -1112,18 +1162,17 @@ vec_mkfamily(struct dvec *v)
* of these things... * of these things...
*/ */
d->v_numdims = 1; d->v_numdims = 1;
d->v_dims[0] = size; d->v_length = size;
if (isreal(v)) { if (isreal(v)) {
bcopy(v->v_realdata + size*i, d->v_realdata, (size_t) size * sizeof(double)); d->v_realdata = TMALLOC(double, size);
bcopy(v->v_realdata + size*j, d->v_realdata, (size_t) size * sizeof(double));
} else { } else {
bcopy(v->v_compdata + size*i, d->v_compdata, (size_t) size * sizeof(ngcomplex_t)); d->v_compdata = TMALLOC(ngcomplex_t, size);
bcopy(v->v_compdata + size*j, d->v_compdata, (size_t) size * sizeof(ngcomplex_t));
} }
/* Add one to the counter. */ /* Add one to the counter. */
(void) incindex(count, v->v_numdims - 1, v->v_dims, v->v_numdims); (void) incindex(count, v->v_numdims - 1, v->v_dims, v->v_numdims);
*t = d;
t = &(d->v_link2);
} }
for (d = vecs; d; d = d->v_link2) for (d = vecs; d; d = d->v_link2)
@ -1148,7 +1197,7 @@ plot_prefix(char *pre, char *str)
str++; str++;
} }
if (*pre || (*str && isdigit(pre[-1]))) if (*pre || (*str && isdigit((int)pre[-1])))
return (FALSE); return (FALSE);
else else
return (TRUE); return (TRUE);