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))
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. */
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)
{
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"),
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,
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
. 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
return (NULL);
}
+/* The argv[] array holds ANSI-encoded strings, and so this function
+ works with ANS_encoded strings. */
void
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 ();
{
static char modname[MAX_PATH];
- if (!GetModuleFileName (NULL, modname, MAX_PATH))
+ if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
emacs_abort ();
argv[0] = modname;
}
/* 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)
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\" "
"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. */
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".
/* 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