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