X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d5db40779d7505244d37476b4f046641f07eea2b..14b6e3bb481f4cb48f397c50ae8116b6fc39c937:/src/w32proc.c diff --git a/src/w32proc.c b/src/w32proc.c index a44a326caf..7d27172781 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -1,5 +1,6 @@ /* Process support for GNU Emacs on the Microsoft W32 API. - Copyright (C) 1992, 1995, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1992, 1995, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. Drew Bliss Oct 14, 1993 Adapted from alarm.c by Tim Fleehart @@ -48,6 +49,11 @@ Boston, MA 02111-1307, USA. extern BOOL WINAPI IsValidLocale(LCID, DWORD); #endif +#ifdef HAVE_LANGINFO_CODESET +#include +#include +#endif + #include "lisp.h" #include "w32.h" #include "w32heap.h" @@ -57,6 +63,11 @@ extern BOOL WINAPI IsValidLocale(LCID, DWORD); #include "syssignal.h" #include "w32term.h" +#define RVA_TO_PTR(var,section,filedata) \ + ((void *)((section)->PointerToRawData \ + + ((DWORD)(var) - (section)->VirtualAddress) \ + + (filedata).file_base)) + /* Control whether spawnve quotes arguments as necessary to ensure correct parsing by child process. Because not all uses of spawnve are careful about constructing argv arrays, we make this behaviour @@ -82,7 +93,7 @@ Lisp_Object Vw32_start_process_inherit_error_mode; avoids the inefficiency of frequently reading small amounts of data. This is primarily necessary for handling DOS processes on Windows 95, but is useful for W32 processes on both Windows 95 and NT as well. */ -Lisp_Object Vw32_pipe_read_delay; +int w32_pipe_read_delay; /* Control conversion of upper case file names to lower case. nil means no, t means yes. */ @@ -120,11 +131,11 @@ typedef void (_CALLBACK_ *signal_handler)(int); static signal_handler sig_handlers[NSIG]; /* Fake signal implementation to record the SIGCHLD handler. */ -signal_handler +signal_handler sys_signal (int sig, signal_handler handler) { signal_handler old; - + if (sig != SIGCHLD) { errno = EINVAL; @@ -151,7 +162,7 @@ new_child (void) { child_process *cp; DWORD id; - + for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) if (!CHILD_ACTIVE (cp)) goto Initialise; @@ -182,7 +193,7 @@ new_child (void) return NULL; } -void +void delete_child (child_process *cp) { int i; @@ -257,14 +268,14 @@ find_child_pid (DWORD pid) is normally blocked until woken by select() to check for input by reading one char. When the read completes, char_avail is signalled to wake up the select emulator and the thread blocks itself again. */ -DWORD WINAPI +DWORD WINAPI reader_thread (void *arg) { child_process *cp; - + /* Our identity */ cp = (child_process *)arg; - + /* We have to wait for the go-ahead before we can start */ if (cp == NULL || WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0) @@ -274,7 +285,10 @@ reader_thread (void *arg) { int rc; - rc = _sys_read_ahead (cp->fd); + if (fd_info[cp->fd].flags & FILE_LISTEN) + rc = _sys_wait_accept (cp->fd); + else + rc = _sys_read_ahead (cp->fd); /* The name char_avail is a misnomer - it really just means the read-ahead has completed, whether successfully or not. */ @@ -287,11 +301,11 @@ reader_thread (void *arg) if (rc == STATUS_READ_ERROR) return 1; - + /* If the read died, the child has died so let the thread die */ if (rc == STATUS_READ_FAILED) break; - + /* Wait until our input is acknowledged before reading again */ if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0) { @@ -308,7 +322,7 @@ reader_thread (void *arg) sys_spawnve, and is not generally valid at any other time. */ static char * process_dir; -static BOOL +static BOOL create_child (char *exe, char *cmdline, char *env, int is_gui_app, int * pPid, child_process *cp) { @@ -319,12 +333,12 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, #endif DWORD flags; char dir[ MAXPATHLEN ]; - + if (cp == NULL) abort (); - + memset (&start, 0, sizeof (start)); start.cb = sizeof (start); - + #ifdef HAVE_NTGUI if (NILP (Vw32_start_process_show_window) && !is_gui_app) start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; @@ -347,7 +361,7 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, sec_attrs.nLength = sizeof (sec_attrs); sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */; sec_attrs.bInheritHandle = FALSE; - + strcpy (dir, process_dir); unixtodos_filename (dir); @@ -367,7 +381,7 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, cp->pid = -cp->pid; /* pid must fit in a Lisp_Int */ - cp->pid = (cp->pid & VALMASK); + cp->pid = cp->pid & INTMASK; *pPid = cp->pid; @@ -383,22 +397,22 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, to register the handle with the process This way the select emulator knows how to match file handles with entries in child_procs. */ -void +void register_child (int pid, int fd) { child_process *cp; - + cp = find_child_pid (pid); if (cp == NULL) { DebPrint (("register_child unable to find pid %lu\n", pid)); return; } - + #ifdef FULL_DEBUG DebPrint (("register_child registered fd %d with pid %lu\n", fd, pid)); #endif - + cp->fd = fd; /* thread is initially blocked until select is called; set status so @@ -419,7 +433,7 @@ register_child (int pid, int fd) signal failure to the select emulator. The select emulator then calls this routine to clean up. Since the thread signaled failure we can assume it is exiting. */ -static void +static void reap_subprocess (child_process *cp) { if (cp->procinfo.hProcess) @@ -448,7 +462,7 @@ reap_subprocess (child_process *cp) When it does, close its handle Return the pid and fill in the status if non-NULL. */ -int +int sys_wait (int *status) { DWORD active, retval; @@ -456,7 +470,7 @@ sys_wait (int *status) int pid; child_process *cp, *cps[MAX_CHILDREN]; HANDLE wait_hnd[MAX_CHILDREN]; - + nh = 0; if (dead_child != NULL) { @@ -472,14 +486,15 @@ sys_wait (int *status) { for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) /* some child_procs might be sockets; ignore them */ - if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess) + if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess + && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) { wait_hnd[nh] = cp->procinfo.hProcess; cps[nh] = cp; nh++; } } - + if (nh == 0) { /* Nothing to wait on, so fail */ @@ -535,7 +550,7 @@ get_result: retval = SIGINT; else retval <<= 8; - + cp = cps[active]; pid = cp->pid; #ifdef FULL_DEBUG @@ -571,7 +586,7 @@ get_result: } reap_subprocess (cp); - + return pid; } @@ -580,7 +595,7 @@ w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app, int { file_data executable; char * p; - + /* Default values in case we can't tell for sure. */ *is_dos_app = FALSE; *is_cygnus_app = FALSE; @@ -590,7 +605,7 @@ w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app, int return; p = strrchr (filename, '.'); - + /* We can only identify DOS .com programs from the extension. */ if (p && stricmp (p, ".com") == 0) *is_dos_app = TRUE; @@ -623,11 +638,11 @@ w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app, int nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew); - if ((char *) nt_header > (char *) dos_header + executable.size) + if ((char *) nt_header > (char *) dos_header + executable.size) { /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ *is_dos_app = TRUE; - } + } else if (nt_header->Signature != IMAGE_NT_SIGNATURE && LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE) { @@ -664,7 +679,7 @@ w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app, int *is_gui_app = (nt_header->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI); } } - + unwind: close_file_data (&executable); } @@ -717,7 +732,7 @@ merge_and_sort_env (char **envp1, char **envp2, char **new_envp) /* When a new child process is created we need to register it in our list, so intercept spawn requests. */ -int +int sys_spawnve (int mode, char *cmdname, char **argv, char **envp) { Lisp_Object program, full; @@ -746,7 +761,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) if (NILP (Ffile_executable_p (program))) { struct gcpro gcpro1; - + full = Qnil; GCPRO1 (program); openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK)); @@ -789,7 +804,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) } unixtodos_filename (cmdname); } - + /* we have to do some conjuring here to put argv and envp into the form CreateProcess wants... argv needs to be a space separated/null terminated list of parameters, and envp is a null @@ -830,8 +845,8 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) else escape_char = is_cygnus_app ? '"' : '\\'; } - - /* Cygwin apps needs quoting a bit more often */ + + /* Cygwin apps needs quoting a bit more often */ if (escape_char == '"') sepchars = "\r\n\t\f '"; @@ -966,7 +981,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) targ++; } *--parg = '\0'; - + /* and envp... */ arglen = 1; targ = envp; @@ -977,7 +992,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) numenv++; } /* extra env vars... */ - sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", + sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", GetCurrentProcessId ()); arglen += strlen (ppid_env_var_buffer) + 1; numenv++; @@ -1004,7 +1019,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) errno = EAGAIN; return -1; } - + /* Now create the process. */ if (!create_child (cmdname, cmdline, env, is_gui_app, &pid, cp)) { @@ -1012,7 +1027,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) errno = ENOEXEC; return -1; } - + return pid; } @@ -1043,7 +1058,7 @@ extern HANDLE interrupt_handle; /* From process.c */ extern int proc_buffered_char[]; -int +int sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, EMACS_TIME *timeout) { @@ -1054,11 +1069,11 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, child_process *cp, *cps[MAX_CHILDREN]; HANDLE wait_hnd[MAXDESC + MAX_CHILDREN]; int fdindex[MAXDESC]; /* mapping from wait handles back to descriptors */ - + timeout_ms = timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFINITE; /* If the descriptor sets are NULL but timeout isn't, then just Sleep. */ - if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) + if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) { Sleep (timeout_ms); return 0; @@ -1070,7 +1085,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, errno = EINVAL; return -1; } - + orfds = *rfds; FD_ZERO (rfds); nr = 0; @@ -1078,7 +1093,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, /* Always wait on interrupt_handle, to detect C-g (quit). */ wait_hnd[0] = interrupt_handle; fdindex[0] = -1; - + /* Build a list of pipe handles to wait on. */ nh = 1; for (i = 0; i < nfds; i++) @@ -1195,15 +1210,15 @@ count_children: cps[nc] = cp; nc++; } - + /* Nothing to look for, so we didn't find anything */ - if (nh + nc == 0) + if (nh + nc == 0) { if (timeout) Sleep (timeout_ms); return 0; } - + start_time = GetTickCount (); /* Wait for input or child death to be signalled. If user input is @@ -1218,7 +1233,7 @@ count_children: { DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n", nh + nc, timeout_ms, GetLastError ())); - /* don't return EBADF - this causes wait_reading_process_input to + /* don't return EBADF - this causes wait_reading_process_output to abort; WAIT_FAILED is returned when single-stepping under Windows 95 after switching thread focus in debugger, and possibly at other times. */ @@ -1362,14 +1377,14 @@ find_child_console (HWND hwnd, LPARAM arg) return TRUE; } -int +int sys_kill (int pid, int sig) { child_process *cp; HANDLE proc_hand; int need_to_free = 0; int rc = 0; - + /* Only handle signals that will result in the process dying */ if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP) { @@ -1396,7 +1411,7 @@ sys_kill (int pid, int sig) /* Try to locate console window for process. */ EnumWindows (find_child_console, (LPARAM) cp); } - + if (sig == SIGINT || sig == SIGQUIT) { if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd) @@ -1572,15 +1587,15 @@ prepare_standard_handles (int in, int out, int err, HANDLE handles[3]) handles[2] = GetStdHandle (STD_ERROR_HANDLE); /* make inheritable copies of the new handles */ - if (!DuplicateHandle (parent, + if (!DuplicateHandle (parent, (HANDLE) _get_osfhandle (in), parent, - &newstdin, - 0, - TRUE, + &newstdin, + 0, + TRUE, DUPLICATE_SAME_ACCESS)) report_file_error ("Duplicating input handle for child", Qnil); - + if (!DuplicateHandle (parent, (HANDLE) _get_osfhandle (out), parent, @@ -1589,7 +1604,7 @@ prepare_standard_handles (int in, int out, int err, HANDLE handles[3]) TRUE, DUPLICATE_SAME_ACCESS)) report_file_error ("Duplicating output handle for child", Qnil); - + if (!DuplicateHandle (parent, (HANDLE) _get_osfhandle (err), parent, @@ -1602,7 +1617,7 @@ prepare_standard_handles (int in, int out, int err, HANDLE handles[3]) /* and store them as our std handles */ if (!SetStdHandle (STD_INPUT_HANDLE, newstdin)) report_file_error ("Changing stdin handle", Qnil); - + if (!SetStdHandle (STD_OUTPUT_HANDLE, newstdout)) report_file_error ("Changing stdout handle", Qnil); @@ -1808,6 +1823,69 @@ If successful, the return value is t, otherwise nil. */) return result; } +#ifdef HAVE_LANGINFO_CODESET +/* Emulation of nl_langinfo. Used in fns.c:Flocale_info. */ +char *nl_langinfo (nl_item item) +{ + /* Conversion of Posix item numbers to their Windows equivalents. */ + static const LCTYPE w32item[] = { + LOCALE_IDEFAULTANSICODEPAGE, + LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, + LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, + LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, + LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, + LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, + LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12 + }; + + static char *nl_langinfo_buf = NULL; + static int nl_langinfo_len = 0; + + if (nl_langinfo_len <= 0) + nl_langinfo_buf = xmalloc (nl_langinfo_len = 1); + + if (item < 0 || item >= _NL_NUM) + nl_langinfo_buf[0] = 0; + else + { + LCID cloc = GetThreadLocale (); + int need_len = GetLocaleInfo (cloc, w32item[item] | LOCALE_USE_CP_ACP, + NULL, 0); + + if (need_len <= 0) + nl_langinfo_buf[0] = 0; + else + { + if (item == CODESET) + { + need_len += 2; /* for the "cp" prefix */ + if (need_len < 8) /* for the case we call GetACP */ + need_len = 8; + } + if (nl_langinfo_len <= need_len) + nl_langinfo_buf = xrealloc (nl_langinfo_buf, + nl_langinfo_len = need_len); + if (!GetLocaleInfo (cloc, w32item[item] | LOCALE_USE_CP_ACP, + nl_langinfo_buf, nl_langinfo_len)) + nl_langinfo_buf[0] = 0; + else if (item == CODESET) + { + if (strcmp (nl_langinfo_buf, "0") == 0 /* CP_ACP */ + || strcmp (nl_langinfo_buf, "1") == 0) /* CP_OEMCP */ + sprintf (nl_langinfo_buf, "cp%u", GetACP ()); + else + { + memmove (nl_langinfo_buf + 2, nl_langinfo_buf, + strlen (nl_langinfo_buf) + 1); + nl_langinfo_buf[0] = 'c'; + nl_langinfo_buf[1] = 'p'; + } + } + } + } + return nl_langinfo_buf; +} +#endif /* HAVE_LANGINFO_CODESET */ DEFUN ("w32-get-locale-info", Fw32_get_locale_info, Sw32_get_locale_info, 1, 2, 0, @@ -1933,7 +2011,7 @@ human-readable form. */) return make_number (GetUserDefaultLCID ()); } - + DEFUN ("w32-set-current-locale", Fw32_set_current_locale, Sw32_set_current_locale, 1, 1, 0, doc: /* Make Windows locale LCID be the current locale setting for Emacs. If successful, the new locale id is returned, otherwise nil. */) @@ -1990,7 +2068,7 @@ DEFUN ("w32-get-console-codepage", Fw32_get_console_codepage, return make_number (GetConsoleCP ()); } - + DEFUN ("w32-set-console-codepage", Fw32_set_console_codepage, Sw32_set_console_codepage, 1, 1, 0, doc: /* Make Windows codepage CP be the current codepage setting for Emacs. @@ -2019,7 +2097,7 @@ DEFUN ("w32-get-console-output-codepage", Fw32_get_console_output_codepage, return make_number (GetConsoleOutputCP ()); } - + DEFUN ("w32-set-console-output-codepage", Fw32_set_console_output_codepage, Sw32_set_console_output_codepage, 1, 1, 0, doc: /* Make Windows codepage CP be the current codepage setting for Emacs. @@ -2099,7 +2177,7 @@ The return value is the cons of the language id and the layout id. */) make_number ((kl >> 16) & 0xffff)); } - + DEFUN ("w32-set-keyboard-layout", Fw32_set_keyboard_layout, Sw32_set_keyboard_layout, 1, 1, 0, doc: /* Make LAYOUT be the current keyboard layout for Emacs. @@ -2141,6 +2219,8 @@ syms_of_ntproc () { Qhigh = intern ("high"); Qlow = intern ("low"); + staticpro (&Qhigh); + staticpro (&Qlow); #ifdef HAVE_SOCKETS defsubr (&Sw32_has_winsock); @@ -2202,7 +2282,7 @@ When non-nil, they inherit their error mode setting from Emacs, which stops them blocking when trying to access unmounted drives etc. */); Vw32_start_process_inherit_error_mode = Qt; - DEFVAR_INT ("w32-pipe-read-delay", &Vw32_pipe_read_delay, + DEFVAR_INT ("w32-pipe-read-delay", &w32_pipe_read_delay, doc: /* Forced delay before reading subprocess output. This is done to improve the buffering of subprocess output, by avoiding the inefficiency of frequently reading small amounts of data. @@ -2211,14 +2291,14 @@ If positive, the value is the number of milliseconds to sleep before reading the subprocess output. If negative, the magnitude is the number of time slices to wait (effectively boosting the priority of the child process temporarily). A value of zero disables waiting entirely. */); - Vw32_pipe_read_delay = 50; + w32_pipe_read_delay = 50; DEFVAR_LISP ("w32-downcase-file-names", &Vw32_downcase_file_names, doc: /* Non-nil means convert all-upper case file names to lower case. This applies when performing completions and file name expansion. Note that the value of this setting also affects remote file names, so you probably don't want to set to non-nil if you use case-sensitive -filesystems via ange-ftp. */); +filesystems via ange-ftp. */); Vw32_downcase_file_names = Qnil; #if 0 @@ -2232,10 +2312,15 @@ the truename of a file can be slow. */); #endif DEFVAR_LISP ("w32-get-true-file-attributes", &Vw32_get_true_file_attributes, - doc: /* Non-nil means determine accurate link count in file-attributes. -This option slows down file-attributes noticeably, so is disabled by -default. Note that it is only useful for files on NTFS volumes, -where hard links are supported. */); + doc: /* Non-nil means determine accurate link count in `file-attributes'. +Note that this option is only useful for files on NTFS volumes, where hard links +are supported. Moreover, it slows down `file-attributes' noticeably. */); Vw32_get_true_file_attributes = Qt; + + staticpro (&Vw32_valid_locale_ids); + staticpro (&Vw32_valid_codepages); } /* end of ntproc.c */ + +/* arch-tag: 23d3a34c-06d2-48a1-833b-ac7609aa5250 + (do not change this comment) */