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