fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / io / win32.c
blob0dc832846b5c4bf5b7a152f1549552f2df213ed5
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/io/win32.c - Win32 I/O utility functions
9 =head1 DESCRIPTION
11 This file implements OS-specific I/O functions for Win32 platforms.
13 =head2 References
15 Win32 System Programming, 2nd Edition.
17 =head2 Functions
19 =over 4
21 =cut
25 #ifdef WIN32
26 # include <windows.h>
27 #endif
29 #include "parrot/parrot.h"
30 #include "pmc/pmc_filehandle.h"
31 #include "io_private.h"
33 #ifdef PIO_OS_WIN32
35 /* HEADERIZER HFILE: include/parrot/io_win32.h */
36 /* HEADERIZER BEGIN: static */
37 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
39 static INTVAL convert_flags_to_win32(
40 INTVAL flags,
41 ARGOUT(DWORD * fdwAccess),
42 ARGOUT(DWORD * fdwShareMode),
43 ARGOUT(DWORD * fdwCreate))
44 __attribute__nonnull__(2)
45 __attribute__nonnull__(3)
46 __attribute__nonnull__(4)
47 FUNC_MODIFIES(* fdwAccess)
48 FUNC_MODIFIES(* fdwShareMode)
49 FUNC_MODIFIES(* fdwCreate);
51 PARROT_WARN_UNUSED_RESULT
52 static INTVAL io_is_tty_win32(PIOHANDLE fd);
54 #define ASSERT_ARGS_convert_flags_to_win32 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
55 PARROT_ASSERT_ARG(fdwAccess) \
56 , PARROT_ASSERT_ARG(fdwShareMode) \
57 , PARROT_ASSERT_ARG(fdwCreate))
58 #define ASSERT_ARGS_io_is_tty_win32 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
59 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
60 /* HEADERIZER END: static */
62 # include <tchar.h>
64 # define PIO_TRACE 0
68 =item C<static INTVAL convert_flags_to_win32(INTVAL flags, DWORD * fdwAccess,
69 DWORD * fdwShareMode, DWORD * fdwCreate)>
71 Convert to platform-specific bit open flags.
73 =cut
77 static INTVAL
78 convert_flags_to_win32(INTVAL flags, ARGOUT(DWORD * fdwAccess),
79 ARGOUT(DWORD * fdwShareMode), ARGOUT(DWORD * fdwCreate))
81 ASSERT_ARGS(convert_flags_to_win32)
82 static DWORD dwDefaultShareMode;
83 if (!dwDefaultShareMode) {
84 OSVERSIONINFO osvi;
85 osvi.dwOSVersionInfoSize = sizeof (osvi);
86 GetVersionEx(&osvi);
87 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
88 dwDefaultShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
90 else {
91 dwDefaultShareMode =
92 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
96 if ((flags & (PIO_F_WRITE | PIO_F_READ)) == (PIO_F_WRITE | PIO_F_READ)) {
97 *fdwAccess = GENERIC_WRITE | GENERIC_READ;
98 if (flags & PIO_F_TRUNC)
99 *fdwCreate = CREATE_ALWAYS;
100 else
101 *fdwCreate = OPEN_ALWAYS;
103 else if (flags & PIO_F_WRITE) {
104 *fdwAccess = GENERIC_WRITE;
105 if (flags & PIO_F_TRUNC)
106 *fdwCreate = CREATE_ALWAYS;
107 else
108 *fdwCreate = OPEN_ALWAYS;
110 else if (flags & PIO_F_READ) {
111 *fdwAccess = GENERIC_READ;
112 *fdwCreate = OPEN_EXISTING;
115 *fdwShareMode = dwDefaultShareMode;
116 if (flags & PIO_F_APPEND) {
117 /* dealt with specially in _write and _puts */
119 return 1;
124 =item C<INTVAL Parrot_io_init_win32(PARROT_INTERP)>
126 Sets up the standard C<std*> IO handles.
128 =cut
132 INTVAL
133 Parrot_io_init_win32(PARROT_INTERP)
135 ASSERT_ARGS(Parrot_io_init_win32)
136 HANDLE h;
137 struct WSAData sockinfo;
138 int ret;
140 if ((h = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
141 _PIO_STDIN(interp) = Parrot_io_fdopen_win32(interp, PMCNULL, h, PIO_F_READ);
143 else {
144 _PIO_STDIN(interp) = PMCNULL;
146 if ((h = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
147 _PIO_STDOUT(interp) = Parrot_io_fdopen_win32(interp, PMCNULL, h, PIO_F_WRITE);
149 else {
150 _PIO_STDOUT(interp) = PMCNULL;
152 if ((h = GetStdHandle(STD_ERROR_HANDLE)) != INVALID_HANDLE_VALUE) {
153 _PIO_STDERR(interp) = Parrot_io_fdopen_win32(interp, PMCNULL, h, PIO_F_WRITE);
155 else {
156 _PIO_STDERR(interp) = PMCNULL;
158 /* Start Winsock
159 * no idea where or whether destroy it
161 ret = WSAStartup(2, &sockinfo);
162 if (ret != 0) {
163 fprintf(stderr, "WSAStartup failed!!\n ErrorCode=%i\n\n",
164 WSAGetLastError());
165 return -4;
167 return 0;
172 =item C<INTVAL Parrot_io_getblksize_win32(PIOHANDLE fd)>
174 Returns C<PIO_BLKSIZE>.
176 =cut
180 INTVAL
181 Parrot_io_getblksize_win32(SHIM(PIOHANDLE fd))
183 ASSERT_ARGS(Parrot_io_getblksize_win32)
184 /* Hard coded for now */
185 return PIO_BLKSIZE;
190 =item C<PMC * Parrot_io_open_win32(PARROT_INTERP, PMC *filehandle, STRING *path,
191 INTVAL flags)>
193 Calls C<CreateFile()> to open C<*spath> with the Win32 translation of
194 C<flags>.
196 =cut
200 PARROT_CAN_RETURN_NULL
201 PMC *
202 Parrot_io_open_win32(PARROT_INTERP, ARGMOD(PMC *filehandle),
203 ARGIN(STRING *path), INTVAL flags)
205 ASSERT_ARGS(Parrot_io_open_win32)
206 DWORD fAcc, fShare, fCreat;
207 PIOHANDLE fd;
209 # if 0
210 if ((Interp_flags_TEST(interp, PARROT_DEBUG_FLAG)) != 0) {
211 fprintf(stderr, "Parrot_io_open_win32: %s\n", spath);
213 # endif
214 if (flags & PIO_F_PIPE)
215 return Parrot_io_open_pipe_win32(interp, filehandle, path, flags);
217 if ((flags & (PIO_F_WRITE | PIO_F_READ)) == 0)
218 return NULL;
220 /* Set open flags - <, >, >>, +<, +> */
221 /* add ? and ! for block/non-block */
222 if (convert_flags_to_win32(flags, &fAcc, &fShare, &fCreat) < 0)
223 return NULL;
225 /* Only files for now */
226 flags |= PIO_F_FILE;
228 { /* enclosing scope for temporary C string */
229 char * const spath = Parrot_str_to_cstring(interp, path);
230 fd = CreateFile(spath, fAcc, fShare, NULL, fCreat,
231 FILE_ATTRIBUTE_NORMAL, NULL);
232 Parrot_str_free_cstring(spath);
234 if (fd != INVALID_HANDLE_VALUE) {
235 PMC *io;
236 if (PMC_IS_NULL(filehandle))
237 io = Parrot_io_new_pmc(interp, flags);
238 else {
239 io = filehandle;
240 Parrot_io_set_flags(interp, io, flags);
243 Parrot_io_set_os_handle(interp, io, fd);
244 return io;
246 else {
247 int err = GetLastError();
248 if (err) {
249 errno = err;
253 return PMCNULL;
258 =item C<PMC * Parrot_io_fdopen_win32(PARROT_INTERP, PMC *filehandle, PIOHANDLE
259 fd, INTVAL flags)>
261 Returns a new C<PMC> with C<fd> as its file descriptor.
263 =cut
267 PARROT_WARN_UNUSED_RESULT
268 PARROT_CANNOT_RETURN_NULL
269 PMC *
270 Parrot_io_fdopen_win32(PARROT_INTERP, ARGMOD_NULLOK(PMC *filehandle),
271 PIOHANDLE fd, INTVAL flags)
273 ASSERT_ARGS(Parrot_io_fdopen_win32)
274 PMC *io;
276 if (io_is_tty_win32(fd))
277 flags |= PIO_F_CONSOLE;
279 /* fdopened files are always shared */
280 flags |= PIO_F_SHARED;
282 if (PMC_IS_NULL(filehandle))
283 io = Parrot_io_new_pmc(interp, flags);
284 else {
285 io = filehandle;
286 Parrot_io_set_flags(interp, io, flags);
289 Parrot_io_set_os_handle(interp, io, fd);
290 return io;
295 =item C<INTVAL Parrot_io_close_piohandle_win32(PARROT_INTERP, PIOHANDLE handle)>
297 Calls C<CloseHandle()> to close the given file descriptor. Returns 0 on
298 success, -1 on error.
300 =cut
304 INTVAL
305 Parrot_io_close_piohandle_win32(PARROT_INTERP, PIOHANDLE handle)
307 ASSERT_ARGS(Parrot_io_close_piohandle_win32)
309 if (handle == INVALID_HANDLE_VALUE)
310 return -1;
312 return CloseHandle(handle) ? 0 : -1;
317 =item C<INTVAL Parrot_io_close_win32(PARROT_INTERP, PMC *filehandle)>
319 Calls C<CloseHandle()> to close C<*io>'s file descriptor.
321 =cut
325 INTVAL
326 Parrot_io_close_win32(PARROT_INTERP, ARGMOD(PMC *filehandle))
328 ASSERT_ARGS(Parrot_io_close_win32)
329 UINTVAL result = 0;
330 PIOHANDLE os_handle = Parrot_io_get_os_handle(interp, filehandle);
331 if (os_handle != INVALID_HANDLE_VALUE) {
332 int flags = Parrot_io_get_flags(interp, filehandle);
333 if (CloseHandle(os_handle) == 0)
334 result = GetLastError();
335 Parrot_io_set_os_handle(interp, filehandle, INVALID_HANDLE_VALUE);
337 if (flags & PIO_F_PIPE) {
338 INTVAL procid = VTABLE_get_integer_keyed_int(interp, filehandle, 0);
339 HANDLE process = (HANDLE) procid;
340 DWORD status = WaitForSingleObject(process, INFINITE);
341 DWORD exit_code;
343 if (status != WAIT_FAILED && GetExitCodeProcess(process, &exit_code))
344 SETATTR_FileHandle_exit_status(interp, filehandle, exit_code);
345 else
346 SETATTR_FileHandle_exit_status(interp, filehandle, 1);
347 CloseHandle(process);
350 return (result != 0);
355 =item C<INTVAL Parrot_io_is_closed_win32(PARROT_INTERP, PMC *filehandle)>
357 Test whether the filehandle has been closed.
359 =cut
363 INTVAL
364 Parrot_io_is_closed_win32(PARROT_INTERP, ARGIN(PMC *filehandle))
366 ASSERT_ARGS(Parrot_io_is_closed_win32)
367 if (Parrot_io_get_os_handle(interp, filehandle) == INVALID_HANDLE_VALUE)
368 return 1;
370 return 0;
375 =item C<static INTVAL io_is_tty_win32(PIOHANDLE fd)>
377 Returns whether C<fd> is a console/tty.
379 =cut
383 PARROT_WARN_UNUSED_RESULT
384 static INTVAL
385 io_is_tty_win32(PIOHANDLE fd)
387 ASSERT_ARGS(io_is_tty_win32)
388 const DWORD ftype = GetFileType(fd);
389 return (ftype == FILE_TYPE_CHAR);
394 =item C<INTVAL Parrot_io_flush_win32(PARROT_INTERP, PMC *filehandle)>
396 Calls C<FlushFileBuffers()> to flush C<*io>'s file descriptor.
398 =cut
402 INTVAL
403 Parrot_io_flush_win32(PARROT_INTERP, ARGMOD(PMC *filehandle))
405 ASSERT_ARGS(Parrot_io_flush_win32)
407 * FlushFileBuffers won't work for console handles. From the MS help file:
409 * Windows NT: The function fails if hFile is a handle to console
410 * output. That is because console output is not buffered. The
411 * function returns FALSE, and GetLastError returns
412 * ERROR_INVALID_HANDLE.
414 * Windows 9x: The function does nothing if hFile is a handle to
415 * console output. That is because console output is not buffered.
416 * The function returns TRUE, but it does nothing.
418 return FlushFileBuffers(Parrot_io_get_os_handle(interp, filehandle));
423 =item C<size_t Parrot_io_read_win32(PARROT_INTERP, PMC *filehandle, STRING
424 **buf)>
426 Calls C<ReadFile()> to read up to C<len> bytes from C<*io>'s file
427 descriptor to the memory starting at C<buffer>.
429 =cut
433 size_t
434 Parrot_io_read_win32(PARROT_INTERP,
435 ARGMOD(PMC *filehandle),
436 ARGOUT(STRING **buf))
438 ASSERT_ARGS(Parrot_io_read_win32)
439 DWORD countread;
440 void *buffer;
441 size_t len;
442 STRING *s;
444 s = Parrot_io_make_string(interp, buf, 2048);
445 len = s->bufused;
446 buffer = Buffer_bufstart(s);
448 if (ReadFile(Parrot_io_get_os_handle(interp, filehandle),
449 (LPVOID) buffer, (DWORD) len, &countread, NULL)) {
450 if (countread > 0) {
451 s->bufused = s->strlen = countread;
452 return (size_t)countread;
454 else if (len > 0)
455 /* EOF if read 0 and bytes were requested */
456 Parrot_io_set_flags(interp, filehandle,
457 (Parrot_io_get_flags(interp, filehandle) | PIO_F_EOF));
459 else {
460 /* FIXME : An error occured */
461 Parrot_io_set_flags(interp, filehandle,
462 (Parrot_io_get_flags(interp, filehandle) | PIO_F_EOF));
465 s->bufused = s->strlen = 0;
466 return 0;
471 =item C<size_t Parrot_io_write_win32(PARROT_INTERP, PMC *filehandle, const
472 STRING *s)>
474 Calls C<WriteFile()> to write C<len> bytes from the memory starting at
475 C<buffer> to C<*io>'s file descriptor. Returns C<(size_t)-1> on
476 failure.
478 =cut
482 size_t
483 Parrot_io_write_win32(PARROT_INTERP, ARGIN(PMC *filehandle), ARGIN(const STRING *s))
485 ASSERT_ARGS(Parrot_io_write_win32)
486 DWORD countwrote = 0;
487 DWORD err;
488 void * const buffer = s->strstart;
489 DWORD len = (DWORD) s->bufused;
490 PIOHANDLE os_handle = Parrot_io_get_os_handle(interp, filehandle);
492 /* do it by hand, Win32 hasn't any specific flag */
493 if (Parrot_io_get_flags(interp, filehandle) & PIO_F_APPEND) {
494 LARGE_INTEGER p;
495 p.LowPart = 0;
496 p.HighPart = 0;
497 p.LowPart = SetFilePointer(os_handle, p.LowPart,
498 &p.HighPart, FILE_END);
499 if (p.LowPart == 0xFFFFFFFF && (GetLastError() != NO_ERROR)) {
500 /* Error - exception */
501 return (size_t)-1;
505 if (WriteFile(os_handle, (LPCSTR) buffer, len, &countwrote, NULL))
506 return countwrote;
508 /* Write may have failed because of small buffers,
509 * see TT #710 for example.
510 * Let's try writing in small chunks */
511 if ((err = GetLastError()) == ERROR_NOT_ENOUGH_MEMORY || err == ERROR_INVALID_USER_BUFFER) {
512 DWORD chunk = 4096; /* Arbitrarily choosen value */
513 if (len < chunk)
514 goto fail;
515 while (len > 0) {
516 if (chunk > len)
517 chunk = len;
518 if (WriteFile(os_handle, (LPCSTR) buffer, chunk, &countwrote, NULL) == 0 ||
519 countwrote != chunk)
520 goto fail;
521 len -= chunk;
523 return len;
525 fail:
526 /* FIXME: Set error flag */
527 return (size_t)-1;
532 =item C<PIOOFF_T Parrot_io_seek_win32(PARROT_INTERP, PMC *filehandle, PIOOFF_T
533 off, INTVAL whence)>
535 Hard seek.
537 Calls C<SetFilePointer()> to move the read/write position of C<*io>'s
538 file descriptor to C<off> bytes relative to the location specified by
539 C<whence>.
541 =cut
545 PIOOFF_T
546 Parrot_io_seek_win32(PARROT_INTERP, ARGMOD(PMC *filehandle),
547 PIOOFF_T off, INTVAL whence)
549 ASSERT_ARGS(Parrot_io_seek_win32)
550 LARGE_INTEGER offset;
552 offset.QuadPart = off;
553 /* offset.HighPart gets overwritten */
554 offset.LowPart = SetFilePointer(Parrot_io_get_os_handle(interp, filehandle),
555 offset.LowPart, &offset.HighPart, whence);
556 if (offset.LowPart == 0xFFFFFFFF && (GetLastError() != NO_ERROR)) {
557 /* Error - exception */
558 return -1;
560 Parrot_io_set_file_position(interp, filehandle, offset.QuadPart);
561 return offset.QuadPart;
566 =item C<PIOOFF_T Parrot_io_tell_win32(PARROT_INTERP, PMC *filehandle)>
568 Returns the current read/write position of C<*io>'s file descriptor.
570 =cut
574 PIOOFF_T
575 Parrot_io_tell_win32(PARROT_INTERP, ARGIN(PMC *filehandle))
577 ASSERT_ARGS(Parrot_io_tell_win32)
578 LARGE_INTEGER p;
580 p.QuadPart = piooffsetzero;
581 p.LowPart = SetFilePointer(Parrot_io_get_os_handle(interp, filehandle),
582 0, &p.HighPart, FILE_CURRENT);
583 if (p.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
584 /* FIXME: Error - exception */
586 return p.QuadPart;
591 =item C<size_t Parrot_io_peek_win32(PARROT_INTERP, PMC *filehandle, STRING
592 **buf)>
594 Retrieve the next character in the stream without modifying the stream. Not
595 implemented for this platform.
597 =cut
601 size_t
602 Parrot_io_peek_win32(PARROT_INTERP,
603 SHIM(PMC *filehandle),
604 SHIM(STRING **buf))
606 ASSERT_ARGS(Parrot_io_peek_win32)
607 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
608 "peek() not implemented");
613 =item C<PMC * Parrot_io_open_pipe_win32(PARROT_INTERP, PMC *filehandle, STRING
614 *command, int flags)>
616 Open a pipe. Not implemented for this platform.
618 =cut
622 PARROT_WARN_UNUSED_RESULT
623 PARROT_CAN_RETURN_NULL
624 PMC *
625 Parrot_io_open_pipe_win32(PARROT_INTERP, ARGMOD(PMC *filehandle),
626 ARGIN(STRING *command), int flags)
628 ASSERT_ARGS(Parrot_io_open_pipe_win32)
630 HANDLE current = GetCurrentProcess();
631 HANDLE hnull = INVALID_HANDLE_VALUE;
632 HANDLE hread = INVALID_HANDLE_VALUE;
633 HANDLE hwrite = INVALID_HANDLE_VALUE;
634 HANDLE hchild = INVALID_HANDLE_VALUE;
635 STARTUPINFO start;
636 SECURITY_ATTRIBUTES sec;
637 PROCESS_INFORMATION procinfo;
638 char *cmd = NULL;
639 const char *comspec;
640 PMC *io = PMC_IS_NULL(filehandle) ? Parrot_io_new_pmc(interp, flags) : filehandle;
641 STRING *auxcomm;
642 int f_read = (flags & PIO_F_READ) != 0;
643 int f_write = (flags & PIO_F_WRITE) != 0;
644 if (f_read == f_write)
645 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
646 "Invalid pipe mode: %X", flags);
648 procinfo.hThread = INVALID_HANDLE_VALUE;
649 procinfo.hProcess = INVALID_HANDLE_VALUE;
650 sec.nLength = sizeof sec;
651 sec.lpSecurityDescriptor = NULL;
652 sec.bInheritHandle = TRUE;
654 comspec = getenv("COMSPEC");
655 if (comspec == NULL)
656 comspec = "cmd";
657 auxcomm = Parrot_str_new(interp, comspec, 0);
658 auxcomm = Parrot_str_concat(interp, auxcomm, Parrot_str_new(interp, " /c ", 0));
659 auxcomm = Parrot_str_concat(interp, auxcomm, command);
660 cmd = Parrot_str_to_cstring(interp, auxcomm);
661 start.cb = sizeof start;
662 GetStartupInfo(&start);
663 start.dwFlags = STARTF_USESTDHANDLES;
664 if (CreatePipe(&hread, &hwrite, NULL, 0) == 0)
665 goto fail;
666 if (DuplicateHandle(current, f_read ? hwrite : hread,
667 current, &hchild,
668 0, TRUE,
669 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)
670 == 0)
671 goto fail;
672 if (hchild == INVALID_HANDLE_VALUE)
673 goto fail;
675 if (f_read) {
676 /* Redirect input to NULL. This is to avoid
677 * interferences in case both the child and
678 * the parent tries to read from stdin.
679 * May be unneccessary or even interfere
680 * with valid usages, need more feedback. */
681 hnull = CreateFile("NUL", GENERIC_READ|GENERIC_WRITE,
682 0, &sec, OPEN_EXISTING,
683 FILE_ATTRIBUTE_NORMAL, NULL);
684 if (hnull == INVALID_HANDLE_VALUE)
685 goto fail;
686 start.hStdInput = hnull;
687 start.hStdOutput = hchild;
688 start.hStdError = hchild;
690 else {
691 start.hStdInput = hchild;
694 if (CreateProcess(NULL,
695 cmd,
696 NULL, NULL, TRUE, 0,
697 NULL, NULL, &start, &procinfo) == 0)
698 goto fail;
699 if (f_read) {
700 Parrot_io_set_os_handle(interp, io, hread);
701 CloseHandle(hwrite);
703 else {
704 Parrot_io_set_os_handle(interp, io, hwrite);
705 CloseHandle(hread);
708 Parrot_str_free_cstring(cmd);
709 CloseHandle(procinfo.hThread);
710 VTABLE_set_integer_keyed_int(interp, io, 0, (INTVAL)procinfo.hProcess);
711 return io;
713 fail:
714 if (cmd != NULL)
715 Parrot_str_free_cstring(cmd);
716 if (hnull != INVALID_HANDLE_VALUE)
717 CloseHandle(hnull);
718 if (hread != INVALID_HANDLE_VALUE)
719 CloseHandle(hread);
720 if (hwrite != INVALID_HANDLE_VALUE)
721 CloseHandle(hwrite);
722 if (hchild != INVALID_HANDLE_VALUE)
723 CloseHandle(hchild);
724 if (procinfo.hThread != INVALID_HANDLE_VALUE)
725 CloseHandle(procinfo.hThread);
726 if (procinfo.hProcess != INVALID_HANDLE_VALUE)
727 CloseHandle(procinfo.hProcess);
728 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
729 "pipe open error");
734 =item C<INTVAL Parrot_io_pipe_win32(PARROT_INTERP, PIOHANDLE *reader, PIOHANDLE
735 *writer)>
737 Uses CreatePipe() to create a matched pair of pipe handles. Returns 0 on
738 success, -1 on failure.
740 =cut
744 PARROT_WARN_UNUSED_RESULT
745 PARROT_CAN_RETURN_NULL
746 INTVAL
747 Parrot_io_pipe_win32(SHIM_INTERP, ARGMOD(PIOHANDLE *reader), ARGMOD(PIOHANDLE *writer))
749 ASSERT_ARGS(Parrot_io_pipe_win32)
750 return CreatePipe(reader, writer, NULL, 0) ? 0 : -1;
753 #endif /* PIO_OS_WIN32 */
757 =back
759 =head1 SEE ALSO
761 F<src/io/unix.c>,
762 F<src/io/stdio.c>,
763 F<src/io/io.c>,
764 F<src/io/io_private.h>.
765 F<include/parrot/io_win32.h>.
767 =cut
773 * Local variables:
774 * c-file-style: "parrot"
775 * End:
776 * vim: expandtab shiftwidth=4: