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