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

« back to all changes in this revision

Viewing changes to lefty/txtview.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
 
 
11
#pragma prototyped
 
12
/* Lefteris Koutsofios - AT&T Bell Laboratories */
 
13
 
 
14
#include "common.h"
 
15
#include "g.h"
 
16
#include "mem.h"
 
17
#include "code.h"
 
18
#include "tbl.h"
 
19
#include "parse.h"
 
20
#include "exec.h"
 
21
#include "str.h"
 
22
#include "txtview.h"
 
23
 
 
24
typedef enum {
 
25
    TXT_SEEN, TXT_ABSTRACT, TXT_FULL
 
26
} txtmode_t;
 
27
typedef struct txtnode_t {
 
28
    txtmode_t mode;
 
29
    Ttype_t ttype;
 
30
    Tobj ko, vo;
 
31
    long time;
 
32
    char *path;
 
33
    union {
 
34
        struct {
 
35
            struct txtnode_t *txtnode;
 
36
            Tobj ko;
 
37
            char *text;
 
38
            int wi;
 
39
        } s;
 
40
        struct {
 
41
            char *text;
 
42
            int wi;
 
43
        } a;
 
44
        union {
 
45
            struct {
 
46
                char *text;
 
47
                int wi;
 
48
            } s;
 
49
            struct {
 
50
                char *ftext, *ltext;
 
51
                int fwi, mwi, lwi;
 
52
                struct txtnode_t *list;
 
53
                int n;
 
54
            } t;
 
55
        } f;
 
56
    } u;
 
57
} txtnode_t;
 
58
static txtnode_t *txtroot;
 
59
static txtnode_t defnode;
 
60
 
 
61
static txtnode_t **seenp;
 
62
static long seeni, seenn;
 
63
#define SEENINCR 100
 
64
#define SEENSIZE sizeof (txtnode_t)
 
65
 
 
66
static Tobj txtvo2toggle = NULL;
 
67
 
 
68
static Gwattr_t arraydata[2], buttondata[5];
 
69
 
 
70
static int txton, txtx, txty, txtwidth, txtheight;
 
71
static int txtwi, queryws[G_QWMODES + 1], listwi, scrollwi, arraywi, cmdwi;
 
72
 
 
73
static Psrc_t src;
 
74
 
 
75
#define max(a, b) (((a) >= (b)) ? (a) : (b))
 
76
 
 
77
static void viewon (void);
 
78
static void viewoff (void);
 
79
static void update (txtnode_t *, long);
 
80
static void buildlist (txtnode_t *);
 
81
static void rebuildlist (txtnode_t *);
 
82
static void fillnode (txtnode_t *, txtnode_t *);
 
83
static void unfillnode (txtnode_t *);
 
84
static int cmp (const void *, const void *);
 
85
static txtnode_t *findseen (txtnode_t *);
 
86
static void add2seen (txtnode_t *);
 
87
static void orderfunc (void *, Gawdata_t *);
 
88
static void coordsfunc (int, Gawdata_t *);
 
89
static void coords2func (int, Gawdata_t *);
 
90
 
 
91
void TXTinit (Grect_t r) {
 
92
    Gwattr_t data[1];
 
93
    int i;
 
94
 
 
95
    txton = TRUE;
 
96
    txtwi = -1;
 
97
    txtx = r.o.x, txty = r.o.y;
 
98
    txtwidth = r.c.x - r.o.x + 1, txtheight = r.c.y - r.o.y + 1;
 
99
 
 
100
    buttondata[0].id = G_ATTRBUTTONCB;
 
101
    buttondata[0].u.func = TXTtoggle;
 
102
    buttondata[1].id = G_ATTRSIZE;
 
103
    buttondata[1].u.s.x = buttondata[1].u.s.y = 0;
 
104
    buttondata[2].id = G_ATTRBORDERWIDTH;
 
105
    buttondata[2].u.i = 0;
 
106
    buttondata[3].id = G_ATTRTEXT;
 
107
    buttondata[4].id = G_ATTRUSERDATA;
 
108
 
 
109
    arraydata[0].id = G_ATTRRESIZECB;
 
110
    arraydata[0].u.func = coordsfunc;
 
111
    arraydata[1].id = G_ATTRSIZE;
 
112
    arraydata[1].u.s.x = arraydata[1].u.s.y = 0;
 
113
 
 
114
    defnode.mode = TXT_ABSTRACT;
 
115
    defnode.ttype = T_TABLE;
 
116
    defnode.ko = defnode.vo = NULL;
 
117
    defnode.time = -1;
 
118
    defnode.path = NULL;
 
119
    defnode.u.s.txtnode = NULL;
 
120
    defnode.u.s.ko = NULL;
 
121
    defnode.u.s.text = NULL;
 
122
    defnode.u.s.wi = 0;
 
123
    defnode.u.a.text = NULL;
 
124
    defnode.u.a.wi = 0;
 
125
    defnode.u.f.s.text = NULL;
 
126
    defnode.u.f.s.wi = 0;
 
127
    defnode.u.f.t.ftext = defnode.u.f.t.ltext = NULL;
 
128
    defnode.u.f.t.fwi = 0;
 
129
    defnode.u.f.t.mwi = 0;
 
130
    defnode.u.f.t.lwi = 0;
 
131
    defnode.u.f.t.list = NULL;
 
132
    defnode.u.f.t.n = 0;
 
133
 
 
134
    for (i = 1; i <= G_QWMODES; i++) {
 
135
        data[0].id = G_ATTRMODE;
 
136
        switch (i) {
 
137
        case G_QWSTRING:
 
138
            data[0].u.t = "string";
 
139
            break;
 
140
        case G_QWFILE:
 
141
            data[0].u.t = "file";
 
142
            break;
 
143
        case G_QWCHOICE:
 
144
            data[0].u.t = "choice";
 
145
            break;
 
146
        }
 
147
        queryws[i] = Gcreatewidget (-1, G_QUERYWIDGET, 1, &data[0]);
 
148
    }
 
149
 
 
150
    src.flag = CHARSRC, src.fp = NULL, src.tok = -1, src.lnum = 1;
 
151
}
 
152
 
 
153
void TXTterm (void) {
 
154
    int i;
 
155
 
 
156
    for (i = 1; i <= G_QWMODES; i++)
 
157
        Gdestroywidget (queryws[i]);
 
158
    if (txton)
 
159
        viewoff (), txton = FALSE;
 
160
}
 
161
 
 
162
/* LEFTY builtin */
 
163
int TXTmode (int argc, lvar_t *argv) {
 
164
    char *s;
 
165
 
 
166
    if (!argv[0].o || Tgettype (argv[0].o) != T_STRING)
 
167
        return L_FAILURE;
 
168
    s = Tgetstring (argv[0].o);
 
169
    if (Strcmp (s, "on") == 0) {
 
170
        if (txtwi == -1)
 
171
            viewon ();
 
172
    } else if (Strcmp (s, "off") == 0) {
 
173
        if (txtwi != -1)
 
174
            viewoff ();
 
175
        else
 
176
            txton = FALSE;
 
177
    }
 
178
    return L_SUCCESS;
 
179
}
 
180
 
 
181
static void viewon (void) {
 
182
    Gwattr_t data[5];
 
183
 
 
184
    data[0].id = G_ATTRNAME;
 
185
    data[0].u.t = "LEFTY text view";
 
186
    data[1].id = G_ATTRORIGIN;
 
187
    data[1].u.p.x = txtx, data[1].u.p.y = txty;
 
188
    data[2].id = G_ATTRSIZE;
 
189
    data[2].u.s.x = txtwidth, data[2].u.s.y = txtheight;
 
190
    txtwi = Gcreatewidget (-1, G_VIEWWIDGET, 3, &data[0]);
 
191
 
 
192
    data[0].id = G_ATTRSIZE;
 
193
    data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight;
 
194
    data[1].id = G_ATTRBORDERWIDTH;
 
195
    data[1].u.i = 1;
 
196
    data[2].id = G_ATTRRESIZECB;
 
197
    data[2].u.func = coords2func;
 
198
    listwi = Gcreatewidget (txtwi, G_ARRAYWIDGET, 3, &data[0]);
 
199
    Gawsetmode (&Gwidgets[listwi], TRUE);
 
200
 
 
201
    data[0].id = G_ATTRSIZE;
 
202
    data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight / 3;
 
203
    data[1].id = G_ATTRBORDERWIDTH;
 
204
    data[1].u.i = 0;
 
205
    data[2].id = G_ATTRTEXT;
 
206
    data[2].u.t = NULL;
 
207
    data[3].id = G_ATTRNEWLINECB;
 
208
    data[3].u.func = TXTprocess;
 
209
    data[4].id = G_ATTRMODE;
 
210
    data[4].u.t = "oneline";
 
211
    cmdwi = Gcreatewidget (listwi, G_TEXTWIDGET, 5, &data[0]);
 
212
 
 
213
    data[0].id = G_ATTRSIZE;
 
214
    data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight * 2 / 3;
 
215
    data[1].id = G_ATTRMODE;
 
216
    data[1].u.t = "forcebars";
 
217
    scrollwi = Gcreatewidget (listwi, G_SCROLLWIDGET, 2, &data[0]);
 
218
 
 
219
    data[0].id = G_ATTRRESIZECB;
 
220
    data[0].u.func = coordsfunc;
 
221
    data[1].id = G_ATTRSIZE;
 
222
    data[1].u.s.x = txtwidth, data[1].u.s.y = txtheight;
 
223
    data[2].id = G_ATTRBORDERWIDTH;
 
224
    data[2].u.i = 0;
 
225
    arraywi = Gcreatewidget (scrollwi, G_ARRAYWIDGET, 3, &data[0]);
 
226
 
 
227
    Gawsetmode (&Gwidgets[listwi], FALSE);
 
228
 
 
229
    if (!(txtroot = malloc (sizeof (txtnode_t))))
 
230
        panic (POS, "TXTinit", "txtroot malloc failed");
 
231
    *txtroot = defnode;
 
232
    txtroot->mode = TXT_FULL;
 
233
    txtroot->vo = root;
 
234
    txtroot->path = NULL;
 
235
    txtroot->u.f.t.mwi = arraywi;
 
236
 
 
237
    seenp = Marrayalloc ((long) SEENINCR * SEENSIZE);
 
238
    seeni = 0;
 
239
    seenn = SEENINCR;
 
240
    txton = TRUE;
 
241
}
 
242
 
 
243
static void viewoff (void) {
 
244
    Marrayfree (seenp);
 
245
    seeni = seenn = 0;
 
246
    unfillnode (txtroot);
 
247
    free (txtroot);
 
248
    Gdestroywidget (arraywi);
 
249
    Gdestroywidget (scrollwi);
 
250
    Gdestroywidget (cmdwi);
 
251
    Gdestroywidget (listwi);
 
252
    Gdestroywidget (txtwi);
 
253
    txton = FALSE;
 
254
    txtwi = -1;
 
255
}
 
256
 
 
257
/* LEFTY builtin */
 
258
int TXTask (int argc, lvar_t *argv) {
 
259
    Tobj so, ao;
 
260
    char buf[1200];
 
261
    char *sp, *ap;
 
262
    int mode;
 
263
 
 
264
    if (argc < 2)
 
265
        mode = G_QWSTRING;
 
266
    else {
 
267
        so = argv[1].o;
 
268
        if (T_ISSTRING (so)) {
 
269
            sp = Tgetstring (so);
 
270
            if (Strcmp (sp, "string") == 0)
 
271
                mode = G_QWSTRING;
 
272
            else if (Strcmp (sp, "file") == 0)
 
273
                mode = G_QWFILE;
 
274
            else if (Strcmp (sp, "choice") == 0)
 
275
                mode = G_QWCHOICE;
 
276
        }
 
277
    }
 
278
    if (argc < 3)
 
279
        ap = NULL;
 
280
    else {
 
281
        ao = argv[2].o;
 
282
        if (T_ISSTRING (ao))
 
283
            ap = Tgetstring (ao);
 
284
    }
 
285
    if (Gqueryask (queryws[mode], Tgetstring (argv[0].o), ap, buf, 1200) == 0)
 
286
        rtno = Tstring (buf);
 
287
    else
 
288
        rtno = NULL;
 
289
#ifndef NOQUERYFIX
 
290
    if (mode == G_QWCHOICE) {
 
291
        Gwattr_t data[1];
 
292
 
 
293
        data[0].id = G_ATTRMODE;
 
294
        data[0].u.t = "choice";
 
295
        Gdestroywidget (queryws[mode]);
 
296
        queryws[mode] = Gcreatewidget (-1, G_QUERYWIDGET, 1, &data[0]);
 
297
    }
 
298
#endif
 
299
    return L_SUCCESS;
 
300
}
 
301
 
 
302
void TXTprocess (int wi, char *sp) {
 
303
    Tobj co;
 
304
 
 
305
    src.s = sp;
 
306
    if ((co = Punit (&src)))
 
307
        Eoktorun = TRUE, Eunit (co);
 
308
}
 
309
 
 
310
void TXTupdate (void) {
 
311
    if (!txton)
 
312
        return;
 
313
    if (txtwi == -1)
 
314
        viewon ();
 
315
    seeni = 0;
 
316
    update (txtroot, txtroot->time);
 
317
    txtroot->time = Ttime;
 
318
    Ttime++;
 
319
}
 
320
 
 
321
void TXTtoggle (int wi, void *data) {
 
322
    txtvo2toggle = data;
 
323
    TXTupdate ();
 
324
    txtvo2toggle = NULL;
 
325
}
 
326
 
 
327
/* update is called only for TXT_FULL tables */
 
328
static void update (txtnode_t *pnode, long ptim) {
 
329
    txtnode_t *cnode, *seennode;
 
330
    long ctim;
 
331
    int i;
 
332
 
 
333
    Gawsetmode (&Gwidgets[pnode->u.f.t.mwi], TRUE);
 
334
    if (!pnode->u.f.t.list)
 
335
        buildlist (pnode);
 
336
    else if (ptim < Tgettime (pnode->vo))
 
337
        rebuildlist (pnode);
 
338
    for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n;
 
339
            i++, cnode++) {
 
340
        ctim = cnode->time;
 
341
        if (txtvo2toggle == cnode->vo) {
 
342
            switch (cnode->mode) {
 
343
            case TXT_SEEN:
 
344
                break;
 
345
            case TXT_ABSTRACT:
 
346
                unfillnode (cnode);
 
347
                cnode->mode = TXT_FULL;
 
348
                fillnode (pnode, cnode);
 
349
                break;
 
350
            case TXT_FULL:
 
351
                unfillnode (cnode);
 
352
                cnode->mode = TXT_ABSTRACT;
 
353
                fillnode (pnode, cnode);
 
354
                break;
 
355
            }
 
356
        }
 
357
        if (!(seennode = findseen (cnode)))
 
358
            add2seen (cnode);
 
359
        if (seennode && cnode->mode == TXT_SEEN &&
 
360
                seennode->ko != cnode->u.s.ko) {
 
361
            unfillnode (cnode);
 
362
            cnode->u.s.txtnode = seennode;
 
363
            cnode->u.s.ko = seennode->ko;
 
364
            fillnode (pnode, cnode);
 
365
        } else if (seennode && cnode->mode != TXT_SEEN) {
 
366
            unfillnode (cnode);
 
367
            cnode->mode = TXT_SEEN;
 
368
            cnode->u.s.txtnode = seennode;
 
369
            cnode->u.s.ko = seennode->ko;
 
370
            fillnode (pnode, cnode);
 
371
        } else if (!seennode && cnode->mode == TXT_SEEN) {
 
372
            unfillnode (cnode);
 
373
            cnode->mode = TXT_ABSTRACT;
 
374
            fillnode (pnode, cnode);
 
375
        } else if (cnode->time == -1) {
 
376
            unfillnode (cnode);
 
377
            if (seennode)
 
378
                cnode->u.s.txtnode = seennode;
 
379
            fillnode (pnode, cnode);
 
380
        }
 
381
        if (cnode->ttype == T_TABLE && cnode->mode == TXT_FULL)
 
382
            update (cnode, ctim);
 
383
    }
 
384
    Gaworder (&Gwidgets[pnode->u.f.t.mwi], pnode, orderfunc);
 
385
    Gawsetmode (&Gwidgets[pnode->u.f.t.mwi], FALSE);
 
386
}
 
