diff --git a/src/frontend/vectors.c b/src/frontend/vectors.c index 3daba86cf..3d26bc95b 100644 --- a/src/frontend/vectors.c +++ b/src/frontend/vectors.c @@ -23,6 +23,17 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/dstring.h" #include "plotting/plotting.h" + +static struct dvec *findvec_all(struct plot *pl); +static struct dvec *findvec_allv(struct plot *pl); +static struct dvec *findvec_alli(struct plot *pl); +static struct dvec *findvec_ally(struct plot *pl); +static struct dvec *find_permanent_vector_by_name( + NGHASHPTR pl_lookup_table, char *name); +static enum ALL_TYPE_ENUM get_all_type(const char *word); +static bool plot_prefix(const char *pre, const char *str); + + #ifdef XSPICE /* gtri - begin - add function prototype for EVTfindvec */ struct dvec *EVTfindvec(char *node); @@ -30,8 +41,7 @@ struct dvec *EVTfindvec(char *node); #endif -static void -vec_rebuild_lookup_table(struct plot *pl) +static void vec_rebuild_lookup_table(struct plot *pl) { if (pl->pl_lookup_table) { /* existing table */ nghash_empty(pl->pl_lookup_table, NULL, NULL); @@ -63,112 +73,107 @@ vec_rebuild_lookup_table(struct plot *pl) ds_free(&dbuf); } - pl->pl_lookup_valid = TRUE; + pl->pl_lookup_valid = TRUE; /* now lookup table valid */ } /* end of function vec_rebuild_lookup_table */ +enum ALL_TYPE_ENUM { + ALL_TYPE_NONE, + ALL_TYPE_ALL, + ALL_TYPE_ALLV, + ALL_TYPE_ALLI, + ALL_TYPE_ALLY +}; + + +/* Efficient identification of "all", "allv", "alli", "ally", and anything + * else */ +static enum ALL_TYPE_ENUM get_all_type(const char *word) +{ + /* Check for start of "all" */ + if (tolower(word[0] != 'a')) { + return ALL_TYPE_NONE; + } + if (tolower(word[1] != 'l')) { + return ALL_TYPE_NONE; + } + if (tolower(word[2] != 'l')) { + return ALL_TYPE_NONE; + } + + /* It may be some type of all */ + switch (tolower(word[3])) { + case '\0': + return ALL_TYPE_ALL; + case 'v': + if (word[4] == '\0') { + return ALL_TYPE_ALLV; + } + else { + return ALL_TYPE_NONE; + } + case 'i': + if (word[4] == '\0') { + return ALL_TYPE_ALLI; + } + else { + return ALL_TYPE_NONE; + } + case 'y': + if (word[4] == '\0') { + return ALL_TYPE_ALLY; + } + else { + return ALL_TYPE_NONE; + } + default: + return ALL_TYPE_NONE; + } /* end of swith over char after "all" */ +} /* end of function get_all_type */ + + + /* Find a named vector in a plot. We are careful to copy the vector if * v_link2 is set, because otherwise we will get screwed up. */ -static struct dvec * -findvec(char *word, struct plot *pl) { - struct dvec *d, *newv = NULL, *end = NULL, *v; - - if (pl == NULL) - return (NULL); - - if (cieq(word, "all")) { - for (d = pl->pl_dvecs; d; d = d->v_next) { - if (d->v_flags & VF_PERMANENT) { - if (d->v_link2) { - v = vec_copy(d); - vec_new(v); - } else { - v = d; - } - if (end) - end->v_link2 = v; - else - newv = v; - end = v; - } - } - return (newv); +static struct dvec *findvec(char *word, struct plot *pl) +{ + /* If no plot, cannot find */ + if (pl == NULL) { + return NULL; } - if (cieq(word, "allv")) { - for (d = pl->pl_dvecs; d; d = d->v_next) { - if ((d->v_flags & VF_PERMANENT) && (d->v_type == SV_VOLTAGE)) { - if (d->v_link2) { - v = vec_copy(d); - vec_new(v); - } else { - v = d; - } - if (end) - end->v_link2 = v; - else - newv = v; - end = v; - } - } - return (newv); + /* Identify and handle special cases all, allv, alli, ally */ + switch (get_all_type(word)) { + case ALL_TYPE_ALL: + return findvec_all(pl); + case ALL_TYPE_ALLV: + return findvec_allv(pl); + case ALL_TYPE_ALLI: + return findvec_alli(pl); + case ALL_TYPE_ALLY: + return findvec_ally(pl); + default: /* case ALL_TYPE_NOT_ALL -- not some type of ALL */ + break; } - if (cieq(word, "alli")) { - for (d = pl->pl_dvecs; d; d = d->v_next) { - if ((d->v_flags & VF_PERMANENT) && (d->v_type == SV_CURRENT)) { - if (d->v_link2) { - v = vec_copy(d); - vec_new(v); - } else { - v = d; - } - if (end) - end->v_link2 = v; - else - newv = v; - end = v; - } - } - return (newv); - } - - if (cieq(word, "ally")) { - for (d = pl->pl_dvecs; d; d = d->v_next) { - if ((d->v_flags & VF_PERMANENT) && (!cieq(d->v_name, pl->pl_scale->v_name))) { - if (d->v_link2) { - v = vec_copy(d); - vec_new(v); - } else { - v = d; - } - if (end) - end->v_link2 = v; - else - newv = v; - end = v; - } - } - return (newv); - } - - if (!pl->pl_lookup_valid) + /* The find is not for one of the "all" cases */ + if (!pl->pl_lookup_valid) { + /* Table lookup not valid, so rebuild to make valid */ vec_rebuild_lookup_table(pl); + } DS_CREATE(dbuf, 200); /* make dynamic buffer */ if (ds_cat_str_case(&dbuf, word, ds_case_lower) != DS_E_OK) { controlled_exit(-1); } char * const lower_name = ds_get_buf(&dbuf); + NGHASHPTR pl_lookup_table = pl->pl_lookup_table; + struct dvec *d = find_permanent_vector_by_name(pl_lookup_table, + lower_name); - for (d = nghash_find(pl->pl_lookup_table, lower_name); - d; - d = nghash_find_again(pl->pl_lookup_table, lower_name)) { - if (d->v_flags & VF_PERMANENT) - break; - } - + /* If the vector was not using the lowercased name, try finding it as + * v(lowercased name) */ if (!d) { ds_clear(&dbuf); bool f_ok = ds_cat_str(&dbuf, "v(") == DS_E_OK; @@ -179,12 +184,7 @@ findvec(char *word, struct plot *pl) { controlled_exit(-1); } char * const node_name = ds_get_buf(&dbuf); - for (d = nghash_find(pl->pl_lookup_table, node_name); - d; - d = nghash_find_again(pl->pl_lookup_table, node_name)) { - if (d->v_flags & VF_PERMANENT) - break; - } + d = find_permanent_vector_by_name(pl_lookup_table, node_name); } ds_free(&dbuf); @@ -192,8 +192,9 @@ findvec(char *word, struct plot *pl) { #ifdef XSPICE /* gtri - begin - Add processing for getting event-driven vector */ - if (!d) + if (!d) { d = EVTfindvec(word); + } /* gtri - end - Add processing for getting event-driven vector */ #endif @@ -207,11 +208,72 @@ findvec(char *word, struct plot *pl) { +/* Macro taking a function name and vector filter as arguments that + * generates the function that applies the filter */ +#define FINDVEC_ALL_GEN(fun_name, filter)\ +static struct dvec *fun_name(struct plot *pl)\ +{\ + struct dvec *d, *newv = NULL, *end = NULL, *v;\ + for (d = pl->pl_dvecs; d; d = d->v_next) {\ + if (filter) {\ + if (d->v_link2) {\ + v = vec_copy(d);\ + vec_new(v);\ + }\ + else {\ + v = d;\ + }\ + if (end) {\ + end->v_link2 = v;\ + }\ + else {\ + newv = v;\ + }\ + end = v;\ + }\ + } /* end of loop over vectors in plot */\ +\ + return newv;\ +} /* end of function */ + +/* Generate the functions for each filter */ +FINDVEC_ALL_GEN(findvec_all, d->v_flags & VF_PERMANENT) +FINDVEC_ALL_GEN(findvec_allv, + (d->v_flags & VF_PERMANENT) && (d->v_type == SV_VOLTAGE)) +FINDVEC_ALL_GEN(findvec_alli, + (d->v_flags & VF_PERMANENT) && (d->v_type == SV_CURRENT)) +FINDVEC_ALL_GEN(findvec_ally, + (d->v_flags & VF_PERMANENT) && + (!cieq(d->v_name, pl->pl_scale->v_name))) + + + +/* Find a permanent vector with the given name */ +static struct dvec *find_permanent_vector_by_name( + NGHASHPTR pl_lookup_table, char *name) +{ + struct dvec *d; + + /* Find the first vector with the given name and then find others + * until one having the VF_PERMANENT flag set is found. */ + for (d = nghash_find(pl_lookup_table, name); + d; + d = nghash_find_again(pl_lookup_table, name)) { + if (d->v_flags & VF_PERMANENT) { + /* A "permanent" vector was found with the name, so done */ + return d; + } + } /* end of loop over vectors in the plot having this name */ + + return (struct dvec *) NULL; /* not found */ +} /* end of function find_permanent_vector_by_name */ + + + /* If there are imbedded numeric strings, compare them numerically, not * alphabetically. */ -static int -namecmp(const void *a, const void *b) +static int namecmp(const void *a, const void *b) { int i, j; @@ -373,38 +435,44 @@ vec_remove(const char *name) * it checks for pre-defined vectors. */ -struct dvec * -vec_fromplot(char *word, struct plot *plot) { - struct dvec *d; - char buf[BSIZE_SP], buf2[BSIZE_SP], cc, *s; - - d = findvec(word, plot); - if (!d) { - (void) strcpy(buf, word); - strtolower(buf); - d = findvec(buf, plot); - } - if (!d) { - (void) strcpy(buf, word); - strtoupper(buf); - d = findvec(buf, plot); +struct dvec *vec_fromplot(char *word, struct plot *plot) { + struct dvec *d = findvec(word, plot); + if (d != (struct dvec *) NULL) { + return d; } - /* scanf("%c(%s)" doesn't do what it should do. ) */ - if (!d && (sscanf(word, "%c(%s", &cc, buf) == 2) && - ((s = strrchr(buf, ')')) != NULL) && - (s[1] == '\0')) { - *s = '\0'; - if (prefix("i(", word) || prefix("I(", word)) { - /* Spice dependency... */ - (void) sprintf(buf2, "%s#branch", buf); - (void) strcpy(buf, buf2); + /* Consider forms I(node) and i(node) -> node#branch */ + if (tolower(word[0]) != (int) 'i') { /* Not i of I.* */ + return (struct dvec *) NULL; + } + + if (word[1] != '(') { /* Not i or I(.* */ + return (struct dvec *) NULL; + } + + { + const char * const p_node = word + 2; + const char *p_end = p_node + strlen(p_node); + if (*--p_end != ')') { /* Not i or I then '(' with a closing ')' */ + return (struct dvec *) NULL; } - d = findvec(buf, plot); - } - return (d); -} + /* Form is correct, so see if node#branch exists */ + DS_CREATE(ds, 100); + if (ds_cat_mem(&ds, p_node, p_end - p_node) != DS_E_OK) { + controlled_exit(-1); + } + if (ds_cat_str(&ds, "#branch") != DS_E_OK) { + controlled_exit(-1); + } + + d = findvec(ds_get_buf(&ds), plot); + ds_free(&ds); + + return d; + } +} /* end of function vec_fromplot */ + /* This is the main lookup routine for names. The possible types of names are: @@ -484,7 +552,7 @@ vec_get(const char *vec_name) { } } - if (!d && (*word == SPECCHAR)) { + if (!d && (*word == SPECCHAR)) { /* "@" */ /* This is a special quantity... */ if (ft_nutmeg) { fprintf(cp_err, @@ -579,30 +647,37 @@ vec_get(const char *vec_name) { */ struct variable *nv; + /* Count the number of nodes in the list */ i = 0; - for (nv = vv->va_vlist; nv; nv = nv->va_next) + for (nv = vv->va_vlist; nv; nv = nv->va_next) { i++; + } - dvec_realloc(d, i, NULL); + dvec_realloc(d, i, NULL); /* Resize to # nodes */ + /* Step through the list again, setting values this time */ i = 0; - for (nv = vv->va_vlist; nv; nv = nv->va_next) + for (nv = vv->va_vlist; nv; nv = nv->va_next) { d->v_realdata[i++] = nv->va_real; + } /* To be able to identify the vector to represent * belongs to a special "conunto" and should be printed in a * special way. */ d->v_dims[1] = 1; - } else if (vv->va_type == CP_NUM) { /* Variable is an integer */ + } + else if (vv->va_type == CP_NUM) { /* Variable is an integer */ *d->v_realdata = (double) vv->va_num; - } else if (vv->va_type == CP_REAL) { /* Variable is a real */ + } + else if (vv->va_type == CP_REAL) { /* Variable is a real */ if (!(vv->va_next)) { /* Only a real data * usually normal */ *d->v_realdata = vv->va_real; - } else { + } + else { /* Real data set * When you print a model @ [all] * Just print numerical values, not the string @@ -632,8 +707,9 @@ vec_get(const char *vec_name) { } nv = nv->va_next; - if (!nv) + if (!nv) { break; + } } /* To distinguish those does not take anything for print screen to @@ -648,7 +724,7 @@ vec_get(const char *vec_name) { tfree(wd); vec_new(d); tfree(whole); - return (d); + return d; } tfree(wd); @@ -676,27 +752,29 @@ plot_docoms(wordlist *wl) } -/* Create a copy of a vector. */ - -struct dvec * -vec_copy(struct dvec *v) { +/* Create a copy of a vector. The vector is not "permananent" */ +struct dvec *vec_copy(struct dvec *v) { struct dvec *nv; - int i; - if (!v) - return (NULL); + if (!v) { + return (struct dvec *) NULL; + } + /* Make a copy with the VF_PERMANENT bit cleared in v_flags */ nv = dvec_alloc(copy(v->v_name), v->v_type, v->v_flags & ~VF_PERMANENT, v->v_length, NULL); - if (isreal(v)) - memcpy(nv->v_realdata, v->v_realdata, + /* Copy the data to the new vector */ + if (isreal(v)) { + (void) memcpy(nv->v_realdata, v->v_realdata, sizeof(double) * (size_t) v->v_length); - else - memcpy(nv->v_compdata, v->v_compdata, + } + else { + (void) memcpy(nv->v_compdata, v->v_compdata, sizeof(ngcomplex_t) * (size_t) v->v_length); + } nv->v_minsignal = v->v_minsignal; nv->v_maxsignal = v->v_maxsignal; @@ -719,23 +797,26 @@ vec_copy(struct dvec *v) { nv->v_color = 0; /*XXX???*/ nv->v_defcolor = v->v_defcolor; nv->v_numdims = v->v_numdims; - for (i = 0; i < v->v_numdims; i++) - nv->v_dims[i] = v->v_dims[i]; + + /* Copy defined dimensions */ + (void) memcpy(nv->v_dims, v->v_dims, v->v_numdims * sizeof *v->v_dims); + nv->v_plot = v->v_plot; nv->v_next = NULL; nv->v_link2 = NULL; nv->v_scale = v->v_scale; - return (nv); -} + return nv; +} /* end of function vec_copy */ + /* Create a new plot structure. This just fills in the typename and sets up * the ccom struct. */ -struct plot * -plot_alloc(char *name) { +struct plot * plot_alloc(char *name) +{ struct plot *pl = TMALLOC(struct plot, 1), *tp; char *s; struct ccom *ccom; @@ -841,71 +922,93 @@ vec_gc(void) * in a plot are gone it stays around... */ -void -vec_free_x(struct dvec *v) +void vec_free_x(struct dvec *v) { - struct plot *pl; - - if ((v == NULL) || (v->v_name == NULL)) + /* Do not free if NULL or name is NULL. The second possibility is a + * special case */ + if ((v == NULL) || (v->v_name == NULL)) { return; - pl = v->v_plot; + } + struct plot * const pl = v->v_plot; /* Now we have to take this dvec out of the plot list. */ if (pl != NULL) { pl->pl_lookup_valid = FALSE; + + /* If at head of list of vectors in the plot, make the next one + * the new head of the list */ if (pl->pl_dvecs == v) { pl->pl_dvecs = v->v_next; - } else { + } + else { + /* Not at head of list so must locate and fix links */ struct dvec *lv = pl->pl_dvecs; - if (lv) - for (; lv->v_next; lv = lv->v_next) - if (lv->v_next == v) + if (lv) { /* the plot has at least one vector */ + for ( ; lv->v_next; lv = lv->v_next) { + if (lv->v_next == v) { /* found prev vector */ break; - if (lv && lv->v_next) + } + } + } + + /* If found in the list, link prev vector to next one */ + if (lv && lv->v_next) { lv->v_next = v->v_next; - else - fprintf(cp_err, + } + else { + (void) fprintf(cp_err, "vec_free: Internal Error: %s not in plot\n", v->v_name); - } + } + } /* end of case that vector being freed is not at head of list */ + if (pl->pl_scale == v) { - if (pl->pl_dvecs) + if (pl->pl_dvecs) { pl->pl_scale = pl->pl_dvecs; /* Random one... */ - else + } + else { pl->pl_scale = NULL; + } + } + } /* end of case that have a plot */ + + dvec_free(v); +} /* end of function vec_free_x */ + + + +/* This function returns TRUE if every element of v and every element of + * every vector linked to v through v_link2 is zero and FALSE otherwise. */ +bool vec_iszero(const struct dvec *v) +{ + for (; v; v = v->v_link2) { /* step through linked vectors */ + if (isreal(v)) { /* current vector is real */ + const int n = v->v_length; + int i; + for (i = 0; i < n; i++) { + if (v->v_realdata[i] != 0.0) { + return FALSE; + } + } + } + else { /* current vector is complex */ + const int n = v->v_length; + int i; + for (i = 0; i < n; i++) { + if (realpart(v->v_compdata[i]) != 0.0) { + return FALSE; + } + if (imagpart(v->v_compdata[i]) != 0.0) { + return FALSE; + } + } } } - dvec_free(v); -} + return TRUE; /* every value tested was 0.0 */ +} /* end of function vec_iszero */ -/* - * return TRUE if every vector element is zero - */ - -bool -vec_iszero(struct dvec *v) -{ - int i; - - for (; v; v = v->v_link2) - if (isreal(v)) - for (i = 0; i < v->v_length; i++) { - if (v->v_realdata[i] != 0.0) - return FALSE; - } - else - for (i = 0; i < v->v_length; i++) { - if (realpart(v->v_compdata[i]) != 0.0) - return FALSE; - if (imagpart(v->v_compdata[i]) != 0.0) - return FALSE; - } - - return TRUE; -} - /* This is something we do in a few places... Since vectors get copied a lot, * we can't just compare pointers to tell if two vectors are 'really' the same. @@ -962,15 +1065,20 @@ vec_basename(struct dvec *v) } /* get address of plot named 'name' */ -struct plot * -get_plot(char* name) { +struct plot *get_plot(char* name) + + +{ struct plot *pl; - for (pl = plot_list; pl; pl = pl->pl_next) - if (plot_prefix(name, pl->pl_typename)) + for (pl = plot_list; pl; pl = pl->pl_next) { + if (plot_prefix(name, pl->pl_typename)) { return pl; + } + } fprintf(cp_err, "Error: no such plot named %s\n", name); - return NULL; -} + return (struct plot *) NULL; +} /* end of function get_plot */ + /* Make a plot the current one. This gets called by cp_usrset() when one @@ -1177,16 +1285,16 @@ vec_mkfamily(struct dvec *v) { /* This function will match "op" with "op1", but not "op1" with "op12". */ - -bool -plot_prefix(char *pre, char *str) +static bool plot_prefix(const char *pre, const char *str) { - if (!*pre) - return (TRUE); + if (!*pre) { /* prefix is empty string */ + return TRUE; /* Define "" to be prefix */ + } while (*pre && *str) { - if (*pre != *str) + if (*pre != *str) { /* stop at first mismatch */ break; + } pre++; str++; } diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 6c35ae118..9a4c9bae0 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -336,7 +336,7 @@ extern int ft_typnum(char *); /* vectors.c */ -extern bool vec_iszero(struct dvec *v); +extern bool vec_iszero(const struct dvec *v); extern bool vec_eq(struct dvec *v1, struct dvec *v2); extern int plot_num; extern struct dvec *vec_fromplot(char *word, struct plot *plot); @@ -363,7 +363,6 @@ extern void plot_setcur(char *name); extern struct plot *get_plot(char* name); extern void plot_new(struct plot *pl); extern char *vec_basename(struct dvec *v); -extern bool plot_prefix(char *pre, char *str); extern void vec_transpose(struct dvec *v); /* main.c */