Support MS-Windows file names that use characters outside of ANSI codepage.

src/w32.c (get_file_security, set_file_security)
 (create_symbolic_link): Separate pointers and boolean flags for
 ANSI and Unicode APIs.  Use the latter if w32_unicode_filenames is
 non-zero, else the former.
 (codepage_for_filenames, filename_to_utf16, )
 (filename_from_utf16, filename_to_ansi, filename_from_ansi): New
 functions.
 (init_user_info): Allow $HOME and $SHELL to include non-ANSI
 characters.
 (normalize_filename): Lose the DBCS code, now works on UTF-8.
 Accept only one argument; all callers changed.
 (dostounix_filename): Remove the second argument, now works in
 UTF-8.  All callers changed.
 (parse_root): Lose DBCS code.
 (get_long_basename, w32_get_short_filename, init_environment)
 (GetCachedVolumeInformation, sys_readdir, open_unc_volume)
 (read_unc_volume, logon_network_drive, faccessat, sys_chdir)
 (sys_chmod, sys_creat, sys_fopen, sys_link, sys_mkdir, sys_open)
 (sys_rename_replace, sys_rmdir, sys_unlink, stat_worker, utime)
 (is_symlink, readlink, chase_symlinks, w32_delayed_load): Work in
 Unicode mode if w32_unicode_filenames is non-zero, in ANSI mode
 otherwise.
 (ansi_encode_filename): New function.
 (get_emacs_configuration, get_emacs_configuration_options):
 Functions deleted.
 (add_volume_info, GetCachedVolumeInformation): Run the input file
 name through unixtodos_filename, to ensure it is stored and
 referenced in canonical form.
 (get_volume_info): Lose the DBCS code, now works in UTF-8.
 (logon_network_drive, sys_link, utime): Improve error handling.
 (sys_access): New function.
 (hashval, generate_inode_val): Unused functions deleted.
 (symlink, readlink, readlinkat): Lose DBCS code, now works in UTF-8.
 (check_windows_init_file): Convert error message from UTF-8 to
 ANSI codepage, for display in the message box.
 (globals_of_w32): Set w32_unicode_filenames according to the OS
 version.
 src/w32term.c (construct_drag_n_drop): Work in Unicode mode when
 w32_unicode_filenames is non-zero, ANSI mode otherwise.
 (syms_of_w32term): Declare w32-unicode-filenames.
 src/w32proc.c (new_child, delete_child): Remove code that handled
 unused pending_deletion and input_file members of the child struct.
 (create_child, sys_spawnve): Convert all file names to ANSI
 codepage.  Use ANSI APIs explicitly; forcibly fail if any file
 name cannot be encoded in ANSI codepage.  Don't use
 unixtodos_filename, mirror slashes by hand.
 (record_infile, record_pending_deletion): Functions deleted.
 (Fw32_short_file_name): Call w32_get_short_filename instead of
 GetShortPathName.
 src/w32notify.c (add_watch): Work in Unicode mode when
 w32_unicode_filenames is non-zero, ANSI mode otherwise.
 (Fw32notify_add_watch): Rewrite to avoid using GetFullPathName;
 instead, do the same with Lisp primitives.
 src/w32fns.c (file_dialog_callback, Fx_file_dialog)
 (Fsystem_move_file_to_trash, Fw32_shell_execute)
 (Ffile_system_info, Fdefault_printer_name): Work in Unicode mode
 when w32_unicode_filenames is non-zero, ANSI mode otherwise.
 (Fw32_shell_execute): Improve error reporting.
 (Fdefault_printer_name): Ifdef away for Cygwin.
 src/w32.h (struct _child_process): Remove input_file and
 pending_deletion members that are no longer used.
 (dostounix_filename, w32_get_short_filename, filename_from_ansi)
 (filename_to_ansi, filename_from_utf16, filename_to_utf16)
 (ansi_encode_filename): New and updated prototypes.
 src/unexw32.c (open_input_file, open_output_file, unexec): Use ANSI
 APIs explicitly.
 (unexec): Don't use dostounix_filename, it expects a file name in
 UTF-8.  Instead, mirror backslashes by hand.  Convert NEW_NAME to
 ANSI encoding.
 src/fileio.c (Ffile_name_directory, file_name_as_directory)
 (directory_file_name, Fexpand_file_name)
 (Fsubstitute_in_file_name) [WINDOWSNT]: Adapt to the change in
 arguments of dostounix_filename.
 (Fexpand_file_name) [WINDOWSNT]: Convert value of $HOME to UTF-8.
 use MAX_UTF8_PATH for size of file-name strings.
 (emacs_readlinkat): Build an explicitly unibyte string for file
 names.
 (syms_of_fileio) <file-name-coding-system>
 default-file-name-coding-system>: Mention MS-Windows peculiarities.
 src/emacs.c (init_cmdargs) [WINDOWSNT]: Convert argv[0] to UTF-8.
 (main) [WINDOWSNT]: Convert the argv[] elements that are files or
 directories to UTF-8.
 (decode_env_path) [WINDOWSNT]: Convert file names taken from the
 environment, and each element of the input PATH, to UTF-8.
 src/dired.c (file_attributes): Use build_unibyte_string explicitly
 to make Lisp strings from user and group names.
 src/coding.h (ENCODE_FILE, DECODE_FILE): Just call encode_file and
 decode_file.
 src/coding.c (decode_file_name, encode_file_name): New functions.
 src/termcap.c (tgetent): Adapt to the change in arguments of
 dostounix_filename.
 src/sysdep.c (sys_subshell) [WINDOWSNT]: Use MAX_UTF8_PATH for file
 names.
 src/msdos.c (dostounix_filename, init_environment): Adapt to the
 change in arguments of dostounix_filename.
 src/image.c (xpm_load, tiff_load, gif_load, imagemagick_load)
 [WINDOWSNT]: Encode file names passed to the image libraries in
 ANSI codepage.
 src/gnutls.c (Fgnutls_boot): Encode all file names passed to GnuTLS.
 [WINDOWSNT]: Convert file names to the current ANSI codepage.
 src/filelock.c (lock_file) [WINDOWSNT]: Adapt to the change in
 arguments of dostounix_filename.

 nt/inc/ms-w32.h (MAX_UTF8_PATH): New macro.
 (opendir, closedir, readdir, seekdir): Redirect to replacement
 functions.
 nt/inc/dirent.h: Make d_name[] be MAXNAMELEN*4 characters long.

 lisp/term/w32-win.el (w32-handle-dropped-file):
 lisp/startup.el (normal-top-level):
 lisp/net/browse-url.el (browse-url-file-url):
 lisp/dnd.el (dnd-get-local-file-name): On MS-Windows, encode and
 decode file names using 'utf-8' rather than
 file-name-coding-system.

 doc/emacs/mule.texi (File Name Coding): Document file-name encoding
 peculiarities on MS-Windows.

 doc/lispref/nonascii.texi (Encoding and I/O): Document file-name encoding
 peculiarities on MS-Windows.

 etc/NEWS: Mention support on MS-Windows of file names outside of the
 current locale.

Fixes: debbugs:7100
This commit is contained in:
Eli Zaretskii 2013-12-12 20:19:10 +02:00
commit 01633a17e7
34 changed files with 2836 additions and 1351 deletions

View file

@ -1,3 +1,8 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
* mule.texi (File Name Coding): Document file-name encoding
peculiarities on MS-Windows.
2013-12-12 Glenn Morris <rgm@gnu.org>
* emacs.texi: Sync direntry with info/dir version.

View file

@ -1130,6 +1130,21 @@ In the default language environment, non-@acronym{ASCII} characters in
file names are not encoded specially; they appear in the file system
using the internal Emacs representation.
@cindex file-name encoding, MS-Windows
@vindex w32-unicode-filenames
When Emacs runs on MS-Windows versions that are descendants of the
NT family (Windows 2000, XP, Vista, Windows 7, and Windows 8), the
value of @code{file-name-coding-system} is largely ignored, as Emacs
by default uses APIs that allow to pass Unicode file names directly.
By contrast, on Windows 9X, file names are encoded using
@code{file-name-coding-system}, which should be set to the codepage
(@pxref{Coding Systems, codepage}) pertinent for the current system
locale. The value of the variable @code{w32-unicode-filenames}
controls whether Emacs uses the Unicode APIs when it calls OS
functions that accept file names. This variable is set by the startup
code to @code{nil} on Windows 9X, and to @code{t} on newer versions of
MS-Windows.
@strong{Warning:} if you change @code{file-name-coding-system} (or the
language environment) in the middle of an Emacs session, problems can
result if you have already visited files whose names were encoded using

View file

@ -1,3 +1,8 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
* nonascii.texi (Encoding and I/O): Document file-name encoding
peculiarities on MS-Windows.
2013-12-12 Glenn Morris <rgm@gnu.org>
* elisp.texi: Sync direntry with info/dir version.

View file

@ -1108,6 +1108,16 @@ visited file name, saving may use the wrong file name, or it may get
an error. If such a problem happens, use @kbd{C-x C-w} to specify a
new file name for that buffer.
@cindex file-name encoding, MS-Windows
On Windows 2000 and later, Emacs by default uses Unicode APIs to
pass file names to the OS, so the value of
@code{file-name-coding-system} is largely ignored. Lisp applications
that need to encode or decode file names on the Lisp level should use
@code{utf-8} coding-system when @code{system-type} is
@code{windows-nt}; the conversion of UTF-8 encoded file names to the
encoding appropriate for communicating with the OS is performed
internally by Emacs.
@node Lisp and Coding Systems
@subsection Coding Systems in Lisp

View file

@ -1,3 +1,8 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
* NEWS: Mention support on MS-Windows of file names outside of the
current locale.
2013-11-23 Xue Fuqiao <xfq.free@gmail.com>
* TODO: Minor update.

View file

