~ubuntu-branches/ubuntu/precise/graphviz/precise-security

« back to all changes in this revision

Viewing changes to lib/agraph/pend.c

  • Committer: Bazaar Package Importer
  • Author(s): David Claughton
  • Date: 2010-03-24 22:45:18 UTC
  • mfrom: (1.2.7 upstream) (6.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100324224518-do441tthbqjaqjzd
Tags: 2.26.3-4
Add patch to fix segfault in circo. Backported from upstream snapshot
release.  Thanks to Francis Russell for his work on this.
(Closes: #575255)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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: */
3
 
 
4
 
/**********************************************************
5
 
*      This software is part of the graphviz package      *
6
 
*                http://www.graphviz.org/                 *
7
 
*                                                         *
8
 
*            Copyright (c) 1994-2004 AT&T Corp.           *
9
 
*                and is licensed under the                *
10
 
*            Common Public License, Version 1.0           *
11
 
*                      by AT&T Corp.                      *
12
 
*                                                         *
13
 
*        Information and Software Systems Research        *
14
 
*              AT&T Research, Florham Park NJ             *
15
 
**********************************************************/
16
 
 
17
 
 
18
 
#include "aghdr.h"
19
 
 
20
 
static char DRName[] = "_AG_pending";
21
 
 
22
 
typedef struct symlist_s {
23
 
    Agsym_t *sym;
24
 
    struct symlist_s *link;
25
 
} symlist_t;
26
 
 
27
 
/* this record describes one pending callback on one object */
28
 
typedef struct {
29
 
    Dtlink_t link;
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 */
35
 
} pending_cb_t;
36
 
 
37
 
typedef struct {
38
 
    Agrec_t h;
39
 
    struct {
40
 
        Dict_t *g, *n, *e;
41
 
    } ins, mod, del;
42
 
} pendingset_t;
43
 
 
44
 
static void free_symlist(pending_cb_t * pcb)
45
 
{
46
 
    symlist_t *s, *t;
47
 
 
48
 
    for (s = pcb->symlist; s; s = t) {
49
 
        t = s->link;
50
 
        agfree(pcb->g_alloc, s);
51
 
    }
52
 
}
53
 
 
54
 
static void freef(Dict_t * dict, void *ptr, Dtdisc_t * disc)
55
 
{
56
 
    pending_cb_t *pcb;
57
 
 
58
 
    NOTUSED(dict);
59
 
    NOTUSED(disc);
60
 
    pcb = ptr;
61
 
    free_symlist(pcb);
62
 
    agfree(pcb->g_alloc, pcb);
63
 
}
64
 
 
65
 
static Dtdisc_t Disc = {
66
 
    offsetof(pending_cb_t, key),        /* sort by 'key' */
67
 
    sizeof(unsigned long),
68
 
    0,                          /* link offset */
69
 
    NIL(Dtmake_f),
70
 
    freef,
71
 
    NIL(Dtcompar_f),
72
 
    NIL(Dthash_f)
73
 
};
74
 
 
75
 
static Dict_t *dictof(pendingset_t * ds, Agobj_t * obj, int kind)
76
 
{
77
 
    Dict_t **dict_ref = NIL(Dict_t **);
78
 
 
79
 
    dict_ref = 0;
80
 
    switch (AGTYPE(obj)) {
81
 
    case AGRAPH:
82
 
        switch (kind) {
83
 
        case CB_INITIALIZE:
84
 
            dict_ref = &(ds->ins.g);
85
 
            break;
86
 
        case CB_UPDATE:
87
 
            dict_ref = &(ds->mod.g);
88
 
            break;
89
 
        case CB_DELETION:
90
 
            dict_ref = &(ds->del.g);
91
 
            break;
92
 
        default:
93
 
            break;
94
 
        }
95
 
        break;
96
 
    case AGNODE:
97
 
        switch (kind) {
98
 
        case CB_INITIALIZE:
99
 
            dict_ref = &(ds->ins.n);
100
 
            break;
101
 
        case CB_UPDATE:
102
 
            dict_ref = &(ds->mod.n);
103
 
            break;
104
 
        case CB_DELETION:
105
 
            dict_ref = &(ds->del.n);
106
 
            break;
107
 
        default:
108
 
            break;
109
 
        }
110
 
        break;
111
 
    case AGEDGE:
112
 
        switch (kind) {
113
 
        case CB_INITIALIZE:
114
 
            dict_ref = &(ds->ins.e);
115
 
            break;
116
 
        case CB_UPDATE:
117
 
            dict_ref = &(ds->mod.e);
118
 
            break;
119
 
        case CB_DELETION:
120
 
            dict_ref = &(ds->del.e);
121
 
            break;
122
 
        default:
123
 
            break;
124
 
        }
125
 
        break;
126
 
    default:
127
 
        break;
128
 
    }
129
 
 
130
 
    if (dict_ref == 0)
131
 
        agerror(AGERROR_BADOBJ, "pend dictof");
132
 
    if (*dict_ref == NIL(Dict_t *))
133
 
        *dict_ref = agdtopen(agraphof(obj), &Disc, Dttree);
134
 
    return *dict_ref;
135
 
}
136
 
 
137
 
static unsigned long genkey(Agobj_t * obj)
138
 
{
139
 
    return obj->tag.id;
140
 
}
141
 
 
142
 
static pending_cb_t *lookup(Dict_t * dict, Agobj_t * obj)
143
 
{
144
 
    pending_cb_t key, *rv;
145
 
 
146
 
    key.key = genkey(obj);
147
 
    rv = (pending_cb_t *) dtsearch(dict, &key);
148
 
    return rv;
149
 
}
150
 
 
151
 
static void record_sym(Agobj_t * obj, pending_cb_t * handle,
152
 
                       Agsym_t * optsym)
153
 
{
154
 
    symlist_t *sym, *nsym, *psym;
155
 
 
156
 
    psym = NIL(symlist_t *);
157
 
    for (sym = handle->symlist; sym; psym = sym, sym = sym->link) {
158
 
        if (sym->sym == optsym)
159
 
            break;
160
 
        if (sym == NIL(symlist_t *)) {
161
 
            nsym = agalloc(agraphof(obj), sizeof(symlist_t));
162
 
            nsym->sym = optsym;
163
 
            if (psym)
164
 
                psym->link = nsym;
165
 
            else
166
 
                handle->symlist = nsym;
167
 
        }
168
 
        /* else we already have a callback registered */
169
 
    }
170
 
}
171
 
 
172
 
static pending_cb_t *insert(Dict_t * dict, Agobj_t * obj, Agsym_t * optsym)
173
 
{
174
 
    pending_cb_t *handle;
175
 
    handle = agalloc(agraphof(obj), sizeof(pending_cb_t));
176
 
    handle->obj = obj;
177
 
    handle->key = genkey(obj);
178
 
    handle->g_alloc = agraphof(obj);
179
 
    if (optsym) {
180
 
        handle->symlist =
181
 
            (symlist_t *) agalloc(handle->g_alloc, sizeof(symlist_t));
182
 
        handle->symlist->sym = optsym;
183
 
    }
184
 
    dtinsert(dict, handle);
185
 
    return handle;
186
 
}
187
 
 
188
 
static void purge(Dict_t * dict, Agobj_t * obj)
189
 
{
190
 
    pending_cb_t *handle;
191
 
 
192
 
    if ((handle = lookup(dict, obj))) {
193
 
        dtdelete(dict, handle);
194
 
    }
195
 
}
196
 
 
197
 
void agrecord_callback(Agobj_t * obj, int kind, Agsym_t * optsym)
198
 
{
199
 
    pendingset_t *pending;
200
 
    Dict_t *dict;
201
 
    pending_cb_t *handle;
202
 
    Agraph_t *g;
203
 
 
204
 
    g = agraphof(obj);
205
 
    pending =
206
 
        (pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t), FALSE);
207
 
 
208
 
    switch (kind) {
209
 
    case CB_INITIALIZE:
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);
214
 
        if (handle == 0)
215
 
            handle = insert(dict, obj, optsym);
216
 
        break;
217
 
    case CB_UPDATE:
218
 
        if (lookup(dictof(pending, obj, CB_INITIALIZE), obj))
219
 
            break;
220
 
        if (lookup(dictof(pending, obj, CB_DELETION), obj))
221
 
            break;
222
 
        dict = dictof(pending, obj, CB_UPDATE);
223
 
        handle = lookup(dict, obj);
224
 
        if (handle == 0)
225
 
            handle = insert(dict, obj, optsym);
226
 
        record_sym(obj, handle, optsym);
227
 
        break;
228
 
    case CB_DELETION:
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);
233
 
        if (handle == 0)
234
 
            handle = insert(dict, obj, optsym);
235
 
        break;
236
 
    default:
237
 
        agerror(AGERROR_BADOBJ, "agrecord_callback");
238
 
    }
