Merge from emacs--devo--0
[bpt/emacs.git] / src / syntax.c
index 3f668ea..f409008 100644 (file)
@@ -1,6 +1,7 @@
 /* GNU Emacs routines to deal with syntax tables; also word and list parsing.
-   Copyright (C) 1985, 1987, 1993, 1994, 1995, 1997, 1998, 1999, 2002,
-                 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1987, 1993, 1994, 1995, 1997, 1998, 1999, 2001,
+                 2002, 2003, 2004, 2005, 2006, 2007
+                 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -25,7 +26,7 @@ Boston, MA 02110-1301, USA.  */
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "keymap.h"
 #include "regex.h"
 
@@ -97,10 +98,12 @@ static int find_start_modiff;
 
 
 static int find_defun_start P_ ((int, int));
-static int back_comment P_ ((int, int, int, int, int, int *, int *));
+static int back_comment P_ ((EMACS_INT, EMACS_INT, EMACS_INT, int, int,
+                            EMACS_INT *, EMACS_INT *));
 static int char_quoted P_ ((int, int));
-static Lisp_Object skip_chars P_ ((int, int, Lisp_Object, Lisp_Object, int));
-static Lisp_Object scan_lists P_ ((int, int, int, int));
+static Lisp_Object skip_chars P_ ((int, Lisp_Object, Lisp_Object, int));
+static Lisp_Object skip_syntaxes P_ ((int, Lisp_Object, Lisp_Object));
+static Lisp_Object scan_lists P_ ((EMACS_INT, EMACS_INT, EMACS_INT, int));
 static void scan_sexps_forward P_ ((struct lisp_parse_state *,
                                    int, int, int, int,
                                    int, Lisp_Object, int));
@@ -304,7 +307,7 @@ char_quoted (charpos, bytepos)
       int c;
 
       UPDATE_SYNTAX_TABLE_BACKWARD (charpos);
-      c = FETCH_CHAR (bytepos);
+      c = FETCH_CHAR_AS_MULTIBYTE (bytepos);
       code = SYNTAX (c);
       if (! (code == Scharquote || code == Sescape))
        break;
@@ -396,11 +399,11 @@ find_defun_start (pos, pos_byte)
 
       /* Open-paren at start of line means we may have found our
         defun-start.  */
-      c = FETCH_CHAR (PT_BYTE);
+      c = FETCH_CHAR_AS_MULTIBYTE (PT_BYTE);
       if (SYNTAX (c) == Sopen)
        {
          SETUP_SYNTAX_TABLE (PT + 1, -1);      /* Try again... */
-         c = FETCH_CHAR (PT_BYTE);
+         c = FETCH_CHAR_AS_MULTIBYTE (PT_BYTE);
          if (SYNTAX (c) == Sopen)
            break;
          /* Now fallback to the default value.  */
@@ -471,9 +474,9 @@ prev_char_comend_first (pos, pos_byte)
 
 static int
 back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_ptr)
-     int from, from_byte, stop;
+     EMACS_INT from, from_byte, stop;
      int comnested, comstyle;
-     int *charpos_ptr, *bytepos_ptr;
+     EMACS_INT *charpos_ptr, *bytepos_ptr;
 {
   /* Look back, counting the parity of string-quotes,
      and recording the comment-starters seen.
@@ -521,7 +524,7 @@ back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_p
       UPDATE_SYNTAX_TABLE_BACKWARD (from);
 
       prev_syntax = syntax;
-      c = FETCH_CHAR (from_byte);
+      c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
       syntax = SYNTAX_WITH_FLAGS (c);
       code = SYNTAX (c);
 
@@ -550,7 +553,7 @@ back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_p
          int next = from, next_byte = from_byte, next_c, next_syntax;
          DEC_BOTH (next, next_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (next);
-         next_c = FETCH_CHAR (next_byte);
+         next_c = FETCH_CHAR_AS_MULTIBYTE (next_byte);
          next_syntax = SYNTAX_WITH_FLAGS (next_c);
          if (((com2start || comnested)
               && SYNTAX_FLAGS_COMEND_SECOND (syntax)
@@ -748,9 +751,8 @@ static void
 check_syntax_table (obj)
      Lisp_Object obj;
 {
-  if (!(CHAR_TABLE_P (obj)
-       && EQ (XCHAR_TABLE (obj)->purpose, Qsyntax_table)))
-    wrong_type_argument (Qsyntax_table_p, obj);
+  CHECK_TYPE (CHAR_TABLE_P (obj) && EQ (XCHAR_TABLE (obj)->purpose, Qsyntax_table),
+             Qsyntax_table_p, obj);
 }
 
 DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0,
@@ -854,29 +856,6 @@ char syntax_code_spec[16] =
 static Lisp_Object Vsyntax_code_object;
 
 \f
-/* Look up the value for CHARACTER in syntax table TABLE's parent
-   and its parents.  SYNTAX_ENTRY calls this, when TABLE itself has nil
-   for CHARACTER.  It's actually used only when not compiled with GCC.  */
-
-Lisp_Object
-syntax_parent_lookup (table, character)
-     Lisp_Object table;
-     int character;
-{
-  Lisp_Object value;
-
-  while (1)
-    {
-      table = XCHAR_TABLE (table)->parent;
-      if (NILP (table))
-       return Qnil;
-
-      value = XCHAR_TABLE (table)->contents[character];
-      if (!NILP (value))
-       return value;
-    }
-}
-
 DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0,
        doc: /* Return the syntax code of CHARACTER, described by a character.
 For example, if CHARACTER is a word constituent,
@@ -915,7 +894,7 @@ DEFUN ("string-to-syntax", Fstring_to_syntax, Sstring_to_syntax, 1, 1, 0,
        doc: /* Convert a syntax specification STRING into syntax cell form.
 STRING should be a string as it is allowed as argument of
 `modify-syntax-entry'.  Value is the equivalent cons cell
-(CODE . MATCHING-CHAR) that can be used as value of a `syntax-table'
+\(CODE . MATCHING-CHAR) that can be used as value of a `syntax-table'
 text property.  */)
      (string)
      Lisp_Object string;
@@ -995,6 +974,8 @@ DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
        doc: /* Set syntax for character CHAR according to string NEWENTRY.
 The syntax is changed only for table SYNTAX-TABLE, which defaults to
  the current buffer's syntax table.
+CHAR may be a cons (MIN . MAX), in which case, syntaxes of all characters
+in the range MIN and MAX are changed.
 The first character of NEWENTRY should be one of the following:
   Space or -  whitespace syntax.    w   word constituent.
   _           symbol constituent.   .   punctuation.
@@ -1031,14 +1012,29 @@ usage: (modify-syntax-entry CHAR NEWENTRY &optional SYNTAX-TABLE) */)
      (c, newentry, syntax_table)
      Lisp_Object c, newentry, syntax_table;
 {
-  CHECK_NUMBER (c);
+  if (CONSP (c))
+    {
+      CHECK_CHARACTER_CAR (c);
+      CHECK_CHARACTER_CDR (c);
+    }
+  else
+    CHECK_CHARACTER (c);
 
   if (NILP (syntax_table))
     syntax_table = current_buffer->syntax_table;
   else
     check_syntax_table (syntax_table);
 
-  SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), Fstring_to_syntax (newentry));
+  newentry = Fstring_to_syntax (newentry);
+  if (CONSP (c))
+    SET_RAW_SYNTAX_ENTRY_RANGE (syntax_table, c, newentry);
+  else
+    SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), newentry);
+
+  /* We clear the regexp cache, since character classes can now have
+     different values from those in the compiled regexps.*/
+  clear_regexp_cache ();
+
   return Qnil;
 }
 \f
@@ -1192,6 +1188,10 @@ DEFUN ("internal-describe-syntax-value", Finternal_describe_syntax_value,
 \f
 int parse_sexp_ignore_comments;
 
+/* Char-table of functions that find the next or previous word
+   boundary.  */
+Lisp_Object Vfind_word_boundary_function_table;
+
 /* Return the position across COUNT words from FROM.
    If that many words cannot be found before the end of the buffer, return 0.
    COUNT negative means scan backward and stop at word beginning.  */
@@ -1205,6 +1205,7 @@ scan_words (from, count)
   register int from_byte = CHAR_TO_BYTE (from);
   register enum syntaxcode code;
   int ch0, ch1;
+  Lisp_Object func, script, pos;
 
   immediate_quit = 1;
   QUIT;
@@ -1221,7 +1222,7 @@ scan_words (from, count)
              return 0;
            }
          UPDATE_SYNTAX_TABLE_FORWARD (from);
-         ch0 = FETCH_CHAR (from_byte);
+         ch0 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (ch0);
          INC_BOTH (from, from_byte);
          if (words_include_escapes
@@ -1232,18 +1233,33 @@ scan_words (from, count)
        }
       /* Now CH0 is a character which begins a word and FROM is the
          position of the next character.  */
-      while (1)
+      func = CHAR_TABLE_REF (Vfind_word_boundary_function_table, ch0);
+      if (! NILP (Ffboundp (func)))
        {
-         if (from == end) break;
-         UPDATE_SYNTAX_TABLE_FORWARD (from);
-         ch1 = FETCH_CHAR (from_byte);
-         code = SYNTAX (ch1);
-         if (!(words_include_escapes
-               && (code == Sescape || code == Scharquote)))
-           if (code != Sword || WORD_BOUNDARY_P (ch0, ch1))
-             break;
-         INC_BOTH (from, from_byte);
-         ch0 = ch1;
+         pos = call2 (func, make_number (from - 1), make_number (end));
+         if (INTEGERP (pos) && XINT (pos) > from)
+           {
+             from = XINT (pos);
+             from_byte = CHAR_TO_BYTE (from);
+           }
+       }
+      else
+       {
+         script = CHAR_TABLE_REF (Vchar_script_table, ch0);
+         while (1)
+           {
+             if (from == end) break;
+             UPDATE_SYNTAX_TABLE_FORWARD (from);
+             ch1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
+             code = SYNTAX (ch1);
+             if ((code != Sword
+                  && (! words_include_escapes
+                      || (code != Sescape && code != Scharquote)))
+                 || ! EQ (CHAR_TABLE_REF (Vchar_script_table, ch1), script))
+               break;
+             INC_BOTH (from, from_byte);
+             ch0 = ch1;
+           }
        }
       count--;
     }
@@ -1258,7 +1274,7 @@ scan_words (from, count)
            }
          DEC_BOTH (from, from_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (from);
-         ch1 = FETCH_CHAR (from_byte);
+         ch1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (ch1);
          if (words_include_escapes
              && (code == Sescape || code == Scharquote))
@@ -1268,22 +1284,37 @@ scan_words (from, count)
        }
       /* Now CH1 is a character which ends a word and FROM is the
          position of it.  */
-      while (1)
+      func = CHAR_TABLE_REF (Vfind_word_boundary_function_table, ch1);
+      if (! NILP (Ffboundp (func)))
+       {
+         pos = call2 (func, make_number (from), make_number (beg));
+         if (INTEGERP (pos) && XINT (pos) < from)
+           {
+             from = XINT (pos);
+             from_byte = CHAR_TO_BYTE (from);
+           }
+       }
+      else
        {
-         int temp_byte;
-
-         if (from == beg)
-           break;
-         temp_byte = dec_bytepos (from_byte);
-         UPDATE_SYNTAX_TABLE_BACKWARD (from);
-         ch0 = FETCH_CHAR (temp_byte);
-         code = SYNTAX (ch0);
-         if (!(words_include_escapes
-               && (code == Sescape || code == Scharquote)))
-           if (code != Sword || WORD_BOUNDARY_P (ch0, ch1))
-             break;
-         DEC_BOTH (from, from_byte);
-         ch1 = ch0;
+         script = CHAR_TABLE_REF (Vchar_script_table, ch1);
+         while (1)
+           {
+             if (from == beg)
+               break;
+             DEC_BOTH (from, from_byte);
+             UPDATE_SYNTAX_TABLE_BACKWARD (from);
+             ch0 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
+             code = SYNTAX (ch0);
+             if ((code != Sword
+                  && (! words_include_escapes
+                      || (code != Sescape && code != Scharquote)))
+                 || ! EQ (CHAR_TABLE_REF (Vchar_script_table, ch0), script))
+               {
+                 INC_BOTH (from, from_byte);
+                 break;
+               }
+             ch1 = ch0;
+           }
        }
       count++;
     }
@@ -1338,7 +1369,7 @@ Returns the distance traveled, either zero or positive.  */)
      (string, lim)
      Lisp_Object string, lim;
 {
-  return skip_chars (1, 0, string, lim, 1);
+  return skip_chars (1, string, lim, 1);
 }
 
 DEFUN ("skip-chars-backward", Fskip_chars_backward, Sskip_chars_backward, 1, 2, 0,
@@ -1348,7 +1379,7 @@ Returns the distance traveled, either zero or negative.  */)
      (string, lim)
      Lisp_Object string, lim;
 {
-  return skip_chars (0, 0, string, lim, 1);
+  return skip_chars (0, string, lim, 1);
 }
 
 DEFUN ("skip-syntax-forward", Fskip_syntax_forward, Sskip_syntax_forward, 1, 2, 0,
@@ -1360,7 +1391,7 @@ This function returns the distance traveled, either zero or positive.  */)
      (syntax, lim)
      Lisp_Object syntax, lim;
 {
-  return skip_chars (1, 1, syntax, lim, 0);
+  return skip_syntaxes (1, syntax, lim);
 }
 
 DEFUN ("skip-syntax-backward", Fskip_syntax_backward, Sskip_syntax_backward, 1, 2, 0,
@@ -1372,25 +1403,27 @@ This function returns the distance traveled, either zero or negative.  */)
      (syntax, lim)
      Lisp_Object syntax, lim;
 {
-  return skip_chars (0, 1, syntax, lim, 0);
+  return skip_syntaxes (0, syntax, lim);
 }
 
 static Lisp_Object
-skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
-     int forwardp, syntaxp;
+skip_chars (forwardp, string, lim, handle_iso_classes)
+     int forwardp;
      Lisp_Object string, lim;
      int handle_iso_classes;
 {
   register unsigned int c;
   unsigned char fastmap[0400];
-  /* If SYNTAXP is 0, STRING may contain multi-byte form of characters
-     of which codes don't fit in FASTMAP.  In that case, set the
-     ranges of characters in CHAR_RANGES.  */
+  /* Store the ranges of non-ASCII characters.  */
   int *char_ranges;
   int n_char_ranges = 0;
   int negate = 0;
   register int i, i_byte;
-  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  /* Set to 1 if the current buffer is multibyte and the region
+     contains non-ASCII chars.  */
+  int multibyte;
+  /* Set to 1 if STRING is multibyte and it contains non-ASCII
+     chars.  */
   int string_multibyte;
   int size_byte;
   const unsigned char *str;
@@ -1398,32 +1431,8 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
   Lisp_Object iso_classes;
 
   CHECK_STRING (string);
-  char_ranges = (int *) alloca (SCHARS (string) * (sizeof (int)) * 2);
-  string_multibyte = STRING_MULTIBYTE (string);
-  str = SDATA (string);
-  size_byte = SBYTES (string);
   iso_classes = Qnil;
 
-  /* Adjust the multibyteness of the string to that of the buffer.  */
-  if (multibyte != string_multibyte)
-    {
-      int nbytes;
-
-      if (multibyte)
-       nbytes = count_size_as_multibyte (SDATA (string),
-                                         SCHARS (string));
-      else
-       nbytes = SCHARS (string);
-      if (nbytes != size_byte)
-       {
-         unsigned char *tmp = (unsigned char *) alloca (nbytes);
-         copy_text (SDATA (string), tmp, size_byte,
-                    string_multibyte, multibyte);
-         size_byte = nbytes;
-         str = tmp;
-       }
-    }
-
   if (NILP (lim))
     XSETINT (lim, forwardp ? ZV : BEGV);
   else
@@ -1435,10 +1444,16 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
   if (XINT (lim) < BEGV)
     XSETFASTINT (lim, BEGV);
 
+  multibyte = (!NILP (current_buffer->enable_multibyte_characters)
+              && (XINT (lim) - PT != CHAR_TO_BYTE (XINT (lim)) - PT_BYTE));
+  string_multibyte = SBYTES (string) > SCHARS (string);
+
   bzero (fastmap, sizeof fastmap);
 
-  i_byte = 0;
+  str = SDATA (string);
+  size_byte = SBYTES (string);
 
+  i_byte = 0;
   if (i_byte < size_byte
       && SREF (string, 0) == '^')
     {
@@ -1446,26 +1461,28 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
     }
 
   /* Find the characters specified and set their elements of fastmap.
-     If syntaxp, each character counts as itself.
-     Otherwise, handle backslashes and ranges specially.  */
+     Handle backslashes and ranges specially.
 
-  while (i_byte < size_byte)
+     If STRING contains non-ASCII characters, setup char_ranges for
+     them and use fastmap only for their leading codes.  */
+
+  if (! string_multibyte)
     {
-      c = STRING_CHAR_AND_LENGTH (str + i_byte, size_byte - i_byte, len);
-      i_byte += len;
+      int string_has_eight_bit = 0;
 
-      if (syntaxp)
-       fastmap[syntax_spec_code[c & 0377]] = 1;
-      else
+      /* At first setup fastmap.  */
+      while (i_byte < size_byte)
        {
+         c = str[i_byte++];
+
          if (handle_iso_classes && c == '['
              && i_byte < size_byte
-             && STRING_CHAR (str + i_byte, size_byte - i_byte) == ':')
+             && str[i_byte] == ':')
            {
              const unsigned char *class_beg = str + i_byte + 1;
              const unsigned char *class_end = class_beg;
              const unsigned char *class_limit = str + size_byte - 2;
-             /* Leave room for the null.        */
+             /* Leave room for the null.  */
              unsigned char class_name[CHAR_CLASS_MAX_LENGTH + 1];
              re_wctype_t cc;
 
@@ -1499,6 +1516,129 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
              if (i_byte == size_byte)
                break;
 
+             c = str[i_byte++];
+           }
+         /* Treat `-' as range character only if another character
+            follows.  */
+         if (i_byte + 1 < size_byte
+             && str[i_byte] == '-')
+           {
+             unsigned int c2;
+
+             /* Skip over the dash.  */
+             i_byte++;
+
+             /* Get the end of the range.  */
+             c2 = str[i_byte++];
+             if (c2 == '\\'
+                 && i_byte < size_byte)
+               c2 = str[i_byte++];
+
+             if (c <= c2)
+               {
+                 while (c <= c2)
+                   fastmap[c++] = 1;
+                 if (! ASCII_CHAR_P (c2))
+                   string_has_eight_bit = 1;
+               }
+           }
+         else
+           {
+             fastmap[c] = 1;
+             if (! ASCII_CHAR_P (c))
+               string_has_eight_bit = 1;
+           }
+       }
+
+      /* If the current range is multibyte and STRING contains
+        eight-bit chars, arrange fastmap and setup char_ranges for
+        the corresponding multibyte chars.  */
+      if (multibyte && string_has_eight_bit)
+       {
+         unsigned char fastmap2[0400];
+         int range_start_byte, range_start_char;
+
+         bcopy (fastmap2 + 0200, fastmap + 0200, 0200);
+         bzero (fastmap + 0200, 0200);
+         /* We are sure that this loop stops.  */
+         for (i = 0200; ! fastmap2[i]; i++);
+         c = unibyte_char_to_multibyte (i);
+         fastmap[CHAR_LEADING_CODE (c)] = 1;
+         range_start_byte = i;
+         range_start_char = c;
+         char_ranges = (int *) alloca (sizeof (int) * 128 * 2);
+         for (i = 129; i < 0400; i++)
+           {
+             c = unibyte_char_to_multibyte (i);
+             fastmap[CHAR_LEADING_CODE (c)] = 1;
+             if (i - range_start_byte != c - range_start_char)
+               {
+                 char_ranges[n_char_ranges++] = range_start_char;
+                 char_ranges[n_char_ranges++] = ((i - 1 - range_start_byte)
+                                                 + range_start_char);
+                 range_start_byte = i;
+                 range_start_char = c;
+               }
+           }
+         char_ranges[n_char_ranges++] = range_start_char;
+         char_ranges[n_char_ranges++] = ((i - 1 - range_start_byte)
+                                         + range_start_char);
+       }
+    }
+  else                         /* STRING is multibyte */
+    {
+      char_ranges = (int *) alloca (sizeof (int) * SCHARS (string) * 2);
+
+      while (i_byte < size_byte)
+       {
+         unsigned char leading_code;
+
+         leading_code = str[i_byte];
+         c = STRING_CHAR_AND_LENGTH (str + i_byte, size_byte-i_byte, len);
+         i_byte += len;
+
+         if (handle_iso_classes && c == '['
+             && i_byte < size_byte
+             && STRING_CHAR (str + i_byte, size_byte - i_byte) == ':')
+           {
+             const unsigned char *class_beg = str + i_byte + 1;
+             const unsigned char *class_end = class_beg;
+             const unsigned char *class_limit = str + size_byte - 2;
+             /* Leave room for the null.        */
+             unsigned char class_name[CHAR_CLASS_MAX_LENGTH + 1];
+             re_wctype_t cc;
+
+             if (class_limit - class_beg > CHAR_CLASS_MAX_LENGTH)
+               class_limit = class_beg + CHAR_CLASS_MAX_LENGTH;
+
+             while (class_end < class_limit
+                    && *class_end >= 'a' && *class_end <= 'z')
+               class_end++;
+
+             if (class_end == class_beg
+                 || *class_end != ':' || class_end[1] != ']')
+               goto not_a_class_name_multibyte;
+
+             bcopy (class_beg, class_name, class_end - class_beg);
+             class_name[class_end - class_beg] = 0;
+
+             cc = re_wctype (class_name);
+             if (cc == 0)
+               error ("Invalid ISO C character class");
+
+             iso_classes = Fcons (make_number (cc), iso_classes);
+
+             i_byte = class_end + 2 - str;
+             continue;
+           }
+
+       not_a_class_name_multibyte:
+         if (c == '\\')
+           {
+             if (i_byte == size_byte)
+               break;
+
+             leading_code = str[i_byte];
              c = STRING_CHAR_AND_LENGTH (str + i_byte,
                                          size_byte - i_byte, len);
              i_byte += len;
@@ -1509,61 +1649,90 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
              && str[i_byte] == '-')
            {
              unsigned int c2;
+             unsigned char leading_code2;
 
              /* Skip over the dash.  */
              i_byte++;
 
              /* Get the end of the range.  */
+             leading_code2 = str[i_byte];
              c2 = STRING_CHAR_AND_LENGTH (str + i_byte,
                                           size_byte - i_byte, len);
              i_byte += len;
 
-             if (SINGLE_BYTE_CHAR_P (c))
+             if (c2 == '\\'
+                 && i_byte < size_byte)
+               {
+                 leading_code2 = str[i_byte];
+                 c2 =STRING_CHAR_AND_LENGTH (str + i_byte, size_byte-i_byte, len);
+                 i_byte += len;
+               }
+
+             if (c > c2)
+               continue;
+             if (ASCII_CHAR_P (c))
+               {
+                 while (c <= c2 && c < 0x80)
+                   fastmap[c++] = 1;
+                 leading_code = CHAR_LEADING_CODE (c);
+               }
+             if (! ASCII_CHAR_P (c))
                {
-                 if (! SINGLE_BYTE_CHAR_P (c2))
+                 while (leading_code <= leading_code2)
+                   fastmap[leading_code++] = 1;
+                 if (c <= c2)
                    {
-                     /* Handle a range starting with a character of
-                        less than 256, and ending with a character of
-                        not less than 256.  Split that into two
-                        ranges, the low one ending at 0377, and the
-                        high one starting at the smallest character
-                        in the charset of C2 and ending at C2.  */
-                     int charset = CHAR_CHARSET (c2);
-                     int c1 = MAKE_CHAR (charset, 0, 0);
-
-                     char_ranges[n_char_ranges++] = c1;
+                     char_ranges[n_char_ranges++] = c;
                      char_ranges[n_char_ranges++] = c2;
-                     c2 = 0377;
-                   }
-                 while (c <= c2)
-                   {
-                     fastmap[c] = 1;
-                     c++;
                    }
                }
-             else if (c <= c2) /* Both C and C2 are multibyte char.  */
-               {
-                 char_ranges[n_char_ranges++] = c;
-                 char_ranges[n_char_ranges++] = c2;
-               }
            }
          else
            {
-             if (SINGLE_BYTE_CHAR_P (c))
+             if (ASCII_CHAR_P (c))
                fastmap[c] = 1;
              else
                {
+                 fastmap[leading_code] = 1;
                  char_ranges[n_char_ranges++] = c;
                  char_ranges[n_char_ranges++] = c;
                }
            }
        }
+
+      /* If the current range is unibyte and STRING contains non-ASCII
+        chars, arrange fastmap for the corresponding unibyte
+        chars.  */
+
+      if (! multibyte && n_char_ranges > 0)
+       {
+         bzero (fastmap + 0200, 0200);
+         for (i = 0; i < n_char_ranges; i += 2)
+           {
+             int c1 = char_ranges[i];
+             int c2 = char_ranges[i + 1];
+
+             for (; c1 <= c2; c1++)
+               fastmap[CHAR_TO_BYTE8 (c1)] = 1;
+           }
+       }
     }
 
   /* If ^ was the first character, complement the fastmap.  */
   if (negate)
-    for (i = 0; i < sizeof fastmap; i++)
-      fastmap[i] ^= 1;
+    {
+      if (! multibyte)
+       for (i = 0; i < sizeof fastmap; i++)
+         fastmap[i] ^= 1;
+      else
+       {
+         for (i = 0; i < 0200; i++)
+           fastmap[i] ^= 1;
+         /* All non-ASCII chars possibly match.  */
+         for (; i < sizeof fastmap; i++)
+           fastmap[i] = 1;
+       }
+    }
 
   {
     int start_point = PT;
@@ -1583,254 +1752,312 @@ skip_chars (forwardp, syntaxp, string, lim, handle_iso_classes)
       }
 
     immediate_quit = 1;
-    if (syntaxp)
+    if (forwardp)
       {
-        SETUP_SYNTAX_TABLE (pos, forwardp ? 1 : -1);
-       if (forwardp)
-         {
-           if (multibyte)
-             while (1)
-               {
-                 int nbytes;
+       if (multibyte)
+         while (1)
+           {
+             int nbytes;
 
-                 if (p >= stop)
-                   {
-                     if (p >= endp)
-                       break;
-                     p = GAP_END_ADDR;
-                     stop = endp;
-                   }
-                 c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, nbytes);
-                 if (! fastmap[(int) SYNTAX (c)])
+             if (p >= stop)
+               {
+                 if (p >= endp)
                    break;
-                 p += nbytes, pos++, pos_byte += nbytes;
-                 UPDATE_SYNTAX_TABLE_FORWARD (pos);
+                 p = GAP_END_ADDR;
+                 stop = endp;
                }
-           else
-             while (1)
+             c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, nbytes);
+             if (! NILP (iso_classes) && in_classes (c, iso_classes))
                {
-                 if (p >= stop)
-                   {
-                     if (p >= endp)
-                       break;
-                     p = GAP_END_ADDR;
-                     stop = endp;
-                   }
-                 if (! fastmap[(int) SYNTAX (*p)])
+                 if (negate)
                    break;
-                 p++, pos++;
-                 UPDATE_SYNTAX_TABLE_FORWARD (pos);
+                 else
+                   goto fwd_ok;
                }
-         }
-       else
-         {
-           if (multibyte)
-             while (1)
-               {
-                 unsigned char *prev_p;
-                 int nbytes;
 
-                 if (p <= stop)
-                   {
-                     if (p <= endp)
-                       break;
-                     p = GPT_ADDR;
-                     stop = endp;
-                   }
-                 prev_p = p;
-                 while (--p >= stop && ! CHAR_HEAD_P (*p));
-                 PARSE_MULTIBYTE_SEQ (p, MAX_MULTIBYTE_LENGTH, nbytes);
-                 if (prev_p - p > nbytes)
-                   p = prev_p - 1, c = *p, nbytes = 1;
-                 else
-                   c = STRING_CHAR (p, MAX_MULTIBYTE_LENGTH);
-                 pos--, pos_byte -= nbytes;
-                 UPDATE_SYNTAX_TABLE_BACKWARD (pos);
-                 if (! fastmap[(int) SYNTAX (c)])
-                   {
-                     pos++;
-                     pos_byte += nbytes;
+             if (! fastmap[*p])
+               break;
+             if (! ASCII_CHAR_P (c))
+               {
+                 /* As we are looking at a multibyte character, we
+                    must look up the character in the table
+                    CHAR_RANGES.  If there's no data in the table,
+                    that character is not what we want to skip.  */
+
+                 /* The following code do the right thing even if
+                    n_char_ranges is zero (i.e. no data in
+                    CHAR_RANGES).  */
+                 for (i = 0; i < n_char_ranges; i += 2)
+                   if (c >= char_ranges[i] && c <= char_ranges[i + 1])
                      break;
-                   }
+                 if (!(negate ^ (i < n_char_ranges)))
+                   break;
                }
-           else
-             while (1)
+           fwd_ok:
+             p += nbytes, pos++, pos_byte += nbytes;
+           }
+       else
+         while (1)
+           {
+             if (p >= stop)
                {
-                 if (p <= stop)
-                   {
-                     if (p <= endp)
-                       break;
-                     p = GPT_ADDR;
-                     stop = endp;
-                   }
-                 if (! fastmap[(int) SYNTAX (p[-1])])
+                 if (p >= endp)
                    break;
-                 p--, pos--;
-                 UPDATE_SYNTAX_TABLE_BACKWARD (pos - 1);
+                 p = GAP_END_ADDR;
+                 stop = endp;
                }
-         }
+
+             if (!NILP (iso_classes) && in_classes (*p, iso_classes))
+               {
+                 if (negate)
+                   break;
+                 else
+                   goto fwd_unibyte_ok;
+               }
+
+             if (!fastmap[*p])
+               break;
+           fwd_unibyte_ok:
+             p++, pos++, pos_byte++;
+           }
       }
     else
       {
-       if (forwardp)
-         {
-           if (multibyte)
-             while (1)
-               {
-                 int nbytes;
-
-                 if (p >= stop)
-                   {
-                     if (p >= endp)
-                       break;
-                     p = GAP_END_ADDR;
-                     stop = endp;
-                   }
-                 c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, nbytes);
+       if (multibyte)
+         while (1)
+           {
+             unsigned char *prev_p;
 
-                 if (! NILP (iso_classes) && in_classes (c, iso_classes))
-                   {
-                     if (negate)
-                       break;
-                     else
-                       goto fwd_ok;
-                   }
+             if (p <= stop)
+               {
+                 if (p <= endp)
+                   break;
+                 p = GPT_ADDR;
+                 stop = endp;
+               }
+             prev_p = p;
+             while (--p >= stop && ! CHAR_HEAD_P (*p));
+             c = STRING_CHAR (p, MAX_MULTIBYTE_LENGTH);
 
-                 if (SINGLE_BYTE_CHAR_P (c))
-                   {
-                     if (!fastmap[c])
-                       break;
-                   }
+             if (! NILP (iso_classes) && in_classes (c, iso_classes))
+               {
+                 if (negate)
+                   break;
                  else
-                   {
-                     /* If we are looking at a multibyte character,
-                        we must look up the character in the table
-                        CHAR_RANGES.  If there's no data in the
-                        table, that character is not what we want to
-                        skip.  */
-
-                     /* The following code do the right thing even if
-                        n_char_ranges is zero (i.e. no data in
-                        CHAR_RANGES).  */
-                     for (i = 0; i < n_char_ranges; i += 2)
-                       if (c >= char_ranges[i] && c <= char_ranges[i + 1])
-                         break;
-                     if (!(negate ^ (i < n_char_ranges)))
-                       break;
-                   }
-               fwd_ok:
-                 p += nbytes, pos++, pos_byte += nbytes;
+                   goto back_ok;
                }
-           else
-             while (1)
-               {
-                 if (p >= stop)
-                   {
-                     if (p >= endp)
-                       break;
-                     p = GAP_END_ADDR;
-                     stop = endp;
-                   }
 
-                 if (!NILP (iso_classes) && in_classes (*p, iso_classes))
-                   {
-                     if (negate)
-                       break;
-                     else
-                       goto fwd_unibyte_ok;
-                   }
-
-                 if (!fastmap[*p])
+             if (! fastmap[*p])
+               break;
+             if (! ASCII_CHAR_P (c))
+               {
+                 /* See the comment in the previous similar code.  */
+                 for (i = 0; i < n_char_ranges; i += 2)
+                   if (c >= char_ranges[i] && c <= char_ranges[i + 1])
+                     break;
+                 if (!(negate ^ (i < n_char_ranges)))
                    break;
-               fwd_unibyte_ok:
-                 p++, pos++;
                }
-         }
+           back_ok:
+             pos--, pos_byte -= prev_p - p;
+           }
        else
-         {
-           if (multibyte)
-             while (1)
+         while (1)
+           {
+             if (p <= stop)
                {
-                 unsigned char *prev_p;
-                 int nbytes;
+                 if (p <= endp)
+                   break;
+                 p = GPT_ADDR;
+                 stop = endp;
+               }
 
-                 if (p <= stop)
-                   {
-                     if (p <= endp)
-                       break;
-                     p = GPT_ADDR;
-                     stop = endp;
-                   }
-                 prev_p = p;
-                 while (--p >= stop && ! CHAR_HEAD_P (*p));
-                 PARSE_MULTIBYTE_SEQ (p, MAX_MULTIBYTE_LENGTH, nbytes);
-                 if (prev_p - p > nbytes)
-                   p = prev_p - 1, c = *p, nbytes = 1;
+             if (! NILP (iso_classes) && in_classes (p[-1], iso_classes))
+               {
+                 if (negate)
+                   break;
                  else
-                   c = STRING_CHAR (p, MAX_MULTIBYTE_LENGTH);
+                   goto back_unibyte_ok;
+               }
 
-                 if (! NILP (iso_classes) && in_classes (c, iso_classes))
-                   {
-                     if (negate)
-                       break;
-                     else
-                       goto back_ok;
-                   }
+             if (!fastmap[p[-1]])
+               break;
+           back_unibyte_ok:
+             p--, pos--, pos_byte--;
+           }
+      }
 
-                 if (SINGLE_BYTE_CHAR_P (c))
-                   {
-                     if (!fastmap[c])
-                       break;
-                   }
-                 else
-                   {
-                     /* See the comment in the previous similar code.  */
-                     for (i = 0; i < n_char_ranges; i += 2)
-                       if (c >= char_ranges[i] && c <= char_ranges[i + 1])
-                         break;
-                     if (!(negate ^ (i < n_char_ranges)))
-                       break;
-                   }
-               back_ok:
-                 pos--, pos_byte -= nbytes;
-               }
-           else
-             while (1)
-               {
-                 if (p <= stop)
-                   {
-                     if (p <= endp)
-                       break;
-                     p = GPT_ADDR;
-                     stop = endp;
-                   }
+    SET_PT_BOTH (pos, pos_byte);
+    immediate_quit = 0;
 
-                 if (! NILP (iso_classes) && in_classes (p[-1], iso_classes))
-                   {
-                     if (negate)
-                       break;
-                     else
-                       goto back_unibyte_ok;
-                   }
+    return make_number (PT - start_point);
+  }
+}
 
-                 if (!fastmap[p[-1]])
-                   break;
-               back_unibyte_ok:
-                 p--, pos--;
-               }
-         }
+
+static Lisp_Object
+skip_syntaxes (forwardp, string, lim)
+     int forwardp;
+     Lisp_Object string, lim;
+{
+  register unsigned int c;
+  unsigned char fastmap[0400];
+  int negate = 0;
+  register int i, i_byte;
+  int multibyte;
+  int size_byte;
+  unsigned char *str;
+
+  CHECK_STRING (string);
+
+  if (NILP (lim))
+    XSETINT (lim, forwardp ? ZV : BEGV);
+  else
+    CHECK_NUMBER_COERCE_MARKER (lim);
+
+  /* In any case, don't allow scan outside bounds of buffer.  */
+  if (XINT (lim) > ZV)
+    XSETFASTINT (lim, ZV);
+  if (XINT (lim) < BEGV)
+    XSETFASTINT (lim, BEGV);
+
+  if (forwardp ? (PT >= XFASTINT (lim)) : (PT <= XFASTINT (lim)))
+    return make_number (0);
+
+  multibyte = (!NILP (current_buffer->enable_multibyte_characters)
+              && (XINT (lim) - PT != CHAR_TO_BYTE (XINT (lim)) - PT_BYTE));
+
+  bzero (fastmap, sizeof fastmap);
+
+  if (SBYTES (string) > SCHARS (string))
+    /* As this is very rare case (syntax spec is ASCII only), don't
+       consider efficiency.  */
+    string = string_make_unibyte (string);
+
+  str = SDATA (string);
+  size_byte = SBYTES (string);
+
+  i_byte = 0;
+  if (i_byte < size_byte
+      && SREF (string, 0) == '^')
+    {
+      negate = 1; i_byte++;
+    }
+
+  /* Find the syntaxes specified and set their elements of fastmap.  */
+
+  while (i_byte < size_byte)
+    {
+      c = str[i_byte++];
+      fastmap[syntax_spec_code[c]] = 1;
+    }
+
+  /* If ^ was the first character, complement the fastmap.  */
+  if (negate)
+    for (i = 0; i < sizeof fastmap; i++)
+      fastmap[i] ^= 1;
+
+  {
+    int start_point = PT;
+    int pos = PT;
+    int pos_byte = PT_BYTE;
+    unsigned char *p = PT_ADDR, *endp, *stop;
+
+    if (forwardp)
+      {
+       endp = (XINT (lim) == GPT) ? GPT_ADDR : CHAR_POS_ADDR (XINT (lim));
+       stop = (pos < GPT && GPT < XINT (lim)) ? GPT_ADDR : endp;
+      }
+    else
+      {
+       endp = CHAR_POS_ADDR (XINT (lim));
+       stop = (pos >= GPT && GPT > XINT (lim)) ? GAP_END_ADDR : endp;
       }
 
-#if 0 /* Not needed now that a position in mid-character
-        cannot be specified in Lisp.  */
-    if (multibyte
-       /* INC_POS or DEC_POS might have moved POS over LIM.  */
-       && (forwardp ? (pos > XINT (lim)) : (pos < XINT (lim))))
-      pos = XINT (lim);
-#endif
+    immediate_quit = 1;
+    SETUP_SYNTAX_TABLE (pos, forwardp ? 1 : -1);
+    if (forwardp)
+      {
+       if (multibyte)
+         {
+           while (1)
+             {
+               int nbytes;
+
+               if (p >= stop)
+                 {
+                   if (p >= endp)
+                     break;
+                   p = GAP_END_ADDR;
+                   stop = endp;
+                 }
+               c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, nbytes);
+               if (! fastmap[(int) SYNTAX (c)])
+                 break;
+               p += nbytes, pos++, pos_byte += nbytes;
+               UPDATE_SYNTAX_TABLE_FORWARD (pos);
+             }
+         }
+       else
+         {
+           while (1)
+             {
+               if (p >= stop)
+                 {
+                   if (p >= endp)
+                     break;
+                   p = GAP_END_ADDR;
+                   stop = endp;
+                 }
+               if (! fastmap[(int) SYNTAX (*p)])
+                 break;
+               p++, pos++, pos_byte++;
+               UPDATE_SYNTAX_TABLE_FORWARD (pos);
+             }
+         }
+      }
+    else
+      {
+       if (multibyte)
+         {
+           while (1)
+             {
+               unsigned char *prev_p;
 
-    if (! multibyte)
-      pos_byte = pos;
+               if (p <= stop)
+                 {
+                   if (p <= endp)
+                     break;
+                   p = GPT_ADDR;
+                   stop = endp;
+                 }
+               UPDATE_SYNTAX_TABLE_BACKWARD (pos - 1);
+               prev_p = p;
+               while (--p >= stop && ! CHAR_HEAD_P (*p));
+               c = STRING_CHAR (p, MAX_MULTIBYTE_LENGTH);
+               if (! fastmap[(int) SYNTAX (c)])
+                 break;
+               pos--, pos_byte -= prev_p - p;
+             }
+         }
+       else
+         {
+           while (1)
+             {
+               if (p <= stop)
+                 {
+                   if (p <= endp)
+                     break;
+                   p = GPT_ADDR;
+                   stop = endp;
+                 }
+               UPDATE_SYNTAX_TABLE_BACKWARD (pos - 1);
+               if (! fastmap[(int) SYNTAX (p[-1])])
+                 break;
+               p--, pos--, pos_byte--;
+             }
+         }
+      }
 
     SET_PT_BOTH (pos, pos_byte);
     immediate_quit = 0;
@@ -1890,9 +2117,10 @@ in_classes (c, iso_classes)
 static int
 forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
              charpos_ptr, bytepos_ptr, incomment_ptr)
-     int from, from_byte, stop;
+     EMACS_INT from, from_byte, stop;
      int nesting, style, prev_syntax;
-     int *charpos_ptr, *bytepos_ptr, *incomment_ptr;
+     EMACS_INT *charpos_ptr, *bytepos_ptr;
+     int *incomment_ptr;
 {
   register int c, c1;
   register enum syntaxcode code;
@@ -1914,7 +2142,7 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
          *bytepos_ptr = from_byte;
          return 0;
        }
-      c = FETCH_CHAR (from_byte);
+      c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
       syntax = SYNTAX_WITH_FLAGS (c);
       code = syntax & 0xff;
       if (code == Sendcomment
@@ -1944,7 +2172,7 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
     forw_incomment:
       if (from < stop && SYNTAX_FLAGS_COMEND_FIRST (syntax)
          && SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style
-         && (c1 = FETCH_CHAR (from_byte),
+         && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
              SYNTAX_COMEND_SECOND (c1))
          && ((SYNTAX_FLAGS_COMMENT_NESTED (syntax) ||
               SYNTAX_COMMENT_NESTED (c1)) ? nesting > 0 : nesting < 0))
@@ -1963,7 +2191,7 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
       if (nesting > 0
          && from < stop
          && SYNTAX_FLAGS_COMSTART_FIRST (syntax)
-         && (c1 = FETCH_CHAR (from_byte),
+         && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
              SYNTAX_COMMENT_STYLE (c1) == style
              && SYNTAX_COMSTART_SECOND (c1))
          && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ||
@@ -1992,16 +2220,16 @@ between them, return t; otherwise return nil.  */)
      (count)
      Lisp_Object count;
 {
-  register int from;
-  int from_byte;
-  register int stop;
+  register EMACS_INT from;
+  EMACS_INT from_byte;
+  register EMACS_INT stop;
   register int c, c1;
   register enum syntaxcode code;
   int comstyle = 0;        /* style of comment encountered */
   int comnested = 0;       /* whether the comment is nestable or not */
   int found;
-  int count1;
-  int out_charpos, out_bytepos;
+  EMACS_INT count1;
+  EMACS_INT out_charpos, out_bytepos;
   int dummy;
 
   CHECK_NUMBER (count);
@@ -2027,7 +2255,7 @@ between them, return t; otherwise return nil.  */)
              immediate_quit = 0;
              return Qnil;
            }
-         c = FETCH_CHAR (from_byte);
+         c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (c);
          comstart_first = SYNTAX_COMSTART_FIRST (c);
          comnested = SYNTAX_COMMENT_NESTED (c);
@@ -2035,7 +2263,7 @@ between them, return t; otherwise return nil.  */)
          INC_BOTH (from, from_byte);
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          if (from < stop && comstart_first
-             && (c1 = FETCH_CHAR (from_byte),
+             && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
                  SYNTAX_COMSTART_SECOND (c1)))
            {
              /* We have encountered a comment start sequence and we
@@ -2093,7 +2321,7 @@ between them, return t; otherwise return nil.  */)
          DEC_BOTH (from, from_byte);
          /* char_quoted does UPDATE_SYNTAX_TABLE_BACKWARD (from).  */
          quoted = char_quoted (from, from_byte);
-         c = FETCH_CHAR (from_byte);
+         c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX (c);
          comstyle = 0;
          comnested = SYNTAX_COMMENT_NESTED (c);
@@ -2110,7 +2338,7 @@ between them, return t; otherwise return nil.  */)
              code = Sendcomment;
              /* Calling char_quoted, above, set up global syntax position
                 at the new value of FROM.  */
-             c1 = FETCH_CHAR (from_byte);
+             c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              comstyle = SYNTAX_COMMENT_STYLE (c1);
              comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
            }
@@ -2123,16 +2351,16 @@ between them, return t; otherwise return nil.  */)
              while (1)
                {
                  DEC_BOTH (from, from_byte);
-                 if (from == stop)
-                   break;
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
-                 c = FETCH_CHAR (from_byte);
+                 c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
                  if (SYNTAX (c) == Scomment_fence
                      && !char_quoted (from, from_byte))
                    {
                      found = 1;
                      break;
                    }
+                 else if (from == stop)
+                   break;
                }
              if (found == 0)
                {
@@ -2140,6 +2368,9 @@ between them, return t; otherwise return nil.  */)
                  from_byte = ini_byte;
                  goto leave;
                }
+             else
+               /* We have skipped one comment.  */
+               break;
            }
          else if (code == Sendcomment)
            {
@@ -2187,20 +2418,21 @@ between them, return t; otherwise return nil.  */)
   return Qt;
 }
 \f
-/* Return syntax code of character C if C is a single byte character
+/* Return syntax code of character C if C is an ASCII character
    or `multibyte_symbol_p' is zero.  Otherwise, return Ssymbol.  */
 
-#define SYNTAX_WITH_MULTIBYTE_CHECK(c)                 \
-  ((SINGLE_BYTE_CHAR_P (c) || !multibyte_symbol_p)     \
+#define SYNTAX_WITH_MULTIBYTE_CHECK(c)         \
+  ((ASCII_CHAR_P (c) || !multibyte_symbol_p)   \
    ? SYNTAX (c) : Ssymbol)
 
 static Lisp_Object
 scan_lists (from, count, depth, sexpflag)
-     register int from;
-     int count, depth, sexpflag;
+     register EMACS_INT from;
+     EMACS_INT count, depth;
+     int sexpflag;
 {
   Lisp_Object val;
-  register int stop = count > 0 ? ZV : BEGV;
+  register EMACS_INT stop = count > 0 ? ZV : BEGV;
   register int c, c1;
   int stringterm;
   int quoted;
@@ -2209,11 +2441,11 @@ scan_lists (from, count, depth, sexpflag)
   int min_depth = depth;    /* Err out if depth gets less than this.  */
   int comstyle = 0;        /* style of comment encountered */
   int comnested = 0;       /* whether the comment is nestable or not */
-  int temp_pos;
-  int last_good = from;
+  EMACS_INT temp_pos;
+  EMACS_INT last_good = from;
   int found;
-  int from_byte;
-  int out_bytepos, out_charpos;
+  EMACS_INT from_byte;
+  EMACS_INT out_bytepos, out_charpos;
   int temp, dummy;
   int multibyte_symbol_p = sexpflag && multibyte_syntax_as_symbol;
 
@@ -2234,7 +2466,7 @@ scan_lists (from, count, depth, sexpflag)
        {
          int comstart_first, prefix;
          UPDATE_SYNTAX_TABLE_FORWARD (from);
-         c = FETCH_CHAR (from_byte);
+         c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX_WITH_MULTIBYTE_CHECK (c);
          comstart_first = SYNTAX_COMSTART_FIRST (c);
          comnested = SYNTAX_COMMENT_NESTED (c);
@@ -2245,7 +2477,8 @@ scan_lists (from, count, depth, sexpflag)
          INC_BOTH (from, from_byte);
          UPDATE_SYNTAX_TABLE_FORWARD (from);
          if (from < stop && comstart_first
-             && (c = FETCH_CHAR (from_byte), SYNTAX_COMSTART_SECOND (c))
+             && (c = FETCH_CHAR_AS_MULTIBYTE (from_byte),
+                 SYNTAX_COMSTART_SECOND (c))
              && parse_sexp_ignore_comments)
            {
              /* we have encountered a comment start sequence and we
@@ -2254,7 +2487,7 @@ scan_lists (from, count, depth, sexpflag)
                 only a comment end of the same style actually ends
                 the comment section */
              code = Scomment;
-             c1 = FETCH_CHAR (from_byte);
+             c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              comstyle = SYNTAX_COMMENT_STYLE (c1);
              comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
              INC_BOTH (from, from_byte);
@@ -2280,7 +2513,7 @@ scan_lists (from, count, depth, sexpflag)
                  UPDATE_SYNTAX_TABLE_FORWARD (from);
 
                  /* Some compilers can't handle this inside the switch.  */
-                 c = FETCH_CHAR (from_byte);
+                 c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
                  temp = SYNTAX_WITH_MULTIBYTE_CHECK (c);
                  switch (temp)
                    {
@@ -2323,7 +2556,7 @@ scan_lists (from, count, depth, sexpflag)
            case Smath:
              if (!sexpflag)
                break;
-             if (from != stop && c == FETCH_CHAR (from_byte))
+             if (from != stop && c == FETCH_CHAR_AS_MULTIBYTE (from_byte))
                {
                  INC_BOTH (from, from_byte);
                }
@@ -2342,21 +2575,20 @@ scan_lists (from, count, depth, sexpflag)
            close1:
              if (!--depth) goto done;
              if (depth < min_depth)
-               Fsignal (Qscan_error,
-                        Fcons (build_string ("Containing expression ends prematurely"),
-                               Fcons (make_number (last_good),
-                                      Fcons (make_number (from), Qnil))));
+               xsignal3 (Qscan_error,
+                         build_string ("Containing expression ends prematurely"),
+                         make_number (last_good), make_number (from));
              break;
 
            case Sstring:
            case Sstring_fence:
              temp_pos = dec_bytepos (from_byte);
-             stringterm = FETCH_CHAR (temp_pos);
+             stringterm = FETCH_CHAR_AS_MULTIBYTE (temp_pos);
              while (1)
                {
                  if (from >= stop) goto lose;
                  UPDATE_SYNTAX_TABLE_FORWARD (from);
-                 c = FETCH_CHAR (from_byte);
+                 c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
                  if (code == Sstring
                      ? (c == stringterm
                         && SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring)
@@ -2399,7 +2631,7 @@ scan_lists (from, count, depth, sexpflag)
        {
          DEC_BOTH (from, from_byte);
          UPDATE_SYNTAX_TABLE_BACKWARD (from);
-         c = FETCH_CHAR (from_byte);
+         c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
          code = SYNTAX_WITH_MULTIBYTE_CHECK (c);
          if (depth == min_depth)
            last_good = from;
@@ -2417,7 +2649,7 @@ scan_lists (from, count, depth, sexpflag)
              DEC_BOTH (from, from_byte);
              UPDATE_SYNTAX_TABLE_BACKWARD (from);
              code = Sendcomment;
-             c1 = FETCH_CHAR (from_byte);
+             c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              comstyle = SYNTAX_COMMENT_STYLE (c1);
              comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
            }
@@ -2450,7 +2682,7 @@ scan_lists (from, count, depth, sexpflag)
                  else
                    temp_pos--;
                  UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
-                 c1 = FETCH_CHAR (temp_pos);
+                 c1 = FETCH_CHAR_AS_MULTIBYTE (temp_pos);
                  temp_code = SYNTAX_WITH_MULTIBYTE_CHECK (c1);
                  /* Don't allow comment-end to be quoted.  */
                  if (temp_code == Sendcomment)
@@ -2462,7 +2694,7 @@ scan_lists (from, count, depth, sexpflag)
                      temp_pos = dec_bytepos (temp_pos);
                      UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
                    }
-                 c1 = FETCH_CHAR (temp_pos);
+                 c1 = FETCH_CHAR_AS_MULTIBYTE (temp_pos);
                  temp_code = SYNTAX_WITH_MULTIBYTE_CHECK (c1);
                  if (! (quoted || temp_code == Sword
                         || temp_code == Ssymbol
@@ -2477,7 +2709,7 @@ scan_lists (from, count, depth, sexpflag)
                break;
              temp_pos = dec_bytepos (from_byte);
              UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
-             if (from != stop && c == FETCH_CHAR (temp_pos))
+             if (from != stop && c == FETCH_CHAR_AS_MULTIBYTE (temp_pos))
                DEC_BOTH (from, from_byte);
              if (mathexit)
                {
@@ -2494,10 +2726,9 @@ scan_lists (from, count, depth, sexpflag)
            open2:
              if (!--depth) goto done2;
              if (depth < min_depth)
-               Fsignal (Qscan_error,
-                        Fcons (build_string ("Containing expression ends prematurely"),
-                               Fcons (make_number (last_good),
-                                      Fcons (make_number (from), Qnil))));
+               xsignal3 (Qscan_error,
+                         build_string ("Containing expression ends prematurely"),
+                         make_number (last_good), make_number (from));
              break;
 
            case Sendcomment:
@@ -2523,7 +2754,7 @@ scan_lists (from, count, depth, sexpflag)
                  DEC_BOTH (from, from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
                  if (!char_quoted (from, from_byte)
-                     && (c = FETCH_CHAR (from_byte),
+                     && (c = FETCH_CHAR_AS_MULTIBYTE (from_byte),
                          SYNTAX_WITH_MULTIBYTE_CHECK (c) == code))
                    break;
                }
@@ -2531,14 +2762,15 @@ scan_lists (from, count, depth, sexpflag)
              break;
 
            case Sstring:
-             stringterm = FETCH_CHAR (from_byte);
+             stringterm = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              while (1)
                {
                  if (from == stop) goto lose;
                  DEC_BOTH (from, from_byte);
                  UPDATE_SYNTAX_TABLE_BACKWARD (from);
                  if (!char_quoted (from, from_byte)
-                     && stringterm == (c = FETCH_CHAR (from_byte))
+                     && (stringterm
+                         == (c = FETCH_CHAR_AS_MULTIBYTE (from_byte)))
                      && SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring)
                    break;
                }
@@ -2566,12 +2798,9 @@ scan_lists (from, count, depth, sexpflag)
   return val;
 
  lose:
-  Fsignal (Qscan_error,
-          Fcons (build_string ("Unbalanced parentheses"),
-                 Fcons (make_number (last_good),
-                        Fcons (make_number (from), Qnil))));
-  abort ();
-  /* NOTREACHED */
+  xsignal3 (Qscan_error,
+           build_string ("Unbalanced parentheses"),
+           make_number (last_good), make_number (from));
 }
 
 DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0,
@@ -2644,7 +2873,7 @@ This includes chars with "quote" or "prefix" syntax (' or p).  */)
 
   while (!char_quoted (pos, pos_byte)
         /* Previous statement updates syntax table.  */
-        && ((c = FETCH_CHAR (pos_byte), SYNTAX (c) == Squote)
+        && ((c = FETCH_CHAR_AS_MULTIBYTE (pos_byte), SYNTAX (c) == Squote)
             || SYNTAX_PREFIX (c)))
     {
       opoint = pos;
@@ -2672,7 +2901,8 @@ scan_sexps_forward (stateptr, from, from_byte, end, targetdepth,
                    stopbefore, oldstate, commentstop)
      struct lisp_parse_state *stateptr;
      register int from;
-     int end, targetdepth, stopbefore, from_byte;
+     int from_byte;
+     int end, targetdepth, stopbefore;
      Lisp_Object oldstate;
      int commentstop;
 {
@@ -2697,7 +2927,7 @@ scan_sexps_forward (stateptr, from, from_byte, end, targetdepth,
   int boundary_stop = commentstop == -1;
   int nofence;
   int found;
-  int out_bytepos, out_charpos;
+  EMACS_INT out_bytepos, out_charpos;
   int temp;
 
   prev_from = from;
@@ -2709,7 +2939,7 @@ scan_sexps_forward (stateptr, from, from_byte, end, targetdepth,
 #define INC_FROM                               \
 do { prev_from = from;                         \
      prev_from_byte = from_byte;               \
-     temp = FETCH_CHAR (prev_from_byte);       \
+     temp = FETCH_CHAR_AS_MULTIBYTE (prev_from_byte);  \
      prev_from_syntax = SYNTAX_WITH_FLAGS (temp); \
      INC_BOTH (from, from_byte);               \
      if (from < end)                           \
@@ -2865,7 +3095,7 @@ do { prev_from = from;                            \
          while (from < end)
            {
              /* Some compilers can't handle this inside the switch.  */
-             temp = FETCH_CHAR (from_byte);
+             temp = FETCH_CHAR_AS_MULTIBYTE (from_byte);
              temp = SYNTAX (temp);
              switch (temp)
                {
@@ -2939,7 +3169,7 @@ do { prev_from = from;                            \
          if (stopbefore) goto stop;  /* this arg means stop at sexp start */
          curlevel->last = prev_from;
          state.instring = (code == Sstring
-                           ? (FETCH_CHAR (prev_from_byte))
+                           ? (FETCH_CHAR_AS_MULTIBYTE (prev_from_byte))
                            : ST_STRING_STYLE);
          if (boundary_stop) goto done;
        startinstring:
@@ -2951,7 +3181,7 @@ do { prev_from = from;                            \
                int c;
 
                if (from >= end) goto done;
-               c = FETCH_CHAR (from_byte);
+               c = FETCH_CHAR_AS_MULTIBYTE (from_byte);
                /* Some compilers can't handle this inside the switch.  */
                temp = SYNTAX (c);
 
@@ -3041,7 +3271,7 @@ Fourth arg STOPBEFORE non-nil means stop when come to
  any character that starts a sexp.
 Fifth arg OLDSTATE is a list like what this function returns.
  It is used to initialize the state of the parse.  Elements number 1, 2, 6
- and 8 are ignored; you can leave off element 8 (the last) entirely.
+ and 8 are ignored.
 Sixth arg COMMENTSTOP non-nil means stop at the start of a comment.
  If it is symbol `syntax-table', stop after the start of a comment or a
  string, or after end of a comment or a string.  */)
@@ -3119,6 +3349,20 @@ init_syntax_once ()
 
   Vstandard_syntax_table = Fmake_char_table (Qsyntax_table, temp);
 
+  /* Control characters should not be whitespace.  */
+  temp = XVECTOR (Vsyntax_code_object)->contents[(int) Spunct];
+  for (i = 0; i <= ' ' - 1; i++)
+    SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, 0177, temp);
+
+  /* Except that a few really are whitespace.  */
+  temp = XVECTOR (Vsyntax_code_object)->contents[(int) Swhitespace];
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ' ', temp);
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '\t', temp);
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '\n', temp);
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, 015, temp);
+  SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, 014, temp);
+
   temp = XVECTOR (Vsyntax_code_object)->contents[(int) Sword];
   for (i = 'a'; i <= 'z'; i++)
     SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
@@ -3163,8 +3407,7 @@ init_syntax_once ()
 
   /* All multibyte characters have syntax `word' by default.  */
   temp = XVECTOR (Vsyntax_code_object)->contents[(int) Sword];
-  for (i = CHAR_TABLE_SINGLE_BYTE_SLOTS; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
-    XCHAR_TABLE (Vstandard_syntax_table)->contents[i] = temp;
+  char_table_set_range (Vstandard_syntax_table, 0x80, MAX_CHAR, temp);
 }
 
 void
@@ -3212,6 +3455,25 @@ See the info node `(elisp)Syntax Properties' for a description of the
               doc: /* *Non-nil means an open paren in column 0 denotes the start of a defun.  */);
   open_paren_in_column_0_is_defun_start = 1;
 
+
+  DEFVAR_LISP ("find-word-boundary-function-table",
+              &Vfind_word_boundary_function_table,
+              doc: /*
+Char table of functions to search for the word boundary.
+Each function is called with two arguments; POS and LIMIT.
+POS and LIMIT are character positions in the current buffer.
+
+If POS is less than LIMIT, POS is at the first character of a word,
+and the return value of a function is a position after the last
+character of that word.
+
+If POS is not less than LIMIT, POS is at the last character of a word,
+and the return value of a function is a position at the first
+character of that word.
+
+In both cases, LIMIT bounds the search. */);
+  Vfind_word_boundary_function_table = Fmake_char_table (Qnil, Qnil);
+
   defsubr (&Ssyntax_table_p);
   defsubr (&Ssyntax_table);
   defsubr (&Sstandard_syntax_table);