forward-line now works with bignums
* src/cmds.c (Fforward_line): Support bignum arg. (scan_newline): Return void since no caller was using the return value. * src/search.c (find_newline, scan_newline_from_point) (find_newline1): Return the number of newlines counted, not the count shortage, so that the return value always fits in ptrdiff_t even if the original count was a bignum. All callers changed. * test/src/cmds-tests.el (forward-line-with-bignum): New test.
This commit is contained in:
parent
6c2ee11d8f
commit
cc1c46e412
5 changed files with 75 additions and 67 deletions
32
src/cmds.c
32
src/cmds.c
|
@ -121,28 +121,36 @@ it as a line moved across, even though there is no next line to
|
|||
go to its beginning. */)
|
||||
(Lisp_Object n)
|
||||
{
|
||||
ptrdiff_t opoint = PT, pos, pos_byte, shortage, count;
|
||||
ptrdiff_t opoint = PT, pos, pos_byte, count;
|
||||
bool excessive = false;
|
||||
|
||||
if (NILP (n))
|
||||
count = 1;
|
||||
else
|
||||
{
|
||||
CHECK_FIXNUM (n);
|
||||
count = XFIXNUM (n);
|
||||
CHECK_INTEGER (n);
|
||||
if (FIXNUMP (n)
|
||||
&& -BUF_BYTES_MAX <= XFIXNUM (n) && XFIXNUM (n) <= BUF_BYTES_MAX)
|
||||
count = XFIXNUM (n);
|
||||
else
|
||||
{
|
||||
count = !NILP (Fnatnump (n)) ? BUF_BYTES_MAX : -BUF_BYTES_MAX;
|
||||
excessive = true;
|
||||
}
|
||||
}
|
||||
|
||||
shortage = scan_newline_from_point (count, &pos, &pos_byte);
|
||||
ptrdiff_t counted = scan_newline_from_point (count, &pos, &pos_byte);
|
||||
|
||||
SET_PT_BOTH (pos, pos_byte);
|
||||
|
||||
if (shortage > 0
|
||||
&& (count <= 0
|
||||
|| (ZV > BEGV
|
||||
&& PT != opoint
|
||||
&& (FETCH_BYTE (PT_BYTE - 1) != '\n'))))
|
||||
shortage--;
|
||||
|
||||
return make_fixnum (count <= 0 ? - shortage : shortage);
|
||||
ptrdiff_t shortage = count - (count <= 0) - counted;
|
||||
if (shortage != 0)
|
||||
shortage -= (count <= 0 ? -1
|
||||
: (BEGV < ZV && PT != opoint
|
||||
&& FETCH_BYTE (PT_BYTE - 1) != '\n'));
|
||||
return (excessive
|
||||
? CALLN (Fplus, make_fixnum (shortage - count), n)
|
||||
: make_fixnum (shortage));
|
||||
}
|
||||
|
||||
DEFUN ("beginning-of-line", Fbeginning_of_line, Sbeginning_of_line, 0, 1, "^p",
|
||||
|
|
|
@ -668,7 +668,7 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
|
|||
/* It is possible that NEW_POS is not within the same field as
|
||||
OLD_POS; try to move NEW_POS so that it is. */
|
||||
{
|
||||
ptrdiff_t shortage;
|
||||
ptrdiff_t counted;
|
||||
Lisp_Object field_bound;
|
||||
|
||||
if (fwd)
|
||||
|
@ -691,8 +691,8 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil. */)
|
|||
there's an intervening newline or not. */
|
||||
|| (find_newline (XFIXNAT (new_pos), -1,
|
||||
XFIXNAT (field_bound), -1,
|
||||
fwd ? -1 : 1, &shortage, NULL, 1),
|
||||
shortage != 0)))
|
||||
fwd ? -1 : 1, &counted, NULL, 1),
|
||||
counted == 0)))
|
||||
/* Constrain NEW_POS to FIELD_BOUND. */
|
||||
new_pos = field_bound;
|
||||
|
||||
|
|
|
@ -4271,8 +4271,8 @@ extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
|
|||
ptrdiff_t, ptrdiff_t, Lisp_Object);
|
||||
extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
|
||||
extern ptrdiff_t scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, bool);
|
||||
extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, bool);
|
||||
extern ptrdiff_t scan_newline_from_point (ptrdiff_t, ptrdiff_t *, ptrdiff_t *);
|
||||
extern ptrdiff_t find_newline_no_quit (ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t *);
|
||||
|
|
92
src/search.c
92
src/search.c
|
@ -647,14 +647,16 @@ newline_cache_on_off (struct buffer *buf)
|
|||
If COUNT is zero, do anything you please; run rogue, for all I care.
|
||||
|
||||
If END is zero, use BEGV or ZV instead, as appropriate for the
|
||||
direction indicated by COUNT.
|
||||
direction indicated by COUNT. If START_BYTE is -1 it is unknown,
|
||||
and similarly for END_BYTE.
|
||||
|
||||
If we find COUNT instances, set *SHORTAGE to zero, and return the
|
||||
If we find COUNT instances, set *COUNTED to COUNT, and return the
|
||||
position past the COUNTth match. Note that for reverse motion
|
||||
this is not the same as the usual convention for Emacs motion commands.
|
||||
|
||||
If we don't find COUNT instances before reaching END, set *SHORTAGE
|
||||
to the number of newlines left unfound, and return END.
|
||||
If we don't find COUNT instances before reaching END, set *COUNTED
|
||||
to the number of newlines left found (negated if COUNT is negative),
|
||||
and return END.
|
||||
|
||||
If BYTEPOS is not NULL, set *BYTEPOS to the byte position corresponding
|
||||
to the returned character position.
|
||||
|
@ -664,23 +666,17 @@ newline_cache_on_off (struct buffer *buf)
|
|||
|
||||
ptrdiff_t
|
||||
find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
||||
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *shortage,
|
||||
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
|
||||
ptrdiff_t *bytepos, bool allow_quit)
|
||||
{
|
||||
struct region_cache *newline_cache;
|
||||
int direction;
|
||||
struct buffer *cache_buffer;
|
||||
|
||||
if (count > 0)
|
||||
if (!end)
|
||||
{
|
||||
direction = 1;
|
||||
if (!end)
|
||||
if (count > 0)
|
||||
end = ZV, end_byte = ZV_BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
direction = -1;
|
||||
if (!end)
|
||||
else
|
||||
end = BEGV, end_byte = BEGV_BYTE;
|
||||
}
|
||||
if (end_byte == -1)
|
||||
|
@ -692,8 +688,8 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
|||
else
|
||||
cache_buffer = current_buffer;
|
||||
|
||||
if (shortage != 0)
|
||||
*shortage = 0;
|
||||
if (counted)
|
||||
*counted = count;
|
||||
|
||||
if (count > 0)
|
||||
while (start != end)
|
||||
|
@ -936,8 +932,8 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
|||
}
|
||||
}
|
||||
|
||||
if (shortage)
|
||||
*shortage = count * direction;
|
||||
if (counted)
|
||||
*counted -= count;
|
||||
if (bytepos)
|
||||
{
|
||||
*bytepos = start_byte == -1 ? CHAR_TO_BYTE (start) : start_byte;
|
||||
|
@ -952,30 +948,28 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
|||
We report the resulting position by calling TEMP_SET_PT_BOTH.
|
||||
|
||||
If we find COUNT instances. we position after (always after,
|
||||
even if scanning backwards) the COUNTth match, and return 0.
|
||||
even if scanning backwards) the COUNTth match.
|
||||
|
||||
If we don't find COUNT instances before reaching the end of the
|
||||
buffer (or the beginning, if scanning backwards), we return
|
||||
the number of line boundaries left unfound, and position at
|
||||
buffer (or the beginning, if scanning backwards), we position at
|
||||
the limit we bumped up against.
|
||||
|
||||
If ALLOW_QUIT, check for quitting. That's good to do
|
||||
except in special cases. */
|
||||
|
||||
ptrdiff_t
|
||||
void
|
||||
scan_newline (ptrdiff_t start, ptrdiff_t start_byte,
|
||||
ptrdiff_t limit, ptrdiff_t limit_byte,
|
||||
ptrdiff_t count, bool allow_quit)
|
||||
{
|
||||
ptrdiff_t charpos, bytepos, shortage;
|
||||
ptrdiff_t charpos, bytepos, counted;
|
||||
|
||||
charpos = find_newline (start, start_byte, limit, limit_byte,
|
||||
count, &shortage, &bytepos, allow_quit);
|
||||
if (shortage)
|
||||
count, &counted, &bytepos, allow_quit);
|
||||
if (counted != count)
|
||||
TEMP_SET_PT_BOTH (limit, limit_byte);
|
||||
else
|
||||
TEMP_SET_PT_BOTH (charpos, bytepos);
|
||||
return shortage;
|
||||
}
|
||||
|
||||
/* Like above, but always scan from point and report the
|
||||
|
@ -985,19 +979,19 @@ ptrdiff_t
|
|||
scan_newline_from_point (ptrdiff_t count, ptrdiff_t *charpos,
|
||||
ptrdiff_t *bytepos)
|
||||
{
|
||||
ptrdiff_t shortage;
|
||||
ptrdiff_t counted;
|
||||
|
||||
if (count <= 0)
|
||||
*charpos = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, count - 1,
|
||||
&shortage, bytepos, 1);
|
||||
&counted, bytepos, 1);
|
||||
else
|
||||
*charpos = find_newline (PT, PT_BYTE, ZV, ZV_BYTE, count,
|
||||
&shortage, bytepos, 1);
|
||||
return shortage;
|
||||
&counted, bytepos, 1);
|
||||
return counted;
|
||||
}
|
||||
|
||||
/* Like find_newline, but doesn't allow QUITting and doesn't return
|
||||
SHORTAGE. */
|
||||
COUNTED. */
|
||||
ptrdiff_t
|
||||
find_newline_no_quit (ptrdiff_t from, ptrdiff_t frombyte,
|
||||
ptrdiff_t cnt, ptrdiff_t *bytepos)
|
||||
|
@ -1013,10 +1007,10 @@ ptrdiff_t
|
|||
find_before_next_newline (ptrdiff_t from, ptrdiff_t to,
|
||||
ptrdiff_t cnt, ptrdiff_t *bytepos)
|
||||
{
|
||||
ptrdiff_t shortage;
|
||||
ptrdiff_t pos = find_newline (from, -1, to, -1, cnt, &shortage, bytepos, 1);
|
||||
ptrdiff_t counted;
|
||||
ptrdiff_t pos = find_newline (from, -1, to, -1, cnt, &counted, bytepos, 1);
|
||||
|
||||
if (shortage == 0)
|
||||
if (counted == cnt)
|
||||
{
|
||||
if (bytepos)
|
||||
DEC_BOTH (pos, *bytepos);
|
||||
|
@ -3210,7 +3204,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0,
|
|||
/* Like find_newline, but doesn't use the cache, and only searches forward. */
|
||||
static ptrdiff_t
|
||||
find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
||||
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *shortage,
|
||||
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
|
||||
ptrdiff_t *bytepos, bool allow_quit)
|
||||
{
|
||||
if (count > 0)
|
||||
|
@ -3226,8 +3220,8 @@ find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
|||
if (end_byte == -1)
|
||||
end_byte = CHAR_TO_BYTE (end);
|
||||
|
||||
if (shortage != 0)
|
||||
*shortage = 0;
|
||||
if (counted)
|
||||
*counted = count;
|
||||
|
||||
if (count > 0)
|
||||
while (start != end)
|
||||
|
@ -3284,8 +3278,8 @@ find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
|||
}
|
||||
}
|
||||
|
||||
if (shortage)
|
||||
*shortage = count;
|
||||
if (counted)
|
||||
*counted -= count;
|
||||
if (bytepos)
|
||||
{
|
||||
*bytepos = start_byte == -1 ? CHAR_TO_BYTE (start) : start_byte;
|
||||
|
@ -3306,7 +3300,7 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */)
|
|||
(Lisp_Object buffer)
|
||||
{
|
||||
struct buffer *buf, *old = NULL;
|
||||
ptrdiff_t shortage, nl_count_cache, nl_count_buf;
|
||||
ptrdiff_t nl_count_cache, nl_count_buf;
|
||||
Lisp_Object cache_newlines, buf_newlines, val;
|
||||
ptrdiff_t from, found, i;
|
||||
|
||||
|
@ -3332,8 +3326,7 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */)
|
|||
|
||||
/* How many newlines are there according to the cache? */
|
||||
find_newline (BEGV, BEGV_BYTE, ZV, ZV_BYTE,
|
||||
TYPE_MAXIMUM (ptrdiff_t), &shortage, NULL, true);
|
||||
nl_count_cache = TYPE_MAXIMUM (ptrdiff_t) - shortage;
|
||||
TYPE_MAXIMUM (ptrdiff_t), &nl_count_cache, NULL, true);
|
||||
|
||||
/* Create vector and populate it. */
|
||||
cache_newlines = make_uninit_vector (nl_count_cache);
|
||||
|
@ -3342,11 +3335,11 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */)
|
|||
{
|
||||
for (from = BEGV, found = from, i = 0; from < ZV; from = found, i++)
|
||||
{
|
||||
ptrdiff_t from_byte = CHAR_TO_BYTE (from);
|
||||
ptrdiff_t from_byte = CHAR_TO_BYTE (from), counted;
|
||||
|
||||
found = find_newline (from, from_byte, 0, -1, 1, &shortage,
|
||||
found = find_newline (from, from_byte, 0, -1, 1, &counted,
|
||||
NULL, true);
|
||||
if (shortage != 0 || i >= nl_count_cache)
|
||||
if (counted == 0 || i >= nl_count_cache)
|
||||
break;
|
||||
ASET (cache_newlines, i, make_fixnum (found - 1));
|
||||
}
|
||||
|
@ -3357,18 +3350,17 @@ the buffer. If the buffer doesn't have a cache, the value is nil. */)
|
|||
|
||||
/* Now do the same, but without using the cache. */
|
||||
find_newline1 (BEGV, BEGV_BYTE, ZV, ZV_BYTE,
|
||||
TYPE_MAXIMUM (ptrdiff_t), &shortage, NULL, true);
|
||||
nl_count_buf = TYPE_MAXIMUM (ptrdiff_t) - shortage;
|
||||
TYPE_MAXIMUM (ptrdiff_t), &nl_count_buf, NULL, true);
|
||||
buf_newlines = make_uninit_vector (nl_count_buf);
|
||||
if (nl_count_buf)
|
||||
{
|
||||
for (from = BEGV, found = from, i = 0; from < ZV; from = found, i++)
|
||||
{
|
||||
ptrdiff_t from_byte = CHAR_TO_BYTE (from);
|
||||
ptrdiff_t from_byte = CHAR_TO_BYTE (from), counted;
|
||||
|
||||
found = find_newline1 (from, from_byte, 0, -1, 1, &shortage,
|
||||
found = find_newline1 (from, from_byte, 0, -1, 1, &counted,
|
||||
NULL, true);
|
||||
if (shortage != 0 || i >= nl_count_buf)
|
||||
if (counted == 0 || i >= nl_count_buf)
|
||||
break;
|
||||
ASET (buf_newlines, i, make_fixnum (found - 1));
|
||||
}
|
||||
|
|
|
@ -30,5 +30,13 @@
|
|||
(let ((last-command-event ?a))
|
||||
(should-error (self-insert-command -1))))
|
||||
|
||||
(ert-deftest forward-line-with-bignum ()
|
||||
(with-temp-buffer
|
||||
(insert "x\n")
|
||||
(let ((shortage (forward-line (1- most-negative-fixnum))))
|
||||
(should (= shortage most-negative-fixnum)))
|
||||
(let ((shortage (forward-line (+ 2 most-positive-fixnum))))
|
||||
(should (= shortage (1+ most-positive-fixnum))))))
|
||||
|
||||
(provide 'cmds-tests)
|
||||
;;; cmds-tests.el ends here
|
||||
|
|
Loading…
Add table
Reference in a new issue