Commit 1fd201bb authored by Eli Zaretskii's avatar Eli Zaretskii

Adapted dostounix_filename. w32-short/long-filename work with wide APIs.

parent 5c4a19a9
......@@ -2153,9 +2153,15 @@ decode_env_path (const char *evarname, const char *defalt)
Lisp_Object lpath, element, tem;
#ifdef WINDOWSNT
bool defaulted = 0;
const char *emacs_dir = egetenv ("emacs_dir");
static const char *emacs_dir_env = "%emacs_dir%/";
const size_t emacs_dir_len = strlen (emacs_dir_env);
const char *edir = egetenv ("emacs_dir");
char emacs_dir[MAX_UTF8_PATH];
/* egetenv looks in process-environment, which holds the variables
in their original system-locale encoding. We need emacs_dir to
be in UTF-8. */
filename_from_ansi (edir, emacs_dir);
#endif
/* It's okay to use getenv here, because this function is only used
......@@ -2176,9 +2182,16 @@ decode_env_path (const char *evarname, const char *defalt)
/* Ensure values from the environment use the proper directory separator. */
if (path)
{
char *path_copy = alloca (strlen (path) + 1);
char *path_copy;
#ifdef WINDOWSNT
path_copy = alloca (MAX_UTF8_PATH);
filename_from_ansi (path, path_copy);
#else /* MSDOS */
path_copy = alloca (strlen (path) + 1);
strcpy (path_copy, path);
dostounix_filename (path_copy, 0);
#endif
dostounix_filename (path_copy);
path = path_copy;
}
#endif
......
......@@ -459,7 +459,8 @@ Given a Unix syntax file name, returns a string ending in slash. */)
strcat (res, "/");
beg = res;
p = beg + strlen (beg);
dostounix_filename (beg, 0);
dostounix_filename (beg);
/* FIXME: Figure out the multibyte vs unibyte stuff here. */
tem_fn = make_specified_string (beg, -1, p - beg,
STRING_MULTIBYTE (filename));
}
......@@ -470,7 +471,7 @@ Given a Unix syntax file name, returns a string ending in slash. */)
else if (STRING_MULTIBYTE (filename))
{
tem_fn = make_specified_string (beg, -1, p - beg, 1);
dostounix_filename (SSDATA (tem_fn), 1);
dostounix_filename (SSDATA (tem_fn));
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
tem_fn = Fdowncase (tem_fn);
......@@ -478,7 +479,7 @@ Given a Unix syntax file name, returns a string ending in slash. */)
}
else
{
dostounix_filename (beg, 0);
dostounix_filename (beg);
tem_fn = make_specified_string (beg, -1, p - beg, 0);
}
return tem_fn;
......@@ -582,7 +583,7 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen,
dst[srclen++] = DIRECTORY_SEP;
dst[srclen] = 0;
#ifdef DOS_NT
dostounix_filename (dst, multibyte);
dostounix_filename (dst);
#endif
return srclen;
}
......@@ -651,7 +652,7 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte)
memcpy (dst, src, srclen);
dst[srclen] = 0;
#ifdef DOS_NT
dostounix_filename (dst, multibyte);
dostounix_filename (dst);
#endif
return srclen;
}
......@@ -1082,7 +1083,8 @@ filesystem tree, not (expand-file-name ".." dirname). */)
#ifdef DOS_NT
/* Make sure directories are all separated with /, but
avoid allocation of a new string when not required. */
dostounix_filename (nm, multibyte);
/* FIXME: Figure out multibyte and downcase here. */
dostounix_filename (nm);
#ifdef WINDOWSNT
if (IS_DIRECTORY_SEP (nm[1]))
{
......@@ -1465,7 +1467,8 @@ filesystem tree, not (expand-file-name ".." dirname). */)
target[1] = ':';
}
result = make_specified_string (target, -1, o - target, multibyte);
dostounix_filename (SSDATA (result), multibyte);
/* FIXME: Figure out the multibyte and downcase here. */
dostounix_filename (SSDATA (result));
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
result = Fdowncase (result);
......@@ -1749,7 +1752,8 @@ those `/' is discarded. */)
nm = xlispstrdupa (filename);
#ifdef DOS_NT
dostounix_filename (nm, multibyte);
/* FIXME: Figure out multibyte and downcase. */
dostounix_filename (nm);
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
#endif
endp = nm + SBYTES (filename);
......
......@@ -689,7 +689,7 @@ lock_file (Lisp_Object fn)
/* Ensure we have only '/' separators, to avoid problems with
looking (inside fill_in_lock_file_name) for backslashes in file
names encoded by some DBCS codepage. */
dostounix_filename (SSDATA (fn), 1);
dostounix_filename (SSDATA (fn));
#endif
encoded_fn = ENCODE_FILE (fn);
......
......@@ -3295,7 +3295,7 @@ void msdos_downcase_filename (unsigned char *);
/* Destructively turn backslashes into slashes. */
void
dostounix_filename (char *p, int ignore)
dostounix_filename (char *p)
{
msdos_downcase_filename (p);
......@@ -3559,7 +3559,7 @@ init_environment (int argc, char **argv, int skip_args)
if (!s) s = "c:/command.com";
t = alloca (strlen (s) + 1);
strcpy (t, s);
dostounix_filename (t, 0);
dostounix_filename (t);
setenv ("SHELL", t, 0);
/* PATH is also downcased and backslashes mirrored. */
......@@ -3569,7 +3569,7 @@ init_environment (int argc, char **argv, int skip_args)
/* Current directory is always considered part of MsDos's path but it is
not normally mentioned. Now it is. */
strcat (strcpy (t, ".;"), s);
dostounix_filename (t, 0); /* Not a single file name, but this should work. */
dostounix_filename (t); /* Not a single file name, but this should work. */
setenv ("PATH", t, 1);
/* In some sense all dos users have root privileges, so... */
......
......@@ -29,7 +29,7 @@ void dos_set_window_size (int *, int *);
int getdefdir (int, char*);
void unixtodos_filename (char *);
void dostounix_filename (char *, int);
void dostounix_filename (char *);
char *rootrelativepath (char *);
void init_environment (int, char **, int);
void internal_terminal_init (void);
......
......@@ -393,7 +393,7 @@ tgetent (char *bp, const char *name)
if (termcap_name && (*termcap_name == '\\'
|| *termcap_name == '/'
|| termcap_name[1] == ':'))
dostounix_filename (termcap_name, 0);
dostounix_filename (termcap_name);
#endif
filep = termcap_name && valid_filename_p (termcap_name);
......
......@@ -728,9 +728,15 @@ unexec (const char *new_name, const char *old_name)
char *q;
/* Ignore old_name, and get our actual location from the OS. */
if (!GetModuleFileName (NULL, in_filename, MAX_PATH))
if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
abort ();
dostounix_filename (in_filename, 0);
/* Can't use dostounix_filename here, since that needs its file name
argument encoded in UTF-8. */
for (p = in_filename; *p; p = CharNextA (p))
if (*p == '\\')
*p = '/';
strcpy (out_filename, in_filename);
/* Change the base of the output filename to match the requested name. */
......
......@@ -1336,7 +1336,7 @@ filename_to_ansi (const char *fn_in, char *fn_out)
return -1;
}
static int
int
filename_from_ansi (const char *fn_in, char *fn_out)
{
wchar_t fn_utf16[MAXPATHLEN];
......@@ -1799,31 +1799,20 @@ max_filename_mbslen (void)
return cp_info.MaxCharSize;
}
/* Normalize filename by converting all path separators to
the specified separator. Also conditionally convert upper
case path name components to lower case. */
/* Normalize filename by converting in-place all of its path
separators to the separator specified by PATH_SEP. */
static void
normalize_filename (register char *fp, char path_sep, int multibyte)
normalize_filename (register char *fp, char path_sep)
{
char sep;
char *elem, *p2;
int dbcs_p = max_filename_mbslen () > 1;
/* Multibyte file names are in the Emacs internal representation, so
we can traverse them by bytes with no problems. */
if (multibyte)
dbcs_p = 0;
char *p2;
/* Always lower-case drive letters a-z, even if the filesystem
preserves case in filenames.
This is so filenames can be compared by string comparison
functions that are case-sensitive. Even case-preserving filesystems
do not distinguish case in drive letters. */
if (dbcs_p)
p2 = CharNextExA (file_name_codepage, fp, 0);
else
p2 = fp + 1;
p2 = fp + 1;
if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
{
......@@ -1831,68 +1820,26 @@ normalize_filename (register char *fp, char path_sep, int multibyte)
fp += 2;
}
if (multibyte || NILP (Vw32_downcase_file_names))
while (*fp)
{
while (*fp)
{
if (*fp == '/' || *fp == '\\')
*fp = path_sep;
if (!dbcs_p)
fp++;
else
fp = CharNextExA (file_name_codepage, fp, 0);
}
return;
if (*fp == '/' || *fp == '\\')
*fp = path_sep;
fp++;
}
sep = path_sep; /* convert to this path separator */
elem = fp; /* start of current path element */
do {
if (*fp >= 'a' && *fp <= 'z')
elem = 0; /* don't convert this element */
if (*fp == 0 || *fp == ':')
{
sep = *fp; /* restore current separator (or 0) */
*fp = '/'; /* after conversion of this element */
}
if (*fp == '/' || *fp == '\\')
{
if (elem && elem != fp)
{
*fp = 0; /* temporary end of string */
_mbslwr (elem); /* while we convert to lower case */
}
*fp = sep; /* convert (or restore) path separator */
elem = fp + 1; /* next element starts after separator */
sep = path_sep;
}
if (*fp)
{
if (!dbcs_p)
fp++;
else
fp = CharNextExA (file_name_codepage, fp, 0);
}
} while (*fp);
}
/* Destructively turn backslashes into slashes. MULTIBYTE non-zero
means the file name is a multibyte string in Emacs's internal
representation. */
/* Destructively turn backslashes into slashes. */
void
dostounix_filename (register char *p, int multibyte)
dostounix_filename (register char *p)
{
normalize_filename (p, '/', multibyte);
normalize_filename (p, '/');
}
/* Destructively turn slashes into backslashes. */
void
unixtodos_filename (register char *p)
{
normalize_filename (p, '\\', 0);
normalize_filename (p, '\\');
}
/* Remove all CR's that are followed by a LF.
......@@ -1943,17 +1890,13 @@ parse_root (char * name, char ** pPath)
else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
{
int slashes = 2;
int dbcs_p = max_filename_mbslen () > 1;
name += 2;
do
{
if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break;
if (dbcs_p)
name = CharNextExA (file_name_codepage, name, 0);
else
name++;
name++;
}
while ( *name );
if (IS_DIRECTORY_SEP (name[0]))
......@@ -1970,23 +1913,44 @@ parse_root (char * name, char ** pPath)
static int
get_long_basename (char * name, char * buf, int size)
{
WIN32_FIND_DATA find_data;
HANDLE dir_handle;
char fname_utf8[MAX_UTF8_PATH];
int len = 0;
int cstatus;
/* must be valid filename, no wild cards or other invalid characters */
if (_mbspbrk (name, "*?|<>\""))
/* Must be valid filename, no wild cards or other invalid characters. */
if (strpbrk (name, "*?|<>\""))
return 0;
dir_handle = FindFirstFile (name, &find_data);
if (dir_handle != INVALID_HANDLE_VALUE)
if (w32_unicode_filenames)
{
if ((len = strlen (find_data.cFileName)) < size)
memcpy (buf, find_data.cFileName, len + 1);
else
len = 0;
FindClose (dir_handle);
wchar_t fname_utf16[MAX_PATH];
WIN32_FIND_DATAW find_data_wide;
filename_to_utf16 (name, fname_utf16);
dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
if (dir_handle != INVALID_HANDLE_VALUE)
cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
}
else
{
char fname_ansi[MAX_PATH];
WIN32_FIND_DATAA find_data_ansi;
filename_to_ansi (name, fname_ansi);
dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
if (dir_handle != INVALID_HANDLE_VALUE)
cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
}
if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
memcpy (buf, fname_utf8, len + 1);
else
len = 0;
if (dir_handle != INVALID_HANDLE_VALUE)
FindClose (dir_handle);
return len;
}
......@@ -1997,11 +1961,11 @@ w32_get_long_filename (char * name, char * buf, int size)
char * o = buf;
char * p;
char * q;
char full[ MAX_PATH ];
char full[ MAX_UTF8_PATH ];
int len;
len = strlen (name);
if (len >= MAX_PATH)
if (len >= MAX_UTF8_PATH)
return FALSE;
/* Use local copy for destructive modification. */
......@@ -2018,7 +1982,7 @@ w32_get_long_filename (char * name, char * buf, int size)
while (p != NULL && *p)
{
q = p;
p = _mbschr (q, '\\');
p = strchr (q, '\\');
if (p) *p = '\0';
len = get_long_basename (full, o, size);
if (len > 0)
......@@ -2042,6 +2006,29 @@ w32_get_long_filename (char * name, char * buf, int size)
return TRUE;
}
unsigned int
w32_get_short_filename (char * name, char * buf, int size)
{
if (w32_unicode_filenames)
{
wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
unsigned int retval;
filename_to_utf16 (name, name_utf16);
retval = GetShortPathNameW (name_utf16, short_name, size);
if (retval && retval < size)
filename_from_utf16 (short_name, buf);
return retval;
}
else
{
char name_ansi[MAX_PATH];
filename_to_ansi (name, name_ansi);
return GetShortPathNameA (name_ansi, buf, size);
}
}
static int
is_unc_volume (const char *filename)
{
......@@ -2506,7 +2493,7 @@ emacs_root_dir (void)
emacs_abort ();
strcpy (root_dir, p);
root_dir[parse_root (root_dir, NULL)] = '\0';
dostounix_filename (root_dir, 0);
dostounix_filename (root_dir);
return root_dir;
}
......@@ -3937,49 +3924,6 @@ convert_from_time_t (time_t time, FILETIME * pft)
pft->dwLowDateTime = tmp.LowPart;
}
#if 0
/* No reason to keep this; faking inode values either by hashing or even
using the file index from GetInformationByHandle, is not perfect and
so by default Emacs doesn't use the inode values on Windows.
Instead, we now determine file-truename correctly (except for
possible drive aliasing etc). */
/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
static unsigned
hashval (const unsigned char * str)
{
unsigned h = 0;
while (*str)
{
h = (h << 4) + *str++;
h ^= (h >> 28);
}
return h;
}
/* Return the hash value of the canonical pathname, excluding the
drive/UNC header, to get a hopefully unique inode number. */
static DWORD
generate_inode_val (const char * name)
{
char fullname[ MAX_PATH ];
char * p;
unsigned hash;
/* Get the truly canonical filename, if it exists. (Note: this
doesn't resolve aliasing due to subst commands, or recognize hard
links. */
if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
emacs_abort ();
parse_root (fullname, &p);
/* Normal W32 filesystems are still case insensitive. */
_strlwr (p);
return hashval (p);
}
#endif
static PSECURITY_DESCRIPTOR
get_file_security_desc_by_handle (HANDLE h)
{
......
......@@ -152,6 +152,9 @@ extern int w32_valid_pointer_p (void *, int);
/* Get long (aka "true") form of file name, if it exists. */
extern BOOL w32_get_long_filename (char * name, char * buf, int size);
/* Get the short (a.k.a. "8+3") form of a file name. */
extern unsigned int w32_get_short_filename (char *, char *, int);
/* Prepare our standard handles for proper inheritance by child processes. */
extern void prepare_standard_handles (int in, int out,
int err, HANDLE handles[4]);
......@@ -181,8 +184,10 @@ extern void init_environment (char **);
extern void check_windows_init_file (void);
extern void syms_of_ntproc (void);
extern void syms_of_ntterm (void);
extern void dostounix_filename (register char *, int);
extern void dostounix_filename (register char *);
extern void unixtodos_filename (register char *);
extern int filename_from_ansi (const char *, char *);
extern BOOL init_winsock (int load_now);
extern void srandom (int);
extern int random (void);
......
......@@ -6466,8 +6466,8 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
#ifdef NTGUI_UNICODE
filename = from_unicode_buffer (filename_buf);
#else /* !NTGUI_UNICODE */
dostounix_filename (filename_buf, 0);
filename = DECODE_FILE (build_string (filename_buf));
filename = DECODE_FILE (build_unibyte_string (filename_buf));
dostounix_filename (SSDATA (filename));
#endif /* NTGUI_UNICODE */
#ifdef CYGWIN
......
......@@ -2647,10 +2647,11 @@ All path elements in FILENAME are converted to their short names. */)
filename = Fexpand_file_name (filename, Qnil);
/* luckily, this returns the short version of each element in the path. */
if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0)
if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)),
shortname, MAX_PATH) == 0)
return Qnil;
dostounix_filename (shortname, 0);
dostounix_filename (shortname);
/* No need to DECODE_FILE, because 8.3 names are pure ASCII. */
return build_string (shortname);
......@@ -2664,7 +2665,7 @@ If FILENAME does not exist, return nil.
All path elements in FILENAME are converted to their long names. */)
(Lisp_Object filename)
{
char longname[ MAX_PATH ];
char longname[ MAX_UTF8_PATH ];
int drive_only = 0;
CHECK_STRING (filename);
......@@ -2676,10 +2677,11 @@ All path elements in FILENAME are converted to their long names. */)
/* first expand it. */
filename = Fexpand_file_name (filename, Qnil);
if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH))
if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname,
MAX_UTF8_PATH))
return Qnil;
dostounix_filename (longname, 0);
dostounix_filename (longname);
/* If we were passed only a drive, make sure that a slash is not appended
for consistency with directories. Allow for drive mapping via SUBST
......@@ -2687,7 +2689,7 @@ All path elements in FILENAME are converted to their long names. */)
if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
longname[2] = '\0';
return DECODE_FILE (build_string (longname));
return DECODE_FILE (build_unibyte_string (longname));
}
DEFUN ("w32-set-process-priority", Fw32_set_process_priority,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment