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