]> granicus.if.org Git - graphviz/commitdiff
Fixes a bug (# unknown) where tcldot or any gv language binding couldn't
authorellson <devnull@localhost>
Thu, 26 Feb 2009 03:10:13 +0000 (03:10 +0000)
committerellson <devnull@localhost>
Thu, 26 Feb 2009 03:10:13 +0000 (03:10 +0000)
write dot,xdot,plain,canon to memory or to Tcl_Channels.

Problem was that agwrite() used fprintf() & putc() directly to an output file.

Fix is to add an output discipline to libgraph so that we can provide our own fwrite() equiv.

The discipline defaults to regular fwrite() and ferror() for backward compat.

Adds new functions to libgraph:
    extern void agsetodisc(
size_t (*fwrite) (FILE *fp, const char *s, size_t len),
int (*ferror) (FILE *fp));
    extern void agfprintf(FILE *fp, const char *format, ...);
    extern int agputs(const char *s, FILE *fp);
    extern int agputc(int c, FILE *fp);

13 files changed:
cmd/dot/dot.c
cmd/tools/gvpack.c
lib/common/output.c
lib/graph/attribs.c
lib/graph/graph.h
lib/graph/graphio.c
lib/graph/libgraph.h
lib/gvc/gvc.c
lib/gvc/gvdevice.c
lib/gvc/gvio.h
lib/gvc/gvplugin.c
plugin/core/gvrender_core_dot.c
tclpkg/tcldot/tcldot.c

index 39c58424139d6b6ac5949575e1eea5a03ba10894..7bf38f94ed237af77435b43e8082a914c39b6a37 100644 (file)
@@ -23,6 +23,7 @@
 #endif
 
 #include "gvc.h"
+#include "gvio.h"
 
 #ifndef WIN32_DLL
 #ifdef GVDLL
@@ -127,6 +128,8 @@ static graph_t *create_test_graph(void)
 
     /* Create a new graph */
 #ifndef WITH_CGRAPH
+    aginit();
+    agsetodisc(gvfwrite, gvferror);
     g = agopen("new_graph", AGDIGRAPH);
 #else /* WITH_CGRAPH */
     g = agopen("new_graph", Agdirected,NIL(Agdisc_t *));
@@ -167,7 +170,7 @@ int main(int argc, char **argv)
 
 #endif /* WITH_CGRAPH */
 
-    Gvc = gvNEWcontext(lt_preloaded_symbols, DEMAND_LOADING);
+    Gvc = gvContextPlugins(lt_preloaded_symbols, DEMAND_LOADING);
     gvParseArgs(Gvc, argc, argv);
 
 #ifndef WIN32
index ded297adfd0e765570836b4e143a6d102de516b6..590ec7e8ffbd611c50d84e06f67a120a8298e19d 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <assert.h>
 #include "gvc.h"
+#include "gvio.h"
 #include "render.h"
 #include "neatoprocs.h"
 #include "ingraphs.h"
@@ -162,6 +163,7 @@ static void init(int argc, char *argv[])
     int c;
 
     aginit();
+    agsetodisc(gvfwrite, gvferror);
     while ((c = getopt(argc, argv, ":ngvum:o:G:?")) != -1) {
        switch (c) {
        case 'n':
index a576de9d03659d8045f020195f8480376c04cce8..8b0930ec4be7d5316b969cd02d2f7117292df809 100644 (file)
@@ -25,7 +25,7 @@ double YF_off;       /* Y_off in inches */
 
 static void printptf(FILE * f, pointf pt)
 {
-    fprintf(f, " %.5g %.5g", PS2INCH(pt.x), PS2INCH(YDIR(pt.y)));
+    agfprintf(f, " %.5g %.5g", PS2INCH(pt.x), PS2INCH(YDIR(pt.y)));
 }
 
 /* setYInvert:
@@ -70,12 +70,12 @@ static void writenodeandport(FILE * fp, node_t * node, char *port)
 #else
        name = agcanonStr (agnameof(node));
 #endif
-    fprintf(fp, "%s", name);   /* slimey i know */
+    agfprintf(fp, "%s", name); /* slimey i know */
     if (port && *port)
 #ifndef WITH_CGRAPH
-       fprintf(fp, ":%s", agcanonical(port));
+       agfprintf(fp, ":%s", agcanonical(port));
 #else
-       fprintf(fp, ":%s", agcanonStr(port));
+       agfprintf(fp, ":%s", agcanonStr(port));
 #endif
 }
 
@@ -94,14 +94,14 @@ void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
 //    setup_graph(job, g);
     setYInvert(g);
     pt = GD_bb(g).UR;
-    fprintf(f, "graph %.5g %.5g %.5g\n", job->zoom, PS2INCH(pt.x), PS2INCH(pt.y));
+    agfprintf(f, "graph %.5g %.5g %.5g\n", job->zoom, PS2INCH(pt.x), PS2INCH(pt.y));
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        if (IS_CLUST_NODE(n))
            continue;
 #ifndef WITH_CGRAPH
-       fprintf(f, "node %s ", agcanonical(agnameof(n)));
+       agfprintf(f, "node %s ", agcanonical(agnameof(n)));
 #else
-       fprintf(f, "node %s ", agcanonStr(agnameof(n)));
+       agfprintf(f, "node %s ", agcanonStr(agnameof(n)));
 #endif
        printptf(f, ND_coord(n));
        if (ND_label(n)->html)   /* if html, get original text */
@@ -112,7 +112,7 @@ void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
 #endif
        else
            lbl = canon(agraphof(n),ND_label(n)->text);
-       fprintf(f, " %.5g %.5g %s %s %s %s %s\n",
+       agfprintf(f, " %.5g %.5g %s %s %s %s %s\n",
                ND_width(n), ND_height(n), lbl,
                late_nnstring(n, N_style, "solid"),
                ND_shape(n)->name,
@@ -148,11 +148,11 @@ void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
                    bz = ED_spl(e)->list[i];
                    splinePoints += bz.size;
                }
-               fprintf(f, "edge ");
+               agfprintf(f, "edge ");
                writenodeandport(f, agtail(e), tport);
-               fprintf(f, " ");
+               agfprintf(f, " ");
                writenodeandport(f, aghead(e), hport);
-               fprintf(f, " %d", splinePoints);
+               agfprintf(f, " %d", splinePoints);
                for (i = 0; i < ED_spl(e)->size; i++) {
                    bz = ED_spl(e)->list[i];
                    for (j = 0; j < bz.size; j++)
@@ -160,14 +160,14 @@ void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
                }
            }
            if (ED_label(e)) {
-               fprintf(f, " %s", canon(agraphof(agtail(e)),ED_label(e)->text));
+               agfprintf(f, " %s", canon(agraphof(agtail(e)),ED_label(e)->text));
                printptf(f, ED_label(e)->pos);
            }
-           fprintf(f, " %s %s\n", late_nnstring(e, E_style, "solid"),
+           agfprintf(f, " %s %s\n", late_nnstring(e, E_style, "solid"),
                    late_nnstring(e, E_color, DEFAULT_COLOR));
        }
     }
-    fprintf(f, "stop\n");
+    agfprintf(f, "stop\n");
 }
 
 static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
index 8e223376cf1eb0d55296c64880c06c15f11794e6..35fe9948b86819fafc815e0bf74f31972cba3907 100644 (file)
@@ -324,6 +324,17 @@ Agsym_t *agprvattr(void *obj, Agsym_t *a)
        return (Agsym_t *)dtprev(dict->dict, a);
 }
 
+static size_t agfwrite(FILE *fp, const char *s, size_t len)
+{
+        return fwrite(s, sizeof(char), len, fp);
+}
+
+static int agferror(FILE *fp)
+{
+        return ferror(fp);
+}
+
+
        /* this is normally called by the aginit() macro */
 void aginitlib(int gs, int ns, int es)
 {
@@ -332,6 +343,8 @@ void aginitlib(int gs, int ns, int es)
        AG.node_nbytes = ns;
        AG.edge_nbytes = es;
        AG.init_called = TRUE;
+       AG.fwrite = agfwrite;
+       AG.ferror = agferror;
        initproto();
     } else
        if ((AG.graph_nbytes != gs) || (AG.node_nbytes != ns)
index f8300f012ae7ce2be7239c58ba80bba2d2268716..824493e8301de3d61fe7a357e28fba23b3cb6615 100644 (file)
@@ -163,6 +163,10 @@ extern "C" {
     extern void agreadline(int);
     extern void agsetfile(char *);
     extern Agraph_t *agmemread(char *);
+    extern void agsetodisc(size_t (*fwrite) (FILE *fp, const char *s, size_t len), int (*ferror) (FILE *fp));
+    extern void agfprintf(FILE *fp, const char *format, ...);
+    extern int agputs(const char *s, FILE *fp);
+    extern int agputc(int c, FILE *fp);
     extern int agwrite(Agraph_t *, FILE *);
     extern int agerrors(void);
     extern Agraph_t *agprotograph(void);
index c3e2cf895b350dd1c623bbc4b2df108316988e77..4edef00a2e14f8bfd0009e8250807a381f292d97 100644 (file)
 
 
 #include "libgraph.h"
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
+#include <string.h>
 
 typedef struct printdict_t {
     Dict_t *nodesleft, *edgesleft, *subgleft, *e_insubg, *n_insubg;
@@ -180,11 +177,61 @@ char *agstrcanon(char *arg, char *buf)
        return (_agstrcanon(arg, buf));
 }
 
+void agsetodisc(size_t (*fwrite) (FILE *fp, const char *s, size_t len), int (*ferror) (FILE *fp))
+{
+       AG.fwrite = fwrite;
+       AG.ferror = ferror;
+}
+
+/* agfprintf:
+ * Note that this function is unsafe due to the fixed buffer size.
+ * It should only be used when the caller is sure the input will not
+ * overflow the buffer. In particular, it should be avoided for
+ * input coming from users. Also, if vsnprintf is available, the
+ * code should check for return values to use it safely.
+ */
+void agfprintf(FILE *fp, const char *format, ...)
+{
+    char buf[BUFSIZ];
+    size_t len;
+    va_list argp;
+
+    va_start(argp, format);
+#ifdef HAVE_VSNPRINTF
+    len = vsnprintf((char *)buf, sizeof(buf), format, argp);
+#else
+    len = vsprintf((char *)buf, format, argp);
+#endif
+    va_end(argp);
+
+    AG.fwrite(fp, buf, len);
+}
+
+int agputs(const char *s, FILE *fp)
+{
+    size_t len = strlen(s);
+
+    if (AG.fwrite(fp, s, len) != len) {
+       return EOF;
+    }
+    return +1;
+}
+
+
+int agputc(int c, FILE *fp)
+{
+    const char cc = c;
+
+    if (AG.fwrite (fp, &cc, 1) != 1) {
+       return EOF;
+    }
+    return c;
+}
 
 static void tabover(FILE * fp, int tab)
 {
     while (tab--)
-       putc('\t', fp);
+       agputc('\t', fp);
 }
 
 static char *getoutputbuffer(char *str)
@@ -232,14 +279,14 @@ static void write_dict(Agdict_t * dict, FILE * fp)
        a = dict->list[i];
        if (ISEMPTYSTR(a->value) == FALSE) {
            if (cnt++ == 0)
-               fprintf(fp, "\t%s [", dict->name);
+               agfprintf(fp, "\t%s [", dict->name);
            else
-               fprintf(fp, ", ");
-           fprintf(fp, "%s=%s", a->name, agcanonical(a->value));
+               agfprintf(fp, ", ");
+           agfprintf(fp, "%s=%s", a->name, agcanonical(a->value));
        }
     }
     if (cnt > 0)
-       fprintf(fp, "];\n");
+       agfprintf(fp, "];\n");
 }
 
 static void write_diffattr(FILE * fp, int indent, void *obj, void *par,
@@ -262,24 +309,24 @@ static void write_diffattr(FILE * fp, int indent, void *obj, void *par,
        if (strcmp(p, q)) {
            if (cnt++ == 0) {
                tabover(fp, indent);
-               fprintf(fp, "%s [", dict->name);
+               agfprintf(fp, "%s [", dict->name);
            } else {
-               fprintf(fp, ",\n");
+               agfprintf(fp, ",\n");
                tabover(fp, indent + 1);
            }
-           fprintf(fp, "%s=", agcanonical(a->name));
-           fprintf(fp, "%s", agcanonical(p));
+           agfprintf(fp, "%s=", agcanonical(a->name));
+           agfprintf(fp, "%s", agcanonical(p));
        }
     }
     if (cnt > 0)
-       fprintf(fp, "];\n");
+       agfprintf(fp, "];\n");
 }
 
 static void writeattr(FILE * fp, int *npp, char *name, char *val)
 {
-    fprintf(fp, ++(*npp) > 1 ? ", " : " [");
-    fprintf(fp, "%s=", agcanonical(name));
-    fprintf(fp, "%s", agcanonical(val));
+    agfprintf(fp, ++(*npp) > 1 ? ", " : " [");
+    agfprintf(fp, "%s=", agcanonical(name));
+    agfprintf(fp, "%s", agcanonical(val));
 }
 
 void agwrnode(Agraph_t * g, FILE * fp, Agnode_t * n, int full, int indent)
@@ -303,20 +350,20 @@ void agwrnode(Agraph_t * g, FILE * fp, Agnode_t * n, int full, int indent)
            if (strcmp(defval, myval)) {
                if (didwrite == FALSE) {
                    tabover(fp, indent);
-                   fprintf(fp, "%s", agcanonical(n->name));
+                   agfprintf(fp, "%s", agcanonical(n->name));
                    didwrite = TRUE;
                }
                writeattr(fp, &nprint, a->name, myval);
            }
        }
        if (didwrite) {
-           fprintf(fp, (nprint > 0 ? "];\n" : ";\n"));
+           agfprintf(fp, (nprint > 0 ? "];\n" : ";\n"));
            return;
        }
     }
     if ((agfstout(g, n) == NULL) && (agfstin(g, n) == NULL)) {
        tabover(fp, indent);
-       fprintf(fp, "%s;\n", agcanonical(n->name));
+       agfprintf(fp, "%s;\n", agcanonical(n->name));
     }
 }
 
@@ -325,23 +372,23 @@ void agwrnode(Agraph_t * g, FILE * fp, Agnode_t * n, int full, int indent)
 static void writenodeandport(FILE * fp, char *node, char *port)
 {
     char *ss;
-    fprintf(fp, "%s", agcanonical(node));      /* slimey i know */
+    agfprintf(fp, "%s", agcanonical(node));    /* slimey i know */
     if (port && *port) {
        if (aghtmlstr(port)) {
-           fprintf(fp, ":%s", agstrcanon(port, getoutputbuffer(port)));
+           agfprintf(fp, ":%s", agstrcanon(port, getoutputbuffer(port)));
        }
        else {
            ss = strchr (port, ':');
            if (ss) {
                *ss = '\0';
-               fprintf(fp, ":%s",
+               agfprintf(fp, ":%s",
                    _agstrcanon(port, getoutputbuffer(port)));
-               fprintf(fp, ":%s",
+               agfprintf(fp, ":%s",
                    _agstrcanon(ss+1, getoutputbuffer(ss+1)));
                *ss = ':';
            }
            else {
-               fprintf(fp, ":%s", _agstrcanon(port, getoutputbuffer(port)));
+               agfprintf(fp, ":%s", _agstrcanon(port, getoutputbuffer(port)));
            }
        }
     }
@@ -364,7 +411,7 @@ void agwredge(Agraph_t * g, FILE * fp, Agedge_t * e, int list_all)
     else
        edgeop = "--";
     writenodeandport(fp, e->tail->name, tport);
-    fprintf(fp, " %s ", edgeop);
+    agfprintf(fp, " %s ", edgeop);
     writenodeandport(fp, e->head->name, hport);
     if (list_all) {
        for (i = 0; i < dtsize(d->dict); i++) {
@@ -381,7 +428,7 @@ void agwredge(Agraph_t * g, FILE * fp, Agedge_t * e, int list_all)
                writeattr(fp, &nprint, a->name, myval);
        }
     }
-    fprintf(fp, (nprint > 0 ? "];\n" : ";\n"));
+    agfprintf(fp, (nprint > 0 ? "];\n" : ";\n"));
 }
 
 Dtdisc_t agEdgedisc = {
@@ -408,9 +455,9 @@ write_subg(Agraph_t * g, FILE * fp, Agraph_t * par, int indent,
        tabover(fp, indent++);
        if (dtsearch(state->subgleft, g->meta_node)) {
            if (strncmp(g->name, "_anonymous", 10))
-               fprintf(fp, "subgraph %s {\n", agcanonical(g->name));
+               agfprintf(fp, "subgraph %s {\n", agcanonical(g->name));
            else
-               fprintf(fp, "{\n");     /* no name printed for anonymous subg */
+               agfprintf(fp, "{\n");   /* no name printed for anonymous subg */
            write_diffattr(fp, indent, g, par, g->univ->globattr);
            /* The root node and edge environment use the dictionaries,
             * not the proto node or edge, so the next level down must
@@ -427,7 +474,7 @@ write_subg(Agraph_t * g, FILE * fp, Agraph_t * par, int indent,
            write_diffattr(fp, indent, g->proto->e, pe, g->univ->edgeattr);
            dtdelete(state->subgleft, g->meta_node);
        } else {
-           fprintf(fp, "subgraph %s;\n", agcanonical(g->name));
+           agfprintf(fp, "subgraph %s;\n", agcanonical(g->name));
            return;
        }
     } else
@@ -477,7 +524,7 @@ write_subg(Agraph_t * g, FILE * fp, Agraph_t * par, int indent,
 
     if (indent > 1) {
        tabover(fp, indent - 1);
-       fprintf(fp, "}\n");
+       agfprintf(fp, "}\n");
     }
 }
 
@@ -527,9 +574,9 @@ int agwrite(Agraph_t * g, FILE * fp)
     t0 = (AG_IS_STRICT(g)) ? "strict " : "";
     t1 = (AG_IS_DIRECTED(g)) ? "digraph" : "graph";
     if (strncmp(g->name, "_anonymous", 10))
-       fprintf(fp, "%s%s %s {\n", t0, t1, agcanonical(g->name));
+       agfprintf(fp, "%s%s %s {\n", t0, t1, agcanonical(g->name));
     else
-       fprintf(fp, "%s%s {\n", t0, t1);
+       agfprintf(fp, "%s%s {\n", t0, t1);
 
     /* write the top level attribute defs */
     write_dict(g->univ->globattr, fp);
@@ -539,7 +586,7 @@ int agwrite(Agraph_t * g, FILE * fp)
     /* write the graph contents */
     p = new_printdict_t(g);
     write_subg(g, fp, (Agraph_t *) 0, 0, p);
-    fprintf(fp, "}\n");
+    agfprintf(fp, "}\n");
     free_printdict_t(p);
-    return ferror(fp);
+    return AG.ferror(fp);
 }
index cd61a1d18946c0f84f303f133284bc9b8d401284..ec1ce104e5aa7a30478c24e7104e48b9953bd491 100644 (file)
@@ -25,8 +25,9 @@ extern "C" {
 #if _PACKAGE_ast
 #include    <ast.h>
 #else
-#include <string.h>
+#include <stdarg.h>
 #include <stdlib.h>
+#include <string.h>
 #ifndef MSWIN32
 #include <unistd.h>
 #endif
@@ -128,6 +129,8 @@ extern "C" {
        char *linebuf;
        short syntax_errors;
        unsigned char accepting_state, init_called;
+       size_t (*fwrite) (FILE *fp, const char *s, size_t len);
+       int (*ferror) (FILE *fp);
     } AG;
 
 /* follow structs used in graph parser */
index a6b2b6837fa7bf5c8f6c0bc16ace69376114d15f..45b02bd0930b915f7fd155431a7d5023f06aa7f0 100644 (file)
@@ -24,6 +24,7 @@
 #include "gvcint.h"
 #include "gvcproc.h"
 #include "gvconfig.h"
+#include "gvio.h"
 
 GVC_t *gvContext(void)
 {
@@ -31,6 +32,7 @@ GVC_t *gvContext(void)
 
 #ifndef WITH_CGRAPH
     aginit();
+    agsetodisc(gvfwrite, gvferror);
     agnodeattr(NULL, "label", NODENAME_ESC);
 #else
     agattr(NULL, AGNODE, "label", NODENAME_ESC);
@@ -47,6 +49,7 @@ GVC_t *gvContextPlugins(const lt_symlist_t *builtins, int demand_loading)
 
 #ifndef WITH_CGRAPH
     aginit();
+    agsetodisc(gvfwrite, gvferror);
     agnodeattr(NULL, "label", NODENAME_ESC);
 #else
     agattr(NULL, AGNODE, "label", NODENAME_ESC);
index 9b07a199948cfc962e8e66b0aa0da9afc8fb3442..1b39e3d80f001ea479c13377df876ef2b777d5b2 100644 (file)
@@ -252,6 +252,16 @@ size_t gvwrite (GVJ_t * job, const char *s, size_t len)
     return len;
 }
 
+int gvferror (FILE* fp)
+{
+    return 0;
+}
+
+size_t gvfwrite (FILE* fp, const char *s, size_t len)
+{
+    return gvwrite((GVJ_t*)fp, s, len);
+}
+
 int gvputs(GVJ_t * job, const char *s)
 {
     size_t len = strlen(s);
index 50694460b1362dfb41dccbdd46a69b0889e30b49..f54d7c4072b211855ba215b87328b01b23a23ee5 100644 (file)
@@ -37,7 +37,9 @@ extern "C" {
 #endif
 /*end visual studio*/
 
-       extern size_t gvwrite (GVJ_t * job, const char *s, size_t len);
+    extern size_t gvwrite (GVJ_t * job, const char *s, size_t len);
+    extern size_t gvfwrite (FILE * job, const char *s, size_t len);
+    extern int gvferror (FILE * job);
     extern int gvputc(GVJ_t * job, int c);
     extern int gvputs(GVJ_t * job, const char *s);
     extern void gvprintf(GVJ_t * job, const char *format, ...);
index ade0cc3fda99b1155e60cacea557d755fea09ee3..70b429c950ba063ed00fdced61f21a3f29feed13 100644 (file)
@@ -29,6 +29,7 @@
 #include        "gvcjob.h"
 #include        "gvcint.h"
 #include        "gvcproc.h"
+#include        "gvio.h"
 
 #include       "const.h"
 
@@ -466,6 +467,7 @@ Agraph_t * gvplugin_graph(GVC_t * gvc)
 
 #ifndef WITH_CGRAPH
     aginit();
+    agsetodisc(gvfwrite, gvferror);
     /* set persistent attributes here */
     agraphattr(NULL, "label", "");
     agraphattr(NULL, "rankdir", "");
index c4234c7cdb3705b969ed51cb436a53d8a8dcca68..c77e8f97edd9323079d2fbfd778bb456099a89f0 100644 (file)
@@ -415,20 +415,20 @@ static void dot_end_graph(GVJ_t *job)
 
     switch (job->render.id) {
        case FORMAT_PLAIN:
-           write_plain(job, g, job->output_file, FALSE);
+           write_plain(job, g, (FILE*)job, FALSE);
            break;
        case FORMAT_PLAIN_EXT:
-           write_plain(job, g, job->output_file, TRUE);
+           write_plain(job, g, (FILE*)job, TRUE);
            break;
        case FORMAT_DOT:
        case FORMAT_CANON:
            if (!(job->flags & OUTPUT_NOT_REQUIRED))
-               agwrite(g, job->output_file);
+               agwrite(g, (FILE*)job);
            break;
        case FORMAT_XDOT:
            xdot_end_graph(g);
            if (!(job->flags & OUTPUT_NOT_REQUIRED))
-               agwrite(g, job->output_file);
+               agwrite(g, (FILE*)job);
            break;
     }
 }
index 5017e665f2834e205c6109fcf7197eefc4df64bd..b8e192e21508f614b1394f644658ef94bf46a987 100644 (file)
@@ -21,6 +21,7 @@
 #include <tcl.h>
 #include "render.h"
 #include "gvc.h"
+#include "gvio.h"
 #include "tclhandle.h"
 
 #ifndef CONST84
@@ -1721,6 +1722,7 @@ int Tcldot_Init(Tcl_Interp * interp)
 #endif
 
     aginit();
+    agsetodisc(gvfwrite, gvferror);
     /* set persistent attributes here */
     agnodeattr(NULL, "label", NODENAME_ESC);