diff lphobos/std/stdio.d @ 131:5825d48b27d1 trunk

[svn r135] * Merged DMD 1.025 * * Fixed a minor linking order mishap * * Added an command line option -annotate * * Fixed some problems with running optimizations * * Added std.stdio and dependencies to lphobos (still not 100% working, but compiles and links) * * Fixed problems with passing aggregate types to variadic functions * * Added initial code towards full GC support, currently based on malloc and friends, not all the runtime calls the GC yet for memory * * Fixed problems with resolving nested function context pointers for some heavily nested cases * * Redid function argument passing + other minor code cleanups, still lots to do on this end... *
author lindquist
date Fri, 04 Jan 2008 01:38:42 +0100
parents 61615fa85940
children
line wrap: on
line diff
--- a/lphobos/std/stdio.d	Fri Dec 28 23:52:40 2007 +0100
+++ b/lphobos/std/stdio.d	Fri Jan 04 01:38:42 2008 +0100
@@ -1,44 +1,548 @@
+
+// Written in the D programming language.
+
+/* Written by Walter Bright and Andrei Alexandrescu
+ * www.digitalmars.com
+ * Placed in the Public Domain.
+ */
+
+/********************************
+ * Standard I/O functions that extend $(B std.c.stdio).
+ * $(B std.c.stdio) is automatically imported when importing
+ * $(B std.stdio).
+ * Macros:
+ *	WIKI=Phobos/StdStdio
+ */
+
 module std.stdio;
 
-import std.traits;
+public import std.c.stdio;
+
+import std.format;
+import std.utf;
+import std.string;
+import std.gc;
+import std.c.stdlib;
+import std.c.string;
+import std.c.stddef;
+
+
+version (DigitalMars)
+{
+    version (Windows)
+    {
+	// Specific to the way Digital Mars C does stdio
+	version = DIGITAL_MARS_STDIO;
+    }
+}
 
