summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c274
1 files changed, 168 insertions, 106 deletions
diff --git a/src/fns.c b/src/fns.c
index 499e4b490a6..5074ae3b41b 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -1127,7 +1127,48 @@ Elements of ALIST that are not conses are also shared. */)
return alist;
}
-DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
+/* Check that ARRAY can have a valid subarray [FROM..TO),
+ given that its size is SIZE.
+ If FROM is nil, use 0; if TO is nil, use SIZE.
+ Count negative values backwards from the end.
+ Set *IFROM and *ITO to the two indexes used. */
+
+static void
+validate_subarray (Lisp_Object array, Lisp_Object from, Lisp_Object to,
+ ptrdiff_t size, EMACS_INT *ifrom, EMACS_INT *ito)
+{
+ EMACS_INT f, t;
+
+ if (INTEGERP (from))
+ {
+ f = XINT (from);
+ if (f < 0)
+ f += size;
+ }
+ else if (NILP (from))
+ f = 0;
+ else
+ wrong_type_argument (Qintegerp, from);
+
+ if (INTEGERP (to))
+ {
+ t = XINT (to);
+ if (t < 0)
+ t += size;
+ }
+ else if (NILP (to))
+ t = size;
+ else
+ wrong_type_argument (Qintegerp, to);
+
+ if (! (0 <= f && f <= t && t <= size))
+ args_out_of_range_3 (array, from, to);
+
+ *ifrom = f;
+ *ito = t;
+}
+
+DEFUN ("substring", Fsubstring, Ssubstring, 1, 3, 0,
doc: /* Return a new string whose contents are a substring of STRING.
The returned string consists of the characters between index FROM
\(inclusive) and index TO (exclusive) of STRING. FROM and TO are
@@ -1137,52 +1178,38 @@ to the end of STRING.
The STRING argument may also be a vector. In that case, the return
value is a new vector that contains the elements between index FROM
-\(inclusive) and index TO (exclusive) of that vector argument. */)
- (Lisp_Object string, register Lisp_Object from, Lisp_Object to)
+\(inclusive) and index TO (exclusive) of that vector argument.
+
+With one argument, just copy STRING (with properties, if any). */)
+ (Lisp_Object string, Lisp_Object from, Lisp_Object to)
{
Lisp_Object res;
ptrdiff_t size;
- EMACS_INT from_char, to_char;
-
- CHECK_VECTOR_OR_STRING (string);
- CHECK_NUMBER (from);
+ EMACS_INT ifrom, ito;
if (STRINGP (string))
size = SCHARS (string);
- else
+ else if (VECTORP (string))
size = ASIZE (string);
-
- if (NILP (to))
- to_char = size;
else
- {
- CHECK_NUMBER (to);
-
- to_char = XINT (to);
- if (to_char < 0)
- to_char += size;
- }
+ wrong_type_argument (Qarrayp, string);
- from_char = XINT (from);
- if (from_char < 0)
- from_char += size;
- if (!(0 <= from_char && from_char <= to_char && to_char <= size))
- args_out_of_range_3 (string, make_number (from_char),
- make_number (to_char));
+ validate_subarray (string, from, to, size, &ifrom, &ito);
if (STRINGP (string))
{
- ptrdiff_t to_byte =
- (NILP (to) ? SBYTES (string) : string_char_to_byte (string, to_char));
- ptrdiff_t from_byte = string_char_to_byte (string, from_char);
+ ptrdiff_t from_byte
+ = !ifrom ? 0 : string_char_to_byte (string, ifrom);
+ ptrdiff_t to_byte
+ = ito == size ? SBYTES (string) : string_char_to_byte (string, ito);
res = make_specified_string (SSDATA (string) + from_byte,
- to_char - from_char, to_byte - from_byte,
+ ito - ifrom, to_byte - from_byte,
STRING_MULTIBYTE (string));
- copy_text_properties (make_number (from_char), make_number (to_char),
+ copy_text_properties (make_number (ifrom), make_number (ito),
string, make_number (0), res, Qnil);
}
else
- res = Fvector (to_char - from_char, aref_addr (string, from_char));
+ res = Fvector (ito - ifrom, aref_addr (string, ifrom));
return res;
}
@@ -1205,34 +1232,11 @@ With one argument, just copy STRING without its properties. */)
CHECK_STRING (string);
size = SCHARS (string);
+ validate_subarray (string, from, to, size, &from_char, &to_char);
- if (NILP (from))
- from_char = 0;
- else
- {
- CHECK_NUMBER (from);
- from_char = XINT (from);
- if (from_char < 0)
- from_char += size;
- }
-
- if (NILP (to))
- to_char = size;
- else
- {
- CHECK_NUMBER (to);
- to_char = XINT (to);
- if (to_char < 0)
- to_char += size;
- }
-
- if (!(0 <= from_char && from_char <= to_char && to_char <= size))
- args_out_of_range_3 (string, make_number (from_char),
- make_number (to_char));
-
- from_byte = NILP (from) ? 0 : string_char_to_byte (string, from_char);
+ from_byte = !from_char ? 0 : string_char_to_byte (string, from_char);
to_byte =
- NILP (to) ? SBYTES (string) : string_char_to_byte (string, to_char);
+ to_char == size ? SBYTES (string) : string_char_to_byte (string, to_char);
return make_specified_string (SSDATA (string) + from_byte,
to_char - from_char, to_byte - from_byte,
STRING_MULTIBYTE (string));
@@ -1693,40 +1697,121 @@ changing the value of a sequence `foo'. */)
}
DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0,
- doc: /* Reverse LIST by modifying cdr pointers.
-Return the reversed list. Expects a properly nil-terminated list. */)
- (Lisp_Object list)
+ doc: /* Reverse order of items in a list, vector or string SEQ.
+If SEQ is a list, it should be nil-terminated.
+This function may destructively modify SEQ to produce the value. */)
+ (Lisp_Object seq)
{
- register Lisp_Object prev, tail, next;
+ if (NILP (seq))
+ return seq;
+ else if (STRINGP (seq))
+ return Freverse (seq);
+ else if (CONSP (seq))
+ {
+ Lisp_Object prev, tail, next;
- if (NILP (list)) return list;
- prev = Qnil;
- tail = list;
- while (!NILP (tail))
+ for (prev = Qnil, tail = seq; !NILP (tail); tail = next)
+ {
+ QUIT;
+ CHECK_LIST_CONS (tail, tail);
+ next = XCDR (tail);
+ Fsetcdr (tail, prev);
+ prev = tail;
+ }
+ seq = prev;
+ }
+ else if (VECTORP (seq))
{
- QUIT;
- CHECK_LIST_CONS (tail, tail);
- next = XCDR (tail);
- Fsetcdr (tail, prev);
- prev = tail;
- tail = next;
+ ptrdiff_t i, size = ASIZE (seq);
+
+ for (i = 0; i < size / 2; i++)
+ {
+ Lisp_Object tem = AREF (seq, i);
+ ASET (seq, i, AREF (seq, size - i - 1));
+ ASET (seq, size - i - 1, tem);
+ }
}
- return prev;
+ else if (BOOL_VECTOR_P (seq))
+ {
+ ptrdiff_t i, size = bool_vector_size (seq);
+
+ for (i = 0; i < size / 2; i++)
+ {
+ bool tem = bool_vector_bitref (seq, i);
+ bool_vector_set (seq, i, bool_vector_bitref (seq, size - i - 1));
+ bool_vector_set (seq, size - i - 1, tem);
+ }
+ }
+ else
+ wrong_type_argument (Qarrayp, seq);
+ return seq;
}
DEFUN ("reverse", Freverse, Sreverse, 1, 1, 0,
- doc: /* Reverse LIST, copying. Return the reversed list.
+ doc: /* Return the reversed copy of list, vector, or string SEQ.
See also the function `nreverse', which is used more often. */)
- (Lisp_Object list)
+ (Lisp_Object seq)
{
Lisp_Object new;
- for (new = Qnil; CONSP (list); list = XCDR (list))
+ if (NILP (seq))
+ return Qnil;
+ else if (CONSP (seq))
{
- QUIT;
- new = Fcons (XCAR (list), new);
+ for (new = Qnil; CONSP (seq); seq = XCDR (seq))
+ {
+ QUIT;
+ new = Fcons (XCAR (seq), new);
+ }
+ CHECK_LIST_END (seq, seq);
+ }
+ else if (VECTORP (seq))
+ {
+ ptrdiff_t i, size = ASIZE (seq);
+
+ new = make_uninit_vector (size);
+ for (i = 0; i < size; i++)
+ ASET (new, i, AREF (seq, size - i - 1));
+ }
+ else if (BOOL_VECTOR_P (seq))
+ {
+ ptrdiff_t i;
+ EMACS_INT nbits = bool_vector_size (seq);
+
+ new = make_uninit_bool_vector (nbits);
+ for (i = 0; i < nbits; i++)
+ bool_vector_set (new, i, bool_vector_bitref (seq, nbits - i - 1));
}
- CHECK_LIST_END (list, list);
+ else if (STRINGP (seq))
+ {
+ ptrdiff_t size = SCHARS (seq), bytes = SBYTES (seq);
+
+ if (size == bytes)
+ {
+ ptrdiff_t i;
+
+ new = make_uninit_string (size);
+ for (i = 0; i < size; i++)
+ SSET (new, i, SREF (seq, size - i - 1));
+ }
+ else
+ {
+ unsigned char *p, *q;
+
+ new = make_uninit_multibyte_string (size, bytes);
+ p = SDATA (seq), q = SDATA (new) + bytes;
+ while (q > SDATA (new))
+ {
+ int ch, len;
+
+ ch = STRING_CHAR_AND_LENGTH (p, len);
+ p += len, q -= len;
+ CHAR_STRING (ch, q);
+ }
+ }
+ }
+ else
+ wrong_type_argument (Qsequencep, seq);
return new;
}
@@ -4032,6 +4117,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
current garbage collection. Remove weak tables that don't survive
from Vweak_hash_tables. Called from gc_sweep. */
+NO_INLINE /* For better stack traces */
void
sweep_weak_hash_tables (void)
{
@@ -4612,36 +4698,12 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, Lisp_
object = code_convert_string (object, coding_system, Qnil, 1, 0, 1);
size = SCHARS (object);
+ validate_subarray (object, start, end, size, &start_char, &end_char);
- if (!NILP (start))
- {
- CHECK_NUMBER (start);
-
- start_char = XINT (start);
-
- if (start_char < 0)
- start_char += size;
- }
-
- if (NILP (end))
- end_char = size;
- else
- {
- CHECK_NUMBER (end);
-
- end_char = XINT (end);
-
- if (end_char < 0)
- end_char += size;
- }
-
- if (!(0 <= start_char && start_char <= end_char && end_char <= size))
- args_out_of_range_3 (object, make_number (start_char),
- make_number (end_char));
-
- start_byte = NILP (start) ? 0 : string_char_to_byte (object, start_char);
- end_byte =
- NILP (end) ? SBYTES (object) : string_char_to_byte (object, end_char);
+ start_byte = !start_char ? 0 : string_char_to_byte (object, start_char);
+ end_byte = (end_char == size
+ ? SBYTES (object)
+ : string_char_to_byte (object, end_char));
}
else
{