conditional (off by default). */
Lisp_Object Vwin32_quote_process_args;
+/* Time to sleep before reading from a subprocess output pipe - this
+ 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 Win32 processes on both Win95 and NT as well. */
+Lisp_Object Vwin32_pipe_read_delay;
+
+/* Control conversion of upper case file names to lower case.
+ nil means no, t means yes. */
+Lisp_Object Vwin32_downcase_file_names;
+
+/* Keep track of whether we have already started a DOS program. */
+BOOL dos_process_running;
+
#ifndef SYS_SIGLIST_DECLARED
extern char *sys_siglist[];
#endif
cp->procinfo.hProcess = NULL;
CloseHandle (cp->procinfo.hThread);
cp->procinfo.hThread = NULL;
+
+ /* If this was a DOS process, indicate that it is now safe to
+ start a new one. */
+ if (cp->is_dos_process)
+ dos_process_running = FALSE;
}
/* For asynchronous children, the child_proc resources will be freed
return pid;
}
+int
+win32_is_dos_binary (char * filename)
+{
+ IMAGE_DOS_HEADER dos_header;
+ DWORD signature;
+ int fd;
+ int is_dos_binary = FALSE;
+
+ fd = open (filename, O_RDONLY | O_BINARY, 0);
+ if (fd >= 0)
+ {
+ char * p = strrchr (filename, '.');
+
+ /* We can only identify DOS .com programs from the extension. */
+ if (p && stricmp (p, ".com") == 0)
+ is_dos_binary = TRUE;
+ else if (p && stricmp (p, ".bat") == 0)
+ {
+ /* A DOS shell script - it appears that CreateProcess is happy
+ to accept this (somewhat surprisingly); presumably it looks
+ at COMSPEC to determine what executable to actually invoke.
+ Therefore, we have to do the same here as well. */
+ p = getenv ("COMSPEC");
+ if (p)
+ is_dos_binary = win32_is_dos_binary (p);
+ }
+ else
+ {
+ /* Look for DOS .exe signature - if found, we must also check
+ that it isn't really a 16- or 32-bit Windows exe, since
+ both formats start with a DOS program stub. Note that
+ 16-bit Windows executables use the OS/2 1.x format. */
+ if (read (fd, &dos_header, sizeof (dos_header)) == sizeof (dos_header)
+ && dos_header.e_magic == IMAGE_DOS_SIGNATURE
+ && lseek (fd, dos_header.e_lfanew, SEEK_SET) != -1)
+ {
+ if (read (fd, &signature, sizeof (signature)) != sizeof (signature)
+ || (signature != IMAGE_NT_SIGNATURE &&
+ LOWORD (signature) != IMAGE_OS2_SIGNATURE))
+ is_dos_binary = TRUE;
+ }
+ }
+ close (fd);
+ }
+
+ return is_dos_binary;
+}
+
/* We pass our process ID to our children by setting up an environment
variable in their environment. */
char ppid_env_var_buffer[64];
int arglen;
int pid;
child_process *cp;
+ int is_dos_binary;
/* We don't care about the other modes */
if (mode != _P_NOWAIT)
strcpy (cmdname = alloca (strlen (cmdname) + 1), argv[0]);
unixtodos_filename (cmdname);
argv[0] = cmdname;
+
+ /* Check if program is a DOS executable, and if so whether we are
+ allowed to start it. */
+ is_dos_binary = win32_is_dos_binary (cmdname);
+ if (is_dos_binary && dos_process_running)
+ {
+ errno = EAGAIN;
+ return -1;
+ }
/* 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
errno = ENOEXEC;
return -1;
}
+
+ if (is_dos_binary)
+ {
+ cp->is_dos_process = TRUE;
+ dos_process_running = TRUE;
+ }
return pid;
}
else
{
/* Kill the process. On Win32 this doesn't kill child processes
- so it doesn't work very well for shells which is why it's
- not used in every case. */
- if (!TerminateProcess (proc_hand, 0xff))
+ so it doesn't work very well for shells which is why it's not
+ used in every case. Also, don't try to terminate DOS processes
+ (on Win95), because this will hang Emacs. */
+ if (!(cp && cp->is_dos_process)
+ && !TerminateProcess (proc_hand, 0xff))
{
DebPrint (("sys_kill.TerminateProcess returned %d "
"for pid %lu\n", GetLastError (), pid));
SetStdHandle (STD_ERROR_HANDLE, handles[2]);
}
+#ifdef HAVE_SOCKETS
+
+/* To avoid problems with winsock implementations that work over dial-up
+ connections causing or requiring a connection to exist while Emacs is
+ running, Emacs no longer automatically loads winsock on startup if it
+ is present. Instead, it will be loaded when open-network-stream is
+ first called.
+
+ To allow full control over when winsock is loaded, we provide these
+ two functions to dynamically load and unload winsock. This allows
+ dial-up users to only be connected when they actually need to use
+ socket services. */
+
+/* From nt.c */
+extern HANDLE winsock_lib;
+extern BOOL term_winsock (void);
+extern BOOL init_winsock (int load_now);
+
+extern Lisp_Object Vsystem_name;
+
+DEFUN ("win32-has-winsock", Fwin32_has_winsock, Swin32_has_winsock, 0, 1, 0,
+ "Test for presence of the Windows socket library `winsock'.\n\
+Returns non-nil if winsock support is present, nil otherwise.\n\
+\n\
+If the optional argument LOAD-NOW is non-nil, the winsock library is\n\
+also loaded immediately if not already loaded. If winsock is loaded,\n\
+the winsock local hostname is returned (since this may be different from\n\
+the value of `system-name' and should supplant it), otherwise t is\n\
+returned to indicate winsock support is present.")
+ (load_now)
+ Lisp_Object load_now;
+{
+ int have_winsock;
+
+ have_winsock = init_winsock (!NILP (load_now));
+ if (have_winsock)
+ {
+ if (winsock_lib != NULL)
+ {
+ /* Return new value for system-name. The best way to do this
+ is to call init_system_name, saving and restoring the
+ original value to avoid side-effects. */
+ Lisp_Object orig_hostname = Vsystem_name;
+ Lisp_Object hostname;
+
+ init_system_name ();
+ hostname = Vsystem_name;
+ Vsystem_name = orig_hostname;
+ return hostname;
+ }
+ return Qt;
+ }
+ return Qnil;
+}
+
+DEFUN ("win32-unload-winsock", Fwin32_unload_winsock, Swin32_unload_winsock,
+ 0, 0, 0,
+ "Unload the Windows socket library `winsock' if loaded.\n\
+This is provided to allow dial-up socket connections to be disconnected\n\
+when no longer needed. Returns nil without unloading winsock if any\n\
+socket connections still exist.")
+ ()
+{
+ return term_winsock () ? Qt : Qnil;
+}
+
+#endif /* HAVE_SOCKETS */
+
\f
syms_of_ntproc ()
{
+#ifdef HAVE_SOCKETS
+ defsubr (&Swin32_has_winsock);
+ defsubr (&Swin32_unload_winsock);
+#endif
+
DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args,
"Non-nil enables quoting of process arguments to ensure correct parsing.\n\
Because Windows does not directly pass argv arrays to child processes,\n\
constructed (or arguments have already been quoted), so enabling this\n\
option may cause unexpected behavior.");
Vwin32_quote_process_args = Qnil;
+
+ DEFVAR_INT ("win32-pipe-read-delay", &Vwin32_pipe_read_delay,
+ "Forced delay before reading subprocess output.\n\
+This is done to improve the buffering of subprocess output, by\n\
+avoiding the inefficiency of frequently reading small amounts of data.\n\
+\n\
+If positive, the value is the number of milliseconds to sleep before\n\
+reading the subprocess output. If negative, the magnitude is the number\n\
+of time slices to wait (effectively boosting the priority of the child\n\
+process temporarily). A value of zero disables waiting entirely.");
+ Vwin32_pipe_read_delay = 50;
+
+ DEFVAR_LISP ("win32-downcase-file-names", &Vwin32_downcase_file_names,
+ "Non-nil means convert all-upper case file names to lower case.\n\
+This applies when performing completions and file name expansion.");
+ Vwin32_downcase_file_names = Qnil;
}
/* end of ntproc.c */