#include <rmsdef.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
/* The d_nameln member of a struct dirent includes the '\0' character
on some systems, but not on others. What's worse, you can't tell
at compile-time which one it will be, since it really depends on
#include "lisp.h"
#include "buffer.h"
#include "commands.h"
-
+#include "charset.h"
+#include "coding.h"
#include "regex.h"
/* Returns a search buffer, with a fastmap allocated and ready to go. */
extern int completion_ignore_case;
extern Lisp_Object Vcompletion_regexp_list;
+extern Lisp_Object Vfile_name_coding_system, Vdefault_file_name_coding_system;
Lisp_Object Vcompletion_ignored_extensions;
Lisp_Object Qcompletion_ignore_case;
DIR *d;
int dirnamelen;
Lisp_Object list, name, dirfilename;
+ Lisp_Object encoded_directory;
Lisp_Object handler;
struct re_pattern_buffer *bufp;
+ int needsep = 0;
+ struct gcpro gcpro1, gcpro2;
/* If the file name has special constructs in it,
call the corresponding file handler. */
return Ffuncall (6, args);
}
- {
- struct gcpro gcpro1, gcpro2;
-
- /* Because of file name handlers, these functions might call
+ /* Because of file name handlers, these functions might call
Ffuncall, and cause a GC. */
- GCPRO1 (match);
- directory = Fexpand_file_name (directory, Qnil);
- UNGCPRO;
- GCPRO2 (match, directory);
- dirfilename = Fdirectory_file_name (directory);
- UNGCPRO;
- }
+ GCPRO1 (match);
+ directory = Fexpand_file_name (directory, Qnil);
+ UNGCPRO;
+ GCPRO2 (match, directory);
+ dirfilename = Fdirectory_file_name (directory);
+ UNGCPRO;
if (!NILP (match))
{
/* MATCH might be a flawed regular expression. Rather than
catching and signaling our own errors, we just call
compile_pattern to do the work for us. */
+ /* Pass 1 for the MULTIBYTE arg
+ because we do make multibyte strings if the contents warrant. */
#ifdef VMS
bufp = compile_pattern (match, 0,
- buffer_defaults.downcase_table->contents, 0);
+ buffer_defaults.downcase_table, 0, 1);
#else
- bufp = compile_pattern (match, 0, 0, 0);
+ bufp = compile_pattern (match, 0, Qnil, 0, 1);
#endif
}
+ dirfilename = ENCODE_FILE (dirfilename);
+
+ encoded_directory = ENCODE_FILE (directory);
+
/* 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! */
report_file_error ("Opening directory", Fcons (directory, Qnil));
list = Qnil;
- dirnamelen = XSTRING (directory)->size;
+ dirnamelen = STRING_BYTES (XSTRING (encoded_directory));
+ re_match_object = Qt;
+
+ /* Decide whether we need to add a directory separator. */
+#ifndef VMS
+ if (dirnamelen == 0
+ || !IS_ANY_SEP (XSTRING (encoded_directory)->data[dirnamelen - 1]))
+ needsep = 1;
+#endif /* not VMS */
+
+ GCPRO2 (encoded_directory, list);
/* Loop reading blocks */
while (1)
{
int afterdirindex = dirnamelen;
int total = len + dirnamelen;
- int needsep = 0;
+ int nchars;
- /* Decide whether we need to add a directory separator. */
-#ifndef VMS
- if (dirnamelen == 0
- || !IS_ANY_SEP (XSTRING (directory)->data[dirnamelen - 1]))
- needsep = 1;
-#endif /* VMS */
-
- name = make_uninit_string (total + needsep);
- bcopy (XSTRING (directory)->data, XSTRING (name)->data,
+ name = make_uninit_multibyte_string (total + needsep,
+ total + needsep);
+ bcopy (XSTRING (encoded_directory)->data, XSTRING (name)->data,
dirnamelen);
if (needsep)
XSTRING (name)->data[afterdirindex++] = DIRECTORY_SEP;
bcopy (dp->d_name,
XSTRING (name)->data + afterdirindex, len);
+ nchars = chars_in_text (XSTRING (name)->data,
+ afterdirindex + len);
+ XSTRING (name)->size = nchars;
+ if (nchars == STRING_BYTES (XSTRING (name)))
+ SET_STRING_BYTES (XSTRING (name), -1);
}
else
name = make_string (dp->d_name, len);
+ name = DECODE_FILE (name);
list = Fcons (name, list);
}
}
}
closedir (d);
+ UNGCPRO;
if (!NILP (nosort))
return list;
return Fsort (Fnreverse (list), Qstring_lessp);
return file_name_completion (file, directory, 1, 0);
}
+static int file_name_completion_stat ();
+
Lisp_Object
file_name_completion (file, dirname, all_flag, ver_flag)
Lisp_Object file, dirname;
unsigned char *p1, *p2;
int matchcount = 0;
Lisp_Object bestmatch, tem, elt, name;
+ Lisp_Object encoded_file;
+ Lisp_Object encoded_dir;
struct stat st;
int directoryp;
int passcount;
int count = specpdl_ptr - specpdl;
- struct gcpro gcpro1, gcpro2, gcpro3;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
#ifdef VMS
extern DIRENTRY * readdirver ();
file = FILE_SYSTEM_CASE (file);
#endif
bestmatch = Qnil;
- GCPRO3 (file, dirname, bestmatch);
+ encoded_file = encoded_dir = Qnil;
+ GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
dirname = Fexpand_file_name (dirname, Qnil);
+ /* Do completion on the encoded file name
+ because the other names in the directory are (we presume)
+ encoded likewise. We decode the completed string at the end. */
+ encoded_file = ENCODE_FILE (file);
+
+ encoded_dir = ENCODE_FILE (dirname);
+
/* With passcount = 0, ignore files that end in an ignored extension.
If nothing found then try again with passcount = 1, don't ignore them.
If looking for all completions, start with passcount = 1,
for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
{
- if (!(d = opendir (XSTRING (Fdirectory_file_name (dirname))->data)))
+ d = opendir (XSTRING (Fdirectory_file_name (encoded_dir))->data);
+ if (!d)
report_file_error ("Opening directory", Fcons (dirname, Qnil));
/* Loop reading blocks */
if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
goto quit;
if (! DIRENTRY_NONEMPTY (dp)
- || len < XSTRING (file)->size
- || 0 <= scmp (dp->d_name, XSTRING (file)->data,
- XSTRING (file)->size))
+ || len < XSTRING (encoded_file)->size
+ || 0 <= scmp (dp->d_name, XSTRING (encoded_file)->data,
+ XSTRING (encoded_file)->size))
continue;
- if (file_name_completion_stat (dirname, dp, &st) < 0)
+ if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
continue;
directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
{
/* Compare extensions-to-be-ignored against end of this file name */
/* if name is not an exact match against specified string */
- if (!passcount && len > XSTRING (file)->size)
+ if (!passcount && len > XSTRING (encoded_file)->size)
/* and exit this for loop if a match is found */
for (tem = Vcompletion_ignored_extensions;
CONSP (tem); tem = XCONS (tem)->cdr)
name = make_string (dp->d_name, len);
if (all_flag)
{
+ name = DECODE_FILE (name);
bestmatch = Fcons (name, bestmatch);
}
else
==
(matchsize + !!directoryp
== XSTRING (bestmatch)->size))
- && !bcmp (p2, XSTRING (file)->data, XSTRING (file)->size)
- && bcmp (p1, XSTRING (file)->data, XSTRING (file)->size)))
+ && !bcmp (p2, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)
+ && bcmp (p1, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)))
{
bestmatch = make_string (dp->d_name, len);
if (directoryp)
bestmatch = unbind_to (count, bestmatch);
if (all_flag || NILP (bestmatch))
- return bestmatch;
+ {
+ if (STRINGP (bestmatch))
+ bestmatch = DECODE_FILE (bestmatch);
+ return bestmatch;
+ }
if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
return Qt;
- return Fsubstring (bestmatch, make_number (0), make_number (bestmatchsize));
+ bestmatch = Fsubstring (bestmatch, make_number (0),
+ make_number (bestmatchsize));
+ /* Now that we got the right initial segment of BESTMATCH,
+ decode it from the coding system in use. */
+ bestmatch = DECODE_FILE (bestmatch);
+ return bestmatch;
+
quit:
if (d) closedir (d);
Vquit_flag = Qnil;
return Fsignal (Qquit, Qnil);
}
+static int
file_name_completion_stat (dirname, dp, st_addr)
Lisp_Object dirname;
DIRENTRY *dp;
{
Lisp_Object values[12];
Lisp_Object dirname;
+ Lisp_Object encoded;
struct stat s;
struct stat sdir;
char modes[10];
if (!NILP (handler))
return call2 (handler, Qfile_attributes, filename);
- if (lstat (XSTRING (filename)->data, &s) < 0)
+ encoded = ENCODE_FILE (filename);
+
+ if (lstat (XSTRING (encoded)->data, &s) < 0)
return Qnil;
switch (s.st_mode & S_IFMT)
#endif
#ifdef BSD4_2 /* file gid will be dir gid */
dirname = Ffile_name_directory (filename);
- if (! NILP (dirname) && stat (XSTRING (dirname)->data, &sdir) == 0)
+ if (! NILP (dirname))
+ encoded = ENCODE_FILE (dirname);
+ if (! NILP (dirname) && stat (XSTRING (encoded)->data, &sdir) == 0)
values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
else /* if we can't tell, assume worst */
values[9] = Qt;
#ifdef BSD4_3
#undef BSD4_2 /* ok, you can look again without throwing up */
#endif
- values[10] = make_number (s.st_ino);
+ /* Cast -1 to avoid warning if int is not as wide as VALBITS. */
+ if (s.st_ino & (((EMACS_INT) (-1)) << VALBITS))
+ /* To allow inode numbers larger than VALBITS, separate the bottom
+ 16 bits. */
+ values[10] = Fcons (make_number (s.st_ino >> 16),
+ make_number (s.st_ino & 0xffff));
+ else
+ /* But keep the most common cases as integers. */
+ values[10] = make_number (s.st_ino);
values[11] = make_number (s.st_dev);
return Flist (sizeof(values) / sizeof(values[0]), values);
}
\f
+void
syms_of_dired ()
{
Qdirectory_files = intern ("directory-files");