611
+ − 1 /* Old process support under MS Windows, soon to die.
428
+ − 2 Copyright (C) 1992, 1995 Free Software Foundation, Inc.
771
+ − 3 Copyright (C) 2001 Ben Wing.
428
+ − 4
+ − 5 This file is part of XEmacs.
+ − 6
+ − 7 XEmacs is free software; you can redistribute it and/or modify it
+ − 8 under the terms of the GNU General Public License as published by the
+ − 9 Free Software Foundation; either version 2, or (at your option) any
+ − 10 later version.
+ − 11
+ − 12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ − 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ − 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ − 15 for more details.
+ − 16
+ − 17 You should have received a copy of the GNU General Public License
+ − 18 along with XEmacs; see the file COPYING. If not, write to
+ − 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 20 Boston, MA 02111-1307, USA.
+ − 21
+ − 22 Drew Bliss Oct 14, 1993
+ − 23 Adapted from alarm.c by Tim Fleehart */
+ − 24
+ − 25 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
771
+ − 26 /* Synced with FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org>
+ − 27 (Note: Sync messages from Marc Paquette may indicate
+ − 28 incomplete synching, so beware.)
+ − 29 */
+ − 30
+ − 31 /* !!#### This piece of crap is not getting Mule-ized. It will go away
+ − 32 as soon as my process-stderr patches go in and there are a few stream
+ − 33 device fixes, so my new call-process-written-using-start-process can
+ − 34 always work. */
428
+ − 35
611
+ − 36 /* #### This ENTIRE file is only around because of callproc.c, which
+ − 37 in turn is only used in batch mode.
+ − 38
+ − 39 We only need two things to get rid of both this and callproc.c:
+ − 40
+ − 41 -- my `stderr-proc' ws, which adds support for a separate stderr
+ − 42 in asynch. subprocesses. (it's a feature in `old-call-process-internal'.)
+ − 43 -- a noninteractive event loop that supports processes.
+ − 44 */
771
+ − 45 #include <config.h>
+ − 46 #include "lisp.h"
611
+ − 47
771
+ − 48 #include "buffer.h"
+ − 49 #include "console-msw.h"
+ − 50 #include "process.h"
428
+ − 51
+ − 52 #ifdef HAVE_A_OUT_H
+ − 53 #include <a.out.h>
+ − 54 #endif
771
+ − 55 #include "sysfile.h"
428
+ − 56 #include "sysproc.h"
+ − 57 #include "syssignal.h"
771
+ − 58 #include "systime.h"
428
+ − 59 #include "syswait.h"
442
+ − 60
428
+ − 61
+ − 62 /* #### I'm not going to play with shit. */
771
+ − 63 // #pragma warning (disable:4013 4024 4090)
428
+ − 64
+ − 65 /* Control whether spawnve quotes arguments as necessary to ensure
+ − 66 correct parsing by child process. Because not all uses of spawnve
+ − 67 are careful about constructing argv arrays, we make this behavior
+ − 68 conditional (off by default). */
+ − 69 Lisp_Object Vwin32_quote_process_args;
+ − 70
+ − 71 /* Control whether create_child causes the process' window to be
+ − 72 hidden. The default is nil. */
+ − 73 Lisp_Object Vwin32_start_process_show_window;
+ − 74
+ − 75 /* Control whether create_child causes the process to inherit Emacs'
+ − 76 console window, or be given a new one of its own. The default is
+ − 77 nil, to allow multiple DOS programs to run on Win95. Having separate
+ − 78 consoles also allows Emacs to cleanly terminate process groups. */
+ − 79 Lisp_Object Vwin32_start_process_share_console;
+ − 80
+ − 81 /* Time to sleep before reading from a subprocess output pipe - this
+ − 82 avoids the inefficiency of frequently reading small amounts of data.
+ − 83 This is primarily necessary for handling DOS processes on Windows 95,
+ − 84 but is useful for Win32 processes on both Win95 and NT as well. */
+ − 85 Lisp_Object Vwin32_pipe_read_delay;
+ − 86
771
+ − 87 extern Lisp_Object Vlisp_EXEC_SUFFIXES;
+ − 88
+ − 89 /* child_process.status values */
+ − 90 enum {
+ − 91 STATUS_READ_ERROR = -1,
+ − 92 STATUS_READ_READY,
+ − 93 STATUS_READ_IN_PROGRESS,
+ − 94 STATUS_READ_FAILED,
+ − 95 STATUS_READ_SUCCEEDED,
+ − 96 STATUS_READ_ACKNOWLEDGED
+ − 97 };
+ − 98
+ − 99 /* This structure is used for both pipes and sockets; for
+ − 100 a socket, the process handle in pi is NULL. */
+ − 101 typedef struct _child_process
+ − 102 {
+ − 103 int fd;
+ − 104 int pid;
+ − 105 HANDLE char_avail;
+ − 106 HANDLE char_consumed;
+ − 107 HANDLE thrd;
+ − 108 HWND hwnd;
+ − 109 PROCESS_INFORMATION procinfo;
+ − 110 volatile int status;
+ − 111 char chr;
+ − 112 } child_process;
+ − 113
+ − 114 #define MAX_CHILDREN MAXDESC/2
+ − 115 #define CHILD_ACTIVE(cp) ((cp)->char_avail != NULL)
+ − 116
+ − 117 extern child_process * new_child (void);
+ − 118 extern void delete_child (child_process *cp);
428
+ − 119
771
+ − 120 /* parallel array of private info on file handles */
+ − 121 typedef struct
+ − 122 {
+ − 123 unsigned flags;
+ − 124 HANDLE hnd;
+ − 125 child_process * cp;
+ − 126 } filedesc;
+ − 127
+ − 128 extern filedesc fd_info [];
428
+ − 129
771
+ − 130 /* fd_info flag definitions */
+ − 131 #define FILE_READ 0x0001
+ − 132 #define FILE_WRITE 0x0002
+ − 133 #define FILE_BINARY 0x0010
+ − 134 #define FILE_LAST_CR 0x0020
+ − 135 #define FILE_AT_EOF 0x0040
+ − 136 #define FILE_SEND_SIGCHLD 0x0080
+ − 137 #define FILE_PIPE 0x0100
+ − 138 #define FILE_SOCKET 0x0200
+ − 139
+ − 140 /* #### This is an evil dirty hack. We must get rid of it.
+ − 141 Word "munging" is not in XEmacs lexicon. - kkm */
+ − 142
+ − 143 /* parallel array of private info on file handles */
+ − 144 filedesc fd_info [ MAXDESC ];
+ − 145
+ − 146 #ifdef DEBUG_XEMACS
+ − 147 #define DebPrint(stuff) _DebPrint stuff
+ − 148 #else
+ − 149 #define DebPrint(stuff)
+ − 150 #endif
+ − 151
+ − 152 /* ------------------------------------------------------------------------- */
428
+ − 153
+ − 154 #ifndef DEBUG_XEMACS
+ − 155 __inline
+ − 156 #endif
+ − 157 void _DebPrint (const char *fmt, ...)
+ − 158 {
+ − 159 #ifdef DEBUG_XEMACS
+ − 160 char buf[1024];
+ − 161 va_list args;
+ − 162
+ − 163 va_start (args, fmt);
+ − 164 vsprintf (buf, fmt, args);
+ − 165 va_end (args);
+ − 166 OutputDebugString (buf);
+ − 167 #endif
+ − 168 }
+ − 169
442
+ − 170 /* sys_signal moved to nt.c. It's now called mswindows_signal... */
428
+ − 171
+ − 172 /* Child process management list. */
+ − 173 int child_proc_count = 0;
+ − 174 child_process child_procs[ MAX_CHILDREN ];
+ − 175 child_process *dead_child = NULL;
+ − 176
+ − 177 DWORD WINAPI reader_thread (void *arg);
+ − 178
+ − 179 /* Find an unused process slot. */
+ − 180 child_process *
+ − 181 new_child (void)
+ − 182 {
+ − 183 child_process *cp;
+ − 184 DWORD id;
+ − 185
+ − 186 for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
+ − 187 if (!CHILD_ACTIVE (cp))
+ − 188 goto Initialize;
+ − 189 if (child_proc_count == MAX_CHILDREN)
+ − 190 return NULL;
+ − 191 cp = &child_procs[child_proc_count++];
+ − 192
+ − 193 Initialize:
+ − 194 xzero (*cp);
+ − 195 cp->fd = -1;
+ − 196 cp->pid = -1;
+ − 197 if (cp->procinfo.hProcess)
+ − 198 CloseHandle(cp->procinfo.hProcess);
+ − 199 cp->procinfo.hProcess = NULL;
+ − 200 cp->status = STATUS_READ_ERROR;
+ − 201
+ − 202 /* use manual reset event so that select() will function properly */
+ − 203 cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
+ − 204 if (cp->char_avail)
+ − 205 {
+ − 206 cp->char_consumed = CreateEvent (NULL, FALSE, FALSE, NULL);
+ − 207 if (cp->char_consumed)
+ − 208 {
+ − 209 cp->thrd = CreateThread (NULL, 1024, reader_thread, cp, 0, &id);
+ − 210 if (cp->thrd)
+ − 211 return cp;
+ − 212 }
+ − 213 }
+ − 214 delete_child (cp);
+ − 215 return NULL;
+ − 216 }
+ − 217
+ − 218 void
+ − 219 delete_child (child_process *cp)
+ − 220 {
+ − 221 int i;
+ − 222
+ − 223 /* Should not be deleting a child that is still needed. */
+ − 224 for (i = 0; i < MAXDESC; i++)
+ − 225 if (fd_info[i].cp == cp)
+ − 226 abort ();
+ − 227
+ − 228 if (!CHILD_ACTIVE (cp))
+ − 229 return;
+ − 230
+ − 231 /* reap thread if necessary */
+ − 232 if (cp->thrd)
+ − 233 {
+ − 234 DWORD rc;
+ − 235
+ − 236 if (GetExitCodeThread (cp->thrd, &rc) && rc == STILL_ACTIVE)
+ − 237 {
+ − 238 /* let the thread exit cleanly if possible */
+ − 239 cp->status = STATUS_READ_ERROR;
+ − 240 SetEvent (cp->char_consumed);
+ − 241 if (WaitForSingleObject (cp->thrd, 1000) != WAIT_OBJECT_0)
+ − 242 {
+ − 243 DebPrint (("delete_child.WaitForSingleObject (thread) failed "
+ − 244 "with %lu for fd %ld\n", GetLastError (), cp->fd));
+ − 245 TerminateThread (cp->thrd, 0);
+ − 246 }
+ − 247 }
+ − 248 CloseHandle (cp->thrd);
+ − 249 cp->thrd = NULL;
+ − 250 }
+ − 251 if (cp->char_avail)
+ − 252 {
+ − 253 CloseHandle (cp->char_avail);
+ − 254 cp->char_avail = NULL;
+ − 255 }
+ − 256 if (cp->char_consumed)
+ − 257 {
+ − 258 CloseHandle (cp->char_consumed);
+ − 259 cp->char_consumed = NULL;
+ − 260 }
+ − 261
+ − 262 /* update child_proc_count (highest numbered slot in use plus one) */
+ − 263 if (cp == child_procs + child_proc_count - 1)
+ − 264 {
+ − 265 for (i = child_proc_count-1; i >= 0; i--)
+ − 266 if (CHILD_ACTIVE (&child_procs[i]))
+ − 267 {
+ − 268 child_proc_count = i + 1;
+ − 269 break;
+ − 270 }
+ − 271 }
+ − 272 if (i < 0)
+ − 273 child_proc_count = 0;
+ − 274 }
+ − 275
+ − 276 /* Find a child by pid. */
+ − 277 static child_process *
+ − 278 find_child_pid (DWORD pid)
+ − 279 {
+ − 280 child_process *cp;
+ − 281
+ − 282 for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
647
+ − 283 if (CHILD_ACTIVE (cp) && pid == (DWORD) cp->pid)
428
+ − 284 return cp;
+ − 285 return NULL;
+ − 286 }
+ − 287
+ − 288 /* Function to do blocking read of one byte, needed to implement
+ − 289 select. It is only allowed on sockets and pipes. */
+ − 290 static int
+ − 291 _sys_read_ahead (int fd)
+ − 292 {
+ − 293 child_process * cp;
+ − 294 int rc = 0;
+ − 295
+ − 296 if (fd < 0 || fd >= MAXDESC)
+ − 297 return STATUS_READ_ERROR;
+ − 298
+ − 299 cp = fd_info[fd].cp;
+ − 300
+ − 301 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
+ − 302 return STATUS_READ_ERROR;
+ − 303
+ − 304 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
+ − 305 || (fd_info[fd].flags & FILE_READ) == 0)
+ − 306 {
+ − 307 /* fd is not a pipe or socket */
+ − 308 abort ();
+ − 309 }
+ − 310
+ − 311 cp->status = STATUS_READ_IN_PROGRESS;
+ − 312
+ − 313 if (fd_info[fd].flags & FILE_PIPE)
+ − 314 {
+ − 315 rc = _read (fd, &cp->chr, sizeof (char));
+ − 316
+ − 317 /* Give subprocess time to buffer some more output for us before
+ − 318 reporting that input is available; we need this because Win95
+ − 319 connects DOS programs to pipes by making the pipe appear to be
+ − 320 the normal console stdout - as a result most DOS programs will
+ − 321 write to stdout without buffering, ie. one character at a
+ − 322 time. Even some Win32 programs do this - "dir" in a command
+ − 323 shell on NT is very slow if we don't do this. */
+ − 324 if (rc > 0)
+ − 325 {
+ − 326 int wait = XINT (Vwin32_pipe_read_delay);
+ − 327
+ − 328 if (wait > 0)
+ − 329 Sleep (wait);
+ − 330 else if (wait < 0)
+ − 331 while (++wait <= 0)
+ − 332 /* Yield remainder of our time slice, effectively giving a
+ − 333 temporary priority boost to the child process. */
+ − 334 Sleep (0);
+ − 335 }
+ − 336 }
+ − 337
+ − 338 if (rc == sizeof (char))
+ − 339 cp->status = STATUS_READ_SUCCEEDED;
+ − 340 else
+ − 341 cp->status = STATUS_READ_FAILED;
+ − 342
+ − 343 return cp->status;
+ − 344 }
+ − 345
+ − 346 /* Thread proc for child process and socket reader threads. Each thread
+ − 347 is normally blocked until woken by select() to check for input by
+ − 348 reading one char. When the read completes, char_avail is signalled
+ − 349 to wake up the select emulator and the thread blocks itself again. */
+ − 350 DWORD WINAPI
+ − 351 reader_thread (void *arg)
+ − 352 {
+ − 353 child_process *cp;
+ − 354
+ − 355 /* Our identity */
+ − 356 cp = (child_process *)arg;
+ − 357
+ − 358 /* <matts@tibco.com> - I think the test below is wrong - we don't
+ − 359 want to wait for someone to signal char_consumed, as we haven't
+ − 360 read anything for them to consume yet! */
+ − 361
+ − 362 /*
+ − 363 if (cp == NULL ||
+ − 364 WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
+ − 365 */
+ − 366
+ − 367 if (cp == NULL)
+ − 368 {
+ − 369 return 1;
+ − 370 }
+ − 371
+ − 372 for (;;)
+ − 373 {
+ − 374 int rc;
+ − 375
+ − 376 rc = _sys_read_ahead (cp->fd);
+ − 377
+ − 378 /* The name char_avail is a misnomer - it really just means the
+ − 379 read-ahead has completed, whether successfully or not. */
+ − 380 if (!SetEvent (cp->char_avail))
+ − 381 {
+ − 382 DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n",
+ − 383 GetLastError (), cp->fd));
+ − 384 return 1;
+ − 385 }
+ − 386
+ − 387 if (rc == STATUS_READ_ERROR)
+ − 388 {
+ − 389 /* We are finished, so clean up handles and set to NULL so
+ − 390 that CHILD_ACTIVE will see what is going on */
+ − 391 if (cp->char_avail) {
+ − 392 CloseHandle (cp->char_avail);
+ − 393 cp->char_avail = NULL;
+ − 394 }
+ − 395 if (cp->thrd) {
+ − 396 CloseHandle (cp->thrd);
+ − 397 cp->thrd = NULL;
+ − 398 }
+ − 399 if (cp->char_consumed) {
+ − 400 CloseHandle(cp->char_consumed);
+ − 401 cp->char_consumed = NULL;
+ − 402 }
+ − 403 if (cp->procinfo.hProcess)
+ − 404 {
+ − 405 CloseHandle (cp->procinfo.hProcess);
+ − 406 cp->procinfo.hProcess=NULL;
+ − 407 }
+ − 408 return 1;
+ − 409 }
+ − 410
+ − 411 /* If the read died, the child has died so let the thread die */
+ − 412 if (rc == STATUS_READ_FAILED)
+ − 413 break;
+ − 414
+ − 415 /* Wait until our input is acknowledged before reading again */
+ − 416 if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
+ − 417 {
+ − 418 DebPrint (("reader_thread.WaitForSingleObject failed with "
+ − 419 "%lu for fd %ld\n", GetLastError (), cp->fd));
+ − 420 break;
+ − 421 }
+ − 422 }
+ − 423 /* We are finished, so clean up handles and set to NULL so that
+ − 424 CHILD_ACTIVE will see what is going on */
+ − 425 if (cp->char_avail) {
+ − 426 CloseHandle (cp->char_avail);
+ − 427 cp->char_avail = NULL;
+ − 428 }
+ − 429 if (cp->thrd) {
+ − 430 CloseHandle (cp->thrd);
+ − 431 cp->thrd = NULL;
+ − 432 }
+ − 433 if (cp->char_consumed) {
+ − 434 CloseHandle(cp->char_consumed);
+ − 435 cp->char_consumed = NULL;
+ − 436 }
+ − 437 if (cp->procinfo.hProcess)
+ − 438 {
+ − 439 CloseHandle (cp->procinfo.hProcess);
+ − 440 cp->procinfo.hProcess=NULL;
+ − 441 }
+ − 442
+ − 443 return 0;
+ − 444 }
+ − 445
771
+ − 446 /* This must die. */
+ − 447 static void
+ − 448 unixtodos_filename (char *p)
+ − 449 {
+ − 450 while (*p)
+ − 451 {
+ − 452 if (*p == '/')
+ − 453 *p = '\\';
+ − 454 p++;
+ − 455 }
+ − 456 }
+ − 457
428
+ − 458 /* To avoid Emacs changing directory, we just record here the directory
+ − 459 the new process should start in. This is set just before calling
+ − 460 sys_spawnve, and is not generally valid at any other time. */
+ − 461 static const char * process_dir;
+ − 462
+ − 463 static BOOL
442
+ − 464 create_child (const char *exe, char *cmdline, char *env,
428
+ − 465 int * pPid, child_process *cp)
+ − 466 {
+ − 467 STARTUPINFO start;
+ − 468 SECURITY_ATTRIBUTES sec_attrs;
+ − 469 SECURITY_DESCRIPTOR sec_desc;
771
+ − 470 char dir[ PATH_MAX ];
428
+ − 471
+ − 472 if (cp == NULL) abort ();
+ − 473
+ − 474 xzero (start);
+ − 475 start.cb = sizeof (start);
+ − 476
+ − 477 if (NILP (Vwin32_start_process_show_window))
+ − 478 start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ − 479 else
+ − 480 start.dwFlags = STARTF_USESTDHANDLES;
+ − 481 start.wShowWindow = SW_HIDE;
+ − 482
+ − 483 start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ − 484 start.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ − 485 start.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+ − 486
+ − 487 /* Explicitly specify no security */
442
+ − 488 /* #### not supported under win98, but will go away */
428
+ − 489 if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
+ − 490 goto EH_Fail;
442
+ − 491 /* #### not supported under win98, but will go away */
428
+ − 492 if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE))
+ − 493 goto EH_Fail;
+ − 494 sec_attrs.nLength = sizeof (sec_attrs);
+ − 495 sec_attrs.lpSecurityDescriptor = &sec_desc;
+ − 496 sec_attrs.bInheritHandle = FALSE;
+ − 497
+ − 498 strcpy (dir, process_dir);
+ − 499 unixtodos_filename (dir);
+ − 500
+ − 501 if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
+ − 502 (!NILP (Vwin32_start_process_share_console)
+ − 503 ? CREATE_NEW_PROCESS_GROUP
+ − 504 : CREATE_NEW_CONSOLE),
+ − 505 env, dir,
+ − 506 &start, &cp->procinfo))
+ − 507 goto EH_Fail;
+ − 508
+ − 509 cp->pid = (int) cp->procinfo.dwProcessId;
+ − 510
+ − 511 CloseHandle (cp->procinfo.hThread);
+ − 512 CloseHandle (cp->procinfo.hProcess);
+ − 513 cp->procinfo.hThread=NULL;
+ − 514 cp->procinfo.hProcess=NULL;
+ − 515
432
+ − 516 /* pid must fit in a Lisp_Int */
428
+ − 517
+ − 518
+ − 519 *pPid = cp->pid;
+ − 520
+ − 521 return TRUE;
+ − 522
+ − 523 EH_Fail:
+ − 524 DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError()););
+ − 525 return FALSE;
+ − 526 }
+ − 527
+ − 528 void
+ − 529 merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
+ − 530 {
+ − 531 char **optr, **nptr;
+ − 532 int num;
+ − 533
+ − 534 nptr = new_envp;
+ − 535 optr = envp1;
+ − 536 while (*optr)
+ − 537 *nptr++ = *optr++;
+ − 538 num = optr - envp1;
+ − 539
+ − 540 optr = envp2;
+ − 541 while (*optr)
+ − 542 *nptr++ = *optr++;
+ − 543 num += optr - envp2;
+ − 544
771
+ − 545 qsort (new_envp, num, sizeof (char*), mswindows_compare_env);
428
+ − 546
+ − 547 *nptr = NULL;
+ − 548 }
+ − 549
+ − 550 /* When a new child process is created we need to register it in our list,
+ − 551 so intercept spawn requests. */
+ − 552 int
771
+ − 553 spawnve_will_die_soon (int mode, const Intbyte *cmdname,
+ − 554 const Intbyte * const *argv, const Intbyte *const *envp)
428
+ − 555 {
+ − 556 Lisp_Object program, full;
+ − 557 char *cmdline, *env, *parg, **targ;
+ − 558 int arglen, numenv;
+ − 559 int pid;
+ − 560 child_process *cp;
+ − 561 int is_dos_app, is_cygnus_app;
+ − 562 int do_quoting = 0;
+ − 563 char escape_char = 0;
+ − 564 /* We pass our process ID to our children by setting up an environment
+ − 565 variable in their environment. */
+ − 566 char ppid_env_var_buffer[64];
+ − 567 char *extra_env[] = {ppid_env_var_buffer, NULL};
+ − 568 struct gcpro gcpro1;
+ − 569
+ − 570 /* We don't care about the other modes */
+ − 571 if (mode != _P_NOWAIT)
+ − 572 {
+ − 573 errno = EINVAL;
+ − 574 return -1;
+ − 575 }
+ − 576
+ − 577 /* Handle executable names without an executable suffix. */
442
+ − 578 program = build_string (cmdname);
428
+ − 579 GCPRO1 (program);
+ − 580 if (NILP (Ffile_executable_p (program)))
+ − 581 {
+ − 582 full = Qnil;
+ − 583 locate_file (Vexec_path, program, Vlisp_EXEC_SUFFIXES, &full, 1);
+ − 584 if (NILP (full))
+ − 585 {
+ − 586 UNGCPRO;
+ − 587 errno = EINVAL;
+ − 588 return -1;
+ − 589 }
440
+ − 590 TO_EXTERNAL_FORMAT (LISP_STRING, full,
+ − 591 C_STRING_ALLOCA, cmdname,
+ − 592 Qfile_name);
428
+ − 593 }
+ − 594 else
+ − 595 {
442
+ − 596 cmdname = (char*)alloca (strlen (argv[0]) + 1);
428
+ − 597 strcpy ((char*)cmdname, argv[0]);
+ − 598 }
+ − 599 UNGCPRO;
+ − 600
+ − 601 /* make sure argv[0] and cmdname are both in DOS format */
+ − 602 unixtodos_filename ((char*)cmdname);
+ − 603 /* #### KLUDGE */
442
+ − 604 ((const char**)argv)[0] = cmdname;
428
+ − 605
+ − 606 /* Determine whether program is a 16-bit DOS executable, or a Win32
+ − 607 executable that is implicitly linked to the Cygnus dll (implying it
+ − 608 was compiled with the Cygnus GNU toolchain and hence relies on
+ − 609 cygwin.dll to parse the command line - we use this to decide how to
+ − 610 escape quote chars in command line args that must be quoted). */
442
+ − 611 mswindows_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
428
+ − 612
+ − 613 /* On Windows 95, if cmdname is a DOS app, we invoke a helper
+ − 614 application to start it by specifying the helper app as cmdname,
+ − 615 while leaving the real app name as argv[0]. */
+ − 616 if (is_dos_app)
+ − 617 {
771
+ − 618 cmdname = (char*) alloca (PATH_MAX);
428
+ − 619 if (egetenv ("CMDPROXY"))
+ − 620 strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
+ − 621 else
+ − 622 {
+ − 623 strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory));
+ − 624 strcat ((char*)cmdname, "cmdproxy.exe");
+ − 625 }
+ − 626 unixtodos_filename ((char*)cmdname);
+ − 627 }
+ − 628
+ − 629 /* we have to do some conjuring here to put argv and envp into the
+ − 630 form CreateProcess wants... argv needs to be a space separated/null
+ − 631 terminated list of parameters, and envp is a null
+ − 632 separated/double-null terminated list of parameters.
+ − 633
+ − 634 Additionally, zero-length args and args containing whitespace or
+ − 635 quote chars need to be wrapped in double quotes - for this to work,
+ − 636 embedded quotes need to be escaped as well. The aim is to ensure
+ − 637 the child process reconstructs the argv array we start with
+ − 638 exactly, so we treat quotes at the beginning and end of arguments
+ − 639 as embedded quotes.
+ − 640
+ − 641 The Win32 GNU-based library from Cygnus doubles quotes to escape
+ − 642 them, while MSVC uses backslash for escaping. (Actually the MSVC
+ − 643 startup code does attempt to recognize doubled quotes and accept
+ − 644 them, but gets it wrong and ends up requiring three quotes to get a
+ − 645 single embedded quote!) So by default we decide whether to use
+ − 646 quote or backslash as the escape character based on whether the
+ − 647 binary is apparently a Cygnus compiled app.
+ − 648
+ − 649 Note that using backslash to escape embedded quotes requires
+ − 650 additional special handling if an embedded quote is already
+ − 651 preceded by backslash, or if an arg requiring quoting ends with
+ − 652 backslash. In such cases, the run of escape characters needs to be
+ − 653 doubled. For consistency, we apply this special handling as long
+ − 654 as the escape character is not quote.
+ − 655
+ − 656 Since we have no idea how large argv and envp are likely to be we
+ − 657 figure out list lengths on the fly and allocate them. */
+ − 658
+ − 659 if (!NILP (Vwin32_quote_process_args))
+ − 660 {
+ − 661 do_quoting = 1;
+ − 662 /* Override escape char by binding win32-quote-process-args to
+ − 663 desired character, or use t for auto-selection. */
+ − 664 if (INTP (Vwin32_quote_process_args))
442
+ − 665 escape_char = (char) XINT (Vwin32_quote_process_args);
428
+ − 666 else
+ − 667 escape_char = is_cygnus_app ? '"' : '\\';
+ − 668 }
+ − 669
+ − 670 /* do argv... */
+ − 671 arglen = 0;
+ − 672 targ = (char**)argv;
+ − 673 while (*targ)
+ − 674 {
+ − 675 char * p = *targ;
+ − 676 int need_quotes = 0;
+ − 677 int escape_char_run = 0;
+ − 678
+ − 679 if (*p == 0)
+ − 680 need_quotes = 1;
+ − 681 for ( ; *p; p++)
+ − 682 {
+ − 683 if (*p == '"')
+ − 684 {
+ − 685 /* allow for embedded quotes to be escaped */
+ − 686 arglen++;
+ − 687 need_quotes = 1;
+ − 688 /* handle the case where the embedded quote is already escaped */
+ − 689 if (escape_char_run > 0)
+ − 690 {
+ − 691 /* To preserve the arg exactly, we need to double the
+ − 692 preceding escape characters (plus adding one to
+ − 693 escape the quote character itself). */
+ − 694 arglen += escape_char_run;
+ − 695 }
+ − 696 }
+ − 697 else if (*p == ' ' || *p == '\t')
+ − 698 {
+ − 699 need_quotes = 1;
+ − 700 }
+ − 701
+ − 702 if (*p == escape_char && escape_char != '"')
+ − 703 escape_char_run++;
+ − 704 else
+ − 705 escape_char_run = 0;
+ − 706 }
+ − 707 if (need_quotes)
+ − 708 {
+ − 709 arglen += 2;
+ − 710 /* handle the case where the arg ends with an escape char - we
+ − 711 must not let the enclosing quote be escaped. */
+ − 712 if (escape_char_run > 0)
+ − 713 arglen += escape_char_run;
+ − 714 }
+ − 715 arglen += strlen (*targ++) + 1;
+ − 716 }
442
+ − 717 cmdline = (char*) alloca (arglen);
428
+ − 718 targ = (char**)argv;
+ − 719 parg = cmdline;
+ − 720 while (*targ)
+ − 721 {
+ − 722 char * p = *targ;
+ − 723 int need_quotes = 0;
+ − 724
+ − 725 if (*p == 0)
+ − 726 need_quotes = 1;
+ − 727
+ − 728 if (do_quoting)
+ − 729 {
+ − 730 for ( ; *p; p++)
+ − 731 if (*p == ' ' || *p == '\t' || *p == '"')
+ − 732 need_quotes = 1;
+ − 733 }
+ − 734 if (need_quotes)
+ − 735 {
+ − 736 int escape_char_run = 0;
+ − 737 char * first;
+ − 738 char * last;
+ − 739
+ − 740 p = *targ;
+ − 741 first = p;
+ − 742 last = p + strlen (p) - 1;
+ − 743 *parg++ = '"';
+ − 744 #if 0
+ − 745 /* This version does not escape quotes if they occur at the
+ − 746 beginning or end of the arg - this could lead to incorrect
+ − 747 behavior when the arg itself represents a command line
+ − 748 containing quoted args. I believe this was originally done
+ − 749 as a hack to make some things work, before
+ − 750 `win32-quote-process-args' was added. */
+ − 751 while (*p)
+ − 752 {
+ − 753 if (*p == '"' && p > first && p < last)
+ − 754 *parg++ = escape_char; /* escape embedded quotes */
+ − 755 *parg++ = *p++;
+ − 756 }
+ − 757 #else
+ − 758 for ( ; *p; p++)
+ − 759 {
+ − 760 if (*p == '"')
+ − 761 {
+ − 762 /* double preceding escape chars if any */
+ − 763 while (escape_char_run > 0)
+ − 764 {
+ − 765 *parg++ = escape_char;
+ − 766 escape_char_run--;
+ − 767 }
+ − 768 /* escape all quote chars, even at beginning or end */
+ − 769 *parg++ = escape_char;
+ − 770 }
+ − 771 *parg++ = *p;
+ − 772
+ − 773 if (*p == escape_char && escape_char != '"')
+ − 774 escape_char_run++;
+ − 775 else
+ − 776 escape_char_run = 0;
+ − 777 }
+ − 778 /* double escape chars before enclosing quote */
+ − 779 while (escape_char_run > 0)
+ − 780 {
+ − 781 *parg++ = escape_char;
+ − 782 escape_char_run--;
+ − 783 }
+ − 784 #endif
+ − 785 *parg++ = '"';
+ − 786 }
+ − 787 else
+ − 788 {
+ − 789 strcpy (parg, *targ);
+ − 790 parg += strlen (*targ);
+ − 791 }
+ − 792 *parg++ = ' ';
+ − 793 targ++;
+ − 794 }
+ − 795 *--parg = '\0';
+ − 796
+ − 797 /* and envp... */
+ − 798 arglen = 1;
442
+ − 799 targ = (char**) envp;
428
+ − 800 numenv = 1; /* for end null */
+ − 801 while (*targ)
+ − 802 {
+ − 803 arglen += strlen (*targ++) + 1;
+ − 804 numenv++;
+ − 805 }
+ − 806 /* extra env vars... */
+ − 807 sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d",
+ − 808 GetCurrentProcessId ());
+ − 809 arglen += strlen (ppid_env_var_buffer) + 1;
+ − 810 numenv++;
+ − 811
+ − 812 /* merge env passed in and extra env into one, and sort it. */
442
+ − 813 targ = (char **) alloca (numenv * sizeof (char*));
+ − 814 merge_and_sort_env ((char**) envp, extra_env, targ);
428
+ − 815
+ − 816 /* concatenate env entries. */
442
+ − 817 env = (char*) alloca (arglen);
428
+ − 818 parg = env;
+ − 819 while (*targ)
+ − 820 {
+ − 821 strcpy (parg, *targ);
+ − 822 parg += strlen (*targ++);
+ − 823 *parg++ = '\0';
+ − 824 }
+ − 825 *parg++ = '\0';
+ − 826 *parg = '\0';
+ − 827
+ − 828 cp = new_child ();
+ − 829 if (cp == NULL)
+ − 830 {
+ − 831 errno = EAGAIN;
+ − 832 return -1;
+ − 833 }
+ − 834
+ − 835 /* Now create the process. */
+ − 836 if (!create_child (cmdname, cmdline, env, &pid, cp))
+ − 837 {
+ − 838 delete_child (cp);
+ − 839 errno = ENOEXEC;
+ − 840 return -1;
+ − 841 }
+ − 842
+ − 843 return pid;
+ − 844 }
+ − 845
+ − 846 /* Substitute for certain kill () operations */
+ − 847
+ − 848 static BOOL CALLBACK
+ − 849 find_child_console (HWND hwnd, child_process * cp)
+ − 850 {
+ − 851 DWORD thread_id;
+ − 852 DWORD process_id;
+ − 853
+ − 854 thread_id = GetWindowThreadProcessId (hwnd, &process_id);
+ − 855 if (process_id == cp->procinfo.dwProcessId)
+ − 856 {
+ − 857 char window_class[32];
+ − 858
+ − 859 GetClassName (hwnd, window_class, sizeof (window_class));
+ − 860 if (strcmp (window_class,
771
+ − 861 mswindows_windows9x_p
428
+ − 862 ? "tty"
+ − 863 : "ConsoleWindowClass") == 0)
+ − 864 {
+ − 865 cp->hwnd = hwnd;
+ − 866 return FALSE;
+ − 867 }
+ − 868 }
+ − 869 /* keep looking */
+ − 870 return TRUE;
+ − 871 }
+ − 872
+ − 873 int
771
+ − 874 kill_will_disappear_soon (int pid, int sig)
428
+ − 875 {
+ − 876 child_process *cp;
+ − 877 HANDLE proc_hand;
+ − 878 int need_to_free = 0;
+ − 879 int rc = 0;
+ − 880
+ − 881 /* Only handle signals that will result in the process dying */
+ − 882 if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
+ − 883 {
+ − 884 errno = EINVAL;
+ − 885 return -1;
+ − 886 }
+ − 887
+ − 888 cp = find_child_pid (pid);
+ − 889 if (cp == NULL)
+ − 890 {
+ − 891 proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid);
+ − 892 if (proc_hand == NULL)
+ − 893 {
+ − 894 errno = EPERM;
+ − 895 return -1;
+ − 896 }
+ − 897 need_to_free = 1;
+ − 898 }
+ − 899 else
+ − 900 {
+ − 901 proc_hand = cp->procinfo.hProcess;
+ − 902 pid = cp->procinfo.dwProcessId;
+ − 903
+ − 904 /* Try to locate console window for process. */
+ − 905 EnumWindows ((WNDENUMPROC)find_child_console, (LPARAM) cp);
+ − 906 }
+ − 907
+ − 908 if (sig == SIGINT)
+ − 909 {
+ − 910 if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
+ − 911 {
+ − 912 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
+ − 913 BYTE vk_break_code = VK_CANCEL;
+ − 914 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ − 915 HWND foreground_window;
+ − 916
+ − 917 if (break_scan_code == 0)
+ − 918 {
+ − 919 /* Fake Ctrl-C if we can't manage Ctrl-Break. */
+ − 920 vk_break_code = 'C';
+ − 921 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ − 922 }
+ − 923
+ − 924 foreground_window = GetForegroundWindow ();
+ − 925 if (foreground_window && SetForegroundWindow (cp->hwnd))
+ − 926 {
+ − 927 /* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C. */
+ − 928 keybd_event (VK_CONTROL, control_scan_code, 0, 0);
+ − 929 keybd_event (vk_break_code, break_scan_code, 0, 0);
+ − 930 keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
+ − 931 keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
+ − 932
+ − 933 /* Sleep for a bit to give time for Emacs frame to respond
+ − 934 to focus change events (if Emacs was active app). */
+ − 935 Sleep (10);
+ − 936
+ − 937 SetForegroundWindow (foreground_window);
+ − 938 }
+ − 939 }
+ − 940 /* Ctrl-Break is NT equivalent of SIGINT. */
+ − 941 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
+ − 942 {
+ − 943 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d "
+ − 944 "for pid %lu\n", GetLastError (), pid));
+ − 945 errno = EINVAL;
+ − 946 rc = -1;
+ − 947 }
+ − 948 }
+ − 949 else
+ − 950 {
+ − 951 if (NILP (Vwin32_start_process_share_console) && cp && cp->hwnd)
+ − 952 {
+ − 953 #if 1
771
+ − 954 if (mswindows_windows9x_p)
428
+ − 955 {
+ − 956 /*
+ − 957 Another possibility is to try terminating the VDM out-right by
+ − 958 calling the Shell VxD (id 0x17) V86 interface, function #4
+ − 959 "SHELL_Destroy_VM", ie.
+ − 960
+ − 961 mov edx,4
+ − 962 mov ebx,vm_handle
+ − 963 call shellapi
+ − 964
+ − 965 First need to determine the current VM handle, and then arrange for
+ − 966 the shellapi call to be made from the system vm (by using
+ − 967 Switch_VM_and_callback).
+ − 968
+ − 969 Could try to invoke DestroyVM through CallVxD.
+ − 970
+ − 971 */
+ − 972 #if 0
+ − 973 /* On Win95, posting WM_QUIT causes the 16-bit subsystem
+ − 974 to hang when cmdproxy is used in conjunction with
+ − 975 command.com for an interactive shell. Posting
+ − 976 WM_CLOSE pops up a dialog that, when Yes is selected,
+ − 977 does the same thing. TerminateProcess is also less
+ − 978 than ideal in that subprocesses tend to stick around
+ − 979 until the machine is shutdown, but at least it
+ − 980 doesn't freeze the 16-bit subsystem. */
+ − 981 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
+ − 982 #endif
+ − 983 if (!TerminateProcess (proc_hand, 0xff))
+ − 984 {
+ − 985 DebPrint (("sys_kill.TerminateProcess returned %d "
+ − 986 "for pid %lu\n", GetLastError (), pid));
+ − 987 errno = EINVAL;
+ − 988 rc = -1;
+ − 989 }
+ − 990 }
+ − 991 else
+ − 992 #endif
+ − 993 PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
+ − 994 }
+ − 995 /* Kill the process. On Win32 this doesn't kill child processes
+ − 996 so it doesn't work very well for shells which is why it's not
+ − 997 used in every case. */
+ − 998 else if (!TerminateProcess (proc_hand, 0xff))
+ − 999 {
+ − 1000 DebPrint (("sys_kill.TerminateProcess returned %d "
+ − 1001 "for pid %lu\n", GetLastError (), pid));
+ − 1002 errno = EINVAL;
+ − 1003 rc = -1;
+ − 1004 }
+ − 1005 }
+ − 1006
+ − 1007 if (need_to_free)
+ − 1008 CloseHandle (proc_hand);
+ − 1009
+ − 1010 return rc;
+ − 1011 }
+ − 1012
771
+ − 1013 /* From callproc.c */
+ − 1014 extern Lisp_Object Vbinary_process_input;
+ − 1015 extern Lisp_Object Vbinary_process_output;
+ − 1016
+ − 1017 /* Unix pipe() has only one arg */
+ − 1018 /* Will die as soon as callproc.c dies */
+ − 1019 int
+ − 1020 pipe_will_die_soon (int *phandles)
+ − 1021 {
+ − 1022 int rc;
+ − 1023 unsigned flags;
+ − 1024
+ − 1025 /* make pipe handles non-inheritable; when we spawn a child, we
+ − 1026 replace the relevant handle with an inheritable one. Also put
+ − 1027 pipes into binary mode; we will do text mode translation ourselves
+ − 1028 if required. */
+ − 1029 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
+ − 1030
+ − 1031 if (rc == 0)
+ − 1032 {
+ − 1033 flags = FILE_PIPE | FILE_READ;
+ − 1034 if (!NILP (Vbinary_process_output))
+ − 1035 flags |= FILE_BINARY;
+ − 1036 fd_info[phandles[0]].flags = flags;
+ − 1037
+ − 1038 flags = FILE_PIPE | FILE_WRITE;
+ − 1039 if (!NILP (Vbinary_process_input))
+ − 1040 flags |= FILE_BINARY;
+ − 1041 fd_info[phandles[1]].flags = flags;
+ − 1042 }
+ − 1043
+ − 1044 return rc;
+ − 1045 }
+ − 1046
428
+ − 1047 /* The following two routines are used to manipulate stdin, stdout, and
+ − 1048 stderr of our child processes.
+ − 1049
+ − 1050 Assuming that in, out, and err are *not* inheritable, we make them
+ − 1051 stdin, stdout, and stderr of the child as follows:
+ − 1052
+ − 1053 - Save the parent's current standard handles.
+ − 1054 - Set the std handles to inheritable duplicates of the ones being passed in.
+ − 1055 (Note that _get_osfhandle() is an io.h procedure that retrieves the
+ − 1056 NT file handle for a crt file descriptor.)
+ − 1057 - Spawn the child, which inherits in, out, and err as stdin,
+ − 1058 stdout, and stderr. (see Spawnve)
+ − 1059 - Close the std handles passed to the child.
+ − 1060 - Reset the parent's standard handles to the saved handles.
+ − 1061 (see reset_standard_handles)
+ − 1062 We assume that the caller closes in, out, and err after calling us. */
+ − 1063
+ − 1064 void
+ − 1065 prepare_standard_handles (int in, int out, int err, HANDLE handles[3])
+ − 1066 {
+ − 1067 HANDLE parent;
+ − 1068 HANDLE newstdin, newstdout, newstderr;
+ − 1069
+ − 1070 parent = GetCurrentProcess ();
+ − 1071
+ − 1072 handles[0] = GetStdHandle (STD_INPUT_HANDLE);
+ − 1073 handles[1] = GetStdHandle (STD_OUTPUT_HANDLE);
+ − 1074 handles[2] = GetStdHandle (STD_ERROR_HANDLE);
+ − 1075
+ − 1076 /* make inheritable copies of the new handles */
+ − 1077 if (!DuplicateHandle (parent,
+ − 1078 (HANDLE) _get_osfhandle (in),
+ − 1079 parent,
+ − 1080 &newstdin,
+ − 1081 0,
+ − 1082 TRUE,
+ − 1083 DUPLICATE_SAME_ACCESS))
563
+ − 1084 mswindows_report_process_error ("Duplicating input handle for child",
+ − 1085 Qunbound, GetLastError ());
428
+ − 1086
+ − 1087 if (!DuplicateHandle (parent,
+ − 1088 (HANDLE) _get_osfhandle (out),
+ − 1089 parent,
+ − 1090 &newstdout,
+ − 1091 0,
+ − 1092 TRUE,
+ − 1093 DUPLICATE_SAME_ACCESS))
563
+ − 1094 mswindows_report_process_error ("Duplicating output handle for child",
+ − 1095 Qunbound, GetLastError ());
428
+ − 1096
+ − 1097 if (!DuplicateHandle (parent,
+ − 1098 (HANDLE) _get_osfhandle (err),
+ − 1099 parent,
+ − 1100 &newstderr,
+ − 1101 0,
+ − 1102 TRUE,
+ − 1103 DUPLICATE_SAME_ACCESS))
563
+ − 1104 mswindows_report_process_error ("Duplicating error handle for child",
+ − 1105 Qunbound, GetLastError ());
428
+ − 1106
+ − 1107 /* and store them as our std handles */
+ − 1108 if (!SetStdHandle (STD_INPUT_HANDLE, newstdin))
563
+ − 1109 mswindows_report_process_error ("Changing stdin handle",
+ − 1110 Qunbound, GetLastError ());
428
+ − 1111
+ − 1112 if (!SetStdHandle (STD_OUTPUT_HANDLE, newstdout))
563
+ − 1113 mswindows_report_process_error ("Changing stdout handle",
+ − 1114 Qunbound, GetLastError ());
428
+ − 1115
+ − 1116 if (!SetStdHandle (STD_ERROR_HANDLE, newstderr))
563
+ − 1117 mswindows_report_process_error ("Changing stderr handle",
+ − 1118 Qunbound, GetLastError ());
428
+ − 1119 }
+ − 1120
+ − 1121 void
+ − 1122 reset_standard_handles (int in, int out, int err, HANDLE handles[3])
+ − 1123 {
+ − 1124 /* close the duplicated handles passed to the child */
+ − 1125 CloseHandle (GetStdHandle (STD_INPUT_HANDLE));
+ − 1126 CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE));
+ − 1127 CloseHandle (GetStdHandle (STD_ERROR_HANDLE));
+ − 1128
+ − 1129 /* now restore parent's saved std handles */
+ − 1130 SetStdHandle (STD_INPUT_HANDLE, handles[0]);
+ − 1131 SetStdHandle (STD_OUTPUT_HANDLE, handles[1]);
+ − 1132 SetStdHandle (STD_ERROR_HANDLE, handles[2]);
+ − 1133 }
+ − 1134
+ − 1135 void
+ − 1136 set_process_dir (const char * dir)
+ − 1137 {
+ − 1138 process_dir = dir;
+ − 1139 }
+ − 1140
+ − 1141
+ − 1142 void
442
+ − 1143 syms_of_ntproc (void)
428
+ − 1144 {
+ − 1145 }
+ − 1146
+ − 1147 void
+ − 1148 vars_of_ntproc (void)
+ − 1149 {
+ − 1150 DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args /*
+ − 1151 Non-nil enables quoting of process arguments to ensure correct parsing.
+ − 1152 Because Windows does not directly pass argv arrays to child processes,
+ − 1153 programs have to reconstruct the argv array by parsing the command
+ − 1154 line string. For an argument to contain a space, it must be enclosed
+ − 1155 in double quotes or it will be parsed as multiple arguments.
+ − 1156
+ − 1157 If the value is a character, that character will be used to escape any
+ − 1158 quote characters that appear, otherwise a suitable escape character
+ − 1159 will be chosen based on the type of the program.
+ − 1160 */ );
+ − 1161 Vwin32_quote_process_args = Qt;
+ − 1162
+ − 1163 DEFVAR_LISP ("win32-start-process-show-window",
+ − 1164 &Vwin32_start_process_show_window /*
+ − 1165 When nil, processes started via start-process hide their windows.
+ − 1166 When non-nil, they show their window in the method of their choice.
+ − 1167 */ );
+ − 1168 Vwin32_start_process_show_window = Qnil;
+ − 1169
+ − 1170 DEFVAR_LISP ("win32-start-process-share-console",
+ − 1171 &Vwin32_start_process_share_console /*
+ − 1172 When nil, processes started via start-process are given a new console.
+ − 1173 When non-nil, they share the Emacs console; this has the limitation of
638
+ − 1174 allowing only one DOS subprocess to run at a time (whether started directly
428
+ − 1175 or indirectly by Emacs), and preventing Emacs from cleanly terminating the
+ − 1176 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't
+ − 1177 otherwise respond to interrupts from Emacs.
+ − 1178 */ );
+ − 1179 Vwin32_start_process_share_console = Qt;
+ − 1180
+ − 1181 DEFVAR_LISP ("win32-pipe-read-delay", &Vwin32_pipe_read_delay /*
+ − 1182 Forced delay before reading subprocess output.
+ − 1183 This is done to improve the buffering of subprocess output, by
+ − 1184 avoiding the inefficiency of frequently reading small amounts of data.
+ − 1185
+ − 1186 If positive, the value is the number of milliseconds to sleep before
+ − 1187 reading the subprocess output. If negative, the magnitude is the number
+ − 1188 of time slices to wait (effectively boosting the priority of the child
+ − 1189 process temporarily). A value of zero disables waiting entirely.
+ − 1190 */ );
+ − 1191 Vwin32_pipe_read_delay = make_int (50);
+ − 1192 }
+ − 1193
+ − 1194 /* end of ntproc.c */