d20bb191356183a8f3bc4747034d25fa1d6b9a54
[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   /* Hack for Windows 95, which assigns large (ie negative) pids */
449   if (cp->pid < 0)
450     cp->pid = -cp->pid;
451
452   /* pid must fit in a Lisp_Int */
453 #ifdef USE_UNION_TYPE
454   cp->pid = (cp->pid & ((1U << VALBITS) - 1));
455 #else
456   cp->pid = (cp->pid & VALMASK);
457 #endif
458
459   *pPid = cp->pid;
460   
461   return TRUE;
462   
463  EH_Fail:
464   DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError()););
465   return FALSE;
466 }
467
468 #ifndef __MINGW32__
469 /* Return pointer to section header for section containing the given
470    relative virtual address. */
471 static IMAGE_SECTION_HEADER *
472 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
473 {
474   PIMAGE_SECTION_HEADER section;
475   int i;
476
477   section = IMAGE_FIRST_SECTION (nt_header);
478
479   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
480     {
481       if (rva >= section->VirtualAddress
482           && rva < section->VirtualAddress + section->SizeOfRawData)
483         return section;
484       section++;
485     }
486   return NULL;
487 }
488 #endif
489
490 void
491 win32_executable_type (CONST char * filename, int * is_dos_app, int * is_cygnus_app)
492 {
493   file_data executable;
494   char * p;
495
496   /* Default values in case we can't tell for sure.  */
497   *is_dos_app = FALSE;
498   *is_cygnus_app = FALSE;
499
500   if (!open_input_file (&executable, filename))
501     return;
502
503   p = strrchr (filename, '.');
504
505       /* We can only identify DOS .com programs from the extension. */
506       if (p && stricmp (p, ".com") == 0)
507     *is_dos_app = TRUE;
508   else if (p && (stricmp (p, ".bat") == 0 ||
509                  stricmp (p, ".cmd") == 0))
510     {
511       /* A DOS shell script - it appears that CreateProcess is happy to
512          accept this (somewhat surprisingly); presumably it looks at
513          COMSPEC to determine what executable to actually invoke.
514              Therefore, we have to do the same here as well. */
515       /* Actually, I think it uses the program association for that
516          extension, which is defined in the registry.  */
517       p = egetenv ("COMSPEC");
518       if (p)
519         win32_executable_type (p, is_dos_app, is_cygnus_app);
520     }
521       else
522         {
523       /* Look for DOS .exe signature - if found, we must also check that
524          it isn't really a 16- or 32-bit Windows exe, since both formats
525          start with a DOS program stub.  Note that 16-bit Windows
526          executables use the OS/2 1.x format. */
527
528 #ifdef __MINGW32__
529           /* mingw32 doesn't have enough headers to detect cygwin
530              apps, just do what we can. */
531           FILHDR * exe_header;
532
533           exe_header = (FILHDR*) executable.file_base;
534           if (exe_header->e_magic != DOSMAGIC)
535             goto unwind;
536
537           if ((char *) exe_header->e_lfanew > (char *) executable.size)
538             {
539               /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
540               *is_dos_app = TRUE;
541             } 
542           else if (exe_header->nt_signature != NT_SIGNATURE)
543             {
544               *is_dos_app = TRUE;
545             }
546 #else
547           IMAGE_DOS_HEADER * dos_header;
548           IMAGE_NT_HEADERS * nt_header;
549
550           dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
551           if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
552             goto unwind;
553           
554           nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
555           
556           if ((char *) nt_header > (char *) dos_header + executable.size) 
557             {
558               /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
559               *is_dos_app = TRUE;
560             } 
561           else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
562                    LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
563             {
564               *is_dos_app = TRUE;
565             }
566           else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
567             {
568               /* Look for cygwin.dll in DLL import list. */
569               IMAGE_DATA_DIRECTORY import_dir =
570                 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
571               IMAGE_IMPORT_DESCRIPTOR * imports;
572               IMAGE_SECTION_HEADER * section;
573
574               section = rva_to_section (import_dir.VirtualAddress, nt_header);
575               imports = RVA_TO_PTR (import_dir.VirtualAddress, section, executable);
576               
577               for ( ; imports->Name; imports++)
578                 {
579                   char * dllname = RVA_TO_PTR (imports->Name, section, executable);
580
581                   if (strcmp (dllname, "cygwin.dll") == 0)
582                     {
583                       *is_cygnus_app = TRUE;
584                       break;
585                     }
586                 }
587             }
588 #endif
589         }
590
591  unwind:
592       close_file_data (&executable);
593 }
594
595 int
596 compare_env (const void *strp1, const void *strp2)
597 {
598   const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2;
599
600   while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
601     {
602       if ((*str1) > (*str2))
603         return 1;
604       else if ((*str1) < (*str2))
605         return -1;
606       str1++, str2++;
607     }
608
609   if (*str1 == '=' && *str2 == '=')
610     return 0;
611   else if (*str1 == '=')
612     return -1;
613   else
614     return 1;
615 }
616
617 void
618 merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
619 {
620   char **optr, **nptr;
621   int num;
622
623   nptr = new_envp;
624   optr = envp1;
625   while (*optr)
626     *nptr++ = *optr++;
627   num = optr - envp1;
628
629   optr = envp2;
630   while (*optr)
631     *nptr++ = *optr++;
632   num += optr - envp2;
633
634   qsort (new_envp, num, sizeof (char *), compare_env);
635
636   *nptr = NULL;
637 }
638
639 /* When a new child process is created we need to register it in our list,
640    so intercept spawn requests.  */
641 int 
642 sys_spawnve (int mode, CONST char *cmdname,
643              CONST char * CONST *argv, CONST char *CONST *envp)
644 {
645   Lisp_Object program, full;
646   char *cmdline, *env, *parg, **targ;
647   int arglen, numenv;
648   int pid;
649   child_process *cp;
650   int is_dos_app, is_cygnus_app;
651   int do_quoting = 0;
652   char escape_char = 0;
653   /* We pass our process ID to our children by setting up an environment
654      variable in their environment.  */
655   char ppid_env_var_buffer[64];
656   char *extra_env[] = {ppid_env_var_buffer, NULL};
657   struct gcpro gcpro1;
658     
659   /* We don't care about the other modes */
660   if (mode != _P_NOWAIT)
661     {
662       errno = EINVAL;
663       return -1;
664     }
665
666   /* Handle executable names without an executable suffix.  */
667   program = make_string (cmdname, strlen (cmdname));
668   GCPRO1 (program);
669   if (NILP (Ffile_executable_p (program)))
670     {
671       full = Qnil;
672       locate_file (Vexec_path, program, Vlisp_EXEC_SUFFIXES, &full, 1);
673       if (NILP (full))
674         {
675           UNGCPRO;
676           errno = EINVAL;
677           return -1;
678         }
679       GET_C_STRING_FILENAME_DATA_ALLOCA (full, cmdname);
680     }
681   else
682     {
683       (char*)cmdname = alloca (strlen (argv[0]) + 1);
684       strcpy ((char*)cmdname, argv[0]);
685     }
686   UNGCPRO;
687
688   /* make sure argv[0] and cmdname are both in DOS format */
689   unixtodos_filename ((char*)cmdname);
690   /* #### KLUDGE */
691   ((CONST char**)argv)[0] = cmdname;
692
693   /* Determine whether program is a 16-bit DOS executable, or a Win32
694      executable that is implicitly linked to the Cygnus dll (implying it
695      was compiled with the Cygnus GNU toolchain and hence relies on
696      cygwin.dll to parse the command line - we use this to decide how to
697      escape quote chars in command line args that must be quoted). */
698   win32_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
699
700   /* On Windows 95, if cmdname is a DOS app, we invoke a helper
701      application to start it by specifying the helper app as cmdname,
702      while leaving the real app name as argv[0].  */
703   if (is_dos_app)
704     {
705       cmdname = alloca (MAXPATHLEN);
706       if (egetenv ("CMDPROXY"))
707         strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
708       else
709     {
710           strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory));
711           strcat ((char*)cmdname, "cmdproxy.exe");
712         }
713       unixtodos_filename ((char*)cmdname);
714     }
715   
716   /* we have to do some conjuring here to put argv and envp into the
717      form CreateProcess wants...  argv needs to be a space separated/null
718      terminated list of parameters, and envp is a null
719      separated/double-null terminated list of parameters.
720
721      Additionally, zero-length args and args containing whitespace or
722      quote chars need to be wrapped in double quotes - for this to work,
723      embedded quotes need to be escaped as well.  The aim is to ensure
724      the child process reconstructs the argv array we start with
725      exactly, so we treat quotes at the beginning and end of arguments
726      as embedded quotes.
727
728      The Win32 GNU-based library from Cygnus doubles quotes to escape
729      them, while MSVC uses backslash for escaping.  (Actually the MSVC
730      startup code does attempt to recognize doubled quotes and accept
731      them, but gets it wrong and ends up requiring three quotes to get a
732      single embedded quote!)  So by default we decide whether to use
733      quote or backslash as the escape character based on whether the
734      binary is apparently a Cygnus compiled app.
735
736      Note that using backslash to escape embedded quotes requires
737      additional special handling if an embedded quote is already
738      preceded by backslash, or if an arg requiring quoting ends with
739      backslash.  In such cases, the run of escape characters needs to be
740      doubled.  For consistency, we apply this special handling as long
741      as the escape character is not quote.
742    
743      Since we have no idea how large argv and envp are likely to be we
744      figure out list lengths on the fly and allocate them.  */
745   
746   if (!NILP (Vwin32_quote_process_args))
747     {
748       do_quoting = 1;
749       /* Override escape char by binding win32-quote-process-args to
750          desired character, or use t for auto-selection.  */
751       if (INTP (Vwin32_quote_process_args))
752         escape_char = XINT (Vwin32_quote_process_args);
753       else
754         escape_char = is_cygnus_app ? '"' : '\\';
755     }
756   
757   /* do argv...  */
758   arglen = 0;
759   targ = (char**)argv;
760   while (*targ)
761     {
762       char * p = *targ;
763       int need_quotes = 0;
764       int escape_char_run = 0;
765
766       if (*p == 0)
767         need_quotes = 1;
768       for ( ; *p; p++)
769         {
770           if (*p == '"')
771           {
772               /* allow for embedded quotes to be escaped */
773             arglen++;
774               need_quotes = 1;
775               /* handle the case where the embedded quote is already escaped */
776               if (escape_char_run > 0)
777                 {
778                   /* To preserve the arg exactly, we need to double the
779                      preceding escape characters (plus adding one to
780                      escape the quote character itself).  */
781                   arglen += escape_char_run;
782           }
783             }
784       else if (*p == ' ' || *p == '\t')
785             {
786               need_quotes = 1;
787             }
788
789           if (*p == escape_char && escape_char != '"')
790             escape_char_run++;
791           else
792             escape_char_run = 0;
793         }
794       if (need_quotes)
795         {
796         arglen += 2;
797           /* handle the case where the arg ends with an escape char - we
798              must not let the enclosing quote be escaped.  */
799           if (escape_char_run > 0)
800             arglen += escape_char_run;
801         }
802       arglen += strlen (*targ++) + 1;
803     }
804   cmdline = alloca (arglen);
805   targ = (char**)argv;
806   parg = cmdline;
807   while (*targ)
808     {
809       char * p = *targ;
810       int need_quotes = 0;
811
812       if (*p == 0)
813         need_quotes = 1;
814
815       if (do_quoting)
816         {
817           for ( ; *p; p++)
818             if (*p == ' ' || *p == '\t' || *p == '"')
819               need_quotes = 1;
820         }
821       if (need_quotes)
822         {
823           int escape_char_run = 0;
824           char * first;
825           char * last;
826
827           p = *targ;
828           first = p;
829           last = p + strlen (p) - 1;
830           *parg++ = '"';
831 #if 0
832           /* This version does not escape quotes if they occur at the
833              beginning or end of the arg - this could lead to incorrect
834              behavior when the arg itself represents a command line
835              containing quoted args.  I believe this was originally done
836              as a hack to make some things work, before
837              `win32-quote-process-args' was added.  */
838           while (*p)
839             {
840               if (*p == '"' && p > first && p < last)
841                 *parg++ = escape_char;  /* escape embedded quotes */
842               *parg++ = *p++;
843             }
844 #else
845           for ( ; *p; p++)
846             {
847               if (*p == '"')
848                 {
849                   /* double preceding escape chars if any */
850                   while (escape_char_run > 0)
851                     {
852                       *parg++ = escape_char;
853                       escape_char_run--;
854                     }
855                   /* escape all quote chars, even at beginning or end */
856                   *parg++ = escape_char;
857                 }
858               *parg++ = *p;
859
860               if (*p == escape_char && escape_char != '"')
861                 escape_char_run++;
862               else
863                 escape_char_run = 0;
864             }
865           /* double escape chars before enclosing quote */
866           while (escape_char_run > 0)
867             {
868               *parg++ = escape_char;
869               escape_char_run--;
870             }
871 #endif
872           *parg++ = '"';
873         }
874       else
875         {
876           strcpy (parg, *targ);
877           parg += strlen (*targ);
878         }
879       *parg++ = ' ';
880       targ++;
881     }
882   *--parg = '\0';
883   
884   /* and envp...  */
885   arglen = 1;
886   targ = (char**)envp;
887   numenv = 1; /* for end null */
888   while (*targ)
889     {
890       arglen += strlen (*targ++) + 1;
891       numenv++;
892     }
893   /* extra env vars... */
894   sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d", 
895            GetCurrentProcessId ());
896   arglen += strlen (ppid_env_var_buffer) + 1;
897   numenv++;
898
899   /* merge env passed in and extra env into one, and sort it.  */
900   targ = (char **) alloca (numenv * sizeof (char *));
901   merge_and_sort_env ((char**)envp, extra_env, targ);
902
903   /* concatenate env entries.  */
904   env = alloca (arglen);
905   parg = env;
906   while (*targ)
907     {
908       strcpy (parg, *targ);
909       parg += strlen (*targ++);
910       *parg++ = '\0';
911     }
912   *parg++ = '\0';
913   *parg = '\0';
914
915   cp = new_child ();
916   if (cp == NULL)
917     {
918       errno = EAGAIN;
919       return -1;
920     }
921   
922   /* Now create the process.  */
923   if (!create_child (cmdname, cmdline, env, &pid, cp))
924     {
925       delete_child (cp);
926       errno = ENOEXEC;
927       return -1;
928     }
929
930   return pid;
931 }
932
933 /* Substitute for certain kill () operations */
934
935 static BOOL CALLBACK
936 find_child_console (HWND hwnd, child_process * cp)
937 {
938   DWORD thread_id;
939   DWORD process_id;
940
941   thread_id = GetWindowThreadProcessId (hwnd, &process_id);
942   if (process_id == cp->procinfo.dwProcessId)
943     {
944       char window_class[32];
945
946       GetClassName (hwnd, window_class, sizeof (window_class));
947       if (strcmp (window_class,
948                   (os_subtype == OS_WIN95)
949                   ? "tty"
950                   : "ConsoleWindowClass") == 0)
951         {
952           cp->hwnd = hwnd;
953           return FALSE;
954         }
955     }
956   /* keep looking */
957   return TRUE;
958 }
959
960 int 
961 sys_kill (int pid, int sig)
962 {
963   child_process *cp;
964   HANDLE proc_hand;
965   int need_to_free = 0;
966   int rc = 0;
967   
968   /* Only handle signals that will result in the process dying */
969   if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
970     {
971       errno = EINVAL;
972       return -1;
973     }
974
975   cp = find_child_pid (pid);
976   if (cp == NULL)
977     {
978       proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid);
979       if (proc_hand == NULL)
980         {
981           errno = EPERM;
982           return -1;
983         }
984       need_to_free = 1;
985     }
986   else
987     {
988       proc_hand = cp->procinfo.hProcess;
989       pid = cp->procinfo.dwProcessId;
990
991       /* Try to locate console window for process. */
992       EnumWindows ((WNDENUMPROC)find_child_console, (LPARAM) cp);
993     }
994   
995   if (sig == SIGINT)
996     {
997       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
998         {
999           BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
1000           BYTE vk_break_code = VK_CANCEL;
1001           BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
1002           HWND foreground_window;
1003
1004           if (break_scan_code == 0)
1005             {
1006               /* Fake Ctrl-C if we can't manage Ctrl-Break. */
1007               vk_break_code = 'C';
1008               break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
1009             }
1010
1011           foreground_window = GetForegroundWindow ();
1012           if (foreground_window && SetForegroundWindow (cp->hwnd))
1013             {
1014               /* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C.  */
1015               keybd_event (VK_CONTROL, control_scan_code, 0, 0);
1016               keybd_event (vk_break_code, break_scan_code, 0, 0);
1017               keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
1018               keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
1019
1020               /* Sleep for a bit to give time for Emacs frame to respond
1021                  to focus change events (if Emacs was active app).  */
1022               Sleep (10);
1023
1024               SetForegroundWindow (foreground_window);
1025             }
1026         }
1027       /* Ctrl-Break is NT equivalent of SIGINT.  */
1028       else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
1029         {
1030           DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d "
1031                      "for pid %lu\n", GetLastError (), pid));
1032           errno = EINVAL;
1033           rc = -1;
1034         }
1035     }
1036   else
1037     {
1038       if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
1039         {
1040 #if 1
1041           if (os_subtype == OS_WIN95)
1042             {
1043 /*
1044    Another possibility is to try terminating the VDM out-right by
1045    calling the Shell VxD (id 0x17) V86 interface, function #4
1046    "SHELL_Destroy_VM", ie.
1047
1048      mov edx,4
1049      mov ebx,vm_handle
1050      call shellapi
1051
1052    First need to determine the current VM handle, and then arrange for
1053    the shellapi call to be made from the system vm (by using
1054    Switch_VM_and_callback).
1055
1056    Could try to invoke DestroyVM through CallVxD.
1057
1058 */
1059 #if 0
1060               /* On Win95, posting WM_QUIT causes the 16-bit subsystem
1061                  to hang when cmdproxy is used in conjunction with
1062                  command.com for an interactive shell.  Posting
1063                  WM_CLOSE pops up a dialog that, when Yes is selected,
1064                  does the same thing.  TerminateProcess is also less
1065                  than ideal in that subprocesses tend to stick around
1066                  until the machine is shutdown, but at least it
1067                  doesn't freeze the 16-bit subsystem.  */
1068               PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
1069 #endif
1070               if (!TerminateProcess (proc_hand, 0xff))
1071                 {
1072                   DebPrint (("sys_kill.TerminateProcess returned %d "
1073                              "for pid %lu\n", GetLastError (), pid));
1074                   errno = EINVAL;
1075                   rc = -1;
1076                 }
1077             }
1078           else
1079 #endif
1080             PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
1081         }
1082       /* Kill the process.  On Win32 this doesn't kill child processes
1083          so it doesn't work very well for shells which is why it's not
1084          used in every case.  */
1085       else if (!TerminateProcess (proc_hand, 0xff))
1086         {
1087           DebPrint (("sys_kill.TerminateProcess returned %d "
1088                      "for pid %lu\n", GetLastError (), pid));
1089           errno = EINVAL;
1090           rc = -1;
1091         }
1092     }
1093
1094   if (need_to_free)
1095     CloseHandle (proc_hand);
1096
1097   return rc;
1098 }
1099
1100 #if 0
1101 /* Sync with FSF Emacs 19.34.6 note: ifdef'ed out in XEmacs */
1102 extern int report_file_error (CONST char *, Lisp_Object);
1103 #endif
1104 /* The following two routines are used to manipulate stdin, stdout, and
1105    stderr of our child processes.
1106
1107    Assuming that in, out, and err are *not* inheritable, we make them
1108    stdin, stdout, and stderr of the child as follows:
1109
1110    - Save the parent's current standard handles.
1111    - Set the std handles to inheritable duplicates of the ones being passed in.
1112      (Note that _get_osfhandle() is an io.h procedure that retrieves the
1113      NT file handle for a crt file descriptor.)
1114    - Spawn the child, which inherits in, out, and err as stdin,
1115      stdout, and stderr. (see Spawnve)
1116    - Close the std handles passed to the child.
1117    - Reset the parent's standard handles to the saved handles.
1118      (see reset_standard_handles)
1119    We assume that the caller closes in, out, and err after calling us.  */
1120
1121 void
1122 prepare_standard_handles (int in, int out, int err, HANDLE handles[3])
1123 {
1124   HANDLE parent;
1125   HANDLE newstdin, newstdout, newstderr;
1126
1127   parent = GetCurrentProcess ();
1128
1129   handles[0] = GetStdHandle (STD_INPUT_HANDLE);
1130   handles[1] = GetStdHandle (STD_OUTPUT_HANDLE);
1131   handles[2] = GetStdHandle (STD_ERROR_HANDLE);
1132
1133   /* make inheritable copies of the new handles */
1134   if (!DuplicateHandle (parent, 
1135                        (HANDLE) _get_osfhandle (in),
1136                        parent,
1137                        &newstdin, 
1138                        0, 
1139                        TRUE, 
1140                        DUPLICATE_SAME_ACCESS))
1141     report_file_error ("Duplicating input handle for child", Qnil);
1142   
1143   if (!DuplicateHandle (parent,
1144                        (HANDLE) _get_osfhandle (out),
1145                        parent,
1146                        &newstdout,
1147                        0,
1148                        TRUE,
1149                        DUPLICATE_SAME_ACCESS))
1150     report_file_error ("Duplicating output handle for child", Qnil);
1151   
1152   if (!DuplicateHandle (parent,
1153                        (HANDLE) _get_osfhandle (err),
1154                        parent,
1155                        &newstderr,
1156                        0,
1157                        TRUE,
1158                        DUPLICATE_SAME_ACCESS))
1159     report_file_error ("Duplicating error handle for child", Qnil);
1160
1161   /* and store them as our std handles */
1162   if (!SetStdHandle (STD_INPUT_HANDLE, newstdin))
1163     report_file_error ("Changing stdin handle", Qnil);
1164   
1165   if (!SetStdHandle (STD_OUTPUT_HANDLE, newstdout))
1166     report_file_error ("Changing stdout handle", Qnil);
1167
1168   if (!SetStdHandle (STD_ERROR_HANDLE, newstderr))
1169     report_file_error ("Changing stderr handle", Qnil);
1170 }
1171
1172 void
1173 reset_standard_handles (int in, int out, int err, HANDLE handles[3])
1174 {
1175   /* close the duplicated handles passed to the child */
1176   CloseHandle (GetStdHandle (STD_INPUT_HANDLE));
1177   CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE));
1178   CloseHandle (GetStdHandle (STD_ERROR_HANDLE));
1179
1180   /* now restore parent's saved std handles */
1181   SetStdHandle (STD_INPUT_HANDLE, handles[0]);
1182   SetStdHandle (STD_OUTPUT_HANDLE, handles[1]);
1183   SetStdHandle (STD_ERROR_HANDLE, handles[2]);
1184 }
1185
1186 void
1187 set_process_dir (const char * dir)
1188 {
1189   process_dir = dir;
1190 }
1191 \f
1192 /* Some miscellaneous functions that are Windows specific, but not GUI
1193    specific (ie. are applicable in terminal or batch mode as well).  */
1194
1195 /* lifted from fileio.c  */
1196 #define CORRECT_DIR_SEPS(s) \
1197   do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
1198        else unixtodos_filename (s); \
1199   } while (0)
1200
1201 DEFUN ("win32-short-file-name", Fwin32_short_file_name, 1, 1, "", /*
1202   Return the short file name version (8.3) of the full path of FILENAME.
1203 If FILENAME does not exist, return nil.
1204 All path elements in FILENAME are converted to their short names.
1205 */
1206        (filename))
1207 {
1208   char shortname[MAX_PATH];
1209
1210   CHECK_STRING (filename);
1211
1212   /* first expand it.  */
1213   filename = Fexpand_file_name (filename, Qnil);
1214
1215   /* luckily, this returns the short version of each element in the path.  */
1216   if (GetShortPathName (XSTRING_DATA (filename), shortname, MAX_PATH) == 0)
1217     return Qnil;
1218
1219   CORRECT_DIR_SEPS (shortname);
1220
1221   return build_string (shortname);
1222 }
1223
1224
1225 DEFUN ("win32-long-file-name", Fwin32_long_file_name, 1, 1, "", /*
1226   Return the long file name version of the full path of FILENAME.
1227 If FILENAME does not exist, return nil.
1228 All path elements in FILENAME are converted to their long names.
1229 */
1230        (filename))
1231 {
1232   char longname[ MAX_PATH ];
1233
1234   CHECK_STRING (filename);
1235
1236   /* first expand it.  */
1237   filename = Fexpand_file_name (filename, Qnil);
1238
1239   if (!win32_get_long_filename (XSTRING_DATA (filename), longname, MAX_PATH))
1240     return Qnil;
1241
1242   CORRECT_DIR_SEPS (longname);
1243
1244   return build_string (longname);
1245 }
1246
1247 DEFUN ("win32-set-process-priority", Fwin32_set_process_priority, 2, 2, "", /*
1248   Set the priority of PROCESS to PRIORITY.
1249 If PROCESS is nil, the priority of Emacs is changed, otherwise the
1250 priority of the process whose pid is PROCESS is changed.
1251 PRIORITY should be one of the symbols high, normal, or low;
1252 any other symbol will be interpreted as normal.
1253
1254 If successful, the return value is t, otherwise nil.
1255 */
1256        (process, priority))
1257 {
1258   HANDLE proc_handle = GetCurrentProcess ();
1259   DWORD  priority_class = NORMAL_PRIORITY_CLASS;
1260   Lisp_Object result = Qnil;
1261
1262   CHECK_SYMBOL (priority);
1263
1264   if (!NILP (process))
1265     {
1266       DWORD pid;
1267       child_process *cp;
1268
1269       CHECK_INT (process);
1270
1271       /* Allow pid to be an internally generated one, or one obtained
1272          externally.  This is necessary because real pids on Win95 are
1273          negative.  */
1274
1275       pid = XINT (process);
1276       cp = find_child_pid (pid);
1277       if (cp != NULL)
1278         pid = cp->procinfo.dwProcessId;
1279
1280       proc_handle = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
1281     }
1282
1283   if (EQ (priority, Qhigh))
1284     priority_class = HIGH_PRIORITY_CLASS;
1285   else if (EQ (priority, Qlow))
1286     priority_class = IDLE_PRIORITY_CLASS;
1287
1288   if (proc_handle != NULL)
1289     {
1290       if (SetPriorityClass (proc_handle, priority_class))
1291         result = Qt;
1292       if (!NILP (process))
1293         CloseHandle (proc_handle);
1294     }
1295
1296   return result;
1297 }
1298
1299
1300 DEFUN ("win32-get-locale-info", Fwin32_get_locale_info, 1, 2, "", /*
1301   "Return information about the Windows locale LCID.
1302 By default, return a three letter locale code which encodes the default
1303 language as the first two characters, and the country or regional variant
1304 as the third letter.  For example, ENU refers to `English (United States)',
1305 while ENC means `English (Canadian)'.
1306
1307 If the optional argument LONGFORM is non-nil, the long form of the locale
1308 name is returned, e.g. `English (United States)' instead.
1309
1310 If LCID (a 16-bit number) is not a valid locale, the result is nil.
1311 */
1312      (lcid, longform))
1313 {
1314   int got_abbrev;
1315   int got_full;
1316   char abbrev_name[32] = { 0 };
1317   char full_name[256] = { 0 };
1318
1319   CHECK_INT (lcid);
1320
1321   if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED))
1322     return Qnil;
1323
1324   if (NILP (longform))
1325     {
1326       got_abbrev = GetLocaleInfo (XINT (lcid),
1327                                   LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1328                                   abbrev_name, sizeof (abbrev_name));
1329       if (got_abbrev)
1330         return build_string (abbrev_name);
1331     }
1332   else
1333     {
1334       got_full = GetLocaleInfo (XINT (lcid),
1335                                 LOCALE_SLANGUAGE | LOCALE_USE_CP_ACP,
1336                                 full_name, sizeof (full_name));
1337       if (got_full)
1338         return build_string (full_name);
1339     }
1340
1341   return Qnil;
1342 }
1343
1344
1345 DEFUN ("win32-get-current-locale-id", Fwin32_get_current_locale_id, 0, 0, "", /*
1346   "Return Windows locale id for current locale setting.
1347 This is a numerical value; use `win32-get-locale-info' to convert to a
1348 human-readable form.
1349 */
1350        ())
1351 {
1352   return make_int (GetThreadLocale ());
1353 }
1354
1355
1356 DEFUN ("win32-get-default-locale-id", Fwin32_get_default_locale_id, 0, 1, "", /*
1357   "Return Windows locale id for default locale setting.
1358 By default, the system default locale setting is returned; if the optional
1359 parameter USERP is non-nil, the user default locale setting is returned.
1360 This is a numerical value; use `win32-get-locale-info' to convert to a
1361 human-readable form.
1362 */
1363        (userp))
1364 {
1365   if (NILP (userp))
1366     return make_int (GetSystemDefaultLCID ());
1367   return make_int (GetUserDefaultLCID ());
1368 }
1369
1370 DWORD int_from_hex (char * s)
1371 {
1372   DWORD val = 0;
1373   static char hex[] = "0123456789abcdefABCDEF";
1374   char * p;
1375
1376   while (*s && (p = strchr(hex, *s)) != NULL)
1377     {
1378       unsigned digit = p - hex;
1379       if (digit > 15)
1380         digit -= 6;
1381       val = val * 16 + digit;
1382       s++;
1383     }
1384   return val;
1385 }
1386
1387 /* We need to build a global list, since the EnumSystemLocale callback
1388    function isn't given a context pointer.  */
1389 Lisp_Object Vwin32_valid_locale_ids;
1390
1391 BOOL CALLBACK enum_locale_fn (LPTSTR localeNum)
1392 {
1393   DWORD id = int_from_hex (localeNum);
1394   Vwin32_valid_locale_ids = Fcons (make_int (id), Vwin32_valid_locale_ids);
1395   return TRUE;
1396 }
1397
1398 DEFUN ("win32-get-valid-locale-ids", Fwin32_get_valid_locale_ids, 0, 0, "", /*
1399   Return list of all valid Windows locale ids.
1400 Each id is a numerical value; use `win32-get-locale-info' to convert to a
1401 human-readable form.
1402 */
1403        ())
1404 {
1405   Vwin32_valid_locale_ids = Qnil;
1406
1407   EnumSystemLocales (enum_locale_fn, LCID_SUPPORTED);
1408
1409   Vwin32_valid_locale_ids = Fnreverse (Vwin32_valid_locale_ids);
1410   return Vwin32_valid_locale_ids;
1411 }
1412
1413
1414 DEFUN ("win32-set-current-locale", Fwin32_set_current_locale, 1, 1, "", /*
1415   Make Windows locale LCID be the current locale setting for Emacs.
1416 If successful, the new locale id is returned, otherwise nil.
1417 */
1418      (lcid))
1419 {
1420   CHECK_INT (lcid);
1421
1422   if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED))
1423     return Qnil;
1424
1425   if (!SetThreadLocale (XINT (lcid)))
1426     return Qnil;
1427
1428 /* Sync with FSF Emacs 19.34.6 note: dwWinThreadId declared in
1429    w32term.h and defined in w32fns.c, both of which are not in current
1430    XEmacs.  ### Check what we lose by ifdef'ing out these. --marcpa */
1431 #if 0
1432   /* Need to set input thread locale if present.  */
1433   if (dwWinThreadId)
1434     /* Reply is not needed.  */
1435     PostThreadMessage (dwWinThreadId, WM_EMACS_SETLOCALE, XINT (lcid), 0);
1436 #endif
1437
1438   return make_int (GetThreadLocale ());
1439 }
1440
1441 \f
1442 void
1443 syms_of_ntproc ()
1444 {
1445   Qhigh = intern ("high");
1446   Qlow = intern ("low");
1447
1448   DEFSUBR (Fwin32_short_file_name);
1449   DEFSUBR (Fwin32_long_file_name);
1450   DEFSUBR (Fwin32_set_process_priority);
1451   DEFSUBR (Fwin32_get_locale_info);
1452   DEFSUBR (Fwin32_get_current_locale_id);
1453   DEFSUBR (Fwin32_get_default_locale_id);
1454   DEFSUBR (Fwin32_get_valid_locale_ids);
1455   DEFSUBR (Fwin32_set_current_locale);
1456
1457   DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args /*
1458     Non-nil enables quoting of process arguments to ensure correct parsing.
1459 Because Windows does not directly pass argv arrays to child processes,
1460 programs have to reconstruct the argv array by parsing the command
1461 line string.  For an argument to contain a space, it must be enclosed
1462 in double quotes or it will be parsed as multiple arguments.
1463
1464 If the value is a character, that character will be used to escape any
1465 quote characters that appear, otherwise a suitable escape character
1466 will be chosen based on the type of the program.
1467 */ );
1468   Vwin32_quote_process_args = Qt;
1469
1470   DEFVAR_LISP ("win32-start-process-show-window",
1471                &Vwin32_start_process_show_window /*
1472     When nil, processes started via start-process hide their windows.
1473 When non-nil, they show their window in the method of their choice.
1474 */ );
1475   Vwin32_start_process_show_window = Qnil;
1476
1477   DEFVAR_LISP ("win32-start-process-share-console",
1478                &Vwin32_start_process_share_console /*
1479     When nil, processes started via start-process are given a new console.
1480 When non-nil, they share the Emacs console; this has the limitation of
1481 allowing only only DOS subprocess to run at a time (whether started directly
1482 or indirectly by Emacs), and preventing Emacs from cleanly terminating the
1483 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't
1484 otherwise respond to interrupts from Emacs.
1485 */ );
1486   Vwin32_start_process_share_console = Qnil;
1487
1488   DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /*
1489     Forced delay before reading subprocess output.
1490 This is done to improve the buffering of subprocess output, by
1491 avoiding the inefficiency of frequently reading small amounts of data.
1492
1493 If positive, the value is the number of milliseconds to sleep before
1494 reading the subprocess output.  If negative, the magnitude is the number
1495 of time slices to wait (effectively boosting the priority of the child
1496 process temporarily).  A value of zero disables waiting entirely.
1497 */ );
1498   Vwin32_pipe_read_delay = make_int (50);
1499
1500 #if 0
1501   DEFVAR_LISP ("win32-generate-fake-inodes", &Vwin32_generate_fake_inodes /*
1502     "Non-nil means attempt to fake realistic inode values.
1503 This works by hashing the truename of files, and should detect 
1504 aliasing between long and short (8.3 DOS) names, but can have
1505 false positives because of hash collisions.  Note that determining
1506 the truename of a file can be slow.
1507 */ );
1508   Vwin32_generate_fake_inodes = Qnil;
1509 #endif
1510 }
1511 /* end of ntproc.c */