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