summaryrefslogtreecommitdiff
path: root/src/dired.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-09-16 13:54:57 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2019-09-16 13:55:23 -0700
commit2335704fccc2a5088c864bea1f10b4f0ef788e6b (patch)
tree98284d464e2143906cb2f9650400b0db85114bb8 /src/dired.c
parent1a84d8fba4b526f7c8f240b8163e66714a41cca6 (diff)
downloademacs-2335704fccc2a5088c864bea1f10b4f0ef788e6b.tar.gz
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.
Diffstat (limited to 'src/dired.c')
-rw-r--r--src/dired.c129
1 files changed, 49 insertions, 80 deletions
diff --git a/src/dired.c b/src/dired.c
index cec79ab46be..5fc6ccd3ead 100644
--- a/src/dired.c
+++ b/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;
+ fileattrs = file_attributes (fd, dp->d_name, directory, name,
+ id_format);
+ if (NILP (fileattrs))
+ continue;
+ }
- 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);
+ 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)