Mercurial > hg > xemacs-beta
comparison src/ntproc.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 3a7e78e1142d |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
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 | |
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 | |
1442 void | |
1443 syms_of_ntproc () | |
1444 { | |
1445 DEFSUBR (Fwin32_short_file_name); | |
1446 DEFSUBR (Fwin32_long_file_name); | |
1447 DEFSUBR (Fwin32_set_process_priority); | |
1448 DEFSUBR (Fwin32_get_locale_info); | |
1449 DEFSUBR (Fwin32_get_current_locale_id); | |
1450 DEFSUBR (Fwin32_get_default_locale_id); | |
1451 DEFSUBR (Fwin32_get_valid_locale_ids); | |
1452 DEFSUBR (Fwin32_set_current_locale); | |
1453 } | |
1454 | |
1455 | |
1456 void | |
1457 vars_of_ntproc (void) | |
1458 { | |
1459 defsymbol (&Qhigh, "high"); | |
1460 defsymbol (&Qlow, "low"); | |
1461 | |
1462 DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args /* | |
1463 Non-nil enables quoting of process arguments to ensure correct parsing. | |
1464 Because Windows does not directly pass argv arrays to child processes, | |
1465 programs have to reconstruct the argv array by parsing the command | |
1466 line string. For an argument to contain a space, it must be enclosed | |
1467 in double quotes or it will be parsed as multiple arguments. | |
1468 | |
1469 If the value is a character, that character will be used to escape any | |
1470 quote characters that appear, otherwise a suitable escape character | |
1471 will be chosen based on the type of the program. | |
1472 */ ); | |
1473 Vwin32_quote_process_args = Qt; | |
1474 | |
1475 DEFVAR_LISP ("win32-start-process-show-window", | |
1476 &Vwin32_start_process_show_window /* | |
1477 When nil, processes started via start-process hide their windows. | |
1478 When non-nil, they show their window in the method of their choice. | |
1479 */ ); | |
1480 Vwin32_start_process_show_window = Qnil; | |
1481 | |
1482 DEFVAR_LISP ("win32-start-process-share-console", | |
1483 &Vwin32_start_process_share_console /* | |
1484 When nil, processes started via start-process are given a new console. | |
1485 When non-nil, they share the Emacs console; this has the limitation of | |
1486 allowing only only DOS subprocess to run at a time (whether started directly | |
1487 or indirectly by Emacs), and preventing Emacs from cleanly terminating the | |
1488 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't | |
1489 otherwise respond to interrupts from Emacs. | |
1490 */ ); | |
1491 Vwin32_start_process_share_console = Qt; | |
1492 | |
1493 DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /* | |
1494 Forced delay before reading subprocess output. | |
1495 This is done to improve the buffering of subprocess output, by | |
1496 avoiding the inefficiency of frequently reading small amounts of data. | |
1497 | |
1498 If positive, the value is the number of milliseconds to sleep before | |
1499 reading the subprocess output. If negative, the magnitude is the number | |
1500 of time slices to wait (effectively boosting the priority of the child | |
1501 process temporarily). A value of zero disables waiting entirely. | |
1502 */ ); | |
1503 Vwin32_pipe_read_delay = make_int (50); | |
1504 | |
1505 #if 0 | |
1506 DEFVAR_LISP ("win32-generate-fake-inodes", &Vwin32_generate_fake_inodes /* | |
1507 "Non-nil means attempt to fake realistic inode values. | |
1508 This works by hashing the truename of files, and should detect | |
1509 aliasing between long and short (8.3 DOS) names, but can have | |
1510 false positives because of hash collisions. Note that determining | |
1511 the truename of a file can be slow. | |
1512 */ ); | |
1513 Vwin32_generate_fake_inodes = Qnil; | |
1514 #endif | |
1515 } | |
1516 | |
1517 /* end of ntproc.c */ |