Graphviz  2.29.20120524.0446
tclpkg/gv/gv.cpp
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include "gvc.h"
00017 
00018 extern "C" {
00019 extern void gv_string_writer_init(GVC_t *gvc);
00020 extern void gv_channel_writer_init(GVC_t *gvc);
00021 }
00022 
00023 #ifdef WITH_CGRAPH
00024 #define agfindattr(x,s) agattrsym(x,s)
00025 #define agraphattr(g,n,s) agattr(g,AGRAPH,n,s)
00026 #define agnodeattr(g,n,s) agattr(g,AGNODE,n,s)
00027 #define agedgeattr(g,n,s) agattr(g,AGEDGE,n,s)
00028 #endif
00029 
00030 static char emptystring[] = {'\0'};
00031 
00032 static GVC_t *gvc;
00033 
00034 static void gv_init(void) {
00035     /* list of builtins, enable demand loading */
00036     gvc = gvContextPlugins(lt_preloaded_symbols, DEMAND_LOADING);
00037 }
00038 
00039 Agraph_t *graph(char *name)
00040 {
00041     if (!gvc)
00042         gv_init();
00043 #ifdef WITH_CGRAPH
00044     return agopen(name, Agundirected, 0);
00045 #else
00046     return agopen(name, AGRAPH);
00047 #endif
00048 }
00049 
00050 Agraph_t *digraph(char *name)
00051 {
00052     if (!gvc)
00053         gv_init();
00054 #ifdef WITH_CGRAPH
00055     return agopen(name, Agdirected, 0);
00056 #else
00057     return agopen(name, AGDIGRAPH);
00058 #endif
00059 }
00060 
00061 Agraph_t *strictgraph(char *name)
00062 {
00063     if (!gvc)
00064         gv_init();
00065 #ifdef WITH_CGRAPH
00066     return agopen(name, Agstrictundirected, 0);
00067 #else
00068     return agopen(name, AGRAPHSTRICT);
00069 #endif
00070 }
00071 
00072 Agraph_t *strictdigraph(char *name)
00073 {
00074     if (!gvc)
00075         gv_init();
00076 #ifdef WITH_CGRAPH
00077     return agopen(name, Agstrictdirected, 0);
00078 #else
00079     return agopen(name, AGDIGRAPHSTRICT);
00080 #endif
00081 }
00082 
00083 Agraph_t *readstring(char *string)
00084 {
00085     if (!gvc)
00086         gv_init();
00087     return agmemread(string);
00088 }
00089 
00090 Agraph_t *read(FILE *f)
00091 {
00092     if (!gvc)
00093         gv_init();
00094 #ifdef WITH_CGRAPH
00095     return agread(f, NULL);
00096 #else
00097     return agread(f);
00098 #endif
00099 }
00100 
00101 Agraph_t *read(const char *filename)
00102 {
00103     FILE *f;
00104     Agraph_t *g;
00105 
00106     f = fopen(filename, "r");
00107     if (!f)
00108         return NULL;
00109     if (!gvc)
00110         gv_init();
00111 #ifdef WITH_CGRAPH
00112     g = agread(f, NULL);
00113 #else
00114     g = agread(f);
00115 #endif
00116     fclose(f);
00117     return g;
00118 }
00119 
00120 //-------------------------------------------------
00121 Agraph_t *graph(Agraph_t *g, char *name)
00122 {
00123     if (!gvc)
00124         gv_init();
00125 #ifdef WITH_CGRAPH
00126     return agsubg(g, name, 1);
00127 #else
00128     return agsubg(g, name);
00129 #endif
00130 }
00131 
00132 Agnode_t *node(Agraph_t *g, char *name)
00133 {
00134     if (!gvc)
00135         return NULL;
00136 #ifdef WITH_CGRAPH
00137     return agnode(g, name, 1);
00138 #else
00139     // creating a protonode is not permitted
00140     if (name[0] == '\001' && strcmp (name, "\001proto") == 0)
00141         return NULL;
00142     return agnode(g, name);
00143 #endif
00144 }
00145 
00146 Agedge_t *edge(Agnode_t *t, Agnode_t *h)
00147 {
00148     if (!gvc || !t || !h)
00149         return NULL;
00150 #ifdef WITH_CGRAPH
00151     // edges from/to the protonode are not permitted
00152     if (AGTYPE(t) == AGRAPH || AGTYPE(h) == AGRAPH)
00153         return NULL;
00154     return agedge(agraphof(t), t, h, NULL, 1);
00155 #else
00156     // edges from/to the protonode are not permitted
00157     if ((agnameof(t)[0] == '\001' && strcmp (agnameof(t), "\001proto") == 0)
00158       || (agnameof(h)[0] == '\001' && strcmp (agnameof(h), "\001proto") == 0))
00159         return NULL;
00160     return agedge(t->graph, t, h);
00161 #endif
00162 }
00163 
00164 // induce tail if necessary
00165 Agedge_t *edge(char *tname, Agnode_t *h)
00166 {
00167 #ifdef WITH_CGRAPH
00168     return edge(node(agraphof(h), tname), h);
00169 #else
00170     return edge(node(h->graph, tname), h);
00171 #endif
00172 }
00173 
00174 // induce head if necessary
00175 Agedge_t *edge(Agnode_t *t, char *hname)
00176 {
00177 #ifdef WITH_CGRAPH
00178     return edge(t, node(agraphof(t), hname));
00179 #else
00180     return edge(t, node(t->graph, hname));
00181 #endif
00182 }
00183 
00184 // induce tail/head if necessary
00185 Agedge_t *edge(Agraph_t *g, char *tname, char *hname)
00186 {
00187     return edge(node(g, tname), node(g, hname));
00188 }
00189 
00190 //-------------------------------------------------
00191 static char* myagxget(void *obj, Agsym_t *a)
00192 {
00193     int len;
00194     char *val, *hs;
00195 
00196     if (!obj || !a)
00197         return emptystring;
00198 #ifndef WITH_CGRAPH
00199     val = agxget(obj, a->index);
00200 #else
00201     val = agxget(obj, a);
00202 #endif
00203     if (!val)
00204         return emptystring;
00205     if (a->name[0] == 'l' && strcmp(a->name, "label") == 0 && aghtmlstr(val)) {
00206         len = strlen(val);
00207         hs = (char*)malloc(len + 3);
00208         hs[0] = '<';
00209         strcpy(hs+1, val);
00210         hs[len+1] = '>';
00211         hs[len+2] = '\0';
00212         return hs;
00213     }
00214     return val;
00215 }
00216 char *getv(Agraph_t *g, Agsym_t *a)
00217 {
00218     return myagxget(g, a);
00219 }
00220 char *getv(Agraph_t *g, char *attr)
00221 {
00222     Agsym_t *a;
00223 
00224     if (!g || !attr)
00225         return NULL;
00226     a = agfindattr(agroot(g), attr);
00227     return myagxget(g, a);
00228 }
00229 static void myagxset(void *obj, Agsym_t *a, char *val)
00230 {
00231     int len;
00232     char *hs;
00233 
00234     if (a->name[0] == 'l' && val[0] == '<' && strcmp(a->name, "label") == 0) {
00235         len = strlen(val);
00236         if (val[len-1] == '>') {
00237             hs = strdup(val+1);
00238                 *(hs+len-2) = '\0';
00239 #ifdef WITH_CGRAPH
00240             val = agstrdup_html(agraphof(obj),hs);
00241 #else
00242             val = agstrdup_html(hs);
00243 #endif
00244             free(hs);
00245         }
00246     }
00247 #ifndef WITH_CGRAPH
00248     agxset(obj, a->index, val);
00249 #else
00250     agxset(obj, a, val);
00251 #endif
00252 }
00253 char *setv(Agraph_t *g, Agsym_t *a, char *val)
00254 {
00255     if (!g || !a || !val)
00256         return NULL;
00257     myagxset(g, a, val);
00258     return val;
00259 }
00260 char *setv(Agraph_t *g, char *attr, char *val)
00261 {
00262     Agsym_t *a;
00263 
00264     if (!g || !attr || !val)
00265         return NULL;
00266     a = agfindattr(agroot(g), attr);
00267     if (!a)
00268         a = agraphattr(g->root, attr, emptystring);
00269     myagxset(g, a, val);
00270     return val;
00271 }
00272 //-------------------------------------------------
00273 char *getv(Agnode_t *n, Agsym_t *a)
00274 {
00275     if (!n || !a)
00276         return NULL;
00277 #ifdef WITH_CGRAPH
00278     if (AGTYPE(n) == AGRAPH) // protonode   
00279         return NULL;   // FIXME ??
00280 #endif
00281     return myagxget(n, a);
00282 }
00283 char *getv(Agnode_t *n, char *attr)
00284 {
00285     Agraph_t *g;
00286     Agsym_t *a;
00287 
00288     if (!n || !attr)
00289         return NULL;
00290 #ifdef WITH_CGRAPH
00291     if (AGTYPE(n) == AGRAPH) // protonode   
00292         return NULL;   // FIXME ??
00293 #endif
00294     g = agroot(agraphof(n));
00295 #ifdef WITH_CGRAPH
00296     a = agattr(g, AGNODE, attr, NULL);
00297 #else
00298     a = agfindattr(g->proto->n, attr);
00299 #endif
00300     return myagxget(n, a);
00301 }
00302 char *setv(Agnode_t *n, Agsym_t *a, char *val)
00303 {
00304     if (!n || !a || !val)
00305         return NULL;
00306 #ifdef WITH_CGRAPH
00307     if (AGTYPE(n) == AGRAPH) // protonode   
00308         return NULL;   // FIXME ??
00309 #endif
00310     myagxset(n, a, val);
00311     return val;
00312 }
00313 char *setv(Agnode_t *n, char *attr, char *val)
00314 {
00315     Agraph_t *g;
00316     Agsym_t *a;
00317 
00318     if (!n || !attr || !val)
00319         return NULL;
00320 #ifdef WITH_CGRAPH
00321     if (AGTYPE(n) == AGRAPH) { // protonode   
00322         g = (Agraph_t*)n;
00323         a = agattr(g, AGNODE, attr, val); // create default attribute in psuodo protonode
00324             // FIXME? - deal with html in "label" attributes
00325         return val;
00326     }
00327 #endif
00328     g = agroot(agraphof(n));
00329 #ifdef WITH_CGRAPH
00330     a = agattr(g, AGNODE, attr, NULL);
00331 #else
00332     a = agfindattr(g->proto->n, attr);
00333 #endif
00334     if (!a)
00335         a = agnodeattr(g, attr, emptystring);
00336     myagxset(n, a, val);
00337     return val;
00338 }
00339 //-------------------------------------------------
00340 char *getv(Agedge_t *e, Agsym_t *a)
00341 {
00342     if (!e || !a)
00343         return NULL;
00344 #ifdef WITH_CGRAPH
00345     if (AGTYPE(e) == AGRAPH) // protoedge   
00346         return NULL;   // FIXME ??
00347 #endif
00348     return myagxget(e, a);
00349 }
00350 char *getv(Agedge_t *e, char *attr)
00351 {
00352     Agraph_t *g;
00353     Agsym_t *a;
00354 
00355     if (!e || !attr)
00356         return NULL;
00357 #ifdef WITH_CGRAPH
00358     if (AGTYPE(e) == AGRAPH) // protoedge   
00359         return NULL;   // FIXME ??
00360 #endif
00361     g = agraphof(agtail(e));
00362 #ifndef WITH_CGRAPH
00363     a = agfindattr(g->proto->e, attr);
00364 #else
00365     a = agattr(g, AGEDGE, attr, NULL);
00366 #endif
00367     return myagxget(e, a);
00368 }
00369 char *setv(Agedge_t *e, Agsym_t *a, char *val)
00370 {
00371     if (!e || !a || !val)
00372         return NULL;
00373 #ifdef WITH_CGRAPH
00374     if (AGTYPE(e) == AGRAPH) // protoedge   
00375         return NULL;   // FIXME ??
00376 #endif
00377     myagxset(e, a, val);
00378     return val;
00379 }
00380 char *setv(Agedge_t *e, char *attr, char *val)
00381 {
00382     Agraph_t *g;
00383     Agsym_t *a;
00384 
00385     if (!e || !attr || !val)
00386         return NULL;
00387 #ifdef WITH_CGRAPH
00388     if (AGTYPE(e) == AGRAPH) { // protoedge   
00389         g = (Agraph_t*)e;
00390         a = agattr(g, AGEDGE, attr, val); // create default attribute in pseudo protoedge
00391             // FIXME? - deal with html in "label" attributes
00392         return val;
00393     }
00394 #endif
00395     g = agroot(agraphof(agtail(e)));
00396 #ifndef WITH_CGRAPH
00397     a = agfindattr(g->proto->e, attr);
00398     if (!a)
00399         a = agedgeattr(g, attr, emptystring);
00400 #else
00401     a = agattr(g, AGEDGE, attr, NULL);
00402     if (!a)
00403         a = agattr(g, AGEDGE, attr, emptystring);
00404 #endif
00405     myagxset(e, a, val);
00406     return val;
00407 }
00408 //-------------------------------------------------
00409 Agraph_t *findsubg(Agraph_t *g, char *name)
00410 {
00411     if (!g || !name)
00412         return NULL;
00413 #ifndef WITH_CGRAPH
00414     return agfindsubg(g, name);
00415 #else
00416     return agsubg(g, name, 0);
00417 #endif
00418 }
00419 
00420 Agnode_t *findnode(Agraph_t *g, char *name)
00421 {
00422     if (!g || !name)
00423         return NULL;
00424 #ifndef WITH_CGRAPH
00425     return agfindnode(g, name);
00426 #else
00427     return agnode(g, name, 0);
00428 #endif
00429 }
00430 
00431 Agedge_t *findedge(Agnode_t *t, Agnode_t *h)
00432 {
00433     if (!t || !h)
00434         return NULL;
00435 #ifdef WITH_CGRAPH
00436     if (AGTYPE(t) == AGRAPH || AGTYPE(h) == AGRAPH)
00437         return NULL;
00438 #endif
00439     return agfindedge(agraphof(t), t, h);
00440 }
00441 
00442 Agsym_t *findattr(Agraph_t *g, char *name)
00443 {
00444     if (!g || !name)
00445         return NULL;
00446     return agfindattr(g, name);
00447 }
00448 
00449 Agsym_t *findattr(Agnode_t *n, char *name)
00450 {
00451     if (!n || !name)
00452         return NULL;
00453     return agfindattr(n, name);
00454 }
00455 
00456 Agsym_t *findattr(Agedge_t *e, char *name)
00457 {
00458     if (!e || !name)
00459         return NULL;
00460     return agfindattr(e, name);
00461 }
00462 
00463 //-------------------------------------------------
00464 
00465 Agnode_t *headof(Agedge_t *e)
00466 {
00467     if (!e)
00468         return NULL;
00469 #ifdef WITH_CGRAPH
00470     if (AGTYPE(e) == AGRAPH)
00471         return NULL;
00472 #endif
00473     return aghead(e);
00474 }
00475 
00476 Agnode_t *tailof(Agedge_t *e)
00477 {
00478     if (!e)
00479         return NULL;
00480 #ifdef WITH_CGRAPH
00481     if (AGTYPE(e) == AGRAPH)
00482         return NULL;
00483 #endif
00484     return agtail(e);
00485 }
00486 
00487 Agraph_t *graphof(Agraph_t *g)
00488 {
00489     if (!g || g == g->root)
00490         return NULL;
00491     return agroot(g);
00492 }
00493 
00494 Agraph_t *graphof(Agedge_t *e)
00495 {
00496     if (!e)
00497         return NULL;
00498 #ifdef WITH_CGRAPH
00499     if (AGTYPE(e) == AGRAPH)
00500         return (Agraph_t*)e; /* graph of protoedge is itself recast */
00501 #endif
00502     return agraphof(agtail(e));
00503 }
00504 
00505 Agraph_t *graphof(Agnode_t *n)
00506 {
00507     if (!n)
00508         return NULL;
00509 #ifdef WITH_CGRAPH
00510     if (AGTYPE(n) == AGRAPH)
00511         return (Agraph_t*)n;  /* graph of protonode is itself recast */
00512 #endif
00513     return agraphof(n);
00514 }
00515 
00516 Agraph_t *rootof(Agraph_t *g)
00517 {
00518     if (!g)
00519         return NULL;
00520     return agroot(g);
00521 }
00522 
00523 //-------------------------------------------------
00524 Agnode_t *protonode(Agraph_t *g)
00525 {
00526     if (!g)
00527         return NULL;
00528 #ifdef WITH_CGRAPH
00529     return (Agnode_t *)g;    // gross abuse of the type system!
00530 #else
00531     return g->proto->n;
00532 #endif
00533 }
00534 
00535 Agedge_t *protoedge(Agraph_t *g)
00536 {
00537     if (!g)
00538         return NULL;
00539 #ifdef WITH_CGRAPH
00540     return (Agedge_t *)g;    // gross abuse of the type system!
00541 #else
00542     return g->proto->e;
00543 #endif
00544 }
00545 
00546 //-------------------------------------------------
00547 char *nameof(Agraph_t *g)
00548 {
00549     if (!g)
00550         return NULL;
00551     return agnameof(g);
00552 }
00553 char *nameof(Agnode_t *n)
00554 {
00555     if (!n)
00556         return NULL;
00557 #ifdef WITH_CGRAPH
00558     if (AGTYPE(n) == AGRAPH)
00559         return NULL;
00560 #endif
00561     return agnameof(n);
00562 }
00563 //char *nameof(Agedge_t *e)
00564 //{
00565 //    if (!e)
00566 //        return NULL;
00567 //#ifdef WITH_CGRAPH
00568 //    if (AGTYPE(e) == AGRAPH)
00569 //      return NULL;
00570 //#endif
00571 //    return agnameof(e);
00572 //}
00573 char *nameof(Agsym_t *a)
00574 {
00575     if (!a)
00576         return NULL;
00577     return a->name;
00578 }
00579 
00580 //-------------------------------------------------
00581 bool ok(Agraph_t *g)
00582 {
00583     if (!g) 
00584         return false;
00585     return true;
00586 }
00587 bool ok(Agnode_t *n)
00588 {
00589     if (!n) 
00590         return false;
00591     return true;
00592 }
00593 bool ok(Agedge_t *e)
00594 {
00595     if (!e) 
00596         return false;
00597     return true;
00598 }
00599 bool ok(Agsym_t *a)
00600 {
00601     if (!a) 
00602         return false;
00603     return true;
00604 }
00605 //-------------------------------------------------
00606 Agraph_t *firstsubg(Agraph_t *g)
00607 {
00608 #ifndef WITH_CGRAPH
00609     Agraph_t *mg;
00610     Agnode_t *n;
00611     Agedge_t *e;
00612 #endif
00613 
00614     if (!g)
00615         return NULL;
00616 #ifdef WITH_CGRAPH
00617     return agfstsubg(g);
00618 #else
00619     n = g->meta_node;
00620     if (!n) 
00621         return NULL;
00622     mg = agraphof(n);
00623     if (!mg) 
00624         return NULL;
00625     e = agfstout(mg, n);
00626     if (!e) 
00627         return NULL;
00628     return agusergraph(aghead(e));
00629 #endif
00630 }
00631 
00632 Agraph_t *nextsubg(Agraph_t *g, Agraph_t *sg)
00633 {
00634 #ifndef WITH_CGRAPH
00635     Agraph_t *mg;
00636     Agnode_t *ng, *nsg;
00637     Agedge_t *e;
00638 #endif
00639 
00640     if (!g || !sg)
00641         return NULL;
00642 #ifdef WITH_CGRAPH
00643     return agnxtsubg(sg);
00644 #else
00645     ng = g->meta_node;
00646     nsg = sg->meta_node;
00647     if (!ng || !nsg) 
00648         return NULL;
00649     mg = agraphof(ng);
00650     if (!mg) 
00651         return NULL;
00652     e = agfindedge(mg, ng, nsg);
00653     if (!e) 
00654         return NULL;
00655     e = agnxtout(mg, e);
00656     if (!e) 
00657         return NULL;
00658     return agusergraph(aghead(e));
00659 #endif
00660 }
00661 
00662 #ifdef WITH_CGRAPH
00663 Agraph_t *firstsupg(Agraph_t *g)
00664 {
00665     return g->parent;
00666 }
00667 
00668 Agraph_t *nextsupg(Agraph_t *g, Agraph_t *sg)
00669 {
00670     return NULL;
00671 }
00672 #else
00673 Agraph_t *firstsupg(Agraph_t *g)
00674 {
00675     Agraph_t *mg;
00676     Agnode_t *n;
00677     Agedge_t *e;
00678 
00679     if (!g)
00680         return NULL;
00681     n = g->meta_node;
00682     if (!n) 
00683         return NULL;
00684     mg = agraphof(n);
00685     if (!mg) 
00686         return NULL;
00687     e = agfstin(mg, n);
00688     if (!e) 
00689         return NULL;
00690     return agusergraph(agtail(e));
00691 }
00692 
00693 Agraph_t *nextsupg(Agraph_t *g, Agraph_t *sg)
00694 {
00695     Agraph_t *mg;
00696     Agnode_t *ng, *nsg;
00697     Agedge_t *e;
00698 
00699     if (!g || !sg)
00700         return NULL;
00701     ng = g->meta_node;
00702     nsg = sg->meta_node;
00703     if (!ng || !nsg) 
00704         return NULL;
00705     mg = agraphof(ng);
00706     if (!mg) 
00707         return NULL;
00708     e = agfindedge(mg, nsg, ng);
00709     if (!e) 
00710         return NULL;
00711     e = agnxtin(mg, e);
00712     if (!e) 
00713         return NULL;
00714     return agusergraph(agtail(e));
00715 }
00716 #endif
00717 
00718 Agedge_t *firstout(Agraph_t *g)
00719 {
00720     Agnode_t *n;
00721     Agedge_t *e;
00722 
00723     if (!g)
00724         return NULL;
00725     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00726         e = agfstout(g, n);
00727         if (e) return e;
00728     }
00729     return NULL;
00730 }
00731 
00732 Agedge_t *nextout(Agraph_t *g, Agedge_t *e)
00733 {
00734     Agnode_t *n;
00735     Agedge_t *ne;
00736 
00737     if (!g || !e)
00738         return NULL;
00739     ne = agnxtout(g, e);
00740     if (ne)
00741         return (ne);
00742     for (n = agnxtnode(g, agtail(e)); n; n = agnxtnode(g, n)) {
00743         ne = agfstout(g, n);
00744         if (ne) return ne;
00745     }
00746     return NULL;
00747 }
00748 
00749 Agedge_t *firstedge(Agraph_t *g)
00750 {
00751     return firstout(g);
00752 } 
00753 
00754 Agedge_t *nextedge(Agraph_t *g, Agedge_t *e)
00755 {
00756     return nextout(g, e);
00757 } 
00758 
00759 Agedge_t *firstout(Agnode_t *n)
00760 {
00761     if (!n)
00762         return NULL;
00763     return agfstout(agraphof(n), n);
00764 }
00765 
00766 Agedge_t *nextout(Agnode_t *n, Agedge_t *e)
00767 {
00768     if (!n || !e)
00769         return NULL;
00770     return agnxtout(agraphof(n), e);
00771 }
00772 
00773 Agnode_t *firsthead(Agnode_t *n)
00774 {
00775     Agedge_t *e;
00776 
00777     if (!n)
00778         return NULL;
00779     e = agfstout(agraphof(n), n);
00780     if (!e)
00781         return NULL;
00782     return aghead(e);
00783 }
00784 
00785 Agnode_t *nexthead(Agnode_t *n, Agnode_t *h)
00786 {
00787     Agedge_t *e;
00788     Agraph_t *g;
00789 
00790     if (!n || !h)
00791         return NULL;
00792     g = agraphof(n);
00793     e = agfindedge(g, n, h);
00794     if (!e)
00795         return NULL;
00796     do {
00797         e = agnxtout(g, e);
00798         if (!e)
00799             return NULL;
00800     } while (aghead(e) == h);
00801     return aghead(e);
00802 }
00803 
00804 Agedge_t *firstedge(Agnode_t *n)
00805 {
00806     if (!n)
00807         return NULL;
00808     return agfstedge(agraphof(n), n);
00809 } 
00810 
00811 Agedge_t *nextedge(Agnode_t *n, Agedge_t *e)
00812 {
00813     if (!n || !e)
00814         return NULL;
00815     return agnxtedge(agraphof(n), e, n); 
00816 } 
00817 
00818 Agedge_t *firstin(Agraph_t *g)
00819 {
00820     Agnode_t *n;
00821 
00822     if (!g)
00823         return NULL;
00824     n = agfstnode(g);
00825     if (!n)
00826         return NULL;
00827     return agfstin(g, n);
00828 }
00829 
00830 Agedge_t *nextin(Agraph_t *g, Agedge_t *e)
00831 {
00832     Agnode_t *n;
00833     Agedge_t *ne;
00834 
00835     if (!g || !e)
00836         return NULL;
00837     ne = agnxtin(g, e);
00838     if (ne)
00839         return (ne);
00840     n = agnxtnode(g, aghead(e));
00841     if (!n)
00842         return NULL;
00843     return agfstin(g, n);
00844 }
00845 
00846 Agedge_t *firstin(Agnode_t *n)
00847 {
00848     if (!n)
00849         return NULL;
00850     return agfstin(agraphof(n), n);
00851 }
00852 
00853 Agedge_t *nextin(Agnode_t *n, Agedge_t *e)
00854 {
00855     if (!n || !e)
00856         return NULL;
00857     return agnxtin(agraphof(n), e);
00858 }
00859 
00860 Agnode_t *firsttail(Agnode_t *n)
00861 {
00862     Agedge_t *e;
00863 
00864     if (!n)
00865         return NULL;
00866     e = agfstin(agraphof(n), n);
00867     if (!e)
00868         return NULL;
00869     return agtail(e);
00870 }
00871 
00872 Agnode_t *nexttail(Agnode_t *n, Agnode_t *t)
00873 {
00874     Agedge_t *e;
00875     Agraph_t *g;
00876 
00877     if (!n || !t)
00878         return NULL;
00879     g = agraphof(n);
00880     e = agfindedge(g, t, n);
00881     if (!e)
00882         return NULL;
00883     do {
00884         e = agnxtout(g, e);
00885         if (!e)
00886             return NULL;
00887     } while (agtail(e) == t);
00888     return agtail(e);
00889 }
00890 
00891 Agnode_t *firstnode(Agraph_t *g)
00892 {
00893     if (!g)
00894         return NULL;
00895     return agfstnode(g);
00896 }
00897 
00898 Agnode_t *nextnode(Agraph_t *g, Agnode_t *n)
00899 {
00900     if (!g || !n)
00901         return NULL;
00902     return agnxtnode(g, n);
00903 }
00904 
00905 Agnode_t *firstnode(Agedge_t *e)
00906 {
00907     if (!e)
00908         return NULL;
00909     return agtail(e);
00910 }
00911 
00912 Agnode_t *nextnode(Agedge_t *e, Agnode_t *n)
00913 {
00914     if (!e || n != agtail(e))
00915         return NULL;
00916     return aghead(e);
00917 }
00918 
00919 Agsym_t *firstattr(Agraph_t *g)
00920 {
00921     if (!g)
00922         return NULL;
00923     g = agroot(g);
00924 #ifdef WITH_CGRAPH
00925     return agnxtattr(g,AGRAPH,NULL);
00926 #else
00927     if (dtsize(g->univ->globattr->dict) == 0)
00928         return NULL;
00929     return g->univ->globattr->list[0];
00930 #endif
00931 }
00932 
00933 Agsym_t *nextattr(Agraph_t *g, Agsym_t *a)
00934 {
00935     int i;
00936 
00937     if (!g || !a)
00938         return NULL;
00939     g = agroot(g);
00940 #ifdef WITH_CGRAPH
00941     return agnxtattr(g,AGRAPH,a);
00942 #else
00943     for (i = 0; i < dtsize(g->univ->globattr->dict); i++)
00944         if (a == g->univ->globattr->list[i])
00945             break;
00946     i++;
00947     if (i > dtsize(g->univ->globattr->dict))
00948         return NULL;
00949     return g->univ->globattr->list[i];
00950 #endif
00951 }
00952 
00953 Agsym_t *firstattr(Agnode_t *n)
00954 {
00955     Agraph_t *g;
00956 
00957     if (!n)
00958         return NULL;
00959     g = agraphof(n);
00960 #ifdef WITH_CGRAPH
00961     return agnxtattr(g,AGNODE,NULL);
00962 #else
00963     if (dtsize(g->univ->nodeattr->dict) == 0)
00964         return NULL;
00965     return g->univ->nodeattr->list[0];
00966 #endif
00967 }
00968 
00969 Agsym_t *nextattr(Agnode_t *n, Agsym_t *a)
00970 {
00971     Agraph_t *g;
00972     int i;
00973 
00974     if (!n || !a)
00975         return NULL;
00976     g = agraphof(n);
00977 #ifdef WITH_CGRAPH
00978     return agnxtattr(g,AGNODE,a);
00979 #else
00980     for (i = 0; i < dtsize(g->univ->nodeattr->dict); i++)
00981         if (a == g->univ->nodeattr->list[i])
00982             break;
00983     i++;
00984     if (i > dtsize(g->univ->nodeattr->dict))
00985         return NULL;
00986     return g->univ->nodeattr->list[i];
00987 #endif
00988 }
00989 
00990 Agsym_t *firstattr(Agedge_t *e)
00991 {
00992     Agraph_t *g;
00993 
00994     if (!e)
00995         return NULL;
00996     g = agraphof(agtail(e));
00997 #ifdef WITH_CGRAPH
00998     return agnxtattr(g,AGEDGE,NULL);
00999 #else
01000     if (dtsize(g->univ->edgeattr->dict) == 0)
01001         return NULL;
01002     return g->univ->edgeattr->list[0];
01003 #endif
01004 }
01005 
01006 Agsym_t *nextattr(Agedge_t *e, Agsym_t *a)
01007 {
01008     Agraph_t *g;
01009     int i;
01010 
01011     if (!e || !a)
01012         return NULL;
01013     g = agraphof(agtail(e));
01014 #ifdef WITH_CGRAPH
01015     return agnxtattr(g,AGEDGE,a);
01016 #else
01017     for (i = 0; i < dtsize(g->univ->edgeattr->dict); i++)
01018         if (a == g->univ->edgeattr->list[i])
01019             break;
01020     i++;
01021     if (i > dtsize(g->univ->edgeattr->dict))
01022         return NULL;
01023     return g->univ->edgeattr->list[i];
01024 #endif
01025 }
01026 
01027 bool rm(Agraph_t *g)
01028 {
01029     Agedge_t *e;
01030 
01031     if (!g)
01032         return false;
01033 #ifdef WITH_CGRAPH
01034     Agraph_t* sg;
01035     for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg))
01036         rm(sg);
01037     if (g == agroot(g))
01038         agclose(g);
01039     else
01040         agdelete(agroot(g), g);
01041     return true;
01042 #else
01043     if (g->meta_node) {
01044         for (e = agfstout(g->meta_node->graph, g->meta_node); e;
01045                         e = agnxtout(g->meta_node->graph, e)) {
01046             rm(agusergraph(aghead(e)));
01047         }
01048         if (g == agroot(g)) {
01049             agclose(g);
01050         } else {
01051             agdelete(g->meta_node->graph, g);
01052         }
01053         return true;
01054     }
01055     fprintf(stderr, "subgraph has no meta_node\n");
01056     return false;
01057 #endif
01058 }
01059 
01060 bool rm(Agnode_t *n)
01061 {
01062     if (!n)
01063         return false;
01064     // removal of the protonode is not permitted
01065     if (agnameof(n)[0] == '\001' && strcmp (agnameof(n), "\001proto") ==0)
01066         return false;
01067     agdelete(agraphof(n), n);
01068     return true;
01069 }
01070 
01071 bool rm(Agedge_t *e)
01072 {
01073     if (!e)
01074         return false;
01075     // removal of the protoedge is not permitted
01076     if ((agnameof(aghead(e))[0] == '\001' && strcmp (agnameof(aghead(e)), "\001proto") == 0)
01077      || (agnameof(agtail(e))[0] == '\001' && strcmp (agnameof(agtail(e)), "\001proto") == 0))
01078         return false;
01079     agdelete(agroot(agraphof(aghead(e))), e);
01080     return true;
01081 }
01082 
01083 bool layout(Agraph_t *g, const char *engine)
01084 {
01085     int err;
01086 
01087     if (!g)
01088         return false;
01089     err = gvFreeLayout(gvc, g);  /* ignore errors */
01090     err = gvLayout(gvc, g, engine);
01091     return (! err);
01092 }
01093 
01094 // annotate the graph with layout information
01095 bool render(Agraph_t *g)
01096 {
01097     if (!g)
01098         return false;
01099     attach_attrs(g);
01100     return true;
01101 }
01102 
01103 // render to stdout
01104 bool render(Agraph_t *g, const char *format)
01105 {
01106     int err;
01107 
01108     if (!g)
01109         return false;
01110     err = gvRender(gvc, g, format, stdout);
01111     return (! err);
01112 }
01113 
01114 // render to an open FILE
01115 bool render(Agraph_t *g, const char *format, FILE *f)
01116 {
01117     int err;
01118 
01119     if (!g)
01120         return false;
01121     err = gvRender(gvc, g, format, f);
01122     return (! err);
01123 }
01124 
01125 // render to an open channel  
01126 bool renderchannel(Agraph_t *g, const char *format, const char *channelname)
01127 {
01128     int err;
01129 
01130     if (!g)
01131         return false;
01132     gv_channel_writer_init(gvc);
01133     err = gvRender(gvc, g, format, (FILE*)channelname);
01134     return (! err);
01135 }
01136 
01137 // render to a filename 
01138 bool render(Agraph_t *g, const char *format, const char *filename)
01139 {
01140     int err;
01141 
01142     if (!g)
01143         return false;
01144     err = gvRenderFilename(gvc, g, format, filename);
01145     return (! err);
01146 }
01147 
01148 // render to string result, using binding-dependent gv_string_writer()
01149 void renderresult(Agraph_t *g, const char *format, char *outdata)
01150 {
01151     int err;
01152 
01153     if (!g)
01154         return;
01155     gv_string_writer_init(gvc);
01156     err = gvRender(gvc, g, format, (FILE*)outdata);
01157 }
01158 
01159 // render to a malloc'ed data string, to be free'd by caller.
01160 char* renderdata(Agraph_t *g, const char *format)
01161 {
01162     int err;
01163     char *data;
01164     unsigned int length;
01165 
01166     if (!g)
01167         return NULL;
01168     err = gvRenderData(gvc, g, format, &data, &length);
01169     if (err)
01170         return NULL;
01171     data = (char*)realloc(data, length + 1);
01172     return data;
01173 }
01174 
01175 bool write(Agraph_t *g, FILE *f)
01176 {
01177     int err;
01178 
01179     if (!g)
01180         return false;
01181     err = agwrite(g, f);
01182     return (! err);
01183 }
01184 
01185 bool write(Agraph_t *g, const char *filename)
01186 {
01187     FILE *f;
01188     int err;
01189 
01190     if (!g)
01191         return false;
01192     f = fopen(filename, "w");
01193     if (!f)
01194         return false;
01195     err = agwrite(g, f);
01196     fclose(f);
01197     return (! err);
01198 }