Browse Source

Made ft_numparse() thread-safe (no internal static variables) and prepared to support ngspice variable type CP_NUM.

pre-master-46
Jim Monte 6 years ago
committed by Holger Vogt
parent
commit
068df274bf
  1. 48
      src/frontend/breakp.c
  2. 128
      src/frontend/com_compose.c
  3. 17
      src/frontend/com_fft.c
  4. 30
      src/frontend/com_measure2.c
  5. 80
      src/frontend/control.c
  6. 110
      src/frontend/dotcards.c
  7. 7
      src/frontend/fourier.c
  8. 274
      src/frontend/parse.c
  9. 265
      src/frontend/parser/numparse.c
  10. 21
      src/frontend/plotting/plotit.c
  11. 44
      src/frontend/postcoms.c
  12. 69
      src/frontend/spec.c
  13. 142
      src/frontend/variable.c
  14. 10
      src/include/ngspice/cpstd.h
  15. 2
      src/include/ngspice/fteext.h
  16. 40
      src/misc/printnum.c
  17. 5
      src/misc/printnum.h

48
src/frontend/breakp.c

@ -46,7 +46,6 @@ com_stop(wordlist *wl)
struct dbcomm *d = NULL; struct dbcomm *d = NULL;
char *s, buf[64]; char *s, buf[64];
int i; int i;
double *val;
while (wl) { while (wl) {
if (thisone == NULL) { if (thisone == NULL) {
@ -80,10 +79,9 @@ com_stop(wordlist *wl)
/* cp_lexer(string) will not discriminate '=', so we have /* cp_lexer(string) will not discriminate '=', so we have
to do it here */ to do it here */
if (strchr(wl->wl_next->wl_word, '=') && 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 */ /* we have vec=val in a single word */
wordlist *wln; wordlist *wln;
char **charr = TMALLOC(char*, 4); char **charr = TMALLOC(char*, 4);
@ -98,17 +96,23 @@ com_stop(wordlist *wl)
wln = wl_build((const char * const *) charr); wln = wl_build((const char * const *) charr);
wl_splice(wl->wl_next, wln); wl_splice(wl->wl_next, wln);
} }
/* continue with parsing the enhanced wordlist */ /* continue with parsing the enhanced wordlist */
if (wl->wl_next->wl_next && wl->wl_next->wl_next->wl_next) { if (wl->wl_next->wl_next && wl->wl_next->wl_next->wl_next) {
wl = wl->wl_next; wl = wl->wl_next;
d->db_number = debugnumber; d->db_number = debugnumber;
d->db_type = DB_STOPWHEN; d->db_type = DB_STOPWHEN;
s = wl->wl_word; 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; wl = wl->wl_next;
/* Now get the condition */ /* Now get the condition */
@ -130,17 +134,23 @@ com_stop(wordlist *wl)
/* Now see about the second one. */ /* Now see about the second one. */
s = wl->wl_word; 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); d->db_nodename2 = copy(wl->wl_word);
}
}
wl = wl->wl_next; wl = wl->wl_next;
} else {
}
else {
goto bad; goto bad;
} }
}
}
} /* end of case of word "when" */
} /* end of loop over wordlist */
if (thisone) { if (thisone) {
if (dbs) { if (dbs) {
@ -159,11 +169,11 @@ com_stop(wordlist *wl)
bad: bad:
fprintf(cp_err, "Syntax error parsing breakpoint specification.\n"); 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 ..."*/
/* Trace a node (have wrd_point print it). Usage is "trace node ..."*/
void void
com_trce(wordlist *wl) com_trce(wordlist *wl)
{ {

128
src/frontend/com_compose.c

@ -1,5 +1,7 @@
/* The 'compose' command. This is a more powerful and convenient form /* The 'compose' command. This is a more powerful and convenient form
* of the 'let' command. */ * of the 'let' command. */
#include <math.h> /* log10 */
#include "ngspice/ngspice.h" #include "ngspice/ngspice.h"
#include "ngspice/complex.h" #include "ngspice/complex.h"
#include "ngspice/dvec.h" #include "ngspice/dvec.h"
@ -14,7 +16,6 @@
#include "com_compose.h" #include "com_compose.h"
#include "completion.h" #include "completion.h"
#include <math.h> /* log10 */
/* Copy the data from a vector into a buffer with larger dimensions. */ /* Copy the data from a vector into a buffer with larger dimensions. */
static void static void
@ -103,8 +104,7 @@ com_compose(wordlist *wl)
int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0; int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0;
int i; int i;
char *s, *var, *val;
double *td, tt;
double tt;
double *data = NULL; double *data = NULL;
ngcomplex_t *cdata = NULL; ngcomplex_t *cdata = NULL;
int length = 0; int length = 0;
@ -227,9 +227,11 @@ com_compose(wordlist *wl)
} }
length *= blocksize; length *= blocksize;
} else {
}
else {
/* Parse the line... */ /* Parse the line... */
while (wl) { while (wl) {
char *s, *var, *val;
if ((s = strchr(wl->wl_word, '=')) != NULL && s[1]) { if ((s = strchr(wl->wl_word, '=')) != NULL && s[1]) {
/* This is var=val. */ /* This is var=val. */
*s = '\0'; *s = '\0';
@ -278,109 +280,124 @@ com_compose(wordlist *wl)
} }
if (cieq(var, "start")) { if (cieq(var, "start")) {
startgiven = TRUE; startgiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &start) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
start = *td;
} else if (cieq(var, "stop")) {
}
else if (cieq(var, "stop")) {
stopgiven = TRUE; stopgiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &stop) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
stop = *td;
} else if (cieq(var, "step")) {
}
else if (cieq(var, "step")) {
stepgiven = TRUE; stepgiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &step) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
step = *td;
} else if (cieq(var, "center")) {
}
else if (cieq(var, "center")) {
centergiven = TRUE; centergiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &center) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
center = *td;
} else if (cieq(var, "span")) {
}
else if (cieq(var, "span")) {
spangiven = TRUE; spangiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &span) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
span = *td;
} else if (cieq(var, "mean")) {
}
else if (cieq(var, "mean")) {
meangiven = TRUE; meangiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &mean) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
mean = *td;
} else if (cieq(var, "sd")) {
}
else if (cieq(var, "sd")) {
sdgiven = TRUE; sdgiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &sd) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
sd = *td;
} else if (cieq(var, "lin")) {
}
else if (cieq(var, "lin")) {
lingiven = TRUE; lingiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &lin) < 0) {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
lin = *td;
} else if (cieq(var, "log")) {
}
else if (cieq(var, "log")) {
double dbl_val;
loggiven = TRUE; 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, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
log = (int)(*td);
} else if (cieq(var, "dec")) {
log = (int) dbl_val;
}
else if (cieq(var, "dec")) {
double dbl_val;
decgiven = TRUE; 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, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
dec = (int)(*td);
} else if (cieq(var, "oct")) {
dec = (int) dbl_val;
}
else if (cieq(var, "oct")) {
double dbl_val;
octgiven = TRUE; 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, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
oct = (int)(*td);
} else if (cieq(var, "gauss")) {
oct = (int) dbl_val;
}
else if (cieq(var, "gauss")) {
double dbl_val;
gaussgiven = TRUE; 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, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
gauss = (int)(*td);
} else if (cieq(var, "unif")) {
gauss = (int) dbl_val;
}
else if (cieq(var, "unif")) {
double dbl_val;
unifgiven = TRUE; unifgiven = TRUE;
if ((td = ft_numparse(&val, FALSE)) == NULL) {
if (ft_numparse(&val, FALSE, &dbl_val)<= 0) {
/* cannot convert to int */
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> bad parm %s = %s\n", var, val); "Error: compose -> bad parm %s = %s\n", var, val);
goto done; goto done;
} }
unif = (int)(*td);
} else {
unif = (int) dbl_val;
}
else {
fprintf(cp_err, "Error: compose -> bad parm %s\n", var); fprintf(cp_err, "Error: compose -> bad parm %s\n", var);
goto done; goto done;
} }
@ -405,7 +422,8 @@ com_compose(wordlist *wl)
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n"); "Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n");
goto done; 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. */ /* Hmm, if we have a start, stop, and step we're ok. */
if (startgiven && stopgiven && stepgiven) { if (startgiven && stopgiven && stepgiven) {
lingiven = TRUE; lingiven = TRUE;
@ -415,7 +433,8 @@ com_compose(wordlist *wl)
} }
lin = (stop - start) / step + 1.; lin = (stop - start) / step + 1.;
stepgiven = FALSE; /* Problems below... */ stepgiven = FALSE; /* Problems below... */
} else {
}
else {
fprintf(cp_err, fprintf(cp_err,
"Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n"); "Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n");
fprintf(cp_err, fprintf(cp_err,
@ -463,10 +482,12 @@ com_compose(wordlist *wl)
step = (stop - start) / (lin - 1.0); 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; data[i] = tt;
}
} else if (loggiven || decgiven || octgiven) {
}
else if (loggiven || decgiven || octgiven) {
/* Create a log sweep... */ /* Create a log sweep... */
if (centergiven && spangiven) { if (centergiven && spangiven) {
if (center <= span/2.0) { if (center <= span/2.0) {
@ -505,7 +526,8 @@ com_compose(wordlist *wl)
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
data[i] = start * pow(stop/start, (double)i/(log-1.0)); data[i] = start * pow(stop/start, (double)i/(log-1.0));
} else if (unifgiven) {
}
else if (unifgiven) {
/* Create a set of uniform distributed values... */ /* Create a set of uniform distributed values... */
if (startgiven || stopgiven) { if (startgiven || stopgiven) {
if (!startgiven || !stopgiven) { if (!startgiven || !stopgiven) {
@ -541,7 +563,8 @@ com_compose(wordlist *wl)
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
data[i] = mean + span * 0.5 * drand(); data[i] = mean + span * 0.5 * drand();
} else if (gaussgiven) {
}
else if (gaussgiven) {
/* Create a gaussian distribution... */ /* Create a gaussian distribution... */
if (gauss <= 0) { if (gauss <= 0) {
fprintf(cp_err, fprintf(cp_err,
@ -558,8 +581,9 @@ com_compose(wordlist *wl)
} }
length = gauss; length = gauss;
data = TMALLOC(double, length); data = TMALLOC(double, length);
for (i = 0; i < length; i++)
for (i = 0; i < length; i++) {
data[i] = mean + sd * gauss1(); data[i] = mean + sd * gauss1();
}
} }
} }
@ -589,5 +613,5 @@ com_compose(wordlist *wl)
done: done:
free_pnode(names); free_pnode(names);
tfree(resname);
}
txfree(resname);
} /* end of function com_compose */

17
src/frontend/com_fft.c

@ -241,7 +241,7 @@ com_psd(wordlist *wl)
{ {
ngcomplex_t **fdvec = NULL; ngcomplex_t **fdvec = NULL;
double **tdvec = NULL; double **tdvec = NULL;
double *freq, *win = NULL, *time, *ave;
double *freq, *win = NULL, *time;
double span, noipower; double span, noipower;
int ngood, fpts, i, j, jj, length, smooth, hsmooth; int ngood, fpts, i, j, jj, length, smooth, hsmooth;
char *s; char *s;
@ -278,12 +278,15 @@ com_psd(wordlist *wl)
// get filter length from parameter input // get filter length from parameter input
s = wl->wl_word; 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; wl = wl->wl_next;

30
src/frontend/com_measure2.c

@ -21,8 +21,8 @@ typedef enum {
MEASUREMENT_FAILURE = 1 MEASUREMENT_FAILURE = 1
} MEASURE_VAL_T; } MEASURE_VAL_T;
#define MEASURE_DEFAULT -1
#define MEASURE_LAST_TRANSITION -2
#define MEASURE_DEFAULT (-1)
#define MEASURE_LAST_TRANSITION (-2)
typedef struct measure typedef struct measure
{ {
@ -1152,7 +1152,7 @@ measure_parse_stdParams(
{ {
int pCnt; int pCnt;
char *p, *pName, *pValue; char *p, *pName, *pValue;
double *engVal, engVal1;
double engVal1;
pCnt = 0; pCnt = 0;
while (wl != wlBreak) { while (wl != wlBreak) {
@ -1176,12 +1176,12 @@ measure_parse_stdParams(
if (strcasecmp(pValue, "LAST") == 0) { if (strcasecmp(pValue, "LAST") == 0) {
engVal1 = MEASURE_LAST_TRANSITION; 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"); sprintf(errbuf, "bad syntax of ??\n");
return 0; return 0;
} }
engVal1 = *engVal; // What is this ??
} }
if (strcasecmp(pName, "RISE") == 0) { if (strcasecmp(pName, "RISE") == 0) {
@ -1257,8 +1257,6 @@ measure_parse_find(
) )
{ {
int pCnt; int pCnt;
char *p, *pName, *pVal;
double *engVal, engVal1;
meas->m_vec = NULL; meas->m_vec = NULL;
meas->m_vec2 = NULL; meas->m_vec2 = NULL;
@ -1280,7 +1278,7 @@ measure_parse_find(
pCnt = 0; pCnt = 0;
while (wl != wlBreak) { while (wl != wlBreak) {
p = wl->wl_word;
char *p = wl->wl_word;
if (pCnt == 0) { if (pCnt == 0) {
meas->m_vec = cp_unquote(wl->wl_word); 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)) if (cieq("ac", meas->m_analysis) || cieq("sp", meas->m_analysis))
correct_vec(meas); correct_vec(meas);
} else if (pCnt == 1) { } else if (pCnt == 1) {
pName = strtok(p, "=");
pVal = strtok(NULL, "=");
char * const pName = strtok(p, "=");
char * const pVal = strtok(NULL, "=");
if (pVal == NULL) { if (pVal == NULL) {
sprintf(errbuf, "bad syntax of WHEN\n"); sprintf(errbuf, "bad syntax of WHEN\n");
@ -1297,16 +1295,12 @@ measure_parse_find(
} }
if (strcasecmp(pName, "AT") == 0) { 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"); sprintf(errbuf, "bad syntax of WHEN\n");
return 0; return 0;
} }
engVal1 = *engVal;
meas->m_at = engVal1;
} else {
}
else {
sprintf(errbuf, "bad syntax of WHEN\n"); sprintf(errbuf, "bad syntax of WHEN\n");
return 0; return 0;
} }

80
src/frontend/control.c

@ -29,13 +29,13 @@ static void cp_free_control(void); /* needed by resetcontrol */
* more clever. */ * more clever. */
bool cp_cwait = FALSE; bool cp_cwait = FALSE;
char *cp_csep = ";";
char *cp_csep = ";"; /* character that separates commands */
bool cp_dounixcom = FALSE; bool cp_dounixcom = FALSE;
/* We have to keep the control structures in a stack, so that when we /* 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 * 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... */ * control structs, and one for the 'current command' pointer... */
struct control *control[CONTROLSTACKSIZE]; struct control *control[CONTROLSTACKSIZE];
struct control *cend[CONTROLSTACKSIZE]; struct control *cend[CONTROLSTACKSIZE];
@ -62,12 +62,13 @@ int stackp = 0;
static char *noredirect[] = { "stop", "define", NULL }; 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) { 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; break;
}
ct = ct->co_next; ct = ct->co_next;
} }
return (ct); return (ct);
@ -116,7 +117,7 @@ ctl_free(struct control *ctrl)
wl_free(ctrl->co_cond); wl_free(ctrl->co_cond);
ctrl->co_cond = NULL; ctrl->co_cond = NULL;
tfree(ctrl->co_foreachvar);
txfree(ctrl->co_foreachvar);
ctrl->co_foreachvar = NULL; ctrl->co_foreachvar = NULL;
wl_free(ctrl->co_text); wl_free(ctrl->co_text);
ctrl->co_text = NULL; ctrl->co_text = NULL;
@ -288,8 +289,9 @@ doblock(struct control *bl, int *num)
switch (bl->co_type) { switch (bl->co_type) {
case CO_WHILE: case CO_WHILE:
if (!bl->co_children) { 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)) { while (bl->co_cond && cp_istrue(bl->co_cond)) {
if (!bl->co_children) cp_periodic(); /*CDHW*/ if (!bl->co_children) cp_periodic(); /*CDHW*/
@ -558,11 +560,11 @@ doblock(struct control *bl, int *num)
char * char *
get_alt_prompt(void) get_alt_prompt(void)
{ {
int i = 0, j;
int i = 0;
static char buf[MAX_CHEVRONS + 2]; /* includes terminating space & null */ static char buf[MAX_CHEVRONS + 2]; /* includes terminating space & null */
struct control *c; struct control *c;
/* if nothing on the command stack return NULL */
/* If nothing on the command stack return NULL */
if (cend[stackp] == NULL) if (cend[stackp] == NULL)
return NULL; return NULL;
@ -570,8 +572,9 @@ get_alt_prompt(void)
for (c = cend[stackp]->co_parent; c; c = c->co_parent) for (c = cend[stackp]->co_parent; c; c = c->co_parent)
i++; i++;
if (i <= 0)
if (i == 0) {
return NULL; return NULL;
}
/* Avoid overflow of buffer and /* Avoid overflow of buffer and
indicate when we've limited the chevrons by starting with a '+' */ 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 */ /* return one chevron per command stack depth */
for (j = 1; j < i; j++)
buf[j] = '>';
/* Add space and terminate */
buf[j] = ' ';
buf[j + 1] = '\0';
{
int j;
for (j = 1; j < i; j++)
buf[j] = '>';
/* Add space and terminate */
buf[j] = ' ';
buf[j + 1] = '\0';
}
return buf; return buf;
}
} /* end of function get_alt_prompt */
/* Get a command. This does all the bookkeeping things like turning /* Get a command. This does all the bookkeeping things like turning
@ -601,8 +608,9 @@ getcommand(char *string)
{ {
wordlist *wlist; wordlist *wlist;
if (cp_debug)
if (cp_debug) {
fprintf(cp_err, "calling getcommand %s\n", string ? string : ""); fprintf(cp_err, "calling getcommand %s\n", string ? string : "");
}
#if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) #if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE)
/* set cp_altprompt for use by the lexer - see parser/lexical.c */ /* set cp_altprompt for use by the lexer - see parser/lexical.c */
@ -617,7 +625,7 @@ getcommand(char *string)
wl_print(wlist, stdout); wl_print(wlist, stdout);
putc('\n', stdout); putc('\n', stdout);
} }
return (wlist);
return wlist;
} }
@ -628,7 +636,6 @@ cp_evloop(char *string)
wordlist *wlist, *ww, *freewl; wordlist *wlist, *ww, *freewl;
struct control *x; struct control *x;
char *i; char *i;
int nn;
#define newblock \ #define newblock \
do { \ do { \
@ -653,8 +660,9 @@ cp_evloop(char *string)
/* User just typed return. */ /* User just typed return. */
wl_free(wlist); /* va, avoid memory leak */ wl_free(wlist); /* va, avoid memory leak */
if (string) { if (string) {
return (1);
} else {
return 1;
}
else {
cp_event--; cp_event--;
continue; continue;
} }
@ -708,22 +716,23 @@ cp_evloop(char *string)
cend[stackp]->co_numtimes = -1; cend[stackp]->co_numtimes = -1;
} else { } else {
char *s; char *s;
double *dd;
double val;
struct wordlist *t; /*CDHW*/ struct wordlist *t; /*CDHW*/
/*CDHW wlist = cp_variablesubst(cp_bquote(cp_doglob(wl_copy(wlist)))); Wrong order? Leak? 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? */ t = cp_doglob(cp_bquote(cp_variablesubst(wl_copy(wlist)))); /*CDHW leak from cp_doglob? */
s = t->wl_next->wl_word; 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, fprintf(cp_err,
"Error: can't repeat a negative number of times\n"); "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, fprintf(cp_err,
"Error: bad repeat argument %s\n", "Error: bad repeat argument %s\n",
t->wl_next->wl_word); /* CDHW */ t->wl_next->wl_word); /* CDHW */
@ -805,7 +814,7 @@ cp_evloop(char *string)
cend[stackp]->co_numtimes = 1; cend[stackp]->co_numtimes = 1;
} }
} else if (eq(wlist->wl_word, "end")) { } 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) { if (!cend[stackp]->co_parent) {
fprintf(stderr, "Error: no block to end.\n"); fprintf(stderr, "Error: no block to end.\n");
cend[stackp]->co_type = CO_UNFILLED; cend[stackp]->co_type = CO_UNFILLED;
@ -824,8 +833,7 @@ cp_evloop(char *string)
} }
} else if (eq(wlist->wl_word, "else")) { } else if (eq(wlist->wl_word, "else")) {
if (!cend[stackp]->co_parent || 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"); fprintf(stderr, "Error: misplaced else.\n");
cend[stackp]->co_type = CO_UNFILLED; cend[stackp]->co_type = CO_UNFILLED;
} else { } else {
@ -847,7 +855,7 @@ cp_evloop(char *string)
* that gotos at the top level will work. * that gotos at the top level will work.
*/ */
do { do {
nn = 0; /* CDHW */
int nn = 0; /* CDHW */
i = doblock(x, &nn); i = doblock(x, &nn);
switch (*i) { switch (*i) {
case NORMAL: case NORMAL:
@ -873,8 +881,8 @@ cp_evloop(char *string)
wl_free(freewl); wl_free(freewl);
if (string) if (string)
return (1); /* The return value is irrelevant. */ return (1); /* The return value is irrelevant. */
}
}
} /* end of unconditional loop */
} /* end of function cp_evloop */
/* This blows away the control structures... */ /* This blows away the control structures... */

110
src/frontend/dotcards.c

@ -12,6 +12,7 @@ Modified: 2000 AlansFixes
#include <assert.h> #include <assert.h>
#include "ngspice/cpdefs.h" #include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h" #include "ngspice/ftedefs.h"
#include "ngspice/dstring.h"
#include "ngspice/dvec.h" #include "ngspice/dvec.h"
#include "ngspice/fteinp.h" #include "ngspice/fteinp.h"
#include "ngspice/sim.h" #include "ngspice/sim.h"
@ -200,8 +201,9 @@ ft_cktcoms(bool terse)
all.wl_next = NULL; all.wl_next = NULL;
all.wl_word = "all"; all.wl_word = "all";
if (!ft_curckt)
if (!ft_curckt) {
return 1; return 1;
}
plot_cur = setcplot("op"); plot_cur = setcplot("op");
if (!ft_curckt->ci_commands && !plot_cur) if (!ft_curckt->ci_commands && !plot_cur)
@ -249,8 +251,9 @@ ft_cktcoms(bool terse)
} }
fprintf(cp_out, "\n"); fprintf(cp_out, "\n");
if (!ft_nomod)
if (!ft_nomod) {
com_showmod(&all); com_showmod(&all);
}
com_show(&all); com_show(&all);
} }
} }
@ -271,8 +274,10 @@ ft_cktcoms(bool terse)
/* Now all the '.' lines */ /* Now all the '.' lines */
while (coms) { while (coms) {
command = cp_lexer(coms->wl_word); command = cp_lexer(coms->wl_word);
if (!command)
if (!command || command->wl_word == (char *) NULL) {
/* Line not converted to a wordlist */
goto bad; goto bad;
}
if (eq(command->wl_word, ".width")) { if (eq(command->wl_word, ".width")) {
do do
command = command->wl_next; command = command->wl_next;
@ -360,12 +365,11 @@ ft_cktcoms(bool terse)
!eq(command->wl_word, ".op") && !eq(command->wl_word, ".op") &&
// !eq(command->wl_word, ".measure") && // !eq(command->wl_word, ".measure") &&
!ciprefix(".meas", command->wl_word) && !ciprefix(".meas", command->wl_word) &&
!eq(command->wl_word, ".tf"))
{
!eq(command->wl_word, ".tf")) {
goto bad; goto bad;
} }
coms = coms->wl_next;
}
coms = coms->wl_next; /* go to next line */
} /* end of loop over '.' lines */
nocmds: nocmds:
/* Now the node table /* Now the node table
@ -399,7 +403,7 @@ bad:
/* These routines make sure that the arguments to .plot and .print in /* 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 * trailing (a,b) in .plot -> xlimit a b
* vm(x) -> mag(v(x)) * vm(x) -> mag(v(x))
* vp(x) -> ph(v(x)) * vp(x) -> ph(v(x))
@ -410,60 +414,70 @@ bad:
static void static void
fixdotplot(wordlist *wl) 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) { while (wl) {
wl->wl_word = fixem(wl->wl_word); 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 == '(')) { 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", fprintf(cp_err, "Error: bad limits \"%s\"\n",
wl->wl_word); 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", fprintf(cp_err, "Error: bad limits \"%s\"\n",
wl->wl_word); wl->wl_word);
return;
goto EXITPOINT;
} }
d2 = *d;
tfree(wl->wl_word); tfree(wl->wl_word);
wl->wl_word = copy("xlimit"); 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; 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) { while (wl) {
wl->wl_word = fixem(wl->wl_word); wl->wl_word = fixem(wl->wl_word);
wl = wl->wl_next; 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 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, ',')) { if (ciprefix("v(", string) &&strchr(string, ',')) {
for (s = string; *s && (*s != ','); s++) for (s = string; *s && (*s != ','); s++)
@ -550,14 +564,15 @@ fixem(char *string)
string += 2; string += 2;
(void) sprintf(buf, "%s#branch", string); (void) sprintf(buf, "%s#branch", string);
} else { } else {
return (string);
return string;
} }
tfree(ss);
txfree(ss);
string = copy(buf); string = copy(buf);
return (string);
}
return string;
} /* end of function fixem */
wordlist * wordlist *
@ -611,7 +626,8 @@ gettoks(char *s)
sprintf(buf, "%s#branch", l + 1); sprintf(buf, "%s#branch", l + 1);
wl->wl_word = copy(buf); wl->wl_word = copy(buf);
c = r = NULL; c = r = NULL;
} else {
}
else {
wl->wl_word = copy(l + 1); wl->wl_word = copy(l + 1);
} }
@ -622,7 +638,11 @@ gettoks(char *s)
prevp = &wl->wl_next; prevp = &wl->wl_next;
} }
tfree(t); tfree(t);
}
tfree(s0);
} /* end of loop parsing string */
txfree(s0);
return list; return list;
}
} /* end of function gettoks */

7
src/frontend/fourier.c

@ -41,7 +41,7 @@ fourier(wordlist *wl, struct plot *current_plot)
{ {
struct dvec *time, *vec; struct dvec *time, *vec;
struct pnode *pn, *names; struct pnode *pn, *names;
double *ff, fundfreq, *data = NULL;
double fundfreq, *data = NULL;
int nfreqs, fourgridsize, polydegree; int nfreqs, fourgridsize, polydegree;
double *freq, *mag, *phase, *nmag, *nphase; /* Outputs from CKTfour */ double *freq, *mag, *phase, *nmag, *nphase; /* Outputs from CKTfour */
double thd, *timescale = NULL; double thd, *timescale = NULL;
@ -78,11 +78,10 @@ fourier(wordlist *wl, struct plot *current_plot)
return 1; return 1;
} }
s = wl->wl_word; 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; return 1;
} }
fundfreq = *ff;
freq = TMALLOC(double, nfreqs); freq = TMALLOC(double, nfreqs);
mag = TMALLOC(double, nfreqs); mag = TMALLOC(double, nfreqs);

274
src/frontend/parse.c

@ -29,8 +29,7 @@ extern int PPparse(char **, struct pnode **);
void db_print_pnode_tree(struct pnode *p, char *print); 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; struct pnode *pn;
@ -62,7 +61,7 @@ ft_getpnames(const wordlist *wl, bool check)
return (struct pnode *) NULL; 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); const char * const sz = wl_flatten(wl);
struct pnode * const pn = ft_getpnames_from_string(sz, check); struct pnode * const pn = ft_getpnames_from_string(sz, check);
txfree((void *) sz); txfree((void *) sz);
@ -213,63 +212,70 @@ struct func func_not = { "not", cx_not };
/* Binary operator node. */ /* 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 op *o;
struct pnode *p; 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; break;
}
}
if (!o->op_name)
if (!o->op_name) {
fprintf(cp_err, "PP_mkbnode: Internal Error: no such op num %d\n", fprintf(cp_err, "PP_mkbnode: Internal Error: no such op num %d\n",
opnum); opnum);
}
p = alloc_pnode(); p = alloc_pnode();
p->pn_op = o; p->pn_op = o;
p->pn_left = arg1; p->pn_left = arg1;
if (p->pn_left)
if (p->pn_left) {
p->pn_left->pn_use++; p->pn_left->pn_use++;
}
p->pn_right = arg2; p->pn_right = arg2;
if (p->pn_right)
if (p->pn_right) {
p->pn_right->pn_use++; p->pn_right->pn_use++;
}
return (p);
}
return p;
} /* end of function PP_mkbnode */
/* Unary operator node. */
struct pnode *
PP_mkunode(int op, struct pnode *arg)
/* Unary operator node. */
struct pnode *PP_mkunode(int op, struct pnode *arg)
{ {
struct pnode *p; struct pnode *p;
struct op *o; struct op *o;
p = alloc_pnode(); 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; break;
}
}
if (!o->op_name)
if (!o->op_name) {
fprintf(cp_err, "PP_mkunode: Internal Error: no such op num %d\n", fprintf(cp_err, "PP_mkunode: Internal Error: no such op num %d\n",
op); op);
}
p->pn_op = o; p->pn_op = o;
p->pn_left = arg; p->pn_left = arg;
if (p->pn_left)
if (p->pn_left) {
p->pn_left->pn_use++; 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 /* 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 * the arguments, and then return a copy of the expression that it was
* defined to be. * 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 func *f;
struct pnode *p, *q; struct pnode *p, *q;
@ -292,15 +296,18 @@ PP_mkfnode(const char *func, struct pnode *arg)
(void) strcpy(buf, func); (void) strcpy(buf, func);
strtolower(buf); /* Make sure the case is ok. */ 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; break;
}
}
if (f->fu_name == NULL) {
if (f->fu_name == NULL) { /* not found yet */
/* Give the user-defined functions a try. */ /* Give the user-defined functions a try. */
q = ft_substdef(func, arg); q = ft_substdef(func, arg);
if (q)
return (q);
if (q) { /* found */
return q;
}
} }
if ((f->fu_name == NULL) && arg->pn_value) { if ((f->fu_name == NULL) && arg->pn_value) {
@ -312,15 +319,16 @@ PP_mkfnode(const char *func, struct pnode *arg)
/* Well, too bad. */ /* Well, too bad. */
fprintf(cp_err, "Error: no such function as %s.\n", fprintf(cp_err, "Error: no such function as %s.\n",
func); func);
return (NULL);
return (struct pnode *) NULL;
} }
/* (void) strcpy(buf, d->v_name); XXX */ /* (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", fprintf(cp_err, "Error: no function as %s with that arity.\n",
func); func);
free_pnode(arg); free_pnode(arg);
return (NULL);
return (struct pnode *) NULL;
} }
if (!f->fu_func && arg->pn_op && arg->pn_op->op_num == PT_OP_COMMA) { 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_func = f;
p->pn_left = arg; p->pn_left = arg;
if (p->pn_left)
if (p->pn_left) {
p->pn_left->pn_use++; p->pn_left->pn_use++;
}
return (p);
}
return p;
} /* end of function PP_mkfnode */
/* Number node. */
struct pnode *
PP_mknnode(double number)
/* Number node. */
struct pnode *PP_mknnode(double number)
{ {
struct pnode *p; struct pnode *p;
struct dvec *v; struct dvec *v;
@ -354,7 +362,7 @@ PP_mknnode(double number)
* to be careful to deal properly with node numbers that are quite * to be careful to deal properly with node numbers that are quite
* large... * large...
*/ */
v = dvec_alloc(number < MAXPOSINT
v = dvec_alloc(number <= INT_MAX
? tprintf("%d", (int) number) ? tprintf("%d", (int) number)
: tprintf("%G", number), : tprintf("%G", number),
SV_NOTYPE, SV_NOTYPE,
@ -368,13 +376,12 @@ PP_mknnode(double number)
p = alloc_pnode(); p = alloc_pnode();
p->pn_value = v; p->pn_value = v;
return (p); return (p);
}
} /* end of function PP_mknnode */
/* String node. */
struct pnode *
PP_mksnode(const char *string)
/* String node. */
struct pnode *PP_mksnode(const char *string)
{ {
struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL; struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL;
struct pnode *p; struct pnode *p;
@ -387,17 +394,19 @@ PP_mksnode(const char *string)
0, 0,
0, NULL); 0, NULL);
p->pn_value = nv; p->pn_value = nv;
return (p);
return p;
} }
/* It's not obvious that we should be doing this, but... */ /* It's not obvious that we should be doing this, but... */
for (vs = v; vs; vs = vs->v_link2) { for (vs = v; vs; vs = vs->v_link2) {
nv = vec_copy(vs); nv = vec_copy(vs);
vec_new(nv); vec_new(nv);
if (end)
if (end) {
end->v_link2 = nv; end->v_link2 = nv;
else
}
else {
newv = end = nv; newv = end = nv;
}
end = nv; end = nv;
} }
p->pn_value = newv; 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] /* 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 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 */ 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); struct pnode *pn = TMALLOC(struct pnode, 1);
@ -432,42 +441,45 @@ alloc_pnode(void)
pn->pn_next = NULL; pn->pn_next = NULL;
return pn; return pn;
}
} /* end of function alloc_pnode */
/* Don't call this directly, always use the free_pnode() macro. /* 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 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 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; 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 */ but the link gets severed by the action of the free_pnode() macro */
if (t->pn_use > 1) { if (t->pn_use > 1) {
t->pn_use--; t->pn_use--;
} else {
}
else {
/* pn_use is now 1, so its safe to free the pnode */ /* pn_use is now 1, so its safe to free the pnode */
free_pnode(t->pn_left); free_pnode(t->pn_left);
free_pnode(t->pn_right); free_pnode(t->pn_right);
free_pnode(t->pn_next); free_pnode(t->pn_next);
tfree(t->pn_name); /* va: it is a copy() of original string, can be free'd */ 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 */ 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) { if (!f) {
fprintf(fdst, "nil"); 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); 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) { if (!op) {
fprintf(fdst, "nil"); 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)", 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); 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) { if (!d) {
fprintf(fdst, "nil"); 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 ...)", 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); 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) { if (!p) {
fprintf(fdst, "nil\n"); 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 && 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, "(pnode-value :pn_use %d", p->pn_use);
fprintf(fdst, " :pn_value "); db_print_dvec(fdst, p->pn_value); fprintf(fdst, " :pn_value "); db_print_dvec(fdst, p->pn_value);
fprintf(fdst, ")\n"); 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 && 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, "(pnode-func :pn_use %d", p->pn_use);
fprintf(fdst, "\n :pn_func "); db_print_func(fdst, p->pn_func); fprintf(fdst, "\n :pn_func "); db_print_func(fdst, p->pn_func);
fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left); 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 && 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, "(pnode-op :pn_use %d", p->pn_use);
fprintf(fdst, "\n :pn_op "); db_print_op(fdst, p->pn_op); fprintf(fdst, "\n :pn_op "); db_print_op(fdst, p->pn_op);
fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left); 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_right "); db_print_pnode(fdst, p->pn_right);
fprintf(fdst, "\n :pn_next "); db_print_pnode(fdst, p->pn_next); fprintf(fdst, "\n :pn_next "); db_print_pnode(fdst, p->pn_next);
fprintf(fdst, "\n)\n"); 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 #if 1
NG_IGNORE(print); 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); printf("%s:%d: %s {%s}\n%s\n", __FILE__, __LINE__, __func__, print, buf);
tfree(buf); tfree(buf);
#endif #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%()-^+*,/|&<>~="; static char *specials = " \t%()-^+*,/|&<>~=";
char *sbuf = *line; char *sbuf = *line;
int token; int token;
while ((*sbuf == ' ') || (*sbuf == '\t'))
while ((*sbuf == ' ') || (*sbuf == '\t')) {
sbuf++; sbuf++;
}
llocp->start = sbuf; llocp->start = sbuf;
@ -590,28 +600,36 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
if ((sbuf[0] == 'g') && (sbuf[1] == 't') && if ((sbuf[0] == 'g') && (sbuf[1] == 't') &&
strchr(specials, sbuf[2])) { strchr(specials, sbuf[2])) {
lexer_return('>', 2); lexer_return('>', 2);
} else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
}
else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
strchr(specials, sbuf[2])) { strchr(specials, sbuf[2])) {
lexer_return('<', 2); lexer_return('<', 2);
} else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
}
else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) { strchr(specials, sbuf[2])) {
lexer_return(TOK_GE, 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])) { strchr(specials, sbuf[2])) {
lexer_return(TOK_LE, 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])) { strchr(specials, sbuf[2])) {
lexer_return(TOK_NE, 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])) { strchr(specials, sbuf[2])) {
lexer_return('=', 2); lexer_return('=', 2);
} else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
}
else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
strchr(specials, sbuf[2])) { strchr(specials, sbuf[2])) {
lexer_return('|', 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])) { (sbuf[2] == 'd') && strchr(specials, sbuf[3])) {
lexer_return('&', 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])) { (sbuf[2] == 't') && strchr(specials, sbuf[3])) {
lexer_return('~', 3); lexer_return('~', 3);
} }
@ -623,18 +641,19 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
lexer_return(*sbuf, 1); lexer_return(*sbuf, 1);
case '>': case '>':
case '<':
{
case '<': {
/* Workaround, The Frontend makes "<>" into "< >" */ /* Workaround, The Frontend makes "<>" into "< >" */
int j = 1;
size_t j = 1;
while (isspace_c(sbuf[j])) while (isspace_c(sbuf[j]))
j++; j++;
if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) { if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) {
/* Allow both <> and >< for NE. */ /* 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); lexer_return((sbuf[0] == '>') ? TOK_GE : TOK_LE, 2);
} else {
}
else {
lexer_return(*sbuf, 1); lexer_return(*sbuf, 1);
} }
} }
@ -659,26 +678,28 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
case '\0': case '\0':
lexer_return(*sbuf, 0); lexer_return(*sbuf, 0);
case '"':
{
case '"': {
char *start = ++sbuf; char *start = ++sbuf;
while (*sbuf && (*sbuf != '"')) while (*sbuf && (*sbuf != '"'))
sbuf++; sbuf++;
lvalp->str = copy_substring(start, sbuf); lvalp->str = copy_substring(start, sbuf);
if (*sbuf)
if (*sbuf) {
sbuf++; sbuf++;
}
lexer_return(TOK_STR, 0); lexer_return(TOK_STR, 0);
} }
default:
{
default: {
char *s = sbuf; 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; sbuf = s;
lvalp->num = *td;
lvalp->num = val;
lexer_return(TOK_NUM, 0); lexer_return(TOK_NUM, 0);
} else {
}
else {
int atsign = 0; int atsign = 0;
char *start = sbuf; char *start = sbuf;
/* It is bad how we have to recognise '[' -- sometimes /* 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 * i(v5) --> v5#branch
*/ */
for (; *sbuf && !strchr(specials, *sbuf); sbuf++) for (; *sbuf && !strchr(specials, *sbuf); sbuf++)
if (*sbuf == '@')
if (*sbuf == '@') {
atsign = 1; atsign = 1;
else if (!atsign && *sbuf == '[')
}
else if (!atsign && *sbuf == '[') {
break; break;
}
else if (*sbuf == ']') { else if (*sbuf == ']') {
if (atsign)
if (atsign) {
sbuf++; sbuf++;
}
break; break;
} }
@ -707,19 +731,25 @@ PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
lexer_return(TOK_STR, 0); lexer_return(TOK_STR, 0);
} }
} }
}
} /* end of switch over characters */
done: done:
if (ft_parsedb) { if (ft_parsedb) {
if (token == TOK_STR)
if (token == TOK_STR) {
fprintf(stderr, "lexer: TOK_STR, \"%s\"\n", lvalp->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); fprintf(stderr, "lexer: TOK_NUM, %G\n", lvalp->num);
else
}
else {
fprintf(stderr, "lexer: token %d\n", token); fprintf(stderr, "lexer: token %d\n", token);
}
} }
*line = sbuf; *line = sbuf;
llocp->stop = sbuf; llocp->stop = sbuf;
return (token);
}
return token;
} /* end of function PPlex */

265
src/frontend/parser/numparse.c

@ -4,6 +4,9 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/ **********/
/* This routine parses a number. */ /* This routine parses a number. */
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include "ngspice/ngspice.h" #include "ngspice/ngspice.h"
#include "ngspice/bool.h" #include "ngspice/bool.h"
@ -11,160 +14,226 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
#include "numparse.h" #include "numparse.h"
static double
power10(double num) /* Chris Inbody */
{
double d = 1.0;
bool ft_strictnumparse = FALSE;
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 /* 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. * 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 * 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 * if no number can be found or if there are trailing characters when
* whole is TRUE. * whole is TRUE.
* *
* If ft_strictnumparse is TRUE, and whole is FALSE, the first of the * 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;
/* See if the number begins with + or -. */
if (*string == '+') {
string++;
} else if (*string == '-') {
string++;
sign = -1;
}
double mant;
double expo;
const char *p_cur = *p_str; /* position in string */
/* 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). */ /* Now look for the scale factor or the exponent (can't have both). */
switch (*string) {
switch (*p_cur) {
case 'e': case 'e':
case 'E': case 'E':
/* Parse another number. */
string++;
if (*string == '+') {
exsign = 1;
string++;
} else if (*string == '-') {
exsign = -1;
string++;
}
while (isdigit_c(*string))
expo = expo * 10.0 + (*string++ - '0');
if (*string == '.') {
string++;
p = 1;
while (isdigit_c(*string))
expo += (*string++ - '0') / power10(p++);
/* 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 */
} }
expo *= exsign;
break; break;
case 't': case 't':
case 'T': case 'T':
expo = 12.0; expo = 12.0;
string++;
++p_cur;
break; break;
case 'g': case 'g':
case 'G': case 'G':
expo = 9.0; expo = 9.0;
string++;
++p_cur;
break; break;
case 'k': case 'k':
case 'K': case 'K':
expo = 3.0; expo = 3.0;
string++;
++p_cur;
break; break;
case 'u': case 'u':
case 'U': case 'U':
expo = -6.0; expo = -6.0;
string++;
++p_cur;
break; break;
case 'n': case 'n':
case 'N': case 'N':
expo = -9.0; expo = -9.0;
string++;
++p_cur;
break; break;
case 'p': case 'p':
case 'P': case 'P':
expo = -12.0; expo = -12.0;
string++;
++p_cur;
break; break;
case 'f': case 'f':
case 'F': case 'F':
expo = -15.0; expo = -15.0;
string++;
++p_cur;
break; break;
case 'm': case 'm':
case 'M':
case 'M': {
char ch_cur;
/* Can be either m, mil, or meg. */ /* 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; 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; expo = -6.0;
mant *= 25.4; mant *= 25.4;
string += 3;
} else {
p_cur += 3;
}
else { /* plain m for milli */
expo = -3.0; expo = -3.0;
string++;
++p_cur;
} }
break; break;
} }
default:
expo = 0.0;
}
/* 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;
}
}
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++;
/* 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;
} }
*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);
}
/* 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 */

21
src/frontend/plotting/plotit.c

@ -29,7 +29,6 @@ static bool sameflag;
static double * static double *
getlims(wordlist *wl, char *name, int number) getlims(wordlist *wl, char *name, int number)
{ {
double *d;
wordlist *beg, *wk; wordlist *beg, *wk;
int n; int n;
@ -43,39 +42,35 @@ getlims(wordlist *wl, char *name, int number)
wk = beg->wl_next; wk = beg->wl_next;
d = TMALLOC(double, number);
double * const d = TMALLOC(double, number); /* alloc for returned vals */
for (n = 0; n < number; n++) { for (n = 0; n < number; n++) {
char *ss; char *ss;
double *td;
if (!wk) { if (!wk) {
fprintf(cp_err, fprintf(cp_err,
"Syntax error: not enough parameters for \"%s\".\n", name); "Syntax error: not enough parameters for \"%s\".\n", name);
txfree(d); txfree(d);
return NULL;
return (double *) NULL;
} }
ss = wk->wl_word; 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, fprintf(cp_err,
"Syntax error: bad parameters for \"%s\".\n", name); "Syntax error: bad parameters for \"%s\".\n", name);
txfree(d); txfree(d);
return NULL;
return (double *) NULL;
} }
d[n] = *td;
wk = wk->wl_next; 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; return d;
}
} /* end of function getlims */
/* Extend a data vector to length by replicating the last element, or /* Extend a data vector to length by replicating the last element, or

44
src/frontend/postcoms.c

@ -444,8 +444,9 @@ com_write(wordlist *wl)
else else
names = ft_getpnames(&all, TRUE); names = ft_getpnames(&all, TRUE);
if (names == NULL)
if (names == NULL) {
return; return;
}
for (pn = names; pn; pn = pn->pn_next) { for (pn = names; pn; pn = pn->pn_next) {
d = ft_evaluate(pn); d = ft_evaluate(pn);
@ -731,22 +732,27 @@ com_transpose(wordlist *wl)
struct dvec *d; struct dvec *d;
char *s; 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); s = cp_unquote(wl->wl_word);
d = vec_get(s); d = vec_get(s);
tfree(s); /*DG: Avoid Memory Leak */ 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); 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) { while (d) {
vec_transpose(d); vec_transpose(d);
d = d->v_link2; 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. */ /* 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; struct pnode *pn, *names;
int i, ind; int i, ind;
bool comp = FALSE; bool comp = FALSE;
double *d;
newvec = wl->wl_word; newvec = wl->wl_word;
wl = wl->wl_next; wl = wl->wl_next;
s = wl->wl_word; 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; wl = wl->wl_next;
names = ft_getpnames(wl, TRUE); names = ft_getpnames(wl, TRUE);
for (pn = names; pn; pn = pn->pn_next) { for (pn = names; pn; pn = pn->pn_next) {

69
src/frontend/spec.c

@ -24,7 +24,7 @@ com_spec(wordlist *wl)
{ {
ngcomplex_t **fdvec = NULL; ngcomplex_t **fdvec = NULL;
double **tdvec = NULL; double **tdvec = NULL;
double *freq, *win = NULL, *time, *dc = NULL;
double *win = NULL, *time, *dc = NULL;
double startf, stopf, stepf, span; double startf, stopf, stepf, span;
int fpts, i, j, k, tlen, ngood; int fpts, i, j, k, tlen, ngood;
bool trace; bool trace;
@ -45,27 +45,24 @@ com_spec(wordlist *wl)
s = wl->wl_word; s = wl->wl_word;
tlen = (plot_cur->pl_scale)->v_length; 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); fprintf(cp_err, "Error: bad start freq %s\n", wl->wl_word);
goto done; goto done;
} }
startf = *freq;
wl = wl->wl_next; wl = wl->wl_next;
s = wl->wl_word; 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); fprintf(cp_err, "Error: bad stop freq %s\n", wl->wl_word);
goto done; goto done;
} }
stopf = *freq;
wl = wl->wl_next; wl = wl->wl_next;
s = wl->wl_word; 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); fprintf(cp_err, "Error: bad step freq %s\n", wl->wl_word);
goto done; goto done;
} }
stepf = *freq;
wl = wl->wl_next; wl = wl->wl_next;
time = (plot_cur->pl_scale)->v_realdata; time = (plot_cur->pl_scale)->v_realdata;
@ -212,9 +209,8 @@ com_spec(wordlist *wl)
VF_REAL | VF_PERMANENT | VF_PRINT, VF_REAL | VF_PERMANENT | VF_PRINT,
fpts, NULL); fpts, NULL);
vec_new(f); vec_new(f);
freq = f->v_realdata;
tdvec = TMALLOC(double *, ngood);
tdvec = TMALLOC(double *, ngood);
fdvec = TMALLOC(ngcomplex_t *, ngood); fdvec = TMALLOC(ngcomplex_t *, ngood);
for (i = 0, vec = vlist; i < ngood; i++) { for (i = 0, vec = vlist; i < ngood; i++) {
tdvec[i] = vec->v_realdata; tdvec[i] = vec->v_realdata;
@ -238,36 +234,41 @@ com_spec(wordlist *wl)
} }
} }
trace = cp_getvar("spectrace", CP_BOOL, NULL, 0); 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);
{
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++) { 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;
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 #ifdef HAS_PROGREP
SetAnalyse("spec", (int)(j * 1000./ fpts));
SetAnalyse("spec", (int)(j * 1000./ fpts));
#endif #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;
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;
}
} }
} }

142
src/frontend/variable.c

@ -77,11 +77,13 @@ wordlist *cp_varwl(struct variable *var)
} }
return wl_cons(buf, NULL); return wl_cons(buf, NULL);
}
} /* end of function cp_varwl */
/* Set a variable. */ /* 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; struct variable *v, *u, *w;
int i; int i;
@ -387,14 +389,12 @@ static void update_option_variables(const char *sz_var_name,
Generate variables (real, string or list) Generate variables (real, string or list)
Value in double quotes will always become string variable. 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 */ 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; char *name = NULL, *val, *copyval, *s, *ss;
double *td;
struct variable *listv = NULL, *vv, *lv = NULL; struct variable *listv = NULL, *vv, *lv = NULL;
struct variable *vars = NULL; struct variable *vars = NULL;
int balance;
/* Step through the list of words. Words may be various combinations of /* 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 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 * the value 3, the data could be supplied as one word x=3, two words
@ -415,21 +415,22 @@ cp_setparse(wordlist *wl)
continue; continue;
} }
if (wl && eq(wl->wl_word, "=")) {
if (wl && eq(wl->wl_word, "=")) { /* name<space>= */
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);
return (NULL);
return NULL;
} }
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<space>=val */
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) {
/* name=<space>value or name=value */
val = s + 1; val = s + 1;
*s = '\0'; *s = '\0';
if (*val == '\0') { if (*val == '\0') {
@ -438,18 +439,19 @@ cp_setparse(wordlist *wl)
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);
return (NULL);
return NULL;
} else { } else {
val = wl->wl_word; val = wl->wl_word;
wl = wl->wl_next; wl = wl->wl_next;
} }
} }
} 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);
return (NULL);
return NULL;
} }
/* if val is in double quotes, treat as string */ /* if val is in double quotes, treat as string */
@ -463,11 +465,12 @@ cp_setparse(wordlist *wl)
strcpy(val, copyval); strcpy(val, copyval);
tfree(copyval); tfree(copyval);
/* Test for a list variable */
if (eq(val, "(")) { if (eq(val, "(")) {
/* The beginning of a list... We have to walk down the /* The beginning of a list... We have to walk down the
* list until we find a close paren... If there are nested * list until we find a close paren... If there are nested
* ()'s, treat them as tokens... */ * ()'s, treat them as tokens... */
balance = 1;
int balance = 1;
while (wl && wl->wl_word) { while (wl && wl->wl_word) {
if (eq(wl->wl_word, "(")) { if (eq(wl->wl_word, "(")) {
balance++; balance++;
@ -481,11 +484,13 @@ cp_setparse(wordlist *wl)
vv = var_alloc_string(NULL, copy(ss), NULL); vv = var_alloc_string(NULL, copy(ss), NULL);
} }
else { 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); vv = var_alloc_string(NULL, copy(ss), NULL);
}
} }
tfree(copyval); tfree(copyval);
if (listv) { if (listv) {
@ -501,9 +506,10 @@ cp_setparse(wordlist *wl)
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);
return (NULL);
return NULL;
} }
/* Add list variable to linked list of variables. */
vars = var_alloc_vlist(copy(name), listv, vars); vars = var_alloc_vlist(copy(name), listv, vars);
wl = wl->wl_next; wl = wl->wl_next;
@ -516,10 +522,10 @@ cp_setparse(wordlist *wl)
vars = var_alloc_string(copy(name), copy(copyval), vars); vars = var_alloc_string(copy(name), copy(copyval), vars);
} }
else { 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... */ /*** We should try to get CP_NUM's... */
vars = var_alloc_real(name, *td, vars);
vars = var_alloc_real(name, dbl_val, vars);
} }
else { else {
vars = var_alloc_string(name, copy(val), vars); vars = var_alloc_string(name, copy(val), vars);
@ -532,8 +538,9 @@ cp_setparse(wordlist *wl)
if (name) { if (name) {
tfree(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 */ /* 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) { while (v) {
struct variable *next_v = v->va_next; struct variable *next_v = v->va_next;
if (v->va_name) if (v->va_name)
tfree(v->va_name);
txfree(v->va_name);
if (v->va_type == CP_LIST) if (v->va_type == CP_LIST)
free_struct_variable(v->va_vlist); free_struct_variable(v->va_vlist);
if (v->va_type == CP_STRING) if (v->va_type == CP_STRING)
tfree(v->va_string);
tfree(v);
txfree(v->va_string);
txfree(v);
v = next_v; v = next_v;
} }
}
} /* end of function free_struct_variable */
void cp_remvar(char *varname) void cp_remvar(char *varname)
@ -770,11 +777,19 @@ char cp_dol = '$';
/* Non-alphanumeric characters that may appear in variable names. < is very /* Non-alphanumeric characters that may appear in variable names. < is very
* special... * special...
*/ */
#define VALIDCHARS "$-_<#?@.()[]&" #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 parenthesis = 0;
int brackets = 0; int brackets = 0;
@ -805,12 +820,11 @@ span_var_expr(char *t)
} }
return t; return t;
}
} /* end of function span_var_expr */
/* Substitute variable name by its value and restore to wordlist */ /* Substitute variable name by its value and restore to wordlist */
wordlist *
cp_variablesubst(wordlist *wlist)
wordlist *cp_variablesubst(wordlist *wlist)
{ {
wordlist *wl; wordlist *wl;
@ -849,24 +863,26 @@ cp_variablesubst(wordlist *wlist)
tfree(x); tfree(x);
} else { } else {
wordlist *next = wl->wl_next; wordlist *next = wl->wl_next;
if (wlist == wl)
if (wlist == wl) {
wlist = next; wlist = next;
}
wl_delete_slice(wl, next); wl_delete_slice(wl, next);
if (!next)
if (!next) { /* wordlist ends after wl */
return wlist; return wlist;
}
wl = next; wl = next;
i = 0; 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. */ /* Evaluate a variable. */
wordlist *
vareval(char *string)
wordlist *vareval(/* NOT const */ char *string)
{ {
struct variable *v, *vfree = NULL; struct variable *v, *vfree = NULL;
wordlist *wl; wordlist *wl;
@ -887,8 +903,8 @@ vareval(char *string)
case '$': case '$':
wl = wl_cons(tprintf("%d", getpid()), NULL); wl = wl_cons(tprintf("%d", getpid()), NULL);
tfree(oldstring);
return (wl);
txfree(oldstring);
return wl;
case '<': case '<':
(void) fflush(cp_out); (void) fflush(cp_out);
@ -903,8 +919,8 @@ vareval(char *string)
/* This is a hack. */ /* This is a hack. */
if (!wl->wl_word) if (!wl->wl_word)
wl->wl_word = copy(""); wl->wl_word = copy("");
tfree(oldstring);
return (wl);
txfree(oldstring);
return wl;
case '?': case '?':
string++; string++;
@ -918,8 +934,8 @@ vareval(char *string)
} }
wl = wl_cons(copy(v ? "1" : "0"), NULL); wl = wl_cons(copy(v ? "1" : "0"), NULL);
free_struct_variable(vfree); free_struct_variable(vfree);
tfree(oldstring);
return (wl);
txfree(oldstring);
return wl;
case '#': case '#':
string++; string++;
@ -933,23 +949,26 @@ vareval(char *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);
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++; i++;
else
}
}
else {
i = (v->va_type != CP_BOOL); i = (v->va_type != CP_BOOL);
}
wl = wl_cons(tprintf("%d", i), NULL); wl = wl_cons(tprintf("%d", i), NULL);
tfree(oldstring);
txfree(oldstring);
free_struct_variable(vfree); free_struct_variable(vfree);
return (wl);
return wl;
case '\0': case '\0':
wl = wl_cons(copy("$"), NULL); wl = wl_cons(copy("$"), NULL);
tfree(oldstring);
return (wl);
txfree(oldstring);
return wl;
} }
vfree = NULL; //just in case ... vfree = NULL; //just in case ...
@ -980,8 +999,8 @@ vareval(char *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);
return (NULL);
txfree(oldstring);
return NULL;
} }
wl = cp_varwl(v); wl = cp_varwl(v);
free_struct_variable(vfree); free_struct_variable(vfree);
@ -1000,7 +1019,7 @@ vareval(char *string)
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);
txfree(oldstring);
wl_free(r); wl_free(r);
return NULL; return NULL;
} }
@ -1018,8 +1037,9 @@ vareval(char *string)
up--, low--; up--, low--;
wl = wl_range(wl, low, up); wl = wl_range(wl, low, up);
wl_free(r); wl_free(r);
}
tfree(oldstring);
} /* end of case of range given for variable */
txfree(oldstring);
return (wl); return (wl);
} }

10
src/include/ngspice/cpstd.h

@ -12,10 +12,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
#define ngspice_CPSTD_H #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 */ /* FIXME: Split this file and adjust all callers to use new header files */
#if 0 #if 0
@ -23,6 +20,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
#endif #endif
#include "ngspice/bool.h" #include "ngspice/bool.h"
#include "ngspice/dstring.h"
#include "ngspice/wordlist.h" #include "ngspice/wordlist.h"
#include "ngspice/complex.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 char *tildexpand(char *string);
extern void printnum(char *buf, double num); extern void printnum(char *buf, double num);
int printnum_ds(DSTRING *p_ds, double num);
extern int cp_numdgt; extern int cp_numdgt;
extern void cp_printword(char *string, FILE *fp); extern void cp_printword(char *string, FILE *fp);
#endif #endif

2
src/include/ngspice/fteext.h

@ -245,7 +245,7 @@ extern void ft_polyderiv(double *coeffs, int degree);
/* numparse.c */ /* numparse.c */
extern bool ft_strictnumparse; extern bool ft_strictnumparse;
double *ft_numparse(char **s, bool whole);
int ft_numparse(char **s, bool whole, double *p_val);
/* options.c */ /* options.c */

40
src/misc/printnum.c

@ -8,23 +8,49 @@ Modified: 2001 Paolo Nenzi
* It is up to the caller to allocate space for strings. * It is up to the caller to allocate space for strings.
*/ */
#include <stdio.h>
#include "ngspice/ngspice.h" #include "ngspice/ngspice.h"
#include "printnum.h" #include "printnum.h"
#include <stdio.h>
int cp_numdgt = -1; int cp_numdgt = -1;
void printnum(char *buf, double num)
static inline int get_num_width(double num)
{ {
int n; int n;
if (cp_numdgt > 1)
if (cp_numdgt > 1) {
n = cp_numdgt; n = cp_numdgt;
else
}
else {
n = 6; n = 6;
if (num < 0.0)
}
if (num < 0.0 && n > 1) {
n--; 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); (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 */

5
src/misc/printnum.h

@ -6,6 +6,9 @@
#ifndef ngspice_PRINTNUM_H #ifndef ngspice_PRINTNUM_H
#define 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 #endif
Loading…
Cancel
Save