comparison src/process-nt.c @ 408:501cfd01ee6d r21-2-34

Import from CVS: tag r21-2-34
author cvs
date Mon, 13 Aug 2007 11:18:11 +0200
parents b8cc9ab3f761
children de805c49cfc1
comparison
equal deleted inserted replaced
407:ed6218a7d4d3 408:501cfd01ee6d
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ 24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */
25 25
26 #include <config.h> 26 #include <config.h>
27 #include "lisp.h" 27 #include "lisp.h"
28 28
29 #include "buffer.h"
29 #include "console-msw.h" 30 #include "console-msw.h"
30 #include "hash.h" 31 #include "hash.h"
31 #include "lstream.h" 32 #include "lstream.h"
33 #include "nt.h"
32 #include "process.h" 34 #include "process.h"
33 #include "procimpl.h" 35 #include "procimpl.h"
34 #include "sysdep.h" 36 #include "sysdep.h"
35 37
36 #include <shellapi.h> 38 #include <shellapi.h>
43 #endif 45 #endif
44 46
45 /* Arbitrary size limit for code fragments passed to run_in_other_process */ 47 /* Arbitrary size limit for code fragments passed to run_in_other_process */
46 #define FRAGMENT_CODE_SIZE 32 48 #define FRAGMENT_CODE_SIZE 32
47 49
48 /* Bound by winnt.el */
49 Lisp_Object Qnt_quote_process_args;
50
51 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ 50 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */
52 struct nt_process_data 51 struct nt_process_data
53 { 52 {
54 HANDLE h_process; 53 HANDLE h_process;
55 DWORD dwProcessId; 54 DWORD dwProcessId;
56 HWND hwnd; /* console window */ 55 HWND hwnd; /* console window */
57 int need_enable_child_signals; 56 int need_enable_child_signals;
58 }; 57 };
58
59 /* Control how args are quoted to ensure correct parsing by child
60 process. */
61 Lisp_Object Vmswindows_quote_process_args;
59 62
60 /* Control whether create_child causes the process to inherit Emacs' 63 /* Control whether create_child causes the process to inherit Emacs'
61 console window, or be given a new one of its own. The default is 64 console window, or be given a new one of its own. The default is
62 nil, to allow multiple DOS programs to run on Win95. Having separate 65 nil, to allow multiple DOS programs to run on Win95. Having separate
63 consoles also allows Emacs to cleanly terminate process groups. */ 66 consoles also allows Emacs to cleanly terminate process groups. */
674 mswindows_set_errno (err); 677 mswindows_set_errno (err);
675 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); 678 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno));
676 } 679 }
677 680
678 static void 681 static void
679 ensure_console_window_exists () 682 ensure_console_window_exists (void)
680 { 683 {
681 if (msw_windows9x_p ()) 684 if (msw_windows9x_p ())
682 msw_hide_console (); 685 msw_hide_console ();
686 }
687
688 int
689 compare_env (const void *strp1, const void *strp2)
690 {
691 const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2;
692
693 while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
694 {
695 if ((*str1) > (*str2))
696 return 1;
697 else if ((*str1) < (*str2))
698 return -1;
699 str1++, str2++;
700 }
701
702 if (*str1 == '=' && *str2 == '=')
703 return 0;
704 else if (*str1 == '=')
705 return -1;
706 else
707 return 1;
683 } 708 }
684 709
685 static int 710 static int
686 nt_create_process (Lisp_Process *p, 711 nt_create_process (Lisp_Process *p,
687 Lisp_Object *argv, int nargv, 712 Lisp_Object *argv, int nargv,
688 Lisp_Object program, Lisp_Object cur_dir) 713 Lisp_Object program, Lisp_Object cur_dir)
689 { 714 {
715 /* Synched up with sys_spawnve in FSF 20.6. Significantly different
716 but still synchable. */
690 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; 717 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr;
691 LPTSTR command_line; 718 Extbyte *command_line;
692 BOOL do_io, windowed; 719 BOOL do_io, windowed;
693 char *proc_env; 720 char *proc_env;
721
722 /* No need to DOS-ize the filename; expand-file-name (called prior)
723 already does this. */
694 724
695 /* Find out whether the application is windowed or not */ 725 /* Find out whether the application is windowed or not */
696 { 726 {
697 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most 727 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
698 errors. This leads to bogus error message. */ 728 errors. This leads to bogus error message. */
737 767
738 CreatePipe (&hprocin, &hmyshove, &sa, 0); 768 CreatePipe (&hprocin, &hmyshove, &sa, 0);
739 CreatePipe (&hmyslurp, &hprocout, &sa, 0); 769 CreatePipe (&hmyslurp, &hprocout, &sa, 0);
740 770
741 /* Duplicate the stdout handle for use as stderr */ 771 /* Duplicate the stdout handle for use as stderr */
742 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr, 772 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(),
743 0, TRUE, DUPLICATE_SAME_ACCESS); 773 &hprocerr, 0, TRUE, DUPLICATE_SAME_ACCESS);
744 774
745 /* Stupid Win32 allows to create a pipe with *both* ends either 775 /* Stupid Win32 allows to create a pipe with *both* ends either
746 inheritable or not. We need process ends inheritable, and local 776 inheritable or not. We need process ends inheritable, and local
747 ends not inheritable. */ 777 ends not inheritable. */
748 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp, 778 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(),
749 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); 779 &htmp, 0, FALSE,
780 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
750 hmyshove = htmp; 781 hmyshove = htmp;
751 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp, 782 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(),
752 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); 783 &htmp, 0, FALSE,
784 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
753 hmyslurp = htmp; 785 hmyslurp = htmp;
754 } 786 }
755 787
756 /* Convert an argv vector into Win32 style command line by a call to 788 /* Convert an argv vector into Win32 style command line. */
757 lisp function `nt-quote-process-args' which see (in winnt.el)*/
758 { 789 {
759 int i; 790 int i;
760 Lisp_Object args_or_ret = Qnil; 791 Bufbyte **quoted_args;
761 struct gcpro gcpro1; 792 int is_dos_app, is_cygnus_app;
762 793 int do_quoting = 0;
763 GCPRO1 (args_or_ret); 794 char escape_char = 0;
764 795
796 nargv++; /* include program; we access argv offset by 1 below */
797 quoted_args = alloca_array (Bufbyte *, nargv);
798
799 /* Determine whether program is a 16-bit DOS executable, or a Win32
800 executable that is implicitly linked to the Cygnus dll (implying it
801 was compiled with the Cygnus GNU toolchain and hence relies on
802 cygwin.dll to parse the command line - we use this to decide how to
803 escape quote chars in command line args that must be quoted). */
804 mswindows_executable_type (XSTRING_DATA (program),
805 &is_dos_app, &is_cygnus_app);
806
807 #if 0
808 /* #### we need to port this. */
809 /* On Windows 95, if cmdname is a DOS app, we invoke a helper
810 application to start it by specifying the helper app as cmdname,
811 while leaving the real app name as argv[0]. */
812 if (is_dos_app)
813 {
814 cmdname = (char*) alloca (MAXPATHLEN);
815 if (egetenv ("CMDPROXY"))
816 strcpy ((char*)cmdname, egetenv ("CMDPROXY"));
817 else
818 {
819 strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory));
820 strcat ((char*)cmdname, "cmdproxy.exe");
821 }
822 }
823 #endif
824
825 /* we have to do some conjuring here to put argv and envp into the
826 form CreateProcess wants... argv needs to be a space separated/null
827 terminated list of parameters, and envp is a null
828 separated/double-null terminated list of parameters.
829
830 Additionally, zero-length args and args containing whitespace or
831 quote chars need to be wrapped in double quotes - for this to work,
832 embedded quotes need to be escaped as well. The aim is to ensure
833 the child process reconstructs the argv array we start with
834 exactly, so we treat quotes at the beginning and end of arguments
835 as embedded quotes.
836
837 The Win32 GNU-based library from Cygnus doubles quotes to escape
838 them, while MSVC uses backslash for escaping. (Actually the MSVC
839 startup code does attempt to recognize doubled quotes and accept
840 them, but gets it wrong and ends up requiring three quotes to get a
841 single embedded quote!) So by default we decide whether to use
842 quote or backslash as the escape character based on whether the
843 binary is apparently a Cygnus compiled app.
844
845 Note that using backslash to escape embedded quotes requires
846 additional special handling if an embedded quote is already
847 preceded by backslash, or if an arg requiring quoting ends with
848 backslash. In such cases, the run of escape characters needs to be
849 doubled. For consistency, we apply this special handling as long
850 as the escape character is not quote.
851
852 Since we have no idea how large argv and envp are likely to be we
853 figure out list lengths on the fly and allocate them. */
854
855 if (!NILP (Vmswindows_quote_process_args))
856 {
857 do_quoting = 1;
858 /* Override escape char by binding mswindows-quote-process-args to
859 desired character, or use t for auto-selection. */
860 if (INTP (Vmswindows_quote_process_args))
861 escape_char = (char) XINT (Vmswindows_quote_process_args);
862 else
863 escape_char = is_cygnus_app ? '"' : '\\';
864 }
865
866 /* do argv... */
765 for (i = 0; i < nargv; ++i) 867 for (i = 0; i < nargv; ++i)
766 args_or_ret = Fcons (*argv++, args_or_ret); 868 {
767 args_or_ret = Fnreverse (args_or_ret); 869 Bufbyte *targ = XSTRING_DATA (i == 0 ? program : argv[i - 1]);
768 args_or_ret = Fcons (program, args_or_ret); 870 Bufbyte *p = targ;
769 871 int need_quotes = 0;
770 args_or_ret = call1 (Qnt_quote_process_args, args_or_ret); 872 int escape_char_run = 0;
771 873 int arglen = 0;
772 if (!STRINGP (args_or_ret)) 874
773 /* Luser wrote his/her own clever version */ 875 if (*p == 0)
774 error ("Bogus return value from `nt-quote-process-args'"); 876 need_quotes = 1;
775 877 for ( ; *p; p++)
776 command_line = alloca_array (char, (XSTRING_LENGTH (program) 878 {
777 + XSTRING_LENGTH (args_or_ret) + 2)); 879 if (*p == '"')
778 strcpy (command_line, XSTRING_DATA (program)); 880 {
779 strcat (command_line, " "); 881 /* allow for embedded quotes to be escaped */
780 strcat (command_line, XSTRING_DATA (args_or_ret)); 882 arglen++;
781 883 need_quotes = 1;
782 UNGCPRO; /* args_or_ret */ 884 /* handle the case where the embedded quote is already escaped */
885 if (escape_char_run > 0)
886 {
887 /* To preserve the arg exactly, we need to double the
888 preceding escape characters (plus adding one to
889 escape the quote character itself). */
890 arglen += escape_char_run;
891 }
892 }
893 else if (*p == ' ' || *p == '\t')
894 {
895 need_quotes = 1;
896 }
897
898 if (*p == escape_char && escape_char != '"')
899 escape_char_run++;
900 else
901 escape_char_run = 0;
902 }
903 if (need_quotes)
904 {
905 arglen += 2;
906 /* handle the case where the arg ends with an escape char - we
907 must not let the enclosing quote be escaped. */
908 if (escape_char_run > 0)
909 arglen += escape_char_run;
910 }
911 arglen += strlen (targ) + 1;
912
913 quoted_args[i] = alloca_array (Bufbyte, arglen);
914 }
915
916 for (i = 0; i < nargv; ++i)
917 {
918 Bufbyte *targ = XSTRING_DATA (i == 0 ? program : argv[i - 1]);
919 Bufbyte *p = targ;
920 int need_quotes = 0;
921 Bufbyte *parg = quoted_args[i];
922
923 if (*p == 0)
924 need_quotes = 1;
925
926 if (do_quoting)
927 {
928 for ( ; *p; p++)
929 if (*p == ' ' || *p == '\t' || *p == '"')
930 need_quotes = 1;
931 }
932 if (need_quotes)
933 {
934 int escape_char_run = 0;
935 Bufbyte * first;
936 Bufbyte * last;
937
938 p = targ;
939 first = p;
940 last = p + strlen (p) - 1;
941 *parg++ = '"';
942 #if 0
943 /* This version does not escape quotes if they occur at the
944 beginning or end of the arg - this could lead to incorrect
945 behavior when the arg itself represents a command line
946 containing quoted args. I believe this was originally done
947 as a hack to make some things work, before
948 `mswindows-quote-process-args' was added. */
949 while (*p)
950 {
951 if (*p == '"' && p > first && p < last)
952 *parg++ = escape_char; /* escape embedded quotes */
953 *parg++ = *p++;
954 }
955 #else
956 for ( ; *p; p++)
957 {
958 if (*p == '"')
959 {
960 /* double preceding escape chars if any */
961 while (escape_char_run > 0)
962 {
963 *parg++ = escape_char;
964 escape_char_run--;
965 }
966 /* escape all quote chars, even at beginning or end */
967 *parg++ = escape_char;
968 }
969 *parg++ = *p;
970
971 if (*p == escape_char && escape_char != '"')
972 escape_char_run++;
973 else
974 escape_char_run = 0;
975 }
976 /* double escape chars before enclosing quote */
977 while (escape_char_run > 0)
978 {
979 *parg++ = escape_char;
980 escape_char_run--;
981 }
982 #endif
983 *parg++ = '"';
984 }
985 else
986 {
987 strcpy (parg, targ);
988 parg += strlen (targ);
989 }
990 *parg = '\0';
991 }
992
993 {
994 int total_cmdline_len = 0;
995 Extcount *extargcount = (Extcount *) alloca_array (Extcount, nargv);
996 Extbyte **extarg = (Extbyte **) alloca_array (Extbyte *, nargv);
997 Extbyte *command_ptr;
998
999 for (i = 0; i < nargv; ++i)
1000 {
1001 TO_EXTERNAL_FORMAT (C_STRING, quoted_args[i], ALLOCA,
1002 (extarg[i], extargcount[i]), Qmswindows_tstr);
1003 /* account for space and terminating null */
1004 total_cmdline_len += extargcount[i] + EITCHAR_SIZE;
1005 }
1006
1007 command_line = alloca_array (char, total_cmdline_len);
1008 command_ptr = command_line;
1009 for (i = 0; i < nargv; ++i)
1010 {
1011 memcpy (command_ptr, extarg[i], extargcount[i]);
1012 command_ptr += extargcount[i];
1013 EICOPY_TCHAR (command_ptr, ' ');
1014 command_ptr += EITCHAR_SIZE;
1015 }
1016 EICOPY_TCHAR (command_ptr, '\0');
1017 command_ptr += EITCHAR_SIZE;
1018 }
783 } 1019 }
784
785 /* Set `proc_env' to a nul-separated array of the strings in 1020 /* Set `proc_env' to a nul-separated array of the strings in
786 Vprocess_environment terminated by 2 nuls. */ 1021 Vprocess_environment terminated by 2 nuls. */
787 1022
788 { 1023 {
789 extern int compare_env (const char **strp1, const char **strp2);
790 char **env; 1024 char **env;
791 REGISTER Lisp_Object tem; 1025 REGISTER Lisp_Object tem;
792 REGISTER char **new_env; 1026 REGISTER char **new_env;
793 REGISTER int new_length = 0, i, new_space; 1027 REGISTER int new_length = 0, i, new_space;
794 char *penv; 1028 char *penv;
796 for (tem = Vprocess_environment; 1030 for (tem = Vprocess_environment;
797 (CONSP (tem) 1031 (CONSP (tem)
798 && STRINGP (XCAR (tem))); 1032 && STRINGP (XCAR (tem)));
799 tem = XCDR (tem)) 1033 tem = XCDR (tem))
800 new_length++; 1034 new_length++;
1035
1036 /* FSF adds an extra env var to hold the current process ID of the
1037 Emacs process. Apparently this is used only by emacsserver.c,
1038 which we have superseded to gnuserv.c. (#### Does it work under
1039 MS Windows?)
1040
1041 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d",
1042 GetCurrentProcessId ());
1043 arglen += strlen (ppid_env_var_buffer) + 1;
1044 numenv++;
1045 */
801 1046
802 /* new_length + 1 to include terminating 0. */ 1047 /* new_length + 1 to include terminating 0. */
803 env = new_env = alloca_array (char *, new_length + 1); 1048 env = new_env = alloca_array (char *, new_length + 1);
804 1049
805 /* Copy the Vprocess_environment strings into new_env. */ 1050 /* Copy the Vprocess_environment strings into new_env. */
1080 if (!send_signal (NT_DATA (p), 0, signo)) 1325 if (!send_signal (NT_DATA (p), 0, signo))
1081 signal_simple_error ("Cannot send signal to process", proc); 1326 signal_simple_error ("Cannot send signal to process", proc);
1082 } 1327 }
1083 1328
1084 /* 1329 /*
1085 * Kill any process in the system given its PID. 1330 * Kill any process in the system given its PID
1086 * 1331 *
1087 * Returns zero if a signal successfully sent, or 1332 * Returns zero if a signal successfully sent, or
1088 * negative number upon failure 1333 * negative number upon failure
1089 */ 1334 */
1090 static int 1335 static int
1337 } 1582 }
1338 1583
1339 void 1584 void
1340 syms_of_process_nt (void) 1585 syms_of_process_nt (void)
1341 { 1586 {
1342 defsymbol (&Qnt_quote_process_args, "nt-quote-process-args");
1343 } 1587 }
1344 1588
1345 void 1589 void
1346 vars_of_process_nt (void) 1590 vars_of_process_nt (void)
1347 { 1591 {
1592 DEFVAR_LISP ("mswindows-quote-process-args",
1593 &Vmswindows_quote_process_args /*
1594 Non-nil enables quoting of process arguments to ensure correct parsing.
1595 Because Windows does not directly pass argv arrays to child processes,
1596 programs have to reconstruct the argv array by parsing the command
1597 line string. For an argument to contain a space, it must be enclosed
1598 in double quotes or it will be parsed as multiple arguments.
1599
1600 If the value is a character, that character will be used to escape any
1601 quote characters that appear, otherwise a suitable escape character
1602 will be chosen based on the type of the program (normal or Cygwin).
1603 */ );
1604 Vmswindows_quote_process_args = Qt;
1605
1348 DEFVAR_LISP ("mswindows-start-process-share-console", 1606 DEFVAR_LISP ("mswindows-start-process-share-console",
1349 &Vmswindows_start_process_share_console /* 1607 &Vmswindows_start_process_share_console /*
1350 When nil, new child processes are given a new console. 1608 When nil, new child processes are given a new console.
1351 When non-nil, they share the Emacs console; this has the limitation of 1609 When non-nil, they share the Emacs console; this has the limitation of
1352 allowing only only DOS subprocess to run at a time (whether started directly 1610 allowing only only DOS subprocess to run at a time (whether started directly