From 080fd64974060e6b47573c94af2b80f1a5f3ef2c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 7 Dec 2013 16:45:31 +0200 Subject: [PATCH] Fixed initialization code and default-printer-name. --- src/callproc.c | 17 +++++--- src/emacs.c | 32 ++++++++++++++- src/w32.c | 53 ++++++++++++++++++++----- src/w32fns.c | 104 +++++++++++++++++++++++++++++++++---------------- 4 files changed, 157 insertions(+), 49 deletions(-) diff --git a/src/callproc.c b/src/callproc.c index 3317c1203bc..2966711978b 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -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)) diff --git a/src/emacs.c b/src/emacs.c index 9f41bc251ea..22be1d82949 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -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"), diff --git a/src/w32.c b/src/w32.c index 0f13703b933..e2649167aee 100644 --- 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. */ @@ -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. */ diff --git a/src/w32fns.c b/src/w32fns.c index 9b630679c39..71ea908374d 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -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)); } -- 2.39.2