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

This commit is contained in:
Jim Monte 2019-12-06 16:04:45 -05:00
parent 0ad9565ba7
commit e6c14b3eb0
17 changed files with 758 additions and 544 deletions

View File

@ -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)
{

View File

@ -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, &center) < 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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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... */

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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