@ -1000,6 +1000,14 @@ files are in share/emacs/VERSION/etc. (Emacs knows about all these
directories and will find the files in there automatically; there's no
need to set any variables due to this change.)
+++
** Emacs on Windows 2000 and later can now access files and directories
whose names cannot be encoded in the current system codepage.
The new variable `w32-unicode-filenames' controls this feature: if it
is t, Emacs uses Unicode APIs to pass file names to system calls,
which lifts the limitation of file names to the current locale.
+++
** The "generate a backtrace on fatal error" feature now works on MS Windows.
The backtrace is written to the 'emacs_backtrace.txt' file in the

View file

@ -1,3 +1,12 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
* term/w32-win.el (w32-handle-dropped-file):
* startup.el (normal-top-level):
* net/browse-url.el (browse-url-file-url):
* dnd.el (dnd-get-local-file-name): On MS-Windows, encode and
decode file names using 'utf-8' rather than
file-name-coding-system.
2013-12-12 Fabián Ezequiel Gallina <fgallina@gnu.org>
* progmodes/python.el (python-indent-context)

View file

@ -152,10 +152,13 @@ Return nil if URI is not a local file."
(let ((f (cond ((string-match "^file:///" uri) ; XDND format.
(substring uri (1- (match-end 0))))
((string-match "^file:" uri) ; Old KDE, Motif, Sun
(substring uri (match-end 0))))))
(and f (setq f (decode-coding-string (dnd-unescape-uri f)
(or file-name-coding-system
default-file-name-coding-system))))
(substring uri (match-end 0)))))
(coding (if (equal system-type 'windows-nt)
;; W32 pretends that file names are UTF-8 encoded.
'utf-8
(or file-name-coding-system
default-file-name-coding-system))))
(and f (setq f (decode-coding-string (dnd-unescape-uri f) coding)))
(when (and f must-exist (not (file-readable-p f)))
(setq f nil))
f))

View file

@ -723,9 +723,12 @@ interactively. Turn the filename into a URL with function
(defun browse-url-file-url (file)
"Return the URL corresponding to FILE.
Use variable `browse-url-filename-alist' to map filenames to URLs."
(let ((coding (and (default-value 'enable-multibyte-characters)
(or file-name-coding-system
default-file-name-coding-system))))
(let ((coding (if (equal system-type 'windows-nt)
;; W32 pretends that file names are UTF-8 encoded.
'utf-8
(and (default-value 'enable-multibyte-characters)
(or file-name-coding-system
default-file-name-coding-system)))))
(if coding (setq file (encode-coding-string file coding))))
(setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
(dolist (map browse-url-filename-alist)

View file

@ -533,43 +533,45 @@ It is the default value of the variable `top-level'."
;; for many other file-name variables and directory lists, so it
;; is important to decode it ASAP.
(when locale-coding-system
(save-excursion
(dolist (elt (buffer-list))
(set-buffer elt)
(if default-directory
(setq default-directory
(decode-coding-string default-directory
locale-coding-system t)))))
(let ((coding (if (eq system-type 'windows-nt)
;; MS-Windows build converts all file names to
;; UTF-8 during startup.
'utf-8
locale-coding-system)))
(save-excursion
(dolist (elt (buffer-list))
(set-buffer elt)
(if default-directory
(setq default-directory
(decode-coding-string default-directory coding t)))))
;; Decode all the important variables and directory lists, now
;; that we know the locale's encoding. This is because the
;; values of these variables are until here unibyte undecoded
;; strings created by build_unibyte_string. data-directory in
;; particular is used to construct many other standard directory
;; names, so it must be decoded ASAP.
;; Note that charset-map-path cannot be decoded here, since we
;; could then be trapped in infinite recursion below, when we
;; load subdirs.el, because encoding a directory name might need
;; to load a charset map, which will want to encode
;; charset-map-path, which will want to load the same charset
;; map... So decoding of charset-map-path is delayed until
;; further down below.
(dolist (pathsym '(load-path exec-path))
(let ((path (symbol-value pathsym)))
(if (listp path)
(set pathsym (mapcar (lambda (dir)
(decode-coding-string
dir
locale-coding-system t))
path)))))
(dolist (filesym '(data-directory doc-directory exec-directory
installation-directory
invocation-directory invocation-name
source-directory
shared-game-score-directory))
(let ((file (symbol-value filesym)))
(if (stringp file)
(set filesym (decode-coding-string file locale-coding-system t))))))
;; Decode all the important variables and directory lists, now
;; that we know the locale's encoding. This is because the
;; values of these variables are until here unibyte undecoded
;; strings created by build_unibyte_string. data-directory in
;; particular is used to construct many other standard
;; directory names, so it must be decoded ASAP. Note that
;; charset-map-path cannot be decoded here, since we could
;; then be trapped in infinite recursion below, when we load
;; subdirs.el, because encoding a directory name might need to
;; load a charset map, which will want to encode
;; charset-map-path, which will want to load the same charset
;; map... So decoding of charset-map-path is delayed until
;; further down below.
(dolist (pathsym '(load-path exec-path))
(let ((path (symbol-value pathsym)))
(if (listp path)
(set pathsym (mapcar (lambda (dir)
(decode-coding-string dir coding t))
path)))))
(dolist (filesym '(data-directory doc-directory exec-directory
installation-directory
invocation-directory invocation-name
source-directory
shared-game-score-directory))
(let ((file (symbol-value filesym)))
(if (stringp file)
(set filesym (decode-coding-string file coding t)))))))
(let ((dir default-directory))
(with-current-buffer "*Messages*"
@ -599,12 +601,13 @@ It is the default value of the variable `top-level'."
;; need for encoding them are already loaded, we are ready to
;; decode charset-map-path.
(if (listp charset-map-path)
(setq charset-map-path
(mapcar (lambda (dir)
(decode-coding-string
dir
locale-coding-system t))
charset-map-path)))
(let ((coding (if (eq system-type 'windows-nt)
'utf-8
locale-coding-system)))
(setq charset-map-path
(mapcar (lambda (dir)
(decode-coding-string dir coding t))
charset-map-path))))
(setq default-directory (abbreviate-file-name default-directory))
(let ((old-face-font-rescale-alist face-font-rescale-alist))
(unwind-protect

View file

@ -110,8 +110,13 @@
(let ((f (if (eq system-type 'cygwin)
(cygwin-convert-file-name-from-windows file-name t)
(subst-char-in-string ?\\ ?/ file-name)))
(coding (or file-name-coding-system
default-file-name-coding-system)))
(coding (if (eq system-type 'windows-nt)
;; Native w32 build pretends that its file names
;; are encoded in UTF-8, and converts to the
;; appropriate encoding internally.
'utf-8
(or file-name-coding-system
default-file-name-coding-system))))
(setq file-name
(mapconcat 'url-hexify-string

View file

@ -1,3 +1,10 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
* inc/ms-w32.h (MAX_UTF8_PATH): New macro.
(opendir, closedir, readdir, seekdir): Redirect to replacement
functions.
* inc/dirent.h: Make d_name[] be MAXNAMELEN*4 characters long.
2013-11-27 Glenn Morris <rgm@gnu.org>
* README.W32:

View file

@ -40,7 +40,7 @@ struct dirent /* data from readdir() */
__int64 d_time_write;
_fsize_t d_size;
#endif
char d_name[MAXNAMLEN+1]; /* name of file */
char d_name[MAXNAMLEN * 4 + 1]; /* name of file */
};
typedef struct

View file

@ -152,6 +152,9 @@ extern char *getenv ();
#define MAXPATHLEN _MAX_PATH
#endif
/* This is used to hold UTF-8 encoded file names. */
#define MAX_UTF8_PATH (MAXPATHLEN * 4)
#ifdef HAVE_NTGUI
# ifndef HAVE_WINDOW_SYSTEM
# define HAVE_WINDOW_SYSTEM 1
@ -218,6 +221,14 @@ extern struct tm * sys_localtime (const time_t *);
#define strerror sys_strerror
#undef unlink
#define unlink sys_unlink
#undef opendir
#define opendir sys_opendir
#undef closedir
#define closedir sys_closedir
#undef readdir
#define readdir sys_readdir
#undef seekdir
#define seekdir sys_seekdir
/* This prototype is needed because some files include config.h
_after_ the standard headers, so sys_unlink gets no prototype from
stdio.h or io.h. */

View file

@ -1,3 +1,128 @@
2013-12-12 Eli Zaretskii <eliz@gnu.org>
Support file names on MS-Windows that use characters outside of
the current system codepage. (Bug#7100)
* w32.c (get_file_security, set_file_security)
(create_symbolic_link): Separate pointers and boolean flags for
ANSI and Unicode APIs. Use the latter if w32_unicode_filenames is
non-zero, else the former.
(codepage_for_filenames, filename_to_utf16, )
(filename_from_utf16, filename_to_ansi, filename_from_ansi): New
functions.
(init_user_info): Allow $HOME and $SHELL to include non-ANSI
characters.
(normalize_filename): Lose the DBCS code, now works on UTF-8.
Accept only one argument; all callers changed.
(dostounix_filename): Remove the second argument, now works in
UTF-8. All callers changed.
(parse_root): Lose DBCS code.
(get_long_basename, w32_get_short_filename, init_environment)
(GetCachedVolumeInformation, sys_readdir, open_unc_volume)
(read_unc_volume, logon_network_drive, faccessat, sys_chdir)
(sys_chmod, sys_creat, sys_fopen, sys_link, sys_mkdir, sys_open)
(sys_rename_replace, sys_rmdir, sys_unlink, stat_worker, utime)
(is_symlink, readlink, chase_symlinks, w32_delayed_load): Work in
Unicode mode if w32_unicode_filenames is non-zero, in ANSI mode
otherwise.
(ansi_encode_filename): New function.
(get_emacs_configuration, get_emacs_configuration_options):
Functions deleted.
(add_volume_info, GetCachedVolumeInformation): Run the input file
name through unixtodos_filename, to ensure it is stored and
referenced in canonical form.
(get_volume_info): Lose the DBCS code, now works in UTF-8.
(logon_network_drive, sys_link, utime): Improve error handling.
(sys_access): New function.
(hashval, generate_inode_val): Unused functions deleted.
(symlink, readlink, readlinkat): Lose DBCS code, now works in UTF-8.
(check_windows_init_file): Convert error message from UTF-8 to
ANSI codepage, for display in the message box.
(globals_of_w32): Set w32_unicode_filenames according to the OS
version.
* w32term.c (construct_drag_n_drop): Work in Unicode mode when
w32_unicode_filenames is non-zero, ANSI mode otherwise.
(syms_of_w32term): Declare w32-unicode-filenames.
* w32proc.c (new_child, delete_child): Remove code that handled
unused pending_deletion and input_file members of the child struct.
(create_child, sys_spawnve): Convert all file names to ANSI
codepage. Use ANSI APIs explicitly; forcibly fail if any file
name cannot be encoded in ANSI codepage. Don't use
unixtodos_filename, mirror slashes by hand.
(record_infile, record_pending_deletion): Functions deleted.
(Fw32_short_file_name): Call w32_get_short_filename instead of
GetShortPathName.
* w32notify.c (add_watch): Work in Unicode mode when
w32_unicode_filenames is non-zero, ANSI mode otherwise.
(Fw32notify_add_watch): Rewrite to avoid using GetFullPathName;
instead, do the same with Lisp primitives.
* w32fns.c (file_dialog_callback, Fx_file_dialog)
(Fsystem_move_file_to_trash, Fw32_shell_execute)
(Ffile_system_info, Fdefault_printer_name): Work in Unicode mode
when w32_unicode_filenames is non-zero, ANSI mode otherwise.
(Fw32_shell_execute): Improve error reporting.
(Fdefault_printer_name): Ifdef away for Cygwin.
* w32.h (struct _child_process): Remove input_file and
pending_deletion members that are no longer used.
(dostounix_filename, w32_get_short_filename, filename_from_ansi)
(filename_to_ansi, filename_from_utf16, filename_to_utf16)
(ansi_encode_filename): New and updated prototypes.
* unexw32.c (open_input_file, open_output_file, unexec): Use ANSI
APIs explicitly.
(unexec): Don't use dostounix_filename, it expects a file name in
UTF-8. Instead, mirror backslashes by hand. Convert NEW_NAME to
ANSI encoding.
* fileio.c (Ffile_name_directory, file_name_as_directory)
(directory_file_name, Fexpand_file_name)
(Fsubstitute_in_file_name) [WINDOWSNT]: Adapt to the change in
arguments of dostounix_filename.
(Fexpand_file_name) [WINDOWSNT]: Convert value of $HOME to UTF-8.
use MAX_UTF8_PATH for size of file-name strings.
(emacs_readlinkat): Build an explicitly unibyte string for file
names.
(syms_of_fileio) <file-name-coding-system>
default-file-name-coding-system>: Mention MS-Windows peculiarities.
* emacs.c (init_cmdargs) [WINDOWSNT]: Convert argv[0] to UTF-8.
(main) [WINDOWSNT]: Convert the argv[] elements that are files or
directories to UTF-8.
(decode_env_path) [WINDOWSNT]: Convert file names taken from the
environment, and each element of the input PATH, to UTF-8.
* dired.c (file_attributes): Use build_unibyte_string explicitly
to make Lisp strings from user and group names.
* coding.h (ENCODE_FILE, DECODE_FILE): Just call encode_file and
decode_file.
* coding.c (decode_file_name, encode_file_name): New functions.
* termcap.c (tgetent): Adapt to the change in arguments of
dostounix_filename.
* sysdep.c (sys_subshell) [WINDOWSNT]: Use MAX_UTF8_PATH for file
names.
* msdos.c (dostounix_filename, init_environment): Adapt to the
change in arguments of dostounix_filename.
* image.c (xpm_load, tiff_load, gif_load, imagemagick_load)
[WINDOWSNT]: Encode file names passed to the image libraries in
ANSI codepage.
* gnutls.c (Fgnutls_boot): Encode all file names passed to GnuTLS.
[WINDOWSNT]: Convert file names to the current ANSI codepage.
* filelock.c (lock_file) [WINDOWSNT]: Adapt to the change in
arguments of dostounix_filename.
2013-12-12 Dmitry Antipov <dmantipov@yandex.ru>
* font.h (struct font_entity) [HAVE_NS]: New field to record

View file

@ -9490,6 +9490,55 @@ code_convert_string_norecord (Lisp_Object string, Lisp_Object coding_system,
return code_convert_string (string, coding_system, Qt, encodep, 0, 1);
}
/* Encode or decode a file name, to or from a unibyte string suitable
for passing to C library functions. */
Lisp_Object
decode_file_name (Lisp_Object fname)
{
#ifdef WINDOWSNT
/* The w32 build pretends to use UTF-8 for file-name encoding, and
converts the file names either to UTF-16LE or to the system ANSI
codepage internally, depending on the underlying OS; see w32.c. */
if (! NILP (Fcoding_system_p (Qutf_8)))
return code_convert_string_norecord (fname, Qutf_8, 0);
return fname;
#else /* !WINDOWSNT */
if (! NILP (Vfile_name_coding_system))
return code_convert_string_norecord (fname, Vfile_name_coding_system, 0);
else if (! NILP (Vdefault_file_name_coding_system))
return code_convert_string_norecord (fname,
Vdefault_file_name_coding_system, 0);
else
return fname;
#endif
}
Lisp_Object
encode_file_name (Lisp_Object fname)
{
/* This is especially important during bootstrap and dumping, when
file-name encoding is not yet known, and therefore any non-ASCII
file names are unibyte strings, and could only be thrashed if we
try to encode them. */
if (!STRING_MULTIBYTE (fname))
return fname;
#ifdef WINDOWSNT
/* The w32 build pretends to use UTF-8 for file-name encoding, and
converts the file names either to UTF-16LE or to the system ANSI
codepage internally, depending on the underlying OS; see w32.c. */
if (! NILP (Fcoding_system_p (Qutf_8)))
return code_convert_string_norecord (fname, Qutf_8, 1);
return fname;
#else /* !WINDOWSNT */
if (! NILP (Vfile_name_coding_system))
return code_convert_string_norecord (fname, Vfile_name_coding_system, 1);
else if (! NILP (Vdefault_file_name_coding_system))
return code_convert_string_norecord (fname,
Vdefault_file_name_coding_system, 1);
else
return fname;
#endif
}
DEFUN ("decode-coding-string", Fdecode_coding_string, Sdecode_coding_string,
2, 4, 0,

View file

@ -670,27 +670,13 @@ struct coding_system
(code) = (s1 << 8) | s2; \
} while (0)
/* Encode the file name NAME using the specified coding system for
file names, if any. If NAME is a unibyte string, return NAME. */
#define ENCODE_FILE(name) \
(! STRING_MULTIBYTE (name) \
? name \
: (! NILP (Vfile_name_coding_system) \
? code_convert_string_norecord (name, Vfile_name_coding_system, 1) \
: (! NILP (Vdefault_file_name_coding_system) \
? code_convert_string_norecord (name, Vdefault_file_name_coding_system, 1) \
: name)))
/* Encode the file name NAME using the specified coding system
for file names, if any. */
#define ENCODE_FILE(NAME) encode_file_name (NAME)
/* Decode the file name NAME using the specified coding system
for file names, if any. */
#define DECODE_FILE(name) \
(! NILP (Vfile_name_coding_system) \
? code_convert_string_norecord (name, Vfile_name_coding_system, 0) \
: (! NILP (Vdefault_file_name_coding_system) \
? code_convert_string_norecord (name, Vdefault_file_name_coding_system, 0) \
: name))
#define DECODE_FILE(NAME) decode_file_name (NAME)
/* Encode the string STR using the specified coding system
for system functions, if any. */
@ -718,6 +704,8 @@ extern Lisp_Object code_convert_string (Lisp_Object, Lisp_Object,
Lisp_Object, bool, bool, bool);
extern Lisp_Object code_convert_string_norecord (Lisp_Object, Lisp_Object,
bool);
extern Lisp_Object encode_file_name (Lisp_Object);
extern Lisp_Object decode_file_name (Lisp_Object);
extern Lisp_Object raw_text_coding_system (Lisp_Object);
extern Lisp_Object coding_inherit_eol_type (Lisp_Object, Lisp_Object);
extern Lisp_Object complement_process_encoding_system (Lisp_Object);

View file

@ -958,11 +958,11 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
unblock_input ();
}
if (uname)
values[2] = DECODE_SYSTEM (build_string (uname));
values[2] = DECODE_SYSTEM (build_unibyte_string (uname));
else
values[2] = make_fixnum_or_float (s.st_uid);
if (gname)
values[3] = DECODE_SYSTEM (build_string (gname));
values[3] = DECODE_SYSTEM (build_unibyte_string (gname));
else
values[3] = make_fixnum_or_float (s.st_gid);

View file

@ -36,6 +36,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#ifdef WINDOWSNT
#include <fcntl.h>
#include <sys/socket.h>
#include <mbstring.h>
#include "w32.h"
#include "w32heap.h"
#endif
@ -393,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. */
@ -795,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)
{
@ -1539,7 +1561,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"),
@ -2185,9 +2216,15 @@ decode_env_path (const char *evarname, const char *defalt, bool empty)
Lisp_Object empty_element = empty ? Qnil : build_string (".");
#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
@ -2208,9 +2245,44 @@ decode_env_path (const char *evarname, const char *defalt, bool empty)
/* Ensure values from the environment use the proper directory separator. */
if (path)
{
char *path_copy = alloca (strlen (path) + 1);
char *path_copy;
#ifdef WINDOWSNT
char *path_utf8, *q, *d;
int cnv_result;
/* Convert each element of PATH to UTF-8. */
p = path_copy = alloca (strlen (path) + 1);
strcpy (path_copy, path);
dostounix_filename (path_copy, 0);
d = path_utf8 = alloca (4 * strlen (path) + 1);
*d = '\0';
do {
q = _mbschr (p, SEPCHAR);
if (q)
*q = '\0';
cnv_result = filename_from_ansi (p, d);
if (q)
{
*q++ = SEPCHAR;
p = q;
/* If conversion of this PATH elements fails, make sure
destination pointer will stay put, thus effectively
ignoring the offending element. */
if (cnv_result == 0)
{
d += strlen (d);
*d++ = SEPCHAR;
}
}
else if (cnv_result != 0 && d > path_utf8)
d[-1] = '\0'; /* remove last semi-colon and null-terminate PATH */
} while (q);
path_copy = path_utf8;
#else /* MSDOS */
path_copy = alloca (strlen (path) + 1);
strcpy (path_copy, path);
#endif
dostounix_filename (path_copy);
path = path_copy;
}
#endif

View file

@ -460,7 +460,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));
}
@ -471,7 +472,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);
@ -479,7 +480,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;
@ -583,7 +584,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;
}
@ -652,7 +653,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;
}
@ -1101,7 +1102,7 @@ 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);
dostounix_filename (nm);
#ifdef WINDOWSNT
if (IS_DIRECTORY_SEP (nm[1]))
{
@ -1162,7 +1163,18 @@ filesystem tree, not (expand-file-name ".." dirname). */)
nm++;
/* `egetenv' may return a unibyte string, which will bite us since
we expect the directory to be multibyte. */
tem = build_string (newdir);
#ifdef WINDOWSNT
if (newdir[0])
{
char newdir_utf8[MAX_UTF8_PATH];
filename_from_ansi (newdir, newdir_utf8);
tem = build_string (newdir_utf8);
}
else
#else
tem = build_string (newdir);
#endif
if (multibyte && !STRING_MULTIBYTE (tem))
{
hdir = DECODE_FILE (tem);
@ -1286,6 +1298,11 @@ filesystem tree, not (expand-file-name ".." dirname). */)
indirectly by prepending newdir to nm if necessary, and using
cwd (or the wd of newdir's drive) as the new newdir. */
char *adir;
#ifdef WINDOWSNT
const int adir_size = MAX_UTF8_PATH;
#else
const int adir_size = MAXPATHLEN + 1;
#endif
if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
{
@ -1301,14 +1318,14 @@ filesystem tree, not (expand-file-name ".." dirname). */)
strcat (tmp, nm);
nm = tmp;
}
adir = alloca (MAXPATHLEN + 1);
adir = alloca (adir_size);
if (drive)
{
if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
strcpy (adir, "/");
}
else
getcwd (adir, MAXPATHLEN + 1);
getcwd (adir, adir_size);
if (multibyte)
{
Lisp_Object tem = build_string (adir);
@ -1479,7 +1496,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
target[1] = ':';
}
result = make_specified_string (target, -1, o - target, multibyte);
dostounix_filename (SSDATA (result), multibyte);
dostounix_filename (SSDATA (result));
#ifdef WINDOWSNT
if (!NILP (Vw32_downcase_file_names))
result = Fdowncase (result);
@ -1763,7 +1780,7 @@ those `/' is discarded. */)
nm = xlispstrdupa (filename);
#ifdef DOS_NT
dostounix_filename (nm, multibyte);
dostounix_filename (nm);
substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
#endif
endp = nm + SBYTES (filename);
@ -2661,9 +2678,9 @@ emacs_readlinkat (int fd, char const *filename)
if (!buf)
return Qnil;
val = build_string (buf);
val = build_unibyte_string (buf);
if (buf[0] == '/' && strchr (buf, ':'))
val = concat2 (build_string ("/:"), val);
val = concat2 (build_unibyte_string ("/:"), val);
if (buf != readlink_buf)
xfree (buf);
val = DECODE_FILE (val);
@ -5858,7 +5875,11 @@ syms_of_fileio (void)
DEFVAR_LISP ("file-name-coding-system", Vfile_name_coding_system,
doc: /* Coding system for encoding file names.
If it is nil, `default-file-name-coding-system' (which see) is used. */);
If it is nil, `default-file-name-coding-system' (which see) is used.
On MS-Windows, the value of this variable is largely ignored if
\`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows
behaves as if file names were encoded in `utf-8'. */);
Vfile_name_coding_system = Qnil;
DEFVAR_LISP ("default-file-name-coding-system",
@ -5869,7 +5890,11 @@ This variable is used only when `file-name-coding-system' is nil.
This variable is set/changed by the command `set-language-environment'.
User should not set this variable manually,
instead use `file-name-coding-system' to get a constant encoding
of file names regardless of the current language environment. */);
of file names regardless of the current language environment.
On MS-Windows, the value of this variable is largely ignored if
\`w32-unicode-filenames' (which see) is non-nil. Emacs on Windows
behaves as if file names were encoded in `utf-8'. */);
Vdefault_file_name_coding_system = Qnil;
DEFSYM (Qformat_decode, "format-decode");

View 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);

View file

@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "lisp.h"
#include "process.h"
#include "coding.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
@ -899,6 +900,13 @@ one trustfile (usually a CA bundle). */)
{
GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ",
SSDATA (trustfile));
trustfile = ENCODE_FILE (trustfile);
#ifdef WINDOWSNT
/* Since GnuTLS doesn't support UTF-8 or UTF-16 encoded
file names on Windows, we need to re-encode the file
name using the current ANSI codepage. */
trustfile = ansi_encode_filename (trustfile);
#endif
ret = fn_gnutls_certificate_set_x509_trust_file
(x509_cred,
SSDATA (trustfile),
@ -921,6 +929,10 @@ one trustfile (usually a CA bundle). */)
{
GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ",
SSDATA (crlfile));
crlfile = ENCODE_FILE (crlfile);
#ifdef WINDOWSNT
crlfile = ansi_encode_filename (crlfile);
#endif
ret = fn_gnutls_certificate_set_x509_crl_file
(x509_cred, SSDATA (crlfile), file_format);
@ -944,6 +956,12 @@ one trustfile (usually a CA bundle). */)
SSDATA (keyfile));
GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ",
SSDATA (certfile));
keyfile = ENCODE_FILE (keyfile);
certfile = ENCODE_FILE (certfile);
#ifdef WINDOWSNT
keyfile = ansi_encode_filename (keyfile);
certfile = ansi_encode_filename (certfile);
#endif
ret = fn_gnutls_certificate_set_x509_key_file
(x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format);

