don't build pcre as part of the linklibs target
[AROS-Contrib.git] / regina / os_win.c
blob20a9dec3c91a4fb133e8e129a374a734f5dd64d2
1 /*
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.
22 #include "rexx.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
30 #if defined(WIN32)
31 # include <share.h>
32 # if defined(__BORLANDC__) || defined(__LCC__)
33 # include <time.h>
34 # include <process.h>
35 # endif
36 # ifdef _MSC_VER
37 # if _MSC_VER >= 1100
38 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
39 # pragma warning(disable: 4115 4201 4214 4514)
40 # endif
41 # endif
42 # include <windows.h>
43 # ifdef _MSC_VER
44 # if _MSC_VER >= 1100
45 # pragma warning(default: 4115 4201 4214)
46 # endif
47 # endif
48 #endif
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 */
52 # define NEED_UNAME
53 # if !defined(__WINS__) && !defined(__EPOC32__)
54 # define MAXPATHLEN _MAX_PATH /* MH 10-06-96 */
55 # endif
56 #else /* MH 10-06-96 */
57 # if defined(WIN32) && defined(__IBMC__) /* LM 26-02-99 */
58 # include "utsname.h"
59 # define NEED_UNAME
60 # define MAXPATHLEN (8192)
61 # include <io.h>
62 # else
63 # include <sys/param.h> /* MH 10-06-96 */
64 # include <sys/utsname.h> /* MH 10-06-96 */
65 # include <sys/wait.h>
66 # endif
67 #endif
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 */
75 # else
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 */
78 # endif
79 # if !defined(__WINS__) && !defined(__EPOC32__) && !defined(__CYGWIN__)
80 # ifndef HAVE_UNISTD_H
81 # include <io.h> /* access() */
82 # endif
83 # include <process.h>
84 # include <share.h>
85 # endif
86 # include <time.h>
87 #endif
89 #if defined(__LCC__)
90 # if !defined(HasOverlappedIoCompleted)
91 # define HasOverlappedIoCompleted(lpOverlapped) ((lpOverlapped)->Internal != STATUS_PENDING)
92 # endif
93 #endif
95 static int IsWin9X(void)
97 static int retval = -1;
98 OSVERSIONINFO osinfo;
100 if ( retval >= 0 )
101 return retval;
103 #ifdef DEBUG
104 if (getenv("REGINA_ACT_AS_WIN9X") != NULL)
106 retval = 1;
107 return retval;
109 #endif
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 */
117 default:
118 retval = 1;
119 break;
120 case VER_PLATFORM_WIN32_NT: /* Reasonable systems ... just my 2 ct, FGC */
121 retval = 0;
122 break;
124 return retval;
127 typedef struct {
128 HANDLE hdl;
129 OVERLAPPED ol;
130 char *buf;
131 unsigned maxbuf;
132 unsigned rused;
133 unsigned rusedbegin;
134 unsigned reading;
135 unsigned wused;
136 int is_reader;
137 } Win32IO;
139 typedef struct {
140 const tsd_t *TSD;
141 Win32IO h[3];
142 } AsyncInfo;
144 static BOOL MyCancelIo(HANDLE handle)
146 static BOOL (WINAPI *DoCancelIo)(HANDLE handle) = NULL;
147 static BOOL first = TRUE;
148 HMODULE mod;
150 if ( first )
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.
164 first = FALSE;
167 if ( DoCancelIo == NULL )
168 return FALSE;
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
183 * to be started.
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 */
194 /* not dynamic */
195 "rexx.exe" };
196 PROCESS_INFORMATION pinfo;
197 STARTUPINFO sinfo;
198 DWORD done;
199 char *execname = NULL;
200 const char *commandline = NULL;
201 char *argline = NULL;
202 BOOL rc;
203 int broken_address_command = get_options_flag( TSD->currlevel, EXT_BROKEN_ADDRESS_COMMAND );
204 int subtype;
206 if (env->subtype == SUBENVIR_REXX) /*special situation caused by recursion*/
208 environment e = *env;
209 char *new_cmdline;
210 int i, rc;
211 unsigned len;
213 if (argv0 == NULL)
214 len = 11; /* max("rexx.exe", "regina.exe") */
215 else
217 len = strlen(argv0) + 2;
218 if (len < 11)
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 ) )
236 free(new_cmdline);
237 return(rc);
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 ) )
251 free(new_cmdline);
252 return(rc);
256 *rcode = -errno; /* assume a load error */
257 free(new_cmdline);
258 return(0);
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)
269 if ( IsWin9X() )
271 sinfo.hStdInput = (HANDLE) _get_osfhandle(env->input.hdls[0]);
273 * fixes Bug 587687
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(),
284 sinfo.hStdInput,
285 GetCurrentProcess(),
286 &sinfo.hStdInput,
288 TRUE,
289 DUPLICATE_SAME_ACCESS );
291 * fixes bug 700405
293 env->input.hdls[2] = (int) sinfo.hStdInput;
295 else
296 sinfo.hStdInput = (HANDLE) env->input.hdls[0];
298 else
299 sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
300 if (env->output.hdls[1] != -1)
302 if ( IsWin9X() )
304 sinfo.hStdOutput = (HANDLE) _get_osfhandle(env->output.hdls[1]);
305 DuplicateHandle( GetCurrentProcess(),
306 sinfo.hStdOutput,
307 GetCurrentProcess(),
308 &sinfo.hStdOutput,
310 TRUE,
311 DUPLICATE_SAME_ACCESS );
313 * fixes bug 700405
315 env->output.hdls[2] = (int) sinfo.hStdOutput;
317 else
318 sinfo.hStdOutput = (HANDLE) env->output.hdls[1];
320 else
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)
326 if ( IsWin9X() )
328 sinfo.hStdError = (HANDLE) _get_osfhandle(env->error.hdls[1]);
329 DuplicateHandle( GetCurrentProcess(),
330 sinfo.hStdError,
331 GetCurrentProcess(),
332 &sinfo.hStdError,
334 TRUE,
335 DUPLICATE_SAME_ACCESS );
337 * fixes bug 700405
339 env->error.hdls[2] = (int) sinfo.hStdError;
341 else
342 sinfo.hStdError = (HANDLE) env->error.hdls[1];
344 else
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;
354 else
355 subtype = env->subtype;
357 switch ( subtype )
359 case SUBENVIR_PATH:
360 execname = NULL;
361 commandline = cmdline;
362 break;
364 case SUBENVIR_COMMAND:
365 execname = NULL;
366 commandline = cmdline;
367 #define NEED_SPLITOFFARG
368 execname = splitoffarg(cmdline, NULL, '^');
369 commandline = cmdline;
370 break;
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 ");
386 else
388 argline = MallocTSD(11 + strlen(cmdline) + 5);
389 if (GetVersion() & 0x80000000) /* not NT ? */
390 strcpy(argline,"COMMAND.COM /c ");
391 else
392 strcpy(argline,"CMD.EXE /c ");
394 strcat(argline, cmdline);
395 execname = NULL;
396 commandline = argline;
397 break;
399 case SUBENVIR_REXX:
400 /* fall through */
402 default: /* illegal subtype */
403 errno = EINVAL;
404 return -1;
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!
417 if ( !IsWin9X() )
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 */
430 &sinfo,
431 &pinfo);
432 *rcode = (int) GetLastError();
433 if (argline)
434 FreeTSD(argline);
435 if (execname)
436 free(execname);
437 if ( !rc )
438 return 0;
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
447 * subprocess.
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);
461 return (int) code;
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;
474 char buf[40];
475 unsigned i;
476 unsigned start,run;
477 DWORD openmode, err;
478 HANDLE in, out;
479 OVERLAPPED ol;
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;
493 /* algorithm:
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);
510 i %= 1000000;
511 if (!i)
512 i = 1;
513 BaseIndex = i;
515 if (++BaseIndex >= 1000000)
516 BaseIndex = 1;
518 start = TSD->thread_id;
519 if (start == 0)
520 start = 999999;
521 start *= (unsigned) (clock() + 1);
522 start *= BaseIndex;
523 start %= 1000000;
525 run = start;
526 for (i = 0;i <= 1000000;i++)
528 sprintf(buf,"%s%06u._rx", "\\\\.\\pipe\\tmp\\", run );
529 in = CreateNamedPipe(buf,
530 openmode,
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)
538 break;
540 err = GetLastError();
541 if (err != ERROR_ACCESS_DENIED)
543 errno = EPIPE;
544 return(-1);
547 /* Check the next possible candidate */
548 run += 9901;
549 run %= 1000000;
550 if (run == start) /* paranoia check. i <= 1000000 should hit exactly */
551 break; /* here */
554 if (in == INVALID_HANDLE_VALUE)
556 errno = EPIPE;
557 return(-1);
560 /* Prepare this pipe and then try to connect it to ourself. */
561 if ((ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
563 CloseHandle(in);
564 errno = EPIPE;
565 return(-1);
567 ConnectNamedPipe(in, &ol); /* ignore the return */
569 out = CreateFile(buf,
570 (ep->flags.isinput) ? GENERIC_READ : GENERIC_WRITE,
571 0, /* dwShareMode */
572 &sa,
573 OPEN_EXISTING,
574 FILE_ATTRIBUTE_NORMAL, /* not OVERLAPPED! */
575 NULL); /* hTemplateFile */
576 if (out == INVALID_HANDLE_VALUE)
578 MyCancelIo(in);
579 CloseHandle(ol.hEvent);
580 CloseHandle(in);
581 errno = EPIPE; /* guess */
582 return(-1);
585 /* Now do the final checking, the server end must be connected */
586 if (!GetOverlappedResult(in, &ol, &openmode /* dummy */, FALSE))
588 CloseHandle(out);
589 MyCancelIo(in);
590 CloseHandle(ol.hEvent);
591 CloseHandle(in);
592 errno = EPIPE; /* guess */
593 return(-1);
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;
603 else
605 ep->hdls[0] = (int) in;
606 ep->hdls[1] = (int) out;
608 return(0);
609 #undef MAGIC_MAX
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
614 * handles.
616 static void Win_unblock_handle( int *handle, void *async_info )
618 AsyncInfo *ai;
619 Win32IO *w;
620 HANDLE hdl;
621 unsigned i;
623 ai = 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)
629 break;
630 assert(i < 3);
631 w->hdl = hdl;
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
645 * watched handles.
647 static int Win_close(int handle, void *async_info)
649 AsyncInfo *ai;
650 Win32IO *w;
651 HANDLE hdl;
652 unsigned i;
654 ai = async_info;
655 hdl = (HANDLE) handle;
657 if (hdl == INVALID_HANDLE_VALUE)
659 errno = EINVAL;
660 return(-1);
663 if (ai == NULL) /* unblocked handle? */
665 if (CloseHandle(hdl))
666 return(0);
667 errno = ENOSPC; /* guess */
668 return(-1);
671 for (i = 0, w = ai->h; i < 3; i++, w++)
672 if (w->hdl == hdl)
673 break;
675 if (i == 3)
677 CloseHandle(hdl);
678 errno = EINVAL;
679 return(-1);
682 MyCancelIo(hdl);
683 CloseHandle(w->ol.hEvent);
684 w->hdl = INVALID_HANDLE_VALUE;
685 if (w->buf)
686 Free_TSD(ai->TSD, w->buf);
687 if (CloseHandle(hdl))
688 return(0);
689 errno = ENOSPC; /* guess */
690 return(-1);
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 )
700 if ( 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
706 * re-read.
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)
712 AsyncInfo *ai;
713 Win32IO *w;
714 HANDLE hdl;
715 unsigned i;
716 OVERLAPPED *ol;
717 DWORD done;
718 int retval;
720 ai = async_info;
721 hdl = (HANDLE) handle;
722 retval = 0;
724 if (ai == NULL)
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 */
733 retval = (int) done;
734 return(retval);
737 /* Async IO */
738 for (i = 0, w = ai->h; i < 3; i++, w++)
739 if (w->hdl == hdl)
740 break;
741 if (i == 3)
742 return(-EINVAL);
744 ol = &w->ol;
746 if (w->reading) /* pending IO? */
748 if (!HasOverlappedIoCompleted(ol))
750 done = 0;
751 retval = -EAGAIN;
753 else if (!GetOverlappedResult(hdl, ol, &done, FALSE))
755 done = 0;
756 if (GetLastError() == ERROR_IO_PENDING)
758 retval = -EAGAIN;
760 else
762 w->reading = 0;
763 retval = -EPIPE;
766 else
767 w->reading = 0;
769 if (done)
770 w->rused += done;
773 if (w->rused)
775 if (size > w->rused)
776 size = w->rused;
777 memcpy(buf, w->buf + w->rusedbegin, size);
778 w->rusedbegin += size;
779 w->rused -= size;
780 retval = size;
782 else
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
788 * work!
790 if (w->buf) /* THIS IS DEFINITELY A BUG! */
791 Free_TSD(ai->TSD, w->buf);
792 w->maxbuf = 0x1000;
793 w->rusedbegin = 0;
794 w->rused = 0;
795 w->reading = 0;
796 w->buf = Malloc_TSD(ai->TSD, w->maxbuf);
799 if (w->reading) /* Pending IO, we can't do more */
800 return(retval);
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);
805 w->rusedbegin = 0;
807 if (w->rused < w->maxbuf)
809 w->reading = w->maxbuf - w->rused;
810 ResetEvent(w->ol.hEvent);
811 if (!ReadFile((HANDLE) hdl,
812 w->buf + w->rused,
813 w->reading,
814 &done,
815 ol))
817 done = GetLastError();
818 if (done == ERROR_IO_PENDING)
819 return(retval);
821 w->reading = 0;
822 if ((retval > 0) || (w->rused != 0))
823 return(retval);
825 if (done == ERROR_BROKEN_PIPE)
826 return(0); /* "Normal" EOF */
827 return(-EPIPE); /* guess */
830 /* success */
831 w->reading = 0;
832 w->rused += done;
835 if ((retval < 0) && w->rused) /* fresh data? return at once */
837 if (size > w->rused)
838 size = w->rused;
839 memcpy(buf, w->buf + w->rusedbegin, size);
840 w->rusedbegin += size;
841 w->rused -= size;
842 retval = size;
844 return(retval);
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
849 * re-write.
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
853 * may be returned.
855 static int Win_write(int handle, const void *buf, unsigned size, void *async_info)
857 AsyncInfo *ai;
858 Win32IO *w;
859 HANDLE hdl;
860 unsigned i;
861 OVERLAPPED *ol;
862 DWORD done;
863 int retval;
864 int pending = 0;
866 ai = async_info;
867 hdl = (HANDLE) handle;
868 retval = 0;
870 if (!ai)
872 if ((buf == NULL) | (size == 0))
873 return(0); /* flushing is useless here! */
875 retval = 0;
876 do {
877 if (!WriteFile(hdl, buf, size, &done, NULL))
879 return(-EPIPE); /* guess */
881 retval += (int) done;
882 buf = (const void *) ((char *) buf + done);
883 size -= done;
884 } while (retval < (int) size);
885 return retval;
888 /* Async IO */
889 for (i = 0, w = ai->h; i < 3; i++, w++)
890 if (w->hdl == hdl)
891 break;
892 if (i == 3)
893 return(-EINVAL);
895 ol = &w->ol;
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))
905 return(-EAGAIN);
906 pending = 1;
908 else
910 if (!GetOverlappedResult(hdl, ol, &done, FALSE))
912 done = GetLastError();
913 if (done == ERROR_IO_PENDING)
914 return(-EAGAIN);
915 return(-EPIPE); /* guess */
917 if (done < w->wused)
919 memmove(w->buf, w->buf + done, w->wused - done);
920 w->wused -= done;
922 else
923 w->wused = 0;
927 if (((buf == NULL) || (size == 0)) && !w->wused)
929 return 0;
932 if (w->buf == NULL)
934 w->maxbuf = 0x10000;
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
941 * a buffer.
944 if (w->wused < w->maxbuf)
946 retval = (int) (w->maxbuf - w->wused);
947 if (retval > (int) size)
949 retval = (int) size;
951 memcpy(w->buf + w->wused, buf, retval);
952 w->wused += (unsigned) retval;
953 if (pending)
955 return retval; /* fixes bug 945218 */
958 else
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)
967 return(retval);
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);
975 return(retval);
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)
985 AsyncInfo *retval;
987 retval = MallocTSD(sizeof(AsyncInfo));
988 memset(retval, 0, sizeof(AsyncInfo));
990 retval->TSD = TSD;
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];
995 return(retval);
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)
1003 AsyncInfo *ai;
1004 unsigned i;
1006 ai = async_info;
1007 if (ai == NULL)
1008 return;
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)
1030 AsyncInfo *ai;
1031 HANDLE hdl;
1032 unsigned i;
1034 ai = async_info;
1035 hdl = (HANDLE) handle;
1036 if (ai)
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;
1043 else
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
1052 * wait for.
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)
1058 AsyncInfo *ai;
1059 Win32IO *w;
1060 unsigned i, used;
1061 HANDLE list[3];
1063 ai = async_info;
1064 for (i = 0, used = 0, w = ai->h; i < 3; i++, w++)
1066 if (w->hdl == INVALID_HANDLE_VALUE)
1067 continue;
1068 if (w->ol.hEvent == INVALID_HANDLE_VALUE)
1069 continue;
1070 if (w->is_reader)
1072 if (w->rused != 0) /* Still data to read? this is a killer! */
1073 return;
1074 if (w->reading == 0)
1075 continue;
1077 else
1079 if (w->wused == 0)
1080 continue;
1082 if (HasOverlappedIoCompleted(&w->ol)) /* fresh meat arrived? */
1083 return;
1084 list[used++] = w->ol.hEvent;
1086 if (used)
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 */
1095 { /* MH 10-06-96 */
1096 SYSTEM_INFO sysinfo;
1097 struct {
1098 OSVERSIONINFO osinfo;
1099 WORD wServicePackMajor;
1100 WORD wServicePackMinor;
1101 WORD wSuiteMask;
1102 BYTE bProductType;
1103 BYTE bReserved;
1104 } osinfoEX;
1106 char computername[MAX_COMPUTERNAME_LENGTH+1];
1107 DWORD namelen = sizeof(computername);
1108 char buf[128];
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" );
1134 break;
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" );
1140 else
1141 strcpy( name->sysname, "WIN95" );
1142 break;
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" );
1152 else
1153 strcpy( name->sysname, "WIN2K" );
1155 else if ( osinfoEX.osinfo.dwMajorVersion == 6 )
1156 strcpy( name->sysname, "WINVISTA" );
1157 else
1158 strcpy( name->sysname, "UNKNOWN" );
1159 break;
1160 default:
1161 strcpy( name->sysname, "UNKNOWN" );
1162 break;
1165 * get name of computer if possible.
1167 if ( GetComputerName(computername, &namelen) )
1168 strcpy( name->nodename, computername );
1169 else
1170 strcpy( name->nodename, "UNKNOWN" );
1171 GetSystemInfo( &sysinfo );
1172 switch( sysinfo.dwProcessorType )
1174 case PROCESSOR_INTEL_386:
1175 strcpy( name->machine, "i386" );
1176 break;
1177 case PROCESSOR_INTEL_486:
1178 strcpy( name->machine, "i486" );
1179 break;
1180 case PROCESSOR_INTEL_PENTIUM:
1181 strcpy( name->machine, "i586" );
1182 break;
1183 #if defined(PROCESSOR_INTEL_MIPS_R4000)
1184 case PROCESSOR_INTEL_MIPS_R4000:
1185 strcpy( name->machine, "mipsR4000" );
1186 break;
1187 #endif
1188 #if defined(PROCESSOR_INTEL_ALPHA_21064)
1189 case PROCESSOR_INTEL_ALPHA_21064:
1190 strcpy( name->machine, "alpha21064" );
1191 break;
1192 #endif
1193 default:
1194 strcpy( name->machine, "UNKNOWN" );
1195 break;
1198 return 0;
1200 #else
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) );
1212 return -1;
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 );
1220 return 0;
1222 #endif
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
1253 if (IsWin9X())
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;