(mail-abbrev-syntax-table): Fix initialization.
[bpt/emacs.git] / src / fns.c
CommitLineData
7b863bd5 1/* Random utility Lisp functions.
f8c25f1b 2 Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
7b863bd5
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4ff1aed9 8the Free Software Foundation; either version 2, or (at your option)
7b863bd5
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
7b863bd5 22
7b863bd5
JB
23/* Note on some machines this defines `vector' as a typedef,
24 so make sure we don't use that name in this file. */
25#undef vector
26#define vector *****
27
7b863bd5
JB
28#include "lisp.h"
29#include "commands.h"
30
7b863bd5 31#include "buffer.h"
f812877e 32#include "keyboard.h"
ac811a55 33#include "intervals.h"
7b863bd5 34
bc937db7
KH
35#ifndef NULL
36#define NULL (void *)0
37#endif
38
9309fdb1
KH
39extern Lisp_Object Flookup_key ();
40
68732608 41Lisp_Object Qstring_lessp, Qprovide, Qrequire;
0ce830bc 42Lisp_Object Qyes_or_no_p_history;
7b863bd5 43
6cb9cafb 44static int internal_equal ();
e0f5cf5a 45\f
7b863bd5
JB
46DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
47 "Return the argument unchanged.")
48 (arg)
49 Lisp_Object arg;
50{
51 return arg;
52}
53
99175c23
KH
54extern long get_random ();
55extern void seed_random ();
56extern long time ();
57
7b863bd5
JB
58DEFUN ("random", Frandom, Srandom, 0, 1, 0,
59 "Return a pseudo-random number.\n\
4cab5074
KH
60All integers representable in Lisp are equally likely.\n\
61 On most systems, this is 28 bits' worth.\n\
99175c23 62With positive integer argument N, return random number in interval [0,N).\n\
7b863bd5 63With argument t, set the random number seed from the current time and pid.")
ce7385cb
RS
64 (limit)
65 Lisp_Object limit;
7b863bd5 66{
e2d6972a
KH
67 EMACS_INT val;
68 Lisp_Object lispy_val;
78217ef1 69 unsigned long denominator;
7b863bd5 70
ce7385cb 71 if (EQ (limit, Qt))
e2d6972a 72 seed_random (getpid () + time (NULL));
4cab5074 73 if (NATNUMP (limit) && XFASTINT (limit) != 0)
7b863bd5 74 {
4cab5074
KH
75 /* Try to take our random number from the higher bits of VAL,
76 not the lower, since (says Gentzel) the low bits of `random'
77 are less random than the higher ones. We do this by using the
78 quotient rather than the remainder. At the high end of the RNG
79 it's possible to get a quotient larger than limit; discarding
80 these values eliminates the bias that would otherwise appear
81 when using a large limit. */
82 denominator = ((unsigned long)1 << VALBITS) / XFASTINT (limit);
83 do
99175c23 84 val = get_random () / denominator;
4cab5074 85 while (val >= XFASTINT (limit));
7b863bd5 86 }
78217ef1 87 else
99175c23 88 val = get_random ();
e2d6972a
KH
89 XSETINT (lispy_val, val);
90 return lispy_val;
7b863bd5
JB
91}
92\f
93/* Random data-structure functions */
94
95DEFUN ("length", Flength, Slength, 1, 1, 0,
96 "Return the length of vector, list or string SEQUENCE.\n\
97A byte-code function object is also allowed.")
98 (obj)
99 register Lisp_Object obj;
100{
101 register Lisp_Object tail, val;
102 register int i;
103
104 retry:
a2ad3e19
KH
105 if (STRINGP (obj))
106 XSETFASTINT (val, XSTRING (obj)->size);
08623493 107 else if (VECTORP (obj))
a2ad3e19 108 XSETFASTINT (val, XVECTOR (obj)->size);
e03f7933
RS
109 else if (CHAR_TABLE_P (obj))
110 XSETFASTINT (val, CHAR_TABLE_ORDINARY_SLOTS);
111 else if (BOOL_VECTOR_P (obj))
112 XSETFASTINT (val, XBOOL_VECTOR (obj)->size);
08623493
RS
113 else if (COMPILEDP (obj))
114 XSETFASTINT (val, XVECTOR (obj)->size & PSEUDOVECTOR_SIZE_MASK);
7b863bd5
JB
115 else if (CONSP (obj))
116 {
a2ad3e19 117 for (i = 0, tail = obj; !NILP (tail); i++)
7b863bd5
JB
118 {
119 QUIT;
120 tail = Fcdr (tail);
121 }
122
ad17573a 123 XSETFASTINT (val, i);
7b863bd5 124 }
a2ad3e19
KH
125 else if (NILP (obj))
126 XSETFASTINT (val, 0);
7b863bd5
JB
127 else
128 {
129 obj = wrong_type_argument (Qsequencep, obj);
130 goto retry;
131 }
a2ad3e19 132 return val;
7b863bd5
JB
133}
134
5a30fab8
RS
135/* This does not check for quits. That is safe
136 since it must terminate. */
137
138DEFUN ("safe-length", Fsafe_length, Ssafe_length, 1, 1, 0,
139 "Return the length of a list, but avoid error or infinite loop.\n\
140This function never gets an error. If LIST is not really a list,\n\
141it returns 0. If LIST is circular, it returns a finite value\n\
142which is at least the number of distinct elements.")
143 (list)
144 Lisp_Object list;
145{
146 Lisp_Object tail, halftail, length;
147 int len = 0;
148
149 /* halftail is used to detect circular lists. */
150 halftail = list;
151 for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
152 {
153 if (EQ (tail, halftail) && len != 0)
cb3d1a0a 154 break;
5a30fab8 155 len++;
3a61aeb4 156 if ((len & 1) == 0)
5a30fab8
RS
157 halftail = XCONS (halftail)->cdr;
158 }
159
160 XSETINT (length, len);
161 return length;
162}
163
7b863bd5
JB
164DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0,
165 "T if two strings have identical contents.\n\
76d0f732 166Case is significant, but text properties are ignored.\n\
7b863bd5
JB
167Symbols are also allowed; their print names are used instead.")
168 (s1, s2)
169 register Lisp_Object s1, s2;
170{
7650760e 171 if (SYMBOLP (s1))
b2791413 172 XSETSTRING (s1, XSYMBOL (s1)->name);
7650760e 173 if (SYMBOLP (s2))
b2791413 174 XSETSTRING (s2, XSYMBOL (s2)->name);
7b863bd5
JB
175 CHECK_STRING (s1, 0);
176 CHECK_STRING (s2, 1);
177
178 if (XSTRING (s1)->size != XSTRING (s2)->size ||
179 bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size))
180 return Qnil;
181 return Qt;
182}
183
184DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0,
185 "T if first arg string is less than second in lexicographic order.\n\
186Case is significant.\n\
187Symbols are also allowed; their print names are used instead.")
188 (s1, s2)
189 register Lisp_Object s1, s2;
190{
191 register int i;
192 register unsigned char *p1, *p2;
193 register int end;
194
7650760e 195 if (SYMBOLP (s1))
b2791413 196 XSETSTRING (s1, XSYMBOL (s1)->name);
7650760e 197 if (SYMBOLP (s2))
b2791413 198 XSETSTRING (s2, XSYMBOL (s2)->name);
7b863bd5
JB
199 CHECK_STRING (s1, 0);
200 CHECK_STRING (s2, 1);
201
202 p1 = XSTRING (s1)->data;
203 p2 = XSTRING (s2)->data;
204 end = XSTRING (s1)->size;
205 if (end > XSTRING (s2)->size)
206 end = XSTRING (s2)->size;
207
208 for (i = 0; i < end; i++)
209 {
210 if (p1[i] != p2[i])
211 return p1[i] < p2[i] ? Qt : Qnil;
212 }
213 return i < XSTRING (s2)->size ? Qt : Qnil;
214}
215\f
216static Lisp_Object concat ();
217
218/* ARGSUSED */
219Lisp_Object
220concat2 (s1, s2)
221 Lisp_Object s1, s2;
222{
223#ifdef NO_ARG_ARRAY
224 Lisp_Object args[2];
225 args[0] = s1;
226 args[1] = s2;
227 return concat (2, args, Lisp_String, 0);
228#else
229 return concat (2, &s1, Lisp_String, 0);
230#endif /* NO_ARG_ARRAY */
231}
232
d4af3687
RS
233/* ARGSUSED */
234Lisp_Object
235concat3 (s1, s2, s3)
236 Lisp_Object s1, s2, s3;
237{
238#ifdef NO_ARG_ARRAY
239 Lisp_Object args[3];
240 args[0] = s1;
241 args[1] = s2;
242 args[2] = s3;
243 return concat (3, args, Lisp_String, 0);
244#else
245 return concat (3, &s1, Lisp_String, 0);
246#endif /* NO_ARG_ARRAY */
247}
248
7b863bd5
JB
249DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
250 "Concatenate all the arguments and make the result a list.\n\
251The result is a list whose elements are the elements of all the arguments.\n\
252Each argument may be a list, vector or string.\n\
aec1184c 253The last argument is not copied, just used as the tail of the new list.")
7b863bd5
JB
254 (nargs, args)
255 int nargs;
256 Lisp_Object *args;
257{
258 return concat (nargs, args, Lisp_Cons, 1);
259}
260
261DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
262 "Concatenate all the arguments and make the result a string.\n\
263The result is a string whose elements are the elements of all the arguments.\n\
37d40ae9
RS
264Each argument may be a string or a list or vector of characters (integers).\n\
265\n\
266Do not use individual integers as arguments!\n\
267The behavior of `concat' in that case will be changed later!\n\
268If your program passes an integer as an argument to `concat',\n\
269you should change it right away not to do so.")
7b863bd5
JB
270 (nargs, args)
271 int nargs;
272 Lisp_Object *args;
273{
274 return concat (nargs, args, Lisp_String, 0);
275}
276
277DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0,
278 "Concatenate all the arguments and make the result a vector.\n\
279The result is a vector whose elements are the elements of all the arguments.\n\
280Each argument may be a list, vector or string.")
281 (nargs, args)
282 int nargs;
283 Lisp_Object *args;
284{
3e7383eb 285 return concat (nargs, args, Lisp_Vectorlike, 0);
7b863bd5
JB
286}
287
288DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
289 "Return a copy of a list, vector or string.\n\
290The elements of a list or vector are not copied; they are shared\n\
291with the original.")
292 (arg)
293 Lisp_Object arg;
294{
265a9e55 295 if (NILP (arg)) return arg;
e03f7933
RS
296
297 if (CHAR_TABLE_P (arg))
298 {
299 int i, size;
300 Lisp_Object copy;
301
302 /* Calculate the number of extra slots. */
303 size = CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (arg));
c8640abf 304 copy = Fmake_char_table (XCHAR_TABLE (arg)->purpose, Qnil);
e03f7933
RS
305 /* Copy all the slots, including the extra ones. */
306 bcopy (XCHAR_TABLE (arg)->contents, XCHAR_TABLE (copy)->contents,
307 (XCHAR_TABLE (arg)->size & PSEUDOVECTOR_SIZE_MASK) * sizeof (Lisp_Object));
308
309 /* Recursively copy any char-tables in the ordinary slots. */
310 for (i = 0; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
311 if (CHAR_TABLE_P (XCHAR_TABLE (arg)->contents[i]))
312 XCHAR_TABLE (copy)->contents[i]
313 = Fcopy_sequence (XCHAR_TABLE (copy)->contents[i]);
314
315 return copy;
316 }
317
318 if (BOOL_VECTOR_P (arg))
319 {
320 Lisp_Object val;
321 int bits_per_char = INTBITS / sizeof (int);
322 int size_in_chars
323 = (XBOOL_VECTOR (arg)->size + bits_per_char) / bits_per_char;
324
325 val = Fmake_bool_vector (Flength (arg), Qnil);
326 bcopy (XBOOL_VECTOR (arg)->data, XBOOL_VECTOR (val)->data,
327 size_in_chars);
328 return val;
329 }
330
7650760e 331 if (!CONSP (arg) && !VECTORP (arg) && !STRINGP (arg))
7b863bd5
JB
332 arg = wrong_type_argument (Qsequencep, arg);
333 return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
334}
335
336static Lisp_Object
337concat (nargs, args, target_type, last_special)
338 int nargs;
339 Lisp_Object *args;
340 enum Lisp_Type target_type;
341 int last_special;
342{
343 Lisp_Object val;
344 Lisp_Object len;
345 register Lisp_Object tail;
346 register Lisp_Object this;
347 int toindex;
348 register int leni;
349 register int argnum;
350 Lisp_Object last_tail;
351 Lisp_Object prev;
352
353 /* In append, the last arg isn't treated like the others */
354 if (last_special && nargs > 0)
355 {
356 nargs--;
357 last_tail = args[nargs];
358 }
359 else
360 last_tail = Qnil;
361
362 for (argnum = 0; argnum < nargs; argnum++)
363 {
364 this = args[argnum];
7650760e 365 if (!(CONSP (this) || NILP (this) || VECTORP (this) || STRINGP (this)
e03f7933 366 || COMPILEDP (this) || BOOL_VECTOR_P (this)))
7b863bd5 367 {
7650760e 368 if (INTEGERP (this))
37d40ae9 369 args[argnum] = Fnumber_to_string (this);
7b863bd5
JB
370 else
371 args[argnum] = wrong_type_argument (Qsequencep, this);
372 }
373 }
374
375 for (argnum = 0, leni = 0; argnum < nargs; argnum++)
376 {
377 this = args[argnum];
378 len = Flength (this);
379 leni += XFASTINT (len);
380 }
381
ad17573a 382 XSETFASTINT (len, leni);
7b863bd5
JB
383
384 if (target_type == Lisp_Cons)
385 val = Fmake_list (len, Qnil);
3e7383eb 386 else if (target_type == Lisp_Vectorlike)
7b863bd5
JB
387 val = Fmake_vector (len, Qnil);
388 else
389 val = Fmake_string (len, len);
390
391 /* In append, if all but last arg are nil, return last arg */
392 if (target_type == Lisp_Cons && EQ (val, Qnil))
393 return last_tail;
394
395 if (CONSP (val))
396 tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */
397 else
398 toindex = 0;
399
400 prev = Qnil;
401
402 for (argnum = 0; argnum < nargs; argnum++)
403 {
404 Lisp_Object thislen;
405 int thisleni;
406 register int thisindex = 0;
407
408 this = args[argnum];
409 if (!CONSP (this))
410 thislen = Flength (this), thisleni = XINT (thislen);
411
7650760e 412 if (STRINGP (this) && STRINGP (val)
ac811a55
JB
413 && ! NULL_INTERVAL_P (XSTRING (this)->intervals))
414 {
415 copy_text_properties (make_number (0), thislen, this,
416 make_number (toindex), val, Qnil);
417 }
418
7b863bd5
JB
419 while (1)
420 {
421 register Lisp_Object elt;
422
ac811a55
JB
423 /* Fetch next element of `this' arg into `elt', or break if
424 `this' is exhausted. */
265a9e55 425 if (NILP (this)) break;
7b863bd5
JB
426 if (CONSP (this))
427 elt = Fcar (this), this = Fcdr (this);
428 else
429 {
430 if (thisindex >= thisleni) break;
7650760e 431 if (STRINGP (this))
ad17573a 432 XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
e03f7933
RS
433 else if (BOOL_VECTOR_P (this))
434 {
435 int bits_per_char = INTBITS / sizeof (int);
436 int size_in_chars
437 = ((XBOOL_VECTOR (this)->size + bits_per_char)
438 / bits_per_char);
439 int byte;
440 byte = XBOOL_VECTOR (val)->data[thisindex / bits_per_char];
441 if (byte & (1 << thisindex))
442 elt = Qt;
443 else
444 elt = Qnil;
445 }
7b863bd5
JB
446 else
447 elt = XVECTOR (this)->contents[thisindex++];
448 }
449
450 /* Store into result */
451 if (toindex < 0)
452 {
453 XCONS (tail)->car = elt;
454 prev = tail;
455 tail = XCONS (tail)->cdr;
456 }
7650760e 457 else if (VECTORP (val))
7b863bd5
JB
458 XVECTOR (val)->contents[toindex++] = elt;
459 else
460 {
7650760e 461 while (!INTEGERP (elt))
7b863bd5
JB
462 elt = wrong_type_argument (Qintegerp, elt);
463 {
464#ifdef MASSC_REGISTER_BUG
465 /* Even removing all "register"s doesn't disable this bug!
466 Nothing simpler than this seems to work. */
467 unsigned char *p = & XSTRING (val)->data[toindex++];
468 *p = XINT (elt);
469#else
470 XSTRING (val)->data[toindex++] = XINT (elt);
471#endif
472 }
473 }
474 }
475 }
265a9e55 476 if (!NILP (prev))
7b863bd5
JB
477 XCONS (prev)->cdr = last_tail;
478
479 return val;
480}
481\f
482DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
483 "Return a copy of ALIST.\n\
484This is an alist which represents the same mapping from objects to objects,\n\
485but does not share the alist structure with ALIST.\n\
486The objects mapped (cars and cdrs of elements of the alist)\n\
487are shared, however.\n\
488Elements of ALIST that are not conses are also shared.")
489 (alist)
490 Lisp_Object alist;
491{
492 register Lisp_Object tem;
493
494 CHECK_LIST (alist, 0);
265a9e55 495 if (NILP (alist))
7b863bd5
JB
496 return alist;
497 alist = concat (1, &alist, Lisp_Cons, 0);
498 for (tem = alist; CONSP (tem); tem = XCONS (tem)->cdr)
499 {
500 register Lisp_Object car;
501 car = XCONS (tem)->car;
502
503 if (CONSP (car))
504 XCONS (tem)->car = Fcons (XCONS (car)->car, XCONS (car)->cdr);
505 }
506 return alist;
507}
508
509DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
510 "Return a substring of STRING, starting at index FROM and ending before TO.\n\
511TO may be nil or omitted; then the substring runs to the end of STRING.\n\
512If FROM or TO is negative, it counts from the end.")
513 (string, from, to)
514 Lisp_Object string;
515 register Lisp_Object from, to;
516{
ac811a55
JB
517 Lisp_Object res;
518
7b863bd5
JB
519 CHECK_STRING (string, 0);
520 CHECK_NUMBER (from, 1);
265a9e55 521 if (NILP (to))
7b863bd5
JB
522 to = Flength (string);
523 else
524 CHECK_NUMBER (to, 2);
525
526 if (XINT (from) < 0)
527 XSETINT (from, XINT (from) + XSTRING (string)->size);
528 if (XINT (to) < 0)
529 XSETINT (to, XINT (to) + XSTRING (string)->size);
530 if (!(0 <= XINT (from) && XINT (from) <= XINT (to)
531 && XINT (to) <= XSTRING (string)->size))
532 args_out_of_range_3 (string, from, to);
533
ac811a55
JB
534 res = make_string (XSTRING (string)->data + XINT (from),
535 XINT (to) - XINT (from));
536 copy_text_properties (from, to, string, make_number (0), res, Qnil);
537 return res;
7b863bd5
JB
538}
539\f
540DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
541 "Take cdr N times on LIST, returns the result.")
542 (n, list)
543 Lisp_Object n;
544 register Lisp_Object list;
545{
546 register int i, num;
547 CHECK_NUMBER (n, 0);
548 num = XINT (n);
265a9e55 549 for (i = 0; i < num && !NILP (list); i++)
7b863bd5
JB
550 {
551 QUIT;
552 list = Fcdr (list);
553 }
554 return list;
555}
556
557DEFUN ("nth", Fnth, Snth, 2, 2, 0,
558 "Return the Nth element of LIST.\n\
559N counts from zero. If LIST is not that long, nil is returned.")
560 (n, list)
561 Lisp_Object n, list;
562{
563 return Fcar (Fnthcdr (n, list));
564}
565
566DEFUN ("elt", Felt, Selt, 2, 2, 0,
567 "Return element of SEQUENCE at index N.")
568 (seq, n)
569 register Lisp_Object seq, n;
570{
571 CHECK_NUMBER (n, 0);
572 while (1)
573 {
7650760e 574 if (CONSP (seq) || NILP (seq))
7b863bd5 575 return Fcar (Fnthcdr (n, seq));
e03f7933
RS
576 else if (STRINGP (seq) || VECTORP (seq) || BOOL_VECTOR_P (seq)
577 || CHAR_TABLE_P (seq))
7b863bd5
JB
578 return Faref (seq, n);
579 else
580 seq = wrong_type_argument (Qsequencep, seq);
581 }
582}
583
584DEFUN ("member", Fmember, Smember, 2, 2, 0,
1d58e36f 585 "Return non-nil if ELT is an element of LIST. Comparison done with `equal'.\n\
7b863bd5
JB
586The value is actually the tail of LIST whose car is ELT.")
587 (elt, list)
588 register Lisp_Object elt;
589 Lisp_Object list;
590{
591 register Lisp_Object tail;
265a9e55 592 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
593 {
594 register Lisp_Object tem;
595 tem = Fcar (tail);
265a9e55 596 if (! NILP (Fequal (elt, tem)))
7b863bd5
JB
597 return tail;
598 QUIT;
599 }
600 return Qnil;
601}
602
603DEFUN ("memq", Fmemq, Smemq, 2, 2, 0,
604 "Return non-nil if ELT is an element of LIST. Comparison done with EQ.\n\
605The value is actually the tail of LIST whose car is ELT.")
606 (elt, list)
607 register Lisp_Object elt;
608 Lisp_Object list;
609{
610 register Lisp_Object tail;
265a9e55 611 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
612 {
613 register Lisp_Object tem;
614 tem = Fcar (tail);
615 if (EQ (elt, tem)) return tail;
616 QUIT;
617 }
618 return Qnil;
619}
620
621DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
3797b4c3
RS
622 "Return non-nil if KEY is `eq' to the car of an element of LIST.\n\
623The value is actually the element of LIST whose car is KEY.\n\
7b863bd5
JB
624Elements of LIST that are not conses are ignored.")
625 (key, list)
626 register Lisp_Object key;
627 Lisp_Object list;
628{
629 register Lisp_Object tail;
265a9e55 630 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
631 {
632 register Lisp_Object elt, tem;
633 elt = Fcar (tail);
634 if (!CONSP (elt)) continue;
635 tem = Fcar (elt);
636 if (EQ (key, tem)) return elt;
637 QUIT;
638 }
639 return Qnil;
640}
641
642/* Like Fassq but never report an error and do not allow quits.
643 Use only on lists known never to be circular. */
644
645Lisp_Object
646assq_no_quit (key, list)
647 register Lisp_Object key;
648 Lisp_Object list;
649{
650 register Lisp_Object tail;
651 for (tail = list; CONSP (tail); tail = Fcdr (tail))
652 {
653 register Lisp_Object elt, tem;
654 elt = Fcar (tail);
655 if (!CONSP (elt)) continue;
656 tem = Fcar (elt);
657 if (EQ (key, tem)) return elt;
658 }
659 return Qnil;
660}
661
662DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
3797b4c3 663 "Return non-nil if KEY is `equal' to the car of an element of LIST.\n\
0fb5a19c 664The value is actually the element of LIST whose car equals KEY.")
7b863bd5
JB
665 (key, list)
666 register Lisp_Object key;
667 Lisp_Object list;
668{
669 register Lisp_Object tail;
265a9e55 670 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
671 {
672 register Lisp_Object elt, tem;
673 elt = Fcar (tail);
674 if (!CONSP (elt)) continue;
675 tem = Fequal (Fcar (elt), key);
265a9e55 676 if (!NILP (tem)) return elt;
7b863bd5
JB
677 QUIT;
678 }
679 return Qnil;
680}
681
682DEFUN ("rassq", Frassq, Srassq, 2, 2, 0,
683 "Return non-nil if ELT is `eq' to the cdr of an element of LIST.\n\
684The value is actually the element of LIST whose cdr is ELT.")
685 (key, list)
686 register Lisp_Object key;
687 Lisp_Object list;
688{
689 register Lisp_Object tail;
265a9e55 690 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
691 {
692 register Lisp_Object elt, tem;
693 elt = Fcar (tail);
694 if (!CONSP (elt)) continue;
695 tem = Fcdr (elt);
696 if (EQ (key, tem)) return elt;
697 QUIT;
698 }
699 return Qnil;
700}
0fb5a19c
RS
701
702DEFUN ("rassoc", Frassoc, Srassoc, 2, 2, 0,
703 "Return non-nil if KEY is `equal' to the cdr of an element of LIST.\n\
704The value is actually the element of LIST whose cdr equals KEY.")
705 (key, list)
706 register Lisp_Object key;
707 Lisp_Object list;
708{
709 register Lisp_Object tail;
710 for (tail = list; !NILP (tail); tail = Fcdr (tail))
711 {
712 register Lisp_Object elt, tem;
713 elt = Fcar (tail);
714 if (!CONSP (elt)) continue;
715 tem = Fequal (Fcdr (elt), key);
716 if (!NILP (tem)) return elt;
717 QUIT;
718 }
719 return Qnil;
720}
7b863bd5
JB
721\f
722DEFUN ("delq", Fdelq, Sdelq, 2, 2, 0,
723 "Delete by side effect any occurrences of ELT as a member of LIST.\n\
724The modified LIST is returned. Comparison is done with `eq'.\n\
725If the first member of LIST is ELT, there is no way to remove it by side effect;\n\
726therefore, write `(setq foo (delq element foo))'\n\
727to be sure of changing the value of `foo'.")
728 (elt, list)
729 register Lisp_Object elt;
730 Lisp_Object list;
731{
732 register Lisp_Object tail, prev;
733 register Lisp_Object tem;
734
735 tail = list;
736 prev = Qnil;
265a9e55 737 while (!NILP (tail))
7b863bd5
JB
738 {
739 tem = Fcar (tail);
740 if (EQ (elt, tem))
741 {
265a9e55 742 if (NILP (prev))
7b863bd5
JB
743 list = Fcdr (tail);
744 else
745 Fsetcdr (prev, Fcdr (tail));
746 }
747 else
748 prev = tail;
749 tail = Fcdr (tail);
750 QUIT;
751 }
752 return list;
753}
754
ca8dd546 755DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0,
1e134a5f
RM
756 "Delete by side effect any occurrences of ELT as a member of LIST.\n\
757The modified LIST is returned. Comparison is done with `equal'.\n\
1d58e36f
RS
758If the first member of LIST is ELT, deleting it is not a side effect;\n\
759it is simply using a different list.\n\
760Therefore, write `(setq foo (delete element foo))'\n\
1e134a5f
RM
761to be sure of changing the value of `foo'.")
762 (elt, list)
763 register Lisp_Object elt;
764 Lisp_Object list;
765{
766 register Lisp_Object tail, prev;
767 register Lisp_Object tem;
768
769 tail = list;
770 prev = Qnil;
265a9e55 771 while (!NILP (tail))
1e134a5f
RM
772 {
773 tem = Fcar (tail);
f812877e 774 if (! NILP (Fequal (elt, tem)))
1e134a5f 775 {
265a9e55 776 if (NILP (prev))
1e134a5f
RM
777 list = Fcdr (tail);
778 else
779 Fsetcdr (prev, Fcdr (tail));
780 }
781 else
782 prev = tail;
783 tail = Fcdr (tail);
784 QUIT;
785 }
786 return list;
787}
788
7b863bd5
JB
789DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0,
790 "Reverse LIST by modifying cdr pointers.\n\
791Returns the beginning of the reversed list.")
792 (list)
793 Lisp_Object list;
794{
795 register Lisp_Object prev, tail, next;
796
265a9e55 797 if (NILP (list)) return list;
7b863bd5
JB
798 prev = Qnil;
799 tail = list;
265a9e55 800 while (!NILP (tail))
7b863bd5
JB
801 {
802 QUIT;
803 next = Fcdr (tail);
804 Fsetcdr (tail, prev);
805 prev = tail;
806 tail = next;
807 }
808 return prev;
809}
810
811DEFUN ("reverse", Freverse, Sreverse, 1, 1, 0,
812 "Reverse LIST, copying. Returns the beginning of the reversed list.\n\
813See also the function `nreverse', which is used more often.")
814 (list)
815 Lisp_Object list;
816{
817 Lisp_Object length;
818 register Lisp_Object *vec;
819 register Lisp_Object tail;
820 register int i;
821
822 length = Flength (list);
823 vec = (Lisp_Object *) alloca (XINT (length) * sizeof (Lisp_Object));
824 for (i = XINT (length) - 1, tail = list; i >= 0; i--, tail = Fcdr (tail))
825 vec[i] = Fcar (tail);
826
827 return Flist (XINT (length), vec);
828}
829\f
830Lisp_Object merge ();
831
832DEFUN ("sort", Fsort, Ssort, 2, 2, 0,
833 "Sort LIST, stably, comparing elements using PREDICATE.\n\
834Returns the sorted list. LIST is modified by side effects.\n\
835PREDICATE is called with two elements of LIST, and should return T\n\
836if the first element is \"less\" than the second.")
837 (list, pred)
838 Lisp_Object list, pred;
839{
840 Lisp_Object front, back;
841 register Lisp_Object len, tem;
842 struct gcpro gcpro1, gcpro2;
843 register int length;
844
845 front = list;
846 len = Flength (list);
847 length = XINT (len);
848 if (length < 2)
849 return list;
850
851 XSETINT (len, (length / 2) - 1);
852 tem = Fnthcdr (len, list);
853 back = Fcdr (tem);
854 Fsetcdr (tem, Qnil);
855
856 GCPRO2 (front, back);
857 front = Fsort (front, pred);
858 back = Fsort (back, pred);
859 UNGCPRO;
860 return merge (front, back, pred);
861}
862
863Lisp_Object
864merge (org_l1, org_l2, pred)
865 Lisp_Object org_l1, org_l2;
866 Lisp_Object pred;
867{
868 Lisp_Object value;
869 register Lisp_Object tail;
870 Lisp_Object tem;
871 register Lisp_Object l1, l2;
872 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
873
874 l1 = org_l1;
875 l2 = org_l2;
876 tail = Qnil;
877 value = Qnil;
878
879 /* It is sufficient to protect org_l1 and org_l2.
880 When l1 and l2 are updated, we copy the new values
881 back into the org_ vars. */
882 GCPRO4 (org_l1, org_l2, pred, value);
883
884 while (1)
885 {
265a9e55 886 if (NILP (l1))
7b863bd5
JB
887 {
888 UNGCPRO;
265a9e55 889 if (NILP (tail))
7b863bd5
JB
890 return l2;
891 Fsetcdr (tail, l2);
892 return value;
893 }
265a9e55 894 if (NILP (l2))
7b863bd5
JB
895 {
896 UNGCPRO;
265a9e55 897 if (NILP (tail))
7b863bd5
JB
898 return l1;
899 Fsetcdr (tail, l1);
900 return value;
901 }
902 tem = call2 (pred, Fcar (l2), Fcar (l1));
265a9e55 903 if (NILP (tem))
7b863bd5
JB
904 {
905 tem = l1;
906 l1 = Fcdr (l1);
907 org_l1 = l1;
908 }
909 else
910 {
911 tem = l2;
912 l2 = Fcdr (l2);
913 org_l2 = l2;
914 }
265a9e55 915 if (NILP (tail))
7b863bd5
JB
916 value = tem;
917 else
918 Fsetcdr (tail, tem);
919 tail = tem;
920 }
921}
922\f
be9d483d
BG
923
924DEFUN ("plist-get", Fplist_get, Splist_get, 2, 2, 0,
925 "Extract a value from a property list.\n\
926PLIST is a property list, which is a list of the form\n\
c07289e0 927\(PROP1 VALUE1 PROP2 VALUE2...). This function returns the value\n\
be9d483d
BG
928corresponding to the given PROP, or nil if PROP is not\n\
929one of the properties on the list.")
930 (val, prop)
931 Lisp_Object val;
7b863bd5
JB
932 register Lisp_Object prop;
933{
934 register Lisp_Object tail;
be9d483d 935 for (tail = val; !NILP (tail); tail = Fcdr (Fcdr (tail)))
7b863bd5
JB
936 {
937 register Lisp_Object tem;
938 tem = Fcar (tail);
939 if (EQ (prop, tem))
940 return Fcar (Fcdr (tail));
941 }
942 return Qnil;
943}
944
be9d483d
BG
945DEFUN ("get", Fget, Sget, 2, 2, 0,
946 "Return the value of SYMBOL's PROPNAME property.\n\
c07289e0
RS
947This is the last value stored with `(put SYMBOL PROPNAME VALUE)'.")
948 (symbol, propname)
949 Lisp_Object symbol, propname;
be9d483d 950{
c07289e0
RS
951 CHECK_SYMBOL (symbol, 0);
952 return Fplist_get (XSYMBOL (symbol)->plist, propname);
be9d483d
BG
953}
954
955DEFUN ("plist-put", Fplist_put, Splist_put, 3, 3, 0,
956 "Change value in PLIST of PROP to VAL.\n\
957PLIST is a property list, which is a list of the form\n\
c07289e0 958\(PROP1 VALUE1 PROP2 VALUE2 ...). PROP is a symbol and VAL is any object.\n\
be9d483d 959If PROP is already a property on the list, its value is set to VAL,\n\
88435890 960otherwise the new PROP VAL pair is added. The new plist is returned;\n\
be9d483d
BG
961use `(setq x (plist-put x prop val))' to be sure to use the new value.\n\
962The PLIST is modified by side effects.")
963 (plist, prop, val)
964 Lisp_Object plist;
965 register Lisp_Object prop;
966 Lisp_Object val;
7b863bd5
JB
967{
968 register Lisp_Object tail, prev;
969 Lisp_Object newcell;
970 prev = Qnil;
f8307c0c
KH
971 for (tail = plist; CONSP (tail) && CONSP (XCONS (tail)->cdr);
972 tail = XCONS (XCONS (tail)->cdr)->cdr)
7b863bd5 973 {
f8307c0c 974 if (EQ (prop, XCONS (tail)->car))
be9d483d 975 {
f8307c0c 976 Fsetcar (XCONS (tail)->cdr, val);
be9d483d
BG
977 return plist;
978 }
7b863bd5
JB
979 prev = tail;
980 }
981 newcell = Fcons (prop, Fcons (val, Qnil));
265a9e55 982 if (NILP (prev))
be9d483d 983 return newcell;
7b863bd5 984 else
f8307c0c 985 Fsetcdr (XCONS (prev)->cdr, newcell);
be9d483d
BG
986 return plist;
987}
988
989DEFUN ("put", Fput, Sput, 3, 3, 0,
990 "Store SYMBOL's PROPNAME property with value VALUE.\n\
991It can be retrieved with `(get SYMBOL PROPNAME)'.")
c07289e0
RS
992 (symbol, propname, value)
993 Lisp_Object symbol, propname, value;
be9d483d 994{
c07289e0
RS
995 CHECK_SYMBOL (symbol, 0);
996 XSYMBOL (symbol)->plist
997 = Fplist_put (XSYMBOL (symbol)->plist, propname, value);
998 return value;
7b863bd5
JB
999}
1000
1001DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
1002 "T if two Lisp objects have similar structure and contents.\n\
1003They must have the same data type.\n\
1004Conses are compared by comparing the cars and the cdrs.\n\
1005Vectors and strings are compared element by element.\n\
d28c4332
RS
1006Numbers are compared by value, but integers cannot equal floats.\n\
1007 (Use `=' if you want integers and floats to be able to be equal.)\n\
1008Symbols must match exactly.")
7b863bd5
JB
1009 (o1, o2)
1010 register Lisp_Object o1, o2;
1011{
6cb9cafb 1012 return internal_equal (o1, o2, 0) ? Qt : Qnil;
e0f5cf5a
RS
1013}
1014
6cb9cafb 1015static int
e0f5cf5a
RS
1016internal_equal (o1, o2, depth)
1017 register Lisp_Object o1, o2;
1018 int depth;
1019{
1020 if (depth > 200)
1021 error ("Stack overflow in equal");
4ff1aed9 1022
6cb9cafb 1023 tail_recurse:
7b863bd5 1024 QUIT;
4ff1aed9
RS
1025 if (EQ (o1, o2))
1026 return 1;
1027 if (XTYPE (o1) != XTYPE (o2))
1028 return 0;
1029
1030 switch (XTYPE (o1))
1031 {
31ef7f7a 1032#ifdef LISP_FLOAT_TYPE
4ff1aed9
RS
1033 case Lisp_Float:
1034 return (extract_float (o1) == extract_float (o2));
31ef7f7a 1035#endif
4ff1aed9
RS
1036
1037 case Lisp_Cons:
4cab5074
KH
1038 if (!internal_equal (XCONS (o1)->car, XCONS (o2)->car, depth + 1))
1039 return 0;
1040 o1 = XCONS (o1)->cdr;
1041 o2 = XCONS (o2)->cdr;
1042 goto tail_recurse;
4ff1aed9
RS
1043
1044 case Lisp_Misc:
81d1fba6 1045 if (XMISCTYPE (o1) != XMISCTYPE (o2))
6cb9cafb 1046 return 0;
4ff1aed9 1047 if (OVERLAYP (o1))
7b863bd5 1048 {
4ff1aed9
RS
1049 if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o1),
1050 depth + 1)
1051 || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o1),
1052 depth + 1))
6cb9cafb 1053 return 0;
4ff1aed9
RS
1054 o1 = XOVERLAY (o1)->plist;
1055 o2 = XOVERLAY (o2)->plist;
1056 goto tail_recurse;
7b863bd5 1057 }
4ff1aed9
RS
1058 if (MARKERP (o1))
1059 {
1060 return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
1061 && (XMARKER (o1)->buffer == 0
1062 || XMARKER (o1)->bufpos == XMARKER (o2)->bufpos));
1063 }
1064 break;
1065
1066 case Lisp_Vectorlike:
4cab5074
KH
1067 {
1068 register int i, size;
1069 size = XVECTOR (o1)->size;
1070 /* Pseudovectors have the type encoded in the size field, so this test
1071 actually checks that the objects have the same type as well as the
1072 same size. */
1073 if (XVECTOR (o2)->size != size)
1074 return 0;
e03f7933
RS
1075 /* Boolvectors are compared much like strings. */
1076 if (BOOL_VECTOR_P (o1))
1077 {
1078 int bits_per_char = INTBITS / sizeof (int);
1079 int size_in_chars
1080 = (XBOOL_VECTOR (o1)->size + bits_per_char) / bits_per_char;
1081
1082 if (XBOOL_VECTOR (o1)->size != XBOOL_VECTOR (o2)->size)
1083 return 0;
1084 if (bcmp (XBOOL_VECTOR (o1)->data, XBOOL_VECTOR (o2)->data,
1085 size_in_chars))
1086 return 0;
1087 return 1;
1088 }
1089
1090 /* Aside from them, only true vectors, char-tables, and compiled
1091 functions are sensible to compare, so eliminate the others now. */
4cab5074
KH
1092 if (size & PSEUDOVECTOR_FLAG)
1093 {
e03f7933 1094 if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE)))
4cab5074
KH
1095 return 0;
1096 size &= PSEUDOVECTOR_SIZE_MASK;
1097 }
1098 for (i = 0; i < size; i++)
1099 {
1100 Lisp_Object v1, v2;
1101 v1 = XVECTOR (o1)->contents [i];
1102 v2 = XVECTOR (o2)->contents [i];
1103 if (!internal_equal (v1, v2, depth + 1))
1104 return 0;
1105 }
1106 return 1;
1107 }
4ff1aed9
RS
1108 break;
1109
1110 case Lisp_String:
4cab5074
KH
1111 if (XSTRING (o1)->size != XSTRING (o2)->size)
1112 return 0;
1113 if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data,
1114 XSTRING (o1)->size))
1115 return 0;
76d0f732 1116#ifdef USE_TEXT_PROPERTIES
4cab5074
KH
1117 /* If the strings have intervals, verify they match;
1118 if not, they are unequal. */
1119 if ((XSTRING (o1)->intervals != 0 || XSTRING (o2)->intervals != 0)
1120 && ! compare_string_intervals (o1, o2))
1121 return 0;
76d0f732 1122#endif
4cab5074 1123 return 1;
7b863bd5 1124 }
6cb9cafb 1125 return 0;
7b863bd5
JB
1126}
1127\f
1128DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
e03f7933
RS
1129 "Store each element of ARRAY with ITEM.\n\
1130ARRAY is a vector, string, char-table, or bool-vector.")
7b863bd5
JB
1131 (array, item)
1132 Lisp_Object array, item;
1133{
1134 register int size, index, charval;
1135 retry:
7650760e 1136 if (VECTORP (array))
7b863bd5
JB
1137 {
1138 register Lisp_Object *p = XVECTOR (array)->contents;
1139 size = XVECTOR (array)->size;
1140 for (index = 0; index < size; index++)
1141 p[index] = item;
1142 }
e03f7933
RS
1143 else if (CHAR_TABLE_P (array))
1144 {
1145 register Lisp_Object *p = XCHAR_TABLE (array)->contents;
1146 size = CHAR_TABLE_ORDINARY_SLOTS;
1147 for (index = 0; index < size; index++)
1148 p[index] = item;
1149 XCHAR_TABLE (array)->defalt = Qnil;
1150 }
7650760e 1151 else if (STRINGP (array))
7b863bd5
JB
1152 {
1153 register unsigned char *p = XSTRING (array)->data;
1154 CHECK_NUMBER (item, 1);
1155 charval = XINT (item);
1156 size = XSTRING (array)->size;
1157 for (index = 0; index < size; index++)
1158 p[index] = charval;
1159 }
e03f7933
RS
1160 else if (BOOL_VECTOR_P (array))
1161 {
1162 register unsigned char *p = XBOOL_VECTOR (array)->data;
1163 int bits_per_char = INTBITS / sizeof (int);
1164 int size_in_chars
1165 = (XBOOL_VECTOR (array)->size + bits_per_char) / bits_per_char;
1166
1167 charval = (! NILP (item) ? -1 : 0);
1168 for (index = 0; index < size_in_chars; index++)
1169 p[index] = charval;
1170 }
7b863bd5
JB
1171 else
1172 {
1173 array = wrong_type_argument (Qarrayp, array);
1174 goto retry;
1175 }
1176 return array;
1177}
1178
999de246
RS
1179DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
1180 1, 1, 0,
1181 "Return the subtype of char-table CHAR-TABLE. The value is a symbol.")
1182 (chartable)
1183 Lisp_Object chartable;
1184{
1185 CHECK_CHAR_TABLE (chartable, 0);
1186
1187 return XCHAR_TABLE (chartable)->purpose;
1188}
1189
e03f7933
RS
1190DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
1191 1, 1, 0,
1192 "Return the parent char-table of CHAR-TABLE.\n\
1193The value is either nil or another char-table.\n\
1194If CHAR-TABLE holds nil for a given character,\n\
1195then the actual applicable value is inherited from the parent char-table\n\
1196\(or from its parents, if necessary).")
1197 (chartable)
1198 Lisp_Object chartable;
1199{
1200 CHECK_CHAR_TABLE (chartable, 0);
1201
1202 return XCHAR_TABLE (chartable)->parent;
1203}
1204
1205DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
1206 2, 2, 0,
1207 "Set the parent char-table of CHAR-TABLE to PARENT.\n\
1208PARENT must be either nil or another char-table.")
1209 (chartable, parent)
1210 Lisp_Object chartable, parent;
1211{
1212 Lisp_Object temp;
1213
1214 CHECK_CHAR_TABLE (chartable, 0);
e03f7933 1215
c8640abf
RS
1216 if (!NILP (parent))
1217 {
1218 CHECK_CHAR_TABLE (parent, 0);
1219
1220 for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
1221 if (EQ (temp, chartable))
1222 error ("Attempt to make a chartable be its own parent");
1223 }
e03f7933
RS
1224
1225 XCHAR_TABLE (chartable)->parent = parent;
1226
1227 return parent;
1228}
1229
1230DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
1231 2, 2, 0,
1232 "Return the value in extra-slot number N of char-table CHAR-TABLE.")
1233 (chartable, n)
1234 Lisp_Object chartable, n;
1235{
1236 CHECK_CHAR_TABLE (chartable, 1);
1237 CHECK_NUMBER (n, 2);
1238 if (XINT (n) < 0
1239 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (chartable)))
1240 args_out_of_range (chartable, n);
1241
1242 return XCHAR_TABLE (chartable)->extras[XINT (n)];
1243}
1244
1245DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
1246 Sset_char_table_extra_slot,
1247 3, 3, 0,
1248 "Set extra-slot number N of CHAR-TABLE to VALUE.")
1249 (chartable, n, value)
1250 Lisp_Object chartable, n, value;
1251{
1252 CHECK_CHAR_TABLE (chartable, 1);
1253 CHECK_NUMBER (n, 2);
1254 if (XINT (n) < 0
1255 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (chartable)))
1256 args_out_of_range (chartable, n);
1257
1258 return XCHAR_TABLE (chartable)->extras[XINT (n)] = value;
1259}
1260
999de246
RS
1261DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
1262 2, 2, 0,
1263 "Return the value in CHARTABLE for a range of characters RANGE.\n\
1264RANGE should be t (for all characters), nil (for the default value)\n\
1265a vector which identifies a character set or a row of a character set,\n\
1266or a character code.")
1267 (chartable, range)
1268 Lisp_Object chartable, range;
1269{
1270 int i;
1271
1272 CHECK_CHAR_TABLE (chartable, 0);
1273
1274 if (EQ (range, Qnil))
1275 return XCHAR_TABLE (chartable)->defalt;
1276 else if (INTEGERP (range))
1277 return Faref (chartable, range);
1278 else if (VECTORP (range))
1279 {
1280 for (i = 0; i < XVECTOR (range)->size - 1; i++)
1281 chartable = Faref (chartable, XVECTOR (range)->contents[i]);
1282
1283 if (EQ (XVECTOR (range)->contents[i], Qnil))
1284 return XCHAR_TABLE (chartable)->defalt;
1285 else
1286 return Faref (chartable, XVECTOR (range)->contents[i]);
1287 }
1288 else
1289 error ("Invalid RANGE argument to `char-table-range'");
1290}
1291
e03f7933
RS
1292DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
1293 3, 3, 0,
1294 "Set the value in CHARTABLE for a range of characters RANGE to VALUE.\n\
1295RANGE should be t (for all characters), nil (for the default value)\n\
1296a vector which identifies a character set or a row of a character set,\n\
1297or a character code.")
1298 (chartable, range, value)
1299 Lisp_Object chartable, range, value;
1300{
1301 int i;
1302
1303 CHECK_CHAR_TABLE (chartable, 0);
1304
1305 if (EQ (range, Qt))
1306 for (i = 0; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
1307 XCHAR_TABLE (chartable)->contents[i] = value;
1308 else if (EQ (range, Qnil))
1309 XCHAR_TABLE (chartable)->defalt = value;
1310 else if (INTEGERP (range))
1311 Faset (chartable, range, value);
1312 else if (VECTORP (range))
1313 {
1314 for (i = 0; i < XVECTOR (range)->size - 1; i++)
1315 chartable = Faref (chartable, XVECTOR (range)->contents[i]);
1316
1317 if (EQ (XVECTOR (range)->contents[i], Qnil))
1318 XCHAR_TABLE (chartable)->defalt = value;
1319 else
1320 Faset (chartable, XVECTOR (range)->contents[i], value);
1321 }
1322 else
1323 error ("Invalid RANGE argument to `set-char-table-range'");
1324
1325 return value;
1326}
1327\f
c8640abf
RS
1328/* Map C_FUNCTION or FUNCTION over CHARTABLE, calling it for each
1329 character or group of characters that share a value.
1330 DEPTH is the current depth in the originally specified
1331 chartable, and INDICES contains the vector indices
1332 for the levels our callers have descended. */
1333
1334void
1335map_char_table (c_function, function, chartable, depth, indices)
1336 Lisp_Object (*c_function) (), function, chartable, depth, *indices;
e03f7933
RS
1337{
1338 int i;
da19ac11 1339 int size = CHAR_TABLE_ORDINARY_SLOTS;
e03f7933
RS
1340
1341 /* Make INDICES longer if we are about to fill it up. */
1342 if ((depth % 10) == 9)
1343 {
1344 Lisp_Object *new_indices
1345 = (Lisp_Object *) alloca ((depth += 10) * sizeof (Lisp_Object));
1346 bcopy (indices, new_indices, depth * sizeof (Lisp_Object));
1347 indices = new_indices;
1348 }
1349
1350 for (i = 0; i < size; i++)
1351 {
1352 Lisp_Object elt;
1353 indices[depth] = i;
1354 elt = XCHAR_TABLE (chartable)->contents[i];
c8640abf
RS
1355 if (CHAR_TABLE_P (elt))
1356 map_char_table (chartable, c_function, function, depth + 1, indices);
1357 else if (c_function)
1358 (*c_function) (depth + 1, indices, elt);
999de246
RS
1359 /* Here we should handle all cases where the range is a single character
1360 by passing that character as a number. Currently, that is
1361 all the time, but with the MULE code this will have to be changed. */
1362 else if (depth == 0)
1363 call2 (function, make_number (i), elt);
e03f7933 1364 else
c8640abf 1365 call2 (function, Fvector (depth + 1, indices), elt);
e03f7933
RS
1366 }
1367}
1368
1369DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
1370 2, 2, 0,
1371 "Call FUNCTION for each range of like characters in CHARTABLE.\n\
1372FUNCTION is called with two arguments--a key and a value.\n\
1373The key is always a possible RANGE argument to `set-char-table-range'.")
1374 (function, chartable)
1375 Lisp_Object function, chartable;
1376{
1377 Lisp_Object keyvec;
1378 Lisp_Object *indices = (Lisp_Object *) alloca (10 * sizeof (Lisp_Object));
1379
cf693838 1380 map_char_table (NULL, function, chartable, 0, indices);
e03f7933
RS
1381 return Qnil;
1382}
1383\f
7b863bd5
JB
1384/* ARGSUSED */
1385Lisp_Object
1386nconc2 (s1, s2)
1387 Lisp_Object s1, s2;
1388{
1389#ifdef NO_ARG_ARRAY
1390 Lisp_Object args[2];
1391 args[0] = s1;
1392 args[1] = s2;
1393 return Fnconc (2, args);
1394#else
1395 return Fnconc (2, &s1);
1396#endif /* NO_ARG_ARRAY */
1397}
1398
1399DEFUN ("nconc", Fnconc, Snconc, 0, MANY, 0,
1400 "Concatenate any number of lists by altering them.\n\
1401Only the last argument is not altered, and need not be a list.")
1402 (nargs, args)
1403 int nargs;
1404 Lisp_Object *args;
1405{
1406 register int argnum;
1407 register Lisp_Object tail, tem, val;
1408
1409 val = Qnil;
1410
1411 for (argnum = 0; argnum < nargs; argnum++)
1412 {
1413 tem = args[argnum];
265a9e55 1414 if (NILP (tem)) continue;
7b863bd5 1415
265a9e55 1416 if (NILP (val))
7b863bd5
JB
1417 val = tem;
1418
1419 if (argnum + 1 == nargs) break;
1420
1421 if (!CONSP (tem))
1422 tem = wrong_type_argument (Qlistp, tem);
1423
1424 while (CONSP (tem))
1425 {
1426 tail = tem;
1427 tem = Fcdr (tail);
1428 QUIT;
1429 }
1430
1431 tem = args[argnum + 1];
1432 Fsetcdr (tail, tem);
265a9e55 1433 if (NILP (tem))
7b863bd5
JB
1434 args[argnum + 1] = tail;
1435 }
1436
1437 return val;
1438}
1439\f
1440/* This is the guts of all mapping functions.
1441 Apply fn to each element of seq, one by one,
1442 storing the results into elements of vals, a C vector of Lisp_Objects.
1443 leni is the length of vals, which should also be the length of seq. */
1444
1445static void
1446mapcar1 (leni, vals, fn, seq)
1447 int leni;
1448 Lisp_Object *vals;
1449 Lisp_Object fn, seq;
1450{
1451 register Lisp_Object tail;
1452 Lisp_Object dummy;
1453 register int i;
1454 struct gcpro gcpro1, gcpro2, gcpro3;
1455
1456 /* Don't let vals contain any garbage when GC happens. */
1457 for (i = 0; i < leni; i++)
1458 vals[i] = Qnil;
1459
1460 GCPRO3 (dummy, fn, seq);
1461 gcpro1.var = vals;
1462 gcpro1.nvars = leni;
1463 /* We need not explicitly protect `tail' because it is used only on lists, and
1464 1) lists are not relocated and 2) the list is marked via `seq' so will not be freed */
1465
7650760e 1466 if (VECTORP (seq))
7b863bd5
JB
1467 {
1468 for (i = 0; i < leni; i++)
1469 {
1470 dummy = XVECTOR (seq)->contents[i];
1471 vals[i] = call1 (fn, dummy);
1472 }
1473 }
7650760e 1474 else if (STRINGP (seq))
7b863bd5
JB
1475 {
1476 for (i = 0; i < leni; i++)
1477 {
ad17573a 1478 XSETFASTINT (dummy, XSTRING (seq)->data[i]);
7b863bd5
JB
1479 vals[i] = call1 (fn, dummy);
1480 }
1481 }
1482 else /* Must be a list, since Flength did not get an error */
1483 {
1484 tail = seq;
1485 for (i = 0; i < leni; i++)
1486 {
1487 vals[i] = call1 (fn, Fcar (tail));
1488 tail = Fcdr (tail);
1489 }
1490 }
1491
1492 UNGCPRO;
1493}
1494
1495DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
1496 "Apply FN to each element of SEQ, and concat the results as strings.\n\
1497In between each pair of results, stick in SEP.\n\
acbeb206 1498Thus, \" \" as SEP results in spaces between the values returned by FN.")
7b863bd5
JB
1499 (fn, seq, sep)
1500 Lisp_Object fn, seq, sep;
1501{
1502 Lisp_Object len;
1503 register int leni;
1504 int nargs;
1505 register Lisp_Object *args;
1506 register int i;
1507 struct gcpro gcpro1;
1508
1509 len = Flength (seq);
1510 leni = XINT (len);
1511 nargs = leni + leni - 1;
1512 if (nargs < 0) return build_string ("");
1513
1514 args = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object));
1515
1516 GCPRO1 (sep);
1517 mapcar1 (leni, args, fn, seq);
1518 UNGCPRO;
1519
1520 for (i = leni - 1; i >= 0; i--)
1521 args[i + i] = args[i];
1522
1523 for (i = 1; i < nargs; i += 2)
1524 args[i] = sep;
1525
1526 return Fconcat (nargs, args);
1527}
1528
1529DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
1530 "Apply FUNCTION to each element of SEQUENCE, and make a list of the results.\n\
1531The result is a list just as long as SEQUENCE.\n\
1532SEQUENCE may be a list, a vector or a string.")
1533 (fn, seq)
1534 Lisp_Object fn, seq;
1535{
1536 register Lisp_Object len;
1537 register int leni;
1538 register Lisp_Object *args;
1539
1540 len = Flength (seq);
1541 leni = XFASTINT (len);
1542 args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
1543
1544 mapcar1 (leni, args, fn, seq);
1545
1546 return Flist (leni, args);
1547}
1548\f
1549/* Anything that calls this function must protect from GC! */
1550
1551DEFUN ("y-or-n-p", Fy_or_n_p, Sy_or_n_p, 1, 1, 0,
1552 "Ask user a \"y or n\" question. Return t if answer is \"y\".\n\
c763f396
RS
1553Takes one argument, which is the string to display to ask the question.\n\
1554It should end in a space; `y-or-n-p' adds `(y or n) ' to it.\n\
7b863bd5
JB
1555No confirmation of the answer is requested; a single character is enough.\n\
1556Also accepts Space to mean yes, or Delete to mean no.")
1557 (prompt)
1558 Lisp_Object prompt;
1559{
f5313ed9
RS
1560 register Lisp_Object obj, key, def, answer_string, map;
1561 register int answer;
7b863bd5
JB
1562 Lisp_Object xprompt;
1563 Lisp_Object args[2];
1564 int ocech = cursor_in_echo_area;
1565 struct gcpro gcpro1, gcpro2;
1566
f5313ed9
RS
1567 map = Fsymbol_value (intern ("query-replace-map"));
1568
7b863bd5
JB
1569 CHECK_STRING (prompt, 0);
1570 xprompt = prompt;
1571 GCPRO2 (prompt, xprompt);
1572
1573 while (1)
1574 {
dfa89228 1575#ifdef HAVE_X_MENU
588064ce
RS
1576 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
1577 && using_x_p ())
1db4cfb2
RS
1578 {
1579 Lisp_Object pane, menu;
a3b14a45 1580 redisplay_preserve_echo_area ();
1db4cfb2
RS
1581 pane = Fcons (Fcons (build_string ("Yes"), Qt),
1582 Fcons (Fcons (build_string ("No"), Qnil),
1583 Qnil));
ec26e1b9 1584 menu = Fcons (prompt, pane);
d2f28f78 1585 obj = Fx_popup_dialog (Qt, menu);
1db4cfb2
RS
1586 answer = !NILP (obj);
1587 break;
1588 }
dfa89228
KH
1589#endif
1590 cursor_in_echo_area = 1;
d8616fc1 1591 message_nolog ("%s(y or n) ", XSTRING (xprompt)->data);
7b863bd5 1592
dfa89228
KH
1593 obj = read_filtered_event (1, 0, 0);
1594 cursor_in_echo_area = 0;
1595 /* If we need to quit, quit with cursor_in_echo_area = 0. */
1596 QUIT;
a63f658b 1597
f5313ed9
RS
1598 key = Fmake_vector (make_number (1), obj);
1599 def = Flookup_key (map, key);
1600 answer_string = Fsingle_key_description (obj);
7b863bd5 1601
f5313ed9
RS
1602 if (EQ (def, intern ("skip")))
1603 {
1604 answer = 0;
1605 break;
1606 }
1607 else if (EQ (def, intern ("act")))
1608 {
1609 answer = 1;
1610 break;
1611 }
29944b73
RS
1612 else if (EQ (def, intern ("recenter")))
1613 {
1614 Frecenter (Qnil);
1615 xprompt = prompt;
1616 continue;
1617 }
f5313ed9 1618 else if (EQ (def, intern ("quit")))
7b863bd5 1619 Vquit_flag = Qt;
ec63af1b
RS
1620 /* We want to exit this command for exit-prefix,
1621 and this is the only way to do it. */
1622 else if (EQ (def, intern ("exit-prefix")))
1623 Vquit_flag = Qt;
f5313ed9 1624
7b863bd5 1625 QUIT;
20aa96aa
JB
1626
1627 /* If we don't clear this, then the next call to read_char will
1628 return quit_char again, and we'll enter an infinite loop. */
088880f1 1629 Vquit_flag = Qnil;
7b863bd5
JB
1630
1631 Fding (Qnil);
1632 Fdiscard_input ();
1633 if (EQ (xprompt, prompt))
1634 {
1635 args[0] = build_string ("Please answer y or n. ");
1636 args[1] = prompt;
1637 xprompt = Fconcat (2, args);
1638 }
1639 }
1640 UNGCPRO;
6a8a9750 1641
09c95874
RS
1642 if (! noninteractive)
1643 {
1644 cursor_in_echo_area = -1;
d8616fc1
KH
1645 message_nolog ("%s(y or n) %c",
1646 XSTRING (xprompt)->data, answer ? 'y' : 'n');
09c95874
RS
1647 cursor_in_echo_area = ocech;
1648 }
6a8a9750 1649
f5313ed9 1650 return answer ? Qt : Qnil;
7b863bd5
JB
1651}
1652\f
1653/* This is how C code calls `yes-or-no-p' and allows the user
1654 to redefined it.
1655
1656 Anything that calls this function must protect from GC! */
1657
1658Lisp_Object
1659do_yes_or_no_p (prompt)
1660 Lisp_Object prompt;
1661{
1662 return call1 (intern ("yes-or-no-p"), prompt);
1663}
1664
1665/* Anything that calls this function must protect from GC! */
1666
1667DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0,
c763f396
RS
1668 "Ask user a yes-or-no question. Return t if answer is yes.\n\
1669Takes one argument, which is the string to display to ask the question.\n\
1670It should end in a space; `yes-or-no-p' adds `(yes or no) ' to it.\n\
1671The user must confirm the answer with RET,\n\
d8616fc1 1672and can edit it until it has been confirmed.")
7b863bd5
JB
1673 (prompt)
1674 Lisp_Object prompt;
1675{
1676 register Lisp_Object ans;
1677 Lisp_Object args[2];
1678 struct gcpro gcpro1;
1db4cfb2 1679 Lisp_Object menu;
7b863bd5
JB
1680
1681 CHECK_STRING (prompt, 0);
1682
dfa89228 1683#ifdef HAVE_X_MENU
588064ce
RS
1684 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
1685 && using_x_p ())
1db4cfb2
RS
1686 {
1687 Lisp_Object pane, menu, obj;
a3b14a45 1688 redisplay_preserve_echo_area ();
1db4cfb2
RS
1689 pane = Fcons (Fcons (build_string ("Yes"), Qt),
1690 Fcons (Fcons (build_string ("No"), Qnil),
1691 Qnil));
1692 GCPRO1 (pane);
ec26e1b9 1693 menu = Fcons (prompt, pane);
b5ccb0a9 1694 obj = Fx_popup_dialog (Qt, menu);
1db4cfb2
RS
1695 UNGCPRO;
1696 return obj;
1697 }
dfa89228 1698#endif
1db4cfb2 1699
7b863bd5
JB
1700 args[0] = prompt;
1701 args[1] = build_string ("(yes or no) ");
1702 prompt = Fconcat (2, args);
1703
1704 GCPRO1 (prompt);
1db4cfb2 1705
7b863bd5
JB
1706 while (1)
1707 {
0ce830bc
RS
1708 ans = Fdowncase (Fread_from_minibuffer (prompt, Qnil, Qnil, Qnil,
1709 Qyes_or_no_p_history));
7b863bd5
JB
1710 if (XSTRING (ans)->size == 3 && !strcmp (XSTRING (ans)->data, "yes"))
1711 {
1712 UNGCPRO;
1713 return Qt;
1714 }
1715 if (XSTRING (ans)->size == 2 && !strcmp (XSTRING (ans)->data, "no"))
1716 {
1717 UNGCPRO;
1718 return Qnil;
1719 }
1720
1721 Fding (Qnil);
1722 Fdiscard_input ();
1723 message ("Please answer yes or no.");
99dc4745 1724 Fsleep_for (make_number (2), Qnil);
7b863bd5 1725 }
7b863bd5
JB
1726}
1727\f
7b863bd5
JB
1728DEFUN ("load-average", Fload_average, Sload_average, 0, 0, 0,
1729 "Return list of 1 minute, 5 minute and 15 minute load averages.\n\
1730Each of the three load averages is multiplied by 100,\n\
daa37602
JB
1731then converted to integer.\n\
1732If the 5-minute or 15-minute load averages are not available, return a\n\
1733shortened list, containing only those averages which are available.")
7b863bd5
JB
1734 ()
1735{
daa37602
JB
1736 double load_ave[3];
1737 int loads = getloadavg (load_ave, 3);
1738 Lisp_Object ret;
7b863bd5 1739
daa37602
JB
1740 if (loads < 0)
1741 error ("load-average not implemented for this operating system");
1742
1743 ret = Qnil;
1744 while (loads > 0)
1745 ret = Fcons (make_number ((int) (load_ave[--loads] * 100.0)), ret);
1746
1747 return ret;
1748}
7b863bd5
JB
1749\f
1750Lisp_Object Vfeatures;
1751
1752DEFUN ("featurep", Ffeaturep, Sfeaturep, 1, 1, 0,
1753 "Returns t if FEATURE is present in this Emacs.\n\
1754Use this to conditionalize execution of lisp code based on the presence or\n\
1755absence of emacs or environment extensions.\n\
1756Use `provide' to declare that a feature is available.\n\
1757This function looks at the value of the variable `features'.")
1758 (feature)
1759 Lisp_Object feature;
1760{
1761 register Lisp_Object tem;
1762 CHECK_SYMBOL (feature, 0);
1763 tem = Fmemq (feature, Vfeatures);
265a9e55 1764 return (NILP (tem)) ? Qnil : Qt;
7b863bd5
JB
1765}
1766
1767DEFUN ("provide", Fprovide, Sprovide, 1, 1, 0,
1768 "Announce that FEATURE is a feature of the current Emacs.")
1769 (feature)
1770 Lisp_Object feature;
1771{
1772 register Lisp_Object tem;
1773 CHECK_SYMBOL (feature, 0);
265a9e55 1774 if (!NILP (Vautoload_queue))
7b863bd5
JB
1775 Vautoload_queue = Fcons (Fcons (Vfeatures, Qnil), Vautoload_queue);
1776 tem = Fmemq (feature, Vfeatures);
265a9e55 1777 if (NILP (tem))
7b863bd5 1778 Vfeatures = Fcons (feature, Vfeatures);
68732608 1779 LOADHIST_ATTACH (Fcons (Qprovide, feature));
7b863bd5
JB
1780 return feature;
1781}
1782
1783DEFUN ("require", Frequire, Srequire, 1, 2, 0,
1784 "If feature FEATURE is not loaded, load it from FILENAME.\n\
1785If FEATURE is not a member of the list `features', then the feature\n\
1786is not loaded; so load the file FILENAME.\n\
1787If FILENAME is omitted, the printname of FEATURE is used as the file name.")
1788 (feature, file_name)
1789 Lisp_Object feature, file_name;
1790{
1791 register Lisp_Object tem;
1792 CHECK_SYMBOL (feature, 0);
1793 tem = Fmemq (feature, Vfeatures);
68732608 1794 LOADHIST_ATTACH (Fcons (Qrequire, feature));
265a9e55 1795 if (NILP (tem))
7b863bd5
JB
1796 {
1797 int count = specpdl_ptr - specpdl;
1798
1799 /* Value saved here is to be restored into Vautoload_queue */
1800 record_unwind_protect (un_autoload, Vautoload_queue);
1801 Vautoload_queue = Qt;
1802
265a9e55 1803 Fload (NILP (file_name) ? Fsymbol_name (feature) : file_name,
7b863bd5
JB
1804 Qnil, Qt, Qnil);
1805
1806 tem = Fmemq (feature, Vfeatures);
265a9e55 1807 if (NILP (tem))
7b863bd5
JB
1808 error ("Required feature %s was not provided",
1809 XSYMBOL (feature)->name->data );
1810
1811 /* Once loading finishes, don't undo it. */
1812 Vautoload_queue = Qt;
1813 feature = unbind_to (count, feature);
1814 }
1815 return feature;
1816}
1817\f
1818syms_of_fns ()
1819{
1820 Qstring_lessp = intern ("string-lessp");
1821 staticpro (&Qstring_lessp);
68732608
RS
1822 Qprovide = intern ("provide");
1823 staticpro (&Qprovide);
1824 Qrequire = intern ("require");
1825 staticpro (&Qrequire);
0ce830bc
RS
1826 Qyes_or_no_p_history = intern ("yes-or-no-p-history");
1827 staticpro (&Qyes_or_no_p_history);
7b863bd5
JB
1828
1829 DEFVAR_LISP ("features", &Vfeatures,
1830 "A list of symbols which are the features of the executing emacs.\n\
1831Used by `featurep' and `require', and altered by `provide'.");
1832 Vfeatures = Qnil;
1833
1834 defsubr (&Sidentity);
1835 defsubr (&Srandom);
1836 defsubr (&Slength);
5a30fab8 1837 defsubr (&Ssafe_length);
7b863bd5
JB
1838 defsubr (&Sstring_equal);
1839 defsubr (&Sstring_lessp);
1840 defsubr (&Sappend);
1841 defsubr (&Sconcat);
1842 defsubr (&Svconcat);
1843 defsubr (&Scopy_sequence);
1844 defsubr (&Scopy_alist);
1845 defsubr (&Ssubstring);
1846 defsubr (&Snthcdr);
1847 defsubr (&Snth);
1848 defsubr (&Selt);
1849 defsubr (&Smember);
1850 defsubr (&Smemq);
1851 defsubr (&Sassq);
1852 defsubr (&Sassoc);
1853 defsubr (&Srassq);
0fb5a19c 1854 defsubr (&Srassoc);
7b863bd5 1855 defsubr (&Sdelq);
ca8dd546 1856 defsubr (&Sdelete);
7b863bd5
JB
1857 defsubr (&Snreverse);
1858 defsubr (&Sreverse);
1859 defsubr (&Ssort);
be9d483d 1860 defsubr (&Splist_get);
7b863bd5 1861 defsubr (&Sget);
be9d483d 1862 defsubr (&Splist_put);
7b863bd5
JB
1863 defsubr (&Sput);
1864 defsubr (&Sequal);
1865 defsubr (&Sfillarray);
999de246 1866 defsubr (&Schar_table_subtype);
e03f7933
RS
1867 defsubr (&Schar_table_parent);
1868 defsubr (&Sset_char_table_parent);
1869 defsubr (&Schar_table_extra_slot);
1870 defsubr (&Sset_char_table_extra_slot);
999de246 1871 defsubr (&Schar_table_range);
e03f7933
RS
1872 defsubr (&Sset_char_table_range);
1873 defsubr (&Smap_char_table);
7b863bd5
JB
1874 defsubr (&Snconc);
1875 defsubr (&Smapcar);
1876 defsubr (&Smapconcat);
1877 defsubr (&Sy_or_n_p);
1878 defsubr (&Syes_or_no_p);
1879 defsubr (&Sload_average);
1880 defsubr (&Sfeaturep);
1881 defsubr (&Srequire);
1882 defsubr (&Sprovide);
1883}