Fix bug #13262 with crashes in completion on MS-Windows with non-ASCII filenames.
src/fileio.c (file_name_as_directory, directory_file_name): Accept an additional argument MULTIBYTE to indicate whether the input C came from a multibyte or a unibyte Lisp string; all callers adjusted. Don't assume the input string is always multibyte. (Ffile_name_directory) [DOS_NT]: Handle unibyte strings correctly: don't ENCODE_FILE them, and return a unibyte string if the input was unibyte. (Fexpand_file_name): Don't mix unibyte with multibyte strings, and don't assume the input strings will always be multibyte. If the input strings are multibyte, decode strings obtained from C library functions.
This commit is contained in:
parent
216ed9cc43
commit
f5c81c80c1
2 changed files with 123 additions and 46 deletions
|
@ -1,3 +1,18 @@
|
|||
2012-12-24 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* fileio.c (file_name_as_directory, directory_file_name): Accept
|
||||
an additional argument MULTIBYTE to indicate whether the input C
|
||||
came from a multibyte or a unibyte Lisp string; all callers
|
||||
adjusted. Don't assume the input string is always multibyte.
|
||||
(Bug#13262)
|
||||
(Ffile_name_directory) [DOS_NT]: Handle unibyte strings correctly:
|
||||
don't ENCODE_FILE them, and return a unibyte string if the input
|
||||
was unibyte.
|
||||
(Fexpand_file_name): Don't mix unibyte with multibyte strings, and
|
||||
don't assume the input strings will always be multibyte. If the
|
||||
input strings are multibyte, decode strings obtained from C
|
||||
library functions.
|
||||
|
||||
2012-12-22 Martin Rudalics <rudalics@gmx.at>
|
||||
|
||||
* window.c (Fselect_window): Reword doc-string (Bug#13248).
|
||||
|
|
154
src/fileio.c
154
src/fileio.c
|
@ -373,12 +373,26 @@ Given a Unix syntax file name, returns a string ending in slash. */)
|
|||
strcat (res, "/");
|
||||
beg = res;
|
||||
p = beg + strlen (beg);
|
||||
dostounix_filename (beg);
|
||||
tem_fn = make_specified_string (beg, -1, p - beg,
|
||||
STRING_MULTIBYTE (filename));
|
||||
}
|
||||
else
|
||||
tem_fn = make_specified_string (beg - 2, -1, p - beg + 2,
|
||||
STRING_MULTIBYTE (filename));
|
||||
}
|
||||
tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg,
|
||||
STRING_MULTIBYTE (filename)));
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
return DECODE_FILE (tem_fn);
|
||||
else if (STRING_MULTIBYTE (filename))
|
||||
{
|
||||
tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg, 1));
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
tem_fn = DECODE_FILE (tem_fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
dostounix_filename (beg);
|
||||
tem_fn = make_specified_string (beg, -1, p - beg, 0);
|
||||
}
|
||||
return tem_fn;
|
||||
#else /* DOS_NT */
|
||||
return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
|
||||
#endif /* DOS_NT */
|
||||
|
@ -453,12 +467,14 @@ get a current directory to run processes in. */)
|
|||
return Ffile_name_directory (filename);
|
||||
}
|
||||
|
||||
/* Convert from file name SRC of length SRCLEN to directory name
|
||||
in DST. On UNIX, just make sure there is a terminating /.
|
||||
Return the length of DST in bytes. */
|
||||
/* Convert from file name SRC of length SRCLEN to directory name in
|
||||
DST. MULTIBYTE non-zero means the file name in SRC is a multibyte
|
||||
string. On UNIX, just make sure there is a terminating /. Return
|
||||
the length of DST in bytes. */
|
||||
|
||||
static ptrdiff_t
|
||||
file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen)
|
||||
file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen,
|
||||
bool multibyte)
|
||||
{
|
||||
if (srclen == 0)
|
||||
{
|
||||
|
@ -477,14 +493,17 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen)
|
|||
srclen++;
|
||||
}
|
||||
#ifdef DOS_NT
|
||||
{
|
||||
Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
|
||||
if (multibyte)
|
||||
{
|
||||
Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
|
||||
|
||||
tem_fn = ENCODE_FILE (tem_fn);
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
tem_fn = DECODE_FILE (tem_fn);
|
||||
memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
|
||||
}
|
||||
tem_fn = ENCODE_FILE (tem_fn);
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
tem_fn = DECODE_FILE (tem_fn);
|
||||
memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
|
||||
}
|
||||
else
|
||||
dostounix_filename (dst);
|
||||
#endif
|
||||
return srclen;
|
||||
}
|
||||
|
@ -520,16 +539,18 @@ For a Unix-syntax file name, just appends a slash. */)
|
|||
}
|
||||
|
||||
buf = alloca (SBYTES (file) + 10);
|
||||
length = file_name_as_directory (buf, SSDATA (file), SBYTES (file));
|
||||
length = file_name_as_directory (buf, SSDATA (file), SBYTES (file),
|
||||
STRING_MULTIBYTE (file));
|
||||
return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file));
|
||||
}
|
||||
|
||||
/* Convert from directory name SRC of length SRCLEN to
|
||||
file name in DST. On UNIX, just make sure there isn't
|
||||
a terminating /. Return the length of DST in bytes. */
|
||||
/* Convert from directory name SRC of length SRCLEN to file name in
|
||||
DST. MULTIBYTE non-zero means the file name in SRC is a multibyte
|
||||
string. On UNIX, just make sure there isn't a terminating /.
|
||||
Return the length of DST in bytes. */
|
||||
|
||||
static ptrdiff_t
|
||||
directory_file_name (char *dst, char *src, ptrdiff_t srclen)
|
||||
directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte)
|
||||
{
|
||||
/* Process as Unix format: just remove any final slash.
|
||||
But leave "/" unchanged; do not change it to "". */
|
||||
|
@ -545,14 +566,17 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen)
|
|||
srclen--;
|
||||
}
|
||||
#ifdef DOS_NT
|
||||
{
|
||||
Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
|
||||
if (multibyte)
|
||||
{
|
||||
Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
|
||||
|
||||
tem_fn = ENCODE_FILE (tem_fn);
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
tem_fn = DECODE_FILE (tem_fn);
|
||||
memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
|
||||
}
|
||||
tem_fn = ENCODE_FILE (tem_fn);
|
||||
dostounix_filename (SSDATA (tem_fn));
|
||||
tem_fn = DECODE_FILE (tem_fn);
|
||||
memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
|
||||
}
|
||||
else
|
||||
dostounix_filename (dst);
|
||||
#endif
|
||||
return srclen;
|
||||
}
|
||||
|
@ -588,7 +612,8 @@ In Unix-syntax, this function just removes the final slash. */)
|
|||
}
|
||||
|
||||
buf = alloca (SBYTES (directory) + 20);
|
||||
length = directory_file_name (buf, SSDATA (directory), SBYTES (directory));
|
||||
length = directory_file_name (buf, SSDATA (directory), SBYTES (directory),
|
||||
STRING_MULTIBYTE (directory));
|
||||
return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory));
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1063,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
/* `egetenv' may return a unibyte string, which will bite us since
|
||||
we expect the directory to be multibyte. */
|
||||
tem = build_string (newdir);
|
||||
if (!STRING_MULTIBYTE (tem))
|
||||
if (multibyte && !STRING_MULTIBYTE (tem))
|
||||
{
|
||||
hdir = DECODE_FILE (tem);
|
||||
newdir = SSDATA (hdir);
|
||||
|
@ -1060,7 +1085,18 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
unblock_input ();
|
||||
if (pw)
|
||||
{
|
||||
Lisp_Object tem;
|
||||
|
||||
newdir = pw->pw_dir;
|
||||
/* `getpwnam' may return a unibyte string, which will
|
||||
bite us since we expect the directory to be
|
||||
multibyte. */
|
||||
tem = build_string (newdir);
|
||||
if (multibyte && !STRING_MULTIBYTE (tem))
|
||||
{
|
||||
hdir = DECODE_FILE (tem);
|
||||
newdir = SSDATA (hdir);
|
||||
}
|
||||
nm = p;
|
||||
#ifdef DOS_NT
|
||||
collapse_newdir = 0;
|
||||
|
@ -1084,6 +1120,13 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
adir = alloca (MAXPATHLEN + 1);
|
||||
if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
|
||||
adir = NULL;
|
||||
else if (multibyte)
|
||||
{
|
||||
Lisp_Object tem = build_string (adir);
|
||||
|
||||
tem = DECODE_FILE (tem);
|
||||
memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
|
||||
}
|
||||
}
|
||||
if (!adir)
|
||||
{
|
||||
|
@ -1142,6 +1185,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
indirectly by prepending newdir to nm if necessary, and using
|
||||
cwd (or the wd of newdir's drive) as the new newdir. */
|
||||
char *adir;
|
||||
|
||||
if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
|
||||
{
|
||||
drive = (unsigned char) newdir[0];
|
||||
|
@ -1151,7 +1195,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
{
|
||||
ptrdiff_t newlen = strlen (newdir);
|
||||
char *tmp = alloca (newlen + strlen (nm) + 2);
|
||||
file_name_as_directory (tmp, newdir, newlen);
|
||||
file_name_as_directory (tmp, newdir, newlen, multibyte);
|
||||
strcat (tmp, nm);
|
||||
nm = tmp;
|
||||
}
|
||||
|
@ -1159,10 +1203,17 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
if (drive)
|
||||
{
|
||||
if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
|
||||
newdir = "/";
|
||||
strcpy (adir, "/");
|
||||
}
|
||||
else
|
||||
getwd (adir);
|
||||
if (multibyte)
|
||||
{
|
||||
Lisp_Object tem = build_string (adir);
|
||||
|
||||
tem = DECODE_FILE (tem);
|
||||
memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
|
||||
}
|
||||
newdir = adir;
|
||||
}
|
||||
|
||||
|
@ -1249,7 +1300,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
strcpy (target, newdir);
|
||||
}
|
||||
else
|
||||
file_name_as_directory (target, newdir, length);
|
||||
file_name_as_directory (target, newdir, length, multibyte);
|
||||
}
|
||||
|
||||
strcat (target, nm);
|
||||
|
@ -1335,9 +1386,14 @@ filesystem tree, not (expand-file-name ".." dirname). */)
|
|||
target[1] = ':';
|
||||
}
|
||||
result = make_specified_string (target, -1, o - target, multibyte);
|
||||
result = ENCODE_FILE (result);
|
||||
dostounix_filename (SSDATA (result));
|
||||
result = DECODE_FILE (result);
|
||||
if (multibyte)
|
||||
{
|
||||
result = ENCODE_FILE (result);
|
||||
dostounix_filename (SSDATA (result));
|
||||
result = DECODE_FILE (result);
|
||||
}
|
||||
else
|
||||
dostounix_filename (SSDATA (result));
|
||||
#else /* !DOS_NT */
|
||||
result = make_specified_string (target, -1, o - target, multibyte);
|
||||
#endif /* !DOS_NT */
|
||||
|
@ -1619,18 +1675,24 @@ those `/' is discarded. */)
|
|||
memcpy (nm, SDATA (filename), SBYTES (filename) + 1);
|
||||
|
||||
#ifdef DOS_NT
|
||||
{
|
||||
Lisp_Object encoded_filename = ENCODE_FILE (filename);
|
||||
Lisp_Object tem_fn;
|
||||
if (multibyte)
|
||||
{
|
||||
Lisp_Object encoded_filename = ENCODE_FILE (filename);
|
||||
Lisp_Object tem_fn;
|
||||
|
||||
dostounix_filename (SDATA (encoded_filename));
|
||||
tem_fn = DECODE_FILE (encoded_filename);
|
||||
nm = alloca (SBYTES (tem_fn) + 1);
|
||||
memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1);
|
||||
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
|
||||
if (substituted)
|
||||
filename = tem_fn;
|
||||
}
|
||||
dostounix_filename (SDATA (encoded_filename));
|
||||
tem_fn = DECODE_FILE (encoded_filename);
|
||||
nm = alloca (SBYTES (tem_fn) + 1);
|
||||
memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1);
|
||||
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
|
||||
if (substituted)
|
||||
filename = tem_fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
dostounix_filename (nm);
|
||||
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
|
||||
}
|
||||
#endif
|
||||
endp = nm + SBYTES (filename);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue