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