update.
[chise/xemacs-chise.git.1] / src / insdel.c
index ae3c614..a459c8a 100644 (file)
@@ -200,7 +200,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include "lisp.h"
-#include <limits.h>
 
 #include "buffer.h"
 #include "device.h"
@@ -219,7 +218,9 @@ Boston, MA 02111-1307, USA.  */
 #define MAX_BUFPOS_GAP_SIZE_3 (65535/3)
 #define MAX_BYTIND_GAP_SIZE_3 (3 * MAX_BUFPOS_GAP_SIZE_3)
 
+#ifndef UTF2000
 short three_to_one_table[1 + MAX_BYTIND_GAP_SIZE_3];
+#endif
 
 /* Various macros modelled along the lines of those in buffer.h.
    Purposefully omitted from buffer.h because files other than this
@@ -304,65 +305,64 @@ do                                                \
    the equivalent length in characters. */
 
 Charcount
-bytecount_to_charcount (CONST Bufbyte *ptr, Bytecount len)
+bytecount_to_charcount (const Bufbyte *ptr, Bytecount len)
 {
   Charcount count = 0;
-  CONST Bufbyte *end = ptr + len;
-
-#if (LONGBITS == 32 || LONGBITS == 64)
-
-# if (LONGBITS == 32)
-#  define LONG_BYTES 4
-#  define ALIGN_MASK 0xFFFFFFFCU
-#  define HIGH_BIT_MASK 0x80808080U
-# else
-#  define LONG_BYTES 8
-#  define ALIGN_MASK 0xFFFFFFFFFFFFFFF8UL
-   /* I had a dream, I was being overrun with early Intel processors ... */
-#  define HIGH_BIT_MASK 0x8080808080808080UL
-# endif
-
-  /* When we have a large number of bytes to scan, we can be trickier
-     and significantly faster by scanning them in chunks of the CPU word
-     size (assuming that they're all ASCII -- we cut out as soon as
-     we find something non-ASCII). */
-  if (len >= 12)
-    {
-      /* Determine the section in the middle of the string that's
-        amenable to this treatment.  Everything has to be aligned
-        on CPU word boundaries. */
-      CONST Bufbyte *aligned_ptr =
-       (CONST Bufbyte *) (((unsigned long) (ptr + LONG_BYTES - 1)) &
-                          ALIGN_MASK);
-      CONST Bufbyte *aligned_end =
-       (CONST Bufbyte *) (((unsigned long) end) & ALIGN_MASK);
-
-      /* Handle unaligned stuff at the beginning. */
-      while (ptr < aligned_ptr)
+  const Bufbyte *end = ptr + len;
+
+#if SIZEOF_LONG == 8
+# define STRIDE_TYPE long
+# define HIGH_BIT_MASK 0x8080808080808080UL
+#elif SIZEOF_LONG_LONG == 8 && !(defined (i386) || defined (__i386__))
+# define STRIDE_TYPE long long
+# define HIGH_BIT_MASK 0x8080808080808080ULL
+#elif SIZEOF_LONG == 4
+# define STRIDE_TYPE long
+# define HIGH_BIT_MASK 0x80808080UL
+#else
+# error Add support for 128-bit systems here
+#endif
+
+#define ALIGN_BITS ((EMACS_UINT) (ALIGNOF (STRIDE_TYPE) - 1))
+#define ALIGN_MASK (~ ALIGN_BITS)
+#define ALIGNED(ptr) ((((EMACS_UINT) ptr) & ALIGN_BITS) == 0)
+#define STRIDE sizeof (STRIDE_TYPE)
+
+  while (ptr < end)
+    {
+      if (BYTE_ASCII_P (*ptr))
        {
-         if (!BYTE_ASCII_P (*ptr))
-           goto bail;
-         count++, ptr++;
+         /* optimize for long stretches of ASCII */
+         if (! ALIGNED (ptr))
+           ptr++, count++;
+         else
+           {
+             const unsigned STRIDE_TYPE *ascii_end =
+               (const unsigned STRIDE_TYPE *) ptr;
+             /* This loop screams, because we can typically
+                detect ASCII characters 8 at a time. */
+             while ((const Bufbyte *) ascii_end + STRIDE <= end
+                    && !(*ascii_end & HIGH_BIT_MASK))
+               ascii_end++;
+             if ((Bufbyte *) ascii_end == ptr)
+               ptr++, count++;
+             else
+               {
+                 count += (Bufbyte *) ascii_end - ptr;
+                 ptr = (Bufbyte *) ascii_end;
+               }
+           }
        }
-      /* Now do it. */
-      while (ptr < aligned_end)
+      else
        {
-
-         if ((* (unsigned long *) ptr) & HIGH_BIT_MASK)
-           goto bail;
-         ptr += LONG_BYTES;
-         count += LONG_BYTES;
+         /* optimize for successive characters from the same charset */
+         Bufbyte leading_byte = *ptr;
+         size_t bytes = REP_BYTES_BY_FIRST_BYTE (leading_byte);
+         while ((ptr < end) && (*ptr == leading_byte))
+           ptr += bytes, count++;
        }
     }
 
-#endif /* LONGBITS == 32 || LONGBITS == 64 */
-
- bail:
-  while (ptr < end)
-    {
-      count++;
-      INC_CHARPTR (ptr);
-    }
 #ifdef ERROR_CHECK_BUFPOS
   /* Bomb out if the specified substring ends in the middle
      of a character.  Note that we might have already gotten
@@ -378,9 +378,9 @@ bytecount_to_charcount (CONST Bufbyte *ptr, Bytecount len)
    the equivalent length in bytes. */
 
 Bytecount
-charcount_to_bytecount (CONST Bufbyte *ptr, Charcount len)
+charcount_to_bytecount (const Bufbyte *ptr, Charcount len)
 {
-  CONST Bufbyte *newptr = ptr;
+  const Bufbyte *newptr = ptr;
 
   while (len > 0)
     {
@@ -431,7 +431,11 @@ bufpos_to_bytind_func (struct buffer *buf, Bufpos x)
   bufmax = buf->text->mule_bufmax;
   bytmin = buf->text->mule_bytmin;
   bytmax = buf->text->mule_bytmax;
+#ifdef UTF2000
+  size = buf->text->mule_size;
+#else
   size = (1 << buf->text->mule_shifter) + !!buf->text->mule_three_p;
+#endif
 
   /* The basic idea here is that we shift the "known region" up or down
      until it overlaps the specified position.  We do this by moving
@@ -491,7 +495,7 @@ bufpos_to_bytind_func (struct buffer *buf, Bufpos x)
     }
 #ifdef ERROR_CHECK_BUFPOS
   else if (x >= bufmin)
-    abort ();
+    ABORT ();
 #endif
   else
     {
@@ -626,11 +630,16 @@ bufpos_to_bytind_func (struct buffer *buf, Bufpos x)
      discovered isn't too large, because we use a fixed-length
      table to divide by 3. */
 
+#ifdef UTF2000
+  buf->text->mule_size = size;
+#endif
   if (size == 3)
     {
       int gap = bytmax - bytmin;
+#ifndef UTF2000
       buf->text->mule_three_p = 1;
       buf->text->mule_shifter = 1;
+#endif
 
       if (gap > MAX_BYTIND_GAP_SIZE_3)
        {
@@ -648,11 +657,13 @@ bufpos_to_bytind_func (struct buffer *buf, Bufpos x)
     }
   else
     {
+#ifndef UTF2000
       buf->text->mule_three_p = 0;
       if (size == 4)
        buf->text->mule_shifter = 2;
       else
        buf->text->mule_shifter = size - 1;
+#endif
     }
 
   buf->text->mule_bufmin = bufmin;
@@ -708,7 +719,11 @@ bytind_to_bufpos_func (struct buffer *buf, Bytind x)
   bufmax = buf->text->mule_bufmax;
   bytmin = buf->text->mule_bytmin;
   bytmax = buf->text->mule_bytmax;
+#ifdef UTF2000
+  size = buf->text->mule_size;
+#else
   size = (1 << buf->text->mule_shifter) + !!buf->text->mule_three_p;
+#endif
 
   /* The basic idea here is that we shift the "known region" up or down
      until it overlaps the specified position.  We do this by moving
@@ -768,7 +783,7 @@ bytind_to_bufpos_func (struct buffer *buf, Bytind x)
     }
 #ifdef ERROR_CHECK_BUFPOS
   else if (x >= bytmin)
-    abort ();
+    ABORT ();
 #endif
   else
     {
@@ -903,11 +918,16 @@ bytind_to_bufpos_func (struct buffer *buf, Bytind x)
      discovered isn't too large, because we use a fixed-length
      table to divide by 3. */
 
+#ifdef UTF2000
+  buf->text->mule_size = size;
+  #endif
   if (size == 3)
     {
       int gap = bytmax - bytmin;
+#ifndef UTF2000
       buf->text->mule_three_p = 1;
       buf->text->mule_shifter = 1;
+#endif
 
       if (gap > MAX_BYTIND_GAP_SIZE_3)
        {
@@ -925,11 +945,13 @@ bytind_to_bufpos_func (struct buffer *buf, Bytind x)
     }
   else
     {
+#ifndef UTF2000
       buf->text->mule_three_p = 0;
       if (size == 4)
        buf->text->mule_shifter = 2;
       else
        buf->text->mule_shifter = size - 1;
+#endif
     }
 
   buf->text->mule_bufmin = bufmin;
@@ -965,7 +987,11 @@ buffer_mule_signal_inserted_region (struct buffer *buf, Bufpos start,
                                    Bytecount bytelength,
                                    Charcount charlength)
 {
+#ifdef UTF2000
+  int size = buf->text->mule_size;
+#else
   int size = (1 << buf->text->mule_shifter) + !!buf->text->mule_three_p;
+#endif
   int i;
 
   /* Adjust the cache of known positions. */
@@ -1196,6 +1222,7 @@ bytind_to_bufpos (struct buffer *buf, Bytind x)
 Bufpos
 get_buffer_pos_char (struct buffer *b, Lisp_Object pos, unsigned int flags)
 {
+  /* Does not GC */
   Bufpos ind;
   Bufpos min_allowed, max_allowed;
 
@@ -1245,6 +1272,7 @@ void
 get_buffer_range_char (struct buffer *b, Lisp_Object from, Lisp_Object to,
                       Bufpos *from_out, Bufpos *to_out, unsigned int flags)
 {
+  /* Does not GC */
   Bufpos min_allowed, max_allowed;
 
   min_allowed = (flags & GB_ALLOW_PAST_ACCESSIBLE) ?
@@ -1605,7 +1633,7 @@ static void
 adjust_markers (struct buffer *buf, Memind from, Memind to,
                Bytecount amount)
 {
-  struct Lisp_Marker *m;
+  Lisp_Marker *m;
 
   for (m = BUF_MARKERS (buf); m; m = marker_next (m))
     m->memind = do_marker_adjustment (m->memind, from, to, amount);
@@ -1617,7 +1645,7 @@ adjust_markers (struct buffer *buf, Memind from, Memind to,
 static void
 adjust_markers_for_insert (struct buffer *buf, Memind ind, Bytecount amount)
 {
-  struct Lisp_Marker *m;
+  Lisp_Marker *m;
 
   for (m = BUF_MARKERS (buf); m; m = marker_next (m))
     {
@@ -1631,18 +1659,6 @@ adjust_markers_for_insert (struct buffer *buf, Memind ind, Bytecount amount)
 /*                  Routines for dealing with the gap                   */
 /************************************************************************/
 
-/* XEmacs requires an ANSI C compiler, and it damn well better have a
-   working memmove() */
-#define GAP_USE_BCOPY
-#ifdef BCOPY_UPWARD_SAFE
-# undef BCOPY_UPWARD_SAFE
-#endif
-#ifdef BCOPY_DOWNWARD_SAFE
-# undef BCOPY_DOWNWARD_SAFE
-#endif
-#define BCOPY_UPWARD_SAFE 1
-#define BCOPY_DOWNWARD_SAFE 1
-
 /* maximum amount of memory moved in a single chunk.  Increasing this
    value improves gap-motion efficiency but decreases QUIT responsiveness
    time.  Was 32000 but today's processors are faster and files are
@@ -1683,23 +1699,15 @@ gap_left (struct buffer *buf, Bytind pos)
       /* Move at most GAP_MOVE_CHUNK chars before checking again for a quit. */
       if (i > GAP_MOVE_CHUNK)
        i = GAP_MOVE_CHUNK;
-#ifdef GAP_USE_BCOPY
-      if (i >= 128
-         /* bcopy is safe if the two areas of memory do not overlap
-            or on systems where bcopy is always safe for moving upward.  */
-         && (BCOPY_UPWARD_SAFE
-             || to - from >= 128))
+
+      if (i >= 128)
        {
-         /* If overlap is not safe, avoid it by not moving too many
-            characters at once.  */
-         if (!BCOPY_UPWARD_SAFE && i > to - from)
-           i = to - from;
          new_s1 -= i;
-         from -= i, to -= i;
+         from   -= i;
+         to     -= i;
          memmove (to, from, i);
        }
       else
-#endif
        {
          new_s1 -= i;
          while (--i >= 0)
@@ -1762,23 +1770,15 @@ gap_right (struct buffer *buf, Bytind pos)
       /* Move at most GAP_MOVE_CHUNK chars before checking again for a quit. */
       if (i > GAP_MOVE_CHUNK)
        i = GAP_MOVE_CHUNK;
-#ifdef GAP_USE_BCOPY
-      if (i >= 128
-         /* bcopy is safe if the two areas of memory do not overlap
-            or on systems where bcopy is always safe for moving downward. */
-         && (BCOPY_DOWNWARD_SAFE
-             || from - to >= 128))
+
+      if (i >= 128)
        {
-         /* If overlap is not safe, avoid it by not moving too many
-            characters at once.  */
-         if (!BCOPY_DOWNWARD_SAFE && i > from - to)
-           i = from - to;
          new_s1 += i;
          memmove (to, from, i);
-         from += i, to += i;
+         from += i;
+         to   += i;
        }
       else
-#endif
        {
          new_s1 += i;
          while (--i >= 0)
@@ -1825,7 +1825,7 @@ static void
 move_gap (struct buffer *buf, Bytind pos)
 {
   if (! BUF_BEG_ADDR (buf))
-    abort ();
+    ABORT ();
   if (pos < BI_BUF_GPT (buf))
     gap_left (buf, pos);
   else if (pos > BI_BUF_GPT (buf))
@@ -2057,7 +2057,12 @@ multiple_change_finish_up (Lisp_Object buffer)
    of the specified region, that will also be handled correctly.
 
    begin_multiple_change() returns a number (actually a specpdl depth)
-   that you must pass to end_multiple_change() when you are done. */
+   that you must pass to end_multiple_change() when you are done.
+
+   FSF Emacs 20 implements a similar feature, accessible from Lisp
+   through a `combine-after-change-calls' special form, which is
+   essentially equivalent to this function.  We should consider
+   whether we want to introduce a similar Lisp form.  */
 
 int
 begin_multiple_change (struct buffer *buf, Bufpos start, Bufpos end)
@@ -2105,7 +2110,8 @@ change_function_restore (Lisp_Object buffer)
   /* We should first reset the variable and then change the buffer,
      because Fset_buffer() can throw.  */
   inside_change_hook = 0;
-  Fset_buffer (buffer);
+  if (XBUFFER (buffer) != current_buffer)
+    Fset_buffer (buffer);
   return Qnil;
 }
 
@@ -2155,6 +2161,7 @@ signal_before_change (struct buffer *buf, Bufpos start, Bufpos end)
   if (!inside_change_hook)
     {
       Lisp_Object buffer;
+      int speccount;
 
       /* Are we in a multiple-change session? */
       if (buf->text->changes->in_multiple_change &&
@@ -2192,6 +2199,9 @@ signal_before_change (struct buffer *buf, Bufpos start, Bufpos end)
        }
 
       /* Now in any case run the before-change-functions if any.  */
+      speccount = specpdl_depth ();
+      record_unwind_protect (change_function_restore, Fcurrent_buffer ());
+      inside_change_hook = 1;
 
       MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
        {
@@ -2200,25 +2210,28 @@ signal_before_change (struct buffer *buf, Bufpos start, Bufpos end)
              /* Obsolete, for compatibility */
              || !NILP (symbol_value_in_buffer (Qbefore_change_function, buffer)))
            {
-             int speccount = specpdl_depth ();
-             record_unwind_protect (change_function_restore, Fcurrent_buffer ());
              set_buffer_internal (buf);
-             inside_change_hook = 1;
              va_run_hook_with_args (Qbefore_change_functions, 2,
                                     make_int (start), make_int (end));
              /* Obsolete, for compatibility */
              va_run_hook_with_args (Qbefore_change_function, 2,
                                     make_int (start), make_int (end));
-             unbind_to (speccount, Qnil);
            }
        }
 
+      /* Make sure endpoints remain valid.  before-change-functions
+        might have modified the buffer. */
+      if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf);
+      if (start > BUF_ZV (buf))   start = BUF_ZV (buf);
+      if (end < BUF_BEGV (buf)) end = BUF_BEGV (buf);
+      if (end > BUF_ZV (buf))   end = BUF_ZV (buf);
+
       MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
        {
          XSETBUFFER (buffer, mbuf);
-         report_extent_modification (buffer, start, end,
-                                     &inside_change_hook, 0);
+         report_extent_modification (buffer, start, end, 0);
        }
+      unbind_to (speccount, Qnil);
 
       /* Only now do we indicate that the before-change-functions have
         been called, in case some function throws out. */
@@ -2255,6 +2268,7 @@ signal_after_change (struct buffer *buf, Bufpos start, Bufpos orig_end,
   if (!inside_change_hook)
     {
       Lisp_Object buffer;
+      int speccount;
 
       if (buf->text->changes->in_multiple_change &&
          buf->text->changes->mc_begin != 0)
@@ -2267,6 +2281,9 @@ signal_after_change (struct buffer *buf, Bufpos start, Bufpos orig_end,
          return; /* after-change-functions signalled when all changes done */
        }
 
+      speccount = specpdl_depth ();
+      record_unwind_protect (change_function_restore, Fcurrent_buffer ());
+      inside_change_hook = 1;
       MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
        {
          XSETBUFFER (buffer, mbuf);
@@ -2275,10 +2292,7 @@ signal_after_change (struct buffer *buf, Bufpos start, Bufpos orig_end,
              /* Obsolete, for compatibility */
              || !NILP (symbol_value_in_buffer (Qafter_change_function, buffer)))
            {
-             int speccount = specpdl_depth ();
-             record_unwind_protect (change_function_restore, Fcurrent_buffer ());
              set_buffer_internal (buf);
-             inside_change_hook = 1;
              /* The actual after-change functions take slightly
                 different arguments than what we were passed. */
              va_run_hook_with_args (Qafter_change_functions, 3,
@@ -2288,16 +2302,24 @@ signal_after_change (struct buffer *buf, Bufpos start, Bufpos orig_end,
              va_run_hook_with_args (Qafter_change_function, 3,
                                     make_int (start), make_int (new_end),
                                     make_int (orig_end - start));
-             unbind_to (speccount, Qnil);
            }
        }
 
+      /* Make sure endpoints remain valid.  after-change-functions
+        might have modified the buffer. */
+      if (start < BUF_BEGV (buf)) start = BUF_BEGV (buf);
+      if (start > BUF_ZV (buf))   start = BUF_ZV (buf);
+      if (new_end < BUF_BEGV (buf)) new_end = BUF_BEGV (buf);
+      if (new_end > BUF_ZV (buf))   new_end = BUF_ZV (buf);
+      if (orig_end < BUF_BEGV (buf)) orig_end = BUF_BEGV (buf);
+      if (orig_end > BUF_ZV (buf))   orig_end = BUF_ZV (buf);
+
       MAP_INDIRECT_BUFFERS (buf, mbuf, bufcons)
        {
          XSETBUFFER (buffer, mbuf);
-         report_extent_modification (buffer, start, new_end,
-                                     &inside_change_hook, 1);
+         report_extent_modification (buffer, start, new_end, 1);
        }
+      unbind_to (speccount, Qnil); /* sets inside_change_hook back to 0 */
     }
 }
 
@@ -2330,16 +2352,15 @@ prepare_to_modify_buffer (struct buffer *buf, Bufpos start, Bufpos end,
   if (!NILP (buf->filename) && lockit &&
       BUF_SAVE_MODIFF (buf) >= BUF_MODIFF (buf))
     {
-#ifdef CLASH_DETECTION
-      if (!NILP (buf->file_truename))
-       /* Make binding buffer-file-name to nil effective.  */
-       lock_file (buf->file_truename);
-#else
       /* At least warn if this file has changed on disk since it was visited.*/
       if (NILP (Fverify_visited_file_modtime (buffer))
          && !NILP (Ffile_exists_p (buf->filename)))
        call1_in_buffer (buf, intern ("ask-user-about-supersession-threat"),
                         buf->filename);
+#ifdef CLASH_DETECTION
+      if (!NILP (buf->file_truename))
+       /* Make binding buffer-file-name to nil effective.  */
+       lock_file (buf->file_truename);
 #endif /* not CLASH_DETECTION */
     }
   UNGCPRO;
@@ -2377,7 +2398,7 @@ prepare_to_modify_buffer (struct buffer *buf, Bufpos start, Bufpos end,
 /************************************************************************/
 
 void
-fixup_internal_substring (CONST Bufbyte *nonreloc, Lisp_Object reloc,
+fixup_internal_substring (const Bufbyte *nonreloc, Lisp_Object reloc,
                          Bytecount offset, Bytecount *len)
 {
   assert ((nonreloc && NILP (reloc)) || (!nonreloc && STRINGP (reloc)));
@@ -2385,7 +2406,7 @@ fixup_internal_substring (CONST Bufbyte *nonreloc, Lisp_Object reloc,
   if (*len < 0)
     {
       if (nonreloc)
-       *len = strlen ((CONST char *) nonreloc) - offset;
+       *len = strlen ((const char *) nonreloc) - offset;
       else
        *len = XSTRING_LENGTH (reloc) - offset;
     }
@@ -2419,7 +2440,7 @@ fixup_internal_substring (CONST Bufbyte *nonreloc, Lisp_Object reloc,
 
 Charcount
 buffer_insert_string_1 (struct buffer *buf, Bufpos pos,
-                       CONST Bufbyte *nonreloc, Lisp_Object reloc,
+                       const Bufbyte *nonreloc, Lisp_Object reloc,
                        Bytecount offset, Bytecount length,
                        int flags)
 {
@@ -2584,7 +2605,7 @@ buffer_insert_string_1 (struct buffer *buf, Bufpos pos,
 
 Charcount
 buffer_insert_raw_string_1 (struct buffer *buf, Bufpos pos,
-                           CONST Bufbyte *nonreloc, Bytecount length,
+                           const Bufbyte *nonreloc, Bytecount length,
                            int flags)
 {
   /* This function can GC */
@@ -2608,12 +2629,12 @@ buffer_insert_lisp_string_1 (struct buffer *buf, Bufpos pos, Lisp_Object str,
 /* Insert the null-terminated string S (in external format). */
 
 Charcount
-buffer_insert_c_string_1 (struct buffer *buf, Bufpos pos, CONST char *s,
+buffer_insert_c_string_1 (struct buffer *buf, Bufpos pos, const char *s,
                          int flags)
 {
   /* This function can GC */
-  CONST char *translated = GETTEXT (s);
-  return buffer_insert_string_1 (buf, pos, (CONST Bufbyte *) translated, Qnil,
+  const char *translated = GETTEXT (s);
+  return buffer_insert_string_1 (buf, pos, (const Bufbyte *) translated, Qnil,
                                 0, strlen (translated), flags);
 }
 
@@ -3079,27 +3100,41 @@ barf_if_buffer_read_only (struct buffer *buf, Bufpos from, Bufpos to)
 }
 
 void
-find_charsets_in_bufbyte_string (unsigned char *charsets, CONST Bufbyte *str,
+find_charsets_in_bufbyte_string (Charset_ID *charsets, const Bufbyte *str,
                                 Bytecount len)
 {
 #ifndef MULE
   /* Telescope this. */
   charsets[0] = 1;
 #else
-  CONST Bufbyte *strend = str + len;
-  memset (charsets, 0, NUM_LEADING_BYTES);
+  const Bufbyte *strend = str + len;
+  memset (charsets, 0, NUM_LEADING_BYTES * sizeof(Charset_ID));
+
+  /* #### SJT doesn't like this. */
+  if (len == 0)
+    {
+      charsets[XCHARSET_LEADING_BYTE (Vcharset_ascii) - MIN_LEADING_BYTE] = 1;
+      return;
+    }
 
   while (str < strend)
     {
-      charsets[CHAR_LEADING_BYTE (charptr_emchar (str)) - 128] = 1;
+#ifdef UTF2000
+      charsets[CHAR_CHARSET_ID (charptr_emchar (str))
+             - MIN_LEADING_BYTE] = 1;
+#else /* I'm not sure the definition for UTF2000 works with leading-byte
+        representation. */
+      charsets[CHAR_LEADING_BYTE (charptr_emchar (str))
+             - MIN_LEADING_BYTE] = 1;
+#endif
       INC_CHARPTR (str);
     }
 #endif
 }
 
 void
-find_charsets_in_emchar_string (unsigned char *charsets, CONST Emchar *str,
-                               Charcount len)
+find_charsets_in_charc_string (Charset_ID *charsets, const Charc *str,
+                              Charcount len)
 {
 #ifndef MULE
   /* Telescope this. */
@@ -3107,25 +3142,33 @@ find_charsets_in_emchar_string (unsigned char *charsets, CONST Emchar *str,
 #else
   int i;
 
-  memset (charsets, 0, NUM_LEADING_BYTES);
+  memset (charsets, 0, NUM_LEADING_BYTES * sizeof(Charset_ID));
+
+  /* #### SJT doesn't like this. */
+  if (len == 0)
+    {
+      charsets[XCHARSET_ID (Vcharset_ascii) - MIN_LEADING_BYTE] = 1;
+      return;
+    }
+
   for (i = 0; i < len; i++)
     {
-      charsets[CHAR_LEADING_BYTE (str[i]) - 128] = 1;
+      charsets[CHARC_CHARSET_ID (str[i]) - MIN_LEADING_BYTE] = 1;
     }
 #endif
 }
 
 int
-bufbyte_string_displayed_columns (CONST Bufbyte *str, Bytecount len)
+bufbyte_string_displayed_columns (const Bufbyte *str, Bytecount len)
 {
   int cols = 0;
-  CONST Bufbyte *end = str + len;
+  const Bufbyte *end = str + len;
 
   while (str < end)
     {
 #ifdef MULE
       Emchar ch = charptr_emchar (str);
-      cols += XCHARSET_COLUMNS (CHAR_CHARSET (ch));
+      cols += CHAR_COLUMNS (ch);
 #else
       cols++;
 #endif
@@ -3136,14 +3179,14 @@ bufbyte_string_displayed_columns (CONST Bufbyte *str, Bytecount len)
 }
 
 int
-emchar_string_displayed_columns (CONST Emchar *str, Charcount len)
+charc_string_displayed_columns (const Charc *str, Charcount len)
 {
 #ifdef MULE
   int cols = 0;
   int i;
 
   for (i = 0; i < len; i++)
-    cols += XCHARSET_COLUMNS (CHAR_CHARSET (str[i]));
+    cols += CHARC_COLUMNS (str[i]);
 
   return cols;
 #else  /* not MULE */
@@ -3154,24 +3197,23 @@ emchar_string_displayed_columns (CONST Emchar *str, Charcount len)
 /* NOTE: Does not reset the Dynarr. */
 
 void
-convert_bufbyte_string_into_emchar_dynarr (CONST Bufbyte *str, Bytecount len,
-                                          Emchar_dynarr *dyn)
+convert_bufbyte_string_into_charc_dynarr (const Bufbyte *str, Bytecount len,
+                                         Charc_dynarr *dyn)
 {
-  CONST Bufbyte *strend = str + len;
+  const Bufbyte *strend = str + len;
 
   while (str < strend)
     {
-      Emchar ch = charptr_emchar (str);
-      Dynarr_add (dyn, ch);
+      Dynarr_add (dyn, CHAR_TO_CHARC (charptr_emchar (str)));
       INC_CHARPTR (str);
     }
 }
 
 Charcount
-convert_bufbyte_string_into_emchar_string (CONST Bufbyte *str, Bytecount len,
+convert_bufbyte_string_into_emchar_string (const Bufbyte *str, Bytecount len,
                                           Emchar *arr)
 {
-  CONST Bufbyte *strend = str + len;
+  const Bufbyte *strend = str + len;
   Charcount newlen = 0;
   while (str < strend)
     {
@@ -3187,15 +3229,15 @@ convert_bufbyte_string_into_emchar_string (CONST Bufbyte *str, Bytecount len,
    Does not add a terminating zero. */
 
 void
-convert_emchar_string_into_bufbyte_dynarr (Emchar *arr, int nels,
-                                         Bufbyte_dynarr *dyn)
+convert_charc_string_into_bufbyte_dynarr (Charc *arr, int nels,
+                                           Bufbyte_dynarr *dyn)
 {
   Bufbyte str[MAX_EMCHAR_LEN];
   int i;
 
   for (i = 0; i < nels; i++)
     {
-      Bytecount len = set_charptr_emchar (str, arr[i]);
+      Bytecount len = set_charptr_emchar (str, CHARC_TO_CHAR (arr[i]));
       Dynarr_add_many (dyn, str, len);
     }
 }
@@ -3207,7 +3249,7 @@ convert_emchar_string_into_bufbyte_dynarr (Emchar *arr, int nels,
    is one more than this: the returned string is zero-terminated. */
 
 Bufbyte *
-convert_emchar_string_into_malloced_string (Emchar *arr, int nels,
+convert_charc_string_into_malloced_string (Charc *arr, int nels,
                                           Bytecount *len_out)
 {
   /* Damn zero-termination. */
@@ -3218,7 +3260,9 @@ convert_emchar_string_into_malloced_string (Emchar *arr, int nels,
   int i;
 
   for (i = 0; i < nels; i++)
-    str += set_charptr_emchar (str, arr[i]);
+    {
+      str += set_charptr_emchar (str, CHARC_TO_CHAR (arr[i]));
+    }
   *str = '\0';
   len = str - strorig;
   str = (Bufbyte *) xmalloc (1 + len);
@@ -3236,13 +3280,17 @@ convert_emchar_string_into_malloced_string (Emchar *arr, int nels,
 void
 reinit_vars_of_insdel (void)
 {
+#ifndef UTF2000
   int i;
+#endif
 
   inside_change_hook = 0;
   in_first_change = 0;
 
+#ifndef UTF2000
   for (i = 0; i <= MAX_BYTIND_GAP_SIZE_3; i++)
     three_to_one_table[i] = i / 3;
+#endif
 }
 
 void
@@ -3272,8 +3320,12 @@ init_buffer_text (struct buffer *b)
 
        b->text->mule_bufmin = b->text->mule_bufmax = 1;
        b->text->mule_bytmin = b->text->mule_bytmax = 1;
+#ifdef UTF2000
+       b->text->mule_size = 0;
+#else
        b->text->mule_shifter = 0;
        b->text->mule_three_p = 0;
+#endif
 
        for (i = 0; i < 16; i++)
          {