]> granicus.if.org Git - graphviz/commitdiff
Add new commands for testing if attributes exists. Needed because
authorerg <devnull@localhost>
Tue, 22 Jul 2008 15:26:00 +0000 (15:26 +0000)
committererg <devnull@localhost>
Tue, 22 Jul 2008 15:26:00 +0000 (15:26 +0000)
libexpr does not allow NULL for strings.

cmd/gvpr/compile.c
cmd/gvpr/gprdata
cmd/gvpr/gvpr.1

index 31b794e5de2c8bb686bbe54f4b26132726fee854..e0815df25738ab4e7381fa988fd64363d28bae95 100644 (file)
@@ -306,6 +306,36 @@ setattr (Agobj_t *objp, char* name, char* val)
     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
@@ -418,8 +448,14 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            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;
 }
@@ -461,13 +497,13 @@ setDfltAttr (Agraph_t *gp, char* k, char* name, char* value)
     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' :
@@ -480,13 +516,24 @@ getDfltAttr (Agraph_t *gp, char* k, char* name)
        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:
@@ -715,8 +762,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        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";
@@ -1186,18 +1232,26 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        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:
@@ -1247,25 +1301,26 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
                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:
index b84d26e5db9a25d97552e9951198c83b1bfe2e62..1cf7c5f538c9e8188883ed904d0166b36be8e0e4 100644 (file)
@@ -98,6 +98,8 @@ F_get       "aget"         FUNCTION S|A(1,O)|A(2,S)
 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
index ada8f74a7be2c4074bd5e199723594a34409ddda..ff68143d0f0bc38f3f15d4941058b8b17903d9c4 100644 (file)
@@ -500,11 +500,23 @@ any attribute values \fItgt\fP may initially have.
 \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.
@@ -514,14 +526,16 @@ Returns 0 on success, non\(hyzero on failure. See \fBaget\fP above.
 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,
@@ -769,7 +783,7 @@ The default value is \fBNULL\fP for each input graph.
 \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