1
/* $Id: pend.c,v 1.2 2006/07/08 17:33:49 ellson Exp $ $Revision: 1.2 $ */
2
/* vim:set shiftwidth=4 ts=8: */
4
/**********************************************************
5
* This software is part of the graphviz package *
6
* http://www.graphviz.org/ *
8
* Copyright (c) 1994-2004 AT&T Corp. *
9
* and is licensed under the *
10
* Common Public License, Version 1.0 *
13
* Information and Software Systems Research *
14
* AT&T Research, Florham Park NJ *
15
**********************************************************/
20
static char DRName[] = "_AG_pending";
22
typedef struct symlist_s {
24
struct symlist_s *link;
27
/* this record describes one pending callback on one object */
30
unsigned long key; /* universal key for main or sub-object */
31
Agobj_t *obj; /* may be a subgraph obj */
32
/* i'm sure there are more elegant approaches,but */
33
Agraph_t *g_alloc; /* save this, because object may become dead */
34
symlist_t *symlist; /* attributes involved */
44
static void free_symlist(pending_cb_t * pcb)
48
for (s = pcb->symlist; s; s = t) {
50
agfree(pcb->g_alloc, s);
54
static void freef(Dict_t * dict, void *ptr, Dtdisc_t * disc)
62
agfree(pcb->g_alloc, pcb);
65
static Dtdisc_t Disc = {
66
offsetof(pending_cb_t, key), /* sort by 'key' */
67
sizeof(unsigned long),
75
static Dict_t *dictof(pendingset_t * ds, Agobj_t * obj, int kind)
77
Dict_t **dict_ref = NIL(Dict_t **);
80
switch (AGTYPE(obj)) {
84
dict_ref = &(ds->ins.g);
87
dict_ref = &(ds->mod.g);
90
dict_ref = &(ds->del.g);
99
dict_ref = &(ds->ins.n);
102
dict_ref = &(ds->mod.n);
105
dict_ref = &(ds->del.n);
114
dict_ref = &(ds->ins.e);
117
dict_ref = &(ds->mod.e);
120
dict_ref = &(ds->del.e);
131
agerror(AGERROR_BADOBJ, "pend dictof");
132
if (*dict_ref == NIL(Dict_t *))
133
*dict_ref = agdtopen(agraphof(obj), &Disc, Dttree);
137
static unsigned long genkey(Agobj_t * obj)
142
static pending_cb_t *lookup(Dict_t * dict, Agobj_t * obj)
144
pending_cb_t key, *rv;
146
key.key = genkey(obj);
147
rv = (pending_cb_t *) dtsearch(dict, &key);
151
static void record_sym(Agobj_t * obj, pending_cb_t * handle,
154
symlist_t *sym, *nsym, *psym;
156
psym = NIL(symlist_t *);
157
for (sym = handle->symlist; sym; psym = sym, sym = sym->link) {
158
if (sym->sym == optsym)
160
if (sym == NIL(symlist_t *)) {
161
nsym = agalloc(agraphof(obj), sizeof(symlist_t));
166
handle->symlist = nsym;
168
/* else we already have a callback registered */
172
static pending_cb_t *insert(Dict_t * dict, Agobj_t * obj, Agsym_t * optsym)
174
pending_cb_t *handle;
175
handle = agalloc(agraphof(obj), sizeof(pending_cb_t));
177
handle->key = genkey(obj);
178
handle->g_alloc = agraphof(obj);
181
(symlist_t *) agalloc(handle->g_alloc, sizeof(symlist_t));
182
handle->symlist->sym = optsym;
184
dtinsert(dict, handle);
188
static void purge(Dict_t * dict, Agobj_t * obj)
190
pending_cb_t *handle;
192
if ((handle = lookup(dict, obj))) {
193
dtdelete(dict, handle);
197
void agrecord_callback(Agobj_t * obj, int kind, Agsym_t * optsym)
199
pendingset_t *pending;
201
pending_cb_t *handle;
206
(pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t), FALSE);
210
assert(lookup(dictof(pending, obj, CB_UPDATE), obj) == 0);
211
assert(lookup(dictof(pending, obj, CB_DELETION), obj) == 0);
212
dict = dictof(pending, obj, CB_INITIALIZE);
213
handle = lookup(dict, obj);
215
handle = insert(dict, obj, optsym);
218
if (lookup(dictof(pending, obj, CB_INITIALIZE), obj))
220
if (lookup(dictof(pending, obj, CB_DELETION), obj))
222
dict = dictof(pending, obj, CB_UPDATE);
223
handle = lookup(dict, obj);
225
handle = insert(dict, obj, optsym);
226
record_sym(obj, handle, optsym);
229
purge(dictof(pending, obj, CB_INITIALIZE), obj);
230
purge(dictof(pending, obj, CB_UPDATE), obj);
231
dict = dictof(pending, obj, CB_DELETION);
232
handle = lookup(dict, obj);
234
handle = insert(dict, obj, optsym);
237
agerror(AGERROR_BADOBJ, "agrecord_callback");
241
static void cb(Dict_t * dict, int callback_kind)
249
while ((pcb = (pending_cb_t *) dtfirst(dict))) {
252
switch (callback_kind) {
254
aginitcb(pcb->obj, stack);
257
for (psym = pcb->symlist; psym; psym = psym->link)
258
agupdcb(pcb->obj, psym->sym, stack);
261
agdelcb(pcb->obj, stack);
268
static void agrelease_callbacks(Agraph_t * g)
270
pendingset_t *pending;
271
if (NOT(g->clos->callbacks_enabled)) {
272
g->clos->callbacks_enabled = TRUE;
274
(pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t),
276
/* this destroys objects in the opposite of their order of creation */
277
cb(pending->ins.g, CB_INITIALIZE);
278
cb(pending->ins.n, CB_INITIALIZE);
279
cb(pending->ins.e, CB_INITIALIZE);
281
cb(pending->mod.g, CB_UPDATE);
282
cb(pending->mod.n, CB_UPDATE);
283
cb(pending->mod.e, CB_UPDATE);
285
cb(pending->del.e, CB_DELETION);
286
cb(pending->del.n, CB_DELETION);
287
cb(pending->del.g, CB_DELETION);
291
int agcallbacks(Agraph_t * g, int flag)
293
if (flag && NOT(g->clos->callbacks_enabled))
294
agrelease_callbacks(g);
295
if (g->clos->callbacks_enabled) {
296
g->clos->callbacks_enabled = flag;
299
g->clos->callbacks_enabled = flag;