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.
This commit is contained in:
parent
1a84d8fba4
commit
2335704fcc
1 changed files with 50 additions and 81 deletions
131
src/dired.c
131
src/dired.c
|
@ -167,28 +167,19 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
|||
Lisp_Object match, Lisp_Object nosort, bool attrs,
|
||||
Lisp_Object id_format)
|
||||
{
|
||||
ptrdiff_t directory_nbytes;
|
||||
Lisp_Object list, dirfilename, encoded_directory;
|
||||
bool needsep = 0;
|
||||
ptrdiff_t count = SPECPDL_INDEX ();
|
||||
#ifdef WINDOWSNT
|
||||
Lisp_Object w32_save = Qnil;
|
||||
#endif
|
||||
if (!NILP (match))
|
||||
CHECK_STRING (match);
|
||||
|
||||
/* Don't let the compiler optimize away all copies of DIRECTORY,
|
||||
which would break GC; see Bug#16986. */
|
||||
Lisp_Object volatile directory_volatile = directory;
|
||||
|
||||
/* Because of file name handlers, these functions might call
|
||||
Ffuncall, and cause a GC. */
|
||||
list = encoded_directory = dirfilename = Qnil;
|
||||
dirfilename = Fdirectory_file_name (directory);
|
||||
Lisp_Object dirfilename = Fdirectory_file_name (directory);
|
||||
|
||||
/* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
|
||||
run_pre_post_conversion_on_str which calls Lisp directly and
|
||||
indirectly. */
|
||||
Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
|
||||
encoded_directory = ENCODE_FILE (directory);
|
||||
|
||||
int fd;
|
||||
DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd);
|
||||
|
@ -196,9 +187,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
|
|||
/* Unfortunately, we can now invoke expand-file-name and
|
||||
file-attributes on filenames, both of which can throw, so we must
|
||||
do a proper unwind-protect. */
|
||||
ptrdiff_t count = SPECPDL_INDEX ();
|
||||
record_unwind_protect_ptr (directory_files_internal_unwind, d);
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
Lisp_Object w32_save = Qnil;
|
||||
if (attrs)
|
||||
{
|
||||
/* 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,
|
|||
}
|
||||
#endif
|
||||
|
||||
directory_nbytes = SBYTES (directory);
|
||||
ptrdiff_t directory_nbytes = SBYTES (directory);
|
||||
re_match_object = Qt;
|
||||
|
||||
/* Decide whether we need to add a directory separator. */
|
||||
if (directory_nbytes == 0
|
||||
|| !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)))
|
||||
needsep = 1;
|
||||
bool needsep = (directory_nbytes == 0
|
||||
|| !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)));
|
||||
|
||||
/* Windows users want case-insensitive wildcards. */
|
||||
Lisp_Object case_table =
|
||||
Lisp_Object case_table = Qnil;
|
||||
#ifdef WINDOWSNT
|
||||
BVAR (&buffer_defaults, case_canon_table)
|
||||
#else
|
||||
Qnil
|
||||
case_table = BVAR (&buffer_defaults, case_canon_table);
|
||||
#endif
|
||||
;
|
||||
|
||||
if (!NILP (match))
|
||||
CHECK_STRING (match);
|
||||
|
||||
/* Loop reading directory entries. */
|
||||
/* Read directory entries and accumulate them into LIST. */
|
||||
Lisp_Object list = Qnil;
|
||||
for (struct dirent *dp; (dp = read_dirent (d, directory)); )
|
||||
{
|
||||
ptrdiff_t len = dirent_namelen (dp);
|
||||
Lisp_Object name = make_unibyte_string (dp->d_name, len);
|
||||
Lisp_Object finalname = name;
|
||||
|
||||
/* Note: DECODE_FILE can GC; it should protect its argument,
|
||||
though. */
|
||||
/* This can GC. */
|
||||
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 ();
|
||||
|
||||
bool wanted = (NILP (match) ||
|
||||
fast_string_match_internal (
|
||||
match, name, case_table) >= 0);
|
||||
if (!NILP (match)
|
||||
&& fast_string_match_internal (match, name, case_table) < 0)
|
||||
continue;
|
||||
|
||||
if (wanted)
|
||||
Lisp_Object fileattrs;
|
||||
if (attrs)
|
||||
{
|
||||
if (!NILP (full))
|
||||
{
|
||||
Lisp_Object fullname;
|
||||
ptrdiff_t nbytes = len + directory_nbytes + needsep;
|
||||
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)
|
||||
{
|
||||
Lisp_Object fileattrs
|
||||
= file_attributes (fd, dp->d_name, directory, name, id_format);
|
||||
if (!NILP (fileattrs))
|
||||
list = Fcons (Fcons (finalname, fileattrs), list);
|
||||
}
|
||||
else
|
||||
list = Fcons (finalname, list);
|
||||
fileattrs = file_attributes (fd, dp->d_name, directory, name,
|
||||
id_format);
|
||||
if (NILP (fileattrs))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NILP (full))
|
||||
{
|
||||
ptrdiff_t name_nbytes = SBYTES (name);
|
||||
ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes;
|
||||
ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name);
|
||||
finalname = make_uninit_multibyte_string (nchars, nbytes);
|
||||
if (nchars == nbytes)
|
||||
STRING_SET_UNIBYTE (finalname);
|
||||
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);
|
||||
|
@ -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.
|
||||
Otherwise, the list returned is sorted with `string-lessp'.
|
||||
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);
|
||||
|
||||
/* If the file name has special constructs in it,
|
||||
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))
|
||||
return call5 (handler, Qdirectory_files, directory,
|
||||
full, match, nosort);
|
||||
|
@ -365,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see
|
|||
`file-attributes' for further documentation.
|
||||
On MS-Windows, performance depends on `w32-get-true-file-attributes',
|
||||
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);
|
||||
|
||||
/* If the file name has special constructs in it,
|
||||
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))
|
||||
return call6 (handler, Qdirectory_files_and_attributes,
|
||||
directory, full, match, nosort, id_format);
|
||||
|
@ -1032,7 +1000,8 @@ file_attributes (int fd, char const *name,
|
|||
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.
|
||||
Comparison is in lexicographic order and case is significant. */)
|
||||
(Lisp_Object f1, Lisp_Object f2)
|
||||
|
|
Loading…
Add table
Reference in a new issue