]> git.eshelyaron.com Git - emacs.git/commitdiff
Adapted dostounix_filename. w32-short/long-filename work with wide APIs.
authorEli Zaretskii <eliz@gnu.org>
Sat, 2 Nov 2013 13:03:32 +0000 (15:03 +0200)
committerEli Zaretskii <eliz@gnu.org>
Sat, 2 Nov 2013 13:03:32 +0000 (15:03 +0200)
src/emacs.c
src/fileio.c
src/filelock.c
src/msdos.c
src/msdos.h
src/termcap.c
src/unexw32.c
src/w32.c
src/w32.h
src/w32fns.c
src/w32proc.c

index 06b8d290caebcd17ccf92731d591d57857ea52d8..a58829e891841cbbdd0c26fad175e57aa83fbcaf 100644 (file)
@@ -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
index dc6d80932c497ad86dde310a395cfeec2cd0b8c2..eeaa736290ceeec3eadd971aa2712f5e3183aae6 100644 (file)
@@ -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);
index 2f53047f52615dd704a6fa134b855c86444f1c8c..82ffd5d172b1ab65b51685103941aaaae0ddfdc8 100644 (file)
@@ -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);
 
index 2ba7a16a44332ff3ce418c734843713e231e6182..cb4f8c3df89feaf152670eb8ef012ad5eaccef1d 100644 (file)
@@ -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...  */
index 27090324b44e615a99b3f38cbbcd7a0bfb1d24c3..11d7eb5c3e17876810171014802d5e7c8c783d7a 100644 (file)
@@ -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);
index aa225d9b3b138d2133fe59c096b2cae3a3078dda..f081926631854276077574e73b2faf8f14a7ccc4 100644 (file)
@@ -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);
index a01ac7995921bd10d0d6eee0785c24869a2fbf61..5320ec1e37183fb8ea3d65e1157984b194d46663 100644 (file)
@@ -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.  */
index 09d78141e14a206d809545323c5b9b8484613ddf..396a8cdd08b4ef0945337680a80321e3ecc7b795 100644 (file)
--- 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)
 {
index c836937bd6631c42779158a77751ba84a898f8f6..80756e8e4ffff9909c3dc5ea6e0c4d72b11442a6 100644 (file)
--- 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);
index c98c84c8542e816c367a750309fd2c1cab4dbe6a..3e60d68023bfe3ba6e9c299fb2c06bfc535fb4a3 100644 (file)
@@ -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
index ea16f26a0ee4fcc4aaeefaf09a29e70d6c2256b7..89748267bc6ea860a87f7ac87c4d90be69927d00 100644 (file)
@@ -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,