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