1/* struct::tree - critcl - layer 1 declarations
2 * (b) Node operations.
3 */
4
5#include <tn.h>
6#include <util.h>
7
8/* .................................................. */
9
10static void extend_children  (TNPtr n);
11static int  fill_descendants (TNPtr n, int lc, Tcl_Obj** lv, int at);
12
13/* .................................................. */
14
15TNPtr
16tn_new (TPtr t, CONST char* name)
17{
18    TNPtr n = ALLOC (TN);
19    int	  new;
20
21    n->name = Tcl_NewStringObj(name, -1);
22    Tcl_IncrRefCount (n->name);
23    tn_shimmer (n->name, n);
24
25    if (Tcl_FindHashEntry (&t->node, name) != NULL) {
26	Tcl_Panic ("struct::tree(c) tn_new - tried to use duplicate name for new node");
27    }
28
29    n->he = Tcl_CreateHashEntry(&t->node, name, &new);
30    Tcl_SetHashValue (n->he, (ClientData) n);
31
32    n->tree     = t;
33    n->nextleaf = NULL;
34    n->prevleaf = NULL;
35    n->nextnode = NULL;
36    n->prevnode = NULL;
37
38    tn_node (n);
39    tn_leaf (n);
40
41    n->parent	   = NULL;
42    n->child	   = NULL;
43    n->maxchildren = 0;
44    n->nchildren   = 0;
45    n->left	   = NULL;
46    n->right	   = NULL;
47    n->attr	   = NULL;
48
49    n->index	   = -1;
50    n->depth	   = -1;
51    n->height	   = -1;
52    n->desc	   = -1;
53
54    return n;
55}
56
57void
58tn_delete (TNPtr n)
59{
60    T* t = n->tree;
61
62    /* We assume that the node either has no parent or siblings anymore,
63     * or that their presence does not matter. The node may still have
64     * children. They are deleted recursively. That is the situation
65     * where the parent/sibling information does not matter anymore, and
66     * can be ignored.
67     */
68
69    tn_notleaf (n);
70    tn_notnode (n);
71
72    Tcl_DecrRefCount	(n->name); n->name = NULL;
73    Tcl_DeleteHashEntry (n->he);   n->he   = NULL;
74
75    if (n->child) {
76	int i;
77
78	for (i = 0; i < n->nchildren; i++) {
79	    ASSERT_BOUNDS (i, n->nchildren);
80
81	    tn_delete (n->child [i]);
82	    n->child [i] = NULL;
83	}
84	ckfree ((char*) n->child);
85
86	n->child       = NULL;
87	n->nchildren   = 0;
88	n->maxchildren = 0;
89    }
90
91    if (n->attr) {
92	Tcl_HashSearch	hs;
93	Tcl_HashEntry*	he;
94
95	for(he = Tcl_FirstHashEntry(n->attr, &hs);
96	    he != NULL;
97	    he = Tcl_NextHashEntry(&hs)) {
98	    Tcl_DecrRefCount ((Tcl_Obj*) Tcl_GetHashValue(he));
99	}
100	Tcl_DeleteHashTable(n->attr);
101	ckfree ((char*) n->attr);
102	n->attr = NULL;
103    }
104
105    ckfree ((char*) n);
106}
107
108/* .................................................. */
109
110void
111tn_node (TNPtr n)
112{
113    TPtr  t	= n->tree;
114    TNPtr first = t->nodes;
115
116    t->nnodes ++;
117
118    n->nextnode = first;
119    n->prevnode = NULL;
120    t->nodes	= n;
121
122    if (!first) return;
123    first->prevnode = n;
124}
125
126void
127tn_notnode (TNPtr n)
128{
129    T* t = n->tree;
130
131    if ((t->nodes == n) || n->prevnode || n->nextnode) {
132	if (t->nodes == n) {
133	    t->nodes = n->nextnode;
134	}
135	if (n->prevnode) {
136	    n->prevnode->nextnode = n->nextnode;
137	}
138	if (n->nextnode) {
139	    n->nextnode->prevnode = n->prevnode;
140	}
141	n->prevnode = NULL;
142	n->nextnode = NULL;
143	t->nnodes --;
144    }
145}
146
147void
148tn_leaf (TNPtr n)
149{
150    TPtr  t	= n->tree;
151    TNPtr first = t->leaves;
152
153    if ((t->leaves == n) || n->prevleaf || n->nextleaf) {
154	/* The node is already a leaf */
155	return;
156    }
157
158    /* Now make the non-leaf it a leaf */
159
160    t->nleaves ++;
161
162    n->nextleaf = first;
163    n->prevleaf = NULL;
164    t->leaves	= n;
165
166    if (!first) return;
167    first->prevleaf = n;
168}
169
170void
171tn_notleaf (TNPtr n)
172{
173    T* t = n->tree;
174
175    if ((t->leaves == n) || n->prevleaf || n->nextleaf) {
176	if (t->leaves == n) {
177	    t->leaves = n->nextleaf;
178	}
179	if (n->prevleaf) {
180	    n->prevleaf->nextleaf = n->nextleaf;
181	}
182	if (n->nextleaf) {
183	    n->nextleaf->prevleaf = n->prevleaf;
184	}
185	n->prevleaf = NULL;
186	n->nextleaf = NULL;
187	t->nleaves --;
188    }
189}
190
191/* .................................................. */
192
193void
194tn_structure (TNPtr n, int depth)
195{
196    n->depth = depth;
197    n->desc  = n->nchildren; /* #direct children */
198
199    depth ++;
200
201    if (n->nchildren) {
202	int i, maxh, h;
203
204	for (i = 0, maxh = -1;
205	     i < n->nchildren;
206	     i++) {
207	    ASSERT_BOUNDS (i, n->nchildren);
208
209	    tn_structure (n->child [i], depth);
210
211	    h = n->child [i]->height;
212
213	    if (h > maxh) {
214		maxh = h;
215	    }
216	}
217
218	n->height = maxh + 1;
219    } else {
220	n->height = 0;
221    }
222
223    /* Extend parent with our descendants. Do not count
224     * ourselves. This is already done in the parent through
225     * the 'direct children' clause above at the beginning
226     * of the function.
227     */
228
229    if (n->parent) {
230	n->parent->desc += n->desc;
231    }
232}
233
234/* .................................................. */
235
236void
237tn_detach (TNPtr n)
238{
239    /* Detaches the node from the tree by removing it from its parent
240     * node. The sibling relationships are squashed as well, and the
241     * index information for all right siblings is adjusted. The node
242     * does retain its children. After this function is called the node
243     * and its children are ready for tn_delete'. Or reinsertion in a
244     * different place.
245   */
246
247    TNPtr p = n->parent;
248
249    if (p->nchildren == 1) {
250	/* This node is the last node in its parent. We can release the
251	 * whole array of children now, and declare the parent to be a
252	 * leaf again. There is no need to touch the siblings references,
253	 * we know that they are NULL.
254	 */
255
256	ckfree ((char*) p->child);
257	p->child       = NULL;
258	p->maxchildren = 0;
259	p->nchildren   = 0;
260
261	tn_leaf (p);
262
263    } else {
264	/* The node is somewhere in the array of children of its
265     * parent. We know the exact location, through 'index'. All
266     * siblings to the right are moved down one slot, and their index
267     * is adjusted in the same way. This is an O(n)
268     * operation. Afterward we adjust the left/right references of the
269     * node's siblings, if there are any, and reset the node's sibling
270     * references as well.
271     */
272
273	int i;
274	for (i = n->index; i < (p->nchildren-1); i++) {
275
276	    ASSERT_BOUNDS (i,	p->nchildren);
277	    ASSERT_BOUNDS (i+1, p->nchildren);
278
279	    p->child [i] = p->child [i+1];
280	    p->child [i]->index --;
281	}
282	p->nchildren --;
283	/* Note regarding the decrement: As the node was _not_ the last
284	 * child we know that the condition 'nchildren > 0' still holds, and
285	 * that there is no need to free the 'child' array.
286     */
287
288	if (n->left) {
289	    n->left->right = n->right;
290	}
291	if (n->right) {
292	    n->right->left = n->left;
293	}
294
295	n->left	  = NULL;
296	n->right  = NULL;
297    }
298
299    n->parent = NULL;
300    n->tree->structure = 0;
301}
302
303TNPtr*
304tn_detachmany (TNPtr n, int len)
305{
306    /* Detaches the node n and its 'len -1' right siblings from the tree
307     * by removing them from their parent node. In toto 'len' nodes are
308     * removed. The sibling relationships are squashed as well, and the
309     * index information for all right siblings is adjusted. The nodes
310     * retain their children. After this function is called thes node
311     * and their children are ready for tn_delete'. Or reinsertion in a
312     * different place.
313   *
314   * The operation fails with a panic if there are less children we
315   * can cut than requested. It also panics when trying to cut
316   * nothing.
317   *
318   * Note: This function does not reset the parent reference in the
319   * cut nodes.
320   */
321
322    TNPtr* ch;
323    TNPtr  p   = n->parent;
324    int	   at  = n->index;
325    int	   end = at + len;
326
327    ASSERT (end <= p->nchildren, "tn_detachmany - tried to cut too many children");
328    ASSERT (len > 0,		 "tn_detachmany - tried to cut nothing");
329
330    if ((at == 0) && (end == p->nchildren)) {
331	/* All children are taken. There is no need to copy anything, we
332	 * can use the whole array, and reset the other information in the
333	 * parent. Note that the condition above implies 'at == 0'. The
334	 * parent node becomes a leaf again.
335	 */
336
337	ch = p->child;
338
339	p->child       = NULL;
340	p->maxchildren = 0;
341	p->nchildren   = 0;
342
343	tn_leaf (p);
344
345    } else {
346	/* Copies the cut nodes into a result array. Shifts the right
347     * siblings down, if there are any.
348     */
349
350	int i, k;
351
352	ch = NALLOC (len, TNPtr);
353
354    /* Examples. We always have nchildren = 10.
355     *
356     * _______________________________
357     * at  = 2, len = 3.
358     *
359     * 01 234 56789 i = 0, k = 2
360     *	  012	    i = 3, k = 5
361     *
362     * 01 234 56789 i = 2, k = 5
363     * 01 567 89    i = 7, k = 10
364     *
365     * _______________________________
366     * at  = 7, len = 3.
367     *
368     * 0123456 789 i = 0, k = 7
369     *	       012 i = 3, k = 10
370     *
371     * 0123456 789 i = 7, k = 10
372     * 0123456	   nothing
373     *
374     * _______________________________
375     * at  = 6, len = 3.
376     *
377     * 012345 678 9 i = 0, k = 6
378     *	      012   i = 3, k = 9
379     *
380     * 012345 678 9 i = 6, k = 9
381     * 012345 9	    i = 7, k = 10
382     *
383     * _______________________________
384     * at  = 6, len = 1.
385     *
386     * 012345 6 789 i = 0, k = 6
387     *	      0	    i = 1, k = 7
388     *
389     * 012345 6 789 i = 6, k = 7
390     * 012345 7 89  i = 9, k = 10
391     */
392
393	for (i = 0, k = at; i < len; i++, k++) {
394
395	    ASSERT_BOUNDS (k, p->nchildren);
396	    ASSERT_BOUNDS (i, len);
397
398	    ch [i] = p->child [k];
399	}
400
401	for (i = at, k = end; k < p->nchildren; i++, k++) {
402
403	    ASSERT_BOUNDS (k, p->nchildren);
404	    ASSERT_BOUNDS (i, p->nchildren);
405
406	    p->child [i] = p->child [k];
407	    p->child [i]->index -= len;
408	}
409
410	p->nchildren -= len;
411
412	if (ch [0]->left) {
413	    ch [0]->left->right = ch [len-1]->right;
414	}
415	if (ch [len-1]->right) {
416	    ch [len-1]->right->left = ch [0]->left;
417	}
418
419	ch [0]->left	  = NULL;
420	ch [len-1]->right = NULL;
421    }
422
423    n->tree->structure = 0;
424    return ch;
425}
426
427TNPtr*
428tn_detachchildren (TNPtr n, int* nc)
429{
430    TNPtr* children = n->child;
431
432    *nc = n->nchildren;
433
434    n->child	   = NULL;
435    n->maxchildren = 0;
436    n->nchildren   = 0;
437
438    tn_leaf (n);
439    return children;
440}
441
442/* .................................................. */
443
444void
445tn_append (TNPtr p, TNPtr n)
446{
447    /* Appending is O(1) */
448
449    /* The node chosen as parent cannot be a leaf (anymore) */
450
451    int at = p->nchildren;
452
453    tn_notleaf (p);
454
455  /* Allocate/Extend child array as needed */
456
457    p->nchildren ++;
458    extend_children (p);
459
460  /* Link the node into the parent and to its left sibling, if
461   * any. This overwrites any existing relationships. Make sure
462   * that the node n is either new or was cut before.
463   */
464
465    ASSERT_BOUNDS (at, p->nchildren);
466
467    p->child [at] = n;
468
469    n->parent = p;
470    n->index  = at;
471    n->right  = NULL;
472
473    if (at > 0) {
474	TNPtr sib;
475
476	ASSERT_BOUNDS (at-1, p->nchildren);
477
478	sib = p->child [at-1];
479	n->left	   = sib;
480	sib->right = n;
481    }
482
483    p->tree->structure = 0;
484}
485
486void
487tn_appendmany (TNPtr p, int nc, TNPtr* nv)
488{
489    int i;
490
491    /* Appending is O(1) */
492
493    /* The node chosen as parent cannot be a leaf (anymore) */
494
495    int at = p->nchildren;
496
497    tn_notleaf (p);
498
499    /* Allocate/Extend child array as needed */
500
501    p->nchildren += nc;
502    extend_children (p);
503
504    /* Link the nodes into the parent and to their left siblings, if
505     * any. This overwrites any existing relationships. Make sure that
506     * the nodes are either new or were cut before.
507     */
508
509    for (i = 0; i < nc; i++, at++) {
510
511	ASSERT_BOUNDS (at, p->nchildren);
512	ASSERT_BOUNDS (i, nc);
513
514	p->child [at] = nv [i];
515
516	nv [i]->parent = p;
517	nv [i]->index  = at;
518	nv [i]->right  = NULL;
519
520	if (at > 0) {
521	    TNPtr sib;
522
523	    ASSERT_BOUNDS (at, p->nchildren);
524
525	    sib = p->child [at-1];
526	    nv [i]->left = sib;
527	    sib->right	 = nv [i];
528	}
529    }
530
531    p->tree->structure = 0;
532}
533
534/* .................................................. */
535
536void
537tn_insert (TNPtr p, int at, TNPtr n)
538{
539    int i, k;
540
541    if (at >= p->nchildren) {
542	tn_append (p, n);
543	return;
544    }
545
546    /* Insertion at beginning, or somewhere in the middle */
547
548    if (at < 0) {
549	at = 0;
550    }
551
552    /* The node chosen as parent cannot be a leaf */
553    /* anymore */
554
555    tn_notleaf (p);
556
557    /* Allocate/Extend child array as needed */
558
559    p->nchildren ++;
560    extend_children (p);
561
562    /* Link the node into the parent and to its left and right siblings,
563     * if any. This overwrites any existing relationships. Make sure
564     * that the node n is either new or was cut before.
565     *
566     * Shift all nodes at 'at' and to the right one slot up.
567     * Note that 'nchildren' is incremented already.
568     */
569
570    for (i = p->nchildren-1, k = i-1; i > at; i--, k--) {
571
572	ASSERT_BOUNDS (i, p->nchildren);
573	ASSERT_BOUNDS (k, p->nchildren);
574
575	p->child [i] = p->child [k];
576	p->child [i]->index ++;
577    }
578
579    p->child [at] = n;
580
581    n->parent = p;
582    n->index  = at;
583
584    /* We have to have a right sibling, otherwise it would have been
585     * appending. We may have a left sibling.
586     */
587
588    ASSERT_BOUNDS (at+1, p->nchildren);
589
590    n->right = p->child [at+1];
591    p->child [at+1]->left = n;
592
593    if (at == 0) {
594	n->left = NULL;
595    } else {
596	ASSERT_BOUNDS (at-1, p->nchildren);
597
598	n->left	       = p->child [at-1];
599	p->child [at-1]->right = n;
600    }
601
602    p->tree->structure = 0;
603}
604
605void
606tn_insertmany (TNPtr p, int at, int nc, TNPtr* nv)
607{
608    int i, k;
609    if (at >= p->nchildren) {
610	tn_appendmany (p, nc, nv);
611	return;
612    }
613
614    if (at < 0) {
615	at = 0;
616    }
617
618    /* The node chosen as parent cannot be a leaf */
619    /* anymore */
620
621    tn_notleaf (p);
622
623    /* Allocate/Extend child array as needed */
624
625    p->nchildren += nc;
626    extend_children (p);
627
628    /* Link the node into the parent and to its left and right siblings,
629     * if any. This overwrites any existing relationships. Make sure
630     * that the node n is either new or was cut before.
631     *
632     * Shift all nodes at 'at' and to the right one slot up.
633     * Note that 'nchildren' is incremented already.
634     */
635
636    for (i = p->nchildren-1, k = i-nc; k >= at; i--, k--) {
637
638	ASSERT_BOUNDS (i, p->nchildren);
639	ASSERT_BOUNDS (k, p->nchildren);
640
641	p->child [i] = p->child [k];
642	p->child [i]->index += nc;
643    }
644
645    for (i = 0, k = at; i < nc; i++, k++) {
646
647	ASSERT_BOUNDS (i, nc);
648	ASSERT_BOUNDS (k, p->nchildren);
649
650	nv [i]->parent = p;
651	nv [i]->index  = k;
652	p->child [k]   = nv [i];
653    }
654
655    for (i = 0, k = at; i < nc; i++, k++) {
656	if (k > 0) {
657	    ASSERT_BOUNDS (k,	p->nchildren);
658	    ASSERT_BOUNDS (k-1, p->nchildren);
659
660	    p->child [k]->left	  = p->child [k-1];
661	    p->child [k-1]->right = p->child [k];
662	}
663
664	if (k < (p->nchildren-1)) {
665	    ASSERT_BOUNDS (k,	p->nchildren);
666	    ASSERT_BOUNDS (k+1, p->nchildren);
667
668	    p->child [k]->right	 = p->child [k+1];
669	    p->child [k+1]->left = p->child [k];
670	}
671    }
672
673    p->tree->structure = 0;
674}
675
676/* .................................................. */
677
678void
679tn_cut (TNPtr n)
680{
681    TNPtr p  = n->parent; /* Remember the location of n in its */
682    int at = n->index;	/* parent, this is the point there its
683			 * children are re-inserted */
684    int	 nc;
685    TNPtr* nv;
686
687    nv = tn_detachchildren (n, &nc);
688    tn_detach (n);
689
690    tn_insertmany (p, at, nc, nv);
691    ckfree ((char*) nv);
692
693    tn_delete (n);
694}
695
696TNPtr
697tn_dup (TPtr dst, TNPtr src)
698{
699    TNPtr dstn;
700
701    dstn = tn_new (dst, Tcl_GetString (src->name));
702
703    if (src->attr) {
704	int i, new;
705	Tcl_HashSearch hs;
706	Tcl_HashEntry* he;
707	Tcl_HashEntry* dhe;
708	CONST char*    key;
709	Tcl_Obj*       val;
710
711	dstn->attr = ALLOC (Tcl_HashTable);
712	Tcl_InitHashTable(dstn->attr, TCL_STRING_KEYS);
713
714	for(i = 0, he = Tcl_FirstHashEntry(src->attr, &hs);
715	    he != NULL;
716	    he = Tcl_NextHashEntry(&hs), i++) {
717
718	    key = Tcl_GetHashKey (src->attr, he);
719	    val = (Tcl_Obj*) Tcl_GetHashValue(he);
720
721	    dhe = Tcl_CreateHashEntry(dstn->attr, key, &new);
722
723	    Tcl_IncrRefCount (val);
724	    Tcl_SetHashValue (dhe, (ClientData) val);
725	}
726    }
727
728    if (src->nchildren) {
729	int i;
730
731	dstn->child	  = NALLOC (src->nchildren, TNPtr);
732	dstn->maxchildren = src->nchildren;
733	dstn->nchildren	  = 0;
734
735	for (i = 0; i < src->nchildren; i++) {
736
737	    ASSERT_BOUNDS (i, src->nchildren);
738
739	    tn_append (dstn,
740		       tn_dup (dst, src->child [i]));
741	}
742    }
743
744    return dstn;
745}
746
747/* .................................................. */
748
749void
750tn_set_attr (TNPtr n, Tcl_Interp* interp, Tcl_Obj* dict)
751{
752    Tcl_HashEntry* he;
753    CONST char*	   key;
754    Tcl_Obj*	   val;
755    int		   new, i;
756    int		   listc;
757    Tcl_Obj**	   listv;
758
759    if (Tcl_ListObjGetElements (interp, dict, &listc, &listv) != TCL_OK) {
760	Tcl_Panic ("Malformed nodes attributes, snuck through validation of serialization.");
761    }
762
763    if (!listc) {
764	return;
765    }
766
767    tn_extend_attr (n);
768
769    for (i = 0; i < listc; i+= 2) {
770
771	ASSERT_BOUNDS (i,   listc);
772	ASSERT_BOUNDS (i+1, listc);
773
774	key = Tcl_GetString (listv [i]);
775	val = listv [i+1];
776
777	he = Tcl_CreateHashEntry(n->attr, key, &new);
778
779	Tcl_IncrRefCount (val);
780	Tcl_SetHashValue (he, (ClientData) val);
781    }
782}
783
784/* .................................................. */
785
786void
787tn_extend_attr (TNPtr n)
788{
789    if (n->attr != NULL) {
790	return;
791    }
792
793    n->attr = ALLOC (Tcl_HashTable);
794    Tcl_InitHashTable(n->attr, TCL_STRING_KEYS);
795}
796
797/* .................................................. */
798
799int
800tn_depth (TNPtr n)
801{
802    if (!n->tree->structure) {
803	t_structure (n->tree);
804    }
805    return n->depth;
806}
807
808int
809tn_height (TNPtr n)
810{
811    if (!n->tree->structure) {
812	t_structure (n->tree);
813    }
814    return n->height;
815}
816
817int
818tn_ndescendants (TNPtr n)
819{
820    if (n == n->tree->root) {
821	/* For the root we do not need to know the structure data of the
822	 * tree to determine the number of descendants. It is the number
823	 * of nodes minus one, i.e. all nodes except the root.
824	 */
825
826	return n->tree->nnodes - 1;
827
828    } else if (!n->nchildren) {
829	/* If the node has no direct children we know there are no
830	 * descendants as well
831	 */
832
833	return 0;
834
835    } else if (!n->tree->structure) {
836	t_structure (n->tree);
837    }
838
839    return n->desc;
840}
841
842Tcl_Obj**
843tn_getdescendants (TNPtr n, int* nc)
844{
845    int	      end;
846    int	      lc = tn_ndescendants (n);
847    Tcl_Obj** lv;
848
849    *nc = lc;
850
851    if (lc == 0) {
852	return NULL;
853    }
854
855    lv	= NALLOC (lc, Tcl_Obj*);
856    end = fill_descendants (n, lc, lv, 0);
857
858    ASSERT (end == lc, "Bad list of descendants");
859    return lv;
860}
861
862Tcl_Obj**
863tn_getchildren (TNPtr n, int* nc)
864{
865    if (!n->nchildren) {
866	*nc = 0;
867	return NULL;
868    } else {
869	int	  i;
870	Tcl_Obj** lv;
871
872	*nc = n->nchildren;
873	lv  = NALLOC (n->nchildren, Tcl_Obj*);
874
875	for (i = 0; i < n->nchildren; i++) {
876
877	    ASSERT_BOUNDS (i, n->nchildren);
878
879	    lv [i] = n->child [i]->name;
880	}
881
882	return lv;
883    }
884}
885
886int
887tn_filternodes (int* nc,   Tcl_Obj** nv,
888		int  cmdc, Tcl_Obj** cmdv,
889		Tcl_Obj* tree, Tcl_Interp* interp)
890{
891    int i;
892    int	      ec;
893    Tcl_Obj** ev;
894
895    if (cmdc && (*nc > 0)) {
896	/* Run the filter command over all nodes in the list.
897	 * Keep only the nodes passing the filter in the list.
898	 */
899
900	int	  lc = *nc;
901
902	int src, dst, res, flag;
903
904	/* Set up the command vector for the callback.
905	 * Two placeholders for tree and node arguments.
906	 */
907
908	ec = cmdc + 2;
909	ev = NALLOC (ec, Tcl_Obj*);
910
911	for (i = 0; i < cmdc; i++) {
912	    ASSERT_BOUNDS (i, ec);
913
914	    ev [i] = cmdv [i];
915	    Tcl_IncrRefCount (ev [i]);
916	}
917	ASSERT_BOUNDS (cmdc, ec);
918
919	ev [cmdc] = tree; /* Tree */
920	Tcl_IncrRefCount (ev [cmdc]);
921
922	/* Run the callback on each element of the list */
923
924	for (src = 0, dst = 0;
925	     src < lc;
926	     src++) {
927
928	    /* Fill the placeholders */
929
930	    ASSERT_BOUNDS (cmdc+1, ec);
931	    ASSERT_BOUNDS (src, lc);
932
933	    ev [cmdc+1] = nv [src]; /* Node */
934
935	    /* Run the callback */
936
937	    Tcl_IncrRefCount (ev [cmdc+1]);
938
939	    res = Tcl_EvalObjv (interp, ec, ev, 0);
940
941	    Tcl_DecrRefCount (ev [cmdc+1]);
942
943	    /* Process the result */
944
945	    if (res != TCL_OK) {
946		goto abort;
947	    }
948
949	    if (Tcl_GetBooleanFromObj (interp,
950				       Tcl_GetObjResult (interp),
951				       &flag) != TCL_OK) {
952		goto abort;
953	    }
954
955	    /* Result is valid, use this decide retain/write over */
956
957	    if (!flag)
958		continue;
959
960	    ASSERT_BOUNDS (dst, lc);
961	    ASSERT_BOUNDS (src, lc);
962
963	    nv [dst] = nv [src];
964	    dst++;
965	}
966
967	/* Cleanup state */
968
969	Tcl_ResetResult (interp);
970
971	for (i = 0; i < cmdc; i++) {
972	    ASSERT_BOUNDS (i, ec);
973	    Tcl_DecrRefCount (ev [i]);
974	}
975	ASSERT_BOUNDS (cmdc, ec);
976	Tcl_DecrRefCount (ev [cmdc]); /* Tree */
977
978	ckfree ((char*) ev);
979
980	*nc = dst;
981    }
982
983    return TCL_OK;
984
985 abort:
986    /* We do not reset the interp result. It either contains
987     * the non-boolean result, or the error message
988     */
989
990    for (i = 0; i < cmdc; i++) {
991	ASSERT_BOUNDS (i, ec);
992	Tcl_DecrRefCount (ev [i]);
993    }
994    ASSERT_BOUNDS (cmdc, ec);
995    Tcl_DecrRefCount (ev [cmdc]); /* Tree */
996
997    ckfree ((char*) ev);
998    return TCL_ERROR;
999}
1000
1001/* .................................................. */
1002
1003int
1004tn_isancestorof (TNPtr na, TNPtr nb)
1005{
1006    /* True <=> a is ancestor of b */
1007
1008    for (nb = nb->parent; nb != NULL; ) {
1009	if (na == nb) {
1010	    return 1;
1011	}
1012	nb = nb->parent;
1013    }
1014
1015    return 0;
1016}
1017
1018/* .................................................. */
1019
1020Tcl_Obj*
1021tn_get_attr (TNPtr tdn, Tcl_Obj* empty)
1022{
1023    int		   i;
1024    Tcl_Obj*	   res;
1025    int		   listc;
1026    Tcl_Obj**	   listv;
1027    Tcl_HashSearch hs;
1028    Tcl_HashEntry* he;
1029    CONST char*	   key;
1030
1031    if ((tdn->attr == NULL) || (tdn->attr->numEntries == 0)) {
1032	return empty;
1033    }
1034
1035    listc = 2 * tdn->attr->numEntries;
1036    listv = NALLOC (listc, Tcl_Obj*);
1037
1038    for(i = 0, he = Tcl_FirstHashEntry(tdn->attr, &hs);
1039	he != NULL;
1040	he = Tcl_NextHashEntry(&hs)) {
1041
1042	key = Tcl_GetHashKey (tdn->attr, he);
1043
1044	ASSERT_BOUNDS (i,   listc);
1045	ASSERT_BOUNDS (i+1, listc);
1046
1047	listv [i] = Tcl_NewStringObj (key, -1);	     i++;
1048	listv [i] = (Tcl_Obj*) Tcl_GetHashValue(he); i++;
1049    }
1050
1051    res = Tcl_NewListObj (listc, listv);
1052    ckfree ((char*) listv);
1053    return res;
1054}
1055
1056int
1057tn_serialize (TNPtr tdn, int listc, Tcl_Obj** listv, int at, int parent, Tcl_Obj* empty)
1058{
1059    int self = at;
1060
1061    ASSERT_BOUNDS (at+0, listc);
1062    ASSERT_BOUNDS (at+1, listc);
1063    ASSERT_BOUNDS (at+2, listc);
1064
1065    listv [at++] = tdn->name;
1066    listv [at++] = (parent < 0 ? empty : Tcl_NewIntObj (parent));
1067    listv [at++] = tn_get_attr (tdn, empty);
1068
1069    if (tdn->nchildren) {
1070	int i;
1071	for (i = 0; i < tdn->nchildren; i++) {
1072	    at = tn_serialize (tdn->child [i], listc, listv, at, self, empty);
1073	}
1074    }
1075
1076    return at;
1077}
1078
1079/* .................................................. */static int
1080fill_descendants (TNPtr n, int lc, Tcl_Obj** lv, int at)
1081{
1082    /* The descendants of the root are simply all nodes except the root
1083     * itself. That is easy to retrieve.
1084   */
1085
1086    if (n == n->tree->root) {
1087	TNPtr iter;
1088
1089	for (iter = n->tree->nodes;
1090	     iter != NULL;
1091	     iter = iter->nextnode) {
1092
1093	    /* Skip the root node, it is not a descendant! */
1094	    if (iter == n) continue;
1095
1096	    ASSERT_BOUNDS (at, lc);
1097
1098	    lv [at] = iter->name;
1099	    at++;
1100	}
1101    } else if (n->child) {
1102	int   i;
1103	TNPtr c;
1104
1105	for (i = 0; i < n->nchildren; i++) {
1106	    c = n->child [i];
1107
1108	    ASSERT_BOUNDS (at, lc);
1109	    ASSERT_BOUNDS (i,  n->nchildren);
1110
1111	    lv [at] = c->name;
1112	    at++;
1113
1114	    at = fill_descendants (c, lc, lv, at);
1115	}
1116    }
1117
1118    return at;
1119}
1120
1121static void
1122extend_children (TNPtr n)
1123{
1124    if (n->nchildren > n->maxchildren) {
1125	if (n->child == NULL) {
1126	    n->child = NALLOC (n->nchildren, TNPtr);
1127	} else {
1128	    int	   nc  = 2 * n->nchildren;
1129	    TNPtr* new = (TNPtr*) attemptckrealloc ((char*) n->child,
1130						    nc * sizeof (TNPtr));
1131	    if (new == NULL) {
1132		nc  = n->nchildren;
1133		new = (TNPtr*) ckrealloc ((char*) n->child, nc * sizeof (TNPtr));
1134	    }
1135	    n->child	   = new;
1136	    n->maxchildren = nc;
1137	}
1138    }
1139}
1140
1141/*
1142 * Local Variables:
1143 * mode: c
1144 * c-basic-offset: 4
1145 * fill-column: 78
1146 * End:
1147 */
1148