387
 
 
388
static void buildlist (txtnode_t *pnode) {
 
389
    Tkvindex_t tkvi;
 
390
    Tobj ko, vo;
 
391
    Ttype_t vtype;
 
392
    txtnode_t *cnode;
 
393
 
 
394
    pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
 
395
    if (!(pnode->u.f.t.list =
 
396
            malloc (max (pnode->u.f.t.n, 1) * sizeof (txtnode_t))))
 
397
        panic (POS, "buildlist", "list malloc failed");
 
398
 
 
399
    for (cnode = &pnode->u.f.t.list[0], Tgetfirst (pnode->vo, &tkvi);
 
400
            tkvi.kvp; Tgetnext (&tkvi)) {
 
401
        ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
 
402
        vtype = Tgettype (vo);
 
403
        if (vtype == T_CODE && TCgettype (vo, TCgetnext (vo, TCgetnext (vo,
 
404
                TCgetnext (vo, TCgetfp (vo, 0))))) == C_INTERNAL) {
 
405
            pnode->u.f.t.n--;
 
406
            continue;
 
407
        }
 
408
        *cnode = defnode;
 
409
        cnode->vo = vo;
 
410
        cnode->ko = ko;
 
411
        cnode->ttype = vtype;
 
412
        cnode++;
 
413
    }
 
414
    qsort ((char *) pnode->u.f.t.list, pnode->u.f.t.n,
 
415
            sizeof (txtnode_t), cmp);
 
416
}
 
417
 
 
418
static void rebuildlist (txtnode_t *pnode) {
 
419
    Tkvindex_t tkvi;
 
420
    Tobj ko, vo;
 
421
    Ttype_t vtype;
 
422
    txtnode_t *cnode;
 
423
    txtnode_t *olist, *nlist;
 
424
    txtnode_t tmpnode;
 
425
    int on, nn, i, j, cmpval;
 
426
 
 
427
    olist = pnode->u.f.t.list;
 
428
    on = pnode->u.f.t.n;
 
429
    pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
 
430
    if (!(pnode->u.f.t.list =
 
431
            malloc (max (pnode->u.f.t.n, 1) * sizeof (txtnode_t))))
 
432
        panic (POS, "rebuildlist", "list malloc failed");
 
433
 
 
434
    for (cnode = &pnode->u.f.t.list[0], Tgetfirst (pnode->vo, &tkvi);
 
435
            tkvi.kvp; Tgetnext (&tkvi)) {
 
436
        ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
 
437
        vtype = Tgettype (vo);
 
438
        if (vtype == T_CODE && TCgettype (vo, TCgetnext (vo, TCgetnext (vo,
 
439
                TCgetnext (vo, TCgetfp (vo, 0))))) == C_INTERNAL) {
 
440
            pnode->u.f.t.n--;
 
441
            continue;
 
442
        }
 
443
        *cnode = defnode;
 
444
        cnode->vo = vo;
 
445
        cnode->ko = ko;
 
446
        cnode->ttype = vtype;
 
447
        cnode++;
 
448
    }
 
449
    qsort ((char *) pnode->u.f.t.list, pnode->u.f.t.n, sizeof (txtnode_t), cmp);
 
450
    nlist = pnode->u.f.t.list;
 
451
    nn = pnode->u.f.t.n;
 
452
    for (i = 0, j = 0; i < nn; i++) {
 
453
        while (j < on && (cmpval = cmp (&olist[j], &nlist[i])) < 0)
 
454
            j++;
 
455
        if (j < on && cmpval == 0 && nlist[i].vo == olist[j].vo)
 
456
            tmpnode = olist[j], olist[j] = nlist[i], nlist[i] = tmpnode, j++;
 
457
    }
 
458
    for (j = 0; j < on; j++)
 
459
        unfillnode (&olist[j]);
 
460
    free (olist);
 
461
}
 
462
 
 
463
static void fillnode (txtnode_t *pnode, txtnode_t *cnode) {
 
464
    cnode->time = Ttime;
 
465
    cnode->path = Spath (pnode->path, cnode->ko);
 
466
    switch (cnode->mode) {
 
467
    case TXT_SEEN:
 
468
        cnode->u.s.text = Sseen (cnode->ko, cnode->u.s.txtnode->path);
 
469
        buttondata[3].u.t = cnode->u.s.text;
 
470
        buttondata[4].u.u = (unsigned long) cnode->vo;
 
471
        cnode->u.s.wi = Gcreatewidget (pnode->u.f.t.mwi,
 
472
                G_BUTTONWIDGET, 5, &buttondata[0]);
 
473
        break;
 
474
    case TXT_ABSTRACT:
 
475
        cnode->u.a.text = Sabstract (cnode->ko, cnode->vo);
 
476
        buttondata[3].u.t = cnode->u.a.text;
 
477
        buttondata[4].u.u = (unsigned long) cnode->vo;
 
478
        cnode->u.a.wi = Gcreatewidget (pnode->u.f.t.mwi,
 
479
                G_BUTTONWIDGET, 5, &buttondata[0]);
 
480
        break;
 
481
    case TXT_FULL:
 
482
        if (cnode->ttype == T_TABLE) {
 
483
            cnode->u.f.t.ftext = Stfull (cnode->ko);
 
484
            cnode->u.f.t.ltext = "];";
 
485
            buttondata[3].u.t = cnode->u.f.t.ftext;
 
486
            buttondata[4].u.u = (unsigned long) cnode->vo;
 
487
            cnode->u.f.t.fwi = Gcreatewidget (pnode->u.f.t.mwi,
 
488
                G_BUTTONWIDGET, 5, &buttondata[0]);
 
489
            cnode->u.f.t.mwi = Gcreatewidget (pnode->u.f.t.mwi,
 
490
                    G_ARRAYWIDGET, 2, &arraydata[0]);
 
491
            buttondata[3].u.t = cnode->u.f.t.ltext;
 
492
            buttondata[4].u.u = (unsigned long) cnode->vo;
 
493
            cnode->u.f.t.lwi = Gcreatewidget (pnode->u.f.t.mwi,
 
494
                G_BUTTONWIDGET, 5, &buttondata[0]);
 
495
        } else {
 
496
            cnode->u.f.s.text = Ssfull (cnode->ko, cnode->vo);
 
497
            buttondata[3].u.t = cnode->u.f.s.text;
 
498
            buttondata[4].u.u = (unsigned long) cnode->vo;
 
499
            cnode->u.f.s.wi = Gcreatewidget (pnode->u.f.t.mwi,
 
500
                G_BUTTONWIDGET, 5, &buttondata[0]);
 
501
        }
 
502
        break;
 
503
    }
 
504
}
 
505
 
 
506
static void unfillnode (txtnode_t *cnode) {
 
507
    int i;
 
508
 
 
509
    if (cnode->path)
 
510
        free (cnode->path), cnode->path = NULL;
 
511
    switch (cnode->mode) {
 
512
    case TXT_SEEN:
 
513
        if (cnode->u.s.text)
 
514
            free (cnode->u.s.text);
 
515
        if (cnode->u.s.wi)
 
516
            Gdestroywidget (cnode->u.s.wi);
 
517
        break;
 
518
    case TXT_ABSTRACT:
 
519
        if (cnode->u.a.text)
 
520
            free (cnode->u.a.text);
 
521
        if (cnode->u.a.wi)
 
522
            Gdestroywidget (cnode->u.a.wi);
 
523
        break;
 
524
    case TXT_FULL:
 
525
        if (cnode->ttype == T_TABLE) {
 
526
            for (i = 0; i < cnode->u.f.t.n; i++)
 
527
                unfillnode (&cnode->u.f.t.list[i]);
 
528
            if (cnode->u.f.t.list)
 
529
                free (cnode->u.f.t.list);
 
530
            if (cnode->u.f.t.ftext)
 
531
                free (cnode->u.f.t.ftext);
 
532
            if (cnode->u.f.t.fwi) {
 
533
                Gdestroywidget (cnode->u.f.t.fwi);
 
534
                Gdestroywidget (cnode->u.f.t.mwi);
 
535
                Gdestroywidget (cnode->u.f.t.lwi);
 
536
            }
 
537
        } else {
 
538
            if (cnode->u.f.s.text)
 
539
                free (cnode->u.f.s.text);
 
540
            if (cnode->u.f.s.wi)
 
541
                Gdestroywidget (cnode->u.f.s.wi);
 
542
        }
 
543
        break;
 
544
    }
 
545
    cnode->u.s.text = NULL;
 
546
    cnode->u.s.wi = 0;
 
547
    cnode->u.a.text = NULL;
 
548
    cnode->u.a.wi = 0;
 
549
    cnode->u.f.t.list = NULL;
 
550
    cnode->u.f.t.ftext = NULL;
 
551
    cnode->u.f.t.fwi = 0;
 
552
    cnode->u.f.t.mwi = 0;
 
553
    cnode->u.f.t.lwi = 0;
 
554
    cnode->u.f.s.text = NULL;
 
555
    cnode->u.f.s.wi = 0;
 
556
}
 
