Graphviz  2.39.20141212.0545
attribs.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include <limits.h>
15 
16 #define EXTERN
17 #include "libgraph.h"
18 
19 #ifdef DMALLOC
20 #include "dmalloc.h"
21 #endif
22 
23 Agdict_t *agdictof(void *obj)
24 {
25  Agdict_t *d = NULL;
26 
27  switch (TAG_OF(obj)) {
28  case TAG_GRAPH:
29  d = ((Agraph_t *) obj)->univ->globattr;
30  break;
31  case TAG_NODE:
32  d = ((Agnode_t *) obj)->graph->univ->nodeattr;
33  break;
34  case TAG_EDGE:
35  d = ((Agedge_t *) obj)->tail->graph->univ->edgeattr;
36  break;
37  }
38  return d;
39 }
40 
41 Agsym_t *agNEWsym(Agdict_t * dict, char *name, char *value)
42 {
43  Agsym_t *a;
44  int i;
45 
46  a = NEW(Agsym_t);
47  a->name = agstrdup(name);
48  a->value = agstrdup(value);
49  a->printed = TRUE;
50  i = a->index = dtsize(dict->dict);
51  dict->list = ALLOC(i + 2, dict->list, Agsym_t *);
52  dict->list[i++] = a;
53  dict->list[i++] = NULL;
54  dtinsert(dict->dict, a);
55  return a;
56 }
57 
58 static void obj_init_attr(void *obj, Agsym_t * attr, int isnew)
59 {
60  int i;
61  Agraph_t *gobj; /* generic object */
62 
63  gobj = (Agraph_t *) obj;
64  i = attr->index;
65  if (isnew) {
66  gobj->attr = ALLOC(i + 1, gobj->attr, char *);
67  gobj->attr[i] = agstrdup(attr->value);
68  if (i % CHAR_BIT == 0) {
69  /* allocate in chunks of CHAR_BIT bits */
70  gobj->didset = ALLOC(i / CHAR_BIT + 1, gobj->didset, char);
71  gobj->didset[i / CHAR_BIT] = 0;
72  }
73  }
74  else if ((gobj->didset[i / CHAR_BIT] & (1 << (i % CHAR_BIT))) == 0) {
75  /* the i-th attr was not set by agxset, so we can replace it */
76  agstrfree(gobj->attr[i]);
77  gobj->attr[i] = agstrdup(attr->value);
78  }
79 }
80 
81 static void add_graph_attr(Agraph_t * g, Agsym_t * attr, int isnew)
82 {
83  Agnode_t *n;
84 
85  if (g->meta_node) {
86  for (n = agfstnode(g->meta_node->graph); n;
87  n = agnxtnode(g->meta_node->graph, n))
88  obj_init_attr(agusergraph(n), attr, isnew);
89  } else
90  obj_init_attr(g, attr, isnew);
91 }
92 
93 static void add_node_attr(Agraph_t * g, Agsym_t * attr, int isnew)
94 {
95  Agnode_t *n;
96  Agproto_t *proto;
97 
98  for (n = agfstnode(g); n; n = agnxtnode(g, n))
99  obj_init_attr(n, attr, isnew);
100  if (g->meta_node) {
101  for (n = agfstnode(g->meta_node->graph); n;
102  n = agnxtnode(g->meta_node->graph, n))
103  for (proto = agusergraph(n)->proto; proto; proto = proto->prev)
104  obj_init_attr(proto->n, attr, isnew);
105  } else
106  for (proto = g->proto; proto; proto = proto->prev)
107  obj_init_attr(proto->n, attr, isnew);
108 }
109 
110 static void add_edge_attr(Agraph_t * g, Agsym_t * attr, int isnew)
111 {
112  Agnode_t *n;
113  Agedge_t *e;
114  Agproto_t *proto;
115 
116  for (n = agfstnode(g); n; n = agnxtnode(g, n))
117  for (e = agfstout(g, n); e; e = agnxtout(g, e))
118  obj_init_attr(e, attr, isnew);
119  if (g->meta_node) {
120  for (n = agfstnode(g->meta_node->graph); n;
121  n = agnxtnode(g->meta_node->graph, n))
122  for (proto = agusergraph(n)->proto; proto; proto = proto->prev)
123  obj_init_attr(proto->e, attr, isnew);
124  } else
125  for (proto = g->proto; proto; proto = proto->prev)
126  obj_init_attr(proto->e, attr, isnew);
127 }
128 
129 Agsym_t *agattr(void *obj, char *name, char *value)
130 {
131  Agsym_t *rv;
132  int isnew = 1;
133 
134  rv = agfindattr(obj, name);
135  if (rv) {
136  if (strcmp(rv->value, value)) {
137  agstrfree(rv->value);
138  rv->value = agstrdup(value);
139  isnew = 0;
140  }
141  else
142  return rv;
143  }
144  else
145  rv = agNEWsym(agdictof(obj), name, value);
146  if (rv) {
147  switch (TAG_OF(obj)) {
148  case TAG_GRAPH:
149  add_graph_attr((Agraph_t *) obj, rv, isnew);
150  break;
151  case TAG_NODE:
152  add_node_attr(((Agnode_t *) obj)->graph, rv, isnew);
153  break;
154  case TAG_EDGE:
155  add_edge_attr(((Agedge_t *) obj)->head->graph, rv, isnew);
156  break;
157  }
158  }
159  return rv;
160 }
161 
163 {
164  return AG.proto_g;
165 }
166 
168 {
169  return g->proto->n;
170 }
171 
172 
174 {
175  return g->proto->e;
176 }
177 
178 
179 static int initproto(void)
180 {
181  Agsym_t *a;
182  Agraph_t *g;
183  g = AG.proto_g = agopen("ProtoGraph", AGRAPH);
184  a = agattr(g->proto->e, KEY_ID, "");
185  if (a->index != KEYX)
186  return 1;
187  a = agattr(g->proto->e, TAIL_ID, "");
188  if (a->index != TAILX)
189  return 1;
190  a->printed = FALSE;
191  a = agattr(g->proto->e, HEAD_ID, "");
192  if (a->index != HEADX)
193  return 1;
194  a->printed = FALSE;
195  return 0;
196 }
197 
198 Agsym_t *agraphattr(Agraph_t * g, char *name, char *value)
199 {
200  if (g == NULL)
201  g = AG.proto_g;
202  if (g != g->root)
203  return NULL;
204  return agattr(g, name, value);
205 }
206 
207 Agsym_t *agnodeattr(Agraph_t * g, char *name, char *value)
208 {
209  if (g == NULL)
210  g = AG.proto_g;
211  if (g != g->root)
212  return NULL;
213  return agattr(g->proto->n, name, value);
214 }
215 
216 Agsym_t *agedgeattr(Agraph_t * g, char *name, char *value)
217 {
218  if (g == NULL)
219  g = AG.proto_g;
220  if (g != g->root)
221  return NULL;
222  return agattr(g->proto->e, name, value);
223 }
224 
225 /* attribute dictionaries */
226 
227 static void agfreesym(void *ptr)
228 {
229  Agsym_t *a;
230  a = (Agsym_t *) ptr;
231  agstrfree(a->name);
232  agstrfree(a->value);
233  free(a);
234 }
235 
236 void agFREEdict(Agraph_t * g, Agdict_t * dict)
237 {
238  int i;
239  Agsym_t *a;
240 
241  g = g;
242  dtclose(dict->dict);
243  if (dict->list) {
244  i = 0;
245  while ((a = dict->list[i++]))
246  agfreesym(a);
247  free(dict->list);
248  }
249  free(dict);
250 }
251 
252 Agdict_t *agNEWdict(char *name)
253 {
254  Agdict_t *dict;
255  static Dtdisc_t symdisc = {
256  offsetof(Agsym_t, name), /* key */
257  -1, /* size */
258  -1, /* link */
259  (Dtmake_f) 0,
260  (Dtfree_f) 0,
261  (Dtcompar_f) 0, /* use strcmp */
262  (Dthash_f) 0,
263  (Dtmemory_f) 0,
264  (Dtevent_f) 0
265  };
266 
267  dict = NEW(Agdict_t);
268  dict->name = name;
269  dict->dict = dtopen(&symdisc, Dttree);
270  dict->list = NULL;
271  return dict;
272 }
273 
274 void agcopydict(Agdict_t * to_dict, Agdict_t * from_dict)
275 {
276  int i, n;
277  Agsym_t *a, *b;
278 
279  n = dtsize(from_dict->dict);
280  for (i = 0; i < n; i++) {
281  a = from_dict->list[i];
282  b = agNEWsym(to_dict, a->name, a->value);
283  b->printed = a->printed;
284  b->fixed = a->fixed;
285 #ifdef WIN32
286  /* Microsoft C is a thing of wonder. */
287  fprintf(stderr, "", a->name, a->value);
288 #endif
289  }
290 }
291 
292 Agsym_t *agfindattr(void *obj, char *name)
293 {
294  Agsym_t *rv;
295  Agdict_t *dict = agdictof(obj);
296 
297  rv = (Agsym_t *) dtmatch(dict->dict, name);
298  return rv;
299 }
300 
301 Agsym_t *agfstattr(void *obj)
302 {
303  Agdict_t *dict = agdictof(obj);
304  return (Agsym_t *)dtfirst(dict->dict);
305 }
306 
307 Agsym_t *agnxtattr(void *obj, Agsym_t *a)
308 {
309  Agdict_t *dict = agdictof(obj);
310  return (Agsym_t *)dtnext(dict->dict, a);
311 }
312 
313 Agsym_t *aglstattr(void *obj)
314 {
315  Agdict_t *dict = agdictof(obj);
316  return (Agsym_t *)dtlast(dict->dict);
317 }
318 
319 Agsym_t *agprvattr(void *obj, Agsym_t *a)
320 {
321  Agdict_t *dict = agdictof(obj);
322  return (Agsym_t *)dtprev(dict->dict, a);
323 }
324 
325  /* this is normally called by the aginit() macro */
326 int aginitlib(int gs, int ns, int es)
327 {
328  int rv = 0;
329  if (AG.proto_g == NULL) {
330  AG.graph_nbytes = gs;
331  AG.node_nbytes = ns;
332  AG.edge_nbytes = es;
333  AG.init_called = TRUE;
334  if (initproto()) {
335  agerr(AGERR, "aginitlib: initproto failed\n");
336  rv = 1;
337  }
338  } else
339  if ((AG.graph_nbytes != gs) || (AG.node_nbytes != ns)
340  || (AG.edge_nbytes != es))
341  agerr(AGWARN, "aginit() called multiply with inconsistent args\n");
342  return rv;
343 }
344 
345 char *agget(void *obj, char *attr)
346 {
347  return agxget(obj, agindex(obj, attr));
348 }
349 
350 int agset(void *obj, char *attr, char *value)
351 {
352  return agxset(obj, agindex(obj, attr), value);
353 }
354 
355 int agindex(void *obj, char *name)
356 {
357  Agsym_t *a;
358  int rv = -1;
359 
360  a = agfindattr(obj, name);
361  if (a)
362  rv = a->index;
363  return rv;
364 }
365 
366 char *agxget(void *obj, int index)
367 {
368  if (index >= 0)
369  return ((Agraph_t *) obj)->attr[index];
370  return NULL;
371 }
372 
373 int agxset(void *obj, int index, char *buf)
374 {
375  char **p;
376  if (index >= 0) {
377  Agraph_t *gobj = (Agraph_t *)obj;
378  p = gobj->attr;
379  agstrfree(p[index]);
380  p[index] = agstrdup(buf);
381  /* the index-th attr was set by agxset */
382  gobj->didset[index / CHAR_BIT] |= 1 << (index % CHAR_BIT);
383  return 0;
384  } else
385  return -1;
386 }
387 
388 int agsafeset(void* obj, char* name, char* value, char* def)
389 {
390  Agsym_t* a = agfindattr(obj, name);
391 
392  if (a == NULL) {
393  if (!def) def = "";
394  switch (TAG_OF(obj)) {
395  case TAG_GRAPH:
396  a = agraphattr(((Agraph_t*)obj)->root, name, def);
397  break;
398  case TAG_NODE:
399  a = agnodeattr(((Agnode_t*)obj)->graph, name, def);
400  break;
401  case TAG_EDGE:
402  a = agedgeattr(((Agedge_t*)obj)->head->graph, name, def);
403  break;
404  }
405  }
406  return agxset(obj, a->index, value);
407 }
408 
409 /* agcopyattr:
410  * Assumes attributes have already been declared.
411  * Do not copy key attribute for edges, as this must be distinct.
412  * Returns non-zero on failure or if objects have different type.
413  */
414 int agcopyattr(void *oldobj, void *newobj)
415 {
416  Agdict_t *d = agdictof(oldobj);
417  Agsym_t **list = d->list;
418  Agsym_t *sym;
419  Agsym_t *newsym;
420  int r = 0;
421  int isEdge = (TAG_OF(oldobj) == TAG_EDGE);
422 
423  if (TAG_OF(oldobj) != TAG_OF(newobj)) return 1;
424  while (!r && (sym = *list++)) {
425  if (isEdge && sym->index == KEYX) continue;
426  newsym = agfindattr(newobj,sym->name);
427  if (!newsym) return 1;
428  r = agxset(newobj, newsym->index, agxget(oldobj, sym->index));
429  }
430  return r;
431 }
432 
Agsym_t * agfindattr(void *obj, char *name)
Definition: attribs.c:292
#define dtprev(d, o)
Definition: cdt.h:307
#define offsetof(typ, fld)
Definition: grid.c:98
int dtsize(Dt_t *dt)
Definition: dtsize.c:20
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:147
#define KEY_ID
Definition: libgraph.h:117
Agnode_t * n
Definition: graph.h:120
void agcopydict(Agdict_t *to_dict, Agdict_t *from_dict)
Definition: attribs.c:274
#define head
Definition: dthdr.h:26
Agsym_t * agnxtattr(void *obj, Agsym_t *a)
Definition: attribs.c:307
EXTERN struct AG_s AG
Agraph_t * proto_g
Definition: libgraph.h:124
char * agxget(void *obj, int index)
Definition: attribs.c:366
int agxset(void *obj, int index, char *buf)
Definition: attribs.c:373
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:163
#define ALLOC(size, ptr, type)
Definition: memory.h:41
Definition: graph.h:212
#define TAG_EDGE
Definition: libgraph.h:109
int agset(void *obj, char *attr, char *value)
Definition: attribs.c:350
unsigned char fixed
Definition: graph.h:110
Definition: cdt.h:95
char ** attr
Definition: graph.h:64
int index
Definition: graph.h:108
#define dtfirst(d)
Definition: cdt.h:303
Definition: graph.h:87
Agnode_t * agprotonode(Agraph_t *g)
Definition: attribs.c:167
unsigned char init_called
Definition: libgraph.h:128
#define dtlast(d)
Definition: cdt.h:306
#define TAG_NODE
Definition: libgraph.h:108
#define TAG_OF(p)
Definition: libgraph.h:111
Agsym_t * aglstattr(void *obj)
Definition: attribs.c:313
Agraph_t * graph
Definition: graph.h:83
Agsym_t * agedgeattr(Agraph_t *g, char *name, char *value)
Definition: attribs.c:216
Definition: graph.h:75
Dict_t * dict
Definition: graph.h:115
Agsym_t * agraphattr(Agraph_t *g, char *name, char *value)
Definition: attribs.c:198
#define TAG_GRAPH
Definition: libgraph.h:110
int agsafeset(void *obj, char *name, char *value, char *def)
Definition: attribs.c:388
int agcopyattr(void *oldobj, void *newobj)
Definition: attribs.c:414
char * value
Definition: graph.h:107
void free()
int i
Definition: gvdevice.c:448
Definition: graph.h:60
#define TRUE
Definition: logic.h:42
#define dtmatch(d, o)
Definition: cdt.h:310
char * name
Definition: graph.h:107
int agerr(agerrlevel_t level, char *fmt,...)
Definition: lexer.c:620
#define dtnext(d, o)
Definition: cdt.h:304
#define HEAD_ID
Definition: types.h:53
Agproto_t * proto
Definition: graph.h:71
Agsym_t * agfstattr(void *obj)
Definition: attribs.c:301
#define HEADX
Definition: libgraph.h:120
char * agget(void *obj, char *attr)
Definition: attribs.c:345
Agedge_t * e
Definition: graph.h:121
int graph_nbytes
Definition: libgraph.h:123
Agraph_t * root
Definition: graph.h:69
Agraph_t * graph(char *name)
Definition: gv.cpp:38
Agsym_t * agprvattr(void *obj, Agsym_t *a)
Definition: attribs.c:319
int agindex(void *obj, char *name)
Definition: attribs.c:355
Agnode_t * agfstnode(Agraph_t *)
Definition: node.c:88
#define dtinsert(d, o)
Definition: cdt.h:311
unsigned char printed
Definition: graph.h:109
Agsym_t * agattr(void *obj, char *name, char *value)
Definition: attribs.c:129
Agdict_t * agNEWdict(char *name)
Definition: attribs.c:252
#define AGRAPH
Definition: graph.h:49
Agsym_t ** list
Definition: graph.h:116
#define NULL
Definition: logic.h:50
#define FALSE
Definition: logic.h:39
Agdict_t * agdictof(void *obj)
Definition: attribs.c:23
Agraph_t * agprotograph()
Definition: attribs.c:162
#define TAILX
Definition: libgraph.h:119
Dtmethod_t * Dttree
int node_nbytes
Definition: libgraph.h:123
Agnode_t * agnxtnode(Agraph_t *, Agnode_t *)
Definition: node.c:93
Definition: graph.h:106
Agraph_t * agusergraph(Agnode_t *n)
Definition: graph.c:279
void agFREEdict(Agraph_t *g, Agdict_t *dict)
Definition: attribs.c:236
#define TAIL_ID
Definition: types.h:52
Agsym_t * agnodeattr(Agraph_t *g, char *name, char *value)
Definition: attribs.c:207
void agstrfree(char *)
Definition: refstr.c:120
#define KEYX
Definition: libgraph.h:118
Dt_t * dtopen(Dtdisc_t *disc, Dtmethod_t *meth)
Definition: dtopen.c:12
Agsym_t * agNEWsym(Agdict_t *dict, char *name, char *value)
Definition: attribs.c:41
char * name
Definition: graph.h:114
Definition: graph.h:212
Agnode_t * meta_node
Definition: graph.h:70
int dtclose(reg Dt_t *dt)
Definition: dtclose.c:8
int aginitlib(int gs, int ns, int es)
Definition: attribs.c:326
Agraph_t * agopen(char *name, int kind)
Definition: graph.c:287
Agproto_t * prev
Definition: graph.h:122
int edge_nbytes
Definition: libgraph.h:123
Agedge_t * agprotoedge(Agraph_t *g)
Definition: attribs.c:173
#define NEW(t)
Definition: memory.h:35
char * agstrdup(char *)
Definition: refstr.c:70
char * didset
Definition: graph.h:65