diff options
-rw-r--r-- | src/emacs.c | 19 | ||||
-rw-r--r-- | src/fileio.c | 20 | ||||
-rw-r--r-- | src/filelock.c | 2 | ||||
-rw-r--r-- | src/msdos.c | 6 | ||||
-rw-r--r-- | src/msdos.h | 2 | ||||
-rw-r--r-- | src/termcap.c | 2 | ||||
-rw-r--r-- | src/unexw32.c | 10 | ||||
-rw-r--r-- | src/w32.c | 202 | ||||
-rw-r--r-- | src/w32.h | 7 | ||||
-rw-r--r-- | src/w32fns.c | 4 | ||||
-rw-r--r-- | src/w32proc.c | 14 |
11 files changed, 131 insertions, 157 deletions
diff --git a/src/emacs.c b/src/emacs.c index 06b8d290cae..a58829e8918 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -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 diff --git a/src/fileio.c b/src/fileio.c index dc6d80932c4..eeaa736290c 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -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); diff --git a/src/filelock.c b/src/filelock.c index 2f53047f526..82ffd5d172b 100644 --- a/src/filelock.c +++ b/src/filelock.c @@ -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); diff --git a/src/msdos.c b/src/msdos.c index 2ba7a16a443..cb4f8c3df89 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -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... */ diff --git a/src/msdos.h b/src/msdos.h index 27090324b44..11d7eb5c3e1 100644 --- a/src/msdos.h +++ b/src/msdos.h @@ -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); diff --git a/src/termcap.c b/src/termcap.c index aa225d9b3b1..f0819266318 100644 --- a/src/termcap.c +++ b/src/termcap.c @@ -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); diff --git a/src/unexw32.c b/src/unexw32.c index a01ac799592..5320ec1e371 100644 --- a/src/unexw32.c +++ b/src/unexw32.c @@ -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. */ diff --git a/src/w32.c b/src/w32.c index 09d78141e14..396a8cdd08b 100644 --- a/src/w32.c +++ b/src/w32.c @@ -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) { diff --git a/src/w32.h b/src/w32.h index c836937bd66..80756e8e4ff 100644 --- a/src/w32.h +++ b/src/w32.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); diff --git a/src/w32fns.c b/src/w32fns.c index c98c84c8542..3e60d68023b 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -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 diff --git a/src/w32proc.c b/src/w32proc.c index ea16f26a0ee..89748267bc6 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -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, |