Wand updates from Evgeny
[sxemacs] / src / fns.c
1 /* Random utility Lisp functions.
2    Copyright (C) 1985, 86, 87, 93, 94, 95 Free Software Foundation, Inc.
3    Copyright (C) 1995, 1996 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Mule 2.0, FSF 19.30. */
22
23 /* This file has been Mule-ized. */
24
25 /* Note: FSF 19.30 has bool vectors.  We have bit vectors. */
26
27 /* Hacked on for Mule by Ben Wing, December 1994, January 1995. */
28
29 #include <config.h>
30
31 /* Note on some machines this defines `vector' as a typedef,
32    so make sure we don't use that name in this file.  */
33 #undef vector
34 #define vector *****
35
36 #include "lisp.h"
37
38 #include "sysfile.h"
39
40 #include "buffer.h"
41 #include "bytecode.h"
42 #include "ui/device.h"
43 #include "events/events.h"
44 #include "extents.h"
45 #include "ui/frame.h"
46 #include "systime.h"
47 #include "ui/insdel.h"
48 #include "lstream.h"
49 /* for the categorial views */
50 #include "category.h"
51 #include "seq.h"
52 /* for all the map* funs */
53 #include "map.h"
54
55 \f
56 /* NOTE: This symbol is also used in lread.c */
57 #define FEATUREP_SYNTAX
58
59 Lisp_Object Qstring_lessp, Qstring_greaterp;
60 Lisp_Object Qidentity;
61
62 static int internal_old_equal(Lisp_Object, Lisp_Object, int);
63 Lisp_Object safe_copy_tree(Lisp_Object arg, Lisp_Object vecp, int depth);
64 int internal_equalp(Lisp_Object, Lisp_Object, int);
65
66 static Lisp_Object mark_bit_vector(Lisp_Object obj)
67 {
68         return Qnil;
69 }
70
71 static void
72 print_bit_vector(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
73 {
74         size_t i;
75         Lisp_Bit_Vector *v = XBIT_VECTOR(obj);
76         size_t len = bit_vector_length(v);
77         size_t last = len;
78
79         if (INTP(Vprint_length))
80                 last = min((EMACS_INT) len, XINT(Vprint_length));
81         write_c_string("#*", printcharfun);
82         for (i = 0; i < last; i++) {
83                 if (bit_vector_bit(v, i))
84                         write_c_string("1", printcharfun);
85                 else
86                         write_c_string("0", printcharfun);
87         }
88
89         if (last != len)
90                 write_c_string("...", printcharfun);
91 }
92
93 static int bit_vector_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
94 {
95         Lisp_Bit_Vector *v1 = XBIT_VECTOR(obj1);
96         Lisp_Bit_Vector *v2 = XBIT_VECTOR(obj2);
97
98         return ((bit_vector_length(v1) == bit_vector_length(v2)) &&
99                 !memcmp(v1->bits, v2->bits,
100                         BIT_VECTOR_LONG_STORAGE(bit_vector_length(v1)) *
101                         sizeof(long)));
102 }
103
104 static unsigned long bit_vector_hash(Lisp_Object obj, int depth)
105 {
106         Lisp_Bit_Vector *v = XBIT_VECTOR(obj);
107         return HASH2(bit_vector_length(v),
108                      memory_hash(v->bits,
109                                  BIT_VECTOR_LONG_STORAGE(bit_vector_length(v)) *
110                                  sizeof(long)));
111 }
112
113 static size_t size_bit_vector(const void *lheader)
114 {
115         const Lisp_Bit_Vector *v = (const Lisp_Bit_Vector *) lheader;
116         return FLEXIBLE_ARRAY_STRUCT_SIZEOF(Lisp_Bit_Vector, unsigned long,
117                                             bits,
118                                             BIT_VECTOR_LONG_STORAGE
119                                             (bit_vector_length(v)));
120 }
121
122 static const struct lrecord_description bit_vector_description[] = {
123         {XD_LISP_OBJECT, offsetof(Lisp_Bit_Vector, next)},
124         {XD_END}
125 };
126
127 DEFINE_BASIC_LRECORD_SEQUENCE_IMPLEMENTATION("bit-vector", bit_vector,
128                                              mark_bit_vector, print_bit_vector,
129                                              0, bit_vector_equal,
130                                              bit_vector_hash,
131                                              bit_vector_description,
132                                              size_bit_vector, Lisp_Bit_Vector);
133 \f
134 DEFUN("identity", Fidentity, 1, 1, 0,   /*
135 Return the argument unchanged.
136 */
137       (arg))
138 {
139         return arg;
140 }
141
142 extern long get_random(void);
143 extern void seed_random(long arg);
144
145 DEFUN("random", Frandom, 0, 1, 0,       /*
146 Return a pseudo-random number.
147 All integers representable in Lisp are equally likely.
148 On most systems, this is 31 bits' worth.
149
150 With positive integer argument LIMIT, return random number 
151 in interval [0,LIMIT). LIMIT can be a big integer, in which
152 case the range of possible values is extended.
153
154 With argument t, set the random number seed from the 
155 current time and pid.
156 */
157       (limit))
158 {
159         EMACS_INT val;
160         unsigned long denominator;
161
162         if (EQ(limit, Qt))
163                 seed_random(getpid() + time(NULL));
164         if (NATNUMP(limit) && !ZEROP(limit)) {
165                 /* Try to take our random number from the higher bits of VAL,
166                    not the lower, since (says Gentzel) the low bits of `random'
167                    are less random than the higher ones.  We do this by using the
168                    quotient rather than the remainder.  At the high end of the RNG
169                    it's possible to get a quotient larger than limit; discarding
170                    these values eliminates the bias that would otherwise appear
171                    when using a large limit.  */
172                 denominator = ((unsigned long)1 << INT_VALBITS) / XINT(limit);
173                 do
174                         val = get_random() / denominator;
175                 while (val >= XINT(limit));
176         } else if (ZEROP(limit)) {
177                 return wrong_type_argument(Qpositivep, limit);
178 #if defined HAVE_MPZ && defined WITH_GMP
179         } else if (BIGZP(limit)) {
180                 bigz bz;
181                 Lisp_Object result;
182
183                 if (bigz_sign(XBIGZ_DATA(limit)) <= 0)
184                         return wrong_type_argument(Qpositivep, limit);
185
186                 bigz_init(bz);
187
188                 bigz_random(bz, XBIGZ_DATA(limit));
189                 result = ent_mpz_downgrade_maybe(bz);
190
191                 bigz_fini(bz);
192                 return result;
193 #endif  /* HAVE_MPZ */
194         } else
195                 val = get_random();
196
197         return make_int(val);
198 }
199
200 #if defined(WITH_GMP) && defined(HAVE_MPZ)
201 DEFUN("randomb", Frandomb, 1, 1, 0,     /*
202 Return a uniform pseudo-random number in the range [0, 2^LIMIT).
203 */
204       (limit))
205 {
206         bigz bz;
207         unsigned long limui;
208         Lisp_Object result;
209
210         CHECK_INTEGER(limit);
211
212         if (NILP(Fnonnegativep(limit)))
213                 return wrong_type_argument(Qnonnegativep, limit);
214         else if (INTP(limit))
215                 limui = XINT(limit);
216         else if (BIGZP(limit) && bigz_fits_ulong_p(XBIGZ_DATA(limit)))
217                 limui = bigz_to_ulong(XBIGZ_DATA(limit));
218         else
219                 return wrong_type_argument(Qintegerp, limit);
220
221         bigz_init(bz);
222
223         mpz_urandomb(bz, random_state, limui);
224         result = make_bigz_bz(bz);
225
226         bigz_fini(bz);
227         return result;
228 }
229 #endif  /* HAVE_MPZ */
230
231 \f
232 /* Random data-structure functions */
233
234 #ifdef LOSING_BYTECODE
235
236 /* #### Delete this shit */
237
238 /* Charcount is a misnomer here as we might be dealing with the
239    length of a vector or list, but emphasizes that we're not dealing
240    with Bytecounts in strings */
241 static Charcount length_with_bytecode_hack(Lisp_Object seq)
242 {
243         if (!COMPILED_FUNCTIONP(seq))
244                 return XINT(Flength(seq));
245         else {
246                 Lisp_Compiled_Function *f = XCOMPILED_FUNCTION(seq);
247
248                 return (f->flags.interactivep ? COMPILED_INTERACTIVE :
249                         f->flags.domainp ? COMPILED_DOMAIN :
250                         COMPILED_DOC_STRING)
251                     + 1;
252         }
253 }
254
255 #endif                          /* LOSING_BYTECODE */
256
257 void check_losing_bytecode(const char *function, Lisp_Object seq)
258 {
259         if (COMPILED_FUNCTIONP(seq))
260                 error_with_frob
261                     (seq,
262                      "As of 20.3, `%s' no longer works with compiled-function objects",
263                      function);
264 }
265
266 DEFUN("length", Flength, 1, 1, 0,       /*
267 Return the length of vector, bit vector, list or string SEQUENCE.
268 */
269       (sequence))
270 {
271 #if 1
272 /* that's whither we have to get */
273         if (LIKELY(!NILP(sequence))) {
274                 return make_int(seq_length((seq_t)sequence));
275         } else {
276                 return Qzero;
277         }
278 #elif 0
279 retry:
280         if (LIKELY(STRINGP(sequence) ||
281                    CONSP(sequence) ||
282                    VECTORP(sequence) ||
283                    DLLISTP(sequence) ||
284                    BIT_VECTORP(sequence))) {
285                 return make_int(seq_length(sequence));
286         } else if (NILP(sequence)) {
287                 return Qzero;
288         } else {
289                 check_losing_bytecode("length", sequence);
290                 sequence = wrong_type_argument(Qsequencep, sequence);
291                 goto retry;
292         }
293 #else
294 retry:
295         if (STRINGP(sequence))
296                 return make_int(XSTRING_CHAR_LENGTH(sequence));
297         else if (CONSP(sequence)) {
298                 return make_int(seq_length(sequence));
299         } else if (VECTORP(sequence))
300                 return make_int(seq_length(sequence));
301         else if (DLLISTP(sequence))
302                 return make_int(XDLLIST_SIZE(sequence));
303         else if (NILP(sequence))
304                 return Qzero;
305         else if (BIT_VECTORP(sequence))
306                 return make_int(bit_vector_length(XBIT_VECTOR(sequence)));
307         else {
308                 check_losing_bytecode("length", sequence);
309                 sequence = wrong_type_argument(Qsequencep, sequence);
310                 goto retry;
311         }
312 #endif
313 }
314
315 DEFUN("safe-length", Fsafe_length, 1, 1, 0,     /*
316 Return the length of a list, but avoid error or infinite loop.
317 This function never gets an error.  If LIST is not really a list,
318 it returns 0.  If LIST is circular, it returns a finite value
319 which is at least the number of distinct elements.
320 */
321       (list))
322 {
323         Lisp_Object hare, tortoise;
324         size_t len;
325
326         for (hare = tortoise = list, len = 0;
327              CONSP(hare) && (!EQ(hare, tortoise) || len == 0);
328              hare = XCDR(hare), len++) {
329                 if (len & 1)
330                         tortoise = XCDR(tortoise);
331         }
332
333         return make_int(len);
334 }
335
336 /*** string functions. ***/
337
338 DEFUN("string-equal", Fstring_equal, 2, 2, 0,   /*
339 Return t if two strings have identical contents.
340 Case is significant.  Text properties are ignored.
341 \(Under SXEmacs, `equal' also ignores text properties and extents in
342 strings, but this is not the case under FSF Emacs 19.  In FSF Emacs 20
343 `equal' is the same as in SXEmacs, in that respect.)
344 Symbols are also allowed; their print names are used instead.
345 */
346       (string1, string2))
347 {
348         Bytecount len;
349         Lisp_String *p1, *p2;
350
351         if (SYMBOLP(string1))
352                 p1 = XSYMBOL(string1)->name;
353         else {
354                 CHECK_STRING(string1);
355                 p1 = XSTRING(string1);
356         }
357
358         if (SYMBOLP(string2))
359                 p2 = XSYMBOL(string2)->name;
360         else {
361                 CHECK_STRING(string2);
362                 p2 = XSTRING(string2);
363         }
364
365         return (((len = string_length(p1)) == string_length(p2)) &&
366                 !memcmp(string_data(p1), string_data(p2), len)) ? Qt : Qnil;
367 }
368
369 DEFUN("string-lessp", Fstring_lessp, 2, 2, 0,   /*
370 Return t if first arg string is less than second in lexicographic order.
371 If I18N2 support (but not Mule support) was compiled in, ordering is
372 determined by the locale. (Case is significant for the default C locale.)
373 In all other cases, comparison is simply done on a character-by-
374 character basis using the numeric value of a character. (Note that
375 this may not produce particularly meaningful results under Mule if
376 characters from different charsets are being compared.)
377
378 Symbols are also allowed; their print names are used instead.
379
380 The reason that the I18N2 locale-specific collation is not used under
381 Mule is that the locale model of internationalization does not handle
382 multiple charsets and thus has no hope of working properly under Mule.
383 What we really should do is create a collation table over all built-in
384 charsets.  This is extremely difficult to do from scratch, however.
385
386 Unicode is a good first step towards solving this problem.  In fact,
387 it is quite likely that a collation table exists (or will exist) for
388 Unicode.  When Unicode support is added to SXEmacs/Mule, this problem
389 may be solved.
390 */
391       (string1, string2))
392 {
393         Lisp_String *p1, *p2;
394         Charcount end, len2;
395         int i;
396
397         if (SYMBOLP(string1))
398                 p1 = XSYMBOL(string1)->name;
399         else {
400                 CHECK_STRING(string1);
401                 p1 = XSTRING(string1);
402         }
403
404         if (SYMBOLP(string2))
405                 p2 = XSYMBOL(string2)->name;
406         else {
407                 CHECK_STRING(string2);
408                 p2 = XSTRING(string2);
409         }
410
411         end = string_char_length(p1);
412         len2 = string_char_length(p2);
413         if (end > len2)
414                 end = len2;
415
416 #if defined (I18N2) && !defined (MULE)
417         /* There is no hope of this working under Mule.  Even if we converted
418            the data into an external format so that strcoll() processed it
419            properly, it would still not work because strcoll() does not
420            handle multiple locales.  This is the fundamental flaw in the
421            locale model. */
422         {
423                 Bytecount bcend = charcount_to_bytecount(string_data(p1), end);
424                 /* Compare strings using collation order of locale. */
425                 /* Need to be tricky to handle embedded nulls. */
426
427                 for (i = 0; i < bcend;
428                      i += strlen((char *)string_data(p1) + i) + 1) {
429                         int val = strcoll((char *)string_data(p1) + i,
430                                           (char *)string_data(p2) + i);
431                         if (val < 0)
432                                 return Qt;
433                         if (val > 0)
434                                 return Qnil;
435                 }
436         }
437 #else                           /* not I18N2, or MULE */
438         {
439                 Bufbyte *ptr1 = string_data(p1);
440                 Bufbyte *ptr2 = string_data(p2);
441
442                 /* #### It is not really necessary to do this: We could compare
443                    byte-by-byte and still get a reasonable comparison, since this
444                    would compare characters with a charset in the same way.  With
445                    a little rearrangement of the leading bytes, we could make most
446                    inter-charset comparisons work out the same, too; even if some
447                    don't, this is not a big deal because inter-charset comparisons
448                    aren't really well-defined anyway. */
449                 for (i = 0; i < end; i++) {
450                         if (charptr_emchar(ptr1) != charptr_emchar(ptr2))
451                                 return charptr_emchar(ptr1) <
452                                     charptr_emchar(ptr2) ? Qt : Qnil;
453                         INC_CHARPTR(ptr1);
454                         INC_CHARPTR(ptr2);
455                 }
456         }
457 #endif                          /* not I18N2, or MULE */
458         /* Can't do i < len2 because then comparison between "foo" and "foo^@"
459            won't work right in I18N2 case */
460         return end < len2 ? Qt : Qnil;
461 }
462
463 DEFUN("string-greaterp", Fstring_greaterp, 2, 2, 0, /*
464 Return t if first arg string is greater than second in lexicographic order.
465 If I18N2 support (but not Mule support) was compiled in, ordering is
466 determined by the locale. (Case is significant for the default C locale.)
467 In all other cases, comparison is simply done on a character-by-
468 character basis using the numeric value of a character. (Note that
469 this may not produce particularly meaningful results under Mule if
470 characters from different charsets are being compared.)
471
472 Symbols are also allowed; their print names are used instead.
473
474 The reason that the I18N2 locale-specific collation is not used under
475 Mule is that the locale model of internationalization does not handle
476 multiple charsets and thus has no hope of working properly under Mule.
477 What we really should do is create a collation table over all built-in
478 charsets.  This is extremely difficult to do from scratch, however.
479
480 Unicode is a good first step towards solving this problem.  In fact,
481 it is quite likely that a collation table exists (or will exist) for
482 Unicode.  When Unicode support is added to SXEmacs/Mule, this problem
483 may be solved.
484 */
485       (string1, string2))
486 {
487         return Fstring_lessp(string2, string1);
488 }
489
490 DEFUN("string-modified-tick", Fstring_modified_tick, 1, 1, 0,   /*
491 Return STRING's tick counter, incremented for each change to the string.
492 Each string has a tick counter which is incremented each time the contents
493 of the string are changed (e.g. with `aset').  It wraps around occasionally.
494 */
495       (string))
496 {
497         Lisp_String *s;
498
499         CHECK_STRING(string);
500         s = XSTRING(string);
501         if (CONSP(s->plist) && INTP(XCAR(s->plist)))
502                 return XCAR(s->plist);
503         else
504                 return Qzero;
505 }
506
507 void bump_string_modiff(Lisp_Object str)
508 {
509         Lisp_String *s = XSTRING(str);
510         Lisp_Object *ptr = &s->plist;
511
512 #ifdef I18N3
513         /* #### remove the `string-translatable' property from the string,
514            if there is one. */
515 #endif
516         /* skip over extent info if it's there */
517         if (CONSP(*ptr) && EXTENT_INFOP(XCAR(*ptr)))
518                 ptr = &XCDR(*ptr);
519         if (CONSP(*ptr) && INTP(XCAR(*ptr)))
520                 XSETINT(XCAR(*ptr), 1 + XINT(XCAR(*ptr)));
521         else
522                 *ptr = Fcons(make_int(1), *ptr);
523 }
524 \f
525 enum concat_target_type { c_cons, c_string, c_vector, c_bit_vector, c_dllist };
526 static Lisp_Object concat(int nargs, Lisp_Object * args,
527                           enum concat_target_type target_type,
528                           int last_special);
529
530 Lisp_Object concat2(Lisp_Object string1, Lisp_Object string2)
531 {
532         Lisp_Object args[2];
533         args[0] = string1;
534         args[1] = string2;
535         return concat(2, args, c_string, 0);
536 }
537
538 Lisp_Object
539 concat3(Lisp_Object string1, Lisp_Object string2, Lisp_Object string3)
540 {
541         Lisp_Object args[3];
542         args[0] = string1;
543         args[1] = string2;
544         args[2] = string3;
545         return concat(3, args, c_string, 0);
546 }
547
548 Lisp_Object vconcat2(Lisp_Object vec1, Lisp_Object vec2)
549 {
550         Lisp_Object args[2];
551         args[0] = vec1;
552         args[1] = vec2;
553         return concat(2, args, c_vector, 0);
554 }
555
556 Lisp_Object vconcat3(Lisp_Object vec1, Lisp_Object vec2, Lisp_Object vec3)
557 {
558         Lisp_Object args[3];
559         args[0] = vec1;
560         args[1] = vec2;
561         args[2] = vec3;
562         return concat(3, args, c_vector, 0);
563 }
564
565 DEFUN("append", Fappend, 0, MANY, 0,    /*
566 Concatenate all the arguments and make the result a list.
567 The result is a list whose elements are the elements of all the arguments.
568 Each argument may be a list, vector, bit vector, or string.
569 The last argument is not copied, just used as the tail of the new list.
570 Also see: `nconc'.
571 */
572       (int nargs, Lisp_Object * args))
573 {
574         return concat(nargs, args, c_cons, 1);
575 }
576
577 DEFUN("concat", Fconcat, 0, MANY, 0,    /*
578 Concatenate all the arguments and make the result a string.
579 The result is a string whose elements are the elements of all the arguments.
580 Each argument may be a string or a list or vector of characters.
581
582 As of XEmacs 21.0, this function does NOT accept individual integers
583 as arguments.  Old code that relies on, for example, (concat "foo" 50)
584 returning "foo50" will fail.  To fix such code, either apply
585 `int-to-string' to the integer argument, or use `format'.
586 */
587       (int nargs, Lisp_Object * args))
588 {
589         return concat(nargs, args, c_string, 0);
590 }
591
592 DEFUN("vconcat", Fvconcat, 0, MANY, 0,  /*
593 Concatenate all the arguments and make the result a vector.
594 The result is a vector whose elements are the elements of all the arguments.
595 Each argument may be a list, vector, bit vector, or string.
596 */
597       (int nargs, Lisp_Object * args))
598 {
599         return concat(nargs, args, c_vector, 0);
600 }
601
602 DEFUN("bvconcat", Fbvconcat, 0, MANY, 0,        /*
603 Concatenate all the arguments and make the result a bit vector.
604 The result is a bit vector whose elements are the elements of all the
605 arguments.  Each argument may be a list, vector, bit vector, or string.
606 */
607       (int nargs, Lisp_Object * args))
608 {
609         return concat(nargs, args, c_bit_vector, 0);
610 }
611
612 /* Copy a (possibly dotted) list.  LIST must be a cons.
613    Can't use concat (1, &alist, c_cons, 0) - doesn't handle dotted lists. */
614 static Lisp_Object copy_list(Lisp_Object list)
615 {
616         Lisp_Object list_copy = Fcons(XCAR(list), XCDR(list));
617         Lisp_Object last = list_copy;
618         Lisp_Object hare, tortoise;
619         size_t len;
620
621         for (tortoise = hare = XCDR(list), len = 1;
622              CONSP(hare); hare = XCDR(hare), len++) {
623                 XCDR(last) = Fcons(XCAR(hare), XCDR(hare));
624                 last = XCDR(last);
625
626                 if (len < CIRCULAR_LIST_SUSPICION_LENGTH)
627                         continue;
628                 if (len & 1)
629                         tortoise = XCDR(tortoise);
630                 if (EQ(tortoise, hare))
631                         signal_circular_list_error(list);
632         }
633
634         return list_copy;
635 }
636
637 DEFUN("copy-list", Fcopy_list, 1, 1, 0, /*
638 Return a copy of list LIST, which may be a dotted list.
639 The elements of LIST are not copied; they are shared
640 with the original.
641 */
642       (list))
643 {
644       again:
645         if (NILP(list))
646                 return list;
647         if (CONSP(list))
648                 return copy_list(list);
649
650         list = wrong_type_argument(Qlistp, list);
651         goto again;
652 }
653
654 DEFUN("copy-sequence", Fcopy_sequence, 1, 1, 0, /*
655 Return a copy of list, dllist, vector, bit vector or string SEQUENCE.
656 The elements of a list or vector are not copied; they are shared
657 with the original. SEQUENCE may be a dotted list.
658 */
659       (sequence))
660 {
661       again:
662         if (NILP(sequence))
663                 return sequence;
664         if (CONSP(sequence))
665                 return copy_list(sequence);
666         if (DLLISTP(sequence))
667                 return Fcopy_dllist(sequence);
668         if (STRINGP(sequence))
669                 return concat(1, &sequence, c_string, 0);
670         if (VECTORP(sequence))
671                 return concat(1, &sequence, c_vector, 0);
672         if (BIT_VECTORP(sequence))
673                 return concat(1, &sequence, c_bit_vector, 0);
674
675         check_losing_bytecode("copy-sequence", sequence);
676         sequence = wrong_type_argument(Qsequencep, sequence);
677         goto again;
678 }
679
680 struct merge_string_extents_struct {
681         Lisp_Object string;
682         Bytecount entry_offset;
683         Bytecount entry_length;
684 };
685
686 static Lisp_Object
687 concat(int nargs, Lisp_Object * args,
688        enum concat_target_type target_type, int last_special)
689 {
690         Lisp_Object val;
691         Lisp_Object tail = Qnil;
692         int toindex;
693         int argnum;
694         Lisp_Object last_tail;
695         Lisp_Object prev;
696         struct merge_string_extents_struct *args_mse = 0;
697         Bufbyte *string_result = 0;
698         Bufbyte *string_result_ptr = 0;
699         struct gcpro gcpro1;
700         int speccount = specpdl_depth();
701         Charcount total_length;
702         
703
704         /* The modus operandi in Emacs is "caller gc-protects args".
705            However, concat is called many times in Emacs on freshly
706            created stuff.  So we help those callers out by protecting
707            the args ourselves to save them a lot of temporary-variable
708            grief. */
709
710         GCPROn(args, nargs);
711
712 #ifdef I18N3
713         /* #### if the result is a string and any of the strings have a string
714            for the `string-translatable' property, then concat should also
715            concat the args but use the `string-translatable' strings, and store
716            the result in the returned string's `string-translatable' property. */
717 #endif
718         if (target_type == c_string)
719                 XMALLOC_OR_ALLOCA(args_mse, nargs, struct merge_string_extents_struct);
720
721         /* In append, the last arg isn't treated like the others */
722         if (last_special && nargs > 0) {
723                 nargs--;
724                 last_tail = args[nargs];
725         } else
726                 last_tail = Qnil;
727
728         /* Check and coerce the arguments. */
729         for (argnum = 0; argnum < nargs; argnum++) {
730                 Lisp_Object seq = args[argnum];
731                 if (LISTP(seq) || DLLISTP(seq)) ;
732                 else if (VECTORP(seq) || STRINGP(seq) || BIT_VECTORP(seq)) ;
733 #ifdef LOSING_BYTECODE
734                 else if (COMPILED_FUNCTIONP(seq))
735                         /* Urk!  We allow this, for "compatibility"... */
736                         ;
737 #endif
738 #if 0                           /* removed for XEmacs 21 */
739                 else if (INTP(seq))
740                         /* This is too revolting to think about but maintains
741                            compatibility with FSF (and lots and lots of old code). */
742                         args[argnum] = Fnumber_to_string(seq);
743 #endif
744                 else {
745                         check_losing_bytecode("concat", seq);
746                         args[argnum] = wrong_type_argument(Qsequencep, seq);
747                 }
748
749                 if (args_mse) {
750                         if (STRINGP(seq))
751                                 args_mse[argnum].string = seq;
752                         else
753                                 args_mse[argnum].string = Qnil;
754                 }
755         }
756
757         {
758                 /* Charcount is a misnomer here as we might be dealing with the
759                    length of a vector or list, but emphasizes that we're not dealing
760                    with Bytecounts in strings */
761                 /* Charcount total_length; */
762
763                 for (argnum = 0, total_length = 0; argnum < nargs; argnum++) {
764 #ifdef LOSING_BYTECODE
765                         Charcount thislen =
766                             length_with_bytecode_hack(args[argnum]);
767 #else
768                         Charcount thislen = XINT(Flength(args[argnum]));
769 #endif
770                         total_length += thislen;
771                 }
772
773                 switch (target_type) {
774                 case c_cons:
775                         if (total_length == 0) {
776                                 /* In append, if all but last arg are nil,
777                                    return last arg */
778                                 XMALLOC_UNBIND(args_mse, nargs, speccount);
779                                 RETURN_UNGCPRO(last_tail);
780                         }
781                         val = Fmake_list(make_int(total_length), Qnil);
782                         break;
783                 case c_dllist:
784                         if (total_length == 0) {
785                                 /* In append, if all but last arg are nil,
786                                    return last arg */
787                                 XMALLOC_UNBIND(args_mse, nargs, speccount);
788                                 RETURN_UNGCPRO(last_tail);
789                         }
790                         val = Fmake_list(make_int(total_length), Qnil);
791                         break;
792                 case c_vector:
793                         val = make_vector(total_length, Qnil);
794                         break;
795                 case c_bit_vector:
796                         val = make_bit_vector(total_length, Qzero);
797                         break;
798                 case c_string:
799                         /* We don't make the string yet because we don't know
800                            the actual number of bytes.  This loop was formerly
801                            written to call Fmake_string() here and then call
802                            set_string_char() for each char.  This seems logical
803                            enough but is waaaaaaaay slow -- set_string_char()
804                            has to scan the whole string up to the place where
805                            the substitution is called for in order to find the
806                            place to change, and may have to do some realloc()ing
807                            in order to make the char fit properly.  O(N^2)
808                            yuckage. */
809                         val = Qnil;
810                         XMALLOC_ATOMIC_OR_ALLOCA( string_result, 
811                                                   total_length * MAX_EMCHAR_LEN,
812                                                   Bufbyte );
813                         string_result_ptr = string_result;
814                         break;
815                 default:
816                         val = Qnil;
817                         abort();
818                 }
819         }
820
821         if (CONSP(val))
822                 tail = val, toindex = -1;       /* -1 in toindex is flag we are
823                                                    making a list */
824         else
825                 toindex = 0;
826
827         prev = Qnil;
828
829         for (argnum = 0; argnum < nargs; argnum++) {
830                 Charcount thisleni = 0;
831                 Charcount thisindex = 0;
832                 Lisp_Object seq = args[argnum];
833                 Bufbyte *string_source_ptr = 0;
834                 Bufbyte *string_prev_result_ptr = string_result_ptr;
835
836                 if (!CONSP(seq)) {
837 #ifdef LOSING_BYTECODE
838                         thisleni = length_with_bytecode_hack(seq);
839 #else
840                         thisleni = XINT(Flength(seq));
841 #endif
842                 }
843                 if (STRINGP(seq))
844                         string_source_ptr = XSTRING_DATA(seq);
845
846                 while (1) {
847                         Lisp_Object elt;
848
849                         /* We've come to the end of this arg, so exit. */
850                         if (NILP(seq))
851                                 break;
852
853                         /* Fetch next element of `seq' arg into `elt' */
854                         if (CONSP(seq)) {
855                                 elt = XCAR(seq);
856                                 seq = XCDR(seq);
857                         } else {
858                                 if (thisindex >= thisleni)
859                                         break;
860
861                                 if (STRINGP(seq)) {
862                                         elt =
863                                             make_char(charptr_emchar
864                                                       (string_source_ptr));
865                                         INC_CHARPTR(string_source_ptr);
866                                 } else if (VECTORP(seq))
867                                         elt = XVECTOR_DATA(seq)[thisindex];
868                                 else if (BIT_VECTORP(seq))
869                                         elt =
870                                             make_int(bit_vector_bit
871                                                      (XBIT_VECTOR(seq),
872                                                       thisindex));
873                                 else
874                                         elt = Felt(seq, make_int(thisindex));
875                                 thisindex++;
876                         }
877
878                         /* Store into result */
879                         if (toindex < 0) {
880                                 /* toindex negative means we are making a list */
881                                 XCAR(tail) = elt;
882                                 prev = tail;
883                                 tail = XCDR(tail);
884                         } else if (VECTORP(val))
885                                 XVECTOR_DATA(val)[toindex++] = elt;
886                         else if (BIT_VECTORP(val)) {
887                                 CHECK_BIT(elt);
888                                 set_bit_vector_bit(XBIT_VECTOR(val), toindex++,
889                                                    XINT(elt));
890                         } else {
891                                 CHECK_CHAR_COERCE_INT(elt);
892                                 assert(string_result_ptr != NULL);
893                                 string_result_ptr +=
894                                     set_charptr_emchar(string_result_ptr,
895                                                        XCHAR(elt));
896                         }
897                 }
898                 if (args_mse) {
899                         args_mse[argnum].entry_offset =
900                             string_prev_result_ptr - string_result;
901                         args_mse[argnum].entry_length =
902                             string_result_ptr - string_prev_result_ptr;
903                 }
904         }
905
906         /* Now we finally make the string. */
907         if (target_type == c_string) {
908                 val =
909                     make_string(string_result,
910                                 string_result_ptr - string_result);
911                 for (argnum = 0; argnum < nargs; argnum++) {
912                         if (STRINGP(args_mse[argnum].string))
913                                 copy_string_extents(val,
914                                                     args_mse[argnum].string,
915                                                     args_mse[argnum].
916                                                     entry_offset, 0,
917                                                     args_mse[argnum].
918                                                     entry_length);
919                 }
920                 XMALLOC_UNBIND(string_result,
921                                total_length * MAX_EMCHAR_LEN, speccount);
922                 XMALLOC_UNBIND(args_mse, nargs, speccount);
923         }
924
925         if (!NILP(prev))
926                 XCDR(prev) = last_tail;
927
928         RETURN_UNGCPRO(val);
929 }
930 \f
931 DEFUN("copy-alist", Fcopy_alist, 1, 1, 0,       /*
932 Return a copy of ALIST.
933 This is an alist which represents the same mapping from objects to objects,
934 but does not share the alist structure with ALIST.
935 The objects mapped (cars and cdrs of elements of the alist)
936 are shared, however.
937 Elements of ALIST that are not conses are also shared.
938 */
939       (alist))
940 {
941         Lisp_Object tail;
942
943         if (NILP(alist))
944                 return alist;
945         CHECK_CONS(alist);
946
947         alist = concat(1, &alist, c_cons, 0);
948         for (tail = alist; CONSP(tail); tail = XCDR(tail)) {
949                 Lisp_Object car = XCAR(tail);
950
951                 if (CONSP(car))
952                         XCAR(tail) = Fcons(XCAR(car), XCDR(car));
953         }
954         return alist;
955 }
956
957 DEFUN("copy-tree", Fcopy_tree, 1, 2, 0, /*
958 Return a copy of a list and substructures.
959 The argument is copied, and any lists contained within it are copied
960 recursively.  Circularities and shared substructures are not preserved.
961 Second arg VECP causes vectors to be copied, too.  Strings and bit vectors
962 are not copied.
963 */
964       (arg, vecp))
965 {
966         return safe_copy_tree(arg, vecp, 0);
967 }
968
969 Lisp_Object safe_copy_tree(Lisp_Object arg, Lisp_Object vecp, int depth)
970 {
971         if (depth > 200)
972                 signal_simple_error("Stack overflow in copy-tree", arg);
973
974         if (CONSP(arg)) {
975                 Lisp_Object rest;
976                 rest = arg = Fcopy_sequence(arg);
977                 while (CONSP(rest)) {
978                         Lisp_Object elt = XCAR(rest);
979                         QUIT;
980                         if (CONSP(elt) || VECTORP(elt))
981                                 XCAR(rest) =
982                                     safe_copy_tree(elt, vecp, depth + 1);
983                         if (VECTORP(XCDR(rest)))        /* hack for (a b . [c d]) */
984                                 XCDR(rest) =
985                                     safe_copy_tree(XCDR(rest), vecp, depth + 1);
986                         rest = XCDR(rest);
987                 }
988         } else if (VECTORP(arg) && !NILP(vecp)) {
989                 int i = XVECTOR_LENGTH(arg);
990                 int j;
991                 arg = Fcopy_sequence(arg);
992                 for (j = 0; j < i; j++) {
993                         Lisp_Object elt = XVECTOR_DATA(arg)[j];
994                         QUIT;
995                         if (CONSP(elt) || VECTORP(elt))
996                                 XVECTOR_DATA(arg)[j] =
997                                     safe_copy_tree(elt, vecp, depth + 1);
998                 }
999         }
1000         return arg;
1001 }
1002
1003 DEFUN("substring", Fsubstring, 2, 3, 0, /*
1004 Return the substring of STRING starting at START and ending before END.
1005 END may be nil or omitted; then the substring runs to the end of STRING.
1006 If START or END is negative, it counts from the end.
1007 Relevant parts of the string-extent-data are copied to the new string.
1008 */
1009       (string, start, end)) 
1010 {
1011         Charcount ccstart, ccend;
1012         Bytecount bstart, blen;
1013         Lisp_Object val;
1014
1015         CHECK_STRING(string);
1016         CHECK_INT(start);
1017         get_string_range_char(string, start, end, &ccstart, &ccend,
1018                               GB_HISTORICAL_STRING_BEHAVIOR);
1019         bstart = charcount_to_bytecount(XSTRING_DATA(string), ccstart);
1020         blen =
1021             charcount_to_bytecount(XSTRING_DATA(string) + bstart,
1022                                    ccend - ccstart);
1023         val = make_string(XSTRING_DATA(string) + bstart, blen);
1024         /* Copy any applicable extent information into the new string. */
1025         copy_string_extents(val, string, 0, bstart, blen);
1026         return val;
1027 }
1028
1029 DEFUN("subseq", Fsubseq, 2, 3, 0,       /*
1030 Return the subsequence of SEQUENCE starting at START and ending before END.
1031 END may be omitted; then the subsequence runs to the end of SEQUENCE.
1032 If START or END is negative, it counts from the end.
1033 The returned subsequence is always of the same type as SEQUENCE.
1034 If SEQUENCE is a string, relevant parts of the string-extent-data
1035 are copied to the new string.
1036 */
1037       (sequence, start, end))
1038 {
1039         EMACS_INT len, s, e;
1040
1041         if (STRINGP(sequence))
1042                 return Fsubstring(sequence, start, end);
1043
1044         len = XINT(Flength(sequence));
1045
1046         CHECK_INT(start);
1047         s = XINT(start);
1048         if (s < 0)
1049                 s = len + s;
1050
1051         if (NILP(end))
1052                 e = len;
1053         else {
1054                 CHECK_INT(end);
1055                 e = XINT(end);
1056                 if (e < 0)
1057                         e = len + e;
1058         }
1059
1060         if (!(0 <= s && s <= e && e <= len))
1061                 args_out_of_range_3(sequence, make_int(s), make_int(e));
1062
1063         if (VECTORP(sequence)) {
1064                 Lisp_Object result = make_vector(e - s, Qnil);
1065                 EMACS_INT i;
1066                 Lisp_Object *in_elts = XVECTOR_DATA(sequence);
1067                 Lisp_Object *out_elts = XVECTOR_DATA(result);
1068
1069                 for (i = s; i < e; i++)
1070                         out_elts[i - s] = in_elts[i];
1071                 return result;
1072         } else if (LISTP(sequence)) {
1073                 Lisp_Object result = Qnil;
1074                 EMACS_INT i;
1075
1076                 sequence = Fnthcdr(make_int(s), sequence);
1077
1078                 for (i = s; i < e; i++) {
1079                         result = Fcons(Fcar(sequence), result);
1080                         sequence = Fcdr(sequence);
1081                 }
1082
1083                 return Fnreverse(result);
1084         } else if (BIT_VECTORP(sequence)) {
1085                 Lisp_Object result = make_bit_vector(e - s, Qzero);
1086                 EMACS_INT i;
1087
1088                 for (i = s; i < e; i++)
1089                         set_bit_vector_bit(XBIT_VECTOR(result), i - s,
1090                                            bit_vector_bit(XBIT_VECTOR(sequence),
1091                                                           i));
1092                 return result;
1093         } else {
1094                 abort();        /* unreachable, since Flength (sequence) did not get
1095                                    an error */
1096                 return Qnil;
1097         }
1098 }
1099 \f
1100 DEFUN("nthcdr", Fnthcdr, 2, 2, 0,       /*
1101 Take cdr N times on LIST, and return the result.
1102 */
1103       (n, list))
1104 {
1105         REGISTER size_t i;
1106         REGISTER Lisp_Object tail = list;
1107         CHECK_NATNUM(n);
1108         for (i = XINT(n); i; i--) {
1109                 if (CONSP(tail))
1110                         tail = XCDR(tail);
1111                 else if (NILP(tail))
1112                         return Qnil;
1113                 else {
1114                         tail = wrong_type_argument(Qlistp, tail);
1115                         i++;
1116                 }
1117         }
1118         return tail;
1119 }
1120
1121 DEFUN("nth", Fnth, 2, 2, 0,     /*
1122 Return the Nth element of LIST.
1123 N counts from zero.  If LIST is not that long, nil is returned.
1124 */
1125       (n, list))
1126 {
1127         return Fcar(Fnthcdr(n, list));
1128 }
1129
1130 DEFUN("elt", Felt, 2, 2, 0,     /*
1131 Return element of SEQUENCE at index N.
1132 */
1133       (sequence, n))
1134 {
1135 retry:
1136         if (!(INTP(n) || CHARP(n))) {
1137                 n = wrong_type_argument(Qinteger_or_char_p, n);
1138                 goto retry;
1139         }
1140
1141         if (LISTP(sequence)) {
1142                 Lisp_Object tem = Fnthcdr(n, sequence);
1143                 /* #### Utterly, completely, fucking disgusting.
1144                  * #### The whole point of "elt" is that it operates on
1145                  * #### sequences, and does error- (bounds-) checking.
1146                  */
1147                 if (CONSP(tem))
1148                         return XCAR(tem);
1149                 else
1150 #if 1
1151                         /* This is The Way It Has Always Been. */
1152                         return Qnil;
1153 #else
1154                         /* This is The Way Mly and Cltl2 say It Should Be. */
1155                         args_out_of_range(sequence, n);
1156 #endif
1157         } else if (DLLISTP(sequence)) {
1158                 dllist_item_t elm = NULL;
1159                 int rev = 0;
1160                 REGISTER size_t i;
1161                 EMACS_INT rn = ent_int(n);
1162
1163                 if (rn < 0) {
1164                         args_out_of_range(sequence, n);
1165                         return Qnil;
1166                 }
1167
1168                 if (rn * 2 < (EMACS_INT)XDLLIST_SIZE(sequence)) {
1169                         /* start at the front */
1170                         elm = XDLLIST_FIRST(sequence);
1171                         i = rn;
1172                 } else {
1173                         /* start at the end */
1174                         elm = XDLLIST_LAST(sequence);
1175                         rev = 1;
1176                         i = XDLLIST_SIZE(sequence) - rn - 1;
1177                 }
1178
1179                 for (; i > 0 && elm != NULL; i--)
1180                         if (rev == 0)
1181                                 elm = elm->next;
1182                         else
1183                                 elm = elm->prev;
1184
1185                 if (elm)
1186                         return (Lisp_Object)elm->item;
1187                 else
1188                         return Qnil;
1189
1190         } else if (STRINGP(sequence) ||
1191                    VECTORP(sequence) || BIT_VECTORP(sequence))
1192                 return Faref(sequence, n);
1193 #ifdef LOSING_BYTECODE
1194         else if (COMPILED_FUNCTIONP(sequence)) {
1195                 EMACS_INT idx = ent_int(n);
1196                 if (idx < 0) {
1197                       lose:
1198                         args_out_of_range(sequence, n);
1199                 }
1200                 /* Utter perversity */
1201                 {
1202                         Lisp_Compiled_Function *f =
1203                             XCOMPILED_FUNCTION(sequence);
1204                         switch (idx) {
1205                         case COMPILED_ARGLIST:
1206                                 return compiled_function_arglist(f);
1207                         case COMPILED_INSTRUCTIONS:
1208                                 return compiled_function_instructions(f);
1209                         case COMPILED_CONSTANTS:
1210                                 return compiled_function_constants(f);
1211                         case COMPILED_STACK_DEPTH:
1212                                 return compiled_function_stack_depth(f);
1213                         case COMPILED_DOC_STRING:
1214                                 return compiled_function_documentation(f);
1215                         case COMPILED_DOMAIN:
1216                                 return compiled_function_domain(f);
1217                         case COMPILED_INTERACTIVE:
1218                                 if (f->flags.interactivep)
1219                                         return compiled_function_interactive(f);
1220                                 /* if we return nil, can't tell interactive with no args
1221                                    from noninteractive. */
1222                                 goto lose;
1223                         default:
1224                                 goto lose;
1225                         }
1226                 }
1227         }
1228 #endif                          /* LOSING_BYTECODE */
1229         else {
1230                 check_losing_bytecode("elt", sequence);
1231                 sequence = wrong_type_argument(Qsequencep, sequence);
1232                 goto retry;
1233         }
1234 }
1235
1236 DEFUN("last", Flast, 1, 2, 0,   /*
1237 Return the tail of list LIST, of length N (default 1).
1238 LIST may be a dotted list, but not a circular list.
1239 Optional argument N must be a non-negative integer.
1240 If N is zero, then the atom that terminates the list is returned.
1241 If N is greater than the length of LIST, then LIST itself is returned.
1242 */
1243       (list, n))
1244 {
1245         EMACS_INT int_n, count;
1246         Lisp_Object retval, tortoise, hare;
1247
1248         if (DLLISTP(list))
1249                 return Fdllist_rac(list);
1250
1251         CHECK_LIST(list);
1252
1253         if (NILP(n))
1254                 int_n = 1;
1255         else {
1256                 CHECK_NATNUM(n);
1257                 int_n = XINT(n);
1258         }
1259
1260         for (retval = tortoise = hare = list, count = 0;
1261              CONSP(hare);
1262              hare = XCDR(hare),
1263              (int_n-- <= 0 ? ((void)(retval = XCDR(retval))) : (void)0),
1264              count++) {
1265                 if (count < CIRCULAR_LIST_SUSPICION_LENGTH)
1266                         continue;
1267
1268                 if (count & 1)
1269                         tortoise = XCDR(tortoise);
1270                 if (EQ(hare, tortoise))
1271                         signal_circular_list_error(list);
1272         }
1273
1274         return retval;
1275 }
1276
1277 DEFUN("nbutlast", Fnbutlast, 1, 2, 0,   /*
1278 Modify LIST to remove the last N (default 1) elements.
1279 If LIST has N or fewer elements, nil is returned and LIST is unmodified.
1280 */
1281       (list, n))
1282 {
1283         EMACS_INT int_n;
1284
1285         CHECK_LIST(list);
1286
1287         if (NILP(n))
1288                 int_n = 1;
1289         else {
1290                 CHECK_NATNUM(n);
1291                 int_n = XINT(n);
1292         }
1293
1294         {
1295                 Lisp_Object last_cons = list;
1296
1297                 EXTERNAL_LIST_LOOP_1(list) {
1298                         if (int_n-- < 0)
1299                                 last_cons = XCDR(last_cons);
1300                 }
1301
1302                 if (int_n >= 0)
1303                         return Qnil;
1304
1305                 XCDR(last_cons) = Qnil;
1306                 return list;
1307         }
1308 }
1309
1310 DEFUN("butlast", Fbutlast, 1, 2, 0,     /*
1311 Return a copy of LIST with the last N (default 1) elements removed.
1312 If LIST has N or fewer elements, nil is returned.
1313 */
1314       (list, n))
1315 {
1316         EMACS_INT int_n;
1317
1318         CHECK_LIST(list);
1319
1320         if (NILP(n))
1321                 int_n = 1;
1322         else {
1323                 CHECK_NATNUM(n);
1324                 int_n = XINT(n);
1325         }
1326
1327         {
1328                 Lisp_Object retval = Qnil;
1329                 Lisp_Object tail = list;
1330
1331                 EXTERNAL_LIST_LOOP_1(list) {
1332                         if (--int_n < 0) {
1333                                 retval = Fcons(XCAR(tail), retval);
1334                                 tail = XCDR(tail);
1335                         }
1336                 }
1337
1338                 return Fnreverse(retval);
1339         }
1340 }
1341
1342 DEFUN("member", Fmember, 2, 2, 0,       /*
1343 Return non-nil if ELT is an element of LIST.  Comparison done with `equal'.
1344 The value is actually the tail of LIST whose car is ELT.
1345 */
1346       (elt, list))
1347 {
1348         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1349                 if (internal_equal(elt, list_elt, 0))
1350                         return tail;
1351         }
1352         return Qnil;
1353 }
1354
1355 DEFUN("old-member", Fold_member, 2, 2, 0,       /*
1356 Return non-nil if ELT is an element of LIST.  Comparison done with `old-equal'.
1357 The value is actually the tail of LIST whose car is ELT.
1358 This function is provided only for byte-code compatibility with v19.
1359 Do not use it.
1360 */
1361       (elt, list))
1362 {
1363         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1364                 if (internal_old_equal(elt, list_elt, 0))
1365                         return tail;
1366         }
1367         return Qnil;
1368 }
1369
1370 DEFUN("memq", Fmemq, 2, 2, 0,   /*
1371 Return non-nil if ELT is an element of LIST.  Comparison done with `eq'.
1372 The value is actually the tail of LIST whose car is ELT.
1373 */
1374       (elt, list))
1375 {
1376         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1377                 if (EQ_WITH_EBOLA_NOTICE(elt, list_elt))
1378                         return tail;
1379         }
1380         return Qnil;
1381 }
1382
1383 DEFUN("old-memq", Fold_memq, 2, 2, 0,   /*
1384 Return non-nil if ELT is an element of LIST.  Comparison done with `old-eq'.
1385 The value is actually the tail of LIST whose car is ELT.
1386 This function is provided only for byte-code compatibility with v19.
1387 Do not use it.
1388 */
1389       (elt, list))
1390 {
1391         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1392                 if (HACKEQ_UNSAFE(elt, list_elt))
1393                         return tail;
1394         }
1395         return Qnil;
1396 }
1397
1398 Lisp_Object memq_no_quit(Lisp_Object elt, Lisp_Object list)
1399 {
1400         LIST_LOOP_3(list_elt, list, tail) {
1401                 if (EQ_WITH_EBOLA_NOTICE(elt, list_elt))
1402                         return tail;
1403         }
1404         return Qnil;
1405 }
1406
1407 DEFUN("assoc", Fassoc, 2, 2, 0, /*
1408 Return non-nil if KEY is `equal' to the car of an element of ALIST.
1409 The value is actually the element of ALIST whose car equals KEY.
1410 */
1411       (key, alist))
1412 {
1413         /* This function can GC. */
1414         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1415                 if (internal_equal(key, elt_car, 0))
1416                         return elt;
1417         }
1418         return Qnil;
1419 }
1420
1421 DEFUN("old-assoc", Fold_assoc, 2, 2, 0, /*
1422 Return non-nil if KEY is `old-equal' to the car of an element of ALIST.
1423 The value is actually the element of ALIST whose car equals KEY.
1424 */
1425       (key, alist))
1426 {
1427         /* This function can GC. */
1428         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1429                 if (internal_old_equal(key, elt_car, 0))
1430                         return elt;
1431         }
1432         return Qnil;
1433 }
1434
1435 Lisp_Object assoc_no_quit(Lisp_Object key, Lisp_Object alist)
1436 {
1437         int speccount = specpdl_depth();
1438         specbind(Qinhibit_quit, Qt);
1439         return unbind_to(speccount, Fassoc(key, alist));
1440 }
1441
1442 DEFUN("assq", Fassq, 2, 2, 0,   /*
1443 Return non-nil if KEY is `eq' to the car of an element of ALIST.
1444 The value is actually the element of ALIST whose car is KEY.
1445 Elements of ALIST that are not conses are ignored.
1446 */
1447       (key, alist))
1448 {
1449         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1450                 if (EQ_WITH_EBOLA_NOTICE(key, elt_car))
1451                         return elt;
1452         }
1453         return Qnil;
1454 }
1455
1456 DEFUN("old-assq", Fold_assq, 2, 2, 0,   /*
1457 Return non-nil if KEY is `old-eq' to the car of an element of ALIST.
1458 The value is actually the element of ALIST whose car is KEY.
1459 Elements of ALIST that are not conses are ignored.
1460 This function is provided only for byte-code compatibility with v19.
1461 Do not use it.
1462 */
1463       (key, alist))
1464 {
1465         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1466                 if (HACKEQ_UNSAFE(key, elt_car))
1467                         return elt;
1468         }
1469         return Qnil;
1470 }
1471
1472 /* Like Fassq but never report an error and do not allow quits.
1473    Use only on lists known never to be circular.  */
1474
1475 Lisp_Object assq_no_quit(Lisp_Object key, Lisp_Object alist)
1476 {
1477         /* This cannot GC. */
1478         LIST_LOOP_2(elt, alist) {
1479                 Lisp_Object elt_car = XCAR(elt);
1480                 if (EQ_WITH_EBOLA_NOTICE(key, elt_car))
1481                         return elt;
1482         }
1483         return Qnil;
1484 }
1485
1486 DEFUN("rassoc", Frassoc, 2, 2, 0,       /*
1487 Return non-nil if VALUE is `equal' to the cdr of an element of ALIST.
1488 The value is actually the element of ALIST whose cdr equals VALUE.
1489 */
1490       (value, alist))
1491 {
1492         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1493                 if (internal_equal(value, elt_cdr, 0))
1494                         return elt;
1495         }
1496         return Qnil;
1497 }
1498
1499 DEFUN("old-rassoc", Fold_rassoc, 2, 2, 0,       /*
1500 Return non-nil if VALUE is `old-equal' to the cdr of an element of ALIST.
1501 The value is actually the element of ALIST whose cdr equals VALUE.
1502 */
1503       (value, alist))
1504 {
1505         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1506                 if (internal_old_equal(value, elt_cdr, 0))
1507                         return elt;
1508         }
1509         return Qnil;
1510 }
1511
1512 DEFUN("rassq", Frassq, 2, 2, 0, /*
1513 Return non-nil if VALUE is `eq' to the cdr of an element of ALIST.
1514 The value is actually the element of ALIST whose cdr is VALUE.
1515 */
1516       (value, alist))
1517 {
1518         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1519                 if (EQ_WITH_EBOLA_NOTICE(value, elt_cdr))
1520                         return elt;
1521         }
1522         return Qnil;
1523 }
1524
1525 DEFUN("old-rassq", Fold_rassq, 2, 2, 0, /*
1526 Return non-nil if VALUE is `old-eq' to the cdr of an element of ALIST.
1527 The value is actually the element of ALIST whose cdr is VALUE.
1528 */
1529       (value, alist))
1530 {
1531         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1532                 if (HACKEQ_UNSAFE(value, elt_cdr))
1533                         return elt;
1534         }
1535         return Qnil;
1536 }
1537
1538 /* Like Frassq, but caller must ensure that ALIST is properly
1539    nil-terminated and ebola-free. */
1540 Lisp_Object rassq_no_quit(Lisp_Object value, Lisp_Object alist)
1541 {
1542         LIST_LOOP_2(elt, alist) {
1543                 Lisp_Object elt_cdr = XCDR(elt);
1544                 if (EQ_WITH_EBOLA_NOTICE(value, elt_cdr))
1545                         return elt;
1546         }
1547         return Qnil;
1548 }
1549 \f
1550 DEFUN("delete", Fdelete, 2, 2, 0,       /*
1551 Delete by side effect any occurrences of ELT as a member of LIST.
1552 The modified LIST is returned.  Comparison is done with `equal'.
1553 If the first member of LIST is ELT, there is no way to remove it by side
1554 effect; therefore, write `(setq foo (delete element foo))' to be sure
1555 of changing the value of `foo'.
1556 Also see: `remove'.
1557 */
1558       (elt, list))
1559 {
1560         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1561                                      (internal_equal(elt, list_elt, 0)));
1562         return list;
1563 }
1564
1565 DEFUN("old-delete", Fold_delete, 2, 2, 0,       /*
1566 Delete by side effect any occurrences of ELT as a member of LIST.
1567 The modified LIST is returned.  Comparison is done with `old-equal'.
1568 If the first member of LIST is ELT, there is no way to remove it by side
1569 effect; therefore, write `(setq foo (old-delete element foo))' to be sure
1570 of changing the value of `foo'.
1571 */
1572       (elt, list))
1573 {
1574         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1575                                      (internal_old_equal(elt, list_elt, 0)));
1576         return list;
1577 }
1578
1579 DEFUN("delq", Fdelq, 2, 2, 0,   /*
1580 Delete by side effect any occurrences of ELT as a member of LIST.
1581 The modified LIST is returned.  Comparison is done with `eq'.
1582 If the first member of LIST is ELT, there is no way to remove it by side
1583 effect; therefore, write `(setq foo (delq element foo))' to be sure of
1584 changing the value of `foo'.
1585 */
1586       (elt, list))
1587 {
1588         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1589                                      (EQ_WITH_EBOLA_NOTICE(elt, list_elt)));
1590         return list;
1591 }
1592
1593 DEFUN("old-delq", Fold_delq, 2, 2, 0,   /*
1594 Delete by side effect any occurrences of ELT as a member of LIST.
1595 The modified LIST is returned.  Comparison is done with `old-eq'.
1596 If the first member of LIST is ELT, there is no way to remove it by side
1597 effect; therefore, write `(setq foo (old-delq element foo))' to be sure of
1598 changing the value of `foo'.
1599 */
1600       (elt, list))
1601 {
1602         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1603                                      (HACKEQ_UNSAFE(elt, list_elt)));
1604         return list;
1605 }
1606
1607 /* Like Fdelq, but caller must ensure that LIST is properly
1608    nil-terminated and ebola-free. */
1609
1610 Lisp_Object delq_no_quit(Lisp_Object elt, Lisp_Object list)
1611 {
1612         LIST_LOOP_DELETE_IF(list_elt, list,
1613                             (EQ_WITH_EBOLA_NOTICE(elt, list_elt)));
1614         return list;
1615 }
1616
1617 /* Be VERY careful with this.  This is like delq_no_quit() but
1618    also calls free_cons() on the removed conses.  You must be SURE
1619    that no pointers to the freed conses remain around (e.g.
1620    someone else is pointing to part of the list).  This function
1621    is useful on internal lists that are used frequently and where
1622    the actual list doesn't escape beyond known code bounds. */
1623
1624 Lisp_Object delq_no_quit_and_free_cons(Lisp_Object elt, Lisp_Object list)
1625 {
1626         REGISTER Lisp_Object tail = list;
1627         REGISTER Lisp_Object prev = Qnil;
1628
1629         while (!NILP(tail)) {
1630                 REGISTER Lisp_Object tem = XCAR(tail);
1631                 if (EQ(elt, tem)) {
1632                         Lisp_Object cons_to_free = tail;
1633                         if (NILP(prev))
1634                                 list = XCDR(tail);
1635                         else
1636                                 XCDR(prev) = XCDR(tail);
1637                         tail = XCDR(tail);
1638                         free_cons(XCONS(cons_to_free));
1639                 } else {
1640                         prev = tail;
1641                         tail = XCDR(tail);
1642                 }
1643         }
1644         return list;
1645 }
1646
1647 DEFUN("remassoc", Fremassoc, 2, 2, 0,   /*
1648 Delete by side effect any elements of ALIST whose car is `equal' to KEY.
1649 The modified ALIST is returned.  If the first member of ALIST has a car
1650 that is `equal' to KEY, there is no way to remove it by side effect;
1651 therefore, write `(setq foo (remassoc key foo))' to be sure of changing
1652 the value of `foo'.
1653 */
1654       (key, alist))
1655 {
1656         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1657                                      (CONSP(elt) &&
1658                                       internal_equal(key, XCAR(elt), 0)));
1659         return alist;
1660 }
1661
1662 Lisp_Object remassoc_no_quit(Lisp_Object key, Lisp_Object alist)
1663 {
1664         int speccount = specpdl_depth();
1665         specbind(Qinhibit_quit, Qt);
1666         return unbind_to(speccount, Fremassoc(key, alist));
1667 }
1668
1669 DEFUN("remassq", Fremassq, 2, 2, 0,     /*
1670 Delete by side effect any elements of ALIST whose car is `eq' to KEY.
1671 The modified ALIST is returned.  If the first member of ALIST has a car
1672 that is `eq' to KEY, there is no way to remove it by side effect;
1673 therefore, write `(setq foo (remassq key foo))' to be sure of changing
1674 the value of `foo'.
1675 */
1676       (key, alist))
1677 {
1678         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1679                                      (CONSP(elt) &&
1680                                       EQ_WITH_EBOLA_NOTICE(key, XCAR(elt))));
1681         return alist;
1682 }
1683
1684 /* no quit, no errors; be careful */
1685
1686 Lisp_Object remassq_no_quit(Lisp_Object key, Lisp_Object alist)
1687 {
1688         LIST_LOOP_DELETE_IF(elt, alist,
1689                             (CONSP(elt) &&
1690                              EQ_WITH_EBOLA_NOTICE(key, XCAR(elt))));
1691         return alist;
1692 }
1693
1694 DEFUN("remrassoc", Fremrassoc, 2, 2, 0, /*
1695 Delete by side effect any elements of ALIST whose cdr is `equal' to VALUE.
1696 The modified ALIST is returned.  If the first member of ALIST has a car
1697 that is `equal' to VALUE, there is no way to remove it by side effect;
1698 therefore, write `(setq foo (remrassoc value foo))' to be sure of changing
1699 the value of `foo'.
1700 */
1701       (value, alist))
1702 {
1703         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1704                                      (CONSP(elt) &&
1705                                       internal_equal(value, XCDR(elt), 0)));
1706         return alist;
1707 }
1708
1709 DEFUN("remrassq", Fremrassq, 2, 2, 0,   /*
1710 Delete by side effect any elements of ALIST whose cdr is `eq' to VALUE.
1711 The modified ALIST is returned.  If the first member of ALIST has a car
1712 that is `eq' to VALUE, there is no way to remove it by side effect;
1713 therefore, write `(setq foo (remrassq value foo))' to be sure of changing
1714 the value of `foo'.
1715 */
1716       (value, alist))
1717 {
1718         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1719                                      (CONSP(elt) &&
1720                                       EQ_WITH_EBOLA_NOTICE(value, XCDR(elt))));
1721         return alist;
1722 }
1723
1724 /* Like Fremrassq, fast and unsafe; be careful */
1725 Lisp_Object remrassq_no_quit(Lisp_Object value, Lisp_Object alist)
1726 {
1727         LIST_LOOP_DELETE_IF(elt, alist,
1728                             (CONSP(elt) &&
1729                              EQ_WITH_EBOLA_NOTICE(value, XCDR(elt))));
1730         return alist;
1731 }
1732
1733 DEFUN("nreverse", Fnreverse, 1, 1, 0,   /*
1734 Reverse LIST by destructively modifying cdr pointers.
1735 Return the beginning of the reversed list.
1736 Also see: `reverse'.
1737 */
1738       (list))
1739 {
1740         struct gcpro gcpro1, gcpro2;
1741         REGISTER Lisp_Object prev = Qnil;
1742         REGISTER Lisp_Object tail = list;
1743
1744         /* We gcpro our args; see `nconc' */
1745         GCPRO2(prev, tail);
1746         while (!NILP(tail)) {
1747                 REGISTER Lisp_Object next;
1748                 CONCHECK_CONS(tail);
1749                 next = XCDR(tail);
1750                 XCDR(tail) = prev;
1751                 prev = tail;
1752                 tail = next;
1753         }
1754         UNGCPRO;
1755         return prev;
1756 }
1757
1758 DEFUN("reverse", Freverse, 1, 1, 0,     /*
1759 Reverse LIST, copying.  Return the beginning of the reversed list.
1760 See also the function `nreverse', which is used more often.
1761 */
1762       (list))
1763 {
1764         Lisp_Object reversed_list = Qnil;
1765         EXTERNAL_LIST_LOOP_2(elt, list) {
1766                 reversed_list = Fcons(elt, reversed_list);
1767         }
1768         return reversed_list;
1769 }
1770 \f
1771 static Lisp_Object list_merge(Lisp_Object org_l1, Lisp_Object org_l2,
1772                               Lisp_Object lisp_arg,
1773                               int (*pred_fn) (Lisp_Object, Lisp_Object,
1774                                               Lisp_Object lisp_arg));
1775
1776 Lisp_Object
1777 list_sort(Lisp_Object list,
1778           Lisp_Object lisp_arg,
1779           int (*pred_fn) (Lisp_Object, Lisp_Object, Lisp_Object lisp_arg))
1780 {
1781         struct gcpro gcpro1, gcpro2, gcpro3;
1782         Lisp_Object back, tem;
1783         Lisp_Object front = list;
1784         Lisp_Object len = Flength(list);
1785
1786         if (XINT(len) < 2)
1787                 return list;
1788
1789         len = make_int(XINT(len) / 2 - 1);
1790         tem = Fnthcdr(len, list);
1791         back = Fcdr(tem);
1792         Fsetcdr(tem, Qnil);
1793
1794         GCPRO3(front, back, lisp_arg);
1795         front = list_sort(front, lisp_arg, pred_fn);
1796         back = list_sort(back, lisp_arg, pred_fn);
1797         UNGCPRO;
1798         return list_merge(front, back, lisp_arg, pred_fn);
1799 }
1800 \f
1801 static int
1802 merge_pred_function(Lisp_Object obj1, Lisp_Object obj2, Lisp_Object pred)
1803 {
1804         Lisp_Object tmp;
1805
1806         /* prevents the GC from happening in call2 */
1807         int speccount = specpdl_depth();
1808 /* Emacs' GC doesn't actually relocate pointers, so this probably
1809    isn't strictly necessary */
1810         record_unwind_protect(restore_gc_inhibit,
1811                               make_int(gc_currently_forbidden));
1812         gc_currently_forbidden = 1;
1813         tmp = call2(pred, obj1, obj2);
1814         unbind_to(speccount, Qnil);
1815
1816         if (NILP(tmp))
1817                 return -1;
1818         else
1819                 return 1;
1820 }
1821
1822 DEFUN("sort", Fsort, 2, 2, 0,   /*
1823 Sort LIST, stably, comparing elements using PREDICATE.
1824 Returns the sorted list.  LIST is modified by side effects.
1825 PREDICATE is called with two elements of LIST, and should return T
1826 if the first element is "less" than the second.
1827 */
1828       (list, predicate))
1829 {
1830         return list_sort(list, predicate, merge_pred_function);
1831 }
1832
1833 Lisp_Object merge(Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred)
1834 {
1835         return list_merge(org_l1, org_l2, pred, merge_pred_function);
1836 }
1837
1838 static Lisp_Object
1839 list_merge(Lisp_Object org_l1, Lisp_Object org_l2,
1840            Lisp_Object lisp_arg,
1841            int (*pred_fn) (Lisp_Object, Lisp_Object, Lisp_Object lisp_arg))
1842 {
1843         Lisp_Object value;
1844         Lisp_Object tail;
1845         Lisp_Object tem;
1846         Lisp_Object l1, l2;
1847         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1848
1849         l1 = org_l1;
1850         l2 = org_l2;
1851         tail = Qnil;
1852         value = Qnil;
1853
1854         /* It is sufficient to protect org_l1 and org_l2.
1855            When l1 and l2 are updated, we copy the new values
1856            back into the org_ vars.  */
1857
1858         GCPRO4(org_l1, org_l2, lisp_arg, value);
1859
1860         while (1) {
1861                 if (NILP(l1)) {
1862                         UNGCPRO;
1863                         if (NILP(tail))
1864                                 return l2;
1865                         Fsetcdr(tail, l2);
1866                         return value;
1867                 }
1868                 if (NILP(l2)) {
1869                         UNGCPRO;
1870                         if (NILP(tail))
1871                                 return l1;
1872                         Fsetcdr(tail, l1);
1873                         return value;
1874                 }
1875
1876                 if (((*pred_fn) (Fcar(l2), Fcar(l1), lisp_arg)) < 0) {
1877                         tem = l1;
1878                         l1 = Fcdr(l1);
1879                         org_l1 = l1;
1880                 } else {
1881                         tem = l2;
1882                         l2 = Fcdr(l2);
1883                         org_l2 = l2;
1884                 }
1885                 if (NILP(tail))
1886                         value = tem;
1887                 else
1888                         Fsetcdr(tail, tem);
1889                 tail = tem;
1890         }
1891 }
1892 \f
1893 /************************************************************************/
1894 /*                      property-list functions                         */
1895 /************************************************************************/
1896
1897 /* For properties of text, we need to do order-insensitive comparison of
1898    plists.  That is, we need to compare two plists such that they are the
1899    same if they have the same set of keys, and equivalent values.
1900    So (a 1 b 2) would be equal to (b 2 a 1).
1901
1902    NIL_MEANS_NOT_PRESENT is as in `plists-eq' etc.
1903    LAXP means use `equal' for comparisons.
1904  */
1905 int
1906 plists_differ(Lisp_Object a, Lisp_Object b, int nil_means_not_present,
1907               int laxp, int depth)
1908 {
1909         int eqp = (depth == -1);        /* -1 as depth means use eq, not equal. */
1910         int la, lb, m, i, fill;
1911         Lisp_Object *keys, *vals;
1912         char *flags;
1913         Lisp_Object rest;
1914         int speccount = specpdl_depth();
1915
1916         if (NILP(a) && NILP(b))
1917                 return 0;
1918
1919         Fcheck_valid_plist(a);
1920         Fcheck_valid_plist(b);
1921
1922         la = XINT(Flength(a));
1923         lb = XINT(Flength(b));
1924         m = (la > lb ? la : lb);
1925         fill = 0;
1926         XMALLOC_OR_ALLOCA(keys, m, Lisp_Object);
1927         XMALLOC_OR_ALLOCA(vals, m, Lisp_Object);
1928         XMALLOC_ATOMIC_OR_ALLOCA(flags, m, char);
1929
1930         /* First extract the pairs from A. */
1931         for (rest = a; !NILP(rest); rest = XCDR(XCDR(rest))) {
1932                 Lisp_Object k = XCAR(rest);
1933                 Lisp_Object v = XCAR(XCDR(rest));
1934                 /* Maybe be Ebolified. */
1935                 if (nil_means_not_present && NILP(v))
1936                         continue;
1937                 keys[fill] = k;
1938                 vals[fill] = v;
1939                 flags[fill] = 0;
1940                 fill++;
1941         }
1942         /* Now iterate over B, and stop if we find something that's not in A,
1943            or that doesn't match.  As we match, mark them. */
1944         for (rest = b; !NILP(rest); rest = XCDR(XCDR(rest))) {
1945                 Lisp_Object k = XCAR(rest);
1946                 Lisp_Object v = XCAR(XCDR(rest));
1947                 /* Maybe be Ebolified. */
1948                 if (nil_means_not_present && NILP(v))
1949                         continue;
1950                 for (i = 0; i < fill; i++) {
1951                         if (!laxp ? EQ(k, keys[i]) :
1952                             internal_equal(k, keys[i], depth)) {
1953                                 if (eqp
1954                                     /* We narrowly escaped being Ebolified
1955                                        here. */
1956                                     ? !EQ_WITH_EBOLA_NOTICE(v, vals[i])
1957                                     : !internal_equal(v, vals[i], depth))
1958                                         /* a property in B has a different value
1959                                            than in A */
1960                                         goto MISMATCH;
1961                                 flags[i] = 1;
1962                                 break;
1963                         }
1964                 }
1965                 if (i == fill)
1966                         /* there are some properties in B that are not in A */
1967                         goto MISMATCH;
1968         }
1969         /* Now check to see that all the properties in A were also in B */
1970         for (i = 0; i < fill; i++)
1971                 if (flags[i] == 0)
1972                         goto MISMATCH;
1973
1974         XMALLOC_UNBIND(flags, m, speccount);
1975         XMALLOC_UNBIND(vals, m, speccount);
1976         XMALLOC_UNBIND(keys, m, speccount);
1977         /* Ok. */
1978         return 0;
1979
1980 MISMATCH:
1981         XMALLOC_UNBIND(flags, m, speccount);
1982         XMALLOC_UNBIND(vals, m, speccount);
1983         XMALLOC_UNBIND(keys, m, speccount);
1984         return 1;
1985 }
1986
1987 DEFUN("plists-eq", Fplists_eq, 2, 3, 0, /*
1988 Return non-nil if property lists A and B are `eq'.
1989 A property list is an alternating list of keywords and values.
1990 This function does order-insensitive comparisons of the property lists:
1991 For example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
1992 Comparison between values is done using `eq'.  See also `plists-equal'.
1993 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
1994 a nil value is ignored.  This feature is a virus that has infected
1995 old Lisp implementations, but should not be used except for backward
1996 compatibility.
1997 */
1998       (a, b, nil_means_not_present))
1999 {
2000         return (plists_differ(a, b, !NILP(nil_means_not_present), 0, -1)
2001                 ? Qnil : Qt);
2002 }
2003
2004 DEFUN("plists-equal", Fplists_equal, 2, 3, 0,   /*
2005 Return non-nil if property lists A and B are `equal'.
2006 A property list is an alternating list of keywords and values.  This
2007 function does order-insensitive comparisons of the property lists: For
2008 example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2009 Comparison between values is done using `equal'.  See also `plists-eq'.
2010 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2011 a nil value is ignored.  This feature is a virus that has infected
2012 old Lisp implementations, but should not be used except for backward
2013 compatibility.
2014 */
2015       (a, b, nil_means_not_present))
2016 {
2017         return (plists_differ(a, b, !NILP(nil_means_not_present), 0, 1)
2018                 ? Qnil : Qt);
2019 }
2020
2021 DEFUN("lax-plists-eq", Flax_plists_eq, 2, 3, 0, /*
2022 Return non-nil if lax property lists A and B are `eq'.
2023 A property list is an alternating list of keywords and values.
2024 This function does order-insensitive comparisons of the property lists:
2025 For example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2026 Comparison between values is done using `eq'.  See also `plists-equal'.
2027 A lax property list is like a regular one except that comparisons between
2028 keywords is done using `equal' instead of `eq'.
2029 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2030 a nil value is ignored.  This feature is a virus that has infected
2031 old Lisp implementations, but should not be used except for backward
2032 compatibility.
2033 */
2034       (a, b, nil_means_not_present))
2035 {
2036         return (plists_differ(a, b, !NILP(nil_means_not_present), 1, -1)
2037                 ? Qnil : Qt);
2038 }
2039
2040 DEFUN("lax-plists-equal", Flax_plists_equal, 2, 3, 0,   /*
2041 Return non-nil if lax property lists A and B are `equal'.
2042 A property list is an alternating list of keywords and values.  This
2043 function does order-insensitive comparisons of the property lists: For
2044 example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2045 Comparison between values is done using `equal'.  See also `plists-eq'.
2046 A lax property list is like a regular one except that comparisons between
2047 keywords is done using `equal' instead of `eq'.
2048 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2049 a nil value is ignored.  This feature is a virus that has infected
2050 old Lisp implementations, but should not be used except for backward
2051 compatibility.
2052 */
2053       (a, b, nil_means_not_present))
2054 {
2055         return (plists_differ(a, b, !NILP(nil_means_not_present), 1, 1)
2056                 ? Qnil : Qt);
2057 }
2058
2059 /* Return the value associated with key PROPERTY in property list PLIST.
2060    Return nil if key not found.  This function is used for internal
2061    property lists that cannot be directly manipulated by the user.
2062    */
2063
2064 Lisp_Object internal_plist_get(Lisp_Object plist, Lisp_Object property)
2065 {
2066         Lisp_Object tail;
2067
2068         for (tail = plist; !NILP(tail); tail = XCDR(XCDR(tail))) {
2069                 if (EQ(XCAR(tail), property))
2070                         return XCAR(XCDR(tail));
2071         }
2072
2073         return Qunbound;
2074 }
2075
2076 /* Set PLIST's value for PROPERTY to VALUE.  Analogous to
2077    internal_plist_get(). */
2078
2079 void
2080 internal_plist_put(Lisp_Object * plist, Lisp_Object property, Lisp_Object value)
2081 {
2082         Lisp_Object tail;
2083
2084         for (tail = *plist; !NILP(tail); tail = XCDR(XCDR(tail))) {
2085                 if (EQ(XCAR(tail), property)) {
2086                         XCAR(XCDR(tail)) = value;
2087                         return;
2088                 }
2089         }
2090
2091         *plist = Fcons(property, Fcons(value, *plist));
2092 }
2093
2094 int internal_remprop(Lisp_Object * plist, Lisp_Object property)
2095 {
2096         Lisp_Object tail, prev;
2097
2098         for (tail = *plist, prev = Qnil; !NILP(tail); tail = XCDR(XCDR(tail))) {
2099                 if (EQ(XCAR(tail), property)) {
2100                         if (NILP(prev))
2101                                 *plist = XCDR(XCDR(tail));
2102                         else
2103                                 XCDR(XCDR(prev)) = XCDR(XCDR(tail));
2104                         return 1;
2105                 } else
2106                         prev = tail;
2107         }
2108
2109         return 0;
2110 }
2111
2112 /* Called on a malformed property list.  BADPLACE should be some
2113    place where truncating will form a good list -- i.e. we shouldn't
2114    result in a list with an odd length. */
2115
2116 static Lisp_Object
2117 bad_bad_bunny(Lisp_Object * plist, Lisp_Object * badplace, Error_behavior errb)
2118 {
2119         if (ERRB_EQ(errb, ERROR_ME))
2120                 return Fsignal(Qmalformed_property_list,
2121                                list2(*plist, *badplace));
2122         else {
2123                 if (ERRB_EQ(errb, ERROR_ME_WARN)) {
2124                         warn_when_safe_lispobj
2125                             (Qlist, Qwarning,
2126                              list2(build_string
2127                                    ("Malformed property list -- list has been truncated"),
2128                                    *plist));
2129                         *badplace = Qnil;
2130                 }
2131                 return Qunbound;
2132         }
2133 }
2134
2135 /* Called on a circular property list.  BADPLACE should be some place
2136    where truncating will result in an even-length list, as above.
2137    If doesn't particularly matter where we truncate -- anywhere we
2138    truncate along the entire list will break the circularity, because
2139    it will create a terminus and the list currently doesn't have one.
2140 */
2141
2142 static Lisp_Object
2143 bad_bad_turtle(Lisp_Object * plist, Lisp_Object * badplace, Error_behavior errb)
2144 {
2145         if (ERRB_EQ(errb, ERROR_ME))
2146                 return Fsignal(Qcircular_property_list, list1(*plist));
2147         else {
2148                 if (ERRB_EQ(errb, ERROR_ME_WARN)) {
2149                         warn_when_safe_lispobj
2150                             (Qlist, Qwarning,
2151                              list2(build_string
2152                                    ("Circular property list -- list has been truncated"),
2153                                    *plist));
2154                         *badplace = Qnil;
2155                 }
2156                 return Qunbound;
2157         }
2158 }
2159
2160 /* Advance the tortoise pointer by two (one iteration of a property-list
2161    loop) and the hare pointer by four and verify that no malformations
2162    or circularities exist.  If so, return zero and store a value into
2163    RETVAL that should be returned by the calling function.  Otherwise,
2164    return 1.  See external_plist_get().
2165  */
2166
2167 static int
2168 advance_plist_pointers(Lisp_Object * plist,
2169                        Lisp_Object ** tortoise, Lisp_Object ** hare,
2170                        Error_behavior errb, Lisp_Object * retval)
2171 {
2172         int i;
2173         Lisp_Object *tortsave = *tortoise;
2174
2175         /* Note that our "fixing" may be more brutal than necessary,
2176            but it's the user's own problem, not ours, if they went in and
2177            manually fucked up a plist. */
2178
2179         for (i = 0; i < 2; i++) {
2180                 /* This is a standard iteration of a defensive-loop-checking
2181                    loop.  We just do it twice because we want to advance past
2182                    both the property and its value.
2183
2184                    If the pointer indirection is confusing you, remember that
2185                    one level of indirection on the hare and tortoise pointers
2186                    is only due to pass-by-reference for this function.  The other
2187                    level is so that the plist can be fixed in place. */
2188
2189                 /* When we reach the end of a well-formed plist, **HARE is
2190                    nil.  In that case, we don't do anything at all except
2191                    advance TORTOISE by one.  Otherwise, we advance HARE
2192                    by two (making sure it's OK to do so), then advance
2193                    TORTOISE by one (it will always be OK to do so because
2194                    the HARE is always ahead of the TORTOISE and will have
2195                    already verified the path), then make sure TORTOISE and
2196                    HARE don't contain the same non-nil object -- if the
2197                    TORTOISE and the HARE ever meet, then obviously we're
2198                    in a circularity, and if we're in a circularity, then
2199                    the TORTOISE and the HARE can't cross paths without
2200                    meeting, since the HARE only gains one step over the
2201                    TORTOISE per iteration. */
2202
2203                 if (!NILP(**hare)) {
2204                         Lisp_Object *haresave = *hare;
2205                         if (!CONSP(**hare)) {
2206                                 *retval = bad_bad_bunny(plist, haresave, errb);
2207                                 return 0;
2208                         }
2209                         *hare = &XCDR(**hare);
2210                         /* In a non-plist, we'd check here for a nil value for
2211                          **HARE, which is OK (it just means the list has an
2212                          odd number of elements).  In a plist, it's not OK
2213                          for the list to have an odd number of elements. */
2214                         if (!CONSP(**hare)) {
2215                                 *retval = bad_bad_bunny(plist, haresave, errb);
2216                                 return 0;
2217                         }
2218                         *hare = &XCDR(**hare);
2219                 }
2220
2221                 *tortoise = &XCDR(**tortoise);
2222                 if (!NILP(**hare) && EQ(**tortoise, **hare)) {
2223                         *retval = bad_bad_turtle(plist, tortsave, errb);
2224                         return 0;
2225                 }
2226         }
2227
2228         return 1;
2229 }
2230
2231 /* Return the value of PROPERTY from PLIST, or Qunbound if
2232    property is not on the list.
2233
2234    PLIST is a Lisp-accessible property list, meaning that it
2235    has to be checked for malformations and circularities.
2236
2237    If ERRB is ERROR_ME, an error will be signalled.  Otherwise, the
2238    function will never signal an error; and if ERRB is ERROR_ME_WARN,
2239    on finding a malformation or a circularity, it issues a warning and
2240    attempts to silently fix the problem.
2241
2242    A pointer to PLIST is passed in so that PLIST can be successfully
2243    "fixed" even if the error is at the beginning of the plist. */
2244
2245 Lisp_Object
2246 external_plist_get(Lisp_Object * plist, Lisp_Object property,
2247                    int laxp, Error_behavior errb)
2248 {
2249         Lisp_Object *tortoise = plist;
2250         Lisp_Object *hare = plist;
2251
2252         while (!NILP(*tortoise)) {
2253                 Lisp_Object *tortsave = tortoise;
2254                 Lisp_Object retval;
2255
2256                 /* We do the standard tortoise/hare march.  We isolate the
2257                    grungy stuff to do this in advance_plist_pointers(), though.
2258                    To us, all this function does is advance the tortoise
2259                    pointer by two and the hare pointer by four and make sure
2260                    everything's OK.  We first advance the pointers and then
2261                    check if a property matched; this ensures that our
2262                    check for a matching property is safe. */
2263
2264                 if (!advance_plist_pointers
2265                     (plist, &tortoise, &hare, errb, &retval))
2266                         return retval;
2267
2268                 if (!laxp ? EQ(XCAR(*tortsave), property)
2269                     : internal_equal(XCAR(*tortsave), property, 0))
2270                         return XCAR(XCDR(*tortsave));
2271         }
2272
2273         return Qunbound;
2274 }
2275
2276 /* Set PLIST's value for PROPERTY to VALUE, given a possibly
2277    malformed or circular plist.  Analogous to external_plist_get(). */
2278
2279 void
2280 external_plist_put(Lisp_Object * plist, Lisp_Object property,
2281                    Lisp_Object value, int laxp, Error_behavior errb)
2282 {
2283         Lisp_Object *tortoise = plist;
2284         Lisp_Object *hare = plist;
2285
2286         while (!NILP(*tortoise)) {
2287                 Lisp_Object *tortsave = tortoise;
2288                 Lisp_Object retval;
2289
2290                 /* See above */
2291                 if (!advance_plist_pointers
2292                     (plist, &tortoise, &hare, errb, &retval))
2293                         return;
2294
2295                 if (!laxp ? EQ(XCAR(*tortsave), property)
2296                     : internal_equal(XCAR(*tortsave), property, 0)) {
2297                         XCAR(XCDR(*tortsave)) = value;
2298                         return;
2299                 }
2300         }
2301
2302         *plist = Fcons(property, Fcons(value, *plist));
2303 }
2304
2305 int
2306 external_remprop(Lisp_Object * plist, Lisp_Object property,
2307                  int laxp, Error_behavior errb)
2308 {
2309         Lisp_Object *tortoise = plist;
2310         Lisp_Object *hare = plist;
2311
2312         while (!NILP(*tortoise)) {
2313                 Lisp_Object *tortsave = tortoise;
2314                 Lisp_Object retval;
2315
2316                 /* See above */
2317                 if (!advance_plist_pointers
2318                     (plist, &tortoise, &hare, errb, &retval))
2319                         return 0;
2320
2321                 if (!laxp ? EQ(XCAR(*tortsave), property)
2322                     : internal_equal(XCAR(*tortsave), property, 0)) {
2323                         /* Now you see why it's so convenient to have that level
2324                            of indirection. */
2325                         *tortsave = XCDR(XCDR(*tortsave));
2326                         return 1;
2327                 }
2328         }
2329
2330         return 0;
2331 }
2332
2333 DEFUN("plist-get", Fplist_get, 2, 3, 0, /*
2334 Extract a value from a property list.
2335 PLIST is a property list, which is a list of the form
2336 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...).
2337 PROPERTY is usually a symbol.
2338 This function returns the value corresponding to the PROPERTY,
2339 or DEFAULT if PROPERTY is not one of the properties on the list.
2340 */
2341       (plist, property, default_))
2342 {
2343         Lisp_Object value = external_plist_get(&plist, property, 0, ERROR_ME);
2344         return UNBOUNDP(value) ? default_ : value;
2345 }
2346
2347 DEFUN("plist-put", Fplist_put, 3, 3, 0, /*
2348 Change value in PLIST of PROPERTY to VALUE.
2349 PLIST is a property list, which is a list of the form
2350 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
2351 PROPERTY is usually a symbol and VALUE is any object.
2352 If PROPERTY is already a property on the list, its value is set to VALUE,
2353 otherwise the new PROPERTY VALUE pair is added.
2354 The new plist is returned; use `(setq x (plist-put x property value))'
2355 to be sure to use the new value.  PLIST is modified by side effect.
2356 */
2357       (plist, property, value))
2358 {
2359         external_plist_put(&plist, property, value, 0, ERROR_ME);
2360         return plist;
2361 }
2362
2363 DEFUN("plist-remprop", Fplist_remprop, 2, 2, 0, /*
2364 Remove from PLIST the property PROPERTY and its value.
2365 PLIST is a property list, which is a list of the form
2366 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
2367 PROPERTY is usually a symbol.
2368 The new plist is returned; use `(setq x (plist-remprop x property))'
2369 to be sure to use the new value.  PLIST is modified by side effect.
2370 */
2371       (plist, property))
2372 {
2373         external_remprop(&plist, property, 0, ERROR_ME);
2374         return plist;
2375 }
2376
2377 DEFUN("plist-member", Fplist_member, 2, 2, 0,   /*
2378 Return t if PROPERTY has a value specified in PLIST.
2379 */
2380       (plist, property))
2381 {
2382         Lisp_Object value = Fplist_get(plist, property, Qunbound);
2383         return UNBOUNDP(value) ? Qnil : Qt;
2384 }
2385
2386 DEFUN("check-valid-plist", Fcheck_valid_plist, 1, 1, 0, /*
2387 Given a plist, signal an error if there is anything wrong with it.
2388 This means that it's a malformed or circular plist.
2389 */
2390       (plist))
2391 {
2392         Lisp_Object *tortoise;
2393         Lisp_Object *hare;
2394
2395       start_over:
2396         tortoise = &plist;
2397         hare = &plist;
2398         while (!NILP(*tortoise)) {
2399                 Lisp_Object retval;
2400
2401                 /* See above */
2402                 if (!advance_plist_pointers(&plist, &tortoise, &hare, ERROR_ME,
2403                                             &retval))
2404                         goto start_over;
2405         }
2406
2407         return Qnil;
2408 }
2409
2410 DEFUN("valid-plist-p", Fvalid_plist_p, 1, 1, 0, /*
2411 Given a plist, return non-nil if its format is correct.
2412 If it returns nil, `check-valid-plist' will signal an error when given
2413 the plist; that means it's a malformed or circular plist.
2414 */
2415       (plist))
2416 {
2417         Lisp_Object *tortoise;
2418         Lisp_Object *hare;
2419
2420         tortoise = &plist;
2421         hare = &plist;
2422         while (!NILP(*tortoise)) {
2423                 Lisp_Object retval;
2424
2425                 /* See above */
2426                 if (!advance_plist_pointers
2427                     (&plist, &tortoise, &hare, ERROR_ME_NOT, &retval))
2428                         return Qnil;
2429         }
2430
2431         return Qt;
2432 }
2433
2434 DEFUN("canonicalize-plist", Fcanonicalize_plist, 1, 2, 0,       /*
2435 Destructively remove any duplicate entries from a plist.
2436 In such cases, the first entry applies.
2437
2438 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2439 a nil value is removed.  This feature is a virus that has infected
2440 old Lisp implementations, but should not be used except for backward
2441 compatibility.
2442
2443 The new plist is returned.  If NIL-MEANS-NOT-PRESENT is given, the
2444 return value may not be EQ to the passed-in value, so make sure to
2445 `setq' the value back into where it came from.
2446 */
2447       (plist, nil_means_not_present))
2448 {
2449         Lisp_Object head = plist;
2450
2451         Fcheck_valid_plist(plist);
2452
2453         while (!NILP(plist)) {
2454                 Lisp_Object prop = Fcar(plist);
2455                 Lisp_Object next = Fcdr(plist);
2456
2457                 CHECK_CONS(next);       /* just make doubly sure we catch any errors */
2458                 if (!NILP(nil_means_not_present) && NILP(Fcar(next))) {
2459                         if (EQ(head, plist))
2460                                 head = Fcdr(next);
2461                         plist = Fcdr(next);
2462                         continue;
2463                 }
2464                 /* external_remprop returns 1 if it removed any property.
2465                    We have to loop till it didn't remove anything, in case
2466                    the property occurs many times. */
2467                 while (external_remprop(&XCDR(next), prop, 0, ERROR_ME))
2468                         DO_NOTHING;
2469                 plist = Fcdr(next);
2470         }
2471
2472         return head;
2473 }
2474
2475 DEFUN("lax-plist-get", Flax_plist_get, 2, 3, 0, /*
2476 Extract a value from a lax property list.
2477 LAX-PLIST is a lax property list, which is a list of the form
2478 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2479 properties is done using `equal' instead of `eq'.
2480 PROPERTY is usually a symbol.
2481 This function returns the value corresponding to PROPERTY,
2482 or DEFAULT if PROPERTY is not one of the properties on the list.
2483 */
2484       (lax_plist, property, default_))
2485 {
2486         Lisp_Object value =
2487             external_plist_get(&lax_plist, property, 1, ERROR_ME);
2488         return UNBOUNDP(value) ? default_ : value;
2489 }
2490
2491 DEFUN("lax-plist-put", Flax_plist_put, 3, 3, 0, /*
2492 Change value in LAX-PLIST of PROPERTY to VALUE.
2493 LAX-PLIST is a lax property list, which is a list of the form
2494 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2495 properties is done using `equal' instead of `eq'.
2496 PROPERTY is usually a symbol and VALUE is any object.
2497 If PROPERTY is already a property on the list, its value is set to
2498 VALUE, otherwise the new PROPERTY VALUE pair is added.
2499 The new plist is returned; use `(setq x (lax-plist-put x property value))'
2500 to be sure to use the new value.  LAX-PLIST is modified by side effect.
2501 */
2502       (lax_plist, property, value))
2503 {
2504         external_plist_put(&lax_plist, property, value, 1, ERROR_ME);
2505         return lax_plist;
2506 }
2507
2508 DEFUN("lax-plist-remprop", Flax_plist_remprop, 2, 2, 0, /*
2509 Remove from LAX-PLIST the property PROPERTY and its value.
2510 LAX-PLIST is a lax property list, which is a list of the form
2511 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2512 properties is done using `equal' instead of `eq'.
2513 PROPERTY is usually a symbol.
2514 The new plist is returned; use `(setq x (lax-plist-remprop x property))'
2515 to be sure to use the new value.  LAX-PLIST is modified by side effect.
2516 */
2517       (lax_plist, property))
2518 {
2519         external_remprop(&lax_plist, property, 1, ERROR_ME);
2520         return lax_plist;
2521 }
2522
2523 DEFUN("lax-plist-member", Flax_plist_member, 2, 2, 0,   /*
2524 Return t if PROPERTY has a value specified in LAX-PLIST.
2525 LAX-PLIST is a lax property list, which is a list of the form
2526 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2527 properties is done using `equal' instead of `eq'.
2528 */
2529       (lax_plist, property))
2530 {
2531         return UNBOUNDP(Flax_plist_get(lax_plist, property, Qunbound)) ? Qnil :
2532             Qt;
2533 }
2534
2535 DEFUN("canonicalize-lax-plist", Fcanonicalize_lax_plist, 1, 2, 0,       /*
2536 Destructively remove any duplicate entries from a lax plist.
2537 In such cases, the first entry applies.
2538
2539 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2540 a nil value is removed.  This feature is a virus that has infected
2541 old Lisp implementations, but should not be used except for backward
2542 compatibility.
2543
2544 The new plist is returned.  If NIL-MEANS-NOT-PRESENT is given, the
2545 return value may not be EQ to the passed-in value, so make sure to
2546 `setq' the value back into where it came from.
2547 */
2548       (lax_plist, nil_means_not_present))
2549 {
2550         Lisp_Object head = lax_plist;
2551
2552         Fcheck_valid_plist(lax_plist);
2553
2554         while (!NILP(lax_plist)) {
2555                 Lisp_Object prop = Fcar(lax_plist);
2556                 Lisp_Object next = Fcdr(lax_plist);
2557
2558                 CHECK_CONS(next);       /* just make doubly sure we catch any errors */
2559                 if (!NILP(nil_means_not_present) && NILP(Fcar(next))) {
2560                         if (EQ(head, lax_plist))
2561                                 head = Fcdr(next);
2562                         lax_plist = Fcdr(next);
2563                         continue;
2564                 }
2565                 /* external_remprop returns 1 if it removed any property.
2566                    We have to loop till it didn't remove anything, in case
2567                    the property occurs many times. */
2568                 while (external_remprop(&XCDR(next), prop, 1, ERROR_ME))
2569                         DO_NOTHING;
2570                 lax_plist = Fcdr(next);
2571         }
2572
2573         return head;
2574 }
2575
2576 /* In C because the frame props stuff uses it */
2577
2578 DEFUN("destructive-alist-to-plist", Fdestructive_alist_to_plist, 1, 1, 0,       /*
2579 Convert association list ALIST into the equivalent property-list form.
2580 The plist is returned.  This converts from
2581
2582 \((a . 1) (b . 2) (c . 3))
2583
2584 into
2585
2586 \(a 1 b 2 c 3)
2587
2588 The original alist is destroyed in the process of constructing the plist.
2589 See also `alist-to-plist'.
2590 */
2591       (alist))
2592 {
2593         Lisp_Object head = alist;
2594         while (!NILP(alist)) {
2595                 /* remember the alist element. */
2596                 Lisp_Object el = Fcar(alist);
2597
2598                 Fsetcar(alist, Fcar(el));
2599                 Fsetcar(el, Fcdr(el));
2600                 Fsetcdr(el, Fcdr(alist));
2601                 Fsetcdr(alist, el);
2602                 alist = Fcdr(Fcdr(alist));
2603         }
2604
2605         return head;
2606 }
2607
2608 DEFUN("get", Fget, 2, 3, 0,     /*
2609 Return the value of OBJECT's PROPERTY property.
2610 This is the last VALUE stored with `(put OBJECT PROPERTY VALUE)'.
2611 If there is no such property, return optional third arg DEFAULT
2612 \(which defaults to `nil').  OBJECT can be a symbol, string, extent,
2613 face, or glyph.  See also `put', `remprop', and `object-plist'.
2614 */
2615       (object, property, default_))
2616 {
2617         /* Various places in emacs call Fget() and expect it not to quit,
2618            so don't quit. */
2619         Lisp_Object val;
2620
2621         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->getprop)
2622                 val =
2623                     XRECORD_LHEADER_IMPLEMENTATION(object)->getprop(object,
2624                                                                     property);
2625         else
2626                 signal_simple_error("Object type has no properties", object);
2627
2628         return UNBOUNDP(val) ? default_ : val;
2629 }
2630
2631 DEFUN("put", Fput, 3, 3, 0,     /*
2632 Set OBJECT's PROPERTY to VALUE.
2633 It can be subsequently retrieved with `(get OBJECT PROPERTY)'.
2634 OBJECT can be a symbol, face, extent, or string.
2635 For a string, no properties currently have predefined meanings.
2636 For the predefined properties for extents, see `set-extent-property'.
2637 For the predefined properties for faces, see `set-face-property'.
2638 See also `get', `remprop', and `object-plist'.
2639 */
2640       (object, property, value))
2641 {
2642         CHECK_LISP_WRITEABLE(object);
2643
2644         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->putprop) {
2645                 if (!XRECORD_LHEADER_IMPLEMENTATION(object)->putprop
2646                     (object, property, value))
2647                         signal_simple_error("Can't set property on object",
2648                                             property);
2649         } else
2650                 signal_simple_error("Object type has no settable properties",
2651                                     object);
2652
2653         return value;
2654 }
2655
2656 DEFUN("remprop", Fremprop, 2, 2, 0,     /*
2657 Remove, from OBJECT's property list, PROPERTY and its corresponding value.
2658 OBJECT can be a symbol, string, extent, face, or glyph.  Return non-nil
2659 if the property list was actually modified (i.e. if PROPERTY was present
2660 in the property list).  See also `get', `put', and `object-plist'.
2661 */
2662       (object, property))
2663 {
2664         int ret = 0;
2665
2666         CHECK_LISP_WRITEABLE(object);
2667
2668         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->remprop) {
2669                 ret =
2670                     XRECORD_LHEADER_IMPLEMENTATION(object)->remprop(object,
2671                                                                     property);
2672                 if (ret == -1)
2673                         signal_simple_error("Can't remove property from object",
2674                                             property);
2675         } else
2676                 signal_simple_error("Object type has no removable properties",
2677                                     object);
2678
2679         return ret ? Qt : Qnil;
2680 }
2681
2682 DEFUN("object-plist", Fobject_plist, 1, 1, 0,   /*
2683 Return a property list of OBJECT's properties.
2684 For a symbol, this is equivalent to `symbol-plist'.
2685 OBJECT can be a symbol, string, extent, face, or glyph.
2686 Do not modify the returned property list directly;
2687 this may or may not have the desired effects.  Use `put' instead.
2688 */
2689       (object))
2690 {
2691         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->plist)
2692                 return XRECORD_LHEADER_IMPLEMENTATION(object)->plist(object);
2693         else
2694                 signal_simple_error("Object type has no properties", object);
2695
2696         return Qnil;
2697 }
2698 \f
2699 int internal_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
2700 {
2701         if (depth > 200)
2702                 error("Stack overflow in equal");
2703         QUIT;
2704         if (EQ_WITH_EBOLA_NOTICE(obj1, obj2))
2705                 return 1;
2706         /* Note that (equal 20 20.0) should be nil */
2707         if (XTYPE(obj1) != XTYPE(obj2))
2708                 return 0;
2709         if (LRECORDP(obj1)) {
2710                 const struct lrecord_implementation
2711                 *imp1 = XRECORD_LHEADER_IMPLEMENTATION(obj1),
2712                     *imp2 = XRECORD_LHEADER_IMPLEMENTATION(obj2);
2713
2714                 return (imp1 == imp2) &&
2715                     /* EQ-ness of the objects was noticed above */
2716                     (imp1->equal && (imp1->equal) (obj1, obj2, depth));
2717         }
2718
2719         return 0;
2720 }
2721
2722 int
2723 internal_equalp (Lisp_Object obj1, Lisp_Object obj2, int depth)
2724 {
2725         if (depth > 200)
2726                 error ("Stack overflow in equalp");
2727         QUIT;
2728         if (EQ_WITH_EBOLA_NOTICE (obj1, obj2))
2729                 return 1;
2730
2731         if (NUMBERP(obj1) && NUMBERP(obj2)) {
2732                 return ent_binrel(ASE_BINARY_REL_EQUALP, obj1, obj2);
2733         }
2734
2735         if (CHARP(obj1) && CHARP(obj2))
2736                 return XCHAR(obj1) == XCHAR(obj2);
2737         if (XTYPE(obj1) != XTYPE(obj2))
2738                 return 0;
2739         if (LRECORDP(obj1)) {
2740                 const struct lrecord_implementation
2741                         *imp1 = XRECORD_LHEADER_IMPLEMENTATION (obj1),
2742                         *imp2 = XRECORD_LHEADER_IMPLEMENTATION (obj2);
2743                 
2744                 /* #### not yet implemented properly, needs another flag to specify
2745                    equalp-ness */
2746                 return (imp1 == imp2) &&
2747                         /* EQ-ness of the objects was noticed above */
2748                         (imp1->equal && (imp1->equal) (obj1, obj2, depth));
2749         }
2750
2751         return 0;
2752 }
2753
2754
2755 /* Note that we may be calling sub-objects that will use
2756    internal_equal() (instead of internal_old_equal()).  Oh well.
2757    We will get an Ebola note if there's any possibility of confusion,
2758    but that seems unlikely. */
2759
2760 static int internal_old_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
2761 {
2762         if (depth > 200)
2763                 error("Stack overflow in equal");
2764         QUIT;
2765         if (HACKEQ_UNSAFE(obj1, obj2))
2766                 return 1;
2767         /* Note that (equal 20 20.0) should be nil */
2768         if (XTYPE(obj1) != XTYPE(obj2))
2769                 return 0;
2770
2771         return internal_equal(obj1, obj2, depth);
2772 }
2773
2774 DEFUN("equal", Fequal, 2, 2, 0, /*
2775 Return t if two Lisp objects have similar structure and contents.
2776 They must have the same data type.
2777 Conses are compared by comparing the cars and the cdrs.
2778 Vectors and strings are compared element by element.
2779 Numbers are compared by value.  Symbols must match exactly.
2780 */
2781       (object1, object2))
2782 {
2783         return internal_equal(object1, object2, 0) ? Qt : Qnil;
2784 }
2785
2786 DEFUN("old-equal", Fold_equal, 2, 2, 0, /*
2787 Return t if two Lisp objects have similar structure and contents.
2788 They must have the same data type.
2789 \(Note, however, that an exception is made for characters and integers;
2790 this is known as the "char-int confoundance disease." See `eq' and
2791 `old-eq'.)
2792 This function is provided only for byte-code compatibility with v19.
2793 Do not use it.
2794 */
2795       (object1, object2))
2796 {
2797         return internal_old_equal(object1, object2, 0) ? Qt : Qnil;
2798 }
2799 \f
2800 DEFUN("fillarray", Ffillarray, 2, 2, 0, /*
2801 Destructively modify ARRAY by replacing each element with ITEM.
2802 ARRAY is a vector, bit vector, or string.
2803 */
2804       (array, item))
2805 {
2806       retry:
2807         if (STRINGP(array)) {
2808                 Lisp_String *s = XSTRING(array);
2809                 Bytecount old_bytecount = string_length(s);
2810                 Bytecount new_bytecount;
2811                 Bytecount item_bytecount;
2812                 Bufbyte item_buf[MAX_EMCHAR_LEN];
2813                 Bufbyte *p;
2814                 Bufbyte *end;
2815
2816                 CHECK_CHAR_COERCE_INT(item);
2817                 CHECK_LISP_WRITEABLE(array);
2818
2819                 item_bytecount = set_charptr_emchar(item_buf, XCHAR(item));
2820                 new_bytecount = item_bytecount * string_char_length(s);
2821
2822                 resize_string(s, -1, new_bytecount - old_bytecount);
2823
2824                 for (p = string_data(s), end = p + new_bytecount;
2825                      p < end; p += item_bytecount)
2826                         memcpy(p, item_buf, item_bytecount);
2827                 *p = '\0';
2828
2829                 bump_string_modiff(array);
2830         } else if (VECTORP(array)) {
2831                 Lisp_Object *p = XVECTOR_DATA(array);
2832                 size_t len = XVECTOR_LENGTH(array);
2833                 CHECK_LISP_WRITEABLE(array);
2834                 while (len--)
2835                         *p++ = item;
2836         } else if (BIT_VECTORP(array)) {
2837                 Lisp_Bit_Vector *v = XBIT_VECTOR(array);
2838                 size_t len = bit_vector_length(v);
2839                 int bit;
2840                 CHECK_BIT(item);
2841                 bit = XINT(item);
2842                 CHECK_LISP_WRITEABLE(array);
2843                 while (len--)
2844                         set_bit_vector_bit(v, len, bit);
2845         } else {
2846                 array = wrong_type_argument(Qarrayp, array);
2847                 goto retry;
2848         }
2849         return array;
2850 }
2851
2852 Lisp_Object nconc2(Lisp_Object arg1, Lisp_Object arg2)
2853 {
2854         Lisp_Object args[2] = {arg1, arg2};
2855         struct gcpro gcpro1;
2856
2857         GCPROn(args, countof(args));
2858         RETURN_UNGCPRO(bytecode_nconc2(args));
2859 }
2860
2861 Lisp_Object bytecode_nconc2(Lisp_Object * args)
2862 {
2863       retry:
2864
2865         if (CONSP(args[0])) {
2866                 /* (setcdr (last args[0]) args[1]) */
2867                 Lisp_Object tortoise, hare;
2868                 size_t count;
2869
2870                 for (hare = tortoise = args[0], count = 0;
2871                      CONSP(XCDR(hare)); hare = XCDR(hare), count++) {
2872                         if (count < CIRCULAR_LIST_SUSPICION_LENGTH)
2873                                 continue;
2874
2875                         if (count & 1)
2876                                 tortoise = XCDR(tortoise);
2877                         if (EQ(hare, tortoise))
2878                                 signal_circular_list_error(args[0]);
2879                 }
2880                 XCDR(hare) = args[1];
2881                 return args[0];
2882         } else if (NILP(args[0])) {
2883                 return args[1];
2884         } else {
2885                 args[0] = wrong_type_argument(args[0], Qlistp);
2886                 goto retry;
2887         }
2888 }
2889
2890 DEFUN("nconc", Fnconc, 0, MANY, 0,      /*
2891 Concatenate any number of lists by altering them.
2892 Only the last argument is not altered, and need not be a list.
2893 Also see: `append'.
2894 If the first argument is nil, there is no way to modify it by side
2895 effect; therefore, write `(setq foo (nconc foo list))' to be sure of
2896 changing the value of `foo'.
2897 */
2898       (int nargs, Lisp_Object * args))
2899 {
2900         int argnum = 0;
2901         struct gcpro gcpro1;
2902
2903         /* The modus operandi in Emacs is "caller gc-protects args".
2904            However, nconc (particularly nconc2 ()) is called many times
2905            in Emacs on freshly created stuff (e.g. you see the idiom
2906            nconc2 (Fcopy_sequence (foo), bar) a lot).  So we help those
2907            callers out by protecting the args ourselves to save them
2908            a lot of temporary-variable grief. */
2909
2910         GCPROn(args, nargs);
2911
2912         while (argnum < nargs) {
2913                 Lisp_Object val;
2914         retry:
2915                 val = args[argnum];
2916                 if (CONSP(val)) {
2917                         /* `val' is the first cons, which will be our return
2918                          * value.
2919                          * `last_cons' will be the cons cell to mutate.  */
2920                         Lisp_Object last_cons = val;
2921                         Lisp_Object tortoise = val;
2922
2923                         for (argnum++; argnum < nargs; argnum++) {
2924                                 Lisp_Object next = args[argnum];
2925                               retry_next:
2926                                 if (CONSP(next) || argnum == nargs - 1) {
2927                                         /* (setcdr (last val) next) */
2928                                         size_t count;
2929
2930                                         for (count = 0;
2931                                              CONSP(XCDR(last_cons));
2932                                              last_cons =
2933                                              XCDR(last_cons), count++) {
2934                                                 if (count <
2935                                                     CIRCULAR_LIST_SUSPICION_LENGTH)
2936                                                         continue;
2937
2938                                                 if (count & 1)
2939                                                         tortoise =
2940                                                             XCDR(tortoise);
2941                                                 if (EQ(last_cons, tortoise))
2942                                                         signal_circular_list_error
2943                                                             (args[argnum - 1]);
2944                                         }
2945                                         XCDR(last_cons) = next;
2946                                 } else if (NILP(next)) {
2947                                         continue;
2948                                 } else {
2949                                         next =
2950                                             wrong_type_argument(Qlistp, next);
2951                                         goto retry_next;
2952                                 }
2953                         }
2954                         RETURN_UNGCPRO(val);
2955                 } else if (NILP(val))
2956                         argnum++;
2957                 else if (argnum == nargs - 1)   /* last arg? */
2958                         RETURN_UNGCPRO(val);
2959                 else {
2960                         args[argnum] = wrong_type_argument(Qlistp, val);
2961                         goto retry;
2962                 }
2963         }
2964         RETURN_UNGCPRO(Qnil);   /* No non-nil args provided. */
2965 }
2966
2967 \f
2968 DEFUN("replace-list", Freplace_list, 2, 2, 0,   /*
2969 Destructively replace the list OLD with NEW.
2970 This is like (copy-sequence NEW) except that it reuses the
2971 conses in OLD as much as possible.  If OLD and NEW are the same
2972 length, no consing will take place.
2973 */
2974       (old, new))
2975 {
2976         Lisp_Object tail, oldtail = old, prevoldtail = Qnil;
2977
2978         EXTERNAL_LIST_LOOP(tail, new) {
2979                 if (!NILP(oldtail)) {
2980                         CHECK_CONS(oldtail);
2981                         XCAR(oldtail) = XCAR(tail);
2982                 } else if (!NILP(prevoldtail)) {
2983                         XCDR(prevoldtail) = Fcons(XCAR(tail), Qnil);
2984                         prevoldtail = XCDR(prevoldtail);
2985                 } else
2986                         old = oldtail = Fcons(XCAR(tail), Qnil);
2987
2988                 if (!NILP(oldtail)) {
2989                         prevoldtail = oldtail;
2990                         oldtail = XCDR(oldtail);
2991                 }
2992         }
2993
2994         if (!NILP(prevoldtail))
2995                 XCDR(prevoldtail) = Qnil;
2996         else
2997                 old = Qnil;
2998
2999         return old;
3000 }
3001 \f
3002 /* #### this function doesn't belong in this file! */
3003
3004 #ifdef HAVE_GETLOADAVG
3005 #ifdef HAVE_SYS_LOADAVG_H
3006 #include <sys/loadavg.h>
3007 #endif
3008 #else
3009 int getloadavg(double loadavg[], int nelem);    /* Defined in getloadavg.c */
3010 #endif
3011
3012 DEFUN("load-average", Fload_average, 0, 1, 0,   /*
3013 Return list of 1 minute, 5 minute and 15 minute load averages.
3014 Each of the three load averages is multiplied by 100,
3015 then converted to integer.
3016
3017 When USE-FLOATS is non-nil, floats will be used instead of integers.
3018 These floats are not multiplied by 100.
3019
3020 If the 5-minute or 15-minute load averages are not available, return a
3021 shortened list, containing only those averages which are available.
3022
3023 On some systems, this won't work due to permissions on /dev/kmem,
3024 in which case you can't use this.
3025 */
3026       (use_floats))
3027 {
3028         double load_ave[3];
3029         int loads = getloadavg(load_ave, countof(load_ave));
3030         Lisp_Object ret = Qnil;
3031
3032         if (loads == -2)
3033                 error("load-average not implemented for this operating system");
3034         else if (loads < 0)
3035                 signal_simple_error("Could not get load-average",
3036                                     lisp_strerror(errno));
3037
3038         while (loads-- > 0) {
3039                 Lisp_Object load = (NILP(use_floats) ?
3040                                     make_int((int)(100.0 * load_ave[loads]))
3041                                     : make_float(load_ave[loads]));
3042                 ret = Fcons(load, ret);
3043         }
3044         return ret;
3045 }
3046 \f
3047 Lisp_Object Vfeatures;
3048
3049 DEFUN("featurep", Ffeaturep, 1, 1, 0,   /*
3050 Return non-nil if feature FEXP is present in this Emacs.
3051 Use this to conditionalize execution of lisp code based on the
3052 presence or absence of emacs or environment extensions.
3053 FEXP can be a symbol, a number, or a list.
3054 If it is a symbol, that symbol is looked up in the `features' variable,
3055 and non-nil will be returned if found.
3056 If it is a number, the function will return non-nil if this Emacs
3057 has an equal or greater version number than FEXP.
3058 If it is a list whose car is the symbol `and', it will return
3059 non-nil if all the features in its cdr are non-nil.
3060 If it is a list whose car is the symbol `or', it will return non-nil
3061 if any of the features in its cdr are non-nil.
3062 If it is a list whose car is the symbol `not', it will return
3063 non-nil if the feature is not present.
3064
3065 Examples:
3066
3067 (featurep 'sxemacs)
3068 => ; Non-nil on SXEmacs.
3069
3070 (featurep '(and sxemacs gnus))
3071 => ; Non-nil on SXEmacs with Gnus loaded.
3072
3073 (featurep '(or tty-frames (and emacs 19.30)))
3074 => ; Non-nil if this Emacs supports TTY frames.
3075
3076 (featurep '(or (and xemacs 19.15) (and emacs 19.34)))
3077 => ; Non-nil on XEmacs 19.15 and later, or FSF Emacs 19.34 and later.
3078
3079 (featurep '(and xemacs 21.02))
3080 => ; Non-nil on XEmacs 21.2 and later.
3081
3082 NOTE: The advanced arguments of this function (anything other than a
3083 symbol) are not yet supported by FSF Emacs.  If you feel they are useful
3084 for supporting multiple Emacs variants, lobby Richard Stallman at
3085 <bug-gnu-emacs@gnu.org>.
3086 */
3087       (fexp))
3088 {
3089 #ifndef FEATUREP_SYNTAX
3090         CHECK_SYMBOL(fexp);
3091         return NILP(Fmemq(fexp, Vfeatures)) ? Qnil : Qt;
3092 #else                           /* FEATUREP_SYNTAX */
3093         static double featurep_emacs_version;
3094
3095         /* Brute force translation from Erik Naggum's lisp function. */
3096         if (SYMBOLP(fexp)) {
3097                 /* Original definition */
3098                 return NILP(Fmemq(fexp, Vfeatures)) ? Qnil : Qt;
3099         } else if (INTP(fexp) || FLOATP(fexp)) {
3100                 double d = extract_float(fexp);
3101
3102                 if (featurep_emacs_version == 0.0) {
3103                         featurep_emacs_version = XINT(Vemacs_major_version) +
3104                             (XINT(Vemacs_minor_version) / 100.0);
3105                 }
3106                 return featurep_emacs_version >= d ? Qt : Qnil;
3107         } else if (CONSP(fexp)) {
3108                 Lisp_Object tem = XCAR(fexp);
3109                 if (EQ(tem, Qnot)) {
3110                         Lisp_Object negate;
3111
3112                         tem = XCDR(fexp);
3113                         negate = Fcar(tem);
3114                         if (!NILP(tem))
3115                                 return NILP(call1(Qfeaturep, negate)) ? Qt :
3116                                     Qnil;
3117                         else
3118                                 return Fsignal(Qinvalid_read_syntax,
3119                                                list1(tem));
3120                 } else if (EQ(tem, Qand)) {
3121                         tem = XCDR(fexp);
3122                         /* Use Fcar/Fcdr for error-checking. */
3123                         while (!NILP(tem) && !NILP(call1(Qfeaturep, Fcar(tem)))) {
3124                                 tem = Fcdr(tem);
3125                         }
3126                         return NILP(tem) ? Qt : Qnil;
3127                 } else if (EQ(tem, Qor)) {
3128                         tem = XCDR(fexp);
3129                         /* Use Fcar/Fcdr for error-checking. */
3130                         while (!NILP(tem) && NILP(call1(Qfeaturep, Fcar(tem)))) {
3131                                 tem = Fcdr(tem);
3132                         }
3133                         return NILP(tem) ? Qnil : Qt;
3134                 } else {
3135                         return Fsignal(Qinvalid_read_syntax, list1(XCDR(fexp)));
3136                 }
3137         } else {
3138                 return Fsignal(Qinvalid_read_syntax, list1(fexp));
3139         }
3140 }
3141 #endif                          /* FEATUREP_SYNTAX */
3142
3143 DEFUN("provide", Fprovide, 1, 1, 0,     /*
3144 Announce that FEATURE is a feature of the current Emacs.
3145 This function updates the value of the variable `features'.
3146 */
3147       (feature))
3148 {
3149         Lisp_Object tem;
3150         CHECK_SYMBOL(feature);
3151         if (!NILP(Vautoload_queue))
3152                 Vautoload_queue =
3153                     Fcons(Fcons(Vfeatures, Qnil), Vautoload_queue);
3154         tem = Fmemq(feature, Vfeatures);
3155         if (NILP(tem))
3156                 Vfeatures = Fcons(feature, Vfeatures);
3157         LOADHIST_ATTACH(Fcons(Qprovide, feature));
3158         return feature;
3159 }
3160
3161 DEFUN("require", Frequire, 1, 2, 0,     /*
3162 If feature FEATURE is not loaded, load it from FILENAME.
3163 If FEATURE is not a member of the list `features', then the feature
3164 is not loaded; so load the file FILENAME.
3165 If FILENAME is omitted, the printname of FEATURE is used as the file name.
3166 */
3167       (feature, filename))
3168 {
3169         Lisp_Object tem;
3170
3171         CHECK_SYMBOL(feature);
3172         tem = Fmemq(feature, Vfeatures);
3173         LOADHIST_ATTACH(Fcons(Qrequire, feature));
3174
3175         if (!NILP(tem)) {
3176                 return feature;
3177         } else {
3178                 int speccount = specpdl_depth();
3179
3180                 /* Value saved here is to be restored into Vautoload_queue */
3181                 record_unwind_protect(un_autoload, Vautoload_queue);
3182                 Vautoload_queue = Qt;
3183
3184                 /* defined in code-files.el */
3185                 call4(Qload, NILP(filename) ? Fsymbol_name(feature) : filename,
3186                       Qnil, Qt, Qnil);
3187
3188                 tem = Fmemq(feature, Vfeatures);
3189                 if (NILP(tem))
3190                         error("Required feature %s was not provided",
3191                               string_data(XSYMBOL(feature)->name));
3192
3193                 /* Once loading finishes, don't undo it.  */
3194                 Vautoload_queue = Qt;
3195                 return unbind_to(speccount, feature);
3196         }
3197 }
3198
3199 DEFUN("revoke", Frevoke, 1, 1, 0,       /*
3200 Announce that FEATURE is no longer a feature of the current Emacs.
3201 */
3202       (feature))
3203 {
3204         CHECK_SYMBOL(feature);
3205         if (!NILP(Vautoload_queue))
3206                 Vautoload_queue =
3207                     Fcons(Fcons(Vfeatures, Qnil), Vautoload_queue);
3208
3209         if (LIKELY(CONSP(Vfeatures) && EQ(XCAR(Vfeatures), feature))) {
3210                 /* special case where feature is the head of 'features */
3211                 Vfeatures = XCDR(Vfeatures);
3212                 return feature;
3213         }
3214         for (Lisp_Object tmp = Vfeatures;
3215              CONSP(tmp) && CONSP(XCDR(tmp));
3216              tmp = XCDR(tmp)) {
3217                 if (EQ(XCAR(XCDR(tmp)), feature)) {
3218                         XCDR(tmp) = XCDR(XCDR(tmp));
3219                 }
3220                 return feature;
3221         }
3222         return Qnil;
3223 }
3224 \f
3225 /* base64 encode/decode functions.
3226
3227    Originally based on code from GNU recode.  Ported to FSF Emacs by
3228    Lars Magne Ingebrigtsen and Karl Heuer.  Ported to XEmacs and
3229    subsequently heavily hacked by Hrvoje Niksic.  */
3230
3231 #define MIME_LINE_LENGTH 72
3232
3233 #define IS_ASCII(Character) \
3234   ((Character) < 128)
3235 #define IS_BASE64(Character) \
3236   (IS_ASCII (Character) && base64_char_to_value[Character] >= 0)
3237
3238 /* Table of characters coding the 64 values.  */
3239 static char base64_value_to_char[64] = {
3240         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',       /*  0- 9 */
3241         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',       /* 10-19 */
3242         'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',       /* 20-29 */
3243         'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',       /* 30-39 */
3244         'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',       /* 40-49 */
3245         'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',       /* 50-59 */
3246         '8', '9', '+', '/'      /* 60-63 */
3247 };
3248
3249 /* Table of base64 values for first 128 characters.  */
3250 static short base64_char_to_value[128] = {
3251         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*   0-  9 */
3252         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  10- 19 */
3253         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  20- 29 */
3254         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  30- 39 */
3255         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /*  40- 49 */
3256         54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /*  50- 59 */
3257         -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,      /*  60- 69 */
3258         5, 6, 7, 8, 9, 10, 11, 12, 13, 14,      /*  70- 79 */
3259         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /*  80- 89 */
3260         25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /*  90- 99 */
3261         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
3262         39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
3263         49, 50, 51, -1, -1, -1, -1, -1  /* 120-127 */
3264 };
3265
3266 /* The following diagram shows the logical steps by which three octets
3267    get transformed into four base64 characters.
3268
3269                  .--------.  .--------.  .--------.
3270                  |aaaaaabb|  |bbbbcccc|  |ccdddddd|
3271                  `--------'  `--------'  `--------'
3272                     6   2      4   4       2   6
3273                .--------+--------+--------+--------.
3274                |00aaaaaa|00bbbbbb|00cccccc|00dddddd|
3275                `--------+--------+--------+--------'
3276
3277                .--------+--------+--------+--------.
3278                |AAAAAAAA|BBBBBBBB|CCCCCCCC|DDDDDDDD|
3279                `--------+--------+--------+--------'
3280
3281    The octets are divided into 6 bit chunks, which are then encoded into
3282    base64 characters.  */
3283
3284 #define ADVANCE_INPUT(c, stream)                                \
3285  ((ec = Lstream_get_emchar (stream)) == -1 ? 0 :                \
3286   ((ec > 255) ?                                                 \
3287    (signal_simple_error ("Non-ascii character in base64 input", \
3288                          make_char (ec)), 0)                    \
3289    : (c = (Bufbyte)ec), 1))
3290
3291 static Bytind base64_encode_1(Lstream * istream, Bufbyte * to, int line_break)
3292 {
3293         EMACS_INT counter = 0;
3294         Bufbyte *e = to;
3295         Emchar ec;
3296         unsigned int value;
3297
3298         while (1) {
3299                 Bufbyte c;
3300                 if (!ADVANCE_INPUT(c, istream))
3301                         break;
3302
3303                 /* Wrap line every 76 characters.  */
3304                 if (line_break) {
3305                         if (counter < MIME_LINE_LENGTH / 4)
3306                                 counter++;
3307                         else {
3308                                 *e++ = '\n';
3309                                 counter = 1;
3310                         }
3311                 }
3312
3313                 /* Process first byte of a triplet.  */
3314                 *e++ = base64_value_to_char[0x3f & c >> 2];
3315                 value = (0x03 & c) << 4;
3316
3317                 /* Process second byte of a triplet.  */
3318                 if (!ADVANCE_INPUT(c, istream)) {
3319                         *e++ = base64_value_to_char[value];
3320                         *e++ = '=';
3321                         *e++ = '=';
3322                         break;
3323                 }
3324
3325                 *e++ = base64_value_to_char[value | (0x0f & c >> 4)];
3326                 value = (0x0f & c) << 2;
3327
3328                 /* Process third byte of a triplet.  */
3329                 if (!ADVANCE_INPUT(c, istream)) {
3330                         *e++ = base64_value_to_char[value];
3331                         *e++ = '=';
3332                         break;
3333                 }
3334
3335                 *e++ = base64_value_to_char[value | (0x03 & c >> 6)];
3336                 *e++ = base64_value_to_char[0x3f & c];
3337         }
3338
3339         return e - to;
3340 }
3341
3342 #undef ADVANCE_INPUT
3343
3344 /* Get next character from the stream, except that non-base64
3345    characters are ignored.  This is in accordance with rfc2045.  EC
3346    should be an Emchar, so that it can hold -1 as the value for EOF.  */
3347 #define ADVANCE_INPUT_IGNORE_NONBASE64(ec, stream, streampos) do {      \
3348   ec = Lstream_get_emchar (stream);                                     \
3349   ++streampos;                                                          \
3350   /* IS_BASE64 may not be called with negative arguments so check for   \
3351      EOF first. */                                                      \
3352   if (ec < 0 || IS_BASE64 (ec) || ec == '=')                            \
3353     break;                                                              \
3354 } while (1)
3355
3356 #define STORE_BYTE(pos, val, ccnt) do {                                 \
3357   pos += set_charptr_emchar (pos, (Emchar)((unsigned char)(val)));      \
3358   ++ccnt;                                                               \
3359 } while (0)
3360
3361 static Bytind
3362 base64_decode_1(Lstream * istream, Bufbyte * to, Charcount * ccptr)
3363 {
3364         Charcount ccnt = 0;
3365         Bufbyte *e = to;
3366         EMACS_INT streampos = 0;
3367
3368         while (1) {
3369                 Emchar ec;
3370                 unsigned long value;
3371
3372                 /* Process first byte of a quadruplet.  */
3373                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3374                 if (ec < 0)
3375                         break;
3376                 if (ec == '=')
3377                         signal_simple_error
3378                             ("Illegal `=' character while decoding base64",
3379                              make_int(streampos));
3380                 value = base64_char_to_value[ec] << 18;
3381
3382                 /* Process second byte of a quadruplet.  */
3383                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3384                 if (ec < 0)
3385                         error("Premature EOF while decoding base64");
3386                 if (ec == '=')
3387                         signal_simple_error
3388                             ("Illegal `=' character while decoding base64",
3389                              make_int(streampos));
3390                 value |= base64_char_to_value[ec] << 12;
3391                 STORE_BYTE(e, value >> 16, ccnt);
3392
3393                 /* Process third byte of a quadruplet.  */
3394                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3395                 if (ec < 0)
3396                         error("Premature EOF while decoding base64");
3397
3398                 if (ec == '=') {
3399                         ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3400                         if (ec < 0)
3401                                 error("Premature EOF while decoding base64");
3402                         if (ec != '=')
3403                                 signal_simple_error
3404                                     ("Padding `=' expected but not found while decoding base64",
3405                                      make_int(streampos));
3406                         continue;
3407                 }
3408
3409                 value |= base64_char_to_value[ec] << 6;
3410                 STORE_BYTE(e, 0xff & value >> 8, ccnt);
3411
3412                 /* Process fourth byte of a quadruplet.  */
3413                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3414                 if (ec < 0)
3415                         error("Premature EOF while decoding base64");
3416                 if (ec == '=')
3417                         continue;
3418
3419                 value |= base64_char_to_value[ec];
3420                 STORE_BYTE(e, 0xff & value, ccnt);
3421         }
3422
3423         *ccptr = ccnt;
3424         return e - to;
3425 }
3426
3427 #undef ADVANCE_INPUT
3428 #undef ADVANCE_INPUT_IGNORE_NONBASE64
3429 #undef STORE_BYTE
3430
3431 DEFUN("base64-encode-region", Fbase64_encode_region, 2, 3, "r", /*
3432 Base64-encode the region between START and END.
3433 Return the length of the encoded text.
3434 Optional third argument NO-LINE-BREAK means do not break long lines
3435 into shorter lines.
3436 */
3437       (start, end, no_line_break))
3438 {
3439         Bufbyte *encoded;
3440         Bytind encoded_length;
3441         Charcount allength, length;
3442         struct buffer *buf = current_buffer;
3443         Bufpos begv, zv, old_pt = BUF_PT(buf);
3444         Lisp_Object input;
3445         int speccount = specpdl_depth();
3446
3447         get_buffer_range_char(buf, start, end, &begv, &zv, 0);
3448         barf_if_buffer_read_only(buf, begv, zv);
3449
3450         /* We need to allocate enough room for encoding the text.
3451            We need 33 1/3% more space, plus a newline every 76
3452            characters, and then we round up. */
3453         length = zv - begv;
3454         allength = length + length / 3 + 1;
3455         allength += allength / MIME_LINE_LENGTH + 1 + 6;
3456
3457         input = make_lisp_buffer_input_stream(buf, begv, zv, 0);
3458         /* We needn't multiply allength with MAX_EMCHAR_LEN because all the
3459            base64 characters will be single-byte.  */
3460         XMALLOC_ATOMIC_OR_ALLOCA(encoded, allength, Bufbyte);
3461         encoded_length = base64_encode_1(XLSTREAM(input), encoded,
3462                                          NILP(no_line_break));
3463         if (encoded_length > allength) {
3464                 abort();
3465         }
3466         Lstream_delete(XLSTREAM(input));
3467
3468         /* Now we have encoded the region, so we insert the new contents
3469            and delete the old.  (Insert first in order to preserve markers.)  */
3470         buffer_insert_raw_string_1(buf, begv, encoded, encoded_length, 0);
3471         XMALLOC_UNBIND(encoded, allength, speccount);
3472         buffer_delete_range(buf, begv + encoded_length, zv + encoded_length, 0);
3473
3474         /* Simulate FSF Emacs implementation of this function: if point was
3475            in the region, place it at the beginning.  */
3476         if (old_pt >= begv && old_pt < zv) {
3477                 BUF_SET_PT(buf, begv);
3478         }
3479
3480         /* We return the length of the encoded text. */
3481         return make_int(encoded_length);
3482 }
3483
3484 DEFUN("base64-encode-string", Fbase64_encode_string, 1, 2, 0,   /*
3485 Base64 encode STRING and return the result.
3486 Optional argument NO-LINE-BREAK means do not break long lines
3487 into shorter lines.
3488 */
3489       (string, no_line_break))
3490 {
3491         Charcount allength, length;
3492         Bytind encoded_length;
3493         Bufbyte *encoded;
3494         Lisp_Object input, result;
3495         int speccount = specpdl_depth();
3496
3497         CHECK_STRING(string);
3498
3499         length = XSTRING_CHAR_LENGTH(string);
3500         allength = length + length / 3 + 1;
3501         allength += allength / MIME_LINE_LENGTH + 1 + 6;
3502
3503         input = make_lisp_string_input_stream(string, 0, -1);
3504         XMALLOC_ATOMIC_OR_ALLOCA(encoded, allength, Bufbyte);
3505         encoded_length = base64_encode_1(XLSTREAM(input), encoded,
3506                                          NILP(no_line_break));
3507         if (encoded_length > allength) {
3508                 abort();
3509         }
3510         Lstream_delete(XLSTREAM(input));
3511         result = make_string(encoded, encoded_length);
3512         XMALLOC_UNBIND(encoded, allength, speccount);
3513         return result;
3514 }
3515
3516 DEFUN("base64-decode-region", Fbase64_decode_region, 2, 2, "r", /*
3517 Base64-decode the region between START and END.
3518 Return the length of the decoded text.
3519 If the region can't be decoded, return nil and don't modify the buffer.
3520 Characters out of the base64 alphabet are ignored.
3521 */
3522       (start, end))
3523 {
3524         struct buffer *buf = current_buffer;
3525         Bufpos begv, zv, old_pt = BUF_PT(buf);
3526         Bufbyte *decoded;
3527         Bytind decoded_length;
3528         Charcount length, cc_decoded_length;
3529         Lisp_Object input;
3530         int speccount = specpdl_depth();
3531
3532         get_buffer_range_char(buf, start, end, &begv, &zv, 0);
3533         barf_if_buffer_read_only(buf, begv, zv);
3534
3535         length = zv - begv;
3536
3537         input = make_lisp_buffer_input_stream(buf, begv, zv, 0);
3538         /* We need to allocate enough room for decoding the text. */
3539         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3540         decoded_length =
3541                 base64_decode_1(XLSTREAM(input), decoded, &cc_decoded_length);
3542         if (decoded_length > length * MAX_EMCHAR_LEN) {
3543                 abort();
3544         }
3545         Lstream_delete(XLSTREAM(input));
3546
3547         /* Now we have decoded the region, so we insert the new contents
3548            and delete the old.  (Insert first in order to preserve markers.)  */
3549         BUF_SET_PT(buf, begv);
3550         buffer_insert_raw_string_1(buf, begv, decoded, decoded_length, 0);
3551         XMALLOC_UNBIND(decoded, length * MAX_EMCHAR_LEN, speccount);
3552         buffer_delete_range(buf, begv + cc_decoded_length,
3553                             zv + cc_decoded_length, 0);
3554
3555         /* Simulate FSF Emacs implementation of this function: if point was
3556            in the region, place it at the beginning.  */
3557         if (old_pt >= begv && old_pt < zv) {
3558                 BUF_SET_PT(buf, begv);
3559         }
3560
3561         return make_int(cc_decoded_length);
3562 }
3563
3564 DEFUN("base64-decode-string", Fbase64_decode_string, 1, 1, 0,   /*
3565 Base64-decode STRING and return the result.
3566 Characters out of the base64 alphabet are ignored.
3567 */
3568       (string))
3569 {
3570         Bufbyte *decoded;
3571         Bytind decoded_length;
3572         Charcount length, cc_decoded_length;
3573         Lisp_Object input, result;
3574         int speccount = specpdl_depth();
3575
3576         CHECK_STRING(string);
3577
3578         length = XSTRING_CHAR_LENGTH(string);
3579         /* We need to allocate enough room for decoding the text. */
3580         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3581
3582         input = make_lisp_string_input_stream(string, 0, -1);
3583         decoded_length = base64_decode_1(XLSTREAM(input), decoded,
3584                                          &cc_decoded_length);
3585         if (decoded_length > length * MAX_EMCHAR_LEN) {
3586                 abort();
3587         }
3588         Lstream_delete(XLSTREAM(input));
3589
3590         result = make_string(decoded, decoded_length);
3591         XMALLOC_UNBIND(decoded, length * MAX_EMCHAR_LEN, speccount);
3592         return result;
3593 }
3594 \f
3595 /* base16 encode/decode functions. */
3596 static Bytind
3597 base16_encode_1(Lstream * istream, int length, Bufbyte * to, int max)
3598 {
3599         Emchar ec;
3600         int i, sz;
3601
3602         for (i=0; i < length; i++) {
3603                 ec = Lstream_get_emchar (istream);
3604                 sz = snprintf((char *)to+2*i, 3, "%02x", ec);
3605                 assert( sz >= 0 && sz < 3);
3606                 max -= sz;
3607                 assert(max >= 0);
3608         }
3609
3610         return 1;
3611 }
3612 static Bytind
3613 base16_decode_1(Lstream * istream, int length, Bufbyte * to)
3614 {
3615         Emchar ec;
3616         Emchar high = 0, low = 0;
3617         int high_set_p = 0, ignore_p = 0;
3618         int i = 0;
3619
3620         /* high and low perform flip flop operation */
3621         while (1) {
3622                 ec = Lstream_get_emchar (istream);
3623                 if (ec < 0)
3624                         break;
3625                 if (isdigit(ec))
3626                         low = ec - '0';
3627                 else if (isupper(ec))
3628                         low = ec - 'A' + 10;
3629                 else if (islower(ec))
3630                         low = ec - 'a' + 10;
3631                 else 
3632                         ignore_p = 1;
3633
3634                 if (low < 0 || low >= 16)
3635                         ignore_p = 1;
3636
3637                 if (!ignore_p) {
3638                         if (!high_set_p) {
3639                                 high = low;
3640                                 high_set_p = 1;
3641                         } else {
3642                                 to[i] = high*16+low;
3643                                 i++;
3644                                 high_set_p = 0;
3645                         }
3646                 } else
3647                         ignore_p = 0;
3648         }
3649
3650         return i;
3651 }
3652 DEFUN("base16-encode-string", Fbase16_encode_string, 1, 1, 0, /*
3653 Base16 encode (i.e. hex dump) STRING and return the result.
3654 Optional argument NO-LINE-BREAK means do not break long lines
3655 into shorter lines.
3656 */
3657       (string))
3658 {
3659         Charcount length;
3660         Bufbyte *encoded;
3661         Lisp_Object input, result;
3662         int sz;
3663         int speccount = specpdl_depth();
3664
3665         CHECK_STRING(string);
3666
3667         length = XSTRING_CHAR_LENGTH(string);
3668         sz = 2 * length;
3669         input = make_lisp_string_input_stream(string, 0, -1);
3670         XMALLOC_ATOMIC_OR_ALLOCA(encoded, sz+1, Bufbyte);
3671         base16_encode_1(XLSTREAM(input), length, encoded, sz);
3672         Lstream_delete(XLSTREAM(input));
3673         result = make_string(encoded, sz);
3674         XMALLOC_UNBIND(encoded, sz+1, speccount);
3675
3676         XSTRING(result)->plist = XSTRING(string)->plist;
3677
3678         return result;
3679 }
3680
3681 DEFUN("base16-decode-string", Fbase16_decode_string, 1, 1, 0, /*
3682 Base16-decode (i.e. read hex data from) STRING and return the result.
3683 Characters out of the base16 alphabet are ignored.
3684 */
3685       (string))
3686 {
3687         Bufbyte *decoded;
3688         Bytind decoded_length;
3689         Charcount length;
3690         Lisp_Object input, result;
3691         int speccount = specpdl_depth();
3692
3693         CHECK_STRING(string);
3694
3695         length = XSTRING_CHAR_LENGTH(string);
3696         /* We need to allocate enough room for decoding the text. */
3697         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length, Bufbyte);
3698
3699         input = make_lisp_string_input_stream(string, 0, -1);
3700         decoded_length = base16_decode_1(XLSTREAM(input), length, decoded);
3701         Lstream_delete(XLSTREAM(input));
3702
3703         /* this result might be raw, we declare it binary */
3704         result = make_ext_string((char *)decoded, decoded_length, Qbinary);
3705         XMALLOC_UNBIND(decoded, length, speccount);
3706
3707         XSTRING(result)->plist = XSTRING(string)->plist;
3708
3709         return result;
3710 }
3711 \f
3712 Lisp_Object Qyes_or_no_p;
3713
3714 DEFUN("foobar", Ffoobar, 2, 2, 0, /*
3715 */
3716       (n, b))
3717 {
3718         return make_int(__nbits_right_of(XINT(n), XINT(b)));
3719 }
3720
3721 void syms_of_fns(void)
3722 {
3723         INIT_LRECORD_IMPLEMENTATION(bit_vector);
3724
3725         defsymbol(&Qstring_lessp, "string-lessp");
3726         defsymbol(&Qstring_greaterp, "string-greaterp");
3727         defsymbol(&Qidentity, "identity");
3728         defsymbol(&Qyes_or_no_p, "yes-or-no-p");
3729
3730         DEFSUBR(Ffoobar);
3731
3732         DEFSUBR(Fidentity);
3733         DEFSUBR(Frandom);
3734 #if defined(WITH_GMP) && defined(HAVE_MPZ)
3735         DEFSUBR(Frandomb);
3736 #endif
3737         DEFSUBR(Flength);
3738         DEFSUBR(Fsafe_length);
3739         DEFSUBR(Fstring_equal);
3740         DEFSUBR(Fstring_lessp);
3741         DEFSUBR(Fstring_greaterp);
3742         DEFSUBR(Fstring_modified_tick);
3743         DEFSUBR(Fappend);
3744         DEFSUBR(Fconcat);
3745         DEFSUBR(Fvconcat);
3746         DEFSUBR(Fbvconcat);
3747         DEFSUBR(Fcopy_list);
3748         DEFSUBR(Fcopy_sequence);
3749         DEFSUBR(Fcopy_alist);
3750         DEFSUBR(Fcopy_tree);
3751         DEFSUBR(Fsubstring);
3752         DEFSUBR(Fsubseq);
3753         DEFSUBR(Fnthcdr);
3754         DEFSUBR(Fnth);
3755         DEFSUBR(Felt);
3756         DEFSUBR(Flast);
3757         DEFSUBR(Fbutlast);
3758         DEFSUBR(Fnbutlast);
3759         DEFSUBR(Fmember);
3760         DEFSUBR(Fold_member);
3761         DEFSUBR(Fmemq);
3762         DEFSUBR(Fold_memq);
3763         DEFSUBR(Fassoc);
3764         DEFSUBR(Fold_assoc);
3765         DEFSUBR(Fassq);
3766         DEFSUBR(Fold_assq);
3767         DEFSUBR(Frassoc);
3768         DEFSUBR(Fold_rassoc);
3769         DEFSUBR(Frassq);
3770         DEFSUBR(Fold_rassq);
3771         DEFSUBR(Fdelete);
3772         DEFSUBR(Fold_delete);
3773         DEFSUBR(Fdelq);
3774         DEFSUBR(Fold_delq);
3775         DEFSUBR(Fremassoc);
3776         DEFSUBR(Fremassq);
3777         DEFSUBR(Fremrassoc);
3778         DEFSUBR(Fremrassq);
3779         DEFSUBR(Fnreverse);
3780         DEFSUBR(Freverse);
3781         DEFSUBR(Fsort);
3782         DEFSUBR(Fplists_eq);
3783         DEFSUBR(Fplists_equal);
3784         DEFSUBR(Flax_plists_eq);
3785         DEFSUBR(Flax_plists_equal);
3786         DEFSUBR(Fplist_get);
3787         DEFSUBR(Fplist_put);
3788         DEFSUBR(Fplist_remprop);
3789         DEFSUBR(Fplist_member);
3790         DEFSUBR(Fcheck_valid_plist);
3791         DEFSUBR(Fvalid_plist_p);
3792         DEFSUBR(Fcanonicalize_plist);
3793         DEFSUBR(Flax_plist_get);
3794         DEFSUBR(Flax_plist_put);
3795         DEFSUBR(Flax_plist_remprop);
3796         DEFSUBR(Flax_plist_member);
3797         DEFSUBR(Fcanonicalize_lax_plist);
3798         DEFSUBR(Fdestructive_alist_to_plist);
3799         DEFSUBR(Fget);
3800         DEFSUBR(Fput);
3801         DEFSUBR(Fremprop);
3802         DEFSUBR(Fobject_plist);
3803         DEFSUBR(Fequal);
3804         DEFSUBR(Fold_equal);
3805         DEFSUBR(Ffillarray);
3806         DEFSUBR(Fnconc);
3807         DEFSUBR(Freplace_list);
3808         DEFSUBR(Fload_average);
3809         DEFSUBR(Ffeaturep);
3810         DEFSUBR(Frequire);
3811         DEFSUBR(Fprovide);
3812         DEFSUBR(Frevoke);
3813         DEFSUBR(Fbase64_encode_region);
3814         DEFSUBR(Fbase64_encode_string);
3815         DEFSUBR(Fbase64_decode_region);
3816         DEFSUBR(Fbase64_decode_string);
3817         DEFSUBR(Fbase16_encode_string);
3818         DEFSUBR(Fbase16_decode_string);
3819
3820 #if 1
3821         map_LTX_init();
3822 #endif
3823 }
3824
3825 void init_provide_once(void)
3826 {
3827         DEFVAR_LISP("features", &Vfeatures      /*
3828 A list of symbols which are the features of the executing emacs.
3829 Used by `featurep' and `require', and altered by `provide'.
3830                                                  */ );
3831         Vfeatures = Qnil;
3832
3833         Fprovide(intern("base64"));
3834         Fprovide(intern("base16"));
3835
3836 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
3837 /* it's fuck ugly to define that here :( */
3838         Fprovide(intern("bdwgc"));
3839 #endif
3840 }