changeset 50471:dc1f6aa29285

Add many calls to CHECK_TOTAL_LENGTH. (set_intervals_multibyte_1): When becoming multibyte, adjust right and left child sizes to a whole set of characters. If an interval gets zero total-length, delete it. If an interval consists of just its children, delete one of them.
author Richard M. Stallman <rms@gnu.org>
date Sun, 06 Apr 2003 20:32:52 +0000
parents c7a0b787faef
children 674bfa5d582d
files src/intervals.c
diffstat 1 files changed, 88 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/intervals.c	Sun Apr 06 20:29:13 2003 +0000
+++ b/src/intervals.c	Sun Apr 06 20:32:52 2003 +0000
@@ -75,12 +75,14 @@
     {
       new->total_length = (BUF_Z (XBUFFER (parent))
 			   - BUF_BEG (XBUFFER (parent)));
+      CHECK_TOTAL_LENGTH (new);
       BUF_INTERVALS (XBUFFER (parent)) = new;
       new->position = 1;
     }
   else if (STRINGP (parent))
     {
       new->total_length = SCHARS (parent);
+      CHECK_TOTAL_LENGTH (new);
       STRING_SET_INTERVALS (parent, new);
       new->position = 0;
     }
@@ -338,9 +340,11 @@
 
   /* A's total length is decreased by the length of B and its left child.  */
   interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval);
+  CHECK_TOTAL_LENGTH (interval);
 
   /* B must have the same total length of A.  */
   B->total_length = old_total;
+  CHECK_TOTAL_LENGTH (B);
 
   return B;
 }
@@ -384,9 +388,11 @@
 
   /* A's total length is decreased by the length of B and its right child.  */
   interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval);
+  CHECK_TOTAL_LENGTH (interval);
 
   /* B must have the same total length of A.  */
   B->total_length = old_total;
+  CHECK_TOTAL_LENGTH (B);
 
   return B;
 }
@@ -405,6 +411,7 @@
       old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i);
       if (old_diff > 0)
 	{
+	  /* Since the left child is longer, there must be one.  */
 	  new_diff = i->total_length - i->left->total_length
 	    + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
 	  if (abs (new_diff) >= old_diff)
@@ -414,6 +421,7 @@
 	}
       else if (old_diff < 0)
 	{
+	  /* Since the right child is longer, there must be one.  */
 	  new_diff = i->total_length - i->right->total_length
 	    + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
 	  if (abs (new_diff) >= -old_diff)
@@ -514,6 +522,7 @@
     {
       interval->right = new;
       new->total_length = new_length;
+      CHECK_TOTAL_LENGTH (new);
     }
   else
     {
@@ -522,6 +531,7 @@
       SET_INTERVAL_PARENT (interval->right, new);
       interval->right = new;
       new->total_length = new_length + new->right->total_length;
+      CHECK_TOTAL_LENGTH (new);
       balance_an_interval (new);
     }
 
@@ -559,6 +569,7 @@
     {
       interval->left = new;
       new->total_length = new_length;
+      CHECK_TOTAL_LENGTH (new);
     }
   else
     {
@@ -567,6 +578,7 @@
       SET_INTERVAL_PARENT (new->left, new);
       interval->left = new;
       new->total_length = new_length + new->left->total_length;
+      CHECK_TOTAL_LENGTH (new);
       balance_an_interval (new);
     }
 
@@ -828,6 +840,7 @@
       if (relative_position <= LEFT_TOTAL_LENGTH (this))
 	{
 	  this->total_length += length;
+	  CHECK_TOTAL_LENGTH (this);
 	  this = this->left;
 	}
       else if (relative_position > (TOTAL_LENGTH (this)
@@ -836,6 +849,7 @@
 	  relative_position -= (TOTAL_LENGTH (this)
 				- RIGHT_TOTAL_LENGTH (this));
 	  this->total_length += length;
+	  CHECK_TOTAL_LENGTH (this);
 	  this = this->right;
 	}
       else
@@ -843,6 +857,7 @@
 	  /* If we are to use zero-length intervals as buffer pointers,
 	     then this code will have to change.  */
 	  this->total_length += length;
+	  CHECK_TOTAL_LENGTH (this);
 	  this->position = LEFT_TOTAL_LENGTH (this)
 	                   + position - relative_position + 1;
 	  return tree;
@@ -987,6 +1002,7 @@
       for (temp = prev ? prev : i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
 	{
 	  temp->total_length += length;
+	  CHECK_TOTAL_LENGTH (temp);
 	  temp = balance_possible_root_interval (temp);
 	}
 
@@ -1043,6 +1059,7 @@
       for (temp = i; temp; temp = INTERVAL_PARENT_OR_NULL (temp))
 	{
 	  temp->total_length += length;
+	  CHECK_TOTAL_LENGTH (temp);
 	  temp = balance_possible_root_interval (temp);
 	}
     }
@@ -1247,6 +1264,7 @@
       this = this->left;
       this->total_length += migrate_amt;
     }
+  CHECK_TOTAL_LENGTH (this);
   this->left = migrate;
   SET_INTERVAL_PARENT (migrate, this);
 
@@ -1331,6 +1349,7 @@
 						   relative_position,
 						   amount);
       tree->total_length -= subtract;
+      CHECK_TOTAL_LENGTH (tree);
       return subtract;
     }
   /* Right branch */
@@ -1345,6 +1364,7 @@
 					       relative_position,
 					       amount);
       tree->total_length -= subtract;
+      CHECK_TOTAL_LENGTH (tree);
       return subtract;
     }
   /* Here -- this node.  */
@@ -1359,6 +1379,7 @@
 	amount = my_amount;
 
       tree->total_length -= amount;
+      CHECK_TOTAL_LENGTH (tree);
       if (LENGTH (tree) == 0)
 	delete_interval (tree);
 
@@ -1402,6 +1423,7 @@
   if (ONLY_INTERVAL_P (tree))
     {
       tree->total_length -= length;
+      CHECK_TOTAL_LENGTH (tree);
       return;
     }
 
@@ -1457,6 +1479,7 @@
 
   /* Zero out this interval.  */
   i->total_length -= absorb;
+  CHECK_TOTAL_LENGTH (i);
 
   /* Find the succeeding interval.  */
   if (! NULL_RIGHT_CHILD (i))      /* It's below us.  Add absorb
@@ -1466,10 +1489,12 @@
       while (! NULL_LEFT_CHILD (successor))
 	{
 	  successor->total_length += absorb;
+	  CHECK_TOTAL_LENGTH (successor);
 	  successor = successor->left;
 	}
 
       successor->total_length += absorb;
+      CHECK_TOTAL_LENGTH (successor);
       delete_interval (i);
       return successor;
     }
@@ -1487,6 +1512,7 @@
 
       successor = INTERVAL_PARENT (successor);
       successor->total_length -= absorb;
+      CHECK_TOTAL_LENGTH (successor);
     }
 
   /* This must be the rightmost or last interval and cannot
@@ -1510,6 +1536,7 @@
 
   /* Zero out this interval.  */
   i->total_length -= absorb;
+  CHECK_TOTAL_LENGTH (i);
 
   /* Find the preceding interval.  */
   if (! NULL_LEFT_CHILD (i))	/* It's below us. Go down,
@@ -1519,10 +1546,12 @@
       while (! NULL_RIGHT_CHILD (predecessor))
 	{
 	  predecessor->total_length += absorb;
+	  CHECK_TOTAL_LENGTH (predecessor);
 	  predecessor = predecessor->right;
 	}
 
       predecessor->total_length += absorb;
+      CHECK_TOTAL_LENGTH (predecessor);
       delete_interval (i);
       return predecessor;
     }
@@ -1540,6 +1569,7 @@
 
       predecessor = INTERVAL_PARENT (predecessor);
       predecessor->total_length -= absorb;
+      CHECK_TOTAL_LENGTH (predecessor);
     }
 
   /* This must be the leftmost or first interval and cannot
@@ -2354,6 +2384,7 @@
   new->position = 0;
   got = (LENGTH (i) - (start - i->position));
   new->total_length = length;
+  CHECK_TOTAL_LENGTH (new);
   copy_properties (i, new);
 
   t = new;
@@ -2440,6 +2471,13 @@
     i->total_length = end - start;
   else
     i->total_length = end_byte - start_byte;
+  CHECK_TOTAL_LENGTH (i);
+
+  if (TOTAL_LENGTH (i) == 0)
+    {
+      delete_interval (i);
+      return;
+    }
 
   /* Recursively fix the length of the subintervals.  */
   if (i->left)
@@ -2448,8 +2486,23 @@
 
       if (multi_flag)
 	{
+	  int temp;
 	  left_end_byte = start_byte + LEFT_TOTAL_LENGTH (i);
 	  left_end = BYTE_TO_CHAR (left_end_byte);
+
+	  temp = CHAR_TO_BYTE (left_end);
+
+	  /* If LEFT_END_BYTE is in the middle of a character,
+	     adjust it and LEFT_END to a char boundary.  */ 
+	  if (left_end_byte > temp)
+	    {
+	      left_end_byte = temp;
+	    }
+	  if (left_end_byte < temp)
+	    {
+	      left_end--;
+	      left_end_byte = CHAR_TO_BYTE (left_end);
+	    }
 	}
       else
 	{
@@ -2466,8 +2519,24 @@
 
       if (multi_flag)
 	{
+	  int temp;
+
 	  right_start_byte = end_byte - RIGHT_TOTAL_LENGTH (i);
 	  right_start = BYTE_TO_CHAR (right_start_byte);
+
+	  /* If RIGHT_START_BYTE is in the middle of a character,
+	     adjust it and RIGHT_START to a char boundary.  */ 
+	  temp = CHAR_TO_BYTE (right_start);
+
+	  if (right_start_byte < temp)
+	    {
+	      right_start_byte = temp;
+	    }
+	  if (right_start_byte > temp)
+	    {
+	      right_start++;
+	      right_start_byte = CHAR_TO_BYTE (right_start);
+	    }
 	}
       else
 	{
@@ -2479,6 +2548,25 @@
 				 right_start, right_start_byte,
 				 end, end_byte);
     }
+
+  /* Rounding to char boundaries can theoretically ake this interval
+     spurious.  If so, delete one child, and copy its property list
+     to this interval.  */
+  if (LEFT_TOTAL_LENGTH (i) + RIGHT_TOTAL_LENGTH (i) >= TOTAL_LENGTH (i))
+    {
+      if ((i)->left)
+	{
+	  (i)->plist = (i)->left->plist;
+	  (i)->left->total_length = 0;
+	  delete_interval ((i)->left);
+	}
+      else
+	{
+	  (i)->plist = (i)->right->plist;
+	  (i)->right->total_length = 0;
+	  delete_interval ((i)->right);
+	}
+    }
 }
 
 /* Update the intervals of the current buffer