/* Lisp functions for making directory listings.
- Copyright (C) 1985-1986, 1993-1994, 1999-2015 Free Software
+ Copyright (C) 1985-1986, 1993-1994, 1999-2016 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "lisp.h"
#include "systime.h"
-#include "character.h"
#include "buffer.h"
-#include "commands.h"
-#include "charset.h"
#include "coding.h"
#include "regex.h"
#include "blockinput.h"
}
static DIR *
-open_directory (char const *name, int *fdp)
+open_directory (Lisp_Object dirname, int *fdp)
{
+ char *name = SSDATA (dirname);
DIR *d;
int fd, opendir_errno;
unblock_input ();
+ if (!d)
+ report_file_errno ("Opening directory", dirname, opendir_errno);
*fdp = fd;
- errno = opendir_errno;
return d;
}
if (dp || errno == 0)
return dp;
if (! (errno == EAGAIN || errno == EINTR))
- report_file_error ("Reading directory", dirname);
+ {
+#ifdef WINDOWSNT
+ /* The MS-Windows implementation of 'opendir' doesn't
+ actually open a directory until the first call to
+ 'readdir'. If 'readdir' fails to open the directory, it
+ sets errno to ENOENT or EACCES, see w32.c. */
+ if (errno == ENOENT || errno == EACCES)
+ report_file_error ("Opening directory", dirname);
+#endif
+ report_file_error ("Reading directory", dirname);
+ }
QUIT;
}
}
Lisp_Object match, Lisp_Object nosort, bool attrs,
Lisp_Object id_format)
{
- DIR *d;
- int fd;
ptrdiff_t directory_nbytes;
Lisp_Object list, dirfilename, encoded_directory;
struct re_pattern_buffer *bufp = NULL;
bool needsep = 0;
ptrdiff_t count = SPECPDL_INDEX ();
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
#ifdef WINDOWSNT
Lisp_Object w32_save = Qnil;
#endif
/* Don't let the compiler optimize away all copies of DIRECTORY,
- which would break GC; see Bug#16986. Although this is required
- only in the common case where GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS,
- it shouldn't break anything in the other cases. */
+ 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;
- GCPRO5 (match, directory, list, dirfilename, encoded_directory);
dirfilename = Fdirectory_file_name (directory);
if (!NILP (match))
/* Now *bufp is the compiled form of MATCH; don't call anything
which might compile a new regexp until we're done with the loop! */
- d = open_directory (SSDATA (dirfilename), &fd);
- if (d == NULL)
- report_file_error ("Opening directory", directory);
+ int fd;
+ DIR *d = open_directory (dirfilename, &fd);
/* Unfortunately, we can now invoke expand-file-name and
file-attributes on filenames, both of which can throw, so we must
ptrdiff_t len = dirent_namelen (dp);
Lisp_Object name = make_unibyte_string (dp->d_name, len);
Lisp_Object finalname = name;
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (finalname, name);
/* Note: DECODE_FILE can GC; it should protect its argument,
though. */
else
list = Fcons (finalname, list);
}
-
- UNGCPRO;
}
block_input ();
attrs ? Qfile_attributes_lessp : Qstring_lessp);
(void) directory_volatile;
- RETURN_UNGCPRO (list);
+ return list;
}
If PREDICATE is non-nil, call PREDICATE with each possible
completion (in absolute form) and ignore it if PREDICATE returns nil.
-This function ignores some of the possible completions as
-determined by the variable `completion-ignored-extensions', which see. */)
+This function ignores some of the possible completions as determined
+by the variables `completion-regexp-list' and
+`completion-ignored-extensions', which see. `completion-regexp-list'
+is matched against file and directory names relative to DIRECTORY. */)
(Lisp_Object file, Lisp_Object directory, Lisp_Object predicate)
{
Lisp_Object handler;
DEFUN ("file-name-all-completions", Ffile_name_all_completions,
Sfile_name_all_completions, 2, 2, 0,
doc: /* Return a list of all completions of file name FILE in directory DIRECTORY.
-These are all file names in directory DIRECTORY which begin with FILE. */)
+These are all file names in directory DIRECTORY which begin with FILE.
+
+This function ignores some of the possible completions as determined
+by `completion-regexp-list', which see. `completion-regexp-list'
+is matched against file and directory names relative to DIRECTORY. */)
(Lisp_Object file, Lisp_Object directory)
{
Lisp_Object handler;
file_name_completion (Lisp_Object file, Lisp_Object dirname, bool all_flag,
Lisp_Object predicate)
{
- DIR *d;
- int fd;
ptrdiff_t bestmatchsize = 0;
int matchcount = 0;
/* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded.
well as "." and "..". Until shown otherwise, assume we can't exclude
anything. */
bool includeall = 1;
+ bool check_decoded = false;
ptrdiff_t count = SPECPDL_INDEX ();
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
elt = Qnil;
bestmatch = Qnil;
encoded_file = encoded_dir = Qnil;
- GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
specbind (Qdefault_directory, dirname);
/* Do completion on the encoded file name
work with decoded file names, but we still do some filtering based
on the encoded file name. */
encoded_file = ENCODE_FILE (file);
-
encoded_dir = ENCODE_FILE (Fdirectory_file_name (dirname));
- d = open_directory (SSDATA (encoded_dir), &fd);
- if (!d)
- report_file_error ("Opening directory", dirname);
-
+ Lisp_Object file_encoding = Vfile_name_coding_system;
+ if (NILP (Vfile_name_coding_system))
+ file_encoding = Vdefault_file_name_coding_system;
+ /* If the file-name encoding decomposes characters, as we do for
+ HFS+ filesystems, we need to make an additional comparison of
+ decoded names in order to filter false positives, such as "a"
+ falsely matching "a-ring". */
+ if (!NILP (file_encoding)
+ && !NILP (Fplist_get (Fcoding_system_plist (file_encoding),
+ Qdecomposed_characters)))
+ {
+ check_decoded = true;
+ if (STRING_MULTIBYTE (file))
+ {
+ /* Recompute FILE to make sure any decomposed characters in
+ it are re-composed by the post-read-conversion.
+ Otherwise, any decomposed characters will be rejected by
+ the additional check below. */
+ file = DECODE_FILE (encoded_file);
+ }
+ }
+ int fd;
+ DIR *d = open_directory (encoded_dir, &fd);
record_unwind_protect_ptr (directory_files_internal_unwind, d);
/* Loop reading directory entries. */
name = Ffile_name_as_directory (name);
/* Test the predicate, if any. */
- if (!NILP (predicate))
- {
- Lisp_Object val;
- struct gcpro gcpro1;
+ if (!NILP (predicate) && NILP (call1 (predicate, name)))
+ continue;
- GCPRO1 (name);
- val = call1 (predicate, name);
- UNGCPRO;
+ /* Reject entries where the encoded strings match, but the
+ decoded don't. For example, "a" should not match "a-ring" on
+ file systems that store decomposed characters. */
+ Lisp_Object zero = make_number (0);
- if (NILP (val))
+ if (check_decoded && SCHARS (file) <= SCHARS (name))
+ {
+ /* FIXME: This is a copy of the code below. */
+ ptrdiff_t compare = SCHARS (file);
+ Lisp_Object cmp
+ = Fcompare_strings (name, zero, make_number (compare),
+ file, zero, make_number (compare),
+ completion_ignore_case ? Qt : Qnil);
+ if (!EQ (cmp, Qt))
continue;
}
}
else
{
- Lisp_Object zero = make_number (0);
/* FIXME: This is a copy of the code in Ftry_completion. */
ptrdiff_t compare = min (bestmatchsize, SCHARS (name));
Lisp_Object cmp
- = Fcompare_strings (bestmatch, zero,
- make_number (compare),
- name, zero,
- make_number (compare),
+ = Fcompare_strings (bestmatch, zero, make_number (compare),
+ name, zero, make_number (compare),
completion_ignore_case ? Qt : Qnil);
ptrdiff_t matchsize = EQ (cmp, Qt) ? compare : eabs (XINT (cmp)) - 1;
}
}
- UNGCPRO;
/* This closes the directory. */
bestmatch = unbind_to (count, bestmatch);
Value is nil if specified file cannot be opened.
ID-FORMAT specifies the preferred format of attributes uid and gid (see
-below) - valid values are 'string and 'integer. The latter is the
+below) - valid values are `string' and `integer'. The latter is the
default, but we plan to change that, so you should specify a non-nil value
for ID-FORMAT if you use the returned uid or gid.
DEFSYM (Qfile_attributes, "file-attributes");
DEFSYM (Qfile_attributes_lessp, "file-attributes-lessp");
DEFSYM (Qdefault_directory, "default-directory");
+ DEFSYM (Qdecomposed_characters, "decomposed-characters");
defsubr (&Sdirectory_files);
defsubr (&Sdirectory_files_and_attributes);