summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c207
1 files changed, 171 insertions, 36 deletions
diff --git a/src/fns.c b/src/fns.c
index 02743c62a57..5126439fd66 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -39,8 +39,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "puresize.h"
#include "gnutls.h"
-static void sort_vector_copy (Lisp_Object, ptrdiff_t,
- Lisp_Object *restrict, Lisp_Object *restrict);
+static void sort_vector_copy (Lisp_Object pred, ptrdiff_t len,
+ Lisp_Object src[restrict VLA_ELEMS (len)],
+ Lisp_Object dest[restrict VLA_ELEMS (len)]);
enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
static bool internal_equal (Lisp_Object, Lisp_Object,
enum equal_kind, int, Lisp_Object);
@@ -54,10 +55,55 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
return argument;
}
+static Lisp_Object
+ccall2 (Lisp_Object (f) (ptrdiff_t nargs, Lisp_Object *args),
+ Lisp_Object arg1, Lisp_Object arg2)
+{
+ Lisp_Object args[2] = {arg1, arg2};
+ return f (2, args);
+}
+
+static Lisp_Object
+get_random_bignum (Lisp_Object limit)
+{
+ /* This is a naive transcription into bignums of the fixnum algorithm.
+ I'd be quite surprised if that's anywhere near the best algorithm
+ for it. */
+ while (true)
+ {
+ Lisp_Object val = make_fixnum (0);
+ Lisp_Object lim = limit;
+ int bits = 0;
+ int bitsperiteration = FIXNUM_BITS - 1;
+ do
+ {
+ /* Shift by one so it is a valid positive fixnum. */
+ EMACS_INT rand = get_random () >> 1;
+ Lisp_Object lrand = make_fixnum (rand);
+ bits += bitsperiteration;
+ val = ccall2 (Flogior,
+ Fash (val, make_fixnum (bitsperiteration)),
+ lrand);
+ lim = Fash (lim, make_fixnum (- bitsperiteration));
+ }
+ while (!EQ (lim, make_fixnum (0)));
+ /* Return the remainder, except reject the rare case where
+ get_random returns a number so close to INTMASK that the
+ remainder isn't random. */
+ Lisp_Object remainder = Frem (val, limit);
+ if (!NILP (ccall2 (Fleq,
+ ccall2 (Fminus, val, remainder),
+ ccall2 (Fminus,
+ Fash (make_fixnum (1), make_fixnum (bits)),
+ limit))))
+ return remainder;
+ }
+}
+
DEFUN ("random", Frandom, Srandom, 0, 1, 0,
doc: /* Return a pseudo-random integer.
By default, return a fixnum; all fixnums are equally likely.
-With positive fixnum LIMIT, return random integer in interval [0,LIMIT).
+With positive integer LIMIT, return random integer in interval [0,LIMIT).
With argument t, set the random number seed from the system's entropy
pool if available, otherwise from less-random volatile data such as the time.
With a string argument, set the seed based on the string's contents.
@@ -71,6 +117,12 @@ See Info node `(elisp)Random Numbers' for more details. */)
init_random ();
else if (STRINGP (limit))
seed_random (SSDATA (limit), SBYTES (limit));
+ if (BIGNUMP (limit))
+ {
+ if (0 > mpz_sgn (*xbignum_val (limit)))
+ xsignal2 (Qwrong_type_argument, Qnatnump, limit);
+ return get_random_bignum (limit);
+ }
val = get_random ();
if (FIXNUMP (limit) && 0 < XFIXNUM (limit))
@@ -1703,7 +1755,8 @@ DEFUN ("assoc", Fassoc, Sassoc, 2, 3, 0,
doc: /* Return non-nil if KEY is equal to the car of an element of ALIST.
The value is actually the first element of ALIST whose car equals KEY.
-Equality is defined by TESTFN if non-nil or by `equal' if nil. */)
+Equality is defined by the function TESTFN, defaulting to `equal'.
+TESTFN is called with 2 arguments: a car of an alist element and KEY. */)
(Lisp_Object key, Lisp_Object alist, Lisp_Object testfn)
{
if (eq_comparable_value (key) && NILP (testfn))
@@ -1816,7 +1869,8 @@ If SEQ is not a list, deletion is never performed destructively;
instead this function creates and returns a new vector or string.
Write `(setq foo (delete element foo))' to be sure of correctly
-changing the value of a sequence `foo'. */)
+changing the value of a sequence `foo'. See also `remove', which
+does not modify the argument. */)
(Lisp_Object elt, Lisp_Object seq)
{
if (VECTORP (seq))
@@ -2227,6 +2281,52 @@ merge (Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred)
}
}
+Lisp_Object
+merge_c (Lisp_Object org_l1, Lisp_Object org_l2, bool (*less) (Lisp_Object, Lisp_Object))
+{
+ Lisp_Object l1 = org_l1;
+ Lisp_Object l2 = org_l2;
+ Lisp_Object tail = Qnil;
+ Lisp_Object value = Qnil;
+
+ while (1)
+ {
+ if (NILP (l1))
+ {
+ if (NILP (tail))
+ return l2;
+ Fsetcdr (tail, l2);
+ return value;
+ }
+ if (NILP (l2))
+ {
+ if (NILP (tail))
+ return l1;
+ Fsetcdr (tail, l1);
+ return value;
+ }
+
+ Lisp_Object tem;
+ if (less (Fcar (l1), Fcar (l2)))
+ {
+ tem = l1;
+ l1 = Fcdr (l1);
+ org_l1 = l1;
+ }
+ else
+ {
+ tem = l2;
+ l2 = Fcdr (l2);
+ org_l2 = l2;
+ }
+ if (NILP (tail))
+ value = tem;
+ else
+ Fsetcdr (tail, tem);
+ tail = tem;
+ }
+}
+
/* This does not check for quits. That is safe since it must terminate. */
@@ -2271,7 +2371,10 @@ This is the last value stored with `(put SYMBOL PROPNAME VALUE)'. */)
DEFUN ("plist-put", Fplist_put, Splist_put, 3, 3, 0,
doc: /* Change value in PLIST of PROP to VAL.
PLIST is a property list, which is a list of the form
-\(PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol and VAL is any object.
+\(PROP1 VALUE1 PROP2 VALUE2 ...).
+
+The comparison with PROP is done using `eq'.
+
If PROP is already a property on the list, its value is set to VAL,
otherwise the new PROP VAL pair is added. The new plist is returned;
use `(setq x (plist-put x prop val))' to be sure to use the new value.
@@ -2873,6 +2976,9 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */)
return obj;
}
+ if (use_short_answers)
+ return call1 (intern ("y-or-n-p"), prompt);
+
AUTO_STRING (yes_or_no, "(yes or no) ");
prompt = CALLN (Fconcat, prompt, yes_or_no);
@@ -3110,7 +3216,10 @@ suppressed. */)
DEFUN ("plist-member", Fplist_member, Splist_member, 2, 2, 0,
doc: /* Return non-nil if PLIST has the property PROP.
PLIST is a property list, which is a list of the form
-\(PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol.
+\(PROP1 VALUE1 PROP2 VALUE2 ...).
+
+The comparison with PROP is done using `eq'.
+
Unlike `plist-get', this allows you to distinguish between a missing
property and a property with the value nil.
The value is actually the tail of PLIST whose car is PROP. */)
@@ -3847,7 +3956,7 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length,
if (c == '=')
continue;
- if (v1 < 0)
+ if (v1 == 0)
return -1;
value += v1 - 1;
@@ -4385,6 +4494,15 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
eassert (!PURE_P (h));
}
+static void
+collect_interval (INTERVAL interval, Lisp_Object collector)
+{
+ nconc2 (collector,
+ list1(list3 (make_fixnum (interval->position),
+ make_fixnum (interval->position + LENGTH (interval)),
+ interval->plist)));
+}
+
/* Put an entry into hash table H that associates KEY with VALUE.
HASH is a previously computed hash code of KEY.
Value is the index of the entry in H matching KEY. */
@@ -4842,6 +4960,30 @@ Hash codes are not guaranteed to be preserved across Emacs sessions. */)
return hashfn_equal (obj, NULL);
}
+DEFUN ("sxhash-equal-including-properties", Fsxhash_equal_including_properties,
+ Ssxhash_equal_including_properties, 1, 1, 0,
+ doc: /* Return an integer hash code for OBJ suitable for
+`equal-including-properties'.
+If (sxhash-equal-including-properties A B), then
+(= (sxhash-equal-including-properties A) (sxhash-equal-including-properties B)).
+
+Hash codes are not guaranteed to be preserved across Emacs sessions. */)
+ (Lisp_Object obj)
+{
+ if (STRINGP (obj))
+ {
+ Lisp_Object collector = Fcons (Qnil, Qnil);
+ traverse_intervals (string_intervals (obj), 0, collect_interval,
+ collector);
+ return
+ make_ufixnum (
+ SXHASH_REDUCE (sxhash_combine (sxhash (obj),
+ sxhash (CDR (collector)))));
+ }
+
+ return hashfn_equal (obj, NULL);
+}
+
DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
doc: /* Create and return a new hash table.
@@ -5628,16 +5770,6 @@ characters. */ )
return list3 (make_int (lines), make_int (longest), make_float (mean));
}
-static bool
-string_ascii_p (Lisp_Object string)
-{
- ptrdiff_t nbytes = SBYTES (string);
- for (ptrdiff_t i = 0; i < nbytes; i++)
- if (SREF (string, i) > 127)
- return false;
- return true;
-}
-
DEFUN ("string-search", Fstring_search, Sstring_search, 2, 3, 0,
doc: /* Search for the string NEEDLE in the string HAYSTACK.
The return value is the position of the first occurrence of NEEDLE in
@@ -5725,15 +5857,6 @@ Case is always significant and text properties are ignored. */)
return make_int (string_byte_to_char (haystack, res - SSDATA (haystack)));
}
-static void
-collect_interval (INTERVAL interval, Lisp_Object collector)
-{
- nconc2 (collector,
- list1(list3 (make_fixnum (interval->position),
- make_fixnum (interval->position + LENGTH (interval)),
- interval->plist)));
-}
-
DEFUN ("object-intervals", Fobject_intervals, Sobject_intervals, 1, 1, 0,
doc: /* Return a copy of the text properties of OBJECT.
OBJECT must be a buffer or a string.
@@ -5761,15 +5884,17 @@ in OBJECT. */)
DEFUN ("line-number-at-pos", Fline_number_at_pos,
Sline_number_at_pos, 0, 2, 0,
- doc: /* Return the line number at POSITION.
-If POSITION is nil, use the current buffer location.
-
-If the buffer is narrowed, the position returned is the position in the
-visible part of the buffer. If ABSOLUTE is non-nil, count the lines
-from the absolute start of the buffer. */)
+ doc: /* Return the line number at POSITION in the current buffer.
+If POSITION is nil or omitted, it defaults to point's position in the
+current buffer.
+
+If the buffer is narrowed, the return value by default counts the lines
+from the beginning of the accessible portion of the buffer. But if the
+second optional argument ABSOLUTE is non-nil, the value counts the lines
+from the absolute start of the buffer, disregarding the narrowing. */)
(register Lisp_Object position, Lisp_Object absolute)
{
- ptrdiff_t pos, start = BEGV;
+ ptrdiff_t pos, start = BEGV_BYTE;
if (MARKERP (position))
pos = marker_position (position);
@@ -5784,9 +5909,9 @@ from the absolute start of the buffer. */)
if (!NILP (absolute))
start = BEG_BYTE;
- /* Check that POSITION is n the visible range of the buffer. */
+ /* Check that POSITION is in the accessible range of the buffer. */
if (pos < BEGV || pos > ZV)
- args_out_of_range (make_int (start), make_int (ZV));
+ args_out_of_range_3 (make_int (pos), make_int (BEGV), make_int (ZV));
return make_int (count_lines (start, CHAR_TO_BYTE (pos)) + 1);
}
@@ -5815,6 +5940,7 @@ syms_of_fns (void)
defsubr (&Ssxhash_eq);
defsubr (&Ssxhash_eql);
defsubr (&Ssxhash_equal);
+ defsubr (&Ssxhash_equal_including_properties);
defsubr (&Smake_hash_table);
defsubr (&Scopy_hash_table);
defsubr (&Shash_table_count);
@@ -5904,6 +6030,15 @@ that disables the use of a file dialog, regardless of the value of
this variable. */);
use_file_dialog = true;
+ DEFVAR_BOOL ("use-short-answers", use_short_answers,
+ doc: /* Non-nil means `yes-or-no-p' uses shorter answers "y" or "n".
+When non-nil, `yes-or-no-p' will use `y-or-n-p' to read the answer.
+We recommend against setting this variable non-nil, because `yes-or-no-p'
+is intended to be used when users are expected not to respond too
+quickly, but to take their time and perhaps think about the answer.
+The same variable also affects the function `read-answer'. */);
+ use_short_answers = false;
+
defsubr (&Sidentity);
defsubr (&Srandom);
defsubr (&Slength);