Made ft_numparse() thread-safe (no internal static variables) and prepared to support ngspice variable type CP_NUM.
This commit is contained in:
parent
0ad9565ba7
commit
e6c14b3eb0
|
|
@ -46,7 +46,6 @@ com_stop(wordlist *wl)
|
|||
struct dbcomm *d = NULL;
|
||||
char *s, buf[64];
|
||||
int i;
|
||||
double *val;
|
||||
|
||||
while (wl) {
|
||||
if (thisone == NULL) {
|
||||
|
|
@ -80,10 +79,9 @@ com_stop(wordlist *wl)
|
|||
/* cp_lexer(string) will not discriminate '=', so we have
|
||||
to do it here */
|
||||
if (strchr(wl->wl_next->wl_word, '=') &&
|
||||
(!(wl->wl_next->wl_next) ||
|
||||
strstr(wl->wl_next->wl_next->wl_word, "when") ||
|
||||
strstr(wl->wl_next->wl_next->wl_word, "after")))
|
||||
{
|
||||
(!(wl->wl_next->wl_next) ||
|
||||
strstr(wl->wl_next->wl_next->wl_word, "when") ||
|
||||
strstr(wl->wl_next->wl_next->wl_word, "after"))) {
|
||||
/* we have vec=val in a single word */
|
||||
wordlist *wln;
|
||||
char **charr = TMALLOC(char*, 4);
|
||||
|
|
@ -98,17 +96,23 @@ com_stop(wordlist *wl)
|
|||
wln = wl_build((const char * const *) charr);
|
||||
wl_splice(wl->wl_next, wln);
|
||||
}
|
||||
|
||||
/* continue with parsing the enhanced wordlist */
|
||||
if (wl->wl_next->wl_next && wl->wl_next->wl_next->wl_next) {
|
||||
wl = wl->wl_next;
|
||||
d->db_number = debugnumber;
|
||||
d->db_type = DB_STOPWHEN;
|
||||
s = wl->wl_word;
|
||||
val = ft_numparse(&s, FALSE);
|
||||
if (val)
|
||||
d->db_value1 = *val;
|
||||
else
|
||||
d->db_nodename1 = copy(wl->wl_word);
|
||||
|
||||
{
|
||||
double val;
|
||||
if (ft_numparse(&s, FALSE, &val) >= 0) {
|
||||
d->db_value1 = val;
|
||||
}
|
||||
else {
|
||||
d->db_nodename1 = copy(wl->wl_word);
|
||||
}
|
||||
}
|
||||
wl = wl->wl_next;
|
||||
|
||||
/* Now get the condition */
|
||||
|
|
@ -130,17 +134,23 @@ com_stop(wordlist *wl)
|
|||
|
||||
/* Now see about the second one. */
|
||||
s = wl->wl_word;
|
||||
val = ft_numparse(&s, FALSE);
|
||||
if (val)
|
||||
d->db_value2 = *val;
|
||||
else
|
||||
|
||||
{
|
||||
double val;
|
||||
if (ft_numparse(&s, FALSE, &val) >= 0) {
|
||||
d->db_value2 = val;
|
||||
}
|
||||
else {
|
||||
d->db_nodename2 = copy(wl->wl_word);
|
||||
}
|
||||
}
|
||||
wl = wl->wl_next;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end of case of word "when" */
|
||||
} /* end of loop over wordlist */
|
||||
|
||||
if (thisone) {
|
||||
if (dbs) {
|
||||
|
|
@ -159,11 +169,11 @@ com_stop(wordlist *wl)
|
|||
|
||||
bad:
|
||||
fprintf(cp_err, "Syntax error parsing breakpoint specification.\n");
|
||||
}
|
||||
} /* end of funtion com_stop */
|
||||
|
||||
|
||||
|
||||
/* Trace a node (have wrd_point print it). Usage is "trace node ..."*/
|
||||
|
||||
void
|
||||
com_trce(wordlist *wl)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* The 'compose' command. This is a more powerful and convenient form
|
||||
* of the 'let' command. */
|
||||
#include <math.h> /* log10 */
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/complex.h"
|
||||
#include "ngspice/dvec.h"
|
||||
|
|
@ -14,7 +16,6 @@
|
|||
#include "com_compose.h"
|
||||
#include "completion.h"
|
||||
|
||||
#include <math.h> /* log10 */
|
||||
|
||||
/* Copy the data from a vector into a buffer with larger dimensions. */
|
||||
static void
|
||||
|
|
@ -103,8 +104,7 @@ com_compose(wordlist *wl)
|
|||
int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0;
|
||||
int i;
|
||||
|
||||
char *s, *var, *val;
|
||||
double *td, tt;
|
||||
double tt;
|
||||
double *data = NULL;
|
||||
ngcomplex_t *cdata = NULL;
|
||||
int length = 0;
|
||||
|
|
@ -227,9 +227,11 @@ com_compose(wordlist *wl)
|
|||
}
|
||||
|
||||
length *= blocksize;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* Parse the line... */
|
||||
while (wl) {
|
||||
char *s, *var, *val;
|
||||
if ((s = strchr(wl->wl_word, '=')) != NULL && s[1]) {
|
||||
/* This is var=val. */
|
||||
*s = '\0';
|
||||
|
|
@ -278,109 +280,124 @@ com_compose(wordlist *wl)
|
|||
}
|
||||
if (cieq(var, "start")) {
|
||||
startgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &start) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
start = *td;
|
||||
} else if (cieq(var, "stop")) {
|
||||
}
|
||||
else if (cieq(var, "stop")) {
|
||||
stopgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &stop) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
stop = *td;
|
||||
} else if (cieq(var, "step")) {
|
||||
}
|
||||
else if (cieq(var, "step")) {
|
||||
stepgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &step) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
step = *td;
|
||||
} else if (cieq(var, "center")) {
|
||||
}
|
||||
else if (cieq(var, "center")) {
|
||||
centergiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, ¢er) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
center = *td;
|
||||
} else if (cieq(var, "span")) {
|
||||
}
|
||||
else if (cieq(var, "span")) {
|
||||
spangiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &span) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
span = *td;
|
||||
} else if (cieq(var, "mean")) {
|
||||
}
|
||||
else if (cieq(var, "mean")) {
|
||||
meangiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &mean) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
mean = *td;
|
||||
} else if (cieq(var, "sd")) {
|
||||
}
|
||||
else if (cieq(var, "sd")) {
|
||||
sdgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &sd) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
sd = *td;
|
||||
} else if (cieq(var, "lin")) {
|
||||
}
|
||||
else if (cieq(var, "lin")) {
|
||||
lingiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &lin) < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
lin = *td;
|
||||
} else if (cieq(var, "log")) {
|
||||
}
|
||||
else if (cieq(var, "log")) {
|
||||
double dbl_val;
|
||||
loggiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &dbl_val) <= 0) {
|
||||
/* Cannot convert value to int */
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
log = (int)(*td);
|
||||
} else if (cieq(var, "dec")) {
|
||||
log = (int) dbl_val;
|
||||
}
|
||||
else if (cieq(var, "dec")) {
|
||||
double dbl_val;
|
||||
decgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &dbl_val) <= 0) {
|
||||
/* Cannot convert value to int */
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
dec = (int)(*td);
|
||||
} else if (cieq(var, "oct")) {
|
||||
dec = (int) dbl_val;
|
||||
}
|
||||
else if (cieq(var, "oct")) {
|
||||
double dbl_val;
|
||||
octgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &dbl_val) <= 0) {
|
||||
/* Cannot convert value to integer */
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
oct = (int)(*td);
|
||||
} else if (cieq(var, "gauss")) {
|
||||
oct = (int) dbl_val;
|
||||
}
|
||||
else if (cieq(var, "gauss")) {
|
||||
double dbl_val;
|
||||
gaussgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &dbl_val) <= 0) {
|
||||
/* Cannot convert value to int */
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
gauss = (int)(*td);
|
||||
} else if (cieq(var, "unif")) {
|
||||
gauss = (int) dbl_val;
|
||||
}
|
||||
else if (cieq(var, "unif")) {
|
||||
double dbl_val;
|
||||
unifgiven = TRUE;
|
||||
if ((td = ft_numparse(&val, FALSE)) == NULL) {
|
||||
if (ft_numparse(&val, FALSE, &dbl_val)<= 0) {
|
||||
/* cannot convert to int */
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> bad parm %s = %s\n", var, val);
|
||||
goto done;
|
||||
}
|
||||
unif = (int)(*td);
|
||||
} else {
|
||||
unif = (int) dbl_val;
|
||||
}
|
||||
else {
|
||||
fprintf(cp_err, "Error: compose -> bad parm %s\n", var);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -405,7 +422,8 @@ com_compose(wordlist *wl)
|
|||
fprintf(cp_err,
|
||||
"Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n");
|
||||
goto done;
|
||||
} else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) {
|
||||
}
|
||||
else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) {
|
||||
/* Hmm, if we have a start, stop, and step we're ok. */
|
||||
if (startgiven && stopgiven && stepgiven) {
|
||||
lingiven = TRUE;
|
||||
|
|
@ -415,7 +433,8 @@ com_compose(wordlist *wl)
|
|||
}
|
||||
lin = (stop - start) / step + 1.;
|
||||
stepgiven = FALSE; /* Problems below... */
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
fprintf(cp_err,
|
||||
"Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n");
|
||||
fprintf(cp_err,
|
||||
|
|
@ -463,10 +482,12 @@ com_compose(wordlist *wl)
|
|||
step = (stop - start) / (lin - 1.0);
|
||||
}
|
||||
|
||||
for (i = 0, tt = start; i < length; i++, tt += step)
|
||||
for (i = 0, tt = start; i < length; i++, tt += step) {
|
||||
data[i] = tt;
|
||||
}
|
||||
|
||||
} else if (loggiven || decgiven || octgiven) {
|
||||
}
|
||||
else if (loggiven || decgiven || octgiven) {
|
||||
/* Create a log sweep... */
|
||||
if (centergiven && spangiven) {
|
||||
if (center <= span/2.0) {
|
||||
|
|
@ -505,7 +526,8 @@ com_compose(wordlist *wl)
|
|||
for (i = 0; i < length; i++)
|
||||
data[i] = start * pow(stop/start, (double)i/(log-1.0));
|
||||
|
||||
} else if (unifgiven) {
|
||||
}
|
||||
else if (unifgiven) {
|
||||
/* Create a set of uniform distributed values... */
|
||||
if (startgiven || stopgiven) {
|
||||
if (!startgiven || !stopgiven) {
|
||||
|
|
@ -541,7 +563,8 @@ com_compose(wordlist *wl)
|
|||
for (i = 0; i < length; i++)
|
||||
data[i] = mean + span * 0.5 * drand();
|
||||
|
||||
} else if (gaussgiven) {
|
||||
}
|
||||
else if (gaussgiven) {
|
||||
/* Create a gaussian distribution... */
|
||||
if (gauss <= 0) {
|
||||
fprintf(cp_err,
|
||||
|
|
@ -558,8 +581,9 @@ com_compose(wordlist *wl)
|
|||
}
|
||||
length = gauss;
|
||||
data = TMALLOC(double, length);
|
||||
for (i = 0; i < length; i++)
|
||||
for (i = 0; i < length; i++) {
|
||||
data[i] = mean + sd * gauss1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -589,5 +613,5 @@ com_compose(wordlist *wl)
|
|||
|
||||
done:
|
||||
free_pnode(names);
|
||||
tfree(resname);
|
||||
}
|
||||
txfree(resname);
|
||||
} /* end of function com_compose */
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ com_psd(wordlist *wl)
|
|||
{
|
||||
ngcomplex_t **fdvec = NULL;
|
||||
double **tdvec = NULL;
|
||||
double *freq, *win = NULL, *time, *ave;
|
||||
double *freq, *win = NULL, *time;
|
||||
double span, noipower;
|
||||
int ngood, fpts, i, j, jj, length, smooth, hsmooth;
|
||||
char *s;
|
||||
|
|
@ -278,12 +278,15 @@ com_psd(wordlist *wl)
|
|||
|
||||
// get filter length from parameter input
|
||||
s = wl->wl_word;
|
||||
ave = ft_numparse(&s, FALSE);
|
||||
if (!ave || (*ave < 1.0)) {
|
||||
fprintf(cp_out, "Number of averaged data points: %d\n", 1);
|
||||
smooth = 1;
|
||||
} else {
|
||||
smooth = (int)(*ave);
|
||||
{
|
||||
double val;
|
||||
if (ft_numparse(&s, FALSE, &val) <= 0 || val < 1.0) {
|
||||
fprintf(cp_out, "Number of averaged data points: 1\n");
|
||||
smooth = 1;
|
||||
}
|
||||
else {
|
||||
smooth = (int) val;
|
||||
}
|
||||
}
|
||||
|
||||
wl = wl->wl_next;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ typedef enum {
|
|||
MEASUREMENT_FAILURE = 1
|
||||
} MEASURE_VAL_T;
|
||||
|
||||
#define MEASURE_DEFAULT -1
|
||||
#define MEASURE_LAST_TRANSITION -2
|
||||
#define MEASURE_DEFAULT (-1)
|
||||
#define MEASURE_LAST_TRANSITION (-2)
|
||||
|
||||
typedef struct measure
|
||||
{
|
||||
|
|
@ -1152,7 +1152,7 @@ measure_parse_stdParams(
|
|||
{
|
||||
int pCnt;
|
||||
char *p, *pName, *pValue;
|
||||
double *engVal, engVal1;
|
||||
double engVal1;
|
||||
|
||||
pCnt = 0;
|
||||
while (wl != wlBreak) {
|
||||
|
|
@ -1176,12 +1176,12 @@ measure_parse_stdParams(
|
|||
|
||||
if (strcasecmp(pValue, "LAST") == 0) {
|
||||
engVal1 = MEASURE_LAST_TRANSITION;
|
||||
} else {
|
||||
if ((engVal = ft_numparse(&pValue, FALSE)) == NULL) {
|
||||
}
|
||||
else {
|
||||
if (ft_numparse(&pValue, FALSE, &engVal1) < 0) {
|
||||
sprintf(errbuf, "bad syntax of ??\n");
|
||||
return 0;
|
||||
}
|
||||
engVal1 = *engVal; // What is this ??
|
||||
}
|
||||
|
||||
if (strcasecmp(pName, "RISE") == 0) {
|
||||
|
|
@ -1257,8 +1257,6 @@ measure_parse_find(
|
|||
)
|
||||
{
|
||||
int pCnt;
|
||||
char *p, *pName, *pVal;
|
||||
double *engVal, engVal1;
|
||||
|
||||
meas->m_vec = NULL;
|
||||
meas->m_vec2 = NULL;
|
||||
|
|
@ -1280,7 +1278,7 @@ measure_parse_find(
|
|||
|
||||
pCnt = 0;
|
||||
while (wl != wlBreak) {
|
||||
p = wl->wl_word;
|
||||
char *p = wl->wl_word;
|
||||
|
||||
if (pCnt == 0) {
|
||||
meas->m_vec = cp_unquote(wl->wl_word);
|
||||
|
|
@ -1288,8 +1286,8 @@ measure_parse_find(
|
|||
if (cieq("ac", meas->m_analysis) || cieq("sp", meas->m_analysis))
|
||||
correct_vec(meas);
|
||||
} else if (pCnt == 1) {
|
||||
pName = strtok(p, "=");
|
||||
pVal = strtok(NULL, "=");
|
||||
char * const pName = strtok(p, "=");
|
||||
char * const pVal = strtok(NULL, "=");
|
||||
|
||||
if (pVal == NULL) {
|
||||
sprintf(errbuf, "bad syntax of WHEN\n");
|
||||
|
|
@ -1297,16 +1295,12 @@ measure_parse_find(
|
|||
}
|
||||
|
||||
if (strcasecmp(pName, "AT") == 0) {
|
||||
if ((engVal = ft_numparse(&pVal, FALSE)) == NULL) {
|
||||
if (ft_numparse((char **) &pVal, FALSE, &meas->m_at) < 0) {
|
||||
sprintf(errbuf, "bad syntax of WHEN\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
engVal1 = *engVal;
|
||||
|
||||
meas->m_at = engVal1;
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sprintf(errbuf, "bad syntax of WHEN\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ static void cp_free_control(void); /* needed by resetcontrol */
|
|||
* more clever. */
|
||||
|
||||
bool cp_cwait = FALSE;
|
||||
char *cp_csep = ";";
|
||||
char *cp_csep = ";"; /* character that separates commands */
|
||||
|
||||
bool cp_dounixcom = FALSE;
|
||||
|
||||
/* We have to keep the control structures in a stack, so that when we
|
||||
* do a 'source', we can push a fresh set onto the top... Actually
|
||||
* there have to be two stacks -- one for the pointer to the list of
|
||||
* there has to be two stacks -- one for the pointer to the list of
|
||||
* control structs, and one for the 'current command' pointer... */
|
||||
struct control *control[CONTROLSTACKSIZE];
|
||||
struct control *cend[CONTROLSTACKSIZE];
|
||||
|
|
@ -62,12 +62,13 @@ int stackp = 0;
|
|||
static char *noredirect[] = { "stop", "define", NULL };
|
||||
|
||||
|
||||
static struct control *
|
||||
findlabel(char *s, struct control *ct)
|
||||
/* This function returns the (first) structure wit the label s */
|
||||
static struct control *findlabel(const char *s, struct control *ct)
|
||||
{
|
||||
while (ct) {
|
||||
if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word))
|
||||
if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word)) {
|
||||
break;
|
||||
}
|
||||
ct = ct->co_next;
|
||||
}
|
||||
return (ct);
|
||||
|
|
@ -116,7 +117,7 @@ ctl_free(struct control *ctrl)
|
|||
|
||||
wl_free(ctrl->co_cond);
|
||||
ctrl->co_cond = NULL;
|
||||
tfree(ctrl->co_foreachvar);
|
||||
txfree(ctrl->co_foreachvar);
|
||||
ctrl->co_foreachvar = NULL;
|
||||
wl_free(ctrl->co_text);
|
||||
ctrl->co_text = NULL;
|
||||
|
|
@ -288,8 +289,9 @@ doblock(struct control *bl, int *num)
|
|||
switch (bl->co_type) {
|
||||
case CO_WHILE:
|
||||
if (!bl->co_children) {
|
||||
fprintf(cp_err, "Warning: Executing empty 'while' block.\n");
|
||||
fprintf(cp_err, " (Use a label statement as a no-op to suppress this warning.)\n");
|
||||
fprintf(cp_err, "Warning: Executing empty 'while' block.\n"
|
||||
" (Use a label statement as a no-op "
|
||||
"to suppress this warning.)\n");
|
||||
}
|
||||
while (bl->co_cond && cp_istrue(bl->co_cond)) {
|
||||
if (!bl->co_children) cp_periodic(); /*CDHW*/
|
||||
|
|
@ -558,11 +560,11 @@ doblock(struct control *bl, int *num)
|
|||
char *
|
||||
get_alt_prompt(void)
|
||||
{
|
||||
int i = 0, j;
|
||||
int i = 0;
|
||||
static char buf[MAX_CHEVRONS + 2]; /* includes terminating space & null */
|
||||
struct control *c;
|
||||
|
||||
/* if nothing on the command stack return NULL */
|
||||
/* If nothing on the command stack return NULL */
|
||||
if (cend[stackp] == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -570,8 +572,9 @@ get_alt_prompt(void)
|
|||
for (c = cend[stackp]->co_parent; c; c = c->co_parent)
|
||||
i++;
|
||||
|
||||
if (i <= 0)
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Avoid overflow of buffer and
|
||||
indicate when we've limited the chevrons by starting with a '+' */
|
||||
|
|
@ -583,15 +586,19 @@ get_alt_prompt(void)
|
|||
}
|
||||
|
||||
/* return one chevron per command stack depth */
|
||||
for (j = 1; j < i; j++)
|
||||
buf[j] = '>';
|
||||
{
|
||||
int j;
|
||||
for (j = 1; j < i; j++)
|
||||
buf[j] = '>';
|
||||
|
||||
/* Add space and terminate */
|
||||
buf[j] = ' ';
|
||||
buf[j + 1] = '\0';
|
||||
/* Add space and terminate */
|
||||
buf[j] = ' ';
|
||||
buf[j + 1] = '\0';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
} /* end of function get_alt_prompt */
|
||||
|
||||
|
||||
|
||||
/* Get a command. This does all the bookkeeping things like turning
|
||||
|
|
@ -601,8 +608,9 @@ getcommand(char *string)
|
|||
{
|
||||
wordlist *wlist;
|
||||
|
||||
if (cp_debug)
|
||||
if (cp_debug) {
|
||||
fprintf(cp_err, "calling getcommand %s\n", string ? string : "");
|
||||
}
|
||||
|
||||
#if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE)
|
||||
/* set cp_altprompt for use by the lexer - see parser/lexical.c */
|
||||
|
|
@ -617,7 +625,7 @@ getcommand(char *string)
|
|||
wl_print(wlist, stdout);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
return (wlist);
|
||||
return wlist;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -628,7 +636,6 @@ cp_evloop(char *string)
|
|||
wordlist *wlist, *ww, *freewl;
|
||||
struct control *x;
|
||||
char *i;
|
||||
int nn;
|
||||
|
||||
#define newblock \
|
||||
do { \
|
||||
|
|
@ -653,8 +660,9 @@ cp_evloop(char *string)
|
|||
/* User just typed return. */
|
||||
wl_free(wlist); /* va, avoid memory leak */
|
||||
if (string) {
|
||||
return (1);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
cp_event--;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -708,22 +716,23 @@ cp_evloop(char *string)
|
|||
cend[stackp]->co_numtimes = -1;
|
||||
} else {
|
||||
char *s;
|
||||
double *dd;
|
||||
double val;
|
||||
|
||||
struct wordlist *t; /*CDHW*/
|
||||
/*CDHW wlist = cp_variablesubst(cp_bquote(cp_doglob(wl_copy(wlist)))); Wrong order? Leak? CDHW*/
|
||||
t = cp_doglob(cp_bquote(cp_variablesubst(wl_copy(wlist)))); /*CDHW leak from cp_doglob? */
|
||||
s = t->wl_next->wl_word;
|
||||
|
||||
dd = ft_numparse(&s, FALSE);
|
||||
if (dd) {
|
||||
if (*dd < 0) {
|
||||
if (ft_numparse(&s, FALSE, &val) > 0) {
|
||||
/* Can be converted to int */
|
||||
if (val < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: can't repeat a negative number of times\n");
|
||||
*dd = 0.0;
|
||||
val = 0.0;
|
||||
}
|
||||
cend[stackp]->co_numtimes = (int) *dd;
|
||||
} else {
|
||||
cend[stackp]->co_numtimes = (int) val;
|
||||
}
|
||||
else {
|
||||
fprintf(cp_err,
|
||||
"Error: bad repeat argument %s\n",
|
||||
t->wl_next->wl_word); /* CDHW */
|
||||
|
|
@ -805,7 +814,7 @@ cp_evloop(char *string)
|
|||
cend[stackp]->co_numtimes = 1;
|
||||
}
|
||||
} else if (eq(wlist->wl_word, "end")) {
|
||||
/* Throw away this thing. */
|
||||
/* Throw away this thing if not in a block. */
|
||||
if (!cend[stackp]->co_parent) {
|
||||
fprintf(stderr, "Error: no block to end.\n");
|
||||
cend[stackp]->co_type = CO_UNFILLED;
|
||||
|
|
@ -824,8 +833,7 @@ cp_evloop(char *string)
|
|||
}
|
||||
} else if (eq(wlist->wl_word, "else")) {
|
||||
if (!cend[stackp]->co_parent ||
|
||||
(cend[stackp]->co_parent->co_type !=
|
||||
CO_IF)) {
|
||||
(cend[stackp]->co_parent->co_type != CO_IF)) {
|
||||
fprintf(stderr, "Error: misplaced else.\n");
|
||||
cend[stackp]->co_type = CO_UNFILLED;
|
||||
} else {
|
||||
|
|
@ -847,7 +855,7 @@ cp_evloop(char *string)
|
|||
* that gotos at the top level will work.
|
||||
*/
|
||||
do {
|
||||
nn = 0; /* CDHW */
|
||||
int nn = 0; /* CDHW */
|
||||
i = doblock(x, &nn);
|
||||
switch (*i) {
|
||||
case NORMAL:
|
||||
|
|
@ -873,8 +881,8 @@ cp_evloop(char *string)
|
|||
wl_free(freewl);
|
||||
if (string)
|
||||
return (1); /* The return value is irrelevant. */
|
||||
}
|
||||
}
|
||||
} /* end of unconditional loop */
|
||||
} /* end of function cp_evloop */
|
||||
|
||||
|
||||
/* This blows away the control structures... */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ Modified: 2000 AlansFixes
|
|||
#include <assert.h>
|
||||
#include "ngspice/cpdefs.h"
|
||||
#include "ngspice/ftedefs.h"
|
||||
#include "ngspice/dstring.h"
|
||||
#include "ngspice/dvec.h"
|
||||
#include "ngspice/fteinp.h"
|
||||
#include "ngspice/sim.h"
|
||||
|
|
@ -200,8 +201,9 @@ ft_cktcoms(bool terse)
|
|||
all.wl_next = NULL;
|
||||
all.wl_word = "all";
|
||||
|
||||
if (!ft_curckt)
|
||||
if (!ft_curckt) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
plot_cur = setcplot("op");
|
||||
if (!ft_curckt->ci_commands && !plot_cur)
|
||||
|
|
@ -249,8 +251,9 @@ ft_cktcoms(bool terse)
|
|||
}
|
||||
fprintf(cp_out, "\n");
|
||||
|
||||
if (!ft_nomod)
|
||||
if (!ft_nomod) {
|
||||
com_showmod(&all);
|
||||
}
|
||||
com_show(&all);
|
||||
}
|
||||
}
|
||||
|
|
@ -271,8 +274,10 @@ ft_cktcoms(bool terse)
|
|||
/* Now all the '.' lines */
|
||||
while (coms) {
|
||||
command = cp_lexer(coms->wl_word);
|
||||
if (!command)
|
||||
if (!command || command->wl_word == (char *) NULL) {
|
||||
/* Line not converted to a wordlist */
|
||||
goto bad;
|
||||
}
|
||||
if (eq(command->wl_word, ".width")) {
|
||||
do
|
||||
command = command->wl_next;
|
||||
|
|
@ -360,12 +365,11 @@ ft_cktcoms(bool terse)
|
|||
!eq(command->wl_word, ".op") &&
|
||||
// !eq(command->wl_word, ".measure") &&
|
||||
!ciprefix(".meas", command->wl_word) &&
|
||||
!eq(command->wl_word, ".tf"))
|
||||
{
|
||||
!eq(command->wl_word, ".tf")) {
|
||||
goto bad;
|
||||
}
|
||||
coms = coms->wl_next;
|
||||
}
|
||||
coms = coms->wl_next; /* go to next line */
|
||||
} /* end of loop over '.' lines */
|
||||
|
||||
nocmds:
|
||||
/* Now the node table
|
||||
|
|
@ -399,7 +403,7 @@ bad:
|
|||
|
||||
|
||||
/* These routines make sure that the arguments to .plot and .print in
|
||||
* spice2 decks are acceptable to spice3. The things we look for are:
|
||||
* spice2 decks are acceptable to spice3. The things we look for are
|
||||
* trailing (a,b) in .plot -> xlimit a b
|
||||
* vm(x) -> mag(v(x))
|
||||
* vp(x) -> ph(v(x))
|
||||
|
|
@ -410,60 +414,70 @@ bad:
|
|||
static void
|
||||
fixdotplot(wordlist *wl)
|
||||
{
|
||||
char *s;
|
||||
char numbuf[128]; /* Printnum Fix */
|
||||
double *d, d1, d2;
|
||||
/* Create a buffer for printing numbers */
|
||||
DS_CREATE(numbuf, 100);
|
||||
|
||||
while (wl) {
|
||||
wl->wl_word = fixem(wl->wl_word);
|
||||
|
||||
/* Is this a trailing (a,b) ? Note that we require it to be
|
||||
* one word.
|
||||
*/
|
||||
/* Is this a trailing "(a,b)"? Note that we require it to be
|
||||
* one word. */
|
||||
if (!wl->wl_next && (*wl->wl_word == '(')) {
|
||||
s = wl->wl_word + 1;
|
||||
d = ft_numparse(&s, FALSE);
|
||||
if (*s != ',') {
|
||||
double d1, d2;
|
||||
char *s = wl->wl_word + 1;
|
||||
if (ft_numparse(&s, FALSE, &d1) < 0 ||
|
||||
*s != ',') {
|
||||
fprintf(cp_err, "Error: bad limits \"%s\"\n",
|
||||
wl->wl_word);
|
||||
return;
|
||||
goto EXITPOINT;
|
||||
}
|
||||
d1 = *d;
|
||||
s++;
|
||||
d = ft_numparse(&s, FALSE);
|
||||
if ((*s != ')') || s[1]) {
|
||||
s++; /* step past comma */
|
||||
if (ft_numparse(&s, FALSE, &d2) < 0 ||
|
||||
*s != ')' || s[1] != '\0') { /* must end with ")" */
|
||||
fprintf(cp_err, "Error: bad limits \"%s\"\n",
|
||||
wl->wl_word);
|
||||
return;
|
||||
goto EXITPOINT;
|
||||
}
|
||||
d2 = *d;
|
||||
|
||||
tfree(wl->wl_word);
|
||||
wl->wl_word = copy("xlimit");
|
||||
printnum(numbuf, d1);
|
||||
wl_append_word(NULL, &wl, copy(numbuf));
|
||||
printnum(numbuf, d2);
|
||||
wl_append_word(NULL, &wl, copy(numbuf));
|
||||
}
|
||||
ds_clear(&numbuf);
|
||||
if (printnum_ds(&numbuf, d1) != 0) {
|
||||
fprintf(cp_err, "Unable to print limit 1: %g\n", d1);
|
||||
goto EXITPOINT;
|
||||
}
|
||||
wl_append_word(NULL, &wl, copy(ds_get_buf(&numbuf)));
|
||||
ds_clear(&numbuf);
|
||||
if (printnum_ds(&numbuf, d2) != 0) {
|
||||
fprintf(cp_err, "Unable to print limit 2: %g\n", d2);
|
||||
goto EXITPOINT;
|
||||
}
|
||||
wl_append_word(NULL, &wl, copy(ds_get_buf(&numbuf)));
|
||||
} /* end of case of start of potential (a,b) */
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
} /* end of loop over words */
|
||||
|
||||
EXITPOINT:
|
||||
ds_free(&numbuf); /* Free DSTRING resources */
|
||||
} /* end of function fixdotplot */
|
||||
|
||||
|
||||
static void
|
||||
fixdotprint(wordlist *wl)
|
||||
|
||||
static void fixdotprint(wordlist *wl)
|
||||
{
|
||||
/* Process each word in the wordlist */
|
||||
while (wl) {
|
||||
wl->wl_word = fixem(wl->wl_word);
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
} /* end of function fixdotprint */
|
||||
|
||||
|
||||
static char *
|
||||
fixem(char *string)
|
||||
|
||||
static char *fixem(char *string)
|
||||
{
|
||||
char buf[BSIZE_SP], *s, *t;
|
||||
char *ss = string; /* Get rid of ss ? */
|
||||
char *ss = string; /* save addr of string in case it is freed */
|
||||
|
||||
if (ciprefix("v(", string) &&strchr(string, ',')) {
|
||||
for (s = string; *s && (*s != ','); s++)
|
||||
|
|
@ -550,14 +564,15 @@ fixem(char *string)
|
|||
string += 2;
|
||||
(void) sprintf(buf, "%s#branch", string);
|
||||
} else {
|
||||
return (string);
|
||||
return string;
|
||||
}
|
||||
|
||||
tfree(ss);
|
||||
txfree(ss);
|
||||
string = copy(buf);
|
||||
|
||||
return (string);
|
||||
}
|
||||
return string;
|
||||
} /* end of function fixem */
|
||||
|
||||
|
||||
|
||||
wordlist *
|
||||
|
|
@ -611,7 +626,8 @@ gettoks(char *s)
|
|||
sprintf(buf, "%s#branch", l + 1);
|
||||
wl->wl_word = copy(buf);
|
||||
c = r = NULL;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
wl->wl_word = copy(l + 1);
|
||||
}
|
||||
|
||||
|
|
@ -622,7 +638,11 @@ gettoks(char *s)
|
|||
prevp = &wl->wl_next;
|
||||
}
|
||||
tfree(t);
|
||||
}
|
||||
tfree(s0);
|
||||
} /* end of loop parsing string */
|
||||
|
||||
txfree(s0);
|
||||
return list;
|
||||
}
|
||||
} /* end of function gettoks */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ fourier(wordlist *wl, struct plot *current_plot)
|
|||
{
|
||||
struct dvec *time, *vec;
|
||||
struct pnode *pn, *names;
|
||||
double *ff, fundfreq, *data = NULL;
|
||||
double fundfreq, *data = NULL;
|
||||
int nfreqs, fourgridsize, polydegree;
|
||||
double *freq, *mag, *phase, *nmag, *nphase; /* Outputs from CKTfour */
|
||||
double thd, *timescale = NULL;
|
||||
|
|
@ -78,11 +78,10 @@ fourier(wordlist *wl, struct plot *current_plot)
|
|||
return 1;
|
||||
}
|
||||
s = wl->wl_word;
|
||||
if ((ff = ft_numparse(&s, FALSE)) == NULL || (*ff <= 0.0)) {
|
||||
fprintf(cp_err, "Error: bad fund freq %s\n", wl->wl_word);
|
||||
if (ft_numparse(&s, FALSE, &fundfreq) < 0 || fundfreq <= 0.0) {
|
||||
fprintf(cp_err, "Error: bad fundamental freq %s\n", wl->wl_word);
|
||||
return 1;
|
||||
}
|
||||
fundfreq = *ff;
|
||||
|
||||
freq = TMALLOC(double, nfreqs);
|
||||
mag = TMALLOC(double, nfreqs);
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ extern int PPparse(char **, struct pnode **);
|
|||
void db_print_pnode_tree(struct pnode *p, char *print);
|
||||
|
||||
|
||||
struct pnode *
|
||||
ft_getpnames_from_string(const char *sz, bool check)
|
||||
struct pnode *ft_getpnames_from_string(const char *sz, bool check)
|
||||
{
|
||||
struct pnode *pn;
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ ft_getpnames(const wordlist *wl, bool check)
|
|||
return (struct pnode *) NULL;
|
||||
}
|
||||
|
||||
/* Convert the list to a string then parse the string */
|
||||
/* Conver the list to a string then parse the string */
|
||||
const char * const sz = wl_flatten(wl);
|
||||
struct pnode * const pn = ft_getpnames_from_string(sz, check);
|
||||
txfree((void *) sz);
|
||||
|
|
@ -213,63 +212,70 @@ struct func func_not = { "not", cx_not };
|
|||
|
||||
|
||||
/* Binary operator node. */
|
||||
|
||||
struct pnode *
|
||||
PP_mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2)
|
||||
struct pnode *PP_mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2)
|
||||
{
|
||||
struct op *o;
|
||||
struct pnode *p;
|
||||
|
||||
for (o = &ops[0]; o->op_name; o++)
|
||||
if (o->op_num == opnum)
|
||||
for (o = &ops[0]; o->op_name; o++) {
|
||||
if (o->op_num == opnum) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!o->op_name)
|
||||
if (!o->op_name) {
|
||||
fprintf(cp_err, "PP_mkbnode: Internal Error: no such op num %d\n",
|
||||
opnum);
|
||||
}
|
||||
|
||||
p = alloc_pnode();
|
||||
|
||||
p->pn_op = o;
|
||||
|
||||
p->pn_left = arg1;
|
||||
if (p->pn_left)
|
||||
if (p->pn_left) {
|
||||
p->pn_left->pn_use++;
|
||||
}
|
||||
|
||||
p->pn_right = arg2;
|
||||
if (p->pn_right)
|
||||
if (p->pn_right) {
|
||||
p->pn_right->pn_use++;
|
||||
}
|
||||
|
||||
return p;
|
||||
} /* end of function PP_mkbnode */
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
/* Unary operator node. */
|
||||
|
||||
struct pnode *
|
||||
PP_mkunode(int op, struct pnode *arg)
|
||||
struct pnode *PP_mkunode(int op, struct pnode *arg)
|
||||
{
|
||||
struct pnode *p;
|
||||
struct op *o;
|
||||
|
||||
p = alloc_pnode();
|
||||
|
||||
for (o = uops; o->op_name; o++)
|
||||
if (o->op_num == op)
|
||||
for (o = uops; o->op_name; o++) {
|
||||
if (o->op_num == op) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!o->op_name)
|
||||
if (!o->op_name) {
|
||||
fprintf(cp_err, "PP_mkunode: Internal Error: no such op num %d\n",
|
||||
op);
|
||||
}
|
||||
|
||||
p->pn_op = o;
|
||||
|
||||
p->pn_left = arg;
|
||||
if (p->pn_left)
|
||||
if (p->pn_left) {
|
||||
p->pn_left->pn_use++;
|
||||
}
|
||||
|
||||
return p;
|
||||
} /* end of function PP_mkunode */
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
/* Function node. We have to worry about a lot of things here. Something
|
||||
|
|
@ -280,9 +286,7 @@ PP_mkunode(int op, struct pnode *arg)
|
|||
* the arguments, and then return a copy of the expression that it was
|
||||
* defined to be.
|
||||
*/
|
||||
|
||||
struct pnode *
|
||||
PP_mkfnode(const char *func, struct pnode *arg)
|
||||
struct pnode *PP_mkfnode(const char *func, struct pnode *arg)
|
||||
{
|
||||
struct func *f;
|
||||
struct pnode *p, *q;
|
||||
|
|
@ -292,15 +296,18 @@ PP_mkfnode(const char *func, struct pnode *arg)
|
|||
(void) strcpy(buf, func);
|
||||
strtolower(buf); /* Make sure the case is ok. */
|
||||
|
||||
for (f = &ft_funcs[0]; f->fu_name; f++)
|
||||
if (eq(f->fu_name, buf))
|
||||
for (f = &ft_funcs[0]; f->fu_name; f++) {
|
||||
if (eq(f->fu_name, buf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->fu_name == NULL) {
|
||||
if (f->fu_name == NULL) { /* not found yet */
|
||||
/* Give the user-defined functions a try. */
|
||||
q = ft_substdef(func, arg);
|
||||
if (q)
|
||||
return (q);
|
||||
if (q) { /* found */
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
||||
if ((f->fu_name == NULL) && arg->pn_value) {
|
||||
|
|
@ -312,15 +319,16 @@ PP_mkfnode(const char *func, struct pnode *arg)
|
|||
/* Well, too bad. */
|
||||
fprintf(cp_err, "Error: no such function as %s.\n",
|
||||
func);
|
||||
return (NULL);
|
||||
return (struct pnode *) NULL;
|
||||
}
|
||||
/* (void) strcpy(buf, d->v_name); XXX */
|
||||
return (PP_mksnode(buf));
|
||||
} else if (f->fu_name == NULL) {
|
||||
return PP_mksnode(buf);
|
||||
}
|
||||
else if (f->fu_name == NULL) {
|
||||
fprintf(cp_err, "Error: no function as %s with that arity.\n",
|
||||
func);
|
||||
free_pnode(arg);
|
||||
return (NULL);
|
||||
return (struct pnode *) NULL;
|
||||
}
|
||||
|
||||
if (!f->fu_func && arg->pn_op && arg->pn_op->op_num == PT_OP_COMMA) {
|
||||
|
|
@ -335,17 +343,17 @@ PP_mkfnode(const char *func, struct pnode *arg)
|
|||
p->pn_func = f;
|
||||
|
||||
p->pn_left = arg;
|
||||
if (p->pn_left)
|
||||
if (p->pn_left) {
|
||||
p->pn_left->pn_use++;
|
||||
}
|
||||
|
||||
return p;
|
||||
} /* end of function PP_mkfnode */
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
/* Number node. */
|
||||
|
||||
struct pnode *
|
||||
PP_mknnode(double number)
|
||||
struct pnode *PP_mknnode(double number)
|
||||
{
|
||||
struct pnode *p;
|
||||
struct dvec *v;
|
||||
|
|
@ -354,7 +362,7 @@ PP_mknnode(double number)
|
|||
* to be careful to deal properly with node numbers that are quite
|
||||
* large...
|
||||
*/
|
||||
v = dvec_alloc(number < MAXPOSINT
|
||||
v = dvec_alloc(number <= INT_MAX
|
||||
? tprintf("%d", (int) number)
|
||||
: tprintf("%G", number),
|
||||
SV_NOTYPE,
|
||||
|
|
@ -368,13 +376,12 @@ PP_mknnode(double number)
|
|||
p = alloc_pnode();
|
||||
p->pn_value = v;
|
||||
return (p);
|
||||
}
|
||||
} /* end of function PP_mknnode */
|
||||
|
||||
|
||||
|
||||
/* String node. */
|
||||
|
||||
struct pnode *
|
||||
PP_mksnode(const char *string)
|
||||
struct pnode *PP_mksnode(const char *string)
|
||||
{
|
||||
struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL;
|
||||
struct pnode *p;
|
||||
|
|
@ -387,17 +394,19 @@ PP_mksnode(const char *string)
|
|||
0,
|
||||
0, NULL);
|
||||
p->pn_value = nv;
|
||||
return (p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* It's not obvious that we should be doing this, but... */
|
||||
for (vs = v; vs; vs = vs->v_link2) {
|
||||
nv = vec_copy(vs);
|
||||
vec_new(nv);
|
||||
if (end)
|
||||
if (end) {
|
||||
end->v_link2 = nv;
|
||||
else
|
||||
}
|
||||
else {
|
||||
newv = end = nv;
|
||||
}
|
||||
end = nv;
|
||||
}
|
||||
p->pn_value = newv;
|
||||
|
|
@ -410,12 +419,12 @@ PP_mksnode(const char *string)
|
|||
/* The two lines above have been commented out to prevent deletion of @xxx[par]
|
||||
after execution of only a single command like plot @xxx[par] or write. We need to
|
||||
monitor if this will lead to excessive memory usage. h_vogt 090221 */
|
||||
return (p);
|
||||
}
|
||||
return p;
|
||||
} /* end of function PP_mksnode */
|
||||
|
||||
|
||||
struct pnode *
|
||||
alloc_pnode(void)
|
||||
|
||||
struct pnode *alloc_pnode(void)
|
||||
{
|
||||
struct pnode *pn = TMALLOC(struct pnode, 1);
|
||||
|
||||
|
|
@ -432,42 +441,45 @@ alloc_pnode(void)
|
|||
pn->pn_next = NULL;
|
||||
|
||||
return pn;
|
||||
}
|
||||
} /* end of function alloc_pnode */
|
||||
|
||||
|
||||
|
||||
/* Don't call this directly, always use the free_pnode() macro.
|
||||
The linked pnodes do not necessarily form a perfect tree as some nodes get
|
||||
reused. Hence, in this recursive walk trough the 'tree' we only free node
|
||||
that have their pn_use value at zero. Nodes that have pn_use values above
|
||||
zero have the link severed and their pn_use value decremented.
|
||||
reused. Hence, in this recursive walk through the 'tree', we only free
|
||||
nodes that have their pn_use value at zero. Nodes that have pn_use values
|
||||
above zero have the link severed and their pn_use value decremented.
|
||||
In addition, we don't walk past nodes with pn_use values avoid zero, just
|
||||
in case we have a circular reference (this probable does not happen in
|
||||
practice, but it does no harm playing safe) */
|
||||
void
|
||||
free_pnode_x(struct pnode *t)
|
||||
in case we have a circular reference (This probably does not happen in
|
||||
practice, but it does no harm playing safe.) */
|
||||
void free_pnode_x(struct pnode *t)
|
||||
{
|
||||
if (!t)
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* don't walk past nodes used elsewhere. We decrement the pn_use value here,
|
||||
/* Don't walk past nodes used elsewhere. We decrement the pn_use value here,
|
||||
but the link gets severed by the action of the free_pnode() macro */
|
||||
if (t->pn_use > 1) {
|
||||
t->pn_use--;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
/* pn_use is now 1, so its safe to free the pnode */
|
||||
free_pnode(t->pn_left);
|
||||
free_pnode(t->pn_right);
|
||||
free_pnode(t->pn_next);
|
||||
tfree(t->pn_name); /* va: it is a copy() of original string, can be free'd */
|
||||
if (t->pn_value && !(t->pn_value->v_flags & VF_PERMANENT))
|
||||
if (t->pn_value && !(t->pn_value->v_flags & VF_PERMANENT)) {
|
||||
vec_free(t->pn_value); /* patch by Stefan Jones */
|
||||
tfree(t);
|
||||
}
|
||||
txfree(t);
|
||||
}
|
||||
}
|
||||
} /* end of function free_pnode_x */
|
||||
|
||||
|
||||
static void
|
||||
db_print_func(FILE *fdst, struct func *f)
|
||||
|
||||
static void db_print_func(FILE *fdst, struct func *f)
|
||||
{
|
||||
if (!f) {
|
||||
fprintf(fdst, "nil");
|
||||
|
|
@ -475,11 +487,11 @@ db_print_func(FILE *fdst, struct func *f)
|
|||
}
|
||||
|
||||
fprintf(fdst, "(func :fu_name %s :fu_func %p)", f->fu_name, f->fu_func);
|
||||
}
|
||||
} /* end of function db_print_func */
|
||||
|
||||
|
||||
static void
|
||||
db_print_op(FILE *fdst, struct op *op)
|
||||
|
||||
static void db_print_op(FILE *fdst, struct op *op)
|
||||
{
|
||||
if (!op) {
|
||||
fprintf(fdst, "nil");
|
||||
|
|
@ -488,11 +500,11 @@ db_print_op(FILE *fdst, struct op *op)
|
|||
|
||||
fprintf(fdst, "(op :op_num %d :op_name %s :op_arity %d :op_func %p)",
|
||||
op->op_num, op->op_name, op->op_arity, op->op_func.anonymous);
|
||||
}
|
||||
} /* end of function db_print_op */
|
||||
|
||||
|
||||
static void
|
||||
db_print_dvec(FILE *fdst, struct dvec *d)
|
||||
|
||||
static void db_print_dvec(FILE *fdst, struct dvec *d)
|
||||
{
|
||||
if (!d) {
|
||||
fprintf(fdst, "nil");
|
||||
|
|
@ -501,11 +513,11 @@ db_print_dvec(FILE *fdst, struct dvec *d)
|
|||
|
||||
fprintf(fdst, "(dvec :v_name %s :v_type %d :v_flags %d :v_length %d ...)",
|
||||
d->v_name, d->v_type, d->v_flags, d->v_length);
|
||||
}
|
||||
} /* end of function db_print_dvec */
|
||||
|
||||
|
||||
static void
|
||||
db_print_pnode(FILE *fdst, struct pnode *p)
|
||||
|
||||
static void db_print_pnode(FILE *fdst, struct pnode *p)
|
||||
{
|
||||
if (!p) {
|
||||
fprintf(fdst, "nil\n");
|
||||
|
|
@ -513,8 +525,7 @@ db_print_pnode(FILE *fdst, struct pnode *p)
|
|||
}
|
||||
|
||||
if (!p->pn_name && p->pn_value && !p->pn_func && !p->pn_op &&
|
||||
!p->pn_left && !p->pn_right && !p->pn_next)
|
||||
{
|
||||
!p->pn_left && !p->pn_right && !p->pn_next) {
|
||||
fprintf(fdst, "(pnode-value :pn_use %d", p->pn_use);
|
||||
fprintf(fdst, " :pn_value "); db_print_dvec(fdst, p->pn_value);
|
||||
fprintf(fdst, ")\n");
|
||||
|
|
@ -522,8 +533,7 @@ db_print_pnode(FILE *fdst, struct pnode *p)
|
|||
}
|
||||
|
||||
if (!p->pn_name && !p->pn_value && p->pn_func && !p->pn_op &&
|
||||
!p->pn_right && !p->pn_next)
|
||||
{
|
||||
!p->pn_right && !p->pn_next) {
|
||||
fprintf(fdst, "(pnode-func :pn_use %d", p->pn_use);
|
||||
fprintf(fdst, "\n :pn_func "); db_print_func(fdst, p->pn_func);
|
||||
fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left);
|
||||
|
|
@ -532,8 +542,7 @@ db_print_pnode(FILE *fdst, struct pnode *p)
|
|||
}
|
||||
|
||||
if (!p->pn_name && !p->pn_value && !p->pn_func && p->pn_op &&
|
||||
!p->pn_next)
|
||||
{
|
||||
!p->pn_next) {
|
||||
fprintf(fdst, "(pnode-op :pn_use %d", p->pn_use);
|
||||
fprintf(fdst, "\n :pn_op "); db_print_op(fdst, p->pn_op);
|
||||
fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left);
|
||||
|
|
@ -550,11 +559,11 @@ db_print_pnode(FILE *fdst, struct pnode *p)
|
|||
fprintf(fdst, "\n :pn_right "); db_print_pnode(fdst, p->pn_right);
|
||||
fprintf(fdst, "\n :pn_next "); db_print_pnode(fdst, p->pn_next);
|
||||
fprintf(fdst, "\n)\n");
|
||||
}
|
||||
} /* end of function db_print_pnode */
|
||||
|
||||
|
||||
void
|
||||
db_print_pnode_tree(struct pnode *p, char *print)
|
||||
|
||||
void db_print_pnode_tree(struct pnode *p, char *print)
|
||||
{
|
||||
#if 1
|
||||
NG_IGNORE(print);
|
||||
|
|
@ -569,18 +578,19 @@ db_print_pnode_tree(struct pnode *p, char *print)
|
|||
printf("%s:%d: %s {%s}\n%s\n", __FILE__, __LINE__, __func__, print, buf);
|
||||
tfree(buf);
|
||||
#endif
|
||||
}
|
||||
} /* end of function db_print_pnode_tree */
|
||||
|
||||
|
||||
int
|
||||
PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
||||
|
||||
int PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
||||
{
|
||||
static char *specials = " \t%()-^+*,/|&<>~=";
|
||||
char *sbuf = *line;
|
||||
int token;
|
||||
|
||||
while ((*sbuf == ' ') || (*sbuf == '\t'))
|
||||
while ((*sbuf == ' ') || (*sbuf == '\t')) {
|
||||
sbuf++;
|
||||
}
|
||||
|
||||
llocp->start = sbuf;
|
||||
|
||||
|
|
@ -590,28 +600,36 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
|||
if ((sbuf[0] == 'g') && (sbuf[1] == 't') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return('>', 2);
|
||||
} else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return('<', 2);
|
||||
} else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return(TOK_GE, 2);
|
||||
} else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return(TOK_LE, 2);
|
||||
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return(TOK_NE, 2);
|
||||
} else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return('=', 2);
|
||||
} else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
|
||||
strchr(specials, sbuf[2])) {
|
||||
lexer_return('|', 2);
|
||||
} else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') &&
|
||||
(sbuf[2] == 'd') && strchr(specials, sbuf[3])) {
|
||||
lexer_return('&', 3);
|
||||
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') &&
|
||||
}
|
||||
else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') &&
|
||||
(sbuf[2] == 't') && strchr(specials, sbuf[3])) {
|
||||
lexer_return('~', 3);
|
||||
}
|
||||
|
|
@ -623,18 +641,19 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
|||
lexer_return(*sbuf, 1);
|
||||
|
||||
case '>':
|
||||
case '<':
|
||||
{
|
||||
case '<': {
|
||||
/* Workaround, The Frontend makes "<>" into "< >" */
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (isspace_c(sbuf[j]))
|
||||
j++;
|
||||
if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) {
|
||||
/* Allow both <> and >< for NE. */
|
||||
lexer_return(TOK_NE, j+1);
|
||||
} else if (sbuf[1] == '=') {
|
||||
lexer_return(TOK_NE, j + 1);
|
||||
}
|
||||
else if (sbuf[1] == '=') {
|
||||
lexer_return((sbuf[0] == '>') ? TOK_GE : TOK_LE, 2);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
lexer_return(*sbuf, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -659,26 +678,28 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
|||
case '\0':
|
||||
lexer_return(*sbuf, 0);
|
||||
|
||||
case '"':
|
||||
{
|
||||
case '"': {
|
||||
char *start = ++sbuf;
|
||||
while (*sbuf && (*sbuf != '"'))
|
||||
sbuf++;
|
||||
lvalp->str = copy_substring(start, sbuf);
|
||||
if (*sbuf)
|
||||
if (*sbuf) {
|
||||
sbuf++;
|
||||
}
|
||||
lexer_return(TOK_STR, 0);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
char *s = sbuf;
|
||||
double *td = ft_numparse(&s, FALSE);
|
||||
if ((!s || *s != ':') && td) {
|
||||
double val;
|
||||
|
||||
if (ft_numparse(&s, FALSE, &val) >= 0 &&
|
||||
(!s || *s != ':')) {
|
||||
sbuf = s;
|
||||
lvalp->num = *td;
|
||||
lvalp->num = val;
|
||||
lexer_return(TOK_NUM, 0);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
int atsign = 0;
|
||||
char *start = sbuf;
|
||||
/* It is bad how we have to recognise '[' -- sometimes
|
||||
|
|
@ -693,13 +714,16 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
|||
* i(v5) --> v5#branch
|
||||
*/
|
||||
for (; *sbuf && !strchr(specials, *sbuf); sbuf++)
|
||||
if (*sbuf == '@')
|
||||
if (*sbuf == '@') {
|
||||
atsign = 1;
|
||||
else if (!atsign && *sbuf == '[')
|
||||
}
|
||||
else if (!atsign && *sbuf == '[') {
|
||||
break;
|
||||
}
|
||||
else if (*sbuf == ']') {
|
||||
if (atsign)
|
||||
if (atsign) {
|
||||
sbuf++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -707,19 +731,25 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
|
|||
lexer_return(TOK_STR, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end of switch over characters */
|
||||
|
||||
done:
|
||||
if (ft_parsedb) {
|
||||
if (token == TOK_STR)
|
||||
if (token == TOK_STR) {
|
||||
fprintf(stderr, "lexer: TOK_STR, \"%s\"\n", lvalp->str);
|
||||
else if (token == TOK_NUM)
|
||||
}
|
||||
else if (token == TOK_NUM) {
|
||||
fprintf(stderr, "lexer: TOK_NUM, %G\n", lvalp->num);
|
||||
else
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "lexer: token %d\n", token);
|
||||
}
|
||||
}
|
||||
|
||||
*line = sbuf;
|
||||
llocp->stop = sbuf;
|
||||
return (token);
|
||||
}
|
||||
return token;
|
||||
} /* end of function PPlex */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
**********/
|
||||
|
||||
/* This routine parses a number. */
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/bool.h"
|
||||
|
|
@ -11,160 +14,226 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
#include "numparse.h"
|
||||
|
||||
|
||||
static double
|
||||
power10(double num) /* Chris Inbody */
|
||||
{
|
||||
double d = 1.0;
|
||||
|
||||
while (num-- > 0)
|
||||
d *= 10.0;
|
||||
return (d);
|
||||
}
|
||||
|
||||
|
||||
bool ft_strictnumparse = FALSE;
|
||||
|
||||
|
||||
static int get_decimal_number(const char **p_str, double *p_val);
|
||||
|
||||
|
||||
/* Parse a number. This will handle things like 10M, etc... If the number
|
||||
* must not end before the end of the string, then whole is TRUE.
|
||||
* If whole is FALSE and there is more left to the number, the argument
|
||||
* is advanced to the end of the word. Returns NULL
|
||||
* is advanced to the end of the word. Returns -1.
|
||||
* if no number can be found or if there are trailing characters when
|
||||
* whole is TRUE.
|
||||
*
|
||||
* If ft_strictnumparse is TRUE, and whole is FALSE, the first of the
|
||||
* trailing characters must be a '_'. */
|
||||
|
||||
double *
|
||||
ft_numparse(char **s, bool whole)
|
||||
* trailing characters must be a '_'.
|
||||
*
|
||||
* Return codes
|
||||
* +1: String represented an integer number that was converted to a double
|
||||
* but which can be stored as an int without loss of data
|
||||
* 0: String represented a non-integer number that was converted to a double
|
||||
* that may not be expressed as an integer.
|
||||
* -1: Conversion failure
|
||||
*/
|
||||
int ft_numparse(char **p_str, bool whole, double *p_val)
|
||||
{
|
||||
double mant = 0.0;
|
||||
int sign = 1, exsign = 1, p;
|
||||
double expo = 0.0;
|
||||
static double num;
|
||||
char *string = *s;
|
||||
double mant;
|
||||
double expo;
|
||||
const char *p_cur = *p_str; /* position in string */
|
||||
|
||||
/* See if the number begins with + or -. */
|
||||
if (*string == '+') {
|
||||
string++;
|
||||
} else if (*string == '-') {
|
||||
string++;
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
/* We don't want to recognise "P" as 0P, or .P as 0.0P... */
|
||||
if ((!isdigit_c(*string) && *string != '.') ||
|
||||
((*string == '.') && !isdigit_c(string[1])))
|
||||
return (NULL);
|
||||
|
||||
/* Now accumulate a number. Note ascii dependencies here... */
|
||||
while (isdigit_c(*string))
|
||||
mant = mant * 10.0 + (*string++ - '0');
|
||||
|
||||
/* Now maybe a decimal point. */
|
||||
if (*string == '.') {
|
||||
string++;
|
||||
p = 1;
|
||||
while (isdigit_c(*string))
|
||||
mant += (*string++ - '0') / power10(p++);
|
||||
/* Parse the mantissa (or decimal number if no exponent) */
|
||||
if (get_decimal_number(&p_cur, &mant) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now look for the scale factor or the exponent (can't have both). */
|
||||
switch (*string) {
|
||||
switch (*p_cur) {
|
||||
case 'e':
|
||||
case 'E':
|
||||
/* Parse another number. */
|
||||
string++;
|
||||
if (*string == '+') {
|
||||
exsign = 1;
|
||||
string++;
|
||||
} else if (*string == '-') {
|
||||
exsign = -1;
|
||||
string++;
|
||||
/* Parse another number. Note that a decimal number such as 1.23
|
||||
* is allowed as the exponent */
|
||||
++p_cur;
|
||||
if (get_decimal_number(&p_cur, &expo) < 0) {
|
||||
expo = 0.0;
|
||||
--p_cur; /* The "E" was not part of the number */
|
||||
}
|
||||
while (isdigit_c(*string))
|
||||
expo = expo * 10.0 + (*string++ - '0');
|
||||
if (*string == '.') {
|
||||
string++;
|
||||
p = 1;
|
||||
while (isdigit_c(*string))
|
||||
expo += (*string++ - '0') / power10(p++);
|
||||
}
|
||||
expo *= exsign;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
expo = 12.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
expo = 9.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
expo = 3.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
expo = -6.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
expo = -9.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
expo = -12.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
expo = -15.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'M': {
|
||||
char ch_cur;
|
||||
|
||||
/* Can be either m, mil, or meg. */
|
||||
if (string[1] && string[2] &&
|
||||
((string[1] == 'e') || (string[1] == 'E')) &&
|
||||
((string[2] == 'g') || (string[2] == 'G')))
|
||||
{
|
||||
if (((ch_cur = p_cur[1]) == 'e' || ch_cur == 'E') &&
|
||||
(((ch_cur = p_cur[2]) == 'g') || ch_cur == 'G')) {
|
||||
expo = 6.0;
|
||||
string += 3;
|
||||
} else if (string[1] && string[2] &&
|
||||
((string[1] == 'i') || (string[1] == 'I')) &&
|
||||
((string[2] == 'l') || (string[2] == 'L')))
|
||||
{
|
||||
p_cur += 3;
|
||||
}
|
||||
else if (((ch_cur = p_cur[1]) == 'i' || ch_cur == 'I') &&
|
||||
(((ch_cur = p_cur[2]) == 'l') || ch_cur == 'L')) {
|
||||
expo = -6.0;
|
||||
mant *= 25.4;
|
||||
string += 3;
|
||||
} else {
|
||||
p_cur += 3;
|
||||
}
|
||||
else { /* plain m for milli */
|
||||
expo = -3.0;
|
||||
string++;
|
||||
++p_cur;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (whole && *string != '\0') {
|
||||
return (NULL);
|
||||
} else if (ft_strictnumparse && *string && isdigit_c(string[-1])) {
|
||||
if (*string == '_')
|
||||
while (isalpha_c(*string) || (*string == '_'))
|
||||
string++;
|
||||
else
|
||||
return (NULL);
|
||||
} else {
|
||||
while (isalpha_c(*string) || (*string == '_'))
|
||||
string++;
|
||||
default:
|
||||
expo = 0.0;
|
||||
}
|
||||
*s = string;
|
||||
num = sign * mant * pow(10.0, expo);
|
||||
if (ft_parsedb)
|
||||
fprintf(cp_err, "numparse: got %e, left = %s\n", num, *s);
|
||||
return (&num);
|
||||
}
|
||||
|
||||
/* p_cur is now pointing to the fist char after the number */
|
||||
{
|
||||
/* If whole is true, it must be the end of the string */
|
||||
const char ch_cur = *p_cur;
|
||||
if (whole && ch_cur != '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If ft_strictnumparse is true, the first character after the
|
||||
* string representing the number, if any, must be '_' */
|
||||
if (ft_strictnumparse && ch_cur != '\0' && ch_cur != '_') {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the alpha and '_' characters after the number */
|
||||
for ( ; ; ++p_cur) {
|
||||
const char ch_cur = *p_cur;
|
||||
if (!isalpha(ch_cur) && ch_cur != '_') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return results */
|
||||
{
|
||||
/* Value of number. Ternary operator used to prevent avoidable
|
||||
* calls to pow(). */
|
||||
const double val = *p_val = mant *
|
||||
(expo == 0.0 ? 1.0 : pow(10.0, expo));
|
||||
*p_str = (char *) p_cur; /* updated location in string */
|
||||
|
||||
if (ft_parsedb) { /* diagnostics for parsing the number */
|
||||
fprintf(cp_err, "numparse: got %e, left = \"%s\"\n",
|
||||
val, p_cur);
|
||||
}
|
||||
|
||||
/* Test if the number can be represented as an intger */
|
||||
return (double) (int) val == val;
|
||||
}
|
||||
} /* end of function ft_numparse */
|
||||
|
||||
|
||||
|
||||
/* This function converts the string form of a decimal number at *p_str to
|
||||
* its value and returns it in *p_val. The location in *p_str is advanced
|
||||
* to the first character after the number if the conversion is OK and
|
||||
* is unchanged otherwise.
|
||||
*
|
||||
* Return codes
|
||||
* -1: Conversion failure. *p_val is unchanged
|
||||
* 0: Conversion OK. The string was not the representation of an integer
|
||||
* +1: Conversion OK. The string was an integer */
|
||||
static int get_decimal_number(const char **p_str, double *p_val)
|
||||
{
|
||||
double sign = 1.0; /* default sign multiplier if missing is 1.0 */
|
||||
const char *p_cur = *p_str;
|
||||
char ch_cur = *p_cur; /* 1st char */
|
||||
bool f_is_integer = TRUE; /* assume integer */
|
||||
|
||||
/* Test for a sign */
|
||||
if (ch_cur == '+') { /* Advance position in string. Sign unchanged */
|
||||
ch_cur = *++p_cur;
|
||||
}
|
||||
else if (ch_cur == '-') { /* Advance position in string. Sign = -1 */
|
||||
ch_cur = *++p_cur;
|
||||
sign = -1.0;
|
||||
}
|
||||
|
||||
/* Ensure string either starts with a digit or a decimal point followed
|
||||
* by a digit */
|
||||
if ((!isdigit(ch_cur) && ch_cur != '.') ||
|
||||
((ch_cur == '.') && !isdigit(p_cur[1]))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse and compute the number. Assuming 0-9 digits are contiguous and
|
||||
* increasing in char representation (true for ASCII and EBCDIC) */
|
||||
double val = 0.0;
|
||||
for ( ; ; p_cur++) {
|
||||
const unsigned int digit =
|
||||
(unsigned int) *p_cur - (unsigned int) '0';
|
||||
if (digit > 9) { /* not digit */
|
||||
break;
|
||||
}
|
||||
val = val * 10.0 + (double) digit;
|
||||
}
|
||||
|
||||
/* Handle fraction, if any */
|
||||
if (*p_cur == '.') {
|
||||
const char *p0 = ++p_cur; /* start of fraction */
|
||||
double numerator = 0.0;
|
||||
|
||||
/* Not an integer expression (even if no fraction after the '.') */
|
||||
f_is_integer = FALSE;
|
||||
|
||||
/* Add the fractional part of the number */
|
||||
for ( ; ; p_cur++) {
|
||||
const unsigned int digit =
|
||||
(unsigned int) *p_cur - (unsigned int) '0';
|
||||
if (digit > 9) { /* not digit */
|
||||
/* Add fractional part to intergral part from earlier */
|
||||
val += numerator * pow(10, (double) (p0 - p_cur));
|
||||
break;
|
||||
}
|
||||
numerator = numerator * 10.0 + (double) digit;
|
||||
}
|
||||
} /* end of case of fraction */
|
||||
|
||||
/* Return the value and update the position in the string */
|
||||
*p_val = sign * val;
|
||||
*p_str = p_cur;
|
||||
return (int) f_is_integer;
|
||||
} /* end of function get_decimal_number */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ static bool sameflag;
|
|||
static double *
|
||||
getlims(wordlist *wl, char *name, int number)
|
||||
{
|
||||
double *d;
|
||||
wordlist *beg, *wk;
|
||||
int n;
|
||||
|
||||
|
|
@ -43,39 +42,35 @@ getlims(wordlist *wl, char *name, int number)
|
|||
|
||||
wk = beg->wl_next;
|
||||
|
||||
d = TMALLOC(double, number);
|
||||
double * const d = TMALLOC(double, number); /* alloc for returned vals */
|
||||
|
||||
for (n = 0; n < number; n++) {
|
||||
|
||||
char *ss;
|
||||
double *td;
|
||||
|
||||
if (!wk) {
|
||||
fprintf(cp_err,
|
||||
"Syntax error: not enough parameters for \"%s\".\n", name);
|
||||
txfree(d);
|
||||
return NULL;
|
||||
return (double *) NULL;
|
||||
}
|
||||
|
||||
ss = wk->wl_word;
|
||||
td = ft_numparse(&ss, FALSE);
|
||||
|
||||
if (!td) {
|
||||
if (ft_numparse(&ss, FALSE, d + n) < 0) { /* put val in d[n] */
|
||||
fprintf(cp_err,
|
||||
"Syntax error: bad parameters for \"%s\".\n", name);
|
||||
txfree(d);
|
||||
return NULL;
|
||||
return (double *) NULL;
|
||||
}
|
||||
|
||||
d[n] = *td;
|
||||
|
||||
wk = wk->wl_next;
|
||||
}
|
||||
} /* end of loop over numbers */
|
||||
|
||||
wl_delete_slice(beg, wk);
|
||||
wl_delete_slice(beg, wk); /* remove param name and its value nodes */
|
||||
|
||||
return d;
|
||||
}
|
||||
} /* end of function getlims */
|
||||
|
||||
|
||||
|
||||
/* Extend a data vector to length by replicating the last element, or
|
||||
|
|
|
|||
|
|
@ -444,8 +444,9 @@ com_write(wordlist *wl)
|
|||
else
|
||||
names = ft_getpnames(&all, TRUE);
|
||||
|
||||
if (names == NULL)
|
||||
if (names == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (pn = names; pn; pn = pn->pn_next) {
|
||||
d = ft_evaluate(pn);
|
||||
|
|
@ -731,22 +732,27 @@ com_transpose(wordlist *wl)
|
|||
struct dvec *d;
|
||||
char *s;
|
||||
|
||||
while (wl) {
|
||||
/* For each vector named in the wordlist, perform the transform to
|
||||
* it and the vectors associated with it through v_link2 */
|
||||
for ( ; wl != (wordlist *) NULL; wl = wl->wl_next) {
|
||||
s = cp_unquote(wl->wl_word);
|
||||
d = vec_get(s);
|
||||
tfree(s); /*DG: Avoid Memory Leak */
|
||||
if (d == NULL)
|
||||
if (d == NULL) {
|
||||
/* Print error message, but continue with other vectors */
|
||||
fprintf(cp_err, "Error: no such vector as %s.\n", wl->wl_word);
|
||||
else
|
||||
}
|
||||
else {
|
||||
/* Transpose the named vector and vectors tied to it
|
||||
* through v_link2 */
|
||||
while (d) {
|
||||
vec_transpose(d);
|
||||
d = d->v_link2;
|
||||
}
|
||||
if (wl->wl_next == NULL)
|
||||
return;
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end of loop over words in wordlist */
|
||||
} /* end of function com_transpose */
|
||||
|
||||
|
||||
|
||||
/* Take a set of vectors and form a new vector of the nth elements of each. */
|
||||
|
|
@ -758,19 +764,23 @@ com_cross(wordlist *wl)
|
|||
struct pnode *pn, *names;
|
||||
int i, ind;
|
||||
bool comp = FALSE;
|
||||
double *d;
|
||||
|
||||
newvec = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
s = wl->wl_word;
|
||||
if ((d = ft_numparse(&s, FALSE)) == NULL) {
|
||||
fprintf(cp_err, "Error: bad number %s\n", wl->wl_word);
|
||||
return;
|
||||
}
|
||||
if ((ind = (int)*d) < 0) {
|
||||
fprintf(cp_err, "Error: badstrchr %d\n", ind);
|
||||
return;
|
||||
|
||||
{
|
||||
double val;
|
||||
if (ft_numparse(&s, FALSE, &val) <= 0) {
|
||||
fprintf(cp_err, "Error: bad index value %s\n", wl->wl_word);
|
||||
return;
|
||||
}
|
||||
if ((ind = (int) val) < 0) {
|
||||
fprintf(cp_err, "Error: badstrchr %d\n", ind);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wl = wl->wl_next;
|
||||
names = ft_getpnames(wl, TRUE);
|
||||
for (pn = names; pn; pn = pn->pn_next) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ com_spec(wordlist *wl)
|
|||
{
|
||||
ngcomplex_t **fdvec = NULL;
|
||||
double **tdvec = NULL;
|
||||
double *freq, *win = NULL, *time, *dc = NULL;
|
||||
double *win = NULL, *time, *dc = NULL;
|
||||
double startf, stopf, stepf, span;
|
||||
int fpts, i, j, k, tlen, ngood;
|
||||
bool trace;
|
||||
|
|
@ -45,27 +45,24 @@ com_spec(wordlist *wl)
|
|||
|
||||
s = wl->wl_word;
|
||||
tlen = (plot_cur->pl_scale)->v_length;
|
||||
if ((freq = ft_numparse(&s, FALSE)) == NULL || (*freq < 0.0)) {
|
||||
if (ft_numparse(&s, FALSE, &startf) < 0 || startf < 0.0) {
|
||||
fprintf(cp_err, "Error: bad start freq %s\n", wl->wl_word);
|
||||
goto done;
|
||||
}
|
||||
startf = *freq;
|
||||
|
||||
wl = wl->wl_next;
|
||||
s = wl->wl_word;
|
||||
if ((freq = ft_numparse(&s, FALSE)) == NULL || (*freq <= startf)) {
|
||||
if (ft_numparse(&s, FALSE, &stopf) < 0 || stopf <= startf) {
|
||||
fprintf(cp_err, "Error: bad stop freq %s\n", wl->wl_word);
|
||||
goto done;
|
||||
}
|
||||
stopf = *freq;
|
||||
|
||||
wl = wl->wl_next;
|
||||
s = wl->wl_word;
|
||||
if ((freq = ft_numparse(&s, FALSE)) == NULL || !(*freq <= (stopf-startf))) {
|
||||
if (ft_numparse(&s, FALSE, &stepf) < 0 || stepf > stopf - startf) {
|
||||
fprintf(cp_err, "Error: bad step freq %s\n", wl->wl_word);
|
||||
goto done;
|
||||
}
|
||||
stepf = *freq;
|
||||
|
||||
wl = wl->wl_next;
|
||||
time = (plot_cur->pl_scale)->v_realdata;
|
||||
|
|
@ -212,9 +209,8 @@ com_spec(wordlist *wl)
|
|||
VF_REAL | VF_PERMANENT | VF_PRINT,
|
||||
fpts, NULL);
|
||||
vec_new(f);
|
||||
freq = f->v_realdata;
|
||||
|
||||
tdvec = TMALLOC(double *, ngood);
|
||||
tdvec = TMALLOC(double *, ngood);
|
||||
fdvec = TMALLOC(ngcomplex_t *, ngood);
|
||||
for (i = 0, vec = vlist; i < ngood; i++) {
|
||||
tdvec[i] = vec->v_realdata;
|
||||
|
|
@ -238,36 +234,41 @@ com_spec(wordlist *wl)
|
|||
}
|
||||
}
|
||||
trace = cp_getvar("spectrace", CP_BOOL, NULL, 0);
|
||||
for (j = (startf == 0 ? 1 : 0); j < fpts; j++) {
|
||||
freq[j] = startf + j*stepf;
|
||||
if (trace)
|
||||
fprintf(cp_err, "spec: %e Hz: \r", freq[j]);
|
||||
for (i = 0; i < ngood; i++) {
|
||||
fdvec[i][j].cx_real = 0;
|
||||
fdvec[i][j].cx_imag = 0;
|
||||
}
|
||||
for (k = 1; k < tlen; k++) {
|
||||
double
|
||||
amp = 2*win[k]/(tlen-1),
|
||||
rad = 2*M_PI*time[k]*freq[j],
|
||||
cosa = amp*cos(rad),
|
||||
sina = amp*sin(rad);
|
||||
for (i = 0; i < ngood; i++) {
|
||||
double value = tdvec[i][k]-dc[i];
|
||||
fdvec[i][j].cx_real += value*cosa;
|
||||
fdvec[i][j].cx_imag += value*sina;
|
||||
}
|
||||
}
|
||||
#ifdef HAS_PROGREP
|
||||
SetAnalyse("spec", (int)(j * 1000./ fpts));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (startf == 0) {
|
||||
freq[0] = 0;
|
||||
for (i = 0; i < ngood; i++) {
|
||||
fdvec[i][0].cx_real = dc[i];
|
||||
fdvec[i][0].cx_imag = 0;
|
||||
{
|
||||
double * const freq = f->v_realdata;
|
||||
for (j = (startf == 0 ? 1 : 0); j < fpts; j++) {
|
||||
freq[j] = startf + j*stepf;
|
||||
if (trace) {
|
||||
fprintf(cp_err, "spec: %e Hz: \r", freq[j]);
|
||||
}
|
||||
for (i = 0; i < ngood; i++) {
|
||||
fdvec[i][j].cx_real = 0;
|
||||
fdvec[i][j].cx_imag = 0;
|
||||
}
|
||||
for (k = 1; k < tlen; k++) {
|
||||
double
|
||||
amp = 2*win[k]/(tlen-1),
|
||||
rad = 2*M_PI*time[k]*freq[j],
|
||||
cosa = amp*cos(rad),
|
||||
sina = amp*sin(rad);
|
||||
for (i = 0; i < ngood; i++) {
|
||||
double value = tdvec[i][k]-dc[i];
|
||||
fdvec[i][j].cx_real += value*cosa;
|
||||
fdvec[i][j].cx_imag += value*sina;
|
||||
}
|
||||
}
|
||||
#ifdef HAS_PROGREP
|
||||
SetAnalyse("spec", (int)(j * 1000./ fpts));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (startf == 0) {
|
||||
freq[0] = 0;
|
||||
for (i = 0; i < ngood; i++) {
|
||||
fdvec[i][0].cx_real = dc[i];
|
||||
fdvec[i][0].cx_imag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,11 +77,13 @@ wordlist *cp_varwl(struct variable *var)
|
|||
}
|
||||
|
||||
return wl_cons(buf, NULL);
|
||||
}
|
||||
} /* end of function cp_varwl */
|
||||
|
||||
|
||||
|
||||
/* Set a variable. */
|
||||
void cp_vset(const char *varname, enum cp_types type, const void *value)
|
||||
void cp_vset(const char *varname, enum cp_types type,
|
||||
const void *value)
|
||||
{
|
||||
struct variable *v, *u, *w;
|
||||
int i;
|
||||
|
|
@ -387,14 +389,12 @@ static void update_option_variables(const char *sz_var_name,
|
|||
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 */
|
||||
struct variable *
|
||||
cp_setparse(wordlist *wl)
|
||||
struct variable *cp_setparse(wordlist *wl)
|
||||
{
|
||||
char *name = NULL, *val, *copyval, *s, *ss;
|
||||
double *td;
|
||||
struct variable *listv = NULL, *vv, *lv = NULL;
|
||||
struct variable *vars = NULL;
|
||||
int balance;
|
||||
|
||||
/* 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
|
||||
|
|
@ -415,21 +415,22 @@ cp_setparse(wordlist *wl)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (wl && eq(wl->wl_word, "=")) {
|
||||
if (wl && eq(wl->wl_word, "=")) { /* name<space>= */
|
||||
wl = wl->wl_next;
|
||||
if (wl == NULL) {
|
||||
fprintf(cp_err, "Error: bad set form.\n");
|
||||
tfree(name); /*DG: cp_unquote Memory leak*/
|
||||
if (ft_stricterror)
|
||||
controlled_exit(EXIT_BAD);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
val = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
} else if (wl && (*wl->wl_word == '=')) {
|
||||
} else if (wl && (*wl->wl_word == '=')) { /* name<space>=val */
|
||||
val = wl->wl_word + 1;
|
||||
wl = wl->wl_next;
|
||||
} else if ((s = strchr(name, '=')) != NULL) {
|
||||
/* name=<space>value or name=value */
|
||||
val = s + 1;
|
||||
*s = '\0';
|
||||
if (*val == '\0') {
|
||||
|
|
@ -438,18 +439,19 @@ cp_setparse(wordlist *wl)
|
|||
tfree(name); /*DG: cp_unquote Memory leak: free name before exiting*/
|
||||
if (ft_stricterror)
|
||||
controlled_exit(EXIT_BAD);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
} else {
|
||||
val = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
fprintf(cp_err, "Error: bad set form.\n");
|
||||
tfree(name); /*DG: cp_unquote Memory leak: free name befor exiting */
|
||||
if (ft_stricterror)
|
||||
controlled_exit(EXIT_BAD);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if val is in double quotes, treat as string */
|
||||
|
|
@ -463,11 +465,12 @@ cp_setparse(wordlist *wl)
|
|||
strcpy(val, copyval);
|
||||
tfree(copyval);
|
||||
|
||||
/* Test for a list variable */
|
||||
if (eq(val, "(")) {
|
||||
/* 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;
|
||||
int balance = 1;
|
||||
while (wl && wl->wl_word) {
|
||||
if (eq(wl->wl_word, "(")) {
|
||||
balance++;
|
||||
|
|
@ -481,11 +484,13 @@ cp_setparse(wordlist *wl)
|
|||
vv = var_alloc_string(NULL, copy(ss), NULL);
|
||||
}
|
||||
else {
|
||||
td = ft_numparse(&ss, FALSE);
|
||||
if (td)
|
||||
vv = var_alloc_real(NULL, *td, NULL);
|
||||
else
|
||||
double dbl_val;
|
||||
if (ft_numparse(&ss, FALSE, &dbl_val) >= 0) {
|
||||
vv = var_alloc_real(NULL, dbl_val, NULL);
|
||||
}
|
||||
else {
|
||||
vv = var_alloc_string(NULL, copy(ss), NULL);
|
||||
}
|
||||
}
|
||||
tfree(copyval);
|
||||
if (listv) {
|
||||
|
|
@ -501,9 +506,10 @@ cp_setparse(wordlist *wl)
|
|||
tfree(name); /* va: cp_unquote memory leak: free name before exiting */
|
||||
if (ft_stricterror)
|
||||
controlled_exit(EXIT_BAD);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add list variable to linked list of variables. */
|
||||
vars = var_alloc_vlist(copy(name), listv, vars);
|
||||
|
||||
wl = wl->wl_next;
|
||||
|
|
@ -516,10 +522,10 @@ cp_setparse(wordlist *wl)
|
|||
vars = var_alloc_string(copy(name), copy(copyval), vars);
|
||||
}
|
||||
else {
|
||||
td = ft_numparse(&ss, FALSE);
|
||||
if (td) {
|
||||
double dbl_val;
|
||||
if (ft_numparse(&ss, FALSE, &dbl_val) >= 0) {
|
||||
/*** We should try to get CP_NUM's... */
|
||||
vars = var_alloc_real(name, *td, vars);
|
||||
vars = var_alloc_real(name, dbl_val, vars);
|
||||
}
|
||||
else {
|
||||
vars = var_alloc_string(name, copy(val), vars);
|
||||
|
|
@ -532,8 +538,9 @@ cp_setparse(wordlist *wl)
|
|||
if (name) {
|
||||
tfree(name);
|
||||
}
|
||||
return (vars);
|
||||
}
|
||||
return vars;
|
||||
} /* end of function cp_setparse */
|
||||
|
||||
|
||||
|
||||
/* free the struct variable. The type of the union is given by va_type */
|
||||
|
|
@ -543,15 +550,15 @@ free_struct_variable(struct variable *v)
|
|||
while (v) {
|
||||
struct variable *next_v = v->va_next;
|
||||
if (v->va_name)
|
||||
tfree(v->va_name);
|
||||
txfree(v->va_name);
|
||||
if (v->va_type == CP_LIST)
|
||||
free_struct_variable(v->va_vlist);
|
||||
if (v->va_type == CP_STRING)
|
||||
tfree(v->va_string);
|
||||
tfree(v);
|
||||
txfree(v->va_string);
|
||||
txfree(v);
|
||||
v = next_v;
|
||||
}
|
||||
}
|
||||
} /* end of function free_struct_variable */
|
||||
|
||||
|
||||
void cp_remvar(char *varname)
|
||||
|
|
@ -770,11 +777,19 @@ char cp_dol = '$';
|
|||
/* Non-alphanumeric characters that may appear in variable names. < is very
|
||||
* special...
|
||||
*/
|
||||
|
||||
#define VALIDCHARS "$-_<#?@.()[]&"
|
||||
|
||||
char *
|
||||
span_var_expr(char *t)
|
||||
/* This function determines the first character after a variable name and
|
||||
* returns its address.
|
||||
*
|
||||
* Parameter
|
||||
* t: Address of the variable name whose end is to be found. This is the
|
||||
* address of the first character following the leading $
|
||||
*
|
||||
* Return value
|
||||
* Address of the first character after the variable name.
|
||||
*/
|
||||
char *span_var_expr(char *t)
|
||||
{
|
||||
int parenthesis = 0;
|
||||
int brackets = 0;
|
||||
|
|
@ -805,12 +820,11 @@ span_var_expr(char *t)
|
|||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
} /* end of function span_var_expr */
|
||||
|
||||
|
||||
/* Substitute variable name by its value and restore to wordlist */
|
||||
wordlist *
|
||||
cp_variablesubst(wordlist *wlist)
|
||||
wordlist *cp_variablesubst(wordlist *wlist)
|
||||
{
|
||||
wordlist *wl;
|
||||
|
||||
|
|
@ -849,24 +863,26 @@ cp_variablesubst(wordlist *wlist)
|
|||
tfree(x);
|
||||
} else {
|
||||
wordlist *next = wl->wl_next;
|
||||
if (wlist == wl)
|
||||
if (wlist == wl) {
|
||||
wlist = next;
|
||||
}
|
||||
wl_delete_slice(wl, next);
|
||||
if (!next)
|
||||
if (!next) { /* wordlist ends after wl */
|
||||
return wlist;
|
||||
}
|
||||
wl = next;
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end of loop over parts of wordlist node */
|
||||
} /* end of loop over words in wordlist */
|
||||
|
||||
return wlist;
|
||||
} /* end of function cp_variablesubst */
|
||||
|
||||
return (wlist);
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate a variable. */
|
||||
wordlist *
|
||||
vareval(char *string)
|
||||
wordlist *vareval(/* NOT const */ char *string)
|
||||
{
|
||||
struct variable *v, *vfree = NULL;
|
||||
wordlist *wl;
|
||||
|
|
@ -887,8 +903,8 @@ vareval(char *string)
|
|||
|
||||
case '$':
|
||||
wl = wl_cons(tprintf("%d", getpid()), NULL);
|
||||
tfree(oldstring);
|
||||
return (wl);
|
||||
txfree(oldstring);
|
||||
return wl;
|
||||
|
||||
case '<':
|
||||
(void) fflush(cp_out);
|
||||
|
|
@ -903,8 +919,8 @@ vareval(char *string)
|
|||
/* This is a hack. */
|
||||
if (!wl->wl_word)
|
||||
wl->wl_word = copy("");
|
||||
tfree(oldstring);
|
||||
return (wl);
|
||||
txfree(oldstring);
|
||||
return wl;
|
||||
|
||||
case '?':
|
||||
string++;
|
||||
|
|
@ -918,8 +934,8 @@ vareval(char *string)
|
|||
}
|
||||
wl = wl_cons(copy(v ? "1" : "0"), NULL);
|
||||
free_struct_variable(vfree);
|
||||
tfree(oldstring);
|
||||
return (wl);
|
||||
txfree(oldstring);
|
||||
return wl;
|
||||
|
||||
case '#':
|
||||
string++;
|
||||
|
|
@ -933,23 +949,26 @@ vareval(char *string)
|
|||
}
|
||||
if (!v) {
|
||||
fprintf(cp_err, "Error: %s: no such variable.\n", string);
|
||||
tfree(oldstring);
|
||||
return (NULL);
|
||||
txfree(oldstring);
|
||||
return NULL;
|
||||
}
|
||||
if (v->va_type == CP_LIST)
|
||||
for (v = v->va_vlist, i = 0; v; v = v->va_next)
|
||||
if (v->va_type == CP_LIST) {
|
||||
for (v = v->va_vlist, i = 0; v; v = v->va_next) {
|
||||
i++;
|
||||
else
|
||||
}
|
||||
}
|
||||
else {
|
||||
i = (v->va_type != CP_BOOL);
|
||||
}
|
||||
wl = wl_cons(tprintf("%d", i), NULL);
|
||||
tfree(oldstring);
|
||||
txfree(oldstring);
|
||||
free_struct_variable(vfree);
|
||||
return (wl);
|
||||
return wl;
|
||||
|
||||
case '\0':
|
||||
wl = wl_cons(copy("$"), NULL);
|
||||
tfree(oldstring);
|
||||
return (wl);
|
||||
txfree(oldstring);
|
||||
return wl;
|
||||
}
|
||||
|
||||
vfree = NULL; //just in case ...
|
||||
|
|
@ -980,8 +999,8 @@ vareval(char *string)
|
|||
}
|
||||
if (!v) {
|
||||
fprintf(cp_err, "Error: %s: no such variable.\n", string);
|
||||
tfree(oldstring);
|
||||
return (NULL);
|
||||
txfree(oldstring);
|
||||
return NULL;
|
||||
}
|
||||
wl = cp_varwl(v);
|
||||
free_struct_variable(vfree);
|
||||
|
|
@ -1000,7 +1019,7 @@ vareval(char *string)
|
|||
r = vareval(range);
|
||||
if (!r || r->wl_next) {
|
||||
fprintf(cp_err, "Error: %s: illegal index.\n", string);
|
||||
tfree(oldstring);
|
||||
txfree(oldstring);
|
||||
wl_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1018,8 +1037,9 @@ vareval(char *string)
|
|||
up--, low--;
|
||||
wl = wl_range(wl, low, up);
|
||||
wl_free(r);
|
||||
}
|
||||
tfree(oldstring);
|
||||
} /* end of case of range given for variable */
|
||||
|
||||
txfree(oldstring);
|
||||
return (wl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
#define ngspice_CPSTD_H
|
||||
|
||||
|
||||
#ifndef FILE
|
||||
/* XXX Bogus */
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
/* FIXME: Split this file and adjust all callers to use new header files */
|
||||
#if 0
|
||||
|
|
@ -23,6 +20,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
#endif
|
||||
|
||||
#include "ngspice/bool.h"
|
||||
#include "ngspice/dstring.h"
|
||||
#include "ngspice/wordlist.h"
|
||||
#include "ngspice/complex.h"
|
||||
|
||||
|
|
@ -30,8 +28,12 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
|||
|
||||
extern char *tildexpand(char *string);
|
||||
extern void printnum(char *buf, double num);
|
||||
int printnum_ds(DSTRING *p_ds, double num);
|
||||
extern int cp_numdgt;
|
||||
|
||||
extern void cp_printword(char *string, FILE *fp);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ extern void ft_polyderiv(double *coeffs, int degree);
|
|||
/* numparse.c */
|
||||
|
||||
extern bool ft_strictnumparse;
|
||||
double *ft_numparse(char **s, bool whole);
|
||||
int ft_numparse(char **s, bool whole, double *p_val);
|
||||
|
||||
/* options.c */
|
||||
|
||||
|
|
|
|||
|
|
@ -8,23 +8,49 @@ Modified: 2001 Paolo Nenzi
|
|||
* It is up to the caller to allocate space for strings.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "printnum.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int cp_numdgt = -1;
|
||||
|
||||
void printnum(char *buf, double num)
|
||||
|
||||
static inline int get_num_width(double num)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (cp_numdgt > 1)
|
||||
if (cp_numdgt > 1) {
|
||||
n = cp_numdgt;
|
||||
else
|
||||
}
|
||||
else {
|
||||
n = 6;
|
||||
if (num < 0.0)
|
||||
}
|
||||
if (num < 0.0 && n > 1) {
|
||||
n--;
|
||||
}
|
||||
|
||||
return n;
|
||||
} /* end of function get_num_width */
|
||||
|
||||
|
||||
|
||||
/* This funtion writes num to buf. It can cause buffer overruns. The size of
|
||||
* buf is unknown, so cp_numdgt can be large enough to cause sprintf()
|
||||
* to write past the end of the array. */
|
||||
void printnum(char *buf, double num)
|
||||
{
|
||||
int n = get_num_width(num);
|
||||
(void) sprintf(buf, "%.*e", n, num);
|
||||
|
||||
}
|
||||
} /* end of function printnum */
|
||||
|
||||
|
||||
|
||||
int printnum_ds(DSTRING *p_ds, double num)
|
||||
{
|
||||
const int n = get_num_width(num);
|
||||
return ds_cat_printf(p_ds, "%.*e", n, num);
|
||||
} /* end of function printnum_ds */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#ifndef ngspice_PRINTNUM_H
|
||||
#define ngspice_PRINTNUM_H
|
||||
|
||||
void printnum(char * buf, double num);
|
||||
#include "ngspice/dstring.h"
|
||||
|
||||
void printnum(char *buf, double num);
|
||||
int printnum_ds(DSTRING *p_dstring, double num);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue