|
|
|
@ -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 */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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; |
|
|
|
enum ALL_TYPE_ENUM { |
|
|
|
ALL_TYPE_NONE, |
|
|
|
ALL_TYPE_ALL, |
|
|
|
ALL_TYPE_ALLV, |
|
|
|
ALL_TYPE_ALLI, |
|
|
|
ALL_TYPE_ALLY |
|
|
|
}; |
|
|
|
|
|
|
|
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); |
|
|
|
/* 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 (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); |
|
|
|
if (tolower(word[1] != 'l')) { |
|
|
|
return ALL_TYPE_NONE; |
|
|
|
} |
|
|
|
if (tolower(word[2] != 'l')) { |
|
|
|
return ALL_TYPE_NONE; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
/* 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; |
|
|
|
} |
|
|
|
return (newv); |
|
|
|
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) |
|
|
|
{ |
|
|
|
/* If no plot, cannot find */ |
|
|
|
if (pl == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
/* 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 (!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; |
|
|
|
struct dvec *vec_fromplot(char *word, struct plot *plot) { |
|
|
|
struct dvec *d = findvec(word, plot); |
|
|
|
if (d != (struct dvec *) NULL) { |
|
|
|
return d; |
|
|
|
} |
|
|
|
|
|
|
|
d = findvec(word, plot); |
|
|
|
if (!d) { |
|
|
|
(void) strcpy(buf, word); |
|
|
|
strtolower(buf); |
|
|
|
d = findvec(buf, plot); |
|
|
|
/* Consider forms I(node) and i(node) -> node#branch */ |
|
|
|
if (tolower(word[0]) != (int) 'i') { /* Not i of I.* */ |
|
|
|
return (struct dvec *) NULL; |
|
|
|
} |
|
|
|
if (!d) { |
|
|
|
(void) strcpy(buf, word); |
|
|
|
strtoupper(buf); |
|
|
|
d = findvec(buf, plot); |
|
|
|
|
|
|
|
if (word[1] != '(') { /* Not i or I(.* */ |
|
|
|
return (struct dvec *) NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* 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); |
|
|
|
{ |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
/* 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(buf, plot); |
|
|
|
|
|
|
|
d = findvec(ds_get_buf(&ds), plot); |
|
|
|
ds_free(&ds); |
|
|
|
|
|
|
|
return d; |
|
|
|
} |
|
|
|
} /* end of function vec_fromplot */ |
|
|
|
|
|
|
|
return (d); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 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,70 +922,92 @@ 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 */ |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
* return TRUE if every vector element is zero |
|
|
|
*/ |
|
|
|
|
|
|
|
bool |
|
|
|
vec_iszero(struct dvec *v) |
|
|
|
/* 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) |
|
|
|
{ |
|
|
|
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) |
|
|
|
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 |
|
|
|
for (i = 0; i < v->v_length; i++) { |
|
|
|
if (realpart(v->v_compdata[i]) != 0.0) |
|
|
|
} |
|
|
|
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) |
|
|
|
} |
|
|
|
if (imagpart(v->v_compdata[i]) != 0.0) { |
|
|
|
return FALSE; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return TRUE; /* every value tested was 0.0 */ |
|
|
|
} /* end of function vec_iszero */ |
|
|
|
|
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* This is something we do in a few places... Since vectors get copied a lot, |
|
|
|
@ -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++; |
|
|
|
} |
|
|
|
|