aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/stdio.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/stdio.d')
-rw-r--r--libphobos/src/std/stdio.d210
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)