557
 
 
558
static int cmp (const void *a, const void *b) {
 
559
    Ttype_t atype, btype;
 
560
    txtnode_t *anode, *bnode;
 
561
    double d1, d2;
 
562
 
 
563
    anode = (txtnode_t *) a, bnode = (txtnode_t *) b;
 
564
    atype = Tgettype (anode->ko), btype = Tgettype (bnode->ko);
 
565
    if (atype != btype)
 
566
        return (atype - btype);
 
567
    if (atype == T_STRING)
 
568
        return Strcmp (Tgetstring (anode->ko), Tgetstring (bnode->ko));
 
569
    if (atype == T_INTEGER)
 
570
        d1 = Tgetinteger (anode->ko), d2 = Tgetinteger (bnode->ko);
 
571
    else if (atype == T_REAL)
 
572
        d1 = Tgetreal (anode->ko), d2 = Tgetreal (bnode->ko);
 
573
    if (d1 < d2)
 
574
        return -1;
 
575
    else if (d1 > d2)
 
576
        return 1;
 
577
    else
 
578
        return 0; /* but this should never happen since keys are unique */
 
579
}
 
580
 
 
581
static txtnode_t *findseen (txtnode_t *cnode) {
 
582
    int i;
 
583
 
 
584
    for (i = 0; i < seeni; i++)
 
585
        if (seenp[i]->vo == cnode->vo)
 
586
            return seenp[i];
 
587
    return NULL;
 
588
}
 
589
 
 
590
static void add2seen (txtnode_t *cnode) {
 
591
    if (seeni >= seenn) {
 
592
        seenp = Marraygrow (seenp, (long) (seenn + SEENINCR) * SEENSIZE);
 
593
        seenn += SEENINCR;
 
594
    }
 
595
    seenp[seeni++] = cnode;
 
596
}
 
597
 
 
598
static void orderfunc (void *data, Gawdata_t *dp) {
 
599
    txtnode_t *pnode, *cnode;
 
600
    int i;
 
601
 
 
602
    pnode = data;
 
603
    dp->cj = 0;
 
604
    for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n; i++, cnode++)
 
605
        switch (cnode->mode) {
 
606
        case TXT_SEEN:
 
607
            dp->carray[dp->cj++].w = Gwidgets[cnode->u.s.wi].w;
 
608
            break;
 
609
        case TXT_ABSTRACT:
 
610
            dp->carray[dp->cj++].w = Gwidgets[cnode->u.a.wi].w;
 
611
            break;
 
612
        case TXT_FULL:
 
613
            if (cnode->ttype == T_TABLE) {
 
614
                dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.fwi].w;
 
615
                dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.mwi].w;
 
616
                dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.lwi].w;
 
617
            } else
 
618
                dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.s.wi].w;
 
619
            break;
 
620
        }
 
621
}
 
622
 
 
623
static void coordsfunc (int wi, Gawdata_t *dp) {
 
624
    Gawcarray_t *cp;
 
625
    int cox, coy;
 
626
    int ci;
 
627
 
 
628
    cox = coy = 0;
 
629
    for (ci = 0; ci < dp->cj; ci++) {
 
630
        cp = &dp->carray[ci];
 
631
        if (!cp->flag)
 
632
            continue;
 
633
        cp->ox = cox, cp->oy = coy;
 
634
        cp->sx = dp->sx - 2 * cp->bs;
 
635
        coy += cp->sy + 2 * cp->bs;
 
636
    }
 
637
    dp->sy = coy;
 
638
}
 
639
 
 
640
static void coords2func (int wi, Gawdata_t *dp) {
 
641
    Gawcarray_t *cp;
 
642
    int cox, coy;
 
643
    int ci, cj;
 
644
 
 
645
    cox = coy = 0;
 
646
    for (ci = 0, cj = 0; ci < dp->cj; ci++) {
 
647
        cp = &dp->carray[ci];
 
648
        if (!cp->flag)
 
649
            continue;
 
650
        cp->ox = cox, cp->oy = coy;
 
651
        cj++;
 
652
        cp->sx = dp->sx - 2 * cp->bs;
 
653
        if (cj == 2)
 
654
            cp->sy = dp->sy - coy - 2 * cp->bs;
 
655
        coy += cp->sy + 2 * cp->bs;
 
656
    }
 
657
}