239
 
}
240
 
 
241
 
static void cb(Dict_t * dict, int callback_kind)
242
 
{
243
 
    pending_cb_t *pcb;
244
 
    Agraph_t *g;
245
 
    symlist_t *psym;
246
 
    Agcbstack_t *stack;
247
 
 
248
 
    if (dict)
249
 
        while ((pcb = (pending_cb_t *) dtfirst(dict))) {
250
 
            g = pcb->g_alloc;
251
 
            stack = g->clos->cb;
252
 
            switch (callback_kind) {
253
 
            case CB_INITIALIZE:
254
 
                aginitcb(pcb->obj, stack);
255
 
                break;
256
 
            case CB_UPDATE:
257
 
                for (psym = pcb->symlist; psym; psym = psym->link)
258
 
                    agupdcb(pcb->obj, psym->sym, stack);
259
 
                break;
260
 
            case CB_DELETION:
261
 
                agdelcb(pcb->obj, stack);
262
 
                break;
263
 
            }
264
 
            dtdelete(dict, pcb);
265
 
        }
266
 
}
267
 
 
268
 
static void agrelease_callbacks(Agraph_t * g)
269
 
{
270
 
    pendingset_t *pending;
271
 
    if (NOT(g->clos->callbacks_enabled)) {
272
 
        g->clos->callbacks_enabled = TRUE;
273
 
        pending =
274
 
            (pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t),
275
 
                                       FALSE);
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);
280
 
 
281
 
        cb(pending->mod.g, CB_UPDATE);
282
 
        cb(pending->mod.n, CB_UPDATE);
283
 
        cb(pending->mod.e, CB_UPDATE);
284
 
 
285
 
        cb(pending->del.e, CB_DELETION);
286
 
        cb(pending->del.n, CB_DELETION);
287
 
        cb(pending->del.g, CB_DELETION);
288
 
    }
289
 
}
290
 
 
291
 
int agcallbacks(Agraph_t * g, int flag)
292
 
{
293
 
    if (flag && NOT(g->clos->callbacks_enabled))
294
 
        agrelease_callbacks(g);
295
 
    if (g->clos->callbacks_enabled) {
296
 
        g->clos->callbacks_enabled = flag;
297
 
        return TRUE;
298
 
    }
299
 
    g->clos->callbacks_enabled = flag;
300
 
    return FALSE;
301
 
}