Cleaned up code to locate a vector in a plot by name. The code was made more modular, and special names like allv are handled more efficiently

This commit is contained in:
Jim Monte 2019-11-29 22:22:04 -05:00 committed by Holger Vogt
parent 8285bd107a
commit ba29c514f9
2 changed files with 318 additions and 211 deletions

View File

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

View File

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