-void _writef(T)(T t) {
-    static if (is(T == char)) {
-        printf("%c", t);
+version (DIGITAL_MARS_STDIO)
+{
+}
+else
+{
+    // Specific to the way Gnu C does stdio
+    version = GCC_IO;
+    import std.c.linux.linux;
+}
+
+version (DIGITAL_MARS_STDIO)
+{
+    extern (C)
+    {
+	/* **
+	 * Digital Mars under-the-hood C I/O functions
+	 */
+	int _fputc_nlock(int, FILE*);
+	int _fputwc_nlock(int, FILE*);
+	int _fgetc_nlock(FILE*);
+	int _fgetwc_nlock(FILE*);
+	int __fp_lock(FILE*);
+	void __fp_unlock(FILE*);
     }
-    else static if (is(T : char[])) {
-        printf("%.*s", t.length, t.ptr);
+    alias _fputc_nlock FPUTC;
+    alias _fputwc_nlock FPUTWC;
+    alias _fgetc_nlock FGETC;
+    alias _fgetwc_nlock FGETWC;
+
+    alias __fp_lock FLOCK;
+    alias __fp_unlock FUNLOCK;
+}
+else version (GCC_IO)
+{
+    /* **
+     * Gnu under-the-hood C I/O functions; see
+     * http://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html#I_002fO-on-Streams
+     */
+    extern (C)
+    {
+	int fputc_unlocked(int, FILE*);
+	int fputwc_unlocked(wchar_t, FILE*);
+	int fgetc_unlocked(FILE*);
+	int fgetwc_unlocked(FILE*);
+	void flockfile(FILE*);
+	void funlockfile(FILE*);
+	ssize_t getline(char**, size_t*, FILE*);
+	ssize_t getdelim (char**, size_t*, int, FILE*);
     }
-    else static if (is(T : long)) {
-        printf("%ld", t);
+
+    alias fputc_unlocked FPUTC;
+    alias fputwc_unlocked FPUTWC;
+    alias fgetc_unlocked FGETC;
+    alias fgetwc_unlocked FGETWC;
+
+    alias flockfile FLOCK;
+    alias funlockfile FUNLOCK;
+}
+else
+{
+    static assert(0, "unsupported C I/O system");
+}
+
+
+/*********************
+ * Thrown if I/O errors happen.
+ */
+class StdioException : Exception
+{
+    uint errno;			// operating system error code
+
+    this(char[] msg)
+    {
+	super(msg);
     }
-    else static if (is(T : ulong)) {
-        printf("%lu", t);
+
+    this(uint errno)
+    {	char* s = strerror(errno);
+	super(std.string.toString(s).dup);
+    }
+
+    static void opCall(char[] msg)
+    {
+	throw new StdioException(msg);
+    }
+
+    static void opCall()
+    {
+	throw new StdioException(getErrno());
     }
-    else static if (is(T : real)) {
-        printf("%f", t);
+}
+
+private
+void writefx(FILE* fp, TypeInfo[] arguments, void* argptr, int newline=false)
+{   int orientation;
+
+    orientation = fwide(fp, 0);
+
+    /* Do the file stream locking at the outermost level
+     * rather than character by character.
+     */
+    FLOCK(fp);
+    scope(exit) FUNLOCK(fp);
+
+    if (orientation <= 0)		// byte orientation or no orientation
+    {
+	void putc(dchar c)
+	{
+	    if (c <= 0x7F)
+	    {
+		FPUTC(c, fp);
+	    }
+	    else
+	    {   char[4] buf;
+		char[] b;
+
+		b = std.utf.toUTF8(buf, c);
+		for (size_t i = 0; i < b.length; i++)
+		    FPUTC(b[i], fp);
+	    }
+	}
+
+	std.format.doFormat(&putc, arguments, argptr);
+	if (newline)
+	    FPUTC('\n', fp);
     }
-    else static if (is(T : Object)) {
-        _writef(t.toString());
+    else if (orientation > 0)		// wide orientation
+    {
+	version (Windows)
+	{
+	    void putcw(dchar c)
+	    {
+		assert(isValidDchar(c));
+		if (c <= 0xFFFF)
+		{
+		    FPUTWC(c, fp);
+		}
+		else
+		{   wchar[2] buf;
+
+		    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+		    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+		    FPUTWC(buf[0], fp);
+		    FPUTWC(buf[1], fp);
+		}
+	    }
+	}
+	else version (linux)
+	{
+	    void putcw(dchar c)
+	    {
+		FPUTWC(c, fp);
+	    }
+	}
+	else
+	{
+	    static assert(0);
+	}
+
+	std.format.doFormat(&putcw, arguments, argptr);
+	if (newline)
+	    FPUTWC('\n', fp);
     }
-    else static if(isArray!(T)) {
-        _writef('[');
-        if (t.length) {
-            _writef(t[0]);
-            foreach(v; t[1..$]) {
-                _writef(','); _writef(v);
-            }
-        }
-        _writef(']');
-    }
-    else static assert(0, "Cannot writef:"~T.tostring);
+}
+
+
+/***********************************
+ * Arguments are formatted per the
+ * $(LINK2 std_format.html#format-string, format strings)
+ * and written to $(B stdout).
+ */
+
+void writef(...)
+{
+    writefx(stdout, _arguments, _argptr, 0);
+}
+
+/***********************************
+ * Same as $(B writef), but a newline is appended
+ * to the output.
+ */
+
+void writefln(...)
+{
+    writefx(stdout, _arguments, _argptr, 1);
+}
+
+/***********************************
+ * Same as $(B writef), but output is sent to the
+ * stream fp instead of $(B stdout).
+ */
+
+void fwritef(FILE* fp, ...)
+{
+    writefx(fp, _arguments, _argptr, 0);
+}
+
+/***********************************
+ * Same as $(B writefln), but output is sent to the
+ * stream fp instead of $(B stdout).
+ */
+
+void fwritefln(FILE* fp, ...)
+{
+    writefx(fp, _arguments, _argptr, 1);
+}
+
+/**********************************
+ * Read line from stream fp.
+ * Returns:
+ *	null for end of file,
+ *	char[] for line read from fp, including terminating '\n'
+ * Params:
+ *	fp = input stream
+ * Throws:
+ *	$(B StdioException) on error
+ * Example:
+ *	Reads $(B stdin) and writes it to $(B stdout).
+---
+import std.stdio;
+
+int main()
+{
+    char[] buf;
+    while ((buf = readln()) != null)
+	writef("%s", buf);
+    return 0;
+}
+---
+ */
+char[] readln(FILE* fp = stdin)
+{
+    char[] buf;
+    readln(fp, buf);
+    return buf;
 }
 
-void writef(T...)(T t)
+/**********************************
+ * Read line from stream fp and write it to buf[],
+ * including terminating '\n'.
+ *
+ * This is often faster than readln(FILE*) because the buffer
+ * is reused each call. Note that reusing the buffer means that
+ * the previous contents of it need to be copied if needed.
+ * Params:
+ *	fp = input stream
+ *	buf = buffer used to store the resulting line data. buf
+ *		is resized as necessary.
+ * Returns:
+ *	0 for end of file, otherwise
+ *	number of characters read
+ * Throws:
+ *	$(B StdioException) on error
+ * Example:
+ *	Reads $(B stdin) and writes it to $(B stdout).
+---
+import std.stdio;
+
+int main()
 {
-    foreach(v;t) _writef(v);
+    char[] buf;
+    while (readln(stdin, buf))
+	writef("%s", buf);
+    return 0;
 }
-void writefln(T...)(T t)
+---
+ */
+size_t readln(FILE* fp, inout char[] buf)
 {
-    writef(t, '\n');
+    version (DIGITAL_MARS_STDIO)
+    {
+	FLOCK(fp);
+	scope(exit) FUNLOCK(fp);
+
+	if (__fhnd_info[fp._file] & FHND_WCHAR)
+	{   /* Stream is in wide characters.
+	     * Read them and convert to chars.
+	     */
+	    static assert(wchar_t.sizeof == 2);
+	    buf.length = 0;
+	    int c2;
+	    for (int c; (c = FGETWC(fp)) != -1; )
+	    {
+		if ((c & ~0x7F) == 0)
+		{   buf ~= c;
+		    if (c == '\n')
+			break;
+		}
+		else
+		{
+		    if (c >= 0xD800 && c <= 0xDBFF)
+		    {
+			if ((c2 = FGETWC(fp)) != -1 ||
+			    c2 < 0xDC00 && c2 > 0xDFFF)
+			{
+			    StdioException("unpaired UTF-16 surrogate");
+			}
+			c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+		    }
+		    std.utf.encode(buf, c);
+		}
+	    }
+	    if (ferror(fp))
+		StdioException();
+	    return buf.length;
+	}
+
+	auto sz = std.gc.capacity(buf.ptr);
+	//auto sz = buf.length;
+	buf = buf.ptr[0 .. sz];
+	if (fp._flag & _IONBF)
+	{
+	    /* Use this for unbuffered I/O, when running
+	     * across buffer boundaries, or for any but the common
+	     * cases.
+	     */
+	 L1:
+	    char *p;
+
+	    if (sz)
+	    {
+		p = buf.ptr;
+	    }
+	    else
+	    {
+		sz = 64;
+		p = cast(char*) std.gc.malloc(sz);
+		std.gc.hasNoPointers(p);
+		buf = p[0 .. sz];
+	    }
+	    size_t i = 0;
+	    for (int c; (c = FGETC(fp)) != -1; )
+	    {
+		if ((p[i] = c) != '\n')
+		{
+		    i++;
+		    if (i < sz)
+			continue;
+		    buf = p[0 .. i] ~ readln(fp);
+		    return buf.length;
+		}
+		else
+		{
+		    buf = p[0 .. i + 1];
+		    return i + 1;
+		}
+	    }
+	    if (ferror(fp))
+		StdioException();
+	    buf = p[0 .. i];
+	    return i;
+	}
+	else
+	{
+	    int u = fp._cnt;
+	    char* p = fp._ptr;
+	    int i;
+	    if (fp._flag & _IOTRAN)
+	    {   /* Translated mode ignores \r and treats ^Z as end-of-file
+		 */
+		char c;
+		while (1)
+		{
+		    if (i == u)		// if end of buffer
+			goto L1;	// give up
+		    c = p[i];
+		    i++;
+		    if (c != '\r')
+		    {
+			if (c == '\n')
+			    break;
+			if (c != 0x1A)
+			    continue;
+			goto L1;
+		    }
+		    else
+		    {   if (i != u && p[i] == '\n')
+			    break;
+			goto L1;
+		    }
+		}
+		if (i > sz)
+		{
+		    buf = cast(char[])std.gc.malloc(i);
+		    std.gc.hasNoPointers(buf.ptr);
+		}
+		if (i - 1)
+		    memcpy(buf.ptr, p, i - 1);
+		buf[i - 1] = '\n';
+		if (c == '\r')
+		    i++;
+	    }
+	    else
+	    {
+		while (1)
+		{
+		    if (i == u)		// if end of buffer
+			goto L1;	// give up
+		    auto c = p[i];
+		    i++;
+		    if (c == '\n')
+			break;
+		}
+		if (i > sz)
+		{
+		    buf = cast(char[])std.gc.malloc(i);
+		    std.gc.hasNoPointers(buf.ptr);
+		}
+		memcpy(buf.ptr, p, i);
+	    }
+	    fp._cnt -= i;
+	    fp._ptr += i;
+	    buf = buf[0 .. i];
+	    return i;
+	}
+    }
+    else version (GCC_IO)
+    {
+	if (fwide(fp, 0) > 0)
+	{   /* Stream is in wide characters.
+	     * Read them and convert to chars.
+	     */
+	    FLOCK(fp);
+	    scope(exit) FUNLOCK(fp);
+	    version (Windows)
+	    {
+		buf.length = 0;
+		int c2;
+		for (int c; (c = FGETWC(fp)) != -1; )
+		{
+		    if ((c & ~0x7F) == 0)
+		    {   buf ~= c;
+			if (c == '\n')
+			    break;
+		    }
+		    else
+		    {
+			if (c >= 0xD800 && c <= 0xDBFF)
+			{
+			    if ((c2 = FGETWC(fp)) != -1 ||
+				c2 < 0xDC00 && c2 > 0xDFFF)
+			    {
+				StdioException("unpaired UTF-16 surrogate");
+			    }
+			    c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+			}
+			std.utf.encode(buf, c);
+		    }
+		}
+		if (ferror(fp))
+		    StdioException();
+		return buf.length;
+	    }
+	    else version (linux)
+	    {
+		buf.length = 0;
+		for (int c; (c = FGETWC(fp)) != -1; )
+		{
+		    if ((c & ~0x7F) == 0)
+			buf ~= c;
+		    else
+			std.utf.encode(buf, cast(dchar)c);
+		    if (c == '\n')
+			break;
+		}
+		if (ferror(fp))
+		    StdioException();
+		return buf.length;
+	    }
+	    else
+	    {
+		static assert(0);
+	    }
+	}
+
+	char *lineptr = null;
+	size_t n = 0;
+	auto s = getdelim(&lineptr, &n, '\n', fp);
+	scope(exit) free(lineptr);
+	if (s < 0)
+	{
+	    if (ferror(fp))
+		StdioException();
+	    buf.length = 0;		// end of file
+	    return 0;
+	}
+	buf = buf.ptr[0 .. std.gc.capacity(buf.ptr)];
+	if (s <= buf.length)
+	{
+	    buf.length = s;
+	    buf[] = lineptr[0 .. s];
+	}
+	else
+	{
+	    buf = lineptr[0 .. s].dup;
+	}
+	return s;
+    }
+    else
+    {
+	static assert(0);
+    }
 }
+
+/** ditto */
+size_t readln(inout char[] buf)
+{
+    return readln(stdin, buf);
+}
+