Initial git import
[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                                 string_result_ptr +=
893                                     set_charptr_emchar(string_result_ptr,
894                                                        XCHAR(elt));
895                         }
896                 }
897                 if (args_mse) {
898                         args_mse[argnum].entry_offset =
899                             string_prev_result_ptr - string_result;
900                         args_mse[argnum].entry_length =
901                             string_result_ptr - string_prev_result_ptr;
902                 }
903         }
904
905         /* Now we finally make the string. */
906         if (target_type == c_string) {
907                 val =
908                     make_string(string_result,
909                                 string_result_ptr - string_result);
910                 for (argnum = 0; argnum < nargs; argnum++) {
911                         if (STRINGP(args_mse[argnum].string))
912                                 copy_string_extents(val,
913                                                     args_mse[argnum].string,
914                                                     args_mse[argnum].
915                                                     entry_offset, 0,
916                                                     args_mse[argnum].
917                                                     entry_length);
918                 }
919                 XMALLOC_UNBIND(string_result,
920                                total_length * MAX_EMCHAR_LEN, speccount);
921                 XMALLOC_UNBIND(args_mse, nargs, speccount);
922         }
923
924         if (!NILP(prev))
925                 XCDR(prev) = last_tail;
926
927         RETURN_UNGCPRO(val);
928 }
929 \f
930 DEFUN("copy-alist", Fcopy_alist, 1, 1, 0,       /*
931 Return a copy of ALIST.
932 This is an alist which represents the same mapping from objects to objects,
933 but does not share the alist structure with ALIST.
934 The objects mapped (cars and cdrs of elements of the alist)
935 are shared, however.
936 Elements of ALIST that are not conses are also shared.
937 */
938       (alist))
939 {
940         Lisp_Object tail;
941
942         if (NILP(alist))
943                 return alist;
944         CHECK_CONS(alist);
945
946         alist = concat(1, &alist, c_cons, 0);
947         for (tail = alist; CONSP(tail); tail = XCDR(tail)) {
948                 Lisp_Object car = XCAR(tail);
949
950                 if (CONSP(car))
951                         XCAR(tail) = Fcons(XCAR(car), XCDR(car));
952         }
953         return alist;
954 }
955
956 DEFUN("copy-tree", Fcopy_tree, 1, 2, 0, /*
957 Return a copy of a list and substructures.
958 The argument is copied, and any lists contained within it are copied
959 recursively.  Circularities and shared substructures are not preserved.
960 Second arg VECP causes vectors to be copied, too.  Strings and bit vectors
961 are not copied.
962 */
963       (arg, vecp))
964 {
965         return safe_copy_tree(arg, vecp, 0);
966 }
967
968 Lisp_Object safe_copy_tree(Lisp_Object arg, Lisp_Object vecp, int depth)
969 {
970         if (depth > 200)
971                 signal_simple_error("Stack overflow in copy-tree", arg);
972
973         if (CONSP(arg)) {
974                 Lisp_Object rest;
975                 rest = arg = Fcopy_sequence(arg);
976                 while (CONSP(rest)) {
977                         Lisp_Object elt = XCAR(rest);
978                         QUIT;
979                         if (CONSP(elt) || VECTORP(elt))
980                                 XCAR(rest) =
981                                     safe_copy_tree(elt, vecp, depth + 1);
982                         if (VECTORP(XCDR(rest)))        /* hack for (a b . [c d]) */
983                                 XCDR(rest) =
984                                     safe_copy_tree(XCDR(rest), vecp, depth + 1);
985                         rest = XCDR(rest);
986                 }
987         } else if (VECTORP(arg) && !NILP(vecp)) {
988                 int i = XVECTOR_LENGTH(arg);
989                 int j;
990                 arg = Fcopy_sequence(arg);
991                 for (j = 0; j < i; j++) {
992                         Lisp_Object elt = XVECTOR_DATA(arg)[j];
993                         QUIT;
994                         if (CONSP(elt) || VECTORP(elt))
995                                 XVECTOR_DATA(arg)[j] =
996                                     safe_copy_tree(elt, vecp, depth + 1);
997                 }
998         }
999         return arg;
1000 }
1001
1002 DEFUN("substring", Fsubstring, 2, 3, 0, /*
1003 Return the substring of STRING starting at START and ending before END.
1004 END may be nil or omitted; then the substring runs to the end of STRING.
1005 If START or END is negative, it counts from the end.
1006 Relevant parts of the string-extent-data are copied to the new string.
1007 */
1008       (string, start, end)) 
1009 {
1010         Charcount ccstart, ccend;
1011         Bytecount bstart, blen;
1012         Lisp_Object val;
1013
1014         CHECK_STRING(string);
1015         CHECK_INT(start);
1016         get_string_range_char(string, start, end, &ccstart, &ccend,
1017                               GB_HISTORICAL_STRING_BEHAVIOR);
1018         bstart = charcount_to_bytecount(XSTRING_DATA(string), ccstart);
1019         blen =
1020             charcount_to_bytecount(XSTRING_DATA(string) + bstart,
1021                                    ccend - ccstart);
1022         val = make_string(XSTRING_DATA(string) + bstart, blen);
1023         /* Copy any applicable extent information into the new string. */
1024         copy_string_extents(val, string, 0, bstart, blen);
1025         return val;
1026 }
1027
1028 DEFUN("subseq", Fsubseq, 2, 3, 0,       /*
1029 Return the subsequence of SEQUENCE starting at START and ending before END.
1030 END may be omitted; then the subsequence runs to the end of SEQUENCE.
1031 If START or END is negative, it counts from the end.
1032 The returned subsequence is always of the same type as SEQUENCE.
1033 If SEQUENCE is a string, relevant parts of the string-extent-data
1034 are copied to the new string.
1035 */
1036       (sequence, start, end))
1037 {
1038         EMACS_INT len, s, e;
1039
1040         if (STRINGP(sequence))
1041                 return Fsubstring(sequence, start, end);
1042
1043         len = XINT(Flength(sequence));
1044
1045         CHECK_INT(start);
1046         s = XINT(start);
1047         if (s < 0)
1048                 s = len + s;
1049
1050         if (NILP(end))
1051                 e = len;
1052         else {
1053                 CHECK_INT(end);
1054                 e = XINT(end);
1055                 if (e < 0)
1056                         e = len + e;
1057         }
1058
1059         if (!(0 <= s && s <= e && e <= len))
1060                 args_out_of_range_3(sequence, make_int(s), make_int(e));
1061
1062         if (VECTORP(sequence)) {
1063                 Lisp_Object result = make_vector(e - s, Qnil);
1064                 EMACS_INT i;
1065                 Lisp_Object *in_elts = XVECTOR_DATA(sequence);
1066                 Lisp_Object *out_elts = XVECTOR_DATA(result);
1067
1068                 for (i = s; i < e; i++)
1069                         out_elts[i - s] = in_elts[i];
1070                 return result;
1071         } else if (LISTP(sequence)) {
1072                 Lisp_Object result = Qnil;
1073                 EMACS_INT i;
1074
1075                 sequence = Fnthcdr(make_int(s), sequence);
1076
1077                 for (i = s; i < e; i++) {
1078                         result = Fcons(Fcar(sequence), result);
1079                         sequence = Fcdr(sequence);
1080                 }
1081
1082                 return Fnreverse(result);
1083         } else if (BIT_VECTORP(sequence)) {
1084                 Lisp_Object result = make_bit_vector(e - s, Qzero);
1085                 EMACS_INT i;
1086
1087                 for (i = s; i < e; i++)
1088                         set_bit_vector_bit(XBIT_VECTOR(result), i - s,
1089                                            bit_vector_bit(XBIT_VECTOR(sequence),
1090                                                           i));
1091                 return result;
1092         } else {
1093                 abort();        /* unreachable, since Flength (sequence) did not get
1094                                    an error */
1095                 return Qnil;
1096         }
1097 }
1098 \f
1099 DEFUN("nthcdr", Fnthcdr, 2, 2, 0,       /*
1100 Take cdr N times on LIST, and return the result.
1101 */
1102       (n, list))
1103 {
1104         REGISTER size_t i;
1105         REGISTER Lisp_Object tail = list;
1106         CHECK_NATNUM(n);
1107         for (i = XINT(n); i; i--) {
1108                 if (CONSP(tail))
1109                         tail = XCDR(tail);
1110                 else if (NILP(tail))
1111                         return Qnil;
1112                 else {
1113                         tail = wrong_type_argument(Qlistp, tail);
1114                         i++;
1115                 }
1116         }
1117         return tail;
1118 }
1119
1120 DEFUN("nth", Fnth, 2, 2, 0,     /*
1121 Return the Nth element of LIST.
1122 N counts from zero.  If LIST is not that long, nil is returned.
1123 */
1124       (n, list))
1125 {
1126         return Fcar(Fnthcdr(n, list));
1127 }
1128
1129 DEFUN("elt", Felt, 2, 2, 0,     /*
1130 Return element of SEQUENCE at index N.
1131 */
1132       (sequence, n))
1133 {
1134 retry:
1135         if (!(INTP(n) || CHARP(n))) {
1136                 n = wrong_type_argument(Qinteger_or_char_p, n);
1137                 goto retry;
1138         }
1139
1140         if (LISTP(sequence)) {
1141                 Lisp_Object tem = Fnthcdr(n, sequence);
1142                 /* #### Utterly, completely, fucking disgusting.
1143                  * #### The whole point of "elt" is that it operates on
1144                  * #### sequences, and does error- (bounds-) checking.
1145                  */
1146                 if (CONSP(tem))
1147                         return XCAR(tem);
1148                 else
1149 #if 1
1150                         /* This is The Way It Has Always Been. */
1151                         return Qnil;
1152 #else
1153                         /* This is The Way Mly and Cltl2 say It Should Be. */
1154                         args_out_of_range(sequence, n);
1155 #endif
1156         } else if (DLLISTP(sequence)) {
1157                 dllist_item_t elm = NULL;
1158                 int rev = 0;
1159                 REGISTER size_t i;
1160                 EMACS_INT rn = ent_int(n);
1161
1162                 if (rn < 0) {
1163                         args_out_of_range(sequence, n);
1164                         return Qnil;
1165                 }
1166
1167                 if (rn * 2 < (EMACS_INT)XDLLIST_SIZE(sequence)) {
1168                         /* start at the front */
1169                         elm = XDLLIST_FIRST(sequence);
1170                         i = rn;
1171                 } else {
1172                         /* start at the end */
1173                         elm = XDLLIST_LAST(sequence);
1174                         rev = 1;
1175                         i = XDLLIST_SIZE(sequence) - rn - 1;
1176                 }
1177
1178                 for (; i > 0 && elm != NULL; i--)
1179                         if (rev == 0)
1180                                 elm = elm->next;
1181                         else
1182                                 elm = elm->prev;
1183
1184                 if (elm)
1185                         return (Lisp_Object)elm->item;
1186                 else
1187                         return Qnil;
1188
1189         } else if (STRINGP(sequence) ||
1190                    VECTORP(sequence) || BIT_VECTORP(sequence))
1191                 return Faref(sequence, n);
1192 #ifdef LOSING_BYTECODE
1193         else if (COMPILED_FUNCTIONP(sequence)) {
1194                 EMACS_INT idx = ent_int(n);
1195                 if (idx < 0) {
1196                       lose:
1197                         args_out_of_range(sequence, n);
1198                 }
1199                 /* Utter perversity */
1200                 {
1201                         Lisp_Compiled_Function *f =
1202                             XCOMPILED_FUNCTION(sequence);
1203                         switch (idx) {
1204                         case COMPILED_ARGLIST:
1205                                 return compiled_function_arglist(f);
1206                         case COMPILED_INSTRUCTIONS:
1207                                 return compiled_function_instructions(f);
1208                         case COMPILED_CONSTANTS:
1209                                 return compiled_function_constants(f);
1210                         case COMPILED_STACK_DEPTH:
1211                                 return compiled_function_stack_depth(f);
1212                         case COMPILED_DOC_STRING:
1213                                 return compiled_function_documentation(f);
1214                         case COMPILED_DOMAIN:
1215                                 return compiled_function_domain(f);
1216                         case COMPILED_INTERACTIVE:
1217                                 if (f->flags.interactivep)
1218                                         return compiled_function_interactive(f);
1219                                 /* if we return nil, can't tell interactive with no args
1220                                    from noninteractive. */
1221                                 goto lose;
1222                         default:
1223                                 goto lose;
1224                         }
1225                 }
1226         }
1227 #endif                          /* LOSING_BYTECODE */
1228         else {
1229                 check_losing_bytecode("elt", sequence);
1230                 sequence = wrong_type_argument(Qsequencep, sequence);
1231                 goto retry;
1232         }
1233 }
1234
1235 DEFUN("last", Flast, 1, 2, 0,   /*
1236 Return the tail of list LIST, of length N (default 1).
1237 LIST may be a dotted list, but not a circular list.
1238 Optional argument N must be a non-negative integer.
1239 If N is zero, then the atom that terminates the list is returned.
1240 If N is greater than the length of LIST, then LIST itself is returned.
1241 */
1242       (list, n))
1243 {
1244         EMACS_INT int_n, count;
1245         Lisp_Object retval, tortoise, hare;
1246
1247         if (DLLISTP(list))
1248                 return Fdllist_rac(list);
1249
1250         CHECK_LIST(list);
1251
1252         if (NILP(n))
1253                 int_n = 1;
1254         else {
1255                 CHECK_NATNUM(n);
1256                 int_n = XINT(n);
1257         }
1258
1259         for (retval = tortoise = hare = list, count = 0;
1260              CONSP(hare);
1261              hare = XCDR(hare),
1262              (int_n-- <= 0 ? ((void)(retval = XCDR(retval))) : (void)0),
1263              count++) {
1264                 if (count < CIRCULAR_LIST_SUSPICION_LENGTH)
1265                         continue;
1266
1267                 if (count & 1)
1268                         tortoise = XCDR(tortoise);
1269                 if (EQ(hare, tortoise))
1270                         signal_circular_list_error(list);
1271         }
1272
1273         return retval;
1274 }
1275
1276 DEFUN("nbutlast", Fnbutlast, 1, 2, 0,   /*
1277 Modify LIST to remove the last N (default 1) elements.
1278 If LIST has N or fewer elements, nil is returned and LIST is unmodified.
1279 */
1280       (list, n))
1281 {
1282         EMACS_INT int_n;
1283
1284         CHECK_LIST(list);
1285
1286         if (NILP(n))
1287                 int_n = 1;
1288         else {
1289                 CHECK_NATNUM(n);
1290                 int_n = XINT(n);
1291         }
1292
1293         {
1294                 Lisp_Object last_cons = list;
1295
1296                 EXTERNAL_LIST_LOOP_1(list) {
1297                         if (int_n-- < 0)
1298                                 last_cons = XCDR(last_cons);
1299                 }
1300
1301                 if (int_n >= 0)
1302                         return Qnil;
1303
1304                 XCDR(last_cons) = Qnil;
1305                 return list;
1306         }
1307 }
1308
1309 DEFUN("butlast", Fbutlast, 1, 2, 0,     /*
1310 Return a copy of LIST with the last N (default 1) elements removed.
1311 If LIST has N or fewer elements, nil is returned.
1312 */
1313       (list, n))
1314 {
1315         EMACS_INT int_n;
1316
1317         CHECK_LIST(list);
1318
1319         if (NILP(n))
1320                 int_n = 1;
1321         else {
1322                 CHECK_NATNUM(n);
1323                 int_n = XINT(n);
1324         }
1325
1326         {
1327                 Lisp_Object retval = Qnil;
1328                 Lisp_Object tail = list;
1329
1330                 EXTERNAL_LIST_LOOP_1(list) {
1331                         if (--int_n < 0) {
1332                                 retval = Fcons(XCAR(tail), retval);
1333                                 tail = XCDR(tail);
1334                         }
1335                 }
1336
1337                 return Fnreverse(retval);
1338         }
1339 }
1340
1341 DEFUN("member", Fmember, 2, 2, 0,       /*
1342 Return non-nil if ELT is an element of LIST.  Comparison done with `equal'.
1343 The value is actually the tail of LIST whose car is ELT.
1344 */
1345       (elt, list))
1346 {
1347         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1348                 if (internal_equal(elt, list_elt, 0))
1349                         return tail;
1350         }
1351         return Qnil;
1352 }
1353
1354 DEFUN("old-member", Fold_member, 2, 2, 0,       /*
1355 Return non-nil if ELT is an element of LIST.  Comparison done with `old-equal'.
1356 The value is actually the tail of LIST whose car is ELT.
1357 This function is provided only for byte-code compatibility with v19.
1358 Do not use it.
1359 */
1360       (elt, list))
1361 {
1362         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1363                 if (internal_old_equal(elt, list_elt, 0))
1364                         return tail;
1365         }
1366         return Qnil;
1367 }
1368
1369 DEFUN("memq", Fmemq, 2, 2, 0,   /*
1370 Return non-nil if ELT is an element of LIST.  Comparison done with `eq'.
1371 The value is actually the tail of LIST whose car is ELT.
1372 */
1373       (elt, list))
1374 {
1375         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1376                 if (EQ_WITH_EBOLA_NOTICE(elt, list_elt))
1377                         return tail;
1378         }
1379         return Qnil;
1380 }
1381
1382 DEFUN("old-memq", Fold_memq, 2, 2, 0,   /*
1383 Return non-nil if ELT is an element of LIST.  Comparison done with `old-eq'.
1384 The value is actually the tail of LIST whose car is ELT.
1385 This function is provided only for byte-code compatibility with v19.
1386 Do not use it.
1387 */
1388       (elt, list))
1389 {
1390         EXTERNAL_LIST_LOOP_3(list_elt, list, tail) {
1391                 if (HACKEQ_UNSAFE(elt, list_elt))
1392                         return tail;
1393         }
1394         return Qnil;
1395 }
1396
1397 Lisp_Object memq_no_quit(Lisp_Object elt, Lisp_Object list)
1398 {
1399         LIST_LOOP_3(list_elt, list, tail) {
1400                 if (EQ_WITH_EBOLA_NOTICE(elt, list_elt))
1401                         return tail;
1402         }
1403         return Qnil;
1404 }
1405
1406 DEFUN("assoc", Fassoc, 2, 2, 0, /*
1407 Return non-nil if KEY is `equal' to the car of an element of ALIST.
1408 The value is actually the element of ALIST whose car equals KEY.
1409 */
1410       (key, alist))
1411 {
1412         /* This function can GC. */
1413         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1414                 if (internal_equal(key, elt_car, 0))
1415                         return elt;
1416         }
1417         return Qnil;
1418 }
1419
1420 DEFUN("old-assoc", Fold_assoc, 2, 2, 0, /*
1421 Return non-nil if KEY is `old-equal' to the car of an element of ALIST.
1422 The value is actually the element of ALIST whose car equals KEY.
1423 */
1424       (key, alist))
1425 {
1426         /* This function can GC. */
1427         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1428                 if (internal_old_equal(key, elt_car, 0))
1429                         return elt;
1430         }
1431         return Qnil;
1432 }
1433
1434 Lisp_Object assoc_no_quit(Lisp_Object key, Lisp_Object alist)
1435 {
1436         int speccount = specpdl_depth();
1437         specbind(Qinhibit_quit, Qt);
1438         return unbind_to(speccount, Fassoc(key, alist));
1439 }
1440
1441 DEFUN("assq", Fassq, 2, 2, 0,   /*
1442 Return non-nil if KEY is `eq' to the car of an element of ALIST.
1443 The value is actually the element of ALIST whose car is KEY.
1444 Elements of ALIST that are not conses are ignored.
1445 */
1446       (key, alist))
1447 {
1448         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1449                 if (EQ_WITH_EBOLA_NOTICE(key, elt_car))
1450                         return elt;
1451         }
1452         return Qnil;
1453 }
1454
1455 DEFUN("old-assq", Fold_assq, 2, 2, 0,   /*
1456 Return non-nil if KEY is `old-eq' to the car of an element of ALIST.
1457 The value is actually the element of ALIST whose car is KEY.
1458 Elements of ALIST that are not conses are ignored.
1459 This function is provided only for byte-code compatibility with v19.
1460 Do not use it.
1461 */
1462       (key, alist))
1463 {
1464         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1465                 if (HACKEQ_UNSAFE(key, elt_car))
1466                         return elt;
1467         }
1468         return Qnil;
1469 }
1470
1471 /* Like Fassq but never report an error and do not allow quits.
1472    Use only on lists known never to be circular.  */
1473
1474 Lisp_Object assq_no_quit(Lisp_Object key, Lisp_Object alist)
1475 {
1476         /* This cannot GC. */
1477         LIST_LOOP_2(elt, alist) {
1478                 Lisp_Object elt_car = XCAR(elt);
1479                 if (EQ_WITH_EBOLA_NOTICE(key, elt_car))
1480                         return elt;
1481         }
1482         return Qnil;
1483 }
1484
1485 DEFUN("rassoc", Frassoc, 2, 2, 0,       /*
1486 Return non-nil if VALUE is `equal' to the cdr of an element of ALIST.
1487 The value is actually the element of ALIST whose cdr equals VALUE.
1488 */
1489       (value, alist))
1490 {
1491         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1492                 if (internal_equal(value, elt_cdr, 0))
1493                         return elt;
1494         }
1495         return Qnil;
1496 }
1497
1498 DEFUN("old-rassoc", Fold_rassoc, 2, 2, 0,       /*
1499 Return non-nil if VALUE is `old-equal' to the cdr of an element of ALIST.
1500 The value is actually the element of ALIST whose cdr equals VALUE.
1501 */
1502       (value, alist))
1503 {
1504         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1505                 if (internal_old_equal(value, elt_cdr, 0))
1506                         return elt;
1507         }
1508         return Qnil;
1509 }
1510
1511 DEFUN("rassq", Frassq, 2, 2, 0, /*
1512 Return non-nil if VALUE is `eq' to the cdr of an element of ALIST.
1513 The value is actually the element of ALIST whose cdr is VALUE.
1514 */
1515       (value, alist))
1516 {
1517         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1518                 if (EQ_WITH_EBOLA_NOTICE(value, elt_cdr))
1519                         return elt;
1520         }
1521         return Qnil;
1522 }
1523
1524 DEFUN("old-rassq", Fold_rassq, 2, 2, 0, /*
1525 Return non-nil if VALUE is `old-eq' to the cdr of an element of ALIST.
1526 The value is actually the element of ALIST whose cdr is VALUE.
1527 */
1528       (value, alist))
1529 {
1530         EXTERNAL_ALIST_LOOP_4(elt, elt_car, elt_cdr, alist) {
1531                 if (HACKEQ_UNSAFE(value, elt_cdr))
1532                         return elt;
1533         }
1534         return Qnil;
1535 }
1536
1537 /* Like Frassq, but caller must ensure that ALIST is properly
1538    nil-terminated and ebola-free. */
1539 Lisp_Object rassq_no_quit(Lisp_Object value, Lisp_Object alist)
1540 {
1541         LIST_LOOP_2(elt, alist) {
1542                 Lisp_Object elt_cdr = XCDR(elt);
1543                 if (EQ_WITH_EBOLA_NOTICE(value, elt_cdr))
1544                         return elt;
1545         }
1546         return Qnil;
1547 }
1548 \f
1549 DEFUN("delete", Fdelete, 2, 2, 0,       /*
1550 Delete by side effect any occurrences of ELT as a member of LIST.
1551 The modified LIST is returned.  Comparison is done with `equal'.
1552 If the first member of LIST is ELT, there is no way to remove it by side
1553 effect; therefore, write `(setq foo (delete element foo))' to be sure
1554 of changing the value of `foo'.
1555 Also see: `remove'.
1556 */
1557       (elt, list))
1558 {
1559         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1560                                      (internal_equal(elt, list_elt, 0)));
1561         return list;
1562 }
1563
1564 DEFUN("old-delete", Fold_delete, 2, 2, 0,       /*
1565 Delete by side effect any occurrences of ELT as a member of LIST.
1566 The modified LIST is returned.  Comparison is done with `old-equal'.
1567 If the first member of LIST is ELT, there is no way to remove it by side
1568 effect; therefore, write `(setq foo (old-delete element foo))' to be sure
1569 of changing the value of `foo'.
1570 */
1571       (elt, list))
1572 {
1573         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1574                                      (internal_old_equal(elt, list_elt, 0)));
1575         return list;
1576 }
1577
1578 DEFUN("delq", Fdelq, 2, 2, 0,   /*
1579 Delete by side effect any occurrences of ELT as a member of LIST.
1580 The modified LIST is returned.  Comparison is done with `eq'.
1581 If the first member of LIST is ELT, there is no way to remove it by side
1582 effect; therefore, write `(setq foo (delq element foo))' to be sure of
1583 changing the value of `foo'.
1584 */
1585       (elt, list))
1586 {
1587         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1588                                      (EQ_WITH_EBOLA_NOTICE(elt, list_elt)));
1589         return list;
1590 }
1591
1592 DEFUN("old-delq", Fold_delq, 2, 2, 0,   /*
1593 Delete by side effect any occurrences of ELT as a member of LIST.
1594 The modified LIST is returned.  Comparison is done with `old-eq'.
1595 If the first member of LIST is ELT, there is no way to remove it by side
1596 effect; therefore, write `(setq foo (old-delq element foo))' to be sure of
1597 changing the value of `foo'.
1598 */
1599       (elt, list))
1600 {
1601         EXTERNAL_LIST_LOOP_DELETE_IF(list_elt, list,
1602                                      (HACKEQ_UNSAFE(elt, list_elt)));
1603         return list;
1604 }
1605
1606 /* Like Fdelq, but caller must ensure that LIST is properly
1607    nil-terminated and ebola-free. */
1608
1609 Lisp_Object delq_no_quit(Lisp_Object elt, Lisp_Object list)
1610 {
1611         LIST_LOOP_DELETE_IF(list_elt, list,
1612                             (EQ_WITH_EBOLA_NOTICE(elt, list_elt)));
1613         return list;
1614 }
1615
1616 /* Be VERY careful with this.  This is like delq_no_quit() but
1617    also calls free_cons() on the removed conses.  You must be SURE
1618    that no pointers to the freed conses remain around (e.g.
1619    someone else is pointing to part of the list).  This function
1620    is useful on internal lists that are used frequently and where
1621    the actual list doesn't escape beyond known code bounds. */
1622
1623 Lisp_Object delq_no_quit_and_free_cons(Lisp_Object elt, Lisp_Object list)
1624 {
1625         REGISTER Lisp_Object tail = list;
1626         REGISTER Lisp_Object prev = Qnil;
1627
1628         while (!NILP(tail)) {
1629                 REGISTER Lisp_Object tem = XCAR(tail);
1630                 if (EQ(elt, tem)) {
1631                         Lisp_Object cons_to_free = tail;
1632                         if (NILP(prev))
1633                                 list = XCDR(tail);
1634                         else
1635                                 XCDR(prev) = XCDR(tail);
1636                         tail = XCDR(tail);
1637                         free_cons(XCONS(cons_to_free));
1638                 } else {
1639                         prev = tail;
1640                         tail = XCDR(tail);
1641                 }
1642         }
1643         return list;
1644 }
1645
1646 DEFUN("remassoc", Fremassoc, 2, 2, 0,   /*
1647 Delete by side effect any elements of ALIST whose car is `equal' to KEY.
1648 The modified ALIST is returned.  If the first member of ALIST has a car
1649 that is `equal' to KEY, there is no way to remove it by side effect;
1650 therefore, write `(setq foo (remassoc key foo))' to be sure of changing
1651 the value of `foo'.
1652 */
1653       (key, alist))
1654 {
1655         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1656                                      (CONSP(elt) &&
1657                                       internal_equal(key, XCAR(elt), 0)));
1658         return alist;
1659 }
1660
1661 Lisp_Object remassoc_no_quit(Lisp_Object key, Lisp_Object alist)
1662 {
1663         int speccount = specpdl_depth();
1664         specbind(Qinhibit_quit, Qt);
1665         return unbind_to(speccount, Fremassoc(key, alist));
1666 }
1667
1668 DEFUN("remassq", Fremassq, 2, 2, 0,     /*
1669 Delete by side effect any elements of ALIST whose car is `eq' to KEY.
1670 The modified ALIST is returned.  If the first member of ALIST has a car
1671 that is `eq' to KEY, there is no way to remove it by side effect;
1672 therefore, write `(setq foo (remassq key foo))' to be sure of changing
1673 the value of `foo'.
1674 */
1675       (key, alist))
1676 {
1677         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1678                                      (CONSP(elt) &&
1679                                       EQ_WITH_EBOLA_NOTICE(key, XCAR(elt))));
1680         return alist;
1681 }
1682
1683 /* no quit, no errors; be careful */
1684
1685 Lisp_Object remassq_no_quit(Lisp_Object key, Lisp_Object alist)
1686 {
1687         LIST_LOOP_DELETE_IF(elt, alist,
1688                             (CONSP(elt) &&
1689                              EQ_WITH_EBOLA_NOTICE(key, XCAR(elt))));
1690         return alist;
1691 }
1692
1693 DEFUN("remrassoc", Fremrassoc, 2, 2, 0, /*
1694 Delete by side effect any elements of ALIST whose cdr is `equal' to VALUE.
1695 The modified ALIST is returned.  If the first member of ALIST has a car
1696 that is `equal' to VALUE, there is no way to remove it by side effect;
1697 therefore, write `(setq foo (remrassoc value foo))' to be sure of changing
1698 the value of `foo'.
1699 */
1700       (value, alist))
1701 {
1702         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1703                                      (CONSP(elt) &&
1704                                       internal_equal(value, XCDR(elt), 0)));
1705         return alist;
1706 }
1707
1708 DEFUN("remrassq", Fremrassq, 2, 2, 0,   /*
1709 Delete by side effect any elements of ALIST whose cdr is `eq' to VALUE.
1710 The modified ALIST is returned.  If the first member of ALIST has a car
1711 that is `eq' to VALUE, there is no way to remove it by side effect;
1712 therefore, write `(setq foo (remrassq value foo))' to be sure of changing
1713 the value of `foo'.
1714 */
1715       (value, alist))
1716 {
1717         EXTERNAL_LIST_LOOP_DELETE_IF(elt, alist,
1718                                      (CONSP(elt) &&
1719                                       EQ_WITH_EBOLA_NOTICE(value, XCDR(elt))));
1720         return alist;
1721 }
1722
1723 /* Like Fremrassq, fast and unsafe; be careful */
1724 Lisp_Object remrassq_no_quit(Lisp_Object value, Lisp_Object alist)
1725 {
1726         LIST_LOOP_DELETE_IF(elt, alist,
1727                             (CONSP(elt) &&
1728                              EQ_WITH_EBOLA_NOTICE(value, XCDR(elt))));
1729         return alist;
1730 }
1731
1732 DEFUN("nreverse", Fnreverse, 1, 1, 0,   /*
1733 Reverse LIST by destructively modifying cdr pointers.
1734 Return the beginning of the reversed list.
1735 Also see: `reverse'.
1736 */
1737       (list))
1738 {
1739         struct gcpro gcpro1, gcpro2;
1740         REGISTER Lisp_Object prev = Qnil;
1741         REGISTER Lisp_Object tail = list;
1742
1743         /* We gcpro our args; see `nconc' */
1744         GCPRO2(prev, tail);
1745         while (!NILP(tail)) {
1746                 REGISTER Lisp_Object next;
1747                 CONCHECK_CONS(tail);
1748                 next = XCDR(tail);
1749                 XCDR(tail) = prev;
1750                 prev = tail;
1751                 tail = next;
1752         }
1753         UNGCPRO;
1754         return prev;
1755 }
1756
1757 DEFUN("reverse", Freverse, 1, 1, 0,     /*
1758 Reverse LIST, copying.  Return the beginning of the reversed list.
1759 See also the function `nreverse', which is used more often.
1760 */
1761       (list))
1762 {
1763         Lisp_Object reversed_list = Qnil;
1764         EXTERNAL_LIST_LOOP_2(elt, list) {
1765                 reversed_list = Fcons(elt, reversed_list);
1766         }
1767         return reversed_list;
1768 }
1769 \f
1770 static Lisp_Object list_merge(Lisp_Object org_l1, Lisp_Object org_l2,
1771                               Lisp_Object lisp_arg,
1772                               int (*pred_fn) (Lisp_Object, Lisp_Object,
1773                                               Lisp_Object lisp_arg));
1774
1775 Lisp_Object
1776 list_sort(Lisp_Object list,
1777           Lisp_Object lisp_arg,
1778           int (*pred_fn) (Lisp_Object, Lisp_Object, Lisp_Object lisp_arg))
1779 {
1780         struct gcpro gcpro1, gcpro2, gcpro3;
1781         Lisp_Object back, tem;
1782         Lisp_Object front = list;
1783         Lisp_Object len = Flength(list);
1784
1785         if (XINT(len) < 2)
1786                 return list;
1787
1788         len = make_int(XINT(len) / 2 - 1);
1789         tem = Fnthcdr(len, list);
1790         back = Fcdr(tem);
1791         Fsetcdr(tem, Qnil);
1792
1793         GCPRO3(front, back, lisp_arg);
1794         front = list_sort(front, lisp_arg, pred_fn);
1795         back = list_sort(back, lisp_arg, pred_fn);
1796         UNGCPRO;
1797         return list_merge(front, back, lisp_arg, pred_fn);
1798 }
1799 \f
1800 static int
1801 merge_pred_function(Lisp_Object obj1, Lisp_Object obj2, Lisp_Object pred)
1802 {
1803         Lisp_Object tmp;
1804
1805         /* prevents the GC from happening in call2 */
1806         int speccount = specpdl_depth();
1807 /* Emacs' GC doesn't actually relocate pointers, so this probably
1808    isn't strictly necessary */
1809         record_unwind_protect(restore_gc_inhibit,
1810                               make_int(gc_currently_forbidden));
1811         gc_currently_forbidden = 1;
1812         tmp = call2(pred, obj1, obj2);
1813         unbind_to(speccount, Qnil);
1814
1815         if (NILP(tmp))
1816                 return -1;
1817         else
1818                 return 1;
1819 }
1820
1821 DEFUN("sort", Fsort, 2, 2, 0,   /*
1822 Sort LIST, stably, comparing elements using PREDICATE.
1823 Returns the sorted list.  LIST is modified by side effects.
1824 PREDICATE is called with two elements of LIST, and should return T
1825 if the first element is "less" than the second.
1826 */
1827       (list, predicate))
1828 {
1829         return list_sort(list, predicate, merge_pred_function);
1830 }
1831
1832 Lisp_Object merge(Lisp_Object org_l1, Lisp_Object org_l2, Lisp_Object pred)
1833 {
1834         return list_merge(org_l1, org_l2, pred, merge_pred_function);
1835 }
1836
1837 static Lisp_Object
1838 list_merge(Lisp_Object org_l1, Lisp_Object org_l2,
1839            Lisp_Object lisp_arg,
1840            int (*pred_fn) (Lisp_Object, Lisp_Object, Lisp_Object lisp_arg))
1841 {
1842         Lisp_Object value;
1843         Lisp_Object tail;
1844         Lisp_Object tem;
1845         Lisp_Object l1, l2;
1846         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1847
1848         l1 = org_l1;
1849         l2 = org_l2;
1850         tail = Qnil;
1851         value = Qnil;
1852
1853         /* It is sufficient to protect org_l1 and org_l2.
1854            When l1 and l2 are updated, we copy the new values
1855            back into the org_ vars.  */
1856
1857         GCPRO4(org_l1, org_l2, lisp_arg, value);
1858
1859         while (1) {
1860                 if (NILP(l1)) {
1861                         UNGCPRO;
1862                         if (NILP(tail))
1863                                 return l2;
1864                         Fsetcdr(tail, l2);
1865                         return value;
1866                 }
1867                 if (NILP(l2)) {
1868                         UNGCPRO;
1869                         if (NILP(tail))
1870                                 return l1;
1871                         Fsetcdr(tail, l1);
1872                         return value;
1873                 }
1874
1875                 if (((*pred_fn) (Fcar(l2), Fcar(l1), lisp_arg)) < 0) {
1876                         tem = l1;
1877                         l1 = Fcdr(l1);
1878                         org_l1 = l1;
1879                 } else {
1880                         tem = l2;
1881                         l2 = Fcdr(l2);
1882                         org_l2 = l2;
1883                 }
1884                 if (NILP(tail))
1885                         value = tem;
1886                 else
1887                         Fsetcdr(tail, tem);
1888                 tail = tem;
1889         }
1890 }
1891 \f
1892 /************************************************************************/
1893 /*                      property-list functions                         */
1894 /************************************************************************/
1895
1896 /* For properties of text, we need to do order-insensitive comparison of
1897    plists.  That is, we need to compare two plists such that they are the
1898    same if they have the same set of keys, and equivalent values.
1899    So (a 1 b 2) would be equal to (b 2 a 1).
1900
1901    NIL_MEANS_NOT_PRESENT is as in `plists-eq' etc.
1902    LAXP means use `equal' for comparisons.
1903  */
1904 int
1905 plists_differ(Lisp_Object a, Lisp_Object b, int nil_means_not_present,
1906               int laxp, int depth)
1907 {
1908         int eqp = (depth == -1);        /* -1 as depth means use eq, not equal. */
1909         int la, lb, m, i, fill;
1910         Lisp_Object *keys, *vals;
1911         char *flags;
1912         Lisp_Object rest;
1913         int speccount = specpdl_depth();
1914
1915         if (NILP(a) && NILP(b))
1916                 return 0;
1917
1918         Fcheck_valid_plist(a);
1919         Fcheck_valid_plist(b);
1920
1921         la = XINT(Flength(a));
1922         lb = XINT(Flength(b));
1923         m = (la > lb ? la : lb);
1924         fill = 0;
1925         XMALLOC_OR_ALLOCA(keys, m, Lisp_Object);
1926         XMALLOC_OR_ALLOCA(vals, m, Lisp_Object);
1927         XMALLOC_ATOMIC_OR_ALLOCA(flags, m, char);
1928
1929         /* First extract the pairs from A. */
1930         for (rest = a; !NILP(rest); rest = XCDR(XCDR(rest))) {
1931                 Lisp_Object k = XCAR(rest);
1932                 Lisp_Object v = XCAR(XCDR(rest));
1933                 /* Maybe be Ebolified. */
1934                 if (nil_means_not_present && NILP(v))
1935                         continue;
1936                 keys[fill] = k;
1937                 vals[fill] = v;
1938                 flags[fill] = 0;
1939                 fill++;
1940         }
1941         /* Now iterate over B, and stop if we find something that's not in A,
1942            or that doesn't match.  As we match, mark them. */
1943         for (rest = b; !NILP(rest); rest = XCDR(XCDR(rest))) {
1944                 Lisp_Object k = XCAR(rest);
1945                 Lisp_Object v = XCAR(XCDR(rest));
1946                 /* Maybe be Ebolified. */
1947                 if (nil_means_not_present && NILP(v))
1948                         continue;
1949                 for (i = 0; i < fill; i++) {
1950                         if (!laxp ? EQ(k, keys[i]) :
1951                             internal_equal(k, keys[i], depth)) {
1952                                 if (eqp
1953                                     /* We narrowly escaped being Ebolified
1954                                        here. */
1955                                     ? !EQ_WITH_EBOLA_NOTICE(v, vals[i])
1956                                     : !internal_equal(v, vals[i], depth))
1957                                         /* a property in B has a different value
1958                                            than in A */
1959                                         goto MISMATCH;
1960                                 flags[i] = 1;
1961                                 break;
1962                         }
1963                 }
1964                 if (i == fill)
1965                         /* there are some properties in B that are not in A */
1966                         goto MISMATCH;
1967         }
1968         /* Now check to see that all the properties in A were also in B */
1969         for (i = 0; i < fill; i++)
1970                 if (flags[i] == 0)
1971                         goto MISMATCH;
1972
1973         XMALLOC_UNBIND(flags, m, speccount);
1974         XMALLOC_UNBIND(vals, m, speccount);
1975         XMALLOC_UNBIND(keys, m, speccount);
1976         /* Ok. */
1977         return 0;
1978
1979 MISMATCH:
1980         XMALLOC_UNBIND(flags, m, speccount);
1981         XMALLOC_UNBIND(vals, m, speccount);
1982         XMALLOC_UNBIND(keys, m, speccount);
1983         return 1;
1984 }
1985
1986 DEFUN("plists-eq", Fplists_eq, 2, 3, 0, /*
1987 Return non-nil if property lists A and B are `eq'.
1988 A property list is an alternating list of keywords and values.
1989 This function does order-insensitive comparisons of the property lists:
1990 For example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
1991 Comparison between values is done using `eq'.  See also `plists-equal'.
1992 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
1993 a nil value is ignored.  This feature is a virus that has infected
1994 old Lisp implementations, but should not be used except for backward
1995 compatibility.
1996 */
1997       (a, b, nil_means_not_present))
1998 {
1999         return (plists_differ(a, b, !NILP(nil_means_not_present), 0, -1)
2000                 ? Qnil : Qt);
2001 }
2002
2003 DEFUN("plists-equal", Fplists_equal, 2, 3, 0,   /*
2004 Return non-nil if property lists A and B are `equal'.
2005 A property list is an alternating list of keywords and values.  This
2006 function does order-insensitive comparisons of the property lists: For
2007 example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2008 Comparison between values is done using `equal'.  See also `plists-eq'.
2009 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2010 a nil value is ignored.  This feature is a virus that has infected
2011 old Lisp implementations, but should not be used except for backward
2012 compatibility.
2013 */
2014       (a, b, nil_means_not_present))
2015 {
2016         return (plists_differ(a, b, !NILP(nil_means_not_present), 0, 1)
2017                 ? Qnil : Qt);
2018 }
2019
2020 DEFUN("lax-plists-eq", Flax_plists_eq, 2, 3, 0, /*
2021 Return non-nil if lax property lists A and B are `eq'.
2022 A property list is an alternating list of keywords and values.
2023 This function does order-insensitive comparisons of the property lists:
2024 For example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2025 Comparison between values is done using `eq'.  See also `plists-equal'.
2026 A lax property list is like a regular one except that comparisons between
2027 keywords is done using `equal' instead of `eq'.
2028 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2029 a nil value is ignored.  This feature is a virus that has infected
2030 old Lisp implementations, but should not be used except for backward
2031 compatibility.
2032 */
2033       (a, b, nil_means_not_present))
2034 {
2035         return (plists_differ(a, b, !NILP(nil_means_not_present), 1, -1)
2036                 ? Qnil : Qt);
2037 }
2038
2039 DEFUN("lax-plists-equal", Flax_plists_equal, 2, 3, 0,   /*
2040 Return non-nil if lax property lists A and B are `equal'.
2041 A property list is an alternating list of keywords and values.  This
2042 function does order-insensitive comparisons of the property lists: For
2043 example, the property lists '(a 1 b 2) and '(b 2 a 1) are equal.
2044 Comparison between values is done using `equal'.  See also `plists-eq'.
2045 A lax property list is like a regular one except that comparisons between
2046 keywords is done using `equal' instead of `eq'.
2047 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2048 a nil value is ignored.  This feature is a virus that has infected
2049 old Lisp implementations, but should not be used except for backward
2050 compatibility.
2051 */
2052       (a, b, nil_means_not_present))
2053 {
2054         return (plists_differ(a, b, !NILP(nil_means_not_present), 1, 1)
2055                 ? Qnil : Qt);
2056 }
2057
2058 /* Return the value associated with key PROPERTY in property list PLIST.
2059    Return nil if key not found.  This function is used for internal
2060    property lists that cannot be directly manipulated by the user.
2061    */
2062
2063 Lisp_Object internal_plist_get(Lisp_Object plist, Lisp_Object property)
2064 {
2065         Lisp_Object tail;
2066
2067         for (tail = plist; !NILP(tail); tail = XCDR(XCDR(tail))) {
2068                 if (EQ(XCAR(tail), property))
2069                         return XCAR(XCDR(tail));
2070         }
2071
2072         return Qunbound;
2073 }
2074
2075 /* Set PLIST's value for PROPERTY to VALUE.  Analogous to
2076    internal_plist_get(). */
2077
2078 void
2079 internal_plist_put(Lisp_Object * plist, Lisp_Object property, Lisp_Object value)
2080 {
2081         Lisp_Object tail;
2082
2083         for (tail = *plist; !NILP(tail); tail = XCDR(XCDR(tail))) {
2084                 if (EQ(XCAR(tail), property)) {
2085                         XCAR(XCDR(tail)) = value;
2086                         return;
2087                 }
2088         }
2089
2090         *plist = Fcons(property, Fcons(value, *plist));
2091 }
2092
2093 int internal_remprop(Lisp_Object * plist, Lisp_Object property)
2094 {
2095         Lisp_Object tail, prev;
2096
2097         for (tail = *plist, prev = Qnil; !NILP(tail); tail = XCDR(XCDR(tail))) {
2098                 if (EQ(XCAR(tail), property)) {
2099                         if (NILP(prev))
2100                                 *plist = XCDR(XCDR(tail));
2101                         else
2102                                 XCDR(XCDR(prev)) = XCDR(XCDR(tail));
2103                         return 1;
2104                 } else
2105                         prev = tail;
2106         }
2107
2108         return 0;
2109 }
2110
2111 /* Called on a malformed property list.  BADPLACE should be some
2112    place where truncating will form a good list -- i.e. we shouldn't
2113    result in a list with an odd length. */
2114
2115 static Lisp_Object
2116 bad_bad_bunny(Lisp_Object * plist, Lisp_Object * badplace, Error_behavior errb)
2117 {
2118         if (ERRB_EQ(errb, ERROR_ME))
2119                 return Fsignal(Qmalformed_property_list,
2120                                list2(*plist, *badplace));
2121         else {
2122                 if (ERRB_EQ(errb, ERROR_ME_WARN)) {
2123                         warn_when_safe_lispobj
2124                             (Qlist, Qwarning,
2125                              list2(build_string
2126                                    ("Malformed property list -- list has been truncated"),
2127                                    *plist));
2128                         *badplace = Qnil;
2129                 }
2130                 return Qunbound;
2131         }
2132 }
2133
2134 /* Called on a circular property list.  BADPLACE should be some place
2135    where truncating will result in an even-length list, as above.
2136    If doesn't particularly matter where we truncate -- anywhere we
2137    truncate along the entire list will break the circularity, because
2138    it will create a terminus and the list currently doesn't have one.
2139 */
2140
2141 static Lisp_Object
2142 bad_bad_turtle(Lisp_Object * plist, Lisp_Object * badplace, Error_behavior errb)
2143 {
2144         if (ERRB_EQ(errb, ERROR_ME))
2145                 return Fsignal(Qcircular_property_list, list1(*plist));
2146         else {
2147                 if (ERRB_EQ(errb, ERROR_ME_WARN)) {
2148                         warn_when_safe_lispobj
2149                             (Qlist, Qwarning,
2150                              list2(build_string
2151                                    ("Circular property list -- list has been truncated"),
2152                                    *plist));
2153                         *badplace = Qnil;
2154                 }
2155                 return Qunbound;
2156         }
2157 }
2158
2159 /* Advance the tortoise pointer by two (one iteration of a property-list
2160    loop) and the hare pointer by four and verify that no malformations
2161    or circularities exist.  If so, return zero and store a value into
2162    RETVAL that should be returned by the calling function.  Otherwise,
2163    return 1.  See external_plist_get().
2164  */
2165
2166 static int
2167 advance_plist_pointers(Lisp_Object * plist,
2168                        Lisp_Object ** tortoise, Lisp_Object ** hare,
2169                        Error_behavior errb, Lisp_Object * retval)
2170 {
2171         int i;
2172         Lisp_Object *tortsave = *tortoise;
2173
2174         /* Note that our "fixing" may be more brutal than necessary,
2175            but it's the user's own problem, not ours, if they went in and
2176            manually fucked up a plist. */
2177
2178         for (i = 0; i < 2; i++) {
2179                 /* This is a standard iteration of a defensive-loop-checking
2180                    loop.  We just do it twice because we want to advance past
2181                    both the property and its value.
2182
2183                    If the pointer indirection is confusing you, remember that
2184                    one level of indirection on the hare and tortoise pointers
2185                    is only due to pass-by-reference for this function.  The other
2186                    level is so that the plist can be fixed in place. */
2187
2188                 /* When we reach the end of a well-formed plist, **HARE is
2189                    nil.  In that case, we don't do anything at all except
2190                    advance TORTOISE by one.  Otherwise, we advance HARE
2191                    by two (making sure it's OK to do so), then advance
2192                    TORTOISE by one (it will always be OK to do so because
2193                    the HARE is always ahead of the TORTOISE and will have
2194                    already verified the path), then make sure TORTOISE and
2195                    HARE don't contain the same non-nil object -- if the
2196                    TORTOISE and the HARE ever meet, then obviously we're
2197                    in a circularity, and if we're in a circularity, then
2198                    the TORTOISE and the HARE can't cross paths without
2199                    meeting, since the HARE only gains one step over the
2200                    TORTOISE per iteration. */
2201
2202                 if (!NILP(**hare)) {
2203                         Lisp_Object *haresave = *hare;
2204                         if (!CONSP(**hare)) {
2205                                 *retval = bad_bad_bunny(plist, haresave, errb);
2206                                 return 0;
2207                         }
2208                         *hare = &XCDR(**hare);
2209                         /* In a non-plist, we'd check here for a nil value for
2210                          **HARE, which is OK (it just means the list has an
2211                          odd number of elements).  In a plist, it's not OK
2212                          for the list to have an odd number of elements. */
2213                         if (!CONSP(**hare)) {
2214                                 *retval = bad_bad_bunny(plist, haresave, errb);
2215                                 return 0;
2216                         }
2217                         *hare = &XCDR(**hare);
2218                 }
2219
2220                 *tortoise = &XCDR(**tortoise);
2221                 if (!NILP(**hare) && EQ(**tortoise, **hare)) {
2222                         *retval = bad_bad_turtle(plist, tortsave, errb);
2223                         return 0;
2224                 }
2225         }
2226
2227         return 1;
2228 }
2229
2230 /* Return the value of PROPERTY from PLIST, or Qunbound if
2231    property is not on the list.
2232
2233    PLIST is a Lisp-accessible property list, meaning that it
2234    has to be checked for malformations and circularities.
2235
2236    If ERRB is ERROR_ME, an error will be signalled.  Otherwise, the
2237    function will never signal an error; and if ERRB is ERROR_ME_WARN,
2238    on finding a malformation or a circularity, it issues a warning and
2239    attempts to silently fix the problem.
2240
2241    A pointer to PLIST is passed in so that PLIST can be successfully
2242    "fixed" even if the error is at the beginning of the plist. */
2243
2244 Lisp_Object
2245 external_plist_get(Lisp_Object * plist, Lisp_Object property,
2246                    int laxp, Error_behavior errb)
2247 {
2248         Lisp_Object *tortoise = plist;
2249         Lisp_Object *hare = plist;
2250
2251         while (!NILP(*tortoise)) {
2252                 Lisp_Object *tortsave = tortoise;
2253                 Lisp_Object retval;
2254
2255                 /* We do the standard tortoise/hare march.  We isolate the
2256                    grungy stuff to do this in advance_plist_pointers(), though.
2257                    To us, all this function does is advance the tortoise
2258                    pointer by two and the hare pointer by four and make sure
2259                    everything's OK.  We first advance the pointers and then
2260                    check if a property matched; this ensures that our
2261                    check for a matching property is safe. */
2262
2263                 if (!advance_plist_pointers
2264                     (plist, &tortoise, &hare, errb, &retval))
2265                         return retval;
2266
2267                 if (!laxp ? EQ(XCAR(*tortsave), property)
2268                     : internal_equal(XCAR(*tortsave), property, 0))
2269                         return XCAR(XCDR(*tortsave));
2270         }
2271
2272         return Qunbound;
2273 }
2274
2275 /* Set PLIST's value for PROPERTY to VALUE, given a possibly
2276    malformed or circular plist.  Analogous to external_plist_get(). */
2277
2278 void
2279 external_plist_put(Lisp_Object * plist, Lisp_Object property,
2280                    Lisp_Object value, int laxp, Error_behavior errb)
2281 {
2282         Lisp_Object *tortoise = plist;
2283         Lisp_Object *hare = plist;
2284
2285         while (!NILP(*tortoise)) {
2286                 Lisp_Object *tortsave = tortoise;
2287                 Lisp_Object retval;
2288
2289                 /* See above */
2290                 if (!advance_plist_pointers
2291                     (plist, &tortoise, &hare, errb, &retval))
2292                         return;
2293
2294                 if (!laxp ? EQ(XCAR(*tortsave), property)
2295                     : internal_equal(XCAR(*tortsave), property, 0)) {
2296                         XCAR(XCDR(*tortsave)) = value;
2297                         return;
2298                 }
2299         }
2300
2301         *plist = Fcons(property, Fcons(value, *plist));
2302 }
2303
2304 int
2305 external_remprop(Lisp_Object * plist, Lisp_Object property,
2306                  int laxp, Error_behavior errb)
2307 {
2308         Lisp_Object *tortoise = plist;
2309         Lisp_Object *hare = plist;
2310
2311         while (!NILP(*tortoise)) {
2312                 Lisp_Object *tortsave = tortoise;
2313                 Lisp_Object retval;
2314
2315                 /* See above */
2316                 if (!advance_plist_pointers
2317                     (plist, &tortoise, &hare, errb, &retval))
2318                         return 0;
2319
2320                 if (!laxp ? EQ(XCAR(*tortsave), property)
2321                     : internal_equal(XCAR(*tortsave), property, 0)) {
2322                         /* Now you see why it's so convenient to have that level
2323                            of indirection. */
2324                         *tortsave = XCDR(XCDR(*tortsave));
2325                         return 1;
2326                 }
2327         }
2328
2329         return 0;
2330 }
2331
2332 DEFUN("plist-get", Fplist_get, 2, 3, 0, /*
2333 Extract a value from a property list.
2334 PLIST is a property list, which is a list of the form
2335 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...).
2336 PROPERTY is usually a symbol.
2337 This function returns the value corresponding to the PROPERTY,
2338 or DEFAULT if PROPERTY is not one of the properties on the list.
2339 */
2340       (plist, property, default_))
2341 {
2342         Lisp_Object value = external_plist_get(&plist, property, 0, ERROR_ME);
2343         return UNBOUNDP(value) ? default_ : value;
2344 }
2345
2346 DEFUN("plist-put", Fplist_put, 3, 3, 0, /*
2347 Change value in PLIST of PROPERTY to VALUE.
2348 PLIST is a property list, which is a list of the form
2349 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
2350 PROPERTY is usually a symbol and VALUE is any object.
2351 If PROPERTY is already a property on the list, its value is set to VALUE,
2352 otherwise the new PROPERTY VALUE pair is added.
2353 The new plist is returned; use `(setq x (plist-put x property value))'
2354 to be sure to use the new value.  PLIST is modified by side effect.
2355 */
2356       (plist, property, value))
2357 {
2358         external_plist_put(&plist, property, value, 0, ERROR_ME);
2359         return plist;
2360 }
2361
2362 DEFUN("plist-remprop", Fplist_remprop, 2, 2, 0, /*
2363 Remove from PLIST the property PROPERTY and its value.
2364 PLIST is a property list, which is a list of the form
2365 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...).
2366 PROPERTY is usually a symbol.
2367 The new plist is returned; use `(setq x (plist-remprop x property))'
2368 to be sure to use the new value.  PLIST is modified by side effect.
2369 */
2370       (plist, property))
2371 {
2372         external_remprop(&plist, property, 0, ERROR_ME);
2373         return plist;
2374 }
2375
2376 DEFUN("plist-member", Fplist_member, 2, 2, 0,   /*
2377 Return t if PROPERTY has a value specified in PLIST.
2378 */
2379       (plist, property))
2380 {
2381         Lisp_Object value = Fplist_get(plist, property, Qunbound);
2382         return UNBOUNDP(value) ? Qnil : Qt;
2383 }
2384
2385 DEFUN("check-valid-plist", Fcheck_valid_plist, 1, 1, 0, /*
2386 Given a plist, signal an error if there is anything wrong with it.
2387 This means that it's a malformed or circular plist.
2388 */
2389       (plist))
2390 {
2391         Lisp_Object *tortoise;
2392         Lisp_Object *hare;
2393
2394       start_over:
2395         tortoise = &plist;
2396         hare = &plist;
2397         while (!NILP(*tortoise)) {
2398                 Lisp_Object retval;
2399
2400                 /* See above */
2401                 if (!advance_plist_pointers(&plist, &tortoise, &hare, ERROR_ME,
2402                                             &retval))
2403                         goto start_over;
2404         }
2405
2406         return Qnil;
2407 }
2408
2409 DEFUN("valid-plist-p", Fvalid_plist_p, 1, 1, 0, /*
2410 Given a plist, return non-nil if its format is correct.
2411 If it returns nil, `check-valid-plist' will signal an error when given
2412 the plist; that means it's a malformed or circular plist.
2413 */
2414       (plist))
2415 {
2416         Lisp_Object *tortoise;
2417         Lisp_Object *hare;
2418
2419         tortoise = &plist;
2420         hare = &plist;
2421         while (!NILP(*tortoise)) {
2422                 Lisp_Object retval;
2423
2424                 /* See above */
2425                 if (!advance_plist_pointers
2426                     (&plist, &tortoise, &hare, ERROR_ME_NOT, &retval))
2427                         return Qnil;
2428         }
2429
2430         return Qt;
2431 }
2432
2433 DEFUN("canonicalize-plist", Fcanonicalize_plist, 1, 2, 0,       /*
2434 Destructively remove any duplicate entries from a plist.
2435 In such cases, the first entry applies.
2436
2437 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2438 a nil value is removed.  This feature is a virus that has infected
2439 old Lisp implementations, but should not be used except for backward
2440 compatibility.
2441
2442 The new plist is returned.  If NIL-MEANS-NOT-PRESENT is given, the
2443 return value may not be EQ to the passed-in value, so make sure to
2444 `setq' the value back into where it came from.
2445 */
2446       (plist, nil_means_not_present))
2447 {
2448         Lisp_Object head = plist;
2449
2450         Fcheck_valid_plist(plist);
2451
2452         while (!NILP(plist)) {
2453                 Lisp_Object prop = Fcar(plist);
2454                 Lisp_Object next = Fcdr(plist);
2455
2456                 CHECK_CONS(next);       /* just make doubly sure we catch any errors */
2457                 if (!NILP(nil_means_not_present) && NILP(Fcar(next))) {
2458                         if (EQ(head, plist))
2459                                 head = Fcdr(next);
2460                         plist = Fcdr(next);
2461                         continue;
2462                 }
2463                 /* external_remprop returns 1 if it removed any property.
2464                    We have to loop till it didn't remove anything, in case
2465                    the property occurs many times. */
2466                 while (external_remprop(&XCDR(next), prop, 0, ERROR_ME))
2467                         DO_NOTHING;
2468                 plist = Fcdr(next);
2469         }
2470
2471         return head;
2472 }
2473
2474 DEFUN("lax-plist-get", Flax_plist_get, 2, 3, 0, /*
2475 Extract a value from a lax property list.
2476 LAX-PLIST is a lax property list, which is a list of the form
2477 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2478 properties is done using `equal' instead of `eq'.
2479 PROPERTY is usually a symbol.
2480 This function returns the value corresponding to PROPERTY,
2481 or DEFAULT if PROPERTY is not one of the properties on the list.
2482 */
2483       (lax_plist, property, default_))
2484 {
2485         Lisp_Object value =
2486             external_plist_get(&lax_plist, property, 1, ERROR_ME);
2487         return UNBOUNDP(value) ? default_ : value;
2488 }
2489
2490 DEFUN("lax-plist-put", Flax_plist_put, 3, 3, 0, /*
2491 Change value in LAX-PLIST of PROPERTY to VALUE.
2492 LAX-PLIST is a lax property list, which is a list of the form
2493 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2494 properties is done using `equal' instead of `eq'.
2495 PROPERTY is usually a symbol and VALUE is any object.
2496 If PROPERTY is already a property on the list, its value is set to
2497 VALUE, otherwise the new PROPERTY VALUE pair is added.
2498 The new plist is returned; use `(setq x (lax-plist-put x property value))'
2499 to be sure to use the new value.  LAX-PLIST is modified by side effect.
2500 */
2501       (lax_plist, property, value))
2502 {
2503         external_plist_put(&lax_plist, property, value, 1, ERROR_ME);
2504         return lax_plist;
2505 }
2506
2507 DEFUN("lax-plist-remprop", Flax_plist_remprop, 2, 2, 0, /*
2508 Remove from LAX-PLIST the property PROPERTY and its value.
2509 LAX-PLIST is a lax property list, which is a list of the form
2510 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2511 properties is done using `equal' instead of `eq'.
2512 PROPERTY is usually a symbol.
2513 The new plist is returned; use `(setq x (lax-plist-remprop x property))'
2514 to be sure to use the new value.  LAX-PLIST is modified by side effect.
2515 */
2516       (lax_plist, property))
2517 {
2518         external_remprop(&lax_plist, property, 1, ERROR_ME);
2519         return lax_plist;
2520 }
2521
2522 DEFUN("lax-plist-member", Flax_plist_member, 2, 2, 0,   /*
2523 Return t if PROPERTY has a value specified in LAX-PLIST.
2524 LAX-PLIST is a lax property list, which is a list of the form
2525 \(PROPERTY1 VALUE1 PROPERTY2 VALUE2...), where comparisons between
2526 properties is done using `equal' instead of `eq'.
2527 */
2528       (lax_plist, property))
2529 {
2530         return UNBOUNDP(Flax_plist_get(lax_plist, property, Qunbound)) ? Qnil :
2531             Qt;
2532 }
2533
2534 DEFUN("canonicalize-lax-plist", Fcanonicalize_lax_plist, 1, 2, 0,       /*
2535 Destructively remove any duplicate entries from a lax plist.
2536 In such cases, the first entry applies.
2537
2538 If optional arg NIL-MEANS-NOT-PRESENT is non-nil, then a property with
2539 a nil value is removed.  This feature is a virus that has infected
2540 old Lisp implementations, but should not be used except for backward
2541 compatibility.
2542
2543 The new plist is returned.  If NIL-MEANS-NOT-PRESENT is given, the
2544 return value may not be EQ to the passed-in value, so make sure to
2545 `setq' the value back into where it came from.
2546 */
2547       (lax_plist, nil_means_not_present))
2548 {
2549         Lisp_Object head = lax_plist;
2550
2551         Fcheck_valid_plist(lax_plist);
2552
2553         while (!NILP(lax_plist)) {
2554                 Lisp_Object prop = Fcar(lax_plist);
2555                 Lisp_Object next = Fcdr(lax_plist);
2556
2557                 CHECK_CONS(next);       /* just make doubly sure we catch any errors */
2558                 if (!NILP(nil_means_not_present) && NILP(Fcar(next))) {
2559                         if (EQ(head, lax_plist))
2560                                 head = Fcdr(next);
2561                         lax_plist = Fcdr(next);
2562                         continue;
2563                 }
2564                 /* external_remprop returns 1 if it removed any property.
2565                    We have to loop till it didn't remove anything, in case
2566                    the property occurs many times. */
2567                 while (external_remprop(&XCDR(next), prop, 1, ERROR_ME))
2568                         DO_NOTHING;
2569                 lax_plist = Fcdr(next);
2570         }
2571
2572         return head;
2573 }
2574
2575 /* In C because the frame props stuff uses it */
2576
2577 DEFUN("destructive-alist-to-plist", Fdestructive_alist_to_plist, 1, 1, 0,       /*
2578 Convert association list ALIST into the equivalent property-list form.
2579 The plist is returned.  This converts from
2580
2581 \((a . 1) (b . 2) (c . 3))
2582
2583 into
2584
2585 \(a 1 b 2 c 3)
2586
2587 The original alist is destroyed in the process of constructing the plist.
2588 See also `alist-to-plist'.
2589 */
2590       (alist))
2591 {
2592         Lisp_Object head = alist;
2593         while (!NILP(alist)) {
2594                 /* remember the alist element. */
2595                 Lisp_Object el = Fcar(alist);
2596
2597                 Fsetcar(alist, Fcar(el));
2598                 Fsetcar(el, Fcdr(el));
2599                 Fsetcdr(el, Fcdr(alist));
2600                 Fsetcdr(alist, el);
2601                 alist = Fcdr(Fcdr(alist));
2602         }
2603
2604         return head;
2605 }
2606
2607 DEFUN("get", Fget, 2, 3, 0,     /*
2608 Return the value of OBJECT's PROPERTY property.
2609 This is the last VALUE stored with `(put OBJECT PROPERTY VALUE)'.
2610 If there is no such property, return optional third arg DEFAULT
2611 \(which defaults to `nil').  OBJECT can be a symbol, string, extent,
2612 face, or glyph.  See also `put', `remprop', and `object-plist'.
2613 */
2614       (object, property, default_))
2615 {
2616         /* Various places in emacs call Fget() and expect it not to quit,
2617            so don't quit. */
2618         Lisp_Object val;
2619
2620         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->getprop)
2621                 val =
2622                     XRECORD_LHEADER_IMPLEMENTATION(object)->getprop(object,
2623                                                                     property);
2624         else
2625                 signal_simple_error("Object type has no properties", object);
2626
2627         return UNBOUNDP(val) ? default_ : val;
2628 }
2629
2630 DEFUN("put", Fput, 3, 3, 0,     /*
2631 Set OBJECT's PROPERTY to VALUE.
2632 It can be subsequently retrieved with `(get OBJECT PROPERTY)'.
2633 OBJECT can be a symbol, face, extent, or string.
2634 For a string, no properties currently have predefined meanings.
2635 For the predefined properties for extents, see `set-extent-property'.
2636 For the predefined properties for faces, see `set-face-property'.
2637 See also `get', `remprop', and `object-plist'.
2638 */
2639       (object, property, value))
2640 {
2641         CHECK_LISP_WRITEABLE(object);
2642
2643         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->putprop) {
2644                 if (!XRECORD_LHEADER_IMPLEMENTATION(object)->putprop
2645                     (object, property, value))
2646                         signal_simple_error("Can't set property on object",
2647                                             property);
2648         } else
2649                 signal_simple_error("Object type has no settable properties",
2650                                     object);
2651
2652         return value;
2653 }
2654
2655 DEFUN("remprop", Fremprop, 2, 2, 0,     /*
2656 Remove, from OBJECT's property list, PROPERTY and its corresponding value.
2657 OBJECT can be a symbol, string, extent, face, or glyph.  Return non-nil
2658 if the property list was actually modified (i.e. if PROPERTY was present
2659 in the property list).  See also `get', `put', and `object-plist'.
2660 */
2661       (object, property))
2662 {
2663         int ret = 0;
2664
2665         CHECK_LISP_WRITEABLE(object);
2666
2667         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->remprop) {
2668                 ret =
2669                     XRECORD_LHEADER_IMPLEMENTATION(object)->remprop(object,
2670                                                                     property);
2671                 if (ret == -1)
2672                         signal_simple_error("Can't remove property from object",
2673                                             property);
2674         } else
2675                 signal_simple_error("Object type has no removable properties",
2676                                     object);
2677
2678         return ret ? Qt : Qnil;
2679 }
2680
2681 DEFUN("object-plist", Fobject_plist, 1, 1, 0,   /*
2682 Return a property list of OBJECT's properties.
2683 For a symbol, this is equivalent to `symbol-plist'.
2684 OBJECT can be a symbol, string, extent, face, or glyph.
2685 Do not modify the returned property list directly;
2686 this may or may not have the desired effects.  Use `put' instead.
2687 */
2688       (object))
2689 {
2690         if (LRECORDP(object) && XRECORD_LHEADER_IMPLEMENTATION(object)->plist)
2691                 return XRECORD_LHEADER_IMPLEMENTATION(object)->plist(object);
2692         else
2693                 signal_simple_error("Object type has no properties", object);
2694
2695         return Qnil;
2696 }
2697 \f
2698 int internal_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
2699 {
2700         if (depth > 200)
2701                 error("Stack overflow in equal");
2702         QUIT;
2703         if (EQ_WITH_EBOLA_NOTICE(obj1, obj2))
2704                 return 1;
2705         /* Note that (equal 20 20.0) should be nil */
2706         if (XTYPE(obj1) != XTYPE(obj2))
2707                 return 0;
2708         if (LRECORDP(obj1)) {
2709                 const struct lrecord_implementation
2710                 *imp1 = XRECORD_LHEADER_IMPLEMENTATION(obj1),
2711                     *imp2 = XRECORD_LHEADER_IMPLEMENTATION(obj2);
2712
2713                 return (imp1 == imp2) &&
2714                     /* EQ-ness of the objects was noticed above */
2715                     (imp1->equal && (imp1->equal) (obj1, obj2, depth));
2716         }
2717
2718         return 0;
2719 }
2720
2721 int
2722 internal_equalp (Lisp_Object obj1, Lisp_Object obj2, int depth)
2723 {
2724         if (depth > 200)
2725                 error ("Stack overflow in equalp");
2726         QUIT;
2727         if (EQ_WITH_EBOLA_NOTICE (obj1, obj2))
2728                 return 1;
2729
2730         if (NUMBERP(obj1) && NUMBERP(obj2)) {
2731                 return ent_binrel(ASE_BINARY_REL_EQUALP, obj1, obj2);
2732         }
2733
2734         if (CHARP(obj1) && CHARP(obj2))
2735                 return XCHAR(obj1) == XCHAR(obj2);
2736         if (XTYPE(obj1) != XTYPE(obj2))
2737                 return 0;
2738         if (LRECORDP(obj1)) {
2739                 const struct lrecord_implementation
2740                         *imp1 = XRECORD_LHEADER_IMPLEMENTATION (obj1),
2741                         *imp2 = XRECORD_LHEADER_IMPLEMENTATION (obj2);
2742                 
2743                 /* #### not yet implemented properly, needs another flag to specify
2744                    equalp-ness */
2745                 return (imp1 == imp2) &&
2746                         /* EQ-ness of the objects was noticed above */
2747                         (imp1->equal && (imp1->equal) (obj1, obj2, depth));
2748         }
2749
2750         return 0;
2751 }
2752
2753
2754 /* Note that we may be calling sub-objects that will use
2755    internal_equal() (instead of internal_old_equal()).  Oh well.
2756    We will get an Ebola note if there's any possibility of confusion,
2757    but that seems unlikely. */
2758
2759 static int internal_old_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
2760 {
2761         if (depth > 200)
2762                 error("Stack overflow in equal");
2763         QUIT;
2764         if (HACKEQ_UNSAFE(obj1, obj2))
2765                 return 1;
2766         /* Note that (equal 20 20.0) should be nil */
2767         if (XTYPE(obj1) != XTYPE(obj2))
2768                 return 0;
2769
2770         return internal_equal(obj1, obj2, depth);
2771 }
2772
2773 DEFUN("equal", Fequal, 2, 2, 0, /*
2774 Return t if two Lisp objects have similar structure and contents.
2775 They must have the same data type.
2776 Conses are compared by comparing the cars and the cdrs.
2777 Vectors and strings are compared element by element.
2778 Numbers are compared by value.  Symbols must match exactly.
2779 */
2780       (object1, object2))
2781 {
2782         return internal_equal(object1, object2, 0) ? Qt : Qnil;
2783 }
2784
2785 DEFUN("old-equal", Fold_equal, 2, 2, 0, /*
2786 Return t if two Lisp objects have similar structure and contents.
2787 They must have the same data type.
2788 \(Note, however, that an exception is made for characters and integers;
2789 this is known as the "char-int confoundance disease." See `eq' and
2790 `old-eq'.)
2791 This function is provided only for byte-code compatibility with v19.
2792 Do not use it.
2793 */
2794       (object1, object2))
2795 {
2796         return internal_old_equal(object1, object2, 0) ? Qt : Qnil;
2797 }
2798 \f
2799 DEFUN("fillarray", Ffillarray, 2, 2, 0, /*
2800 Destructively modify ARRAY by replacing each element with ITEM.
2801 ARRAY is a vector, bit vector, or string.
2802 */
2803       (array, item))
2804 {
2805       retry:
2806         if (STRINGP(array)) {
2807                 Lisp_String *s = XSTRING(array);
2808                 Bytecount old_bytecount = string_length(s);
2809                 Bytecount new_bytecount;
2810                 Bytecount item_bytecount;
2811                 Bufbyte item_buf[MAX_EMCHAR_LEN];
2812                 Bufbyte *p;
2813                 Bufbyte *end;
2814
2815                 CHECK_CHAR_COERCE_INT(item);
2816                 CHECK_LISP_WRITEABLE(array);
2817
2818                 item_bytecount = set_charptr_emchar(item_buf, XCHAR(item));
2819                 new_bytecount = item_bytecount * string_char_length(s);
2820
2821                 resize_string(s, -1, new_bytecount - old_bytecount);
2822
2823                 for (p = string_data(s), end = p + new_bytecount;
2824                      p < end; p += item_bytecount)
2825                         memcpy(p, item_buf, item_bytecount);
2826                 *p = '\0';
2827
2828                 bump_string_modiff(array);
2829         } else if (VECTORP(array)) {
2830                 Lisp_Object *p = XVECTOR_DATA(array);
2831                 size_t len = XVECTOR_LENGTH(array);
2832                 CHECK_LISP_WRITEABLE(array);
2833                 while (len--)
2834                         *p++ = item;
2835         } else if (BIT_VECTORP(array)) {
2836                 Lisp_Bit_Vector *v = XBIT_VECTOR(array);
2837                 size_t len = bit_vector_length(v);
2838                 int bit;
2839                 CHECK_BIT(item);
2840                 bit = XINT(item);
2841                 CHECK_LISP_WRITEABLE(array);
2842                 while (len--)
2843                         set_bit_vector_bit(v, len, bit);
2844         } else {
2845                 array = wrong_type_argument(Qarrayp, array);
2846                 goto retry;
2847         }
2848         return array;
2849 }
2850
2851 Lisp_Object nconc2(Lisp_Object arg1, Lisp_Object arg2)
2852 {
2853         Lisp_Object args[2] = {arg1, arg2};
2854         struct gcpro gcpro1;
2855
2856         GCPROn(args, countof(args));
2857         RETURN_UNGCPRO(bytecode_nconc2(args));
2858 }
2859
2860 Lisp_Object bytecode_nconc2(Lisp_Object * args)
2861 {
2862       retry:
2863
2864         if (CONSP(args[0])) {
2865                 /* (setcdr (last args[0]) args[1]) */
2866                 Lisp_Object tortoise, hare;
2867                 size_t count;
2868
2869                 for (hare = tortoise = args[0], count = 0;
2870                      CONSP(XCDR(hare)); hare = XCDR(hare), count++) {
2871                         if (count < CIRCULAR_LIST_SUSPICION_LENGTH)
2872                                 continue;
2873
2874                         if (count & 1)
2875                                 tortoise = XCDR(tortoise);
2876                         if (EQ(hare, tortoise))
2877                                 signal_circular_list_error(args[0]);
2878                 }
2879                 XCDR(hare) = args[1];
2880                 return args[0];
2881         } else if (NILP(args[0])) {
2882                 return args[1];
2883         } else {
2884                 args[0] = wrong_type_argument(args[0], Qlistp);
2885                 goto retry;
2886         }
2887 }
2888
2889 DEFUN("nconc", Fnconc, 0, MANY, 0,      /*
2890 Concatenate any number of lists by altering them.
2891 Only the last argument is not altered, and need not be a list.
2892 Also see: `append'.
2893 If the first argument is nil, there is no way to modify it by side
2894 effect; therefore, write `(setq foo (nconc foo list))' to be sure of
2895 changing the value of `foo'.
2896 */
2897       (int nargs, Lisp_Object * args))
2898 {
2899         int argnum = 0;
2900         struct gcpro gcpro1;
2901
2902         /* The modus operandi in Emacs is "caller gc-protects args".
2903            However, nconc (particularly nconc2 ()) is called many times
2904            in Emacs on freshly created stuff (e.g. you see the idiom
2905            nconc2 (Fcopy_sequence (foo), bar) a lot).  So we help those
2906            callers out by protecting the args ourselves to save them
2907            a lot of temporary-variable grief. */
2908
2909         GCPROn(args, nargs);
2910
2911         while (argnum < nargs) {
2912                 Lisp_Object val;
2913         retry:
2914                 val = args[argnum];
2915                 if (CONSP(val)) {
2916                         /* `val' is the first cons, which will be our return
2917                          * value.
2918                          * `last_cons' will be the cons cell to mutate.  */
2919                         Lisp_Object last_cons = val;
2920                         Lisp_Object tortoise = val;
2921
2922                         for (argnum++; argnum < nargs; argnum++) {
2923                                 Lisp_Object next = args[argnum];
2924                               retry_next:
2925                                 if (CONSP(next) || argnum == nargs - 1) {
2926                                         /* (setcdr (last val) next) */
2927                                         size_t count;
2928
2929                                         for (count = 0;
2930                                              CONSP(XCDR(last_cons));
2931                                              last_cons =
2932                                              XCDR(last_cons), count++) {
2933                                                 if (count <
2934                                                     CIRCULAR_LIST_SUSPICION_LENGTH)
2935                                                         continue;
2936
2937                                                 if (count & 1)
2938                                                         tortoise =
2939                                                             XCDR(tortoise);
2940                                                 if (EQ(last_cons, tortoise))
2941                                                         signal_circular_list_error
2942                                                             (args[argnum - 1]);
2943                                         }
2944                                         XCDR(last_cons) = next;
2945                                 } else if (NILP(next)) {
2946                                         continue;
2947                                 } else {
2948                                         next =
2949                                             wrong_type_argument(Qlistp, next);
2950                                         goto retry_next;
2951                                 }
2952                         }
2953                         RETURN_UNGCPRO(val);
2954                 } else if (NILP(val))
2955                         argnum++;
2956                 else if (argnum == nargs - 1)   /* last arg? */
2957                         RETURN_UNGCPRO(val);
2958                 else {
2959                         args[argnum] = wrong_type_argument(Qlistp, val);
2960                         goto retry;
2961                 }
2962         }
2963         RETURN_UNGCPRO(Qnil);   /* No non-nil args provided. */
2964 }
2965
2966 \f
2967 DEFUN("replace-list", Freplace_list, 2, 2, 0,   /*
2968 Destructively replace the list OLD with NEW.
2969 This is like (copy-sequence NEW) except that it reuses the
2970 conses in OLD as much as possible.  If OLD and NEW are the same
2971 length, no consing will take place.
2972 */
2973       (old, new))
2974 {
2975         Lisp_Object tail, oldtail = old, prevoldtail = Qnil;
2976
2977         EXTERNAL_LIST_LOOP(tail, new) {
2978                 if (!NILP(oldtail)) {
2979                         CHECK_CONS(oldtail);
2980                         XCAR(oldtail) = XCAR(tail);
2981                 } else if (!NILP(prevoldtail)) {
2982                         XCDR(prevoldtail) = Fcons(XCAR(tail), Qnil);
2983                         prevoldtail = XCDR(prevoldtail);
2984                 } else
2985                         old = oldtail = Fcons(XCAR(tail), Qnil);
2986
2987                 if (!NILP(oldtail)) {
2988                         prevoldtail = oldtail;
2989                         oldtail = XCDR(oldtail);
2990                 }
2991         }
2992
2993         if (!NILP(prevoldtail))
2994                 XCDR(prevoldtail) = Qnil;
2995         else
2996                 old = Qnil;
2997
2998         return old;
2999 }
3000 \f
3001 /* #### this function doesn't belong in this file! */
3002
3003 #ifdef HAVE_GETLOADAVG
3004 #ifdef HAVE_SYS_LOADAVG_H
3005 #include <sys/loadavg.h>
3006 #endif
3007 #else
3008 int getloadavg(double loadavg[], int nelem);    /* Defined in getloadavg.c */
3009 #endif
3010
3011 DEFUN("load-average", Fload_average, 0, 1, 0,   /*
3012 Return list of 1 minute, 5 minute and 15 minute load averages.
3013 Each of the three load averages is multiplied by 100,
3014 then converted to integer.
3015
3016 When USE-FLOATS is non-nil, floats will be used instead of integers.
3017 These floats are not multiplied by 100.
3018
3019 If the 5-minute or 15-minute load averages are not available, return a
3020 shortened list, containing only those averages which are available.
3021
3022 On some systems, this won't work due to permissions on /dev/kmem,
3023 in which case you can't use this.
3024 */
3025       (use_floats))
3026 {
3027         double load_ave[3];
3028         int loads = getloadavg(load_ave, countof(load_ave));
3029         Lisp_Object ret = Qnil;
3030
3031         if (loads == -2)
3032                 error("load-average not implemented for this operating system");
3033         else if (loads < 0)
3034                 signal_simple_error("Could not get load-average",
3035                                     lisp_strerror(errno));
3036
3037         while (loads-- > 0) {
3038                 Lisp_Object load = (NILP(use_floats) ?
3039                                     make_int((int)(100.0 * load_ave[loads]))
3040                                     : make_float(load_ave[loads]));
3041                 ret = Fcons(load, ret);
3042         }
3043         return ret;
3044 }
3045 \f
3046 Lisp_Object Vfeatures;
3047
3048 DEFUN("featurep", Ffeaturep, 1, 1, 0,   /*
3049 Return non-nil if feature FEXP is present in this Emacs.
3050 Use this to conditionalize execution of lisp code based on the
3051 presence or absence of emacs or environment extensions.
3052 FEXP can be a symbol, a number, or a list.
3053 If it is a symbol, that symbol is looked up in the `features' variable,
3054 and non-nil will be returned if found.
3055 If it is a number, the function will return non-nil if this Emacs
3056 has an equal or greater version number than FEXP.
3057 If it is a list whose car is the symbol `and', it will return
3058 non-nil if all the features in its cdr are non-nil.
3059 If it is a list whose car is the symbol `or', it will return non-nil
3060 if any of the features in its cdr are non-nil.
3061 If it is a list whose car is the symbol `not', it will return
3062 non-nil if the feature is not present.
3063
3064 Examples:
3065
3066 (featurep 'sxemacs)
3067 => ; Non-nil on SXEmacs.
3068
3069 (featurep '(and sxemacs gnus))
3070 => ; Non-nil on SXEmacs with Gnus loaded.
3071
3072 (featurep '(or tty-frames (and emacs 19.30)))
3073 => ; Non-nil if this Emacs supports TTY frames.
3074
3075 (featurep '(or (and xemacs 19.15) (and emacs 19.34)))
3076 => ; Non-nil on XEmacs 19.15 and later, or FSF Emacs 19.34 and later.
3077
3078 (featurep '(and xemacs 21.02))
3079 => ; Non-nil on XEmacs 21.2 and later.
3080
3081 NOTE: The advanced arguments of this function (anything other than a
3082 symbol) are not yet supported by FSF Emacs.  If you feel they are useful
3083 for supporting multiple Emacs variants, lobby Richard Stallman at
3084 <bug-gnu-emacs@gnu.org>.
3085 */
3086       (fexp))
3087 {
3088 #ifndef FEATUREP_SYNTAX
3089         CHECK_SYMBOL(fexp);
3090         return NILP(Fmemq(fexp, Vfeatures)) ? Qnil : Qt;
3091 #else                           /* FEATUREP_SYNTAX */
3092         static double featurep_emacs_version;
3093
3094         /* Brute force translation from Erik Naggum's lisp function. */
3095         if (SYMBOLP(fexp)) {
3096                 /* Original definition */
3097                 return NILP(Fmemq(fexp, Vfeatures)) ? Qnil : Qt;
3098         } else if (INTP(fexp) || FLOATP(fexp)) {
3099                 double d = extract_float(fexp);
3100
3101                 if (featurep_emacs_version == 0.0) {
3102                         featurep_emacs_version = XINT(Vemacs_major_version) +
3103                             (XINT(Vemacs_minor_version) / 100.0);
3104                 }
3105                 return featurep_emacs_version >= d ? Qt : Qnil;
3106         } else if (CONSP(fexp)) {
3107                 Lisp_Object tem = XCAR(fexp);
3108                 if (EQ(tem, Qnot)) {
3109                         Lisp_Object negate;
3110
3111                         tem = XCDR(fexp);
3112                         negate = Fcar(tem);
3113                         if (!NILP(tem))
3114                                 return NILP(call1(Qfeaturep, negate)) ? Qt :
3115                                     Qnil;
3116                         else
3117                                 return Fsignal(Qinvalid_read_syntax,
3118                                                list1(tem));
3119                 } else if (EQ(tem, Qand)) {
3120                         tem = XCDR(fexp);
3121                         /* Use Fcar/Fcdr for error-checking. */
3122                         while (!NILP(tem) && !NILP(call1(Qfeaturep, Fcar(tem)))) {
3123                                 tem = Fcdr(tem);
3124                         }
3125                         return NILP(tem) ? Qt : Qnil;
3126                 } else if (EQ(tem, Qor)) {
3127                         tem = XCDR(fexp);
3128                         /* Use Fcar/Fcdr for error-checking. */
3129                         while (!NILP(tem) && NILP(call1(Qfeaturep, Fcar(tem)))) {
3130                                 tem = Fcdr(tem);
3131                         }
3132                         return NILP(tem) ? Qnil : Qt;
3133                 } else {
3134                         return Fsignal(Qinvalid_read_syntax, list1(XCDR(fexp)));
3135                 }
3136         } else {
3137                 return Fsignal(Qinvalid_read_syntax, list1(fexp));
3138         }
3139 }
3140 #endif                          /* FEATUREP_SYNTAX */
3141
3142 DEFUN("provide", Fprovide, 1, 1, 0,     /*
3143 Announce that FEATURE is a feature of the current Emacs.
3144 This function updates the value of the variable `features'.
3145 */
3146       (feature))
3147 {
3148         Lisp_Object tem;
3149         CHECK_SYMBOL(feature);
3150         if (!NILP(Vautoload_queue))
3151                 Vautoload_queue =
3152                     Fcons(Fcons(Vfeatures, Qnil), Vautoload_queue);
3153         tem = Fmemq(feature, Vfeatures);
3154         if (NILP(tem))
3155                 Vfeatures = Fcons(feature, Vfeatures);
3156         LOADHIST_ATTACH(Fcons(Qprovide, feature));
3157         return feature;
3158 }
3159
3160 DEFUN("require", Frequire, 1, 2, 0,     /*
3161 If feature FEATURE is not loaded, load it from FILENAME.
3162 If FEATURE is not a member of the list `features', then the feature
3163 is not loaded; so load the file FILENAME.
3164 If FILENAME is omitted, the printname of FEATURE is used as the file name.
3165 */
3166       (feature, filename))
3167 {
3168         Lisp_Object tem;
3169
3170         CHECK_SYMBOL(feature);
3171         tem = Fmemq(feature, Vfeatures);
3172         LOADHIST_ATTACH(Fcons(Qrequire, feature));
3173
3174         if (!NILP(tem)) {
3175                 return feature;
3176         } else {
3177                 int speccount = specpdl_depth();
3178
3179                 /* Value saved here is to be restored into Vautoload_queue */
3180                 record_unwind_protect(un_autoload, Vautoload_queue);
3181                 Vautoload_queue = Qt;
3182
3183                 /* defined in code-files.el */
3184                 call4(Qload, NILP(filename) ? Fsymbol_name(feature) : filename,
3185                       Qnil, Qt, Qnil);
3186
3187                 tem = Fmemq(feature, Vfeatures);
3188                 if (NILP(tem))
3189                         error("Required feature %s was not provided",
3190                               string_data(XSYMBOL(feature)->name));
3191
3192                 /* Once loading finishes, don't undo it.  */
3193                 Vautoload_queue = Qt;
3194                 return unbind_to(speccount, feature);
3195         }
3196 }
3197
3198 DEFUN("revoke", Frevoke, 1, 1, 0,       /*
3199 Announce that FEATURE is no longer a feature of the current Emacs.
3200 */
3201       (feature))
3202 {
3203         CHECK_SYMBOL(feature);
3204         if (!NILP(Vautoload_queue))
3205                 Vautoload_queue =
3206                     Fcons(Fcons(Vfeatures, Qnil), Vautoload_queue);
3207
3208         if (LIKELY(CONSP(Vfeatures) && EQ(XCAR(Vfeatures), feature))) {
3209                 /* special case where feature is the head of 'features */
3210                 Vfeatures = XCDR(Vfeatures);
3211                 return feature;
3212         }
3213         for (Lisp_Object tmp = Vfeatures;
3214              CONSP(tmp) && CONSP(XCDR(tmp));
3215              tmp = XCDR(tmp)) {
3216                 if (EQ(XCAR(XCDR(tmp)), feature)) {
3217                         XCDR(tmp) = XCDR(XCDR(tmp));
3218                 }
3219                 return feature;
3220         }
3221         return Qnil;
3222 }
3223 \f
3224 /* base64 encode/decode functions.
3225
3226    Originally based on code from GNU recode.  Ported to FSF Emacs by
3227    Lars Magne Ingebrigtsen and Karl Heuer.  Ported to XEmacs and
3228    subsequently heavily hacked by Hrvoje Niksic.  */
3229
3230 #define MIME_LINE_LENGTH 72
3231
3232 #define IS_ASCII(Character) \
3233   ((Character) < 128)
3234 #define IS_BASE64(Character) \
3235   (IS_ASCII (Character) && base64_char_to_value[Character] >= 0)
3236
3237 /* Table of characters coding the 64 values.  */
3238 static char base64_value_to_char[64] = {
3239         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',       /*  0- 9 */
3240         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',       /* 10-19 */
3241         'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',       /* 20-29 */
3242         'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',       /* 30-39 */
3243         'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',       /* 40-49 */
3244         'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',       /* 50-59 */
3245         '8', '9', '+', '/'      /* 60-63 */
3246 };
3247
3248 /* Table of base64 values for first 128 characters.  */
3249 static short base64_char_to_value[128] = {
3250         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*   0-  9 */
3251         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  10- 19 */
3252         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  20- 29 */
3253         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*  30- 39 */
3254         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /*  40- 49 */
3255         54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /*  50- 59 */
3256         -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,      /*  60- 69 */
3257         5, 6, 7, 8, 9, 10, 11, 12, 13, 14,      /*  70- 79 */
3258         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /*  80- 89 */
3259         25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /*  90- 99 */
3260         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
3261         39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
3262         49, 50, 51, -1, -1, -1, -1, -1  /* 120-127 */
3263 };
3264
3265 /* The following diagram shows the logical steps by which three octets
3266    get transformed into four base64 characters.
3267
3268                  .--------.  .--------.  .--------.
3269                  |aaaaaabb|  |bbbbcccc|  |ccdddddd|
3270                  `--------'  `--------'  `--------'
3271                     6   2      4   4       2   6
3272                .--------+--------+--------+--------.
3273                |00aaaaaa|00bbbbbb|00cccccc|00dddddd|
3274                `--------+--------+--------+--------'
3275
3276                .--------+--------+--------+--------.
3277                |AAAAAAAA|BBBBBBBB|CCCCCCCC|DDDDDDDD|
3278                `--------+--------+--------+--------'
3279
3280    The octets are divided into 6 bit chunks, which are then encoded into
3281    base64 characters.  */
3282
3283 #define ADVANCE_INPUT(c, stream)                                \
3284  ((ec = Lstream_get_emchar (stream)) == -1 ? 0 :                \
3285   ((ec > 255) ?                                                 \
3286    (signal_simple_error ("Non-ascii character in base64 input", \
3287                          make_char (ec)), 0)                    \
3288    : (c = (Bufbyte)ec), 1))
3289
3290 static Bytind base64_encode_1(Lstream * istream, Bufbyte * to, int line_break)
3291 {
3292         EMACS_INT counter = 0;
3293         Bufbyte *e = to;
3294         Emchar ec;
3295         unsigned int value;
3296
3297         while (1) {
3298                 Bufbyte c;
3299                 if (!ADVANCE_INPUT(c, istream))
3300                         break;
3301
3302                 /* Wrap line every 76 characters.  */
3303                 if (line_break) {
3304                         if (counter < MIME_LINE_LENGTH / 4)
3305                                 counter++;
3306                         else {
3307                                 *e++ = '\n';
3308                                 counter = 1;
3309                         }
3310                 }
3311
3312                 /* Process first byte of a triplet.  */
3313                 *e++ = base64_value_to_char[0x3f & c >> 2];
3314                 value = (0x03 & c) << 4;
3315
3316                 /* Process second byte of a triplet.  */
3317                 if (!ADVANCE_INPUT(c, istream)) {
3318                         *e++ = base64_value_to_char[value];
3319                         *e++ = '=';
3320                         *e++ = '=';
3321                         break;
3322                 }
3323
3324                 *e++ = base64_value_to_char[value | (0x0f & c >> 4)];
3325                 value = (0x0f & c) << 2;
3326
3327                 /* Process third byte of a triplet.  */
3328                 if (!ADVANCE_INPUT(c, istream)) {
3329                         *e++ = base64_value_to_char[value];
3330                         *e++ = '=';
3331                         break;
3332                 }
3333
3334                 *e++ = base64_value_to_char[value | (0x03 & c >> 6)];
3335                 *e++ = base64_value_to_char[0x3f & c];
3336         }
3337
3338         return e - to;
3339 }
3340
3341 #undef ADVANCE_INPUT
3342
3343 /* Get next character from the stream, except that non-base64
3344    characters are ignored.  This is in accordance with rfc2045.  EC
3345    should be an Emchar, so that it can hold -1 as the value for EOF.  */
3346 #define ADVANCE_INPUT_IGNORE_NONBASE64(ec, stream, streampos) do {      \
3347   ec = Lstream_get_emchar (stream);                                     \
3348   ++streampos;                                                          \
3349   /* IS_BASE64 may not be called with negative arguments so check for   \
3350      EOF first. */                                                      \
3351   if (ec < 0 || IS_BASE64 (ec) || ec == '=')                            \
3352     break;                                                              \
3353 } while (1)
3354
3355 #define STORE_BYTE(pos, val, ccnt) do {                                 \
3356   pos += set_charptr_emchar (pos, (Emchar)((unsigned char)(val)));      \
3357   ++ccnt;                                                               \
3358 } while (0)
3359
3360 static Bytind
3361 base64_decode_1(Lstream * istream, Bufbyte * to, Charcount * ccptr)
3362 {
3363         Charcount ccnt = 0;
3364         Bufbyte *e = to;
3365         EMACS_INT streampos = 0;
3366
3367         while (1) {
3368                 Emchar ec;
3369                 unsigned long value;
3370
3371                 /* Process first byte of a quadruplet.  */
3372                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3373                 if (ec < 0)
3374                         break;
3375                 if (ec == '=')
3376                         signal_simple_error
3377                             ("Illegal `=' character while decoding base64",
3378                              make_int(streampos));
3379                 value = base64_char_to_value[ec] << 18;
3380
3381                 /* Process second byte of a quadruplet.  */
3382                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3383                 if (ec < 0)
3384                         error("Premature EOF while decoding base64");
3385                 if (ec == '=')
3386                         signal_simple_error
3387                             ("Illegal `=' character while decoding base64",
3388                              make_int(streampos));
3389                 value |= base64_char_to_value[ec] << 12;
3390                 STORE_BYTE(e, value >> 16, ccnt);
3391
3392                 /* Process third byte of a quadruplet.  */
3393                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3394                 if (ec < 0)
3395                         error("Premature EOF while decoding base64");
3396
3397                 if (ec == '=') {
3398                         ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3399                         if (ec < 0)
3400                                 error("Premature EOF while decoding base64");
3401                         if (ec != '=')
3402                                 signal_simple_error
3403                                     ("Padding `=' expected but not found while decoding base64",
3404                                      make_int(streampos));
3405                         continue;
3406                 }
3407
3408                 value |= base64_char_to_value[ec] << 6;
3409                 STORE_BYTE(e, 0xff & value >> 8, ccnt);
3410
3411                 /* Process fourth byte of a quadruplet.  */
3412                 ADVANCE_INPUT_IGNORE_NONBASE64(ec, istream, streampos);
3413                 if (ec < 0)
3414                         error("Premature EOF while decoding base64");
3415                 if (ec == '=')
3416                         continue;
3417
3418                 value |= base64_char_to_value[ec];
3419                 STORE_BYTE(e, 0xff & value, ccnt);
3420         }
3421
3422         *ccptr = ccnt;
3423         return e - to;
3424 }
3425
3426 #undef ADVANCE_INPUT
3427 #undef ADVANCE_INPUT_IGNORE_NONBASE64
3428 #undef STORE_BYTE
3429
3430 DEFUN("base64-encode-region", Fbase64_encode_region, 2, 3, "r", /*
3431 Base64-encode the region between START and END.
3432 Return the length of the encoded text.
3433 Optional third argument NO-LINE-BREAK means do not break long lines
3434 into shorter lines.
3435 */
3436       (start, end, no_line_break))
3437 {
3438         Bufbyte *encoded;
3439         Bytind encoded_length;
3440         Charcount allength, length;
3441         struct buffer *buf = current_buffer;
3442         Bufpos begv, zv, old_pt = BUF_PT(buf);
3443         Lisp_Object input;
3444         int speccount = specpdl_depth();
3445
3446         get_buffer_range_char(buf, start, end, &begv, &zv, 0);
3447         barf_if_buffer_read_only(buf, begv, zv);
3448
3449         /* We need to allocate enough room for encoding the text.
3450            We need 33 1/3% more space, plus a newline every 76
3451            characters, and then we round up. */
3452         length = zv - begv;
3453         allength = length + length / 3 + 1;
3454         allength += allength / MIME_LINE_LENGTH + 1 + 6;
3455
3456         input = make_lisp_buffer_input_stream(buf, begv, zv, 0);
3457         /* We needn't multiply allength with MAX_EMCHAR_LEN because all the
3458            base64 characters will be single-byte.  */
3459         XMALLOC_ATOMIC_OR_ALLOCA(encoded, allength, Bufbyte);
3460         encoded_length = base64_encode_1(XLSTREAM(input), encoded,
3461                                          NILP(no_line_break));
3462         if (encoded_length > allength) {
3463                 abort();
3464         }
3465         Lstream_delete(XLSTREAM(input));
3466
3467         /* Now we have encoded the region, so we insert the new contents
3468            and delete the old.  (Insert first in order to preserve markers.)  */
3469         buffer_insert_raw_string_1(buf, begv, encoded, encoded_length, 0);
3470         XMALLOC_UNBIND(encoded, allength, speccount);
3471         buffer_delete_range(buf, begv + encoded_length, zv + encoded_length, 0);
3472
3473         /* Simulate FSF Emacs implementation of this function: if point was
3474            in the region, place it at the beginning.  */
3475         if (old_pt >= begv && old_pt < zv) {
3476                 BUF_SET_PT(buf, begv);
3477         }
3478
3479         /* We return the length of the encoded text. */
3480         return make_int(encoded_length);
3481 }
3482
3483 DEFUN("base64-encode-string", Fbase64_encode_string, 1, 2, 0,   /*
3484 Base64 encode STRING and return the result.
3485 Optional argument NO-LINE-BREAK means do not break long lines
3486 into shorter lines.
3487 */
3488       (string, no_line_break))
3489 {
3490         Charcount allength, length;
3491         Bytind encoded_length;
3492         Bufbyte *encoded;
3493         Lisp_Object input, result;
3494         int speccount = specpdl_depth();
3495
3496         CHECK_STRING(string);
3497
3498         length = XSTRING_CHAR_LENGTH(string);
3499         allength = length + length / 3 + 1;
3500         allength += allength / MIME_LINE_LENGTH + 1 + 6;
3501
3502         input = make_lisp_string_input_stream(string, 0, -1);
3503         XMALLOC_ATOMIC_OR_ALLOCA(encoded, allength, Bufbyte);
3504         encoded_length = base64_encode_1(XLSTREAM(input), encoded,
3505                                          NILP(no_line_break));
3506         if (encoded_length > allength) {
3507                 abort();
3508         }
3509         Lstream_delete(XLSTREAM(input));
3510         result = make_string(encoded, encoded_length);
3511         XMALLOC_UNBIND(encoded, allength, speccount);
3512         return result;
3513 }
3514
3515 DEFUN("base64-decode-region", Fbase64_decode_region, 2, 2, "r", /*
3516 Base64-decode the region between START and END.
3517 Return the length of the decoded text.
3518 If the region can't be decoded, return nil and don't modify the buffer.
3519 Characters out of the base64 alphabet are ignored.
3520 */
3521       (start, end))
3522 {
3523         struct buffer *buf = current_buffer;
3524         Bufpos begv, zv, old_pt = BUF_PT(buf);
3525         Bufbyte *decoded;
3526         Bytind decoded_length;
3527         Charcount length, cc_decoded_length;
3528         Lisp_Object input;
3529         int speccount = specpdl_depth();
3530
3531         get_buffer_range_char(buf, start, end, &begv, &zv, 0);
3532         barf_if_buffer_read_only(buf, begv, zv);
3533
3534         length = zv - begv;
3535
3536         input = make_lisp_buffer_input_stream(buf, begv, zv, 0);
3537         /* We need to allocate enough room for decoding the text. */
3538         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3539         decoded_length =
3540                 base64_decode_1(XLSTREAM(input), decoded, &cc_decoded_length);
3541         if (decoded_length > length * MAX_EMCHAR_LEN) {
3542                 abort();
3543         }
3544         Lstream_delete(XLSTREAM(input));
3545
3546         /* Now we have decoded the region, so we insert the new contents
3547            and delete the old.  (Insert first in order to preserve markers.)  */
3548         BUF_SET_PT(buf, begv);
3549         buffer_insert_raw_string_1(buf, begv, decoded, decoded_length, 0);
3550         XMALLOC_UNBIND(decoded, length * MAX_EMCHAR_LEN, speccount);
3551         buffer_delete_range(buf, begv + cc_decoded_length,
3552                             zv + cc_decoded_length, 0);
3553
3554         /* Simulate FSF Emacs implementation of this function: if point was
3555            in the region, place it at the beginning.  */
3556         if (old_pt >= begv && old_pt < zv) {
3557                 BUF_SET_PT(buf, begv);
3558         }
3559
3560         return make_int(cc_decoded_length);
3561 }
3562
3563 DEFUN("base64-decode-string", Fbase64_decode_string, 1, 1, 0,   /*
3564 Base64-decode STRING and return the result.
3565 Characters out of the base64 alphabet are ignored.
3566 */
3567       (string))
3568 {
3569         Bufbyte *decoded;
3570         Bytind decoded_length;
3571         Charcount length, cc_decoded_length;
3572         Lisp_Object input, result;
3573         int speccount = specpdl_depth();
3574
3575         CHECK_STRING(string);
3576
3577         length = XSTRING_CHAR_LENGTH(string);
3578         /* We need to allocate enough room for decoding the text. */
3579         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3580
3581         input = make_lisp_string_input_stream(string, 0, -1);
3582         decoded_length = base64_decode_1(XLSTREAM(input), decoded,
3583                                          &cc_decoded_length);
3584         if (decoded_length > length * MAX_EMCHAR_LEN) {
3585                 abort();
3586         }
3587         Lstream_delete(XLSTREAM(input));
3588
3589         result = make_string(decoded, decoded_length);
3590         XMALLOC_UNBIND(decoded, length * MAX_EMCHAR_LEN, speccount);
3591         return result;
3592 }
3593 \f
3594 /* base16 encode/decode functions. */
3595 static Bytind
3596 base16_encode_1(Lstream * istream, int length, Bufbyte * to)
3597 {
3598         Emchar ec;
3599         int i;
3600
3601         for (i=0; i < length; i++) {
3602                 ec = Lstream_get_emchar (istream);
3603                 sprintf((char *)to+2*i,"%02x", ec);
3604         }
3605
3606         return 1;
3607 }
3608 static Bytind
3609 base16_decode_1(Lstream * istream, int length, Bufbyte * to)
3610 {
3611         Emchar ec;
3612         Emchar high = 0, low = 0;
3613         int high_set_p = 0, ignore_p = 0;
3614         int i = 0;
3615
3616         /* high and low perform flip flop operation */
3617         while (1) {
3618                 ec = Lstream_get_emchar (istream);
3619                 if (ec < 0)
3620                         break;
3621                 if (isdigit(ec))
3622                         low = ec - '0';
3623                 else if (isupper(ec))
3624                         low = ec - 'A' + 10;
3625                 else if (islower(ec))
3626                         low = ec - 'a' + 10;
3627                 else 
3628                         ignore_p = 1;
3629
3630                 if (low < 0 || low >= 16)
3631                         ignore_p = 1;
3632
3633                 if (!ignore_p) {
3634                         if (!high_set_p) {
3635                                 high = low;
3636                                 high_set_p = 1;
3637                         } else {
3638                                 to[i] = high*16+low;
3639                                 i++;
3640                                 high_set_p = 0;
3641                         }
3642                 } else
3643                         ignore_p = 0;
3644         }
3645
3646         return i;
3647 }
3648 DEFUN("base16-encode-string", Fbase16_encode_string, 1, 1, 0, /*
3649 Base16 encode (i.e. hex dump) STRING and return the result.
3650 Optional argument NO-LINE-BREAK means do not break long lines
3651 into shorter lines.
3652 */
3653       (string))
3654 {
3655         Charcount length;
3656         Bufbyte *encoded;
3657         Lisp_Object input, result;
3658         int speccount = specpdl_depth();
3659
3660         CHECK_STRING(string);
3661
3662         length = XSTRING_CHAR_LENGTH(string);
3663
3664         input = make_lisp_string_input_stream(string, 0, -1);
3665         XMALLOC_ATOMIC_OR_ALLOCA(encoded, 2*length, Bufbyte);
3666         base16_encode_1(XLSTREAM(input), length, encoded);
3667         Lstream_delete(XLSTREAM(input));
3668         result = make_string(encoded, 2*length);
3669         XMALLOC_UNBIND(encoded, 2*length, speccount);
3670
3671         XSTRING(result)->plist = XSTRING(string)->plist;
3672
3673         return result;
3674 }
3675
3676 DEFUN("base16-decode-string", Fbase16_decode_string, 1, 1, 0, /*
3677 Base16-decode (i.e. read hex data from) STRING and return the result.
3678 Characters out of the base16 alphabet are ignored.
3679 */
3680       (string))
3681 {
3682         Bufbyte *decoded;
3683         Bytind decoded_length;
3684         Charcount length;
3685         Lisp_Object input, result;
3686         int speccount = specpdl_depth();
3687
3688         CHECK_STRING(string);
3689
3690         length = XSTRING_CHAR_LENGTH(string);
3691         /* We need to allocate enough room for decoding the text. */
3692         XMALLOC_ATOMIC_OR_ALLOCA(decoded, length, Bufbyte);
3693
3694         input = make_lisp_string_input_stream(string, 0, -1);
3695         decoded_length = base16_decode_1(XLSTREAM(input), length, decoded);
3696         Lstream_delete(XLSTREAM(input));
3697
3698         /* this result might be raw, we declare it binary */
3699         result = make_ext_string((char *)decoded, decoded_length, Qbinary);
3700         XMALLOC_UNBIND(decoded, length, speccount);
3701
3702         XSTRING(result)->plist = XSTRING(string)->plist;
3703
3704         return result;
3705 }
3706 \f
3707 Lisp_Object Qyes_or_no_p;
3708
3709 DEFUN("foobar", Ffoobar, 2, 2, 0, /*
3710 */
3711       (n, b))
3712 {
3713         return make_int(__nbits_right_of(XINT(n), XINT(b)));
3714 }
3715
3716 void syms_of_fns(void)
3717 {
3718         INIT_LRECORD_IMPLEMENTATION(bit_vector);
3719
3720         defsymbol(&Qstring_lessp, "string-lessp");
3721         defsymbol(&Qstring_greaterp, "string-greaterp");
3722         defsymbol(&Qidentity, "identity");
3723         defsymbol(&Qyes_or_no_p, "yes-or-no-p");
3724
3725         DEFSUBR(Ffoobar);
3726
3727         DEFSUBR(Fidentity);
3728         DEFSUBR(Frandom);
3729 #if defined(WITH_GMP) && defined(HAVE_MPZ)
3730         DEFSUBR(Frandomb);
3731 #endif
3732         DEFSUBR(Flength);
3733         DEFSUBR(Fsafe_length);
3734         DEFSUBR(Fstring_equal);
3735         DEFSUBR(Fstring_lessp);
3736         DEFSUBR(Fstring_greaterp);
3737         DEFSUBR(Fstring_modified_tick);
3738         DEFSUBR(Fappend);
3739         DEFSUBR(Fconcat);
3740         DEFSUBR(Fvconcat);
3741         DEFSUBR(Fbvconcat);
3742         DEFSUBR(Fcopy_list);
3743         DEFSUBR(Fcopy_sequence);
3744         DEFSUBR(Fcopy_alist);
3745         DEFSUBR(Fcopy_tree);
3746         DEFSUBR(Fsubstring);
3747         DEFSUBR(Fsubseq);
3748         DEFSUBR(Fnthcdr);
3749         DEFSUBR(Fnth);
3750         DEFSUBR(Felt);
3751         DEFSUBR(Flast);
3752         DEFSUBR(Fbutlast);
3753         DEFSUBR(Fnbutlast);
3754         DEFSUBR(Fmember);
3755         DEFSUBR(Fold_member);
3756         DEFSUBR(Fmemq);
3757         DEFSUBR(Fold_memq);
3758         DEFSUBR(Fassoc);
3759         DEFSUBR(Fold_assoc);
3760         DEFSUBR(Fassq);
3761         DEFSUBR(Fold_assq);
3762         DEFSUBR(Frassoc);
3763         DEFSUBR(Fold_rassoc);
3764         DEFSUBR(Frassq);
3765         DEFSUBR(Fold_rassq);
3766         DEFSUBR(Fdelete);
3767         DEFSUBR(Fold_delete);
3768         DEFSUBR(Fdelq);
3769         DEFSUBR(Fold_delq);
3770         DEFSUBR(Fremassoc);
3771         DEFSUBR(Fremassq);
3772         DEFSUBR(Fremrassoc);
3773         DEFSUBR(Fremrassq);
3774         DEFSUBR(Fnreverse);
3775         DEFSUBR(Freverse);
3776         DEFSUBR(Fsort);
3777         DEFSUBR(Fplists_eq);
3778         DEFSUBR(Fplists_equal);
3779         DEFSUBR(Flax_plists_eq);
3780         DEFSUBR(Flax_plists_equal);
3781         DEFSUBR(Fplist_get);
3782         DEFSUBR(Fplist_put);
3783         DEFSUBR(Fplist_remprop);
3784         DEFSUBR(Fplist_member);
3785         DEFSUBR(Fcheck_valid_plist);
3786         DEFSUBR(Fvalid_plist_p);
3787         DEFSUBR(Fcanonicalize_plist);
3788         DEFSUBR(Flax_plist_get);
3789         DEFSUBR(Flax_plist_put);
3790         DEFSUBR(Flax_plist_remprop);
3791         DEFSUBR(Flax_plist_member);
3792         DEFSUBR(Fcanonicalize_lax_plist);
3793         DEFSUBR(Fdestructive_alist_to_plist);
3794         DEFSUBR(Fget);
3795         DEFSUBR(Fput);
3796         DEFSUBR(Fremprop);
3797         DEFSUBR(Fobject_plist);
3798         DEFSUBR(Fequal);
3799         DEFSUBR(Fold_equal);
3800         DEFSUBR(Ffillarray);
3801         DEFSUBR(Fnconc);
3802         DEFSUBR(Freplace_list);
3803         DEFSUBR(Fload_average);
3804         DEFSUBR(Ffeaturep);
3805         DEFSUBR(Frequire);
3806         DEFSUBR(Fprovide);
3807         DEFSUBR(Frevoke);
3808         DEFSUBR(Fbase64_encode_region);
3809         DEFSUBR(Fbase64_encode_string);
3810         DEFSUBR(Fbase64_decode_region);
3811         DEFSUBR(Fbase64_decode_string);
3812         DEFSUBR(Fbase16_encode_string);
3813         DEFSUBR(Fbase16_decode_string);
3814
3815 #if 1
3816         map_LTX_init();
3817 #endif
3818 }
3819
3820 void init_provide_once(void)
3821 {
3822         DEFVAR_LISP("features", &Vfeatures      /*
3823 A list of symbols which are the features of the executing emacs.
3824 Used by `featurep' and `require', and altered by `provide'.
3825                                                  */ );
3826         Vfeatures = Qnil;
3827
3828         Fprovide(intern("base64"));
3829         Fprovide(intern("base16"));
3830
3831 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
3832 /* it's fuck ugly to define that here :( */
3833         Fprovide(intern("bdwgc"));
3834 #endif
3835 }