XEmacs 21.2.20 "Yoko".
[chise/xemacs-chise.git.1] / 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 (semantically
907                different from "empty suffix list")
908    b) list   - list of suffixes to append to file name.  Each of these
909                must be a string.
910    c) string - colon-separated suffixes to append to file name (backward
911                compatibility).
912
913    All of this got hairy, so I decided to use write a mapper.  Calling
914    a function for each suffix shouldn't slow things down, since
915    locate_file is rarely call with enough suffixes for it to make a
916    difference.  */
917
918 /* Map FUN over SUFFIXES, as described above.  FUN will be called with a
919    char * containing the current file name, and ARG.  Mapping stops when
920    FUN returns non-zero. */
921 static void
922 locate_file_map_suffixes (Lisp_Object filename, Lisp_Object suffixes,
923                           int (*fun) (char *, void *),
924                           void *arg)
925 {
926   /* This function can GC */
927   char *fn;
928   int fn_len, max;
929
930   /* Calculate maximum size of any filename made from
931      this path element/specified file name and any possible suffix.  */
932   if (CONSP (suffixes))
933     {
934       /* We must traverse the list, so why not do it right. */
935       Lisp_Object tail;
936       max = 0;
937       LIST_LOOP (tail, suffixes)
938         {
939           if (XSTRING_LENGTH (XCAR (tail)) > max)
940             max = XSTRING_LENGTH (XCAR (tail));
941         }
942     }
943   else if (NILP (suffixes))
944     max = 0;
945   else
946     /* Just take the easy way out */
947     max = XSTRING_LENGTH (suffixes);
948
949   fn_len = XSTRING_LENGTH (filename);
950   fn = (char *) alloca (max + fn_len + 1);
951   memcpy (fn, (char *) XSTRING_DATA (filename), fn_len);
952
953   /* Loop over suffixes.  */
954   if (!STRINGP (suffixes))
955     {
956       if (NILP (suffixes))
957         {
958           /* Case a) discussed in the comment above. */
959           fn[fn_len] = 0;
960           if ((*fun) (fn, arg))
961             return;
962         }
963       else
964         {
965           /* Case b) */
966           Lisp_Object tail;
967           LIST_LOOP (tail, suffixes)
968             {
969               memcpy (fn + fn_len, XSTRING_DATA (XCAR (tail)),
970                       XSTRING_LENGTH (XCAR (tail)));
971               fn[fn_len + XSTRING_LENGTH (XCAR (tail))] = 0;
972               if ((*fun) (fn, arg))
973                 return;
974             }
975         }
976     }
977   else
978     {
979       /* Case c) */
980       CONST char *nsuffix = (CONST char *) XSTRING_DATA (suffixes);
981
982       while (1)
983         {
984           char *esuffix = (char *) strchr (nsuffix, ':');
985           int lsuffix = ((esuffix) ? (esuffix - nsuffix) : strlen (nsuffix));
986
987           /* Concatenate path element/specified name with the suffix.  */
988           strncpy (fn + fn_len, nsuffix, lsuffix);
989           fn[fn_len + lsuffix] = 0;
990
991           if ((*fun) (fn, arg))
992             return;
993
994           /* Advance to next suffix.  */
995           if (esuffix == 0)
996             break;
997           nsuffix += lsuffix + 1;
998         }
999     }
1000 }
1001
1002 struct locate_file_in_directory_mapper_closure {
1003   int fd;
1004   Lisp_Object *storeptr;
1005   int mode;
1006 };
1007
1008 static int
1009 locate_file_in_directory_mapper (char *fn, void *arg)
1010 {
1011   struct locate_file_in_directory_mapper_closure *closure =
1012     (struct locate_file_in_directory_mapper_closure *)arg;
1013   struct stat st;
1014
1015   /* Ignore file if it's a directory.  */
1016   if (stat (fn, &st) >= 0
1017       && (st.st_mode & S_IFMT) != S_IFDIR)
1018     {
1019       /* Check that we can access or open it.  */
1020       if (closure->mode >= 0)
1021         closure->fd = access (fn, closure->mode);
1022       else
1023         closure->fd = open (fn, O_RDONLY | OPEN_BINARY, 0);
1024
1025       if (closure->fd >= 0)
1026         {
1027           /* We succeeded; return this descriptor and filename.  */
1028           if (closure->storeptr)
1029             *closure->storeptr = build_string (fn);
1030
1031 #ifndef WINDOWSNT
1032           /* If we actually opened the file, set close-on-exec flag
1033              on the new descriptor so that subprocesses can't whack
1034              at it.  */
1035           if (closure->mode < 0)
1036             (void) fcntl (closure->fd, F_SETFD, FD_CLOEXEC);
1037 #endif
1038
1039           return 1;
1040         }
1041     }
1042   /* Keep mapping. */
1043   return 0;
1044 }
1045
1046
1047 /* look for STR in PATH, optionally adding SUFFIXES.  DIRECTORY need
1048    not have been expanded.  */
1049
1050 static int
1051 locate_file_in_directory (Lisp_Object directory, Lisp_Object str,
1052                           Lisp_Object suffixes, Lisp_Object *storeptr,
1053                           int mode)
1054 {
1055   /* This function can GC */
1056   struct locate_file_in_directory_mapper_closure closure;
1057   Lisp_Object filename = Qnil;
1058   struct gcpro gcpro1, gcpro2, gcpro3;
1059
1060   GCPRO3 (directory, str, filename);
1061
1062   filename = Fexpand_file_name (str, directory);
1063   if (NILP (filename) || NILP (Ffile_name_absolute_p (filename)))
1064     /* If there are non-absolute elts in PATH (eg ".") */
1065     /* Of course, this could conceivably lose if luser sets
1066        default-directory to be something non-absolute ... */
1067     {
1068       if (NILP (filename))
1069         /* NIL means current directory */
1070         filename = current_buffer->directory;
1071       else
1072         filename = Fexpand_file_name (filename,
1073                                       current_buffer->directory);
1074       if (NILP (Ffile_name_absolute_p (filename)))
1075         {
1076           /* Give up on this directory! */
1077           UNGCPRO;
1078           return -1;
1079         }
1080     }
1081
1082   closure.fd = -1;
1083   closure.storeptr = storeptr;
1084   closure.mode = mode;
1085
1086   locate_file_map_suffixes (filename, suffixes, locate_file_in_directory_mapper,
1087                             &closure);
1088
1089   UNGCPRO;
1090   return closure.fd;
1091 }
1092
1093 /* do the same as locate_file() but don't use any hash tables. */
1094
1095 static int
1096 locate_file_without_hash (Lisp_Object path, Lisp_Object str,
1097                           Lisp_Object suffixes, Lisp_Object *storeptr,
1098                           int mode)
1099 {
1100   /* This function can GC */
1101   int absolute = !NILP (Ffile_name_absolute_p (str));
1102
1103   EXTERNAL_LIST_LOOP (path, path)
1104     {
1105       int val = locate_file_in_directory (XCAR (path), str, suffixes, storeptr,
1106                                           mode);
1107       if (val >= 0)
1108         return val;
1109       if (absolute)
1110         break;
1111     }
1112   return -1;
1113 }
1114
1115 static int
1116 locate_file_construct_suffixed_files_mapper (char *fn, void *arg)
1117 {
1118   Lisp_Object *tail = (Lisp_Object *)arg;
1119   *tail = Fcons (build_string (fn), *tail);
1120   return 0;
1121 }
1122
1123 /* Construct a list of all files to search for.
1124    It makes sense to have this despite locate_file_map_suffixes()
1125    because we need Lisp strings to access the hash-table, and it would
1126    be inefficient to create them on the fly, again and again for each
1127    path component.  See locate_file(). */
1128
1129 static Lisp_Object
1130 locate_file_construct_suffixed_files (Lisp_Object filename,
1131                                       Lisp_Object suffixes)
1132 {
1133   Lisp_Object tail = Qnil;
1134   struct gcpro gcpro1;
1135   GCPRO1 (tail);
1136
1137   locate_file_map_suffixes (filename, suffixes,
1138                             locate_file_construct_suffixed_files_mapper,
1139                             &tail);
1140
1141   UNGCPRO;
1142   return Fnreverse (tail);
1143 }
1144
1145 DEFUN ("locate-file-clear-hashing", Flocate_file_clear_hashing, 1, 1, 0, /*
1146 Clear the hash records for the specified list of directories.
1147 `locate-file' uses a hashing scheme to speed lookup, and will correctly
1148 track the following environmental changes:
1149
1150 -- changes of any sort to the list of directories to be searched.
1151 -- addition and deletion of non-shadowing files (see below) from the
1152    directories in the list.
1153 -- byte-compilation of a .el file into a .elc file.
1154
1155 `locate-file' will primarily get confused if you add a file that shadows
1156 \(i.e. has the same name as) another file further down in the directory list.
1157 In this case, you must call `locate-file-clear-hashing'.
1158
1159 If PATH is t, it means to fully clear all the accumulated hashes.  This
1160 can be used if the internal tables grow too large, or when dumping.
1161 */
1162        (path))
1163 {
1164   if (EQ (path, Qt))
1165     Fclrhash (Vlocate_file_hash_table);
1166   else
1167     {
1168       Lisp_Object pathtail;
1169       EXTERNAL_LIST_LOOP (pathtail, path)
1170         {
1171           Lisp_Object pathel = Fexpand_file_name (XCAR (pathtail), Qnil);
1172           Fremhash (pathel, Vlocate_file_hash_table);
1173         }
1174     }
1175   return Qnil;
1176 }
1177
1178 /* Search for a file whose name is STR, looking in directories
1179    in the Lisp list PATH, and trying suffixes from SUFFIXES.
1180    SUFFIXES is a list of possible suffixes, or (for backward
1181    compatibility) a string containing possible suffixes separated by
1182    colons.
1183    On success, returns a file descriptor.  On failure, returns -1.
1184
1185    MODE nonnegative means don't open the files,
1186    just look for one for which access(file,MODE) succeeds.  In this case,
1187    returns 1 on success.
1188
1189    If STOREPTR is nonzero, it points to a slot where the name of
1190    the file actually found should be stored as a Lisp string.
1191    Nil is stored there on failure.
1192
1193    Called openp() in FSFmacs. */
1194
1195 int
1196 locate_file (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
1197              Lisp_Object *storeptr, int mode)
1198 {
1199   /* This function can GC */
1200   Lisp_Object suffixtab = Qnil;
1201   Lisp_Object pathtail, pathel_expanded;
1202   int val;
1203   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1204
1205   if (storeptr)
1206     *storeptr = Qnil;
1207
1208   /* Is it really necessary to gcpro path and str?  It shouldn't be
1209      unless some caller has fucked up.  There are known instances that
1210      call us with build_string("foo:bar") as SUFFIXES, though. */
1211   GCPRO4 (path, str, suffixes, suffixtab);
1212
1213   /* if this filename has directory components, it's too complicated
1214      to try and use the hash tables. */
1215   if (!NILP (Ffile_name_directory (str)))
1216     {
1217       val = locate_file_without_hash (path, str, suffixes, storeptr, mode);
1218       UNGCPRO;
1219       return val;
1220     }
1221
1222   suffixtab = locate_file_construct_suffixed_files (str, suffixes);
1223
1224   EXTERNAL_LIST_LOOP (pathtail, path)
1225     {
1226       Lisp_Object pathel = XCAR (pathtail);
1227       Lisp_Object hash_table;
1228       Lisp_Object tail;
1229       int found = 0;
1230
1231       /* If this path element is relative, we have to look by hand. */
1232       if (NILP (Ffile_name_absolute_p (pathel)))
1233         {
1234           val = locate_file_in_directory (pathel, str, suffixes, storeptr,
1235                                           mode);
1236           if (val >= 0)
1237             {
1238               UNGCPRO;
1239               return val;
1240             }
1241           continue;
1242         }
1243
1244       pathel_expanded = Fexpand_file_name (pathel, Qnil);
1245       hash_table = locate_file_find_directory_hash_table (pathel_expanded);
1246
1247       if (!NILP (hash_table))
1248         {
1249           /* Loop over suffixes.  */
1250           LIST_LOOP (tail, suffixtab)
1251             if (!NILP (Fgethash (XCAR (tail), hash_table, Qnil)))
1252               {
1253                 found = 1;
1254                 break;
1255               }
1256         }
1257
1258       if (found)
1259         {
1260           /* This is a likely candidate.  Look by hand in this directory
1261              so we don't get thrown off if someone byte-compiles a file. */
1262           val = locate_file_in_directory (pathel, str, suffixes, storeptr,
1263                                           mode);
1264           if (val >= 0)
1265             {
1266               UNGCPRO;
1267               return val;
1268             }
1269
1270           /* Hmm ...  the file isn't actually there. (Or possibly it's
1271              a directory ...)  So refresh our hashing. */
1272           locate_file_refresh_hashing (pathel_expanded);
1273         }
1274     }
1275
1276   /* File is probably not there, but check the hard way just in case. */
1277   val = locate_file_without_hash (path, str, suffixes, storeptr, mode);
1278   if (val >= 0)
1279     {
1280       /* Sneaky user added a file without telling us. */
1281       Flocate_file_clear_hashing (path);
1282     }
1283
1284   UNGCPRO;
1285   return val;
1286 }
1287
1288 \f
1289 #ifdef LOADHIST
1290
1291 /* Merge the list we've accumulated of globals from the current input source
1292    into the load_history variable.  The details depend on whether
1293    the source has an associated file name or not. */
1294
1295 static void
1296 build_load_history (int loading, Lisp_Object source)
1297 {
1298   REGISTER Lisp_Object tail, prev, newelt;
1299   REGISTER Lisp_Object tem, tem2;
1300   int foundit;
1301
1302 #if !defined(LOADHIST_DUMPED)
1303   /* Don't bother recording anything for preloaded files.  */
1304   if (purify_flag)
1305     return;
1306 #endif
1307
1308   tail = Vload_history;
1309   prev = Qnil;
1310   foundit = 0;
1311   while (!NILP (tail))
1312     {
1313       tem = Fcar (tail);
1314
1315       /* Find the feature's previous assoc list... */
1316       if (internal_equal (source, Fcar (tem), 0))
1317         {
1318           foundit = 1;
1319
1320           /*  If we're loading, remove it. */
1321           if (loading)
1322             {
1323               if (NILP (prev))
1324                 Vload_history = Fcdr (tail);
1325               else
1326                 Fsetcdr (prev, Fcdr (tail));
1327             }
1328
1329           /*  Otherwise, cons on new symbols that are not already members.  */
1330           else
1331             {
1332               tem2 = Vcurrent_load_list;
1333
1334               while (CONSP (tem2))
1335                 {
1336                   newelt = XCAR (tem2);
1337
1338                   if (NILP (Fmemq (newelt, tem)))
1339                     Fsetcar (tail, Fcons (Fcar (tem),
1340                                           Fcons (newelt, Fcdr (tem))));
1341
1342                   tem2 = XCDR (tem2);
1343                   QUIT;
1344                 }
1345             }
1346         }
1347       else
1348         prev = tail;
1349       tail = Fcdr (tail);
1350       QUIT;
1351     }
1352
1353   /* If we're loading, cons the new assoc onto the front of load-history,
1354      the most-recently-loaded position.  Also do this if we didn't find
1355      an existing member for the current source.  */
1356   if (loading || !foundit)
1357     Vload_history = Fcons (Fnreverse (Vcurrent_load_list),
1358                            Vload_history);
1359 }
1360
1361 #else /* !LOADHIST */
1362 #define build_load_history(x,y)
1363 #endif /* !LOADHIST */
1364
1365 \f
1366 #if 0 /* FSFmacs defun hack */
1367 Lisp_Object
1368 unreadpure (void)       /* Used as unwind-protect function in readevalloop */
1369 {
1370   read_pure = 0;
1371   return Qnil;
1372 }
1373 #endif /* 0 */
1374
1375 static void
1376 readevalloop (Lisp_Object readcharfun,
1377               Lisp_Object sourcename,
1378               Lisp_Object (*evalfun) (Lisp_Object),
1379               int printflag)
1380 {
1381   /* This function can GC */
1382   REGISTER Emchar c;
1383   REGISTER Lisp_Object val = Qnil;
1384   int speccount = specpdl_depth ();
1385   struct gcpro gcpro1, gcpro2;
1386   struct buffer *b = 0;
1387
1388   if (BUFFERP (readcharfun))
1389     b = XBUFFER (readcharfun);
1390   else if (MARKERP (readcharfun))
1391     b = XMARKER (readcharfun)->buffer;
1392
1393   /* Don't do this.  It is not necessary, and it needlessly exposes
1394      READCHARFUN (which can be a stream) to Lisp.  --hniksic */
1395   /*specbind (Qstandard_input, readcharfun);*/
1396
1397   specbind (Qcurrent_load_list, Qnil);
1398
1399 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1400   Vcurrent_compiled_function_annotation = Qnil;
1401 #endif
1402   GCPRO2 (val, sourcename);
1403
1404   LOADHIST_ATTACH (sourcename);
1405
1406   while (1)
1407     {
1408       QUIT;
1409
1410       if (b != 0 && !BUFFER_LIVE_P (b))
1411         error ("Reading from killed buffer");
1412
1413       c = readchar (readcharfun);
1414       if (c == ';')
1415         {
1416           /* Skip comment */
1417           while ((c = readchar (readcharfun)) != '\n' && c != -1)
1418             QUIT;
1419           continue;
1420         }
1421       if (c < 0)
1422         break;
1423
1424       /* Ignore whitespace here, so we can detect eof.  */
1425       if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r')
1426         continue;
1427
1428 #if 0 /* FSFmacs defun hack */
1429       if (purify_flag && c == '(')
1430         {
1431           int count1 = specpdl_depth ();
1432           record_unwind_protect (unreadpure, Qnil);
1433           val = read_list (readcharfun, ')', -1, 1);
1434           unbind_to (count1, Qnil);
1435         }
1436       else
1437 #else /* No "defun hack" -- Emacs 19 uses read-time syntax for bytecodes */
1438         {
1439           unreadchar (readcharfun, c);
1440           Vread_objects = Qnil;
1441           if (NILP (Vload_read_function))
1442             val = read0 (readcharfun);
1443           else
1444             val = call1 (Vload_read_function, readcharfun);
1445         }
1446 #endif
1447       val = (*evalfun) (val);
1448       if (printflag)
1449         {
1450           Vvalues = Fcons (val, Vvalues);
1451           if (EQ (Vstandard_output, Qt))
1452             Fprin1 (val, Qnil);
1453           else
1454             Fprint (val, Qnil);
1455         }
1456     }
1457
1458   build_load_history (LSTREAMP (readcharfun) ||
1459                       /* This looks weird, but it's what's in FSFmacs */
1460                       (b ? BUF_NARROWED (b) : BUF_NARROWED (current_buffer)),
1461                       sourcename);
1462   UNGCPRO;
1463
1464   unbind_to (speccount, Qnil);
1465 }
1466
1467 DEFUN ("eval-buffer", Feval_buffer, 0, 2, "bBuffer: ", /*
1468 Execute BUFFER as Lisp code.
1469 Programs can pass two arguments, BUFFER and PRINTFLAG.
1470 BUFFER is the buffer to evaluate (nil means use current buffer).
1471 PRINTFLAG controls printing of output:
1472 nil means discard it; anything else is stream for print.
1473
1474 If there is no error, point does not move.  If there is an error,
1475 point remains at the end of the last character read from the buffer.
1476 Execute BUFFER as Lisp code.
1477 */
1478        (bufname, printflag))
1479 {
1480   /* This function can GC */
1481   int speccount = specpdl_depth ();
1482   Lisp_Object tem, buf;
1483
1484   if (NILP (bufname))
1485     buf = Fcurrent_buffer ();
1486   else
1487     buf = Fget_buffer (bufname);
1488   if (NILP (buf))
1489     error ("No such buffer.");
1490
1491   if (NILP (printflag))
1492     tem = Qsymbolp;             /* #### #@[]*&$#*[& SI:NULL-STREAM */
1493   else
1494     tem = printflag;
1495   specbind (Qstandard_output, tem);
1496   record_unwind_protect (save_excursion_restore, save_excursion_save ());
1497   BUF_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
1498   readevalloop (buf, XBUFFER (buf)->filename, Feval,
1499                 !NILP (printflag));
1500
1501   return unbind_to (speccount, Qnil);
1502 }
1503
1504 #if 0
1505 xxDEFUN ("eval-current-buffer", Feval_current_buffer, 0, 1, "", /*
1506 Execute the current buffer as Lisp code.
1507 Programs can pass argument PRINTFLAG which controls printing of output:
1508 nil means discard it; anything else is stream for print.
1509
1510 If there is no error, point does not move.  If there is an error,
1511 point remains at the end of the last character read from the buffer.
1512 */
1513          (printflag))
1514 {
1515   code omitted;
1516 }
1517 #endif /* 0 */
1518
1519 DEFUN ("eval-region", Feval_region, 2, 3, "r", /*
1520 Execute the region as Lisp code.
1521 When called from programs, expects two arguments,
1522 giving starting and ending indices in the current buffer
1523 of the text to be executed.
1524 Programs can pass third argument PRINTFLAG which controls output:
1525 nil means discard it; anything else is stream for printing it.
1526
1527 If there is no error, point does not move.  If there is an error,
1528 point remains at the end of the last character read from the buffer.
1529
1530 Note:  Before evaling the region, this function narrows the buffer to it.
1531 If the code being eval'd should happen to trigger a redisplay you may
1532 see some text temporarily disappear because of this.
1533 */
1534        (b, e, printflag))
1535 {
1536   /* This function can GC */
1537   int speccount = specpdl_depth ();
1538   Lisp_Object tem;
1539   Lisp_Object cbuf = Fcurrent_buffer ();
1540
1541   if (NILP (printflag))
1542     tem = Qsymbolp;             /* #### #@[]*&$#*[& SI:NULL-STREAM */
1543   else
1544     tem = printflag;
1545   specbind (Qstandard_output, tem);
1546
1547   if (NILP (printflag))
1548     record_unwind_protect (save_excursion_restore, save_excursion_save ());
1549   record_unwind_protect (save_restriction_restore, save_restriction_save ());
1550
1551   /* This both uses b and checks its type.  */
1552   Fgoto_char (b, cbuf);
1553   Fnarrow_to_region (make_int (BUF_BEGV (current_buffer)), e, cbuf);
1554   readevalloop (cbuf, XBUFFER (cbuf)->filename, Feval,
1555                 !NILP (printflag));
1556
1557   return unbind_to (speccount, Qnil);
1558 }
1559 \f
1560 DEFUN ("read", Fread, 0, 1, 0, /*
1561 Read one Lisp expression as text from STREAM, return as Lisp object.
1562 If STREAM is nil, use the value of `standard-input' (which see).
1563 STREAM or the value of `standard-input' may be:
1564  a buffer (read from point and advance it)
1565  a marker (read from where it points and advance it)
1566  a function (call it with no arguments for each character,
1567      call it with a char as argument to push a char back)
1568  a string (takes text from string, starting at the beginning)
1569  t (read text line using minibuffer and use it).
1570 */
1571        (stream))
1572 {
1573   if (NILP (stream))
1574     stream = Vstandard_input;
1575   if (EQ (stream, Qt))
1576     stream = Qread_char;
1577
1578   Vread_objects = Qnil;
1579
1580 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1581   Vcurrent_compiled_function_annotation = Qnil;
1582 #endif
1583   if (EQ (stream, Qread_char))
1584     {
1585       Lisp_Object val = call1 (Qread_from_minibuffer,
1586                                build_translated_string ("Lisp expression: "));
1587       return Fcar (Fread_from_string (val, Qnil, Qnil));
1588     }
1589
1590   if (STRINGP (stream))
1591     return Fcar (Fread_from_string (stream, Qnil, Qnil));
1592
1593   return read0 (stream);
1594 }
1595
1596 DEFUN ("read-from-string", Fread_from_string, 1, 3, 0, /*
1597 Read one Lisp expression which is represented as text by STRING.
1598 Returns a cons: (OBJECT-READ . FINAL-STRING-INDEX).
1599 START and END optionally delimit a substring of STRING from which to read;
1600  they default to 0 and (length STRING) respectively.
1601 */
1602        (string, start, end))
1603 {
1604   Bytecount startval, endval;
1605   Lisp_Object tem;
1606   Lisp_Object lispstream = Qnil;
1607   struct gcpro gcpro1;
1608
1609 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
1610   Vcurrent_compiled_function_annotation = Qnil;
1611 #endif
1612   GCPRO1 (lispstream);
1613   CHECK_STRING (string);
1614   get_string_range_byte (string, start, end, &startval, &endval,
1615                          GB_HISTORICAL_STRING_BEHAVIOR);
1616   lispstream = make_lisp_string_input_stream (string, startval,
1617                                               endval - startval);
1618
1619   Vread_objects = Qnil;
1620
1621   tem = read0 (lispstream);
1622   /* Yeah, it's ugly.  Gonna make something of it?
1623      At least our reader is reentrant ... */
1624   tem =
1625     (Fcons (tem, make_int
1626             (bytecount_to_charcount
1627              (XSTRING_DATA (string),
1628               startval + Lstream_byte_count (XLSTREAM (lispstream))))));
1629   Lstream_delete (XLSTREAM (lispstream));
1630   UNGCPRO;
1631   return tem;
1632 }
1633
1634 \f
1635 #ifdef LISP_BACKQUOTES
1636
1637 static Lisp_Object
1638 backquote_unwind (Lisp_Object ptr)
1639 {  /* used as unwind-protect function in read0() */
1640   int *counter = (int *) get_opaque_ptr (ptr);
1641   if (--*counter < 0)
1642     *counter = 0;
1643   free_opaque_ptr (ptr);
1644   return Qnil;
1645 }
1646
1647 #endif
1648
1649 /* Use this for recursive reads, in contexts where internal tokens
1650    are not allowed.  See also read1(). */
1651 static Lisp_Object
1652 read0 (Lisp_Object readcharfun)
1653 {
1654   Lisp_Object val = read1 (readcharfun);
1655
1656   if (CONSP (val) && UNBOUNDP (XCAR (val)))
1657     {
1658       Emchar c = XCHAR (XCDR (val));
1659       free_cons (XCONS (val));
1660       return Fsignal (Qinvalid_read_syntax,
1661                       list1 (Fchar_to_string (make_char (c))));
1662     }
1663
1664   return val;
1665 }
1666 \f
1667 static Emchar
1668 read_escape (Lisp_Object readcharfun)
1669 {
1670   /* This function can GC */
1671   Emchar c = readchar (readcharfun);
1672
1673   if (c < 0)
1674     signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1675
1676   switch (c)
1677     {
1678     case 'a': return '\007';
1679     case 'b': return '\b';
1680     case 'd': return 0177;
1681     case 'e': return 033;
1682     case 'f': return '\f';
1683     case 'n': return '\n';
1684     case 'r': return '\r';
1685     case 't': return '\t';
1686     case 'v': return '\v';
1687     case '\n': return -1;
1688
1689     case 'M':
1690       c = readchar (readcharfun);
1691       if (c < 0)
1692         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1693       if (c != '-')
1694         error ("Invalid escape character syntax");
1695       c = readchar (readcharfun);
1696       if (c < 0)
1697         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1698       if (c == '\\')
1699         c = read_escape (readcharfun);
1700       return c | 0200;
1701
1702       /* Originally, FSF_KEYS provided a degree of FSF Emacs
1703          compatibility by defining character "modifiers" alt, super,
1704          hyper and shift to infest the characters (i.e. integers).
1705
1706          However, this doesn't cut it for XEmacs 20, which
1707          distinguishes characters from integers.  Without Mule, ?\H-a
1708          simply returns ?a because every character is clipped into
1709          0-255.  Under Mule it is much worse -- ?\H-a with FSF_KEYS
1710          produces an illegal character, and moves us to crash-land.
1711
1712          For these reasons, FSF_KEYS hack is useless and without hope
1713          of ever working under XEmacs 20.  */
1714 #undef FSF_KEYS
1715
1716 #ifdef FSF_KEYS
1717 #define alt_modifier   (0x040000)
1718 #define super_modifier (0x080000)
1719 #define hyper_modifier (0x100000)
1720 #define shift_modifier (0x200000)
1721 /* fsf uses a different modifiers for meta and control.  Possibly
1722    byte_compiled code will still work fsfmacs, though... --Stig
1723
1724    #define ctl_modifier   (0x400000)
1725    #define meta_modifier  (0x800000)
1726 */
1727 #define FSF_LOSSAGE(mask)                                                       \
1728       if (fail_on_bucky_bit_character_escapes ||                                \
1729           ((c = readchar (readcharfun)) != '-'))                                \
1730         error ("Invalid escape character syntax");                              \
1731       c = readchar (readcharfun);                                               \
1732       if (c < 0)                                                                \
1733         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));   \
1734       if (c == '\\')                                                            \
1735         c = read_escape (readcharfun);                                          \
1736       return c | mask
1737
1738     case 'S': FSF_LOSSAGE (shift_modifier);
1739     case 'H': FSF_LOSSAGE (hyper_modifier);
1740     case 'A': FSF_LOSSAGE (alt_modifier);
1741     case 's': FSF_LOSSAGE (super_modifier);
1742 #undef alt_modifier
1743 #undef super_modifier
1744 #undef hyper_modifier
1745 #undef shift_modifier
1746 #undef FSF_LOSSAGE
1747
1748 #endif /* FSF_KEYS */
1749
1750     case 'C':
1751       c = readchar (readcharfun);
1752       if (c < 0)
1753         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1754       if (c != '-')
1755         error ("Invalid escape character syntax");
1756     case '^':
1757       c = readchar (readcharfun);
1758       if (c < 0)
1759         signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1760       if (c == '\\')
1761         c = read_escape (readcharfun);
1762       /* FSFmacs junk for non-ASCII controls.
1763          Not used here. */
1764       if (c == '?')
1765         return 0177;
1766       else
1767         return c & (0200 | 037);
1768
1769     case '0':
1770     case '1':
1771     case '2':
1772     case '3':
1773     case '4':
1774     case '5':
1775     case '6':
1776     case '7':
1777       /* An octal escape, as in ANSI C.  */
1778       {
1779         REGISTER Emchar i = c - '0';
1780         REGISTER int count = 0;
1781         while (++count < 3)
1782           {
1783             if ((c = readchar (readcharfun)) >= '0' && c <= '7')
1784               i = (i << 3) + (c - '0');
1785             else
1786               {
1787                 unreadchar (readcharfun, c);
1788                 break;
1789               }
1790           }
1791         return i;
1792       }
1793
1794     case 'x':
1795       /* A hex escape, as in ANSI C, except that we only allow latin-1
1796          characters to be read this way.  What is "\x4e03" supposed to
1797          mean, anyways, if the internal representation is hidden?
1798          This is also consistent with the treatment of octal escapes. */
1799       {
1800         REGISTER Emchar i = 0;
1801         REGISTER int count = 0;
1802         while (++count <= 2)
1803           {
1804             c = readchar (readcharfun);
1805             /* Remember, can't use isdigit(), isalpha() etc. on Emchars */
1806             if      (c >= '0' && c <= '9')  i = (i << 4) + (c - '0');
1807             else if (c >= 'a' && c <= 'f')  i = (i << 4) + (c - 'a') + 10;
1808             else if (c >= 'A' && c <= 'F')  i = (i << 4) + (c - 'A') + 10;
1809             else
1810               {
1811                 unreadchar (readcharfun, c);
1812                 break;
1813               }
1814           }
1815         return i;
1816       }
1817
1818 #ifdef MULE
1819       /* #### need some way of reading an extended character with
1820          an escape sequence. */
1821 #endif
1822
1823     default:
1824         return c;
1825     }
1826 }
1827
1828
1829 \f
1830 /* read symbol-constituent stuff into `Vread_buffer_stream'. */
1831 static Bytecount
1832 read_atom_0 (Lisp_Object readcharfun, Emchar firstchar, int *saw_a_backslash)
1833 {
1834   /* This function can GC */
1835   Emchar c = ((firstchar) >= 0 ? firstchar : readchar (readcharfun));
1836   Lstream_rewind (XLSTREAM (Vread_buffer_stream));
1837
1838   *saw_a_backslash = 0;
1839
1840   while (c > 040        /* #### - comma should be here as should backquote */
1841          && !(c == '\"' || c == '\'' || c == ';'
1842               || c == '(' || c == ')'
1843 #ifndef LISP_FLOAT_TYPE
1844               /* If we have floating-point support, then we need
1845                  to allow <digits><dot><digits>.  */
1846               || c =='.'
1847 #endif /* not LISP_FLOAT_TYPE */
1848               || c == '[' || c == ']' || c == '#'
1849               ))
1850     {
1851       if (c == '\\')
1852         {
1853           c = readchar (readcharfun);
1854           if (c < 0)
1855             signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
1856           *saw_a_backslash = 1;
1857         }
1858       Lstream_put_emchar (XLSTREAM (Vread_buffer_stream), c);
1859       QUIT;
1860       c = readchar (readcharfun);
1861     }
1862
1863   if (c >= 0)
1864     unreadchar (readcharfun, c);
1865   /* blasted terminating 0 */
1866   Lstream_put_emchar (XLSTREAM (Vread_buffer_stream), 0);
1867   Lstream_flush (XLSTREAM (Vread_buffer_stream));
1868
1869   return Lstream_byte_count (XLSTREAM (Vread_buffer_stream)) - 1;
1870 }
1871
1872 static Lisp_Object parse_integer (CONST Bufbyte *buf, Bytecount len, int base);
1873
1874 static Lisp_Object
1875 read_atom (Lisp_Object readcharfun,
1876            Emchar firstchar,
1877            int uninterned_symbol)
1878 {
1879   /* This function can GC */
1880   int saw_a_backslash;
1881   Bytecount len = read_atom_0 (readcharfun, firstchar, &saw_a_backslash);
1882   char *read_ptr = (char *)
1883     resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream));
1884
1885   /* Is it an integer? */
1886   if (! (saw_a_backslash || uninterned_symbol))
1887     {
1888       /* If a token had any backslashes in it, it is disqualified from
1889          being an integer or a float.  This means that 123\456 is a
1890          symbol, as is \123 (which is the way (intern "123") prints).
1891          Also, if token was preceded by #:, it's always a symbol.
1892        */
1893       char *p = read_ptr + len;
1894       char *p1 = read_ptr;
1895
1896       if (*p1 == '+' || *p1 == '-') p1++;
1897       if (p1 != p)
1898         {
1899           int c;
1900
1901           while (p1 != p && (c = *p1) >= '0' && c <= '9')
1902             p1++;
1903 #ifdef LISP_FLOAT_TYPE
1904           /* Integers can have trailing decimal points.  */
1905           if (p1 > read_ptr && p1 < p && *p1 == '.')
1906             p1++;
1907 #endif
1908           if (p1 == p)
1909             {
1910               /* It is an integer. */
1911 #ifdef LISP_FLOAT_TYPE
1912               if (p1[-1] == '.')
1913                 p1[-1] = '\0';
1914 #endif
1915 #if 0
1916               {
1917                 int number = 0;
1918                 if (sizeof (int) == sizeof (EMACS_INT))
1919                   number = atoi (read_buffer);
1920                 else if (sizeof (long) == sizeof (EMACS_INT))
1921                   number = atol (read_buffer);
1922                 else
1923                   abort ();
1924                 return make_int (number);
1925               }
1926 #else
1927               return parse_integer ((Bufbyte *) read_ptr, len, 10);
1928 #endif
1929             }
1930         }
1931 #ifdef LISP_FLOAT_TYPE
1932       if (isfloat_string (read_ptr))
1933         return make_float (atof (read_ptr));
1934 #endif
1935     }
1936
1937   {
1938     Lisp_Object sym;
1939     if (uninterned_symbol)
1940       sym = Fmake_symbol ( make_string ((Bufbyte *) read_ptr, len));
1941     else
1942       {
1943         Lisp_Object name = make_string ((Bufbyte *) read_ptr, len);
1944         sym = Fintern (name, Qnil);
1945       }
1946     return sym;
1947   }
1948 }
1949
1950
1951 static Lisp_Object
1952 parse_integer (CONST Bufbyte *buf, Bytecount len, int base)
1953 {
1954   CONST Bufbyte *lim = buf + len;
1955   CONST Bufbyte *p = buf;
1956   EMACS_UINT num = 0;
1957   int negativland = 0;
1958
1959   if (*p == '-')
1960     {
1961       negativland = 1;
1962       p++;
1963     }
1964   else if (*p == '+')
1965     {
1966       p++;
1967     }
1968
1969   if (p == lim)
1970     goto loser;
1971
1972   for (; (p < lim) && (*p != '\0'); p++)
1973     {
1974       int c = *p;
1975       EMACS_UINT onum;
1976
1977       if (isdigit (c))
1978         c = c - '0';
1979       else if (isupper (c))
1980         c = c - 'A' + 10;
1981       else if (islower (c))
1982         c = c - 'a' + 10;
1983       else
1984         goto loser;
1985
1986       if (c < 0 || c >= base)
1987         goto loser;
1988
1989       onum = num;
1990       num = num * base + c;
1991       if (num < onum)
1992         goto overflow;
1993     }
1994
1995   {
1996     EMACS_INT int_result = negativland ? - (EMACS_INT) num : (EMACS_INT) num;
1997     Lisp_Object result = make_int (int_result);
1998     if (num && ((XINT (result) < 0) != negativland))
1999       goto overflow;
2000     if (XINT (result) != int_result)
2001       goto overflow;
2002     return result;
2003   }
2004  overflow:
2005   return Fsignal (Qinvalid_read_syntax,
2006                   list3 (build_translated_string
2007                          ("Integer constant overflow in reader"),
2008                          make_string (buf, len),
2009                          make_int (base)));
2010  loser:
2011   return Fsignal (Qinvalid_read_syntax,
2012                   list3 (build_translated_string
2013                          ("Invalid integer constant in reader"),
2014                          make_string (buf, len),
2015                          make_int (base)));
2016 }
2017
2018
2019 static Lisp_Object
2020 read_integer (Lisp_Object readcharfun, int base)
2021 {
2022   /* This function can GC */
2023   int saw_a_backslash;
2024   Bytecount len = read_atom_0 (readcharfun, -1, &saw_a_backslash);
2025   return (parse_integer
2026           (resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)),
2027            ((saw_a_backslash)
2028             ? 0 /* make parse_integer signal error */
2029             : len),
2030            base));
2031 }
2032
2033 static Lisp_Object
2034 read_bit_vector (Lisp_Object readcharfun)
2035 {
2036   unsigned_char_dynarr *dyn = Dynarr_new (unsigned_char);
2037   Emchar c;
2038
2039   while (1)
2040     {
2041       c = readchar (readcharfun);
2042       if (c != '0' && c != '1')
2043         break;
2044       Dynarr_add (dyn, (unsigned char) (c - '0'));
2045     }
2046
2047   if (c >= 0)
2048     unreadchar (readcharfun, c);
2049
2050   return make_bit_vector_from_byte_vector (Dynarr_atp (dyn, 0),
2051                                            Dynarr_length (dyn));
2052 }
2053
2054 \f
2055
2056 /* structures */
2057
2058 struct structure_type *
2059 define_structure_type (Lisp_Object type,
2060                        int (*validate) (Lisp_Object data,
2061                                         Error_behavior errb),
2062                        Lisp_Object (*instantiate) (Lisp_Object data))
2063 {
2064   struct structure_type st;
2065
2066   st.type = type;
2067   st.keywords = Dynarr_new (structure_keyword_entry);
2068   st.validate = validate;
2069   st.instantiate = instantiate;
2070   Dynarr_add (the_structure_type_dynarr, st);
2071
2072   return Dynarr_atp (the_structure_type_dynarr,
2073                      Dynarr_length (the_structure_type_dynarr) - 1);
2074 }
2075
2076 void
2077 define_structure_type_keyword (struct structure_type *st, Lisp_Object keyword,
2078                                int (*validate) (Lisp_Object keyword,
2079                                                 Lisp_Object value,
2080                                                 Error_behavior errb))
2081 {
2082   struct structure_keyword_entry en;
2083
2084   en.keyword = keyword;
2085   en.validate = validate;
2086   Dynarr_add (st->keywords, en);
2087 }
2088
2089 static struct structure_type *
2090 recognized_structure_type (Lisp_Object type)
2091 {
2092   int i;
2093
2094   for (i = 0; i < Dynarr_length (the_structure_type_dynarr); i++)
2095     {
2096       struct structure_type *st = Dynarr_atp (the_structure_type_dynarr, i);
2097       if (EQ (st->type, type))
2098         return st;
2099     }
2100
2101   return 0;
2102 }
2103
2104 static Lisp_Object
2105 read_structure (Lisp_Object readcharfun)
2106 {
2107   Emchar c = readchar (readcharfun);
2108   Lisp_Object list = Qnil;
2109   Lisp_Object orig_list = Qnil;
2110   Lisp_Object already_seen = Qnil;
2111   int keyword_count;
2112   struct structure_type *st;
2113   struct gcpro gcpro1, gcpro2;
2114
2115   GCPRO2 (orig_list, already_seen);
2116   if (c != '(')
2117     RETURN_UNGCPRO (continuable_syntax_error ("#s not followed by paren"));
2118   list = read_list (readcharfun, ')', 0, 0);
2119   orig_list = list;
2120   {
2121     int len = XINT (Flength (list));
2122     if (len == 0)
2123       RETURN_UNGCPRO (continuable_syntax_error
2124                       ("structure type not specified"));
2125     if (!(len & 1))
2126       RETURN_UNGCPRO
2127         (continuable_syntax_error
2128          ("structures must have alternating keyword/value pairs"));
2129   }
2130
2131   st = recognized_structure_type (XCAR (list));
2132   if (!st)
2133     RETURN_UNGCPRO (Fsignal (Qinvalid_read_syntax,
2134                              list2 (build_translated_string
2135                                     ("unrecognized structure type"),
2136                                     XCAR (list))));
2137
2138   list = Fcdr (list);
2139   keyword_count = Dynarr_length (st->keywords);
2140   while (!NILP (list))
2141     {
2142       Lisp_Object keyword, value;
2143       int i;
2144       struct structure_keyword_entry *en = NULL;
2145
2146       keyword = Fcar (list);
2147       list = Fcdr (list);
2148       value = Fcar (list);
2149       list = Fcdr (list);
2150
2151       if (!NILP (memq_no_quit (keyword, already_seen)))
2152         RETURN_UNGCPRO (Fsignal (Qinvalid_read_syntax,
2153                                  list2 (build_translated_string
2154                                         ("structure keyword already seen"),
2155                                         keyword)));
2156
2157       for (i = 0; i < keyword_count; i++)
2158         {
2159           en = Dynarr_atp (st->keywords, i);
2160           if (EQ (keyword, en->keyword))
2161             break;
2162         }
2163
2164       if (i == keyword_count)
2165         RETURN_UNGCPRO (Fsignal (Qinvalid_read_syntax,
2166                                    list2 (build_translated_string
2167                                           ("unrecognized structure keyword"),
2168                                           keyword)));
2169
2170       if (en->validate && ! (en->validate) (keyword, value, ERROR_ME))
2171         RETURN_UNGCPRO
2172           (Fsignal (Qinvalid_read_syntax,
2173                     list3 (build_translated_string
2174                            ("invalid value for structure keyword"),
2175                            keyword, value)));
2176
2177       already_seen = Fcons (keyword, already_seen);
2178     }
2179
2180   if (st->validate && ! (st->validate) (orig_list, ERROR_ME))
2181     RETURN_UNGCPRO (Fsignal (Qinvalid_read_syntax,
2182                              list2 (build_translated_string
2183                                     ("invalid structure initializer"),
2184                                     orig_list)));
2185
2186   RETURN_UNGCPRO ((st->instantiate) (XCDR (orig_list)));
2187 }
2188
2189 \f
2190 static Lisp_Object read_compiled_function (Lisp_Object readcharfun,
2191                                            int terminator);
2192 static Lisp_Object read_vector (Lisp_Object readcharfun, int terminator);
2193
2194 /* Get the next character; filter out whitespace and comments */
2195
2196 static Emchar
2197 reader_nextchar (Lisp_Object readcharfun)
2198 {
2199   /* This function can GC */
2200   Emchar c;
2201
2202  retry:
2203   QUIT;
2204   c = readchar (readcharfun);
2205   if (c < 0)
2206     signal_error (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
2207
2208   switch (c)
2209     {
2210     default:
2211       {
2212         /* Ignore whitespace and control characters */
2213         if (c <= 040)
2214           goto retry;
2215         return c;
2216       }
2217
2218     case ';':
2219       {
2220         /* Comment */
2221         while ((c = readchar (readcharfun)) >= 0 && c != '\n')
2222           QUIT;
2223         goto retry;
2224       }
2225     }
2226 }
2227
2228 #if 0
2229 static Lisp_Object
2230 list2_pure (int pure, Lisp_Object a, Lisp_Object b)
2231 {
2232   return pure ? pure_cons (a, pure_cons (b, Qnil)) : list2 (a, b);
2233 }
2234 #endif
2235
2236 /* Read the next Lisp object from the stream READCHARFUN and return it.
2237    If the return value is a cons whose car is Qunbound, then read1()
2238    encountered a misplaced token (e.g. a right bracket, right paren,
2239    or dot followed by a non-number).  To filter this stuff out,
2240    use read0(). */
2241
2242 static Lisp_Object
2243 read1 (Lisp_Object readcharfun)
2244 {
2245   Emchar c;
2246
2247 retry:
2248   c = reader_nextchar (readcharfun);
2249
2250   switch (c)
2251     {
2252     case '(':
2253       {
2254 #ifdef LISP_BACKQUOTES  /* old backquote compatibility in lisp reader */
2255         /* if this is disabled, then other code in eval.c must be enabled */
2256         Emchar ch = reader_nextchar (readcharfun);
2257         switch (ch)
2258           {
2259           case '`':
2260             {
2261               Lisp_Object tem;
2262               int speccount = specpdl_depth ();
2263               ++old_backquote_flag;
2264               record_unwind_protect (backquote_unwind,
2265                                      make_opaque_ptr (&old_backquote_flag));
2266               tem = read0 (readcharfun);
2267               unbind_to (speccount, Qnil);
2268               ch = reader_nextchar (readcharfun);
2269               if (ch != ')')
2270                 {
2271                   unreadchar (readcharfun, ch);
2272                   return Fsignal (Qinvalid_read_syntax,
2273                                   list1 (build_string
2274                                          ("Weird old-backquote syntax")));
2275                 }
2276               return list2 (Qbacktick, tem);
2277             }
2278           case ',':
2279             {
2280               if (old_backquote_flag)
2281                 {
2282                   Lisp_Object tem, comma_type;
2283                   ch = readchar (readcharfun);
2284                   if (ch == '@')
2285                     comma_type = Qcomma_at;
2286                   else
2287                     {
2288                       if (ch >= 0)
2289                         unreadchar (readcharfun, ch);
2290                       comma_type = Qcomma;
2291                     }
2292                   tem = read0 (readcharfun);
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 (comma_type, tem);
2302                 }
2303               else
2304                 {
2305                   unreadchar (readcharfun, ch);
2306 #if 0
2307                   return Fsignal (Qinvalid_read_syntax,
2308                        list1 (build_string ("Comma outside of backquote")));
2309 #else
2310                   /* #### - yuck....but this is reverse compatible. */
2311                   /* mostly this is required by edebug, which does its own
2312                      annotated reading.  We need to have an annotated_read
2313                      function that records (with markers) the buffer
2314                      positions of the elements that make up lists, then that
2315                      can be used in edebug and bytecomp and the check above
2316                      can go back in. --Stig */
2317                   break;
2318 #endif
2319                 }
2320             }
2321           default:
2322             unreadchar (readcharfun, ch);
2323           }                     /* switch(ch) */
2324 #endif /* old backquote crap... */
2325         return read_list (readcharfun, ')', 1, 1);
2326       }
2327     case '[':
2328       return read_vector (readcharfun, ']');
2329
2330     case ')':
2331     case ']':
2332       /* #### - huh? these don't do what they seem... */
2333       return noseeum_cons (Qunbound, make_char (c));
2334     case '.':
2335       {
2336 #ifdef LISP_FLOAT_TYPE
2337         /* If a period is followed by a number, then we should read it
2338            as a floating point number.  Otherwise, it denotes a dotted
2339            pair.
2340          */
2341         c = readchar (readcharfun);
2342         unreadchar (readcharfun, c);
2343
2344         /* Can't use isdigit on Emchars */
2345         if (c < '0' || c > '9')
2346           return noseeum_cons (Qunbound, make_char ('.'));
2347
2348         /* Note that read_atom will loop
2349            at least once, assuring that we will not try to UNREAD
2350            two characters in a row.
2351            (I think this doesn't matter anymore because there should
2352            be no more danger in unreading multiple characters) */
2353         return read_atom (readcharfun, '.', 0);
2354
2355 #else /* ! LISP_FLOAT_TYPE */
2356         return noseeum_cons (Qunbound, make_char ('.'));
2357 #endif /* ! LISP_FLOAT_TYPE */
2358       }
2359
2360     case '#':
2361       {
2362         c = readchar (readcharfun);
2363         switch (c)
2364           {
2365 #if 0 /* FSFmacs silly char-table syntax */
2366           case '^':
2367 #endif
2368 #if 0 /* FSFmacs silly bool-vector syntax */
2369           case '&':
2370 #endif
2371             /* "#["-- byte-code constant syntax */
2372             /* purecons #[...] syntax */
2373           case '[': return read_compiled_function (readcharfun, ']'
2374                                                    /*, purify_flag */ );
2375             /* "#:"-- gensym syntax */
2376           case ':': return read_atom (readcharfun, -1, 1);
2377             /* #'x => (function x) */
2378           case '\'': return list2 (Qfunction, read0 (readcharfun));
2379 #if 0
2380             /* RMS uses this syntax for fat-strings.
2381                If we use it for vectors, then obscure bugs happen.
2382              */
2383             /* "#(" -- Scheme/CL vector syntax */
2384           case '(': return read_vector (readcharfun, ')');
2385 #endif
2386 #if 0 /* FSFmacs */
2387           case '(':
2388             {
2389               Lisp_Object tmp;
2390               struct gcpro gcpro1;
2391
2392               /* Read the string itself.  */
2393               tmp = read1 (readcharfun);
2394               if (!STRINGP (tmp))
2395                 {
2396                   if (CONSP (tmp) && UNBOUNDP (XCAR (tmp)))
2397                     free_cons (XCONS (tmp));
2398                   return Fsignal (Qinvalid_read_syntax,
2399                                    list1 (build_string ("#")));
2400                 }
2401               GCPRO1 (tmp);
2402               /* Read the intervals and their properties.  */
2403               while (1)
2404                 {
2405                   Lisp_Object beg, end, plist;
2406                   Emchar ch;
2407                   int invalid = 0;
2408
2409                   beg = read1 (readcharfun);
2410                   if (CONSP (beg) && UNBOUNDP (XCAR (beg)))
2411                     {
2412                       ch = XCHAR (XCDR (beg));
2413                       free_cons (XCONS (beg));
2414                       if (ch == ')')
2415                         break;
2416                       else
2417                         invalid = 1;
2418                     }
2419                   if (!invalid)
2420                     {
2421                       end = read1 (readcharfun);
2422                       if (CONSP (end) && UNBOUNDP (XCAR (end)))
2423                         {
2424                           free_cons (XCONS (end));
2425                           invalid = 1;
2426                         }
2427                     }
2428                   if (!invalid)
2429                     {
2430                       plist = read1 (readcharfun);
2431                       if (CONSP (plist) && UNBOUNDP (XCAR (plist)))
2432                         {
2433                           free_cons (XCONS (plist));
2434                           invalid = 1;
2435                         }
2436                     }
2437                   if (invalid)
2438                     RETURN_UNGCPRO
2439                       (Fsignal (Qinvalid_read_syntax,
2440                                 list2
2441                                 (build_string ("invalid string property list"),
2442                                  XCDR (plist))));
2443                   Fset_text_properties (beg, end, plist, tmp);
2444                 }
2445               UNGCPRO;
2446               return tmp;
2447             }
2448 #endif /* 0 */
2449           case '@':
2450             {
2451               /* #@NUMBER is used to skip NUMBER following characters.
2452                  That's used in .elc files to skip over doc strings
2453                  and function definitions.  */
2454               int i, nskip = 0;
2455
2456               /* Read a decimal integer.  */
2457               while ((c = readchar (readcharfun)) >= 0
2458                      && c >= '0' && c <= '9')
2459                 nskip = (10 * nskip) + (c - '0');
2460               if (c >= 0)
2461                 unreadchar (readcharfun, c);
2462
2463               /* FSF has code here that maybe caches the skipped
2464                  string.  See above for why this is totally
2465                  losing.  We handle this differently. */
2466
2467               /* Skip that many characters.  */
2468               for (i = 0; i < nskip && c >= 0; i++)
2469                 c = readchar (readcharfun);
2470
2471               goto retry;
2472             }
2473           case '$': return Vload_file_name_internal;
2474             /* bit vectors */
2475           case '*': return read_bit_vector (readcharfun);
2476             /* #o10 => 8 -- octal constant syntax */
2477           case 'o': return read_integer (readcharfun, 8);
2478             /* #xdead => 57005 -- hex constant syntax */
2479           case 'x': return read_integer (readcharfun, 16);
2480             /* #b010 => 2 -- binary constant syntax */
2481           case 'b': return read_integer (readcharfun, 2);
2482             /* #s(foobar key1 val1 key2 val2) -- structure syntax */
2483           case 's': return read_structure (readcharfun);
2484           case '<':
2485             {
2486               unreadchar (readcharfun, c);
2487               return Fsignal (Qinvalid_read_syntax,
2488                     list1 (build_string ("Cannot read unreadable object")));
2489             }
2490 #ifdef FEATUREP_SYNTAX
2491           case '+':
2492           case '-':
2493             {
2494               Lisp_Object fexp, obj, tem;
2495               struct gcpro gcpro1, gcpro2;
2496
2497               fexp = read0(readcharfun);
2498               obj = read0(readcharfun);
2499
2500               /* the call to `featurep' may GC. */
2501               GCPRO2 (fexp, obj);
2502               tem = call1 (Qfeaturep, fexp);
2503               UNGCPRO;
2504
2505               if (c == '+' &&  NILP(tem)) goto retry;
2506               if (c == '-' && !NILP(tem)) goto retry;
2507               return obj;
2508             }
2509 #endif
2510           case '0': case '1': case '2': case '3': case '4':
2511           case '5': case '6': case '7': case '8': case '9':
2512             /* Reader forms that can reuse previously read objects.  */
2513             {
2514               int n = 0;
2515               Lisp_Object found;
2516
2517               /* Using read_integer() here is impossible, because it
2518                  chokes on `='.  Using parse_integer() is too hard.
2519                  So we simply read it in, and ignore overflows, which
2520                  is safe.  */
2521               while (c >= '0' && c <= '9')
2522                 {
2523                   n *= 10;
2524                   n += c - '0';
2525                   c = readchar (readcharfun);
2526                 }
2527               found = assq_no_quit (make_int (n), Vread_objects);
2528               if (c == '=')
2529                 {
2530                   /* #n=object returns object, but associates it with
2531                      n for #n#.  */
2532                   Lisp_Object obj;
2533                   if (CONSP (found))
2534                     return Fsignal (Qinvalid_read_syntax,
2535                                     list2 (build_translated_string
2536                                            ("Multiply defined symbol label"),
2537                                            make_int (n)));
2538                   obj = read0 (readcharfun);
2539                   Vread_objects = Fcons (Fcons (make_int (n), obj),
2540                                          Vread_objects);
2541                   return obj;
2542                 }
2543               else if (c == '#')
2544                 {
2545                   /* #n# returns a previously read object.  */
2546                   if (CONSP (found))
2547                     return XCDR (found);
2548                   else
2549                     return Fsignal (Qinvalid_read_syntax,
2550                                     list2 (build_translated_string
2551                                            ("Undefined symbol label"),
2552                                            make_int (n)));
2553                 }
2554               return Fsignal (Qinvalid_read_syntax,
2555                               list1 (build_string ("#")));
2556             }
2557           default:
2558             {
2559               unreadchar (readcharfun, c);
2560               return Fsignal (Qinvalid_read_syntax,
2561                               list1 (build_string ("#")));
2562             }
2563           }
2564       }
2565
2566       /* Quote */
2567     case '\'': return list2 (Qquote, read0 (readcharfun));
2568
2569 #ifdef LISP_BACKQUOTES
2570     case '`':
2571       {
2572         Lisp_Object tem;
2573         int speccount = specpdl_depth ();
2574         ++new_backquote_flag;
2575         record_unwind_protect (backquote_unwind,
2576                                make_opaque_ptr (&new_backquote_flag));
2577         tem = read0 (readcharfun);
2578         unbind_to (speccount, Qnil);
2579         return list2 (Qbackquote, tem);
2580       }
2581
2582     case ',':
2583       {
2584         if (new_backquote_flag)
2585           {
2586             Lisp_Object comma_type = Qnil;
2587             int ch = readchar (readcharfun);
2588
2589             if (ch == '@')
2590               comma_type = Qcomma_at;
2591             else if (ch == '.')
2592               comma_type = Qcomma_dot;
2593             else
2594               {
2595                 if (ch >= 0)
2596                   unreadchar (readcharfun, ch);
2597                 comma_type = Qcomma;
2598               }
2599             return list2 (comma_type, read0 (readcharfun));
2600           }
2601         else
2602           {
2603             /* YUCK.  99.999% backwards compatibility.  The Right
2604                Thing(tm) is to signal an error here, because it's
2605                really invalid read syntax.  Instead, this permits
2606                commas to begin symbols (unless they're inside
2607                backquotes).  If an error is signalled here in the
2608                future, then commas should be invalid read syntax
2609                outside of backquotes anywhere they're found (i.e.
2610                they must be quoted in symbols) -- Stig */
2611             return read_atom (readcharfun, c, 0);
2612           }
2613       }
2614 #endif
2615
2616     case '?':
2617       {
2618         /* Evil GNU Emacs "character" (ie integer) syntax */
2619         c = readchar (readcharfun);
2620         if (c < 0)
2621           return Fsignal (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
2622
2623         if (c == '\\')
2624           c = read_escape (readcharfun);
2625         return make_char (c);
2626       }
2627
2628     case '\"':
2629       {
2630         /* String */
2631 #ifdef I18N3
2632         /* #### If the input stream is translating, then the string
2633            should be marked as translatable by setting its
2634            `string-translatable' property to t.  .el and .elc files
2635            normally are translating input streams.  See Fgettext()
2636            and print_internal(). */
2637 #endif
2638         int cancel = 0;
2639
2640         Lstream_rewind (XLSTREAM (Vread_buffer_stream));
2641         while ((c = readchar (readcharfun)) >= 0
2642                && c != '\"')
2643           {
2644             if (c == '\\')
2645               c = read_escape (readcharfun);
2646             /* c is -1 if \ newline has just been seen */
2647             if (c == -1)
2648               {
2649                 if (Lstream_byte_count (XLSTREAM (Vread_buffer_stream)) == 0)
2650                   cancel = 1;
2651               }
2652             else
2653               Lstream_put_emchar (XLSTREAM (Vread_buffer_stream), c);
2654             QUIT;
2655           }
2656         if (c < 0)
2657           return Fsignal (Qend_of_file, list1 (READCHARFUN_MAYBE (readcharfun)));
2658
2659         /* If purifying, and string starts with \ newline,
2660            return zero instead.  This is for doc strings
2661            that we are really going to find in lib-src/DOC.nn.nn  */
2662         if (purify_flag && NILP (Vinternal_doc_file_name) && cancel)
2663           return Qzero;
2664
2665         Lstream_flush (XLSTREAM (Vread_buffer_stream));
2666         return
2667           make_string
2668           (resizing_buffer_stream_ptr (XLSTREAM (Vread_buffer_stream)),
2669            Lstream_byte_count (XLSTREAM (Vread_buffer_stream)));
2670       }
2671
2672     default:
2673       {
2674         /* Ignore whitespace and control characters */
2675         if (c <= 040)
2676           goto retry;
2677         return read_atom (readcharfun, c, 0);
2678       }
2679     }
2680 }
2681
2682
2683 \f
2684 #ifdef LISP_FLOAT_TYPE
2685
2686 #define LEAD_INT 1
2687 #define DOT_CHAR 2
2688 #define TRAIL_INT 4
2689 #define E_CHAR 8
2690 #define EXP_INT 16
2691
2692 int
2693 isfloat_string (CONST char *cp)
2694 {
2695   int state = 0;
2696   CONST Bufbyte *ucp = (CONST Bufbyte *) cp;
2697
2698   if (*ucp == '+' || *ucp == '-')
2699     ucp++;
2700
2701   if (*ucp >= '0' && *ucp <= '9')
2702     {
2703       state |= LEAD_INT;
2704       while (*ucp >= '0' && *ucp <= '9')
2705         ucp++;
2706     }
2707   if (*ucp == '.')
2708     {
2709       state |= DOT_CHAR;
2710       ucp++;
2711     }
2712   if (*ucp >= '0' && *ucp <= '9')
2713     {
2714       state |= TRAIL_INT;
2715       while (*ucp >= '0' && *ucp <= '9')
2716         ucp++;
2717     }
2718   if (*ucp == 'e' || *ucp == 'E')
2719     {
2720       state |= E_CHAR;
2721       ucp++;
2722       if ((*ucp == '+') || (*ucp == '-'))
2723         ucp++;
2724     }
2725
2726   if (*ucp >= '0' && *ucp <= '9')
2727     {
2728       state |= EXP_INT;
2729       while (*ucp >= '0' && *ucp <= '9')
2730         ucp++;
2731     }
2732   return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t') || (*ucp == '\n')
2733            || (*ucp == '\r') || (*ucp == '\f'))
2734           && (state == (LEAD_INT|DOT_CHAR|TRAIL_INT)
2735               || state == (DOT_CHAR|TRAIL_INT)
2736               || state == (LEAD_INT|E_CHAR|EXP_INT)
2737               || state == (LEAD_INT|DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT)
2738               || state == (DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT)));
2739 }
2740 #endif /* LISP_FLOAT_TYPE */
2741 \f
2742 static void *
2743 sequence_reader (Lisp_Object readcharfun,
2744                  Emchar terminator,
2745                  void *state,
2746                  void * (*conser) (Lisp_Object readcharfun,
2747                                    void *state, Charcount len))
2748 {
2749   Charcount len;
2750
2751   for (len = 0; ; len++)
2752     {
2753       Emchar ch;
2754
2755       QUIT;
2756       ch = reader_nextchar (readcharfun);
2757
2758       if (ch == terminator)
2759         return state;
2760       else
2761         unreadchar (readcharfun, ch);
2762 #ifdef FEATUREP_SYNTAX
2763       if (ch == ']')
2764         syntax_error ("\"]\" in a list");
2765       else if (ch == ')')
2766         syntax_error ("\")\" in a vector");
2767 #endif
2768       state = ((conser) (readcharfun, state, len));
2769     }
2770 }
2771
2772
2773 struct read_list_state
2774   {
2775     Lisp_Object head;
2776     Lisp_Object tail;
2777     int length;
2778     int allow_dotted_lists;
2779     Emchar terminator;
2780   };
2781
2782 static void *
2783 read_list_conser (Lisp_Object readcharfun, void *state, Charcount len)
2784 {
2785   struct read_list_state *s = (struct read_list_state *) state;
2786   Lisp_Object elt;
2787
2788   elt = read1 (readcharfun);
2789
2790   if (CONSP (elt) && UNBOUNDP (XCAR (elt)))
2791     {
2792       Lisp_Object tem = elt;
2793       Emchar ch;
2794
2795       elt = XCDR (elt);
2796       free_cons (XCONS (tem));
2797       tem = Qnil;
2798       ch = XCHAR (elt);
2799 #ifdef FEATUREP_SYNTAX
2800       if (ch == s->terminator) /* deal with #+, #- reader macros */
2801         {
2802           unreadchar (readcharfun, s->terminator);
2803           goto done;
2804         }
2805       else if (ch == ']')
2806         syntax_error ("']' in a list");
2807       else if (ch == ')')
2808         syntax_error ("')' in a vector");
2809       else
2810 #endif
2811       if (ch != '.')
2812         signal_simple_error ("BUG! Internal reader error", elt);
2813       else if (!s->allow_dotted_lists)
2814         syntax_error ("\".\" in a vector");
2815       else
2816         {
2817           if (!NILP (s->tail))
2818             XCDR (s->tail) = read0 (readcharfun);
2819           else
2820             s->head = read0 (readcharfun);
2821           elt = read1 (readcharfun);
2822           if (CONSP (elt) && UNBOUNDP (XCAR (elt)))
2823             {
2824               ch = XCHAR (XCDR (elt));
2825               free_cons (XCONS (elt));
2826               if (ch == s->terminator)
2827                 {
2828                   unreadchar (readcharfun, s->terminator);
2829                   goto done;
2830                 }
2831             }
2832           syntax_error (". in wrong context");
2833         }
2834     }
2835
2836 #if 0 /* FSFmacs defun hack, or something ... */
2837   if (NILP (tail) && defun_hack && EQ (elt, Qdefun) && !read_pure)
2838     {
2839       record_unwind_protect (unreadpure, Qzero);
2840       read_pure = 1;
2841     }
2842 #endif
2843
2844 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
2845   if (s->length == 1 && s->allow_dotted_lists && EQ (XCAR (s->head), Qfset))
2846     {
2847       if (CONSP (elt) && EQ (XCAR (elt), Qquote) && CONSP (XCDR (elt)))
2848         Vcurrent_compiled_function_annotation = XCAR (XCDR (elt));
2849       else
2850         Vcurrent_compiled_function_annotation = elt;
2851     }
2852 #endif
2853
2854   elt = Fcons (elt, Qnil);
2855   if (!NILP (s->tail))
2856     XCDR (s->tail) = elt;
2857   else
2858     s->head = elt;
2859   s->tail = elt;
2860  done:
2861   s->length++;
2862   return s;
2863 }
2864
2865 \f
2866 #if 0 /* FSFmacs defun hack */
2867 /* -1 for allow_dotted_lists means allow_dotted_lists and check
2868    for starting with defun and make structure pure. */
2869 #endif
2870
2871 static Lisp_Object
2872 read_list (Lisp_Object readcharfun,
2873            Emchar terminator,
2874            int allow_dotted_lists,
2875            int check_for_doc_references)
2876 {
2877   struct read_list_state s;
2878   struct gcpro gcpro1, gcpro2;
2879 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
2880   Lisp_Object old_compiled_function_annotation =
2881     Vcurrent_compiled_function_annotation;
2882 #endif
2883
2884   s.head = Qnil;
2885   s.tail = Qnil;
2886   s.length = 0;
2887   s.allow_dotted_lists = allow_dotted_lists;
2888   s.terminator = terminator;
2889   GCPRO2 (s.head, s.tail);
2890
2891   sequence_reader (readcharfun, terminator, &s, read_list_conser);
2892 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
2893   Vcurrent_compiled_function_annotation = old_compiled_function_annotation;
2894 #endif
2895
2896   if ((purify_flag || load_force_doc_strings) && check_for_doc_references)
2897     {
2898       /* check now for any doc string references and record them
2899          for later. */
2900       Lisp_Object tail;
2901
2902       /* We might be dealing with an imperfect list so don't
2903          use LIST_LOOP */
2904       for (tail = s.head; CONSP (tail); tail = XCDR (tail))
2905         {
2906           Lisp_Object holding_cons = Qnil;
2907
2908           {
2909             Lisp_Object elem = XCAR (tail);
2910             /* elem might be (#$ . INT) ... */
2911             if (CONSP (elem) && EQ (XCAR (elem), Vload_file_name_internal))
2912               holding_cons = tail;
2913             /* or it might be (quote (#$ . INT)) i.e.
2914                (quote . ((#$ . INT) . nil)) in the case of
2915                `autoload' (autoload evaluates its arguments, while
2916                `defvar', `defun', etc. don't). */
2917             if (CONSP (elem) && EQ (XCAR (elem), Qquote)
2918                 && CONSP (XCDR (elem)))
2919               {
2920                 elem = XCAR (XCDR (elem));
2921                 if (CONSP (elem) && EQ (XCAR (elem), Vload_file_name_internal))
2922                   holding_cons = XCDR (XCAR (tail));
2923               }
2924           }
2925
2926           if (CONSP (holding_cons))
2927             {
2928               if (purify_flag)
2929                 {
2930                   if (NILP (Vinternal_doc_file_name))
2931                     /* We have not yet called Snarf-documentation, so
2932                        assume this file is described in the DOC file
2933                        and Snarf-documentation will fill in the right
2934                        value later.  For now, replace the whole list
2935                        with 0.  */
2936                     XCAR (holding_cons) = Qzero;
2937                   else
2938                     /* We have already called Snarf-documentation, so
2939                        make a relative file name for this file, so it
2940                        can be found properly in the installed Lisp
2941                        directory.  We don't use Fexpand_file_name
2942                        because that would make the directory absolute
2943                        now.  */
2944                     XCAR (XCAR (holding_cons)) =
2945                       concat2 (build_string ("../lisp/"),
2946                                Ffile_name_nondirectory
2947                                (Vload_file_name_internal));
2948                 }
2949               else
2950                 /* Not pure.  Just add to Vload_force_doc_string_list,
2951                    and the string will be filled in properly in
2952                    load_force_doc_string_unwind(). */
2953                 Vload_force_doc_string_list =
2954                   /* We pass the cons that holds the (#$ . INT) so we
2955                      can modify it in-place. */
2956                   Fcons (holding_cons, Vload_force_doc_string_list);
2957             }
2958         }
2959     }
2960
2961   UNGCPRO;
2962   return s.head;
2963 }
2964
2965 static Lisp_Object
2966 read_vector (Lisp_Object readcharfun,
2967              Emchar terminator)
2968 {
2969   Lisp_Object tem;
2970   Lisp_Object *p;
2971   int len;
2972   int i;
2973   struct read_list_state s;
2974   struct gcpro gcpro1, gcpro2;
2975
2976   s.head = Qnil;
2977   s.tail = Qnil;
2978   s.length = 0;
2979   s.allow_dotted_lists = 0;
2980   GCPRO2 (s.head, s.tail);
2981
2982   sequence_reader (readcharfun, terminator, &s, read_list_conser);
2983
2984   UNGCPRO;
2985   tem = s.head;
2986   len = XINT (Flength (tem));
2987
2988 #if 0 /* FSFmacs defun hack */
2989   if (read_pure)
2990     s.head = make_pure_vector (len, Qnil);
2991   else
2992 #endif
2993     s.head = make_vector (len, Qnil);
2994
2995   for (i = 0, p = &(XVECTOR_DATA (s.head)[0]);
2996        i < len;
2997        i++, p++)
2998   {
2999     struct Lisp_Cons *otem = XCONS (tem);
3000     tem = Fcar (tem);
3001     *p = tem;
3002     tem = otem->cdr;
3003     free_cons (otem);
3004   }
3005   return s.head;
3006 }
3007
3008 static Lisp_Object
3009 read_compiled_function (Lisp_Object readcharfun, Emchar terminator)
3010 {
3011   /* Accept compiled functions at read-time so that we don't
3012      have to build them at load-time. */
3013   Lisp_Object stuff;
3014   Lisp_Object make_byte_code_args[COMPILED_DOMAIN + 1];
3015   struct gcpro gcpro1;
3016   int len;
3017   int iii;
3018   int saw_a_doc_ref = 0;
3019
3020   /* Note: we tell read_list not to search for doc references
3021      because we need to handle the "doc reference" for the
3022      instructions and constants differently. */
3023   stuff = read_list (readcharfun, terminator, 0, 0);
3024   len = XINT (Flength (stuff));
3025   if (len < COMPILED_STACK_DEPTH + 1 || len > COMPILED_DOMAIN + 1)
3026     return
3027       continuable_syntax_error ("#[...] used with wrong number of elements");
3028
3029   for (iii = 0; CONSP (stuff); iii++)
3030     {
3031       struct Lisp_Cons *victim = XCONS (stuff);
3032       make_byte_code_args[iii] = Fcar (stuff);
3033       if ((purify_flag || load_force_doc_strings)
3034            && CONSP (make_byte_code_args[iii])
3035           && EQ (XCAR (make_byte_code_args[iii]), Vload_file_name_internal))
3036         {
3037           if (purify_flag && iii == COMPILED_DOC_STRING)
3038             {
3039               /* same as in read_list(). */
3040               if (NILP (Vinternal_doc_file_name))
3041                 make_byte_code_args[iii] = Qzero;
3042               else
3043                 XCAR (make_byte_code_args[iii]) =
3044                   concat2 (build_string ("../lisp/"),
3045                            Ffile_name_nondirectory
3046                            (Vload_file_name_internal));
3047             }
3048           else
3049             saw_a_doc_ref = 1;
3050         }
3051       stuff = Fcdr (stuff);
3052       free_cons (victim);
3053     }
3054   GCPRO1 (make_byte_code_args[0]);
3055   gcpro1.nvars = len;
3056
3057   /* v18 or v19 bytecode file.  Need to Ebolify. */
3058   if (load_byte_code_version < 20 && VECTORP (make_byte_code_args[2]))
3059     ebolify_bytecode_constants (make_byte_code_args[2]);
3060
3061   /* make-byte-code looks at purify_flag, which should have the same
3062    *  value as our "read-pure" argument */
3063   stuff = Fmake_byte_code (len, make_byte_code_args);
3064   XCOMPILED_FUNCTION (stuff)->flags.ebolified = (load_byte_code_version < 20);
3065   if (saw_a_doc_ref)
3066     Vload_force_doc_string_list = Fcons (stuff, Vload_force_doc_string_list);
3067   UNGCPRO;
3068   return stuff;
3069 }
3070
3071
3072 \f
3073 void
3074 init_lread (void)
3075 {
3076   Vvalues = Qnil;
3077
3078   load_in_progress = 0;
3079
3080   Vload_descriptor_list = Qnil;
3081
3082   /* kludge: locate-file does not work for a null load-path, even if
3083      the file name is absolute. */
3084
3085   Vload_path = Fcons (build_string (""), Qnil);
3086
3087   /* This used to get initialized in init_lread because all streams
3088      got closed when dumping occurs.  This is no longer true --
3089      Vread_buffer_stream is a resizing output stream, and there is no
3090      reason to close it at dump-time.
3091
3092      Vread_buffer_stream is set to Qnil in vars_of_lread, and this
3093      will initialize it only once, at dump-time.  */
3094   if (NILP (Vread_buffer_stream))
3095     Vread_buffer_stream = make_resizing_buffer_output_stream ();
3096
3097   Vload_force_doc_string_list = Qnil;
3098 }
3099
3100 void
3101 syms_of_lread (void)
3102 {
3103   DEFSUBR (Fread);
3104   DEFSUBR (Fread_from_string);
3105   DEFSUBR (Fload_internal);
3106   DEFSUBR (Flocate_file);
3107   DEFSUBR (Flocate_file_clear_hashing);
3108   DEFSUBR (Feval_buffer);
3109   DEFSUBR (Feval_region);
3110
3111   defsymbol (&Qstandard_input, "standard-input");
3112   defsymbol (&Qread_char, "read-char");
3113   defsymbol (&Qcurrent_load_list, "current-load-list");
3114   defsymbol (&Qload, "load");
3115   defsymbol (&Qload_file_name, "load-file-name");
3116   defsymbol (&Qfset, "fset");
3117
3118 #ifdef LISP_BACKQUOTES
3119   defsymbol (&Qbackquote, "backquote");
3120   defsymbol (&Qbacktick, "`");
3121   defsymbol (&Qcomma, ",");
3122   defsymbol (&Qcomma_at, ",@");
3123   defsymbol (&Qcomma_dot, ",.");
3124 #endif
3125
3126   defsymbol (&Qexists, "exists");
3127   defsymbol (&Qreadable, "readable");
3128   defsymbol (&Qwritable, "writable");
3129   defsymbol (&Qexecutable, "executable");
3130 }
3131
3132 void
3133 structure_type_create (void)
3134 {
3135   the_structure_type_dynarr = Dynarr_new (structure_type);
3136 }
3137
3138 void
3139 reinit_vars_of_lread (void)
3140 {
3141   Vread_buffer_stream = Qnil;
3142   staticpro_nodump (&Vread_buffer_stream);
3143 }
3144
3145 void
3146 vars_of_lread (void)
3147 {
3148   reinit_vars_of_lread ();
3149
3150   DEFVAR_LISP ("values", &Vvalues /*
3151 List of values of all expressions which were read, evaluated and printed.
3152 Order is reverse chronological.
3153 */ );
3154
3155   DEFVAR_LISP ("standard-input", &Vstandard_input /*
3156 Stream for read to get input from.
3157 See documentation of `read' for possible values.
3158 */ );
3159   Vstandard_input = Qt;
3160
3161   DEFVAR_LISP ("load-path", &Vload_path /*
3162 *List of directories to search for files to load.
3163 Each element is a string (directory name) or nil (try default directory).
3164
3165 Note that the elements of this list *may not* begin with "~", so you must
3166 call `expand-file-name' on them before adding them to this list.
3167
3168 Initialized based on EMACSLOADPATH environment variable, if any,
3169 otherwise to default specified in by file `paths.h' when XEmacs was built.
3170 If there were no paths specified in `paths.h', then XEmacs chooses a default
3171 value for this variable by looking around in the file-system near the
3172 directory in which the XEmacs executable resides.
3173 */ );
3174   Vload_path = Qnil;
3175
3176 /*  xxxDEFVAR_LISP ("dump-load-path", &Vdump_load_path,
3177     "*Location of lisp files to be used when dumping ONLY."); */
3178
3179   DEFVAR_BOOL ("load-in-progress", &load_in_progress /*
3180 Non-nil iff inside of `load'.
3181 */ );
3182
3183   DEFVAR_LISP ("after-load-alist", &Vafter_load_alist /*
3184 An alist of expressions to be evalled when particular files are loaded.
3185 Each element looks like (FILENAME FORMS...).
3186 When `load' is run and the file-name argument is FILENAME,
3187 the FORMS in the corresponding element are executed at the end of loading.
3188
3189 FILENAME must match exactly!  Normally FILENAME is the name of a library,
3190 with no directory specified, since that is how `load' is normally called.
3191 An error in FORMS does not undo the load,
3192 but does prevent execution of the rest of the FORMS.
3193 */ );
3194   Vafter_load_alist = Qnil;
3195
3196   DEFVAR_BOOL ("load-warn-when-source-newer", &load_warn_when_source_newer /*
3197 *Whether `load' should check whether the source is newer than the binary.
3198 If this variable is true, then when a `.elc' file is being loaded and the
3199 corresponding `.el' is newer, a warning message will be printed.
3200 */ );
3201   load_warn_when_source_newer = 0;
3202
3203   DEFVAR_BOOL ("load-warn-when-source-only", &load_warn_when_source_only /*
3204 *Whether `load' should warn when loading a `.el' file instead of an `.elc'.
3205 If this variable is true, then when `load' is called with a filename without
3206 an extension, and the `.elc' version doesn't exist but the `.el' version does,
3207 then a message will be printed.  If an explicit extension is passed to `load',
3208 no warning will be printed.
3209 */ );
3210   load_warn_when_source_only = 0;
3211
3212   DEFVAR_BOOL ("load-ignore-elc-files", &load_ignore_elc_files /*
3213 *Whether `load' should ignore `.elc' files when a suffix is not given.
3214 This is normally used only to bootstrap the `.elc' files when building XEmacs.
3215 */ );
3216   load_ignore_elc_files = 0;
3217
3218 #ifdef LOADHIST
3219   DEFVAR_LISP ("load-history", &Vload_history /*
3220 Alist mapping source file names to symbols and features.
3221 Each alist element is a list that starts with a file name,
3222 except for one element (optional) that starts with nil and describes
3223 definitions evaluated from buffers not visiting files.
3224 The remaining elements of each list are symbols defined as functions
3225 or variables, and cons cells `(provide . FEATURE)' and `(require . FEATURE)'.
3226 */ );
3227   Vload_history = Qnil;
3228
3229   DEFVAR_LISP ("current-load-list", &Vcurrent_load_list /*
3230 Used for internal purposes by `load'.
3231 */ );
3232   Vcurrent_load_list = Qnil;
3233 #endif
3234
3235   DEFVAR_LISP ("load-file-name", &Vload_file_name /*
3236 Full name of file being loaded by `load'.
3237 */ );
3238   Vload_file_name = Qnil;
3239
3240   DEFVAR_LISP ("load-read-function", &Vload_read_function /*
3241 Function used by `load' and `eval-region' for reading expressions.
3242 The default is nil, which means use the function `read'.
3243 */ );
3244   Vload_read_function = Qnil;
3245
3246   DEFVAR_BOOL ("load-force-doc-strings", &load_force_doc_strings /*
3247 Non-nil means `load' should force-load all dynamic doc strings.
3248 This is useful when the file being loaded is a temporary copy.
3249 */ );
3250   load_force_doc_strings = 0;
3251
3252   /* See read_escape().  */
3253 #if 0
3254   /* Used to be named `puke-on-fsf-keys' */
3255   DEFVAR_BOOL ("fail-on-bucky-bit-character-escapes",
3256                &fail_on_bucky_bit_character_escapes /*
3257 Whether `read' should signal an error when it encounters unsupported
3258 character escape syntaxes or just read them incorrectly.
3259 */ );
3260   fail_on_bucky_bit_character_escapes = 0;
3261 #endif
3262
3263   /* This must be initialized in init_lread otherwise it may start out
3264      with values saved when the image is dumped. */
3265   staticpro (&Vload_descriptor_list);
3266
3267   /* Initialized in init_lread. */
3268   staticpro (&Vload_force_doc_string_list);
3269
3270   Vload_file_name_internal = Qnil;
3271   staticpro (&Vload_file_name_internal);
3272
3273   Vload_file_name_internal_the_purecopy = Qnil;
3274   staticpro (&Vload_file_name_internal_the_purecopy);
3275
3276 #ifdef COMPILED_FUNCTION_ANNOTATION_HACK
3277   Vcurrent_compiled_function_annotation = Qnil;
3278   staticpro (&Vcurrent_compiled_function_annotation);
3279 #endif
3280
3281   /* So that early-early stuff will work */
3282   Ffset (Qload, intern ("load-internal"));
3283
3284 #ifdef FEATUREP_SYNTAX
3285   defsymbol (&Qfeaturep, "featurep");
3286   Fprovide(intern("xemacs"));
3287 #ifdef INFODOCK
3288   Fprovide(intern("infodock"));
3289 #endif /* INFODOCK */
3290 #endif /* FEATUREP_SYNTAX */
3291
3292 #ifdef LISP_BACKQUOTES
3293   old_backquote_flag = new_backquote_flag = 0;
3294 #endif
3295
3296 #ifdef I18N3
3297   Vfile_domain = Qnil;
3298 #endif
3299
3300   Vread_objects = Qnil;
3301   staticpro (&Vread_objects);
3302
3303   Vlocate_file_hash_table = make_lisp_hash_table (200,
3304                                                   HASH_TABLE_NON_WEAK,
3305                                                   HASH_TABLE_EQUAL);
3306   staticpro (&Vlocate_file_hash_table);
3307 #ifdef DEBUG_XEMACS
3308   symbol_value (XSYMBOL (intern ("Vlocate-file-hash-table")))
3309     = Vlocate_file_hash_table;
3310 #endif
3311 }