/* Lisp parsing and input streams.
-Copyright (C) 1985-1989, 1993-1995, 1997-2013 Free Software Foundation, Inc.
+Copyright (C) 1985-1989, 1993-1995, 1997-2014 Free Software Foundation,
+Inc.
This file is part of GNU Emacs.
else
{
c = BUF_FETCH_BYTE (inbuffer, pt_byte);
- if (! ASCII_BYTE_P (c))
+ if (! ASCII_CHAR_P (c))
c = BYTE8_TO_CHAR (c);
pt_byte++;
}
else
{
c = BUF_FETCH_BYTE (inbuffer, bytepos);
- if (! ASCII_BYTE_P (c))
+ if (! ASCII_CHAR_P (c))
c = BYTE8_TO_CHAR (c);
bytepos++;
}
return c;
if (multibyte)
*multibyte = 1;
- if (ASCII_BYTE_P (c))
+ if (ASCII_CHAR_P (c))
return c;
if (emacs_mule_encoding)
return read_emacs_mule_char (c, readbyte, readcharfun);
return value of `get-load-suffixes' is used, i.e. the file name is
required to have a non-empty suffix.
+When searching suffixes, this function normally stops at the first
+one that exists. If the option `load-prefer-newer' is non-nil,
+however, it tries all suffixes, and uses whichever file is the newest.
+
Loading a file records its definitions, and its `provide' and
`require' calls, in an element of `load-history' whose
car is the file name loaded. See `load-history'.
}
}
- fd = openp (Vload_path, file, suffixes, &found, Qnil);
+ fd = openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer);
UNGCPRO;
}
#ifdef DOS_NT
fmode = "rb";
#endif /* DOS_NT */
- result = stat (SSDATA (efound), &s1);
- if (result == 0)
- {
- SSET (efound, SBYTES (efound) - 1, 0);
- result = stat (SSDATA (efound), &s2);
- SSET (efound, SBYTES (efound) - 1, 'c');
- }
- if (result == 0
- && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0)
- {
- /* Make the progress messages mention that source is newer. */
- newer = 1;
+ /* openp already checked for newness, no point doing it again.
+ FIXME would be nice to get a message when openp
+ ignores suffix order due to load_prefer_newer. */
+ if (!load_prefer_newer)
+ {
+ result = stat (SSDATA (efound), &s1);
+ if (result == 0)
+ {
+ SSET (efound, SBYTES (efound) - 1, 0);
+ result = stat (SSDATA (efound), &s2);
+ SSET (efound, SBYTES (efound) - 1, 'c');
+ }
- /* If we won't print another message, mention this anyway. */
- if (!NILP (nomessage) && !force_load_messages)
- {
- Lisp_Object msg_file;
- msg_file = Fsubstring (found, make_number (0), make_number (-1));
- message_with_string ("Source file `%s' newer than byte-compiled file",
- msg_file, 1);
- }
- }
+ if (result == 0
+ && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0)
+ {
+ /* Make the progress messages mention that source is newer. */
+ newer = 1;
+
+ /* If we won't print another message, mention this anyway. */
+ if (!NILP (nomessage) && !force_load_messages)
+ {
+ Lisp_Object msg_file;
+ msg_file = Fsubstring (found, make_number (0), make_number (-1));
+ message_with_string ("Source file `%s' newer than byte-compiled file",
+ msg_file, 1);
+ }
+ }
+ } /* !load_prefer_newer */
UNGCPRO;
}
}
(Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object predicate)
{
Lisp_Object file;
- int fd = openp (path, filename, suffixes, &file, predicate);
+ int fd = openp (path, filename, suffixes, &file, predicate, false);
if (NILP (predicate) && fd >= 0)
emacs_close (fd);
return file;
nil is stored there on failure.
If the file we find is remote, return -2
- but store the found remote file name in *STOREPTR. */
+ but store the found remote file name in *STOREPTR.
+
+ If NEWER is true, try all SUFFIXes and return the result for the
+ newest file that exists. Does not apply to remote files,
+ or if PREDICATE is specified. */
int
openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
- Lisp_Object *storeptr, Lisp_Object predicate)
+ Lisp_Object *storeptr, Lisp_Object predicate, bool newer)
{
ptrdiff_t fn_size = 100;
char buf[100];
char *fn = buf;
- bool absolute = 0;
+ bool absolute;
ptrdiff_t want_length;
Lisp_Object filename;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
- Lisp_Object string, tail, encoded_fn;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6, gcpro7;
+ Lisp_Object string, tail, encoded_fn, save_string;
ptrdiff_t max_suffix_len = 0;
int last_errno = ENOENT;
+ int save_fd = -1;
+
+ /* The last-modified time of the newest matching file found.
+ Initialize it to something less than all valid timestamps. */
+ struct timespec save_mtime = make_timespec (TYPE_MINIMUM (time_t), -1);
CHECK_STRING (str);
SBYTES (XCAR (tail)));
}
- string = filename = encoded_fn = Qnil;
- GCPRO6 (str, string, filename, path, suffixes, encoded_fn);
+ string = filename = encoded_fn = save_string = Qnil;
+ GCPRO7 (str, string, save_string, filename, path, suffixes, encoded_fn);
if (storeptr)
*storeptr = Qnil;
- if (complete_filename_p (str))
- absolute = 1;
+ absolute = complete_filename_p (str);
for (; CONSP (path); path = XCDR (path))
{
{
Lisp_Object tmp = call1 (predicate, string);
if (NILP (tmp))
- exists = 0;
+ exists = false;
else if (EQ (tmp, Qdir_ok)
|| NILP (Ffile_directory_p (string)))
- exists = 1;
+ exists = true;
else
{
- exists = 0;
+ exists = false;
last_errno = EISDIR;
}
}
if (exists)
{
- /* We succeeded; return this descriptor and filename. */
- if (storeptr)
- *storeptr = string;
- UNGCPRO;
- return -2;
+ /* We succeeded; return this descriptor and filename. */
+ if (storeptr)
+ *storeptr = string;
+ UNGCPRO;
+ return -2;
}
}
else
{
int fd;
const char *pfn;
+ struct stat st;
encoded_fn = ENCODE_FILE (string);
pfn = SSDATA (encoded_fn);
}
else
{
- struct stat st;
int err = (fstat (fd, &st) != 0 ? errno
: S_ISDIR (st.st_mode) ? EISDIR : 0);
if (err)
if (fd >= 0)
{
- /* We succeeded; return this descriptor and filename. */
- if (storeptr)
- *storeptr = string;
- UNGCPRO;
- return fd;
+ if (newer && !NATNUMP (predicate))
+ {
+ struct timespec mtime = get_stat_mtime (&st);
+
+ if (timespec_cmp (mtime, save_mtime) <= 0)
+ emacs_close (fd);
+ else
+ {
+ if (0 <= save_fd)
+ emacs_close (save_fd);
+ save_fd = fd;
+ save_mtime = mtime;
+ save_string = string;
+ }
+ }
+ else
+ {
+ /* We succeeded; return this descriptor and filename. */
+ if (storeptr)
+ *storeptr = string;
+ UNGCPRO;
+ return fd;
+ }
}
+
+ /* No more suffixes. Return the newest. */
+ if (0 <= save_fd && ! CONSP (XCDR (tail)))
+ {
+ if (storeptr)
+ *storeptr = save_string;
+ UNGCPRO;
+ return save_fd;
+ }
}
}
if (absolute)
xsignal0 (Qend_of_file);
}
+static Lisp_Object
+readevalloop_eager_expand_eval (Lisp_Object val, Lisp_Object macroexpand)
+{
+ /* If we macroexpand the toplevel form non-recursively and it ends
+ up being a `progn' (or if it was a progn to start), treat each
+ form in the progn as a top-level form. This way, if one form in
+ the progn defines a macro, that macro is in effect when we expand
+ the remaining forms. See similar code in bytecomp.el. */
+ val = call2 (macroexpand, val, Qnil);
+ if (EQ (CAR_SAFE (val), Qprogn))
+ {
+ Lisp_Object subforms = XCDR (val);
+ val = Qnil;
+ for (; CONSP (subforms); subforms = XCDR (subforms))
+ val = readevalloop_eager_expand_eval (XCAR (subforms),
+ macroexpand);
+ }
+ else
+ val = eval_sub (call2 (macroexpand, val, Qt));
+
+ return val;
+}
+
/* UNIBYTE specifies how to set load_convert_to_unibyte
for this invocation.
READFUN, if non-nil, is used instead of `read'.
/* Now eval what we just read. */
if (!NILP (macroexpand))
- val = call1 (macroexpand, val);
- val = eval_sub (val);
+ val = readevalloop_eager_expand_eval (val, macroexpand);
+ else
+ val = eval_sub (val);
if (printflag)
{
if (EQ (stream, Qt))
stream = Qread_char;
if (EQ (stream, Qread_char))
- /* FIXME: ¿¡ When is this used !? */
+ /* FIXME: ?! When is this used !? */
return call1 (intern ("read-minibuffer"),
build_string ("Lisp expression: "));
/* Accept compiled functions at read-time so that we don't have to
build them using function calls. */
Lisp_Object tmp;
+ struct Lisp_Vector *vec;
tmp = read_vector (readcharfun, 1);
- struct Lisp_Vector* vec = XVECTOR (tmp);
- if (vec->header.size==0)
+ vec = XVECTOR (tmp);
+ if (vec->header.size == 0)
invalid_syntax ("Empty byte-code object");
make_byte_code (vec);
return tmp;
SET_SYMBOL_VAL (XSYMBOL (sym), sym);
}
- ptr = aref_addr (obarray, XINT(tem));
+ ptr = aref_addr (obarray, XINT (tem));
if (SYMBOLP (*ptr))
set_symbol_next (sym, XSYMBOL (*ptr));
else
The value is t if a symbol was found and deleted, nil otherwise.
NAME may be a string or a symbol. If it is a symbol, that symbol
is deleted, if it belongs to OBARRAY--no other symbol is deleted.
-OBARRAY defaults to the value of the variable `obarray'. */)
+OBARRAY, if nil, defaults to the value of the variable `obarray'.
+usage: (unintern NAME OBARRAY) */)
(Lisp_Object name, Lisp_Object obarray)
{
register Lisp_Object string, tem;
\f
/* Return the symbol in OBARRAY whose names matches the string
of SIZE characters (SIZE_BYTE bytes) at PTR.
- If there is no such symbol in OBARRAY, return nil.
+ If there is no such symbol, return the integer bucket number of
+ where the symbol would be if it were present.
Also store the bucket number in oblookup_last_bucket_number. */
}
}
-/* Record the value of load-path used at the start of dumping
- so we can see if the site changed it later during dumping. */
-static Lisp_Object dump_path;
-
/* Return the default load-path, to be used if EMACSLOADPATH is unset.
This does not include the standard site-lisp directories
under the installation prefix (i.e., PATH_SITELOADSEARCH),
If purify-flag (ie dumping) just use PATH_DUMPLOADSEARCH.
Otherwise use PATH_LOADSEARCH.
- If !initialized, then just set dump_path and return PATH_DUMPLOADSEARCH.
- If initialized, then if Vload_path != dump_path, return just Vload_path.
- (Presumably the load-path has already been changed by something.
- This can only be from a site-load file during dumping.)
+ If !initialized, then just return PATH_DUMPLOADSEARCH.
+ If initialized:
If Vinstallation_directory is not nil (ie, running uninstalled):
If installation-dir/lisp exists and not already a member,
we must be running uninstalled. Reset the load-path
to just installation-dir/lisp. (The default PATH_LOADSEARCH
refers to the eventual installation directories. Since we
are not yet installed, we should not use them, even if they exist.)
- If installation-dir/lisp does not exist, just add dump_path at the
- end instead.
+ If installation-dir/lisp does not exist, just add
+ PATH_DUMPLOADSEARCH at the end instead.
Add installation-dir/site-lisp (if !no_site_lisp, and exists
and not already a member) at the front.
If installation-dir != source-dir (ie running an uninstalled,
check), then repeat the above steps for source-dir/lisp, site-lisp. */
static Lisp_Object
-load_path_default (bool changed)
+load_path_default (void)
{
Lisp_Object lpath = Qnil;
const char *normal;
normal = NILP (Vpurify_flag) ? PATH_LOADSEARCH : PATH_DUMPLOADSEARCH;
- /* In a dumped Emacs, we normally reset the value of Vload_path using
- PATH_LOADSEARCH, since the value that was dumped uses lisp/ in
- the source directory, instead of the path of the installed elisp
- libraries. However, if it appears that Vload_path has already been
- changed from the default that was saved before dumping, don't
- change it further. Changes can only be due to site-lisp
- files that were processed during dumping. */
- /* FIXME? AFAICS, it does not make sense to change load-path in a
- dumped site-lisp file, so maybe we should just drop this check.
- E.g., if you add an element to load-path, you are going to be
- adding it to PATH_DUMPLOADSEARCH, which refers to the source directory.
- This will make no sense (and may not still exist) in an installed Emacs.
- And the only change it is sensible to make to load-path is to add
- something to the front, which you should do with configure's
- --enable-locallisppath option if you really want to have it dumped. */
if (initialized)
{
- if (changed || NILP (Fequal (dump_path, Vload_path)))
- {
- /* Do not make any changes. */
- return Vload_path;
- }
- else
- {
#ifdef HAVE_NS
- const char *loadpath = ns_load_path ();
- lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
+ const char *loadpath = ns_load_path ();
+ lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
#else
- lpath = decode_env_path (0, normal, 0);
+ lpath = decode_env_path (0, normal, 0);
#endif
- if (!NILP (Vinstallation_directory))
+ if (!NILP (Vinstallation_directory))
+ {
+ Lisp_Object tem, tem1;
+
+ /* Add to the path the lisp subdir of the installation
+ dir, if it is accessible. Note: in out-of-tree builds,
+ this directory is empty save for Makefile. */
+ tem = Fexpand_file_name (build_string ("lisp"),
+ Vinstallation_directory);
+ tem1 = Ffile_accessible_directory_p (tem);
+ if (!NILP (tem1))
+ {
+ if (NILP (Fmember (tem, lpath)))
+ {
+ /* We are running uninstalled. The default load-path
+ points to the eventual installed lisp directories.
+ We should not use those now, even if they exist,
+ so start over from a clean slate. */
+ lpath = list1 (tem);
+ }
+ }
+ else
+ /* That dir doesn't exist, so add the build-time
+ Lisp dirs instead. */
{
- Lisp_Object tem, tem1;
+ Lisp_Object dump_path =
+ decode_env_path (0, PATH_DUMPLOADSEARCH, 0);
+ lpath = nconc2 (lpath, dump_path);
+ }
- /* Add to the path the lisp subdir of the installation
- dir, if it is accessible. Note: in out-of-tree builds,
- this directory is empty save for Makefile. */
- tem = Fexpand_file_name (build_string ("lisp"),
+ /* Add site-lisp under the installation dir, if it exists. */
+ if (!no_site_lisp)
+ {
+ tem = Fexpand_file_name (build_string ("site-lisp"),
Vinstallation_directory);
tem1 = Ffile_accessible_directory_p (tem);
if (!NILP (tem1))
{
if (NILP (Fmember (tem, lpath)))
- {
- /* We are running uninstalled. The default load-path
- points to the eventual installed lisp directories.
- We should not use those now, even if they exist,
- so start over from a clean slate. */
- lpath = list1 (tem);
- }
+ lpath = Fcons (tem, lpath);
}
- else
- /* That dir doesn't exist, so add the build-time
- Lisp dirs instead. */
- lpath = nconc2 (lpath, dump_path);
+ }
- /* Add site-lisp under the installation dir, if it exists. */
- if (!no_site_lisp)
- {
- tem = Fexpand_file_name (build_string ("site-lisp"),
- Vinstallation_directory);
- tem1 = Ffile_accessible_directory_p (tem);
- if (!NILP (tem1))
- {
- if (NILP (Fmember (tem, lpath)))
- lpath = Fcons (tem, lpath);
- }
- }
+ /* If Emacs was not built in the source directory,
+ and it is run from where it was built, add to load-path
+ the lisp and site-lisp dirs under that directory. */
- /* If Emacs was not built in the source directory,
- and it is run from where it was built, add to load-path
- the lisp and site-lisp dirs under that directory. */
+ if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
+ {
+ Lisp_Object tem2;
+
+ tem = Fexpand_file_name (build_string ("src/Makefile"),
+ Vinstallation_directory);
+ tem1 = Ffile_exists_p (tem);
- if (NILP (Fequal (Vinstallation_directory, Vsource_directory)))
+ /* Don't be fooled if they moved the entire source tree
+ AFTER dumping Emacs. If the build directory is indeed
+ different from the source dir, src/Makefile.in and
+ src/Makefile will not be found together. */
+ tem = Fexpand_file_name (build_string ("src/Makefile.in"),
+ Vinstallation_directory);
+ tem2 = Ffile_exists_p (tem);
+ if (!NILP (tem1) && NILP (tem2))
{
- Lisp_Object tem2;
-
- tem = Fexpand_file_name (build_string ("src/Makefile"),
- Vinstallation_directory);
- tem1 = Ffile_exists_p (tem);
-
- /* Don't be fooled if they moved the entire source tree
- AFTER dumping Emacs. If the build directory is indeed
- different from the source dir, src/Makefile.in and
- src/Makefile will not be found together. */
- tem = Fexpand_file_name (build_string ("src/Makefile.in"),
- Vinstallation_directory);
- tem2 = Ffile_exists_p (tem);
- if (!NILP (tem1) && NILP (tem2))
- {
- tem = Fexpand_file_name (build_string ("lisp"),
- Vsource_directory);
+ tem = Fexpand_file_name (build_string ("lisp"),
+ Vsource_directory);
- if (NILP (Fmember (tem, lpath)))
- lpath = Fcons (tem, lpath);
+ if (NILP (Fmember (tem, lpath)))
+ lpath = Fcons (tem, lpath);
- if (!no_site_lisp)
+ if (!no_site_lisp)
+ {
+ tem = Fexpand_file_name (build_string ("site-lisp"),
+ Vsource_directory);
+ tem1 = Ffile_accessible_directory_p (tem);
+ if (!NILP (tem1))
{
- tem = Fexpand_file_name (build_string ("site-lisp"),
- Vsource_directory);
- tem1 = Ffile_accessible_directory_p (tem);
- if (!NILP (tem1))
- {
- if (NILP (Fmember (tem, lpath)))
- lpath = Fcons (tem, lpath);
- }
+ if (NILP (Fmember (tem, lpath)))
+ lpath = Fcons (tem, lpath);
}
}
- } /* Vinstallation_directory != Vsource_directory */
-
- } /* if Vinstallation_directory */
+ }
+ } /* Vinstallation_directory != Vsource_directory */
- } /* if dump_path == Vload_path */
+ } /* if Vinstallation_directory */
}
else /* !initialized */
{
/* NORMAL refers to PATH_DUMPLOADSEARCH, ie the lisp dir in the
source directory. We used to add ../lisp (ie the lisp dir in
- the build directory) at the front here, but that caused trouble
- because it was copied from dump_path into Vload_path, above,
- when Vinstallation_directory was non-nil. It should not be
- necessary, since in out of tree builds lisp/ is empty, save
+ the build directory) at the front here, but that should not
+ be necessary, since in out of tree builds lisp/ is empty, save
for Makefile. */
lpath = decode_env_path (0, normal, 0);
- dump_path = lpath;
}
#endif /* !CANNOT_DUMP */
{
/* First, set Vload_path. */
- /* NB: Do not change Vload_path before calling load_path_default,
- since it may check it against dump_path.
- (This behavior could be changed.) */
+ /* Ignore EMACSLOADPATH when dumping. */
+#ifdef CANNOT_DUMP
+ bool use_loadpath = true;
+#else
+ bool use_loadpath = NILP (Vpurify_flag);
+#endif
- /* We explicitly ignore EMACSLOADPATH when dumping. */
- if (NILP (Vpurify_flag) && egetenv ("EMACSLOADPATH"))
+ if (use_loadpath && egetenv ("EMACSLOADPATH"))
{
- Lisp_Object elpath = decode_env_path ("EMACSLOADPATH", 0, 1);
+ Vload_path = decode_env_path ("EMACSLOADPATH", 0, 1);
/* Check (non-nil) user-supplied elements. */
- load_path_check (elpath);
+ load_path_check (Vload_path);
/* If no nils in the environment variable, use as-is.
Otherwise, replace any nils with the default. */
- if (NILP (Fmemq (Qnil, elpath)))
+ if (! NILP (Fmemq (Qnil, Vload_path)))
{
- Vload_path = elpath;
- }
- else
- {
- Lisp_Object elem, default_lpath = load_path_default (0);
+ Lisp_Object elem, elpath = Vload_path;
+ Lisp_Object default_lpath = load_path_default ();
/* Check defaults, before adding site-lisp. */
load_path_check (default_lpath);
}
} /* Fmemq (Qnil, Vload_path) */
}
- else /* Vpurify_flag || !EMACSLOADPATH */
+ else
{
-#ifdef CANNOT_DUMP
- bool changed = 0;
-#else
- bool changed = initialized && NILP (Fequal (dump_path, Vload_path));
-#endif
-
- Vload_path = load_path_default (changed);
+ Vload_path = load_path_default ();
/* Check before adding site-lisp directories.
The install should have created them, but they are not
Or we might be running before installation. */
load_path_check (Vload_path);
- /* Add the site-lisp directories at the front, unless the
- load-path has already been changed.
- FIXME? Should we ignore changed here? */
- if (initialized && !no_site_lisp && !changed)
+ /* Add the site-lisp directories at the front. */
+ if (initialized && !no_site_lisp)
{
Lisp_Object sitelisp;
sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0);
if (! NILP (sitelisp)) Vload_path = nconc2 (sitelisp, Vload_path);
}
- } /* !Vpurify_flag && EMACSLOADPATH */
+ }
Vvalues = Qnil;
Vold_style_backquotes = Qnil;
DEFSYM (Qold_style_backquotes, "old-style-backquotes");
+ DEFVAR_BOOL ("load-prefer-newer", load_prefer_newer,
+ doc: /* Non-nil means `load' prefers the newest version of a file.
+This applies when a filename suffix is not explicitly specified and
+`load' is trying various possible suffixes (see `load-suffixes' and
+`load-file-rep-suffixes'). Normally, it stops at the first file
+that exists unless you explicitly specify one or the other. If this
+option is non-nil, it checks all suffixes and uses whichever file is
+newest.
+Note that if you customize this, obviously it will not affect files
+that are loaded before your customizations are read! */);
+ load_prefer_newer = 0;
+
/* Vsource_directory was initialized in init_lread. */
DEFSYM (Qcurrent_load_list, "current-load-list");
DEFSYM (Qdir_ok, "dir-ok");
DEFSYM (Qdo_after_load_evaluation, "do-after-load-evaluation");
- staticpro (&dump_path);
-
staticpro (&read_objects);
read_objects = Qnil;
staticpro (&seen_list);