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