+ while (1)
+ {
+ if (from == beg)
+ {
+ immediate_quit = 0;
+ return 0;
+ }
+ DEC_BOTH (from, from_byte);
+ UPDATE_SYNTAX_TABLE_BACKWARD (from);
+ ch1 = FETCH_CHAR (from_byte);
+ code = SYNTAX (ch1);
+ if (words_include_escapes
+ && (code == Sescape || code == Scharquote))
+ break;
+ if (code == Sword)
+ break;
+ }
+ /* Now CH1 is a character which ends a word and FROM is the
+ position of it. */
+ while (1)
+ {
+ 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;
+ }
+ count++;
+ }
+
+ immediate_quit = 0;
+
+ return from;
+}
+
+DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p",
+ "Move point forward ARG words (backward if ARG is negative).\n\
+Normally returns t.\n\
+If an edge of the buffer or a field boundary is reached, point is left there\n\
+and the function returns nil. Field boundaries are not noticed if\n\
+`inhibit-field-text-motion' is non-nil.")
+ (count)
+ Lisp_Object count;
+{
+ int orig_val, val;
+ CHECK_NUMBER (count, 0);
+
+ val = orig_val = scan_words (PT, XINT (count));
+ if (! orig_val)
+ val = XINT (count) > 0 ? ZV : BEGV;
+
+ /* Avoid jumping out of an input field. */
+ val = XFASTINT (Fconstrain_to_field (make_number (val), make_number (PT),
+ Qt, Qnil, Qnil));
+
+ SET_PT (val);
+ return val == orig_val ? Qt : Qnil;
+}
+\f
+Lisp_Object skip_chars ();
+
+DEFUN ("skip-chars-forward", Fskip_chars_forward, Sskip_chars_forward, 1, 2, 0,
+ "Move point forward, stopping before a char not in STRING, or at pos LIM.\n\
+STRING is like the inside of a `[...]' in a regular expression\n\
+except that `]' is never special and `\\' quotes `^', `-' or `\\'\n\
+ (but not as the end of a range; quoting is never needed there).\n\
+Thus, with arg \"a-zA-Z\", this skips letters stopping before first nonletter.\n\
+With arg \"^a-zA-Z\", skips nonletters stopping before first letter.\n\
+Returns the distance traveled, either zero or positive.")
+ (string, lim)
+ Lisp_Object string, lim;
+{
+ return skip_chars (1, 0, string, lim);
+}
+
+DEFUN ("skip-chars-backward", Fskip_chars_backward, Sskip_chars_backward, 1, 2, 0,
+ "Move point backward, stopping after a char not in STRING, or at pos LIM.\n\
+See `skip-chars-forward' for details.\n\
+Returns the distance traveled, either zero or negative.")
+ (string, lim)
+ Lisp_Object string, lim;
+{
+ return skip_chars (0, 0, string, lim);
+}
+
+DEFUN ("skip-syntax-forward", Fskip_syntax_forward, Sskip_syntax_forward, 1, 2, 0,
+ "Move point forward across chars in specified syntax classes.\n\
+SYNTAX is a string of syntax code characters.\n\
+Stop before a char whose syntax is not in SYNTAX, or at position LIM.\n\
+If SYNTAX starts with ^, skip characters whose syntax is NOT in SYNTAX.\n\
+This function returns the distance traveled, either zero or positive.")
+ (syntax, lim)
+ Lisp_Object syntax, lim;
+{
+ return skip_chars (1, 1, syntax, lim);
+}
+
+DEFUN ("skip-syntax-backward", Fskip_syntax_backward, Sskip_syntax_backward, 1, 2, 0,
+ "Move point backward across chars in specified syntax classes.\n\
+SYNTAX is a string of syntax code characters.\n\
+Stop on reaching a char whose syntax is not in SYNTAX, or at position LIM.\n\
+If SYNTAX starts with ^, skip characters whose syntax is NOT in SYNTAX.\n\
+This function returns the distance traveled, either zero or negative.")
+ (syntax, lim)
+ Lisp_Object syntax, lim;
+{
+ return skip_chars (0, 1, syntax, lim);
+}
+
+static Lisp_Object
+skip_chars (forwardp, syntaxp, string, lim)
+ int forwardp, syntaxp;
+ Lisp_Object string, lim;
+{
+ register unsigned int c;
+ register int ch;
+ 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, we set the
+ first byte of multibyte form (i.e. base leading-code) in FASTMAP
+ and set the actual ranges of characters in CHAR_RANGES. In the
+ form "X-Y" of STRING, both X and Y must belong to the same
+ character set because a range striding across character sets is
+ meaningless. */
+ int *char_ranges;
+ int n_char_ranges = 0;
+ int negate = 0;
+ register int i, i_byte;
+ int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+ int string_multibyte;
+ int size_byte;
+ unsigned char *str;
+ int len;
+
+ CHECK_STRING (string, 0);
+ char_ranges = (int *) alloca (XSTRING (string)->size * (sizeof (int)) * 2);
+ string_multibyte = STRING_MULTIBYTE (string);
+ str = XSTRING (string)->data;
+ size_byte = STRING_BYTES (XSTRING (string));
+
+ /* Adjust the multibyteness of the string to that of the buffer. */
+ if (multibyte != string_multibyte)
+ {
+ int nbytes;
+
+ if (multibyte)
+ nbytes = count_size_as_multibyte (XSTRING (string)->data,
+ XSTRING (string)->size);
+ else
+ nbytes = XSTRING (string)->size;
+ if (nbytes != size_byte)
+ {
+ str = (unsigned char *) alloca (nbytes);
+ copy_text (XSTRING (string)->data, str, size_byte,
+ string_multibyte, multibyte);
+ size_byte = nbytes;
+ }
+ }
+
+ if (NILP (lim))
+ XSETINT (lim, forwardp ? ZV : BEGV);
+ else
+ CHECK_NUMBER_COERCE_MARKER (lim, 0);
+
+ /* 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);
+
+ bzero (fastmap, sizeof fastmap);
+
+ i_byte = 0;
+
+ if (i_byte < size_byte
+ && XSTRING (string)->data[0] == '^')
+ {
+ negate = 1; i_byte++;
+ }
+
+ /* Find the characters specified and set their elements of fastmap.
+ If syntaxp, each character counts as itself.
+ Otherwise, handle backslashes and ranges specially. */
+
+ while (i_byte < size_byte)
+ {
+ int c_leading_code = str[i_byte];
+
+ c = STRING_CHAR_AND_LENGTH (str + i_byte, size_byte - i_byte, len);
+ i_byte += len;
+
+ if (syntaxp)
+ fastmap[syntax_spec_code[c & 0377]] = 1;
+ else
+ {
+ if (c == '\\')
+ {
+ if (i_byte == size_byte)
+ break;
+
+ c_leading_code = str[i_byte];
+ c = STRING_CHAR_AND_LENGTH (str+i_byte, size_byte-i_byte, len);
+ i_byte += len;
+ }
+ if (i_byte < size_byte
+ && str[i_byte] == '-')
+ {
+ unsigned int c2, c2_leading_code;
+
+ /* Skip over the dash. */
+ i_byte++;
+
+ if (i_byte == size_byte)
+ break;
+
+ /* Get the end of the range. */
+ c2_leading_code = 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 (! SINGLE_BYTE_CHAR_P (c2))
+ {
+ /* Handle a range such as \177-\377 in multibyte
+ mode. Split that into two ranges, the low
+ one ending at 0237, 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);
+
+ fastmap[c2_leading_code] = 1;
+ char_ranges[n_char_ranges++] = c1;
+ char_ranges[n_char_ranges++] = c2;
+ c2 = 0237;
+ }
+ while (c <= c2)
+ {
+ fastmap[c] = 1;
+ c++;
+ }
+ }
+ else if (! SINGLE_BYTE_CHAR_P (c2))
+ {
+ if (c_leading_code != c2_leading_code)
+ error ("Invalid character range: %s",
+ XSTRING (string)->data);
+ if (c <= c2)
+ {
+ fastmap[c_leading_code] = 1;
+ char_ranges[n_char_ranges++] = c;
+ char_ranges[n_char_ranges++] = c2;
+ }
+ }
+ }
+ else
+ {
+ if (SINGLE_BYTE_CHAR_P (c))
+ fastmap[c] = 1;
+ else
+ {
+ fastmap[c_leading_code] = 1;
+ char_ranges[n_char_ranges++] = c;
+ char_ranges[n_char_ranges++] = c;
+ }
+ }
+ }
+ }
+
+ /* If ^ was the first character, complement the fastmap. In
+ addition, as all multibyte characters have possibility of
+ matching, set all entries for base leading codes, which is
+ harmless even if SYNTAXP is 1. */
+
+ if (negate)
+ for (i = 0; i < sizeof fastmap; i++)
+ {
+ if (!multibyte || !BASE_LEADING_CODE_P (i))
+ fastmap[i] ^= 1;
+ else
+ fastmap[i] = 1;
+ }
+
+ {
+ int start_point = PT;
+ int pos = PT;
+ int pos_byte = PT_BYTE;
+
+ immediate_quit = 1;
+ if (syntaxp)
+ {
+ SETUP_SYNTAX_TABLE (pos, forwardp ? 1 : -1);
+ if (forwardp)
+ {
+ if (multibyte)
+ {
+ if (pos < XINT (lim))
+ while (fastmap[(int) SYNTAX (FETCH_CHAR (pos_byte))])
+ {
+ /* Since we already checked for multibyteness,
+ avoid using INC_BOTH which checks again. */
+ INC_POS (pos_byte);
+ pos++;
+ if (pos >= XINT (lim))
+ break;
+ UPDATE_SYNTAX_TABLE_FORWARD (pos);
+ }
+ }
+ else
+ {
+ while (pos < XINT (lim)
+ && fastmap[(int) SYNTAX (FETCH_BYTE (pos))])
+ {
+ pos++;
+ UPDATE_SYNTAX_TABLE_FORWARD (pos);
+ }
+ }
+ }
+ else
+ {
+ if (multibyte)
+ {
+ while (pos > XINT (lim))
+ {
+ int savepos = pos_byte;
+ /* Since we already checked for multibyteness,
+ avoid using DEC_BOTH which checks again. */
+ pos--;
+ DEC_POS (pos_byte);
+ UPDATE_SYNTAX_TABLE_BACKWARD (pos);
+ if (!fastmap[(int) SYNTAX (FETCH_CHAR (pos_byte))])
+ {
+ pos++;
+ pos_byte = savepos;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (pos > XINT (lim))
+ while (fastmap[(int) SYNTAX (FETCH_BYTE (pos - 1))])
+ {
+ pos--;
+ if (pos <= XINT (lim))
+ break;
+ UPDATE_SYNTAX_TABLE_BACKWARD (pos - 1);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (forwardp)
+ {
+ if (multibyte)
+ while (pos < XINT (lim) && fastmap[(c = FETCH_BYTE (pos_byte))])
+ {
+ /* 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. */
+ if (BASE_LEADING_CODE_P (c)
+ && (c = FETCH_MULTIBYTE_CHAR (pos_byte),
+ ! SINGLE_BYTE_CHAR_P (c)))
+ {
+ /* 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;
+ }
+ INC_BOTH (pos, pos_byte);
+ }
+ else
+ while (pos < XINT (lim) && fastmap[FETCH_BYTE (pos)])
+ pos++;
+ }
+ else
+ {
+ if (multibyte)
+ while (pos > XINT (lim))
+ {
+ int prev_pos_byte = pos_byte;
+
+ DEC_POS (prev_pos_byte);
+ if (!fastmap[(c = FETCH_BYTE (prev_pos_byte))])
+ break;
+
+ /* See the comment in the previous similar code. */
+ if (BASE_LEADING_CODE_P (c)
+ && (c = FETCH_MULTIBYTE_CHAR (prev_pos_byte),
+ ! SINGLE_BYTE_CHAR_P (c)))
+ {
+ 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;
+ }
+ pos--;
+ pos_byte = prev_pos_byte;
+ }
+ else
+ while (pos > XINT (lim) && fastmap[FETCH_BYTE (pos - 1)])
+ pos--;
+ }
+ }
+
+#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
+
+ if (! multibyte)
+ pos_byte = pos;
+
+ SET_PT_BOTH (pos, pos_byte);
+ immediate_quit = 0;
+
+ return make_number (PT - start_point);
+ }
+}
+\f
+/* Jump over a comment, assuming we are at the beginning of one.
+ FROM is the current position.
+ FROM_BYTE is the bytepos corresponding to FROM.
+ Do not move past STOP (a charpos).
+ The comment over which we have to jump is of style STYLE
+ (either SYNTAX_COMMENT_STYLE(foo) or ST_COMMENT_STYLE).
+ NESTING should be positive to indicate the nesting at the beginning
+ for nested comments and should be zero or negative else.
+ ST_COMMENT_STYLE cannot be nested.
+ PREV_SYNTAX is the SYNTAX_WITH_FLAGS of the previous character
+ (or 0 If the search cannot start in the middle of a two-character).
+
+ If successful, return 1 and store the charpos of the comment's end
+ into *CHARPOS_PTR and the corresponding bytepos into *BYTEPOS_PTR.
+ Else, return 0 and store the charpos STOP into *CHARPOS_PTR, the
+ corresponding bytepos into *BYTEPOS_PTR and the current nesting
+ (as defined for state.incomment) in *INCOMMENT_PTR.
+
+ The comment end is the last character of the comment rather than the
+ character just after the comment.
+
+ Global syntax data is assumed to initially be valid for FROM and
+ remains valid for forward search starting at the returned position. */
+
+static int
+forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
+ charpos_ptr, bytepos_ptr, incomment_ptr)
+ int from, from_byte, stop;
+ int nesting, style, prev_syntax;
+ int *charpos_ptr, *bytepos_ptr, *incomment_ptr;
+{
+ register int c, c1;
+ register enum syntaxcode code;
+ register int syntax;
+
+ if (nesting <= 0) nesting = -1;
+
+ /* Enter the loop in the middle so that we find
+ a 2-char comment ender if we start in the middle of it. */
+ syntax = prev_syntax;
+ if (syntax != 0) goto forw_incomment;
+
+ while (1)
+ {
+ if (from == stop)