442
|
1 /* Utility routines for XEmacs on Windows 9x, NT and Cygwin.
|
|
2 Copyright (C) 2000 Ben Wing.
|
|
3
|
|
4 This file is part of XEmacs.
|
|
5
|
|
6 XEmacs is free software; you can redistribute it and/or modify it
|
|
7 under the terms of the GNU General Public License as published by the
|
|
8 Free Software Foundation; either version 2, or (at your option) any
|
|
9 later version.
|
|
10
|
|
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
|
|
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 for more details.
|
|
15
|
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with XEmacs; see the file COPYING. If not, write to the Free
|
|
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
19 02111-1307, USA. */
|
|
20
|
|
21 #include <config.h>
|
|
22 #include "lisp.h"
|
|
23
|
|
24 #include "buffer.h"
|
611
|
25
|
|
26 #include "syssignal.h"
|
|
27 #include "systime.h"
|
442
|
28 #include "syswindows.h"
|
|
29
|
|
30 typedef BOOL (WINAPI *pfSwitchToThread_t) (VOID);
|
|
31 pfSwitchToThread_t xSwitchToThread;
|
|
32
|
|
33 typedef HKL (WINAPI *pfGetKeyboardLayout_t) (DWORD);
|
|
34 pfGetKeyboardLayout_t xGetKeyboardLayout;
|
|
35 typedef BOOL (WINAPI *pfSetMenuDefaultItem_t) (HMENU, UINT, UINT);
|
|
36 pfSetMenuDefaultItem_t xSetMenuDefaultItem;
|
|
37 typedef BOOL (WINAPI *pfInsertMenuItemA_t)
|
|
38 (HMENU, UINT, BOOL, LPCMENUITEMINFOA);
|
|
39 pfInsertMenuItemA_t xInsertMenuItemA;
|
|
40 typedef BOOL (WINAPI *pfInsertMenuItemW_t)
|
|
41 (HMENU, UINT, BOOL, LPCMENUITEMINFOW);
|
|
42 pfInsertMenuItemW_t xInsertMenuItemW;
|
|
43 typedef HANDLE (WINAPI *pfLoadImageA_t)
|
|
44 (HINSTANCE, LPCSTR, UINT, int, int, UINT);
|
|
45 pfLoadImageA_t xLoadImageA;
|
|
46 typedef HANDLE (WINAPI *pfLoadImageW_t)
|
|
47 (HINSTANCE, LPCWSTR, UINT, int, int, UINT);
|
|
48 pfLoadImageW_t xLoadImageW;
|
|
49 typedef ATOM (WINAPI *pfRegisterClassExA_t) (CONST WNDCLASSEXA *);
|
|
50 pfRegisterClassExA_t xRegisterClassExA;
|
|
51 typedef ATOM (WINAPI *pfRegisterClassExW_t) (CONST WNDCLASSEXW *);
|
|
52 pfRegisterClassExW_t xRegisterClassExW;
|
|
53
|
|
54 typedef int (WINAPI *pfEnumFontFamiliesExA_t)
|
|
55 (HDC, LPLOGFONTA, FONTENUMPROCA, LPARAM, DWORD);
|
|
56 pfEnumFontFamiliesExA_t xEnumFontFamiliesExA;
|
|
57 typedef int (WINAPI *pfEnumFontFamiliesExW_t)
|
|
58 (HDC, LPLOGFONTW, FONTENUMPROCW, LPARAM, DWORD);
|
|
59 pfEnumFontFamiliesExW_t xEnumFontFamiliesExW;
|
|
60
|
|
61 typedef DWORD (WINAPI *pfSHGetFileInfoA_t)
|
|
62 (LPCSTR, DWORD, SHFILEINFOA FAR *, UINT, UINT);
|
|
63 pfSHGetFileInfoA_t xSHGetFileInfoA;
|
|
64 typedef DWORD (WINAPI *pfSHGetFileInfoW_t)
|
|
65 (LPCWSTR, DWORD, SHFILEINFOW FAR *, UINT, UINT);
|
|
66 pfSHGetFileInfoW_t xSHGetFileInfoW;
|
|
67
|
531
|
68 typedef NET_API_STATUS (NET_API_FUNCTION *pfNetUserEnum_t)
|
|
69 (
|
|
70 IN LPCWSTR servername OPTIONAL,
|
|
71 IN DWORD level,
|
|
72 IN DWORD filter,
|
|
73 OUT LPBYTE *bufptr,
|
|
74 IN DWORD prefmaxlen,
|
|
75 OUT LPDWORD entriesread,
|
|
76 OUT LPDWORD totalentries,
|
|
77 IN OUT LPDWORD resume_handle OPTIONAL
|
|
78 );
|
|
79 pfNetUserEnum_t xNetUserEnum;
|
|
80
|
|
81 typedef NET_API_STATUS (NET_API_FUNCTION *pfNetApiBufferFree_t)
|
|
82 (
|
|
83 IN LPVOID Buffer
|
|
84 );
|
|
85 pfNetApiBufferFree_t xNetApiBufferFree;
|
|
86
|
442
|
87 Lisp_Object
|
|
88 tstr_to_local_file_format (Extbyte *pathout)
|
|
89 {
|
665
|
90 Intbyte *ttlff;
|
442
|
91 Lisp_Object in;
|
|
92
|
|
93 EXTERNAL_TO_C_STRING (pathout, ttlff, Qmswindows_tstr);
|
|
94 WIN32_TO_LOCAL_FILE_FORMAT (ttlff, in);
|
|
95
|
|
96 return in;
|
|
97 }
|
|
98
|
|
99 static void
|
|
100 init_potentially_nonexistent_functions (void)
|
|
101 {
|
|
102 HMODULE h_kernel = GetModuleHandle ("kernel32");
|
|
103 HMODULE h_user = GetModuleHandle ("user32");
|
|
104 HMODULE h_gdi = GetModuleHandle ("gdi32");
|
|
105 HMODULE h_shell = GetModuleHandle ("shell32");
|
531
|
106 /* the following does not seem to get mapped in automatically */
|
|
107 HMODULE h_netapi = LoadLibrary ("netapi32.dll");
|
442
|
108
|
|
109 if (h_kernel)
|
|
110 {
|
|
111 xSwitchToThread =
|
|
112 (pfSwitchToThread_t) GetProcAddress (h_kernel, "SwitchToThread");
|
|
113 }
|
|
114
|
|
115 if (h_user)
|
|
116 {
|
|
117 xGetKeyboardLayout =
|
|
118 (pfGetKeyboardLayout_t) GetProcAddress (h_user, "GetKeyboardLayout");
|
|
119 xSetMenuDefaultItem =
|
|
120 (pfSetMenuDefaultItem_t) GetProcAddress (h_user, "SetMenuDefaultItem");
|
|
121 xInsertMenuItemA =
|
|
122 (pfInsertMenuItemA_t) GetProcAddress (h_user, "InsertMenuItemA");
|
|
123 xInsertMenuItemW =
|
|
124 (pfInsertMenuItemW_t) GetProcAddress (h_user, "InsertMenuItemW");
|
|
125 xLoadImageA =
|
|
126 (pfLoadImageA_t) GetProcAddress (h_user, "LoadImageA");
|
|
127 xLoadImageW =
|
|
128 (pfLoadImageW_t) GetProcAddress (h_user, "LoadImageW");
|
|
129 xRegisterClassExA =
|
|
130 (pfRegisterClassExA_t) GetProcAddress (h_user, "RegisterClassExA");
|
|
131 xRegisterClassExW =
|
|
132 (pfRegisterClassExW_t) GetProcAddress (h_user, "RegisterClassExW");
|
|
133 }
|
|
134
|
|
135 if (h_gdi)
|
|
136 {
|
|
137 xEnumFontFamiliesExA =
|
|
138 (pfEnumFontFamiliesExA_t) GetProcAddress (h_gdi, "EnumFontFamiliesExA");
|
|
139 xEnumFontFamiliesExW =
|
|
140 (pfEnumFontFamiliesExW_t) GetProcAddress (h_gdi, "EnumFontFamiliesExW");
|
|
141 }
|
|
142
|
|
143 if (h_shell)
|
|
144 {
|
|
145 xSHGetFileInfoA =
|
|
146 (pfSHGetFileInfoA_t) GetProcAddress (h_shell, "SHGetFileInfoA");
|
|
147 xSHGetFileInfoW =
|
|
148 (pfSHGetFileInfoW_t) GetProcAddress (h_shell, "SHGetFileInfoW");
|
|
149 }
|
531
|
150
|
|
151 if (h_netapi)
|
|
152 {
|
|
153 xNetUserEnum =
|
|
154 (pfNetUserEnum_t) GetProcAddress (h_netapi, "NetUserEnum");
|
|
155 xNetApiBufferFree =
|
|
156 (pfNetApiBufferFree_t) GetProcAddress (h_netapi, "NetApiBufferFree");
|
|
157 }
|
442
|
158 }
|
|
159
|
|
160 DEFUN ("mswindows-shell-execute", Fmswindows_shell_execute, 2, 4, 0, /*
|
|
161 Get Windows to perform OPERATION on DOCUMENT.
|
|
162 This is a wrapper around the ShellExecute system function, which
|
|
163 invokes the application registered to handle OPERATION for DOCUMENT.
|
|
164 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
|
|
165 nil for the default action), and DOCUMENT is typically the name of a
|
|
166 document file or URL, but can also be a program executable to run or
|
|
167 a directory to open in the Windows Explorer.
|
|
168
|
|
169 If DOCUMENT is a program executable, PARAMETERS can be a string
|
|
170 containing command line parameters, but otherwise should be nil.
|
|
171
|
|
172 SHOW-FLAG can be used to control whether the invoked application is hidden
|
|
173 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
|
|
174 otherwise it is an integer representing a ShowWindow flag:
|
|
175
|
|
176 0 - start hidden
|
|
177 1 - start normally
|
|
178 3 - start maximized
|
|
179 6 - start minimized
|
|
180 */
|
|
181 (operation, document, parameters, show_flag))
|
|
182 {
|
|
183 /* Encode filename and current directory. */
|
|
184 Lisp_Object current_dir = Ffile_name_directory (document);
|
|
185 char* path = NULL;
|
673
|
186 #ifdef CYGWIN
|
|
187 char* fname1, *fname2;
|
|
188 int pos, sz;
|
|
189 #endif
|
442
|
190 char* doc = NULL;
|
|
191 int ret;
|
|
192 struct gcpro gcpro1, gcpro2;
|
|
193
|
|
194 CHECK_STRING (document);
|
|
195
|
|
196 if (NILP (current_dir))
|
|
197 current_dir = current_buffer->directory;
|
|
198
|
|
199 GCPRO2 (current_dir, document);
|
|
200
|
|
201 /* Use mule and cygwin-safe APIs top get at file data. */
|
|
202 if (STRINGP (current_dir))
|
|
203 {
|
673
|
204 LOCAL_TO_WIN32_FILE_FORMAT (current_dir, path);
|
442
|
205 }
|
|
206
|
|
207 if (STRINGP (document))
|
|
208 {
|
673
|
209 doc = XSTRING_DATA (document);
|
442
|
210 #ifdef CYGWIN
|
673
|
211 if ((fname1 = strchr (doc, ':')) != NULL
|
|
212 && *++fname1 == '/' && *++fname1 == '/')
|
|
213 {
|
707
|
214 // URL-style if we get here, but we must only convert file
|
|
215 // arguments, since win32 paths are illegal in http etc.
|
|
216 if (strncmp (doc, "file://", 7) == 0)
|
673
|
217 {
|
707
|
218 fname1++;
|
|
219 pos = fname1 - doc;
|
|
220 if (!(isalpha (fname1[0]) && (IS_DEVICE_SEP (fname1[1]))))
|
|
221 {
|
|
222 sz = cygwin_posix_to_win32_path_list_buf_size (fname1);
|
|
223 fname2 = alloca (sz + pos);
|
|
224 strncpy (fname2, doc, pos);
|
|
225 doc = fname2;
|
|
226 fname2 += pos;
|
|
227 cygwin_posix_to_win32_path_list (fname1, fname2);
|
|
228 }
|
673
|
229 }
|
|
230 }
|
|
231 else {
|
707
|
232 // Not URL-style, must be a straight filename.
|
673
|
233 LOCAL_TO_WIN32_FILE_FORMAT (document, doc);
|
|
234 }
|
442
|
235 #endif
|
|
236 }
|
|
237
|
|
238 UNGCPRO;
|
|
239
|
|
240 ret = (int) ShellExecute (NULL,
|
|
241 (STRINGP (operation) ?
|
593
|
242 /* !!#### more mule bogosity */
|
|
243 (char *) XSTRING_DATA (operation) : NULL),
|
442
|
244 doc,
|
|
245 (STRINGP (parameters) ?
|
593
|
246 /* !!#### more mule bogosity */
|
|
247 (char *) XSTRING_DATA (parameters) : NULL),
|
442
|
248 path,
|
|
249 (INTP (show_flag) ?
|
|
250 XINT (show_flag) : SW_SHOWDEFAULT));
|
|
251
|
|
252 if (ret > 32)
|
|
253 return Qt;
|
|
254
|
|
255 if (ret == ERROR_FILE_NOT_FOUND)
|
563
|
256 signal_error (Qfile_error, "file not found", document);
|
442
|
257 else if (ret == ERROR_PATH_NOT_FOUND)
|
563
|
258 signal_error (Qfile_error, "path not found", current_dir);
|
442
|
259 else if (ret == ERROR_BAD_FORMAT)
|
563
|
260 signal_error (Qfile_error, "bad executable format", document);
|
442
|
261 else
|
563
|
262 signal_error (Qinternal_error, "internal error", Qunbound);
|
442
|
263
|
|
264 return Qnil;
|
|
265 }
|
|
266
|
673
|
267 #ifdef CYGWIN
|
|
268 DEFUN ("mswindows-cygwin-to-win32-path", Fmswindows_cygwin_to_win32_path, 1, 1, 0, /*
|
|
269 Get the cygwin environment to convert the Unix PATH to win32 format.
|
|
270 No expansion is performed, all conversion is done by the cygwin runtime.
|
|
271 */
|
|
272 (path))
|
|
273 {
|
|
274 Extbyte* f;
|
|
275 Intbyte* p;
|
|
276 CHECK_STRING (path);
|
|
277
|
|
278 /* There appears to be a bug in the cygwin conversion routines in
|
|
279 that they are not idempotent. */
|
|
280 p = XSTRING_DATA (path);
|
|
281 if (isalpha (p[0]) && (IS_DEVICE_SEP (p[1])))
|
|
282 return path;
|
|
283
|
|
284 /* Use mule and cygwin-safe APIs top get at file data. */
|
|
285 LOCAL_TO_WIN32_FILE_FORMAT (path, f);
|
|
286 return build_ext_string (f, Qnative);
|
|
287 }
|
|
288 #endif
|
|
289
|
613
|
290 #if defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS)
|
|
291
|
|
292 /* setitimer() does not exist on native MS Windows, and appears broken
|
|
293 on Cygwin (random lockups when BROKEN_SIGIO is defined), so we
|
|
294 emulate in both cases by using multimedia timers. Furthermore,
|
|
295 the lockups still occur on Cygwin even when we do nothing but
|
|
296 use the standard signalling mechanism -- so we have to emulate
|
|
297 that, too. (But only for timeouts -- we have to use the standard
|
|
298 mechanism for SIGCHLD. Yuck.)
|
|
299 */
|
|
300
|
|
301
|
|
302 /*--------------------------------------------------------------------*/
|
|
303 /* Signal support */
|
|
304 /*--------------------------------------------------------------------*/
|
|
305
|
|
306 #define sigmask(nsig) (1U << nsig)
|
|
307
|
|
308 /* We can support as many signals as fit into word */
|
|
309 #define SIG_MAX 32
|
|
310
|
|
311 /* Signal handlers. Initial value = 0 = SIG_DFL */
|
|
312 static mswindows_sighandler signal_handlers[SIG_MAX] = {0};
|
|
313
|
|
314 /* Signal block mask: bit set to 1 means blocked */
|
|
315 unsigned signal_block_mask = 0;
|
|
316
|
|
317 /* Signal pending mask: bit set to 1 means sig is pending */
|
|
318 unsigned signal_pending_mask = 0;
|
|
319
|
|
320 mswindows_sighandler
|
|
321 mswindows_sigset (int nsig, mswindows_sighandler handler)
|
|
322 {
|
|
323 /* We delegate some signals to the system function */
|
|
324 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
|
|
325 return signal (nsig, handler);
|
|
326
|
|
327 if (nsig < 0 || nsig > SIG_MAX)
|
|
328 {
|
|
329 errno = EINVAL;
|
|
330 return NULL;
|
|
331 }
|
|
332
|
|
333 /* Store handler ptr */
|
|
334 {
|
|
335 mswindows_sighandler old_handler = signal_handlers[nsig];
|
|
336 signal_handlers[nsig] = handler;
|
|
337 return old_handler;
|
|
338 }
|
|
339 }
|
|
340
|
|
341 int
|
|
342 mswindows_sighold (int nsig)
|
|
343 {
|
|
344 if (nsig < 0 || nsig > SIG_MAX)
|
|
345 return errno = EINVAL;
|
|
346
|
|
347 signal_block_mask |= sigmask (nsig);
|
|
348 return 0;
|
|
349 }
|
|
350
|
|
351 int
|
|
352 mswindows_sigrelse (int nsig)
|
|
353 {
|
|
354 if (nsig < 0 || nsig > SIG_MAX)
|
|
355 return errno = EINVAL;
|
|
356
|
|
357 signal_block_mask &= ~sigmask (nsig);
|
|
358
|
|
359 if (signal_pending_mask & sigmask (nsig))
|
|
360 mswindows_raise (nsig);
|
|
361
|
|
362 return 0;
|
|
363 }
|
|
364
|
|
365 int
|
|
366 mswindows_sigpause (int nsig)
|
|
367 {
|
|
368 /* This is currently not called, because the only call to sigpause
|
|
369 inside XEmacs is with SIGCHLD parameter. Just in case, we put an
|
|
370 assert here, so anyone adds a call to sigpause will be surprised
|
|
371 (or surprise someone else...) */
|
|
372 assert (0);
|
|
373 return 0;
|
|
374 }
|
|
375
|
|
376 int
|
|
377 mswindows_raise (int nsig)
|
|
378 {
|
|
379 /* We delegate some raises to the system routine */
|
|
380 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
|
|
381 return raise (nsig);
|
|
382
|
|
383 if (nsig < 0 || nsig > SIG_MAX)
|
|
384 return errno = EINVAL;
|
|
385
|
|
386 /* If the signal is blocked, remember to issue later */
|
|
387 if (signal_block_mask & sigmask (nsig))
|
|
388 {
|
|
389 signal_pending_mask |= sigmask (nsig);
|
|
390 return 0;
|
|
391 }
|
|
392
|
|
393 if (signal_handlers[nsig] == SIG_IGN)
|
|
394 return 0;
|
|
395
|
|
396 if (signal_handlers[nsig] != SIG_DFL)
|
|
397 {
|
|
398 (*signal_handlers[nsig]) (nsig);
|
|
399 return 0;
|
|
400 }
|
|
401
|
|
402 /* Default signal actions */
|
|
403 if (nsig == SIGALRM || nsig == SIGPROF)
|
|
404 exit (3);
|
|
405
|
|
406 /* Other signals are ignored by default */
|
|
407 return 0;
|
|
408 }
|
|
409
|
611
|
410
|
|
411 /*--------------------------------------------------------------------*/
|
|
412 /* Async timers */
|
|
413 /*--------------------------------------------------------------------*/
|
|
414
|
|
415 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
|
|
416
|
|
417 itimerproc() function has an implementation limitation: it does
|
|
418 not allow to set *both* interval and period. If an attempt is
|
|
419 made to set both, and then they are unequal, the function
|
|
420 asserts.
|
|
421
|
|
422 Minimum timer resolution on Win32 systems varies, and is greater
|
|
423 than or equal than 1 ms. The resolution is always wrapped not to
|
|
424 attempt to get below the system defined limit.
|
|
425 */
|
|
426
|
|
427 /* Timer precision, denominator of one fraction: for 100 ms
|
|
428 interval, request 10 ms precision
|
|
429 */
|
|
430 const int setitimer_helper_timer_prec = 10;
|
|
431
|
|
432 /* Last itimervals, as set by calls to setitimer */
|
|
433 static struct itimerval it_alarm;
|
|
434 static struct itimerval it_prof;
|
|
435
|
|
436 /* Timer IDs as returned by MM */
|
|
437 MMRESULT tid_alarm = 0;
|
|
438 MMRESULT tid_prof = 0;
|
|
439
|
|
440 static void CALLBACK
|
|
441 setitimer_helper_proc (UINT uID, UINT uMsg, DWORD dwUser,
|
|
442 DWORD dw1, DWORD dw2)
|
|
443 {
|
|
444 /* Just raise the signal indicated by the dwUser parameter */
|
|
445 mswindows_raise (dwUser);
|
|
446 }
|
|
447
|
|
448 /* Divide time in ms specified by IT by DENOM. Return 1 ms
|
|
449 if division results in zero */
|
|
450 static UINT
|
|
451 setitimer_helper_period (const struct itimerval* it, UINT denom)
|
|
452 {
|
|
453 static TIMECAPS time_caps;
|
|
454
|
|
455 UINT res;
|
|
456 const struct timeval* tv =
|
|
457 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
|
|
458 ? &it->it_interval : &it->it_value;
|
|
459
|
|
460 /* Zero means stop timer */
|
|
461 if (tv->tv_sec == 0 && tv->tv_usec == 0)
|
|
462 return 0;
|
|
463
|
|
464 /* Convert to ms and divide by denom */
|
|
465 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
|
|
466
|
|
467 /* Converge to minimum timer resolution */
|
|
468 if (time_caps.wPeriodMin == 0)
|
|
469 timeGetDevCaps (&time_caps, sizeof(time_caps));
|
|
470
|
|
471 if (res < time_caps.wPeriodMin)
|
|
472 res = time_caps.wPeriodMin;
|
|
473
|
|
474 return res;
|
|
475 }
|
|
476
|
|
477 static int
|
|
478 setitimer_helper (const struct itimerval* itnew,
|
|
479 struct itimerval* itold, struct itimerval* itcurrent,
|
|
480 MMRESULT* tid, DWORD sigkind)
|
|
481 {
|
|
482 UINT delay, resolution, event_type;
|
|
483
|
|
484 /* First stop the old timer */
|
|
485 if (*tid)
|
|
486 {
|
|
487 timeKillEvent (*tid);
|
|
488 timeEndPeriod (setitimer_helper_period (itcurrent,
|
|
489 setitimer_helper_timer_prec));
|
|
490 *tid = 0;
|
|
491 }
|
|
492
|
|
493 /* Return old itimerval if requested */
|
|
494 if (itold)
|
|
495 *itold = *itcurrent;
|
|
496
|
|
497 *itcurrent = *itnew;
|
|
498
|
|
499 /* Determine if to start new timer */
|
|
500 delay = setitimer_helper_period (itnew, 1);
|
|
501 if (delay)
|
|
502 {
|
|
503 resolution = setitimer_helper_period (itnew,
|
|
504 setitimer_helper_timer_prec);
|
|
505 event_type = (itnew->it_value.tv_sec == 0 &&
|
|
506 itnew->it_value.tv_usec == 0)
|
|
507 ? TIME_ONESHOT : TIME_PERIODIC;
|
|
508 timeBeginPeriod (resolution);
|
|
509 *tid = timeSetEvent (delay, resolution, setitimer_helper_proc, sigkind,
|
|
510 event_type);
|
|
511 }
|
|
512
|
|
513 return !delay || *tid;
|
|
514 }
|
|
515
|
|
516 int
|
|
517 mswindows_setitimer (int kind, const struct itimerval *itnew,
|
|
518 struct itimerval *itold)
|
|
519 {
|
|
520 /* In this version, both interval and value are allowed
|
|
521 only if they are equal. */
|
|
522 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
|
|
523 || (itnew->it_interval.tv_sec == 0 &&
|
|
524 itnew->it_interval.tv_usec == 0)
|
|
525 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
|
|
526 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
|
|
527
|
|
528 if (kind == ITIMER_REAL)
|
|
529 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
|
|
530 else if (kind == ITIMER_PROF)
|
|
531 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
|
|
532 else
|
|
533 return errno = EINVAL;
|
|
534 }
|
|
535
|
613
|
536 #endif /* defined (WIN32_NATIVE) || defined (CYGWIN_BROKEN_SIGNALS) */
|
|
537
|
611
|
538
|
442
|
539 void
|
|
540 syms_of_win32 (void)
|
|
541 {
|
|
542 DEFSUBR (Fmswindows_shell_execute);
|
673
|
543 #ifdef CYGWIN
|
|
544 DEFSUBR (Fmswindows_cygwin_to_win32_path);
|
|
545 #endif
|
442
|
546 }
|
|
547
|
|
548 void
|
|
549 init_win32 (void)
|
|
550 {
|
|
551 init_potentially_nonexistent_functions ();
|
|
552 }
|