2 * The Regina Rexx Interpreter
3 * Copyright (C) 2005 Florian Grosse-Coosmann
5 * This file contains Windows specific code.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 # if defined(__BORLANDC__) || defined(__LCC__)
38 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
39 # pragma warning(disable: 4115 4201 4214 4514)
45 # pragma warning(default: 4115 4201 4214)
50 #if (defined(__WATCOMC__) && !defined(__QNX__)) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__EPOC32__) || defined(__WINS__) || defined(__LCC__)
51 # include "utsname.h" /* MH 10-06-96 */
53 # if !defined(__WINS__) && !defined(__EPOC32__)
54 # define MAXPATHLEN _MAX_PATH /* MH 10-06-96 */
56 #else /* MH 10-06-96 */
57 # if defined(WIN32) && defined(__IBMC__) /* LM 26-02-99 */
60 # define MAXPATHLEN (8192)
63 # include <sys/param.h> /* MH 10-06-96 */
64 # include <sys/utsname.h> /* MH 10-06-96 */
65 # include <sys/wait.h>
69 #if (defined(__WATCOMC__) && !defined(__QNX__)) || defined(_MSC_VER) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__BORLANDC__) || defined(__MINGW32__) || defined(__WINS__) || defined(__EPOC32__)
70 # define HAVE_BROKEN_TMPNAM
71 # define PATH_DELIMS ":\\/"
72 # if defined(__CYGWIN32__)
73 # define ISTR_SLASH "/" /* This is not a must, \\ works, too */
74 # define I_SLASH '/' /* This is not a must, \\ works, too */
76 # define ISTR_SLASH "\\" /* This is not a must, / works at least for MSC, too */
77 # define I_SLASH '\\' /* This is not a must, / works at least for MSC, too */
79 # if !defined(__WINS__) && !defined(__EPOC32__) && !defined(__CYGWIN__)
80 # ifndef HAVE_UNISTD_H
81 # include <io.h> /* access() */
90 # if !defined(HasOverlappedIoCompleted)
91 # define HasOverlappedIoCompleted(lpOverlapped) ((lpOverlapped)->Internal != STATUS_PENDING)
95 static int IsWin9X(void)
97 static int retval
= -1;
104 if (getenv("REGINA_ACT_AS_WIN9X") != NULL
)
111 osinfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
112 GetVersionEx( &osinfo
);
114 switch( osinfo
.dwPlatformId
) {
115 case VER_PLATFORM_WIN32s
: /* Very stupid system */
116 case VER_PLATFORM_WIN32_WINDOWS
: /* Stupid systems */
120 case VER_PLATFORM_WIN32_NT
: /* Reasonable systems ... just my 2 ct, FGC */
144 static BOOL
MyCancelIo(HANDLE handle
)
146 static BOOL (WINAPI
*DoCancelIo
)(HANDLE handle
) = NULL
;
147 static BOOL first
= TRUE
;
153 * The kernel is always mapped, a LoadLibrary is useless
155 if ( ( mod
= GetModuleHandle( "kernel32" ) ) != NULL
)
157 DoCancelIo
= (BOOL (WINAPI
*)(HANDLE
)) GetProcAddress( mod
, "CancelIo" );
161 * It's safe now to set first. Never do it before the main work,
162 * otherwise we're not reentrant.
167 if ( DoCancelIo
== NULL
)
170 return DoCancelIo( handle
);
173 static int Win_setenv( const char *name
, const char *value
)
175 return SetEnvironmentVariable( name
, value
);
178 /* fork_exec spawns a new process with the given commandline.
179 * it returns -1 on error (errno set), 0 on process start error (rcode set),
180 * a process descriptor otherwise.
181 * Basically this is a child process and we run in the child's environment
182 * after the first few lines. The setup hasn't been done and the command needs
184 * Redirection takes place if one of the handles env->input.hdls[0],
185 * env->output.hdls[1] or env->error.hdls[1] is defined. Other handles (except
186 * standard handles) are closed. env->subtype must be a SUBENVIR_... constant.
187 * cmdline is the whole command line.
188 * Never use TSD after the fork() since this is not only a different thread,
189 * it's a different process!
191 static int Win_fork_exec(tsd_t
*TSD
, environment
*env
, const char *cmdline
, int *rcode
)
193 static const char *interpreter
[] = { "regina.exe", /* preferable even if */
196 PROCESS_INFORMATION pinfo
;
199 char *execname
= NULL
;
200 const char *commandline
= NULL
;
201 char *argline
= NULL
;
203 int broken_address_command
= get_options_flag( TSD
->currlevel
, EXT_BROKEN_ADDRESS_COMMAND
);
206 if (env
->subtype
== SUBENVIR_REXX
) /*special situation caused by recursion*/
208 environment e
= *env
;
214 len
= 11; /* max("rexx.exe", "regina.exe") */
217 len
= strlen(argv0
) + 2;
219 len
= 11; /* max("rexx.exe", "regina.exe") */
221 len
+= strlen(cmdline
) + 2; /* Blank + term ASCII0 */
223 if ((new_cmdline
= malloc(len
)) == NULL
)
224 return(-1); /* ENOMEM is set */
226 if (argv0
!= NULL
) /* always the best choice */
228 strcpy(new_cmdline
, "\"");
229 strcat(new_cmdline
, argv0
);
230 strcat(new_cmdline
, "\" ");
231 strcat(new_cmdline
, cmdline
);
232 e
.subtype
= SUBENVIR_COMMAND
;
233 rc
= Win_fork_exec(TSD
, &e
, new_cmdline
, &rc
);
234 if ( ( rc
!= 0 ) && ( rc
!= -1 ) )
241 /* load an interpreter by name from the path */
242 for (i
= 0; i
< sizeof(interpreter
) / sizeof(interpreter
[0]);i
++)
244 strcpy(new_cmdline
, interpreter
[i
]);
245 strcat(new_cmdline
, " ");
246 strcat(new_cmdline
, cmdline
);
247 e
.subtype
= SUBENVIR_COMMAND
;
248 rc
= Win_fork_exec(TSD
, &e
, new_cmdline
, &rc
);
249 if ( ( rc
!= 0 ) && ( rc
!= -1 ) )
256 *rcode
= -errno
; /* assume a load error */
261 memset(&sinfo
, 0, sizeof(sinfo
));
262 sinfo
.cb
= sizeof(sinfo
);
264 sinfo
.dwFlags
= STARTF_USESTDHANDLES
;
266 /* The following three handles have been created inheritable */
267 if (env
->input
.hdls
[0] != -1)
271 sinfo
.hStdInput
= (HANDLE
) _get_osfhandle(env
->input
.hdls
[0]);
274 * We must ensure the called process already *uses* the handles;
275 * they are closed by the OS in the other case. One chance is to
276 * delay the execution until this happens, the other chance is to
277 * wait with the closing until the called process works or
278 * terminates. We use the latter one. For more info see MSDN.
279 * Topics: Q190351, *Q150956*
280 * I think, Q150956 is a workaround for the bug they didn't solve.
281 * M$ just close the handles too early.
283 DuplicateHandle( GetCurrentProcess(),
289 DUPLICATE_SAME_ACCESS
);
293 env
->input
.hdls
[2] = (int) sinfo
.hStdInput
;
296 sinfo
.hStdInput
= (HANDLE
) env
->input
.hdls
[0];
299 sinfo
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
300 if (env
->output
.hdls
[1] != -1)
304 sinfo
.hStdOutput
= (HANDLE
) _get_osfhandle(env
->output
.hdls
[1]);
305 DuplicateHandle( GetCurrentProcess(),
311 DUPLICATE_SAME_ACCESS
);
315 env
->output
.hdls
[2] = (int) sinfo
.hStdOutput
;
318 sinfo
.hStdOutput
= (HANDLE
) env
->output
.hdls
[1];
321 sinfo
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
322 if (env
->error
.SameAsOutput
)
323 sinfo
.hStdError
= (HANDLE
) sinfo
.hStdOutput
;
324 else if (env
->error
.hdls
[1] != -1)
328 sinfo
.hStdError
= (HANDLE
) _get_osfhandle(env
->error
.hdls
[1]);
329 DuplicateHandle( GetCurrentProcess(),
335 DUPLICATE_SAME_ACCESS
);
339 env
->error
.hdls
[2] = (int) sinfo
.hStdError
;
342 sinfo
.hStdError
= (HANDLE
) env
->error
.hdls
[1];
345 sinfo
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
348 * If the BROKEN_ADDRESS_COMMAND OPTION is in place,
349 * and our environment is COMMAND, change it to SYSTEM
351 if ( env
->subtype
== SUBENVIR_PATH
/* was SUBENVIR_COMMAND */
352 && broken_address_command
)
353 subtype
= SUBENVIR_SYSTEM
;
355 subtype
= env
->subtype
;
361 commandline
= cmdline
;
364 case SUBENVIR_COMMAND
:
366 commandline
= cmdline
;
367 #define NEED_SPLITOFFARG
368 execname
= splitoffarg(cmdline
, NULL
, '^');
369 commandline
= cmdline
;
372 case SUBENVIR_SYSTEM
:
373 /* insert "%COMSPEC% /c " or "%SHELL% -c " in front */
374 if ((done
= GetEnvironmentVariable("COMSPEC","",0)) != 0)
376 argline
= MallocTSD(done
+ strlen(cmdline
) + 5);
377 GetEnvironmentVariable("COMSPEC",argline
,done
+ 5);
378 strcat(argline
," /c ");
380 else if ((done
= GetEnvironmentVariable("SHELL","",0)) != 0)
382 argline
= MallocTSD(done
+ strlen(cmdline
) + 5);
383 GetEnvironmentVariable("SHELL",argline
,done
+ 5);
384 strcat(argline
," -c ");
388 argline
= MallocTSD(11 + strlen(cmdline
) + 5);
389 if (GetVersion() & 0x80000000) /* not NT ? */
390 strcpy(argline
,"COMMAND.COM /c ");
392 strcpy(argline
,"CMD.EXE /c ");
394 strcat(argline
, cmdline
);
396 commandline
= argline
;
402 default: /* illegal subtype */
408 * FGC: I checked different configurations.
409 * 1) Never use DETACHED_PROCESS, the communication gets lost in NT
410 * kernels to a text program invoked using shells.
411 * 2) Never use STARTF_USESHOWWINDOW/SW_HIDE in Win9x, this gives problems
412 * under Win9x or you have to know which combination fits to COMSPEC and
413 * your called program's type.
414 * --> We can fiddle with CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP,
415 * CREATE_DEFAULT_ERROR_MODE. Select your choice!
419 sinfo
.dwFlags
|= STARTF_USESHOWWINDOW
;
420 sinfo
.wShowWindow
= SW_HIDE
;
422 rc
= CreateProcess(execname
,
423 (char *) commandline
,
424 NULL
, /* pointer to process security attributes */
425 NULL
, /* pointer to thread security attributes */
426 TRUE
, /* no inheritance except sinfo.hStd... */
427 CREATE_NEW_PROCESS_GROUP
| CREATE_DEFAULT_ERROR_MODE
,
428 NULL
, /* pointer to new environment block */
429 NULL
, /* pointer to current directory name */
432 *rcode
= (int) GetLastError();
440 CloseHandle(pinfo
.hThread
); /* We don't need it */
441 return (int) pinfo
.hProcess
;
444 /* __regina_wait waits for a process started by fork_exec.
445 * In general, this is called after the complete IO to the called process but
446 * it isn't guaranteed. Never call if you don't expect a sudden death of the
448 * Returns the exit status of the subprocess under normal circumstances. If
449 * the subprocess has died by a signal, the return value is -signalnumber.
451 static int Win_wait(int process
)
453 DWORD code
= (DWORD
) -1; /* in case something goes wrong */
455 WaitForSingleObject((HANDLE
) process
, INFINITE
);
456 GetExitCodeProcess((HANDLE
) process
, &code
);
457 CloseHandle((HANDLE
) process
);
459 if ((code
& 0xC0000000) == 0xC0000000) /* assume signal */
460 return -(int)(code
& ~0xC0000000);
464 /* open_subprocess_connection acts like the unix-known function pipe and sets
465 * ep->RedirectedFile if necessary. Just in the latter case ep->data
466 * is set to the filename.
467 * Close the handles with __regina_close later.
468 * Do IO by using __regina_read() and __regina_write().
470 static int Win_open_subprocess_connection(const tsd_t
*TSD
, environpart
*ep
)
472 #define MAGIC_MAX 2000000 /* Much beyond maximum, see below */
473 static volatile unsigned BaseIndex
= MAGIC_MAX
;
480 SECURITY_ATTRIBUTES sa
;
482 in
= INVALID_HANDLE_VALUE
;
484 /* Anonymous pipes can't be run in overlapped mode. Therefore we use
485 * named pipes (and files for W9x).
487 sa
.nLength
= sizeof(sa
);
488 sa
.lpSecurityDescriptor
= NULL
;
489 sa
.bInheritHandle
= TRUE
;
490 openmode
= (ep
->flags
.isinput
) ? PIPE_ACCESS_OUTBOUND
: PIPE_ACCESS_INBOUND
;
491 openmode
|= FILE_FLAG_OVERLAPPED
;
494 * select a random number, e.g. a mixture of pid, tid and time.
495 * increment this number by a fixed amount until we reach the starting
496 * value again. Do a wrap around and an increment which is a unique prime.
497 * The number 1000000 has the primes 2 and 5. We may use all primes
498 * except 2 and 5; 9901 (which is prime) will give a good distribution.
500 * We want to be able to create several temporary files at once without
501 * more OS calls than needed. Thus, we have a program wide runner to
502 * ensure a simple distribution without strength.
504 if (BaseIndex
== MAGIC_MAX
)
507 * We have to create (nearly) reentrant code.
509 i
= (unsigned) getpid() * (unsigned) time(NULL
);
515 if (++BaseIndex
>= 1000000)
518 start
= TSD
->thread_id
;
521 start
*= (unsigned) (clock() + 1);
526 for (i
= 0;i
<= 1000000;i
++)
528 sprintf(buf
,"%s%06u._rx", "\\\\.\\pipe\\tmp\\", run
);
529 in
= CreateNamedPipe(buf
,
531 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
| PIPE_WAIT
,
532 1, /* just this instance! */
533 0, /* OutBufferSize: use system minimum, e.g.4K */
534 0, /* InBufferSize: use system minimum, e.g.4K */
535 0, /* nDefaultTimeout */
536 NULL
); /* This handle won't be shared */
537 if (in
!= INVALID_HANDLE_VALUE
)
540 err
= GetLastError();
541 if (err
!= ERROR_ACCESS_DENIED
)
547 /* Check the next possible candidate */
550 if (run
== start
) /* paranoia check. i <= 1000000 should hit exactly */
554 if (in
== INVALID_HANDLE_VALUE
)
560 /* Prepare this pipe and then try to connect it to ourself. */
561 if ((ol
.hEvent
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
)) == NULL
)
567 ConnectNamedPipe(in
, &ol
); /* ignore the return */
569 out
= CreateFile(buf
,
570 (ep
->flags
.isinput
) ? GENERIC_READ
: GENERIC_WRITE
,
574 FILE_ATTRIBUTE_NORMAL
, /* not OVERLAPPED! */
575 NULL
); /* hTemplateFile */
576 if (out
== INVALID_HANDLE_VALUE
)
579 CloseHandle(ol
.hEvent
);
581 errno
= EPIPE
; /* guess */
585 /* Now do the final checking, the server end must be connected */
586 if (!GetOverlappedResult(in
, &ol
, &openmode
/* dummy */, FALSE
))
590 CloseHandle(ol
.hEvent
);
592 errno
= EPIPE
; /* guess */
595 CloseHandle(ol
.hEvent
);
597 /* We always want to have the server's end of the named pipe: */
598 if (ep
->flags
.isinput
)
600 ep
->hdls
[0] = (int) out
;
601 ep
->hdls
[1] = (int) in
;
605 ep
->hdls
[0] = (int) in
;
606 ep
->hdls
[1] = (int) out
;
612 /* sets the given handle to the non-blocking mode. The value may change.
613 * async_info CAN be used to add the handle to the internal list of watched
616 static void Win_unblock_handle( int *handle
, void *async_info
)
624 hdl
= (HANDLE
) *handle
;
626 assert(async_info
!= NULL
);
627 for (i
= 0, w
= ai
->h
; i
< 3; i
++, w
++)
628 if (w
->hdl
== INVALID_HANDLE_VALUE
)
632 w
->ol
.hEvent
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
635 /* sets the file pointer of the given handle to the beginning.
637 static void Win_restart_file(int hdl
)
639 assert((HANDLE
) hdl
== INVALID_HANDLE_VALUE
);
642 /* __regina_close acts like close() but closes a handle returned by
643 * open_subprocess_connection.
644 * async_info MAY be used to delete the handle from the internal list of
647 static int Win_close(int handle
, void *async_info
)
655 hdl
= (HANDLE
) handle
;
657 if (hdl
== INVALID_HANDLE_VALUE
)
663 if (ai
== NULL
) /* unblocked handle? */
665 if (CloseHandle(hdl
))
667 errno
= ENOSPC
; /* guess */
671 for (i
= 0, w
= ai
->h
; i
< 3; i
++, w
++)
683 CloseHandle(w
->ol
.hEvent
);
684 w
->hdl
= INVALID_HANDLE_VALUE
;
686 Free_TSD(ai
->TSD
, w
->buf
);
687 if (CloseHandle(hdl
))
689 errno
= ENOSPC
; /* guess */
694 * __regina_close_special acts like close() but closes any OS specific handle.
695 * The close happens if the handle is not -1. A specific operation may be
696 * associated with this. Have a look for occurances of "hdls[2]".
698 static void Win_close_special( int handle
)
701 CloseHandle( (HANDLE
) handle
);
704 /* __regina_read acts like read() but returns either an error (return code
705 * == -errno) or the number of bytes read. EINTR and friends leads to a
707 * async_info is both a structure and a flag. If set, asynchronous IO shall
708 * be used, otherwise blocked IO has to be used.
710 static int Win_read(int handle
, void *buf
, unsigned size
, void *async_info
)
721 hdl
= (HANDLE
) handle
;
726 if (!ReadFile( (HANDLE
) hdl
, buf
, size
, &done
, NULL
))
728 retval
= (int) GetLastError();
729 if (retval
== ERROR_BROKEN_PIPE
)
730 return(0); /* "Normal" EOF */
731 return(-EPIPE
); /* guess */
738 for (i
= 0, w
= ai
->h
; i
< 3; i
++, w
++)
746 if (w
->reading
) /* pending IO? */
748 if (!HasOverlappedIoCompleted(ol
))
753 else if (!GetOverlappedResult(hdl
, ol
, &done
, FALSE
))
756 if (GetLastError() == ERROR_IO_PENDING
)
777 memcpy(buf
, w
->buf
+ w
->rusedbegin
, size
);
778 w
->rusedbegin
+= size
;
783 retval
= -EAGAIN
; /* still may change! */
785 if (w
->maxbuf
< 0x1000) /* Buffer not allocated? */
787 /* Never allocate too much, we want a fast response to do some
790 if (w
->buf
) /* THIS IS DEFINITELY A BUG! */
791 Free_TSD(ai
->TSD
, w
->buf
);
796 w
->buf
= Malloc_TSD(ai
->TSD
, w
->maxbuf
);
799 if (w
->reading
) /* Pending IO, we can't do more */
802 /* not reading or no longer reading, initiate a new reading */
803 if (w
->rused
&& (w
->rusedbegin
!= 0))
804 memmove(w
->buf
, w
->buf
+ w
->rusedbegin
, w
->rused
);
807 if (w
->rused
< w
->maxbuf
)
809 w
->reading
= w
->maxbuf
- w
->rused
;
810 ResetEvent(w
->ol
.hEvent
);
811 if (!ReadFile((HANDLE
) hdl
,
817 done
= GetLastError();
818 if (done
== ERROR_IO_PENDING
)
822 if ((retval
> 0) || (w
->rused
!= 0))
825 if (done
== ERROR_BROKEN_PIPE
)
826 return(0); /* "Normal" EOF */
827 return(-EPIPE
); /* guess */
835 if ((retval
< 0) && w
->rused
) /* fresh data? return at once */
839 memcpy(buf
, w
->buf
+ w
->rusedbegin
, size
);
840 w
->rusedbegin
+= size
;
847 /* __regina_write acts like write() but returns either an error (return code
848 * == -errno) or the number of bytes written. EINTR and friends leads to a
850 * async_info is both a structure and a flag. If set, asynchronous IO shall
851 * be used, otherwise blocked IO has to be used.
852 * The file must be flushed if buf or size are 0. Even in this case -EAGAIN
855 static int Win_write(int handle
, const void *buf
, unsigned size
, void *async_info
)
867 hdl
= (HANDLE
) handle
;
872 if ((buf
== NULL
) | (size
== 0))
873 return(0); /* flushing is useless here! */
877 if (!WriteFile(hdl
, buf
, size
, &done
, NULL
))
879 return(-EPIPE
); /* guess */
881 retval
+= (int) done
;
882 buf
= (const void *) ((char *) buf
+ done
);
884 } while (retval
< (int) size
);
889 for (i
= 0, w
= ai
->h
; i
< 3; i
++, w
++)
898 * Reap any pending overlapped IO first.
900 if (w
->wused
) /* pending IO? */
902 if (!HasOverlappedIoCompleted(ol
))
904 if ((w
->wused
== w
->maxbuf
) || (buf
== NULL
) || (size
== 0))
910 if (!GetOverlappedResult(hdl
, ol
, &done
, FALSE
))
912 done
= GetLastError();
913 if (done
== ERROR_IO_PENDING
)
915 return(-EPIPE
); /* guess */
919 memmove(w
->buf
, w
->buf
+ done
, w
->wused
- done
);
927 if (((buf
== NULL
) || (size
== 0)) && !w
->wused
)
935 w
->buf
= Malloc_TSD(ai
->TSD
, w
->maxbuf
);
939 * At this point we may have set pending, in which case it is forbidden
940 * to reinitiate a write or a semaphore event. We just may ADD something to
944 if (w
->wused
< w
->maxbuf
)
946 retval
= (int) (w
->maxbuf
- w
->wused
);
947 if (retval
> (int) size
)
951 memcpy(w
->buf
+ w
->wused
, buf
, retval
);
952 w
->wused
+= (unsigned) retval
;
955 return retval
; /* fixes bug 945218 */
959 return -EAGAIN
; /* Nothing written/copied, must be pending */
961 ResetEvent(ol
->hEvent
);
963 if (!WriteFile(hdl
, w
->buf
, w
->wused
, &done
, ol
))
965 done
= (int) GetLastError();
966 if (done
== ERROR_IO_PENDING
)
968 return(-EPIPE
); /* guess */
970 /* No errors, thus success. We don't want to redo all the stuff. We
971 * simply set your wait-semaphore to prevent sleeping.
973 SetEvent(ol
->hEvent
);
978 /* create_async_info return an opaque structure to allow the process wait for
979 * asyncronous IO. There are three IO slots (in, out, error) which can be
980 * filled by add_waiter. The structure can be cleaned by reset_async_info.
981 * The structure must be destroyed by delete_async_info.
983 static void *Win_create_async_info(const tsd_t
*TSD
)
987 retval
= MallocTSD(sizeof(AsyncInfo
));
988 memset(retval
, 0, sizeof(AsyncInfo
));
991 retval
->h
[0].hdl
= INVALID_HANDLE_VALUE
;
992 retval
->h
[0].ol
.hEvent
= INVALID_HANDLE_VALUE
;
993 retval
->h
[1] = retval
->h
[0];
994 retval
->h
[2] = retval
->h
[0];
998 /* delete_async_info deletes the structure created by create_async_info and
999 * all of its components.
1001 static void Win_delete_async_info(void *async_info
)
1010 for (i
= 0; i
< 3;i
++)
1011 Win_close((int) ai
->h
[i
].hdl
, ai
);
1012 Free_TSD(ai
->TSD
, ai
);
1015 /* reset_async_info clears async_info in such a way that fresh add_waiter()
1016 * calls can be performed.
1018 static void Win_reset_async_info(void *async_info
)
1022 /* add_async_waiter adds a further handle to the asyncronous IO structure.
1023 * add_as_read_handle must be != 0 if the next operation shall be a
1024 * __regina_read, else it must be 0 for __regina_write.
1025 * Call reset_async_info before a wait-cycle to different handles and use
1026 * wait_async_info to wait for at least one IO-able handle.
1028 static void Win_add_async_waiter(void *async_info
, int handle
, int add_as_read_handle
)
1035 hdl
= (HANDLE
) handle
;
1038 for (i
= 0;i
< 3;i
++)
1039 if (ai
->h
[i
].hdl
== hdl
)
1041 if (add_as_read_handle
)
1042 ai
->h
[i
].is_reader
= 1;
1044 ai
->h
[i
].is_reader
= 0;
1049 /* wait_async_info waits for some handles to become ready. This function
1050 * returns if at least one handle becomes ready.
1051 * A handle can be added with add_async_waiter to the bundle of handles to
1053 * No special handling is implemented if an asyncronous interrupt occurs.
1054 * Thus, there is no guarantee to have handle which works.
1056 static void Win_wait_async_info(void *async_info
)
1064 for (i
= 0, used
= 0, w
= ai
->h
; i
< 3; i
++, w
++)
1066 if (w
->hdl
== INVALID_HANDLE_VALUE
)
1068 if (w
->ol
.hEvent
== INVALID_HANDLE_VALUE
)
1072 if (w
->rused
!= 0) /* Still data to read? this is a killer! */
1074 if (w
->reading
== 0)
1082 if (HasOverlappedIoCompleted(&w
->ol
)) /* fresh meat arrived? */
1084 list
[used
++] = w
->ol
.hEvent
;
1087 WaitForMultipleObjects(used
, list
, FALSE
, INFINITE
);
1091 #if defined(__WINS__) || defined(__EPOC32__)
1092 # define Win_uname epoc32_uname
1093 #elif defined(NEED_UNAME)
1094 int Win_uname(struct regina_utsname
*name
) /* MH 10-06-96 */
1096 SYSTEM_INFO sysinfo
;
1098 OSVERSIONINFO osinfo
;
1099 WORD wServicePackMajor
;
1100 WORD wServicePackMinor
;
1106 char computername
[MAX_COMPUTERNAME_LENGTH
+1];
1107 DWORD namelen
= sizeof(computername
);
1111 * Modern Windows have support for OSVERSIONINFOEX, but this structure may
1112 * not be defined in any case. We support it with our own structure and
1113 * test whether it is supported or not.
1115 memset( &osinfoEX
, 0, sizeof(osinfoEX
) );
1116 osinfoEX
.osinfo
.dwOSVersionInfoSize
= sizeof(osinfoEX
);
1117 if ( !GetVersionEx( &osinfoEX
.osinfo
) )
1119 osinfoEX
.osinfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
1120 GetVersionEx( &osinfoEX
.osinfo
);
1123 sprintf( buf
, "%u.%u", osinfoEX
.osinfo
.dwMajorVersion
, osinfoEX
.osinfo
.dwMinorVersion
);
1124 if (osinfoEX
.wServicePackMajor
)
1125 sprintf( buf
+ strlen(buf
), "SP%u", ( unsigned ) osinfoEX
.wServicePackMajor
);
1126 strncpy( name
->version
, buf
, sizeof(name
->version
) - 1 );
1127 sprintf( name
->release
, "%u", osinfoEX
.osinfo
.dwBuildNumber
);
1129 /* get specific OS version... */
1130 switch( osinfoEX
.osinfo
.dwPlatformId
)
1132 case VER_PLATFORM_WIN32s
:
1133 strcpy( name
->sysname
, "WIN32S" );
1135 case VER_PLATFORM_WIN32_WINDOWS
:
1136 if ( osinfoEX
.osinfo
.dwMinorVersion
>= 90 )
1137 strcpy( name
->sysname
, "WINME" );
1138 else if ( osinfoEX
.osinfo
.dwMinorVersion
>= 10 )
1139 strcpy( name
->sysname
, "WIN98" );
1141 strcpy( name
->sysname
, "WIN95" );
1143 case VER_PLATFORM_WIN32_NT
:
1144 if ( osinfoEX
.osinfo
.dwMajorVersion
== 4 )
1145 strcpy( name
->sysname
, "WINNT" );
1146 else if ( osinfoEX
.osinfo
.dwMajorVersion
== 5 )
1148 if ( osinfoEX
.osinfo
.dwMinorVersion
== 1 )
1149 strcpy( name
->sysname
, "WINXP" );
1150 else if ( osinfoEX
.osinfo
.dwMinorVersion
== 2 )
1151 strcpy( name
->sysname
, "WIN2003" );
1153 strcpy( name
->sysname
, "WIN2K" );
1155 else if ( osinfoEX
.osinfo
.dwMajorVersion
== 6 )
1156 strcpy( name
->sysname
, "WINVISTA" );
1158 strcpy( name
->sysname
, "UNKNOWN" );
1161 strcpy( name
->sysname
, "UNKNOWN" );
1165 * get name of computer if possible.
1167 if ( GetComputerName(computername
, &namelen
) )
1168 strcpy( name
->nodename
, computername
);
1170 strcpy( name
->nodename
, "UNKNOWN" );
1171 GetSystemInfo( &sysinfo
);
1172 switch( sysinfo
.dwProcessorType
)
1174 case PROCESSOR_INTEL_386
:
1175 strcpy( name
->machine
, "i386" );
1177 case PROCESSOR_INTEL_486
:
1178 strcpy( name
->machine
, "i486" );
1180 case PROCESSOR_INTEL_PENTIUM
:
1181 strcpy( name
->machine
, "i586" );
1183 #if defined(PROCESSOR_INTEL_MIPS_R4000)
1184 case PROCESSOR_INTEL_MIPS_R4000
:
1185 strcpy( name
->machine
, "mipsR4000" );
1188 #if defined(PROCESSOR_INTEL_ALPHA_21064)
1189 case PROCESSOR_INTEL_ALPHA_21064
:
1190 strcpy( name
->machine
, "alpha21064" );
1194 strcpy( name
->machine
, "UNKNOWN" );
1201 int Win_uname(struct regina_utsname
*name
)
1203 struct utsname osdata
;
1206 * Don't know whether utsname uses pointer or char[].
1207 * So just copy data.
1209 if ( uname( &osdata
) < 0 )
1211 memset( name
, 0, sizeof(struct regina_utsname
) );
1215 strcpy( name
->sysname
, osdata
.sysname
);
1216 strcpy( name
->nodename
, osdata
.nodename
);
1217 strcpy( name
->release
, osdata
.release
);
1218 strcpy( name
->version
, osdata
.version
);
1219 strcpy( name
->machine
, osdata
.machine
);
1224 static void Win_init(void);
1226 OS_Dep_funcs __regina_OS_Win
=
1228 Win_init
, /* init */
1229 Win_setenv
, /* setenv */
1230 Win_fork_exec
, /* fork_exec */
1231 Win_wait
, /* wait */
1232 Win_open_subprocess_connection
, /* open_subprocess_connection */
1233 Win_unblock_handle
, /* unblock_handle */
1234 Win_restart_file
, /* restart_file */
1235 Win_close
, /* close */
1236 Win_close_special
, /* close_special */
1237 Win_read
, /* read */
1238 Win_write
, /* write */
1239 Win_create_async_info
, /* create_async_info */
1240 Win_delete_async_info
, /* delete_async_info */
1241 Win_reset_async_info
, /* reset_async_info */
1242 Win_add_async_waiter
, /* add_async_waiter */
1243 Win_wait_async_info
, /* wait_async_info */
1244 Win_uname
/* uname */
1247 extern OS_Dep_funcs __regina_OS_Other
;
1249 static void Win_init(void)
1251 #define WIN __regina_OS_Win
1252 #define DOS __regina_OS_Other
1255 WIN
.fork_exec
= DOS
.fork_exec
;
1256 WIN
.open_subprocess_connection
= DOS
.open_subprocess_connection
;
1257 WIN
.unblock_handle
= DOS
.unblock_handle
;
1258 WIN
.restart_file
= DOS
.restart_file
;
1259 WIN
.close
= DOS
.close
;
1260 WIN
.read
= DOS
.read
;
1261 WIN
.write
= DOS
.write
;
1262 WIN
.create_async_info
= DOS
.create_async_info
;
1263 WIN
.delete_async_info
= DOS
.delete_async_info
;
1264 WIN
.reset_async_info
= DOS
.reset_async_info
;
1265 WIN
.add_async_waiter
= DOS
.add_async_waiter
;
1266 WIN
.wait_async_info
= DOS
.wait_async_info
;