Bug-fix: 160 #'package-suppress, `load-suppress-alist' don't suppress anything
[sxemacs] / src / lread.c
1 /* Lisp parsing and input streams.
2    Copyright (C) 1985-1989, 1992-1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Tinker Systems.
4    Copyright (C) 1996 Ben Wing.
5    Copyright (C) 2004 Steve Youngs.
6
7 This file is part of SXEmacs
8
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
21
22
23 /* Synched up with: Mule 2.0, FSF 19.30. */
24
25 /* This file has been Mule-ized. */
26
27 #include <config.h>
28 #include "lisp.h"
29
30 #include "buffer.h"
31 #include "bytecode.h"
32 #include "elhash.h"
33 #include "lstream.h"
34 #include "opaque.h"
35 #ifdef FILE_CODING
36 #include "mule/file-coding.h"
37 #endif
38 #include "ent/ent.h"
39
40 #include "sysfile.h"
41
42 Lisp_Object Qread_char, Qstandard_input;
43 Lisp_Object Qvariable_documentation;
44 #define LISP_BACKQUOTES
45 #ifdef LISP_BACKQUOTES
46 /*
47    Nonzero means inside a new-style backquote
48    with no surrounding parentheses.
49    Fread initializes this to zero, so we need not specbind it
50    or worry about what happens to it when there is an error.
51
52 SXEmacs:
53    Nested backquotes are perfectly legal and fail utterly with
54    this silliness. */
55 static int new_backquote_flag, old_backquote_flag;
56 Lisp_Object Qbackquote, Qbacktick, Qcomma, Qcomma_at, Qcomma_dot;
57 #endif
58 Lisp_Object Qvariable_domain;   /* I18N3 */
59 Lisp_Object Vvalues, Vstandard_input, Vafter_load_alist;
60 Lisp_Object Qcurrent_load_list;
61 Lisp_Object Qload, Qload_file_name;
62 Lisp_Object Qfset;
63 Lisp_Object Vload_suppress_alist;
64
65 /* Hash-table that maps directory names to hashes of their contents.  */
66 static Lisp_Object Vlocate_file_hash_table;
67
68 Lisp_Object Qexists, Qreadable, Qwritable, Qexecutable;
69
70 Lisp_Object Vureaders;
71
72 /* See read_escape() for an explanation of this.  */
73 #if 0
74 int fail_on_bucky_bit_character_escapes;
75 #endif
76
77 /* This symbol is also used in fns.c */
78 #define FEATUREP_SYNTAX
79
80 #ifdef FEATUREP_SYNTAX
81 Lisp_Object Qfeaturep;
82 #endif
83
84 /* non-zero if inside `load' */
85 int load_in_progress;
86
87 /* Whether Fload_internal() should check whether the .el is newer
88    when loading .elc */
89 int load_warn_when_source_newer;
90 /* Whether Fload_internal() should check whether the .elc doesn't exist */
91 int load_warn_when_source_only;
92 /* Whether Fload_internal() should ignore .elc files when no suffix is given */
93 int load_ignore_elc_files;
94
95 /* Search path for files to be loaded. */
96 Lisp_Object Vload_path;
97
98 /* Search path for files when dumping. */
99 /* Lisp_Object Vdump_load_path; */
100
101 /* This is the user-visible association list that maps features to
102    lists of defs in their load files. */
103 Lisp_Object Vload_history;
104
105 /* This is used to build the load history.  */
106 Lisp_Object Vcurrent_load_list;
107
108 /* Name of file actually being read by `load'.  */
109 Lisp_Object Vload_file_name;
110
111 /* Same as Vload_file_name but not Lisp-accessible.  This ensures that
112    our #$ checks are reliable. */
113 Lisp_Object Vload_file_name_internal;
114
115 Lisp_Object Vload_file_name_internal_the_purecopy;
116
117 /* Function to use for reading, in `load' and friends.  */
118 Lisp_Object Vload_read_function;
119
120 /* The association list of objects read with the #n=object form.
121    Each member of the list has the form (n . object), and is used to
122    look up the object for the corresponding #n# construct.
123    It must be set to nil before all top-level calls to read0.  */
124 Lisp_Object Vread_objects;
125
126 /* Nonzero means load should forcibly load all dynamic doc strings.  */
127 /* Note that this always happens (with some special behavior) when
128    purify_flag is set. */
129 static int load_force_doc_strings;
130
131 /* List of descriptors now open for Fload_internal.  */
132 static Lisp_Object Vload_descriptor_list;
133
134 /* In order to implement "load_force_doc_strings", we keep
135    a list of all the compiled-function objects and such
136    that we have created in the process of loading this file.
137    See the rant below.
138
139    We specbind this just like Vload_file_name, so there's no
140    problems with recursive loading. */
141 static Lisp_Object Vload_force_doc_string_list;
142
143 /* A resizing-buffer stream used to temporarily hold data while reading */
144 static Lisp_Object Vread_buffer_stream;
145
146 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
147 Lisp_Object Vcurrent_compiled_function_annotation;
148 #endif
149
150 static int load_byte_code_version;
151
152 /* An array describing all known built-in structure types */
153 static structure_type_dynarr *the_structure_type_dynarr;
154
155 #if 0                           /* FSF defun hack */
156 /* When nonzero, read conses in pure space */
157 static int read_pure;
158 #endif
159
160 #if 0                           /* FSF stuff */
161 /* For use within read-from-string (this reader is non-reentrant!!)  */
162 static int read_from_string_index;
163 static int read_from_string_limit;
164 #endif
165
166 /* parser hook for resclass objects */
167 int(*ase_resc_rng_pred_f)(const char *cp) = NULL;
168 int(*ase_resc_elm_pred_f)(const char *cp) = NULL;
169 Lisp_Object(*ase_resc_rng_f)(char *cp) = NULL;
170 Lisp_Object(*ase_resc_elm_f)(char *cp) = NULL;
171 /* parser hook for perms */
172 Lisp_Object(*ase_permutation_f)(Lisp_Object);
173
174
175 #if 0                           /* More FSF implementation kludges. */
176 /* In order to implement load-force-doc-string, FSF saves the
177    #@-quoted string when it's seen, and goes back and retrieves
178    it later.
179
180    This approach is not only kludgy, but it in general won't work
181    correctly because there's no stack of remembered #@-quoted-strings
182    and those strings don't generally appear in the file in the same
183    order as their #$ references. (Yes, that is amazingly stupid too.
184
185    It would be trivially easy to always encode the #@ string
186    [which is a comment, anyway] in the middle of the (#$ . INT) cons
187    reference.  That way, it would be really easy to implement
188    load-force-doc-string in a non-kludgy way by just retrieving the
189    string immediately, because it's delivered on a silver platter.)
190
191    And finally, this stupid approach doesn't work under Mule, or
192    under MS-DOS or Windows NT, or under VMS, or any other place
193    where you either can't do an ftell() or don't get back a byte
194    count.
195
196    Oh, and one more lossage in this approach: If you attempt to
197    dump any ELC files that were compiled with `byte-compile-dynamic'
198    (as opposed to just `byte-compile-dynamic-docstring'), you
199    get hosed.  FMH! (as the illustrious JWZ was prone to utter)
200
201    The approach we use is clean, solves all of these problems, and is
202    probably easier to implement anyway.  We just save a list of all
203    the containing objects that have (#$ . INT) conses in them (this
204    will only be compiled-function objects and lists), and when the
205    file is finished loading, we go through and fill in all the
206    doc strings at once. */
207
208  /* This contains the last string skipped with #@.  */
209 static char *saved_doc_string;
210 /* Length of buffer allocated in saved_doc_string.  */
211 static int saved_doc_string_size;
212 /* Length of actual data in saved_doc_string.  */
213 static int saved_doc_string_length;
214 /* This is the file position that string came from.  */
215 static int saved_doc_string_position;
216 #endif
217
218 EXFUN(Fread_from_string, 3);
219
220 /* When errors are signaled, the actual readcharfun should not be used
221    as an argument if it is an lstream, so that lstreams don't escape
222    to the Lisp level.  */
223 #define READCHARFUN_MAYBE(x) (LSTREAMP (x)                                      \
224                               ? (build_string ("internal input stream"))        \
225                               : (x))
226 \f
227 static DOESNT_RETURN read_syntax_error(const char *string)
228 {
229         signal_error(Qinvalid_read_syntax,
230                      list1(build_translated_string(string)));
231 }
232
233 static Lisp_Object continuable_read_syntax_error(const char *string)
234 {
235         return Fsignal(Qinvalid_read_syntax,
236                        list1(build_translated_string(string)));
237 }
238 \f
239 /* Handle unreading and rereading of characters. */
240 static Emchar readchar(Lisp_Object readcharfun)
241 {
242         /* This function can GC */
243
244         if (BUFFERP(readcharfun)) {
245                 Emchar c;
246                 struct buffer *b = XBUFFER(readcharfun);
247
248                 if (!BUFFER_LIVE_P(b))
249                         error("Reading from killed buffer");
250
251                 if (BUF_PT(b) >= BUF_ZV(b))
252                         return -1;
253                 c = BUF_FETCH_CHAR(b, BUF_PT(b));
254                 BUF_SET_PT(b, BUF_PT(b) + 1);
255
256                 return c;
257         } else if (LSTREAMP(readcharfun)) {
258                 Emchar c = Lstream_get_emchar(XLSTREAM(readcharfun));
259 #ifdef DEBUG_SXEMACS            /* testing Mule */
260                 static int testing_mule = 0;    /* Change via debugger */
261                 if (testing_mule) {
262                         if (c >= 0x20 && c <= 0x7E)
263                                 stderr_out("%c", c);
264                         else if (c == '\n')
265                                 stderr_out("\\n\n");
266                         else
267                                 stderr_out("\\%o ", c);
268                 }
269 #endif                          /* testing Mule */
270                 return c;
271         } else if (MARKERP(readcharfun)) {
272                 Emchar c;
273                 Bufpos mpos = marker_position(readcharfun);
274                 struct buffer *inbuffer = XMARKER(readcharfun)->buffer;
275
276                 if (mpos >= BUF_ZV(inbuffer))
277                         return -1;
278                 c = BUF_FETCH_CHAR(inbuffer, mpos);
279                 set_marker_position(readcharfun, mpos + 1);
280                 return c;
281         } else {
282                 Lisp_Object tem = call0(readcharfun);
283
284                 if (!CHAR_OR_CHAR_INTP(tem))
285                         return -1;
286                 return XCHAR_OR_CHAR_INT(tem);
287         }
288 }
289
290 /* Unread the character C in the way appropriate for the stream READCHARFUN.
291    If the stream is a user function, call it with the char as argument.  */
292
293 static void unreadchar(Lisp_Object readcharfun, Emchar c)
294 {
295         if (c == -1)
296                 /* Don't back up the pointer if we're unreading the end-of-input mark,
297                    since readchar didn't advance it when we read it.  */
298                 ;
299         else if (BUFFERP(readcharfun))
300                 BUF_SET_PT(XBUFFER(readcharfun),
301                            BUF_PT(XBUFFER(readcharfun)) - 1);
302         else if (LSTREAMP(readcharfun)) {
303                 Lstream_unget_emchar(XLSTREAM(readcharfun), c);
304 #ifdef DEBUG_SXEMACS            /* testing Mule */
305                 {
306                         static int testing_mule = 0;    /* Set this using debugger */
307                         if (testing_mule)
308                                 fprintf(stderr,
309                                         (c >= 0x20 && c <= 0x7E) ? "UU%c" :
310                                         ((c == '\n') ? "UU\\n\n" : "UU\\%o"),
311                                         c);
312                 }
313 #endif
314         } else if (MARKERP(readcharfun))
315                 set_marker_position(readcharfun,
316                                     marker_position(readcharfun) - 1);
317         else
318                 call1(readcharfun, make_char(c));
319 }
320
321 static Lisp_Object read0(Lisp_Object readcharfun);
322 static Lisp_Object read1(Lisp_Object readcharfun);
323 /* allow_dotted_lists means that something like (foo bar . baz)
324    is acceptable.  If -1, means check for starting with defun
325    and make structure pure. (not implemented, probably for very
326    good reasons)
327 */
328 /*
329    If check_for_doc_references, look for (#$ . INT) doc references
330    in the list and record if load_force_doc_strings is non-zero.
331    (Such doc references will be destroyed during the loadup phase
332    by replacing with Qzero, because Snarf-documentation will fill
333    them in again.)
334
335    WARNING: If you set this, you sure as hell better not call
336    free_list() on the returned list here. */
337
338 static Lisp_Object read_list(Lisp_Object readcharfun,
339                              Emchar terminator,
340                              int allow_dotted_lists,
341                              int check_for_doc_references);
342 \f
343 static void readevalloop(Lisp_Object readcharfun,
344                          Lisp_Object sourcefile,
345                          Lisp_Object(*evalfun) (Lisp_Object), int printflag);
346
347 static Lisp_Object load_unwind(Lisp_Object stream)
348 {                               /* used as unwind-protect function in load */
349         Lstream_close(XLSTREAM(stream));
350         if (--load_in_progress < 0)
351                 load_in_progress = 0;
352         return Qnil;
353 }
354
355 static Lisp_Object load_descriptor_unwind(Lisp_Object oldlist)
356 {
357         Vload_descriptor_list = oldlist;
358         return Qnil;
359 }
360
361 static Lisp_Object load_file_name_internal_unwind(Lisp_Object oldval)
362 {
363         Vload_file_name_internal = oldval;
364         return Qnil;
365 }
366
367 static Lisp_Object
368 load_file_name_internal_the_purecopy_unwind(Lisp_Object oldval)
369 {
370         Vload_file_name_internal_the_purecopy = oldval;
371         return Qnil;
372 }
373
374 static Lisp_Object load_byte_code_version_unwind(Lisp_Object oldval)
375 {
376         load_byte_code_version = XINT(oldval);
377         return Qnil;
378 }
379
380 static inline int
381 suppressedp_loop(int len, char *nonreloc, Lisp_Object reloc)
382 {
383         EXTERNAL_LIST_LOOP_2(_acons_, Vload_suppress_alist) {
384                 if (CONSP(_acons_) && STRINGP(XCAR(_acons_))) {
385                         Lisp_Object name = XCAR(_acons_);
386                         if (XSTRING_LENGTH(name) == len &&
387                             !memcmp(XSTRING_DATA(name), nonreloc, len)) {
388                                 struct gcpro gcpro1;
389                                 Lisp_Object val;
390
391                                 GCPRO1(reloc);
392                                 val = Feval(XCDR(_acons_));
393                                 UNGCPRO;
394
395                                 if (!NILP(val))
396                                         return 1;
397                         }
398                 }
399         }
400         return 0;
401 }
402
403 static int
404 suppressedp(char *nonreloc, Lisp_Object reloc)
405 {
406 /* Check if NONRELOC/RELOC (an absolute filename) is suppressed according
407    to load-suppress-alist. */
408         int len;
409
410         if (!NILP (reloc)) {
411                 nonreloc = (char*)XSTRING_DATA(reloc);
412                 len = XSTRING_LENGTH(reloc);
413         } else {
414                 len = strlen(nonreloc);
415         }
416         if (len >= 4 && !strcmp(nonreloc + len - 4, ".elc"))
417                 len -= 4;
418         else if (len >= 3 && !strcmp(nonreloc + len - 3, ".el"))
419                 len -= 3;
420
421         return suppressedp_loop(len, nonreloc, reloc);
422 }
423
424 /* The plague is coming.
425
426    Ring around the rosy, pocket full of posy,
427    Ashes ashes, they all fall down.
428    */
429 void ebolify_bytecode_constants(Lisp_Object vector)
430 {
431         int len = XVECTOR_LENGTH(vector);
432         int i;
433
434         for (i = 0; i < len; i++) {
435                 Lisp_Object el = XVECTOR_DATA(vector)[i];
436
437                 /* We don't check for `eq', `equal', and the others that have
438                    bytecode opcodes.  This might lose if someone passes #'eq or
439                    something to `funcall', but who would really do that?  As
440                    they say in law, we've made a "good-faith effort" to
441                    unfuckify ourselves.  And doing it this way avoids screwing
442                    up args to `make-hash-table' and such.  As it is, we have to
443                    add an extra Ebola check in decode_weak_list_type(). --ben */
444                 if (EQ(el, Qassoc))
445                         el = Qold_assoc;
446                 else if (EQ(el, Qdelq))
447                         el = Qold_delq;
448 #if 0
449                 /* I think this is a bad idea because it will probably mess
450                    with keymap code. */
451                 else if (EQ(el, Qdelete))
452                         el = Qold_delete;
453 #endif
454                 else if (EQ(el, Qrassq))
455                         el = Qold_rassq;
456                 else if (EQ(el, Qrassoc))
457                         el = Qold_rassoc;
458
459                 XVECTOR_DATA(vector)[i] = el;
460         }
461 }
462
463 static Lisp_Object pas_de_lache_ici(int fd, Lisp_Object victim)
464 {
465         Lisp_Object tem;
466         EMACS_INT pos;
467
468         if (!INTP(XCDR(victim)))
469                 signal_simple_error("Bogus doc string reference", victim);
470         pos = XINT(XCDR(victim));
471         if (pos < 0)
472                 pos = -pos;     /* kludge to mark a user variable */
473         tem = unparesseuxify_doc_string(fd, pos, 0, Vload_file_name_internal);
474         if (!STRINGP(tem))
475                 signal_error(Qerror, tem);
476         return tem;
477 }
478
479 static Lisp_Object load_force_doc_string_unwind(Lisp_Object oldlist)
480 {
481         struct gcpro gcpro1;
482         Lisp_Object list = Vload_force_doc_string_list;
483         Lisp_Object tail;
484         int fd = XINT(XCAR(Vload_descriptor_list));
485
486         GCPRO1(list);
487         /* restore the old value first just in case an error occurs. */
488         Vload_force_doc_string_list = oldlist;
489
490         LIST_LOOP(tail, list) {
491                 Lisp_Object john = Fcar(tail);
492                 if (CONSP(john)) {
493                         assert(CONSP(XCAR(john)));
494                         assert(!purify_flag);   /* should have been handled in read_list() */
495                         XCAR(john) = pas_de_lache_ici(fd, XCAR(john));
496                 } else {
497                         Lisp_Object doc;
498
499                         assert(COMPILED_FUNCTIONP(john));
500                         if (CONSP(XCOMPILED_FUNCTION(john)->instructions)) {
501                                 struct gcpro ngcpro1;
502                                 Lisp_Object juan = (pas_de_lache_ici
503                                                     (fd,
504                                                      XCOMPILED_FUNCTION(john)->
505                                                      instructions));
506                                 Lisp_Object ivan;
507
508                                 NGCPRO1(juan);
509                                 ivan = Fread(juan);
510                                 if (!CONSP(ivan))
511                                         signal_simple_error
512                                             ("invalid lazy-loaded byte code",
513                                              ivan);
514                                 XCOMPILED_FUNCTION(john)->instructions =
515                                     XCAR(ivan);
516                                 /* v18 or v19 bytecode file.  Need to Ebolify. */
517                                 if (XCOMPILED_FUNCTION(john)->flags.ebolified
518                                     && VECTORP(XCDR(ivan)))
519                                         ebolify_bytecode_constants(XCDR(ivan));
520                                 XCOMPILED_FUNCTION(john)->constants =
521                                     XCDR(ivan);
522                                 NUNGCPRO;
523                         }
524                         doc =
525                             compiled_function_documentation(XCOMPILED_FUNCTION
526                                                             (john));
527                         if (CONSP(doc)) {
528                                 assert(!purify_flag);   /* should have been handled in
529                                                            read_compiled_function() */
530                                 doc = pas_de_lache_ici(fd, doc);
531                                 set_compiled_function_documentation
532                                     (XCOMPILED_FUNCTION(john), doc);
533                         }
534                 }
535         }
536
537         if (!NILP(list))
538                 free_list(list);
539
540         UNGCPRO;
541         return Qnil;
542 }
543
544 /* Close all descriptors in use for Fload_internal.
545    This is used when starting a subprocess.  */
546
547 void close_load_descs(void)
548 {
549         Lisp_Object tail;
550         LIST_LOOP(tail, Vload_descriptor_list)
551             close(XINT(XCAR(tail)));
552 }
553
554 #ifdef I18N3
555 Lisp_Object Vfile_domain;
556
557 Lisp_Object restore_file_domain(Lisp_Object val)
558 {
559         Vfile_domain = val;
560         return Qnil;
561 }
562 #endif                          /* I18N3 */
563
564 DEFUN("load-internal", Fload_internal, 1, 6, 0, /*
565 Execute a file of Lisp code named FILE; no coding-system frobbing.
566 This function is identical to `load' except for the handling of the
567 CODESYS and USED-CODESYS arguments under SXEmacs/Mule. (When Mule
568 support is not present, both functions are identical and ignore the
569 CODESYS and USED-CODESYS arguments.)
570
571 If support for Mule exists in this Emacs, the file is decoded
572 according to CODESYS; if omitted, no conversion happens.  If
573 USED-CODESYS is non-nil, it should be a symbol, and the actual coding
574 system that was used for the decoding is stored into it.  It will in
575 general be different from CODESYS if CODESYS specifies automatic
576 encoding detection or end-of-line detection.
577 */
578       (file, noerror, nomessage, nosuffix, codesys, used_codesys))
579 {
580         /* This function can GC */
581         int fd = -1;
582         int speccount = specpdl_depth();
583         int source_only = 0;
584         Lisp_Object newer = Qnil;
585         Lisp_Object handler = Qnil;
586         Lisp_Object found = Qnil;
587         struct gcpro gcpro1, gcpro2, gcpro3;
588         int reading_elc = 0;
589         int message_p = NILP(nomessage);
590 /*#ifdef DEBUG_SXEMACS*/
591         static Lisp_Object last_file_loaded;
592 /*#endif*/
593         struct stat s1, s2;
594         GCPRO3(file, newer, found);
595
596         CHECK_STRING(file);
597
598 /*#ifdef DEBUG_SXEMACS*/
599         if (purify_flag && noninteractive) {
600                 message_p = 1;
601                 last_file_loaded = file;
602         }
603 /*#endif / * DEBUG_SXEMACS */
604
605         /* If file name is magic, call the handler.  */
606         handler = Ffind_file_name_handler(file, Qload);
607         if (!NILP(handler))
608                 RETURN_UNGCPRO(call5(handler, Qload, file, noerror,
609                                      nomessage, nosuffix));
610
611         /* Do this after the handler to avoid
612            the need to gcpro noerror, nomessage and nosuffix.
613            (Below here, we care only whether they are nil or not.)  */
614         file = Fsubstitute_in_file_name(file);
615 #ifdef FILE_CODING
616         if (!NILP(used_codesys))
617                 CHECK_SYMBOL(used_codesys);
618 #endif
619
620         /* Avoid weird lossage with null string as arg,
621            since it would try to load a directory as a Lisp file.
622            Unix truly sucks. */
623         if (XSTRING_LENGTH(file) > 0) {
624                 char *foundstr;
625                 int foundlen;
626
627                 fd = locate_file(Vload_path, file,
628                                  ((!NILP(nosuffix))
629                                   ? Qnil
630                                   : build_string(load_ignore_elc_files
631                                                  ? ".el:"
632                                                  : ".elc:.el:")), &found, -1);
633
634                 if (fd < 0) {
635                         if (NILP(noerror)) {
636                                 signal_file_error("Cannot open load file",
637                                                   file);
638                         } else {
639                                 UNGCPRO;
640                                 return Qnil;
641                         }
642                 }
643
644                 foundlen = XSTRING_LENGTH(found);
645                 foundstr = (char *)alloca( foundlen+ 1);
646                 strncpy(foundstr, (char *)XSTRING_DATA(found), foundlen+1);
647
648
649                 /* The omniscient JWZ thinks this is worthless, but I beg to
650                    differ. --ben */
651                 if (load_ignore_elc_files) {
652                         newer = Ffile_name_nondirectory(found);
653                 } else if (load_warn_when_source_newer &&
654                            !memcmp(".elc", foundstr + foundlen - 4, 4)) {
655                         if (!fstat(fd, &s1)) {  /* can't fail, right? */
656                                 int result;
657                                 /* temporarily hack the 'c' off the end of the
658                                    filename */
659                                 foundstr[foundlen - 1] = '\0';
660                                 result = sxemacs_stat(foundstr, &s2);
661                                 if (result >= 0 &&
662                                     (unsigned)s1.st_mtime <
663                                     (unsigned)s2.st_mtime) {
664                                         Lisp_Object newer_name =
665                                                 make_string((Bufbyte*)foundstr,
666                                                             foundlen - 1);
667                                         struct gcpro nngcpro1;
668                                         NNGCPRO1(newer_name);
669                                         newer = Ffile_name_nondirectory(
670                                                 newer_name);
671                                         NNUNGCPRO;
672                                 }
673                                 /* put the 'c' back on (kludge-o-rama) */
674                                 foundstr[foundlen - 1] = 'c';
675                         }
676                 } else if (load_warn_when_source_only &&
677                            /* `found' ends in ".el" */
678                            !memcmp(".el", foundstr + foundlen - 3, 3) &&
679                            /* `file' does not end in ".el" */
680                            memcmp(".el",
681                                   XSTRING_DATA(file) + XSTRING_LENGTH(file) - 3,
682                                   3)) {
683                         source_only = 1;
684                 }
685
686                 if (!memcmp(".elc", foundstr + foundlen - 4, 4))
687                         reading_elc = 1;
688         }
689 #define PRINT_LOADING_MESSAGE(done)                                     \
690         do {                                                            \
691                 if (load_ignore_elc_files) {                            \
692                         if (message_p) {                                \
693                                 message("Loading %s..." done,           \
694                                         XSTRING_DATA(newer));           \
695                         }                                               \
696                 } else if (!NILP(newer)) {                              \
697                         message("Loading %s..." done " (file %s is newer)", \
698                                 XSTRING_DATA(file),                     \
699                                 XSTRING_DATA(newer));                   \
700                 } else if (source_only) {                               \
701                         Lisp_Object tmp = Ffile_name_nondirectory(file); \
702                         message("Loading %s..." done                    \
703                                 " (file %s.elc does not exist)",        \
704                                 XSTRING_DATA(file),                     \
705                                 XSTRING_DATA(tmp)); \
706                 } else if (message_p) {                                 \
707                         message("Loading %s..." done,                   \
708                                 XSTRING_DATA(file));                    \
709                 }                                                       \
710         } while (0)
711
712         PRINT_LOADING_MESSAGE("");
713
714         {
715                 /* Lisp_Object's must be malloc'ed, not stack-allocated */
716                 Lisp_Object lstrm = Qnil;
717                 const int block_size = 8192;
718                 struct gcpro ngcpro1;
719
720                 NGCPRO1(lstrm);
721                if (fd < 0)
722                       signal_file_error("Cannot open load file", file);
723
724                 lstrm = make_filedesc_input_stream(fd, 0, -1, LSTR_CLOSING);
725                 /* 64K is used for normal files; 8K should be OK here because
726                  * Lisp files aren't really all that big. */
727                 Lstream_set_buffering(XLSTREAM(lstrm),
728                                       LSTREAM_BLOCKN_BUFFERED, block_size);
729 #ifdef FILE_CODING
730                 lstrm = make_decoding_input_stream(
731                         XLSTREAM(lstrm), Fget_coding_system(codesys));
732                 Lstream_set_buffering(XLSTREAM(lstrm),
733                                       LSTREAM_BLOCKN_BUFFERED, block_size);
734 #endif
735                 /* NOTE: Order of these is very important.
736                  * Don't rearrange them. */
737                 record_unwind_protect(load_unwind, lstrm);
738                 record_unwind_protect(load_descriptor_unwind,
739                                       Vload_descriptor_list);
740                 record_unwind_protect(load_file_name_internal_unwind,
741                                       Vload_file_name_internal);
742                 record_unwind_protect(
743                         load_file_name_internal_the_purecopy_unwind,
744                         Vload_file_name_internal_the_purecopy);
745                 record_unwind_protect(load_force_doc_string_unwind,
746                                       Vload_force_doc_string_list);
747                 Vload_file_name_internal = found;
748                 Vload_file_name_internal_the_purecopy = Qnil;
749                 specbind(Qload_file_name, found);
750                 Vload_descriptor_list =
751                         Fcons(make_int(fd), Vload_descriptor_list);
752                 Vload_force_doc_string_list = Qnil;
753 #ifdef I18N3
754                 record_unwind_protect(restore_file_domain, Vfile_domain);
755                 /* set it to nil; a call to #'domain will set it. */
756                 Vfile_domain = Qnil;
757 #endif
758                 load_in_progress++;
759
760                 /* Now determine what sort of ELC file we're reading in. */
761                 record_unwind_protect(load_byte_code_version_unwind,
762                                       make_int(load_byte_code_version));
763                 if (reading_elc) {
764                         char elc_header[8];
765                         int num_read;
766
767                         num_read = Lstream_read(XLSTREAM(lstrm), elc_header, 8);
768                         if (num_read < 8 || strncmp(elc_header, ";ELC", 4)) {
769                                 /* Huh?  Probably not a valid ELC file. */
770                                 /* no Ebolification needed */
771                                 load_byte_code_version = 100;
772                                 Lstream_unread(XLSTREAM(lstrm), elc_header,
773                                                num_read);
774                         } else {
775                                 load_byte_code_version = elc_header[4];
776                         }
777                 } else {
778                         /* no Ebolification needed */
779                         load_byte_code_version = 100;
780                 }
781
782                 readevalloop(lstrm, file, Feval, 0);
783 #ifdef FILE_CODING
784                 if (!NILP(used_codesys)) {
785                         Lisp_Object tmp =
786                                 decoding_stream_coding_system(XLSTREAM(lstrm));
787                         Fset(used_codesys, XCODING_SYSTEM_NAME(tmp));
788                 }
789 #endif
790                 unbind_to(speccount, Qnil);
791
792                 NUNGCPRO;
793         }
794
795         {
796                 Lisp_Object tem;
797                 /* #### Disgusting kludge */
798                 /* Run any load-hooks for this file.  */
799                 /* #### An even more disgusting kludge.  There is horrible code */
800                 /* that is relying on the fact that dumped lisp files are found */
801                 /* via `load-path' search. */
802                 Lisp_Object name = file;
803
804                 if (!NILP(Ffile_name_absolute_p(file))) {
805                         name = Ffile_name_nondirectory(file);
806                 }
807
808                 {
809                         struct gcpro ngcpro1;
810
811                         NGCPRO1(name);
812                         tem = Fassoc(name, Vafter_load_alist);
813                         NUNGCPRO;
814                 }
815                 if (!NILP(tem)) {
816                         struct gcpro ngcpro1;
817
818                         NGCPRO1(tem);
819                         /* Use eval so that errors give a semi-meaningful
820                          * backtrace.  --Stig */
821                         tem = Fcons(Qprogn, Fcdr(tem));
822                         Feval(tem);
823                         NUNGCPRO;
824                 }
825         }
826
827 /*#ifdef DEBUG_SXEMACS*/
828         if (purify_flag && noninteractive) {
829                 if (!EQ(last_file_loaded, file)) {
830                         message("Loading %s ...done", XSTRING_DATA(file));
831                 }
832         }
833 /*#endif / * DEBUG_SXEMACS */
834
835         if (!noninteractive) {
836                 PRINT_LOADING_MESSAGE("done");
837         }
838         UNGCPRO;
839         return Qt;
840 }
841 \f
842 /* ------------------------------- */
843 /*          locate_file            */
844 /* ------------------------------- */
845
846 static int decode_mode_1(Lisp_Object mode)
847 {
848         if (EQ(mode, Qexists))
849                 return F_OK;
850         else if (EQ(mode, Qexecutable))
851                 return X_OK;
852         else if (EQ(mode, Qwritable))
853                 return W_OK;
854         else if (EQ(mode, Qreadable))
855                 return R_OK;
856         else if (INTP(mode)) {
857                 check_int_range(XINT(mode), 0, 7);
858                 return XINT(mode);
859         } else
860                 signal_simple_error("Invalid value", mode);
861         return 0;               /* unreached */
862 }
863
864 static int decode_mode(Lisp_Object mode)
865 {
866         if (NILP(mode))
867                 return R_OK;
868         else if (CONSP(mode)) {
869                 Lisp_Object tail;
870                 int mask = 0;
871                 EXTERNAL_LIST_LOOP(tail, mode)
872                     mask |= decode_mode_1(XCAR(tail));
873                 return mask;
874         } else
875                 return decode_mode_1(mode);
876 }
877
878 DEFUN("locate-file", Flocate_file, 2, 4, 0,     /*
879 Search for FILENAME through PATH-LIST.
880 If SUFFIXES is non-nil, it should be a list of suffixes to append to
881 file name when searching.
882
883 If MODE is non-nil, it should be a symbol or a list of symbol representing
884 requirements.  Allowed symbols are `exists', `executable', `writable', and
885 `readable'.  If MODE is nil, it defaults to `readable'.
886
887 Filenames are checked against `load-suppress-alist' to determine if they
888 should be ignored.
889
890 `locate-file' keeps hash tables of the directories it searches through,
891 in order to speed things up.  It tries valiantly to not get confused in
892 the face of a changing and unpredictable environment, but can occasionally
893 get tripped up.  In this case, you will have to call
894 `locate-file-clear-hashing' to get it back on track.  See that function
895 for details.
896 */
897       (filename, path_list, suffixes, mode))
898 {
899         /* This function can GC */
900         Lisp_Object tp;
901
902         CHECK_STRING(filename);
903
904         if (LISTP(suffixes)) {
905                 Lisp_Object tail;
906                 EXTERNAL_LIST_LOOP(tail, suffixes)
907                     CHECK_STRING(XCAR(tail));
908         } else
909                 CHECK_STRING(suffixes);
910
911         locate_file(path_list, filename, suffixes, &tp, decode_mode(mode));
912         return tp;
913 }
914
915 /* Recalculate the hash table for the given string.  DIRECTORY should
916    better have been through Fexpand_file_name() by now.  */
917
918 static Lisp_Object locate_file_refresh_hashing(Lisp_Object directory)
919 {
920         Lisp_Object hash =
921             make_directory_hash_table((char *)XSTRING_DATA(directory));
922
923         if (!NILP(hash))
924                 Fputhash(directory, hash, Vlocate_file_hash_table);
925         return hash;
926 }
927
928 /* find the hash table for the given directory, recalculating if necessary */
929
930 static Lisp_Object locate_file_find_directory_hash_table(Lisp_Object directory)
931 {
932         Lisp_Object hash = Fgethash(directory, Vlocate_file_hash_table, Qnil);
933         if (NILP(hash))
934                 return locate_file_refresh_hashing(directory);
935         else
936                 return hash;
937 }
938
939 /* The SUFFIXES argument in any of the locate_file* functions can be
940    nil, a list, or a string (for backward compatibility), with the
941    following semantics:
942
943    a) nil    - no suffix, just search for file name intact
944                (semantically different from "empty suffix list", which
945                would be meaningless.)
946    b) list   - list of suffixes to append to file name.  Each of these
947                must be a string.
948    c) string - colon-separated suffixes to append to file name (backward
949                compatibility).
950
951    All of this got hairy, so I decided to use a mapper.  Calling a
952    function for each suffix shouldn't slow things down, since
953    locate_file is rarely called with enough suffixes for funcalls to
954    make any difference.  */
955
956 /* Map FUN over SUFFIXES, as described above.  FUN will be called with a
957    char * containing the current file name, and ARG.  Mapping stops when
958    FUN returns non-zero. */
959 static void
960 locate_file_map_suffixes(Lisp_Object filename, Lisp_Object suffixes,
961                          int (*fun) (char *, void *), void *arg)
962 {
963         /* This function can GC */
964         char *fn;
965         int fn_len, max;
966
967         /* Calculate maximum size of any filename made from
968            this path element/specified file name and any possible suffix.  */
969         if (CONSP(suffixes)) {
970                 /* We must traverse the list, so why not do it right. */
971                 Lisp_Object tail;
972                 max = 0;
973                 LIST_LOOP(tail, suffixes) {
974                         if (XSTRING_LENGTH(XCAR(tail)) > max)
975                                 max = XSTRING_LENGTH(XCAR(tail));
976                 }
977         } else if (NILP(suffixes))
978                 max = 0;
979         else
980                 /* Just take the easy way out */
981                 max = XSTRING_LENGTH(suffixes);
982
983         fn_len = XSTRING_LENGTH(filename);
984         fn = (char *)alloca(max + fn_len + 1);
985         memcpy(fn, (char *)XSTRING_DATA(filename), fn_len);
986
987         /* Loop over suffixes.  */
988         if (!STRINGP(suffixes)) {
989                 if (NILP(suffixes)) {
990                         /* Case a) discussed in the comment above. */
991                         fn[fn_len] = 0;
992                         if ((*fun) (fn, arg))
993                                 return;
994                 } else {
995                         /* Case b) */
996                         Lisp_Object tail;
997                         LIST_LOOP(tail, suffixes) {
998                                 memcpy(fn + fn_len, XSTRING_DATA(XCAR(tail)),
999                                        XSTRING_LENGTH(XCAR(tail)));
1000                                 fn[fn_len + XSTRING_LENGTH(XCAR(tail))] = 0;
1001                                 if ((*fun) (fn, arg))
1002                                         return;
1003                         }
1004                 }
1005         } else {
1006                 /* Case c) */
1007                 const char *nsuffix = (const char *)XSTRING_DATA(suffixes);
1008
1009                 while (1) {
1010                         char *esuffix = (char *)strchr(nsuffix, ':');
1011                         int lsuffix =
1012                             esuffix ? esuffix - nsuffix : (int)strlen(nsuffix);
1013
1014                         /* Concatenate path element/specified name with the suffix.  */
1015                         strncpy(fn + fn_len, nsuffix, lsuffix);
1016                         fn[fn_len + lsuffix] = '\0';
1017
1018                         if ((*fun) (fn, arg))
1019                                 return;
1020
1021                         /* Advance to next suffix.  */
1022                         if (esuffix == 0)
1023                                 break;
1024                         nsuffix += lsuffix + 1;
1025                 }
1026         }
1027 }
1028
1029 struct locate_file_in_directory_mapper_closure {
1030         int fd;
1031         Lisp_Object *storeptr;
1032         int mode;
1033 };
1034
1035 static int locate_file_in_directory_mapper(char *fn, void *arg)
1036 {
1037         struct locate_file_in_directory_mapper_closure *closure =
1038             (struct locate_file_in_directory_mapper_closure *)arg;
1039         struct stat st;
1040
1041         /* Ignore file if it's a directory.  */
1042         if (sxemacs_stat(fn, &st) >= 0 && (st.st_mode & S_IFMT) != S_IFDIR) {
1043                 /* Check that we can access or open it.  */
1044                 if (closure->mode >= 0)
1045                         closure->fd = access(fn, closure->mode);
1046                 else
1047                         closure->fd = open(fn, O_RDONLY | OPEN_BINARY, 0);
1048
1049                 if (closure->fd >= 0) {
1050                         if (!suppressedp(fn, Qnil)) {
1051                                 /* We succeeded; return this descriptor and
1052                                    filename.  */
1053                                 if (closure->storeptr)
1054                                         *closure->storeptr = build_string(fn);
1055
1056                                 /* If we actually opened the file, set
1057                                    close-on-exec flag on the new descriptor so
1058                                    that subprocesses can't whack at it.  */
1059                                 if (closure->mode < 0)
1060                                         (void)fcntl(closure->fd,
1061                                                     F_SETFD, FD_CLOEXEC);
1062
1063                                 return 1;
1064                         } else {
1065                                 close(closure->fd);
1066                                 closure->fd=-1;
1067                         }
1068                 }
1069         }
1070         /* Keep mapping. */
1071         return 0;
1072 }
1073
1074 /* look for STR in PATH, optionally adding SUFFIXES.  DIRECTORY need
1075    not have been expanded.  */
1076
1077 static int
1078 locate_file_in_directory(Lisp_Object directory, Lisp_Object str,
1079                          Lisp_Object suffixes, Lisp_Object * storeptr, int mode)
1080 {
1081         /* This function can GC */
1082         struct locate_file_in_directory_mapper_closure closure;
1083         Lisp_Object filename = Qnil;
1084         struct gcpro gcpro1, gcpro2, gcpro3;
1085
1086         GCPRO3(directory, str, filename);
1087
1088         filename = Fexpand_file_name(str, directory);
1089         if (NILP(filename) || NILP(Ffile_name_absolute_p(filename)))
1090                 /* If there are non-absolute elts in PATH (eg ".") */
1091                 /* Of course, this could conceivably lose if luser sets
1092                    default-directory to be something non-absolute ... */
1093         {
1094                 if (NILP(filename))
1095                         /* NIL means current directory */
1096                         filename = current_buffer->directory;
1097                 else
1098                         filename = Fexpand_file_name(filename,
1099                                                      current_buffer->directory);
1100                 if (NILP(Ffile_name_absolute_p(filename))) {
1101                         /* Give up on this directory! */
1102                         UNGCPRO;
1103                         return -1;
1104                 }
1105         }
1106
1107         closure.fd = -1;
1108         closure.storeptr = storeptr;
1109         closure.mode = mode;
1110
1111         locate_file_map_suffixes(filename, suffixes,
1112                                  locate_file_in_directory_mapper, &closure);
1113
1114         UNGCPRO;
1115         return closure.fd;
1116 }
1117
1118 /* do the same as locate_file() but don't use any hash tables. */
1119
1120 static int
1121 locate_file_without_hash(Lisp_Object path, Lisp_Object str,
1122                          Lisp_Object suffixes, Lisp_Object * storeptr, int mode)
1123 {
1124         /* This function can GC */
1125         int absolute = !NILP(Ffile_name_absolute_p(str));
1126
1127         EXTERNAL_LIST_LOOP(path, path) {
1128                 int val =
1129                     locate_file_in_directory(XCAR(path), str, suffixes,
1130                                              storeptr,
1131                                              mode);
1132                 if (val >= 0)
1133                         return val;
1134                 if (absolute)
1135                         break;
1136         }
1137         return -1;
1138 }
1139
1140 static int locate_file_construct_suffixed_files_mapper(char *fn, void *arg)
1141 {
1142         Lisp_Object *tail = (Lisp_Object *) arg;
1143         *tail = Fcons(build_string(fn), *tail);
1144         return 0;
1145 }
1146
1147 /* Construct a list of all files to search for.
1148    It makes sense to have this despite locate_file_map_suffixes()
1149    because we need Lisp strings to access the hash-table, and it would
1150    be inefficient to create them on the fly, again and again for each
1151    path component.  See locate_file(). */
1152
1153 static Lisp_Object
1154 locate_file_construct_suffixed_files(Lisp_Object filename, Lisp_Object suffixes)
1155 {
1156         Lisp_Object tail = Qnil;
1157         struct gcpro gcpro1;
1158         GCPRO1(tail);
1159
1160         locate_file_map_suffixes(filename, suffixes,
1161                                  locate_file_construct_suffixed_files_mapper,
1162                                  &tail);
1163
1164         UNGCPRO;
1165         return Fnreverse(tail);
1166 }
1167
1168 DEFUN("locate-file-clear-hashing", Flocate_file_clear_hashing, 1, 1, 0, /*
1169 Clear the hash records for the specified list of directories.
1170 `locate-file' uses a hashing scheme to speed lookup, and will correctly
1171 track the following environmental changes:
1172
1173   -- changes of any sort to the list of directories to be searched.
1174   -- addition and deletion of non-shadowing files (see below) from the
1175      directories in the list.
1176   -- byte-compilation of a .el file into a .elc file.
1177
1178 `locate-file' will primarily get confused if you add a file that shadows
1179 \(i.e. has the same name as) another file further down in the directory list.
1180 In this case, you must call `locate-file-clear-hashing'.
1181
1182 If PATH is t, it means to fully clear all the accumulated hashes.  This
1183 can be used if the internal tables grow too large, or when dumping.
1184 */
1185       (path))
1186 {
1187         if (EQ(path, Qt))
1188                 Fclrhash(Vlocate_file_hash_table);
1189         else {
1190                 Lisp_Object pathtail;
1191                 EXTERNAL_LIST_LOOP(pathtail, path) {
1192                         Lisp_Object pathel =
1193                             Fexpand_file_name(XCAR(pathtail), Qnil);
1194                         Fremhash(pathel, Vlocate_file_hash_table);
1195                 }
1196         }
1197         return Qnil;
1198 }
1199
1200 /* Search for a file whose name is STR, looking in directories
1201    in the Lisp list PATH, and trying suffixes from SUFFIXES.
1202    SUFFIXES is a list of possible suffixes, or (for backward
1203    compatibility) a string containing possible suffixes separated by
1204    colons.
1205    On success, returns a file descriptor.  On failure, returns -1.
1206
1207    MODE nonnegative means don't open the files,
1208    just look for one for which access(file,MODE) succeeds.  In this case,
1209    returns a nonnegative value on success.  On failure, returns -1.
1210
1211    If STOREPTR is nonzero, it points to a slot where the name of
1212    the file actually found should be stored as a Lisp string.
1213    Nil is stored there on failure.
1214
1215    Called openp() in FSFmacs. */
1216
1217 int
1218 locate_file(Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
1219             Lisp_Object * storeptr, int mode)
1220 {
1221         /* This function can GC */
1222         Lisp_Object suffixtab = Qnil;
1223         Lisp_Object pathtail, pathel_expanded;
1224         int val;
1225         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1226
1227         if (storeptr)
1228                 *storeptr = Qnil;
1229
1230         /* Is it really necessary to gcpro path and str?  It shouldn't be
1231            unless some caller has fucked up.  There are known instances that
1232            call us with build_string("foo:bar") as SUFFIXES, though. */
1233         GCPRO4(path, str, suffixes, suffixtab);
1234
1235         /* if this filename has directory components, it's too complicated
1236            to try and use the hash tables. */
1237         if (!NILP(Ffile_name_directory(str))) {
1238                 val =
1239                     locate_file_without_hash(path, str, suffixes, storeptr,
1240                                              mode);
1241                 UNGCPRO;
1242                 return val;
1243         }
1244
1245         suffixtab = locate_file_construct_suffixed_files(str, suffixes);
1246
1247         EXTERNAL_LIST_LOOP(pathtail, path) {
1248                 Lisp_Object pathel = XCAR(pathtail);
1249                 Lisp_Object hash_table;
1250                 Lisp_Object tail;
1251                 int found = 0;
1252
1253                 /* If this path element is relative, we have to look by hand. */
1254                 if (NILP(pathel) || NILP(Ffile_name_absolute_p(pathel))) {
1255                         val =
1256                             locate_file_in_directory(pathel, str, suffixes,
1257                                                      storeptr, mode);
1258                         if (val >= 0) {
1259                                 UNGCPRO;
1260                                 return val;
1261                         }
1262                         continue;
1263                 }
1264
1265                 pathel_expanded = Fexpand_file_name(pathel, Qnil);
1266                 hash_table =
1267                     locate_file_find_directory_hash_table(pathel_expanded);
1268
1269                 if (!NILP(hash_table)) {
1270                         /* Loop over suffixes.  */
1271                         LIST_LOOP(tail, suffixtab)
1272                             if (!NILP(Fgethash(XCAR(tail), hash_table, Qnil))) {
1273                                 found = 1;
1274                                 break;
1275                         }
1276                 }
1277
1278                 if (found) {
1279                         /* This is a likely candidate.  Look by hand in this directory
1280                            so we don't get thrown off if someone byte-compiles a file. */
1281                         val =
1282                             locate_file_in_directory(pathel, str, suffixes,
1283                                                      storeptr, mode);
1284                         if (val >= 0) {
1285                                 UNGCPRO;
1286                                 return val;
1287                         }
1288
1289                         /* Hmm ...  the file isn't actually there. (Or possibly it's
1290                            a directory ...)  So refresh our hashing. */
1291                         locate_file_refresh_hashing(pathel_expanded);
1292                 }
1293         }
1294
1295         /* File is probably not there, but check the hard way just in case. */
1296         val = locate_file_without_hash(path, str, suffixes, storeptr, mode);
1297         if (val >= 0) {
1298                 /* Sneaky user added a file without telling us. */
1299                 Flocate_file_clear_hashing(path);
1300         }
1301
1302         UNGCPRO;
1303         return val;
1304 }
1305 \f
1306 #ifdef LOADHIST
1307
1308 /* Merge the list we've accumulated of globals from the current input source
1309    into the load_history variable.  The details depend on whether
1310    the source has an associated file name or not. */
1311
1312 static void build_load_history(int loading, Lisp_Object source)
1313 {
1314         REGISTER Lisp_Object tail, prev, newelt;
1315         REGISTER Lisp_Object tem, tem2;
1316         int foundit;
1317
1318 #if !defined(LOADHIST_DUMPED)
1319         /* Don't bother recording anything for preloaded files.  */
1320         if (purify_flag)
1321                 return;
1322 #endif
1323
1324         tail = Vload_history;
1325         prev = Qnil;
1326         foundit = 0;
1327         while (!NILP(tail)) {
1328                 tem = Fcar(tail);
1329
1330                 /* Find the feature's previous assoc list... */
1331                 if (internal_equal(source, Fcar(tem), 0)) {
1332                         foundit = 1;
1333
1334                         /*  If we're loading, remove it. */
1335                         if (loading) {
1336                                 if (NILP(prev))
1337                                         Vload_history = Fcdr(tail);
1338                                 else
1339                                         Fsetcdr(prev, Fcdr(tail));
1340                         }
1341
1342                         /*  Otherwise, cons on new symbols that are not already members.  */
1343                         else {
1344                                 tem2 = Vcurrent_load_list;
1345
1346                                 while (CONSP(tem2)) {
1347                                         newelt = XCAR(tem2);
1348
1349                                         if (NILP(Fmemq(newelt, tem)))
1350                                                 Fsetcar(tail, Fcons(Fcar(tem),
1351                                                                     Fcons
1352                                                                     (newelt,
1353                                                                      Fcdr
1354                                                                      (tem))));
1355
1356                                         tem2 = XCDR(tem2);
1357                                         QUIT;
1358                                 }
1359                         }
1360                 } else
1361                         prev = tail;
1362                 tail = Fcdr(tail);
1363                 QUIT;
1364         }
1365
1366         /* If we're loading, cons the new assoc onto the front of load-history,
1367            the most-recently-loaded position.  Also do this if we didn't find
1368            an existing member for the current source.  */
1369         if (loading || !foundit)
1370                 Vload_history = Fcons(Fnreverse(Vcurrent_load_list),
1371                                       Vload_history);
1372 }
1373
1374 #else                           /* !LOADHIST */
1375 #define build_load_history(x,y)
1376 #endif                          /* !LOADHIST */
1377 \f
1378 #if 0                           /* FSFmacs defun hack */
1379 Lisp_Object unreadpure(void)
1380 {                               /* Used as unwind-protect function in readevalloop */
1381         read_pure = 0;
1382         return Qnil;
1383 }
1384 #endif                          /* 0 */
1385
1386 static void
1387 readevalloop(Lisp_Object readcharfun,
1388              Lisp_Object sourcename,
1389              Lisp_Object(*evalfun) (Lisp_Object), int printflag)
1390 {
1391         /* This function can GC */
1392         REGISTER Emchar c;
1393         REGISTER Lisp_Object val = Qnil;
1394         int speccount = specpdl_depth();
1395         struct gcpro gcpro1, gcpro2;
1396         struct buffer *b = 0;
1397
1398         if (BUFFERP(readcharfun))
1399                 b = XBUFFER(readcharfun);
1400         else if (MARKERP(readcharfun))
1401                 b = XMARKER(readcharfun)->buffer;
1402
1403         /* Don't do this.  It is not necessary, and it needlessly exposes
1404            READCHARFUN (which can be a stream) to Lisp.  --hniksic */
1405         /*specbind (Qstandard_input, readcharfun); */
1406
1407         specbind(Qcurrent_load_list, Qnil);
1408
1409 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1410         Vcurrent_compiled_function_annotation = Qnil;
1411 #endif
1412         GCPRO2(val, sourcename);
1413
1414         LOADHIST_ATTACH(sourcename);
1415
1416         while (1) {
1417                 QUIT;
1418
1419                 if (b != 0 && !BUFFER_LIVE_P(b))
1420                         error("Reading from killed buffer");
1421
1422                 c = readchar(readcharfun);
1423                 if (c == ';') {
1424                         /* Skip comment */
1425                         while ((c = readchar(readcharfun)) != '\n' && c != -1)
1426                                 QUIT;
1427                         continue;
1428                 }
1429                 if (c < 0)
1430                         break;
1431
1432                 /* Ignore whitespace here, so we can detect eof.  */
1433                 if (c == ' ' || c == '\t' || c == '\n' || c == '\f'
1434                     || c == '\r')
1435                         continue;
1436
1437 #if 0                           /* FSFmacs defun hack */
1438                 if (purify_flag && c == '(') {
1439                         int count1 = specpdl_depth();
1440                         record_unwind_protect(unreadpure, Qnil);
1441                         val = read_list(readcharfun, ')', -1, 1);
1442                         unbind_to(count1, Qnil);
1443                 } else
1444 #else                           /* No "defun hack" -- Emacs 19 uses read-time syntax for bytecodes */
1445                 {
1446                         unreadchar(readcharfun, c);
1447                         Vread_objects = Qnil;
1448                         if (NILP(Vload_read_function))
1449                                 val = read0(readcharfun);
1450                         else
1451                                 val = call1(Vload_read_function, readcharfun);
1452                 }
1453 #endif
1454                 val = (*evalfun) (val);
1455                 if (printflag) {
1456                         Vvalues = Fcons(val, Vvalues);
1457                         if (EQ(Vstandard_output, Qt))
1458                                 Fprin1(val, Qnil);
1459                         else
1460                                 Fprint(val, Qnil);
1461                 }
1462         }
1463
1464         build_load_history(LSTREAMP(readcharfun) ||
1465                            /* This looks weird, but it's what's in FSFmacs */
1466                            (b ? BUF_NARROWED(b) : BUF_NARROWED(current_buffer)),
1467                            sourcename);
1468         UNGCPRO;
1469
1470         unbind_to(speccount, Qnil);
1471 }
1472
1473 DEFUN("eval-buffer", Feval_buffer, 0, 2, "bBuffer: ",   /*
1474 Execute BUFFER as Lisp code.
1475 Programs can pass two arguments, BUFFER and PRINTFLAG.
1476 BUFFER is the buffer to evaluate (nil means use current buffer).
1477 PRINTFLAG controls printing of output:
1478 nil means discard it; anything else is a stream for printing.
1479
1480 If there is no error, point does not move.  If there is an error,
1481 point remains at the end of the last character read from the buffer.
1482 */
1483       (buffer, printflag))
1484 {
1485         /* This function can GC */
1486         int speccount = specpdl_depth();
1487         Lisp_Object tem, buf;
1488
1489         if (NILP(buffer))
1490                 buf = Fcurrent_buffer();
1491         else
1492                 buf = Fget_buffer(buffer);
1493         if (NILP(buf))
1494                 error("No such buffer.");
1495
1496         if (NILP(printflag))
1497                 tem = Qsymbolp; /* #### #@[]*&$#*[& SI:NULL-STREAM */
1498         else
1499                 tem = printflag;
1500         specbind(Qstandard_output, tem);
1501         record_unwind_protect(save_excursion_restore, save_excursion_save());
1502         BUF_SET_PT(XBUFFER(buf), BUF_BEGV(XBUFFER(buf)));
1503         readevalloop(buf, XBUFFER(buf)->filename, Feval, !NILP(printflag));
1504
1505         return unbind_to(speccount, Qnil);
1506 }
1507
1508 #if 0
1509 xxDEFUN("eval-current-buffer", Feval_current_buffer, 0, 1, "",  /*
1510 Execute the current buffer as Lisp code.
1511 Programs can pass argument PRINTFLAG which controls printing of output:
1512 nil means discard it; anything else is stream for print.
1513
1514 If there is no error, point does not move.  If there is an error,
1515 point remains at the end of the last character read from the buffer.
1516                                                                  */
1517         (printflag)) {
1518         code omitted;
1519 }
1520 #endif                          /* 0 */
1521
1522 DEFUN("eval-region", Feval_region, 2, 3, "r",   /*
1523 Execute the region as Lisp code.
1524 When called from programs, expects two arguments START and END
1525 giving starting and ending indices in the current buffer
1526 of the text to be executed.
1527 Programs can pass third optional argument STREAM which controls output:
1528 nil means discard it; anything else is stream for printing it.
1529
1530 If there is no error, point does not move.  If there is an error,
1531 point remains at the end of the last character read from the buffer.
1532
1533 Note:  Before evaling the region, this function narrows the buffer to it.
1534 If the code being eval'd should happen to trigger a redisplay you may
1535 see some text temporarily disappear because of this.
1536 */
1537       (start, end, stream))
1538 {
1539         /* This function can GC */
1540         int speccount = specpdl_depth();
1541         Lisp_Object tem;
1542         Lisp_Object cbuf = Fcurrent_buffer();
1543
1544         if (NILP(stream))
1545                 tem = Qsymbolp; /* #### #@[]*&$#*[& SI:NULL-STREAM */
1546         else
1547                 tem = stream;
1548         specbind(Qstandard_output, tem);
1549
1550         if (NILP(stream))
1551                 record_unwind_protect(save_excursion_restore,
1552                                       save_excursion_save());
1553         record_unwind_protect(save_restriction_restore,
1554                               save_restriction_save());
1555
1556         /* This both uses start and checks its type.  */
1557         Fgoto_char(start, cbuf);
1558         Fnarrow_to_region(make_int(BUF_BEGV(current_buffer)), end, cbuf);
1559         readevalloop(cbuf, XBUFFER(cbuf)->filename, Feval, !NILP(stream));
1560
1561         return unbind_to(speccount, Qnil);
1562 }
1563 \f
1564 DEFUN("read", Fread, 0, 1, 0,   /*
1565 Read one Lisp expression as text from STREAM, return as Lisp object.
1566 If STREAM is nil, use the value of `standard-input' (which see).
1567 STREAM or the value of `standard-input' may be:
1568 a buffer (read from point and advance it)
1569 a marker (read from where it points and advance it)
1570 a function (call it with no arguments for each character,
1571 call it with a char as argument to push a char back)
1572 a string (takes text from string, starting at the beginning)
1573 t (read text line using minibuffer and use it).
1574 */
1575       (stream))
1576 {
1577         if (NILP(stream))
1578                 stream = Vstandard_input;
1579         if (EQ(stream, Qt))
1580                 stream = Qread_char;
1581
1582         Vread_objects = Qnil;
1583
1584 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1585         Vcurrent_compiled_function_annotation = Qnil;
1586 #endif
1587         if (EQ(stream, Qread_char)) {
1588                 Lisp_Object val = call1(Qread_from_minibuffer,
1589                                         build_translated_string
1590                                         ("Lisp expression: "));
1591                 return Fcar(Fread_from_string(val, Qnil, Qnil));
1592         }
1593
1594         if (STRINGP(stream))
1595                 return Fcar(Fread_from_string(stream, Qnil, Qnil));
1596
1597         return read0(stream);
1598 }
1599
1600 DEFUN("read-from-string", Fread_from_string, 1, 3, 0,   /*
1601 Read one Lisp expression which is represented as text by STRING.
1602 Returns a cons: (OBJECT-READ . FINAL-STRING-INDEX).
1603 START and END optionally delimit a substring of STRING from which to read;
1604 they default to 0 and (length STRING) respectively.
1605 */
1606       (string, start, end))
1607 {
1608         Bytecount startval, endval;
1609         Lisp_Object tem;
1610         Lisp_Object lispstream = Qnil;
1611         struct gcpro gcpro1;
1612
1613 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1614         Vcurrent_compiled_function_annotation = Qnil;
1615 #endif
1616         GCPRO1(lispstream);
1617         CHECK_STRING(string);
1618         get_string_range_byte(string, start, end, &startval, &endval,
1619                               GB_HISTORICAL_STRING_BEHAVIOR);
1620         lispstream = make_lisp_string_input_stream(string, startval,
1621                                                    endval - startval);
1622
1623         Vread_objects = Qnil;
1624
1625         tem = read0(lispstream);
1626         /* Yeah, it's ugly.  Gonna make something of it?
1627            At least our reader is reentrant ... */
1628         tem =
1629             (Fcons(tem, make_int
1630                    (bytecount_to_charcount
1631                     (XSTRING_DATA(string),
1632                      startval + Lstream_byte_count(XLSTREAM(lispstream))))));
1633         Lstream_delete(XLSTREAM(lispstream));
1634         UNGCPRO;
1635         return tem;
1636 }
1637
1638 static Lisp_Object
1639 ureader_find(Lisp_Object name)
1640 {
1641         return Fcdr(Fassoc(name, Vureaders));
1642 }
1643
1644 /*
1645  * NOTE:
1646  *  ureader_read() assumes that input starts with < character and
1647  *  should finish on matching > character.
1648  */
1649 static Lisp_Object
1650 ureader_read(Lisp_Object ureader_fun, Lisp_Object readcharfun)
1651 {
1652         Emchar c;
1653         unsigned int oparens = 0;
1654         struct gcpro gcpro1;
1655         Lisp_Object instr;
1656
1657         Lstream_rewind(XLSTREAM(Vread_buffer_stream));
1658         while ((c = readchar(readcharfun)) >= 0) {
1659                 if (c == '<')
1660                         oparens++;
1661                 else if (c == '>') {
1662                         if (oparens == 0)
1663                                 /* We got final closing paren */
1664                                 break;
1665                         else
1666                                 oparens--;
1667                 }
1668                 Lstream_put_emchar(XLSTREAM (Vread_buffer_stream), c);
1669                 QUIT;
1670         }
1671         if (c < 0)
1672                 return Fsignal(Qend_of_file,
1673                                list1(READCHARFUN_MAYBE(readcharfun)));
1674
1675         Lstream_flush(XLSTREAM(Vread_buffer_stream));
1676         GCPRO1(instr);
1677         instr = make_string(resizing_buffer_stream_ptr
1678                             (XLSTREAM(Vread_buffer_stream)),
1679                             Lstream_byte_count(XLSTREAM(Vread_buffer_stream)));
1680
1681         RETURN_UNGCPRO(call1(ureader_fun, instr));
1682 }
1683
1684 \f
1685 #ifdef LISP_BACKQUOTES
1686
1687 static Lisp_Object backquote_unwind(Lisp_Object ptr)
1688 {                               /* used as unwind-protect function in read0() */
1689         int *counter = (int *)get_opaque_ptr(ptr);
1690         if (--*counter < 0)
1691                 *counter = 0;
1692         free_opaque_ptr(ptr);
1693         return Qnil;
1694 }
1695
1696 #endif
1697
1698 /* Use this for recursive reads, in contexts where internal tokens
1699    are not allowed.  See also read1(). */
1700 static Lisp_Object read0(Lisp_Object readcharfun)
1701 {
1702         Lisp_Object val = read1(readcharfun);
1703
1704         if (CONSP(val) && UNBOUNDP(XCAR(val))) {
1705                 Emchar c = XCHAR(XCDR(val));
1706                 free_cons(XCONS(val));
1707                 return Fsignal(Qinvalid_read_syntax,
1708                                list1(Fchar_to_string(make_char(c))));
1709         }
1710
1711         return val;
1712 }
1713 \f
1714 static Emchar read_escape(Lisp_Object readcharfun)
1715 {
1716         /* This function can GC */
1717         Emchar c = readchar(readcharfun);
1718
1719         if (c < 0)
1720                 signal_error(Qend_of_file,
1721                              list1(READCHARFUN_MAYBE(readcharfun)));
1722
1723         switch (c) {
1724         case 'a':
1725                 return '\007';
1726         case 'b':
1727                 return '\b';
1728         case 'd':
1729                 return 0177;
1730         case 'e':
1731                 return 033;
1732         case 'f':
1733                 return '\f';
1734         case 'n':
1735                 return '\n';
1736         case 'r':
1737                 return '\r';
1738         case 't':
1739                 return '\t';
1740         case 'v':
1741                 return '\v';
1742         case '\n':
1743                 return -1;
1744
1745         case 'M':
1746                 c = readchar(readcharfun);
1747                 if (c < 0)
1748                         signal_error(Qend_of_file,
1749                                      list1(READCHARFUN_MAYBE(readcharfun)));
1750                 if (c != '-')
1751                         error("Invalid escape character syntax");
1752                 c = readchar(readcharfun);
1753                 if (c < 0)
1754                         signal_error(Qend_of_file,
1755                                      list1(READCHARFUN_MAYBE(readcharfun)));
1756                 if (c == '\\')
1757                         c = read_escape(readcharfun);
1758                 return c | 0200;
1759
1760                 /* Originally, FSF_KEYS provided a degree of FSF Emacs
1761                    compatibility by defining character "modifiers" alt, super,
1762                    hyper and shift to infest the characters (i.e. integers).
1763
1764                    However, this doesn't cut it for XEmacs 20, which
1765                    distinguishes characters from integers.  Without Mule, ?\H-a
1766                    simply returns ?a because every character is clipped into
1767                    0-255.  Under Mule it is much worse -- ?\H-a with FSF_KEYS
1768                    produces an illegal character, and moves us to crash-land.
1769
1770                    For these reasons, FSF_KEYS hack is useless and without hope
1771                    of ever working under XEmacs 20.  */
1772 #undef FSF_KEYS
1773
1774 #ifdef FSF_KEYS
1775 #define alt_modifier   (0x040000)
1776 #define super_modifier (0x080000)
1777 #define hyper_modifier (0x100000)
1778 #define shift_modifier (0x200000)
1779 /* fsf uses a different modifiers for meta and control.  Possibly
1780    byte_compiled code will still work fsfmacs, though... --Stig
1781
1782    #define ctl_modifier   (0x400000)
1783    #define meta_modifier  (0x800000)
1784 */
1785 #define FSF_LOSSAGE(mask)                                                       \
1786       if (fail_on_bucky_bit_character_escapes ||                                \
1787           ((c = readchar (readcharfun)) != '-'))                                \
1788         error ("Invalid escape character syntax");                              \
1789       c = readchar (readcharfun);                                               \
1790       if (c < 0)                                                                \
1791         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));   \
1792       if (c == '\\')                                                            \
1793         c = read_escape (readcharfun);                                          \
1794       return c | mask
1795
1796         case 'S':
1797                 FSF_LOSSAGE(shift_modifier);
1798         case 'H':
1799                 FSF_LOSSAGE(hyper_modifier);
1800         case 'A':
1801                 FSF_LOSSAGE(alt_modifier);
1802         case 's':
1803                 FSF_LOSSAGE(super_modifier);
1804 #undef alt_modifier
1805 #undef super_modifier
1806 #undef hyper_modifier
1807 #undef shift_modifier
1808 #undef FSF_LOSSAGE
1809
1810 #endif                          /* FSF_KEYS */
1811
1812         case 'C':
1813                 c = readchar(readcharfun);
1814                 if (c < 0)
1815                         signal_error(Qend_of_file,
1816                                      list1(READCHARFUN_MAYBE(readcharfun)));
1817                 if (c != '-')
1818                         error("Invalid escape character syntax");
1819         case '^':
1820                 c = readchar(readcharfun);
1821                 if (c < 0)
1822                         signal_error(Qend_of_file,
1823                                      list1(READCHARFUN_MAYBE(readcharfun)));
1824                 if (c == '\\')
1825                         c = read_escape(readcharfun);
1826                 /* FSFmacs junk for non-ASCII controls.
1827                    Not used here. */
1828                 if (c == '?')
1829                         return 0177;
1830                 else
1831                         return c & (0200 | 037);
1832
1833         case '0':
1834         case '1':
1835         case '2':
1836         case '3':
1837         case '4':
1838         case '5':
1839         case '6':
1840         case '7':
1841                 /* An octal escape, as in ANSI C.  */
1842                 {
1843                         REGISTER Emchar i = c - '0';
1844                         REGISTER int count = 0;
1845                         while (++count < 3) {
1846                                 if ((c = readchar(readcharfun)) >= '0'
1847                                     && c <= '7')
1848                                         i = (i << 3) + (c - '0');
1849                                 else {
1850                                         unreadchar(readcharfun, c);
1851                                         break;
1852                                 }
1853                         }
1854                         return i;
1855                 }
1856
1857         case 'x':
1858                 /* A hex escape, as in ANSI C, except that we only allow latin-1
1859                    characters to be read this way.  What is "\x4e03" supposed to
1860                    mean, anyways, if the internal representation is hidden?
1861                    This is also consistent with the treatment of octal escapes. */
1862                 {
1863                         REGISTER Emchar i = 0;
1864                         REGISTER int count = 0;
1865                         while (++count <= 2) {
1866                                 c = readchar(readcharfun);
1867                                 /* Remember, can't use isdigit(), isalpha() etc. on Emchars */
1868                                 if (c >= '0' && c <= '9')
1869                                         i = (i << 4) + (c - '0');
1870                                 else if (c >= 'a' && c <= 'f')
1871                                         i = (i << 4) + (c - 'a') + 10;
1872                                 else if (c >= 'A' && c <= 'F')
1873                                         i = (i << 4) + (c - 'A') + 10;
1874                                 else {
1875                                         unreadchar(readcharfun, c);
1876                                         break;
1877                                 }
1878                         }
1879                         return i;
1880                 }
1881
1882 #ifdef MULE
1883                 /* #### need some way of reading an extended character with
1884                    an escape sequence. */
1885 #endif
1886
1887         default:
1888                 return c;
1889         }
1890 }
1891 \f
1892 /* read symbol-constituent stuff into `Vread_buffer_stream'. */
1893 static Bytecount
1894 read_atom_0(Lisp_Object readcharfun, Emchar firstchar, int *saw_a_backslash)
1895 {
1896         /* This function can GC */
1897         Emchar c = ((firstchar) >= 0 ? firstchar : readchar(readcharfun));
1898         Lstream_rewind(XLSTREAM(Vread_buffer_stream));
1899
1900         *saw_a_backslash = 0;
1901
1902         while (c > 040          /* #### - comma should be here as should backquote */
1903                && !(c == '\"' || c == '\'' || c == ';' || c == '(' || c == ')'
1904 #ifndef HAVE_FPFLOAT
1905                     /* If we have floating-point support, then we need
1906                        to allow <digits><dot><digits>.  */
1907                     || c == '.'
1908 #endif                          /* not HAVE_FPFLOAT */
1909                     || c == '[' || c == ']' || c == '#')) {
1910                 if (c == '\\') {
1911                         c = readchar(readcharfun);
1912                         if (c < 0)
1913                                 signal_error(Qend_of_file,
1914                                              list1(READCHARFUN_MAYBE
1915                                                    (readcharfun)));
1916                         *saw_a_backslash = 1;
1917                 }
1918                 Lstream_put_emchar(XLSTREAM(Vread_buffer_stream), c);
1919                 QUIT;
1920                 c = readchar(readcharfun);
1921         }
1922
1923         if (c >= 0)
1924                 unreadchar(readcharfun, c);
1925         /* blasted terminating 0 */
1926         Lstream_put_emchar(XLSTREAM(Vread_buffer_stream), 0);
1927         Lstream_flush(XLSTREAM(Vread_buffer_stream));
1928
1929         return Lstream_byte_count(XLSTREAM(Vread_buffer_stream)) - 1;
1930 }
1931
1932 static Lisp_Object parse_integer(const Bufbyte * buf, Bytecount len, int base);
1933
1934 static Lisp_Object
1935 read_atom(Lisp_Object readcharfun, Emchar firstchar, int uninterned_symbol)
1936 {
1937         /* This function can GC */
1938         int saw_a_backslash;
1939         Bytecount len = read_atom_0(readcharfun, firstchar, &saw_a_backslash);
1940         char *read_ptr = (char *)
1941             resizing_buffer_stream_ptr(XLSTREAM(Vread_buffer_stream));
1942
1943         /* Is it an integer? */
1944         if (!(saw_a_backslash || uninterned_symbol)) {
1945                 /* If a token had any backslashes in it, it is disqualified from
1946                    being an integer or a float.  This means that 123\456 is a
1947                    symbol, as is \123 (which is the way (intern "123") prints).
1948                    Also, if token was preceded by #:, it's always a symbol.
1949                  */
1950                 char *p = read_ptr + len;
1951                 char *p1 = read_ptr;
1952
1953                 if (*p1 == '+' || *p1 == '-')
1954                         p1++;
1955                 if (p1 != p) {
1956                         int c;
1957
1958                         while (p1 != p && (c = *p1) >= '0' && c <= '9')
1959                                 p1++;
1960 #ifdef HAVE_FPFLOAT
1961                         /* Integers can have trailing decimal points.  */
1962                         if (p1 > read_ptr && p1 < p && *p1 == '.')
1963                                 p1++;
1964 #endif
1965                         if (p1 == p) {
1966                                 /* It is an integer. */
1967 #ifdef HAVE_FPFLOAT
1968                                 if (p1[-1] == '.')
1969                                         p1[-1] = '\0';
1970 #endif
1971                                 return parse_integer((Bufbyte*)read_ptr, len,
1972                                                      10);
1973                         }
1974                 }
1975 #if defined HAVE_MPQ && defined WITH_GMP
1976                 if (isbigq_string(read_ptr))
1977                         return read_bigq_string(read_ptr);
1978 #endif
1979 #if defined HAVE_MPFR && defined WITH_MPFR
1980                 if (isfloat_string(read_ptr) && (Vread_real_as == Qbigfr))
1981                         return read_bigfr_string(read_ptr);
1982 #endif  /* HAVE_MPFR */
1983 #if defined HAVE_MPF && defined WITH_GMP
1984                 if (isfloat_string(read_ptr) && (Vread_real_as == Qbigf))
1985                         return read_bigf_string(read_ptr);
1986
1987 #endif  /* HAVE_MPF */
1988 #ifdef HAVE_FPFLOAT
1989                 if (isfloat_string(read_ptr)) {
1990                         return make_float(str_to_fpfloat(read_ptr));
1991                 }
1992 #endif
1993 #if defined HAVE_PSEUG && defined WITH_PSEUG
1994                 if (isgaussian_string(read_ptr))
1995                         return read_bigg_string(read_ptr);
1996 #endif
1997 #if defined HAVE_MPC && defined WITH_MPC ||     \
1998         defined HAVE_PSEUC && defined WITH_PSEUC
1999                 if (isbigc_string(read_ptr))
2000                         return read_bigc_string(read_ptr);
2001 #endif  /* HAVE_MPC */
2002 #if defined HAVE_QUATERN && defined WITH_QUATERN
2003                 if (isquatern_string(read_ptr))
2004                         return read_quatern_string(read_ptr);
2005 #endif
2006         }
2007
2008         /* check for resclass syntax */
2009         if (ase_resc_rng_pred_f && ase_resc_rng_f &&
2010             ase_resc_rng_pred_f(read_ptr))
2011                 return ase_resc_rng_f(read_ptr);
2012         if (ase_resc_elm_pred_f && ase_resc_elm_f &&
2013             ase_resc_elm_pred_f(read_ptr))
2014                 return ase_resc_elm_f(read_ptr);
2015
2016         {
2017                 Lisp_Object sym;
2018                 if (uninterned_symbol)
2019                         sym =
2020                             Fmake_symbol(make_string
2021                                          ((Bufbyte *) read_ptr, len));
2022                 else {
2023                         Lisp_Object name =
2024                             make_string((Bufbyte *) read_ptr, len);
2025                         sym = Fintern(name, Qnil);
2026                 }
2027                 return sym;
2028         }
2029 }
2030
2031 static Lisp_Object
2032 parse_integer(const Bufbyte * buf, Bytecount len, int base)
2033 {
2034         const Bufbyte *lim = buf + len;
2035         const Bufbyte *p = buf;
2036         EMACS_UINT num = 0;
2037         int negativland = 0;
2038
2039         if (*p == '-') {
2040                 negativland = 1;
2041                 p++;
2042         } else if (*p == '+') {
2043                 p++;
2044         }
2045
2046         if (p == lim)
2047                 goto loser;
2048
2049         for (; (p < lim) && (*p != '\0'); p++) {
2050                 int c = *p;
2051                 EMACS_UINT onum;
2052
2053                 if (isdigit(c))
2054                         c = c - '0';
2055                 else if (isupper(c))
2056                         c = c - 'A' + 10;
2057                 else if (islower(c))
2058                         c = c - 'a' + 10;
2059                 else
2060                         goto loser;
2061
2062                 if (c < 0 || c >= base)
2063                         goto loser;
2064
2065                 onum = num;
2066                 num = num * base + c;
2067                 if (num < onum)
2068                         goto overflow;
2069         }
2070
2071         {
2072                 EMACS_INT int_result =
2073                     negativland ? -(EMACS_INT) num : (EMACS_INT) num;
2074                 Lisp_Object result = make_int(int_result);
2075                 if (num && ((XINT(result) < 0) != negativland))
2076                         goto overflow;
2077                 if (XINT(result) != int_result)
2078                         goto overflow;
2079                 return result;
2080         }
2081       overflow:
2082 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_BSDMP)
2083         return read_bigz_string((const char*)buf, base);
2084 #elif 0
2085         /* This is going to kill us!
2086          * Big integers cannot be used anywhere if the reader rewards
2087          * their occurence that harshly
2088          */
2089         return Fsignal(Qinvalid_read_syntax,
2090                        list3(build_translated_string
2091                              ("Integer constant overflow in reader"),
2092                              make_string(buf, len), make_int(base)));
2093 #else
2094         warn_when_safe(Qinvalid_read_syntax, Qwarning,
2095                        "Integer constant overflow in reader: %s,"
2096                        "  proceeding nervously with 0.",
2097                        buf);
2098         return Qzero;
2099 #endif /* HAVE_MPZ && WITH_GMP||WITH_BSDMP */
2100       loser:
2101         return Fsignal(Qinvalid_read_syntax,
2102                        list3(build_translated_string
2103                              ("Invalid integer constant in reader"),
2104                              make_string(buf, len), make_int(base)));
2105 }
2106
2107 static Lisp_Object
2108 read_integer(Lisp_Object readcharfun, int base)
2109 {
2110         /* This function can GC */
2111         int saw_a_backslash;
2112         Bytecount len = read_atom_0(readcharfun, -1, &saw_a_backslash);
2113         return (parse_integer
2114                 (resizing_buffer_stream_ptr(XLSTREAM(Vread_buffer_stream)),
2115                  ((saw_a_backslash)
2116                   ? 0           /* make parse_integer signal error */
2117                   : len), base));
2118 }
2119
2120 static Lisp_Object
2121 read_bit_vector(Lisp_Object readcharfun)
2122 {
2123         unsigned_char_dynarr *dyn = Dynarr_new(unsigned_char);
2124         Lisp_Object val;
2125
2126         while (1) {
2127                 unsigned char bit;
2128                 Emchar c = readchar(readcharfun);
2129                 if (c == '0')
2130                         bit = 0;
2131                 else if (c == '1')
2132                         bit = 1;
2133                 else {
2134                         if (c >= 0)
2135                                 unreadchar(readcharfun, c);
2136                         break;
2137                 }
2138                 Dynarr_add(dyn, bit);
2139         }
2140
2141         val = make_bit_vector_from_byte_vector(Dynarr_atp(dyn, 0),
2142                                                Dynarr_length(dyn));
2143         Dynarr_free(dyn);
2144
2145         return val;
2146 }
2147 \f
2148 /* structures */
2149
2150 struct structure_type*
2151 define_structure_type(Lisp_Object type,
2152                       int(*validate)(Lisp_Object data, Error_behavior errb),
2153                       Lisp_Object(*instantiate)(Lisp_Object data))
2154 {
2155         struct structure_type st;
2156
2157         st.type = type;
2158         st.keywords = Dynarr_new(structure_keyword_entry);
2159         st.validate = validate;
2160         st.instantiate = instantiate;
2161         Dynarr_add(the_structure_type_dynarr, st);
2162
2163         return Dynarr_atp(the_structure_type_dynarr,
2164                           Dynarr_length(the_structure_type_dynarr) - 1);
2165 }
2166
2167 void
2168 define_structure_type_keyword(struct structure_type *st, Lisp_Object keyword,
2169                               int (*validate) (Lisp_Object keyword,
2170                                                Lisp_Object value,
2171                                                Error_behavior errb))
2172 {
2173         struct structure_keyword_entry en;
2174
2175         en.keyword = keyword;
2176         en.validate = validate;
2177         Dynarr_add(st->keywords, en);
2178 }
2179
2180 static struct structure_type*
2181 recognized_structure_type(Lisp_Object type)
2182 {
2183         int i;
2184
2185         for (i = 0; i < Dynarr_length(the_structure_type_dynarr); i++) {
2186                 struct structure_type *st =
2187                     Dynarr_atp(the_structure_type_dynarr, i);
2188                 if (EQ(st->type, type))
2189                         return st;
2190         }
2191
2192         return 0;
2193 }
2194
2195 static Lisp_Object
2196 read_structure(Lisp_Object readcharfun)
2197 {
2198         Emchar c = readchar(readcharfun);
2199         Lisp_Object list = Qnil;
2200         Lisp_Object orig_list = Qnil;
2201         Lisp_Object already_seen = Qnil;
2202         int keyword_count;
2203         struct structure_type *st;
2204         struct gcpro gcpro1, gcpro2;
2205
2206         GCPRO2(orig_list, already_seen);
2207         if (c != '(')
2208                 RETURN_UNGCPRO(continuable_read_syntax_error
2209                                ("#s not followed by paren"));
2210         list = read_list(readcharfun, ')', 0, 0);
2211         orig_list = list;
2212         {
2213                 int len = XINT(Flength(list));
2214                 if (len == 0)
2215                         RETURN_UNGCPRO(continuable_read_syntax_error
2216                                        ("structure type not specified"));
2217                 if (!(len & 1))
2218                         RETURN_UNGCPRO
2219                             (continuable_read_syntax_error
2220                              ("structures must have alternating keyword/value pairs"));
2221         }
2222
2223         st = recognized_structure_type(XCAR(list));
2224         if (!st)
2225                 RETURN_UNGCPRO(Fsignal(Qinvalid_read_syntax,
2226                                        list2(build_translated_string
2227                                              ("unrecognized structure type"),
2228                                              XCAR(list))));
2229
2230         list = Fcdr(list);
2231         keyword_count = Dynarr_length(st->keywords);
2232         while (!NILP(list)) {
2233                 Lisp_Object keyword, value;
2234                 int i;
2235                 struct structure_keyword_entry *en = NULL;
2236
2237                 keyword = Fcar(list);
2238                 list = Fcdr(list);
2239                 value = Fcar(list);
2240                 list = Fcdr(list);
2241
2242                 if (!NILP(memq_no_quit(keyword, already_seen)))
2243                         RETURN_UNGCPRO(Fsignal(Qinvalid_read_syntax,
2244                                                list2(build_translated_string
2245                                                      ("structure keyword already seen"),
2246                                                      keyword)));
2247
2248                 for (i = 0; i < keyword_count; i++) {
2249                         en = Dynarr_atp(st->keywords, i);
2250                         if (EQ(keyword, en->keyword))
2251                                 break;
2252                 }
2253
2254                 if (i == keyword_count)
2255                         RETURN_UNGCPRO(Fsignal(Qinvalid_read_syntax,
2256                                                list2(build_translated_string
2257                                                      ("unrecognized structure keyword"),
2258                                                      keyword)));
2259
2260                 if (en->validate && !(en->validate) (keyword, value, ERROR_ME))
2261                         RETURN_UNGCPRO
2262                             (Fsignal(Qinvalid_read_syntax,
2263                                      list3(build_translated_string
2264                                            ("invalid value for structure keyword"),
2265                                            keyword, value)));
2266
2267                 already_seen = Fcons(keyword, already_seen);
2268         }
2269
2270         if (st->validate && !(st->validate) (orig_list, ERROR_ME))
2271                 RETURN_UNGCPRO(Fsignal(Qinvalid_read_syntax,
2272                                        list2(build_translated_string
2273                                              ("invalid structure initializer"),
2274                                              orig_list)));
2275
2276         RETURN_UNGCPRO((st->instantiate) (XCDR(orig_list)));
2277 }
2278 \f
2279 static Lisp_Object read_compiled_function(Lisp_Object readcharfun, int);
2280 static Lisp_Object read_vector(Lisp_Object readcharfun, int terminator);
2281
2282 /* Get the next character; filter out whitespace and comments */
2283
2284 static Emchar
2285 reader_nextchar(Lisp_Object readcharfun)
2286 {
2287         /* This function can GC */
2288         Emchar c;
2289
2290       retry:
2291         QUIT;
2292         c = readchar(readcharfun);
2293         if (c < 0)
2294                 signal_error(Qend_of_file,
2295                              list1(READCHARFUN_MAYBE(readcharfun)));
2296
2297         switch (c) {
2298         default:
2299                 {
2300                         /* Ignore whitespace and control characters */
2301                         if (c <= 040)
2302                                 goto retry;
2303                         return c;
2304                 }
2305
2306         case ';':
2307                 {
2308                         /* Comment */
2309                         while ((c = readchar(readcharfun)) >= 0 && c != '\n')
2310                                 QUIT;
2311                         goto retry;
2312                 }
2313         }
2314 }
2315
2316 #if 0
2317 static Lisp_Object list2_pure(int pure, Lisp_Object a, Lisp_Object b)
2318 {
2319         return pure ? pure_cons(a, pure_cons(b, Qnil)) : list2(a, b);
2320 }
2321 #endif
2322
2323 /* Read the next Lisp object from the stream READCHARFUN and return it.
2324    If the return value is a cons whose car is Qunbound, then read1()
2325    encountered a misplaced token (e.g. a right bracket, right paren,
2326    or dot followed by a non-number).  To filter this stuff out,
2327    use read0(). */
2328
2329 static Lisp_Object
2330 read_string(Lisp_Object readcharfun, Emchar delim, int raw)
2331 {
2332 #ifdef I18N3
2333         /* #### If the input stream is translating, then the string
2334            should be marked as translatable by setting its
2335            `string-translatable' property to t.  .el and .elc files
2336            normally are translating input streams.  See Fgettext()
2337            and print_internal(). */
2338 #endif
2339         Emchar c;
2340         int cancel = 0;
2341
2342         Lstream_rewind(XLSTREAM(Vread_buffer_stream));
2343         while ((c = readchar(readcharfun)) >= 0 && c != delim) {
2344                 if (c == '\\') {
2345                         if (raw) {
2346                                 /* For raw strings, insert the
2347                                    backslash and the next char, */
2348                                 Lstream_put_emchar(
2349                                         XLSTREAM(Vread_buffer_stream), c);
2350                                 c = readchar(readcharfun);
2351                         } else {
2352                                 /* otherwise, backslash escapes the next char */
2353                                 c = read_escape(readcharfun);
2354                         }
2355                 }
2356                 /* c is -1 if \ newline has just been seen */
2357                 if (c == -1) {
2358                         if (!Lstream_byte_count(XLSTREAM(Vread_buffer_stream))) {
2359                                 cancel = 1;
2360                         }
2361                 } else {
2362                         Lstream_put_emchar(XLSTREAM
2363                                            (Vread_buffer_stream),
2364                                            c);
2365                 }
2366                 QUIT;
2367         }
2368         if (c < 0) {
2369                 return Fsignal(Qend_of_file,
2370                                list1(READCHARFUN_MAYBE(readcharfun)));
2371         }
2372
2373         /* If purifying, and string starts with \ newline,
2374            return zero instead.  This is for doc strings
2375            that we are really going to find in lib-src/DOC.nn.nn  */
2376         if (purify_flag && NILP(Vinternal_doc_file_name) && cancel) {
2377                 return Qzero;
2378         }
2379
2380         Lstream_flush(XLSTREAM(Vread_buffer_stream));
2381         return make_string(resizing_buffer_stream_ptr
2382                            (XLSTREAM(Vread_buffer_stream)),
2383                            Lstream_byte_count(XLSTREAM(Vread_buffer_stream)));
2384 }
2385
2386 static Lisp_Object
2387 read_raw_string(Lisp_Object readcharfun)
2388 {
2389         Emchar c;
2390         c = reader_nextchar(readcharfun);
2391         switch (c) {
2392                 /* #r:engine"my sexy raw string" -- raw string w/ flags*/
2393         /* case ':': */
2394                 /* #r"my raw string" -- raw string */
2395         case '\"':
2396                 return read_string(readcharfun, '\"', 1);
2397                 /* invalid syntax */
2398         default: {
2399                 unreadchar(readcharfun, c);
2400                 return Fsignal(Qinvalid_read_syntax,
2401                                list1(build_string
2402                                      ("unrecognized raw string syntax")));
2403         }
2404         }
2405 }
2406
2407 static Lisp_Object
2408 read1(Lisp_Object readcharfun)
2409 {
2410         Emchar c;
2411
2412 retry:
2413         c = reader_nextchar(readcharfun);
2414
2415         switch (c) {
2416         case '(': {
2417 #ifdef LISP_BACKQUOTES          /* old backquote compatibility in lisp reader */
2418                 /* if this is disabled, then other code in eval.c must be
2419                    enabled */
2420                 Emchar ch = reader_nextchar(readcharfun);
2421                 switch (ch) {
2422                 case '`': {
2423                         Lisp_Object tem;
2424                         int speccount = specpdl_depth();
2425                         ++old_backquote_flag;
2426                         record_unwind_protect(backquote_unwind,
2427                                               make_opaque_ptr
2428                                               (&old_backquote_flag));
2429                         tem = read0(readcharfun);
2430                         unbind_to(speccount, Qnil);
2431                         ch = reader_nextchar(readcharfun);
2432                         if (ch != ')') {
2433                                 unreadchar(readcharfun, ch);
2434                                 return
2435                                         Fsignal
2436                                         (Qinvalid_read_syntax,
2437                                          list1(build_string
2438                                                ("Weird old-backquote syntax")));
2439                         }
2440                         return list2(Qbacktick, tem);
2441                 }
2442                 case ',': {
2443                         if (old_backquote_flag) {
2444                                 Lisp_Object tem, comma_type;
2445                                 ch = readchar(readcharfun);
2446                                 if (ch == '@')
2447                                         comma_type = Qcomma_at;
2448                                 else {
2449                                         if (ch >= 0)
2450                                                 unreadchar
2451                                                         (readcharfun,
2452                                                          ch);
2453                                         comma_type = Qcomma;
2454                                 }
2455                                 tem = read0(readcharfun);
2456                                 ch = reader_nextchar
2457                                         (readcharfun);
2458                                 if (ch != ')') {
2459                                         unreadchar(readcharfun,
2460                                                    ch);
2461                                         return Fsignal(
2462                                                 Qinvalid_read_syntax,
2463                                                 list1(build_string
2464                                                       ("Weird old-backquote "
2465                                                        "syntax")));
2466                                 }
2467                                 return list2(comma_type, tem);
2468                         } else {
2469                                 unreadchar(readcharfun, ch);
2470 #if 0
2471                                 return
2472                                         Fsignal
2473                                         (Qinvalid_read_syntax,
2474                                          list1(build_string
2475                                                ("Comma outside of backquote")));
2476 #else
2477                                 /* #### - yuck....but this is reverse
2478                                    ####   compatible. */
2479                                 /* mostly this is required by edebug, which does
2480                                    its own annotated reading.  We need to have
2481                                    an annotated_read function that records (with
2482                                    markers) the buffer positions of the elements
2483                                    that make up lists, then that can be used in
2484                                    edebug and bytecomp and the check above can
2485                                    go back in. --Stig */
2486                                 break;
2487 #endif
2488                         }
2489                 }
2490                 default:
2491                         unreadchar(readcharfun, ch);
2492                 }       /* switch(ch) */
2493 #endif                          /* old backquote crap... */
2494                 return read_list(readcharfun, ')', 1, 1);
2495         }
2496         case '[':
2497                 return read_vector(readcharfun, ']');
2498
2499         case ')':
2500         case ']':
2501                 /* #### - huh? these don't do what they seem... */
2502                 return noseeum_cons(Qunbound, make_char(c));
2503         case '.': {
2504 #ifdef HAVE_FPFLOAT
2505                 /* If a period is followed by a number, then we should read it
2506                    as a floating point number.  Otherwise, it denotes a dotted
2507                    pair.
2508                 */
2509                 c = readchar(readcharfun);
2510                 unreadchar(readcharfun, c);
2511
2512                 /* Can't use isdigit on Emchars */
2513                 if (c < '0' || c > '9')
2514                         return noseeum_cons(Qunbound, make_char('.'));
2515
2516                 /* Note that read_atom will loop
2517                    at least once, assuring that we will not try to UNREAD
2518                    two characters in a row.
2519                    (I think this doesn't matter anymore because there should
2520                    be no more danger in unreading multiple characters) */
2521                 return read_atom(readcharfun, '.', 0);
2522
2523 #else                           /* ! HAVE_FPFLOAT */
2524                 return noseeum_cons(Qunbound, make_char('.'));
2525 #endif                          /* ! HAVE_FPFLOAT */
2526         }
2527
2528         case '#': {
2529                 c = readchar(readcharfun);
2530                 switch (c) {
2531 #if 0                           /* FSFmacs silly char-table syntax */
2532                 case '^':
2533 #endif
2534 #if 0                           /* FSFmacs silly bool-vector syntax */
2535                 case '&':
2536 #endif
2537                         /* "#["-- byte-code constant syntax */
2538                         /* purecons #[...] syntax */
2539                 case '[':
2540                         return read_compiled_function(readcharfun, ']'
2541                                                       /*, purify_flag */
2542                                 );
2543                         /* "#:"-- gensym syntax */
2544                 case ':':
2545                         return read_atom(readcharfun, -1, 1);
2546                         /* #'x => (function x) */
2547                 case '\'':
2548                         return list2(Qfunction, read0(readcharfun));
2549 #if 0
2550                         /* RMS uses this syntax for fat-strings.
2551                            If we use it for vectors, then obscure bugs happen.
2552                         */
2553                         /* "#(" -- Scheme/CL vector syntax */
2554                 case '(':
2555                         return read_vector(readcharfun, ')');
2556 #endif
2557 #if 0                           /* FSFmacs */
2558 /* When are we going to drop this crap??? -hroptatyr */
2559                 case '(': {
2560                         Lisp_Object tmp;
2561                         struct gcpro gcpro1;
2562
2563                         /* Read the string itself.  */
2564                         tmp = read1(readcharfun);
2565                         if (!STRINGP(tmp)) {
2566                                 if (CONSP(tmp)
2567                                     && UNBOUNDP(XCAR(tmp)))
2568                                         free_cons(XCONS(tmp));
2569                                 return
2570                                         Fsignal
2571                                         (Qinvalid_read_syntax,
2572                                          list1(build_string("#")));
2573                         }
2574                         GCPRO1(tmp);
2575                         /* Read the intervals and their properties.  */
2576                         while (1) {
2577                                 Lisp_Object beg, end, plist;
2578                                 Emchar ch;
2579                                 int invalid = 0;
2580
2581                                 beg = read1(readcharfun);
2582                                 if (CONSP(beg) && UNBOUNDP(XCAR(beg))) {
2583                                         ch = XCHAR(XCDR(beg));
2584                                         free_cons(XCONS(beg));
2585                                         if (ch == ')')
2586                                                 break;
2587                                         else
2588                                                 invalid = 1;
2589                                 }
2590                                 if (!invalid) {
2591                                         end =
2592                                                 read1(readcharfun);
2593                                         if (CONSP(end)
2594                                             &&
2595                                             UNBOUNDP(XCAR(end)))
2596                                         {
2597                                                 free_cons(XCONS
2598                                                           (end));
2599                                                 invalid = 1;
2600                                         }
2601                                 }
2602                                 if (!invalid) {
2603                                         plist =
2604                                                 read1(readcharfun);
2605                                         if (CONSP(plist)
2606                                             &&
2607                                             UNBOUNDP(XCAR
2608                                                      (plist))) {
2609                                                 free_cons(XCONS
2610                                                           (plist));
2611                                                 invalid = 1;
2612                                         }
2613                                 }
2614                                 if (invalid) {
2615                                         RETURN_UNGCPRO
2616                                                 (Fsignal
2617                                                  (Qinvalid_read_syntax,
2618                                                   list2(build_string
2619                                                         ("invalid string "
2620                                                          "property list"),
2621                                                         XCDR(plist))));
2622                                 }
2623                                 Fset_text_properties(beg, end, plist, tmp);
2624                         }
2625                         UNGCPRO;
2626                         return tmp;
2627                 }
2628 #endif  /* 0 */
2629                 case '@': {
2630                         /* #@NUMBER is used to skip NUMBER following characters.
2631                            That's used in .elc files to skip over doc strings
2632                            and function definitions.  */
2633                         int i, nskip = 0;
2634
2635                         /* Read a decimal integer.  */
2636                         while ((c = readchar(readcharfun)) >= 0
2637                                && c >= '0' && c <= '9')
2638                                 nskip =
2639                                         (10 * nskip) + (c - '0');
2640                         if (c >= 0)
2641                                 unreadchar(readcharfun, c);
2642
2643                         /* FSF has code here that maybe caches the skipped
2644                            string.  See above for why this is totally
2645                            losing.  We handle this differently. */
2646
2647                         /* Skip that many characters.  */
2648                         for (i = 0; i < nskip && c >= 0; i++)
2649                                 c = readchar(readcharfun);
2650
2651                         goto retry;
2652                 }
2653                 case '$':
2654                         return Vload_file_name_internal;
2655                         /* bit vectors */
2656                 case '*':
2657                         return read_bit_vector(readcharfun);
2658                         /* #o10 => 8 -- octal constant syntax */
2659                 case 'o':
2660                         return read_integer(readcharfun, 8);
2661                         /* #xdead => 57005 -- hex constant syntax */
2662                 case 'x':
2663                         return read_integer(readcharfun, 16);
2664                         /* #b010 => 2 -- binary constant syntax */
2665                 case 'b':
2666                         return read_integer(readcharfun, 2);
2667
2668                 case 'p': {
2669                         Emchar _c_ = reader_nextchar(readcharfun);
2670                         /* check for permutation syntax */
2671                         if (_c_ == '[') {
2672                                 Lisp_Object perm =
2673                                         read_vector(readcharfun, ']');
2674                                 if (ase_permutation_f) {
2675                                         return ase_permutation_f(perm);
2676                                 }
2677                                 return perm;
2678                         } else {
2679                                 Lisp_Object err;
2680                                 unreadchar(readcharfun, _c_);
2681                                 err = build_string(
2682                                         "unrecognised permutation syntax");
2683                                 return Fsignal(
2684                                         Qinvalid_read_syntax, list1(err));
2685                         }
2686                 }
2687
2688                 case 'r':
2689                         /* #r"raw\stringt" -- raw string syntax */
2690                         return read_raw_string(readcharfun);
2691
2692                 case 's':
2693                         /* #s(foobar key1 val1 key2 val2) --
2694                          * structure syntax */
2695                         return read_structure(readcharfun);
2696                 case '<': {
2697                         /* Check user readers */
2698                         Lisp_Object uoname = read_string(readcharfun, ' ', 0);
2699                         Lisp_Object ureader = ureader_find(uoname);
2700                         if (!NILP(ureader))
2701                                 return ureader_read(ureader, readcharfun);
2702
2703                         unreadchar(readcharfun, c);
2704                         return Fsignal(Qinvalid_read_syntax,
2705                                        list2(build_string
2706                                              ("No ureader for"), uoname));
2707                 }
2708 #ifdef FEATUREP_SYNTAX
2709                 case '+':
2710                 case '-': {
2711                         Lisp_Object feature_exp, obj, tem;
2712                         struct gcpro gcpro1, gcpro2;
2713
2714                         feature_exp = read0(readcharfun);
2715                         obj = read0(readcharfun);
2716
2717                         /* the call to `featurep' may GC. */
2718                         GCPRO2(feature_exp, obj);
2719                         tem = call1(Qfeaturep, feature_exp);
2720                         UNGCPRO;
2721
2722                         if (c == '+' && NILP(tem))
2723                                 goto retry;
2724                         if (c == '-' && !NILP(tem))
2725                                 goto retry;
2726                         return obj;
2727                 }
2728 #endif
2729                 case '0':
2730                 case '1':
2731                 case '2':
2732                 case '3':
2733                 case '4':
2734                 case '5':
2735                 case '6':
2736                 case '7':
2737                 case '8':
2738                 case '9': {
2739                         /* Reader forms that can reuse previously read
2740                            objects.  */
2741                         int n = 0;
2742                         Lisp_Object found;
2743
2744                         /* Using read_integer() here is impossible, because it
2745                            chokes on `='.  Using parse_integer() is too hard.
2746                            So we simply read it in, and ignore overflows, which
2747                            is safe.  */
2748                         while (c >= '0' && c <= '9') {
2749                                 n *= 10;
2750                                 n += c - '0';
2751                                 c = readchar(readcharfun);
2752                         }
2753                         found = assq_no_quit(make_int(n), Vread_objects);
2754                         if (c == '=') {
2755                                 /* #n=object returns object, but associates it
2756                                    #with
2757                                    n for #n#.  */
2758                                 Lisp_Object obj;
2759                                 if (CONSP(found))
2760                                         return
2761                                                 Fsignal
2762                                                 (Qinvalid_read_syntax,
2763                                                  list2
2764                                                  (build_translated_string
2765                                                   ("Multiply defined symbol label"),
2766                                                   make_int(n)));
2767                                 obj = read0(readcharfun);
2768                                 Vread_objects =
2769                                         Fcons(Fcons
2770                                               (make_int(n), obj),
2771                                               Vread_objects);
2772                                 return obj;
2773                         } else if (c == '#') {
2774                                 /* #n# returns a previously read object.  */
2775                                 if (CONSP(found))
2776                                         return XCDR(found);
2777                                 else
2778                                         return
2779                                                 Fsignal
2780                                                 (Qinvalid_read_syntax,
2781                                                  list2
2782                                                  (build_translated_string
2783                                                   ("Undefined symbol label"),
2784                                                   make_int(n)));
2785                         }
2786                         return Fsignal(Qinvalid_read_syntax,
2787                                        list1(build_string
2788                                              ("#")));
2789                 }
2790                 default: {
2791                         unreadchar(readcharfun, c);
2792                         return Fsignal(Qinvalid_read_syntax,
2793                                        list1(build_string
2794                                              ("#")));
2795                 }
2796                 }
2797         }
2798
2799         /* Quote */
2800         case '\'':
2801                 return list2(Qquote, read0(readcharfun));
2802
2803 #ifdef LISP_BACKQUOTES
2804         case '`': {
2805                 Lisp_Object tem;
2806                 int speccount = specpdl_depth();
2807                 ++new_backquote_flag;
2808                 record_unwind_protect(backquote_unwind,
2809                                       make_opaque_ptr
2810                                       (&new_backquote_flag));
2811                 tem = read0(readcharfun);
2812                 unbind_to(speccount, Qnil);
2813                 return list2(Qbackquote, tem);
2814         }
2815
2816         case ',': {
2817                 if (new_backquote_flag) {
2818                         Lisp_Object comma_type = Qnil;
2819                         int ch = readchar(readcharfun);
2820
2821                         if (ch == '@')
2822                                 comma_type = Qcomma_at;
2823                         else if (ch == '.')
2824                                 comma_type = Qcomma_dot;
2825                         else {
2826                                 if (ch >= 0)
2827                                         unreadchar(readcharfun, ch);
2828                                 comma_type = Qcomma;
2829                         }
2830                         return list2(comma_type, read0(readcharfun));
2831                 } else {
2832                         /* YUCK.  99.999% backwards compatibility.  The Right
2833                            Thing(tm) is to signal an error here, because it's
2834                            really invalid read syntax.  Instead, this permits
2835                            commas to begin symbols (unless they're inside
2836                            backquotes).  If an error is signalled here in the
2837                            future, then commas should be invalid read syntax
2838                            outside of backquotes anywhere they're found (i.e.
2839                            they must be quoted in symbols) -- Stig */
2840                         return read_atom(readcharfun, c, 0);
2841                 }
2842         }
2843 #endif
2844
2845         case '?': {
2846                 /* Evil GNU Emacs "character" (ie integer) syntax */
2847                 c = readchar(readcharfun);
2848                 if (c < 0)
2849                         return Fsignal(Qend_of_file,
2850                                        list1(READCHARFUN_MAYBE
2851                                              (readcharfun)));
2852
2853                 if (c == '\\')
2854                         c = read_escape(readcharfun);
2855                 return make_char(c);
2856         }
2857
2858         case '\"':
2859                 /* String */
2860                 return read_string(readcharfun, '\"', 0);
2861
2862         default: {
2863                 /* Ignore whitespace and control characters */
2864                 if (c <= 040)
2865                         goto retry;
2866                 return read_atom(readcharfun, c, 0);
2867         }
2868         }
2869 }
2870 \f
2871 #ifdef HAVE_FPFLOAT
2872
2873 #define LEAD_INT 1
2874 #define DOT_CHAR 2
2875 #define TRAIL_INT 4
2876 #define E_CHAR 8
2877 #define EXP_INT 16
2878 /* for complex numbers */
2879 #define INTERMEDIATE_UNARY_SYMBOL 32
2880 #define LEAD_INT2 64
2881 #define DOT_CHAR2 128
2882 #define TRAIL_INT2 256
2883 #define E_CHAR2 512
2884 #define EXP_INT2 1024
2885 #define I_CHAR 2048
2886 #define LEAD_Z 2
2887 #define Z_CHAR 4096
2888
2889 int
2890 isfloat_string(const char *cp)
2891 {
2892         int state = 0;
2893         const Bufbyte *ucp = (const Bufbyte *)cp;
2894
2895         if (*ucp == '+' || *ucp == '-')
2896                 ucp++;
2897
2898         if (*ucp >= '0' && *ucp <= '9') {
2899                 state |= LEAD_INT;
2900                 while (*ucp >= '0' && *ucp <= '9')
2901                         ucp++;
2902         }
2903         if (*ucp == '.') {
2904                 state |= DOT_CHAR;
2905                 ucp++;
2906         }
2907         if (*ucp >= '0' && *ucp <= '9') {
2908                 state |= TRAIL_INT;
2909                 while (*ucp >= '0' && *ucp <= '9')
2910                         ucp++;
2911         }
2912         if (*ucp == 'e' || *ucp == 'E') {
2913                 state |= E_CHAR;
2914                 ucp++;
2915                 if ((*ucp == '+') || (*ucp == '-'))
2916                         ucp++;
2917         }
2918
2919         if (*ucp >= '0' && *ucp <= '9') {
2920                 state |= EXP_INT;
2921                 while (*ucp >= '0' && *ucp <= '9')
2922                         ucp++;
2923         }
2924         return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t')
2925                  || (*ucp == '\n')
2926                  || (*ucp == '\r') || (*ucp == '\f'))
2927                 && (state == (LEAD_INT | DOT_CHAR | TRAIL_INT)
2928                     || state == (DOT_CHAR | TRAIL_INT)
2929                     || state == (LEAD_INT | E_CHAR | EXP_INT)
2930                     || state ==
2931                     (LEAD_INT | DOT_CHAR | TRAIL_INT | E_CHAR | EXP_INT)
2932                     || state == (DOT_CHAR | TRAIL_INT | E_CHAR | EXP_INT)));
2933 }
2934 #endif                          /* HAVE_FPFLOAT */
2935 #if defined HAVE_MPC && defined WITH_MPC ||     \
2936         defined HAVE_PSEUC && defined WITH_PSEUC
2937 int
2938 isbigc_string (const char *cp)
2939 {
2940         int state;
2941         const Bufbyte *ucp = (const Bufbyte *)cp;
2942
2943
2944 /* parse the real part */
2945         state = 0;
2946         if (*ucp == '+' || *ucp == '-')
2947                 ucp++;
2948
2949         if (*ucp >= '0' && *ucp <= '9') {
2950                 state |= LEAD_INT;
2951                 while (*ucp >= '0' && *ucp <= '9')
2952                         ucp++;
2953         }
2954         if (*ucp == '.') {
2955                 state |= DOT_CHAR;
2956                 ucp++;
2957         }
2958         if (*ucp >= '0' && *ucp <= '9') {
2959                 state |= TRAIL_INT;
2960                 while (*ucp >= '0' && *ucp <= '9')
2961                         ucp++;
2962         }
2963         if (*ucp == 'e' || *ucp == 'E') {
2964                 state |= E_CHAR;
2965                 ucp++;
2966                 if ((*ucp == '+') || (*ucp == '-'))
2967                         ucp++;
2968         }
2969
2970         if (*ucp >= '0' && *ucp <= '9') {
2971                 state |= EXP_INT;
2972                 while (*ucp >= '0' && *ucp <= '9')
2973                         ucp++;
2974         }
2975
2976         /* check if we had a real number until here */
2977         if (!(state == (LEAD_INT | DOT_CHAR | TRAIL_INT) ||
2978               state == (DOT_CHAR | TRAIL_INT) ||
2979               state == (LEAD_INT | E_CHAR | EXP_INT) ||
2980               state == (LEAD_INT | DOT_CHAR | TRAIL_INT | E_CHAR | EXP_INT) ||
2981               state == (DOT_CHAR | TRAIL_INT | E_CHAR | EXP_INT)))
2982                 return 0;
2983
2984 /* now parse imaginary part */
2985         state = 0;
2986         if (*ucp == '+' || *ucp == '-') {
2987                 state |= INTERMEDIATE_UNARY_SYMBOL;
2988                 ucp++;
2989         }
2990
2991         if (*ucp >= '0' && *ucp <= '9') {
2992                 state |= LEAD_INT2;
2993                 while (*ucp >= '0' && *ucp <= '9')
2994                         ucp++;
2995         }
2996         if (*ucp == '.') {
2997                 state |= DOT_CHAR2;
2998                 ucp++;
2999         }
3000         if (*ucp >= '0' && *ucp <= '9') {
3001                 state |= TRAIL_INT2;
3002                 while (*ucp >= '0' && *ucp <= '9')
3003                         ucp++;
3004         }
3005         if (*ucp == 'e' || *ucp == 'E') {
3006                 state |= E_CHAR2;
3007                 ucp++;
3008                 if ((*ucp == '+') || (*ucp == '-'))
3009                         ucp++;
3010         }
3011
3012         if (*ucp >= '0' && *ucp <= '9') {
3013                 state |= EXP_INT2;
3014                 while (*ucp >= '0' && *ucp <= '9')
3015                         ucp++;
3016         }
3017         if (*ucp == 'i' || *ucp == 'I') {
3018                 state |= I_CHAR;
3019                 ucp++;
3020         }
3021         return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t') ||
3022                  (*ucp == '\n') || (*ucp == '\r') || (*ucp == '\f')) &&
3023                 (state == (INTERMEDIATE_UNARY_SYMBOL | LEAD_INT2 | DOT_CHAR2 |
3024                            TRAIL_INT2 | I_CHAR) ||
3025                  state == (INTERMEDIATE_UNARY_SYMBOL | DOT_CHAR2 |
3026                            TRAIL_INT2 | I_CHAR) ||
3027                  state == (INTERMEDIATE_UNARY_SYMBOL | LEAD_INT2 |
3028                            E_CHAR2 | EXP_INT2 | I_CHAR) ||
3029                  state == (INTERMEDIATE_UNARY_SYMBOL | LEAD_INT2 | DOT_CHAR2 |
3030                            TRAIL_INT2 | E_CHAR2 | EXP_INT2 | I_CHAR) ||
3031                  state == (INTERMEDIATE_UNARY_SYMBOL | DOT_CHAR2 | TRAIL_INT2 |
3032                            E_CHAR2 | EXP_INT2 | I_CHAR) ||
3033                  state == (INTERMEDIATE_UNARY_SYMBOL | I_CHAR)));
3034 }
3035 #endif  /* HAVE_MPC */
3036 #if defined WITH_PSEUG && defined HAVE_PSEUG
3037 int
3038 isgaussian_string (const char *cp)
3039 {
3040         int state;
3041         const Bufbyte *ucp = (const Bufbyte *)cp;
3042
3043
3044 /* parse the real part */
3045         state = 0;
3046         if (*ucp == '+' || *ucp == '-')
3047                 ucp++;
3048
3049         if (*ucp >= '0' && *ucp <= '9') {
3050                 state |= LEAD_INT;
3051                 while (*ucp >= '0' && *ucp <= '9')
3052                         ucp++;
3053         }
3054
3055         /* check if we had a int number until here */
3056         if (!(state == (LEAD_INT)))
3057                 return 0;
3058
3059 /* now parse imaginary part */
3060         state = 0;
3061         if (*ucp == '+' || *ucp == '-') {
3062                 state |= INTERMEDIATE_UNARY_SYMBOL;
3063                 ucp++;
3064         }
3065
3066         if (*ucp >= '0' && *ucp <= '9') {
3067                 state |= LEAD_INT2;
3068                 while (*ucp >= '0' && *ucp <= '9')
3069                         ucp++;
3070         }
3071         if (*ucp == 'i' || *ucp == 'I') {
3072                 state |= I_CHAR;
3073                 ucp++;
3074         }
3075         return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t') ||
3076                  (*ucp == '\n') || (*ucp == '\r') || (*ucp == '\f')) &&
3077                 (state == (INTERMEDIATE_UNARY_SYMBOL | LEAD_INT2 | I_CHAR) ||
3078                  state == (INTERMEDIATE_UNARY_SYMBOL | I_CHAR)));
3079 }
3080 #endif  /* HAVE_PSEUG */
3081 #if defined HAVE_MPQ && defined WITH_GMP
3082 int
3083 isbigq_string (const char *cp)
3084 {
3085         /* Possible minus/plus sign */
3086         if (*cp == '-' || *cp == '+')
3087                 cp++;
3088
3089         /* Numerator */
3090         if (*cp < '0' || *cp > '9')
3091                 return 0;
3092
3093         do {
3094                 cp++;
3095         } while (*cp >= '0' && *cp <= '9');
3096
3097         /* Slash */
3098         if (*cp++ != '/')
3099                 return 0;
3100
3101         /* Denominator */
3102         if (*cp < '0' || *cp > '9')
3103                 return 0;
3104
3105         do {
3106                 cp++;
3107         } while (*cp >= '0' && *cp <= '9');
3108
3109         return *cp == '\0' || *cp == ' ' || *cp =='\t' || *cp == '\n' ||
3110                 *cp == '\r' || *cp == '\f';
3111 }
3112 #endif  /* HAVE_MPQ */
3113
3114 \f
3115 static void*
3116 sequence_reader(Lisp_Object readcharfun,
3117                 Emchar terminator,
3118                 void *state,
3119                 void*(*conser)(Lisp_Object, void*, Charcount))
3120 {
3121         Charcount len;
3122
3123         for (len = 0;; len++) {
3124                 Emchar ch;
3125
3126                 QUIT;
3127                 ch = reader_nextchar(readcharfun);
3128
3129                 if (ch == terminator)
3130                         return state;
3131                 else
3132                         unreadchar(readcharfun, ch);
3133 #ifdef FEATUREP_SYNTAX
3134                 if (ch == ']')
3135                         read_syntax_error("\"]\" in a list");
3136                 else if (ch == ')')
3137                         read_syntax_error("\")\" in a vector");
3138 #endif
3139                 state = ((conser) (readcharfun, state, len));
3140         }
3141 }
3142
3143 struct read_list_state {
3144         Lisp_Object head;
3145         Lisp_Object tail;
3146         int length;
3147         int allow_dotted_lists;
3148         Emchar terminator;
3149 };
3150
3151 static void*
3152 read_list_conser(Lisp_Object readcharfun, void *state, Charcount len)
3153 {
3154         struct read_list_state *s = (struct read_list_state *)state;
3155         Lisp_Object elt;
3156
3157         elt = read1(readcharfun);
3158
3159         if (CONSP(elt) && UNBOUNDP(XCAR(elt))) {
3160                 Lisp_Object tem = elt;
3161                 Emchar ch;
3162
3163                 elt = XCDR(elt);
3164                 free_cons(XCONS(tem));
3165                 tem = Qnil;
3166                 ch = XCHAR(elt);
3167 #ifdef FEATUREP_SYNTAX
3168                 if (ch == s->terminator) {
3169                         /* deal with #+, #- reader macros */
3170                         unreadchar(readcharfun, s->terminator);
3171                         goto done;
3172                 } else if (ch == ']')
3173                         read_syntax_error("']' in a list");
3174                 else if (ch == ')')
3175                         read_syntax_error("')' in a vector");
3176                 else
3177 #endif
3178                 if (ch != '.')
3179                         signal_simple_error("BUG! Internal reader error", elt);
3180                 else if (!s->allow_dotted_lists)
3181                         read_syntax_error("\".\" in a vector");
3182                 else {
3183                         if (!NILP(s->tail))
3184                                 XCDR(s->tail) = read0(readcharfun);
3185                         else
3186                                 s->head = read0(readcharfun);
3187                         elt = read1(readcharfun);
3188                         if (CONSP(elt) && UNBOUNDP(XCAR(elt))) {
3189                                 ch = XCHAR(XCDR(elt));
3190                                 free_cons(XCONS(elt));
3191                                 if (ch == s->terminator) {
3192                                         unreadchar(readcharfun, s->terminator);
3193                                         goto done;
3194                                 }
3195                         }
3196                         read_syntax_error(". in wrong context");
3197                 }
3198         }
3199 #if 0                           /* FSFmacs defun hack, or something ... */
3200         if (NILP(tail) && defun_hack && EQ(elt, Qdefun) && !read_pure) {
3201                 record_unwind_protect(unreadpure, Qzero);
3202                 read_pure = 1;
3203         }
3204 #endif
3205
3206 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
3207         if (s->length == 1 && s->allow_dotted_lists && EQ(XCAR(s->head), Qfset)) {
3208                 if (CONSP(elt) && EQ(XCAR(elt), Qquote) && CONSP(XCDR(elt)))
3209                         Vcurrent_compiled_function_annotation = XCAR(XCDR(elt));
3210                 else
3211                         Vcurrent_compiled_function_annotation = elt;
3212         }
3213 #endif
3214
3215         elt = Fcons(elt, Qnil);
3216         if (!NILP(s->tail))
3217                 XCDR(s->tail) = elt;
3218         else
3219                 s->head = elt;
3220         s->tail = elt;
3221       done:
3222         s->length++;
3223         return s;
3224 }
3225 \f
3226 #if 0                           /* FSFmacs defun hack */
3227 /* -1 for allow_dotted_lists means allow_dotted_lists and check
3228    for starting with defun and make structure pure. */
3229 #endif
3230
3231 static Lisp_Object
3232 read_list(Lisp_Object readcharfun,
3233           Emchar terminator,
3234           int allow_dotted_lists, int check_for_doc_references)
3235 {
3236         struct read_list_state s;
3237         struct gcpro gcpro1, gcpro2;
3238 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
3239         Lisp_Object old_compiled_function_annotation =
3240             Vcurrent_compiled_function_annotation;
3241 #endif
3242
3243         s.head = Qnil;
3244         s.tail = Qnil;
3245         s.length = 0;
3246         s.allow_dotted_lists = allow_dotted_lists;
3247         s.terminator = terminator;
3248         GCPRO2(s.head, s.tail);
3249
3250         sequence_reader(readcharfun, terminator, &s, read_list_conser);
3251 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
3252         Vcurrent_compiled_function_annotation =
3253             old_compiled_function_annotation;
3254 #endif
3255
3256         if ((purify_flag || load_force_doc_strings) && check_for_doc_references) {
3257                 /* check now for any doc string references and record them
3258                    for later. */
3259                 Lisp_Object tail;
3260
3261                 /* We might be dealing with an imperfect list so don't
3262                    use LIST_LOOP */
3263                 for (tail = s.head; CONSP(tail); tail = XCDR(tail)) {
3264                         Lisp_Object holding_cons = Qnil;
3265
3266                         {
3267                                 Lisp_Object elem = XCAR(tail);
3268                                 /* elem might be (#$ . INT) ... */
3269                                 if (CONSP(elem)
3270                                     && EQ(XCAR(elem), Vload_file_name_internal))
3271                                         holding_cons = tail;
3272                                 /* or it might be (quote (#$ . INT)) i.e.
3273                                    (quote . ((#$ . INT) . nil)) in the case of
3274                                    `autoload' (autoload evaluates its arguments, while
3275                                    `defvar', `defun', etc. don't). */
3276                                 if (CONSP(elem) && EQ(XCAR(elem), Qquote)
3277                                     && CONSP(XCDR(elem))) {
3278                                         elem = XCAR(XCDR(elem));
3279                                         if (CONSP(elem)
3280                                             && EQ(XCAR(elem),
3281                                                   Vload_file_name_internal))
3282                                                 holding_cons = XCDR(XCAR(tail));
3283                                 }
3284                         }
3285
3286                         if (CONSP(holding_cons)) {
3287                                 if (purify_flag) {
3288                                         if (NILP(Vinternal_doc_file_name))
3289                                                 /* We have not yet called
3290                                                    Snarf-documentation, so
3291                                                    assume this file is described
3292                                                    in the DOC file and
3293                                                    Snarf-documentation will fill
3294                                                    in the right value later.
3295                                                    For now, replace the whole
3296                                                    list with 0.  */
3297                                                 XCAR(holding_cons) = Qzero;
3298                                         else
3299                                                 /* We have already called
3300                                                    Snarf-documentation, so make
3301                                                    a relative file name for this
3302                                                    file, so it can be found
3303                                                    properly in the installed
3304                                                    Lisp directory.  We don't use
3305                                                    Fexpand_file_name because
3306                                                    that would make the directory
3307                                                    absolute now.  */
3308                                                 XCAR(XCAR(holding_cons)) =
3309                                                     concat2(build_string
3310                                                             ("../lisp/"),
3311                                                             Ffile_name_nondirectory
3312                                                             (Vload_file_name_internal));
3313                                 } else
3314                                         /* Not pure.  Just add to
3315                                            Vload_force_doc_string_list, and the
3316                                            string will be filled in properly in
3317                                            load_force_doc_string_unwind(). */
3318                                         Vload_force_doc_string_list =
3319                                             /* We pass the cons that holds the
3320                                                (#$ . INT) so we can modify it
3321                                                in-place. */
3322                                             Fcons(holding_cons,
3323                                                   Vload_force_doc_string_list);
3324                         }
3325                 }
3326         }
3327
3328         UNGCPRO;
3329         return s.head;
3330 }
3331
3332 static Lisp_Object
3333 read_vector(Lisp_Object readcharfun, Emchar terminator)
3334 {
3335         Lisp_Object tem;
3336         Lisp_Object *p;
3337         int len;
3338         int i;
3339         struct read_list_state s;
3340         struct gcpro gcpro1, gcpro2;
3341
3342         s.head = Qnil;
3343         s.tail = Qnil;
3344         s.length = 0;
3345         s.allow_dotted_lists = 0;
3346         GCPRO2(s.head, s.tail);
3347
3348         sequence_reader(readcharfun, terminator, &s, read_list_conser);
3349
3350         UNGCPRO;
3351         tem = s.head;
3352         len = XINT(Flength(tem));
3353
3354 #if 0                           /* FSFmacs defun hack */
3355         if (read_pure)
3356                 s.head = make_pure_vector(len, Qnil);
3357         else
3358 #endif
3359                 s.head = make_vector(len, Qnil);
3360
3361         for (i = 0, p = &(XVECTOR_DATA(s.head)[0]); i < len; i++, p++) {
3362                 Lisp_Cons *otem = XCONS(tem);
3363                 tem = Fcar(tem);
3364                 *p = tem;
3365                 tem = otem->cdr;
3366                 free_cons(otem);
3367         }
3368         return s.head;
3369 }
3370
3371 static Lisp_Object
3372 read_compiled_function(Lisp_Object readcharfun, Emchar terminator)
3373 {
3374         /* Accept compiled functions at read-time so that we don't
3375            have to build them at load-time. */
3376         Lisp_Object stuff;
3377         Lisp_Object make_byte_code_args[COMPILED_DOMAIN + 1];
3378         struct gcpro gcpro1;
3379         int len;
3380         int iii;
3381         int saw_a_doc_ref = 0;
3382
3383         /* Note: we tell read_list not to search for doc references
3384            because we need to handle the "doc reference" for the
3385            instructions and constants differently. */
3386         stuff = read_list(readcharfun, terminator, 0, 0);
3387         len = XINT(Flength(stuff));
3388         if (len < COMPILED_STACK_DEPTH + 1 || len > COMPILED_DOMAIN + 1)
3389                 return
3390                     continuable_read_syntax_error
3391                     ("#[...] used with wrong number of elements");
3392
3393         for (iii = 0; CONSP(stuff); iii++) {
3394                 Lisp_Cons *victim = XCONS(stuff);
3395                 make_byte_code_args[iii] = Fcar(stuff);
3396                 if ((purify_flag || load_force_doc_strings)
3397                     && CONSP(make_byte_code_args[iii])
3398                     && EQ(XCAR(make_byte_code_args[iii]),
3399                           Vload_file_name_internal)) {
3400                         if (purify_flag && iii == COMPILED_DOC_STRING) {
3401                                 /* same as in read_list(). */
3402                                 if (NILP(Vinternal_doc_file_name))
3403                                         make_byte_code_args[iii] = Qzero;
3404                                 else
3405                                         XCAR(make_byte_code_args[iii]) =
3406                                             concat2(build_string("../lisp/"),
3407                                                     Ffile_name_nondirectory
3408                                                     (Vload_file_name_internal));
3409                         } else
3410                                 saw_a_doc_ref = 1;
3411                 }
3412                 stuff = Fcdr(stuff);
3413                 free_cons(victim);
3414         }
3415         GCPROn(make_byte_code_args, len);
3416
3417         /* v18 or v19 bytecode file.  Need to Ebolify. */
3418         if (load_byte_code_version < 20 && VECTORP(make_byte_code_args[2]))
3419                 ebolify_bytecode_constants(make_byte_code_args[2]);
3420
3421         /* make-byte-code looks at purify_flag, which should have the same
3422          *  value as our "read-pure" argument */
3423         stuff = Fmake_byte_code(len, make_byte_code_args);
3424         XCOMPILED_FUNCTION(stuff)->flags.ebolified =
3425             (load_byte_code_version < 20);
3426         if (saw_a_doc_ref)
3427                 Vload_force_doc_string_list =
3428                     Fcons(stuff, Vload_force_doc_string_list);
3429         UNGCPRO;
3430         return stuff;
3431 }
3432 \f
3433 void init_lread(void)
3434 {
3435         char *stroot = NULL, *btroot = NULL;
3436         Vvalues = Qnil;
3437
3438         load_in_progress = 0;
3439
3440         Vload_descriptor_list = Qnil;
3441
3442         /* kludge: locate-file does not work for a null load-path, even if
3443            the file name is absolute. */
3444
3445         Vload_path = Fcons(build_string(""), Qnil);
3446         /* The following is intended for the build chain only */
3447         if ((stroot = getenv("SOURCE_TREE_ROOT")) && strlen(stroot)) {
3448                 Lisp_Object lispsubdir = build_string("lisp");
3449                 Lisp_Object strootdir = build_string(stroot);
3450                 Lisp_Object stlispdir =
3451                         Fexpand_file_name(lispsubdir, strootdir);
3452                 Vload_path = Fcons(stlispdir, Vload_path);
3453         }
3454         if ((btroot = getenv("BUILD_TREE_ROOT")) && strlen(btroot)) {
3455                 Lisp_Object lispsubdir = build_string("lisp");
3456                 Lisp_Object btrootdir = build_string(btroot);
3457                 Lisp_Object btlispdir =
3458                         Fexpand_file_name(lispsubdir, btrootdir);
3459                 Vload_path = Fcons(btlispdir, Vload_path);
3460         }
3461
3462         /* This used to get initialized in init_lread because all streams
3463            got closed when dumping occurs.  This is no longer true --
3464            Vread_buffer_stream is a resizing output stream, and there is no
3465            reason to close it at dump-time.
3466
3467            Vread_buffer_stream is set to Qnil in vars_of_lread, and this
3468            will initialize it only once, at dump-time.  */
3469         if (NILP(Vread_buffer_stream))
3470                 Vread_buffer_stream = make_resizing_buffer_output_stream();
3471
3472         Vload_force_doc_string_list = Qnil;
3473 }
3474
3475 void syms_of_lread(void)
3476 {
3477         DEFSUBR(Fread);
3478         DEFSUBR(Fread_from_string);
3479         DEFSUBR(Fload_internal);
3480         DEFSUBR(Flocate_file);
3481         DEFSUBR(Flocate_file_clear_hashing);
3482         DEFSUBR(Feval_buffer);
3483         DEFSUBR(Feval_region);
3484
3485         defsymbol(&Qstandard_input, "standard-input");
3486         defsymbol(&Qread_char, "read-char");
3487         defsymbol(&Qcurrent_load_list, "current-load-list");
3488         defsymbol(&Qload, "load");
3489         defsymbol(&Qload_file_name, "load-file-name");
3490         defsymbol(&Qfset, "fset");
3491
3492 #ifdef LISP_BACKQUOTES
3493         defsymbol(&Qbackquote, "backquote");
3494         defsymbol(&Qbacktick, "`");
3495         defsymbol(&Qcomma, ",");
3496         defsymbol(&Qcomma_at, ",@");
3497         defsymbol(&Qcomma_dot, ",.");
3498 #endif
3499
3500         defsymbol(&Qexists, "exists");
3501         defsymbol(&Qreadable, "readable");
3502         defsymbol(&Qwritable, "writable");
3503         defsymbol(&Qexecutable, "executable");
3504 }
3505
3506 void structure_type_create(void)
3507 {
3508         the_structure_type_dynarr = Dynarr_new(structure_type);
3509 }
3510
3511 void reinit_vars_of_lread(void)
3512 {
3513         Vread_buffer_stream = Qnil;
3514         staticpro_nodump(&Vread_buffer_stream);
3515 }
3516
3517 void vars_of_lread(void)
3518 {
3519         reinit_vars_of_lread();
3520
3521         DEFVAR_LISP("values", &Vvalues  /*
3522 List of values of all expressions which were read, evaluated and printed.
3523 Order is reverse chronological.
3524                                          */ );
3525
3526         DEFVAR_LISP("standard-input", &Vstandard_input  /*
3527 Stream for read to get input from.
3528 See documentation of `read' for possible values.
3529                                                          */ );
3530         Vstandard_input = Qt;
3531
3532         DEFVAR_LISP("load-path", &Vload_path    /*
3533 *List of directories to search for files to load.
3534 Each element is a string (directory name) or nil (try default directory).
3535
3536 Note that the elements of this list *may not* begin with "~", so you must
3537 call `expand-file-name' on them before adding them to this list.
3538
3539 Initialized based on EMACSLOADPATH environment variable, if any,
3540 otherwise to default specified in by file `paths.h' when SXEmacs was built.
3541 If there were no paths specified in `paths.h', then SXEmacs chooses a default
3542 value for this variable by looking around in the file-system near the
3543 directory in which the SXEmacs executable resides.
3544                                                  */ );
3545         Vload_path = Qnil;
3546
3547 /*  xxxDEFVAR_LISP ("dump-load-path", &Vdump_load_path,
3548     "*Location of lisp files to be used when dumping ONLY."); */
3549
3550         DEFVAR_BOOL("load-in-progress", &load_in_progress       /*
3551 Non-nil iff inside of `load'.
3552                                                                  */ );
3553         DEFVAR_LISP ("load-suppress-alist", &Vload_suppress_alist /*
3554 An alist of expressions controlling whether particular files can be loaded.
3555 Each element looks like (FILENAME EXPR).
3556 FILENAME should be a full pathname, but without the .el suffix.
3557 When `load' is run and is about to load the specified file, it evaluates
3558 the form to determine if the file can be loaded.
3559 This variable is normally initialized automatically.
3560                                                                   */ );
3561         Vload_suppress_alist = Qnil;
3562
3563         DEFVAR_LISP("after-load-alist", &Vafter_load_alist      /*
3564 An alist of expressions to be evalled when particular files are loaded.
3565 Each element looks like (FILENAME FORMS...).
3566 When `load' is run and the file-name argument is FILENAME,
3567 the FORMS in the corresponding element are executed at the end of loading.
3568
3569 FILENAME must match exactly!  Normally FILENAME is the name of a library,
3570 with no directory specified, since that is how `load' is normally called.
3571 An error in FORMS does not undo the load,
3572 but does prevent execution of the rest of the FORMS.
3573                                                                  */ );
3574         Vafter_load_alist = Qnil;
3575
3576         DEFVAR_BOOL("load-warn-when-source-newer", &load_warn_when_source_newer /*
3577 *Whether `load' should check whether the source is newer than the binary.
3578 If this variable is true, then when a `.elc' file is being loaded and the
3579 corresponding `.el' is newer, a warning message will be printed.
3580                                                                                  */ );
3581         load_warn_when_source_newer = 0;
3582
3583         DEFVAR_BOOL("load-warn-when-source-only", &load_warn_when_source_only   /*
3584 *Whether `load' should warn when loading a `.el' file instead of an `.elc'.
3585 If this variable is true, then when `load' is called with a filename without
3586 an extension, and the `.elc' version doesn't exist but the `.el' version does,
3587 then a message will be printed.  If an explicit extension is passed to `load',
3588 no warning will be printed.
3589                                                                                  */ );
3590         load_warn_when_source_only = 0;
3591
3592         DEFVAR_BOOL("load-ignore-elc-files", &load_ignore_elc_files     /*
3593 *Whether `load' should ignore `.elc' files when a suffix is not given.
3594 This is normally used only to bootstrap the `.elc' files when building SXEmacs.
3595                                                                          */ );
3596         load_ignore_elc_files = 0;
3597
3598 #ifdef LOADHIST
3599         DEFVAR_LISP("load-history", &Vload_history      /*
3600 Alist mapping source file names to symbols and features.
3601 Each alist element is a list that starts with a file name,
3602 except for one element (optional) that starts with nil and describes
3603 definitions evaluated from buffers not visiting files.
3604 The remaining elements of each list are symbols defined as functions
3605 or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.
3606                                                          */ );
3607         Vload_history = Qnil;
3608
3609         DEFVAR_LISP("current-load-list", &Vcurrent_load_list    /*
3610 Used for internal purposes by `load'.
3611                                                                  */ );
3612         Vcurrent_load_list = Qnil;
3613 #endif
3614
3615         DEFVAR_LISP("load-file-name", &Vload_file_name  /*
3616 Full name of file being loaded by `load'.
3617                                                          */ );
3618         Vload_file_name = Qnil;
3619
3620         DEFVAR_LISP("load-read-function", &Vload_read_function  /*
3621 Function used by `load' and `eval-region' for reading expressions.
3622 The default is nil, which means use the function `read'.
3623                                                                  */ );
3624         Vload_read_function = Qnil;
3625
3626         DEFVAR_BOOL("load-force-doc-strings", &load_force_doc_strings   /*
3627 Non-nil means `load' should force-load all dynamic doc strings.
3628 This is useful when the file being loaded is a temporary copy.
3629                                                                          */ );
3630         load_force_doc_strings = 0;
3631
3632         /* See read_escape().  */
3633 #if 0
3634         /* Used to be named `puke-on-fsf-keys' */
3635         DEFVAR_BOOL("fail-on-bucky-bit-character-escapes", &fail_on_bucky_bit_character_escapes /*
3636 Whether `read' should signal an error when it encounters unsupported
3637 character escape syntaxes or just read them incorrectly.
3638                                                                                                  */ );
3639         fail_on_bucky_bit_character_escapes = 0;
3640 #endif
3641
3642         /* This must be initialized in init_lread otherwise it may start out
3643            with values saved when the image is dumped. */
3644         staticpro(&Vload_descriptor_list);
3645
3646         /* Initialized in init_lread. */
3647         staticpro(&Vload_force_doc_string_list);
3648
3649         Vload_file_name_internal = Qnil;
3650         staticpro(&Vload_file_name_internal);
3651
3652         Vload_file_name_internal_the_purecopy = Qnil;
3653         staticpro(&Vload_file_name_internal_the_purecopy);
3654
3655 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
3656         Vcurrent_compiled_function_annotation = Qnil;
3657         staticpro(&Vcurrent_compiled_function_annotation);
3658 #endif
3659
3660         /* So that early-early stuff will work */
3661         Ffset(Qload, intern("load-internal"));
3662
3663 #ifdef FEATUREP_SYNTAX
3664         defsymbol(&Qfeaturep, "featurep");
3665         Fprovide(intern("xemacs"));
3666         Fprovide(intern("sxemacs"));
3667         Fprovide(intern("raw-strings"));
3668 #ifdef INFODOCK
3669         Fprovide(intern("infodock"));
3670 #endif                          /* INFODOCK */
3671 #endif                          /* FEATUREP_SYNTAX */
3672
3673 #ifdef LISP_BACKQUOTES
3674         old_backquote_flag = new_backquote_flag = 0;
3675 #endif
3676
3677 #ifdef I18N3
3678         Vfile_domain = Qnil;
3679 #endif
3680
3681         Vread_objects = Qnil;
3682         staticpro(&Vread_objects);
3683
3684         Vlocate_file_hash_table = make_lisp_hash_table(200,
3685                                                        HASH_TABLE_NON_WEAK,
3686                                                        HASH_TABLE_EQUAL);
3687         staticpro(&Vlocate_file_hash_table);
3688 #ifdef DEBUG_SXEMACS
3689         {
3690                 Lisp_Object tmp = intern("Vlocate-file-hash-table");
3691                 symbol_value(XSYMBOL(tmp)) = Vlocate_file_hash_table;
3692         }
3693 #endif
3694
3695         /* User defined readers */
3696         DEFVAR_LISP("ureaders", &Vureaders /*
3697 Alist of user defined readers.
3698 Car is ureader NAME, represented by string to match against when reading
3699 #<NAME bla-bla-bla>
3700 Cdr is user function called with one arg - string.
3701 Function must return lisp object or signal error.
3702                                            */
3703                 );
3704 }
3705
3706 /* lread.c ends here */