Mercurial > hg > xemacs-beta
comparison src/callproc.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 | a5df635868b2 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* Synchronous subprocess invocation for XEmacs. | |
2 Copyright (C) 1985, 86, 87, 88, 93, 94, 95 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 /* Synched up with: Mule 2.0, FSF 19.30. */ | |
22 /* Partly sync'ed with 19.36.4 */ | |
23 | |
24 #include <config.h> | |
25 #include "lisp.h" | |
26 | |
27 #include "buffer.h" | |
28 #include "commands.h" | |
29 #include "insdel.h" | |
30 #include "lstream.h" | |
31 #include "process.h" | |
32 #include "sysdep.h" | |
33 #include "window.h" | |
34 #ifdef FILE_CODING | |
35 #include "file-coding.h" | |
36 #endif | |
37 | |
38 #include "systime.h" | |
39 #include "sysproc.h" | |
40 #include "sysfile.h" /* Always include after sysproc.h */ | |
41 #include "syssignal.h" /* Always include before systty.h */ | |
42 #include "systty.h" | |
43 | |
44 #ifdef WINDOWSNT | |
45 #define _P_NOWAIT 1 /* from process.h */ | |
46 #include <windows.h> | |
47 #include "nt.h" | |
48 #endif | |
49 | |
50 #ifdef DOS_NT | |
51 /* When we are starting external processes we need to know whether they | |
52 take binary input (no conversion) or text input (\n is converted to | |
53 \r\n). Similarly for output: if newlines are written as \r\n then it's | |
54 text process output, otherwise it's binary. */ | |
55 Lisp_Object Vbinary_process_input; | |
56 Lisp_Object Vbinary_process_output; | |
57 #endif /* DOS_NT */ | |
58 | |
59 Lisp_Object Vshell_file_name; | |
60 | |
61 /* The environment to pass to all subprocesses when they are started. | |
62 This is in the semi-bogus format of ("VAR=VAL" "VAR2=VAL2" ... ) | |
63 */ | |
64 Lisp_Object Vprocess_environment; | |
65 | |
66 /* True iff we are about to fork off a synchronous process or if we | |
67 are waiting for it. */ | |
68 volatile int synch_process_alive; | |
69 | |
70 /* Nonzero => this is a string explaining death of synchronous subprocess. */ | |
71 CONST char *synch_process_death; | |
72 | |
73 /* If synch_process_death is zero, | |
74 this is exit code of synchronous subprocess. */ | |
75 int synch_process_retcode; | |
76 | |
77 /* Clean up when exiting Fcall_process_internal. | |
78 On MSDOS, delete the temporary file on any kind of termination. | |
79 On Unix, kill the process and any children on termination by signal. */ | |
80 | |
81 /* Nonzero if this is termination due to exit. */ | |
82 static int call_process_exited; | |
83 | |
84 Lisp_Object Vlisp_EXEC_SUFFIXES; | |
85 | |
86 static Lisp_Object | |
87 call_process_kill (Lisp_Object fdpid) | |
88 { | |
89 Lisp_Object fd = Fcar (fdpid); | |
90 Lisp_Object pid = Fcdr (fdpid); | |
91 | |
92 if (!NILP (fd)) | |
93 close (XINT (fd)); | |
94 | |
95 if (!NILP (pid)) | |
96 EMACS_KILLPG (XINT (pid), SIGKILL); | |
97 | |
98 synch_process_alive = 0; | |
99 return Qnil; | |
100 } | |
101 | |
102 static Lisp_Object | |
103 call_process_cleanup (Lisp_Object fdpid) | |
104 { | |
105 int fd = XINT (Fcar (fdpid)); | |
106 int pid = XINT (Fcdr (fdpid)); | |
107 | |
108 if (!call_process_exited && | |
109 EMACS_KILLPG (pid, SIGINT) == 0) | |
110 { | |
111 int speccount = specpdl_depth (); | |
112 | |
113 record_unwind_protect (call_process_kill, fdpid); | |
114 /* #### "c-G" -- need non-consing Single-key-description */ | |
115 message ("Waiting for process to die...(type C-g again to kill it instantly)"); | |
116 | |
117 wait_for_termination (pid); | |
118 | |
119 /* "Discard" the unwind protect. */ | |
120 XCAR (fdpid) = Qnil; | |
121 XCDR (fdpid) = Qnil; | |
122 unbind_to (speccount, Qnil); | |
123 | |
124 message ("Waiting for process to die... done"); | |
125 } | |
126 synch_process_alive = 0; | |
127 close (fd); | |
128 return Qnil; | |
129 } | |
130 | |
131 static Lisp_Object fork_error; | |
132 #if 0 /* UNUSED */ | |
133 static void | |
134 report_fork_error (char *string, Lisp_Object data) | |
135 { | |
136 Lisp_Object errstring = lisp_strerror (errno); | |
137 | |
138 fork_error = Fcons (build_string (string), Fcons (errstring, data)); | |
139 | |
140 /* terminate this branch of the fork, without closing stdin/out/etc. */ | |
141 _exit (1); | |
142 } | |
143 #endif /* unused */ | |
144 | |
145 DEFUN ("call-process-internal", Fcall_process_internal, 1, MANY, 0, /* | |
146 Call PROGRAM synchronously in separate process, with coding-system specified. | |
147 Arguments are | |
148 (PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS). | |
149 The program's input comes from file INFILE (nil means `/dev/null'). | |
150 Insert output in BUFFER before point; t means current buffer; | |
151 nil for BUFFER means discard it; 0 means discard and don't wait. | |
152 BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, | |
153 REAL-BUFFER says what to do with standard output, as above, | |
154 while STDERR-FILE says what to do with standard error in the child. | |
155 STDERR-FILE may be nil (discard standard error output), | |
156 t (mix it with ordinary output), or a file name string. | |
157 | |
158 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted. | |
159 Remaining arguments are strings passed as command arguments to PROGRAM. | |
160 | |
161 If BUFFER is 0, `call-process' returns immediately with value nil. | |
162 Otherwise it waits for PROGRAM to terminate and returns a numeric exit status | |
163 or a signal description string. | |
164 If you quit, the process is killed with SIGINT, or SIGKILL if you | |
165 quit again. | |
166 */ | |
167 (int nargs, Lisp_Object *args)) | |
168 { | |
169 /* This function can GC */ | |
170 Lisp_Object infile, buffer, current_dir, display, path; | |
171 int fd[2]; | |
172 int filefd; | |
173 int pid; | |
174 char buf[16384]; | |
175 char *bufptr = buf; | |
176 int bufsize = 16384; | |
177 int speccount = specpdl_depth (); | |
178 struct gcpro gcpro1, gcpro2; | |
179 char **new_argv = alloca_array (char *, max (2, nargs - 2)); | |
180 | |
181 /* File to use for stderr in the child. | |
182 t means use same as standard output. */ | |
183 Lisp_Object error_file; | |
184 | |
185 CHECK_STRING (args[0]); | |
186 | |
187 error_file = Qt; | |
188 | |
189 #if defined (NO_SUBPROCESSES) | |
190 /* Without asynchronous processes we cannot have BUFFER == 0. */ | |
191 if (nargs >= 3 && !INTP (args[2])) | |
192 error ("Operating system cannot handle asynchronous subprocesses"); | |
193 #endif /* NO_SUBPROCESSES */ | |
194 | |
195 /* Do this before building new_argv because GC in Lisp code | |
196 * called by various filename-hacking routines might relocate strings */ | |
197 locate_file (Vexec_path, args[0], Vlisp_EXEC_SUFFIXES, &path, X_OK); | |
198 | |
199 /* Make sure that the child will be able to chdir to the current | |
200 buffer's current directory, or its unhandled equivalent. We | |
201 can't just have the child check for an error when it does the | |
202 chdir, since it's in a vfork. */ | |
203 { | |
204 struct gcpro ngcpro1, ngcpro2; | |
205 /* Do this test before building new_argv because GC in Lisp code | |
206 * called by various filename-hacking routines might relocate strings */ | |
207 /* Make sure that the child will be able to chdir to the current | |
208 buffer's current directory. We can't just have the child check | |
209 for an error when it does the chdir, since it's in a vfork. */ | |
210 | |
211 NGCPRO2 (current_dir, path); /* Caller gcprotects args[] */ | |
212 current_dir = current_buffer->directory; | |
213 current_dir = Funhandled_file_name_directory (current_dir); | |
214 current_dir = expand_and_dir_to_file (current_dir, Qnil); | |
215 #if 0 | |
216 /* This is in FSF, but it breaks everything in the presence of | |
217 ange-ftp-visited files, so away with it. */ | |
218 if (NILP (Ffile_accessible_directory_p (current_dir))) | |
219 report_file_error ("Setting current directory", | |
220 Fcons (current_buffer->directory, Qnil)); | |
221 #endif /* 0 */ | |
222 NUNGCPRO; | |
223 } | |
224 | |
225 GCPRO1 (current_dir); | |
226 | |
227 if (nargs >= 2 && ! NILP (args[1])) | |
228 { | |
229 struct gcpro ngcpro1; | |
230 NGCPRO1 (current_buffer->directory); | |
231 infile = Fexpand_file_name (args[1], current_buffer->directory); | |
232 NUNGCPRO; | |
233 CHECK_STRING (infile); | |
234 } | |
235 else | |
236 infile = build_string (NULL_DEVICE); | |
237 | |
238 UNGCPRO; | |
239 | |
240 GCPRO2 (infile, current_dir); /* Fexpand_file_name might trash it */ | |
241 | |
242 if (nargs >= 3) | |
243 { | |
244 buffer = args[2]; | |
245 | |
246 /* If BUFFER is a list, its meaning is | |
247 (BUFFER-FOR-STDOUT FILE-FOR-STDERR). */ | |
248 if (CONSP (buffer)) | |
249 { | |
250 if (CONSP (XCDR (buffer))) | |
251 { | |
252 Lisp_Object file_for_stderr = XCAR (XCDR (buffer)); | |
253 | |
254 if (NILP (file_for_stderr) || EQ (Qt, file_for_stderr)) | |
255 error_file = file_for_stderr; | |
256 else | |
257 error_file = Fexpand_file_name (file_for_stderr, Qnil); | |
258 } | |
259 | |
260 buffer = XCAR (buffer); | |
261 } | |
262 | |
263 if (!(EQ (buffer, Qnil) | |
264 || EQ (buffer, Qt) | |
265 || ZEROP (buffer))) | |
266 { | |
267 Lisp_Object spec_buffer = buffer; | |
268 buffer = Fget_buffer (buffer); | |
269 /* Mention the buffer name for a better error message. */ | |
270 if (NILP (buffer)) | |
271 CHECK_BUFFER (spec_buffer); | |
272 CHECK_BUFFER (buffer); | |
273 } | |
274 } | |
275 else | |
276 buffer = Qnil; | |
277 | |
278 UNGCPRO; | |
279 | |
280 display = ((nargs >= 4) ? args[3] : Qnil); | |
281 | |
282 /* From here we assume we won't GC (unless an error is signaled). */ | |
283 { | |
284 REGISTER int i; | |
285 for (i = 4; i < nargs; i++) | |
286 { | |
287 CHECK_STRING (args[i]); | |
288 new_argv[i - 3] = (char *) XSTRING_DATA (args[i]); | |
289 } | |
290 new_argv[nargs - 3] = 0; | |
291 } | |
292 | |
293 if (NILP (path)) | |
294 report_file_error ("Searching for program", Fcons (args[0], Qnil)); | |
295 new_argv[0] = (char *) XSTRING_DATA (path); | |
296 | |
297 filefd = open ((char *) XSTRING_DATA (infile), O_RDONLY | OPEN_BINARY, 0); | |
298 if (filefd < 0) | |
299 report_file_error ("Opening process input file", Fcons (infile, Qnil)); | |
300 | |
301 if (INTP (buffer)) | |
302 { | |
303 fd[1] = open (NULL_DEVICE, O_WRONLY | OPEN_BINARY, 0); | |
304 fd[0] = -1; | |
305 } | |
306 else | |
307 { | |
308 pipe (fd); | |
309 #if 0 | |
310 /* Replaced by close_process_descs */ | |
311 set_exclusive_use (fd[0]); | |
312 #endif | |
313 } | |
314 | |
315 { | |
316 /* child_setup must clobber environ in systems with true vfork. | |
317 Protect it from permanent change. */ | |
318 REGISTER char **save_environ = environ; | |
319 REGISTER int fd1 = fd[1]; | |
320 int fd_error = fd1; | |
321 char **env; | |
322 | |
323 env = environ; | |
324 | |
325 /* Record that we're about to create a synchronous process. */ | |
326 synch_process_alive = 1; | |
327 | |
328 /* These vars record information from process termination. | |
329 Clear them now before process can possibly terminate, | |
330 to avoid timing error if process terminates soon. */ | |
331 synch_process_death = 0; | |
332 synch_process_retcode = 0; | |
333 | |
334 if (NILP (error_file)) | |
335 fd_error = open (NULL_DEVICE, O_WRONLY | OPEN_BINARY); | |
336 else if (STRINGP (error_file)) | |
337 { | |
338 fd_error = open ((CONST char *) XSTRING_DATA (error_file), | |
339 #ifdef DOS_NT | |
340 O_WRONLY | O_TRUNC | O_CREAT | O_TEXT, | |
341 S_IREAD | S_IWRITE | |
342 #else /* not DOS_NT */ | |
343 O_WRONLY | O_TRUNC | O_CREAT | OPEN_BINARY, | |
344 CREAT_MODE | |
345 #endif /* not DOS_NT */ | |
346 ); | |
347 } | |
348 | |
349 if (fd_error < 0) | |
350 { | |
351 close (filefd); | |
352 close (fd[0]); | |
353 if (fd1 >= 0) | |
354 close (fd1); | |
355 report_file_error ("Cannot open", Fcons(error_file, Qnil)); | |
356 } | |
357 | |
358 fork_error = Qnil; | |
359 #ifdef WINDOWSNT | |
360 pid = child_setup (filefd, fd1, fd_error, new_argv, | |
361 (char *) XSTRING_DATA (current_dir)); | |
362 #else /* not WINDOWSNT */ | |
363 pid = fork (); | |
364 | |
365 if (pid == 0) | |
366 { | |
367 if (fd[0] >= 0) | |
368 close (fd[0]); | |
369 /* This is necessary because some shells may attempt to | |
370 access the current controlling terminal and will hang | |
371 if they are run in the background, as will be the case | |
372 when XEmacs is started in the background. Martin | |
373 Buchholz observed this problem running a subprocess | |
374 that used zsh to call gzip to uncompress an info | |
375 file. */ | |
376 disconnect_controlling_terminal (); | |
377 child_setup (filefd, fd1, fd_error, new_argv, | |
378 (char *) XSTRING_DATA (current_dir)); | |
379 } | |
380 if (fd_error >= 0) | |
381 close (fd_error); | |
382 | |
383 #endif /* not WINDOWSNT */ | |
384 | |
385 environ = save_environ; | |
386 | |
387 /* Close most of our fd's, but not fd[0] | |
388 since we will use that to read input from. */ | |
389 close (filefd); | |
390 if (fd1 >= 0) | |
391 close (fd1); | |
392 } | |
393 | |
394 if (!NILP (fork_error)) | |
395 signal_error (Qfile_error, fork_error); | |
396 | |
397 if (pid < 0) | |
398 { | |
399 if (fd[0] >= 0) | |
400 close (fd[0]); | |
401 report_file_error ("Doing fork", Qnil); | |
402 } | |
403 | |
404 if (INTP (buffer)) | |
405 { | |
406 if (fd[0] >= 0) | |
407 close (fd[0]); | |
408 #if defined (NO_SUBPROCESSES) | |
409 /* If Emacs has been built with asynchronous subprocess support, | |
410 we don't need to do this, I think because it will then have | |
411 the facilities for handling SIGCHLD. */ | |
412 wait_without_blocking (); | |
413 #endif /* NO_SUBPROCESSES */ | |
414 return Qnil; | |
415 } | |
416 | |
417 { | |
418 int nread; | |
419 int first = 1; | |
420 int total_read = 0; | |
421 Lisp_Object instream; | |
422 struct gcpro ngcpro1; | |
423 | |
424 /* Enable sending signal if user quits below. */ | |
425 call_process_exited = 0; | |
426 | |
427 record_unwind_protect (call_process_cleanup, | |
428 Fcons (make_int (fd[0]), make_int (pid))); | |
429 | |
430 /* FSFmacs calls Fset_buffer() here. We don't have to because | |
431 we can insert into buffers other than the current one. */ | |
432 if (EQ (buffer, Qt)) | |
433 XSETBUFFER (buffer, current_buffer); | |
434 instream = make_filedesc_input_stream (fd[0], 0, -1, LSTR_ALLOW_QUIT); | |
435 #ifdef FILE_CODING | |
436 instream = | |
437 make_decoding_input_stream | |
438 (XLSTREAM (instream), | |
439 Fget_coding_system (Vcoding_system_for_read)); | |
440 Lstream_set_character_mode (XLSTREAM (instream)); | |
441 #endif | |
442 NGCPRO1 (instream); | |
443 while (1) | |
444 { | |
445 QUIT; | |
446 /* Repeatedly read until we've filled as much as possible | |
447 of the buffer size we have. But don't read | |
448 less than 1024--save that for the next bufferfull. */ | |
449 | |
450 nread = 0; | |
451 while (nread < bufsize - 1024) | |
452 { | |
453 ssize_t this_read | |
454 = Lstream_read (XLSTREAM (instream), bufptr + nread, | |
455 bufsize - nread); | |
456 | |
457 if (this_read < 0) | |
458 goto give_up; | |
459 | |
460 if (this_read == 0) | |
461 goto give_up_1; | |
462 | |
463 nread += this_read; | |
464 } | |
465 | |
466 give_up_1: | |
467 | |
468 /* Now NREAD is the total amount of data in the buffer. */ | |
469 if (nread == 0) | |
470 break; | |
471 | |
472 #ifdef DOS_NT | |
473 /* Until we pull out of MULE things like | |
474 make_decoding_input_stream(), we do the following which is | |
475 less elegant. --marcpa */ | |
476 { | |
477 int lf_count = 0; | |
478 if (NILP (Vbinary_process_output)) { | |
479 nread = crlf_to_lf(nread, bufptr, &lf_count); | |
480 } | |
481 } | |
482 #endif | |
483 | |
484 total_read += nread; | |
485 | |
486 if (!NILP (buffer)) | |
487 buffer_insert_raw_string (XBUFFER (buffer), (Bufbyte *) bufptr, | |
488 nread); | |
489 | |
490 /* Make the buffer bigger as we continue to read more data, | |
491 but not past 64k. */ | |
492 if (bufsize < 64 * 1024 && total_read > 32 * bufsize) | |
493 { | |
494 bufsize *= 2; | |
495 bufptr = (char *) alloca (bufsize); | |
496 } | |
497 | |
498 if (!NILP (display) && INTERACTIVE) | |
499 { | |
500 first = 0; | |
501 redisplay (); | |
502 } | |
503 } | |
504 give_up: | |
505 Lstream_close (XLSTREAM (instream)); | |
506 NUNGCPRO; | |
507 | |
508 QUIT; | |
509 /* Wait for it to terminate, unless it already has. */ | |
510 wait_for_termination (pid); | |
511 | |
512 /* Don't kill any children that the subprocess may have left behind | |
513 when exiting. */ | |
514 call_process_exited = 1; | |
515 unbind_to (speccount, Qnil); | |
516 | |
517 if (synch_process_death) | |
518 return build_string (synch_process_death); | |
519 return make_int (synch_process_retcode); | |
520 } | |
521 } | |
522 | |
523 | |
524 | |
525 /* Move the file descriptor FD so that its number is not less than MIN. * | |
526 The original file descriptor remains open. */ | |
527 static int | |
528 relocate_fd (int fd, int min) | |
529 { | |
530 if (fd >= min) | |
531 return fd; | |
532 else | |
533 { | |
534 int newfd = dup (fd); | |
535 if (newfd == -1) | |
536 { | |
537 stderr_out ("Error while setting up child: %s\n", | |
538 strerror (errno)); | |
539 _exit (1); | |
540 } | |
541 return relocate_fd (newfd, min); | |
542 } | |
543 } | |
544 | |
545 /* This is the last thing run in a newly forked inferior | |
546 either synchronous or asynchronous. | |
547 Copy descriptors IN, OUT and ERR | |
548 as descriptors STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO. | |
549 Initialize inferior's priority, pgrp, connected dir and environment. | |
550 then exec another program based on new_argv. | |
551 | |
552 This function may change environ for the superior process. | |
553 Therefore, the superior process must save and restore the value | |
554 of environ around the fork and the call to this function. | |
555 | |
556 ENV is the environment for the subprocess. | |
557 | |
558 XEmacs: We've removed the SET_PGRP argument because it's already | |
559 done by the callers of child_setup. | |
560 | |
561 CURRENT_DIR is an elisp string giving the path of the current | |
562 directory the subprocess should have. Since we can't really signal | |
563 a decent error from within the child, this should be verified as an | |
564 executable directory by the parent. */ | |
565 | |
566 #ifdef WINDOWSNT | |
567 int | |
568 #else | |
569 void | |
570 #endif | |
571 child_setup (int in, int out, int err, char **new_argv, | |
572 CONST char *current_dir) | |
573 { | |
574 char **env; | |
575 char *pwd; | |
576 #ifdef WINDOWSNT | |
577 int cpid; | |
578 HANDLE handles[4]; | |
579 #endif /* WINDOWSNT */ | |
580 | |
581 #ifdef SET_EMACS_PRIORITY | |
582 if (emacs_priority != 0) | |
583 nice (- emacs_priority); | |
584 #endif | |
585 | |
586 #if !defined (NO_SUBPROCESSES) && !defined (WINDOWSNT) | |
587 /* Close Emacs's descriptors that this process should not have. */ | |
588 close_process_descs (); | |
589 #endif /* not NO_SUBPROCESSES */ | |
590 close_load_descs (); | |
591 | |
592 /* Note that use of alloca is always safe here. It's obvious for systems | |
593 that do not have true vfork or that have true (stack) alloca. | |
594 If using vfork and C_ALLOCA it is safe because that changes | |
595 the superior's static variables as if the superior had done alloca | |
596 and will be cleaned up in the usual way. */ | |
597 { | |
598 REGISTER int i; | |
599 | |
600 i = strlen (current_dir); | |
601 pwd = alloca_array (char, i + 6); | |
602 memcpy (pwd, "PWD=", 4); | |
603 memcpy (pwd + 4, current_dir, i); | |
604 i += 4; | |
605 if (!IS_DIRECTORY_SEP (pwd[i - 1])) | |
606 pwd[i++] = DIRECTORY_SEP; | |
607 pwd[i] = 0; | |
608 | |
609 /* We can't signal an Elisp error here; we're in a vfork. Since | |
610 the callers check the current directory before forking, this | |
611 should only return an error if the directory's permissions | |
612 are changed between the check and this chdir, but we should | |
613 at least check. */ | |
614 if (chdir (pwd + 4) < 0) | |
615 { | |
616 /* Don't report the chdir error, or ange-ftp.el doesn't work. */ | |
617 /* (FSFmacs does _exit (errno) here.) */ | |
618 pwd = 0; | |
619 } | |
620 else | |
621 { | |
622 /* Strip trailing "/". Cretinous *[]&@$#^%@#$% Un*x */ | |
623 /* leave "//" (from FSF) */ | |
624 while (i > 6 && IS_DIRECTORY_SEP (pwd[i - 1])) | |
625 pwd[--i] = 0; | |
626 } | |
627 } | |
628 | |
629 /* Set `env' to a vector of the strings in Vprocess_environment. */ | |
630 /* + 2 to include PWD and terminating 0. */ | |
631 env = alloca_array (char *, XINT (Flength (Vprocess_environment)) + 2); | |
632 { | |
633 REGISTER Lisp_Object tail; | |
634 char **new_env = env; | |
635 | |
636 /* If we have a PWD envvar and we know the real current directory, | |
637 pass one down, but with corrected value. */ | |
638 if (pwd && getenv ("PWD")) | |
639 *new_env++ = pwd; | |
640 | |
641 /* Copy the Vprocess_environment strings into new_env. */ | |
642 for (tail = Vprocess_environment; | |
643 CONSP (tail) && STRINGP (XCAR (tail)); | |
644 tail = XCDR (tail)) | |
645 { | |
646 char **ep = env; | |
647 char *envvar_external; | |
648 Bufbyte *envvar_internal = XSTRING_DATA (XCAR (tail)); | |
649 | |
650 GET_C_CHARPTR_EXT_FILENAME_DATA_ALLOCA (envvar_internal, envvar_external); | |
651 | |
652 /* See if envvar_external duplicates any string already in the env. | |
653 If so, don't put it in. | |
654 When an env var has multiple definitions, | |
655 we keep the definition that comes first in process-environment. */ | |
656 for (; ep != new_env; ep++) | |
657 { | |
658 char *p = *ep, *q = envvar_external; | |
659 while (1) | |
660 { | |
661 if (*q == 0) | |
662 /* The string is malformed; might as well drop it. */ | |
663 goto duplicate; | |
664 if (*q != *p) | |
665 break; | |
666 if (*q == '=') | |
667 goto duplicate; | |
668 p++, q++; | |
669 } | |
670 } | |
671 if (pwd && !strncmp ("PWD=", envvar_external, 4)) | |
672 { | |
673 *new_env++ = pwd; | |
674 pwd = 0; | |
675 } | |
676 else | |
677 *new_env++ = envvar_external; | |
678 | |
679 duplicate: ; | |
680 } | |
681 *new_env = 0; | |
682 } | |
683 | |
684 #ifdef WINDOWSNT | |
685 prepare_standard_handles (in, out, err, handles); | |
686 set_process_dir (current_dir); | |
687 #else /* not WINDOWSNT */ | |
688 /* Make sure that in, out, and err are not actually already in | |
689 descriptors zero, one, or two; this could happen if Emacs is | |
690 started with its standard in, out, or error closed, as might | |
691 happen under X. */ | |
692 in = relocate_fd (in, 3); | |
693 out = relocate_fd (out, 3); | |
694 err = relocate_fd (err, 3); | |
695 | |
696 /* Set the standard input/output channels of the new process. */ | |
697 close (STDIN_FILENO); | |
698 close (STDOUT_FILENO); | |
699 close (STDERR_FILENO); | |
700 | |
701 dup2 (in, STDIN_FILENO); | |
702 dup2 (out, STDOUT_FILENO); | |
703 dup2 (err, STDERR_FILENO); | |
704 | |
705 close (in); | |
706 close (out); | |
707 close (err); | |
708 | |
709 /* I can't think of any reason why child processes need any more | |
710 than the standard 3 file descriptors. It would be cleaner to | |
711 close just the ones that need to be, but the following brute | |
712 force approach is certainly effective, and not too slow. */ | |
713 { | |
714 int fd; | |
715 for (fd=3; fd<=64; fd++) | |
716 close (fd); | |
717 } | |
718 #endif /* not WINDOWSNT */ | |
719 | |
720 #ifdef vipc | |
721 something missing here; | |
722 #endif /* vipc */ | |
723 | |
724 #ifdef WINDOWSNT | |
725 /* Spawn the child. (See ntproc.c:Spawnve). */ | |
726 cpid = spawnve (_P_NOWAIT, new_argv[0], (CONST char* CONST*)new_argv, | |
727 (CONST char* CONST*)env); | |
728 if (cpid == -1) | |
729 /* An error occurred while trying to spawn the process. */ | |
730 report_file_error ("Spawning child process", Qnil); | |
731 reset_standard_handles (in, out, err, handles); | |
732 return cpid; | |
733 #else /* not WINDOWSNT */ | |
734 /* execvp does not accept an environment arg so the only way | |
735 to pass this environment is to set environ. Our caller | |
736 is responsible for restoring the ambient value of environ. */ | |
737 environ = env; | |
738 execvp (new_argv[0], new_argv); | |
739 | |
740 stdout_out ("Can't exec program %s\n", new_argv[0]); | |
741 _exit (1); | |
742 #endif /* not WINDOWSNT */ | |
743 } | |
744 | |
745 static int | |
746 getenv_internal (CONST Bufbyte *var, | |
747 Bytecount varlen, | |
748 Bufbyte **value, | |
749 Bytecount *valuelen) | |
750 { | |
751 Lisp_Object scan; | |
752 | |
753 for (scan = Vprocess_environment; CONSP (scan); scan = XCDR (scan)) | |
754 { | |
755 Lisp_Object entry = XCAR (scan); | |
756 | |
757 if (STRINGP (entry) | |
758 && XSTRING_LENGTH (entry) > varlen | |
759 && XSTRING_BYTE (entry, varlen) == '=' | |
760 #ifdef WINDOWSNT | |
761 /* NT environment variables are case insensitive. */ | |
762 && ! memicmp (XSTRING_DATA (entry), var, varlen) | |
763 #else /* not WINDOWSNT */ | |
764 && ! memcmp (XSTRING_DATA (entry), var, varlen) | |
765 #endif /* not WINDOWSNT */ | |
766 ) | |
767 { | |
768 *value = XSTRING_DATA (entry) + (varlen + 1); | |
769 *valuelen = XSTRING_LENGTH (entry) - (varlen + 1); | |
770 return 1; | |
771 } | |
772 } | |
773 | |
774 return 0; | |
775 } | |
776 | |
777 DEFUN ("getenv", Fgetenv, 1, 2, "sEnvironment variable: \np", /* | |
778 Return the value of environment variable VAR, as a string. | |
779 VAR is a string, the name of the variable. | |
780 When invoked interactively, prints the value in the echo area. | |
781 */ | |
782 (var, interactivep)) | |
783 { | |
784 Bufbyte *value; | |
785 Bytecount valuelen; | |
786 Lisp_Object v = Qnil; | |
787 struct gcpro gcpro1; | |
788 | |
789 CHECK_STRING (var); | |
790 GCPRO1 (v); | |
791 if (getenv_internal (XSTRING_DATA (var), XSTRING_LENGTH (var), | |
792 &value, &valuelen)) | |
793 v = make_string (value, valuelen); | |
794 if (!NILP (interactivep)) | |
795 { | |
796 if (NILP (v)) | |
797 message ("%s not defined in environment", XSTRING_DATA (var)); | |
798 else | |
799 /* #### Should use Fprin1_to_string or Fprin1 to handle string | |
800 containing quotes correctly. */ | |
801 message ("\"%s\"", value); | |
802 } | |
803 RETURN_UNGCPRO (v); | |
804 } | |
805 | |
806 /* A version of getenv that consults process_environment, easily | |
807 callable from C. */ | |
808 char * | |
809 egetenv (CONST char *var) | |
810 { | |
811 Bufbyte *value; | |
812 Bytecount valuelen; | |
813 | |
814 if (getenv_internal ((CONST Bufbyte *) var, strlen (var), &value, &valuelen)) | |
815 return (char *) value; | |
816 else | |
817 return 0; | |
818 } | |
819 | |
820 | |
821 void | |
822 init_callproc (void) | |
823 { | |
824 /* This function can GC */ | |
825 | |
826 { | |
827 /* jwz: always initialize Vprocess_environment, so that egetenv() | |
828 works in temacs. */ | |
829 char **envp; | |
830 Vprocess_environment = Qnil; | |
831 for (envp = environ; envp && *envp; envp++) | |
832 { | |
833 Vprocess_environment = Fcons (build_ext_string (*envp, FORMAT_OS), | |
834 Vprocess_environment); | |
835 } | |
836 } | |
837 | |
838 { | |
839 /* Initialize shell-file-name from environment variables or best guess. */ | |
840 #ifdef WINDOWSNT | |
841 CONST char *shell = egetenv ("COMSPEC"); | |
842 if (!shell) shell = "\\WINNT\\system32\\cmd.exe"; | |
843 #else /* not WINDOWSNT */ | |
844 CONST char *shell = egetenv ("SHELL"); | |
845 if (!shell) shell = "/bin/sh"; | |
846 #endif | |
847 | |
848 Vshell_file_name = build_string (shell); | |
849 } | |
850 } | |
851 | |
852 #if 0 | |
853 void | |
854 set_process_environment (void) | |
855 { | |
856 REGISTER char **envp; | |
857 | |
858 Vprocess_environment = Qnil; | |
859 #ifndef CANNOT_DUMP | |
860 if (initialized) | |
861 #endif | |
862 for (envp = environ; *envp; envp++) | |
863 Vprocess_environment = Fcons (build_string (*envp), | |
864 Vprocess_environment); | |
865 } | |
866 #endif /* unused */ | |
867 | |
868 void | |
869 syms_of_callproc (void) | |
870 { | |
871 DEFSUBR (Fcall_process_internal); | |
872 DEFSUBR (Fgetenv); | |
873 } | |
874 | |
875 void | |
876 vars_of_callproc (void) | |
877 { | |
878 /* This function can GC */ | |
879 #ifdef DOS_NT | |
880 DEFVAR_LISP ("binary-process-input", &Vbinary_process_input /* | |
881 *If non-nil then new subprocesses are assumed to take binary input. | |
882 */ ); | |
883 Vbinary_process_input = Qnil; | |
884 | |
885 DEFVAR_LISP ("binary-process-output", &Vbinary_process_output /* | |
886 *If non-nil then new subprocesses are assumed to produce binary output. | |
887 */ ); | |
888 Vbinary_process_output = Qnil; | |
889 #endif /* DOS_NT */ | |
890 | |
891 DEFVAR_LISP ("shell-file-name", &Vshell_file_name /* | |
892 *File name to load inferior shells from. | |
893 Initialized from the SHELL environment variable. | |
894 */ ); | |
895 | |
896 DEFVAR_LISP ("process-environment", &Vprocess_environment /* | |
897 List of environment variables for subprocesses to inherit. | |
898 Each element should be a string of the form ENVVARNAME=VALUE. | |
899 The environment which Emacs inherits is placed in this variable | |
900 when Emacs starts. | |
901 */ ); | |
902 | |
903 Vlisp_EXEC_SUFFIXES = build_string (EXEC_SUFFIXES); | |
904 staticpro (&Vlisp_EXEC_SUFFIXES); | |
905 } |