/* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
-Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
+Copyright (C) 1994-1995, 2000-2014 Free Software Foundation, Inc.
This file is part of GNU Emacs.
PIP_ADAPTER_INFO pAdapterInfo,
PULONG pOutBufLen);
+int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
+int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+
/* ** A utility function ** */
static BOOL
is_windows_9x (void)
conversion back and forth from UTF-8 to UTF-16, then don't: first,
it was measured to take only a few microseconds on a not-so-fast
machine, and second, that's exactly what the ANSI APIs we used
- before do anyway, because they are just thin wrappers around the
+ before did anyway, because they are just thin wrappers around the
Unicode APIs.)
The variables file-name-coding-system and default-file-name-coding-system
For the same reasons, no CRT function or Win32 API can be called
directly in Emacs sources, without either converting the file
- name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
- through some shadowing function defined here.
+ names from UTF-8 to 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
. Running subprocesses in non-ASCII directories and with non-ASCII
file arguments is limited to the current codepage (even though
Emacs is perfectly capable of finding an executable program file
- even in a directory whose name cannot be encoded in the current
+ in a directory whose name cannot be encoded in the current
codepage). This is because the command-line arguments are
encoded _before_ they get to the w32-specific level, and the
encoding is not known in advance (it doesn't have to be the
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. */
+ works) requires UNICOWS.DLL, which is thus a requirement even in
+ non-GUI sessions, something the we previously avoided. */
\f
int
filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
{
- int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
- fn_out, MAX_PATH);
+ int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
+ fn_out, MAX_PATH);
if (!result)
{
int
filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
{
- int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
- fn_out, MAX_UTF8_PATH, NULL, NULL);
+ int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
+ fn_out, MAX_UTF8_PATH, NULL, NULL);
if (!result)
{
int result;
int codepage = codepage_for_filenames (NULL);
- result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
- fn_out, MAX_PATH, NULL, NULL);
+ result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
+ fn_out, MAX_PATH, NULL, NULL);
if (!result)
{
DWORD err = GetLastError ();
{
wchar_t fn_utf16[MAX_PATH];
int codepage = codepage_for_filenames (NULL);
- int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
- fn_utf16, MAX_PATH);
+ int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
+ fn_utf16, MAX_PATH);
if (!result)
{
/* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
indicates that flag is unsupported for CP_UTF8, and OTOH says
it is the default anyway. */
- wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
- data.wid.cStreamName, MAX_PATH);
+ wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
+ data.wid.cStreamName, MAX_PATH);
if (wlen > 0)
{
LPVOID context = NULL;
return -1;
}
- /* Remove trailing directory separator, unless name is the root
- directory of a drive or UNC volume in which case ensure there
- is a trailing separator. */
len = strlen (name);
+ /* Allocate 1 extra byte so that we could append a slash to a root
+ directory, down below. */
name = strcpy (alloca (len + 2), name);
/* Avoid a somewhat costly call to is_symlink if the filesystem
}
else if (rootdir)
{
+ /* Make sure root directories end in a slash. */
if (!IS_DIRECTORY_SEP (name[len-1]))
strcat (name, "\\");
if (GetDriveType (name) < 2)
{
int have_wfd = -1;
+ /* Make sure non-root directories do NOT end in a slash,
+ otherwise FindFirstFile might fail. */
if (IS_DIRECTORY_SEP (name[len-1]))
name[len - 1] = 0;
if (fd != AT_FDCWD)
{
- if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
+ char lastc = dir_pathname[strlen (dir_pathname) - 1];
+
+ if (_snprintf (fullname, sizeof fullname, "%s%s%s",
+ dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
< 0)
{
errno = ENAMETOOLONG;
return 0;
}
-/* Emacs expects us to support the traditional octal form of the mode
- bits, which is not what msvcrt.dll wants. */
-
-#define WRITE_USER 00200
-
int
sys_umask (int mode)
{
at all. */
/* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
to prevent access by other users on NTFS. */
- if ((mode & WRITE_USER) != 0)
+ if ((mode & S_IWRITE) != 0)
arg |= S_IWRITE;
retval = _umask (arg);
/* Merge into the return value the bits they've set the last time,
which msvcrt.dll ignores and never returns. Emacs insists on its
notion of mask being identical to what we return. */
- retval |= (current_mask & ~WRITE_USER);
+ retval |= (current_mask & ~S_IWRITE);
current_mask = mode;
return retval;
"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);
+ needed = pMultiByteToWideChar (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);
+ pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
+ msg_w, needed);
+ needed = pWideCharToMultiByte (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);
+ pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
+ NULL, NULL);
msg = msg_a;
}
}
return FALSE;
}
+/* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
+ NT, return a handle to GDI32.DLL. */
+HANDLE
+maybe_load_unicows_dll (void)
+{
+ if (os_subtype == OS_9X)
+ {
+ HANDLE ret = LoadLibrary ("Unicows.dll");
+ if (ret)
+ {
+ /* These two functions are present on Windows 9X as stubs
+ that always fail. We need the real implementations from
+ UNICOWS.DLL, so we must call these functions through
+ pointers, and assign the correct addresses to these
+ pointers at program startup (see emacs.c, which calls
+ this function early on). */
+ pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
+ pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
+ return ret;
+ }
+ else
+ {
+ int button;
+
+ button = MessageBox (NULL,
+ "Emacs cannot load the UNICOWS.DLL library.\n"
+ "This library is essential for using Emacs\n"
+ "on this system. You need to install it.\n\n"
+ "Emacs will exit when you click OK.",
+ "Emacs cannot load UNICOWS.DLL",
+ MB_ICONERROR | MB_TASKMODAL
+ | MB_SETFOREGROUND | MB_OK);
+ switch (button)
+ {
+ case IDOK:
+ default:
+ exit (1);
+ }
+ }
+ }
+ else
+ {
+ /* On NT family of Windows, these two functions are always
+ linked in, so we just assign their addresses to the 2
+ pointers; no need for the LoadLibrary dance. */
+ pMultiByteToWideChar = MultiByteToWideChar;
+ pWideCharToMultiByte = WideCharToMultiByte;
+ return LoadLibrary ("Gdi32.dll");
+ }
+}
+
/*
globals_of_w32 is used to initialize those global variables that
must always be initialized on startup even when the global variable