/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/graph/attribs.c

Go to the documentation of this file.
00001 /* $Id: attribs.c,v 1.7 2008/02/08 10:50:53 glenlow Exp $ $Revision: 1.7 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #include <limits.h>
00018 
00019 #define EXTERN
00020 #include "libgraph.h"
00021 
00022 #ifdef DMALLOC
00023 #include "dmalloc.h"
00024 #endif
00025 
00026 Agdict_t *agdictof(void *obj)
00027 {
00028     Agdict_t *d = NULL;
00029 
00030     switch (TAG_OF(obj)) {
00031     case TAG_GRAPH:
00032         d = ((Agraph_t *) obj)->univ->globattr;
00033         break;
00034     case TAG_NODE:
00035         d = ((Agnode_t *) obj)->graph->univ->nodeattr;
00036         break;
00037     case TAG_EDGE:
00038         d = ((Agedge_t *) obj)->tail->graph->univ->edgeattr;
00039         break;
00040     }
00041     return d;
00042 }
00043 
00044 Agsym_t *agNEWsym(Agdict_t * dict, char *name, char *value)
00045 {
00046     Agsym_t *a;
00047     int i;
00048 
00049     a = NEW(Agsym_t);
00050     a->name = agstrdup(name);
00051     a->value = agstrdup(value);
00052     a->printed = TRUE;
00053     i = a->index = dtsize(dict->dict);
00054     dict->list = ALLOC(i + 2, dict->list, Agsym_t *);
00055     dict->list[i++] = a;
00056     dict->list[i++] = NULL;
00057     dtinsert(dict->dict, a);
00058     return a;
00059 }
00060 
00061 static void obj_init_attr(void *obj, Agsym_t * attr, int isnew)
00062 {
00063     int i;
00064     Agraph_t *gobj;             /* generic object */
00065 
00066     gobj = (Agraph_t *) obj;
00067     i = attr->index;
00068         if (isnew) {
00069                 gobj->attr = ALLOC(i + 1, gobj->attr, char *);
00070                 gobj->attr[i] = agstrdup(attr->value);
00071                 if (i % CHAR_BIT == 0) {
00072                         /* allocate in chunks of CHAR_BIT bits */
00073                         gobj->didset = ALLOC(i / CHAR_BIT + 1, gobj->didset, char);
00074                         gobj->didset[i / CHAR_BIT] = 0;
00075                 }
00076         }
00077         else if ((gobj->didset[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) == 0) {
00078                 /* the i-th attr was not set by agxset, so we can replace it */
00079                 agstrfree(gobj->attr[i]);
00080                 gobj->attr[i] = agstrdup(attr->value);
00081         }
00082 }
00083 
00084 static void add_graph_attr(Agraph_t * g, Agsym_t * attr, int isnew)
00085 {
00086     Agnode_t *n;
00087 
00088     if (g->meta_node) {
00089         for (n = agfstnode(g->meta_node->graph); n;
00090              n = agnxtnode(g->meta_node->graph, n))
00091             obj_init_attr(agusergraph(n), attr, isnew);
00092     } else
00093         obj_init_attr(g, attr, isnew);
00094 }
00095 
00096 static void add_node_attr(Agraph_t * g, Agsym_t * attr, int isnew)
00097 {
00098     Agnode_t *n;
00099     Agproto_t *proto;
00100 
00101     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00102         obj_init_attr(n, attr, isnew);
00103     if (g->meta_node) {
00104         for (n = agfstnode(g->meta_node->graph); n;
00105              n = agnxtnode(g->meta_node->graph, n))
00106             for (proto = agusergraph(n)->proto; proto; proto = proto->prev)
00107                 obj_init_attr(proto->n, attr, isnew);
00108     } else
00109         for (proto = g->proto; proto; proto = proto->prev)
00110             obj_init_attr(proto->n, attr, isnew);
00111 }
00112 
00113 static void add_edge_attr(Agraph_t * g, Agsym_t * attr, int isnew)
00114 {
00115     Agnode_t *n;
00116     Agedge_t *e;
00117     Agproto_t *proto;
00118 
00119     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00120         for (e = agfstout(g, n); e; e = agnxtout(g, e))
00121             obj_init_attr(e, attr, isnew);
00122     if (g->meta_node) {
00123         for (n = agfstnode(g->meta_node->graph); n;
00124              n = agnxtnode(g->meta_node->graph, n))
00125             for (proto = agusergraph(n)->proto; proto; proto = proto->prev)
00126                 obj_init_attr(proto->e, attr, isnew);
00127     } else
00128         for (proto = g->proto; proto; proto = proto->prev)
00129             obj_init_attr(proto->e, attr, isnew);
00130 }
00131 
00132 static Agsym_t *dcl_attr(void *obj, char *name, char *value)
00133 {
00134     Agsym_t *rv;
00135         int isnew = 1;
00136 
00137     rv = agfindattr(obj, name);
00138     if (rv) {
00139         if (strcmp(rv->value, value)) {
00140                 agstrfree(rv->value);
00141                 rv->value = agstrdup(value);
00142                 isnew = 0;
00143         }
00144         else
00145                 return rv;
00146     }
00147         else
00148                 rv = agNEWsym(agdictof(obj), name, value);
00149     if (rv) {
00150         switch (TAG_OF(obj)) {
00151         case TAG_GRAPH:
00152             add_graph_attr((Agraph_t *) obj, rv, isnew);
00153             break;
00154         case TAG_NODE:
00155             add_node_attr(((Agnode_t *) obj)->graph, rv, isnew);
00156             break;
00157         case TAG_EDGE:
00158             add_edge_attr(((Agedge_t *) obj)->head->graph, rv, isnew);
00159             break;
00160         }
00161     }
00162     return rv;
00163 }
00164 
00165 Agraph_t *agprotograph()
00166 {
00167     return AG.proto_g;
00168 }
00169 
00170 static void initproto(void)
00171 {
00172     Agsym_t *a;
00173     Agraph_t *g;
00174     g = AG.proto_g = agopen("ProtoGraph", AGRAPH);
00175     a = dcl_attr(g->proto->e, KEY_ID, "");
00176     if (a->index != KEYX)
00177         abort();
00178     a = dcl_attr(g->proto->e, TAIL_ID, "");
00179     if (a->index != TAILX)
00180         abort();
00181     a->printed = FALSE;
00182     a = dcl_attr(g->proto->e, HEAD_ID, "");
00183     if (a->index != HEADX)
00184         abort();
00185     a->printed = FALSE;
00186 }
00187 
00188 Agsym_t *agraphattr(Agraph_t * g, char *name, char *value)
00189 {
00190     if (g == NULL)
00191         g = AG.proto_g;
00192     if (g != g->root)
00193         return NULL;
00194     return dcl_attr(g, name, value);
00195 }
00196 
00197 Agsym_t *agnodeattr(Agraph_t * g, char *name, char *value)
00198 {
00199     if (g == NULL)
00200         g = AG.proto_g;
00201     if (g != g->root)
00202         return NULL;
00203     return dcl_attr(g->proto->n, name, value);
00204 }
00205 
00206 Agsym_t *agedgeattr(Agraph_t * g, char *name, char *value)
00207 {
00208     if (g == NULL)
00209         g = AG.proto_g;
00210     if (g != g->root)
00211         return NULL;
00212     return dcl_attr(g->proto->e, name, value);
00213 }
00214 
00215 /* attribute dictionaries */
00216 
00217 static void agfreesym(void *ptr)
00218 {
00219     Agsym_t *a;
00220     a = (Agsym_t *) ptr;
00221     agstrfree(a->name);
00222     agstrfree(a->value);
00223     free(a);
00224 }
00225 
00226 void agFREEdict(Agraph_t * g, Agdict_t * dict)
00227 {
00228     int i;
00229     Agsym_t *a;
00230 
00231     g = g;
00232     dtclose(dict->dict);
00233     if (dict->list) {
00234         i = 0;
00235         while ((a = dict->list[i++]))
00236             agfreesym(a);
00237         free(dict->list);
00238     }
00239     free(dict);
00240 }
00241 
00242 Agdict_t *agNEWdict(char *name)
00243 {
00244     Agdict_t *dict;
00245     static Dtdisc_t symdisc = {
00246         offsetof(Agsym_t, name),        /* key */
00247         -1,                     /* size */
00248         -1,                     /* link */
00249         (Dtmake_f) 0,
00250         (Dtfree_f) 0,
00251         (Dtcompar_f) 0,         /* use strcmp */
00252         (Dthash_f) 0,
00253         (Dtmemory_f) 0,
00254         (Dtevent_f) 0
00255     };
00256 
00257     dict = NEW(Agdict_t);
00258     dict->name = name;
00259     dict->dict = dtopen(&symdisc, Dttree);
00260     dict->list = NULL;
00261     return dict;
00262 }
00263 
00264 void agcopydict(Agdict_t * to_dict, Agdict_t * from_dict)
00265 {
00266     int i, n;
00267     Agsym_t *a, *b;
00268 
00269     n = dtsize(from_dict->dict);
00270     for (i = 0; i < n; i++) {
00271         a = from_dict->list[i];
00272         b = agNEWsym(to_dict, a->name, a->value);
00273         b->printed = a->printed;
00274         b->fixed = a->fixed;
00275 #ifdef WIN32
00276         /* Microsoft C is a thing of wonder. */
00277         fprintf(stderr, "", a->name, a->value);
00278 #endif
00279     }
00280 }
00281 
00282 Agsym_t *agfindattr(void *obj, char *name)
00283 {
00284     Agsym_t *rv;
00285     Agdict_t *dict = agdictof(obj);
00286 
00287     rv = (Agsym_t *) dtmatch(dict->dict, name);
00288     return rv;
00289 }
00290 
00291         /* this is normally called by the aginit() macro */
00292 void aginitlib(int gs, int ns, int es)
00293 {
00294     if (AG.proto_g == NULL) {
00295         AG.graph_nbytes = gs;
00296         AG.node_nbytes = ns;
00297         AG.edge_nbytes = es;
00298         AG.init_called = TRUE;
00299         initproto();
00300     } else
00301         if ((AG.graph_nbytes != gs) || (AG.node_nbytes != ns)
00302             || (AG.edge_nbytes != es))
00303         agerr(AGWARN, "aginit() called multiply with inconsistent args\n");
00304 }
00305 
00306 char *agget(void *obj, char *attr)
00307 {
00308     return agxget(obj, agindex(obj, attr));
00309 }
00310 
00311 int agset(void *obj, char *attr, char *value)
00312 {
00313     return agxset(obj, agindex(obj, attr), value);
00314 }
00315 
00316 int agindex(void *obj, char *name)
00317 {
00318     Agsym_t *a;
00319     int rv = -1;
00320 
00321     a = agfindattr(obj, name);
00322     if (a)
00323         rv = a->index;
00324     return rv;
00325 }
00326 
00327 char *agxget(void *obj, int index)
00328 {
00329     if (index >= 0)
00330         return ((Agraph_t *) obj)->attr[index];
00331     return NULL;
00332 }
00333 
00334 int agxset(void *obj, int index, char *buf)
00335 {
00336         char **p;
00337     if (index >= 0) {
00338         Agraph_t *gobj = (Agraph_t *)obj;
00339         p = gobj->attr;
00340         agstrfree(p[index]);
00341         p[index] = agstrdup(buf);
00342         /* the index-th attr was set by agxset */
00343         gobj->didset[index / CHAR_BIT] |= 1 << (index % CHAR_BIT);
00344         return 0;
00345     } else
00346         return -1;
00347 }
00348 
00349 int agsafeset(void* obj, char* name, char* value, char* def)
00350 {
00351     Agsym_t* a = agfindattr(obj, name);
00352 
00353     if (a == NULL) {
00354         if (!def) def = "";
00355         switch (TAG_OF(obj)) {
00356         case TAG_GRAPH:
00357             a = agraphattr(((Agraph_t*)obj)->root, name, def);
00358             break;
00359         case TAG_NODE:
00360             a = agnodeattr(((Agnode_t*)obj)->graph, name, def);
00361             break;
00362         case TAG_EDGE:
00363             a = agedgeattr(((Agedge_t*)obj)->head->graph, name, def);
00364             break;
00365         }
00366     }
00367     return agxset(obj, a->index, value);
00368 }
00369 
00370 /* agcopyattr:
00371  * Assumes attributes have already been declared.
00372  * Do not copy key attribute for edges, as this must be distinct.
00373  * Returns non-zero on failure or if objects have different type.
00374  */
00375 int agcopyattr(void *oldobj, void *newobj)
00376 {
00377     Agdict_t *d = agdictof(oldobj);
00378     Agsym_t **list = d->list;
00379     Agsym_t *sym;
00380     Agsym_t *newsym;
00381     int r = 0;
00382     int isEdge = (TAG_OF(oldobj) == TAG_EDGE);
00383 
00384     if (TAG_OF(oldobj) != TAG_OF(newobj)) return 1;
00385     while (!r && (sym = *list++)) {
00386         if (isEdge && sym->index == KEYX) continue;
00387         newsym = agfindattr(newobj,sym->name);
00388         if (!newsym) return 1;
00389         r = agxset(newobj, newsym->index, agxget(oldobj, sym->index));
00390     }
00391     return r;
00392 }
00393 

Generated on Mon Mar 31 19:03:26 2008 for Graphviz by  doxygen 1.5.1