Mercurial > emacs
comparison src/w32proc.c @ 21613:fe4f5bfae371
(w32_executable_type): Properly cast dos_header when
making size comparison.
(sys_spawnve): Update comments.
(sys_select): Ignore children dead children with pending input.
Delay sending SIGCHLD until all output has been read.
(sys_kill): Sleep to allow focus change events to propagate.
Use TerminateProcess on Win95.
(int_from_hex, enum_locale_fn, Fw32_get_valid_locale_ids):
New functions.
(Vw32_valid_locale_ids): New variable.
(Fw32_set_current_locale): Send message to input thread.
(syms_of_ntproc): defsubr Sw32_get_valid_locale_ids.
author | Geoff Voelker <voelker@cs.washington.edu> |
---|---|
date | Fri, 17 Apr 1998 05:10:29 +0000 |
parents | bd9b548fd162 |
children | b1c3fe58dbbe |
comparison
equal
deleted
inserted
replaced
21612:24a01af0cd38 | 21613:fe4f5bfae371 |
---|---|
43 #include "w32.h" | 43 #include "w32.h" |
44 #include "w32heap.h" | 44 #include "w32heap.h" |
45 #include "systime.h" | 45 #include "systime.h" |
46 #include "syswait.h" | 46 #include "syswait.h" |
47 #include "process.h" | 47 #include "process.h" |
48 #include "w32term.h" | |
48 | 49 |
49 /* Control whether spawnve quotes arguments as necessary to ensure | 50 /* Control whether spawnve quotes arguments as necessary to ensure |
50 correct parsing by child process. Because not all uses of spawnve | 51 correct parsing by child process. Because not all uses of spawnve |
51 are careful about constructing argv arrays, we make this behaviour | 52 are careful about constructing argv arrays, we make this behaviour |
52 conditional (off by default). */ | 53 conditional (off by default). */ |
604 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) | 605 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) |
605 goto unwind; | 606 goto unwind; |
606 | 607 |
607 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew); | 608 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew); |
608 | 609 |
609 if (nt_header > dos_header + executable.size) | 610 if ((char *) nt_header > (char *) dos_header + executable.size) |
610 { | 611 { |
611 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ | 612 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */ |
612 *is_dos_app = TRUE; | 613 *is_dos_app = TRUE; |
613 } | 614 } |
614 else if (nt_header->Signature != IMAGE_NT_SIGNATURE | 615 else if (nt_header->Signature != IMAGE_NT_SIGNATURE |
734 /* make sure argv[0] and cmdname are both in DOS format */ | 735 /* make sure argv[0] and cmdname are both in DOS format */ |
735 cmdname = XSTRING (program)->data; | 736 cmdname = XSTRING (program)->data; |
736 unixtodos_filename (cmdname); | 737 unixtodos_filename (cmdname); |
737 argv[0] = cmdname; | 738 argv[0] = cmdname; |
738 | 739 |
739 /* Determine whether program is a 16-bit DOS executable, or a Win32 | 740 /* Determine whether program is a 16-bit DOS executable, or a w32 |
740 executable that is implicitly linked to the Cygnus dll (implying it | 741 executable that is implicitly linked to the Cygnus dll (implying it |
741 was compiled with the Cygnus GNU toolchain and hence relies on | 742 was compiled with the Cygnus GNU toolchain and hence relies on |
742 cygwin.dll to parse the command line - we use this to decide how to | 743 cygwin.dll to parse the command line - we use this to decide how to |
743 escape quote chars in command line args that must be quoted). */ | 744 escape quote chars in command line args that must be quoted). */ |
744 w32_executable_type (cmdname, &is_dos_app, &is_cygnus_app); | 745 w32_executable_type (cmdname, &is_dos_app, &is_cygnus_app); |
769 embedded quotes need to be escaped as well. The aim is to ensure | 770 embedded quotes need to be escaped as well. The aim is to ensure |
770 the child process reconstructs the argv array we start with | 771 the child process reconstructs the argv array we start with |
771 exactly, so we treat quotes at the beginning and end of arguments | 772 exactly, so we treat quotes at the beginning and end of arguments |
772 as embedded quotes. | 773 as embedded quotes. |
773 | 774 |
774 The Win32 GNU-based library from Cygnus doubles quotes to escape | 775 The w32 GNU-based library from Cygnus doubles quotes to escape |
775 them, while MSVC uses backslash for escaping. (Actually the MSVC | 776 them, while MSVC uses backslash for escaping. (Actually the MSVC |
776 startup code does attempt to recognise doubled quotes and accept | 777 startup code does attempt to recognise doubled quotes and accept |
777 them, but gets it wrong and ends up requiring three quotes to get a | 778 them, but gets it wrong and ends up requiring three quotes to get a |
778 single embedded quote!) So by default we decide whether to use | 779 single embedded quote!) So by default we decide whether to use |
779 quote or backslash as the escape character based on whether the | 780 quote or backslash as the escape character based on whether the |
1107 #endif | 1108 #endif |
1108 } | 1109 } |
1109 else | 1110 else |
1110 { | 1111 { |
1111 /* Unable to find something to wait on for this fd, skip */ | 1112 /* Unable to find something to wait on for this fd, skip */ |
1113 | |
1114 /* Note that this is not a fatal error, and can in fact | |
1115 happen in unusual circumstances. Specifically, if | |
1116 sys_spawnve fails, eg. because the program doesn't | |
1117 exist, and debug-on-error is t so Fsignal invokes a | |
1118 nested input loop, then the process output pipe is | |
1119 still included in input_wait_mask with no child_proc | |
1120 associated with it. (It is removed when the debugger | |
1121 exits the nested input loop and the error is thrown.) */ | |
1122 | |
1112 DebPrint (("sys_select: fd %ld is invalid! ignoring\n", i)); | 1123 DebPrint (("sys_select: fd %ld is invalid! ignoring\n", i)); |
1113 abort (); | |
1114 } | 1124 } |
1115 } | 1125 } |
1116 } | 1126 } |
1117 | 1127 |
1118 count_children: | 1128 count_children: |
1119 /* Add handles of child processes. */ | 1129 /* Add handles of child processes. */ |
1120 nc = 0; | 1130 nc = 0; |
1121 for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) | 1131 for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--) |
1122 /* some child_procs might be sockets; ignore them */ | 1132 /* Some child_procs might be sockets; ignore them. Also some |
1123 if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess) | 1133 children may have died already, but we haven't finished reading |
1134 the process output; ignore them too. */ | |
1135 if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess | |
1136 && (cp->fd < 0 | |
1137 || (fd_info[cp->fd].flags & FILE_SEND_SIGCHLD) == 0 | |
1138 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0) | |
1139 ) | |
1124 { | 1140 { |
1125 wait_hnd[nh + nc] = cp->procinfo.hProcess; | 1141 wait_hnd[nh + nc] = cp->procinfo.hProcess; |
1126 cps[nc] = cp; | 1142 cps[nc] = cp; |
1127 nc++; | 1143 nc++; |
1128 } | 1144 } |
1174 do | 1190 do |
1175 { | 1191 { |
1176 if (active >= nh) | 1192 if (active >= nh) |
1177 { | 1193 { |
1178 cp = cps[active - nh]; | 1194 cp = cps[active - nh]; |
1195 | |
1196 /* We cannot always signal SIGCHLD immediately; if we have not | |
1197 finished reading the process output, we must delay sending | |
1198 SIGCHLD until we do. */ | |
1199 | |
1200 if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0) | |
1201 fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD; | |
1179 /* SIG_DFL for SIGCHLD is ignore */ | 1202 /* SIG_DFL for SIGCHLD is ignore */ |
1180 if (sig_handlers[SIGCHLD] != SIG_DFL | 1203 else if (sig_handlers[SIGCHLD] != SIG_DFL && |
1181 && sig_handlers[SIGCHLD] != SIG_IGN) | 1204 sig_handlers[SIGCHLD] != SIG_IGN) |
1182 { | 1205 { |
1183 #ifdef FULL_DEBUG | 1206 #ifdef FULL_DEBUG |
1184 DebPrint (("select calling SIGCHLD handler for pid %d\n", | 1207 DebPrint (("select calling SIGCHLD handler for pid %d\n", |
1185 cp->pid)); | 1208 cp->pid)); |
1186 #endif | 1209 #endif |
1312 keybd_event (VK_CONTROL, control_scan_code, 0, 0); | 1335 keybd_event (VK_CONTROL, control_scan_code, 0, 0); |
1313 keybd_event (vk_break_code, break_scan_code, 0, 0); | 1336 keybd_event (vk_break_code, break_scan_code, 0, 0); |
1314 keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0); | 1337 keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0); |
1315 keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0); | 1338 keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0); |
1316 | 1339 |
1340 /* Sleep for a bit to give time for Emacs frame to respond | |
1341 to focus change events (if Emacs was active app). */ | |
1342 Sleep (10); | |
1343 | |
1317 SetForegroundWindow (foreground_window); | 1344 SetForegroundWindow (foreground_window); |
1318 } | 1345 } |
1319 } | 1346 } |
1320 /* Ctrl-Break is NT equivalent of SIGINT. */ | 1347 /* Ctrl-Break is NT equivalent of SIGINT. */ |
1321 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | 1348 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) |
1347 Switch_VM_and_callback). | 1374 Switch_VM_and_callback). |
1348 | 1375 |
1349 Could try to invoke DestroyVM through CallVxD. | 1376 Could try to invoke DestroyVM through CallVxD. |
1350 | 1377 |
1351 */ | 1378 */ |
1379 #if 0 | |
1380 /* On Win95, posting WM_QUIT causes the 16-bit subsystem | |
1381 to hang when cmdproxy is used in conjunction with | |
1382 command.com for an interactive shell. Posting | |
1383 WM_CLOSE pops up a dialog that, when Yes is selected, | |
1384 does the same thing. TerminateProcess is also less | |
1385 than ideal in that subprocesses tend to stick around | |
1386 until the machine is shutdown, but at least it | |
1387 doesn't freeze the 16-bit subsystem. */ | |
1352 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0); | 1388 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0); |
1389 #endif | |
1390 if (!TerminateProcess (proc_hand, 0xff)) | |
1391 { | |
1392 DebPrint (("sys_kill.TerminateProcess returned %d " | |
1393 "for pid %lu\n", GetLastError (), pid)); | |
1394 errno = EINVAL; | |
1395 rc = -1; | |
1396 } | |
1353 } | 1397 } |
1354 else | 1398 else |
1355 #endif | 1399 #endif |
1356 PostMessage (cp->hwnd, WM_CLOSE, 0, 0); | 1400 PostMessage (cp->hwnd, WM_CLOSE, 0, 0); |
1357 } | 1401 } |
1694 () | 1738 () |
1695 { | 1739 { |
1696 return make_number (GetThreadLocale ()); | 1740 return make_number (GetThreadLocale ()); |
1697 } | 1741 } |
1698 | 1742 |
1743 DWORD int_from_hex (char * s) | |
1744 { | |
1745 DWORD val = 0; | |
1746 static char hex[] = "0123456789abcdefABCDEF"; | |
1747 char * p; | |
1748 | |
1749 while (*s && (p = strchr(hex, *s)) != NULL) | |
1750 { | |
1751 unsigned digit = p - hex; | |
1752 if (digit > 15) | |
1753 digit -= 6; | |
1754 val = val * 16 + digit; | |
1755 s++; | |
1756 } | |
1757 return val; | |
1758 } | |
1759 | |
1760 /* We need to build a global list, since the EnumSystemLocale callback | |
1761 function isn't given a context pointer. */ | |
1762 Lisp_Object Vw32_valid_locale_ids; | |
1763 | |
1764 BOOL CALLBACK enum_locale_fn (LPTSTR localeNum) | |
1765 { | |
1766 DWORD id = int_from_hex (localeNum); | |
1767 Vw32_valid_locale_ids = Fcons (make_number (id), Vw32_valid_locale_ids); | |
1768 return TRUE; | |
1769 } | |
1770 | |
1771 DEFUN ("w32-get-valid-locale-ids", Fw32_get_valid_locale_ids, Sw32_get_valid_locale_ids, 0, 0, 0, | |
1772 "Return list of all valid Windows locale ids.\n\ | |
1773 Each id is a numerical value; use `w32-get-locale-info' to convert to a\n\ | |
1774 human-readable form.") | |
1775 () | |
1776 { | |
1777 Vw32_valid_locale_ids = Qnil; | |
1778 | |
1779 EnumSystemLocales (enum_locale_fn, LCID_SUPPORTED); | |
1780 | |
1781 Vw32_valid_locale_ids = Fnreverse (Vw32_valid_locale_ids); | |
1782 return Vw32_valid_locale_ids; | |
1783 } | |
1784 | |
1699 | 1785 |
1700 DEFUN ("w32-get-default-locale-id", Fw32_get_default_locale_id, Sw32_get_default_locale_id, 0, 1, 0, | 1786 DEFUN ("w32-get-default-locale-id", Fw32_get_default_locale_id, Sw32_get_default_locale_id, 0, 1, 0, |
1701 "Return Windows locale id for default locale setting.\n\ | 1787 "Return Windows locale id for default locale setting.\n\ |
1702 By default, the system default locale setting is returned; if the optional\n\ | 1788 By default, the system default locale setting is returned; if the optional\n\ |
1703 parameter USERP is non-nil, the user default locale setting is returned.\n\ | 1789 parameter USERP is non-nil, the user default locale setting is returned.\n\ |
1723 if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED)) | 1809 if (!IsValidLocale (XINT (lcid), LCID_SUPPORTED)) |
1724 return Qnil; | 1810 return Qnil; |
1725 | 1811 |
1726 if (!SetThreadLocale (XINT (lcid))) | 1812 if (!SetThreadLocale (XINT (lcid))) |
1727 return Qnil; | 1813 return Qnil; |
1814 | |
1815 /* Need to set input thread locale if present. */ | |
1816 if (dwWindowsThreadId) | |
1817 /* Reply is not needed. */ | |
1818 PostThreadMessage (dwWindowsThreadId, WM_EMACS_SETLOCALE, XINT (lcid), 0); | |
1728 | 1819 |
1729 return make_number (GetThreadLocale ()); | 1820 return make_number (GetThreadLocale ()); |
1730 } | 1821 } |
1731 | 1822 |
1732 | 1823 |
1743 defsubr (&Sw32_long_file_name); | 1834 defsubr (&Sw32_long_file_name); |
1744 defsubr (&Sw32_set_process_priority); | 1835 defsubr (&Sw32_set_process_priority); |
1745 defsubr (&Sw32_get_locale_info); | 1836 defsubr (&Sw32_get_locale_info); |
1746 defsubr (&Sw32_get_current_locale_id); | 1837 defsubr (&Sw32_get_current_locale_id); |
1747 defsubr (&Sw32_get_default_locale_id); | 1838 defsubr (&Sw32_get_default_locale_id); |
1839 defsubr (&Sw32_get_valid_locale_ids); | |
1748 defsubr (&Sw32_set_current_locale); | 1840 defsubr (&Sw32_set_current_locale); |
1749 | 1841 |
1750 DEFVAR_LISP ("w32-quote-process-args", &Vw32_quote_process_args, | 1842 DEFVAR_LISP ("w32-quote-process-args", &Vw32_quote_process_args, |
1751 "Non-nil enables quoting of process arguments to ensure correct parsing.\n\ | 1843 "Non-nil enables quoting of process arguments to ensure correct parsing.\n\ |
1752 Because Windows does not directly pass argv arrays to child processes,\n\ | 1844 Because Windows does not directly pass argv arrays to child processes,\n\ |