libexpr does not allow NULL for strings.
return agxset(objp, gsym, val);
}
+/* kindToStr:
+ */
+static char*
+kindToStr (int kind)
+{
+ char* s;
+
+ switch (kind) {
+ case AGRAPH :
+ s = "graph";
+ break;
+ case AGNODE :
+ s = "node";
+ break;
+ default :
+ s = "edge";
+ break;
+ }
+ return s;
+}
+
+/* kindOf:
+ * Return string rep of object's kind
+ */
+static char*
+kindOf (Agobj_t* objp)
+{
+ return (kindToStr (agobjkind (objp)));
+}
+
/* lookup:
* Apply symbol to get field value of objp
* Assume objp != NULL
return -1;
break;
}
- } else
- v->string = agget(objp, sym->name);
+ } else {
+ Agsym_t *gsym = agattrsym(objp, sym->name);
+ if (!gsym) {
+ gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), sym->name, "");
+ error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\"", sym->name, kindOf (objp), agnameof(objp));
+ }
+ v->string = agxget(objp, gsym);
+ }
return 0;
}
return 0;
}
-/* getDfltAttr:
+/* toKind:
+ * Map string to object kind
*/
-static char*
-getDfltAttr (Agraph_t *gp, char* k, char* name)
+static int
+toKind (char* k)
{
int kind;
- Agsym_t* sym;
switch (*k) {
case 'G' :
kind = AGNODE;
break;
default :
- error(ERROR_WARNING, "Unknown kind \"%s\" passed to getDflt()", k);
- return 0;
+ error(ERROR_FATAL, "Unknown kind \"%s\" passed to getDflt()", k);
break;
}
- sym = agattr (gp, kind, name, 0);
- if (sym) return sym->defval;
- else return 0;
+ return kind;
+}
+
+/* getDfltAttr:
+ */
+static char*
+getDfltAttr (Agraph_t *gp, char* k, char* name)
+{
+ int kind = toKind (k);
+ Agsym_t* sym = agattr (gp, kind, name, 0);
+ if (!sym) {
+ sym = agattr(gp, kind, name, "");
+ error(ERROR_WARNING, "Uninitialized %s attribute \"%s\" in getDflt", kindToStr (kind), name);
+ }
+ return sym->defval;
}
/* getval:
case F_kindof:
objp = INT2PTR(Agobj_t *, args[0].integer);
if (!objp) {
- error(ERROR_WARNING, "NULL object passed to kindOf()");
- v.string = 0;
+ error(ERROR_FATAL, "NULL object passed to kindOf()");
} else switch (AGTYPE(objp)) {
case AGRAPH :
v.string = "G";
case F_log:
v.floating = log(args[0].floating);
break;
+ case F_hasattr:
case F_get:
objp = INT2PTR(Agobj_t *, args[0].integer);
+ char* name = args[1].string;
if (!objp) {
- error(ERROR_WARNING, "NULL object passed to aget()");
- v.string = 0;
- } else {
- char* name = args[1].string;
- if (name) v.string = agget(objp, name);
+ error(ERROR_FATAL, "NULL object passed to aget()/hasAttr()");
+ } else if (!name) {
+ error(ERROR_FATAL, "NULL name passed to aget()/hasAttr()");
+ }
+ else {
+ Agsym_t *gsym = agattrsym(objp, name);
+ if (sym->index == F_hasattr)
+ v.integer = (gsym != NULL);
else {
- error(ERROR_WARNING, "NULL name passed to aget()");
- v.string = 0;
- }
+ if (!gsym) {
+ gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), name, "");
+ error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\" in aget()", name, kindOf (objp), agnameof(objp));
+ }
+ v.string = agxget(objp, gsym);
+ }
}
break;
case F_set:
v.integer = 0;
}
break;
+ case F_isattr:
case F_dget:
gp = INT2PTR(Agraph_t *, args[0].integer);
if (gp) {
char* kind = args[1].string;
char* name = args[2].string;
if (!name) {
- error(ERROR_WARNING, "NULL name passed to getDflt()");
- v.string = 0;
+ error(ERROR_FATAL,"NULL name passed to getDflt()/isAttr()");
}
else if (!kind) {
- error(ERROR_WARNING, "NULL kind passed to getDflt()");
- v.string = 0;
+ error(ERROR_FATAL,"NULL kind passed to getDflt()/isAttr()");
}
+ else if (sym->index == F_isattr) {
+ v.integer = (agattr(gp, toKind (kind), name, 0) != NULL);
+ }
else {
v.string = getDfltAttr(gp, kind, name);
}
} else {
- error(ERROR_WARNING, "NULL graph passed to node()");
- v.string = 0;
+ error(ERROR_FATAL, "NULL graph passed to getDflt()/isAttr()");
}
break;
case F_canon:
F_set "aset" FUNCTION I|A(1,O)|A(2,S)|A(3,S)
F_dget "getDflt" FUNCTION S|A(1,G)|A(2,S)|A(3,S)
F_dset "setDflt" FUNCTION I|A(1,G)|A(2,S)|A(3,S)|A(4,S)
+F_hasattr "hasAttr" FUNCTION I|A(1,O)|A(2,S)
+F_isattr "isAttr" FUNCTION I|A(1,G)|A(2,S)|A(3,S)
C_flat "TV_flat" CONSTANT T_tvtyp
C_dfs "TV_dfs" CONSTANT T_tvtyp
C_bfs "TV_bfs" CONSTANT T_tvtyp
\fBinduce\fP(\fIg\fP : \fBgraph_t\fP) : \fBvoid\fP
extends \fIg\fP to its node\(hyinduced subgraph extension in its root graph.
.TP
+\fBhasAttr\fP(\fIsrc\fP : \fBobj_t\fP, \fIname\fP : \fBstring\fP) : \fBint\fP
+returns non-zero if object \fIsrc\fP has an attribute whose name is
+\fIname\fP. It returns 0 otherwise.
+.TP
+\fBisAttr\fP(\fIg\fP : \fBgraph_t\fP, \fIkind\fP : \fBstring\fP, \fIname\fP : \fBstring\fP) : \fBint\fP
+returns non-zero if an attribute \fIname\fP has been defined in \fIg\fP
+for objects of the given \fIkind\fP. For nodes, edges, and graphs, \fIkind\fP
+should be "N", "E", and "G", respectively.
+It returns 0 otherwise.
+.TP
\fBaget\fP(\fIsrc\fP : \fBobj_t\fP, \fIname\fP : \fBstring\fP) : \fBstring\fP
returns the value of attribute \fIname\fP in object \fIsrc\fP. This is
useful for those cases when \fIname\fP conflicts with one of the keywords
such as "head" or "root".
-Returns \fBNULL\fP on failure or if the attribute is not defined.
+If the attribute has not been declared in the graph, the function will
+initialize it with a default value of "". To avoid this, one should use
+the \fBhasAttr\fP or \fBisAttr\fP function to check that the attribute exists.
.TP
\fBaset\fP(\fIsrc\fP : \fBobj_t\fP, \fIname\fP : \fBstring\fP, \fIvalue\fP : \fBstring\fP) : \fBint\fP
sets the value of attribute \fIname\fP in object \fIsrc\fP to \fIvalue\fP.
returns the default value of attribute \fIname\fP in objects in \fIg\fP of
the given \fIkind\fP. For nodes, edges, and graphs, \fIkind\fP
should be "N", "E", and "G", respectively.
-Returns \fBNULL\fP on failure or if the attribute is not defined.
+If the attribute has not been declared in the graph, the function will
+initialize it with a default value of "". To avoid this, one should use
+the \fBisAttr\fP function to check that the attribute exists.
.TP
\fBsetDflt\fP(\fIg\fP : \fBgraph_t\fP, \fIkind\fP : \fBstring\fP, \fIname\fP : \fBstring\fP, \fIvalue\fP : \fBstring\fP) : \fBint\fP
sets the default value of attribute \fIname\fP to \fIvalue\fP in
objects in \fIg\fP of
the given \fIkind\fP. For nodes, edges, and graphs, \fIkind\fP
should be "N", "E", and "G", respectively.
-Returns 0 on success, non\(hyzero on failure. See \fBsetDflt\fP above.
+Returns 0 on success, non\(hyzero on failure. See \fBgetDflt\fP above.
.TP
\fBcompOf\fP(\fIg\fP : \fBgraph_t\fP, \fIn\fP : \fBnode_t\fP) : \fBgraph_t\fP
returns the connected component of the graph \fIg\fP containing node \fIn\fP,
\fB$tvtype\fP : \fBtvtype_t\fP
indicates how \fBgvpr\fP traverses a graph. At present, it can only take
one of six values: \fBTV_flat\fP, \fBTV_dfs\fP, \fBTV_fwd\fP,
-\fBTV_ref\fP, \fBTV_bfs\fP, \fBTV_ne\fP, and \fBTV_en\fP.
+\fBTV_rev\fP, \fBTV_bfs\fP, \fBTV_ne\fP, and \fBTV_en\fP.
\fBTV_flat\fP is the default.
The meaning of these values is discussed below.
.TP