00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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;
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
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
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
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),
00247 -1,
00248 -1,
00249 (Dtmake_f) 0,
00250 (Dtfree_f) 0,
00251 (Dtcompar_f) 0,
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
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
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
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
00371
00372
00373
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