Commit 2335704f authored by Paul Eggert's avatar Paul Eggert

directory-files cleanup and speed tweaking

* src/dired.c (directory_files_internal):
Check ‘match’ before doing anything heavyweight.
Move decls closer to use.
Remove obsolete comments about GC.
No need to encode ‘directory’ or to call multibyte_chars_in_text.
Remove no-longer-needed bug check.
Skip finalname construction if file_attributes fails.
parent 1a84d8fb
Pipeline #3162 failed with stage
in 90 minutes and 3 seconds
...@@ -167,28 +167,19 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, ...@@ -167,28 +167,19 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
Lisp_Object match, Lisp_Object nosort, bool attrs, Lisp_Object match, Lisp_Object nosort, bool attrs,
Lisp_Object id_format) Lisp_Object id_format)
{ {
ptrdiff_t directory_nbytes; if (!NILP (match))
Lisp_Object list, dirfilename, encoded_directory; CHECK_STRING (match);
bool needsep = 0;
ptrdiff_t count = SPECPDL_INDEX ();
#ifdef WINDOWSNT
Lisp_Object w32_save = Qnil;
#endif
/* Don't let the compiler optimize away all copies of DIRECTORY, /* Don't let the compiler optimize away all copies of DIRECTORY,
which would break GC; see Bug#16986. */ which would break GC; see Bug#16986. */
Lisp_Object volatile directory_volatile = directory; Lisp_Object volatile directory_volatile = directory;
/* Because of file name handlers, these functions might call Lisp_Object dirfilename = Fdirectory_file_name (directory);
Ffuncall, and cause a GC. */
list = encoded_directory = dirfilename = Qnil;
dirfilename = Fdirectory_file_name (directory);
/* Note: ENCODE_FILE and DECODE_FILE can GC because they can run /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
run_pre_post_conversion_on_str which calls Lisp directly and run_pre_post_conversion_on_str which calls Lisp directly and
indirectly. */ indirectly. */
Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename); Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
encoded_directory = ENCODE_FILE (directory);
int fd; int fd;
DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd); DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd);
...@@ -196,9 +187,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, ...@@ -196,9 +187,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
/* Unfortunately, we can now invoke expand-file-name and /* Unfortunately, we can now invoke expand-file-name and
file-attributes on filenames, both of which can throw, so we must file-attributes on filenames, both of which can throw, so we must
do a proper unwind-protect. */ do a proper unwind-protect. */
ptrdiff_t count = SPECPDL_INDEX ();
record_unwind_protect_ptr (directory_files_internal_unwind, d); record_unwind_protect_ptr (directory_files_internal_unwind, d);
#ifdef WINDOWSNT #ifdef WINDOWSNT
Lisp_Object w32_save = Qnil;
if (attrs) if (attrs)
{ {
/* Do this only once to avoid doing it (in w32.c:stat) for each /* Do this only once to avoid doing it (in w32.c:stat) for each
...@@ -218,89 +211,63 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full, ...@@ -218,89 +211,63 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
} }
#endif #endif
directory_nbytes = SBYTES (directory); ptrdiff_t directory_nbytes = SBYTES (directory);
re_match_object = Qt; re_match_object = Qt;
/* Decide whether we need to add a directory separator. */ /* Decide whether we need to add a directory separator. */
if (directory_nbytes == 0 bool needsep = (directory_nbytes == 0
|| !IS_ANY_SEP (SREF (directory, directory_nbytes - 1))) || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)));
needsep = 1;
/* Windows users want case-insensitive wildcards. */ /* Windows users want case-insensitive wildcards. */
Lisp_Object case_table = Lisp_Object case_table = Qnil;
#ifdef WINDOWSNT #ifdef WINDOWSNT
BVAR (&buffer_defaults, case_canon_table) case_table = BVAR (&buffer_defaults, case_canon_table);
#else
Qnil
#endif #endif
;
if (!NILP (match)) /* Read directory entries and accumulate them into LIST. */
CHECK_STRING (match); Lisp_Object list = Qnil;
/* Loop reading directory entries. */
for (struct dirent *dp; (dp = read_dirent (d, directory)); ) for (struct dirent *dp; (dp = read_dirent (d, directory)); )
{ {
ptrdiff_t len = dirent_namelen (dp); ptrdiff_t len = dirent_namelen (dp);
Lisp_Object name = make_unibyte_string (dp->d_name, len); Lisp_Object name = make_unibyte_string (dp->d_name, len);
Lisp_Object finalname = name; Lisp_Object finalname = name;
/* Note: DECODE_FILE can GC; it should protect its argument, /* This can GC. */
though. */
name = DECODE_FILE (name); name = DECODE_FILE (name);
len = SBYTES (name);
/* Now that we have unwind_protect in place, we might as well
allow matching to be interrupted. */
maybe_quit (); maybe_quit ();
bool wanted = (NILP (match) || if (!NILP (match)
fast_string_match_internal ( && fast_string_match_internal (match, name, case_table) < 0)
match, name, case_table) >= 0); continue;
if (wanted) Lisp_Object fileattrs;
if (attrs)
{ {
if (!NILP (full)) fileattrs = file_attributes (fd, dp->d_name, directory, name,
{ id_format);
Lisp_Object fullname; if (NILP (fileattrs))
ptrdiff_t nbytes = len + directory_nbytes + needsep; continue;
ptrdiff_t nchars; }
fullname = make_uninit_multibyte_string (nbytes, nbytes);
memcpy (SDATA (fullname), SDATA (directory),
directory_nbytes);
if (needsep)
SSET (fullname, directory_nbytes, DIRECTORY_SEP);
memcpy (SDATA (fullname) + directory_nbytes + needsep,
SDATA (name), len);
nchars = multibyte_chars_in_text (SDATA (fullname), nbytes);
/* Some bug somewhere. */
if (nchars > nbytes)
emacs_abort ();
STRING_SET_CHARS (fullname, nchars);
if (nchars == nbytes)
STRING_SET_UNIBYTE (fullname);
finalname = fullname;
}
else
finalname = name;
if (attrs) if (!NILP (full))
{ {
Lisp_Object fileattrs ptrdiff_t name_nbytes = SBYTES (name);
= file_attributes (fd, dp->d_name, directory, name, id_format); ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes;
if (!NILP (fileattrs)) ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name);
list = Fcons (Fcons (finalname, fileattrs), list); finalname = make_uninit_multibyte_string (nchars, nbytes);
} if (nchars == nbytes)
else STRING_SET_UNIBYTE (finalname);
list = Fcons (finalname, list); memcpy (SDATA (finalname), SDATA (directory), directory_nbytes);
if (needsep)
SSET (finalname, directory_nbytes, DIRECTORY_SEP);
memcpy (SDATA (finalname) + directory_nbytes + needsep,
SDATA (name), name_nbytes);
} }
else
finalname = name;
list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list);
} }
closedir (d); closedir (d);
...@@ -330,14 +297,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH. ...@@ -330,14 +297,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH.
If NOSORT is non-nil, the list is not sorted--its order is unpredictable. If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
Otherwise, the list returned is sorted with `string-lessp'. Otherwise, the list returned is sorted with `string-lessp'.
NOSORT is useful if you plan to sort the result yourself. */) NOSORT is useful if you plan to sort the result yourself. */)
(Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort) (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
Lisp_Object nosort)
{ {
Lisp_Object handler;
directory = Fexpand_file_name (directory, Qnil); directory = Fexpand_file_name (directory, Qnil);
/* If the file name has special constructs in it, /* If the file name has special constructs in it,
call the corresponding file name handler. */ call the corresponding file name handler. */
handler = Ffind_file_name_handler (directory, Qdirectory_files); Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files);
if (!NILP (handler)) if (!NILP (handler))
return call5 (handler, Qdirectory_files, directory, return call5 (handler, Qdirectory_files, directory,
full, match, nosort); full, match, nosort);
...@@ -365,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see ...@@ -365,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see
`file-attributes' for further documentation. `file-attributes' for further documentation.
On MS-Windows, performance depends on `w32-get-true-file-attributes', On MS-Windows, performance depends on `w32-get-true-file-attributes',
which see. */) which see. */)
(Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, Lisp_Object id_format) (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
Lisp_Object nosort, Lisp_Object id_format)
{ {
Lisp_Object handler;
directory = Fexpand_file_name (directory, Qnil); directory = Fexpand_file_name (directory, Qnil);
/* If the file name has special constructs in it, /* If the file name has special constructs in it,
call the corresponding file name handler. */ call the corresponding file name handler. */
handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); Lisp_Object handler
= Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
if (!NILP (handler)) if (!NILP (handler))
return call6 (handler, Qdirectory_files_and_attributes, return call6 (handler, Qdirectory_files_and_attributes,
directory, full, match, nosort, id_format); directory, full, match, nosort, id_format);
...@@ -1032,7 +1000,8 @@ file_attributes (int fd, char const *name, ...@@ -1032,7 +1000,8 @@ file_attributes (int fd, char const *name,
INT_TO_INTEGER (s.st_dev)); INT_TO_INTEGER (s.st_dev));
} }
DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, DEFUN ("file-attributes-lessp", Ffile_attributes_lessp,
Sfile_attributes_lessp, 2, 2, 0,
doc: /* Return t if first arg file attributes list is less than second. doc: /* Return t if first arg file attributes list is less than second.
Comparison is in lexicographic order and case is significant. */) Comparison is in lexicographic order and case is significant. */)
(Lisp_Object f1, Lisp_Object f2) (Lisp_Object f1, Lisp_Object f2)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment