(CHAR_TO_CHARC): New inline function.
[chise/xemacs-chise.git-] / src / ntproc.c
index aee5649..eebf13f 100644 (file)
@@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA.
 #include <signal.h>
 
 /* must include CRT headers *before* config.h */
-/* ### I don't believe it - martin */
+/* #### I don't believe it - martin */
 #include <config.h>
 #undef signal
 #undef wait
@@ -42,15 +42,22 @@ Boston, MA 02111-1307, USA.
 
 #include <windows.h>
 #include <sys/socket.h>
-
+#ifdef HAVE_A_OUT_H
+#include <a.out.h>
+#endif
 #include "lisp.h"
 #include "sysproc.h"
 #include "nt.h"
 #include "ntheap.h" /* From 19.34.6 */
 #include "systime.h"
 #include "syssignal.h"
+#include "sysfile.h"
 #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. */
@@ -86,6 +93,8 @@ Lisp_Object Vwin32_generate_fake_inodes;
 
 Lisp_Object Qhigh, Qlow;
 
+extern Lisp_Object Vlisp_EXEC_SUFFIXES;
+
 #ifndef DEBUG_XEMACS
 __inline
 #endif
@@ -223,6 +232,63 @@ find_child_pid (DWORD pid)
   return NULL;
 }
 
+/* Function to do blocking read of one byte, needed to implement
+   select.  It is only allowed on sockets and pipes. */
+static int
+_sys_read_ahead (int fd)
+{
+  child_process * cp;
+  int rc = 0;
+
+  if (fd < 0 || fd >= MAXDESC)
+    return STATUS_READ_ERROR;
+
+  cp = fd_info[fd].cp;
+
+  if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
+    return STATUS_READ_ERROR;
+
+  if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
+      || (fd_info[fd].flags & FILE_READ) == 0)
+    {
+      /* fd is not a pipe or socket */
+      abort ();
+    }
+  
+  cp->status = STATUS_READ_IN_PROGRESS;
+  
+  if (fd_info[fd].flags & FILE_PIPE)
+    {
+      rc = _read (fd, &cp->chr, sizeof (char));
+
+      /* Give subprocess time to buffer some more output for us before
+        reporting that input is available; we need this because Win95
+        connects DOS programs to pipes by making the pipe appear to be
+        the normal console stdout - as a result most DOS programs will
+        write to stdout without buffering, ie.  one character at a
+        time.  Even some Win32 programs do this - "dir" in a command
+        shell on NT is very slow if we don't do this. */
+      if (rc > 0)
+       {
+         int wait = XINT (Vwin32_pipe_read_delay);
+
+         if (wait > 0)
+           Sleep (wait);
+         else if (wait < 0)
+           while (++wait <= 0)
+             /* Yield remainder of our time slice, effectively giving a
+                temporary priority boost to the child process. */
+             Sleep (0);
+       }
+    }
+
+  if (rc == sizeof (char))
+    cp->status = STATUS_READ_SUCCEEDED;
+  else
+    cp->status = STATUS_READ_FAILED;
+
+  return cp->status;
+}
 
 /* Thread proc for child process and socket reader threads. Each thread
    is normally blocked until woken by select() to check for input by
@@ -330,7 +396,7 @@ reader_thread (void *arg)
 static const char * process_dir;
 
 static BOOL 
-create_child (char *exe, char *cmdline, char *env,
+create_child (const char *exe, char *cmdline, char *env,
              int * pPid, child_process *cp)
 {
   STARTUPINFO start;
@@ -343,7 +409,6 @@ create_child (char *exe, char *cmdline, char *env,
   xzero (start);
   start.cb = sizeof (start);
   
-#ifdef HAVE_NTGUI
   if (NILP (Vwin32_start_process_show_window))
   start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   else
@@ -353,7 +418,6 @@ create_child (char *exe, char *cmdline, char *env,
   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))
@@ -382,16 +446,8 @@ create_child (char *exe, char *cmdline, char *env,
   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;
   
@@ -403,113 +459,6 @@ create_child (char *exe, char *cmdline, char *env,
 }
 
 void
-win32_executable_type (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. */
-
-      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;
-               }
-           }
-       }
-    }
-
-unwind:
-  close_file_data (&executable);
-}
-
-int
-compare_env (const char **strp1, const char **strp2)
-{
-  const char *str1 = *strp1, *str2 = *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)
 {
   char **optr, **nptr;
@@ -526,7 +475,7 @@ merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
     *nptr++ = *optr++;
   num += optr - envp2;
 
-  qsort (new_envp, num, sizeof (char *), compare_env);
+  qsort (new_envp, num, sizeof (char*), compare_env);
 
   *nptr = NULL;
 }
@@ -534,8 +483,8 @@ 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 
-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;
@@ -544,7 +493,7 @@ sys_spawnve (int mode, CONST char *cmdname,
   child_process *cp;
   int is_dos_app, is_cygnus_app;
   int do_quoting = 0;
-  char escape_char;
+  char escape_char = 0;
   /* We pass our process ID to our children by setting up an environment
      variable in their environment.  */
   char ppid_env_var_buffer[64];
@@ -564,46 +513,50 @@ sys_spawnve (int mode, CONST char *cmdname,
   if (NILP (Ffile_executable_p (program)))
     {
       full = Qnil;
-      locate_file (Vexec_path, program, EXEC_SUFFIXES, &full, 1);
+      locate_file (Vexec_path, program, Vlisp_EXEC_SUFFIXES, &full, 1);
       if (NILP (full))
        {
          UNGCPRO;
          errno = EINVAL;
          return -1;
        }
-      cmdname = XSTRING_DATA (full);
-      /* #### KLUDGE */
-      *(char**)(argv[0]) = cmdname;
+      TO_EXTERNAL_FORMAT (LISP_STRING, full,
+                         C_STRING_ALLOCA, cmdname,
+                         Qfile_name);
+    }
+  else
+    {
+      cmdname = (char*)alloca (strlen (argv[0]) + 1);
+      strcpy ((char*)cmdname, argv[0]);
     }
   UNGCPRO;
 
   /* make sure argv[0] and cmdname are both in DOS format */
-  strcpy (cmdname = alloca (strlen (cmdname) + 1), argv[0]);
-  unixtodos_filename (cmdname);
+  unixtodos_filename ((char*)cmdname);
   /* #### KLUDGE */
-  *(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). */
-  win32_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
+  mswindows_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 = alloca (MAXPATHLEN);
+      cmdname = (char*) alloca (MAXPATHLEN);
       if (egetenv ("CMDPROXY"))
-       strcpy (cmdname, egetenv ("CMDPROXY"));
+       strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
       else
     {
-         strcpy (cmdname, XSTRING_DATA (Vinvocation_directory));
-         strcat (cmdname, "cmdproxy.exe");
+         strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory));
+         strcat ((char*)cmdname, "cmdproxy.exe");
        }
-      unixtodos_filename (cmdname);
+      unixtodos_filename ((char*)cmdname);
     }
   
   /* we have to do some conjuring here to put argv and envp into the
@@ -642,14 +595,14 @@ sys_spawnve (int mode, CONST char *cmdname,
       /* 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 = XINT (Vwin32_quote_process_args);
+       escape_char = (char) XINT (Vwin32_quote_process_args);
       else
        escape_char = is_cygnus_app ? '"' : '\\';
     }
   
   /* do argv...  */
   arglen = 0;
-  targ = argv;
+  targ = (char**)argv;
   while (*targ)
     {
       char * p = *targ;
@@ -694,8 +647,8 @@ sys_spawnve (int mode, CONST char *cmdname,
        }
       arglen += strlen (*targ++) + 1;
     }
-  cmdline = alloca (arglen);
-  targ = argv;
+  cmdline = (char*) alloca (arglen);
+  targ = (char**)argv;
   parg = cmdline;
   while (*targ)
     {
@@ -776,7 +729,7 @@ sys_spawnve (int mode, CONST char *cmdname,
   
   /* and envp...  */
   arglen = 1;
-  targ = envp;
+  targ = (char**) envp;
   numenv = 1; /* for end null */
   while (*targ)
     {
@@ -790,11 +743,11 @@ sys_spawnve (int mode, CONST char *cmdname,
   numenv++;
 
   /* merge env passed in and extra env into one, and sort it.  */
-  targ = (char **) alloca (numenv * sizeof (char *));
-  merge_and_sort_env (envp, extra_env, targ);
+  targ = (char **) alloca (numenv * sizeof (char*));
+  merge_and_sort_env ((char**) envp, extra_env, targ);
 
   /* concatenate env entries.  */
-  env = alloca (arglen);
+  env = (char*) alloca (arglen);
   parg = env;
   while (*targ)
     {
@@ -838,7 +791,7 @@ find_child_console (HWND hwnd, child_process * cp)
 
       GetClassName (hwnd, window_class, sizeof (window_class));
       if (strcmp (window_class,
-                 (os_subtype == OS_WIN95)
+                 msw_windows9x_p()
                  ? "tty"
                  : "ConsoleWindowClass") == 0)
        {
@@ -882,7 +835,7 @@ sys_kill (int pid, int sig)
       pid = cp->procinfo.dwProcessId;
 
       /* Try to locate console window for process. */
-      EnumWindows (find_child_console, (LPARAM) cp);
+      EnumWindows ((WNDENUMPROC)find_child_console, (LPARAM) cp);
     }
   
   if (sig == SIGINT)
@@ -931,7 +884,7 @@ sys_kill (int pid, int sig)
       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
        {
 #if 1
-         if (os_subtype == OS_WIN95)
+         if (msw_windows9x_p())
            {
 /*
    Another possibility is to try terminating the VDM out-right by
@@ -992,7 +945,7 @@ sys_kill (int pid, int sig)
 
 #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.
@@ -1320,7 +1273,7 @@ If successful, the new locale id is returned, otherwise nil.
 
 /* 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)
@@ -1333,11 +1286,8 @@ If successful, the new locale id is returned, otherwise nil.
 
 \f
 void
-syms_of_ntproc ()
+syms_of_ntproc (void)
 {
-  Qhigh = intern ("high");
-  Qlow = intern ("low");
-
   DEFSUBR (Fwin32_short_file_name);
   DEFSUBR (Fwin32_long_file_name);
   DEFSUBR (Fwin32_set_process_priority);
@@ -1346,6 +1296,14 @@ syms_of_ntproc ()
   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.
@@ -1376,7 +1334,7 @@ or indirectly by Emacs), and preventing Emacs from cleanly terminating the
 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't
 otherwise respond to interrupts from Emacs.
 */ );
-  Vwin32_start_process_share_console = Qnil;
+  Vwin32_start_process_share_console = Qt;
 
   DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /*
     Forced delay before reading subprocess output.
@@ -1401,4 +1359,5 @@ the truename of a file can be slow.
   Vwin32_generate_fake_inodes = Qnil;
 #endif
 }
+
 /* end of ntproc.c */