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+