XEmacs 21.2.24 "Hecate".
[chise/xemacs-chise.git.1] / src / ntproc.c
1 /* Process support for Windows NT port of XEMACS.
2    Copyright (C) 1992, 1995 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21    Drew Bliss                   Oct 14, 1993
22      Adapted from alarm.c by Tim Fleehart */
23
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
25 /* Synced with FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <io.h>
31 #include <fcntl.h>
32 #include <signal.h>
33
34 /* must include CRT headers *before* config.h */
35 /* ### I don't believe it - martin */
36 #include <config.h>
37 #undef signal
38 #undef wait
39 #undef spawnve
40 #undef select
41 #undef kill
42
43 #include <windows.h>
44 #include <sys/socket.h>
45 #ifdef HAVE_A_OUT_H
46 #include <a.out.h>
47 #endif
48 #include "lisp.h"
49 #include "sysproc.h"
50 #include "nt.h"
51 #include "ntheap.h" /* From 19.34.6 */
52 #include "systime.h"
53 #include "syssignal.h"
54 #include "sysfile.h"
55 #include "syswait.h"
56 #include "buffer.h"
57 #include "process.h"
58 /*#include "w32term.h"*/ /* From 19.34.6: sync in ? --marcpa */
59
60 /* #### I'm not going to play with shit. */
61 #pragma warning (disable:4013 4024 4090)
62
63 /* Control whether spawnve quotes arguments as necessary to ensure
64    correct parsing by child process.  Because not all uses of spawnve
65    are careful about constructing argv arrays, we make this behavior
66    conditional (off by default). */
67 Lisp_Object Vwin32_quote_process_args;
68
69 /* Control whether create_child causes the process' window to be
70    hidden.  The default is nil. */
71 Lisp_Object Vwin32_start_process_show_window;
72
73 /* Control whether create_child causes the process to inherit Emacs'
74    console window, or be given a new one of its own.  The default is
75    nil, to allow multiple DOS programs to run on Win95.  Having separate
76    consoles also allows Emacs to cleanly terminate process groups.  */
77 Lisp_Object Vwin32_start_process_share_console;
78
79 /* Time to sleep before reading from a subprocess output pipe - this
80    avoids the inefficiency of frequently reading small amounts of data.
81    This is primarily necessary for handling DOS processes on Windows 95,
82    but is useful for Win32 processes on both Win95 and NT as well.  */
83 Lisp_Object Vwin32_pipe_read_delay;
84
85 /* Control whether stat() attempts to generate fake but hopefully
86    "accurate" inode values, by hashing the absolute truenames of files.
87    This should detect aliasing between long and short names, but still
88    allows the possibility of hash collisions.  */
89 Lisp_Object Vwin32_generate_fake_inodes;
90
91 Lisp_Object Qhigh, Qlow;
92
93 extern Lisp_Object Vlisp_EXEC_SUFFIXES;
94
95 #ifndef DEBUG_XEMACS
96 __inline
97 #endif
98 void _DebPrint (const char *fmt, ...)
99 {
100 #ifdef DEBUG_XEMACS
101   char buf[1024];
102   va_list args;
103
104   va_start (args, fmt);
105   vsprintf (buf, fmt, args);
106   va_end (args);
107   OutputDebugString (buf);
108 #endif
109 }
110
111 /* sys_signal moved to nt.c. It's now called msw_signal... */
112
113 /* Defined in <process.h> which conflicts with the local copy */
114 #define _P_NOWAIT 1
115
116 /* Child process management list.  */
117 int child_proc_count = 0;
118 child_process child_procs[ MAX_CHILDREN ];
119 child_process *dead_child = NULL;
120
121 DWORD WINAPI reader_thread (void *arg);
122
123 /* Find an unused process slot.  */
124 child_process *
125 new_child (void)
126 {
127   child_process *cp;
128   DWORD id;
129   
130   for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
131     if (!CHILD_ACTIVE (cp))
132       goto Initialize;
133   if (child_proc_count == MAX_CHILDREN)
134     return NULL;
135   cp = &child_procs[child_proc_count++];
136
137  Initialize:
138   xzero (*cp);
139   cp->fd = -1;
140   cp->pid = -1;
141   if (cp->procinfo.hProcess)
142     CloseHandle(cp->procinfo.hProcess);
143   cp->procinfo.hProcess = NULL;
144   cp->status = STATUS_READ_ERROR;
145
146   /* use manual reset event so that select() will function properly */
147   cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
148   if (cp->char_avail)
149     {
150       cp->char_consumed = CreateEvent (NULL, FALSE, FALSE, NULL);
151       if (cp->char_consumed)
152         {
153           cp->thrd = CreateThread (NULL, 1024, reader_thread, cp, 0, &id);
154           if (cp->thrd)
155             return cp;
156         }
157     }
158   delete_child (cp);
159   return NULL;
160 }
161
162 void 
163 delete_child (child_process *cp)
164 {
165   int i;
166
167   /* Should not be deleting a child that is still needed. */
168   for (i = 0; i < MAXDESC; i++)
169     if (fd_info[i].cp == cp)
170       abort ();
171
172   if (!CHILD_ACTIVE (cp))
173     return;
174
175   /* reap thread if necessary */
176   if (cp->thrd)
177     {
178       DWORD rc;
179
180       if (GetExitCodeThread (cp->thrd, &rc) && rc == STILL_ACTIVE)
181         {
182           /* let the thread exit cleanly if possible */
183           cp->status = STATUS_READ_ERROR;
184           SetEvent (cp->char_consumed);
185           if (WaitForSingleObject (cp->thrd, 1000) != WAIT_OBJECT_0)
186             {
187               DebPrint (("delete_child.WaitForSingleObject (thread) failed "
188                          "with %lu for fd %ld\n", GetLastError (), cp->fd));
189               TerminateThread (cp->thrd, 0);
190             }
191         }
192       CloseHandle (cp->thrd);
193       cp->thrd = NULL;
194     }
195   if (cp->char_avail)
196     {
197       CloseHandle (cp->char_avail);
198       cp->char_avail = NULL;
199     }
200   if (cp->char_consumed)
201     {
202       CloseHandle (cp->char_consumed);
203       cp->char_consumed = NULL;
204     }
205
206   /* update child_proc_count (highest numbered slot in use plus one) */
207   if (cp == child_procs + child_proc_count - 1)
208     {
209       for (i = child_proc_count-1; i >= 0; i--)
210         if (CHILD_ACTIVE (&child_procs[i]))
211           {
212             child_proc_count = i + 1;
213             break;
214           }
215     }
216   if (i < 0)
217     child_proc_count = 0;
218 }
219
220 /* Find a child by pid.  */
221 static child_process *
222 find_child_pid (DWORD pid)
223 {
224   child_process *cp;
225
226   for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
227     if (CHILD_ACTIVE (cp) && pid == cp->pid)
228       return cp;
229   return NULL;
230 }
231
232 /* Function to do blocking read of one byte, needed to implement
233    select.  It is only allowed on sockets and pipes. */
234 static int
235 _sys_read_ahead (int fd)
236 {
237   child_process * cp;
238   int rc = 0;
239
240   if (fd < 0 || fd >= MAXDESC)
241     return STATUS_READ_ERROR;
242
243   cp = fd_info[fd].cp;
244
245   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
246     return STATUS_READ_ERROR;
247
248   if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
249       || (fd_info[fd].flags & FILE_READ) == 0)
250     {
251       /* fd is not a pipe or socket */
252       abort ();
253     }
254   
255   cp->status = STATUS_READ_IN_PROGRESS;
256   
257   if (fd_info[fd].flags & FILE_PIPE)
258     {
259       rc = _read (fd, &cp->chr, sizeof (char));
260
261       /* Give subprocess time to buffer some more output for us before
262          reporting that input is available; we need this because Win95
263          connects DOS programs to pipes by making the pipe appear to be
264          the normal console stdout - as a result most DOS programs will
265          write to stdout without buffering, ie.  one character at a
266          time.  Even some Win32 programs do this - "dir" in a command
267          shell on NT is very slow if we don't do this. */
268       if (rc > 0)
269         {
270           int wait = XINT (Vwin32_pipe_read_delay);
271
272           if (wait > 0)
273             Sleep (wait);
274           else if (wait < 0)
275             while (++wait <= 0)
276               /* Yield remainder of our time slice, effectively giving a
277                  temporary priority boost to the child process. */
278               Sleep (0);
279         }
280     }
281
282   if (rc == sizeof (char))
283     cp->status = STATUS_READ_SUCCEEDED;
284   else
285     cp->status = STATUS_READ_FAILED;
286
287   return cp->status;
288 }
289
290 /* Thread proc for child process and socket reader threads. Each thread
291    is normally blocked until woken by select() to check for input by
292    reading one char.  When the read completes, char_avail is signalled
293    to wake up the select emulator and the thread blocks itself again. */
294 DWORD WINAPI 
295 reader_thread (void *arg)
296 {
297   child_process *cp;
298   
299   /* Our identity */
300   cp = (child_process *)arg;
301   
302   /* <matts@tibco.com> - I think the test below is wrong - we don't
303      want to wait for someone to signal char_consumed, as we haven't
304      read anything for them to consume yet! */
305
306   /*
307   if (cp == NULL ||
308       WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
309   */
310
311   if (cp == NULL)
312   {
313       return 1;
314   }
315
316   for (;;)
317     {
318       int rc;
319
320       rc = _sys_read_ahead (cp->fd);
321
322       /* The name char_avail is a misnomer - it really just means the
323          read-ahead has completed, whether successfully or not. */
324       if (!SetEvent (cp->char_avail))
325         {
326           DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n",
327                      GetLastError (), cp->fd));
328           return 1;
329         }
330
331       if (rc == STATUS_READ_ERROR)
332       {
333         /* We are finished, so clean up handles and set to NULL so
334            that CHILD_ACTIVE will see what is going on */
335         if (cp->char_avail) {
336           CloseHandle (cp->char_avail);
337           cp->char_avail = NULL;
338         }
339         if (cp->thrd) {
340           CloseHandle (cp->thrd);
341           cp->thrd = NULL;
342         }
343         if (cp->char_consumed) {
344           CloseHandle(cp->char_consumed);
345           cp->char_consumed = NULL;
346         }
347         if (cp->procinfo.hProcess)
348         {
349           CloseHandle (cp->procinfo.hProcess);
350           cp->procinfo.hProcess=NULL;
351         }
352         return 1;
353       }
354         
355       /* If the read died, the child has died so let the thread die */
356       if (rc == STATUS_READ_FAILED)
357         break;
358         
359       /* Wait until our input is acknowledged before reading again */
360       if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
361         {
362           DebPrint (("reader_thread.WaitForSingleObject failed with "
363                      "%lu for fd %ld\n", GetLastError (), cp->fd));
364           break;
365         }
366     }
367   /* We are finished, so clean up handles and set to NULL so that
368      CHILD_ACTIVE will see what is going on */
369   if (cp->char_avail) {
370     CloseHandle (cp->char_avail);
371     cp->char_avail = NULL;
372   }
373   if (cp->thrd) {
374     CloseHandle (cp->thrd);
375     cp->thrd = NULL;
376   }
377   if (cp->char_consumed) {
378     CloseHandle(cp->char_consumed);
379     cp->char_consumed = NULL;
380   }
381   if (cp->procinfo.hProcess)
382   {
383     CloseHandle (cp->procinfo.hProcess);
384     cp->procinfo.hProcess=NULL;
385   }
386   
387   return 0;
388 }
389
390 /* To avoid Emacs changing directory, we just record here the directory
391    the new process should start in.  This is set just before calling
392    sys_spawnve, and is not generally valid at any other time.  */
393 static const char * process_dir;
394
395 static BOOL 
396 create_child (CONST char *exe, char *cmdline, char *env,
397               int * pPid, child_process *cp)
398 {
399   STARTUPINFO start;
400   SECURITY_ATTRIBUTES sec_attrs;
401   SECURITY_DESCRIPTOR sec_desc;
402   char dir[ MAXPATHLEN ];
403   
404   if (cp == NULL) abort ();
405   
406   xzero (start);
407   start.cb = sizeof (start);
408   
409 #ifdef HAVE_NTGUI
410   if (NILP (Vwin32_start_process_show_window))
411   start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
412   else
413     start.dwFlags = STARTF_USESTDHANDLES;
414   start.wShowWindow = SW_HIDE;
415
416   start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
417   start.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
418   start.hStdError = GetStdHandle (STD_ERROR_HANDLE);
419 #endif /* HAVE_NTGUI */
420
421   /* Explicitly specify no security */
422   if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
423     goto EH_Fail;
424   if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE))
425     goto EH_Fail;
426   sec_attrs.nLength = sizeof (sec_attrs);
427   sec_attrs.lpSecurityDescriptor = &sec_desc;
428   sec_attrs.bInheritHandle = FALSE;
429   
430   strcpy (dir, process_dir);
431   unixtodos_filename (dir);
432   
433   if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
434                       (!NILP (Vwin32_start_process_share_console)
435                        ? CREATE_NEW_PROCESS_GROUP
436                        : CREATE_NEW_CONSOLE),
437                       env, dir,
438                       &start, &cp->procinfo))
439     goto EH_Fail;
440
441   cp->pid = (int) cp->procinfo.dwProcessId;
442
443   CloseHandle (cp->procinfo.hThread);
444   CloseHandle (cp->procinfo.hProcess);
445   cp->procinfo.hThread=NULL;
446   cp->procinfo.hProcess=NULL;
447
448   /* pid must fit in a Lisp_Int */
449
450
451   *pPid = cp->pid;
452   
453   return TRUE;
454   
455  EH_Fail:
456   DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError()););
457   return FALSE;
458 }
459
460 #ifndef __MINGW32__
461 /* Return pointer to section header for section containing the given
462    relative virtual address. */
463 static IMAGE_SECTION_HEADER *
464 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
465 {
466   PIMAGE_SECTION_HEADER section;
467   int i;
468
469   section = IMAGE_FIRST_SECTION (nt_header);
470
471   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
472     {
473       if (rva >= section->VirtualAddress
474           && rva < section->VirtualAddress + section->SizeOfRawData)
475         return section;
476       section++;
477     }
478   return NULL;
479 }
480 #endif
481
482 void
483 win32_executable_type (CONST char * filename, int * is_dos_app, int * is_cygnus_app)
484 {
485   file_data executable;
486   char * p;
487
488   /* Default values in case we can't tell for sure.  */
489   *is_dos_app = FALSE;
490   *is_cygnus_app = FALSE;
491
492   if (!open_input_file (&executable, filename))
493     return;
494
495   p = strrchr (filename, '.');
496
497       /* We can only identify DOS .com programs from the extension. */
498       if (p && stricmp (p, ".com") == 0)
499     *is_dos_app = TRUE;
500   else if (p && (stricmp (p, ".bat") == 0 ||
501                  stricmp (p, ".cmd") == 0))
502     {
503       /* A DOS shell script - it appears that CreateProcess is happy to
504          accept this (somewhat surprisingly); presumably it looks at
505          COMSPEC to determine what executable to actually invoke.
506              Therefore, we have to do the same here as well. */
507       /* Actually, I think it uses the program association for that
508          extension, which is defined in the registry.  */
509       p = egetenv ("COMSPEC");
510       if (p)
511         win32_executable_type (p, is_dos_app, is_cygnus_app);
512     }
513       else
514         {
515       /* Look for DOS .exe signature - if found, we must also check that
516          it isn't really a 16- or 32-bit Windows exe, since both formats
517          start with a DOS program stub.  Note that 16-bit Windows
518          executables use the OS/2 1.x format. */
519
520 #ifdef __MINGW32__
521           /* mingw32 doesn't have enough headers to detect cygwin
522              apps, just do what we can. */
523           FILHDR * exe_header;
524
525           exe_header = (FILHDR*) executable.file_base;
526           if (exe_header->e_magic != DOSMAGIC)
527             goto unwind;
528
529           if ((char *) exe_header->e_lfanew > (char *) executable.size)
530             {
531               /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
532               *is_dos_app = TRUE;
533             } 
534           else if (exe_header->nt_signature != NT_SIGNATURE)
535             {
536               *is_dos_app = TRUE;
537             }
538 #else
539           IMAGE_DOS_HEADER * dos_header;
540           IMAGE_NT_HEADERS * nt_header;
541
542           dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
543           if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
544             goto unwind;
545           
546           nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
547           
548           if ((char *) nt_header > (char *) dos_header + executable.size) 
549             {
550               /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
551               *is_dos_app = TRUE;
552             } 
553           else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
554                    LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
555             {
556               *is_dos_app = TRUE;
557             }
558           else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
559             {
560               /* Look for cygwin.dll in DLL import list. */
561               IMAGE_DATA_DIRECTORY import_dir =
562                 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
563               IMAGE_IMPORT_DESCRIPTOR * imports;
564               IMAGE_SECTION_HEADER * section;
565
566               section = rva_to_section (import_dir.VirtualAddress, nt_header);
567               imports = RVA_TO_PTR (import_dir.VirtualAddress, section, executable);
568               
569               for ( ; imports->Name; imports++)
570                 {
571                   char * dllname = RVA_TO_PTR (imports->Name, section, executable);
572
573                   if (strcmp (dllname, "cygwin.dll") == 0)
574                     {
575                       *is_cygnus_app = TRUE;
576                       break;
577                     }
578                 }
579             }
580 #endif
581         }
582
583  unwind:
584       close_file_data (&executable);
585 }
586
587 int
588 compare_env (const void *strp1, const void *strp2)
589 {
590   const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2;
591
592   while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
593     {
594       if ((*str1) > (*str2))
595         return 1;
596       else if ((*str1) < (*str2))
597         return -1;
598       str1++, str2++;
599     }
600
601   if (*str1 == '=' && *str2 == '=')
602     return 0;
603   else if (*str1 == '=')
604     return -1;
605   else
606     return 1;
607 }
608
609 void
610 merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
611 {
612   char **optr, **nptr;
613   int num;
614
615   nptr = new_envp;
616   optr = envp1;
617   while (*optr)
618     *nptr++ = *optr++;
619   num = optr - envp1;
620
621   optr = envp2;
622   while (*optr)
623     *nptr++ = *optr++;
624   num += optr - envp2;
625
626   qsort (new_envp, num, sizeof (char *), compare_env);
627
628   *nptr = NULL;
629 }
630
631 /* When a new child process is created we need to register it in our list,
632    so intercept spawn requests.  */
633 int 
634 sys_spawnve (int mode, CONST char *cmdname,
635              CONST char * CONST *argv, CONST char *CONST *envp)
636 {
637   Lisp_Object program, full;
638   char *cmdline, *env, *parg, **targ;
639   int arglen, numenv;
640   int pid;
641   child_process *cp;
642   int is_dos_app, is_cygnus_app;
643   int do_quoting = 0;
644   char escape_char = 0;
645   /* We pass our process ID to our children by setting up an environment
646      variable in their environment.  */
647   char ppid_env_var_buffer[64];
648   char *extra_env[] = {ppid_env_var_buffer, NULL};
649   struct gcpro gcpro1;
650     
651   /* We don't care about the other modes */
652   if (mode != _P_NOWAIT)
653     {
654       errno = EINVAL;
655       return -1;
656     }
657
658   /* Handle executable names without an executable suffix.  */
659   program = make_string (cmdname, strlen (cmdname));
660   GCPRO1 (program);
661   if (NILP (Ffile_executable_p (program)))
662     {
663       full = Qnil;
664       locate_file (Vexec_path, program, Vlisp_EXEC_SUFFIXES, &full, 1);
665       if (NILP (full))
666         {
667           UNGCPRO;
668           errno = EINVAL;
669           return -1;
670         }
671       GET_C_STRING_FILENAME_DATA_ALLOCA (full, cmdname);
672     }
673   else
674     {
675       (char*)cmdname = alloca (strlen (argv[0]) + 1);
676       strcpy ((char*)cmdname, argv[0]);
677     }
678   UNGCPRO;
679
680   /* make sure argv[0] and cmdname are both in DOS format */
681   unixtodos_filename ((char*)cmdname);
682   /* #### KLUDGE */
683   ((CONST char**)argv)[0] = cmdname;
684
685   /* Determine whether program is a 16-bit DOS executable, or a Win32
686      executable that is implicitly linked to the Cygnus dll (implying it
687      was compiled with the Cygnus GNU toolchain and hence relies on
688      cygwin.dll to parse the command line - we use this to decide how to
689      escape quote chars in command line args that must be quoted). */
690   win32_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
691
692   /* On Windows 95, if cmdname is a DOS app, we invoke a helper
693      application to start it by specifying the helper app as cmdname,
694      while leaving the real app name as argv[0].  */
695   if (is_dos_app)
696     {
697       cmdname = alloca (MAXPATHLEN);
698       if (egetenv ("CMDPROXY"))
699         strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
700       else
701     {
702           strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory));
703           strcat ((char*)cmdname, "cmdproxy.exe");
704         }
705       unixtodos_filename ((char*)cmdname);
706     }
707   
708   /* we have to do some conjuring here to put argv and envp into the
709      form CreateProcess wants...  argv needs to be a space separated/null
710      terminated list of parameters, and envp is a null
711      separated/double-null terminated list of parameters.
712
713      Additionally, zero-length args and args containing whitespace or
714      quote chars need to be wrapped in double quotes - for this to work,
715      embedded quotes need to be escaped as well.  The aim is to ensure
716      the child process reconstructs the argv array we start with
717      exactly, so we treat quotes at the beginning and end of arguments
718      as embedded quotes.
719
720      The Win32 GNU-based library from Cygnus doubles quotes to escape
721      them, while MSVC uses backslash for escaping.  (Actually the MSVC
722      startup code does attempt to recognize doubled quotes and accept
723      them, but gets it wrong and ends up requiring three quotes to get a
724      single embedded quote!)  So by default we decide whether to use
725      quote or backslash as the escape character based on whether the
726      binary is apparently a Cygnus compiled app.
727
728      Note that using backslash to escape embedded quotes requires
729      additional special handling if an embedded quote is already
730      preceded by backslash, or if an arg requiring quoting ends with
731      backslash.  In such cases, the run of escape characters needs to be
732      doubled.  For consistency, we apply this special handling as long
733      as the escape character is not quote.
734    
735      Since we have no idea how large argv and envp are likely to be we
736      figure out list lengths on the fly and allocate them.  */
737   
738   if (!NILP (Vwin32_quote_process_args))
739     {
740       do_quoting = 1;
741       /* Override escape char by binding win32-quote-process-args to
742          desired character, or use t for auto-selection.  */
743       if (INTP (Vwin32_quote_process_args))
744         escape_char = XINT (Vwin32_quote_process_args);
745       else
746         escape_char = is_cygnus_app ? '"' : '\\';
747     }
748   
749   /* do argv...  */
750   arglen = 0;
751   targ = (char**)argv;
752   while (*targ)
753     {
754       char * p = *targ;
755       int need_quotes = 0;
756       int escape_char_run = 0;
757
758       if (*p == 0)
759         need_quotes = 1;
760       for ( ; *p; p++)
761         {
762           if (*p == '"')
763           {
764               /* allow for embedded quotes to be escaped */
765             arglen++;
766               need_quotes = 1;
767               /* handle the case where the embedded quote is already escaped */
768               if (escape_char_run > 0)
769                 {
770                   /* To preserve the arg exactly, we need to double the
771                      preceding escape characters (plus adding one to
772                      escape the quote character itself).  */
773                   arglen += escape_char_run;
774           }
775             }
776       else if (*p == ' ' || *p == '\t')
777             {
778               need_quotes = 1;
779             }
780
781           if (*p == escape_char && escape_char != '"')
782             escape_char_run++;
783           else
784             escape_char_run = 0;
785         }
786       if (need_quotes)
787         {
788         arglen += 2;
789           /* handle the case where the arg ends with an escape char - we
790              must not let the enclosing quote be escaped.  */
791           if (escape_char_run > 0)
792             arglen += escape_char_run;
793         }
794       arglen += strlen (*targ++) + 1;
795     }
796   cmdline = alloca (arglen);
797   targ = (char**)argv;
798   parg = cmdline;
799   while (*targ)
800     {
801       char * p = *targ;
802       int need_quotes = 0;
803
804       if (*p == 0)
805         need_quotes = 1;
806
807       if (do_quoting)
808         {
809           for ( ; *p; p++)
810             if (*p == ' ' || *p == '\t' || *p == '"')
811               need_quotes = 1;
812         }
813       if (need_quotes)
814         {
815           int escape_char_run = 0;
816           char * first;
817           char * last;
818
819           p = *targ;
820           first = p;
821           last = p + strlen (p) - 1;
822           *parg++ = '"';
823 #if 0
824           /* This version does not escape quotes if they occur at the
825              beginning or end of the arg - this could lead to incorrect
826              behavior when the arg itself represents a command line
827              containing quoted args.  I believe this was originally done
828              as a hack to make some things work, before
829              `win32-quote-process-args' was added.  */
830           while (*p)
831             {
832               if (*p == '"' && p > first && p < last)
833                 *parg++ = escape_char;  /* escape embedded quotes */
834               *parg++ = *p++;
835             }
836 #else
837           for ( ; *p; p++)
838             {
839               if (*p == '"')
840                 {
841                   /* double preceding escape chars if any */
842                   while (escape_char_run > 0)
843                     {
844                       *parg++ = escape_char;
845                       escape_char_run--;
846                     }
847                   /* escape all quote chars, even at beginning or end */
848                   *parg++ = escape_char;
849                 }
850               *parg++ = *p;
851
852               if (*p == escape_char && escape_char != '"')
853                 escape_char_run++;
854               else
855                 escape_char_run = 0;
856             }
857           /* double escape chars before enclosing quote */
858           while (escape_char_run > 0)
859             {
860               *parg++ = escape_char;
861               escape_char_run--;
862             }
863 #endif
864           *parg++ = '"';
865         }
866       else
867         {
868           strcpy (parg, *targ);
869           parg += strlen (*targ);
870         }
871       *parg++ = ' ';
872       targ++;
873     }
874   *--parg = '\0';
875   
876   /* and envp...  */
877   arglen = 1;
878   targ = (char**)envp;
879   numenv = 1; /* for end null */
880   while (*targ)
881     {
882       arglen += strlen (*targ++) + 1;
883       numenv++;
884     }
885   /* extra env vars... */
886   sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d", 
887            GetCurrentProcessId ());
888   arglen += strlen (ppid_env_var_buffer) + 1;
889   numenv++;
890
891   /* merge env passed in and extra env into one, and sort it.  */
892   targ = (char **) alloca (numenv * sizeof (char *));
893   merge_and_sort_env ((char**)envp, extra_env, targ);
894
895   /* concatenate env entries.  */
896   env = alloca (arglen);
897   parg = env;
898   while (*targ)
899     {
900       strcpy (parg, *targ);
901       parg += strlen (*targ++);
902       *parg++ = '\0';
903     }
904   *parg++ = '\0';
905   *parg = '\0';
906
907   cp = new_child ();
908   if (cp == NULL)
909     {
910       errno = EAGAIN;
911       return -1;
912     }
913   
914   /* Now create the process.  */
915   if (!create_child (cmdname, cmdline, env, &pid, cp))
916     {
917       delete_child (cp);
918       errno = ENOEXEC;
919       return -1;
920     }
921
922   return pid;
923 }
924
925 /* Substitute for certain kill () operations */
926
927 static BOOL CALLBACK
928 find_child_console (HWND hwnd, child_process * cp)
929 {
930   DWORD thread_id;
931   DWORD process_id;
932
933   thread_id = GetWindowThreadProcessId (hwnd, &process_id);
934   if (process_id == cp->procinfo.dwProcessId)
935     {
936       char window_class[32];
937
938       GetClassName (hwnd, window_class, sizeof (window_class));
939       if (strcmp (window_class,
940                   (os_subtype == OS_WIN95)
941                   ? "tty"
942                   : "ConsoleWindowClass") == 0)
943         {
944           cp->hwnd = hwnd;
945           return FALSE;
946         }
947     }
948   /* keep looking */
949   return TRUE;
950 }
951
952 int 
953 sys_kill (int pid, int sig)
954 {
955   child_process *cp;
956   HANDLE proc_hand;
957   int need_to_free = 0;
958   int rc = 0;
959   
960   /* Only handle signals that will result in the process dying */
961   if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
962     {
963       errno = EINVAL;
964       return -1;
965     }
966
967   cp = find_child_pid (pid);
968   if (cp == NULL)
969     {
970       proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid);
971       if (proc_hand == NULL)
972         {
973           errno = EPERM;
974           return -1;
975         }
976       need_to_free = 1;
977     }
978   else
979     {
980       proc_hand = cp->procinfo.hProcess;
981       pid = cp->procinfo.dwProcessId;
982
983       /* Try to locate console window for process. */
984       EnumWindows ((WNDENUMPROC)find_child_console, (LPARAM) cp);
985     }
986   
987   if (sig == SIGINT)
988     {
989       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
990         {
991           BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
992           BYTE vk_break_code = VK_CANCEL;
993           BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
994           HWND foreground_window;
995
996           if (break_scan_code == 0)
997             {
998               /* Fake Ctrl-C if we can't manage Ctrl-Break. */
999               vk_break_code = 'C';
1000               break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
1001             }
1002
1003           foreground_window = GetForegroundWindow ();
1004           if (foreground_window && SetForegroundWindow (cp->hwnd))
1005             {
1006               /* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C.  */
1007               keybd_event (VK_CONTROL, control_scan_code, 0, 0);
1008               keybd_event (vk_break_code, break_scan_code, 0, 0);
1009               keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
1010               keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
1011
1012               /* Sleep for a bit to give time for Emacs frame to respond
1013                  to focus change events (if Emacs was active app).  */
1014               Sleep (10);
1015
1016               SetForegroundWindow (foreground_window);
1017             }
1018         }
1019       /* Ctrl-Break is NT equivalent of SIGINT.  */
1020       else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
1021         {
1022           DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d "
1023                      "for pid %lu\n", GetLastError (), pid));
1024           errno = EINVAL;
1025           rc = -1;
1026         }
1027     }
1028   else
1029     {
1030       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
1031         {
1032 #if 1
1033           if (os_subtype == OS_WIN95)
1034             {
1035 /*
1036    Another possibility is to try terminating the VDM out-right by
1037    calling the Shell VxD (id 0x17) V86 interface, function #4
1038    "SHELL_Destroy_VM", ie.
1039
1040      mov edx,4
1041      mov ebx,vm_handle
1042      call shellapi
1043
1044    First need to determine the current VM handle, and then arrange for
1045    the shellapi call to be made from the system vm (by using
1046    Switch_VM_and_callback).
1047
1048    Could try to invoke DestroyVM through CallVxD.
1049
1050 */
1051 #if 0
1052               /* On Win95, posting WM_QUIT causes the 16-bit subsystem
1053                  to hang when cmdproxy is used in conjunction with
1054                  command.com for an interactive shell.  Posting
1055                  WM_CLOSE pops up a dialog that, when Yes is selected,
1056                  does the same thing.  TerminateProcess is also less
1057                  than ideal in that subprocesses tend to stick around
1058                  until the machine is shutdown, but at least it
1059                  doesn't freeze the 16-bit subsystem.  */
1060               PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
1061 #endif
1062               if (!TerminateProcess (proc_hand, 0xff))
1063                 {
1064                   DebPrint (("sys_kill.TerminateProcess returned %d "
1065                              "for pid %lu\n", GetLastError (), pid));
1066                   errno = EINVAL;
1067                   rc = -1;
1068                 }
1069             }
1070           else
1071 #endif
1072             PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
1073         }
1074       /* Kill the process.  On Win32 this doesn't kill child processes
1075          so it doesn't work very well for shells which is why it's not
1076          used in every case.  */
1077       else if (!TerminateProcess (proc_hand, 0xff))
1078         {
1079           DebPrint (("sys_kill.TerminateProcess returned %d "
1080                      "for pid %lu\n", GetLastError (), pid));
1081           errno = EINVAL;
1082           rc = -1;
1083         }
1084     }
1085
1086   if (need_to_free)
1087     CloseHandle (proc_hand);
1088
1089   return rc;
1090 }
1091
1092 #if 0
1093 /* Sync with FSF Emacs 19.34.6 note: ifdef'ed out in XEmacs */
1094 extern int report_file_error (CONST char *, Lisp_Object);
1095 #endif
1096 /* The following two routines are used to manipulate stdin, stdout, and
1097    stderr of our child processes.
1098
1099    Assuming that in, out, and err are *not* inheritable, we make them
1100    stdin, stdout, and stderr of the child as follows:
1101
1102    - Save the parent's current standard handles.
1103    - Set the std handles to inheritable duplicates of the ones being passed in.
1104      (Note that _get_osfhandle() is an io.h procedure that retrieves the
1105      NT file handle for a crt file descriptor.)
1106    - Spawn the child, which inherits in, out, and err as stdin,
1107      stdout, and stderr. (see Spawnve)
1108    - Close the std handles passed to the child.
1109    - Reset the parent's standard handles to the saved handles.
1110      (see reset_standard_handles)
1111    We assume that the caller closes in, out, and err after calling us.  */
1112
1113 void
1114 prepare_standard_handles (int in, int out, int err, HANDLE handles[3])
1115 {
1116   HANDLE parent;
1117   HANDLE newstdin, newstdout, newstderr;
1118
1119   parent = GetCurrentProcess ();
1120
1121   handles[0] = GetStdHandle (STD_INPUT_HANDLE);
1122   handles[1] = GetStdHandle (STD_OUTPUT_HANDLE);
1123   handles[2] = GetStdHandle (STD_ERROR_HANDLE);
1124
1125   /* make inheritable copies of the new handles */
1126   if (!DuplicateHandle (parent, 
1127                        (HANDLE) _get_osfhandle (in),
1128                        parent,
1129                        &newstdin, 
1130                        0, 
1131                        TRUE, 
1132                        DUPLICATE_SAME_ACCESS))
1133     report_file_error ("Duplicating input handle for child", Qnil);
1134   
1135   if (!DuplicateHandle (parent,
1136                        (HANDLE) _get_osfhandle (out),
1137                        parent,
1138                        &newstdout,
1139                        0,
1140                        TRUE,
1141                        DUPLICATE_SAME_ACCESS))
1142     report_file_error ("Duplicating output handle for child", Qnil);
1143   
1144   if (!DuplicateHandle (parent,
1145                        (HANDLE) _get_osfhandle (err),
1146                        parent,
1147                        &newstderr,
1148                        0,
1149                        TRUE,
1150                        DUPLICATE_SAME_ACCESS))
1151     report_file_error ("Duplicating error handle for child", Qnil);
1152
1153   /* and store them as our std handles */
1154   if (!SetStdHandle (STD_INPUT_HANDLE, newstdin))
1155     report_file_error ("Changing stdin handle", Qnil);
1156   
1157   if (!SetStdHandle (STD_OUTPUT_HANDLE, newstdout))
1158     report_file_error ("Changing stdout handle", Qnil);
1159
1160   if (!SetStdHandle (STD_ERROR_HANDLE, newstderr))
1161     report_file_error ("Changing stderr handle", Qnil);
1162 }
1163
1164 void
1165 reset_standard_handles (int in, int out, int err, HANDLE handles[3])
1166 {
1167   /* close the duplicated handles passed to the child */
1168   CloseHandle (GetStdHandle (STD_INPUT_HANDLE));
1169   CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE));
1170   CloseHandle (GetStdHandle (STD_ERROR_HANDLE));
1171
1172   /* now restore parent's saved std handles */
1173   SetStdHandle (STD_INPUT_HANDLE, handles[0]);
1174   SetStdHandle (STD_OUTPUT_HANDLE, handles[1]);
1175   SetStdHandle (STD_ERROR_HANDLE, handles[2]);
1176 }
1177
1178 void
1179 set_process_dir (const char * dir)
1180 {
1181   process_dir = dir;
1182 }
1183 \f
1184 /* Some miscellaneous functions that are Windows specific, but not GUI
1185    specific (ie. are applicable in terminal or batch mode as well).  */
1186
1187 /* lifted from fileio.c  */
1188 #define CORRECT_DIR_SEPS(s) \
1189   do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
1190        else unixtodos_filename (s); \
1191   } while (0)
1192
1193 DEFUN ("win32-short-file-name", Fwin32_short_file_name, 1, 1, "", /*
1194   Return the short file name version (8.3) of the full path of FILENAME.
1195 If FILENAME does not exist, return nil.
1196 All path elements in FILENAME are converted to their short names.
1197 */
1198        (filename))
1199 {
1200   char shortname[MAX_PATH];
1201
1202   CHECK_STRING (filename);
1203
1204   /* first expand it.  */
1205   filename = Fexpand_file_name (filename, Qnil);
1206
1207   /* luckily, this returns the short version of each element in the path.  */
1208   if (GetShortPathName (XSTRING_DATA (filename), shortname, MAX_PATH) == 0)
1209     return Qnil;
1210
1211   CORRECT_DIR_SEPS (shortname);
1212
1213   return build_string (shortname);
1214 }
1215
1216
1217 DEFUN ("win32-long-file-name", Fwin32_long_file_name, 1, 1, "", /*
1218   Return the long file name version of the full path of FILENAME.
1219 If FILENAME does not exist, return nil.
1220 All path elements in FILENAME are converted to their long names.
1221 */
1222        (filename))
1223 {
1224   char longname[ MAX_PATH ];
1225
1226   CHECK_STRING (filename);
1227
1228   /* first expand it.  */
1229   filename = Fexpand_file_name (filename, Qnil);
1230
1231   if (!win32_get_long_filename (XSTRING_DATA (filename), longname, MAX_PATH))
1232     return Qnil;
1233
1234   CORRECT_DIR_SEPS (longname);
1235
1236   return build_string (longname);
1237 }
1238
1239 DEFUN ("win32-set-process-priority", Fwin32_set_process_priority, 2, 2, "", /*
1240   Set the priority of PROCESS to PRIORITY.
1241 If PROCESS is nil, the priority of Emacs is changed, otherwise the
1242 priority of the process whose pid is PROCESS is changed.
1243 PRIORITY should be one of the symbols high, normal, or low;
1244 any other symbol will be interpreted as normal.
1245
1246 If successful, the return value is t, otherwise nil.
1247 */
1248        (process, priority))
1249 {
1250   HANDLE proc_handle = GetCurrentProcess ();
1251   DWORD  priority_class = NORMAL_PRIORITY_CLASS;
1252   Lisp_Object result = Qnil;
1253
1254   CHECK_SYMBOL (priority);
1255
1256   if (!NILP (process))
1257     {
1258       DWORD pid;
1259       child_process *cp;
1260
1261       CHECK_INT (process);
1262
1263       /* Allow pid to be an internally generated one, or one obtained
1264          externally.  This is necessary because real pids on Win95 are
1265          negative.  */
1266
1267       pid = XINT (process);
1268       cp = find_child_pid (pid);
1269       if (cp != NULL)
1270         pid = cp->procinfo.dwProcessId;
1271
1272       proc_handle = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
1273     }
1274
1275   if (EQ (priority, Qhigh))
1276     priority_class = HIGH_PRIORITY_CLASS;
1277   else if (EQ (priority, Qlow))
1278     priority_class = IDLE_PRIORITY_CLASS;
1279
1280   if (proc_handle != NULL)
1281     {
1282       if (SetPriorityClass (proc_handle, priority_class))
1283         result = Qt;
1284       if (!NILP (process))
1285         CloseHandle (proc_handle);
1286     }
1287
1288   return result;
1289 }
1290
1291
1292 DEFUN ("win32-get-locale-info", Fwin32_get_locale_info, 1, 2, "", /*
1293   "Return information about the Windows locale LCID.
1294 By default, return a three letter locale code which encodes the default
1295 language as the first two characters, and the country or regional variant
1296 as the third letter.  For example, ENU refers to `English (United States)',
1297 while ENC means `English (Canadian)'.
1298
1299 If the optional argument LONGFORM is non-nil, the long form of the locale
1300 name is returned, e.g. `English (United States)' instead.
1301
1302 If LCID (a 16-bit number) is not a valid locale, the result is nil.
1303 */
1304      (lcid, longform))
1305 {
1306   int got_abbrev;
1307   int got_full;
1308   char abbrev_name[32] = { 0 };
1309   char full_name[256] = { 0 };
1310
1311   CHECK_INT (lcid);
1312
1313   if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED))
1314     return Qnil;
1315
1316   if (NILP (longform))
1317     {
1318       got_abbrev = GetLocaleInfo (XINT (lcid),
1319                                   LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1320                                   abbrev_name, sizeof (abbrev_name));
1321       if (got_abbrev)
1322         return build_string (abbrev_name);
1323     }
1324   else
1325     {
1326       got_full = GetLocaleInfo (XINT (lcid),
1327                                 LOCALE_SLANGUAGE | LOCALE_USE_CP_ACP,
1328                                 full_name, sizeof (full_name));
1329       if (got_full)
1330         return build_string (full_name);
1331     }
1332
1333   return Qnil;
1334 }
1335
1336
1337 DEFUN ("win32-get-current-locale-id", Fwin32_get_current_locale_id, 0, 0, "", /*
1338   "Return Windows locale id for current locale setting.
1339 This is a numerical value; use `win32-get-locale-info' to convert to a
1340 human-readable form.
1341 */
1342        ())
1343 {
1344   return make_int (GetThreadLocale ());
1345 }
1346
1347
1348 DEFUN ("win32-get-default-locale-id", Fwin32_get_default_locale_id, 0, 1, "", /*
1349   "Return Windows locale id for default locale setting.
1350 By default, the system default locale setting is returned; if the optional
1351 parameter USERP is non-nil, the user default locale setting is returned.
1352 This is a numerical value; use `win32-get-locale-info' to convert to a
1353 human-readable form.
1354 */
1355        (userp))
1356 {
1357   if (NILP (userp))
1358     return make_int (GetSystemDefaultLCID ());
1359   return make_int (GetUserDefaultLCID ());
1360 }
1361
1362 DWORD int_from_hex (char * s)
1363 {
1364   DWORD val = 0;
1365   static char hex[] = "0123456789abcdefABCDEF";
1366   char * p;
1367
1368   while (*s && (p = strchr(hex, *s)) != NULL)
1369     {
1370       unsigned digit = p - hex;
1371       if (digit > 15)
1372         digit -= 6;
1373       val = val * 16 + digit;
1374       s++;
1375     }
1376   return val;
1377 }
1378
1379 /* We need to build a global list, since the EnumSystemLocale callback
1380    function isn't given a context pointer.  */
1381 Lisp_Object Vwin32_valid_locale_ids;
1382
1383 BOOL CALLBACK enum_locale_fn (LPTSTR localeNum)
1384 {
1385   DWORD id = int_from_hex (localeNum);
1386   Vwin32_valid_locale_ids = Fcons (make_int (id), Vwin32_valid_locale_ids);
1387   return TRUE;
1388 }
1389
1390 DEFUN ("win32-get-valid-locale-ids", Fwin32_get_valid_locale_ids, 0, 0, "", /*
1391   Return list of all valid Windows locale ids.
1392 Each id is a numerical value; use `win32-get-locale-info' to convert to a
1393 human-readable form.
1394 */
1395        ())
1396 {
1397   Vwin32_valid_locale_ids = Qnil;
1398
1399   EnumSystemLocales (enum_locale_fn, LCID_SUPPORTED);
1400
1401   Vwin32_valid_locale_ids = Fnreverse (Vwin32_valid_locale_ids);
1402   return Vwin32_valid_locale_ids;
1403 }
1404
1405
1406 DEFUN ("win32-set-current-locale", Fwin32_set_current_locale, 1, 1, "", /*
1407   Make Windows locale LCID be the current locale setting for Emacs.
1408 If successful, the new locale id is returned, otherwise nil.
1409 */
1410      (lcid))
1411 {
1412   CHECK_INT (lcid);
1413
1414   if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED))
1415     return Qnil;
1416
1417   if (!SetThreadLocale (XINT (lcid)))
1418     return Qnil;
1419
1420 /* Sync with FSF Emacs 19.34.6 note: dwWinThreadId declared in
1421    w32term.h and defined in w32fns.c, both of which are not in current
1422    XEmacs.  ### Check what we lose by ifdef'ing out these. --marcpa */
1423 #if 0
1424   /* Need to set input thread locale if present.  */
1425   if (dwWinThreadId)
1426     /* Reply is not needed.  */
1427     PostThreadMessage (dwWinThreadId, WM_EMACS_SETLOCALE, XINT (lcid), 0);
1428 #endif
1429
1430   return make_int (GetThreadLocale ());
1431 }
1432
1433 \f
1434 void
1435 syms_of_ntproc ()
1436 {
1437   DEFSUBR (Fwin32_short_file_name);
1438   DEFSUBR (Fwin32_long_file_name);
1439   DEFSUBR (Fwin32_set_process_priority);
1440   DEFSUBR (Fwin32_get_locale_info);
1441   DEFSUBR (Fwin32_get_current_locale_id);
1442   DEFSUBR (Fwin32_get_default_locale_id);
1443   DEFSUBR (Fwin32_get_valid_locale_ids);
1444   DEFSUBR (Fwin32_set_current_locale);
1445 }
1446
1447
1448 void
1449 vars_of_ntproc (void)
1450 {
1451   defsymbol (&Qhigh, "high");
1452   defsymbol (&Qlow, "low");
1453
1454   DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args /*
1455     Non-nil enables quoting of process arguments to ensure correct parsing.
1456 Because Windows does not directly pass argv arrays to child processes,
1457 programs have to reconstruct the argv array by parsing the command
1458 line string.  For an argument to contain a space, it must be enclosed
1459 in double quotes or it will be parsed as multiple arguments.
1460
1461 If the value is a character, that character will be used to escape any
1462 quote characters that appear, otherwise a suitable escape character
1463 will be chosen based on the type of the program.
1464 */ );
1465   Vwin32_quote_process_args = Qt;
1466
1467   DEFVAR_LISP ("win32-start-process-show-window",
1468                &Vwin32_start_process_show_window /*
1469     When nil, processes started via start-process hide their windows.
1470 When non-nil, they show their window in the method of their choice.
1471 */ );
1472   Vwin32_start_process_show_window = Qnil;
1473
1474   DEFVAR_LISP ("win32-start-process-share-console",
1475                &Vwin32_start_process_share_console /*
1476     When nil, processes started via start-process are given a new console.
1477 When non-nil, they share the Emacs console; this has the limitation of
1478 allowing only only DOS subprocess to run at a time (whether started directly
1479 or indirectly by Emacs), and preventing Emacs from cleanly terminating the
1480 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't
1481 otherwise respond to interrupts from Emacs.
1482 */ );
1483   Vwin32_start_process_share_console = Qt;
1484
1485   DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /*
1486     Forced delay before reading subprocess output.
1487 This is done to improve the buffering of subprocess output, by
1488 avoiding the inefficiency of frequently reading small amounts of data.
1489
1490 If positive, the value is the number of milliseconds to sleep before
1491 reading the subprocess output.  If negative, the magnitude is the number
1492 of time slices to wait (effectively boosting the priority of the child
1493 process temporarily).  A value of zero disables waiting entirely.
1494 */ );
1495   Vwin32_pipe_read_delay = make_int (50);
1496
1497 #if 0
1498   DEFVAR_LISP ("win32-generate-fake-inodes", &Vwin32_generate_fake_inodes /*
1499     "Non-nil means attempt to fake realistic inode values.
1500 This works by hashing the truename of files, and should detect 
1501 aliasing between long and short (8.3 DOS) names, but can have
1502 false positives because of hash collisions.  Note that determining
1503 the truename of a file can be slow.
1504 */ );
1505   Vwin32_generate_fake_inodes = Qnil;
1506 #endif
1507 }
1508
1509 /* end of ntproc.c */