This source file includes following definitions.
- malloc_before_init
- realloc_before_init
- free_before_init
- _start
- sys_signal
- sigaction
- sigemptyset
- sigaddset
- sigfillset
- sigprocmask
- pthread_sigmask
- sigismember
- w32_raise
- getpgrp
- tcgetpgrp
- setpgid
- setsid
- w32_get_timer_time
- timer_loop
- stop_timer_thread
- term_timers
- init_timers
- start_timer_thread
- getitimer
- setitimer
- alarm
- new_child
- delete_child
- find_child_pid
- release_listen_threads
- reader_thread
- create_child
- register_child
- reap_subprocess
- waitpid
- open_input_file
- rva_to_section
- close_file_data
- w32_executable_type
- compare_env
- merge_and_sort_env
- sys_spawnve
- sys_select
- find_child_console
- sys_kill
- prepare_standard_handles
- reset_standard_handles
- set_process_dir
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- nl_langinfo
- DEFUN
- int_from_hex
- enum_locale_fn
- DEFUN
- DEFUN
- DEFUN
- enum_codepage_fn
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- get_lcid_callback
- get_lcid
- w32_compare_strings
- syms_of_ntproc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #define DEFER_MS_W32_H
26 #include <config.h>
27
28 #include <mingw_time.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <io.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <signal.h>
37 #include <sys/file.h>
38 #include <mbstring.h>
39 #include <locale.h>
40
41
42 #include <ms-w32.h>
43
44 #undef signal
45 #undef wait
46 #undef spawnve
47 #undef select
48 #undef kill
49
50 #include <windows.h>
51
52 #ifdef HAVE_LANGINFO_CODESET
53 #include <nl_types.h>
54 #include <langinfo.h>
55 #endif
56
57 #include "lisp.h"
58 #include "w32.h"
59 #include "w32common.h"
60 #include "w32heap.h"
61 #include "syswait.h"
62 #include "syssignal.h"
63 #include "w32term.h"
64 #include "coding.h"
65
66 void w32_raise (int);
67
68 #define RVA_TO_PTR(var,section,filedata) \
69 ((void *)((section)->PointerToRawData \
70 + ((DWORD_PTR)(var) - (section)->VirtualAddress) \
71 + (filedata).file_base))
72
73 extern BOOL g_b_init_compare_string_w;
74 extern BOOL g_b_init_debug_break_process;
75
76 int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
77 const struct timespec *, const sigset_t *);
78
79
80 static signal_handler sig_handlers[NSIG];
81
82 static sigset_t sig_mask;
83
84 static CRITICAL_SECTION crit_sig;
85
86
87
88
89 _Noreturn void * malloc_before_init (size_t);
90 _Noreturn void * realloc_before_init (void *, size_t);
91 _Noreturn void free_before_init (void *);
92
93 _Noreturn void *
94 malloc_before_init (size_t size)
95 {
96 fprintf (stderr,
97 "error: 'malloc' called before setting up heap allocation; exiting.\n");
98 exit (-1);
99 }
100
101 _Noreturn void *
102 realloc_before_init (void *ptr, size_t size)
103 {
104 fprintf (stderr,
105 "error: 'realloc' called before setting up heap allocation; exiting.\n");
106 exit (-1);
107 }
108
109 _Noreturn void
110 free_before_init (void *ptr)
111 {
112 fprintf (stderr,
113 "error: 'free' called before setting up heap allocation; exiting.\n");
114 exit (-1);
115 }
116
117 extern BOOL ctrl_c_handler (unsigned long type);
118
119
120
121
122 #ifdef __MINGW64__
123 #define _start __start
124 #endif
125
126 extern void mainCRTStartup (void);
127
128
129
130
131
132 void _start (void);
133
134 void
135 _start (void)
136 {
137
138 #if 1
139
140
141 if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
142 DebugBreak ();
143 #endif
144
145 the_malloc_fn = malloc_before_init;
146 the_realloc_fn = realloc_before_init;
147 the_free_fn = free_before_init;
148
149
150 cache_system_info ();
151
152
153
154 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE);
155
156
157
158 SetErrorMode (SEM_FAILCRITICALERRORS);
159 mainCRTStartup ();
160 }
161
162
163
164 signal_handler
165 sys_signal (int sig, signal_handler handler)
166 {
167 signal_handler old;
168
169
170
171
172 if (!(sig == SIGINT || sig == SIGSEGV || sig == SIGILL
173 || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM
174 || sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF))
175 {
176 errno = EINVAL;
177 return SIG_ERR;
178 }
179 old = sig_handlers[sig];
180
181
182
183
184
185 if (!(sig == SIGABRT && old == term_ntproc))
186 {
187 sig_handlers[sig] = handler;
188 if (!(sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF))
189 signal (sig, handler);
190 }
191 return old;
192 }
193
194
195 int
196 sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
197 {
198 signal_handler old = SIG_DFL;
199 int retval = 0;
200
201 if (act)
202 old = sys_signal (sig, act->sa_handler);
203 else if (oact)
204 old = sig_handlers[sig];
205
206 if (old == SIG_ERR)
207 {
208 errno = EINVAL;
209 retval = -1;
210 }
211 if (oact)
212 {
213 oact->sa_handler = old;
214 oact->sa_flags = 0;
215 oact->sa_mask = empty_mask;
216 }
217 return retval;
218 }
219
220
221
222 int
223 sigemptyset (sigset_t *set)
224 {
225 *set = 0;
226 return 0;
227 }
228
229 int
230 sigaddset (sigset_t *set, int signo)
231 {
232 if (!set)
233 {
234 errno = EINVAL;
235 return -1;
236 }
237 if (signo < 0 || signo >= NSIG)
238 {
239 errno = EINVAL;
240 return -1;
241 }
242
243 *set |= (1U << signo);
244
245 return 0;
246 }
247
248 int
249 sigfillset (sigset_t *set)
250 {
251 if (!set)
252 {
253 errno = EINVAL;
254 return -1;
255 }
256
257 *set = 0xFFFFFFFF;
258 return 0;
259 }
260
261 int
262 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
263 {
264 if (!(how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK))
265 {
266 errno = EINVAL;
267 return -1;
268 }
269
270 if (oset)
271 *oset = sig_mask;
272
273 if (!set)
274 return 0;
275
276 switch (how)
277 {
278 case SIG_BLOCK:
279 sig_mask |= *set;
280 break;
281 case SIG_SETMASK:
282 sig_mask = *set;
283 break;
284 case SIG_UNBLOCK:
285
286
287 sig_mask &= ~(*set);
288 break;
289 }
290
291 return 0;
292 }
293
294 int
295 pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
296 {
297 if (sigprocmask (how, set, oset) == -1)
298 return EINVAL;
299 return 0;
300 }
301
302 int
303 sigismember (const sigset_t *set, int signo)
304 {
305 if (signo < 0 || signo >= NSIG)
306 {
307 errno = EINVAL;
308 return -1;
309 }
310 if (signo > sizeof (*set) * CHAR_BIT)
311 emacs_abort ();
312
313 return (*set & (1U << signo)) != 0;
314 }
315
316
317
318 void
319 w32_raise (int signo)
320 {
321 if (!(signo == SIGCHLD || signo == SIGALRM || signo == SIGPROF))
322 raise (signo);
323
324
325
326 signal_handler handler = sig_handlers[signo];
327 if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR))
328 handler (signo);
329 }
330
331 pid_t
332 getpgrp (void)
333 {
334 return getpid ();
335 }
336
337 pid_t
338 tcgetpgrp (int fd)
339 {
340 return getpid ();
341 }
342
343 int
344 setpgid (pid_t pid, pid_t pgid)
345 {
346 return 0;
347 }
348
349 pid_t
350 setsid (void)
351 {
352 return getpid ();
353 }
354
355
356
357
358
359
360
361
362
363 struct itimer_data {
364 volatile ULONGLONG expire;
365 volatile ULONGLONG reload;
366 volatile int terminate;
367 int type;
368 HANDLE caller_thread;
369 HANDLE timer_thread;
370 };
371
372 static ULONGLONG ticks_now;
373 static struct itimer_data real_itimer, prof_itimer;
374 static ULONGLONG clocks_min;
375
376
377 static int disable_itimers;
378
379 static CRITICAL_SECTION crit_real, crit_prof;
380
381
382 typedef BOOL (WINAPI *GetThreadTimes_Proc) (
383 HANDLE hThread,
384 LPFILETIME lpCreationTime,
385 LPFILETIME lpExitTime,
386 LPFILETIME lpKernelTime,
387 LPFILETIME lpUserTime);
388
389 static GetThreadTimes_Proc s_pfn_Get_Thread_Times;
390
391 #define MAX_SINGLE_SLEEP 30
392 #define TIMER_TICKS_PER_SEC 1000
393
394
395
396
397
398
399 static ULONGLONG
400 w32_get_timer_time (HANDLE thread)
401 {
402 ULONGLONG retval;
403 int use_system_time = 1;
404
405 const int tscale = 10 * TIMER_TICKS_PER_SEC;
406
407 if (thread && thread != INVALID_HANDLE_VALUE
408 && s_pfn_Get_Thread_Times != NULL)
409 {
410 FILETIME creation_ftime, exit_ftime, kernel_ftime, user_ftime;
411 ULARGE_INTEGER temp_creation, temp_kernel, temp_user;
412
413 if (s_pfn_Get_Thread_Times (thread, &creation_ftime, &exit_ftime,
414 &kernel_ftime, &user_ftime))
415 {
416 use_system_time = 0;
417 temp_creation.LowPart = creation_ftime.dwLowDateTime;
418 temp_creation.HighPart = creation_ftime.dwHighDateTime;
419 temp_kernel.LowPart = kernel_ftime.dwLowDateTime;
420 temp_kernel.HighPart = kernel_ftime.dwHighDateTime;
421 temp_user.LowPart = user_ftime.dwLowDateTime;
422 temp_user.HighPart = user_ftime.dwHighDateTime;
423 retval =
424 temp_creation.QuadPart / tscale + temp_kernel.QuadPart / tscale
425 + temp_user.QuadPart / tscale;
426 }
427 else
428 DebPrint (("GetThreadTimes failed with error code %lu\n",
429 GetLastError ()));
430 }
431
432 if (use_system_time)
433 {
434 FILETIME current_ftime;
435 ULARGE_INTEGER temp;
436
437 GetSystemTimeAsFileTime (¤t_ftime);
438
439 temp.LowPart = current_ftime.dwLowDateTime;
440 temp.HighPart = current_ftime.dwHighDateTime;
441
442 retval = temp.QuadPart / tscale;
443 }
444
445 return retval;
446 }
447
448
449 static DWORD WINAPI
450 timer_loop (LPVOID arg)
451 {
452 struct itimer_data *itimer = (struct itimer_data *)arg;
453 int which = itimer->type;
454 int sig = (which == ITIMER_REAL) ? SIGALRM : SIGPROF;
455 CRITICAL_SECTION *crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
456 const DWORD max_sleep = MAX_SINGLE_SLEEP * 1000 / TIMER_TICKS_PER_SEC;
457 HANDLE hth = (which == ITIMER_REAL) ? NULL : itimer->caller_thread;
458
459 while (1)
460 {
461 DWORD sleep_time;
462 signal_handler handler;
463 ULONGLONG now, expire, reload;
464
465
466 EnterCriticalSection (crit);
467 expire = itimer->expire;
468 reload = itimer->reload;
469 LeaveCriticalSection (crit);
470 if (itimer->terminate)
471 return 0;
472
473 if (expire == 0)
474 {
475
476 Sleep (max_sleep);
477 continue;
478 }
479
480 if (expire > (now = w32_get_timer_time (hth)))
481 sleep_time = expire - now;
482 else
483 sleep_time = 0;
484
485
486 while (sleep_time > max_sleep)
487 {
488 if (itimer->terminate)
489 return 0;
490 Sleep (max_sleep);
491 EnterCriticalSection (crit);
492 expire = itimer->expire;
493 LeaveCriticalSection (crit);
494 sleep_time =
495 (expire > (now = w32_get_timer_time (hth))) ? expire - now : 0;
496 }
497 if (itimer->terminate)
498 return 0;
499 if (sleep_time > 0)
500 {
501 Sleep (sleep_time * 1000 / TIMER_TICKS_PER_SEC);
502
503
504
505
506
507 while (w32_get_timer_time (hth) < expire)
508 Sleep (5);
509 }
510
511 EnterCriticalSection (crit);
512 expire = itimer->expire;
513 LeaveCriticalSection (crit);
514 if (expire == 0)
515 continue;
516
517
518 handler = sig_handlers[sig];
519 if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR)
520
521
522
523 && !sigismember (&sig_mask, sig)
524
525
526 && !fatal_error_in_progress
527 && itimer->caller_thread)
528 {
529
530
531
532 HANDLE th = itimer->caller_thread;
533 DWORD result = SuspendThread (th);
534
535 if (result == (DWORD)-1)
536 return 2;
537
538 handler (sig);
539 ResumeThread (th);
540 }
541
542
543 EnterCriticalSection (crit);
544 expire = itimer->expire;
545 if (expire == 0)
546 {
547 LeaveCriticalSection (crit);
548 continue;
549 }
550 reload = itimer->reload;
551 if (reload > 0)
552 {
553 now = w32_get_timer_time (hth);
554 if (expire <= now)
555 {
556 ULONGLONG lag = now - expire;
557
558
559
560
561 if (lag > reload)
562 expire = now - (lag % reload);
563
564 expire += reload;
565 }
566 }
567 else
568 expire = 0;
569 itimer->expire = expire;
570 LeaveCriticalSection (crit);
571 }
572 return 0;
573 }
574
575 static void
576 stop_timer_thread (int which)
577 {
578 struct itimer_data *itimer =
579 (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
580 int i;
581 DWORD err = 0, exit_code = 255;
582 BOOL status;
583
584
585 itimer->terminate = 1;
586
587 if (itimer->timer_thread == NULL)
588 return;
589
590
591
592
593 for (i = 0; i < MAX_SINGLE_SLEEP / 5; i++)
594 {
595 if (!((status = GetExitCodeThread (itimer->timer_thread, &exit_code))
596 && exit_code == STILL_ACTIVE))
597 break;
598 Sleep (10);
599 }
600 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
601 || exit_code == STILL_ACTIVE)
602 {
603 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
604 TerminateThread (itimer->timer_thread, 0);
605 }
606
607
608 CloseHandle (itimer->timer_thread);
609 itimer->timer_thread = NULL;
610 if (itimer->caller_thread)
611 {
612 CloseHandle (itimer->caller_thread);
613 itimer->caller_thread = NULL;
614 }
615 }
616
617
618 void
619 term_timers (void)
620 {
621 if (real_itimer.timer_thread)
622 stop_timer_thread (ITIMER_REAL);
623 if (prof_itimer.timer_thread)
624 stop_timer_thread (ITIMER_PROF);
625
626
627
628 disable_itimers = 1;
629
630 DeleteCriticalSection (&crit_real);
631 DeleteCriticalSection (&crit_prof);
632 DeleteCriticalSection (&crit_sig);
633 }
634
635
636 void
637 init_timers (void)
638 {
639
640
641
642 s_pfn_Get_Thread_Times = NULL;
643 if (os_subtype != OS_SUBTYPE_9X)
644 s_pfn_Get_Thread_Times = (GetThreadTimes_Proc)
645 get_proc_addr (GetModuleHandle ("kernel32.dll"), "GetThreadTimes");
646
647
648
649 memset (&real_itimer, 0, sizeof real_itimer);
650 memset (&prof_itimer, 0, sizeof prof_itimer);
651
652 InitializeCriticalSection (&crit_real);
653 InitializeCriticalSection (&crit_prof);
654 InitializeCriticalSection (&crit_sig);
655
656 disable_itimers = 0;
657 }
658
659 static int
660 start_timer_thread (int which)
661 {
662 DWORD exit_code, tid;
663 HANDLE th;
664 struct itimer_data *itimer =
665 (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
666
667 if (itimer->timer_thread
668 && GetExitCodeThread (itimer->timer_thread, &exit_code)
669 && exit_code == STILL_ACTIVE)
670 return 0;
671
672
673 if (itimer->timer_thread)
674 {
675 CloseHandle (itimer->timer_thread);
676 itimer->timer_thread = NULL;
677 }
678 if (itimer->caller_thread)
679 {
680 CloseHandle (itimer->caller_thread);
681 itimer->caller_thread = NULL;
682 }
683
684
685 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
686 GetCurrentProcess (), &th, 0, FALSE,
687 DUPLICATE_SAME_ACCESS))
688 {
689 errno = ESRCH;
690 return -1;
691 }
692 itimer->terminate = 0;
693 itimer->type = which;
694 itimer->caller_thread = th;
695
696
697
698
699 itimer->timer_thread = CreateThread (NULL, 64 * 1024, timer_loop,
700 (void *)itimer, 0x00010000, &tid);
701
702 if (!itimer->timer_thread)
703 {
704 CloseHandle (itimer->caller_thread);
705 itimer->caller_thread = NULL;
706 errno = EAGAIN;
707 return -1;
708 }
709
710
711
712 if (which == ITIMER_PROF)
713 SetThreadPriority (itimer->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
714
715 return 0;
716 }
717
718
719
720
721 int
722 getitimer (int which, struct itimerval *value)
723 {
724 volatile ULONGLONG *t_expire;
725 volatile ULONGLONG *t_reload;
726 ULONGLONG expire, reload;
727 __int64 usecs;
728 CRITICAL_SECTION *crit;
729 struct itimer_data *itimer;
730
731 if (disable_itimers)
732 return -1;
733
734 if (!value)
735 {
736 errno = EFAULT;
737 return -1;
738 }
739
740 if (which != ITIMER_REAL && which != ITIMER_PROF)
741 {
742 errno = EINVAL;
743 return -1;
744 }
745
746 itimer = (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
747
748 ticks_now = w32_get_timer_time ((which == ITIMER_REAL)
749 ? NULL
750 : GetCurrentThread ());
751
752 t_expire = &itimer->expire;
753 t_reload = &itimer->reload;
754 crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
755
756 EnterCriticalSection (crit);
757 reload = *t_reload;
758 expire = *t_expire;
759 LeaveCriticalSection (crit);
760
761 if (expire)
762 expire -= ticks_now;
763
764 value->it_value.tv_sec = expire / TIMER_TICKS_PER_SEC;
765 usecs =
766 (expire % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC;
767 value->it_value.tv_usec = usecs;
768 value->it_interval.tv_sec = reload / TIMER_TICKS_PER_SEC;
769 usecs =
770 (reload % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC;
771 value->it_interval.tv_usec= usecs;
772
773 return 0;
774 }
775
776 int
777 setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
778 {
779 volatile ULONGLONG *t_expire, *t_reload;
780 ULONGLONG expire, reload, expire_old, reload_old;
781 __int64 usecs;
782 CRITICAL_SECTION *crit;
783 struct itimerval tem, *ptem;
784
785 if (disable_itimers)
786 return -1;
787
788
789
790
791 if (!clocks_min)
792 {
793 ULONGLONG t1, t2;
794
795 for (t1 = w32_get_timer_time (NULL);
796 (t2 = w32_get_timer_time (NULL)) == t1; )
797 ;
798 clocks_min = t2 - t1;
799 }
800
801 if (ovalue)
802 ptem = ovalue;
803 else
804 ptem = &tem;
805
806 if (getitimer (which, ptem))
807 return -1;
808
809 t_expire =
810 (which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire;
811 t_reload =
812 (which == ITIMER_REAL) ? &real_itimer.reload : &prof_itimer.reload;
813
814 crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
815
816 if (!value
817 || (value->it_value.tv_sec == 0 && value->it_value.tv_usec == 0))
818 {
819 EnterCriticalSection (crit);
820
821 *t_expire = 0;
822 *t_reload = 0;
823 LeaveCriticalSection (crit);
824 return 0;
825 }
826
827 reload = value->it_interval.tv_sec * TIMER_TICKS_PER_SEC;
828
829 usecs = value->it_interval.tv_usec;
830 if (value->it_interval.tv_sec == 0
831 && usecs && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
832 reload = clocks_min;
833 else
834 {
835 usecs *= TIMER_TICKS_PER_SEC;
836 reload += usecs / 1000000;
837 }
838
839 expire = value->it_value.tv_sec * TIMER_TICKS_PER_SEC;
840 usecs = value->it_value.tv_usec;
841 if (value->it_value.tv_sec == 0
842 && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
843 expire = clocks_min;
844 else
845 {
846 usecs *= TIMER_TICKS_PER_SEC;
847 expire += usecs / 1000000;
848 }
849
850 expire += ticks_now;
851
852 EnterCriticalSection (crit);
853 expire_old = *t_expire;
854 reload_old = *t_reload;
855 if (!(expire == expire_old && reload == reload_old))
856 {
857 *t_reload = reload;
858 *t_expire = expire;
859 }
860 LeaveCriticalSection (crit);
861
862 return start_timer_thread (which);
863 }
864
865 int
866 alarm (int seconds)
867 {
868 #ifdef HAVE_SETITIMER
869 struct itimerval new_values, old_values;
870
871 new_values.it_value.tv_sec = seconds;
872 new_values.it_value.tv_usec = 0;
873 new_values.it_interval.tv_sec = new_values.it_interval.tv_usec = 0;
874
875 if (setitimer (ITIMER_REAL, &new_values, &old_values) < 0)
876 return 0;
877 return old_values.it_value.tv_sec;
878 #else
879 return seconds;
880 #endif
881 }
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 #define _P_NOWAIT 1
1017
1018
1019 int child_proc_count = 0;
1020 child_process child_procs[ MAX_CHILDREN ];
1021
1022 static DWORD WINAPI reader_thread (void *arg);
1023
1024
1025 child_process *
1026 new_child (void)
1027 {
1028 child_process *cp;
1029 DWORD id;
1030
1031 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1032 if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
1033 goto Initialize;
1034 if (child_proc_count == MAX_CHILDREN)
1035 {
1036 int i = 0;
1037 child_process *dead_cp = NULL;
1038
1039 DebPrint (("new_child: No vacant slots, looking for dead processes\n"));
1040 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1041 if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess)
1042 {
1043 DWORD status = 0;
1044
1045 if (!GetExitCodeProcess (cp->procinfo.hProcess, &status))
1046 {
1047 DebPrint (("new_child.GetExitCodeProcess: error %lu for PID %lu\n",
1048 GetLastError (), cp->procinfo.dwProcessId));
1049 status = STILL_ACTIVE;
1050 }
1051 if (status != STILL_ACTIVE
1052 || WaitForSingleObject (cp->procinfo.hProcess, 0) == WAIT_OBJECT_0)
1053 {
1054 DebPrint (("new_child: Freeing slot of dead process %d, fd %d\n",
1055 cp->procinfo.dwProcessId, cp->fd));
1056 CloseHandle (cp->procinfo.hProcess);
1057 cp->procinfo.hProcess = NULL;
1058 CloseHandle (cp->procinfo.hThread);
1059 cp->procinfo.hThread = NULL;
1060
1061
1062
1063 if (i == 0)
1064 dead_cp = cp;
1065 else
1066 break;
1067 i++;
1068 }
1069 }
1070 if (dead_cp)
1071 {
1072 cp = dead_cp;
1073 goto Initialize;
1074 }
1075 }
1076 if (child_proc_count == MAX_CHILDREN)
1077 return NULL;
1078 cp = &child_procs[child_proc_count++];
1079
1080 Initialize:
1081
1082
1083 if (cp->procinfo.hProcess)
1084 CloseHandle (cp->procinfo.hProcess);
1085 if (cp->procinfo.hThread)
1086 CloseHandle (cp->procinfo.hThread);
1087 memset (cp, 0, sizeof (*cp));
1088 cp->fd = -1;
1089 cp->pid = -1;
1090 cp->procinfo.hProcess = NULL;
1091 cp->status = STATUS_READ_ERROR;
1092
1093
1094 cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
1095 if (cp->char_avail)
1096 {
1097 cp->char_consumed = CreateEvent (NULL, FALSE, FALSE, NULL);
1098 if (cp->char_consumed)
1099 {
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 cp->thrd = CreateThread (NULL, 64 * 1024, reader_thread, cp,
1118 0x00010000, &id);
1119 if (cp->thrd)
1120 return cp;
1121 }
1122 }
1123 delete_child (cp);
1124 return NULL;
1125 }
1126
1127 void
1128 delete_child (child_process *cp)
1129 {
1130 int i;
1131
1132
1133 for (i = 0; i < MAXDESC; i++)
1134 if (fd_info[i].cp == cp)
1135 emacs_abort ();
1136
1137 if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
1138 return;
1139
1140
1141 if (cp->thrd)
1142 {
1143 DWORD rc;
1144
1145 if (GetExitCodeThread (cp->thrd, &rc) && rc == STILL_ACTIVE)
1146 {
1147
1148 cp->status = STATUS_READ_ERROR;
1149 SetEvent (cp->char_consumed);
1150 #if 0
1151
1152
1153
1154
1155 if (WaitForSingleObject (cp->thrd, 1000) != WAIT_OBJECT_0)
1156 {
1157 DebPrint (("delete_child.WaitForSingleObject (thread) failed "
1158 "with %lu for fd %ld\n", GetLastError (), cp->fd));
1159 TerminateThread (cp->thrd, 0);
1160 }
1161 #endif
1162 }
1163 CloseHandle (cp->thrd);
1164 cp->thrd = NULL;
1165 }
1166 if (cp->char_avail)
1167 {
1168 CloseHandle (cp->char_avail);
1169 cp->char_avail = NULL;
1170 }
1171 if (cp->char_consumed)
1172 {
1173 CloseHandle (cp->char_consumed);
1174 cp->char_consumed = NULL;
1175 }
1176
1177
1178 if (cp == child_procs + child_proc_count - 1)
1179 {
1180 for (i = child_proc_count-1; i >= 0; i--)
1181 if (CHILD_ACTIVE (&child_procs[i])
1182 || child_procs[i].procinfo.hProcess != NULL)
1183 {
1184 child_proc_count = i + 1;
1185 break;
1186 }
1187 }
1188 if (i < 0)
1189 child_proc_count = 0;
1190 }
1191
1192
1193 static child_process *
1194 find_child_pid (DWORD pid)
1195 {
1196 child_process *cp;
1197
1198 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1199 if ((CHILD_ACTIVE (cp) || cp->procinfo.hProcess != NULL)
1200 && pid == cp->pid)
1201 return cp;
1202 return NULL;
1203 }
1204
1205 void
1206 release_listen_threads (void)
1207 {
1208 int i;
1209
1210 for (i = child_proc_count - 1; i >= 0; i--)
1211 {
1212 if (CHILD_ACTIVE (&child_procs[i])
1213 && (fd_info[child_procs[i].fd].flags & FILE_LISTEN))
1214 child_procs[i].status = STATUS_READ_ERROR;
1215 }
1216 }
1217
1218
1219
1220
1221
1222 static DWORD WINAPI
1223 reader_thread (void *arg)
1224 {
1225 child_process *cp;
1226 int fd;
1227
1228
1229 cp = (child_process *)arg;
1230
1231
1232 if (cp == NULL
1233 || WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0
1234 || cp->fd < 0)
1235 return 1;
1236
1237 for (;;)
1238 {
1239 int rc;
1240
1241 fd = cp->fd;
1242 if (fd >= 0 && (fd_info[fd].flags & FILE_CONNECT) != 0)
1243 rc = _sys_wait_connect (fd);
1244 else if (fd >= 0 && (fd_info[fd].flags & FILE_LISTEN) != 0)
1245 rc = _sys_wait_accept (fd);
1246 else
1247 rc = _sys_read_ahead (fd);
1248
1249
1250
1251 if (cp->status == STATUS_READ_ERROR || !cp->char_avail)
1252 break;
1253
1254
1255
1256 if (!SetEvent (cp->char_avail))
1257 {
1258 DebPrint (("reader_thread.SetEvent(0x%x) failed with %lu for fd %ld (PID %d)\n",
1259 (DWORD_PTR)cp->char_avail, GetLastError (),
1260 fd, cp->pid));
1261 return 1;
1262 }
1263
1264 if (rc == STATUS_READ_ERROR || rc == STATUS_CONNECT_FAILED)
1265 return 2;
1266
1267
1268 if (rc == STATUS_READ_FAILED)
1269 break;
1270
1271
1272
1273 if (cp->status == STATUS_READ_ERROR || !cp->char_consumed)
1274 break;
1275
1276
1277 if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
1278 {
1279 DebPrint (("reader_thread.WaitForSingleObject failed with "
1280 "%lu for fd %ld\n", GetLastError (), cp->fd));
1281 break;
1282 }
1283
1284
1285 if (cp->status == STATUS_READ_ERROR)
1286 break;
1287 }
1288
1289
1290 if ((fd_info[fd].flags & FILE_DONT_CLOSE) == FILE_DONT_CLOSE)
1291 {
1292 int i;
1293
1294
1295 for (i = 0; i < 5; i++)
1296 {
1297 if (fd_info[fd].flags == FILE_DONT_CLOSE)
1298 {
1299 fd_info[fd].flags = 0;
1300 _close (fd);
1301 break;
1302 }
1303 Sleep (5);
1304 }
1305 }
1306 return 0;
1307 }
1308
1309
1310
1311
1312
1313 static char * process_dir;
1314
1315 static BOOL
1316 create_child (char *exe, char *cmdline, char *env, int is_gui_app,
1317 pid_t * pPid, child_process *cp)
1318 {
1319 STARTUPINFO start;
1320 SECURITY_ATTRIBUTES sec_attrs;
1321 #if 0
1322 SECURITY_DESCRIPTOR sec_desc;
1323 #endif
1324 DWORD flags;
1325 char dir[ MAX_PATH ];
1326 char *p;
1327 const char *ext;
1328
1329 if (cp == NULL) emacs_abort ();
1330
1331 memset (&start, 0, sizeof (start));
1332 start.cb = sizeof (start);
1333
1334 #ifdef HAVE_NTGUI
1335 if (NILP (Vw32_start_process_show_window) && !is_gui_app)
1336 start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1337 else
1338 start.dwFlags = STARTF_USESTDHANDLES;
1339 start.wShowWindow = SW_HIDE;
1340
1341 start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
1342 start.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
1343 start.hStdError = GetStdHandle (STD_ERROR_HANDLE);
1344 #endif
1345
1346 #if 0
1347
1348 if (!InitializeSecurityDescriptor (&sec_desc, SECURITY_DESCRIPTOR_REVISION))
1349 goto EH_Fail;
1350 if (!SetSecurityDescriptorDacl (&sec_desc, TRUE, NULL, FALSE))
1351 goto EH_Fail;
1352 #endif
1353 sec_attrs.nLength = sizeof (sec_attrs);
1354 sec_attrs.lpSecurityDescriptor = NULL ;
1355 sec_attrs.bInheritHandle = FALSE;
1356
1357 filename_to_ansi (process_dir, dir);
1358
1359
1360
1361
1362 for (p = dir; *p; p = CharNextA (p))
1363 if (*p == '/')
1364 *p = '\\';
1365
1366
1367
1368
1369 if (exe && cmdline[0] == '"' &&
1370 (ext = strrchr (exe, '.')) &&
1371 (xstrcasecmp (ext, ".bat") == 0
1372 || xstrcasecmp (ext, ".cmd") == 0))
1373 exe = NULL;
1374
1375 flags = (!NILP (Vw32_start_process_share_console)
1376 ? CREATE_NEW_PROCESS_GROUP
1377 : CREATE_NEW_CONSOLE);
1378 if (NILP (Vw32_start_process_inherit_error_mode))
1379 flags |= CREATE_DEFAULT_ERROR_MODE;
1380 if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
1381 flags, env, dir, &start, &cp->procinfo))
1382 goto EH_Fail;
1383
1384 cp->pid = (int) cp->procinfo.dwProcessId;
1385
1386
1387 if (cp->pid < 0)
1388 cp->pid = -cp->pid;
1389
1390 *pPid = cp->pid;
1391
1392 return TRUE;
1393
1394 EH_Fail:
1395 DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError ()););
1396 return FALSE;
1397 }
1398
1399
1400
1401
1402
1403
1404 void
1405 register_child (pid_t pid, int fd)
1406 {
1407 child_process *cp;
1408
1409 cp = find_child_pid ((DWORD)pid);
1410 if (cp == NULL)
1411 {
1412 DebPrint (("register_child unable to find pid %lu\n", pid));
1413 return;
1414 }
1415
1416 #ifdef FULL_DEBUG
1417 DebPrint (("register_child registered fd %d with pid %lu\n", fd, pid));
1418 #endif
1419
1420 cp->fd = fd;
1421
1422
1423
1424 cp->status = STATUS_READ_ACKNOWLEDGED;
1425
1426
1427 if (fd_info[fd].cp != NULL)
1428 {
1429 DebPrint (("register_child: fd_info[%d] apparently in use!\n", fd));
1430 emacs_abort ();
1431 }
1432
1433 fd_info[fd].cp = cp;
1434 }
1435
1436
1437 static void
1438 reap_subprocess (child_process *cp)
1439 {
1440 if (cp->procinfo.hProcess)
1441 {
1442
1443 #ifdef FULL_DEBUG
1444
1445 if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0)
1446 DebPrint (("reap_subprocess: child for fd %d has not died yet!", cp->fd));
1447 #endif
1448 CloseHandle (cp->procinfo.hProcess);
1449 cp->procinfo.hProcess = NULL;
1450 CloseHandle (cp->procinfo.hThread);
1451 cp->procinfo.hThread = NULL;
1452 }
1453
1454
1455
1456
1457
1458 if (cp->fd < 0)
1459 delete_child (cp);
1460 }
1461
1462
1463
1464
1465
1466
1467 pid_t
1468 waitpid (pid_t pid, int *status, int options)
1469 {
1470 DWORD active, retval;
1471 int nh;
1472 child_process *cp, *cps[MAX_CHILDREN];
1473 HANDLE wait_hnd[MAX_CHILDREN];
1474 DWORD timeout_ms;
1475 int dont_wait = (options & WNOHANG) != 0;
1476
1477 nh = 0;
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496 if (pid > 0)
1497 {
1498 int our_child = 0;
1499
1500
1501 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1502 {
1503
1504
1505
1506 if (CHILD_ACTIVE (cp)
1507 && cp->procinfo.hProcess
1508 && cp->pid == pid)
1509 {
1510 our_child = 1;
1511 break;
1512 }
1513 }
1514 if (our_child)
1515 {
1516 if (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)
1517 {
1518 wait_hnd[nh] = cp->procinfo.hProcess;
1519 cps[nh] = cp;
1520 nh++;
1521 }
1522 else if (dont_wait)
1523 {
1524
1525
1526 return 0;
1527 }
1528 }
1529 if (nh == 0)
1530 {
1531
1532 errno = ECHILD;
1533 return -1;
1534 }
1535 }
1536 else
1537 {
1538 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1539 {
1540 if (CHILD_ACTIVE (cp)
1541 && cp->procinfo.hProcess
1542 && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0))
1543 {
1544 wait_hnd[nh] = cp->procinfo.hProcess;
1545 cps[nh] = cp;
1546 nh++;
1547 }
1548 }
1549 if (nh == 0)
1550 {
1551
1552 errno = ECHILD;
1553 return -1;
1554 }
1555 }
1556
1557 if (dont_wait)
1558 timeout_ms = 0;
1559 else
1560 timeout_ms = 1000;
1561
1562 do
1563 {
1564
1565
1566
1567 if (!dont_wait)
1568 maybe_quit ();
1569 active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms);
1570 } while (active == WAIT_TIMEOUT && !dont_wait);
1571
1572 if (active == WAIT_FAILED)
1573 {
1574 errno = EBADF;
1575 return -1;
1576 }
1577 else if (active == WAIT_TIMEOUT && dont_wait)
1578 {
1579
1580
1581 #ifdef FULL_DEBUG
1582 DebPrint (("Wait: PID %d not reap yet\n", cp->pid));
1583 #endif
1584 return 0;
1585 }
1586 else if (active >= WAIT_OBJECT_0
1587 && active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
1588 {
1589 active -= WAIT_OBJECT_0;
1590 }
1591 else if (active >= WAIT_ABANDONED_0
1592 && active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
1593 {
1594 active -= WAIT_ABANDONED_0;
1595 }
1596 else
1597 emacs_abort ();
1598
1599 if (!GetExitCodeProcess (wait_hnd[active], &retval))
1600 {
1601 DebPrint (("Wait.GetExitCodeProcess failed with %lu\n",
1602 GetLastError ()));
1603 retval = 1;
1604 }
1605 if (retval == STILL_ACTIVE)
1606 {
1607
1608
1609
1610
1611
1612 DebPrint (("Wait.WaitForMultipleObjects returned an active process\n"));
1613 if (!(pid > 0 && dont_wait))
1614 {
1615 errno = EINVAL;
1616 return -1;
1617 }
1618 }
1619
1620
1621
1622
1623
1624 if (retval == STATUS_CONTROL_C_EXIT)
1625 retval = SIGINT;
1626 else
1627 retval <<= 8;
1628
1629 if (pid > 0 && active != 0)
1630 emacs_abort ();
1631 cp = cps[active];
1632 pid = cp->pid;
1633 #ifdef FULL_DEBUG
1634 DebPrint (("Wait signaled with process pid %d\n", cp->pid));
1635 #endif
1636
1637 if (status)
1638 *status = retval;
1639 reap_subprocess (cp);
1640
1641 return pid;
1642 }
1643
1644 int
1645 open_input_file (file_data *p_file, char *filename)
1646 {
1647 HANDLE file;
1648 HANDLE file_mapping;
1649 void *file_base;
1650 unsigned long size, upper_size;
1651
1652 file = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
1653 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1654 if (file == INVALID_HANDLE_VALUE)
1655 return FALSE;
1656
1657 size = GetFileSize (file, &upper_size);
1658 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
1659 0, size, NULL);
1660 if (!file_mapping)
1661 return FALSE;
1662
1663 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
1664 if (file_base == 0)
1665 return FALSE;
1666
1667 p_file->name = filename;
1668 p_file->size = size;
1669 p_file->file = file;
1670 p_file->file_mapping = file_mapping;
1671 p_file->file_base = file_base;
1672
1673 return TRUE;
1674 }
1675
1676
1677
1678 IMAGE_SECTION_HEADER *
1679 rva_to_section (DWORD_PTR rva, IMAGE_NT_HEADERS * nt_header)
1680 {
1681 PIMAGE_SECTION_HEADER section;
1682 int i;
1683
1684 section = IMAGE_FIRST_SECTION (nt_header);
1685
1686 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
1687 {
1688
1689
1690
1691
1692
1693
1694 DWORD_PTR real_size = max (section->SizeOfRawData,
1695 section->Misc.VirtualSize);
1696 if (rva >= section->VirtualAddress
1697 && rva < section->VirtualAddress + real_size)
1698 return section;
1699 section++;
1700 }
1701 return NULL;
1702 }
1703
1704
1705 void
1706 close_file_data (file_data *p_file)
1707 {
1708 UnmapViewOfFile (p_file->file_base);
1709 CloseHandle (p_file->file_mapping);
1710
1711 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
1712 SetEndOfFile (p_file->file);
1713 CloseHandle (p_file->file);
1714 }
1715
1716
1717
1718 #ifndef IMAGE_NT_OPTIONAL_HDR32_MAGIC
1719 # define IMAGE_NT_OPTIONAL_HDR32_MAGIC IMAGE_NT_OPTIONAL_HDR_MAGIC
1720 # define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
1721 #endif
1722
1723
1724
1725 static int
1726 w32_executable_type (char * filename,
1727 int * is_dos_app,
1728 int * is_cygnus_app,
1729 int * is_msys_app,
1730 int * is_gui_app)
1731 {
1732 file_data executable;
1733 char * p;
1734 int retval = 0;
1735
1736
1737 *is_dos_app = FALSE;
1738 *is_cygnus_app = FALSE;
1739 *is_msys_app = FALSE;
1740 *is_gui_app = FALSE;
1741
1742 if (!open_input_file (&executable, filename))
1743 return -1;
1744
1745 p = strrchr (filename, '.');
1746
1747
1748 if (p && xstrcasecmp (p, ".com") == 0)
1749 *is_dos_app = TRUE;
1750 else if (p && (xstrcasecmp (p, ".bat") == 0
1751 || xstrcasecmp (p, ".cmd") == 0))
1752 {
1753
1754
1755
1756
1757
1758
1759 p = egetenv ("COMSPEC");
1760 if (p)
1761 retval = w32_executable_type (p, is_dos_app, is_cygnus_app, is_msys_app,
1762 is_gui_app);
1763 }
1764 else
1765 {
1766
1767
1768
1769
1770
1771 IMAGE_DOS_HEADER * dos_header;
1772 IMAGE_NT_HEADERS * nt_header;
1773
1774 dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
1775 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
1776 goto unwind;
1777
1778 nt_header = (PIMAGE_NT_HEADERS) ((unsigned char *) dos_header + dos_header->e_lfanew);
1779
1780 if ((char *) nt_header > (char *) dos_header + executable.size)
1781 {
1782
1783 *is_dos_app = TRUE;
1784 }
1785 else if (nt_header->Signature != IMAGE_NT_SIGNATURE
1786 && LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
1787 {
1788 *is_dos_app = TRUE;
1789 }
1790 else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
1791 {
1792 IMAGE_DATA_DIRECTORY *data_dir = NULL;
1793 if (nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1794 {
1795
1796 IMAGE_OPTIONAL_HEADER32 *opt
1797 = (IMAGE_OPTIONAL_HEADER32*) &(nt_header->OptionalHeader);
1798 data_dir = opt->DataDirectory;
1799 *is_gui_app = (opt->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI);
1800 }
1801
1802
1803 #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC
1804 else if (nt_header->OptionalHeader.Magic
1805 == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1806 {
1807 IMAGE_OPTIONAL_HEADER64 *opt
1808 = (IMAGE_OPTIONAL_HEADER64*) &(nt_header->OptionalHeader);
1809 data_dir = opt->DataDirectory;
1810 *is_gui_app = (opt->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI);
1811 }
1812 #endif
1813 if (data_dir)
1814 {
1815
1816 IMAGE_DATA_DIRECTORY import_dir
1817 = data_dir[IMAGE_DIRECTORY_ENTRY_IMPORT];
1818
1819
1820 if (import_dir.VirtualAddress != 0)
1821 {
1822 IMAGE_SECTION_HEADER *section
1823 = rva_to_section (import_dir.VirtualAddress, nt_header);
1824 if (!section)
1825 emacs_abort ();
1826
1827 IMAGE_IMPORT_DESCRIPTOR * imports =
1828 RVA_TO_PTR (import_dir.VirtualAddress, section,
1829 executable);
1830
1831 for ( ; imports->Name; imports++)
1832 {
1833 section = rva_to_section (imports->Name, nt_header);
1834 if (!section)
1835 emacs_abort ();
1836
1837 char * dllname = RVA_TO_PTR (imports->Name, section,
1838 executable);
1839
1840
1841
1842
1843 if (strncmp (dllname, "cygwin", 6) == 0)
1844 {
1845 *is_cygnus_app = TRUE;
1846 break;
1847 }
1848 else if (strncmp (dllname, "msys-", 5) == 0)
1849 {
1850
1851
1852
1853
1854
1855 *is_msys_app = TRUE;
1856 break;
1857 }
1858 }
1859 }
1860 }
1861 }
1862 }
1863
1864 unwind:
1865 close_file_data (&executable);
1866 return retval;
1867 }
1868
1869 static int
1870 compare_env (const void *strp1, const void *strp2)
1871 {
1872 const char *str1 = *(const char **)strp1, *str2 = *(const char **)strp2;
1873
1874 while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
1875 {
1876
1877
1878 if (toupper (*str1) > toupper (*str2))
1879 return 1;
1880 else if (toupper (*str1) < toupper (*str2))
1881 return -1;
1882 str1++, str2++;
1883 }
1884
1885 if (*str1 == '=' && *str2 == '=')
1886 return 0;
1887 else if (*str1 == '=')
1888 return -1;
1889 else
1890 return 1;
1891 }
1892
1893 static void
1894 merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
1895 {
1896 char **optr, **nptr;
1897 int num;
1898
1899 nptr = new_envp;
1900 optr = envp1;
1901 while (*optr)
1902 *nptr++ = *optr++;
1903 num = optr - envp1;
1904
1905 optr = envp2;
1906 while (*optr)
1907 *nptr++ = *optr++;
1908 num += optr - envp2;
1909
1910 qsort (new_envp, num, sizeof (char *), compare_env);
1911
1912 *nptr = NULL;
1913 }
1914
1915
1916
1917 int
1918 sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1919 {
1920 Lisp_Object program, full;
1921 char *cmdline, *env, *parg, **targ;
1922 int arglen, numenv;
1923 pid_t pid;
1924 child_process *cp;
1925 int is_dos_app, is_cygnus_app, is_msys_app, is_gui_app;
1926 int do_quoting = 0;
1927
1928
1929 char ppid_env_var_buffer[64];
1930 char *extra_env[] = {ppid_env_var_buffer, NULL};
1931
1932
1933
1934
1935
1936
1937
1938 const char *sepchars = " \t*?";
1939
1940 char escape_char = '\\';
1941 char cmdname_a[MAX_PATH];
1942
1943
1944 if (mode != _P_NOWAIT)
1945 {
1946 errno = EINVAL;
1947 return -1;
1948 }
1949
1950
1951
1952
1953
1954 if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0)
1955 {
1956 program = build_string (cmdname);
1957 full = Qnil;
1958 openp (Vexec_path, program, Vexec_suffixes, &full, make_fixnum (X_OK),
1959 0, 0, NULL);
1960 if (NILP (full))
1961 {
1962 errno = EINVAL;
1963 return -1;
1964 }
1965 program = ENCODE_FILE (full);
1966 cmdname = SSDATA (program);
1967 }
1968 else
1969 {
1970 char *p = alloca (strlen (cmdname) + 1);
1971
1972
1973
1974
1975 cmdname = strcpy (p, cmdname);
1976 }
1977
1978
1979 unixtodos_filename (cmdname);
1980
1981
1982
1983
1984 filename_to_ansi (cmdname, cmdname_a);
1985
1986
1987
1988 if (_mbspbrk ((unsigned char *)cmdname_a, (const unsigned char *)"?"))
1989 {
1990 errno = ENOENT;
1991 return -1;
1992 }
1993
1994 cmdname = cmdname_a;
1995 argv[0] = cmdname;
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006 w32_executable_type (cmdname, &is_dos_app, &is_cygnus_app, &is_msys_app,
2007 &is_gui_app);
2008
2009
2010
2011
2012 if (is_dos_app)
2013 {
2014 char *p;
2015
2016 cmdname = alloca (MAX_PATH);
2017 if (egetenv ("CMDPROXY"))
2018 {
2019
2020
2021
2022
2023 strcpy (cmdname, egetenv ("CMDPROXY"));
2024 }
2025 else
2026 {
2027 char *q = lispstpcpy (cmdname,
2028
2029 ansi_encode_filename (Vexec_directory));
2030
2031
2032 for (p = q - 2; p > cmdname; p = CharPrevA (cmdname, p))
2033 if (*p == '/')
2034 break;
2035 if (*p == '/' && xstrcasecmp (p, "/lib-src/") == 0)
2036 q = stpcpy (p, "/nt/");
2037 strcpy (q, "cmdproxy.exe");
2038 }
2039
2040
2041
2042 for (p = cmdname; *p; p = CharNextA (p))
2043 if (*p == '/')
2044 *p = '\\';
2045 }
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077 if (!NILP (Vw32_quote_process_args))
2078 {
2079 do_quoting = 1;
2080
2081
2082 if (FIXNUMP (Vw32_quote_process_args))
2083 escape_char = XFIXNUM (Vw32_quote_process_args);
2084 else
2085 escape_char = (is_cygnus_app || is_msys_app) ? '"' : '\\';
2086 }
2087
2088
2089 if (escape_char == '"')
2090 sepchars = "\r\n\t\f '";
2091
2092
2093 arglen = 0;
2094 targ = argv;
2095 while (*targ)
2096 {
2097 char * p = *targ;
2098 int need_quotes = 0;
2099 int escape_char_run = 0;
2100
2101 if (*p == 0)
2102 need_quotes = 1;
2103 for ( ; *p; p++)
2104 {
2105 if (escape_char == '"' && *p == '\\')
2106
2107 arglen++;
2108 else if (*p == '"')
2109 {
2110
2111 arglen++;
2112 need_quotes = 1;
2113
2114 if (escape_char_run > 0)
2115 {
2116
2117
2118
2119 arglen += escape_char_run;
2120 }
2121 }
2122 else if (strchr (sepchars, *p) != NULL)
2123 {
2124 need_quotes = 1;
2125 }
2126
2127 if (*p == escape_char && escape_char != '"')
2128 escape_char_run++;
2129 else
2130 escape_char_run = 0;
2131 }
2132 if (need_quotes)
2133 {
2134 arglen += 2;
2135
2136
2137 if (escape_char_run > 0)
2138 arglen += escape_char_run;
2139 }
2140 arglen += strlen (*targ++) + 1;
2141 }
2142 cmdline = alloca (arglen);
2143 targ = argv;
2144 parg = cmdline;
2145 while (*targ)
2146 {
2147 char * p = *targ;
2148 int need_quotes = 0;
2149
2150 if (*p == 0)
2151 need_quotes = 1;
2152
2153 if (do_quoting)
2154 {
2155 for ( ; *p; p++)
2156 if ((strchr (sepchars, *p) != NULL) || *p == '"')
2157 need_quotes = 1;
2158 }
2159 if (need_quotes)
2160 {
2161 int escape_char_run = 0;
2162
2163
2164
2165 p = *targ;
2166
2167
2168 *parg++ = '"';
2169 #if 0
2170
2171
2172
2173
2174
2175
2176 while (*p)
2177 {
2178 if (*p == '"' && p > first && p < last)
2179 *parg++ = escape_char;
2180 *parg++ = *p++;
2181 }
2182 #else
2183 for ( ; *p; p++)
2184 {
2185 if (*p == '"')
2186 {
2187
2188 while (escape_char_run > 0)
2189 {
2190 *parg++ = escape_char;
2191 escape_char_run--;
2192 }
2193
2194 *parg++ = escape_char;
2195 }
2196 else if (escape_char == '"' && *p == '\\')
2197 *parg++ = '\\';
2198 *parg++ = *p;
2199
2200 if (*p == escape_char && escape_char != '"')
2201 escape_char_run++;
2202 else
2203 escape_char_run = 0;
2204 }
2205
2206 while (escape_char_run > 0)
2207 {
2208 *parg++ = escape_char;
2209 escape_char_run--;
2210 }
2211 #endif
2212 *parg++ = '"';
2213 }
2214 else
2215 {
2216 strcpy (parg, *targ);
2217 parg += strlen (*targ);
2218 }
2219 *parg++ = ' ';
2220 targ++;
2221 }
2222 *--parg = '\0';
2223
2224
2225 arglen = 1;
2226 targ = envp;
2227 numenv = 1;
2228 while (*targ)
2229 {
2230 arglen += strlen (*targ++) + 1;
2231 numenv++;
2232 }
2233
2234 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%lu",
2235 GetCurrentProcessId ());
2236 arglen += strlen (ppid_env_var_buffer) + 1;
2237 numenv++;
2238
2239
2240 targ = (char **) alloca (numenv * sizeof (char *));
2241 merge_and_sort_env (envp, extra_env, targ);
2242
2243
2244 env = alloca (arglen);
2245 parg = env;
2246 while (*targ)
2247 {
2248 strcpy (parg, *targ);
2249 parg += strlen (*targ++);
2250 *parg++ = '\0';
2251 }
2252 *parg++ = '\0';
2253 *parg = '\0';
2254
2255 cp = new_child ();
2256 if (cp == NULL)
2257 {
2258 errno = EAGAIN;
2259 return -1;
2260 }
2261
2262
2263 if (!create_child (cmdname, cmdline, env, is_gui_app, &pid, cp))
2264 {
2265 delete_child (cp);
2266 errno = ENOEXEC;
2267 return -1;
2268 }
2269
2270 return pid;
2271 }
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293 extern HANDLE keyboard_handle;
2294
2295
2296 extern HANDLE interrupt_handle;
2297
2298
2299 extern int proc_buffered_char[];
2300
2301 int
2302 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
2303 const struct timespec *timeout, const sigset_t *ignored)
2304 {
2305 SELECT_TYPE orfds, owfds;
2306 DWORD timeout_ms, start_time;
2307 int i, nh, nc, nr;
2308 DWORD active;
2309 child_process *cp, *cps[MAX_CHILDREN];
2310 HANDLE wait_hnd[MAXDESC + MAX_CHILDREN];
2311 int fdindex[MAXDESC];
2312
2313 timeout_ms =
2314 timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000) : INFINITE;
2315
2316
2317 if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL)
2318 {
2319 Sleep (timeout_ms);
2320 return 0;
2321 }
2322
2323
2324 if ((rfds == NULL && wfds == NULL) || efds != NULL)
2325 {
2326 errno = EINVAL;
2327 return -1;
2328 }
2329
2330 if (rfds)
2331 {
2332 orfds = *rfds;
2333 FD_ZERO (rfds);
2334 }
2335 else
2336 FD_ZERO (&orfds);
2337 if (wfds)
2338 {
2339 owfds = *wfds;
2340 FD_ZERO (wfds);
2341 }
2342 else
2343 FD_ZERO (&owfds);
2344 nr = 0;
2345
2346
2347
2348 nh = 0;
2349 if (interrupt_handle && interrupt_handle != INVALID_HANDLE_VALUE)
2350 {
2351 wait_hnd[0] = interrupt_handle;
2352 fdindex[0] = -1;
2353 nh++;
2354 }
2355
2356
2357 for (i = 0; i < nfds; i++)
2358 if (FD_ISSET (i, &orfds) || FD_ISSET (i, &owfds))
2359 {
2360 if (i == 0)
2361 {
2362 if (keyboard_handle)
2363 {
2364
2365 wait_hnd[nh] = keyboard_handle;
2366 fdindex[nh] = i;
2367 nh++;
2368 }
2369
2370
2371
2372 if (rfds && detect_input_pending ())
2373 {
2374 FD_SET (i, rfds);
2375 return 1;
2376 }
2377 else if (noninteractive)
2378 {
2379 if (handle_file_notifications (NULL))
2380 return 1;
2381 }
2382 }
2383 else
2384 {
2385
2386 cp = fd_info[i].cp;
2387 if (FD_ISSET (i, &owfds)
2388 && cp
2389 && (fd_info[i].flags & FILE_CONNECT) == 0)
2390 {
2391 DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i));
2392 cp = NULL;
2393 }
2394 if (cp)
2395 {
2396 int current_status = cp->status;
2397
2398 if (current_status == STATUS_READ_ACKNOWLEDGED)
2399 {
2400
2401 cp->fd = i;
2402
2403 cp->errcode = 0;
2404
2405 cp->status = STATUS_READ_READY;
2406 if (!SetEvent (cp->char_consumed))
2407 DebPrint (("sys_select.SetEvent failed with "
2408 "%lu for fd %ld\n", GetLastError (), i));
2409 }
2410
2411 #ifdef CHECK_INTERLOCK
2412
2413
2414 current_status = cp->status;
2415 if (WaitForSingleObject (cp->char_avail, 0) == WAIT_OBJECT_0)
2416 {
2417
2418
2419
2420 current_status = cp->status;
2421 if (current_status != STATUS_READ_SUCCEEDED
2422 && current_status != STATUS_READ_FAILED)
2423 DebPrint (("char_avail set, but read not completed: status %d\n",
2424 current_status));
2425 }
2426 else
2427 {
2428
2429
2430
2431
2432
2433 if (current_status != STATUS_READ_READY
2434 && current_status != STATUS_READ_IN_PROGRESS
2435 && current_status != STATUS_READ_SUCCEEDED
2436 && current_status != STATUS_READ_FAILED)
2437 DebPrint (("char_avail reset, but read status is bad: %d\n",
2438 current_status));
2439 }
2440 #endif
2441 wait_hnd[nh] = cp->char_avail;
2442 fdindex[nh] = i;
2443 if (!wait_hnd[nh]) emacs_abort ();
2444 nh++;
2445 #ifdef FULL_DEBUG
2446 DebPrint (("select waiting on child %d fd %d\n",
2447 cp-child_procs, i));
2448 #endif
2449 }
2450 else
2451 {
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463 DebPrint (("sys_select: fd %ld is invalid! ignoring\n", i));
2464 }
2465 }
2466 }
2467
2468 count_children:
2469
2470 nc = 0;
2471 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
2472
2473
2474
2475 if ((CHILD_ACTIVE (cp) && cp->procinfo.hProcess)
2476 && (cp->fd < 0
2477 || (fd_info[cp->fd].flags & FILE_SEND_SIGCHLD) == 0
2478 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)
2479 )
2480 {
2481 wait_hnd[nh + nc] = cp->procinfo.hProcess;
2482 cps[nc] = cp;
2483 nc++;
2484 }
2485
2486
2487 if (nh + nc == 0)
2488 {
2489 if (timeout)
2490 Sleep (timeout_ms);
2491 if (noninteractive)
2492 {
2493 if (handle_file_notifications (NULL))
2494 return 1;
2495 }
2496 return 0;
2497 }
2498
2499 start_time = GetTickCount ();
2500
2501
2502
2503 if (FD_ISSET (0, &orfds))
2504 active = MsgWaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms,
2505 QS_ALLINPUT);
2506 else
2507 active = WaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms);
2508
2509 if (active == WAIT_FAILED)
2510 {
2511 DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n",
2512 nh + nc, timeout_ms, GetLastError ()));
2513
2514
2515
2516
2517 errno = EINTR;
2518 return -1;
2519 }
2520 else if (active == WAIT_TIMEOUT)
2521 {
2522 if (noninteractive)
2523 {
2524 if (handle_file_notifications (NULL))
2525 return 1;
2526 }
2527 return 0;
2528 }
2529 else if (active >= WAIT_OBJECT_0
2530 && active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
2531 {
2532 active -= WAIT_OBJECT_0;
2533 }
2534 else if (active >= WAIT_ABANDONED_0
2535 && active < WAIT_ABANDONED_0+MAXIMUM_WAIT_OBJECTS)
2536 {
2537 active -= WAIT_ABANDONED_0;
2538 }
2539 else
2540 emacs_abort ();
2541
2542
2543
2544
2545
2546 do
2547 {
2548 if (active == nh + nc)
2549 {
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565 if (drain_message_queue ()
2566
2567
2568
2569
2570
2571
2572
2573 && FRAME_TERMCAP_P (SELECTED_FRAME ())
2574
2575 && FD_ISSET (0, &orfds)
2576
2577 && keyboard_handle)
2578 {
2579 FD_SET (0, rfds);
2580 if (nr == 0)
2581 nr = 1;
2582 }
2583 }
2584 else if (active >= nh)
2585 {
2586 cp = cps[active - nh];
2587
2588
2589
2590
2591
2592 if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0)
2593 fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD;
2594
2595 else if (sig_handlers[SIGCHLD] != SIG_DFL &&
2596 sig_handlers[SIGCHLD] != SIG_IGN)
2597 {
2598 #ifdef FULL_DEBUG
2599 DebPrint (("select calling SIGCHLD handler for pid %d\n",
2600 cp->pid));
2601 #endif
2602 sig_handlers[SIGCHLD] (SIGCHLD);
2603 }
2604 }
2605 else if (fdindex[active] == -1)
2606 {
2607
2608 errno = EINTR;
2609 return -1;
2610 }
2611 else if (rfds && fdindex[active] == 0)
2612 {
2613
2614 FD_SET (0, rfds);
2615 nr++;
2616 }
2617 else
2618 {
2619
2620
2621
2622
2623 if (wfds && (fd_info[fdindex[active]].flags & FILE_CONNECT) != 0)
2624 {
2625 cp = fd_info[fdindex[active]].cp;
2626 if (cp)
2627 {
2628
2629
2630
2631
2632
2633
2634
2635 if (cp->status == STATUS_READ_SUCCEEDED)
2636 {
2637 fd_info[cp->fd].flags &= ~FILE_CONNECT;
2638 cp->status = STATUS_READ_ACKNOWLEDGED;
2639 }
2640 ResetEvent (cp->char_avail);
2641 }
2642 FD_SET (fdindex[active], wfds);
2643 }
2644 else if (rfds)
2645 FD_SET (fdindex[active], rfds);
2646 nr++;
2647 }
2648
2649
2650
2651
2652 while (++active < nh + nc)
2653 if (WaitForSingleObject (wait_hnd[active], 0) == WAIT_OBJECT_0)
2654 break;
2655 } while (active < nh + nc);
2656
2657 if (noninteractive)
2658 {
2659 if (handle_file_notifications (NULL))
2660 nr++;
2661 }
2662
2663
2664 if (nr == 0)
2665 {
2666 DWORD elapsed = GetTickCount () - start_time;
2667
2668 if (timeout_ms > elapsed)
2669 {
2670 if (timeout_ms != INFINITE)
2671 timeout_ms -= elapsed;
2672 goto count_children;
2673 }
2674 }
2675
2676 return nr;
2677 }
2678
2679
2680
2681 static BOOL CALLBACK
2682 find_child_console (HWND hwnd, LPARAM arg)
2683 {
2684 child_process * cp = (child_process *) arg;
2685 DWORD process_id;
2686
2687 GetWindowThreadProcessId (hwnd, &process_id);
2688 if (process_id == cp->procinfo.dwProcessId)
2689 {
2690 char window_class[32];
2691
2692 GetClassName (hwnd, window_class, sizeof (window_class));
2693 if (strcmp (window_class,
2694 (os_subtype == OS_SUBTYPE_9X)
2695 ? "tty"
2696 : "ConsoleWindowClass") == 0)
2697 {
2698 cp->hwnd = hwnd;
2699 return FALSE;
2700 }
2701 }
2702
2703 return TRUE;
2704 }
2705
2706 typedef BOOL (WINAPI * DebugBreakProcess_Proc) (
2707 HANDLE hProcess);
2708
2709
2710 int
2711 sys_kill (pid_t pid, int sig)
2712 {
2713 child_process *cp;
2714 HANDLE proc_hand;
2715 int need_to_free = 0;
2716 int rc = 0;
2717
2718
2719 if (pid < 0)
2720 pid = -pid;
2721
2722
2723 if (sig != 0
2724 && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP && sig != SIGTRAP)
2725 {
2726 errno = EINVAL;
2727 return -1;
2728 }
2729
2730 if (sig == 0)
2731 {
2732
2733
2734 if (pid <= 4)
2735 {
2736 errno = EPERM;
2737 return -1;
2738 }
2739 proc_hand = OpenProcess (PROCESS_QUERY_INFORMATION, 0, pid);
2740 if (proc_hand == NULL)
2741 {
2742 DWORD err = GetLastError ();
2743
2744 switch (err)
2745 {
2746 case ERROR_ACCESS_DENIED:
2747 errno = EPERM;
2748 return -1;
2749 case ERROR_INVALID_PARAMETER:
2750 errno = ESRCH;
2751 return -1;
2752 }
2753 }
2754 else
2755 CloseHandle (proc_hand);
2756 return 0;
2757 }
2758
2759 cp = find_child_pid (pid);
2760 if (cp == NULL)
2761 {
2762
2763
2764
2765
2766
2767
2768 DWORD desiredAccess =
2769 (sig == SIGTRAP) ? PROCESS_ALL_ACCESS : PROCESS_TERMINATE;
2770
2771 proc_hand = OpenProcess (desiredAccess, 0, pid);
2772 if (proc_hand == NULL)
2773 {
2774 errno = EPERM;
2775 return -1;
2776 }
2777 need_to_free = 1;
2778 }
2779 else
2780 {
2781 proc_hand = cp->procinfo.hProcess;
2782 pid = cp->procinfo.dwProcessId;
2783
2784
2785 EnumWindows (find_child_console, (LPARAM) cp);
2786 }
2787
2788 if (sig == SIGINT || sig == SIGQUIT)
2789 {
2790 if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd)
2791 {
2792 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
2793
2794 BYTE vk_break_code = (sig == SIGINT) ? 'C' : VK_CANCEL;
2795 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
2796 HWND foreground_window;
2797
2798 if (break_scan_code == 0)
2799 {
2800
2801 vk_break_code = 'C';
2802 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
2803 }
2804
2805 foreground_window = GetForegroundWindow ();
2806 if (foreground_window)
2807 {
2808
2809
2810
2811
2812
2813
2814 DWORD foreground_thread, child_thread;
2815 foreground_thread =
2816 GetWindowThreadProcessId (foreground_window, NULL);
2817 if (foreground_thread == GetCurrentThreadId ()
2818 || !AttachThreadInput (GetCurrentThreadId (),
2819 foreground_thread, TRUE))
2820 foreground_thread = 0;
2821
2822 child_thread = GetWindowThreadProcessId (cp->hwnd, NULL);
2823 if (child_thread == GetCurrentThreadId ()
2824 || !AttachThreadInput (GetCurrentThreadId (),
2825 child_thread, TRUE))
2826 child_thread = 0;
2827
2828
2829 if (SetForegroundWindow (cp->hwnd))
2830 {
2831
2832
2833
2834
2835 short ctrl_state = GetKeyState (VK_LCONTROL) & 0x8000;
2836
2837
2838
2839 keybd_event (VK_CONTROL, control_scan_code, 0, 0);
2840 keybd_event (vk_break_code, break_scan_code,
2841 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0);
2842 keybd_event (vk_break_code, break_scan_code,
2843 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY)
2844 | KEYEVENTF_KEYUP, 0);
2845 keybd_event (VK_CONTROL, control_scan_code,
2846 KEYEVENTF_KEYUP, 0);
2847
2848
2849
2850 Sleep (100);
2851
2852 SetForegroundWindow (foreground_window);
2853
2854 if (ctrl_state != 0)
2855 keybd_event (VK_CONTROL, control_scan_code, 0, 0);
2856 }
2857
2858
2859 if (foreground_thread)
2860 AttachThreadInput (GetCurrentThreadId (),
2861 foreground_thread, FALSE);
2862 if (child_thread)
2863 AttachThreadInput (GetCurrentThreadId (),
2864 child_thread, FALSE);
2865 }
2866 }
2867
2868 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
2869 {
2870 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d "
2871 "for pid %lu\n", GetLastError (), pid));
2872 errno = EINVAL;
2873 rc = -1;
2874 }
2875 }
2876 else if (sig == SIGTRAP)
2877 {
2878 static DebugBreakProcess_Proc s_pfn_Debug_Break_Process = NULL;
2879
2880 if (g_b_init_debug_break_process == 0)
2881 {
2882 g_b_init_debug_break_process = 1;
2883 s_pfn_Debug_Break_Process = (DebugBreakProcess_Proc)
2884 get_proc_addr (GetModuleHandle ("kernel32.dll"),
2885 "DebugBreakProcess");
2886 }
2887
2888 if (s_pfn_Debug_Break_Process == NULL)
2889 {
2890 errno = ENOTSUP;
2891 rc = -1;
2892 }
2893 else if (!s_pfn_Debug_Break_Process (proc_hand))
2894 {
2895 DWORD err = GetLastError ();
2896
2897 DebPrint (("sys_kill.DebugBreakProcess return %d "
2898 "for pid %lu\n", err, pid));
2899
2900 switch (err)
2901 {
2902 case ERROR_ACCESS_DENIED:
2903 errno = EPERM;
2904 break;
2905 default:
2906 errno = EINVAL;
2907 break;
2908 }
2909
2910 rc = -1;
2911 }
2912 }
2913 else
2914 {
2915 if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd)
2916 {
2917 #if 1
2918 if (os_subtype == OS_SUBTYPE_9X)
2919 {
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936 #if 0
2937
2938
2939
2940
2941
2942
2943
2944
2945 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
2946 #endif
2947 if (!TerminateProcess (proc_hand, 0xff))
2948 {
2949 DebPrint (("sys_kill.TerminateProcess returned %d "
2950 "for pid %lu\n", GetLastError (), pid));
2951 errno = EINVAL;
2952 rc = -1;
2953 }
2954 }
2955 else
2956 #endif
2957 PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
2958 }
2959
2960
2961
2962 else if (!TerminateProcess (proc_hand, 0xff))
2963 {
2964 DebPrint (("sys_kill.TerminateProcess returned %d "
2965 "for pid %lu\n", GetLastError (), pid));
2966 errno = EINVAL;
2967 rc = -1;
2968 }
2969 }
2970
2971 if (need_to_free)
2972 CloseHandle (proc_hand);
2973
2974 return rc;
2975 }
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994 void
2995 prepare_standard_handles (int in, int out, int err, HANDLE handles[3])
2996 {
2997 HANDLE parent;
2998 HANDLE newstdin, newstdout, newstderr;
2999
3000 parent = GetCurrentProcess ();
3001
3002 handles[0] = GetStdHandle (STD_INPUT_HANDLE);
3003 handles[1] = GetStdHandle (STD_OUTPUT_HANDLE);
3004 handles[2] = GetStdHandle (STD_ERROR_HANDLE);
3005
3006
3007 if (!DuplicateHandle (parent,
3008 (HANDLE) _get_osfhandle (in),
3009 parent,
3010 &newstdin,
3011 0,
3012 TRUE,
3013 DUPLICATE_SAME_ACCESS))
3014 report_file_error ("Duplicating input handle for child", Qnil);
3015
3016 if (!DuplicateHandle (parent,
3017 (HANDLE) _get_osfhandle (out),
3018 parent,
3019 &newstdout,
3020 0,
3021 TRUE,
3022 DUPLICATE_SAME_ACCESS))
3023 report_file_error ("Duplicating output handle for child", Qnil);
3024
3025 if (!DuplicateHandle (parent,
3026 (HANDLE) _get_osfhandle (err),
3027 parent,
3028 &newstderr,
3029 0,
3030 TRUE,
3031 DUPLICATE_SAME_ACCESS))
3032 report_file_error ("Duplicating error handle for child", Qnil);
3033
3034
3035 if (!SetStdHandle (STD_INPUT_HANDLE, newstdin))
3036 report_file_error ("Changing stdin handle", Qnil);
3037
3038 if (!SetStdHandle (STD_OUTPUT_HANDLE, newstdout))
3039 report_file_error ("Changing stdout handle", Qnil);
3040
3041 if (!SetStdHandle (STD_ERROR_HANDLE, newstderr))
3042 report_file_error ("Changing stderr handle", Qnil);
3043 }
3044
3045 void
3046 reset_standard_handles (int in, int out, int err, HANDLE handles[3])
3047 {
3048
3049 CloseHandle (GetStdHandle (STD_INPUT_HANDLE));
3050 CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE));
3051 CloseHandle (GetStdHandle (STD_ERROR_HANDLE));
3052
3053
3054 SetStdHandle (STD_INPUT_HANDLE, handles[0]);
3055 SetStdHandle (STD_OUTPUT_HANDLE, handles[1]);
3056 SetStdHandle (STD_ERROR_HANDLE, handles[2]);
3057 }
3058
3059 void
3060 set_process_dir (const char * dir)
3061 {
3062 process_dir = (char *) dir;
3063 }
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077 extern HANDLE winsock_lib;
3078 extern BOOL term_winsock (void);
3079
3080 DEFUN ("w32-has-winsock", Fw32_has_winsock, Sw32_has_winsock, 0, 1, 0,
3081 doc:
3082
3083
3084
3085
3086
3087
3088 )
3089 (Lisp_Object load_now)
3090 {
3091 int have_winsock;
3092
3093 have_winsock = init_winsock (!NILP (load_now));
3094 if (have_winsock)
3095 {
3096 if (winsock_lib != NULL)
3097 {
3098
3099
3100
3101 Lisp_Object orig_hostname = Vsystem_name;
3102 Lisp_Object hostname;
3103
3104 init_system_name ();
3105 hostname = Vsystem_name;
3106 Vsystem_name = orig_hostname;
3107 return hostname;
3108 }
3109 return Qt;
3110 }
3111 return Qnil;
3112 }
3113
3114 DEFUN ("w32-unload-winsock", Fw32_unload_winsock, Sw32_unload_winsock,
3115 0, 0, 0,
3116 doc:
3117
3118
3119 )
3120 (void)
3121 {
3122 return term_winsock () ? Qt : Qnil;
3123 }
3124
3125
3126
3127
3128
3129 DEFUN ("w32-short-file-name", Fw32_short_file_name, Sw32_short_file_name, 1, 1, 0,
3130 doc:
3131
3132 )
3133 (Lisp_Object filename)
3134 {
3135 char shortname[MAX_PATH];
3136
3137 CHECK_STRING (filename);
3138
3139
3140 filename = Fexpand_file_name (filename, Qnil);
3141
3142
3143 if (w32_get_short_filename (SSDATA (ENCODE_FILE (filename)),
3144 shortname, MAX_PATH) == 0)
3145 return Qnil;
3146
3147 dostounix_filename (shortname);
3148
3149
3150 return build_string (shortname);
3151 }
3152
3153
3154 DEFUN ("w32-long-file-name", Fw32_long_file_name, Sw32_long_file_name,
3155 1, 1, 0,
3156 doc:
3157
3158 )
3159 (Lisp_Object filename)
3160 {
3161 char longname[ MAX_UTF8_PATH ];
3162 int drive_only = 0;
3163
3164 CHECK_STRING (filename);
3165
3166 if (SBYTES (filename) == 2
3167 && *(SDATA (filename) + 1) == ':')
3168 drive_only = 1;
3169
3170
3171 filename = Fexpand_file_name (filename, Qnil);
3172
3173 if (!w32_get_long_filename (SSDATA (ENCODE_FILE (filename)), longname,
3174 MAX_UTF8_PATH))
3175 return Qnil;
3176
3177 dostounix_filename (longname);
3178
3179
3180
3181
3182 if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
3183 longname[2] = '\0';
3184
3185 return DECODE_FILE (build_unibyte_string (longname));
3186 }
3187
3188 DEFUN ("w32-set-process-priority", Fw32_set_process_priority,
3189 Sw32_set_process_priority, 2, 2, 0,
3190 doc:
3191
3192
3193
3194
3195
3196 )
3197 (Lisp_Object process, Lisp_Object priority)
3198 {
3199 HANDLE proc_handle = GetCurrentProcess ();
3200 DWORD priority_class = NORMAL_PRIORITY_CLASS;
3201 Lisp_Object result = Qnil;
3202
3203 CHECK_SYMBOL (priority);
3204
3205 if (!NILP (process))
3206 {
3207 DWORD pid;
3208 child_process *cp;
3209
3210 CHECK_FIXNUM (process);
3211
3212
3213
3214
3215
3216 pid = XFIXNUM (process);
3217 cp = find_child_pid (pid);
3218 if (cp != NULL)
3219 pid = cp->procinfo.dwProcessId;
3220
3221 proc_handle = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
3222 }
3223
3224 if (EQ (priority, Qhigh))
3225 priority_class = HIGH_PRIORITY_CLASS;
3226 else if (EQ (priority, Qlow))
3227 priority_class = IDLE_PRIORITY_CLASS;
3228
3229 if (proc_handle != NULL)
3230 {
3231 if (SetPriorityClass (proc_handle, priority_class))
3232 result = Qt;
3233 if (!NILP (process))
3234 CloseHandle (proc_handle);
3235 }
3236
3237 return result;
3238 }
3239
3240 DEFUN ("w32-application-type", Fw32_application_type,
3241 Sw32_application_type, 1, 1, 0,
3242 doc:
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264 )
3265 (Lisp_Object program)
3266 {
3267 int is_dos_app, is_cygwin_app, is_msys_app, dummy;
3268 Lisp_Object encoded_progname;
3269 char *progname, progname_a[MAX_PATH];
3270
3271 program = Fexpand_file_name (program, Qnil);
3272 encoded_progname = Fcopy_sequence (ENCODE_FILE (program));
3273 progname = SSDATA (encoded_progname);
3274 unixtodos_filename (progname);
3275 filename_to_ansi (progname, progname_a);
3276
3277
3278 if (_mbspbrk ((unsigned char *)progname_a, (const unsigned char *)"?"))
3279 return Qunknown;
3280
3281 if (w32_executable_type (progname_a, &is_dos_app, &is_cygwin_app,
3282 &is_msys_app, &dummy) != 0)
3283 return Qunknown;
3284 if (is_dos_app)
3285 return Qdos;
3286 if (is_cygwin_app)
3287 return Qcygwin;
3288 if (is_msys_app)
3289 return Qmsys;
3290 return Qw32_native;
3291 }
3292
3293 #ifdef HAVE_LANGINFO_CODESET
3294
3295
3296
3297 #ifndef LOCALE_IPAPERSIZE
3298 # define LOCALE_IPAPERSIZE 0x100A
3299 #endif
3300
3301 char *
3302 nl_langinfo (nl_item item)
3303 {
3304
3305 static const LCTYPE w32item[] = {
3306 LOCALE_IDEFAULTANSICODEPAGE,
3307 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
3308 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
3309 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
3310 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
3311 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
3312 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
3313 LOCALE_IPAPERSIZE, LOCALE_IPAPERSIZE
3314 };
3315
3316 static char *nl_langinfo_buf = NULL;
3317 static int nl_langinfo_len = 0;
3318
3319 if (nl_langinfo_len <= 0)
3320 nl_langinfo_buf = xmalloc (nl_langinfo_len = 1);
3321
3322 char *retval = nl_langinfo_buf;
3323
3324 if (item < 0 || item >= _NL_NUM)
3325 nl_langinfo_buf[0] = 0;
3326 else
3327 {
3328 LCID cloc = GetThreadLocale ();
3329 int need_len = GetLocaleInfo (cloc, w32item[item] | LOCALE_USE_CP_ACP,
3330 NULL, 0);
3331
3332 if (need_len <= 0)
3333 nl_langinfo_buf[0] = 0;
3334 else
3335 {
3336 if (item == CODESET)
3337 {
3338 need_len += 2;
3339 if (need_len < 8)
3340 need_len = 8;
3341 }
3342 if (nl_langinfo_len <= need_len)
3343 nl_langinfo_buf = xrealloc (nl_langinfo_buf,
3344 nl_langinfo_len = need_len);
3345 retval = nl_langinfo_buf;
3346
3347 if (!GetLocaleInfo (cloc, w32item[item] | LOCALE_USE_CP_ACP,
3348 nl_langinfo_buf, nl_langinfo_len))
3349 nl_langinfo_buf[0] = 0;
3350 else if (item == CODESET)
3351 {
3352 if (strcmp (nl_langinfo_buf, "0") == 0
3353 || strcmp (nl_langinfo_buf, "1") == 0)
3354 sprintf (nl_langinfo_buf, "cp%u", GetACP ());
3355 else
3356 {
3357 memmove (nl_langinfo_buf + 2, nl_langinfo_buf,
3358 strlen (nl_langinfo_buf) + 1);
3359 nl_langinfo_buf[0] = 'c';
3360 nl_langinfo_buf[1] = 'p';
3361 }
3362 }
3363 else if (item == _NL_PAPER_WIDTH || item == _NL_PAPER_HEIGHT)
3364 {
3365 static const int paper_size[][2] =
3366 {
3367 { -1, -1 },
3368 { 216, 279 },
3369 { -1, -1 },
3370 { -1, -1 },
3371 { -1, -1 },
3372 { 216, 356 },
3373 { -1, -1 },
3374 { -1, -1 },
3375 { 297, 420 },
3376 { 210, 297 }
3377 };
3378 int idx = atoi (nl_langinfo_buf);
3379 if (0 <= idx && idx < ARRAYELTS (paper_size))
3380 retval = (char *)(intptr_t) (item == _NL_PAPER_WIDTH
3381 ? paper_size[idx][0]
3382 : paper_size[idx][1]);
3383 else
3384 retval = (char *)(intptr_t) -1;
3385 }
3386 }
3387 }
3388 return retval;
3389 }
3390 #endif
3391
3392 DEFUN ("w32-get-locale-info", Fw32_get_locale_info,
3393 Sw32_get_locale_info, 1, 2, 0,
3394 doc:
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405 )
3406 (Lisp_Object lcid, Lisp_Object longform)
3407 {
3408 int got_abbrev;
3409 int got_full;
3410 char abbrev_name[32] = { 0 };
3411 char full_name[256] = { 0 };
3412
3413 CHECK_FIXNUM (lcid);
3414
3415 if (!IsValidLocale (XFIXNUM (lcid), LCID_SUPPORTED))
3416 return Qnil;
3417
3418 if (NILP (longform))
3419 {
3420 got_abbrev = GetLocaleInfo (XFIXNUM (lcid),
3421 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
3422 abbrev_name, sizeof (abbrev_name));
3423 if (got_abbrev)
3424 return build_string (abbrev_name);
3425 }
3426 else if (EQ (longform, Qt))
3427 {
3428 got_full = GetLocaleInfo (XFIXNUM (lcid),
3429 LOCALE_SLANGUAGE | LOCALE_USE_CP_ACP,
3430 full_name, sizeof (full_name));
3431 if (got_full)
3432 return DECODE_SYSTEM (build_string (full_name));
3433 }
3434 else if (FIXNUMP (longform))
3435 {
3436 got_full = GetLocaleInfo (XFIXNUM (lcid),
3437 XFIXNUM (longform),
3438 full_name, sizeof (full_name));
3439
3440
3441
3442
3443 if (got_full)
3444 return make_unibyte_string (full_name, got_full - 1);
3445 }
3446
3447 return Qnil;
3448 }
3449
3450
3451 DEFUN ("w32-get-current-locale-id", Fw32_get_current_locale_id,
3452 Sw32_get_current_locale_id, 0, 0, 0,
3453 doc:
3454
3455 )
3456 (void)
3457 {
3458 return make_fixnum (GetThreadLocale ());
3459 }
3460
3461 static DWORD
3462 int_from_hex (char * s)
3463 {
3464 DWORD val = 0;
3465 static char hex[] = "0123456789abcdefABCDEF";
3466 char * p;
3467
3468 while (*s && (p = strchr (hex, *s)) != NULL)
3469 {
3470 unsigned digit = p - hex;
3471 if (digit > 15)
3472 digit -= 6;
3473 val = val * 16 + digit;
3474 s++;
3475 }
3476 return val;
3477 }
3478
3479
3480
3481 Lisp_Object Vw32_valid_locale_ids;
3482
3483 static BOOL CALLBACK ALIGN_STACK
3484 enum_locale_fn (LPTSTR localeNum)
3485 {
3486 DWORD id = int_from_hex (localeNum);
3487 Vw32_valid_locale_ids = Fcons (make_fixnum (id), Vw32_valid_locale_ids);
3488 return TRUE;
3489 }
3490
3491 DEFUN ("w32-get-valid-locale-ids", Fw32_get_valid_locale_ids,
3492 Sw32_get_valid_locale_ids, 0, 0, 0,
3493 doc:
3494
3495 )
3496 (void)
3497 {
3498 Vw32_valid_locale_ids = Qnil;
3499
3500 EnumSystemLocales (enum_locale_fn, LCID_SUPPORTED);
3501
3502 Vw32_valid_locale_ids = Fnreverse (Vw32_valid_locale_ids);
3503 return Vw32_valid_locale_ids;
3504 }
3505
3506
3507 DEFUN ("w32-get-default-locale-id", Fw32_get_default_locale_id, Sw32_get_default_locale_id, 0, 1, 0,
3508 doc:
3509
3510
3511
3512 )
3513 (Lisp_Object userp)
3514 {
3515 if (NILP (userp))
3516 return make_fixnum (GetSystemDefaultLCID ());
3517 return make_fixnum (GetUserDefaultLCID ());
3518 }
3519
3520
3521 DEFUN ("w32-set-current-locale", Fw32_set_current_locale, Sw32_set_current_locale, 1, 1, 0,
3522 doc:
3523 )
3524 (Lisp_Object lcid)
3525 {
3526 CHECK_FIXNUM (lcid);
3527
3528 if (!IsValidLocale (XFIXNUM (lcid), LCID_SUPPORTED))
3529 return Qnil;
3530
3531 if (!SetThreadLocale (XFIXNUM (lcid)))
3532 return Qnil;
3533
3534
3535 if (dwWindowsThreadId)
3536
3537 PostThreadMessage (dwWindowsThreadId, WM_EMACS_SETLOCALE, XFIXNUM (lcid), 0);
3538
3539 return make_fixnum (GetThreadLocale ());
3540 }
3541
3542
3543
3544
3545 Lisp_Object Vw32_valid_codepages;
3546
3547 static BOOL CALLBACK ALIGN_STACK
3548 enum_codepage_fn (LPTSTR codepageNum)
3549 {
3550 DWORD id = atoi (codepageNum);
3551 Vw32_valid_codepages = Fcons (make_fixnum (id), Vw32_valid_codepages);
3552 return TRUE;
3553 }
3554
3555 DEFUN ("w32-get-valid-codepages", Fw32_get_valid_codepages,
3556 Sw32_get_valid_codepages, 0, 0, 0,
3557 doc: )
3558 (void)
3559 {
3560 Vw32_valid_codepages = Qnil;
3561
3562 EnumSystemCodePages (enum_codepage_fn, CP_SUPPORTED);
3563
3564 Vw32_valid_codepages = Fnreverse (Vw32_valid_codepages);
3565 return Vw32_valid_codepages;
3566 }
3567
3568
3569 DEFUN ("w32-get-console-codepage", Fw32_get_console_codepage,
3570 Sw32_get_console_codepage, 0, 0, 0,
3571 doc: )
3572 (void)
3573 {
3574 return make_fixnum (GetConsoleCP ());
3575 }
3576
3577
3578 DEFUN ("w32-set-console-codepage", Fw32_set_console_codepage,
3579 Sw32_set_console_codepage, 1, 1, 0,
3580 doc:
3581
3582 )
3583 (Lisp_Object cp)
3584 {
3585 CHECK_FIXNUM (cp);
3586
3587 if (!IsValidCodePage (XFIXNUM (cp)))
3588 return Qnil;
3589
3590 if (!SetConsoleCP (XFIXNUM (cp)))
3591 return Qnil;
3592
3593 return make_fixnum (GetConsoleCP ());
3594 }
3595
3596
3597 DEFUN ("w32-get-console-output-codepage", Fw32_get_console_output_codepage,
3598 Sw32_get_console_output_codepage, 0, 0, 0,
3599 doc: )
3600 (void)
3601 {
3602 return make_fixnum (GetConsoleOutputCP ());
3603 }
3604
3605
3606 DEFUN ("w32-set-console-output-codepage", Fw32_set_console_output_codepage,
3607 Sw32_set_console_output_codepage, 1, 1, 0,
3608 doc:
3609
3610 )
3611 (Lisp_Object cp)
3612 {
3613 CHECK_FIXNUM (cp);
3614
3615 if (!IsValidCodePage (XFIXNUM (cp)))
3616 return Qnil;
3617
3618 if (!SetConsoleOutputCP (XFIXNUM (cp)))
3619 return Qnil;
3620
3621 return make_fixnum (GetConsoleOutputCP ());
3622 }
3623
3624
3625 DEFUN ("w32-get-codepage-charset", Fw32_get_codepage_charset,
3626 Sw32_get_codepage_charset, 1, 1, 0,
3627 doc:
3628
3629
3630
3631
3632
3633 )
3634 (Lisp_Object cp)
3635 {
3636 CHARSETINFO info;
3637 DWORD_PTR dwcp;
3638
3639 CHECK_FIXNUM (cp);
3640
3641 if (!IsValidCodePage (XFIXNUM (cp)))
3642 return Qnil;
3643
3644
3645
3646
3647 dwcp = XFIXNUM (cp);
3648 if (TranslateCharsetInfo ((DWORD *) dwcp, &info, TCI_SRCCODEPAGE))
3649 return make_fixnum (info.ciCharset);
3650
3651 return Qnil;
3652 }
3653
3654
3655 DEFUN ("w32-get-valid-keyboard-layouts", Fw32_get_valid_keyboard_layouts,
3656 Sw32_get_valid_keyboard_layouts, 0, 0, 0,
3657 doc:
3658 )
3659 (void)
3660 {
3661 int num_layouts = GetKeyboardLayoutList (0, NULL);
3662 HKL * layouts = (HKL *) alloca (num_layouts * sizeof (HKL));
3663 Lisp_Object obj = Qnil;
3664
3665 if (GetKeyboardLayoutList (num_layouts, layouts) == num_layouts)
3666 {
3667 while (--num_layouts >= 0)
3668 {
3669 HKL kl = layouts[num_layouts];
3670
3671 obj = Fcons (Fcons (make_fixnum (LOWORD (kl)),
3672 make_fixnum (HIWORD (kl))),
3673 obj);
3674 }
3675 }
3676
3677 return obj;
3678 }
3679
3680
3681 DEFUN ("w32-get-keyboard-layout", Fw32_get_keyboard_layout,
3682 Sw32_get_keyboard_layout, 0, 0, 0,
3683 doc:
3684 )
3685 (void)
3686 {
3687 HKL kl = GetKeyboardLayout (dwWindowsThreadId);
3688
3689 return Fcons (make_fixnum (LOWORD (kl)),
3690 make_fixnum (HIWORD (kl)));
3691 }
3692
3693
3694 DEFUN ("w32-set-keyboard-layout", Fw32_set_keyboard_layout,
3695 Sw32_set_keyboard_layout, 1, 1, 0,
3696 doc:
3697
3698 )
3699 (Lisp_Object layout)
3700 {
3701 HKL kl;
3702
3703 CHECK_CONS (layout);
3704 CHECK_FIXNUM (XCAR (layout));
3705 CHECK_FIXNUM (XCDR (layout));
3706
3707 kl = (HKL) (UINT_PTR) ((XFIXNUM (XCAR (layout)) & 0xffff)
3708 | (XFIXNUM (XCDR (layout)) << 16));
3709
3710
3711 if (dwWindowsThreadId)
3712 {
3713 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_SETKEYBOARDLAYOUT,
3714 (WPARAM) kl, 0))
3715 {
3716 MSG msg;
3717 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
3718
3719 if (msg.wParam == 0)
3720 return Qnil;
3721 }
3722 }
3723 else if (!ActivateKeyboardLayout (kl, 0))
3724 return Qnil;
3725
3726 return Fw32_get_keyboard_layout ();
3727 }
3728
3729
3730
3731 #ifndef LOCALE_NAME_MAX_LENGTH
3732 # define LOCALE_NAME_MAX_LENGTH 85
3733 #endif
3734 static LCID found_lcid;
3735 static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
3736
3737
3738 static BOOL CALLBACK
3739 get_lcid_callback (LPTSTR locale_num_str)
3740 {
3741 char *endp;
3742 char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
3743 LCID try_lcid = strtoul (locale_num_str, &endp, 16);
3744
3745 if (GetLocaleInfo (try_lcid, LOCALE_SABBREVLANGNAME,
3746 locval, LOCALE_NAME_MAX_LENGTH))
3747 {
3748 size_t locval_len;
3749
3750
3751 if (stricmp (locval, lname) == 0)
3752 {
3753 found_lcid = try_lcid;
3754 return FALSE;
3755 }
3756 locval_len = strlen (locval);
3757 strcpy (locval + locval_len, "_");
3758 if (GetLocaleInfo (try_lcid, LOCALE_SABBREVCTRYNAME,
3759 locval + locval_len + 1, LOCALE_NAME_MAX_LENGTH))
3760 {
3761 locval_len = strlen (locval);
3762 if (strnicmp (locval, lname, locval_len) == 0
3763 && (lname[locval_len] == '.'
3764 || lname[locval_len] == '\0'))
3765 {
3766 found_lcid = try_lcid;
3767 return FALSE;
3768 }
3769 }
3770 }
3771 return TRUE;
3772 }
3773
3774
3775
3776
3777
3778 static LCID
3779 get_lcid (const char *locale_name)
3780 {
3781
3782 static LCID last_lcid;
3783 static char last_locale[1000];
3784
3785
3786
3787 if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0)
3788 return last_lcid;
3789
3790 strncpy (lname, locale_name, sizeof (lname) - 1);
3791 lname[sizeof (lname) - 1] = '\0';
3792 found_lcid = 0;
3793 EnumSystemLocales (get_lcid_callback, LCID_SUPPORTED);
3794 if (found_lcid > 0)
3795 {
3796 last_lcid = found_lcid;
3797 strcpy (last_locale, locale_name);
3798 }
3799 return found_lcid;
3800 }
3801
3802 #ifndef _NLSCMPERROR
3803 # define _NLSCMPERROR INT_MAX
3804 #endif
3805 #ifndef LINGUISTIC_IGNORECASE
3806 # define LINGUISTIC_IGNORECASE 0x00000010
3807 #endif
3808
3809 typedef int (WINAPI *CompareStringW_Proc)
3810 (LCID, DWORD, LPCWSTR, int, LPCWSTR, int);
3811
3812 int
3813 w32_compare_strings (const char *s1, const char *s2, char *locname,
3814 int ignore_case)
3815 {
3816 LCID lcid = GetThreadLocale ();
3817 wchar_t *string1_w, *string2_w;
3818 int val, needed;
3819 static CompareStringW_Proc pCompareStringW;
3820 DWORD flags = 0;
3821
3822 USE_SAFE_ALLOCA;
3823
3824
3825
3826 if (locname
3827 && ((locname[0] == 'C' && (locname[1] == '\0' || locname[1] == '.'))
3828 || strcmp (locname, "POSIX") == 0))
3829 return (ignore_case ? stricmp (s1, s2) : strcmp (s1, s2));
3830
3831 if (!g_b_init_compare_string_w)
3832 {
3833 if (os_subtype == OS_SUBTYPE_9X)
3834 {
3835 pCompareStringW = (CompareStringW_Proc)
3836 get_proc_addr (LoadLibrary ("Unicows.dll"),
3837 "CompareStringW");
3838 if (!pCompareStringW)
3839 {
3840 errno = EINVAL;
3841
3842
3843 return _NLSCMPERROR;
3844 }
3845 }
3846 else
3847 pCompareStringW = CompareStringW;
3848
3849 g_b_init_compare_string_w = 1;
3850 }
3851
3852 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, NULL, 0);
3853 if (needed > 0)
3854 {
3855 SAFE_NALLOCA (string1_w, 1, needed + 1);
3856 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1,
3857 string1_w, needed);
3858 }
3859 else
3860 {
3861 errno = EINVAL;
3862 return _NLSCMPERROR;
3863 }
3864
3865 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0);
3866 if (needed > 0)
3867 {
3868 SAFE_NALLOCA (string2_w, 1, needed + 1);
3869 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1,
3870 string2_w, needed);
3871 }
3872 else
3873 {
3874 SAFE_FREE ();
3875 errno = EINVAL;
3876 return _NLSCMPERROR;
3877 }
3878
3879 if (locname)
3880 {
3881
3882
3883
3884
3885 LCID new_lcid = get_lcid (locname);
3886
3887 if (new_lcid > 0)
3888 lcid = new_lcid;
3889 else
3890 error ("Invalid locale %s: Invalid argument", locname);
3891 }
3892
3893 if (ignore_case)
3894 {
3895
3896
3897
3898
3899 if (w32_major_version >= 6)
3900 flags |= LINGUISTIC_IGNORECASE;
3901 else
3902 flags |= NORM_IGNORECASE;
3903 }
3904
3905
3906 if (!NILP (Vw32_collate_ignore_punctuation))
3907 flags |= NORM_IGNORESYMBOLS;
3908 val = pCompareStringW (lcid, flags, string1_w, -1, string2_w, -1);
3909 SAFE_FREE ();
3910 if (!val)
3911 {
3912 errno = EINVAL;
3913 return _NLSCMPERROR;
3914 }
3915 return val - 2;
3916 }
3917
3918
3919 void
3920 syms_of_ntproc (void)
3921 {
3922 DEFSYM (Qhigh, "high");
3923 DEFSYM (Qlow, "low");
3924 DEFSYM (Qcygwin, "cygwin");
3925 DEFSYM (Qmsys, "msys");
3926 DEFSYM (Qw32_native, "w32-native");
3927
3928 defsubr (&Sw32_has_winsock);
3929 defsubr (&Sw32_unload_winsock);
3930
3931 defsubr (&Sw32_short_file_name);
3932 defsubr (&Sw32_long_file_name);
3933 defsubr (&Sw32_set_process_priority);
3934 defsubr (&Sw32_application_type);
3935 defsubr (&Sw32_get_locale_info);
3936 defsubr (&Sw32_get_current_locale_id);
3937 defsubr (&Sw32_get_default_locale_id);
3938 defsubr (&Sw32_get_valid_locale_ids);
3939 defsubr (&Sw32_set_current_locale);
3940
3941 defsubr (&Sw32_get_console_codepage);
3942 defsubr (&Sw32_set_console_codepage);
3943 defsubr (&Sw32_get_console_output_codepage);
3944 defsubr (&Sw32_set_console_output_codepage);
3945 defsubr (&Sw32_get_valid_codepages);
3946 defsubr (&Sw32_get_codepage_charset);
3947
3948 defsubr (&Sw32_get_valid_keyboard_layouts);
3949 defsubr (&Sw32_get_keyboard_layout);
3950 defsubr (&Sw32_set_keyboard_layout);
3951
3952 DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args,
3953 doc:
3954
3955
3956
3957
3958
3959
3960
3961 );
3962 Vw32_quote_process_args = Qt;
3963
3964 DEFVAR_LISP ("w32-start-process-show-window",
3965 Vw32_start_process_show_window,
3966 doc:
3967
3968 );
3969 Vw32_start_process_show_window = Qnil;
3970
3971 DEFVAR_LISP ("w32-start-process-share-console",
3972 Vw32_start_process_share_console,
3973 doc:
3974
3975
3976
3977
3978 );
3979 Vw32_start_process_share_console = Qnil;
3980
3981 DEFVAR_LISP ("w32-start-process-inherit-error-mode",
3982 Vw32_start_process_inherit_error_mode,
3983 doc:
3984
3985 );
3986 Vw32_start_process_inherit_error_mode = Qt;
3987
3988 DEFVAR_INT ("w32-pipe-read-delay", w32_pipe_read_delay,
3989 doc:
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999 );
4000 w32_pipe_read_delay = 0;
4001
4002 DEFVAR_INT ("w32-pipe-buffer-size", w32_pipe_buffer_size,
4003 doc:
4004
4005
4006 );
4007 w32_pipe_buffer_size = 0;
4008
4009 DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names,
4010 doc:
4011
4012
4013
4014 );
4015 Vw32_downcase_file_names = Qnil;
4016
4017 #if 0
4018 DEFVAR_LISP ("w32-generate-fake-inodes", Vw32_generate_fake_inodes,
4019 doc:
4020
4021
4022
4023 );
4024 Vw32_generate_fake_inodes = Qnil;
4025 #endif
4026
4027 DEFVAR_LISP ("w32-get-true-file-attributes", Vw32_get_true_file_attributes,
4028 doc:
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039 );
4040 Vw32_get_true_file_attributes = Qlocal;
4041
4042 DEFVAR_LISP ("w32-collate-ignore-punctuation",
4043 Vw32_collate_ignore_punctuation,
4044 doc:
4045
4046
4047
4048
4049
4050
4051
4052
4053 );
4054 Vw32_collate_ignore_punctuation = Qnil;
4055
4056 staticpro (&Vw32_valid_locale_ids);
4057 staticpro (&Vw32_valid_codepages);
4058 }
4059