~ubuntu-branches/ubuntu/lucid/graphviz/lucid-security

« back to all changes in this revision

Viewing changes to agraph/pend.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-02-05 18:52:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020205185212-8i04c70te00rc40y
Tags: upstream-1.7.16
ImportĀ upstreamĀ versionĀ 1.7.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This software may only be used by you under license from AT&T Corp.
 
3
    ("AT&T").  A copy of AT&T's Source Code Agreement is available at
 
4
    AT&T's Internet website having the URL:
 
5
    <http://www.research.att.com/sw/tools/graphviz/license/source.html>
 
6
    If you received this software without first entering into a license
 
7
    with AT&T, you have an infringing copy of this software and cannot use
 
8
    it without violating AT&T's intellectual property rights.
 
9
*/
 
10
#include <aghdr.h>
 
11
 
 
12
#ifdef DMALLOC
 
13
#include "dmalloc.h"
 
14
#endif
 
15
 
 
16
static char DRName[] = "_AG_pending";
 
17
 
 
18
typedef struct symlist_s {Agsym_t *sym; struct symlist_s *link;} symlist_t;
 
19
 
 
20
typedef struct {
 
21
        Dtlink_t        link;
 
22
        Agobj_t         *key;   /* i.e. the root obj */
 
23
        Agobj_t         *obj;   /* may be a subgraph obj */ 
 
24
        symlist_t       *symlist;
 
25
        int                     callback_kind;
 
26
} pending_cb_t;
 
27
 
 
28
typedef struct {
 
29
        Agrec_t         h;
 
30
        struct {Dict_t *g,*n,*e;} pending;
 
31
} dirtyset_t;
 
32
 
 
33
static void clean_symlist(pending_cb_t *pcb)
 
34
{
 
35
        Agraph_t                *g;
 
36
        symlist_t               *s,*t;
 
37
 
 
38
        g = agroot(agraphof(pcb->obj));
 
39
        for (s = pcb->symlist; s; s = t) {
 
40
                t = s->link;
 
41
                agfree(g,s);
 
42
        }
 
43
}
 
44
 
 
45
static void freef(Dict_t *dict, void *ptr, Dtdisc_t *disc)
 
46
{
 
47
        pending_cb_t    *pcb;
 
48
 
 
49
        NOTUSED(dict);
 
50
        NOTUSED(disc);
 
51
        pcb = ptr;
 
52
        clean_symlist(pcb);
 
53
        agfree(agraphof(pcb->obj),pcb);
 
54
}
 
55
 
 
56
static Dtdisc_t Disc = {
 
57
        offsetof(pending_cb_t,key),     /* sort by 'key' */
 
58
        sizeof(Agobj_t*),
 
59
        0, /* link offset */
 
60
        NIL(Dtmake_f),
 
61
        freef,
 
62
        NIL(Dtcompar_f),
 
63
        NIL(Dthash_f)
 
64
};
 
65
 
 
66
static Dict_t *dictof(dirtyset_t *ds, Agobj_t *obj)
 
67
{
 
68
        Dict_t  **dict_ref = NIL(Dict_t**);
 
69
        switch(AGTYPE(obj)) {
 
70
                case AGRAPH: dict_ref = &(ds->pending.g); break;
 
71
                case AGNODE: dict_ref = &(ds->pending.n); break;
 
72
                case AGINEDGE: case AGOUTEDGE: dict_ref = &(ds->pending.e); break;
 
73
        }
 
74
        if (*dict_ref == NIL(Dict_t*))
 
75
                *dict_ref = agdtopen(agraphof(obj),&Disc,Dttree);
 
76
        return *dict_ref;
 
77
}
 
78
 
 
79
static Agobj_t* genkey(Agobj_t *obj)
 
80
{
 
81
        switch (AGTYPE(obj)) {
 
82
                case AGRAPH: return obj;
 
83
                case AGNODE:
 
84
                        return (Agobj_t*)agsubnode(agroot(agraphof(obj)),(Agnode_t*)obj,FALSE);
 
85
                case AGINEDGE: case AGOUTEDGE:
 
86
                        return (Agobj_t*)agsubedge(agroot(agraphof(obj)),(Agedge_t*)obj,FALSE);
 
87
        }
 
88
        return NIL(Agobj_t*);
 
89
}
 
90
 
 
91
static pending_cb_t *lookup(Dict_t *dict, Agobj_t *obj)
 
92
{
 
93
        pending_cb_t    key, *rv;
 
94
 
 
95
        key.key = genkey(obj);
 
96
        rv = (pending_cb_t*) dtsearch(dict,&key);
 
97
        return rv; 
 
98
}
 
99
 
 
100
static void resolve(Dict_t *dict, pending_cb_t *handle, Agobj_t *obj, int cbkind, Agsym_t *optsym)
 
101
{
 
102
        symlist_t       *sym,*nsym,*psym;
 
103
 
 
104
        switch (cbkind) {
 
105
                case CB_INITIALIZE:     /* dominate CB_UPDATE */
 
106
                        clean_symlist(handle);
 
107
                        handle->callback_kind = cbkind;
 
108
                        break;
 
109
                case CB_DELETION:       /* cancels all pending callbacks */
 
110
                        dtdelete(dict,handle);
 
111
                        break;
 
112
                case CB_UPDATE:         /* least strength */
 
113
                        if (handle->callback_kind == CB_UPDATE) {
 
114
                                psym = NIL(symlist_t*);
 
115
                                for (sym = handle->symlist; sym; psym = sym, sym = sym->link)
 
116
                                        if (sym->sym == optsym) break;
 
117
                                if (sym == NIL(symlist_t*)) {
 
118
                                        nsym = agalloc(agraphof(obj),sizeof(symlist_t));
 
119
                                        nsym->sym = optsym;
 
120
                                        if (psym) psym->link = nsym;
 
121
                                        else handle->symlist = nsym;
 
122
                                }
 
123
                                /* else we already have a callback registered */
 
124
                        }
 
125
                        /* else update is dominated by CB_INITIALIZE or CB_DELETION */
 
126
                        break;
 
127
        }
 
128
}
 
129
 
 
130
static void insert(Dict_t *dict, Agobj_t *obj, int cbkind, Agsym_t *optsym)
 
131
{
 
132
        pending_cb_t    *handle;
 
133
        handle = agalloc(agraphof(obj),sizeof(pending_cb_t));
 
134
        handle->obj = obj;
 
135
        handle->key = genkey(obj);
 
136
        if (optsym) {
 
137
                handle->symlist = (symlist_t*)agalloc(agraphof(obj),sizeof(symlist_t));
 
138
                handle->symlist->sym = optsym;
 
139
        }
 
140
        handle->callback_kind = cbkind;
 
141
        dtinsert(dict,handle);
 
142
}
 
143
 
 
144
void agrecord_callback(Agobj_t *obj, int kind, Agsym_t *optsym)
 
145
{
 
146
        dirtyset_t              *dirty;
 
147
        Dict_t                  *dict;
 
148
        pending_cb_t    *handle;
 
149
        Agraph_t                *g;
 
150
 
 
151
        g = agraphof(obj);
 
152
        dirty = (dirtyset_t*) agbindrec(g,DRName,sizeof(dirtyset_t),FALSE);
 
153
        dict = dictof(dirty,obj);
 
154
        if ((handle = lookup(dict,obj))) resolve(dict,handle,obj,kind,optsym);
 
155
        else insert(dict,obj,kind,optsym);
 
156
}
 
157
 
 
158
static void cb(Dict_t *dict)
 
159
{
 
160
        pending_cb_t    *pcb;
 
161
        Agraph_t                *g;
 
162
        symlist_t               *psym;
 
163
        Agcbstack_t             *stack;
 
164
 
 
165
        if (dict) while ((pcb = (pending_cb_t*)dtfirst(dict))) {
 
166
                g = agraphof(pcb->obj);
 
167
                stack = g->clos->cb;
 
168
                switch(pcb->callback_kind) {
 
169
                case CB_INITIALIZE:     aginitcb(pcb->obj,stack); break;
 
170
                case CB_UPDATE: 
 
171
                        for (psym = pcb->symlist; psym; psym = psym->link)
 
172
                                agupdcb(pcb->obj, psym->sym, stack);
 
173
                        break;
 
174
                case CB_DELETION:       agdelcb(pcb->obj,stack); break;
 
175
                }
 
176
                dtdelete(dict,pcb);
 
177
        }
 
178
}
 
179
 
 
180
static void agrelease_callbacks(Agraph_t *g)
 
181
{
 
182
        dirtyset_t *dirty;
 
183
        if (NOT(g->clos->callbacks_enabled)) {
 
184
                g->clos->callbacks_enabled = TRUE;
 
185
                dirty = (dirtyset_t*) agbindrec(g,DRName,sizeof(dirtyset_t),FALSE);
 
186
                cb (dirty->pending.g);
 
187
                cb (dirty->pending.n);
 
188
                cb (dirty->pending.e);
 
189
        }
 
190
}
 
191
 
 
192
int agcallbacks(Agraph_t *g, int flag)
 
193
{
 
194
#ifdef OLD
 
195
        if (flag && NOT(g->clos->callbacks_enabled))
 
196
                agrelease_callbacks(g);
 
197
        else if (NOT(flag) && g->clos->callbacks_enabled)
 
198
                g->clos->callbacks_enabled = FALSE;
 
199
#else
 
200
        if (flag && NOT(g->clos->callbacks_enabled))
 
201
                agrelease_callbacks(g);
 
202
        if (g->clos->callbacks_enabled) {
 
203
                g->clos->callbacks_enabled = flag;
 
204
                return TRUE;
 
205
        } 
 
206
        g->clos->callbacks_enabled = flag;
 
207
        return FALSE;
 
208
#endif
 
209
}