diff src/ntproc.c @ 412:697ef44129c6 r21-2-14

Import from CVS: tag r21-2-14
author cvs
date Mon, 13 Aug 2007 11:20:41 +0200
parents de805c49cfc1
children da8ed4261e83
line wrap: on
line diff
--- a/src/ntproc.c	Mon Aug 13 11:19:22 2007 +0200
+++ b/src/ntproc.c	Mon Aug 13 11:20:41 2007 +0200
@@ -24,6 +24,15 @@
 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
 /* Synced with FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h>
+
+/* must include CRT headers *before* config.h */
+/* ### I don't believe it - martin */
 #include <config.h>
 #undef signal
 #undef wait
@@ -32,6 +41,7 @@
 #undef kill
 
 #include <windows.h>
+#include <sys/socket.h>
 #ifdef HAVE_A_OUT_H
 #include <a.out.h>
 #endif
@@ -45,9 +55,6 @@
 #include "syswait.h"
 #include "buffer.h"
 #include "process.h"
-
-#include "console-msw.h"
-
 /*#include "w32term.h"*/ /* From 19.34.6: sync in ? --marcpa */
 
 /* #### I'm not going to play with shit. */
@@ -101,7 +108,7 @@
 #endif
 }
 
-/* sys_signal moved to nt.c. It's now called mswindows_signal... */
+/* sys_signal moved to nt.c. It's now called msw_signal... */
 
 /* Defined in <process.h> which conflicts with the local copy */
 #define _P_NOWAIT 1
@@ -386,7 +393,7 @@
 static const char * process_dir;
 
 static BOOL 
-create_child (const char *exe, char *cmdline, char *env,
+create_child (CONST char *exe, char *cmdline, char *env,
 	      int * pPid, child_process *cp)
 {
   STARTUPINFO start;
@@ -399,6 +406,7 @@
   xzero (start);
   start.cb = sizeof (start);
   
+#ifdef HAVE_NTGUI
   if (NILP (Vwin32_start_process_show_window))
   start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   else
@@ -408,6 +416,7 @@
   start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
   start.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
   start.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+#endif /* HAVE_NTGUI */
 
   /* Explicitly specify no security */
   if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
@@ -436,8 +445,16 @@
   cp->procinfo.hThread=NULL;
   cp->procinfo.hProcess=NULL;
 
+  /* Hack for Windows 95, which assigns large (ie negative) pids */
+  if (cp->pid < 0)
+    cp->pid = -cp->pid;
+
   /* pid must fit in a Lisp_Int */
-
+#ifdef USE_UNION_TYPE
+  cp->pid = (cp->pid & ((1U << VALBITS) - 1));
+#else
+  cp->pid = (cp->pid & VALMASK);
+#endif
 
   *pPid = cp->pid;
   
@@ -448,6 +465,155 @@
   return FALSE;
 }
 
+#ifndef __MINGW32__
+/* Return pointer to section header for section containing the given
+   relative virtual address. */
+static IMAGE_SECTION_HEADER *
+rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
+{
+  PIMAGE_SECTION_HEADER section;
+  int i;
+
+  section = IMAGE_FIRST_SECTION (nt_header);
+
+  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+    {
+      if (rva >= section->VirtualAddress
+	  && rva < section->VirtualAddress + section->SizeOfRawData)
+	return section;
+      section++;
+    }
+  return NULL;
+}
+#endif
+
+void
+win32_executable_type (CONST char * filename, int * is_dos_app, int * is_cygnus_app)
+{
+  file_data executable;
+  char * p;
+
+  /* Default values in case we can't tell for sure.  */
+  *is_dos_app = FALSE;
+  *is_cygnus_app = FALSE;
+
+  if (!open_input_file (&executable, filename))
+    return;
+
+  p = strrchr (filename, '.');
+
+      /* We can only identify DOS .com programs from the extension. */
+      if (p && stricmp (p, ".com") == 0)
+    *is_dos_app = TRUE;
+  else if (p && (stricmp (p, ".bat") == 0 ||
+		 stricmp (p, ".cmd") == 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. */
+      /* Actually, I think it uses the program association for that
+	 extension, which is defined in the registry.  */
+      p = egetenv ("COMSPEC");
+      if (p)
+	win32_executable_type (p, is_dos_app, is_cygnus_app);
+    }
+      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. */
+
+#ifdef __MINGW32__
+	  /* mingw32 doesn't have enough headers to detect cygwin
+             apps, just do what we can. */
+	  FILHDR * exe_header;
+
+	  exe_header = (FILHDR*) executable.file_base;
+	  if (exe_header->e_magic != DOSMAGIC)
+	    goto unwind;
+
+	  if ((char *) exe_header->e_lfanew > (char *) executable.size)
+	    {
+	      /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
+	      *is_dos_app = TRUE;
+	    } 
+	  else if (exe_header->nt_signature != NT_SIGNATURE)
+	    {
+	      *is_dos_app = TRUE;
+	    }
+#else
+	  IMAGE_DOS_HEADER * dos_header;
+	  IMAGE_NT_HEADERS * nt_header;
+
+	  dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
+	  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+	    goto unwind;
+	  
+	  nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
+	  
+	  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)
+	    {
+	      *is_dos_app = TRUE;
+	    }
+	  else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
+	    {
+	      /* Look for cygwin.dll in DLL import list. */
+	      IMAGE_DATA_DIRECTORY import_dir =
+		nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+	      IMAGE_IMPORT_DESCRIPTOR * imports;
+	      IMAGE_SECTION_HEADER * section;
+
+	      section = rva_to_section (import_dir.VirtualAddress, nt_header);
+	      imports = RVA_TO_PTR (import_dir.VirtualAddress, section, executable);
+	      
+	      for ( ; imports->Name; imports++)
+		{
+		  char * dllname = RVA_TO_PTR (imports->Name, section, executable);
+
+		  if (strcmp (dllname, "cygwin.dll") == 0)
+		    {
+		      *is_cygnus_app = TRUE;
+		      break;
+		    }
+		}
+	    }
+#endif
+	}
+
+ unwind:
+      close_file_data (&executable);
+}
+
+int
+compare_env (const void *strp1, const void *strp2)
+{
+  const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2;
+
+  while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
+    {
+      if ((*str1) > (*str2))
+	return 1;
+      else if ((*str1) < (*str2))
+	return -1;
+      str1++, str2++;
+    }
+
+  if (*str1 == '=' && *str2 == '=')
+    return 0;
+  else if (*str1 == '=')
+    return -1;
+  else
+    return 1;
+}
+
 void
 merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
 {
@@ -465,7 +631,7 @@
     *nptr++ = *optr++;
   num += optr - envp2;
 
-  qsort (new_envp, num, sizeof (char*), compare_env);
+  qsort (new_envp, num, sizeof (char *), compare_env);
 
   *nptr = NULL;
 }
