Fixed initialization code and default-printer-name.
authorEli Zaretskii <eliz@gnu.org>
Sat, 7 Dec 2013 14:45:31 +0000 (16:45 +0200)
committerEli Zaretskii <eliz@gnu.org>
Sat, 7 Dec 2013 14:45:31 +0000 (16:45 +0200)
src/callproc.c
src/emacs.c
src/w32.c
src/w32fns.c

index 3317c12..2966711 100644 (file)
@@ -1606,17 +1606,24 @@ init_callproc (void)
      source directory.  */
   if (data_dir == 0)
     {
-      Lisp_Object tem, tem1, srcdir;
+      Lisp_Object tem, tem1, tem2, srcdir;
+#ifdef WINDOWSNT
+      /* PATH_DUMPLOADSEARCH is in ANSI codepage; convert to UTF-8.  */
+      char dumpload_dir[MAX_UTF8_PATH];
+
+      filename_from_ansi (PATH_DUMPLOADSEARCH, dumpload_dir);
+      tem2 = build_unibyte_string (dumpload_dir);
+#else
+      tem2 = build_unibyte_string (PATH_DUMPLOADSEARCH);
+#endif
 
-      srcdir = Fexpand_file_name (build_string ("../src/"),
-                                 build_unibyte_string (PATH_DUMPLOADSEARCH));
+      srcdir = Fexpand_file_name (build_string ("../src/"), tem2);
       tem = Fexpand_file_name (build_string ("GNU"), Vdata_directory);
       tem1 = Ffile_exists_p (tem);
       if (!NILP (Fequal (srcdir, Vinvocation_directory)) || NILP (tem1))
        {
          Lisp_Object newdir;
-         newdir = Fexpand_file_name (build_string ("../etc/"),
-                                     build_unibyte_string (PATH_DUMPLOADSEARCH));
+         newdir = Fexpand_file_name (build_string ("../etc/"), tem2);
          tem = Fexpand_file_name (build_string ("GNU"), newdir);
          tem1 = Ffile_exists_p (tem);
          if (!NILP (tem1))
index 9f41bc2..22be1d8 100644 (file)
@@ -394,7 +394,20 @@ init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
   initial_argv = argv;
   initial_argc = argc;
 
+#ifdef WINDOWSNT
+  /* Must use argv[0] converted to UTF-8, as it begets many standard
+     file and directory names.  */
+  {
+    char argv0[MAX_UTF8_PATH];
+
+    if (filename_from_ansi (argv[0], argv0) == 0)
+      raw_name = build_unibyte_string (argv0);
+    else
+      raw_name = build_unibyte_string (argv[0]);
+  }
+#else
   raw_name = build_unibyte_string (argv[0]);
+#endif
 
   /* Add /: to the front of the name
      if it would otherwise be treated as magic.  */
@@ -796,6 +809,14 @@ main (int argc, char **argv)
 
   if (argmatch (argv, argc, "-chdir", "--chdir", 4, &ch_to_dir, &skip_args))
     {
+#ifdef WINDOWSNT
+      /* argv[] array is kept in its original ANSI codepage encoding,
+        we need to convert to UTF-8, for chdir to work.  */
+      char newdir[MAX_UTF8_PATH];
+
+      filename_from_ansi (ch_to_dir, newdir);
+      ch_to_dir = newdir;
+#endif
       original_pwd = get_current_dir_name ();
       if (chdir (ch_to_dir) != 0)
         {
@@ -1531,7 +1552,16 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
       char *file;
       /* Handle -l loadup, args passed by Makefile.  */
       if (argmatch (argv, argc, "-l", "--load", 3, &file, &skip_args))
-       Vtop_level = list2 (intern_c_string ("load"), build_string (file));
+       {
+#ifdef WINDOWSNT
+         char file_utf8[MAX_UTF8_PATH];
+
+         if (filename_from_ansi (file, file_utf8) == 0)
+           file = file_utf8;
+#endif
+         Vtop_level = list2 (intern_c_string ("load"),
+                             build_unibyte_string (file));
+       }
       /* Unless next switch is -nl, load "loadup.el" first thing.  */
       if (! no_loadup)
        Vtop_level = list2 (intern_c_string ("load"),
index 0f13703..e264916 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1333,7 +1333,8 @@ w32_valid_pointer_p (void *p, int size)
    encoding when w32-unicode-filenames is t; this is similar to
    selection-coding-system.
 
-   This arrangement works very well, but it has a few gotchas:
+   This arrangement works very well, but it has a few gotchas and
+   limitations:
 
    . Lisp code that encodes or decodes file names manually should
      normally use 'utf-8' as the coding-system on Windows,
@@ -1351,6 +1352,12 @@ w32_valid_pointer_p (void *p, int size)
      name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
      through some shadowing function defined here.
 
+   . Environment variables stored in Vprocess_environment are encoded
+     in the ANSI codepage, so if getenv/egetenv is used for a variable
+     whose value is a file name or a list of directories, it needs to
+     be converted to UTF-8, before it is used as argument to functions
+     or decoded into a Lisp string.
+
    . File names passed to external libraries, like the image libraries
      and GnuTLS, need special handling.  These libraries generally
      don't support UTF-16 or UTF-8 file names, so they must get file
@@ -1378,7 +1385,12 @@ w32_valid_pointer_p (void *p, int size)
    . For similar reasons, server.el and emacsclient are also limited
      to the current ANSI codepage for now.
 
-*/
+   . Emacs itself can only handle command-line arguments encoded in
+     the current codepage.
+
+   . Turning on w32-unicode-filename on Windows 9X (if it at all
+     works) requires UNICOWS.DLL, which is currently loaded only in a
+     GUI session.  */
 
 \f
 
@@ -2365,6 +2377,8 @@ w32_get_resource (char *key, LPDWORD lpdwtype)
   return (NULL);
 }
 
+/* The argv[] array holds ANSI-encoded strings, and so this function
+   works with ANS_encoded strings.  */
 void
 init_environment (char ** argv)
 {
@@ -2508,7 +2522,7 @@ init_environment (char ** argv)
       char *p;
       char modname[MAX_PATH];
 
-      if (!GetModuleFileName (NULL, modname, MAX_PATH))
+      if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
        emacs_abort ();
       if ((p = _mbsrchr (modname, '\\')) == NULL)
        emacs_abort ();
@@ -2672,7 +2686,7 @@ init_environment (char ** argv)
   {
     static char modname[MAX_PATH];
 
-    if (!GetModuleFileName (NULL, modname, MAX_PATH))
+    if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
       emacs_abort ();
     argv[0] = modname;
   }
@@ -8434,10 +8448,10 @@ check_windows_init_file (void)
 
       /* Implementation note: this function runs early during Emacs
         startup, before startup.el is run.  So Vload_path is still in
-        its initial unibyte form, holding ANSI-encoded file names.
-        That is why we never bother to ENCODE_FILE here, nor use wide
-        APIs for file names: we will never get UTF-8 encoded file
-        names here.  */
+        its initial unibyte form, but it holds UTF-8 encoded file
+        names, since init_callproc was already called.  So we do not
+        need to ENCODE_FILE here, but we do need to convert the file
+        names from UTF-8 to ANSI.  */
       init_file = build_string ("term/w32-win");
       fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
       if (fd < 0)
@@ -8448,6 +8462,8 @@ check_windows_init_file (void)
          char *buffer = alloca (1024
                                 + strlen (init_file_name)
                                 + strlen (load_path));
+         char *msg = buffer;
+         int needed;
 
          sprintf (buffer,
                   "The Emacs Windows initialization file \"%s.el\" "
@@ -8459,8 +8475,27 @@ check_windows_init_file (void)
                   "not unpacked properly.\nSee the README.W32 file in the "
                   "top-level Emacs directory for more information.",
                   init_file_name, load_path);
+         needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
+                                       -1, NULL, 0);
+         if (needed > 0)
+           {
+             wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
+
+             MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
+                                  msg_w, needed);
+             needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
+                                           NULL, 0, NULL, NULL);
+             if (needed > 0)
+               {
+                 char *msg_a = alloca (needed + 1);
+
+                 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
+                                      NULL, NULL);
+                 msg = msg_a;
+               }
+           }
          MessageBox (NULL,
-                     buffer,
+                     msg,
                      "Emacs Abort Dialog",
                      MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
          /* Use the low-level system abort. */
index 9b63067..71ea908 100644 (file)
@@ -7428,8 +7428,11 @@ DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
   static char pname_buf[256];
   int err;
   HANDLE hPrn;
-  PRINTER_INFO_2 *ppi2 = NULL;
+  PRINTER_INFO_2W *ppi2w = NULL;
+  PRINTER_INFO_2A *ppi2a = NULL;
   DWORD dwNeeded = 0, dwReturned = 0;
+  char server_name[MAX_UTF8_PATH], share_name[MAX_UTF8_PATH];
+  char port_name[MAX_UTF8_PATH];
 
   /* Retrieve the default string from Win.ini (the registry).
    * String will be in form "printername,drivername,portname".
@@ -7441,54 +7444,87 @@ DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
   /* We want to know more than the printer name */
   if (!OpenPrinter (pname_buf, &hPrn, NULL))
     return Qnil;
-  GetPrinter (hPrn, 2, NULL, 0, &dwNeeded);
+  /* GetPrinterW is not supported by unicows.dll.  */
+  if (w32_unicode_filenames && os_subtype != OS_9X)
+    GetPrinterW (hPrn, 2, NULL, 0, &dwNeeded);
+  else
+    GetPrinterA (hPrn, 2, NULL, 0, &dwNeeded);
   if (dwNeeded == 0)
     {
       ClosePrinter (hPrn);
       return Qnil;
     }
-  /* Allocate memory for the PRINTER_INFO_2 struct */
-  ppi2 = xmalloc (dwNeeded);
-  if (!ppi2)
+  /* Call GetPrinter again with big enough memory block.  */
+  if (w32_unicode_filenames && os_subtype != OS_9X)
     {
+      /* Allocate memory for the PRINTER_INFO_2 struct.  */
+      ppi2w = xmalloc (dwNeeded);
+      err = GetPrinterW (hPrn, 2, (LPBYTE)ppi2w, dwNeeded, &dwReturned);
       ClosePrinter (hPrn);
-      return Qnil;
+      if (!err)
+       {
+         xfree (ppi2w);
+         return Qnil;
+       }
+
+      if ((ppi2w->Attributes & PRINTER_ATTRIBUTE_SHARED)
+         && ppi2w->pServerName)
+       {
+         filename_from_utf16 (ppi2w->pServerName, server_name);
+         filename_from_utf16 (ppi2w->pShareName, share_name);
+       }
+      else
+       {
+         server_name[0] = '\0';
+         filename_from_utf16 (ppi2w->pPortName, port_name);
+       }
     }
-  /* Call GetPrinter again with big enough memory block.  */
-  err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
-  ClosePrinter (hPrn);
-  if (!err)
+  else
     {
-      xfree (ppi2);
-      return Qnil;
-    }
+      ppi2a = xmalloc (dwNeeded);
+      err = GetPrinterA (hPrn, 2, (LPBYTE)ppi2a, dwNeeded, &dwReturned);
+      ClosePrinter (hPrn);
+      if (!err)
+       {
+         xfree (ppi2a);
+         return Qnil;
+       }
 
-  if (ppi2)
-    {
-      if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName)
-        {
-         /* a remote printer */
-         if (*ppi2->pServerName == '\\')
-           snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
-                      ppi2->pShareName);
-         else
-           snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
-                      ppi2->pShareName);
-         pname_buf[sizeof (pname_buf) - 1] = '\0';
+      if ((ppi2a->Attributes & PRINTER_ATTRIBUTE_SHARED)
+         && ppi2a->pServerName)
+       {
+         filename_from_ansi (ppi2a->pServerName, server_name);
+         filename_from_ansi (ppi2a->pShareName, share_name);
        }
       else
-        {
-         /* a local printer */
-         strncpy (pname_buf, ppi2->pPortName, sizeof (pname_buf));
-         pname_buf[sizeof (pname_buf) - 1] = '\0';
-         /* `pPortName' can include several ports, delimited by ','.
-          * we only use the first one. */
-         strtok (pname_buf, ",");
+       {
+         server_name[0] = '\0';
+         filename_from_ansi (ppi2a->pPortName, port_name);
        }
-      xfree (ppi2);
     }
 
-  return build_string (pname_buf);
+  if (server_name[0])
+    {
+      /* a remote printer */
+      if (server_name[0] == '\\')
+       snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", server_name,
+                 share_name);
+      else
+       snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", server_name,
+                 share_name);
+      pname_buf[sizeof (pname_buf) - 1] = '\0';
+    }
+  else
+    {
+      /* a local printer */
+      strncpy (pname_buf, port_name, sizeof (pname_buf));
+      pname_buf[sizeof (pname_buf) - 1] = '\0';
+      /* `pPortName' can include several ports, delimited by ','.
+       * we only use the first one. */
+      strtok (pname_buf, ",");
+    }
+
+  return DECODE_FILE (build_unibyte_string (pname_buf));
 }
 \f