?? tktextbtree.c
字號(hào):
} while (nodePtr->level > 0) { nodePtr = nodePtr->children.nodePtr; } return nodePtr->children.linePtr;}/* *---------------------------------------------------------------------- * * TkBTreePreviousLine -- * * Given an existing line in a B-tree, this procedure locates the * previous line in the B-tree. This procedure is used for scanning * through the B-tree in the reverse direction. * * Results: * The return value is a pointer to the line that immediately * preceeds linePtr, or NULL if there is no such line. * * Side effects: * None. * *---------------------------------------------------------------------- */TkTextLine *TkBTreePreviousLine(linePtr) register TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */{ register Node *nodePtr; register Node *node2Ptr; register TkTextLine *prevPtr; /* * Find the line under this node just before the starting line. */ prevPtr = linePtr->parentPtr->children.linePtr; /* First line at leaf */ while (prevPtr != linePtr) { if (prevPtr->nextPtr == linePtr) { return prevPtr; } prevPtr = prevPtr->nextPtr; if (prevPtr == (TkTextLine *) NULL) { panic("TkBTreePreviousLine ran out of lines"); } } /* * This was the first line associated with the particular parent node. * Search up the tree for the previous node, then search down from that * node to find its last line. */ for (nodePtr = linePtr->parentPtr; ; nodePtr = nodePtr->parentPtr) { if (nodePtr == (Node *) NULL || nodePtr->parentPtr == (Node *) NULL) { return (TkTextLine *) NULL; } if (nodePtr != nodePtr->parentPtr->children.nodePtr) { break; } } for (node2Ptr = nodePtr->parentPtr->children.nodePtr; ; node2Ptr = node2Ptr->children.nodePtr) { while (node2Ptr->nextPtr != nodePtr) { node2Ptr = node2Ptr->nextPtr; } if (node2Ptr->level == 0) { break; } nodePtr = (Node *)NULL; } for (prevPtr = node2Ptr->children.linePtr ; ; prevPtr = prevPtr->nextPtr) { if (prevPtr->nextPtr == (TkTextLine *) NULL) { return prevPtr; } }}/* *---------------------------------------------------------------------- * * TkBTreeLineIndex -- * * Given a pointer to a line in a B-tree, return the numerical * index of that line. * * Results: * The result is the index of linePtr within the tree, where 0 * corresponds to the first line in the tree. * * Side effects: * None. * *---------------------------------------------------------------------- */intTkBTreeLineIndex(linePtr) TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */{ register TkTextLine *linePtr2; register Node *nodePtr, *parentPtr, *nodePtr2; int index; /* * First count how many lines precede this one in its level-0 * node. */ nodePtr = linePtr->parentPtr; index = 0; for (linePtr2 = nodePtr->children.linePtr; linePtr2 != linePtr; linePtr2 = linePtr2->nextPtr) { if (linePtr2 == NULL) { panic("TkBTreeLineIndex couldn't find line"); } index += 1; } /* * Now work up through the levels of the tree one at a time, * counting how many lines are in nodes preceding the current * node. */ for (parentPtr = nodePtr->parentPtr ; parentPtr != NULL; nodePtr = parentPtr, parentPtr = parentPtr->parentPtr) { for (nodePtr2 = parentPtr->children.nodePtr; nodePtr2 != nodePtr; nodePtr2 = nodePtr2->nextPtr) { if (nodePtr2 == NULL) { panic("TkBTreeLineIndex couldn't find node"); } index += nodePtr2->numLines; } } return index;}/* *---------------------------------------------------------------------- * * TkBTreeLinkSegment -- * * This procedure adds a new segment to a B-tree at a given * location. * * Results: * None. * * Side effects: * SegPtr will be linked into its tree. * *---------------------------------------------------------------------- */ /* ARGSUSED */voidTkBTreeLinkSegment(segPtr, indexPtr) TkTextSegment *segPtr; /* Pointer to new segment to be added to * B-tree. Should be completely initialized * by caller except for nextPtr field. */ TkTextIndex *indexPtr; /* Where to add segment: it gets linked * in just before the segment indicated * here. */{ register TkTextSegment *prevPtr; prevPtr = SplitSeg(indexPtr); if (prevPtr == NULL) { segPtr->nextPtr = indexPtr->linePtr->segPtr; indexPtr->linePtr->segPtr = segPtr; } else { segPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = segPtr; } CleanupLine(indexPtr->linePtr); if (tkBTreeDebug) { TkBTreeCheck(indexPtr->tree); }}/* *---------------------------------------------------------------------- * * TkBTreeUnlinkSegment -- * * This procedure unlinks a segment from its line in a B-tree. * * Results: * None. * * Side effects: * SegPtr will be unlinked from linePtr. The segment itself * isn't modified by this procedure. * *---------------------------------------------------------------------- */ /* ARGSUSED */voidTkBTreeUnlinkSegment(tree, segPtr, linePtr) TkTextBTree tree; /* Tree containing segment. */ TkTextSegment *segPtr; /* Segment to be unlinked. */ TkTextLine *linePtr; /* Line that currently contains * segment. */{ register TkTextSegment *prevPtr; if (linePtr->segPtr == segPtr) { linePtr->segPtr = segPtr->nextPtr; } else { for (prevPtr = linePtr->segPtr; prevPtr->nextPtr != segPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = segPtr->nextPtr; } CleanupLine(linePtr);}/* *---------------------------------------------------------------------- * * TkBTreeTag -- * * Turn a given tag on or off for a given range of characters in * a B-tree of text. * * Results: * None. * * Side effects: * The given tag is added to the given range of characters * in the tree or removed from all those characters, depending * on the "add" argument. The structure of the btree is modified * enough that index1Ptr and index2Ptr are no longer valid after * this procedure returns, and the indexes may be modified by * this procedure. * *---------------------------------------------------------------------- */voidTkBTreeTag(index1Ptr, index2Ptr, tagPtr, add) register TkTextIndex *index1Ptr; /* Indicates first character in * range. */ register TkTextIndex *index2Ptr; /* Indicates character just after the * last one in range. */ TkTextTag *tagPtr; /* Tag to add or remove. */ int add; /* One means add tag to the given * range of characters; zero means * remove the tag from the range. */{ TkTextSegment *segPtr, *prevPtr; TkTextSearch search; TkTextLine *cleanupLinePtr; int oldState; int changed; /* * See whether the tag is present at the start of the range. If * the state doesn't already match what we want then add a toggle * there. */ oldState = TkBTreeCharTagged(index1Ptr, tagPtr); if ((add != 0) ^ oldState) { segPtr = (TkTextSegment *) ckalloc(TSEG_SIZE); segPtr->typePtr = (add) ? &tkTextToggleOnType : &tkTextToggleOffType; prevPtr = SplitSeg(index1Ptr); if (prevPtr == NULL) { segPtr->nextPtr = index1Ptr->linePtr->segPtr; index1Ptr->linePtr->segPtr = segPtr; } else { segPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = segPtr; } segPtr->size = 0; segPtr->body.toggle.tagPtr = tagPtr; segPtr->body.toggle.inNodeCounts = 0; } /* * Scan the range of characters and delete any internal tag * transitions. Keep track of what the old state was at the end * of the range, and add a toggle there if it's needed. */ TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search); cleanupLinePtr = index1Ptr->linePtr; while (TkBTreeNextTag(&search)) { oldState ^= 1; segPtr = search.segPtr; prevPtr = search.curIndex.linePtr->segPtr; if (prevPtr == segPtr) { search.curIndex.linePtr->segPtr = segPtr->nextPtr; } else { while (prevPtr->nextPtr != segPtr) { prevPtr = prevPtr->nextPtr; } prevPtr->nextPtr = segPtr->nextPtr; } if (segPtr->body.toggle.inNodeCounts) { ChangeNodeToggleCount(search.curIndex.linePtr->parentPtr, segPtr->body.toggle.tagPtr, -1); segPtr->body.toggle.inNodeCounts = 0; changed = 1; } else { changed = 0; } ckfree((char *) segPtr); /* * The code below is a bit tricky. After deleting a toggle * we eventually have to call CleanupLine, in order to allow * character segments to be merged together. To do this, we * remember in cleanupLinePtr a line that needs to be * cleaned up, but we don't clean it up until we've moved * on to a different line. That way the cleanup process * won't goof up segPtr. */ if (cleanupLinePtr != search.curIndex.linePtr) { CleanupLine(cleanupLinePtr); cleanupLinePtr = search.curIndex.linePtr; } /* * Quick hack. ChangeNodeToggleCount may move the tag's root * location around and leave the search in the void. This resets * the search. */ if (changed) { TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search); } } if ((add != 0) ^ oldState) { segPtr = (TkTextSegment *) ckalloc(TSEG_SIZE); segPtr->typePtr = (add) ? &tkTextToggleOffType : &tkTextToggleOnType; prevPtr = SplitSeg(index2Ptr); if (prevPtr == NULL) { segPtr->nextPtr = index2Ptr->linePtr->segPtr; index2Ptr->linePtr->segPtr = segPtr; } else { segPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = segPtr; } segPtr->size = 0; segPtr->body.toggle.tagPtr = tagPtr; segPtr->body.toggle.inNodeCounts = 0; } /* * Cleanup cleanupLinePtr and the last line of the range, if * these are different. */ CleanupLine(cleanupLinePtr); if (cleanupLinePtr != index2Ptr->linePtr) { CleanupLine(index2Ptr->linePtr); } if (tkBTreeDebug) { TkBTreeCheck(index1Ptr->tree); }}/* *---------------------------------------------------------------------- * * ChangeNodeToggleCount -- * * This procedure increments or decrements the toggle count for * a particular tag in a particular node and all its ancestors * up to the per-tag root node. * * Results: * None. * * Side effects: * The toggle count for tag is adjusted up or down by "delta" in * nodePtr. This routine maintains the tagRootPtr that identifies * the root node for the tag, moving it up or down the tree as needed. * *---------------------------------------------------------------------- */static voidChangeNodeToggleCount(nodePtr, tagPtr, delta) register Node *nodePtr; /* Node whose toggle count for a tag * must be changed. */ TkTextTag *tagPtr; /* Information about tag. */ int delta; /* Amount to add to current toggle * count for tag (may be negative). */{ register Summary *summaryPtr, *prevPtr; register Node *node2Ptr; int rootLevel; /* Level of original tag root */ tagPtr->toggleCount += delta; if (tagPtr->tagRootPtr == (Node *) NULL) { tagPtr->tagRootPtr = nodePtr; return; } /* * Note the level of the existing root for the tag so we can detect * if it needs to be moved because of the toggle count change. */ rootLevel = tagPtr->tagRootPtr->level; /* * Iterate over the node and its ancestors up to the tag root, adjusting * summary counts at each node and moving the tag's root upwards if * necessary. */ for ( ; nodePtr != tagPtr->tagRootPtr; nodePtr = nodePtr->parentPtr) { /* * See if there's already an entry for this tag for this node. If so, * perhaps all we have to do is adjust its count. */ for (prevPtr = NULL, summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; prevPtr = summaryPtr, summaryPtr = summaryPtr->nextPtr) { if (summaryPtr->tagPtr == tagPtr) { break; } } if (summaryPtr != NULL) { summaryPtr->toggleCount += delta; if (summaryPtr->toggleCount > 0 && summaryPtr->toggleCount < tagPtr->toggleCount) { continue; } if (summaryPtr->toggleCount != 0) { /* * Should never find a node with max toggle count at this * point (there shouldn't have been a summary entry in the * first place). */ panic("ChangeNodeToggleCount: bad toggle count (%d) max (%d)", summaryPtr->toggleCount, tagPtr->toggleCount); } /* * Zero toggle count; must remove this tag from the list. */ if (prevPtr == NULL) {
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -