diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index 3f74e6102..86acbfd4b 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -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) { diff --git a/src/frontend/com_compose.c b/src/frontend/com_compose.c index f91f8f9d9..4c80a8170 100644 --- a/src/frontend/com_compose.c +++ b/src/frontend/com_compose.c @@ -1,5 +1,7 @@ /* The 'compose' command. This is a more powerful and convenient form * of the 'let' command. */ +#include /* 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 /* log10 */ /* Copy the data from a vector into a buffer with larger dimensions. */ static void @@ -103,8 +104,7 @@ com_compose(wordlist *wl) int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0; int i; - char *s, *var, *val; - double *td, tt; + double tt; double *data = NULL; ngcomplex_t *cdata = NULL; int length = 0; @@ -227,9 +227,11 @@ com_compose(wordlist *wl) } length *= blocksize; - } else { + } + else { /* Parse the line... */ while (wl) { + char *s, *var, *val; if ((s = strchr(wl->wl_word, '=')) != NULL && s[1]) { /* This is var=val. */ *s = '\0'; @@ -278,109 +280,124 @@ com_compose(wordlist *wl) } if (cieq(var, "start")) { startgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &start) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - start = *td; - } else if (cieq(var, "stop")) { + } + else if (cieq(var, "stop")) { stopgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &stop) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - stop = *td; - } else if (cieq(var, "step")) { + } + else if (cieq(var, "step")) { stepgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &step) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - step = *td; - } else if (cieq(var, "center")) { + } + else if (cieq(var, "center")) { centergiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, ¢er) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - center = *td; - } else if (cieq(var, "span")) { + } + else if (cieq(var, "span")) { spangiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &span) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - span = *td; - } else if (cieq(var, "mean")) { + } + else if (cieq(var, "mean")) { meangiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &mean) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - mean = *td; - } else if (cieq(var, "sd")) { + } + else if (cieq(var, "sd")) { sdgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &sd) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - sd = *td; - } else if (cieq(var, "lin")) { + } + else if (cieq(var, "lin")) { lingiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &lin) < 0) { fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - lin = *td; - } else if (cieq(var, "log")) { + } + else if (cieq(var, "log")) { + double dbl_val; loggiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &dbl_val) <= 0) { + /* Cannot convert value to int */ fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - log = (int)(*td); - } else if (cieq(var, "dec")) { + log = (int) dbl_val; + } + else if (cieq(var, "dec")) { + double dbl_val; decgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &dbl_val) <= 0) { + /* Cannot convert value to int */ fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - dec = (int)(*td); - } else if (cieq(var, "oct")) { + dec = (int) dbl_val; + } + else if (cieq(var, "oct")) { + double dbl_val; octgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &dbl_val) <= 0) { + /* Cannot convert value to integer */ fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - oct = (int)(*td); - } else if (cieq(var, "gauss")) { + oct = (int) dbl_val; + } + else if (cieq(var, "gauss")) { + double dbl_val; gaussgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &dbl_val) <= 0) { + /* Cannot convert value to int */ fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - gauss = (int)(*td); - } else if (cieq(var, "unif")) { + gauss = (int) dbl_val; + } + else if (cieq(var, "unif")) { + double dbl_val; unifgiven = TRUE; - if ((td = ft_numparse(&val, FALSE)) == NULL) { + if (ft_numparse(&val, FALSE, &dbl_val)<= 0) { + /* cannot convert to int */ fprintf(cp_err, "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - unif = (int)(*td); - } else { + unif = (int) dbl_val; + } + else { fprintf(cp_err, "Error: compose -> bad parm %s\n", var); goto done; } @@ -405,7 +422,8 @@ com_compose(wordlist *wl) fprintf(cp_err, "Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n"); goto done; - } else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) { + } + else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) { /* Hmm, if we have a start, stop, and step we're ok. */ if (startgiven && stopgiven && stepgiven) { lingiven = TRUE; @@ -415,7 +433,8 @@ com_compose(wordlist *wl) } lin = (stop - start) / step + 1.; stepgiven = FALSE; /* Problems below... */ - } else { + } + else { fprintf(cp_err, "Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n"); fprintf(cp_err, @@ -463,10 +482,12 @@ com_compose(wordlist *wl) step = (stop - start) / (lin - 1.0); } - for (i = 0, tt = start; i < length; i++, tt += step) + for (i = 0, tt = start; i < length; i++, tt += step) { data[i] = tt; + } - } else if (loggiven || decgiven || octgiven) { + } + else if (loggiven || decgiven || octgiven) { /* Create a log sweep... */ if (centergiven && spangiven) { if (center <= span/2.0) { @@ -505,7 +526,8 @@ com_compose(wordlist *wl) for (i = 0; i < length; i++) data[i] = start * pow(stop/start, (double)i/(log-1.0)); - } else if (unifgiven) { + } + else if (unifgiven) { /* Create a set of uniform distributed values... */ if (startgiven || stopgiven) { if (!startgiven || !stopgiven) { @@ -541,7 +563,8 @@ com_compose(wordlist *wl) for (i = 0; i < length; i++) data[i] = mean + span * 0.5 * drand(); - } else if (gaussgiven) { + } + else if (gaussgiven) { /* Create a gaussian distribution... */ if (gauss <= 0) { fprintf(cp_err, @@ -558,8 +581,9 @@ com_compose(wordlist *wl) } length = gauss; data = TMALLOC(double, length); - for (i = 0; i < length; i++) + for (i = 0; i < length; i++) { data[i] = mean + sd * gauss1(); + } } } @@ -589,5 +613,5 @@ com_compose(wordlist *wl) done: free_pnode(names); - tfree(resname); -} + txfree(resname); +} /* end of function com_compose */ diff --git a/src/frontend/com_fft.c b/src/frontend/com_fft.c index e9bd460a1..31baa1a51 100644 --- a/src/frontend/com_fft.c +++ b/src/frontend/com_fft.c @@ -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; diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 0eb609679..5346cf7c9 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -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; } diff --git a/src/frontend/control.c b/src/frontend/control.c index d2f5f13ae..27192b768 100644 --- a/src/frontend/control.c +++ b/src/frontend/control.c @@ -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... */ diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c index 1171ab211..48cf5a26a 100644 --- a/src/frontend/dotcards.c +++ b/src/frontend/dotcards.c @@ -12,6 +12,7 @@ Modified: 2000 AlansFixes #include #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 */ + + + diff --git a/src/frontend/fourier.c b/src/frontend/fourier.c index 5e86b7642..2aad24cb2 100644 --- a/src/frontend/fourier.c +++ b/src/frontend/fourier.c @@ -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); diff --git a/src/frontend/parse.c b/src/frontend/parse.c index c4e2f775a..fe3a1d852 100644 --- a/src/frontend/parse.c +++ b/src/frontend/parse.c @@ -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 */ + + + diff --git a/src/frontend/parser/numparse.c b/src/frontend/parser/numparse.c index 991ff6ab7..43e69fb24 100644 --- a/src/frontend/parser/numparse.c +++ b/src/frontend/parser/numparse.c @@ -4,6 +4,9 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group **********/ /* This routine parses a number. */ +#include +#include +#include #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 */ + + + diff --git a/src/frontend/plotting/plotit.c b/src/frontend/plotting/plotit.c index d53f7b436..6daa82ba1 100644 --- a/src/frontend/plotting/plotit.c +++ b/src/frontend/plotting/plotit.c @@ -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 diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c index 978bdecf2..846ae1115 100644 --- a/src/frontend/postcoms.c +++ b/src/frontend/postcoms.c @@ -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) { diff --git a/src/frontend/spec.c b/src/frontend/spec.c index 11db680d9..73cd11e84 100644 --- a/src/frontend/spec.c +++ b/src/frontend/spec.c @@ -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; + } } } diff --git a/src/frontend/variable.c b/src/frontend/variable.c index 9c4151c11..270303605 100644 --- a/src/frontend/variable.c +++ b/src/frontend/variable.c @@ -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= */ 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=val */ val = wl->wl_word + 1; wl = wl->wl_next; } else if ((s = strchr(name, '=')) != NULL) { + /* name=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); } diff --git a/src/include/ngspice/cpstd.h b/src/include/ngspice/cpstd.h index 121654381..b6498de39 100644 --- a/src/include/ngspice/cpstd.h +++ b/src/include/ngspice/cpstd.h @@ -12,10 +12,7 @@ Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group #define ngspice_CPSTD_H -#ifndef FILE -/* XXX Bogus */ -# include -#endif +#include /* 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 diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 9a4c9bae0..e7f405f49 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -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 */ diff --git a/src/misc/printnum.c b/src/misc/printnum.c index 99a8ae922..297af4cd4 100644 --- a/src/misc/printnum.c +++ b/src/misc/printnum.c @@ -8,23 +8,49 @@ Modified: 2001 Paolo Nenzi * It is up to the caller to allocate space for strings. */ +#include + #include "ngspice/ngspice.h" #include "printnum.h" -#include 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 */ + + + diff --git a/src/misc/printnum.h b/src/misc/printnum.h index b569c77fc..8426b4fe2 100644 --- a/src/misc/printnum.h +++ b/src/misc/printnum.h @@ -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