aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-09-16 13:54:57 -0700
committerPaul Eggert2019-09-16 13:55:23 -0700
commit2335704fccc2a5088c864bea1f10b4f0ef788e6b (patch)
tree98284d464e2143906cb2f9650400b0db85114bb8 /src
parent1a84d8fba4b526f7c8f240b8163e66714a41cca6 (diff)
downloademacs-2335704fccc2a5088c864bea1f10b4f0ef788e6b.tar.gz
emacs-2335704fccc2a5088c864bea1f10b4f0ef788e6b.zip
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')
-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,
167 Lisp_Object match, Lisp_Object nosort, bool attrs, 167 Lisp_Object match, Lisp_Object nosort, bool attrs,
168 Lisp_Object id_format) 168 Lisp_Object id_format)
169{ 169{
170 ptrdiff_t directory_nbytes; 170 if (!NILP (match))
171 Lisp_Object list, dirfilename, encoded_directory; 171 CHECK_STRING (match);
172 bool needsep = 0;
173 ptrdiff_t count = SPECPDL_INDEX ();
174#ifdef WINDOWSNT
175 Lisp_Object w32_save = Qnil;
176#endif
177 172
178 /* Don't let the compiler optimize away all copies of DIRECTORY, 173 /* Don't let the compiler optimize away all copies of DIRECTORY,
179 which would break GC; see Bug#16986. */ 174 which would break GC; see Bug#16986. */
180 Lisp_Object volatile directory_volatile = directory; 175 Lisp_Object volatile directory_volatile = directory;
181 176
182 /* Because of file name handlers, these functions might call 177 Lisp_Object dirfilename = Fdirectory_file_name (directory);
183 Ffuncall, and cause a GC. */
184 list = encoded_directory = dirfilename = Qnil;
185 dirfilename = Fdirectory_file_name (directory);
186 178
187 /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run 179 /* Note: ENCODE_FILE and DECODE_FILE can GC because they can run
188 run_pre_post_conversion_on_str which calls Lisp directly and 180 run_pre_post_conversion_on_str which calls Lisp directly and
189 indirectly. */ 181 indirectly. */
190 Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename); 182 Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
191 encoded_directory = ENCODE_FILE (directory);
192 183
193 int fd; 184 int fd;
194 DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd); 185 DIR *d = open_directory (dirfilename, encoded_dirfilename, &fd);
@@ -196,9 +187,11 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
196 /* Unfortunately, we can now invoke expand-file-name and 187 /* Unfortunately, we can now invoke expand-file-name and
197 file-attributes on filenames, both of which can throw, so we must 188 file-attributes on filenames, both of which can throw, so we must
198 do a proper unwind-protect. */ 189 do a proper unwind-protect. */
190 ptrdiff_t count = SPECPDL_INDEX ();
199 record_unwind_protect_ptr (directory_files_internal_unwind, d); 191 record_unwind_protect_ptr (directory_files_internal_unwind, d);
200 192
201#ifdef WINDOWSNT 193#ifdef WINDOWSNT
194 Lisp_Object w32_save = Qnil;
202 if (attrs) 195 if (attrs)
203 { 196 {
204 /* Do this only once to avoid doing it (in w32.c:stat) for each 197 /* 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 } 211 }
219#endif 212#endif
220 213
221 directory_nbytes = SBYTES (directory); 214 ptrdiff_t directory_nbytes = SBYTES (directory);
222 re_match_object = Qt; 215 re_match_object = Qt;
223 216
224 /* Decide whether we need to add a directory separator. */ 217 /* Decide whether we need to add a directory separator. */
225 if (directory_nbytes == 0 218 bool needsep = (directory_nbytes == 0
226 || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1))) 219 || !IS_ANY_SEP (SREF (directory, directory_nbytes - 1)));
227 needsep = 1;
228 220
229 /* Windows users want case-insensitive wildcards. */ 221 /* Windows users want case-insensitive wildcards. */
230 Lisp_Object case_table = 222 Lisp_Object case_table = Qnil;
231#ifdef WINDOWSNT 223#ifdef WINDOWSNT
232 BVAR (&buffer_defaults, case_canon_table) 224 case_table = BVAR (&buffer_defaults, case_canon_table);
233#else
234 Qnil
235#endif 225#endif
236 ;
237 226
238 if (!NILP (match)) 227 /* Read directory entries and accumulate them into LIST. */
239 CHECK_STRING (match); 228 Lisp_Object list = Qnil;
240
241 /* Loop reading directory entries. */
242 for (struct dirent *dp; (dp = read_dirent (d, directory)); ) 229 for (struct dirent *dp; (dp = read_dirent (d, directory)); )
243 { 230 {
244 ptrdiff_t len = dirent_namelen (dp); 231 ptrdiff_t len = dirent_namelen (dp);
245 Lisp_Object name = make_unibyte_string (dp->d_name, len); 232 Lisp_Object name = make_unibyte_string (dp->d_name, len);
246 Lisp_Object finalname = name; 233 Lisp_Object finalname = name;
247 234
248 /* Note: DECODE_FILE can GC; it should protect its argument, 235 /* This can GC. */
249 though. */
250 name = DECODE_FILE (name); 236 name = DECODE_FILE (name);
251 len = SBYTES (name);
252 237
253 /* Now that we have unwind_protect in place, we might as well
254 allow matching to be interrupted. */
255 maybe_quit (); 238 maybe_quit ();
256 239
257 bool wanted = (NILP (match) || 240 if (!NILP (match)
258 fast_string_match_internal ( 241 && fast_string_match_internal (match, name, case_table) < 0)
259 match, name, case_table) >= 0); 242 continue;
260 243
261 if (wanted) 244 Lisp_Object fileattrs;
245 if (attrs)
262 { 246 {
263 if (!NILP (full)) 247 fileattrs = file_attributes (fd, dp->d_name, directory, name,
264 { 248 id_format);
265 Lisp_Object fullname; 249 if (NILP (fileattrs))
266 ptrdiff_t nbytes = len + directory_nbytes + needsep; 250 continue;
267 ptrdiff_t nchars; 251 }
268
269 fullname = make_uninit_multibyte_string (nbytes, nbytes);
270 memcpy (SDATA (fullname), SDATA (directory),
271 directory_nbytes);
272
273 if (needsep)
274 SSET (fullname, directory_nbytes, DIRECTORY_SEP);
275
276 memcpy (SDATA (fullname) + directory_nbytes + needsep,
277 SDATA (name), len);
278
279 nchars = multibyte_chars_in_text (SDATA (fullname), nbytes);
280
281 /* Some bug somewhere. */
282 if (nchars > nbytes)
283 emacs_abort ();
284
285 STRING_SET_CHARS (fullname, nchars);
286 if (nchars == nbytes)
287 STRING_SET_UNIBYTE (fullname);
288
289 finalname = fullname;
290 }
291 else
292 finalname = name;
293 252
294 if (attrs) 253 if (!NILP (full))
295 { 254 {
296 Lisp_Object fileattrs 255 ptrdiff_t name_nbytes = SBYTES (name);
297 = file_attributes (fd, dp->d_name, directory, name, id_format); 256 ptrdiff_t nbytes = directory_nbytes + needsep + name_nbytes;
298 if (!NILP (fileattrs)) 257 ptrdiff_t nchars = SCHARS (directory) + needsep + SCHARS (name);
299 list = Fcons (Fcons (finalname, fileattrs), list); 258 finalname = make_uninit_multibyte_string (nchars, nbytes);
300 } 259 if (nchars == nbytes)
301 else 260 STRING_SET_UNIBYTE (finalname);
302 list = Fcons (finalname, list); 261 memcpy (SDATA (finalname), SDATA (directory), directory_nbytes);
262 if (needsep)
263 SSET (finalname, directory_nbytes, DIRECTORY_SEP);
264 memcpy (SDATA (finalname) + directory_nbytes + needsep,
265 SDATA (name), name_nbytes);
303 } 266 }
267 else
268 finalname = name;
269
270 list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list);
304 } 271 }
305 272
306 closedir (d); 273 closedir (d);
@@ -330,14 +297,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH.
330If NOSORT is non-nil, the list is not sorted--its order is unpredictable. 297If NOSORT is non-nil, the list is not sorted--its order is unpredictable.
331 Otherwise, the list returned is sorted with `string-lessp'. 298 Otherwise, the list returned is sorted with `string-lessp'.
332 NOSORT is useful if you plan to sort the result yourself. */) 299 NOSORT is useful if you plan to sort the result yourself. */)
333 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort) 300 (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
301 Lisp_Object nosort)
334{ 302{
335 Lisp_Object handler;
336 directory = Fexpand_file_name (directory, Qnil); 303 directory = Fexpand_file_name (directory, Qnil);
337 304
338 /* If the file name has special constructs in it, 305 /* If the file name has special constructs in it,
339 call the corresponding file name handler. */ 306 call the corresponding file name handler. */
340 handler = Ffind_file_name_handler (directory, Qdirectory_files); 307 Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files);
341 if (!NILP (handler)) 308 if (!NILP (handler))
342 return call5 (handler, Qdirectory_files, directory, 309 return call5 (handler, Qdirectory_files, directory,
343 full, match, nosort); 310 full, match, nosort);
@@ -365,14 +332,15 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see
365`file-attributes' for further documentation. 332`file-attributes' for further documentation.
366On MS-Windows, performance depends on `w32-get-true-file-attributes', 333On MS-Windows, performance depends on `w32-get-true-file-attributes',
367which see. */) 334which see. */)
368 (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, Lisp_Object id_format) 335 (Lisp_Object directory, Lisp_Object full, Lisp_Object match,
336 Lisp_Object nosort, Lisp_Object id_format)
369{ 337{
370 Lisp_Object handler;
371 directory = Fexpand_file_name (directory, Qnil); 338 directory = Fexpand_file_name (directory, Qnil);
372 339
373 /* If the file name has special constructs in it, 340 /* If the file name has special constructs in it,
374 call the corresponding file name handler. */ 341 call the corresponding file name handler. */
375 handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); 342 Lisp_Object handler
343 = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
376 if (!NILP (handler)) 344 if (!NILP (handler))
377 return call6 (handler, Qdirectory_files_and_attributes, 345 return call6 (handler, Qdirectory_files_and_attributes,
378 directory, full, match, nosort, id_format); 346 directory, full, match, nosort, id_format);
@@ -1032,7 +1000,8 @@ file_attributes (int fd, char const *name,
1032 INT_TO_INTEGER (s.st_dev)); 1000 INT_TO_INTEGER (s.st_dev));
1033} 1001}
1034 1002
1035DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, 1003DEFUN ("file-attributes-lessp", Ffile_attributes_lessp,
1004 Sfile_attributes_lessp, 2, 2, 0,
1036 doc: /* Return t if first arg file attributes list is less than second. 1005 doc: /* Return t if first arg file attributes list is less than second.
1037Comparison is in lexicographic order and case is significant. */) 1006Comparison is in lexicographic order and case is significant. */)
1038 (Lisp_Object f1, Lisp_Object f2) 1007 (Lisp_Object f1, Lisp_Object f2)