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:
Eli Zaretskii 2012-12-24 18:15:13 +02:00
parent 216ed9cc43
commit f5c81c80c1
2 changed files with 123 additions and 46 deletions

View file

@ -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).

View file

@ -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);