View file

@ -3590,6 +3590,12 @@ xpm_load (struct frame *f, struct image *img)
}
#ifdef HAVE_NTGUI
#ifdef WINDOWSNT
/* FILE is encoded in UTF-8, but image libraries on Windows
support neither UTF-8 nor UTF-16 encoded file names. So we
need to re-encode it in ANSI. */
file = ansi_encode_filename (file);
#endif
/* XpmReadFileToPixmap is not available in the Windows port of
libxpm. But XpmReadFileToImage almost does what we want. */
rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
@ -6968,6 +6974,9 @@ tiff_load (struct frame *f, struct image *img)
image_error ("Cannot find image file `%s'", specified_file, Qnil);
return 0;
}
#ifdef WINDOWSNT
file = ansi_encode_filename (file);
#endif
/* Try to open the image file. */
tiff = fn_TIFFOpen (SSDATA (file), "r");
@ -7353,6 +7362,9 @@ gif_load (struct frame *f, struct image *img)
image_error ("Cannot find image file `%s'", specified_file, Qnil);
return 0;
}
#ifdef WINDOWSNT
file = ansi_encode_filename (file);
#endif
/* Open the GIF file. */
#if GIFLIB_MAJOR < 5
@ -8479,6 +8491,9 @@ imagemagick_load (struct frame *f, struct image *img)
image_error ("Cannot find image file `%s'", file_name, Qnil);
return 0;
}
#ifdef WINDOWSNT
file = ansi_encode_filename (file);
#endif
success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
}
/* Else its not a file, its a lisp object. Load the image from a

View 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... */

View 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);

View file

@ -464,7 +464,11 @@ sys_subshell (void)
{
#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
int st;
#ifdef MSDOS
char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
#else
char oldwd[MAX_UTF8_PATH];
#endif
#endif
pid_t pid;
int status;

View 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);

View file

@ -120,6 +120,8 @@ _start (void)
/* File handling. */
/* Implementation note: this and the next functions work with ANSI
codepage encoded file names! */
int
open_input_file (file_data *p_file, char *filename)
{
@ -128,8 +130,8 @@ open_input_file (file_data *p_file, char *filename)
void *file_base;
unsigned long size, upper_size;
file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (file == INVALID_HANDLE_VALUE)
return FALSE;
@ -166,9 +168,9 @@ open_output_file (file_data *p_file, char *filename, unsigned long size)
creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
links to the same file, which defeats the purpose of these hard
links: being able to run previous builds. */
DeleteFile (filename);
file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DeleteFileA (filename);
file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (file == INVALID_HANDLE_VALUE)
return FALSE;
@ -722,23 +724,30 @@ void
unexec (const char *new_name, const char *old_name)
{
file_data in_file, out_file;
char out_filename[MAX_PATH], in_filename[MAX_PATH];
char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
unsigned long size;
char *p;
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);
filename_to_ansi (new_name, new_name_a);
/* Change the base of the output filename to match the requested name. */
if ((p = strrchr (out_filename, '/')) == NULL)
abort ();
/* The filenames have already been expanded, and will be in Unix
format, so it is safe to expect an absolute name. */
if ((q = strrchr (new_name, '/')) == NULL)
if ((q = strrchr (new_name_a, '/')) == NULL)
abort ();
strcpy (p, q);

2605
src/w32.c

File diff suppressed because it is too large Load diff

View file

@ -103,12 +103,6 @@ typedef struct _child_process
OVERLAPPED ovl_read;
/* Used for async write operations on serial comm ports. */
OVERLAPPED ovl_write;
/* Input file, if any, for this subprocess. Should only be non-NULL
for async subprocesses. */
char *input_file;
/* If non-zero, the subprocess input file is temporary and should be
deleted when the subprocess exits. */
int pending_deletion;
} child_process;
#define MAXDESC FD_SETSIZE
@ -152,6 +146,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 +178,14 @@ 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 int filename_to_ansi (const char *, char *);
extern int filename_from_utf16 (const wchar_t *, char *);
extern int filename_to_utf16 (const char *, wchar_t *);
extern Lisp_Object ansi_encode_filename (Lisp_Object);
extern BOOL init_winsock (int load_now);
extern void srandom (int);
extern int random (void);
@ -194,14 +197,10 @@ extern int pipe2 (int *, int);
extern void set_process_dir (char *);
extern int sys_spawnve (int, char *, char **, char **);
extern void register_child (pid_t, int);
extern void record_infile (pid_t, char *);
extern void record_pending_deletion (char *);
extern void sys_sleep (int);
extern int sys_link (const char *, const char *);
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>

View file

@ -51,6 +51,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#ifdef WINDOWSNT
#include "w32heap.h"
#include <mbstring.h>
#endif /* WINDOWSNT */
#if CYGWIN
@ -6305,18 +6306,31 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_NOTIFY)
{
OFNOTIFYW * notify_w = (OFNOTIFYW *)lParam;
OFNOTIFYA * notify_a = (OFNOTIFYA *)lParam;
int dropdown_changed;
int dir_index;
#ifdef NTGUI_UNICODE
OFNOTIFYW * notify = (OFNOTIFYW *)lParam;
const int use_unicode = 1;
#else /* !NTGUI_UNICODE */
OFNOTIFYA * notify = (OFNOTIFYA *)lParam;
int use_unicode = w32_unicode_filenames;
#endif /* NTGUI_UNICODE */
/* Detect when the Filter dropdown is changed. */
if (notify->hdr.code == CDN_TYPECHANGE
|| notify->hdr.code == CDN_INITDONE)
if (use_unicode)
dropdown_changed =
notify_w->hdr.code == CDN_TYPECHANGE
|| notify_w->hdr.code == CDN_INITDONE;
else
dropdown_changed =
notify_a->hdr.code == CDN_TYPECHANGE
|| notify_a->hdr.code == CDN_INITDONE;
if (dropdown_changed)
{
HWND dialog = GetParent (hwnd);
HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
HWND list = GetDlgItem (dialog, FILE_NAME_LIST);
int hdr_code;
/* At least on Windows 7, the above attempt to get the window handle
to the File Name Text Field fails. The following code does the
@ -6334,10 +6348,24 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
/* Directories is in index 2. */
if (notify->lpOFN->nFilterIndex == 2)
if (use_unicode)
{
CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
GUISTR ("Current Directory"));
dir_index = notify_w->lpOFN->nFilterIndex;
hdr_code = notify_w->hdr.code;
}
else
{
dir_index = notify_a->lpOFN->nFilterIndex;
hdr_code = notify_a->hdr.code;
}
if (dir_index == 2)
{
if (use_unicode)
SendMessageW (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
(LPARAM)L"Current Directory");
else
SendMessageA (dialog, CDM_SETCONTROLTEXT, FILE_NAME_TEXT_FIELD,
(LPARAM)"Current Directory");
EnableWindow (edit_control, FALSE);
/* Note that at least on Windows 7, the above call to EnableWindow
disables the window that would ordinarily have focus. If we
@ -6345,16 +6373,21 @@ file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
no man's land and the user will be unable to tab through the
dialog box (pressing tab will only result in a beep).
Avoid that problem by setting focus to the list here. */
if (notify->hdr.code == CDN_INITDONE)
if (hdr_code == CDN_INITDONE)
SetFocus (list);
}
else
{
/* Don't override default filename on init done. */
if (notify->hdr.code == CDN_TYPECHANGE)
CommDlg_OpenSave_SetControlText (dialog,
FILE_NAME_TEXT_FIELD,
GUISTR (""));
if (hdr_code == CDN_TYPECHANGE)
{
if (use_unicode)
SendMessageW (dialog, CDM_SETCONTROLTEXT,
FILE_NAME_TEXT_FIELD, (LPARAM)L"");
else
SendMessageA (dialog, CDM_SETCONTROLTEXT,
FILE_NAME_TEXT_FIELD, (LPARAM)"");
}
EnableWindow (edit_control, TRUE);
}
}
@ -6374,8 +6407,8 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
(Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p)
{
/* Filter index: 1: All Files, 2: Directories only */
static const guichar_t filter[] =
GUISTR ("All Files (*.*)\0*.*\0Directories\0*|*\0");
static const wchar_t filter_w[] = L"All Files (*.*)\0*.*\0Directories\0*|*\0";
static const char filter_a[] = "All Files (*.*)\0*.*\0Directories\0*|*\0";
Lisp_Object filename = default_filename;
struct frame *f = SELECTED_FRAME ();
@ -6388,25 +6421,36 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
enough struct for the new dialog to trick GetOpenFileName into
giving us the new dialogs on newer versions of Windows. */
struct {
#ifdef NTGUI_UNICODE
OPENFILENAMEW details;
#else /* !NTGUI_UNICODE */
OPENFILENAMEA details;
#endif /* NTGUI_UNICODE */
#if _WIN32_WINNT < 0x500 /* < win2k */
PVOID pvReserved;
DWORD dwReserved;
DWORD FlagsEx;
#endif /* < win2k */
} new_file_details;
} new_file_details_w;
#ifdef NTGUI_UNICODE
wchar_t filename_buf[32*1024 + 1]; // NT kernel maximum
OPENFILENAMEW * file_details = &new_file_details.details;
wchar_t filename_buf_w[32*1024 + 1]; // NT kernel maximum
OPENFILENAMEW * file_details_w = &new_file_details_w.details;
const int use_unicode = 1;
#else /* not NTGUI_UNICODE */
char filename_buf[MAX_PATH + 1];
OPENFILENAMEA * file_details = &new_file_details.details;
struct {
OPENFILENAMEA details;
#if _WIN32_WINNT < 0x500 /* < win2k */
PVOID pvReserved;
DWORD dwReserved;
DWORD FlagsEx;
#endif /* < win2k */
} new_file_details_a;
wchar_t filename_buf_w[MAX_PATH + 1], dir_w[MAX_PATH];
char filename_buf_a[MAX_PATH + 1], dir_a[MAX_PATH];
OPENFILENAMEW * file_details_w = &new_file_details_w.details;
OPENFILENAMEA * file_details_a = &new_file_details_a.details;
int use_unicode = w32_unicode_filenames;
wchar_t *prompt_w;
char *prompt_a;
int len;
char fname_ret[MAX_UTF8_PATH];
#endif /* NTGUI_UNICODE */
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
@ -6452,6 +6496,10 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
to_unicode (prompt, &prompt);
to_unicode (dir, &dir);
to_unicode (filename, &filename);
if (SBYTES (filename) + 1 > sizeof (filename_buf_w))
report_file_error ("filename too long", default_filename);
memcpy (filename_buf_w, SDATA (filename), SBYTES (filename) + 1);
#else /* !NTGUI_UNICODE */
prompt = ENCODE_FILE (prompt);
dir = ENCODE_FILE (dir);
@ -6462,6 +6510,49 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
unixtodos_filename (SDATA (dir));
filename = Fcopy_sequence (filename);
unixtodos_filename (SDATA (filename));
if (SBYTES (filename) >= MAX_UTF8_PATH)
report_file_error ("filename too long", default_filename);
if (w32_unicode_filenames)
{
filename_to_utf16 (SSDATA (dir), dir_w);
if (filename_to_utf16 (SSDATA (filename), filename_buf_w) != 0)
{
/* filename_to_utf16 sets errno to ENOENT when the file
name is too long or cannot be converted to UTF-16. */
if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
report_file_error ("filename too long", default_filename);
}
len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
SSDATA (prompt), -1, NULL, 0);
if (len > 32768)
len = 32768;
prompt_w = alloca (len * sizeof (wchar_t));
MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
SSDATA (prompt), -1, prompt_w, len);
}
else
{
filename_to_ansi (SSDATA (dir), dir_a);
if (filename_to_ansi (SSDATA (filename), filename_buf_a) != '\0')
{
/* filename_to_ansi sets errno to ENOENT when the file
name is too long or cannot be converted to UTF-16. */
if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
report_file_error ("filename too long", default_filename);
}
len = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
SSDATA (prompt), -1, NULL, 0);
if (len > 32768)
len = 32768;
prompt_w = alloca (len * sizeof (wchar_t));
MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
SSDATA (prompt), -1, prompt_w, len);
len = WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL);
if (len > 32768)
len = 32768;
prompt_a = alloca (len);
WideCharToMultiByte (CP_ACP, 0, prompt_w, -1, prompt_a, len, NULL, NULL);
}
#endif /* NTGUI_UNICODE */
/* Fill in the structure for the call to GetOpenFileName below.
@ -6470,48 +6561,88 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
builds, we tell the OS we're using an old version of the
structure if the OS isn't new enough to support the newer
version. */
memset (&new_file_details, 0, sizeof (new_file_details));
if (w32_major_version > 4 && w32_major_version < 95)
file_details->lStructSize = sizeof (new_file_details);
else
file_details->lStructSize = sizeof (*file_details);
/* Set up the inout parameter for the selected file name. */
if (SBYTES (filename) + 1 > sizeof (filename_buf))
report_file_error ("filename too long", default_filename);
memcpy (filename_buf, SDATA (filename), SBYTES (filename) + 1);
file_details->lpstrFile = filename_buf;
file_details->nMaxFile = sizeof (filename_buf) / sizeof (*filename_buf);
file_details->hwndOwner = FRAME_W32_WINDOW (f);
/* Undocumented Bug in Common File Dialog:
If a filter is not specified, shell links are not resolved. */
file_details->lpstrFilter = filter;
file_details->lpstrInitialDir = (guichar_t*) SDATA (dir);
file_details->lpstrTitle = (guichar_t*) SDATA (prompt);
file_details->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
| OFN_EXPLORER | OFN_ENABLEHOOK);
if (!NILP (mustmatch))
if (use_unicode)
{
/* Require that the path to the parent directory exists. */
file_details->Flags |= OFN_PATHMUSTEXIST;
/* If we are looking for a file, require that it exists. */
if (NILP (only_dir_p))
file_details->Flags |= OFN_FILEMUSTEXIST;
memset (&new_file_details_w, 0, sizeof (new_file_details_w));
if (w32_major_version > 4 && w32_major_version < 95)
file_details_w->lStructSize = sizeof (new_file_details_w);
else
file_details_w->lStructSize = sizeof (*file_details_w);
/* Set up the inout parameter for the selected file name. */
file_details_w->lpstrFile = filename_buf_w;
file_details_w->nMaxFile =
sizeof (filename_buf_w) / sizeof (*filename_buf_w);
file_details_w->hwndOwner = FRAME_W32_WINDOW (f);
/* Undocumented Bug in Common File Dialog:
If a filter is not specified, shell links are not resolved. */
file_details_w->lpstrFilter = filter_w;
#ifdef NTGUI_UNICODE
file_details_w->lpstrInitialDir = (wchar_t*) SDATA (dir);
file_details_w->lpstrTitle = (guichar_t*) SDATA (prompt);
#else
file_details_w->lpstrInitialDir = dir_w;
file_details_w->lpstrTitle = prompt_w;
#endif
file_details_w->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
file_details_w->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
| OFN_EXPLORER | OFN_ENABLEHOOK);
if (!NILP (mustmatch))
{
/* Require that the path to the parent directory exists. */
file_details_w->Flags |= OFN_PATHMUSTEXIST;
/* If we are looking for a file, require that it exists. */
if (NILP (only_dir_p))
file_details_w->Flags |= OFN_FILEMUSTEXIST;
}
}
#ifndef NTGUI_UNICODE
else
{
memset (&new_file_details_a, 0, sizeof (new_file_details_a));
if (w32_major_version > 4 && w32_major_version < 95)
file_details_a->lStructSize = sizeof (new_file_details_a);
else
file_details_a->lStructSize = sizeof (*file_details_a);
file_details_a->lpstrFile = filename_buf_a;
file_details_a->nMaxFile =
sizeof (filename_buf_a) / sizeof (*filename_buf_a);
file_details_a->hwndOwner = FRAME_W32_WINDOW (f);
file_details_a->lpstrFilter = filter_a;
file_details_a->lpstrInitialDir = dir_a;
file_details_a->lpstrTitle = prompt_a;
file_details_a->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
file_details_a->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
| OFN_EXPLORER | OFN_ENABLEHOOK);
if (!NILP (mustmatch))
{
/* Require that the path to the parent directory exists. */
file_details_a->Flags |= OFN_PATHMUSTEXIST;
/* If we are looking for a file, require that it exists. */
if (NILP (only_dir_p))
file_details_a->Flags |= OFN_FILEMUSTEXIST;
}
}
#endif /* !NTGUI_UNICODE */
{
int count = SPECPDL_INDEX ();
/* Prevent redisplay. */
specbind (Qinhibit_redisplay, Qt);
block_input ();
file_details->lpfnHook = file_dialog_callback;
if (use_unicode)
{
file_details_w->lpfnHook = file_dialog_callback;
file_opened = GUI_FN (GetOpenFileName) (file_details);
file_opened = GetOpenFileNameW (file_details_w);
}
#ifndef NTGUI_UNICODE
else
{
file_details_a->lpfnHook = file_dialog_callback;
file_opened = GetOpenFileNameA (file_details_a);
}
#endif /* !NTGUI_UNICODE */
unblock_input ();
unbind_to (count, Qnil);
}
@ -6520,10 +6651,14 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
{
/* Get an Emacs string from the value Windows gave us. */
#ifdef NTGUI_UNICODE
filename = from_unicode_buffer (filename_buf);
filename = from_unicode_buffer (filename_buf_w);
#else /* !NTGUI_UNICODE */
dostounix_filename (filename_buf, 0);
filename = DECODE_FILE (build_string (filename_buf));
if (use_unicode)
filename_from_utf16 (filename_buf_w, fname_ret);
else
filename_from_ansi (filename_buf_a, fname_ret);
dostounix_filename (fname_ret);
filename = DECODE_FILE (build_unibyte_string (fname_ret));
#endif /* NTGUI_UNICODE */
#ifdef CYGWIN
@ -6532,10 +6667,12 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
/* Strip the dummy filename off the end of the string if we
added it to select a directory. */
if (file_details->nFilterIndex == 2)
{
filename = Ffile_name_directory (filename);
}
if (use_unicode && file_details_w->nFilterIndex == 2
#ifndef NTGUI_UNICODE
|| !use_unicode && file_details_a->nFilterIndex == 2
#endif
)
filename = Ffile_name_directory (filename);
}
/* User canceled the dialog without making a selection. */
else if (!CommDlgExtendedError ())
@ -6582,38 +6719,80 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
operation = intern ("delete-directory");
filename = Fdirectory_file_name (filename);
}
/* Must have fully qualified file names for moving files to Recycle
Bin. */
filename = Fexpand_file_name (filename, Qnil);
handler = Ffind_file_name_handler (filename, operation);
if (!NILP (handler))
return call2 (handler, operation, filename);
else
{
const char * path;
int result;
encoded_file = ENCODE_FILE (filename);
encoded_file = ENCODE_FILE (filename);
{
const char * path;
SHFILEOPSTRUCT file_op;
char tmp_path[MAX_PATH + 1];
path = map_w32_filename (SDATA (encoded_file), NULL);
path = map_w32_filename (SDATA (encoded_file), NULL);
/* The Unicode version of SHFileOperation is not supported on
Windows 9X. */
if (w32_unicode_filenames && os_subtype != OS_9X)
{
SHFILEOPSTRUCTW file_op_w;
/* We need one more element beyond MAX_PATH because this is
a list of file names, with the last element double-null
terminated. */
wchar_t tmp_path_w[MAX_PATH + 1];
/* On Windows, write permission is required to delete/move files. */
_chmod (path, 0666);
memset (tmp_path_w, 0, sizeof (tmp_path_w));
filename_to_utf16 (path, tmp_path_w);
memset (tmp_path, 0, sizeof (tmp_path));
strcpy (tmp_path, path);
/* On Windows, write permission is required to delete/move files. */
_wchmod (tmp_path_w, 0666);
memset (&file_op, 0, sizeof (file_op));
file_op.hwnd = HWND_DESKTOP;
file_op.wFunc = FO_DELETE;
file_op.pFrom = tmp_path;
file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
| FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
file_op.fAnyOperationsAborted = FALSE;
memset (&file_op_w, 0, sizeof (file_op_w));
file_op_w.hwnd = HWND_DESKTOP;
file_op_w.wFunc = FO_DELETE;
file_op_w.pFrom = tmp_path_w;
file_op_w.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
| FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
file_op_w.fAnyOperationsAborted = FALSE;
if (SHFileOperation (&file_op) != 0)
report_file_error ("Removing old name", list1 (filename));
}
result = SHFileOperationW (&file_op_w);
}
else
{
SHFILEOPSTRUCTA file_op_a;
char tmp_path_a[MAX_PATH + 1];
memset (tmp_path_a, 0, sizeof (tmp_path_a));
filename_to_ansi (path, tmp_path_a);
/* If a file cannot be represented in ANSI codepage, don't
let them inadvertently delete other files because some
characters are interpreted as a wildcards. */
if (_mbspbrk (tmp_path_a, "?*"))
result = ERROR_FILE_NOT_FOUND;
else
{
_chmod (tmp_path_a, 0666);
memset (&file_op_a, 0, sizeof (file_op_a));
file_op_a.hwnd = HWND_DESKTOP;
file_op_a.wFunc = FO_DELETE;
file_op_a.pFrom = tmp_path_a;
file_op_a.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
| FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
file_op_a.fAnyOperationsAborted = FALSE;
result = SHFileOperationA (&file_op_a);
}
}
if (result != 0)
report_file_error ("Removing old name", list1 (filename));
}
return Qnil;
}
@ -6688,38 +6867,159 @@ an integer representing a ShowWindow flag:
6 - start minimized */)
(Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag)
{
Lisp_Object current_dir;
char *errstr;
Lisp_Object current_dir = BVAR (current_buffer, directory);;
wchar_t *doc_w = NULL, *params_w = NULL, *ops_w = NULL;
intptr_t result;
#ifndef CYGWIN
int use_unicode = w32_unicode_filenames;
char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
#endif
CHECK_STRING (document);
/* Encode filename, current directory and parameters. */
current_dir = BVAR (current_buffer, directory);
#ifdef CYGWIN
current_dir = Fcygwin_convert_file_name_to_windows (current_dir, Qt);
if (STRINGP (document))
document = Fcygwin_convert_file_name_to_windows (document, Qt);
#endif /* CYGWIN */
/* Encode filename, current directory and parameters. */
current_dir = GUI_ENCODE_FILE (current_dir);
if (STRINGP (document))
document = GUI_ENCODE_FILE (document);
{
document = GUI_ENCODE_FILE (document);
doc_w = GUI_SDATA (document);
}
if (STRINGP (parameters))
parameters = GUI_ENCODE_SYSTEM (parameters);
{
parameters = GUI_ENCODE_SYSTEM (parameters);
params_w = GUI_SDATA (parameters);
}
if (STRINGP (operation))
{
operation = GUI_ENCODE_SYSTEM (operation);
ops_w = GUI_SDATA (operation);
}
result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
GUI_SDATA (current_dir),
(INTEGERP (show_flag)
? XINT (show_flag) : SW_SHOWDEFAULT));
#else /* !CYGWIN */
if (use_unicode)
{
wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
if ((int) GUI_FN (ShellExecute) (NULL,
(STRINGP (operation) ?
GUI_SDATA (operation) : NULL),
GUI_SDATA (document),
(STRINGP (parameters) ?
GUI_SDATA (parameters) : NULL),
GUI_SDATA (current_dir),
(INTEGERP (show_flag) ?
XINT (show_flag) : SW_SHOWDEFAULT))
> 32)
/* Encode filename, current directory and parameters, and
convert operation to UTF-16. */
current_dir = ENCODE_FILE (current_dir);
filename_to_utf16 (SSDATA (current_dir), current_dir_w);
if (STRINGP (document))
{
document = ENCODE_FILE (document);
filename_to_utf16 (SSDATA (document), document_w);
doc_w = document_w;
}
if (STRINGP (parameters))
{
int len;
parameters = ENCODE_SYSTEM (parameters);
len = MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
SSDATA (parameters), -1, NULL, 0);
if (len > 32768)
len = 32768;
params_w = alloca (len * sizeof (wchar_t));
MultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
SSDATA (parameters), -1, params_w, len);
}
if (STRINGP (operation))
{
/* Assume OPERATION is pure ASCII. */
const char *s = SSDATA (operation);
wchar_t *d;
int len = SBYTES (operation) + 1;
if (len > 32768)
len = 32768;
d = ops_w = alloca (len * sizeof (wchar_t));
while (d < ops_w + len - 1)
*d++ = *s++;
*d = 0;
}
result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
current_dir_w,
(INTEGERP (show_flag)
? XINT (show_flag) : SW_SHOWDEFAULT));
}
else
{
char document_a[MAX_PATH], current_dir_a[MAX_PATH];
current_dir = ENCODE_FILE (current_dir);
filename_to_ansi (SSDATA (current_dir), current_dir_a);
if (STRINGP (document))
{
ENCODE_FILE (document);
filename_to_ansi (SSDATA (document), document_a);
doc_a = document_a;
}
if (STRINGP (parameters))
{
int len;
parameters = ENCODE_SYSTEM (parameters);
params_a = SSDATA (parameters);
}
if (STRINGP (operation))
{
/* Assume OPERATION is pure ASCII. */
ops_a = SSDATA (operation);
}
result = (intptr_t) ShellExecuteA (NULL, ops_a, doc_a, params_a,
current_dir_a,
(INTEGERP (show_flag)
? XINT (show_flag) : SW_SHOWDEFAULT));
}
#endif /* !CYGWIN */
if (result > 32)
return Qt;
errstr = w32_strerror (0);
switch (result)
{
case SE_ERR_ACCESSDENIED:
errstr = w32_strerror (ERROR_ACCESS_DENIED);
break;
case SE_ERR_ASSOCINCOMPLETE:
case SE_ERR_NOASSOC:
errstr = w32_strerror (ERROR_NO_ASSOCIATION);
break;
case SE_ERR_DDEBUSY:
case SE_ERR_DDEFAIL:
errstr = w32_strerror (ERROR_DDE_FAIL);
break;
case SE_ERR_DDETIMEOUT:
errstr = w32_strerror (ERROR_TIMEOUT);
break;
case SE_ERR_DLLNOTFOUND:
errstr = w32_strerror (ERROR_DLL_NOT_FOUND);
break;
case SE_ERR_FNF:
errstr = w32_strerror (ERROR_FILE_NOT_FOUND);
break;
case SE_ERR_OOM:
errstr = w32_strerror (ERROR_NOT_ENOUGH_MEMORY);
break;
case SE_ERR_PNF:
errstr = w32_strerror (ERROR_PATH_NOT_FOUND);
break;
case SE_ERR_SHARE:
errstr = w32_strerror (ERROR_SHARING_VIOLATION);
break;
default:
errstr = w32_strerror (0);
break;
}
/* The error string might be encoded in the locale's encoding. */
if (!NILP (Vlocale_coding_system))
{
@ -7132,14 +7432,23 @@ If the underlying system call fails, value is nil. */)
added rather late on. */
{
HMODULE hKernel = GetModuleHandle ("kernel32");
BOOL (*pfn_GetDiskFreeSpaceEx)
BOOL (*pfn_GetDiskFreeSpaceExW)
(wchar_t *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
= (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExW");
BOOL (*pfn_GetDiskFreeSpaceExA)
(char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
= (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
= (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceExA");
bool have_pfn_GetDiskFreeSpaceEx =
(w32_unicode_filenames && pfn_GetDiskFreeSpaceExW
|| !w32_unicode_filenames && pfn_GetDiskFreeSpaceExA);
/* On Windows, we may need to specify the root directory of the
volume holding FILENAME. */
char rootname[MAX_PATH];
char rootname[MAX_UTF8_PATH];
wchar_t rootname_w[MAX_PATH];
char rootname_a[MAX_PATH];
char *name = SDATA (encoded);
BOOL result;
/* find the root name of the volume if given */
if (isalpha (name[0]) && name[1] == ':')
@ -7165,7 +7474,12 @@ If the underlying system call fails, value is nil. */)
*str = 0;
}
if (pfn_GetDiskFreeSpaceEx)
if (w32_unicode_filenames)
filename_to_utf16 (rootname, rootname_w);
else
filename_to_ansi (rootname, rootname_a);
if (have_pfn_GetDiskFreeSpaceEx)
{
/* Unsigned large integers cannot be cast to double, so
use signed ones instead. */
@ -7173,10 +7487,17 @@ If the underlying system call fails, value is nil. */)
LARGE_INTEGER freebytes;
LARGE_INTEGER totalbytes;
if (pfn_GetDiskFreeSpaceEx (rootname,
(ULARGE_INTEGER *)&availbytes,
(ULARGE_INTEGER *)&totalbytes,
(ULARGE_INTEGER *)&freebytes))
if (w32_unicode_filenames)
result = pfn_GetDiskFreeSpaceExW (rootname_w,
(ULARGE_INTEGER *)&availbytes,
(ULARGE_INTEGER *)&totalbytes,
(ULARGE_INTEGER *)&freebytes);
else
result = pfn_GetDiskFreeSpaceExA (rootname_a,
(ULARGE_INTEGER *)&availbytes,
(ULARGE_INTEGER *)&totalbytes,
(ULARGE_INTEGER *)&freebytes);
if (result)
value = list3 (make_float ((double) totalbytes.QuadPart),
make_float ((double) freebytes.QuadPart),
make_float ((double) availbytes.QuadPart));
@ -7188,11 +7509,19 @@ If the underlying system call fails, value is nil. */)
DWORD free_clusters;
DWORD total_clusters;
if (GetDiskFreeSpace (rootname,
&sectors_per_cluster,
&bytes_per_sector,
&free_clusters,
&total_clusters))
if (w32_unicode_filenames)
result = GetDiskFreeSpaceW (rootname_w,
&sectors_per_cluster,
&bytes_per_sector,
&free_clusters,
&total_clusters);
else
result = GetDiskFreeSpaceA (rootname_a,
&sectors_per_cluster,
&bytes_per_sector,
&free_clusters,
&total_clusters);
if (result)
value = list3 (make_float ((double) total_clusters
* sectors_per_cluster * bytes_per_sector),
make_float ((double) free_clusters
@ -7207,6 +7536,7 @@ If the underlying system call fails, value is nil. */)
#endif /* WINDOWSNT */
#ifdef WINDOWSNT
DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
0, 0, 0, doc: /* Return the name of Windows default printer device. */)
(void)
@ -7214,8 +7544,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".
@ -7227,55 +7560,89 @@ 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)
{
ClosePrinter (hPrn);
return Qnil;
}
/* Call GetPrinter again with big enough memory block. */
err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
ClosePrinter (hPrn);
if (!err)
if (w32_unicode_filenames && os_subtype != OS_9X)
{
xfree (ppi2);
return Qnil;
}
/* Allocate memory for the PRINTER_INFO_2 struct. */
ppi2w = xmalloc (dwNeeded);
err = GetPrinterW (hPrn, 2, (LPBYTE)ppi2w, dwNeeded, &dwReturned);
ClosePrinter (hPrn);
if (!err)
{
xfree (ppi2w);
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 ((ppi2w->Attributes & PRINTER_ATTRIBUTE_SHARED)
&& ppi2w->pServerName)
{
filename_from_utf16 (ppi2w->pServerName, server_name);
filename_from_utf16 (ppi2w->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_utf16 (ppi2w->pPortName, port_name);
}
}
else
{
ppi2a = xmalloc (dwNeeded);
err = GetPrinterA (hPrn, 2, (LPBYTE)ppi2a, dwNeeded, &dwReturned);
ClosePrinter (hPrn);
if (!err)
{
xfree (ppi2a);
return Qnil;
}
if ((ppi2a->Attributes & PRINTER_ATTRIBUTE_SHARED)
&& ppi2a->pServerName)
{
filename_from_ansi (ppi2a->pServerName, server_name);
filename_from_ansi (ppi2a->pShareName, share_name);
}
else
{
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));
}
#endif /* WINDOWSNT */
/* Equivalent of strerror for W32 error codes. */
@ -7946,9 +8313,9 @@ only be necessary if the default setting causes problems. */);
#ifdef WINDOWSNT
defsubr (&Sfile_system_info);
defsubr (&Sdefault_printer_name);
#endif
defsubr (&Sdefault_printer_name);
defsubr (&Sset_message_beep);
hourglass_hwnd = NULL;

View file

@ -105,7 +105,7 @@ struct notification {
OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
BOOL subtree; /* whether to watch subdirectories */
DWORD filter; /* bit mask for events to watch */
char *watchee; /* the file we are interested in */
char *watchee; /* the file we are interested in, UTF-8 encoded */
HANDLE dir; /* handle to the watched directory */
HANDLE thr; /* handle to the thread that watches */
volatile int terminate; /* if non-zero, request for the thread to terminate */
@ -332,15 +332,43 @@ add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
if (!file)
return NULL;
hdir = CreateFile (parent_dir,
FILE_LIST_DIRECTORY,
/* FILE_SHARE_DELETE doesn't preclude other
processes from deleting files inside
parent_dir. */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (w32_unicode_filenames)
{
wchar_t dir_w[MAX_PATH], file_w[MAX_PATH];
filename_to_utf16 (parent_dir, dir_w);
if (*file)
filename_to_utf16 (file, file_w);
else
file_w[0] = 0;
hdir = CreateFileW (dir_w,
FILE_LIST_DIRECTORY,
/* FILE_SHARE_DELETE doesn't preclude other
processes from deleting files inside
parent_dir. */
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
}
else
{
char dir_a[MAX_PATH], file_a[MAX_PATH];
filename_to_ansi (parent_dir, dir_a);
if (*file)
filename_to_ansi (file, file_a);
else
file_a[0] = '\0';
hdir = CreateFileA (dir_a,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
}
if (hdir == INVALID_HANDLE_VALUE)
return NULL;
@ -490,9 +518,7 @@ will never come in. Volumes shared from remote Windows machines do
generate notifications correctly, though. */)
(Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
{
Lisp_Object encoded_file, watch_object, watch_descriptor;
char parent_dir[MAX_PATH], *basename;
size_t fn_len;
Lisp_Object dirfn, basefn, watch_object, watch_descriptor;
DWORD flags;
BOOL subdirs = FALSE;
struct notification *dirwatch = NULL;
@ -510,49 +536,33 @@ generate notifications correctly, though. */)
Qnil);
}
/* We need a full absolute file name of FILE, and we need to remove
any trailing slashes from it, so that GetFullPathName below gets
the basename part correctly. */
file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
encoded_file = ENCODE_FILE (file);
fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir,
&basename);
if (!fn_len)
{
errstr = w32_strerror (0);
errno = EINVAL;
if (!NILP (Vlocale_coding_system))
lisp_errstr
= code_convert_string_norecord (build_unibyte_string (errstr),
Vlocale_coding_system, 0);
else
lisp_errstr = build_string (errstr);
report_file_error ("GetFullPathName failed",
Fcons (lisp_errstr, Fcons (file, Qnil)));
}
/* filenotify.el always passes us a directory, either the parent
directory of a file to be watched, or the directory to be
watched. */
if (file_directory_p (parent_dir))
basename = "";
else
file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
if (NILP (Ffile_directory_p (file)))
{
/* This should only happen if we are called directly, not via
filenotify.el. If BASENAME is NULL, the argument was the
root directory on its drive. */
if (basename)
basename[-1] = '\0';
else
filenotify.el. If BASEFN is empty, the argument was the root
directory on its drive. */
dirfn = ENCODE_FILE (Ffile_name_directory (file));
basefn = ENCODE_FILE (Ffile_name_nondirectory (file));
if (*SDATA (basefn) == '\0')
subdirs = TRUE;
}
else
{
dirfn = ENCODE_FILE (file);
basefn = Qnil;
}
if (!NILP (Fmember (Qsubtree, filter)))
subdirs = TRUE;
flags = filter_list_to_flags (filter);
dirwatch = add_watch (parent_dir, basename, subdirs, flags);
dirwatch = add_watch (SSDATA (dirfn), NILP (basefn) ? "" : SSDATA (basefn),
subdirs, flags);
if (!dirwatch)
{
DWORD err = GetLastError ();

View file

@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
#include <mbstring.h>
/* must include CRT headers *before* config.h */
#include <config.h>
@ -861,8 +862,6 @@ new_child (void)
cp->pid = -1;
cp->procinfo.hProcess = NULL;
cp->status = STATUS_READ_ERROR;
cp->input_file = NULL;
cp->pending_deletion = 0;
/* use manual reset event so that select() will function properly */
cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
@ -911,21 +910,6 @@ delete_child (child_process *cp)
if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
return;
/* Delete the child's temporary input file, if any, that is pending
deletion. */
if (cp->input_file)
{
if (cp->pending_deletion)
{
if (unlink (cp->input_file))
DebPrint (("delete_child.unlink (%s) failed, errno: %d\n",
cp->input_file, errno));
cp->pending_deletion = 0;
}
xfree (cp->input_file);
cp->input_file = NULL;
}
/* reap thread if necessary */
if (cp->thrd)
{
@ -1073,9 +1057,10 @@ reader_thread (void *arg)
return 0;
}
/* To avoid Emacs changing directory, we just record here the directory
the new process should start in. This is set just before calling
sys_spawnve, and is not generally valid at any other time. */
/* To avoid Emacs changing directory, we just record here the
directory the new process should start in. This is set just before
calling sys_spawnve, and is not generally valid at any other time.
Note that this directory's name is UTF-8 encoded. */
static char * process_dir;
static BOOL
@ -1088,7 +1073,8 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
SECURITY_DESCRIPTOR sec_desc;
#endif
DWORD flags;
char dir[ MAXPATHLEN ];
char dir[ MAX_PATH ];
char *p;
if (cp == NULL) emacs_abort ();
@ -1118,16 +1104,22 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
sec_attrs.bInheritHandle = FALSE;
strcpy (dir, process_dir);
unixtodos_filename (dir);
filename_to_ansi (process_dir, dir);
/* Can't use unixtodos_filename here, since that needs its file name
argument encoded in UTF-8. OTOH, process_dir, which _is_ in
UTF-8, points, to the directory computed by our caller, and we
don't want to modify that, either. */
for (p = dir; *p; p = CharNextA (p))
if (*p == '/')
*p = '\\';
flags = (!NILP (Vw32_start_process_share_console)
? CREATE_NEW_PROCESS_GROUP
: CREATE_NEW_CONSOLE);
if (NILP (Vw32_start_process_inherit_error_mode))
flags |= CREATE_DEFAULT_ERROR_MODE;
if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
flags, env, dir, &start, &cp->procinfo))
if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
flags, env, dir, &start, &cp->procinfo))
goto EH_Fail;
cp->pid = (int) cp->procinfo.dwProcessId;
@ -1182,45 +1174,6 @@ register_child (pid_t pid, int fd)
fd_info[fd].cp = cp;
}
/* Record INFILE as an input file for process PID. */
void
record_infile (pid_t pid, char *infile)
{
child_process *cp;
/* INFILE should never be NULL, since xstrdup would have signaled
memory full condition in that case, see callproc.c where this
function is called. */
eassert (infile);
cp = find_child_pid ((DWORD)pid);
if (cp == NULL)
{
DebPrint (("record_infile is unable to find pid %lu\n", pid));
return;
}
cp->input_file = infile;
}
/* Mark the input file INFILE of the corresponding subprocess as
temporary, to be deleted when the subprocess exits. */
void
record_pending_deletion (char *infile)
{
child_process *cp;
eassert (infile);
for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
if (CHILD_ACTIVE (cp)
&& cp->input_file && xstrcasecmp (cp->input_file, infile) == 0)
{
cp->pending_deletion = 1;
break;
}
}
/* Called from waitpid when a process exits. */
static void
reap_subprocess (child_process *cp)
@ -1427,6 +1380,8 @@ waitpid (pid_t pid, int *status, int options)
# define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
#endif
/* Implementation note: This function works with file names encoded in
the current ANSI codepage. */
static void
w32_executable_type (char * filename,
int * is_dos_app,
@ -1617,6 +1572,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
char *sepchars = " \t*?";
/* This is for native w32 apps; modified below for Cygwin apps. */
char escape_char = '\\';
char cmdname_a[MAX_PATH];
/* We don't care about the other modes */
if (mode != _P_NOWAIT)
@ -1625,12 +1581,15 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
return -1;
}
/* Handle executable names without an executable suffix. */
program = build_string (cmdname);
if (NILP (Ffile_executable_p (program)))
/* Handle executable names without an executable suffix. The caller
already searched exec-path and verified the file is executable,
but start-process doesn't do that for file names that are already
absolute. So we double-check this here, just in case. */
if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0)
{
struct gcpro gcpro1;
program = build_string (cmdname);
full = Qnil;
GCPRO1 (program);
openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK));
@ -1640,12 +1599,27 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
errno = EINVAL;
return -1;
}
program = full;
program = ENCODE_FILE (full);
cmdname = SDATA (program);
}
/* make sure argv[0] and cmdname are both in DOS format */
cmdname = SDATA (program);
unixtodos_filename (cmdname);
/* argv[0] was encoded by caller using ENCODE_FILE, so it is in
UTF-8. All the other arguments are encoded by ENCODE_SYSTEM or
some such, and are in some ANSI codepage. We need to have
argv[0] encoded in ANSI codepage. */
filename_to_ansi (cmdname, cmdname_a);
/* We explicitly require that the command's file name be encodable
in the current ANSI codepage, because we will be invoking it via
the ANSI APIs. */
if (_mbspbrk (cmdname_a, "?"))
{
errno = ENOENT;
return -1;
}
/* From here on, CMDNAME is an ANSI-encoded string. */
cmdname = cmdname_a;
argv[0] = cmdname;
/* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
@ -1663,7 +1637,9 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
while leaving the real app name as argv[0]. */
if (is_dos_app)
{
cmdname = alloca (MAXPATHLEN);
char *p;
cmdname = alloca (MAX_PATH);
if (egetenv ("CMDPROXY"))
strcpy (cmdname, egetenv ("CMDPROXY"));
else
@ -1671,7 +1647,12 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
strcpy (cmdname, SDATA (Vinvocation_directory));
strcat (cmdname, "cmdproxy.exe");
}
unixtodos_filename (cmdname);
/* Can't use unixtodos_filename here, since that needs its file
name argument encoded in UTF-8. */
for (p = cmdname; *p; p = CharNextA (p))
if (*p == '/')
*p = '\\';
}
/* we have to do some conjuring here to put argv and envp into the
@ -2673,10 +2654,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);
@ -2690,7 +2672,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);
@ -2702,10 +2684,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
@ -2713,7 +2696,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,

View file

@ -52,6 +52,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "keymap.h"
#ifdef WINDOWSNT
#include "w32.h" /* for filename_from_utf16, filename_from_ansi */
#include "w32heap.h"
#endif
@ -3128,7 +3129,14 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
HDROP hdrop;
POINT p;
WORD num_files;
guichar_t *name;
wchar_t name_w[MAX_PATH];
#ifdef NTGUI_UNICODE
const int use_unicode = 1;
#else
int use_unicode = w32_unicode_filenames;
char name_a[MAX_PATH];
char file[MAX_UTF8_PATH];
#endif
int i, len;
result->kind = DRAG_N_DROP_EVENT;
@ -3153,17 +3161,30 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f)
for (i = 0; i < num_files; i++)
{
len = GUI_FN (DragQueryFile) (hdrop, i, NULL, 0);
if (len <= 0)
continue;
name = alloca ((len + 1) * sizeof (*name));
GUI_FN (DragQueryFile) (hdrop, i, name, len + 1);
if (use_unicode)
{
eassert (DragQueryFileW (hdrop, i, NULL, 0) < MAX_PATH);
/* If DragQueryFile returns zero, it failed to fetch a file
name. */
if (DragQueryFileW (hdrop, i, name_w, MAX_PATH) == 0)
continue;
#ifdef NTGUI_UNICODE
files = Fcons (from_unicode_buffer (name), files);
files = Fcons (from_unicode_buffer (name_w), files);
#else
files = Fcons (DECODE_FILE (build_string (name)), files);
filename_from_utf16 (name_w, file);
files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
#endif /* NTGUI_UNICODE */
}
#ifndef NTGUI_UNICODE
else
{
eassert (DragQueryFileA (hdrop, i, NULL, 0) < MAX_PATH);
if (DragQueryFileA (hdrop, i, name_a, MAX_PATH) == 0)
continue;
filename_from_ansi (name_a, file);
files = Fcons (DECODE_FILE (build_unibyte_string (file)), files);
}
#endif
}
DragFinish (hdrop);
@ -6640,6 +6661,18 @@ X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
With MS Windows or Nextstep, the value is t. */);
Vx_toolkit_scroll_bars = Qt;
DEFVAR_BOOL ("w32-unicode-filenames",
w32_unicode_filenames,
doc: /* Non-nil means use Unicode APIs when passing file names to the OS.
A value of nil means file names passed to the OS APIs and returned
from those APIs are encoded/decoded using the ANSI codepage
specified by `file-name-coding-system'.
This variable is set to non-nil by default when Emacs runs on Windows
systems of the NT family, including W2K, XP, Vista, Windows 7 and
Windows 8. It is set to nil on Windows 9X. */);
w32_unicode_filenames = 0;
/* Tell Emacs about this window system. */
Fprovide (Qw32, Qnil);
}