@@ -473,8 +639,8 @@
 /* When a new child process is created we need to register it in our list,
    so intercept spawn requests.  */
 int 
-sys_spawnve (int mode, const char *cmdname,
-	     const char * const *argv, const char *const *envp)
+sys_spawnve (int mode, CONST char *cmdname,
+	     CONST char * CONST *argv, CONST char *CONST *envp)
 {
   Lisp_Object program, full;
   char *cmdline, *env, *parg, **targ;
@@ -510,13 +676,11 @@
 	  errno = EINVAL;
 	  return -1;
 	}
-      TO_EXTERNAL_FORMAT (LISP_STRING, full,
-			  C_STRING_ALLOCA, cmdname,
-			  Qfile_name);
+      GET_C_STRING_FILENAME_DATA_ALLOCA (full, cmdname);
     }
   else
     {
-      cmdname = (char*)alloca (strlen (argv[0]) + 1);
+      (char*)cmdname = alloca (strlen (argv[0]) + 1);
       strcpy ((char*)cmdname, argv[0]);
     }
   UNGCPRO;
@@ -524,21 +688,21 @@
   /* make sure argv[0] and cmdname are both in DOS format */
   unixtodos_filename ((char*)cmdname);
   /* #### KLUDGE */
-  ((const char**)argv)[0] = cmdname;
+  ((CONST char**)argv)[0] = cmdname;
 
   /* Determine whether program is a 16-bit DOS executable, or a Win32
      executable that is implicitly linked to the Cygnus dll (implying it
      was compiled with the Cygnus GNU toolchain and hence relies on
      cygwin.dll to parse the command line - we use this to decide how to
      escape quote chars in command line args that must be quoted). */
-  mswindows_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
+  win32_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
 
   /* On Windows 95, if cmdname is a DOS app, we invoke a helper
      application to start it by specifying the helper app as cmdname,
      while leaving the real app name as argv[0].  */
   if (is_dos_app)
     {
-      cmdname = (char*) alloca (MAXPATHLEN);
+      cmdname = alloca (MAXPATHLEN);
       if (egetenv ("CMDPROXY"))
 	strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
       else
@@ -585,7 +749,7 @@
       /* Override escape char by binding win32-quote-process-args to
 	 desired character, or use t for auto-selection.  */
       if (INTP (Vwin32_quote_process_args))
-	escape_char = (char) XINT (Vwin32_quote_process_args);
+	escape_char = XINT (Vwin32_quote_process_args);
       else
 	escape_char = is_cygnus_app ? '"' : '\\';
     }
@@ -637,7 +801,7 @@
 	}
       arglen += strlen (*targ++) + 1;
     }
-  cmdline = (char*) alloca (arglen);
+  cmdline = alloca (arglen);
   targ = (char**)argv;
   parg = cmdline;
   while (*targ)
@@ -719,7 +883,7 @@
   
   /* and envp...  */
   arglen = 1;
-  targ = (char**) envp;
+  targ = (char**)envp;
   numenv = 1; /* for end null */
   while (*targ)
     {
@@ -733,11 +897,11 @@
   numenv++;
 
   /* merge env passed in and extra env into one, and sort it.  */
-  targ = (char **) alloca (numenv * sizeof (char*));
-  merge_and_sort_env ((char**) envp, extra_env, targ);
+  targ = (char **) alloca (numenv * sizeof (char *));
+  merge_and_sort_env ((char**)envp, extra_env, targ);
 
   /* concatenate env entries.  */
-  env = (char*) alloca (arglen);
+  env = alloca (arglen);
   parg = env;
   while (*targ)
     {
@@ -781,7 +945,7 @@
 
       GetClassName (hwnd, window_class, sizeof (window_class));
       if (strcmp (window_class,
-		  mswindows_windows9x_p()
+		  (os_subtype == OS_WIN95)
 		  ? "tty"
 		  : "ConsoleWindowClass") == 0)
 	{
@@ -874,7 +1038,7 @@
       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
 	{
 #if 1
-	  if (mswindows_windows9x_p())
+	  if (os_subtype == OS_WIN95)
 	    {
 /*
    Another possibility is to try terminating the VDM out-right by
@@ -935,7 +1099,7 @@
 
 #if 0
 /* Sync with FSF Emacs 19.34.6 note: ifdef'ed out in XEmacs */
-extern int report_file_error (const char *, Lisp_Object);
+extern int report_file_error (CONST char *, Lisp_Object);
 #endif
 /* The following two routines are used to manipulate stdin, stdout, and
    stderr of our child processes.
@@ -1028,6 +1192,12 @@
 /* Some miscellaneous functions that are Windows specific, but not GUI
    specific (ie. are applicable in terminal or batch mode as well).  */
 
+/* lifted from fileio.c  */
+#define CORRECT_DIR_SEPS(s) \
+  do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
+       else unixtodos_filename (s); \
+  } while (0)
+
 DEFUN ("win32-short-file-name", Fwin32_short_file_name, 1, 1, "", /*
   Return the short file name version (8.3) of the full path of FILENAME.
 If FILENAME does not exist, return nil.
@@ -1257,7 +1427,7 @@
 
 /* Sync with FSF Emacs 19.34.6 note: dwWinThreadId declared in
    w32term.h and defined in w32fns.c, both of which are not in current
-   XEmacs.  #### Check what we lose by ifdef'ing out these. --marcpa */
+   XEmacs.  ### Check what we lose by ifdef'ing out these. --marcpa */
 #if 0
   /* Need to set input thread locale if present.  */
   if (dwWinThreadId)
@@ -1270,8 +1440,11 @@
 
 
 void
-syms_of_ntproc (void)
+syms_of_ntproc ()
 {
+  Qhigh = intern ("high");
+  Qlow = intern ("low");
+
   DEFSUBR (Fwin32_short_file_name);
   DEFSUBR (Fwin32_long_file_name);
   DEFSUBR (Fwin32_set_process_priority);
@@ -1280,14 +1453,6 @@
   DEFSUBR (Fwin32_get_default_locale_id);
   DEFSUBR (Fwin32_get_valid_locale_ids);
   DEFSUBR (Fwin32_set_current_locale);
-}
-
-
-void
-vars_of_ntproc (void)
-{
-  defsymbol (&Qhigh, "high");
-  defsymbol (&Qlow, "low");
 
   DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args /*
     Non-nil enables quoting of process arguments to ensure correct parsing.
@@ -1318,7 +1483,7 @@
 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't
 otherwise respond to interrupts from Emacs.
 */ );
-  Vwin32_start_process_share_console = Qt;
+  Vwin32_start_process_share_console = Qnil;
 
   DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /*
     Forced delay before reading subprocess output.
@@ -1343,5 +1508,4 @@
   Vwin32_generate_fake_inodes = Qnil;
 #endif
 }
-
 /* end of ntproc.c */