mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1de6f88f1e | ||
|
|
6e6e9fb73f | ||
|
|
33fed391fd | ||
|
|
e84700a607 | ||
|
|
5f5248b3d0 | ||
|
|
0bee21ccc8 | ||
|
|
80f9263004 | ||
|
|
c269f1de89 | ||
|
|
edb50746cb | ||
|
|
4443826f9e | ||
|
|
f2368ca223 | ||
|
|
a60dac6124 | ||
|
|
ee93d52a26 | ||
|
|
bbe645f0ab |
+219
-7
@@ -7530,6 +7530,12 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
|
||||
else {
|
||||
lob = ob;
|
||||
ob->type = i++;
|
||||
if (ob->model.class == NULL) {
|
||||
ob->model.class = strsave(tc->name);
|
||||
}
|
||||
if (ob->instance.name == NULL) {
|
||||
ob->instance.name = strsave(firstpin->instance.name);
|
||||
}
|
||||
ob = ob->next;
|
||||
}
|
||||
tob = tob->next;
|
||||
@@ -7595,6 +7601,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
int hasproxy1 = 0, hasproxy2 = 0;
|
||||
int needclean1 = 0, needclean2 = 0;
|
||||
int nomatch = 0;
|
||||
int P1, P2;
|
||||
int filenum = -1;
|
||||
int *correspond;
|
||||
char *ostr;
|
||||
@@ -7627,6 +7634,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
return 2;
|
||||
}
|
||||
|
||||
correspond = (int *)CALLOC((tc1->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
cover = (char *)CALLOC(numnodes, sizeof(char));
|
||||
numorig = numnodes;
|
||||
|
||||
@@ -7845,8 +7853,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
ob1 = tc1->cell;
|
||||
|
||||
correspond = (int *)CALLOC((tc1->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
|
||||
@@ -7967,7 +7973,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
else {
|
||||
else if (IsPort(ob1) && IsPort(ob2)) {
|
||||
struct Permutation *permute1, *permute2;
|
||||
struct objlist *ob1a = NULL, *ob2a = NULL;
|
||||
|
||||
@@ -7997,10 +8003,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
}
|
||||
if (ob1a && ob2a) {
|
||||
if ((ob1->node == ob1a->node) && (ob2->node == ob2a->node)) {
|
||||
/* This should be enough to prove equivalency */
|
||||
if ((correspond[ob1->node] == 0) || (correspond[ob1->node] == ob2->node)) {
|
||||
|
||||
correspond[ob1->node] = ob2->node; /* remember corresponding node */
|
||||
if ((correspond[ob1->node] == 0) ||
|
||||
(correspond[ob1->node] == ob2->node)) {
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
@@ -8263,6 +8267,38 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0)
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
|
||||
/* Catch errors where disconnected ports get effectively hidden by */
|
||||
/* pin permutations. */
|
||||
|
||||
if (result == 1) {
|
||||
int found = 0;
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
P1 = P2 = 0;
|
||||
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
|
||||
if (N1->graph == Circuit2->file)
|
||||
if (IsPort(N1->object)) P2++;
|
||||
if (N1->graph == Circuit1->file)
|
||||
if (IsPort(N1->object)) P1++;
|
||||
}
|
||||
if (P1 != P2) {
|
||||
if (found == 0)
|
||||
Fprintf(stdout, "\nPort connection errors found:\n");
|
||||
found = 1;
|
||||
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
|
||||
obn = N1->object;
|
||||
|
||||
if (IsPort(obn))
|
||||
Fprintf(stdout, " %s (%d)\n", obn->name, N1->graph);
|
||||
else
|
||||
Fprintf(stdout, " %s (%d) (no port)\n", obn->name, N1->graph);
|
||||
if (N1->graph == Circuit1->file)
|
||||
correspond[obn->node] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == 1) Fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
/* Run cleanuppins on circuit 1 */
|
||||
if (needclean1)
|
||||
CleanupPins(tc1->name, tc1->file);
|
||||
@@ -8475,6 +8511,182 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Structure and definitins used by derivedprops() */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
enum DerivedType {area_type, perimeter_type};
|
||||
|
||||
typedef struct _derivedpropdata {
|
||||
struct nlist *cell;
|
||||
int fnum;
|
||||
char *pwidth;
|
||||
char *plength;
|
||||
enum DerivedType type;
|
||||
} DerivedPropData;
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* derivedprops --- Callback function for a recursive */
|
||||
/* search over all cells with a pointer clientdata. */
|
||||
/* The pointer is a DerivedPropData structure that */
|
||||
/* contains the information needed to determine how to */
|
||||
/* generate an "area" or "perimeter" property based on */
|
||||
/* the device length and width. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct nlist *derivedprops(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob;
|
||||
struct valuelist *vl, *newvlist;
|
||||
struct nlist *tc;
|
||||
struct property *prop;
|
||||
int i;
|
||||
double valuew, valuel, valuea = 0.0, valuep = 0.0;
|
||||
int haswidth = FALSE, haslength = FALSE;
|
||||
int hasarea = FALSE, hasperimeter = FALSE;
|
||||
|
||||
DerivedPropData *dpd = (DerivedPropData *)clientdata;
|
||||
|
||||
tc = dpd->cell;
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (ptr->file != tc->file) return NULL;
|
||||
|
||||
/* Search all instances in the cell for properties, find those matching
|
||||
* the cell class to be modified, and create a new derived property for
|
||||
* area or perimeter for that instance.
|
||||
*/
|
||||
|
||||
for (ob = ptr->cell; ob; ob = ob->next) {
|
||||
if (ob->type == PROPERTY) {
|
||||
if ((*matchfunc)(ob->model.class, tc->name)) {
|
||||
for (i = 0;; i++) {
|
||||
vl = &(ob->instance.props[i]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
prop = (struct property *)HashLookup(vl->key, &(tc->propdict));
|
||||
if (prop != NULL) {
|
||||
if ((*matchfunc)(vl->key, dpd->pwidth)) {
|
||||
haswidth = TRUE;
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
valuew = vl->value.dval;
|
||||
else if (vl->type == PROP_INTEGER)
|
||||
valuew = (double)vl->value.ival;
|
||||
else
|
||||
haswidth = FALSE;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, dpd->plength)) {
|
||||
haslength = TRUE;
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
valuel = vl->value.dval;
|
||||
else if (vl->type == PROP_INTEGER)
|
||||
valuel = (double)vl->value.ival;
|
||||
else
|
||||
haslength = FALSE;
|
||||
}
|
||||
else if ((dpd->type == area_type)
|
||||
&& ((*matchfunc)(vl->key, "area"))) {
|
||||
hasarea = TRUE;
|
||||
}
|
||||
else if ((dpd->type == perimeter_type)
|
||||
&& ((*matchfunc)(vl->key, "perimeter"))) {
|
||||
hasperimeter = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (haslength && haswidth) {
|
||||
|
||||
/* Once the property names for device width and length have
|
||||
* been found, and the values recorded, add the area or
|
||||
* perimeter value to the property list for the instance,
|
||||
* unless the instance already has the property.
|
||||
*/
|
||||
newvlist = (struct valuelist *)CALLOC(i + 1, sizeof(struct valuelist));
|
||||
vl = &newvlist[i];
|
||||
vl->key = NULL;
|
||||
vl->type = PROP_ENDLIST;
|
||||
vl->value.ival = 0;
|
||||
|
||||
vl = &newvlist[--i];
|
||||
if ((dpd->type == area_type) && (!hasarea)) {
|
||||
valuea = valuew * valuel;
|
||||
vl->key = strsave("area");
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = valuea;
|
||||
|
||||
} else if ((dpd->type == perimeter_type) && (!hasperimeter)) {
|
||||
valuep = 2 * (valuew + valuel);
|
||||
vl->key = strsave("perimeter");
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = valuep;
|
||||
}
|
||||
for (--i; i >= 0; i--) {
|
||||
vl = &newvlist[i];
|
||||
vl->key = ob->instance.props[i].key;
|
||||
vl->type = ob->instance.props[i].type;
|
||||
vl->value = ob->instance.props[i].value;
|
||||
}
|
||||
FREE(ob->instance.props);
|
||||
ob->instance.props = newvlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "area" or "perimeter" property in all */
|
||||
/* instances of a given device, based on the specified */
|
||||
/* names for the width and length parameters. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DeriveProperty(struct nlist *tc, int fnum, char *pwidth, char *plength,
|
||||
enum DerivedType type)
|
||||
{
|
||||
DerivedPropData dpd;
|
||||
|
||||
dpd.pwidth = pwidth;
|
||||
dpd.plength = plength;
|
||||
dpd.fnum = fnum;
|
||||
dpd.cell = tc;
|
||||
dpd.type = type;
|
||||
|
||||
/* Create the new derived property in the cell. */
|
||||
if (type == area_type)
|
||||
PropertyDouble(tc->name, fnum, "area", 0.01, 0.0);
|
||||
else if (type == perimeter_type)
|
||||
PropertyDouble(tc->name, fnum, "perimeter", 0.01, 0.0);
|
||||
else
|
||||
return;
|
||||
|
||||
/* Find all instances of the cell and add the derived property */
|
||||
RecurseCellHashTable2(derivedprops, (void *)(&dpd));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "area" property in all instances of a */
|
||||
/* given device, based on the specified width and */
|
||||
/* length parameter names. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DeriveAreaProperty(struct nlist *tp, int fnum, char *pwidth, char *plength)
|
||||
{
|
||||
DeriveProperty(tp, fnum, pwidth, plength, area_type);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "perimeter" property in all instances */
|
||||
/* of a given device, based on the specified width and */
|
||||
/* length parameter names. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DerivePerimeterProperty(struct nlist *tp, int fnum, char *pwidth, char *plength)
|
||||
{
|
||||
DeriveProperty(tp, fnum, pwidth, plength, perimeter_type);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Flatten the two cells at the top of the compare */
|
||||
/* queue. */
|
||||
|
||||
@@ -70,6 +70,8 @@ extern int remove_group_tags(struct objlist *ob);
|
||||
#ifdef TCL_NETGEN
|
||||
extern int EquivalentNode();
|
||||
extern int EquivalentElement();
|
||||
extern void DeriveAreaProperty();
|
||||
extern void DerivePerimeterProperty();
|
||||
|
||||
extern void enable_interrupt();
|
||||
extern void disable_interrupt();
|
||||
|
||||
+19
-3
@@ -329,6 +329,11 @@ int GetNextLineNoNewline(char *delimiter)
|
||||
llen = strlen(line);
|
||||
}
|
||||
while (llen == linesize - 1) {
|
||||
/* Note that in the rare case where a newline is in the last buffer
|
||||
* position, we're done.
|
||||
*/
|
||||
if (*(line + llen - 1) == '\n') break;
|
||||
|
||||
newbuf = (char *)MALLOC(linesize + 501);
|
||||
strcpy(newbuf, line);
|
||||
FREE(line);
|
||||
@@ -599,7 +604,7 @@ void SpiceTokNoNewline(void)
|
||||
{
|
||||
int contline;
|
||||
|
||||
if ((nexttok = strdtok(NULL, WHITESPACE_DELIMITER, NULL)) != NULL) return;
|
||||
if ((nexttok = strdtok0(NULL, WHITESPACE_DELIMITER, NULL, FALSE)) != NULL) return;
|
||||
|
||||
while (nexttok == NULL) {
|
||||
contline = getc(infile);
|
||||
@@ -701,7 +706,7 @@ void SpiceSkipNewLine(void)
|
||||
/* the boundary between two-character and one-character delimiters. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
|
||||
{
|
||||
static char *stoken = NULL;
|
||||
static char *sstring = NULL;
|
||||
@@ -746,7 +751,7 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
/* should know whether it is parsing SPICE or verilog and handle the syntax */
|
||||
/* accordingly (needs to be done). */
|
||||
|
||||
if (*s == '\\') {
|
||||
if (isverilog && (*s == '\\')) {
|
||||
s++;
|
||||
while (*s != '\0') {
|
||||
if ((*s == ' ') || ((*s == '\\') && (*(s + 1) == '\0'))) {
|
||||
@@ -817,6 +822,17 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
return sstring;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* strdtok() is the original string tokenizer. It calls strdtok0() */
|
||||
/* with isverilog=TRUE, so that tokens are parsed as (potentially) */
|
||||
/* verilog names, which includes verilog backslash notation. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
char *strdtok(char *pstring, char *delim1, char *delim2)
|
||||
{
|
||||
return strdtok0(pstring, delim1, delim2, TRUE);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void InputParseError(FILE *f)
|
||||
|
||||
@@ -36,6 +36,7 @@ extern struct hashdict *definitions;
|
||||
|
||||
extern char *nexttok;
|
||||
#define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a))
|
||||
extern char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog);
|
||||
extern char *strdtok(char *pstring, char *delim1, char *delim2);
|
||||
extern char *GetLineAtTok();
|
||||
extern void SkipTok(char *delimiter);
|
||||
|
||||
+4
-1
@@ -2248,7 +2248,10 @@ int PromoteProperty(struct property *prop, struct valuelist *vl,
|
||||
if (prop == NULL || vl == NULL) return -1;
|
||||
if (prop->type == vl->type) return 1; /* Nothing to do */
|
||||
result = 0;
|
||||
if (prop->type == PROP_EXPRESSION) {
|
||||
/* If vl is an expression but prop is not, then try to reduce
|
||||
* the expression in vl.
|
||||
*/
|
||||
if (vl->type == PROP_EXPRESSION) {
|
||||
ReduceOneExpression(vl, ob, tc, FALSE);
|
||||
}
|
||||
switch (prop->type) {
|
||||
|
||||
@@ -532,6 +532,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
SkipTok(NULL); /* get the next token */
|
||||
if ((EndParseFile()) && (nexttok == NULL)) break;
|
||||
if (nexttok == NULL) break;
|
||||
|
||||
if (nexttok[0] == '*') SkipNewLine(NULL);
|
||||
|
||||
|
||||
@@ -594,6 +594,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
lappend properr [lindex $endval 0]
|
||||
} elseif {$uresult == -2} { ;# unmatched pins
|
||||
set doCheckFlatten 1
|
||||
} elseif {$uresult == -4} { ;# unmatched pins and properties
|
||||
lappend properr [lindex $endval 0]
|
||||
set doCheckFlatten 1
|
||||
}
|
||||
} else {
|
||||
# not equivalent
|
||||
|
||||
+60
-9
@@ -2572,6 +2572,7 @@ _netcmp_run(ClientData clientData,
|
||||
/* 0: not verified */
|
||||
/* -1: no elements or nodes */
|
||||
/* -3: verified with property error */
|
||||
/* -4: verified with property and port errors */
|
||||
/* equiv option */
|
||||
/* -2: pin mismatch */
|
||||
/* */
|
||||
@@ -2673,8 +2674,12 @@ _netcmp_verify(ClientData clientData,
|
||||
else if (automorphisms == -2) {
|
||||
if (index == EQUIV_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
else if (index == UNIQUE_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
|
||||
else if (index == UNIQUE_IDX) {
|
||||
if (PropertyErrorDetected == 0)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
|
||||
else
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-4));
|
||||
}
|
||||
else if (index > 0)
|
||||
Fprintf(stdout, "Circuits match uniquely with port errors.\n");
|
||||
}
|
||||
@@ -3428,13 +3433,21 @@ _netcmp_property(ClientData clientData,
|
||||
double dval;
|
||||
int ival, argstart;
|
||||
|
||||
char *topoptions[] = {
|
||||
"default", "series", "serial", "parallel", "topology", NULL
|
||||
};
|
||||
enum TopOptionIdx {
|
||||
TOP_DEFAULT_IDX, TOP_SERIES_IDX, TOP_SERIAL_IDX, TOP_PARALLEL_IDX,
|
||||
TOP_TOPOLOGY_IDX
|
||||
};
|
||||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||
"series", "parallel", "associate", "topology", NULL
|
||||
"series", "parallel", "associate", "derive", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, TOPOLOGY_IDX
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, DERIVE_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
@@ -3469,6 +3482,14 @@ _netcmp_property(ClientData clientData,
|
||||
COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_CRITICAL_IDX
|
||||
};
|
||||
|
||||
char *deriveoptions[] = {
|
||||
"area", "perimeter", NULL
|
||||
};
|
||||
|
||||
enum DeriveOptionIdx {
|
||||
AREA_IDX, PERIMETER_IDX
|
||||
};
|
||||
|
||||
char *yesno[] = {
|
||||
"on", "yes", "true", "enable", "allow",
|
||||
"off", "no", "false", "disable", "prohibit", NULL
|
||||
@@ -3483,8 +3504,13 @@ _netcmp_property(ClientData clientData,
|
||||
"strict", "relaxed", NULL
|
||||
};
|
||||
|
||||
/* Don't need to check return value */
|
||||
index = -1;
|
||||
Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)topoptions,
|
||||
"option", 0, &index);
|
||||
|
||||
/* Check for special command "property default" */
|
||||
if ((objc == 2) && (!strcmp(Tcl_GetString(objv[1]), "default"))) {
|
||||
if ((objc == 2) && (index == TOP_DEFAULT_IDX)) {
|
||||
|
||||
/* For each FET device, do "merge {w add_critical}" and */
|
||||
/* "remove as ad ps pd". This allows parallel devices */
|
||||
@@ -3531,7 +3557,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && (!strcmp(Tcl_GetString(objv[1]), "parallel"))) {
|
||||
else if ((objc == 3) && (index == TOP_PARALLEL_IDX)) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
GlobalParallelNone = TRUE;
|
||||
SetParallelCombine(FALSE);
|
||||
@@ -3553,8 +3579,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && ((!strcmp(Tcl_GetString(objv[1]), "series")) ||
|
||||
(!strcmp(Tcl_GetString(objv[1]), "serial")))) {
|
||||
else if ((objc == 3) && ((index == TOP_SERIES_IDX) || (index == TOP_SERIAL_IDX))) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
SetSeriesCombine(FALSE);
|
||||
}
|
||||
@@ -3568,7 +3593,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc > 1) && (!strcmp(Tcl_GetString(objv[1]), "topology"))) {
|
||||
else if ((objc > 1) && (index == TOP_TOPOLOGY_IDX)) {
|
||||
if (objc == 2) {
|
||||
if (ExactTopology)
|
||||
Tcl_SetResult(interp, "Strict topology property matching.",
|
||||
@@ -4014,6 +4039,32 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
break;
|
||||
|
||||
case DERIVE_IDX:
|
||||
/* Create a derived property. For now, this just creates
|
||||
* "area" or "perimeter" properties. There may not (?)
|
||||
* be enough cause to make other ones. Unlike other
|
||||
* "property" options, this option causes the whole circuit
|
||||
* database to be searched for the device in question, and
|
||||
* the new property is added.
|
||||
*/
|
||||
if (objc < 6) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "{area|perimeter width length}");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
result = Tcl_GetIndexFromObj(interp, objv[3],
|
||||
(CONST84 char **)deriveoptions,
|
||||
"area|perimeter", 0, &idx2);
|
||||
if (result != TCL_OK) return result;
|
||||
switch (idx2) {
|
||||
case AREA_IDX:
|
||||
DeriveAreaProperty(tp, fnum, Tcl_GetString(objv[4]),
|
||||
Tcl_GetString(objv[5]));
|
||||
break;
|
||||
case PERIMETER_IDX:
|
||||
DerivePerimeterProperty(tp, fnum, Tcl_GetString(objv[4]),
|
||||
Tcl_GetString(objv[5]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
Reference in New Issue
Block a user