diff options
Diffstat (limited to 'libphobos/src/std/stdio.d')
-rw-r--r-- | libphobos/src/std/stdio.d | 210 |
1 files changed, 116 insertions, 94 deletions
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index ffd6da8..802aa128 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -52,7 +52,7 @@ import std.algorithm.mutation : copy; import std.meta : allSatisfy; import std.range : ElementEncodingType, empty, front, isBidirectionalRange, isInputRange, isSomeFiniteCharInputRange, put; -import std.traits : isSomeChar, isSomeString, Unqual, isPointer; +import std.traits : isSomeChar, isSomeString, Unqual; import std.typecons : Flag, No, Yes; /++ @@ -768,7 +768,7 @@ Throws: `ErrnoException` in case of error. _name = name; } - @system unittest // Test changing filename + @safe unittest // Test changing filename { import std.exception : assertThrown, assertNotThrown; static import std.file; @@ -790,7 +790,7 @@ Throws: `ErrnoException` in case of error. version (CRuntime_DigitalMars) {} else // Not implemented version (CRuntime_Microsoft) {} else // Not implemented - @system unittest // Test changing mode + @safe unittest // Test changing mode { import std.exception : assertThrown, assertNotThrown; static import std.file; @@ -1853,15 +1853,15 @@ void main() } --- */ - S readln(S = string)(dchar terminator = '\n') + S readln(S = string)(dchar terminator = '\n') @safe if (isSomeString!S) { Unqual!(ElementEncodingType!S)[] buf; readln(buf, terminator); - return cast(S) buf; + return (() @trusted => cast(S) buf)(); } - @system unittest + @safe unittest { import std.algorithm.comparison : equal; static import std.file; @@ -1885,7 +1885,7 @@ void main() }} } - @system unittest + @safe unittest { static import std.file; import std.typecons : Tuple; @@ -1984,7 +1984,7 @@ void main() This is actually what $(LREF byLine) does internally, so its usage is recommended if you want to process a complete file. */ - size_t readln(C)(ref C[] buf, dchar terminator = '\n') + size_t readln(C)(ref C[] buf, dchar terminator = '\n') @safe if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum)) { import std.exception : enforce; @@ -2020,9 +2020,8 @@ is recommended if you want to process a complete file. } } - @system unittest + @safe unittest { - // @system due to readln static import std.file; auto deleteme = testFilename(); std.file.write(deleteme, "123\n456789"); @@ -2039,7 +2038,7 @@ is recommended if you want to process a complete file. } // https://issues.dlang.org/show_bug.cgi?id=15293 - @system unittest + @safe unittest { // @system due to readln static import std.file; @@ -2063,7 +2062,7 @@ is recommended if you want to process a complete file. } /** ditto */ - size_t readln(C, R)(ref C[] buf, R terminator) + size_t readln(C, R)(ref C[] buf, R terminator) @safe if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) && isBidirectionalRange!R && is(typeof(terminator.front == dchar.init))) { @@ -2093,7 +2092,7 @@ is recommended if you want to process a complete file. return buf.length; } - @system unittest + @safe unittest { static import std.file; import std.typecons : Tuple; @@ -3735,9 +3734,8 @@ void main() assert(f.tell == 0); } -@system unittest +@safe unittest { - // @system due to readln static import std.file; import std.range : chain, only, repeat; import std.range.primitives : isOutputRange; @@ -5169,13 +5167,13 @@ Initialize with a message and an error code. } /** Convenience functions that throw an `StdioException`. */ - static void opCall(string msg) + static void opCall(string msg) @safe { throw new StdioException(msg); } /// ditto - static void opCall() + static void opCall() @safe { throw new StdioException(null, core.stdc.errno.errno); } @@ -5388,7 +5386,7 @@ private struct ReadlnAppender size_t pos; bool safeAppend = false; - void initialize(char[] b) + void initialize(char[] b) @safe { buf = b; pos = 0; @@ -5445,7 +5443,7 @@ private struct ReadlnAppender foreach (c; ubuf) buf.ptr[pos++] = c; } - void putonly(char[] b) @trusted + void putonly(const char[] b) @trusted { import core.stdc.string : memcpy; assert(pos == 0); // assume this is the only put call @@ -5457,28 +5455,60 @@ private struct ReadlnAppender } } -// Private implementation of readln -private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) +private struct LockedFile { - version (DIGITAL_MARS_STDIO) + private @system _iobuf* fp; + + this(FILE* fps) @trusted { _FLOCK(fps); - scope(exit) _FUNLOCK(fps); + // Since fps is now locked, we can cast away shared + fp = cast(_iobuf*) fps; + } + + @disable this(); + @disable this(this); + @disable void opAssign(LockedFile); - /* Since fps is now locked, we can create an "unshared" version - * of fp. - */ - auto fp = cast(_iobuf*) fps; + // these use unlocked fgetc calls + @trusted fgetc() { return _FGETC(fp); } + @trusted fgetwc() { return _FGETWC(fp); } + ~this() @trusted + { + _FUNLOCK(cast(FILE*) fp); + } +} + +@safe unittest +{ + void f() @safe + { + FILE* fps; + auto lf = LockedFile(fps); + static assert(!__traits(compiles, lf = LockedFile(fps))); + version (ShouldFail) + { + lf.fps = null; // error with -preview=systemVariables + } + } +} + +// Private implementation of readln +private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation) @safe +{ + version (DIGITAL_MARS_STDIO) + return () @trusted { + auto lf = LockedFile(fps); ReadlnAppender app; app.initialize(buf); - if (__fhnd_info[fp._file] & FHND_WCHAR) + if (__fhnd_info[lf.fp._file] & FHND_WCHAR) { /* Stream is in wide characters. * Read them and convert to chars. */ static assert(wchar_t.sizeof == 2); - for (int c = void; (c = _FGETWC(fp)) != -1; ) + for (int c = void; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { @@ -5491,7 +5521,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5504,8 +5534,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (ferror(fps)) StdioException(); } - - else if (fp._flag & _IONBF) + else if (lf.fp._flag & _IONBF) { /* Use this for unbuffered I/O, when running * across buffer boundaries, or for any but the common @@ -5513,7 +5542,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie */ L1: int c; - while ((c = _FGETC(fp)) != -1) + while ((c = lf.fgetc()) != -1) { app.putchar(cast(char) c); if (c == terminator) @@ -5529,10 +5558,10 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } else { - int u = fp._cnt; - char* p = fp._ptr; + int u = lf.fp._cnt; + char* p = lf.fp._ptr; int i; - if (fp._flag & _IOTRAN) + if (lf.fp._flag & _IOTRAN) { /* Translated mode ignores \r and treats ^Z as end-of-file */ char c; @@ -5574,28 +5603,22 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } app.putonly(p[0 .. i]); } - fp._cnt -= i; - fp._ptr += i; + lf.fp._cnt -= i; + lf.fp._ptr += i; } buf = app.data; return buf.length; - } + }(); else version (MICROSOFT_STDIO) { - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - - /* Since fps is now locked, we can create an "unshared" version - * of fp. - */ - auto fp = cast(_iobuf*) fps; + auto lf = LockedFile(fps); ReadlnAppender app; app.initialize(buf); int c; - while ((c = _FGETC(fp)) != -1) + while ((c = lf.fgetc()) != -1) { app.putchar(cast(char) c); if (c == terminator) @@ -5613,21 +5636,18 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } else static if (__traits(compiles, core.sys.posix.stdio.getdelim)) { - import core.stdc.stdlib : free; - import core.stdc.wchar_ : fwide; - if (orientation == File.Orientation.wide) { + import core.stdc.wchar_ : fwide; + + auto lf = LockedFile(fps); /* Stream is in wide characters. * Read them and convert to chars. */ - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - auto fp = cast(_iobuf*) fps; version (Windows) { buf.length = 0; - for (int c = void; (c = _FGETWC(fp)) != -1; ) + for (int c = void; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; @@ -5639,7 +5659,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5650,14 +5670,14 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie encode(buf, c); } } - if (ferror(fp)) + if (ferror(fps)) StdioException(); return buf.length; } else version (Posix) { buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { import std.utf : encode; @@ -5677,47 +5697,49 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie static assert(0); } } + return () @trusted { + import core.stdc.stdlib : free; - static char *lineptr = null; - static size_t n = 0; - scope(exit) - { - if (n > 128 * 1024) + static char *lineptr = null; + static size_t n = 0; + scope(exit) { - // Bound memory used by readln - free(lineptr); - lineptr = null; - n = 0; + if (n > 128 * 1024) + { + // Bound memory used by readln + free(lineptr); + lineptr = null; + n = 0; + } } - } - auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps); - if (s < 0) - { - if (ferror(fps)) - StdioException(); - buf.length = 0; // end of file - return 0; - } + const s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps); + if (s < 0) + { + if (ferror(fps)) + StdioException(); + buf.length = 0; // end of file + return 0; + } - if (s <= buf.length) - { - buf = buf[0 .. s]; - buf[] = lineptr[0 .. s]; - } - else - { - buf = lineptr[0 .. s].dup; - } - return s; + const line = lineptr[0 .. s]; + if (s <= buf.length) + { + buf = buf[0 .. s]; + buf[] = line; + } + else + { + buf = line.dup; + } + return s; + }(); } else // version (NO_GETDELIM) { import core.stdc.wchar_ : fwide; - _FLOCK(fps); - scope(exit) _FUNLOCK(fps); - auto fp = cast(_iobuf*) fps; + auto lf = LockedFile(fps); if (orientation == File.Orientation.wide) { /* Stream is in wide characters. @@ -5726,7 +5748,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie version (Windows) { buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) { buf ~= c; @@ -5738,7 +5760,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie if (c >= 0xD800 && c <= 0xDBFF) { int c2 = void; - if ((c2 = _FGETWC(fp)) != -1 || + if ((c2 = lf.fgetwc()) != -1 || c2 < 0xDC00 && c2 > 0xDFFF) { StdioException("unpaired UTF-16 surrogate"); @@ -5749,7 +5771,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie encode(buf, c); } } - if (ferror(fp)) + if (ferror(fps)) StdioException(); return buf.length; } @@ -5757,7 +5779,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie { import std.utf : encode; buf.length = 0; - for (int c; (c = _FGETWC(fp)) != -1; ) + for (int c; (c = lf.fgetwc()) != -1; ) { if ((c & ~0x7F) == 0) buf ~= cast(char) c; @@ -5780,7 +5802,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie // First, fill the existing buffer for (size_t bufPos = 0; bufPos < buf.length; ) { - immutable c = _FGETC(fp); + immutable c = lf.fgetc(); if (c == -1) { buf.length = bufPos; @@ -5795,7 +5817,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie } } // Then, append to it - for (int c; (c = _FGETC(fp)) != -1; ) + for (int c; (c = lf.fgetc()) != -1; ) { buf ~= cast(char) c; if (c == terminator) |