From 503af6ac002951090139c4334b8e1ea56b7628eb Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Thu, 12 Dec 2019 19:10:29 -0500 Subject: [PATCH] Fixed several issues related to plotting and vector lifetimes and made ownership of vectors clearer. The issues in bugs 419, 423, 425, and 426 were related and were addressed here. --- src/frontend/com_hardcopy.c | 61 ++++-- src/frontend/dvec.c | 79 +++++--- src/frontend/outitf.c | 60 +++--- src/frontend/plotting/graf.c | 270 ++++++++++++++----------- src/frontend/plotting/graphdb.c | 342 ++++++++++++++++++++------------ src/frontend/postcoms.c | 89 +++++---- src/frontend/runcoms.c | 3 +- src/frontend/variable.c | 142 +++++++------ src/frontend/vectors.c | 60 +++--- src/include/ngspice/bool.h | 2 +- src/include/ngspice/dvec.h | 72 ++++--- src/include/ngspice/fteext.h | 4 +- 12 files changed, 710 insertions(+), 474 deletions(-) diff --git a/src/frontend/com_hardcopy.c b/src/frontend/com_hardcopy.c index 595dfc583..39aa0baed 100644 --- a/src/frontend/com_hardcopy.c +++ b/src/frontend/com_hardcopy.c @@ -21,10 +21,16 @@ /* hardcopy file plotargs, or 'hardcopy file' -- with no other args * this prompts the user for a window to dump to a plot file. XXX no * it doesn't. */ -void -com_hardcopy(wordlist *wl) +void com_hardcopy(wordlist *wl) { + /* Check if there is a graph available */ + if (currentgraph == (GRAPH *) NULL) { + (void) fprintf(cp_err, "There is no graph to hardcopy.\n"); + return; + } + char *fname; + size_t n_byte_fname; /* size of fname in bytes, including null */ char buf[BSIZE_SP], device[BSIZE_SP]; bool tempf = FALSE; char *devtype; @@ -40,18 +46,22 @@ com_hardcopy(wordlist *wl) if (wl) { hc_button = 0; - fname = wl->wl_word; + fname = copy(wl->wl_word); wl = wl->wl_next; - } else { + } + else { hc_button = 1; fname = smktemp("hc"); tempf = TRUE; } + n_byte_fname = (strlen(fname) + 1) * sizeof *fname; - if (!cp_getvar("hcopydevtype", CP_STRING, buf, sizeof(buf))) + if (!cp_getvar("hcopydevtype", CP_STRING, buf, sizeof(buf))) { devtype = "postscript"; - else + } + else { devtype = buf; + } /* enable screen plot selection for these display types */ foundit = 0; @@ -63,8 +73,9 @@ com_hardcopy(wordlist *wl) if (!wl && hc_button) { char *psfname; GRAPH *tempgraph; - if (DevSwitch(devtype)) + if (DevSwitch(devtype)) { return; + } tempgraph = CopyGraph(currentgraph); /* change .tmp to .ps */ psfname = strchr(fname, '.'); @@ -72,11 +83,15 @@ com_hardcopy(wordlist *wl) psfname[1] = 'p'; psfname[2] = 's'; psfname[3] = '\0'; - } else { - fname = trealloc(fname, strlen(fname)+4); - strcat(fname, ".ps"); + } + else { + fname = trealloc(fname, n_byte_fname + 3); + (void) memcpy(fname + n_byte_fname - 1, ".ps", 4); + n_byte_fname += 3; } tempgraph->devdep = fname; + tempgraph->n_byte_devdep = n_byte_fname; + if (NewViewport(tempgraph)) { DevSwitch(NULL); return; @@ -92,21 +107,23 @@ com_hardcopy(wordlist *wl) #ifndef X_DISPLAY_MISSING if (!wl && hc_button) { - REQUEST request; RESPONSE response; GRAPH *tempgraph; request.option = click_option; Input(&request, &response); - if (response.option == error_option) + if (response.option == error_option) { return; + } if (response.reply.graph) { - if (DevSwitch(devtype)) + if (DevSwitch(devtype)) { return; + } tempgraph = CopyGraph(response.reply.graph); tempgraph->devdep = fname; + tempgraph->n_byte_devdep = n_byte_fname; if (NewViewport(tempgraph)) { DevSwitch(NULL); return; @@ -133,19 +150,20 @@ com_hardcopy(wordlist *wl) PushGraphContext(currentgraph); if (!foundit) { - if (!wl) { char *buf2; outmenuprompt("which variable ? "); buf2 = prompt(cp_in); - if (!buf2) + if (!buf2) { return; + } wl = wl_cons(buf2, NULL); wl = process(wl); } - if (DevSwitch(devtype)) + if (DevSwitch(devtype)) { return; + } if (!wl || !plotit(wl, fname, NULL)) { printf("com_hardcopy: graph not defined\n"); @@ -189,11 +207,13 @@ com_hardcopy(wordlist *wl) fname); fprintf(cp_out, "\tor by using the '-g' flag to the Unix lpr command.\n"); - } else if (!strcmp(devtype, "postscript")) { + } + else if (!strcmp(devtype, "postscript")) { fprintf(cp_out, "\nThe file \"%s\" may be printed on a postscript printer.\n", fname); - } else if (!strcmp(devtype, "MFB")) { + } + else if (!strcmp(devtype, "MFB")) { fprintf(cp_out, "The file \"%s\" may be printed on a MFB device.\n", fname); @@ -205,4 +225,7 @@ com_hardcopy(wordlist *wl) /* restore previous graphics context by retrieving the previous currentgraph */ PopGraphContext(); -} +} /* end of function com_hardcopy */ + + + diff --git a/src/frontend/dvec.c b/src/frontend/dvec.c index f837f17e3..303f2455f 100644 --- a/src/frontend/dvec.c +++ b/src/frontend/dvec.c @@ -2,10 +2,10 @@ #include "ngspice/dvec.h" -struct dvec * -dvec_alloc(char *name, int type, short flags, int length, void *storage) +struct dvec *dvec_alloc(const char *name, + int type, short flags, int length, void *storage) { - struct dvec *rv = TMALLOC(struct dvec, 1); + struct dvec * const rv = TMALLOC(struct dvec, 1); /* If the allocation failed, return NULL as a failure flag. * As of 2019-03, TMALLOC will not return on failure, so this check is @@ -54,60 +54,81 @@ dvec_alloc(char *name, int type, short flags, int length, void *storage) rv->v_numdims = 0; /* Really "unknown" */ return rv; -} +} /* end of function dvec_alloc */ -void -dvec_realloc(struct dvec *v, int length, void *storage) +/* Resize dvec to length if storage is NULL orr replace + * its existing allocation with storage if not + */ +void dvec_realloc(struct dvec *v, int length, void *storage) { if (isreal(v)) { if (storage) { tfree(v->v_realdata); v->v_realdata = (double *) storage; - } else { + } + else { v->v_realdata = TREALLOC(double, v->v_realdata, length); } - } else { + } + else { if (storage) { tfree(v->v_compdata); v->v_compdata = (ngcomplex_t *) storage; - } else { + } + else { v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length); } } v->v_length = length; v->v_alloc_length = length; -} +} /* end of function dvec_realloc */ -void -dvec_extend(struct dvec *v, int length) +void dvec_extend(struct dvec *v, int length) { - if (isreal(v)) + if (isreal(v)) { v->v_realdata = TREALLOC(double, v->v_realdata, length); - else + } + else { v->v_compdata = TREALLOC(ngcomplex_t, v->v_compdata, length); + } v->v_alloc_length = length; -} +} /* end of function dvec_extend */ -void -dvec_trunc(struct dvec *v, int length) + +void dvec_trunc(struct dvec *v, int length) { - v->v_length = length; -} + /* Ensure valid */ + if (v->v_alloc_length <= length) { + v->v_length = length; + } +} /* end of function dvec_trunc */ -void -dvec_free(struct dvec *v) + +void dvec_free(struct dvec *v) { - if (v->v_name) - tfree(v->v_name); - if (v->v_realdata) - tfree(v->v_realdata); - if (v->v_compdata) - tfree(v->v_compdata); - tfree(v); -} + /* Check for freed vector */ + if (v == (struct dvec *) NULL) { + return; + } + + /* Free the various allocations */ + if (v->v_name) { + txfree(v->v_name); + } + if (v->v_realdata) { + txfree(v->v_realdata); + } + else if (v->v_compdata) { /* if data real, not complex */ + txfree(v->v_compdata); + } + txfree(v); +} /* end of function dvec_free */ + + + diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 6738b9fa0..0e617df92 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -565,21 +565,22 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) #ifdef TCL_MODULE steps_completed = run->pointCount; #endif - /* interpolated batch mode output to file in transient analysis */ - if (interpolated && run->circuit->CKTcurJob->JOBtype == 4 && run->writeOut) { - InterpFileAdd(run, refValue, valuePtr); - return (OK); - } - /* interpolated interactive or control mode output to plot in transient analysis */ - else if (interpolated && run->circuit->CKTcurJob->JOBtype == 4 && !(run->writeOut)) { - InterpPlotAdd(run, refValue, valuePtr); - return (OK); + /* interpolated batch mode output to file/plot in transient analysis */ + if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) { + if (run->writeOut) { /* To file */ + InterpFileAdd(run, refValue, valuePtr); + } + else { /* To plot */ + InterpPlotAdd(run, refValue, valuePtr); + } + return OK; } + /* standard batch mode output to file */ else if (run->writeOut) { - - if (run->pointCount == 1) + if (run->pointCount == 1) { fileInit_pass2(run); + } fileStartPoint(run->fp, run->binary, run->pointCount); @@ -600,10 +601,8 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) } } #endif - } else { - - /* And the same for a non-complex value */ - + } + else { /* And the same for a non-complex (real) value */ fileAddRealValue(run->fp, run->binary, refValue->rValue); #ifndef HAS_WINGUI if (!orflag && !ft_norefprint) { @@ -620,8 +619,9 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) for (i = 0; i < run->numData; i++) { /* we've already printed reference vec first */ - if (run->data[i].outIndex == -1) + if (run->data[i].outIndex == -1) { continue; + } #ifdef TCL_MODULE blt_add(i, refValue ? refValue->rValue : NAN); @@ -630,13 +630,14 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) if (run->data[i].regular) { if (run->data[i].type == IF_REAL) fileAddRealValue(run->fp, run->binary, - valuePtr->v.vec.rVec [run->data[i].outIndex]); + valuePtr->v.vec.rVec [run->data[i].outIndex]); else if (run->data[i].type == IF_COMPLEX) fileAddComplexValue(run->fp, run->binary, - valuePtr->v.vec.cVec [run->data[i].outIndex]); + valuePtr->v.vec.cVec [run->data[i].outIndex]); else fprintf(stderr, "OUTpData: unsupported data type\n"); - } else { + } + else { IFvalue val; /* should pre-check instance */ if (!getSpecial(&run->data[i], run, &val)) { @@ -652,7 +653,8 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) val.cValue.real = 0; val.cValue.imag = 0; fileAddComplexValue(run->fp, run->binary, val.cValue); - } else { + } + else { val.rValue = 0; fileAddRealValue(run->fp, run->binary, val.rValue); } @@ -683,8 +685,8 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) shouldstop = TRUE; } - } else { - + } + else { OUTpD_memory(run, refValue, valuePtr); /* This is interactive mode. Update the screen with the reference @@ -718,18 +720,18 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr) sh_ExecutePerLoop(); #endif - return (OK); -} + return OK; +} /* end of function OUTpData */ -int -OUTwReference(void *plotPtr, IFvalue *valuePtr, void **refPtr) + +int OUTwReference(void *plotPtr, IFvalue *valuePtr, void **refPtr) { NG_IGNORE(refPtr); NG_IGNORE(valuePtr); NG_IGNORE(plotPtr); - return (OK); + return OK; } @@ -741,7 +743,7 @@ OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr) NG_IGNORE(dataIndex); NG_IGNORE(plotPtr); - return (OK); + return OK; } @@ -750,7 +752,7 @@ OUTwEnd(runDesc *plotPtr) { NG_IGNORE(plotPtr); - return (OK); + return OK; } diff --git a/src/frontend/plotting/graf.c b/src/frontend/plotting/graf.c index d8bf48ef2..15ad1bdb8 100644 --- a/src/frontend/plotting/graf.c +++ b/src/frontend/plotting/graf.c @@ -17,19 +17,18 @@ Author: 1988 Jeffrey M. Hsu #include "ngspice/dvec.h" /* for struct dvec */ #include "ngspice/ftedefs.h" /* for FTEextern.h and IPOINT{MIN,MAX} */ #include "ngspice/fteinput.h" -#include "ngspice/graph.h" #include "ngspice/ftedbgra.h" #include "ngspice/ftedev.h" +#include "ngspice/graph.h" +#include "ngspice/grid.h" #include "ngspice/sim.h" -#include +#include "ngspice/stringskip.h" +#include "breakp2.h" +#include "display.h" #include "graf.h" #include "graphdb.h" -#include "ngspice/grid.h" -#include "../terminal.h" -#include "../breakp2.h" -#include "../display.h" -#include "../runcoms.h" -#include "ngspice/stringskip.h" +#include "runcoms.h" +#include "terminal.h" static void gr_start_internal(struct dvec *dv, bool copyvec); @@ -107,8 +106,10 @@ int gr_init(double *xlims, double *ylims, /* The size of the screen. */ cur.plotno = 0; /* note: should do only once, maybe in gr_init_once */ - if (!cp_getvar("pointchars", CP_STRING, pointchars, sizeof(pointchars))) + if (!cp_getvar("pointchars", CP_STRING, + pointchars, sizeof(pointchars))) { (void) strcpy(pointchars, DEFPOINTCHARS); + } if (!cp_getvar("ticmarks", CP_NUM, &graph->ticmarks, 0)) { if (cp_getvar("ticmarks", CP_BOOL, NULL, 0)) { @@ -242,8 +243,7 @@ int gr_init(double *xlims, double *ylims, /* The size of the screen. */ * We pass two points in so we can multiplex plots. * */ -void -gr_point(struct dvec *dv, +void gr_point(struct dvec *dv, double newx, double newy, double oldx, double oldy, int np) @@ -262,11 +262,13 @@ gr_point(struct dvec *dv, oldtox = tox; oldtoy = toy; if (!currentgraph->grid.circular) { if (clip_line(&fromx, &fromy, &tox, &toy, - currentgraph->viewportxoff, currentgraph->viewportyoff, - currentgraph->viewport.width + currentgraph->viewportxoff, - currentgraph->viewport.height + currentgraph->viewportyoff)) + currentgraph->viewportxoff, currentgraph->viewportyoff, + currentgraph->viewport.width + currentgraph->viewportxoff, + currentgraph->viewport.height + currentgraph->viewportyoff)) { return; - } else { + } + } + else { if (clip_to_circle(&fromx, &fromy, &tox, &toy, currentgraph->grid.xaxis.circular.center, currentgraph->grid.yaxis.circular.center, @@ -276,11 +278,13 @@ gr_point(struct dvec *dv, if (currentgraph->plottype != PLOT_POINT) { SetLinestyle(dv->v_linestyle); - } else { + } + else { /* if PLOT_POINT, don't want to plot an endpoint which have been clipped */ - if (tox != oldtox || toy != oldtoy) + if (tox != oldtox || toy != oldtoy) { return; + } } SetColor(dv->v_color); @@ -290,8 +294,9 @@ gr_point(struct dvec *dv, case PLOT_MONOLIN: /* If it's a linear plot, ignore first point since we don't want to connect with oldx and oldy. */ - if (np) + if (np) { DevDrawLine(fromx, fromy, tox, toy); + } if ((tics = currentgraph->ticdata) != NULL) { for (; *tics < HUGE; tics++) if (*tics == (double) np) { @@ -304,9 +309,9 @@ gr_point(struct dvec *dv, (int) (toy - currentgraph->fontheight / 2)); */ break; } - } else if ((currentgraph->ticmarks >0) && (np > 0) && - (np % currentgraph->ticmarks == 0)) - { + } + else if ((currentgraph->ticmarks >0) && (np > 0) && + (np % currentgraph->ticmarks == 0)) { /* Draw an 'x' */ DevDrawText("x", (int) (tox - currentgraph->fontwidth / 2), (int) (toy - currentgraph->fontheight / 2), 0); @@ -382,34 +387,45 @@ static void gr_start_internal(struct dvec *dv, bool copyvec) link = TMALLOC(struct dveclist, 1); link->next = currentgraph->plotdata; + /* Either reuse input vector or copy depnding on copyvec */ if (copyvec) { link->vector = vec_copy(dv); /* vec_copy doesn't set v_color or v_linestyle */ link->vector->v_color = dv->v_color; link->vector->v_linestyle = dv->v_linestyle; link->vector->v_flags |= VF_PERMANENT; - } else { + link->f_own_vector = TRUE; + } + else { link->vector = dv; + link->f_own_vector = FALSE; } currentgraph->plotdata = link; /* Add the scale vector to the list of vectors associated with the plot - * and use the copy instead of the original scale vector */ - link = TMALLOC(struct dveclist, 1); - link->next = currentgraph->plotdata; + * and use the copy instead of the original scale vector if requested */ + { + struct dvec * const custom_scale = dv->v_scale; + if (custom_scale != (struct dvec *) NULL) { + link = TMALLOC(struct dveclist, 1); + link->next = currentgraph->plotdata; - if (copyvec) { - link->vector = vec_copy(dv->v_scale); - link->vector->v_flags |= VF_PERMANENT; - link->next->vector->v_scale = link->vector; - } - else { - link->vector = dv->v_scale; - } + if (copyvec) { + link->vector = vec_copy(dv->v_scale); + link->vector->v_flags |= VF_PERMANENT; + link->next->vector->v_scale = link->vector; + link->f_own_vector = TRUE; + } + else { + link->vector = dv->v_scale; + link->f_own_vector = FALSE; + } - /* Make the new vector the start of the list of vectors */ - currentgraph->plotdata = link; + /* Make the new vector the start of the list of vectors */ + currentgraph->plotdata = link; + } + } /* Put the legend entry on the screen. */ @@ -470,8 +486,7 @@ void drawlegend(GRAPH *graph, int plotno, struct dvec *dv) /* end one plot of a graph */ -void -gr_end(struct dvec *dv) +void gr_end(struct dvec *dv) { NG_IGNORE(dv); DevUpdate(); @@ -480,8 +495,7 @@ gr_end(struct dvec *dv) /* Print text in the bottom line. */ -void -gr_pmsg(char *text) +void gr_pmsg(char *text) { char buf[BSIZE_SP]; buf[0] = '\0'; @@ -503,16 +517,14 @@ gr_pmsg(char *text) } -void -gr_clean(void) +void gr_clean(void) { DevUpdate(); } /* call this routine after viewport size changes */ -void -gr_resize(GRAPH *graph) +void gr_resize(GRAPH *graph) { double oldxratio, oldyratio; double scalex, scaley; @@ -552,8 +564,7 @@ gr_resize(GRAPH *graph) /* PN static */ -void -gr_resize_internal(GRAPH *graph) +void gr_resize_internal(GRAPH *graph) { if (!graph->grid.xsized) graph->viewport.width = (int)(graph->absolute.width - @@ -579,8 +590,7 @@ gr_resize_internal(GRAPH *graph) /* redraw everything in struct graph */ -void -gr_redraw(GRAPH *graph) +void gr_redraw(GRAPH *graph) { struct dveclist *link; @@ -616,8 +626,7 @@ gr_redraw(GRAPH *graph) } -void -gr_restoretext(GRAPH *graph) +void gr_restoretext(GRAPH *graph) { struct _keyed *k; @@ -633,7 +642,8 @@ gr_restoretext(GRAPH *graph) * * First, if length < IPOINTMIN, don't do anything. * - * Second, if length = IPOINTMIN, plot what we have so far. + * Second, if length = IPOINTMIN, plot what we have so far. This step + * is essentially the initializaiton for the graph. * * Third, if length > IPOINTMIN, plot the last points and resize if * needed. @@ -643,16 +653,25 @@ gr_restoretext(GRAPH *graph) * FIXME: there is a problem with multiple iplots that use the same * vector, namely, that vector has the same color throughout. This is * another reason why we need to pull color and linestyle out of dvec - * XXX Or maybe even something more drastic ?? */ - -static int -iplot(struct plot *pl, int id) + * XXX Or maybe even something more drastic ?? + * It would be better to associate a color with an instance using a + * vector than the vector itself, for which color is something artificial. */ +static int iplot(struct plot *pl, int id) { int len = pl->pl_scale->v_length; + + if (ft_grdb) { + fprintf(cp_err, "Entering iplot, len = %d\n", len); + } + + /* Do simple check for exit first */ + if (len < IPOINTMIN) { /* Nothing yet */ + return 0; + } + struct dvec *v, *xs = pl->pl_scale; double *lims, dy; double start, stop, step; - register int j; bool changed = FALSE; int yt; char *yl = NULL; @@ -660,51 +679,61 @@ iplot(struct plot *pl, int id) static REQUEST reqst = { checkup_option, NULL }; int inited = 0; char commandline[513]; + int n_vec_plot = 0; - for (j = 0, v = pl->pl_dvecs; v; v = v->v_next) - if (v->v_flags & VF_PLOT) - j++; - if (!j) - return (0); - if (ft_grdb) - fprintf(cp_err, "Entering iplot, len = %d\n", len); + /* Exit if nothing is being plotted */ + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (v->v_flags & VF_PLOT) { + ++n_vec_plot; + } + } - if (len < IPOINTMIN) { - /* Nothing yet */ - return (0); - } else if (len == IPOINTMIN || !id) { + if (n_vec_plot == 0) { + return 0; + } + + if (len == IPOINTMIN || !id) { /* Do initialization */ resumption = FALSE; /* Draw the grid for the first time, and plot everything. */ lims = ft_minmax(xs, TRUE); xlims[0] = lims[0]; xlims[1] = lims[1]; ylims[0] = HUGE; - ylims[1] = - ylims[0]; - for (v = pl->pl_dvecs; v; v = v->v_next) + ylims[1] = -ylims[0]; + for (v = pl->pl_dvecs; v; v = v->v_next) { if (v->v_flags & VF_PLOT) { lims = ft_minmax(v, TRUE); - if (ylims[0] > lims[0]) + if (ylims[0] > lims[0]) { ylims[0] = lims[0]; - if (ylims[1] < lims[1]) + } + if (ylims[1] < lims[1]) { ylims[1] = lims[1]; - if (!yl) + } + if (!yl) { yl = v->v_name; + } } - /* generate a small difference between ymin and ymax - to catch the y=const case */ - if (ylims[0] == ylims[1]) - ylims[1] += 1e-9; + } - if (ft_grdb) + /* Generate a small difference between ymin and ymax + to catch the y=const case */ + if (ylims[0] == ylims[1]) { + ylims[1] += 1e-9; + } + + if (ft_grdb) { fprintf(cp_err, "iplot: after 5, xlims = %G, %G, ylims = %G, %G\n", xlims[0], xlims[1], ylims[0], ylims[1]); + } - for (yt = pl->pl_dvecs->v_type, v = pl->pl_dvecs->v_next; v; v = v->v_next) + for (yt = pl->pl_dvecs->v_type, v = pl->pl_dvecs->v_next; v; + v = v->v_next) { if ((v->v_flags & VF_PLOT) && (v->v_type != yt)) { yt = SV_NOTYPE; break; } + } /* note: have command options for iplot to specify xdelta, etc. So don't need static variables hack. Assume default @@ -712,25 +741,28 @@ iplot(struct plot *pl, int id) sprintf(commandline, "plot %s", yl); (void) gr_init(xlims, ylims, xs->v_name, - pl->pl_title, NULL, j, 0.0, 0.0, - GRID_LIN, PLOT_LIN, xs->v_name, yl, xs->v_type, yt, - plot_cur->pl_typename, commandline); + pl->pl_title, NULL, n_vec_plot, 0.0, 0.0, + GRID_LIN, PLOT_LIN, xs->v_name, yl, xs->v_type, yt, + plot_cur->pl_typename, commandline); - for (v = pl->pl_dvecs; v; v = v->v_next) + for (v = pl->pl_dvecs; v; v = v->v_next) { if (v->v_flags & VF_PLOT) { gr_start_internal(v, FALSE); ft_graf(v, xs, TRUE); } + } inited = 1; - } else { + } + else { /* plot the last points and resize if needed */ Input(&reqst, NULL); /* First see if we have to make the screen bigger */ dy = (isreal(xs) ? xs->v_realdata[len - 1] : realpart(xs->v_compdata[len - 1])); - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "x = %G\n", dy); + } if (!if_tranparams(ft_curckt, &start, &stop, &step) || !ciprefix("tran", pl->pl_typename)) { stop = HUGE; @@ -739,32 +771,35 @@ iplot(struct plot *pl, int id) /* checking for x lo */ while (dy < currentgraph->data.xmin) { changed = TRUE; - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "resize: xlo %G -> %G\n", currentgraph->data.xmin, currentgraph->data.xmin - (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); + } /* set the new x lo value */ currentgraph->data.xmin -= - (currentgraph->data.xmax - currentgraph->data.xmin) - * XFACTOR; + (currentgraph->data.xmax - currentgraph->data.xmin) + * XFACTOR; if (currentgraph->data.xmin < start) { currentgraph->data.xmin = start; break; } } - if (currentgraph->data.xmax < currentgraph->data.xmin) + if (currentgraph->data.xmax < currentgraph->data.xmin) { currentgraph->data.xmax = currentgraph->data.xmin; + } /* checking for x hi */ while (dy > currentgraph->data.xmax) { changed = TRUE; - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "resize: xhi %G -> %G\n", currentgraph->data.xmax, currentgraph->data.xmax + (currentgraph->data.xmax - currentgraph->data.xmin) * XFACTOR); + } /* set the new x hi value */ currentgraph->data.xmax += (currentgraph->data.xmax - currentgraph->data.xmin) * @@ -776,21 +811,24 @@ iplot(struct plot *pl, int id) } /* checking for all y values */ for (v = pl->pl_dvecs; v; v = v->v_next) { - if (!(v->v_flags & VF_PLOT)) + if (!(v->v_flags & VF_PLOT)) { continue; + } dy = (isreal(v) ? v->v_realdata[len - 1] : realpart(v->v_compdata[len - 1])); - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "y = %G\n", dy); + } /* checking for y lo */ while (dy < currentgraph->data.ymin) { changed = TRUE; - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "resize: ylo %G -> %G\n", currentgraph->data.ymin, currentgraph->data.ymin - (currentgraph->data.ymax - currentgraph->data.ymin) * YFACTOR); + } /* set the new y lo value */ currentgraph->data.ymin -= (currentgraph->data.ymax - currentgraph->data.ymin) @@ -800,17 +838,19 @@ iplot(struct plot *pl, int id) /* currentgraph->data.ymin = dy; currentgraph->data.ymin *= (1 + YFACTOR); */ } - if (currentgraph->data.ymax < currentgraph->data.ymin) + if (currentgraph->data.ymax < currentgraph->data.ymin) { currentgraph->data.ymax = currentgraph->data.ymin; + } /* checking for y hi */ while (dy > currentgraph->data.ymax) { changed = TRUE; - if (ft_grdb) + if (ft_grdb) { fprintf(cp_err, "resize: yhi %G -> %G\n", currentgraph->data.ymax, currentgraph->data.ymax + (currentgraph->data.ymax - currentgraph->data.ymin) * YFACTOR); + } /* set the new y hi value */ currentgraph->data.ymax += (currentgraph->data.ymax - currentgraph->data.ymin) @@ -829,10 +869,11 @@ iplot(struct plot *pl, int id) #ifndef X_DISPLAY_MISSING gr_redraw(currentgraph); #endif - } else { + } + else { /* Just connect the last two points. This won't be done * with curve interpolation, so it might look funny. */ - for (v = pl->pl_dvecs; v; v = v->v_next) + for (v = pl->pl_dvecs; v; v = v->v_next) { if (v->v_flags & VF_PLOT) { gr_point(v, (isreal(xs) ? xs->v_realdata[len - 1] : @@ -845,15 +886,15 @@ iplot(struct plot *pl, int id) realpart(v->v_compdata[len - 2])), len - 1); } + } } } DevUpdate(); - return (inited); + return inited; } -static void -set(struct plot *plot, struct dbcomm *db, bool unset, short mode) +static void set(struct plot *plot, struct dbcomm *db, bool unset, short mode) { struct dvec *v; struct dbcomm *dc; @@ -885,8 +926,7 @@ set(struct plot *plot, struct dbcomm *db, bool unset, short mode) } -static char * -getitright(char *buf, double num) +static char *getitright(char *buf, double num) { char *p; int k; @@ -909,16 +949,14 @@ getitright(char *buf, double num) static int hit, hit2; -void -reset_trace(void) +void reset_trace(void) { hit = -1; hit2 = -1; } -void -gr_iplot(struct plot *plot) +void gr_iplot(struct plot *plot) { struct dbcomm *db; int dontpop; /* So we don't pop w/o push. */ @@ -959,10 +997,12 @@ gr_iplot(struct plot *plot) if (v->v_flags & VF_PRINT) { u = plot->pl_scale; if (len <= 1 || hit <= 0 || hit2 < 0) { - if (len <= 1 || hit2 < 0) + if (len <= 1 || hit2 < 0) { term_clear(); - else + } + else { term_home(); + } hit = 1; hit2 = 1; printf( @@ -975,7 +1015,8 @@ gr_iplot(struct plot *plot) if (isreal(u)) { printf("%s", getitright(buf, u->v_realdata[len - 1])); - } else { + } + else { /* MW. Complex data here, realdata is NULL (why someone use realdata here again) */ printf("%s", @@ -987,12 +1028,14 @@ gr_iplot(struct plot *plot) printf("\n"); } } - if (v == u) + if (v == u) { continue; + } printf("%12s:", v->v_name); if (isreal(v)) { printf("%s", getitright(buf, v->v_realdata[len - 1])); - } else { + } + else { /* MW. Complex data again */ printf("%s", getitright(buf, v->v_compdata[len - 1].cx_real)); printf(", %s", getitright(buf, v->v_compdata[len - 1].cx_imag)); @@ -1014,8 +1057,7 @@ gr_iplot(struct plot *plot) * Note: This is a clear case for separating the linestyle and color * fields from dvec. */ -void -gr_end_iplot(void) +void gr_end_iplot(void) { struct dbcomm *db, *prev, *next; GRAPH *graph; @@ -1034,7 +1076,8 @@ gr_end_iplot(void) ft_curckt->ci_dbs = dbs = next; dbfree1(db); } - } else if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) { + } + else if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) { if (db->db_graphid) { /* get private copy of dvecs */ @@ -1063,8 +1106,7 @@ gr_end_iplot(void) } -double * -readtics(char *string) +double *readtics(char *string) { int k; char *words, *worde; diff --git a/src/frontend/plotting/graphdb.c b/src/frontend/plotting/graphdb.c index 09ba1dc90..a11a6640f 100644 --- a/src/frontend/plotting/graphdb.c +++ b/src/frontend/plotting/graphdb.c @@ -44,232 +44,320 @@ static GBUCKET GBucket[NUMGBUCKETS]; /* note: Zero is not a valid id. This is used in plot() in graf.c. */ static int RunningId = 1; -/* initialize graph structure */ -#define SETGRAPH(pgraph, id) \ - do { \ - (pgraph)->graphid = (id); \ - (pgraph)->degree = 1; \ - (pgraph)->linestyle = -1; \ - } while(0) - - -/* returns NULL on error */ - -GRAPH * -NewGraph(void) +/* Initialize graph structure */ +static inline void setgraph(GRAPH *pgraph, int id) +{ + pgraph->graphid = id; + pgraph->degree = 1; + pgraph->linestyle = -1; +} /* end of function setgraph */ + + + +/* Creates a new graph. Returns NULL on error */ +GRAPH *NewGraph(void) { - GRAPH *pgraph; LISTGRAPH *list; - int BucketId = RunningId % NUMGBUCKETS; + const int BucketId = RunningId % NUMGBUCKETS; if ((list = TMALLOC(LISTGRAPH, 1)) == NULL) { internalerror("can't allocate a listgraph"); - return (NULL); + return (GRAPH *) NULL; } - pgraph = &list->graph; - SETGRAPH(pgraph, RunningId); + GRAPH * const pgraph = &list->graph; + setgraph(pgraph, RunningId); + GBUCKET *p_bucket = GBucket + BucketId; - if (!GBucket[BucketId].list) { - GBucket[BucketId].list = list; - } else { + /* Add to the appropriate bucket at the front of the linked list */ + if (!p_bucket->list) { /* no list yet */ + p_bucket->list = list; + } + else { /* insert at front of current list */ - list->next = GBucket[BucketId].list; - GBucket[BucketId].list = list; + list->next = p_bucket->list; + p_bucket->list = list; } RunningId++; - return (pgraph); -} + return pgraph; +} /* end of function NewGraph */ + /* Given graph id, return graph */ -GRAPH * -FindGraph(int id) +GRAPH *FindGraph(int id) { LISTGRAPH *list; + /* Step through list of graphs until found or list ends */ for (list = GBucket[id % NUMGBUCKETS].list; - list && list->graph.graphid != id; - list = list->next) + list && list->graph.graphid != id; + list = list->next) { ; + } - if (list) - return (&list->graph); - else - return (NULL); -} + if (list) { /* found */ + return &list->graph; + } + else { + return (GRAPH *) NULL; + } +} /* end of function FindGraph */ -GRAPH * -CopyGraph(GRAPH *graph) + +GRAPH *CopyGraph(GRAPH *graph) { GRAPH *ret; - struct _keyed *k; struct dveclist *link, *newlink; - if (!graph) + if (!graph) { return NULL; + } ret = NewGraph(); - memcpy(ret, graph, sizeof(GRAPH)); /* va: compatible pointer types */ - ret->graphid = RunningId - 1; /* restore id */ + { + const int id = ret->graphid; /* save ID of the new graph */ + memcpy(ret, graph, sizeof(GRAPH)); /* copy graph info (inc. ID) */ + ret->graphid = id; /* restore ID */ + } /* copy keyed */ - for (ret->keyed = NULL, k = graph->keyed; k; k = k->next) - SaveText(ret, k->text, k->x, k->y); - - /* copy dvecs */ - ret->plotdata = NULL; - for (link = graph->plotdata; link; link = link->next) { - newlink = TMALLOC(struct dveclist, 1); - newlink->next = ret->plotdata; - newlink->vector = vec_copy(link->vector); - /* vec_copy doesn't set v_color or v_linestyle */ - newlink->vector->v_color = link->vector->v_color; - newlink->vector->v_linestyle = link->vector->v_linestyle; - newlink->vector->v_flags |= VF_PERMANENT; - ret->plotdata = newlink; + { + struct _keyed *k; + for (ret->keyed = NULL, k = graph->keyed; k; k = k->next) { + SaveText(ret, k->text, k->x, k->y); + } } + /* copy dvecs or reuse if "borrowed" already */ + { + struct dveclist *new_plotdata = (struct dveclist *) NULL; + for (link = graph->plotdata; link; link = link->next) { + if (link->f_own_vector) { + struct dvec * const old_vector = link->vector; + struct dvec * const new_vector = vec_copy(old_vector); + /* vec_copy doesn't set v_color or v_linestyle */ + new_vector->v_color = old_vector->v_color; + new_vector->v_linestyle = old_vector->v_linestyle; + new_vector->v_flags |= VF_PERMANENT; + newlink = TMALLOC(struct dveclist, 1); + newlink->next = new_plotdata; + newlink->f_own_vector = TRUE; + newlink->vector = new_vector; + + /* If the link owns the vector, it also owns its scale + * vector, if present */ + struct dvec *old_scale = old_vector->v_scale; + if (old_scale != (struct dvec *) NULL) { + new_plotdata = newlink; /* put in front */ + struct dvec * const new_scale = vec_copy(old_scale); + new_scale->v_flags |= VF_PERMANENT; + newlink = TMALLOC(struct dveclist, 1); + newlink->next = new_plotdata; + newlink->f_own_vector = TRUE; + newlink->vector = new_scale; + newlink->next = new_plotdata; + } + } + else { + newlink->vector = link->vector; + newlink->f_own_vector = FALSE; + } + new_plotdata = newlink; /* put in front */ + } + + ret->plotdata = new_plotdata; /* give vector list to plot */ + } /* end of block copying or reusing dvecs */ + ret->commandline = copy(graph->commandline); ret->plotname = copy(graph->plotname); - return (ret); -} + { + const char * const lbl = graph->grid.xlabel; + if (lbl) { + ret->grid.xlabel = copy(lbl); + } + } + + { + const char * const lbl = graph->grid.ylabel; + if (lbl) { + ret->grid.ylabel = copy(lbl); + } + } + + /* Copy devdep information and size if present */ + { + const void * const p = graph->devdep; + if (p != NULL) { + const size_t n = ret->n_byte_devdep = graph->n_byte_devdep; + void * const dst = ret->devdep = tmalloc(n); + (void) memcpy(dst, graph->devdep, n); + } + } + + return ret; +} /* end of function CopyGraph */ -int -DestroyGraph(int id) + +int DestroyGraph(int id) { - LISTGRAPH *list, *lastlist; - struct _keyed *k, *nextk; - struct dveclist *d, *nextd; - struct dbcomm *db; + /* Locate hash bucket for this graph */ + const int index = id % NUMGBUCKETS; + LISTGRAPH *list = GBucket[index].list; - list = GBucket[id % NUMGBUCKETS].list; - lastlist = NULL; + /* Pointer before current one. Allows fixing list when the current + * node is deleted. Init to NULL to indicate that at head of list */ + LISTGRAPH *lastlist = (LISTGRAPH *) NULL; + + /* Step through graphs in the bucket until the one with id is found */ while (list) { if (list->graph.graphid == id) { /* found it */ + struct _keyed *k, *nextk; + struct dbcomm *db; /* Fix the iplot/trace dbs list */ - for (db = dbs; db && db->db_graphid != id; db = db->db_next) + for (db = dbs; db && db->db_graphid != id; db = db->db_next) { ; - - if (db && (db->db_type == DB_IPLOT || - db->db_type == DB_IPLOTALL)) - { - db->db_type = DB_DEADIPLOT; - /* Delete this later */ - return (0); } - /* adjust bucket pointers */ - if (lastlist) - lastlist->next = list->next; - else - GBucket[id % NUMGBUCKETS].list = list->next; + if (db && (db->db_type == DB_IPLOT || + db->db_type == DB_IPLOTALL)) { + db->db_type = DB_DEADIPLOT; + /* Delete this later */ + return 0; + } - /* run through and de-allocate dynamically allocated keyed list */ + /* Adjust bucket pointers to remove the current node */ + if (lastlist) { /* not at front */ + lastlist->next = list->next; + } + else { /* at front */ + GBucket[index].list = list->next; + } + + /* Run through and de-allocate dynamically allocated keyed list */ k = list->graph.keyed; while (k) { nextk = k->next; - tfree(k->text); - tfree(k); + txfree(k->text); + txfree(k); k = nextk; } - /* de-allocate dveclist */ - d = list->graph.plotdata; - while (d) { - nextd = d->next; - dvec_free(d->vector); - tfree(d); - d = nextd; + /* Free vectors owned by this graph and free the list */ + { + struct dveclist *d = list->graph.plotdata; + struct dveclist *nextd; + while (d != (struct dveclist *) NULL) { + nextd = d->next; + if (d->f_own_vector) { + /* list responsible for freeing this vector */ + dvec_free(d->vector); + } + txfree(d); + d = nextd; + } } - tfree(list->graph.commandline); - tfree(list->graph.plotname); + txfree(list->graph.commandline); + txfree(list->graph.plotname); + txfree(list->graph.grid.xlabel); + txfree(list->graph.grid.ylabel); - /* If device dependent space allocated, free it. */ - if (list->graph.devdep) - tfree(list->graph.devdep); - tfree(list); + /* If device-dependent space was allocated, free it. */ + { + void * const p = list->graph.devdep; + if (p) { + txfree(p); + } + } - return (1); - } - lastlist = list; - list = list->next; - } + txfree(list); + return 1; + } /* end of case that graph ID was found */ + + lastlist = list; /* update previous node */ + list = list->next; /* step to next node */ + } /* end of loop over graphs in the current bucket */ + + /* The graph with ID id was not found */ internalerror("tried to destroy non-existent graph"); - return (0); -} + return 0; +} /* end of function DestroyGraph */ -/* free up all dynamically allocated data structures */ -void -FreeGraphs(void) + +/* Free up all dynamically allocated data structures */ +void FreeGraphs(void) { + /* Iterate over all hash buckets */ GBUCKET *gbucket; - LISTGRAPH *list, *deadl; - for (gbucket = GBucket; gbucket < &GBucket[NUMGBUCKETS]; gbucket++) { - list = gbucket->list; - while (list) { - deadl = list; + LISTGRAPH * list = gbucket->list; /* linked list of graphs here */ + while (list) { /* Free each until end of list */ + LISTGRAPH *deadl = list; list = list->next; - tfree(deadl); + txfree(deadl); } } -} +} /* end of functdion FreeGraphs */ -void -SetGraphContext(int graphid) + +/* This function sets global varial currentgraph based on graphid */ +void SetGraphContext(int graphid) { currentgraph = FindGraph(graphid); -} +} /* end of function SetGraphContext */ + +/* Stack of graph objects implemented as a linked list */ typedef struct gcstack { GRAPH *pgraph; struct gcstack *next; } GCSTACK; -GCSTACK *gcstacktop; +static GCSTACK *gcstacktop; /* top of the stack of graphs */ /* note: This Push and Pop has tricky semantics. Push(graph) will push the currentgraph onto the stack and set currentgraph to graph. - Pop() simply sets currentgraph to the top of the stack and pops stack. + Pop() simply sets currentgraph to previous value at the top of the stack + and pops stack. */ -void -PushGraphContext(GRAPH *graph) +void PushGraphContext(GRAPH *graph) { GCSTACK *gcstack = TMALLOC(GCSTACK, 1); if (!gcstacktop) { gcstacktop = gcstack; - } else { + } + else { gcstack->next = gcstacktop; gcstacktop = gcstack; } gcstacktop->pgraph = currentgraph; currentgraph = graph; -} +} /* end of function PushGraphContext */ -void -PopGraphContext(void) + +void PopGraphContext(void) { - GCSTACK *dead; - - currentgraph = gcstacktop->pgraph; - dead = gcstacktop; + currentgraph = gcstacktop->pgraph; /* pop from stack, making current */ + GCSTACK *dead = gcstacktop; /* remove from stack */ gcstacktop = gcstacktop->next; - tfree(dead); -} + txfree(dead); /* free allocation */ +} /* end of function PopGraphContext */ + + + diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c index 846ae1115..0484fcd4a 100644 --- a/src/frontend/postcoms.c +++ b/src/frontend/postcoms.c @@ -835,90 +835,111 @@ done: free_pnode(names); } - -void -com_destroy(wordlist *wl) +/* Free resources associated with "plot" datasets. The wordlist contains + * the names of the plots to delete or the word "all" to delete all but the + * default "const" plot, which cannot be deleted, even by name. If there are + * no names given, the current plot is deleted */ +void com_destroy(wordlist *wl) { - struct plot *pl, *npl = NULL; - + /* If no name given, delete the current output data */ if (!wl) { DelPlotWindows(plot_cur); killplot(plot_cur); - } else if (eq(wl->wl_word, "all")) { + } + else if (eq(wl->wl_word, "all")) { /* "all" -> all plots deleted */ + struct plot *pl, *npl = NULL; for (pl = plot_list; pl; pl = npl) { npl = pl->pl_next; if (!eq(pl->pl_typename, "const")) { DelPlotWindows(pl); killplot(pl); - } else { + } + else { plot_num = 1; } } - } else { + } + else { /* list of plots by name */ while (wl) { - for (pl = plot_list; pl; pl = pl->pl_next) - if (eq(pl->pl_typename, wl->wl_word)) + struct plot *pl; + for (pl = plot_list; pl; pl = pl->pl_next) { + if (eq(pl->pl_typename, wl->wl_word)) { break; + } + } if (pl) { DelPlotWindows(pl); killplot(pl); - } else { + } + else { fprintf(cp_err, "Error: no such plot %s\n", wl->wl_word); } wl = wl->wl_next; } } -} +} /* end of function com_destroy */ -static void -killplot(struct plot *pl) + +static void killplot(struct plot *pl) { - struct dvec *v, *nv = NULL; - struct plot *op; - if (eq(pl->pl_typename, "const")) { fprintf(cp_err, "Error: can't destroy the constant plot\n"); return; } /* pl_dvecs, pl_scale */ - for (v = pl->pl_dvecs; v; v = nv) { - nv = v->v_next; - vec_free(v); + { + struct dvec *v; + struct dvec *nv; + for (v = pl->pl_dvecs; v; v = nv) { + nv = v->v_next; + vec_free(v); + } } + /* unlink from plot_list (linked via pl_next) */ - if (pl == plot_list) { + if (pl == plot_list) { /* First in list */ plot_list = pl->pl_next; - if (pl == plot_cur) + if (pl == plot_cur) { plot_cur = plot_list; - } else { - for (op = plot_list; op; op = op->pl_next) - if (op->pl_next == pl) + } + } + else { /* inside list */ + struct plot *op; + for (op = plot_list; op; op = op->pl_next) { + if (op->pl_next == pl) { break; - if (!op) + } + } + if (!op) { fprintf(cp_err, "Internal Error: kill plot -- not in list\n"); + return; + } op->pl_next = pl->pl_next; - if (pl == plot_cur) + if (pl == plot_cur) { plot_cur = op; + } } /* delete the hash table entry for this plot */ - if (pl->pl_lookup_table) + if (pl->pl_lookup_table) { nghash_free(pl->pl_lookup_table, NULL, NULL); - tfree(pl->pl_title); - tfree(pl->pl_name); - tfree(pl->pl_typename); + } + txfree(pl->pl_title); + txfree(pl->pl_name); + txfree(pl->pl_typename); wl_free(pl->pl_commands); - tfree(pl->pl_date); /* va: also tfree (memory leak) */ - if (pl->pl_ccom) /* va: also tfree (memory leak) */ + txfree(pl->pl_date); /* va: also tfree (memory leak) */ + if (pl->pl_ccom) { /* va: also tfree (memory leak) */ throwaway(pl->pl_ccom); + } if (pl->pl_env) { /* The 'environment' for this plot. */ /* va: HOW to do? */ printf("va: killplot should tfree pl->pl_env=(%p)\n", pl->pl_env); fflush(stdout); } - tfree(pl); /* va: also tfree pl itself (memory leak) */ + txfree(pl); /* va: also tfree pl itself (memory leak) */ } diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 17c28e032..1c5b629ec 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -369,8 +369,7 @@ dosim( /* Usage is run [filename] */ -void -com_run(wordlist *wl) +void com_run(wordlist *wl) { /* ft_getsaves(); */ dosim("run", wl); diff --git a/src/frontend/variable.c b/src/frontend/variable.c index 7c1772cd9..5883b4c0a 100644 --- a/src/frontend/variable.c +++ b/src/frontend/variable.c @@ -938,8 +938,9 @@ wordlist *vareval(/* NOT const */ char *string) break; if (!v) { v = cp_enqvar(string, &tbfreed); - if (tbfreed) + if (tbfreed) { vfree = v; + } } wl = wl_cons(copy(v ? "1" : "0"), NULL); free_struct_variable(vfree); @@ -948,13 +949,16 @@ wordlist *vareval(/* NOT const */ char *string) case '#': string++; - for (v = variables; v; v = v->va_next) - if (eq(v->va_name, string)) + for (v = variables; v; v = v->va_next) { + if (eq(v->va_name, string)) { break; + } + } if (!v) { v = cp_enqvar(string, &tbfreed); - if (tbfreed) + if (tbfreed) { vfree = v; + } } if (!v) { fprintf(cp_err, "Error: %s: no such variable.\n", string); @@ -989,17 +993,20 @@ wordlist *vareval(/* NOT const */ char *string) if (eq(v->va_name, string)) break; if (!v && isdigit_c(*string)) { - for (v = variables; v; v = v->va_next) - if (eq(v->va_name, "argv")) + for (v = variables; v; v = v->va_next) { + if (eq(v->va_name, "argv")) { break; + } + } range = string; } if (!v) { range = NULL; string = oldstring; v = cp_enqvar(string, &tbfreed); - if (tbfreed) + if (tbfreed) { vfree = v; + } } if (!v && (s = getenv(string)) != NULL) { wl = wl_cons(copy(s), NULL); @@ -1020,10 +1027,12 @@ wordlist *vareval(/* NOT const */ char *string) wordlist *r = NULL; if (*range == '$') { char *t = ++range; - if (*t == '&') + if (*t == '&') { t++; - while (isalnum_c(*t)) + } + while (isalnum_c(*t)) { t++; + } *t = '\0'; r = vareval(range); if (!r || r->wl_next) { @@ -1034,15 +1043,20 @@ wordlist *vareval(/* NOT const */ char *string) } range = r->wl_word; } - for (low = 0; isdigit_c(*range); range++) + for (low = 0; isdigit_c(*range); range++) { low = low * 10 + *range - '0'; - if ((*range == '-') && isdigit_c(range[1])) - for (up = 0, range++; isdigit_c(*range); range++) + } + if ((*range == '-') && isdigit_c(range[1])) { + for (up = 0, range++; isdigit_c(*range); range++) { up = up * 10 + *range - '0'; - else if (*range == '-') + } + } + else if (*range == '-') { up = wl_length(wl); - else + } + else { up = low; + } up--, low--; wl = wl_range(wl, low, up); wl_free(r); @@ -1059,23 +1073,23 @@ struct xxx { }; -static int -vcmp(const void *a, const void *b) +static int vcmp(const void *a, const void *b) { int i; struct xxx *v1 = (struct xxx *) a; struct xxx *v2 = (struct xxx *) b; - if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)) != 0) - return (i); - else - return (v1->x_char - v2->x_char); + if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)) != 0) { + return i; + } + else { + return v1->x_char - v2->x_char; + } } /* Print the values of currently defined variables. */ -void -cp_vprint(void) +void cp_vprint(void) { struct variable *v; struct variable *uv1; @@ -1086,16 +1100,22 @@ cp_vprint(void) uv1 = cp_usrvars(); - for (v = variables, i = 0; v; v = v->va_next) + for (v = variables, i = 0; v; v = v->va_next) { i++; - for (v = uv1; v; v = v->va_next) + } + for (v = uv1; v; v = v->va_next) { i++; - if (plot_cur) - for (v = plot_cur->pl_env; v; v = v->va_next) + } + if (plot_cur) { + for (v = plot_cur->pl_env; v; v = v->va_next) { i++; - if (ft_curckt) - for (v = ft_curckt->ci_vars; v; v = v->va_next) + } + } + if (ft_curckt) { + for (v = ft_curckt->ci_vars; v; v = v->va_next) { i++; + } + } vars = TMALLOC(struct xxx, i); @@ -1108,26 +1128,30 @@ cp_vprint(void) vars[i].x_v = v; vars[i].x_char = '*'; } - if (plot_cur) + if (plot_cur) { for (v = plot_cur->pl_env; v; v = v->va_next, i++) { vars[i].x_v = v; vars[i].x_char = '*'; } - if (ft_curckt) + } + if (ft_curckt) { for (v = ft_curckt->ci_vars; v; v = v->va_next, i++) { vars[i].x_v = v; vars[i].x_char = '+'; } + } qsort(vars, (size_t) i, sizeof(*vars), vcmp); for (j = 0; j < i; j++) { - if (j && eq(vars[j].x_v->va_name, vars[j-1].x_v->va_name)) + if (j && eq(vars[j].x_v->va_name, vars[j-1].x_v->va_name)) { continue; + } v = vars[j].x_v; if (v->va_type == CP_BOOL) { out_printf("%c %s\n", vars[j].x_char, v->va_name); - } else { + } + else { out_printf("%c %s\t", vars[j].x_char, v->va_name); wl = vareval(v->va_name); s = wl_flatten(wl); @@ -1140,88 +1164,86 @@ cp_vprint(void) free_struct_variable(uv1); tfree(vars); -} +} /* end of function cp_vprint */ -struct variable * -var_alloc(char *name, struct variable *next) + + +struct variable *var_alloc(char *name, struct variable *next) { - struct variable *v = TMALLOC(struct variable, 1); - ZERO(v, struct variable); - v -> va_name = name; - v -> va_next = next; - return v; + struct variable * const v = TMALLOC(struct variable, 1); + ZERO(v, struct variable); + v -> va_name = name; + v -> va_next = next; + return v; } -struct variable * -var_alloc_bool(char *name, bool value, struct variable *next) + + +struct variable *var_alloc_bool(char *name, bool value, + struct variable *next) { struct variable *v = var_alloc(name, next); var_set_bool(v, value); return v; } -struct variable * -var_alloc_num(char *name, int value, struct variable *next) +struct variable *var_alloc_num(char *name, int value, + struct variable *next) { struct variable *v = var_alloc(name, next); var_set_num(v, value); return v; } -struct variable * -var_alloc_real(char *name, double value, struct variable *next) +struct variable *var_alloc_real(char *name, double value, + struct variable *next) { struct variable *v = var_alloc(name, next); var_set_real(v, value); return v; } -struct variable * -var_alloc_string(char *name, char * value, struct variable *next) +struct variable *var_alloc_string(char *name, char * value, + struct variable *next) { struct variable *v = var_alloc(name, next); var_set_string(v, value); return v; } -struct variable * -var_alloc_vlist(char *name, struct variable * value, struct variable *next) +struct variable * var_alloc_vlist(char *name, struct variable * value, + struct variable *next) { struct variable *v = var_alloc(name, next); var_set_vlist(v, value); return v; } -void -var_set_bool(struct variable *v, bool value) +void var_set_bool(struct variable *v, bool value) { v->va_type = CP_BOOL; v->va_bool = value; } -void -var_set_num(struct variable *v, int value) +void var_set_num(struct variable *v, int value) { v->va_type = CP_NUM; v->va_num = value; } -void -var_set_real(struct variable *v, double value) +void var_set_real(struct variable *v, double value) { v->va_type = CP_REAL; v->va_real = value; } -void -var_set_string(struct variable *v, char *value) +void var_set_string(struct variable *v, char *value) { v->va_type = CP_STRING; v->va_string = value; } -void -var_set_vlist(struct variable *v, struct variable *value) +void var_set_vlist(struct variable *v, struct variable *value) { v->va_type = CP_LIST; v->va_vlist = value; diff --git a/src/frontend/vectors.c b/src/frontend/vectors.c index 60168fea2..15f994176 100644 --- a/src/frontend/vectors.c +++ b/src/frontend/vectors.c @@ -1065,7 +1065,7 @@ vec_basename(struct dvec *v) } /* get address of plot named 'name' */ -struct plot *get_plot(char* name) +struct plot *get_plot(const char *name) { @@ -1086,9 +1086,7 @@ struct plot *get_plot(char* name) * va: ATTENTION: has unlinked old keyword-class-tree from keywords[CT_VECTOR] * (potentially memory leak) */ - -void -plot_setcur(char *name) +void plot_setcur(const char *name) { struct plot *pl; @@ -1103,28 +1101,43 @@ plot_setcur(char *name) } /* plots are listed in pl in reverse order */ else if (cieq(name, "previous")) { - if (plot_cur->pl_next) + if (plot_cur->pl_next) { plot_cur = plot_cur->pl_next; - else - fprintf(cp_err, "Warning: Switching to previous plot not possible, stay with current plot (%s)\n", plot_cur->pl_typename); - return; - } else if (cieq(name, "next")) { - struct plot *prev_pl = NULL; - for (pl = plot_list; pl; pl = pl->pl_next) { - if (pl == plot_cur) - break; - prev_pl = pl; } - if (!prev_pl) { - fprintf(cp_err, "Warning: Switching to next plot not possible, stay with current plot (%s)\n", plot_cur->pl_typename); - return; + else { + fprintf(cp_err, + "Warning: No previous plot is available. " + "Plot remains unchanged (%s).\n", + plot_cur->pl_typename); } - plot_cur = prev_pl; return; } - pl = get_plot(name); - if (!pl) + else if (cieq(name, "next")) { + /* Step through the list, which has plots in reverse order */ + struct plot *prev_pl = NULL; + for (pl = plot_list; pl; pl = pl->pl_next) { + if (pl == plot_cur) { + break; + } + prev_pl = pl; + } + if (prev_pl) { /* found */ + plot_cur = prev_pl; + } + else { /* no next plot */ + fprintf(cp_err, + "Warning: No next plot is available. " + "Plot remains unchanged (%s).\n", + plot_cur->pl_typename); + } return; + } + + pl = get_plot(name); + if (!pl) { + return; + } + /* va: we skip cp_kwswitch, because it confuses the keyword-tree management for * repeated op-commands. When however cp_kwswitch is necessary for other * reasons, we should hold the original keyword table pointer in an @@ -1135,15 +1148,14 @@ plot_setcur(char *name) } */ plot_cur = pl; -} +} /* end of function plot_setcur */ + /* Add a plot to the plot list. This is different from plot_add() in that * all this does is update the list and the variable $plots. */ - -void -plot_new(struct plot *pl) +void plot_new(struct plot *pl) { pl->pl_next = plot_list; plot_list = pl; diff --git a/src/include/ngspice/bool.h b/src/include/ngspice/bool.h index 6bdc0df8e..873b1a15e 100644 --- a/src/include/ngspice/bool.h +++ b/src/include/ngspice/bool.h @@ -4,7 +4,7 @@ //typedef unsigned char bool; typedef int bool; -typedef int BOOL ; +typedef int BOOL; #define BOOLEAN int #define TRUE 1 diff --git a/src/include/ngspice/dvec.h b/src/include/ngspice/dvec.h index e24aa066f..888e31242 100644 --- a/src/include/ngspice/dvec.h +++ b/src/include/ngspice/dvec.h @@ -1,6 +1,7 @@ #ifndef ngspice_DVEC_H #define ngspice_DVEC_H +#include "ngspice/bool.h" #include "ngspice/complex.h" #include "ngspice/grid.h" #include "ngspice/sim.h" @@ -8,14 +9,14 @@ /* Dvec flags. */ enum dvec_flags { - VF_REAL = (1 << 0), /* The data is real. */ - VF_COMPLEX = (1 << 1), /* The data is complex. */ - VF_ACCUM = (1 << 2), /* writedata should save this vector. */ - VF_PLOT = (1 << 3), /* writedata should incrementally plot it. */ - VF_PRINT = (1 << 4), /* writedata should print this vector. */ - VF_MINGIVEN = (1 << 5), /* The v_minsignal value is valid. */ - VF_MAXGIVEN = (1 << 6), /* The v_maxsignal value is valid. */ - VF_PERMANENT = (1 << 7) /* Don't garbage collect this vector. */ + VF_REAL = (1 << 0), /* The data is real. */ + VF_COMPLEX = (1 << 1), /* The data is complex. */ + VF_ACCUM = (1 << 2), /* writedata should save this vector. */ + VF_PLOT = (1 << 3), /* writedata should incrementally plot it. */ + VF_PRINT = (1 << 4), /* writedata should print this vector. */ + VF_MINGIVEN = (1 << 5), /* The v_minsignal value is valid. */ + VF_MAXGIVEN = (1 << 6), /* The v_maxsignal value is valid. */ + VF_PERMANENT = (1 << 7) /* Don't garbage collect this vector. */ }; @@ -36,41 +37,46 @@ typedef enum { #define MAXDIMS 8 struct dvec { - char *v_name; /* Same as so_vname. */ + char *v_name; /* Same as so_vname. */ enum simulation_types v_type; /* Same as so_vtype. */ - short v_flags; /* Flags (a combination of VF_*). */ - double *v_realdata; /* Real data. */ - ngcomplex_t *v_compdata; /* Complex data. */ - double v_minsignal; /* Minimum value to plot. */ - double v_maxsignal; /* Maximum value to plot. */ - GRIDTYPE v_gridtype; /* One of GRID_*. */ - PLOTTYPE v_plottype; /* One of PLOT_*. */ - int v_length; /* Length of the vector. */ - int v_alloc_length; /* How much has been actually allocated. */ - int v_rlength; /* How much space we really have. Used as binary flag */ - int v_outindex; /* Index if writedata is building the - vector. */ - int v_linestyle; /* What line style we are using. */ - int v_color; /* What color we are using. */ - char *v_defcolor; /* The name of a color to use. */ - int v_numdims; /* How many dims -- 0 = scalar (len = 1). */ - int v_dims[MAXDIMS]; /* The actual size in each dimension. */ - struct plot *v_plot; /* The plot structure (if it has one). */ - struct dvec *v_next; /* Link for list of plot vectors. */ - struct dvec *v_link2; /* Extra link for things like print. */ - struct dvec *v_scale; /* If this has a non-standard scale... */ + short v_flags; /* Flags (a combination of VF_*). */ + double *v_realdata; /* Real data. */ + ngcomplex_t *v_compdata; /* Complex data. */ + double v_minsignal; /* Minimum value to plot. */ + double v_maxsignal; /* Maximum value to plot. */ + GRIDTYPE v_gridtype; /* One of GRID_*. */ + PLOTTYPE v_plottype; /* One of PLOT_*. */ + int v_length; /* Length of the vector. */ + int v_alloc_length; /* How much has been actually allocated. */ + int v_rlength; /* How much space we really have. Used as binary flag */ + int v_outindex; /* Index if writedata is building the vector. */ + int v_linestyle; /* What line style we are using. */ + int v_color; /* What color we are using. */ + char *v_defcolor; /* The name of a color to use. */ + int v_numdims; /* How many dims -- 0 = scalar (len = 1). */ + int v_dims[MAXDIMS]; /* The actual size in each dimension. */ + struct plot *v_plot; /* The plot structure (if it has one). */ + struct dvec *v_next; /* Link for list of plot vectors. */ + struct dvec *v_link2; /* Extra link for things like print. */ + struct dvec *v_scale; /* If this has a non-standard scale... */ } ; -#define isreal(v) ((v)->v_flags & VF_REAL) +#define isreal(v) ((v)->v_flags & VF_REAL) #define iscomplex(v) ((v)->v_flags & VF_COMPLEX) /* list of data vectors being displayed */ struct dveclist { - struct dvec *vector; struct dveclist *next; + struct dvec *vector; + + /* Flag that this list owns the vector in the sense that it is + * responsible for freeing it. Depending on how the entry was created, + * it either made its own copy or "borrowed" one from anothe use. */ + bool f_own_vector; }; -struct dvec *dvec_alloc(char *name, int type, short flags, int length, void *storage); +struct dvec *dvec_alloc(const char *name, + int type, short flags, int length, void *storage); void dvec_realloc(struct dvec *v, int length, void *storage); void dvec_extend(struct dvec *v, int length); void dvec_trunc(struct dvec *v, int length); diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index e7f405f49..08e5e5449 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -359,8 +359,8 @@ extern void ft_loadfile(char *file); extern void vec_new(struct dvec *d); extern void plot_docoms(wordlist *wl); extern void vec_remove(const char *name); -extern void plot_setcur(char *name); -extern struct plot *get_plot(char* name); +extern void plot_setcur(const char *name); +extern struct plot *get_plot(const char *name); extern void plot_new(struct plot *pl); extern char *vec_basename(struct dvec *v); extern void vec_transpose(struct dvec *v);