11
11
* See the file "license.terms" for information on usage and redistribution
12
12
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14
* RCS: @(#) $Id: tkTextBTree.c,v 1.2 1998/09/14 18:23:18 stanton Exp $
14
* RCS: @(#) $Id: tkTextBTree.c,v 1.6 2002/08/05 04:30:40 dgp Exp $
127
127
static void CleanupLine _ANSI_ARGS_((TkTextLine *linePtr));
128
128
static void DeleteSummaries _ANSI_ARGS_((Summary *tagPtr));
129
129
static void DestroyNode _ANSI_ARGS_((Node *nodePtr));
130
static TkTextSegment * FindTagEnd _ANSI_ARGS_((TkTextBTree tree,
130
static TkTextSegment * FindTagEnd _ANSI_ARGS_((TkTextBTree tree,
131
131
TkTextTag *tagPtr, TkTextIndex *indexPtr));
132
132
static void IncCount _ANSI_ARGS_((TkTextTag *tagPtr, int inc,
133
133
TagInfo *tagInfoPtr));
284
284
TkBTreeDestroy(tree)
285
TkTextBTree tree; /* Pointer to tree to delete. */
285
TkTextBTree tree; /* Pointer to tree to delete. */
287
287
BTree *treePtr = (BTree *) tree;
289
289
DestroyNode(treePtr->rootPtr);
290
290
ckfree((char *) treePtr);
294
294
*----------------------------------------------------------------------
393
393
* index is no longer valid because
394
394
* of changes to the segment
396
char *string; /* Pointer to bytes to insert (may
396
CONST char *string; /* Pointer to bytes to insert (may
397
397
* contain newlines, must be null-
398
398
* terminated). */
402
402
* new segment (NULL means new segment
403
403
* is at beginning of line). */
404
404
TkTextSegment *curPtr; /* Current segment; new characters
405
* are inserted just after this one.
405
* are inserted just after this one.
406
406
* NULL means insert at beginning of
408
408
TkTextLine *linePtr; /* Current line (new segments are
410
410
register TkTextSegment *segPtr;
411
411
TkTextLine *newLinePtr;
412
412
int chunkSize; /* # characters in current chunk. */
413
register char *eol; /* Pointer to character just after last
413
register CONST char *eol; /* Pointer to character just after last
414
414
* one in current chunk. */
415
415
int changeToLineCount; /* Counts change to total number of
416
416
* lines in file. */
535
535
TkTextSegment *prevPtr, *segPtr;
538
for (count = indexPtr->charIndex, prevPtr = NULL,
538
for (count = indexPtr->byteIndex, prevPtr = NULL,
539
539
segPtr = indexPtr->linePtr->segPtr; segPtr != NULL;
540
540
count -= segPtr->size, prevPtr = segPtr, segPtr = segPtr->nextPtr) {
541
541
if (segPtr->size > count) {
971
for (node2Ptr = nodePtr->parentPtr->children.nodePtr; ;
971
for (node2Ptr = nodePtr->parentPtr->children.nodePtr; ;
972
972
node2Ptr = node2Ptr->children.nodePtr) {
973
973
while (node2Ptr->nextPtr != nodePtr) {
974
974
node2Ptr = node2Ptr->nextPtr;
1330
1330
* See if there's already an entry for this tag for this node. If so,
1331
1331
* perhaps all we have to do is adjust its count.
1334
1334
for (prevPtr = NULL, summaryPtr = nodePtr->summaryPtr;
1335
1335
summaryPtr != NULL;
1336
1336
prevPtr = summaryPtr, summaryPtr = summaryPtr->nextPtr) {
1370
1370
* This tag isn't currently in the summary information list.
1373
1373
if (rootLevel == nodePtr->level) {
1376
1376
* The old tag root is at the same level in the tree as this
1377
1377
* node, but it isn't at this node. Move the tag root up
1602
1602
for (lastLinePtr = NULL, linePtr = nodePtr->children.linePtr;
1603
1603
linePtr != (TkTextLine *) NULL; linePtr = linePtr->nextPtr) {
1604
1604
for (offset = 0, lastSegPtr = NULL, segPtr = linePtr->segPtr ;
1606
1606
offset += segPtr->size, segPtr = segPtr->nextPtr) {
1607
1607
if (((segPtr->typePtr == &tkTextToggleOnType)
1608
1608
|| (segPtr->typePtr == &tkTextToggleOffType))
1637
1637
* Side effects:
1638
1638
* The information at *searchPtr is set up so that subsequent calls
1639
1639
* to TkBTreeNextTag or TkBTreePrevTag will return information about the
1640
* locations of tag transitions. Note that TkBTreeNextTag or
1640
* locations of tag transitions. Note that TkBTreeNextTag or
1641
1641
* TkBTreePrevTag must be called to get the first transition.
1642
1642
* Note: unlike TkBTreeNextTag and TkBTreePrevTag, this routine does not
1643
1643
* guarantee that searchPtr->curIndex is equal to *index1Ptr. It may be
1694
1694
searchPtr->curIndex = *index1Ptr;
1695
1695
searchPtr->segPtr = NULL;
1696
1696
searchPtr->nextPtr = TkTextIndexToSeg(index1Ptr, &offset);
1697
searchPtr->curIndex.charIndex -= offset;
1697
searchPtr->curIndex.byteIndex -= offset;
1699
1699
searchPtr->lastPtr = TkTextIndexToSeg(index2Ptr, (int *) NULL);
1700
1700
searchPtr->tagPtr = tagPtr;
1708
1708
* first. A search does not return a toggle at the very start of
1709
1709
* the range, unless the range is artificially moved up to index0.
1711
if (((index1Ptr == &index0) &&
1712
(index1Ptr->charIndex > index2Ptr->charIndex)) ||
1713
((index1Ptr != &index0) &&
1714
(index1Ptr->charIndex >= index2Ptr->charIndex))) {
1711
if (((index1Ptr == &index0) &&
1712
(index1Ptr->byteIndex > index2Ptr->byteIndex)) ||
1713
((index1Ptr != &index0) &&
1714
(index1Ptr->byteIndex >= index2Ptr->byteIndex))) {
1715
1715
searchPtr->linesLeft = 0;
1721
1721
*----------------------------------------------------------------------
1794
1794
searchPtr->segPtr = NULL;
1795
1795
searchPtr->nextPtr = TkTextIndexToSeg(&searchPtr->curIndex, &offset);
1796
searchPtr->curIndex.charIndex -= offset;
1796
searchPtr->curIndex.byteIndex -= offset;
1799
1799
* Adjust the end of the search so it does find toggles that are right
1889
1889
searchPtr->tagPtr = segPtr->body.toggle.tagPtr;
1892
searchPtr->curIndex.charIndex += segPtr->size;
1892
searchPtr->curIndex.byteIndex += segPtr->size;
1896
1896
* See if there are more lines associated with the current parent
1897
1897
* node. If so, go back to the top of the loop to search the next
1907
1907
if (searchPtr->curIndex.linePtr != NULL) {
1908
1908
segPtr = searchPtr->curIndex.linePtr->segPtr;
1909
searchPtr->curIndex.charIndex = 0;
1909
searchPtr->curIndex.byteIndex = 0;
1912
1912
if (nodePtr == searchPtr->tagPtr->tagRootPtr) {
1913
1913
goto searchOver;
1917
1917
* Search across and up through the B-tree's node hierarchy looking
1918
1918
* for the next node that has a relevant tag transition somewhere in
1919
1919
* its subtree. Be sure to update linesLeft as we skip over large
1920
1920
* chunks of lines.
1924
1924
while (nodePtr->nextPtr == NULL) {
1925
1925
if (nodePtr->parentPtr == NULL ||
1939
1939
searchPtr->linesLeft -= nodePtr->numLines;
1943
1943
* At this point we've found a subtree that has a relevant tag
1944
1944
* transition. Now search down (and across) through that subtree
1945
1945
* to find the first level-0 node that has a relevant tag transition.
1948
1948
gotNodeWithTag:
1949
1949
while (nodePtr->level > 0) {
1950
1950
for (nodePtr = nodePtr->children.nodePtr; ;
1974
1974
searchPtr->curIndex.linePtr = nodePtr->children.linePtr;
1975
searchPtr->curIndex.charIndex = 0;
1975
searchPtr->curIndex.byteIndex = 0;
1976
1976
segPtr = searchPtr->curIndex.linePtr->segPtr;
1977
1977
if (searchPtr->linesLeft <= 0) {
1978
1978
goto searchOver;
2022
2022
register TkTextLine *linePtr, *prevLinePtr;
2023
2023
register Node *nodePtr, *node2Ptr, *prevNodePtr;
2024
2024
register Summary *summaryPtr;
2026
2026
int pastLast; /* Saw last marker during scan */
2027
2027
int linesSkipped;
2034
2034
* The outermost loop iterates over lines that may potentially contain
2035
2035
* a relevant tag transition, starting from the current segment in
2036
2036
* the current line. "nextPtr" is maintained as the last segment in
2037
* a line that we can look at.
2037
* a line that we can look at.
2042
2042
* Check for the last toggle before the current segment on this line.
2045
2045
if (searchPtr->lastPtr == NULL) {
2047
2047
* Search back to the very beginning, so pastLast is irrelevent.
2058
2058
&& (searchPtr->allTags
2059
2059
|| (segPtr->body.toggle.tagPtr == searchPtr->tagPtr))) {
2060
2060
prevPtr = segPtr;
2061
searchPtr->curIndex.charIndex = charIndex;
2061
searchPtr->curIndex.byteIndex = byteIndex;
2063
2063
if (segPtr == searchPtr->lastPtr) {
2064
2064
prevPtr = NULL; /* Segments earlier than last don't count */
2067
charIndex += segPtr->size;
2067
byteIndex += segPtr->size;
2069
2069
if (prevPtr != NULL) {
2070
2070
if (searchPtr->linesLeft == 1 && !pastLast) {
2115
2115
* one we find, if any, is recorded in prevNodePtr, and any nodes
2116
2116
* past prevNodePtr that don't have tag state increment linesSkipped.
2120
2120
for (prevNodePtr = NULL, linesSkipped = 0,
2121
2121
node2Ptr = nodePtr->parentPtr->children.nodePtr ;
2145
2145
goto searchOver;
2150
2150
* At this point we've found a subtree that has a relevant tag
2151
2151
* transition. Now search down (and across) through that subtree
2152
2152
* to find the last level-0 node that has a relevant tag transition.
2155
2155
gotNodeWithTag:
2156
2156
while (nodePtr->level > 0) {
2157
2157
for (linesSkipped = 0, prevNodePtr = NULL,
2233
2233
TkTextSegment *toggleSegPtr;
2234
2234
int toggles, index;
2237
2237
* Check for toggles for the tag in indexPtr's line but before
2238
2238
* indexPtr. If there is one, its type indicates whether or
2239
2239
* not the character is tagged.
2242
2242
toggleSegPtr = NULL;
2243
2243
for (index = 0, segPtr = indexPtr->linePtr->segPtr;
2244
(index + segPtr->size) <= indexPtr->charIndex;
2244
(index + segPtr->size) <= indexPtr->byteIndex;
2245
2245
index += segPtr->size, segPtr = segPtr->nextPtr) {
2246
2246
if (((segPtr->typePtr == &tkTextToggleOnType)
2247
2247
|| (segPtr->typePtr == &tkTextToggleOffType))
2287
2287
register Node *siblingPtr;
2288
2288
register Summary *summaryPtr;
2290
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2290
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2291
2291
siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) {
2292
2292
for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL;
2293
2293
summaryPtr = summaryPtr->nextPtr) {
2362
2362
for (index = 0, segPtr = indexPtr->linePtr->segPtr;
2363
(index + segPtr->size) <= indexPtr->charIndex;
2363
(index + segPtr->size) <= indexPtr->byteIndex;
2364
2364
index += segPtr->size, segPtr = segPtr->nextPtr) {
2365
2365
if ((segPtr->typePtr == &tkTextToggleOnType)
2366
2366
|| (segPtr->typePtr == &tkTextToggleOffType)) {
2395
2395
register Node *siblingPtr;
2396
2396
register Summary *summaryPtr;
2398
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2398
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2399
2399
siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) {
2400
2400
for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL;
2401
2401
summaryPtr = summaryPtr->nextPtr) {
2428
2428
return tagInfo.tagPtrs;
2433
special case to just return information about elided attribute
2434
specialized from TkBTreeGetTags(indexPtr, numTagsPtr) and GetStyle(textPtr, indexPtr)
2435
just need to keep track of invisibility settings for each priority, pick highest one active at end
2432
*----------------------------------------------------------------------
2436
* Special case to just return information about elided attribute.
2437
* Specialized from TkBTreeGetTags(indexPtr, numTagsPtr)
2438
* and GetStyle(textPtr, indexPtr).
2439
* Just need to keep track of invisibility settings for each priority,
2440
* pick highest one active at end
2443
* Returns whether this text should be elided or not.
2448
*----------------------------------------------------------------------
2438
2453
TkTextIsElided(textPtr, indexPtr)
2439
2454
TkText *textPtr; /* Overall information about text widget. */
2441
2456
* display information is wanted. */
2443
2458
#define LOTSA_TAGS 1000
2444
int elide = 0; /* if nobody says otherwise, it's visible */
2459
int elide = 0; /* if nobody says otherwise, it's visible */
2446
int deftagCnts[LOTSA_TAGS];
2447
int *tagCnts = deftagCnts;
2448
TkTextTag *deftagPtrs[LOTSA_TAGS];
2449
TkTextTag **tagPtrs = deftagPtrs;
2450
int numTags = textPtr->numTags;
2461
int deftagCnts[LOTSA_TAGS];
2462
int *tagCnts = deftagCnts;
2463
TkTextTag *deftagPtrs[LOTSA_TAGS];
2464
TkTextTag **tagPtrs = deftagPtrs;
2465
int numTags = textPtr->numTags;
2451
2466
register Node *nodePtr;
2452
2467
register TkTextLine *siblingLinePtr;
2453
2468
register TkTextSegment *segPtr;
2455
2470
register int i, index;
2457
2472
/* almost always avoid malloc, so stay out of system calls */
2458
if (LOTSA_TAGS < numTags) {
2459
tagCnts = (int *)ckalloc((unsigned)sizeof(int) * numTags);
2460
tagPtrs = (TkTextTag **)ckalloc((unsigned)sizeof(TkTextTag *) * numTags);
2463
for (i=0; i<numTags; i++) tagCnts[i]=0;
2473
if (LOTSA_TAGS < numTags) {
2474
tagCnts = (int *)ckalloc((unsigned)sizeof(int) * numTags);
2475
tagPtrs = (TkTextTag **)ckalloc((unsigned)sizeof(TkTextTag *) * numTags);
2478
for (i=0; i<numTags; i++) {
2467
2483
* Record tag toggles within the line of indexPtr but preceding
2471
2487
for (index = 0, segPtr = indexPtr->linePtr->segPtr;
2472
(index + segPtr->size) <= indexPtr->charIndex;
2473
index += segPtr->size, segPtr = segPtr->nextPtr) {
2488
(index + segPtr->size) <= indexPtr->byteIndex;
2489
index += segPtr->size, segPtr = segPtr->nextPtr) {
2474
2490
if ((segPtr->typePtr == &tkTextToggleOnType)
2475
|| (segPtr->typePtr == &tkTextToggleOffType)) {
2491
|| (segPtr->typePtr == &tkTextToggleOffType)) {
2476
2492
tagPtr = segPtr->body.toggle.tagPtr;
2477
if (tagPtr->state != TK_STATE_NULL) {
2478
tagPtrs[tagPtr->priority] = tagPtr;
2479
tagCnts[tagPtr->priority]++;
2493
if (tagPtr->elideString != NULL) {
2494
tagPtrs[tagPtr->priority] = tagPtr;
2495
tagCnts[tagPtr->priority]++;
2489
2505
for (siblingLinePtr = indexPtr->linePtr->parentPtr->children.linePtr;
2490
siblingLinePtr != indexPtr->linePtr;
2491
siblingLinePtr = siblingLinePtr->nextPtr) {
2506
siblingLinePtr != indexPtr->linePtr;
2507
siblingLinePtr = siblingLinePtr->nextPtr) {
2492
2508
for (segPtr = siblingLinePtr->segPtr; segPtr != NULL;
2493
segPtr = segPtr->nextPtr) {
2509
segPtr = segPtr->nextPtr) {
2494
2510
if ((segPtr->typePtr == &tkTextToggleOnType)
2495
|| (segPtr->typePtr == &tkTextToggleOffType)) {
2496
tagPtr = segPtr->body.toggle.tagPtr;
2497
if (tagPtr->state != TK_STATE_NULL) {
2498
tagPtrs[tagPtr->priority] = tagPtr;
2499
tagCnts[tagPtr->priority]++;
2511
|| (segPtr->typePtr == &tkTextToggleOffType)) {
2512
tagPtr = segPtr->body.toggle.tagPtr;
2513
if (tagPtr->elideString != NULL) {
2514
tagPtrs[tagPtr->priority] = tagPtr;
2515
tagCnts[tagPtr->priority]++;
2510
2526
for (nodePtr = indexPtr->linePtr->parentPtr; nodePtr->parentPtr != NULL;
2511
nodePtr = nodePtr->parentPtr) {
2527
nodePtr = nodePtr->parentPtr) {
2512
2528
register Node *siblingPtr;
2513
2529
register Summary *summaryPtr;
2515
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2516
siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) {
2531
for (siblingPtr = nodePtr->parentPtr->children.nodePtr;
2532
siblingPtr != nodePtr; siblingPtr = siblingPtr->nextPtr) {
2517
2533
for (summaryPtr = siblingPtr->summaryPtr; summaryPtr != NULL;
2518
summaryPtr = summaryPtr->nextPtr) {
2534
summaryPtr = summaryPtr->nextPtr) {
2519
2535
if (summaryPtr->toggleCount & 1) {
2520
2536
tagPtr = summaryPtr->tagPtr;
2521
if (tagPtr->state != TK_STATE_NULL) {
2522
tagPtrs[tagPtr->priority] = tagPtr;
2523
tagCnts[tagPtr->priority] += summaryPtr->toggleCount;
2537
if (tagPtr->elideString != NULL) {
2538
tagPtrs[tagPtr->priority] = tagPtr;
2539
tagCnts[tagPtr->priority] += summaryPtr->toggleCount;
2532
* Now traverse from highest priority to lowest,
2547
* Now traverse from highest priority to lowest,
2533
2548
* take elided value from first odd count (= on)
2536
2551
for (i = numTags-1; i >=0; i--) {
2537
if (tagCnts[i] & 1) {
2552
if (tagCnts[i] & 1) {
2538
2553
#ifndef ALWAYS_SHOW_SELECTION
2539
/* who would make the selection elided? */
2540
if ((tagPtr == textPtr->selTagPtr) && !(textPtr->flags & GOT_FOCUS)) {
2554
/* who would make the selection elided? */
2555
if ((tagPtr == textPtr->selTagPtr)
2556
&& !(textPtr->flags & GOT_FOCUS)) {
2544
elide = (tagPtrs[i]->state == TK_STATE_HIDDEN);
2560
elide = tagPtrs[i]->elide;
2549
2565
if (LOTSA_TAGS < numTags) {
2550
ckfree((char *) tagCnts);
2551
ckfree((char *) tagPtrs);
2566
ckfree((char *) tagCnts);
2567
ckfree((char *) tagPtrs);
2558
2574
*----------------------------------------------------------------------
2971
2987
* If the node being split is the root node, then make a
2972
2988
* new root node above it first.
2975
2991
if (nodePtr->parentPtr == NULL) {
2976
2992
newPtr = (Node *) ckalloc(sizeof(Node));
2977
2993
newPtr->parentPtr = NULL;
3268
3284
summaryPtr2 = NULL;
3269
3285
for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; ) {
3270
if (summaryPtr->toggleCount > 0 &&
3286
if (summaryPtr->toggleCount > 0 &&
3271
3287
summaryPtr->toggleCount < summaryPtr->tagPtr->toggleCount) {
3272
3288
if (nodePtr->level == summaryPtr->tagPtr->tagRootPtr->level) {
3716
3732
for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) {
3733
if (segPtr->typePtr == &tkTextCharType) {
3734
count += Tcl_NumUtfChars(segPtr->body.chars, segPtr->size);
3736
count += segPtr->size;
3743
TkBTreeBytesInLine(linePtr)
3744
TkTextLine *linePtr; /* Line whose characters should be
3747
TkTextSegment *segPtr;
3751
for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) {
3717
3752
count += segPtr->size;