/* String search routines for GNU Emacs.
- Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1993 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "syntax.h"
#include "buffer.h"
#include "commands.h"
+#include "blockinput.h"
#include <sys/types.h>
#include "regex.h"
last_regexp = Qnil;
bufp->translate = translate;
+ BLOCK_INPUT;
val = re_compile_pattern ((char *) XSTRING (pattern)->data,
XSTRING (pattern)->size,
bufp);
+ UNBLOCK_INPUT;
if (val)
{
dummy = build_string (val);
/* Advise the searching functions about the space we have allocated
for register data. */
+ BLOCK_INPUT;
if (regp)
re_set_registers (bufp, regp, regp->num_regs, regp->start, regp->end);
+ UNBLOCK_INPUT;
return;
}
return (scan_buffer ('\n', from, cnt, (int *) 0));
}
\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 CHARS, or at position LIM.\n\
CHARS is like the inside of a `[...]' in a regular expression\n\
except that `]' is never special and `\\' quotes `^', `-' or `\\'.\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.")
+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;
{
- skip_chars (1, string, lim);
- return Qnil;
+ 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 CHARS, or at position LIM.\n\
-See `skip-chars-forward' for details.")
+See `skip-chars-forward' for details.\n\
+Returns the distance traveled, either zero or negative.")
(string, lim)
Lisp_Object string, lim;
{
- skip_chars (0, string, lim);
- return Qnil;
+ 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);
}
-skip_chars (forwardp, string, lim)
- int forwardp;
+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);
+}
+
+Lisp_Object
+skip_chars (forwardp, syntaxp, string, lim)
+ int forwardp, syntaxp;
Lisp_Object string, lim;
{
register unsigned char *p, *pend;
negate = 1; p++;
}
- /* Find the characters specified and set their elements of fastmap. */
+ /* Find the characters specified and set their elements of fastmap.
+ If syntaxp, each character counts as itself.
+ Otherwise, handle backslashes and ranges specially */
while (p != pend)
{
c = *p++;
- if (c == '\\')
- {
- if (p == pend) break;
- c = *p++;
- }
- if (p != pend && *p == '-')
+ if (syntaxp)
+ fastmap[c] = 1;
+ else
{
- p++;
- if (p == pend) break;
- while (c <= *p)
+ if (c == '\\')
{
- fastmap[c] = 1;
- c++;
+ if (p == pend) break;
+ c = *p++;
}
- p++;
+ if (p != pend && *p == '-')
+ {
+ p++;
+ if (p == pend) break;
+ while (c <= *p)
+ {
+ fastmap[c] = 1;
+ c++;
+ }
+ p++;
+ }
+ else
+ fastmap[c] = 1;
}
- else
- fastmap[c] = 1;
}
/* If ^ was the first character, complement the fastmap. */
for (i = 0; i < sizeof fastmap; i++)
fastmap[i] ^= 1;
- immediate_quit = 1;
- if (forwardp)
- {
- while (point < XINT (lim) && fastmap[FETCH_CHAR (point)])
- SET_PT (point + 1);
- }
- else
- {
- while (point > XINT (lim) && fastmap[FETCH_CHAR (point - 1)])
- SET_PT (point - 1);
- }
- immediate_quit = 0;
+ {
+ int start_point = point;
+
+ immediate_quit = 1;
+ if (syntaxp)
+ {
+
+ if (forwardp)
+ {
+ while (point < XINT (lim)
+ && fastmap[(unsigned char) syntax_code_spec[(int) SYNTAX (FETCH_CHAR (point))]])
+ SET_PT (point + 1);
+ }
+ else
+ {
+ while (point > XINT (lim)
+ && fastmap[(unsigned char) syntax_code_spec[(int) SYNTAX (FETCH_CHAR (point - 1))]])
+ SET_PT (point - 1);
+ }
+ }
+ else
+ {
+ if (forwardp)
+ {
+ while (point < XINT (lim) && fastmap[FETCH_CHAR (point)])
+ SET_PT (point + 1);
+ }
+ else
+ {
+ while (point > XINT (lim) && fastmap[FETCH_CHAR (point - 1)])
+ SET_PT (point - 1);
+ }
+ }
+ immediate_quit = 0;
+
+ return make_number (point - start_point);
+ }
}
\f
/* Subroutines of Lisp buffer search functions. */
if (lim < BEGV || lim > ZV)
abort ();
SET_PT (lim);
+ return Qnil;
+#if 0 /* This would be clean, but maybe programs depend on
+ a value of nil here. */
+ np = lim;
+#endif
}
- return Qnil;
+ else
+ return Qnil;
}
if (np < BEGV || np > ZV)
}
while (n < 0)
{
- int val = re_search_2 (&searchbuf, (char *) p1, s1, (char *) p2, s2,
- pos - BEGV, lim - pos, &search_regs,
- /* Don't allow match past current point */
- pos - BEGV);
+ int val;
+ val = re_search_2 (&searchbuf, (char *) p1, s1, (char *) p2, s2,
+ pos - BEGV, lim - pos, &search_regs,
+ /* Don't allow match past current point */
+ pos - BEGV);
if (val == -2)
matcher_overflow ();
if (val >= 0)
}
while (n > 0)
{
- int val = re_search_2 (&searchbuf, (char *) p1, s1, (char *) p2, s2,
- pos - BEGV, lim - pos, &search_regs,
- lim - BEGV);
+ int val;
+ val = re_search_2 (&searchbuf, (char *) p1, s1, (char *) p2, s2,
+ pos - BEGV, lim - pos, &search_regs,
+ lim - BEGV);
if (val == -2)
matcher_overflow ();
if (val >= 0)
(regoff_t *) xmalloc (2 * sizeof (regoff_t));
ends =
(regoff_t *) xmalloc (2 * sizeof (regoff_t));
+ BLOCK_INPUT;
re_set_registers (&searchbuf,
&search_regs,
2, starts, ends);
+ UNBLOCK_INPUT;
}
search_regs.start[0]
while ((limit - pos) * direction >= 0)
pos += BM_tab[FETCH_CHAR(pos)];
/* now run the same tests to distinguish going off the */
- /* end, a match or a phoney match. */
+ /* end, a match or a phony match. */
if ((pos - limit) * direction <= len)
break; /* ran off the end */
/* Found what might be a match.
(regoff_t *) xmalloc (2 * sizeof (regoff_t));
ends =
(regoff_t *) xmalloc (2 * sizeof (regoff_t));
+ BLOCK_INPUT;
re_set_registers (&searchbuf,
&search_regs,
2, starts, ends);
+ UNBLOCK_INPUT;
}
search_regs.start[0]
enum { nochange, all_caps, cap_initial } case_action;
register int pos, last;
int some_multiletter_word;
- int some_letter = 0;
+ int some_lowercase;
+ int some_uppercase_initial;
register int c, prevc;
int inslen;
if (search_regs.start[0] < BEGV
|| search_regs.start[0] > search_regs.end[0]
|| search_regs.end[0] > ZV)
- args_out_of_range(make_number (search_regs.start[0]),
- make_number (search_regs.end[0]));
+ args_out_of_range (make_number (search_regs.start[0]),
+ make_number (search_regs.end[0]));
if (NILP (fixedcase))
{
/* some_multiletter_word is set nonzero if any original word
is more than one letter long. */
some_multiletter_word = 0;
+ some_lowercase = 0;
+ some_uppercase_initial = 0;
for (pos = search_regs.start[0]; pos < last; pos++)
{
{
/* Cannot be all caps if any original char is lower case */
- case_action = cap_initial;
+ some_lowercase = 1;
if (SYNTAX (prevc) != Sword)
- {
- /* Cannot even be cap initials
- if some original initial is lower case */
- case_action = nochange;
- break;
- }
+ ;
else
some_multiletter_word = 1;
}
else if (!NOCASEP (c))
{
- some_letter = 1;
- if (!some_multiletter_word && SYNTAX (prevc) == Sword)
+ if (SYNTAX (prevc) != Sword)
+ some_uppercase_initial = 1;
+ else
some_multiletter_word = 1;
}
prevc = c;
}
- /* Do not make new text all caps
- if the original text contained only single letter words. */
- if (case_action == all_caps && !some_multiletter_word)
+ /* Convert to all caps if the old text is all caps
+ and has at least one multiletter word. */
+ if (! some_lowercase && some_multiletter_word)
+ case_action = all_caps;
+ /* Capitalize each word, if the old text has a capitalized word. */
+ else if (some_uppercase_initial)
case_action = cap_initial;
-
- if (!some_letter) case_action = nochange;
+ else
+ case_action = nochange;
}
- SET_PT (search_regs.end[0]);
+ /* We insert the replacement text before the old text, and then
+ delete the original text. This means that markers at the
+ beginning or end of the original will float to the corresponding
+ position in the replacement. */
+ SET_PT (search_regs.start[0]);
if (!NILP (literal))
Finsert (1, &string);
else
for (pos = 0; pos < XSTRING (string)->size; pos++)
{
+ int offset = point - search_regs.start[0];
+
c = XSTRING (string)->data[pos];
if (c == '\\')
{
c = XSTRING (string)->data[++pos];
if (c == '&')
- Finsert_buffer_substring (Fcurrent_buffer (),
- make_number (search_regs.start[0]),
- make_number (search_regs.end[0]));
+ Finsert_buffer_substring
+ (Fcurrent_buffer (),
+ make_number (search_regs.start[0] + offset),
+ make_number (search_regs.end[0] + offset));
else if (c >= '1' && c <= search_regs.num_regs + '0')
{
if (search_regs.start[c - '0'] >= 1)
- Finsert_buffer_substring (Fcurrent_buffer (),
- make_number (search_regs.start[c - '0']),
- make_number (search_regs.end[c - '0']));
+ Finsert_buffer_substring
+ (Fcurrent_buffer (),
+ make_number (search_regs.start[c - '0'] + offset),
+ make_number (search_regs.end[c - '0'] + offset));
}
else
insert_char (c);
UNGCPRO;
}
- inslen = point - (search_regs.end[0]);
- del_range (search_regs.start[0], search_regs.end[0]);
+ inslen = point - (search_regs.start[0]);
+ del_range (search_regs.start[0] + inslen, search_regs.end[0] + inslen);
if (case_action == all_caps)
Fupcase_region (make_number (point - inslen), make_number (point));
register Lisp_Object marker;
if (!CONSP (list) && !NILP (list))
- list = wrong_type_argument (Qconsp, list, 0);
+ list = wrong_type_argument (Qconsp, list);
/* Unless we find a marker with a buffer in LIST, assume that this
match data came from a string. */
/* Allocate registers if they don't already exist. */
{
- int length = Flength (list) / 2;
+ int length = XFASTINT (Flength (list)) / 2;
if (length > search_regs.num_regs)
{
length * sizeof (regoff_t));
}
+ BLOCK_INPUT;
re_set_registers (&searchbuf, &search_regs, length,
search_regs.start, search_regs.end);
+ UNBLOCK_INPUT;
}
}
defsubr (&Slooking_at);
defsubr (&Sskip_chars_forward);
defsubr (&Sskip_chars_backward);
+ defsubr (&Sskip_syntax_forward);
+ defsubr (&Sskip_syntax_backward);
defsubr (&Ssearch_forward);
defsubr (&Ssearch_backward);
defsubr (&Sword_search_forward);