mirror of
https://github.com/dlang/phobos.git
synced 2025-05-04 09:00:22 +03:00
Merge pull request #1888 from CyberShadow/std-stdio-handle
std.stdio: Add File.windowsHandle, fdopen and windowsHandleOpen
This commit is contained in:
commit
fe532ece6f
2 changed files with 135 additions and 84 deletions
|
@ -124,26 +124,12 @@ version (Windows)
|
||||||
version (DMC_RUNTIME) { } else
|
version (DMC_RUNTIME) { } else
|
||||||
{
|
{
|
||||||
import core.stdc.stdint;
|
import core.stdc.stdint;
|
||||||
extern(C)
|
|
||||||
{
|
|
||||||
int _fileno(FILE* stream);
|
|
||||||
HANDLE _get_osfhandle(int fd);
|
|
||||||
int _open_osfhandle(HANDLE osfhandle, int flags);
|
|
||||||
FILE* _fdopen(int fd, const (char)* mode);
|
|
||||||
int _close(int fd);
|
|
||||||
}
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
STDIN_FILENO = 0,
|
STDIN_FILENO = 0,
|
||||||
STDOUT_FILENO = 1,
|
STDOUT_FILENO = 1,
|
||||||
STDERR_FILENO = 2,
|
STDERR_FILENO = 2,
|
||||||
}
|
}
|
||||||
enum
|
|
||||||
{
|
|
||||||
_O_RDONLY = 0x0000,
|
|
||||||
_O_APPEND = 0x0004,
|
|
||||||
_O_TEXT = 0x4000,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,13 +469,9 @@ private Pid spawnProcessImpl(in char[] commandLine,
|
||||||
static void prepareStream(ref File file, DWORD stdHandle, string which,
|
static void prepareStream(ref File file, DWORD stdHandle, string which,
|
||||||
out int fileDescriptor, out HANDLE handle)
|
out int fileDescriptor, out HANDLE handle)
|
||||||
{
|
{
|
||||||
fileDescriptor = _fileno(file.getFP());
|
fileDescriptor = file.isOpen ? file.fileno() : -1;
|
||||||
if (fileDescriptor < 0) handle = GetStdHandle(stdHandle);
|
if (fileDescriptor < 0) handle = GetStdHandle(stdHandle);
|
||||||
else
|
else handle = file.windowsHandle;
|
||||||
{
|
|
||||||
version (DMC_RUNTIME) handle = _fdToHandle(fileDescriptor);
|
|
||||||
else /* MSVCRT */ handle = _get_osfhandle(fileDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD dwFlags;
|
DWORD dwFlags;
|
||||||
if (GetHandleInformation(handle, &dwFlags))
|
if (GetHandleInformation(handle, &dwFlags))
|
||||||
|
@ -1440,69 +1422,24 @@ Pipe pipe() @trusted //TODO: @safe
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create file descriptors from the handles
|
scope(failure)
|
||||||
version (DMC_RUNTIME)
|
|
||||||
{
|
{
|
||||||
auto readFD = _handleToFD(readHandle, FHND_DEVICE);
|
CloseHandle(readHandle);
|
||||||
auto writeFD = _handleToFD(writeHandle, FHND_DEVICE);
|
CloseHandle(writeHandle);
|
||||||
}
|
|
||||||
else // MSVCRT
|
|
||||||
{
|
|
||||||
auto readFD = _open_osfhandle(readHandle, _O_RDONLY);
|
|
||||||
auto writeFD = _open_osfhandle(writeHandle, _O_APPEND);
|
|
||||||
}
|
|
||||||
version (DMC_RUNTIME) alias _close = .close;
|
|
||||||
if (readFD == -1 || writeFD == -1)
|
|
||||||
{
|
|
||||||
// Close file descriptors, then throw.
|
|
||||||
if (readFD >= 0) _close(readFD);
|
|
||||||
else CloseHandle(readHandle);
|
|
||||||
if (writeFD >= 0) _close(writeFD);
|
|
||||||
else CloseHandle(writeHandle);
|
|
||||||
throw new StdioException("Error creating pipe");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create FILE pointers from the file descriptors
|
try
|
||||||
Pipe p;
|
|
||||||
version (DMC_RUNTIME)
|
|
||||||
{
|
{
|
||||||
// This is a re-implementation of DMC's fdopen, but without the
|
Pipe p;
|
||||||
// mucking with the file descriptor. POSIX standard requires the
|
p._read .windowsHandleOpen(readHandle , "r");
|
||||||
// new fdopen'd file to retain the given file descriptor's
|
p._write.windowsHandleOpen(writeHandle, "a");
|
||||||
// position.
|
return p;
|
||||||
FILE * local_fdopen(int fd, const(char)* mode)
|
|
||||||
{
|
|
||||||
auto fp = core.stdc.stdio.fopen("NUL", mode);
|
|
||||||
if(!fp) return null;
|
|
||||||
FLOCK(fp);
|
|
||||||
auto iob = cast(_iobuf*)fp;
|
|
||||||
.close(iob._file);
|
|
||||||
iob._file = fd;
|
|
||||||
iob._flag &= ~_IOTRAN;
|
|
||||||
FUNLOCK(fp);
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto readFP = local_fdopen(readFD, "r");
|
|
||||||
auto writeFP = local_fdopen(writeFD, "a");
|
|
||||||
}
|
}
|
||||||
else // MSVCRT
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
auto readFP = _fdopen(readFD, "r");
|
throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
|
||||||
auto writeFP = _fdopen(writeFD, "a");
|
0);
|
||||||
}
|
}
|
||||||
if (readFP == null || writeFP == null)
|
|
||||||
{
|
|
||||||
// Close streams, then throw.
|
|
||||||
if (readFP != null) fclose(readFP);
|
|
||||||
else _close(readFD);
|
|
||||||
if (writeFP != null) fclose(writeFP);
|
|
||||||
else _close(writeFD);
|
|
||||||
throw new StdioException("Cannot open pipe");
|
|
||||||
}
|
|
||||||
p._read = File(readFP, null);
|
|
||||||
p._write = File(writeFP, null);
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
130
std/stdio.d
130
std/stdio.d
|
@ -69,6 +69,8 @@ version(Windows)
|
||||||
/+ Waiting for druntime pull 299
|
/+ Waiting for druntime pull 299
|
||||||
+/
|
+/
|
||||||
extern (C) nothrow FILE* _wfopen(in wchar* filename, in wchar* mode);
|
extern (C) nothrow FILE* _wfopen(in wchar* filename, in wchar* mode);
|
||||||
|
|
||||||
|
import core.sys.windows.windows : HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
version (DIGITAL_MARS_STDIO)
|
version (DIGITAL_MARS_STDIO)
|
||||||
|
@ -101,7 +103,6 @@ version (DIGITAL_MARS_STDIO)
|
||||||
enum _O_BINARY = 0x8000;
|
enum _O_BINARY = 0x8000;
|
||||||
int _fileno(FILE* f) { return f._file; }
|
int _fileno(FILE* f) { return f._file; }
|
||||||
alias fileno = _fileno;
|
alias fileno = _fileno;
|
||||||
alias _get_osfhandle = _fdToHandle;
|
|
||||||
}
|
}
|
||||||
else version (MICROSOFT_STDIO)
|
else version (MICROSOFT_STDIO)
|
||||||
{
|
{
|
||||||
|
@ -118,6 +119,7 @@ else version (MICROSOFT_STDIO)
|
||||||
void _unlock_file(FILE*);
|
void _unlock_file(FILE*);
|
||||||
int _setmode(int, int);
|
int _setmode(int, int);
|
||||||
int _fileno(FILE*);
|
int _fileno(FILE*);
|
||||||
|
FILE* _fdopen(int, const (char)*);
|
||||||
}
|
}
|
||||||
alias FPUTC = _fputc_nolock;
|
alias FPUTC = _fputc_nolock;
|
||||||
alias FPUTWC = _fputwc_nolock;
|
alias FPUTWC = _fputwc_nolock;
|
||||||
|
@ -127,8 +129,13 @@ else version (MICROSOFT_STDIO)
|
||||||
alias FLOCK = _lock_file;
|
alias FLOCK = _lock_file;
|
||||||
alias FUNLOCK = _unlock_file;
|
alias FUNLOCK = _unlock_file;
|
||||||
|
|
||||||
enum _O_BINARY = 0x8000;
|
enum
|
||||||
|
{
|
||||||
|
_O_RDONLY = 0x0000,
|
||||||
|
_O_APPEND = 0x0004,
|
||||||
|
_O_TEXT = 0x4000,
|
||||||
|
_O_BINARY = 0x8000,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else version (GCC_IO)
|
else version (GCC_IO)
|
||||||
{
|
{
|
||||||
|
@ -403,6 +410,94 @@ Throws: $(D ErrnoException) in case of error.
|
||||||
command, 1, true);
|
command, 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
First calls $(D detach) (throwing on failure), and then attempts to
|
||||||
|
associate the given file descriptor with the $(D File). The mode must
|
||||||
|
be compatible with the mode of the file descriptor.
|
||||||
|
|
||||||
|
Throws: $(D ErrnoException) in case of error.
|
||||||
|
*/
|
||||||
|
void fdopen(int fd, in char[] stdioOpenmode = "rb")
|
||||||
|
{
|
||||||
|
fdopen(fd, stdioOpenmode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
package void fdopen(int fd, in char[] stdioOpenmode, string name)
|
||||||
|
{
|
||||||
|
import std.string : toStringz;
|
||||||
|
import std.exception : errnoEnforce;
|
||||||
|
|
||||||
|
detach();
|
||||||
|
|
||||||
|
version (DIGITAL_MARS_STDIO)
|
||||||
|
{
|
||||||
|
// This is a re-implementation of DMC's fdopen, but without the
|
||||||
|
// mucking with the file descriptor. POSIX standard requires the
|
||||||
|
// new fdopen'd file to retain the given file descriptor's
|
||||||
|
// position.
|
||||||
|
auto fp = core.stdc.stdio.fopen("NUL", toStringz(stdioOpenmode));
|
||||||
|
errnoEnforce(fp, "Cannot open placeholder NUL stream");
|
||||||
|
FLOCK(fp);
|
||||||
|
auto iob = cast(_iobuf*)fp;
|
||||||
|
.close(iob._file);
|
||||||
|
iob._file = fd;
|
||||||
|
iob._flag &= ~_IOTRAN;
|
||||||
|
FUNLOCK(fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
version (Windows) // MSVCRT
|
||||||
|
auto fp = _fdopen(fd, toStringz(stdioOpenmode));
|
||||||
|
else
|
||||||
|
auto fp = .fdopen(fd, toStringz(stdioOpenmode));
|
||||||
|
errnoEnforce(fp);
|
||||||
|
}
|
||||||
|
this = File(fp, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
First calls $(D detach) (throwing on failure), and then attempts to
|
||||||
|
associate the given Windows $(D HANDLE) with the $(D File). The mode must
|
||||||
|
be compatible with the access attributes of the handle. Windows only.
|
||||||
|
|
||||||
|
Throws: $(D ErrnoException) in case of error.
|
||||||
|
*/
|
||||||
|
version(StdDdoc)
|
||||||
|
void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode);
|
||||||
|
|
||||||
|
version(Windows)
|
||||||
|
void windowsHandleOpen(HANDLE handle, in char[] stdioOpenmode)
|
||||||
|
{
|
||||||
|
import std.exception : errnoEnforce;
|
||||||
|
import std.string : format;
|
||||||
|
|
||||||
|
// Create file descriptors from the handles
|
||||||
|
version (DIGITAL_MARS_STDIO)
|
||||||
|
auto fd = _handleToFD(handle, FHND_DEVICE);
|
||||||
|
else // MSVCRT
|
||||||
|
{
|
||||||
|
int mode;
|
||||||
|
modeLoop:
|
||||||
|
foreach (c; stdioOpenmode)
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'r': mode |= _O_RDONLY; break;
|
||||||
|
case '+': mode &=~_O_RDONLY; break;
|
||||||
|
case 'a': mode |= _O_APPEND; break;
|
||||||
|
case 'b': mode |= _O_BINARY; break;
|
||||||
|
case 't': mode |= _O_TEXT; break;
|
||||||
|
case ',': break modeLoop;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fd = _open_osfhandle(cast(intptr_t)handle, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
errnoEnforce(fd >= 0, "Cannot open Windows HANDLE");
|
||||||
|
fdopen(fd, stdioOpenmode, "HANDLE(%s)".format(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns $(D true) if the file is opened. */
|
/** Returns $(D true) if the file is opened. */
|
||||||
@property bool isOpen() const pure nothrow
|
@property bool isOpen() const pure nothrow
|
||||||
{
|
{
|
||||||
|
@ -797,7 +892,7 @@ Throws: $(D Exception) if the file is not opened.
|
||||||
version(Windows)
|
version(Windows)
|
||||||
{
|
{
|
||||||
import core.sys.windows.windows;
|
import core.sys.windows.windows;
|
||||||
import std.windows.syserror;
|
|
||||||
private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length,
|
private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length,
|
||||||
Flags flags)
|
Flags flags)
|
||||||
{
|
{
|
||||||
|
@ -810,12 +905,14 @@ Throws: $(D Exception) if the file is not opened.
|
||||||
overlapped.Offset = liStart.LowPart;
|
overlapped.Offset = liStart.LowPart;
|
||||||
overlapped.OffsetHigh = liStart.HighPart;
|
overlapped.OffsetHigh = liStart.HighPart;
|
||||||
overlapped.hEvent = null;
|
overlapped.hEvent = null;
|
||||||
return F(cast(HANDLE)_get_osfhandle(fileno), flags, 0,
|
return F(windowsHandle, flags, 0, liLength.LowPart,
|
||||||
liLength.LowPart, liLength.HighPart, &overlapped);
|
liLength.HighPart, &overlapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T wenforce(T)(T cond, string str)
|
private static T wenforce(T)(T cond, string str)
|
||||||
{
|
{
|
||||||
|
import std.windows.syserror;
|
||||||
|
|
||||||
if (cond) return cond;
|
if (cond) return cond;
|
||||||
throw new Exception(str ~ ": " ~ sysErrorString(GetLastError()));
|
throw new Exception(str ~ ": " ~ sysErrorString(GetLastError()));
|
||||||
}
|
}
|
||||||
|
@ -1380,6 +1477,22 @@ Returns the file number corresponding to this object.
|
||||||
return .fileno(cast(FILE*) _p.handle);
|
return .fileno(cast(FILE*) _p.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the underlying operating system $(D HANDLE) (Windows only).
|
||||||
|
*/
|
||||||
|
version(StdDdoc)
|
||||||
|
@property HANDLE windowsHandle();
|
||||||
|
|
||||||
|
version(Windows)
|
||||||
|
@property HANDLE windowsHandle()
|
||||||
|
{
|
||||||
|
version (DIGITAL_MARS_STDIO)
|
||||||
|
return _fdToHandle(fileno);
|
||||||
|
else
|
||||||
|
return cast(HANDLE)_get_osfhandle(fileno);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note: This was documented until 2013/08
|
// Note: This was documented until 2013/08
|
||||||
/*
|
/*
|
||||||
Range that reads one line at a time. Returned by $(LREF byLine).
|
Range that reads one line at a time. Returned by $(LREF byLine).
|
||||||
|
@ -3679,8 +3792,9 @@ version(linux)
|
||||||
enforce(sock.connect(s, cast(sock.sockaddr*) &addr, addr.sizeof) != -1,
|
enforce(sock.connect(s, cast(sock.sockaddr*) &addr, addr.sizeof) != -1,
|
||||||
new StdioException("Connect failed"));
|
new StdioException("Connect failed"));
|
||||||
|
|
||||||
return File(enforce(fdopen(s, "w+".ptr)),
|
File f;
|
||||||
host ~ ":" ~ to!string(port));
|
f.fdopen(s, "w+", host ~ ":" ~ to!string(port));
|
||||||
|
return f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue