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