(SET_REGS_MATCHED): Do nothing if set_regs_matched_done is 1.
[bpt/emacs.git] / src / fns.c
CommitLineData
7b863bd5 1/* Random utility Lisp functions.
3a22ee35 2 Copyright (C) 1985, 1986, 1987, 1993, 1994 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
8the Free Software Foundation; either version 1, or (at your option)
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
9309fdb1
KH
35extern Lisp_Object Flookup_key ();
36
68732608 37Lisp_Object Qstring_lessp, Qprovide, Qrequire;
0ce830bc 38Lisp_Object Qyes_or_no_p_history;
7b863bd5 39
6cb9cafb 40static int internal_equal ();
e0f5cf5a 41\f
7b863bd5
JB
42DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
43 "Return the argument unchanged.")
44 (arg)
45 Lisp_Object arg;
46{
47 return arg;
48}
49
50DEFUN ("random", Frandom, Srandom, 0, 1, 0,
51 "Return a pseudo-random number.\n\
52On most systems all integers representable in Lisp are equally likely.\n\
53 This is 24 bits' worth.\n\
54With argument N, return random number in interval [0,N).\n\
55With argument t, set the random number seed from the current time and pid.")
ce7385cb
RS
56 (limit)
57 Lisp_Object limit;
7b863bd5
JB
58{
59 int val;
78217ef1 60 unsigned long denominator;
7b863bd5
JB
61 extern long random ();
62 extern srandom ();
63 extern long time ();
64
ce7385cb 65 if (EQ (limit, Qt))
7b863bd5 66 srandom (getpid () + time (0));
7650760e 67 if (INTEGERP (limit) && XINT (limit) > 0)
7b863bd5 68 {
9309fdb1 69 if (XFASTINT (limit) >= 0x40000000)
d1ab4ede 70 /* This case may occur on 64-bit machines. */
9309fdb1 71 val = random () % XFASTINT (limit);
d1ab4ede
RS
72 else
73 {
74 /* Try to take our random number from the higher bits of VAL,
75 not the lower, since (says Gentzel) the low bits of `random'
76 are less random than the higher ones. We do this by using the
77 quotient rather than the remainder. At the high end of the RNG
78 it's possible to get a quotient larger than limit; discarding
79 these values eliminates the bias that would otherwise appear
80 when using a large limit. */
81 denominator = (unsigned long)0x40000000 / XFASTINT (limit);
82 do
83 val = (random () & 0x3fffffff) / denominator;
9309fdb1 84 while (val >= XFASTINT (limit));
d1ab4ede 85 }
7b863bd5 86 }
78217ef1
KH
87 else
88 val = random ();
7b863bd5
JB
89 return make_number (val);
90}
91\f
92/* Random data-structure functions */
93
94DEFUN ("length", Flength, Slength, 1, 1, 0,
95 "Return the length of vector, list or string SEQUENCE.\n\
96A byte-code function object is also allowed.")
97 (obj)
98 register Lisp_Object obj;
99{
100 register Lisp_Object tail, val;
101 register int i;
102
103 retry:
a2ad3e19
KH
104 if (STRINGP (obj))
105 XSETFASTINT (val, XSTRING (obj)->size);
106 else if (VECTORP (obj) || COMPILEDP (obj))
107 XSETFASTINT (val, XVECTOR (obj)->size);
7b863bd5
JB
108 else if (CONSP (obj))
109 {
a2ad3e19 110 for (i = 0, tail = obj; !NILP (tail); i++)
7b863bd5
JB
111 {
112 QUIT;
113 tail = Fcdr (tail);
114 }
115
ad17573a 116 XSETFASTINT (val, i);
7b863bd5 117 }
a2ad3e19
KH
118 else if (NILP (obj))
119 XSETFASTINT (val, 0);
7b863bd5
JB
120 else
121 {
122 obj = wrong_type_argument (Qsequencep, obj);
123 goto retry;
124 }
a2ad3e19 125 return val;
7b863bd5
JB
126}
127
128DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0,
129 "T if two strings have identical contents.\n\
76d0f732 130Case is significant, but text properties are ignored.\n\
7b863bd5
JB
131Symbols are also allowed; their print names are used instead.")
132 (s1, s2)
133 register Lisp_Object s1, s2;
134{
7650760e 135 if (SYMBOLP (s1))
b2791413 136 XSETSTRING (s1, XSYMBOL (s1)->name);
7650760e 137 if (SYMBOLP (s2))
b2791413 138 XSETSTRING (s2, XSYMBOL (s2)->name);
7b863bd5
JB
139 CHECK_STRING (s1, 0);
140 CHECK_STRING (s2, 1);
141
142 if (XSTRING (s1)->size != XSTRING (s2)->size ||
143 bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size))
144 return Qnil;
145 return Qt;
146}
147
148DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0,
149 "T if first arg string is less than second in lexicographic order.\n\
150Case is significant.\n\
151Symbols are also allowed; their print names are used instead.")
152 (s1, s2)
153 register Lisp_Object s1, s2;
154{
155 register int i;
156 register unsigned char *p1, *p2;
157 register int end;
158
7650760e 159 if (SYMBOLP (s1))
b2791413 160 XSETSTRING (s1, XSYMBOL (s1)->name);
7650760e 161 if (SYMBOLP (s2))
b2791413 162 XSETSTRING (s2, XSYMBOL (s2)->name);
7b863bd5
JB
163 CHECK_STRING (s1, 0);
164 CHECK_STRING (s2, 1);
165
166 p1 = XSTRING (s1)->data;
167 p2 = XSTRING (s2)->data;
168 end = XSTRING (s1)->size;
169 if (end > XSTRING (s2)->size)
170 end = XSTRING (s2)->size;
171
172 for (i = 0; i < end; i++)
173 {
174 if (p1[i] != p2[i])
175 return p1[i] < p2[i] ? Qt : Qnil;
176 }
177 return i < XSTRING (s2)->size ? Qt : Qnil;
178}
179\f
180static Lisp_Object concat ();
181
182/* ARGSUSED */
183Lisp_Object
184concat2 (s1, s2)
185 Lisp_Object s1, s2;
186{
187#ifdef NO_ARG_ARRAY
188 Lisp_Object args[2];
189 args[0] = s1;
190 args[1] = s2;
191 return concat (2, args, Lisp_String, 0);
192#else
193 return concat (2, &s1, Lisp_String, 0);
194#endif /* NO_ARG_ARRAY */
195}
196
d4af3687
RS
197/* ARGSUSED */
198Lisp_Object
199concat3 (s1, s2, s3)
200 Lisp_Object s1, s2, s3;
201{
202#ifdef NO_ARG_ARRAY
203 Lisp_Object args[3];
204 args[0] = s1;
205 args[1] = s2;
206 args[2] = s3;
207 return concat (3, args, Lisp_String, 0);
208#else
209 return concat (3, &s1, Lisp_String, 0);
210#endif /* NO_ARG_ARRAY */
211}
212
7b863bd5
JB
213DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
214 "Concatenate all the arguments and make the result a list.\n\
215The result is a list whose elements are the elements of all the arguments.\n\
216Each argument may be a list, vector or string.\n\
aec1184c 217The last argument is not copied, just used as the tail of the new list.")
7b863bd5
JB
218 (nargs, args)
219 int nargs;
220 Lisp_Object *args;
221{
222 return concat (nargs, args, Lisp_Cons, 1);
223}
224
225DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
226 "Concatenate all the arguments and make the result a string.\n\
227The result is a string whose elements are the elements of all the arguments.\n\
27d0b45a
RS
228Each argument may be a string, a list of characters (integers),\n\
229or a vector of characters (integers).")
7b863bd5
JB
230 (nargs, args)
231 int nargs;
232 Lisp_Object *args;
233{
234 return concat (nargs, args, Lisp_String, 0);
235}
236
237DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0,
238 "Concatenate all the arguments and make the result a vector.\n\
239The result is a vector whose elements are the elements of all the arguments.\n\
240Each argument may be a list, vector or string.")
241 (nargs, args)
242 int nargs;
243 Lisp_Object *args;
244{
3e7383eb 245 return concat (nargs, args, Lisp_Vectorlike, 0);
7b863bd5
JB
246}
247
248DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
249 "Return a copy of a list, vector or string.\n\
250The elements of a list or vector are not copied; they are shared\n\
251with the original.")
252 (arg)
253 Lisp_Object arg;
254{
265a9e55 255 if (NILP (arg)) return arg;
7650760e 256 if (!CONSP (arg) && !VECTORP (arg) && !STRINGP (arg))
7b863bd5
JB
257 arg = wrong_type_argument (Qsequencep, arg);
258 return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
259}
260
261static Lisp_Object
262concat (nargs, args, target_type, last_special)
263 int nargs;
264 Lisp_Object *args;
265 enum Lisp_Type target_type;
266 int last_special;
267{
268 Lisp_Object val;
269 Lisp_Object len;
270 register Lisp_Object tail;
271 register Lisp_Object this;
272 int toindex;
273 register int leni;
274 register int argnum;
275 Lisp_Object last_tail;
276 Lisp_Object prev;
277
278 /* In append, the last arg isn't treated like the others */
279 if (last_special && nargs > 0)
280 {
281 nargs--;
282 last_tail = args[nargs];
283 }
284 else
285 last_tail = Qnil;
286
287 for (argnum = 0; argnum < nargs; argnum++)
288 {
289 this = args[argnum];
7650760e
KH
290 if (!(CONSP (this) || NILP (this) || VECTORP (this) || STRINGP (this)
291 || COMPILEDP (this)))
7b863bd5 292 {
7650760e 293 if (INTEGERP (this))
f2980264 294 args[argnum] = Fnumber_to_string (this);
7b863bd5
JB
295 else
296 args[argnum] = wrong_type_argument (Qsequencep, this);
297 }
298 }
299
300 for (argnum = 0, leni = 0; argnum < nargs; argnum++)
301 {
302 this = args[argnum];
303 len = Flength (this);
304 leni += XFASTINT (len);
305 }
306
ad17573a 307 XSETFASTINT (len, leni);
7b863bd5
JB
308
309 if (target_type == Lisp_Cons)
310 val = Fmake_list (len, Qnil);
3e7383eb 311 else if (target_type == Lisp_Vectorlike)
7b863bd5
JB
312 val = Fmake_vector (len, Qnil);
313 else
314 val = Fmake_string (len, len);
315
316 /* In append, if all but last arg are nil, return last arg */
317 if (target_type == Lisp_Cons && EQ (val, Qnil))
318 return last_tail;
319
320 if (CONSP (val))
321 tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */
322 else
323 toindex = 0;
324
325 prev = Qnil;
326
327 for (argnum = 0; argnum < nargs; argnum++)
328 {
329 Lisp_Object thislen;
330 int thisleni;
331 register int thisindex = 0;
332
333 this = args[argnum];
334 if (!CONSP (this))
335 thislen = Flength (this), thisleni = XINT (thislen);
336
7650760e 337 if (STRINGP (this) && STRINGP (val)
ac811a55
JB
338 && ! NULL_INTERVAL_P (XSTRING (this)->intervals))
339 {
340 copy_text_properties (make_number (0), thislen, this,
341 make_number (toindex), val, Qnil);
342 }
343
7b863bd5
JB
344 while (1)
345 {
346 register Lisp_Object elt;
347
ac811a55
JB
348 /* Fetch next element of `this' arg into `elt', or break if
349 `this' is exhausted. */
265a9e55 350 if (NILP (this)) break;
7b863bd5
JB
351 if (CONSP (this))
352 elt = Fcar (this), this = Fcdr (this);
353 else
354 {
355 if (thisindex >= thisleni) break;
7650760e 356 if (STRINGP (this))
ad17573a 357 XSETFASTINT (elt, XSTRING (this)->data[thisindex++]);
7b863bd5
JB
358 else
359 elt = XVECTOR (this)->contents[thisindex++];
360 }
361
362 /* Store into result */
363 if (toindex < 0)
364 {
365 XCONS (tail)->car = elt;
366 prev = tail;
367 tail = XCONS (tail)->cdr;
368 }
7650760e 369 else if (VECTORP (val))
7b863bd5
JB
370 XVECTOR (val)->contents[toindex++] = elt;
371 else
372 {
7650760e 373 while (!INTEGERP (elt))
7b863bd5
JB
374 elt = wrong_type_argument (Qintegerp, elt);
375 {
376#ifdef MASSC_REGISTER_BUG
377 /* Even removing all "register"s doesn't disable this bug!
378 Nothing simpler than this seems to work. */
379 unsigned char *p = & XSTRING (val)->data[toindex++];
380 *p = XINT (elt);
381#else
382 XSTRING (val)->data[toindex++] = XINT (elt);
383#endif
384 }
385 }
386 }
387 }
265a9e55 388 if (!NILP (prev))
7b863bd5
JB
389 XCONS (prev)->cdr = last_tail;
390
391 return val;
392}
393\f
394DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
395 "Return a copy of ALIST.\n\
396This is an alist which represents the same mapping from objects to objects,\n\
397but does not share the alist structure with ALIST.\n\
398The objects mapped (cars and cdrs of elements of the alist)\n\
399are shared, however.\n\
400Elements of ALIST that are not conses are also shared.")
401 (alist)
402 Lisp_Object alist;
403{
404 register Lisp_Object tem;
405
406 CHECK_LIST (alist, 0);
265a9e55 407 if (NILP (alist))
7b863bd5
JB
408 return alist;
409 alist = concat (1, &alist, Lisp_Cons, 0);
410 for (tem = alist; CONSP (tem); tem = XCONS (tem)->cdr)
411 {
412 register Lisp_Object car;
413 car = XCONS (tem)->car;
414
415 if (CONSP (car))
416 XCONS (tem)->car = Fcons (XCONS (car)->car, XCONS (car)->cdr);
417 }
418 return alist;
419}
420
421DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
422 "Return a substring of STRING, starting at index FROM and ending before TO.\n\
423TO may be nil or omitted; then the substring runs to the end of STRING.\n\
424If FROM or TO is negative, it counts from the end.")
425 (string, from, to)
426 Lisp_Object string;
427 register Lisp_Object from, to;
428{
ac811a55
JB
429 Lisp_Object res;
430
7b863bd5
JB
431 CHECK_STRING (string, 0);
432 CHECK_NUMBER (from, 1);
265a9e55 433 if (NILP (to))
7b863bd5
JB
434 to = Flength (string);
435 else
436 CHECK_NUMBER (to, 2);
437
438 if (XINT (from) < 0)
439 XSETINT (from, XINT (from) + XSTRING (string)->size);
440 if (XINT (to) < 0)
441 XSETINT (to, XINT (to) + XSTRING (string)->size);
442 if (!(0 <= XINT (from) && XINT (from) <= XINT (to)
443 && XINT (to) <= XSTRING (string)->size))
444 args_out_of_range_3 (string, from, to);
445
ac811a55
JB
446 res = make_string (XSTRING (string)->data + XINT (from),
447 XINT (to) - XINT (from));
448 copy_text_properties (from, to, string, make_number (0), res, Qnil);
449 return res;
7b863bd5
JB
450}
451\f
452DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
453 "Take cdr N times on LIST, returns the result.")
454 (n, list)
455 Lisp_Object n;
456 register Lisp_Object list;
457{
458 register int i, num;
459 CHECK_NUMBER (n, 0);
460 num = XINT (n);
265a9e55 461 for (i = 0; i < num && !NILP (list); i++)
7b863bd5
JB
462 {
463 QUIT;
464 list = Fcdr (list);
465 }
466 return list;
467}
468
469DEFUN ("nth", Fnth, Snth, 2, 2, 0,
470 "Return the Nth element of LIST.\n\
471N counts from zero. If LIST is not that long, nil is returned.")
472 (n, list)
473 Lisp_Object n, list;
474{
475 return Fcar (Fnthcdr (n, list));
476}
477
478DEFUN ("elt", Felt, Selt, 2, 2, 0,
479 "Return element of SEQUENCE at index N.")
480 (seq, n)
481 register Lisp_Object seq, n;
482{
483 CHECK_NUMBER (n, 0);
484 while (1)
485 {
7650760e 486 if (CONSP (seq) || NILP (seq))
7b863bd5 487 return Fcar (Fnthcdr (n, seq));
7650760e 488 else if (STRINGP (seq) || VECTORP (seq))
7b863bd5
JB
489 return Faref (seq, n);
490 else
491 seq = wrong_type_argument (Qsequencep, seq);
492 }
493}
494
495DEFUN ("member", Fmember, Smember, 2, 2, 0,
1d58e36f 496 "Return non-nil if ELT is an element of LIST. Comparison done with `equal'.\n\
7b863bd5
JB
497The value is actually the tail of LIST whose car is ELT.")
498 (elt, list)
499 register Lisp_Object elt;
500 Lisp_Object list;
501{
502 register Lisp_Object tail;
265a9e55 503 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
504 {
505 register Lisp_Object tem;
506 tem = Fcar (tail);
265a9e55 507 if (! NILP (Fequal (elt, tem)))
7b863bd5
JB
508 return tail;
509 QUIT;
510 }
511 return Qnil;
512}
513
514DEFUN ("memq", Fmemq, Smemq, 2, 2, 0,
515 "Return non-nil if ELT is an element of LIST. Comparison done with EQ.\n\
516The value is actually the tail of LIST whose car is ELT.")
517 (elt, list)
518 register Lisp_Object elt;
519 Lisp_Object list;
520{
521 register Lisp_Object tail;
265a9e55 522 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
523 {
524 register Lisp_Object tem;
525 tem = Fcar (tail);
526 if (EQ (elt, tem)) return tail;
527 QUIT;
528 }
529 return Qnil;
530}
531
532DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
3797b4c3
RS
533 "Return non-nil if KEY is `eq' to the car of an element of LIST.\n\
534The value is actually the element of LIST whose car is KEY.\n\
7b863bd5
JB
535Elements of LIST that are not conses are ignored.")
536 (key, list)
537 register Lisp_Object key;
538 Lisp_Object list;
539{
540 register Lisp_Object tail;
265a9e55 541 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
542 {
543 register Lisp_Object elt, tem;
544 elt = Fcar (tail);
545 if (!CONSP (elt)) continue;
546 tem = Fcar (elt);
547 if (EQ (key, tem)) return elt;
548 QUIT;
549 }
550 return Qnil;
551}
552
553/* Like Fassq but never report an error and do not allow quits.
554 Use only on lists known never to be circular. */
555
556Lisp_Object
557assq_no_quit (key, list)
558 register Lisp_Object key;
559 Lisp_Object list;
560{
561 register Lisp_Object tail;
562 for (tail = list; CONSP (tail); tail = Fcdr (tail))
563 {
564 register Lisp_Object elt, tem;
565 elt = Fcar (tail);
566 if (!CONSP (elt)) continue;
567 tem = Fcar (elt);
568 if (EQ (key, tem)) return elt;
569 }
570 return Qnil;
571}
572
573DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
3797b4c3
RS
574 "Return non-nil if KEY is `equal' to the car of an element of LIST.\n\
575The value is actually the element of LIST whose car is KEY.")
7b863bd5
JB
576 (key, list)
577 register Lisp_Object key;
578 Lisp_Object list;
579{
580 register Lisp_Object tail;
265a9e55 581 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
582 {
583 register Lisp_Object elt, tem;
584 elt = Fcar (tail);
585 if (!CONSP (elt)) continue;
586 tem = Fequal (Fcar (elt), key);
265a9e55 587 if (!NILP (tem)) return elt;
7b863bd5
JB
588 QUIT;
589 }
590 return Qnil;
591}
592
593DEFUN ("rassq", Frassq, Srassq, 2, 2, 0,
594 "Return non-nil if ELT is `eq' to the cdr of an element of LIST.\n\
595The value is actually the element of LIST whose cdr is ELT.")
596 (key, list)
597 register Lisp_Object key;
598 Lisp_Object list;
599{
600 register Lisp_Object tail;
265a9e55 601 for (tail = list; !NILP (tail); tail = Fcdr (tail))
7b863bd5
JB
602 {
603 register Lisp_Object elt, tem;
604 elt = Fcar (tail);
605 if (!CONSP (elt)) continue;
606 tem = Fcdr (elt);
607 if (EQ (key, tem)) return elt;
608 QUIT;
609 }
610 return Qnil;
611}
612\f
613DEFUN ("delq", Fdelq, Sdelq, 2, 2, 0,
614 "Delete by side effect any occurrences of ELT as a member of LIST.\n\
615The modified LIST is returned. Comparison is done with `eq'.\n\
616If the first member of LIST is ELT, there is no way to remove it by side effect;\n\
617therefore, write `(setq foo (delq element foo))'\n\
618to be sure of changing the value of `foo'.")
619 (elt, list)
620 register Lisp_Object elt;
621 Lisp_Object list;
622{
623 register Lisp_Object tail, prev;
624 register Lisp_Object tem;
625
626 tail = list;
627 prev = Qnil;
265a9e55 628 while (!NILP (tail))
7b863bd5
JB
629 {
630 tem = Fcar (tail);
631 if (EQ (elt, tem))
632 {
265a9e55 633 if (NILP (prev))
7b863bd5
JB
634 list = Fcdr (tail);
635 else
636 Fsetcdr (prev, Fcdr (tail));
637 }
638 else
639 prev = tail;
640 tail = Fcdr (tail);
641 QUIT;
642 }
643 return list;
644}
645
ca8dd546 646DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0,
1e134a5f
RM
647 "Delete by side effect any occurrences of ELT as a member of LIST.\n\
648The modified LIST is returned. Comparison is done with `equal'.\n\
1d58e36f
RS
649If the first member of LIST is ELT, deleting it is not a side effect;\n\
650it is simply using a different list.\n\
651Therefore, write `(setq foo (delete element foo))'\n\
1e134a5f
RM
652to be sure of changing the value of `foo'.")
653 (elt, list)
654 register Lisp_Object elt;
655 Lisp_Object list;
656{
657 register Lisp_Object tail, prev;
658 register Lisp_Object tem;
659
660 tail = list;
661 prev = Qnil;
265a9e55 662 while (!NILP (tail))
1e134a5f
RM
663 {
664 tem = Fcar (tail);
f812877e 665 if (! NILP (Fequal (elt, tem)))
1e134a5f 666 {
265a9e55 667 if (NILP (prev))
1e134a5f
RM
668 list = Fcdr (tail);
669 else
670 Fsetcdr (prev, Fcdr (tail));
671 }
672 else
673 prev = tail;
674 tail = Fcdr (tail);
675 QUIT;
676 }
677 return list;
678}
679
7b863bd5
JB
680DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0,
681 "Reverse LIST by modifying cdr pointers.\n\
682Returns the beginning of the reversed list.")
683 (list)
684 Lisp_Object list;
685{
686 register Lisp_Object prev, tail, next;
687
265a9e55 688 if (NILP (list)) return list;
7b863bd5
JB
689 prev = Qnil;
690 tail = list;
265a9e55 691 while (!NILP (tail))
7b863bd5
JB
692 {
693 QUIT;
694 next = Fcdr (tail);
695 Fsetcdr (tail, prev);
696 prev = tail;
697 tail = next;
698 }
699 return prev;
700}
701
702DEFUN ("reverse", Freverse, Sreverse, 1, 1, 0,
703 "Reverse LIST, copying. Returns the beginning of the reversed list.\n\
704See also the function `nreverse', which is used more often.")
705 (list)
706 Lisp_Object list;
707{
708 Lisp_Object length;
709 register Lisp_Object *vec;
710 register Lisp_Object tail;
711 register int i;
712
713 length = Flength (list);
714 vec = (Lisp_Object *) alloca (XINT (length) * sizeof (Lisp_Object));
715 for (i = XINT (length) - 1, tail = list; i >= 0; i--, tail = Fcdr (tail))
716 vec[i] = Fcar (tail);
717
718 return Flist (XINT (length), vec);
719}
720\f
721Lisp_Object merge ();
722
723DEFUN ("sort", Fsort, Ssort, 2, 2, 0,
724 "Sort LIST, stably, comparing elements using PREDICATE.\n\
725Returns the sorted list. LIST is modified by side effects.\n\
726PREDICATE is called with two elements of LIST, and should return T\n\
727if the first element is \"less\" than the second.")
728 (list, pred)
729 Lisp_Object list, pred;
730{
731 Lisp_Object front, back;
732 register Lisp_Object len, tem;
733 struct gcpro gcpro1, gcpro2;
734 register int length;
735
736 front = list;
737 len = Flength (list);
738 length = XINT (len);
739 if (length < 2)
740 return list;
741
742 XSETINT (len, (length / 2) - 1);
743 tem = Fnthcdr (len, list);
744 back = Fcdr (tem);
745 Fsetcdr (tem, Qnil);
746
747 GCPRO2 (front, back);
748 front = Fsort (front, pred);
749 back = Fsort (back, pred);
750 UNGCPRO;
751 return merge (front, back, pred);
752}
753
754Lisp_Object
755merge (org_l1, org_l2, pred)
756 Lisp_Object org_l1, org_l2;
757 Lisp_Object pred;
758{
759 Lisp_Object value;
760 register Lisp_Object tail;
761 Lisp_Object tem;
762 register Lisp_Object l1, l2;
763 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
764
765 l1 = org_l1;
766 l2 = org_l2;
767 tail = Qnil;
768 value = Qnil;
769
770 /* It is sufficient to protect org_l1 and org_l2.
771 When l1 and l2 are updated, we copy the new values
772 back into the org_ vars. */
773 GCPRO4 (org_l1, org_l2, pred, value);
774
775 while (1)
776 {
265a9e55 777 if (NILP (l1))
7b863bd5
JB
778 {
779 UNGCPRO;
265a9e55 780 if (NILP (tail))
7b863bd5
JB
781 return l2;
782 Fsetcdr (tail, l2);
783 return value;
784 }
265a9e55 785 if (NILP (l2))
7b863bd5
JB
786 {
787 UNGCPRO;
265a9e55 788 if (NILP (tail))
7b863bd5
JB
789 return l1;
790 Fsetcdr (tail, l1);
791 return value;
792 }
793 tem = call2 (pred, Fcar (l2), Fcar (l1));
265a9e55 794 if (NILP (tem))
7b863bd5
JB
795 {
796 tem = l1;
797 l1 = Fcdr (l1);
798 org_l1 = l1;
799 }
800 else
801 {
802 tem = l2;
803 l2 = Fcdr (l2);
804 org_l2 = l2;
805 }
265a9e55 806 if (NILP (tail))
7b863bd5
JB
807 value = tem;
808 else
809 Fsetcdr (tail, tem);
810 tail = tem;
811 }
812}
813\f
814DEFUN ("get", Fget, Sget, 2, 2, 0,
815 "Return the value of SYMBOL's PROPNAME property.\n\
816This is the last VALUE stored with `(put SYMBOL PROPNAME VALUE)'.")
817 (sym, prop)
818 Lisp_Object sym;
819 register Lisp_Object prop;
820{
821 register Lisp_Object tail;
265a9e55 822 for (tail = Fsymbol_plist (sym); !NILP (tail); tail = Fcdr (Fcdr (tail)))
7b863bd5
JB
823 {
824 register Lisp_Object tem;
825 tem = Fcar (tail);
826 if (EQ (prop, tem))
827 return Fcar (Fcdr (tail));
828 }
829 return Qnil;
830}
831
832DEFUN ("put", Fput, Sput, 3, 3, 0,
833 "Store SYMBOL's PROPNAME property with value VALUE.\n\
834It can be retrieved with `(get SYMBOL PROPNAME)'.")
835 (sym, prop, val)
836 Lisp_Object sym;
837 register Lisp_Object prop;
838 Lisp_Object val;
839{
840 register Lisp_Object tail, prev;
841 Lisp_Object newcell;
842 prev = Qnil;
265a9e55 843 for (tail = Fsymbol_plist (sym); !NILP (tail); tail = Fcdr (Fcdr (tail)))
7b863bd5
JB
844 {
845 register Lisp_Object tem;
846 tem = Fcar (tail);
847 if (EQ (prop, tem))
848 return Fsetcar (Fcdr (tail), val);
849 prev = tail;
850 }
851 newcell = Fcons (prop, Fcons (val, Qnil));
265a9e55 852 if (NILP (prev))
7b863bd5
JB
853 Fsetplist (sym, newcell);
854 else
855 Fsetcdr (Fcdr (prev), newcell);
856 return val;
857}
858
859DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
860 "T if two Lisp objects have similar structure and contents.\n\
861They must have the same data type.\n\
862Conses are compared by comparing the cars and the cdrs.\n\
863Vectors and strings are compared element by element.\n\
d28c4332
RS
864Numbers are compared by value, but integers cannot equal floats.\n\
865 (Use `=' if you want integers and floats to be able to be equal.)\n\
866Symbols must match exactly.")
7b863bd5
JB
867 (o1, o2)
868 register Lisp_Object o1, o2;
869{
6cb9cafb 870 return internal_equal (o1, o2, 0) ? Qt : Qnil;
e0f5cf5a
RS
871}
872
6cb9cafb 873static int
e0f5cf5a
RS
874internal_equal (o1, o2, depth)
875 register Lisp_Object o1, o2;
876 int depth;
877{
878 if (depth > 200)
879 error ("Stack overflow in equal");
6cb9cafb 880 tail_recurse:
7b863bd5 881 QUIT;
6cb9cafb 882 if (EQ (o1, o2)) return 1;
31ef7f7a 883#ifdef LISP_FLOAT_TYPE
d28c4332 884 if (FLOATP (o1) && FLOATP (o2))
6cb9cafb 885 return (extract_float (o1) == extract_float (o2));
31ef7f7a 886#endif
6cb9cafb
KH
887 if (XTYPE (o1) != XTYPE (o2)) return 0;
888 if (MISCP (o1) && XMISC (o1)->type != XMISC (o2)->type) return 0;
889 if (CONSP (o1))
890 {
891 if (!internal_equal (XCONS (o1)->car, XCONS (o2)->car, depth + 1))
892 return 0;
893 o1 = XCONS (o1)->cdr;
894 o2 = XCONS (o2)->cdr;
895 goto tail_recurse;
896 }
897 if (OVERLAYP (o1))
898 {
899 if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o1), depth + 1)
900 || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o1), depth + 1))
901 return 0;
902 o1 = XOVERLAY (o1)->plist;
903 o2 = XOVERLAY (o2)->plist;
904 goto tail_recurse;
7b863bd5 905 }
7650760e 906 if (MARKERP (o1))
7b863bd5 907 {
6cb9cafb 908 return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
871d0ce7 909 && (XMARKER (o1)->buffer == 0
6cb9cafb 910 || XMARKER (o1)->bufpos == XMARKER (o2)->bufpos));
7b863bd5 911 }
7650760e 912 if (VECTORP (o1) || COMPILEDP (o1))
7b863bd5
JB
913 {
914 register int index;
915 if (XVECTOR (o1)->size != XVECTOR (o2)->size)
6cb9cafb 916 return 0;
7b863bd5
JB
917 for (index = 0; index < XVECTOR (o1)->size; index++)
918 {
6cb9cafb 919 Lisp_Object v1, v2;
7b863bd5
JB
920 v1 = XVECTOR (o1)->contents [index];
921 v2 = XVECTOR (o2)->contents [index];
6cb9cafb
KH
922 if (!internal_equal (v1, v2, depth + 1))
923 return 0;
7b863bd5 924 }
6cb9cafb 925 return 1;
7b863bd5 926 }
7650760e 927 if (STRINGP (o1))
7b863bd5
JB
928 {
929 if (XSTRING (o1)->size != XSTRING (o2)->size)
6cb9cafb 930 return 0;
7b863bd5 931 if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data, XSTRING (o1)->size))
6cb9cafb 932 return 0;
76d0f732
RS
933#ifdef USE_TEXT_PROPERTIES
934 /* If the strings have intervals, verify they match;
935 if not, they are unequal. */
936 if ((XSTRING (o1)->intervals != 0 || XSTRING (o2)->intervals != 0)
937 && ! compare_string_intervals (o1, o2))
938 return 0;
939#endif
6cb9cafb 940 return 1;
7b863bd5 941 }
6cb9cafb 942 return 0;
7b863bd5
JB
943}
944\f
945DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
946 "Store each element of ARRAY with ITEM. ARRAY is a vector or string.")
947 (array, item)
948 Lisp_Object array, item;
949{
950 register int size, index, charval;
951 retry:
7650760e 952 if (VECTORP (array))
7b863bd5
JB
953 {
954 register Lisp_Object *p = XVECTOR (array)->contents;
955 size = XVECTOR (array)->size;
956 for (index = 0; index < size; index++)
957 p[index] = item;
958 }
7650760e 959 else if (STRINGP (array))
7b863bd5
JB
960 {
961 register unsigned char *p = XSTRING (array)->data;
962 CHECK_NUMBER (item, 1);
963 charval = XINT (item);
964 size = XSTRING (array)->size;
965 for (index = 0; index < size; index++)
966 p[index] = charval;
967 }
968 else
969 {
970 array = wrong_type_argument (Qarrayp, array);
971 goto retry;
972 }
973 return array;
974}
975
976/* ARGSUSED */
977Lisp_Object
978nconc2 (s1, s2)
979 Lisp_Object s1, s2;
980{
981#ifdef NO_ARG_ARRAY
982 Lisp_Object args[2];
983 args[0] = s1;
984 args[1] = s2;
985 return Fnconc (2, args);
986#else
987 return Fnconc (2, &s1);
988#endif /* NO_ARG_ARRAY */
989}
990
991DEFUN ("nconc", Fnconc, Snconc, 0, MANY, 0,
992 "Concatenate any number of lists by altering them.\n\
993Only the last argument is not altered, and need not be a list.")
994 (nargs, args)
995 int nargs;
996 Lisp_Object *args;
997{
998 register int argnum;
999 register Lisp_Object tail, tem, val;
1000
1001 val = Qnil;
1002
1003 for (argnum = 0; argnum < nargs; argnum++)
1004 {
1005 tem = args[argnum];
265a9e55 1006 if (NILP (tem)) continue;
7b863bd5 1007
265a9e55 1008 if (NILP (val))
7b863bd5
JB
1009 val = tem;
1010
1011 if (argnum + 1 == nargs) break;
1012
1013 if (!CONSP (tem))
1014 tem = wrong_type_argument (Qlistp, tem);
1015
1016 while (CONSP (tem))
1017 {
1018 tail = tem;
1019 tem = Fcdr (tail);
1020 QUIT;
1021 }
1022
1023 tem = args[argnum + 1];
1024 Fsetcdr (tail, tem);
265a9e55 1025 if (NILP (tem))
7b863bd5
JB
1026 args[argnum + 1] = tail;
1027 }
1028
1029 return val;
1030}
1031\f
1032/* This is the guts of all mapping functions.
1033 Apply fn to each element of seq, one by one,
1034 storing the results into elements of vals, a C vector of Lisp_Objects.
1035 leni is the length of vals, which should also be the length of seq. */
1036
1037static void
1038mapcar1 (leni, vals, fn, seq)
1039 int leni;
1040 Lisp_Object *vals;
1041 Lisp_Object fn, seq;
1042{
1043 register Lisp_Object tail;
1044 Lisp_Object dummy;
1045 register int i;
1046 struct gcpro gcpro1, gcpro2, gcpro3;
1047
1048 /* Don't let vals contain any garbage when GC happens. */
1049 for (i = 0; i < leni; i++)
1050 vals[i] = Qnil;
1051
1052 GCPRO3 (dummy, fn, seq);
1053 gcpro1.var = vals;
1054 gcpro1.nvars = leni;
1055 /* We need not explicitly protect `tail' because it is used only on lists, and
1056 1) lists are not relocated and 2) the list is marked via `seq' so will not be freed */
1057
7650760e 1058 if (VECTORP (seq))
7b863bd5
JB
1059 {
1060 for (i = 0; i < leni; i++)
1061 {
1062 dummy = XVECTOR (seq)->contents[i];
1063 vals[i] = call1 (fn, dummy);
1064 }
1065 }
7650760e 1066 else if (STRINGP (seq))
7b863bd5
JB
1067 {
1068 for (i = 0; i < leni; i++)
1069 {
ad17573a 1070 XSETFASTINT (dummy, XSTRING (seq)->data[i]);
7b863bd5
JB
1071 vals[i] = call1 (fn, dummy);
1072 }
1073 }
1074 else /* Must be a list, since Flength did not get an error */
1075 {
1076 tail = seq;
1077 for (i = 0; i < leni; i++)
1078 {
1079 vals[i] = call1 (fn, Fcar (tail));
1080 tail = Fcdr (tail);
1081 }
1082 }
1083
1084 UNGCPRO;
1085}
1086
1087DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
1088 "Apply FN to each element of SEQ, and concat the results as strings.\n\
1089In between each pair of results, stick in SEP.\n\
acbeb206 1090Thus, \" \" as SEP results in spaces between the values returned by FN.")
7b863bd5
JB
1091 (fn, seq, sep)
1092 Lisp_Object fn, seq, sep;
1093{
1094 Lisp_Object len;
1095 register int leni;
1096 int nargs;
1097 register Lisp_Object *args;
1098 register int i;
1099 struct gcpro gcpro1;
1100
1101 len = Flength (seq);
1102 leni = XINT (len);
1103 nargs = leni + leni - 1;
1104 if (nargs < 0) return build_string ("");
1105
1106 args = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object));
1107
1108 GCPRO1 (sep);
1109 mapcar1 (leni, args, fn, seq);
1110 UNGCPRO;
1111
1112 for (i = leni - 1; i >= 0; i--)
1113 args[i + i] = args[i];
1114
1115 for (i = 1; i < nargs; i += 2)
1116 args[i] = sep;
1117
1118 return Fconcat (nargs, args);
1119}
1120
1121DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
1122 "Apply FUNCTION to each element of SEQUENCE, and make a list of the results.\n\
1123The result is a list just as long as SEQUENCE.\n\
1124SEQUENCE may be a list, a vector or a string.")
1125 (fn, seq)
1126 Lisp_Object fn, seq;
1127{
1128 register Lisp_Object len;
1129 register int leni;
1130 register Lisp_Object *args;
1131
1132 len = Flength (seq);
1133 leni = XFASTINT (len);
1134 args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
1135
1136 mapcar1 (leni, args, fn, seq);
1137
1138 return Flist (leni, args);
1139}
1140\f
1141/* Anything that calls this function must protect from GC! */
1142
1143DEFUN ("y-or-n-p", Fy_or_n_p, Sy_or_n_p, 1, 1, 0,
1144 "Ask user a \"y or n\" question. Return t if answer is \"y\".\n\
c763f396
RS
1145Takes one argument, which is the string to display to ask the question.\n\
1146It should end in a space; `y-or-n-p' adds `(y or n) ' to it.\n\
7b863bd5
JB
1147No confirmation of the answer is requested; a single character is enough.\n\
1148Also accepts Space to mean yes, or Delete to mean no.")
1149 (prompt)
1150 Lisp_Object prompt;
1151{
f5313ed9
RS
1152 register Lisp_Object obj, key, def, answer_string, map;
1153 register int answer;
7b863bd5
JB
1154 Lisp_Object xprompt;
1155 Lisp_Object args[2];
1156 int ocech = cursor_in_echo_area;
1157 struct gcpro gcpro1, gcpro2;
1158
f5313ed9
RS
1159 map = Fsymbol_value (intern ("query-replace-map"));
1160
7b863bd5
JB
1161 CHECK_STRING (prompt, 0);
1162 xprompt = prompt;
1163 GCPRO2 (prompt, xprompt);
1164
1165 while (1)
1166 {
dfa89228 1167#ifdef HAVE_X_MENU
588064ce
RS
1168 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
1169 && using_x_p ())
1db4cfb2
RS
1170 {
1171 Lisp_Object pane, menu;
a3b14a45 1172 redisplay_preserve_echo_area ();
1db4cfb2
RS
1173 pane = Fcons (Fcons (build_string ("Yes"), Qt),
1174 Fcons (Fcons (build_string ("No"), Qnil),
1175 Qnil));
ec26e1b9 1176 menu = Fcons (prompt, pane);
d2f28f78 1177 obj = Fx_popup_dialog (Qt, menu);
1db4cfb2
RS
1178 answer = !NILP (obj);
1179 break;
1180 }
dfa89228
KH
1181#endif
1182 cursor_in_echo_area = 1;
1183 message ("%s(y or n) ", XSTRING (xprompt)->data);
7b863bd5 1184
dfa89228
KH
1185 obj = read_filtered_event (1, 0, 0);
1186 cursor_in_echo_area = 0;
1187 /* If we need to quit, quit with cursor_in_echo_area = 0. */
1188 QUIT;
a63f658b 1189
f5313ed9
RS
1190 key = Fmake_vector (make_number (1), obj);
1191 def = Flookup_key (map, key);
1192 answer_string = Fsingle_key_description (obj);
7b863bd5 1193
f5313ed9
RS
1194 if (EQ (def, intern ("skip")))
1195 {
1196 answer = 0;
1197 break;
1198 }
1199 else if (EQ (def, intern ("act")))
1200 {
1201 answer = 1;
1202 break;
1203 }
29944b73
RS
1204 else if (EQ (def, intern ("recenter")))
1205 {
1206 Frecenter (Qnil);
1207 xprompt = prompt;
1208 continue;
1209 }
f5313ed9 1210 else if (EQ (def, intern ("quit")))
7b863bd5 1211 Vquit_flag = Qt;
ec63af1b
RS
1212 /* We want to exit this command for exit-prefix,
1213 and this is the only way to do it. */
1214 else if (EQ (def, intern ("exit-prefix")))
1215 Vquit_flag = Qt;
f5313ed9 1216
7b863bd5 1217 QUIT;
20aa96aa
JB
1218
1219 /* If we don't clear this, then the next call to read_char will
1220 return quit_char again, and we'll enter an infinite loop. */
088880f1 1221 Vquit_flag = Qnil;
7b863bd5
JB
1222
1223 Fding (Qnil);
1224 Fdiscard_input ();
1225 if (EQ (xprompt, prompt))
1226 {
1227 args[0] = build_string ("Please answer y or n. ");
1228 args[1] = prompt;
1229 xprompt = Fconcat (2, args);
1230 }
1231 }
1232 UNGCPRO;
6a8a9750 1233
09c95874
RS
1234 if (! noninteractive)
1235 {
1236 cursor_in_echo_area = -1;
1237 message ("%s(y or n) %c", XSTRING (xprompt)->data, answer ? 'y' : 'n');
1238 cursor_in_echo_area = ocech;
1239 }
6a8a9750 1240
f5313ed9 1241 return answer ? Qt : Qnil;
7b863bd5
JB
1242}
1243\f
1244/* This is how C code calls `yes-or-no-p' and allows the user
1245 to redefined it.
1246
1247 Anything that calls this function must protect from GC! */
1248
1249Lisp_Object
1250do_yes_or_no_p (prompt)
1251 Lisp_Object prompt;
1252{
1253 return call1 (intern ("yes-or-no-p"), prompt);
1254}
1255
1256/* Anything that calls this function must protect from GC! */
1257
1258DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0,
c763f396
RS
1259 "Ask user a yes-or-no question. Return t if answer is yes.\n\
1260Takes one argument, which is the string to display to ask the question.\n\
1261It should end in a space; `yes-or-no-p' adds `(yes or no) ' to it.\n\
1262The user must confirm the answer with RET,\n\
1263and can edit it until it as been confirmed.")
7b863bd5
JB
1264 (prompt)
1265 Lisp_Object prompt;
1266{
1267 register Lisp_Object ans;
1268 Lisp_Object args[2];
1269 struct gcpro gcpro1;
1db4cfb2 1270 Lisp_Object menu;
7b863bd5
JB
1271
1272 CHECK_STRING (prompt, 0);
1273
dfa89228 1274#ifdef HAVE_X_MENU
588064ce
RS
1275 if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
1276 && using_x_p ())
1db4cfb2
RS
1277 {
1278 Lisp_Object pane, menu, obj;
a3b14a45 1279 redisplay_preserve_echo_area ();
1db4cfb2
RS
1280 pane = Fcons (Fcons (build_string ("Yes"), Qt),
1281 Fcons (Fcons (build_string ("No"), Qnil),
1282 Qnil));
1283 GCPRO1 (pane);
ec26e1b9 1284 menu = Fcons (prompt, pane);
b5ccb0a9 1285 obj = Fx_popup_dialog (Qt, menu);
1db4cfb2
RS
1286 UNGCPRO;
1287 return obj;
1288 }
dfa89228 1289#endif
1db4cfb2 1290
7b863bd5
JB
1291 args[0] = prompt;
1292 args[1] = build_string ("(yes or no) ");
1293 prompt = Fconcat (2, args);
1294
1295 GCPRO1 (prompt);
1db4cfb2 1296
7b863bd5
JB
1297 while (1)
1298 {
0ce830bc
RS
1299 ans = Fdowncase (Fread_from_minibuffer (prompt, Qnil, Qnil, Qnil,
1300 Qyes_or_no_p_history));
7b863bd5
JB
1301 if (XSTRING (ans)->size == 3 && !strcmp (XSTRING (ans)->data, "yes"))
1302 {
1303 UNGCPRO;
1304 return Qt;
1305 }
1306 if (XSTRING (ans)->size == 2 && !strcmp (XSTRING (ans)->data, "no"))
1307 {
1308 UNGCPRO;
1309 return Qnil;
1310 }
1311
1312 Fding (Qnil);
1313 Fdiscard_input ();
1314 message ("Please answer yes or no.");
99dc4745 1315 Fsleep_for (make_number (2), Qnil);
7b863bd5 1316 }
7b863bd5
JB
1317}
1318\f
7b863bd5
JB
1319DEFUN ("load-average", Fload_average, Sload_average, 0, 0, 0,
1320 "Return list of 1 minute, 5 minute and 15 minute load averages.\n\
1321Each of the three load averages is multiplied by 100,\n\
daa37602
JB
1322then converted to integer.\n\
1323If the 5-minute or 15-minute load averages are not available, return a\n\
1324shortened list, containing only those averages which are available.")
7b863bd5
JB
1325 ()
1326{
daa37602
JB
1327 double load_ave[3];
1328 int loads = getloadavg (load_ave, 3);
1329 Lisp_Object ret;
7b863bd5 1330
daa37602
JB
1331 if (loads < 0)
1332 error ("load-average not implemented for this operating system");
1333
1334 ret = Qnil;
1335 while (loads > 0)
1336 ret = Fcons (make_number ((int) (load_ave[--loads] * 100.0)), ret);
1337
1338 return ret;
1339}
7b863bd5
JB
1340\f
1341Lisp_Object Vfeatures;
1342
1343DEFUN ("featurep", Ffeaturep, Sfeaturep, 1, 1, 0,
1344 "Returns t if FEATURE is present in this Emacs.\n\
1345Use this to conditionalize execution of lisp code based on the presence or\n\
1346absence of emacs or environment extensions.\n\
1347Use `provide' to declare that a feature is available.\n\
1348This function looks at the value of the variable `features'.")
1349 (feature)
1350 Lisp_Object feature;
1351{
1352 register Lisp_Object tem;
1353 CHECK_SYMBOL (feature, 0);
1354 tem = Fmemq (feature, Vfeatures);
265a9e55 1355 return (NILP (tem)) ? Qnil : Qt;
7b863bd5
JB
1356}
1357
1358DEFUN ("provide", Fprovide, Sprovide, 1, 1, 0,
1359 "Announce that FEATURE is a feature of the current Emacs.")
1360 (feature)
1361 Lisp_Object feature;
1362{
1363 register Lisp_Object tem;
1364 CHECK_SYMBOL (feature, 0);
265a9e55 1365 if (!NILP (Vautoload_queue))
7b863bd5
JB
1366 Vautoload_queue = Fcons (Fcons (Vfeatures, Qnil), Vautoload_queue);
1367 tem = Fmemq (feature, Vfeatures);
265a9e55 1368 if (NILP (tem))
7b863bd5 1369 Vfeatures = Fcons (feature, Vfeatures);
68732608 1370 LOADHIST_ATTACH (Fcons (Qprovide, feature));
7b863bd5
JB
1371 return feature;
1372}
1373
1374DEFUN ("require", Frequire, Srequire, 1, 2, 0,
1375 "If feature FEATURE is not loaded, load it from FILENAME.\n\
1376If FEATURE is not a member of the list `features', then the feature\n\
1377is not loaded; so load the file FILENAME.\n\
1378If FILENAME is omitted, the printname of FEATURE is used as the file name.")
1379 (feature, file_name)
1380 Lisp_Object feature, file_name;
1381{
1382 register Lisp_Object tem;
1383 CHECK_SYMBOL (feature, 0);
1384 tem = Fmemq (feature, Vfeatures);
68732608 1385 LOADHIST_ATTACH (Fcons (Qrequire, feature));
265a9e55 1386 if (NILP (tem))
7b863bd5
JB
1387 {
1388 int count = specpdl_ptr - specpdl;
1389
1390 /* Value saved here is to be restored into Vautoload_queue */
1391 record_unwind_protect (un_autoload, Vautoload_queue);
1392 Vautoload_queue = Qt;
1393
265a9e55 1394 Fload (NILP (file_name) ? Fsymbol_name (feature) : file_name,
7b863bd5
JB
1395 Qnil, Qt, Qnil);
1396
1397 tem = Fmemq (feature, Vfeatures);
265a9e55 1398 if (NILP (tem))
7b863bd5
JB
1399 error ("Required feature %s was not provided",
1400 XSYMBOL (feature)->name->data );
1401
1402 /* Once loading finishes, don't undo it. */
1403 Vautoload_queue = Qt;
1404 feature = unbind_to (count, feature);
1405 }
1406 return feature;
1407}
1408\f
1409syms_of_fns ()
1410{
1411 Qstring_lessp = intern ("string-lessp");
1412 staticpro (&Qstring_lessp);
68732608
RS
1413 Qprovide = intern ("provide");
1414 staticpro (&Qprovide);
1415 Qrequire = intern ("require");
1416 staticpro (&Qrequire);
0ce830bc
RS
1417 Qyes_or_no_p_history = intern ("yes-or-no-p-history");
1418 staticpro (&Qyes_or_no_p_history);
7b863bd5
JB
1419
1420 DEFVAR_LISP ("features", &Vfeatures,
1421 "A list of symbols which are the features of the executing emacs.\n\
1422Used by `featurep' and `require', and altered by `provide'.");
1423 Vfeatures = Qnil;
1424
1425 defsubr (&Sidentity);
1426 defsubr (&Srandom);
1427 defsubr (&Slength);
1428 defsubr (&Sstring_equal);
1429 defsubr (&Sstring_lessp);
1430 defsubr (&Sappend);
1431 defsubr (&Sconcat);
1432 defsubr (&Svconcat);
1433 defsubr (&Scopy_sequence);
1434 defsubr (&Scopy_alist);
1435 defsubr (&Ssubstring);
1436 defsubr (&Snthcdr);
1437 defsubr (&Snth);
1438 defsubr (&Selt);
1439 defsubr (&Smember);
1440 defsubr (&Smemq);
1441 defsubr (&Sassq);
1442 defsubr (&Sassoc);
1443 defsubr (&Srassq);
1444 defsubr (&Sdelq);
ca8dd546 1445 defsubr (&Sdelete);
7b863bd5
JB
1446 defsubr (&Snreverse);
1447 defsubr (&Sreverse);
1448 defsubr (&Ssort);
1449 defsubr (&Sget);
1450 defsubr (&Sput);
1451 defsubr (&Sequal);
1452 defsubr (&Sfillarray);
1453 defsubr (&Snconc);
1454 defsubr (&Smapcar);
1455 defsubr (&Smapconcat);
1456 defsubr (&Sy_or_n_p);
1457 defsubr (&Syes_or_no_p);
1458 defsubr (&Sload_average);
1459 defsubr (&Sfeaturep);
1460 defsubr (&Srequire);
1461 defsubr (&Sprovide);
1462}