Mercurial > hg > xemacs-beta
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 |