Changeset 1721

Show
Ignore:
Timestamp:
07/04/10 17:49:23 (4 years ago)
Author:
andrei
Message:

Implemented readf (yay)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/stdio.d

    r1624 r1721  
    88WIKI=Phobos/StdStdio 
    99 
    10 Copyright: Copyright Digital Mars 2007 - 2009
    11 License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>
     10Copyright: Copyright Digital Mars 2007-
     11License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0)
    1212Authors:   $(WEB digitalmars.com, Walter Bright), 
    1313           $(WEB erdani.org, Andrei Alexandrescu) 
    14  
    15          Copyright Digital Mars 2007 - 2009. 
    16 Distributed under the Boost Software License, Version 1.0. 
    17    (See accompanying file LICENSE_1_0.txt or copy at 
    18          http://www.boost.org/LICENSE_1_0.txt) 
    1914 */ 
    2015module std.stdio; 
    2116 
    2217public import core.stdc.stdio; 
    23 private import std.stdiobase; 
    24 private import core.memory, core.stdc.errno, core.stdc.stddef
    25     core.stdc.stdlib, core.stdc.string, core.stdc.wchar_; 
    26 private import std.algorithm, std.array, std.contracts, std.conv, std.file, std.format, 
    27     /*std.metastrings,*/ std.range, std.string, std.traits, std.typecons, 
     18import std.stdiobase; 
     19import core.memory, core.stdc.errno, core.stdc.stddef, core.stdc.stdlib
     20    core.stdc.string, core.stdc.wchar_; 
     21import std.algorithm, std.array, std.contracts, std.conv, std.file, std.format, 
     22    std.range, std.string, std.traits, std.typecons, 
    2823    std.typetuple, std.utf; 
    2924 
     
    6560        /* ** 
    6661         * Digital Mars under-the-hood C I/O functions. 
    67      * Use _iobuf* for the unshared version of FILE*, 
    68      * usable when the FILE is locked. 
     62         * Use _iobuf* for the unshared version of FILE*, 
     63         * usable when the FILE is locked. 
    6964         */ 
    7065        int _fputc_nlock(int, _iobuf*); 
     
    136131 
    137132    int fputc_unlocked(int c, _iobuf* fp) { return fputc(c, cast(shared) fp); } 
    138     int fputwc_unlocked(wchar_t c, _iobuf* fp) { return fputwc(c, cast(shared) fp); } 
     133    int fputwc_unlocked(wchar_t c, _iobuf* fp) 
     134    { 
     135        return fputwc(c, cast(shared) fp); 
     136    } 
    139137    int fgetc_unlocked(_iobuf* fp) { return fgetc(cast(shared) fp); } 
    140138    int fgetwc_unlocked(_iobuf* fp) { return fgetwc(cast(shared) fp); } 
     
    156154struct ByRecord(Fields...) 
    157155{ 
     156private: 
    158157    File file; 
    159158    char[] line; 
     
    161160    string format; 
    162161 
     162public: 
    163163    this(File f, string format) 
    164164    { 
     
    170170 
    171171    /// Range primitive implementations. 
    172     bool empty() 
     172    @property bool empty() 
    173173    { 
    174174        return !file.isOpen; 
     
    176176 
    177177    /// Ditto 
    178     ref Tuple!(Fields) front() 
     178    @property ref Tuple!(Fields) front() 
    179179    { 
    180180        return current; 
     
    248248struct File 
    249249{ 
    250     /*private*/ struct Impl 
     250    private struct Impl 
    251251    { 
    252252        FILE * handle = null; 
     
    260260        } 
    261261    } 
    262     /*private*/ Impl * p; 
     262    private Impl * p; 
    263263 
    264264/** 
     
    274274object refers to it anymore. 
    275275 */ 
    276  
    277276    this(string name, in char[] stdioOpenmode = "rb") 
    278277    { 
    279278        p = new Impl(errnoEnforce(.fopen(name, stdioOpenmode), 
    280                         "Cannot open file `"~name 
    281                         ~"' in mode `"~stdioOpenmode.idup~"'"), 
     279                        text("Cannot open file `", name, "' in mode `", 
     280                                stdioOpenmode, "'")), 
    282281                1, name); 
    283282    } 
     
    286285    { 
    287286        if (!p) return; 
    288         // @@@BUG@@@ These lines prematurely close the file 
    289         //printf("Destroying file `%s' with %d refs\n", toStringz(p.name), p.refs); 
    290287        if (p.refs == 1) close; 
    291288        else --p.refs; 
     
    295292    { 
    296293        if (!p) return; 
    297         //printf("Copying file %s with %d refs\n", toStringz(p.name), p.refs); 
    298         enforce(p.refs); 
     294        assert(p.refs); 
    299295        ++p.refs; 
    300296    } 
     
    307303    void opAssign(File rhs) 
    308304    { 
    309         // printf("Assigning file %s with %d refs\n", 
    310         //         toStringz(rhs.p.name), rhs.p.refs); 
    311         // @@@BUG@@@ 
    312305        swap(p, rhs.p); 
    313         // p = rhs.p; 
    314         // rhs.p = null; 
    315306    } 
    316307 
     
    322313Throws exception in case of error. 
    323314 */ 
    324     void open(string name, string stdioOpenmode = "rb") 
     315    void open(string name, in char[] stdioOpenmode = "rb") 
    325316    { 
    326317        detach; 
     
    334325opengroup.org/onlinepubs/007908799/xsh/_popen.html, _popen). 
    335326 */ 
    336     version(Posix) void popen(string command, string stdioOpenmode = "r") 
     327    version(Posix) void popen(string command, in char[] stdioOpenmode = "r") 
    337328    { 
    338329        detach; 
     
    343334 
    344335/** Returns $(D true) if the file is opened. */ 
    345     bool isOpen() const 
     336    @property bool isOpen() const 
    346337    { 
    347338        return p !is null && p.handle; 
     
    353344must be opened, otherwise an exception is thrown. 
    354345 */ 
    355     bool eof() const 
     346    @property bool eof() const 
    356347    { 
    357348        enforce(p && p.handle, "Calling eof() against an unopened file."); 
     
    360351 
    361352/** Returns the name of the file, if any. */ 
    362     string name() const 
     353    @property string name() const 
    363354    { 
    364355        return p.name; 
     
    370361the file handle. 
    371362 */ 
    372     bool error() const 
     363    @property bool error() const 
    373364    { 
    374365        return !p.handle || .ferror(cast(FILE*) p.handle); 
     
    522513        f.close(); 
    523514        assert(std.file.read("deleteme") == "\r\n\n\r\n"); 
    524         /+ 
    525         stdout.rawWrite("\r\n\n\r\n"); 
    526         +/ 
    527515    } 
    528516 
     
    564552    void rewind() 
    565553    { 
    566         enforce(p && p.handle, 
    567                 "Attempting to rewind() an unopened file"); 
     554        enforce(isOpen, "Attempting to rewind() an unopened file"); 
    568555        .rewind(p.handle); 
    569556    } 
     
    576563    void setvbuf(size_t size, int mode = _IOFBF) 
    577564    { 
    578         errnoEnforce( 
    579             .setvbuf(enforce(p.handle, 
    580                             "Attempting to call setvbuf() on an unopened file"), 
    581                     null, mode, size) == 0, 
    582             "Could not set buffering for file `"~p.name~"'"); 
     565        enforce(isOpen, "Attempting to call setvbuf() on an unopened file"); 
     566        errnoEnforce(.setvbuf(p.handle, null, mode, size) == 0, 
     567                "Could not set buffering for file `"~p.name~"'"); 
    583568    } 
    584569 
     
    589574    void setvbuf(void[] buf, int mode = _IOFBF) 
    590575    { 
    591         errnoEnforce( 
    592             .setvbuf(enforce(p.handle, 
    593                             "Attempting to call setvbuf() on an unopened file"), 
    594                     cast(char*) buf.ptr, mode, buf.length) == 0, 
    595             "Could not set buffering for file `"~p.name~"'"); 
     576        enforce(isOpen, "Attempting to call setvbuf() on an unopened file"); 
     577        errnoEnforce(.setvbuf(p.handle, 
     578                        cast(char*) buf.ptr, mode, buf.length) == 0, 
     579                "Could not set buffering for file `"~p.name~"'"); 
    596580    } 
    597581 
     
    601585    void write(S...)(S args) 
    602586    { 
    603         auto w = lockingTextWriter
     587        auto w = lockingTextWriter()
    604588        foreach (arg; args) 
    605589        { 
     
    621605    { 
    622606        write(args, '\n'); 
    623         .fflush(p.handle); 
     607        errnoEnforce(.fflush(p.handle) == 0, 
     608                    "Could not flush file `"~p.name~"'"); 
    624609    } 
    625610 
     
    775760    size_t readf(Data...)(in char[] format, Data data) 
    776761    { 
    777         auto input = InputByChar(this); 
     762        assert(isOpen); 
     763        auto input = LockingTextReader(this); 
    778764        formattedRead(input, format, data); 
    779765        return 1; 
     766    } 
     767 
     768    unittest 
     769    { 
     770        std.file.write("deleteme", "hello\nworld\n"); 
     771        scope(exit) std.file.remove("deleteme"); 
     772        string s; 
     773        auto f = File("deleteme"); 
     774        f.readf("%s\n", &s); 
     775        assert(s == "hello", "["~s~"]"); 
    780776    } 
    781777 
     
    11351131    LockingTextWriter lockingTextWriter() 
    11361132    { 
    1137         // @@@BUG2341@@@ 
    11381133        return LockingTextWriter(this); 
    1139         // The code below avoids bug 2341 
    1140         //printf("Entering fn with %d refs\n", *_refs); 
    1141         // auto result = LockingTextWriter(this); 
    1142         // return result; 
    1143     } 
    1144 
    1145  
    1146     struct InputByChar 
    1147     { 
    1148         private File _f; 
    1149         private dchar _crt; 
    1150  
    1151         this(File f) 
    1152         { 
    1153             _f = f; 
    1154         } 
    1155  
    1156         bool empty() 
    1157         { 
    1158             return _f.eof; 
    1159         } 
    1160  
    1161         dchar front() 
    1162         { 
    1163             assert(!empty); 
    1164             if (_crt == _crt.init) popFront; 
    1165             return _crt; 
    1166         } 
    1167  
    1168         void popFront() 
    1169         { 
    1170             enforce(_f.p && _f.p.handle, 
    1171                     "Attempt to read from an unopened file."); 
    1172             assert(!empty); 
    1173             _crt = getc(cast(FILE*) _f.p.handle); 
    1174         } 
    1175  
    1176         void unget(dchar c) 
    1177         { 
    1178             ungetc(c, cast(FILE*) _f.p.handle); 
    1179         } 
    1180     } 
     1134    } 
     1135
     1136 
     1137struct LockingTextReader 
     1138
     1139    private File _f; 
     1140    private dchar _crt; 
     1141 
     1142    this(File f) 
     1143    { 
     1144        enforce(f.isOpen); 
     1145        _f = f; 
     1146        FLOCK(_f.p.handle); 
     1147    } 
     1148 
     1149    this(this) 
     1150    { 
     1151        FLOCK(_f.p.handle); 
     1152    } 
     1153 
     1154    ~this() 
     1155    { 
     1156        // File locking has its own reference count 
     1157        if (_f.isOpen) FUNLOCK(_f.p.handle); 
     1158    } 
     1159 
     1160    void opAssign(LockingTextReader r) 
     1161    { 
     1162        swap(this, r); 
     1163    } 
     1164 
     1165    @property bool empty() 
     1166    { 
     1167        if (!_f.isOpen || _f.eof) return true; 
     1168        if (_crt == _crt.init) 
     1169        { 
     1170            _crt = FGETC(cast(_iobuf*) _f.p.handle); 
     1171            if (_crt == -1) 
     1172            { 
     1173                clear(_f); 
     1174                return true; 
     1175            } 
     1176            else 
     1177            { 
     1178                enforce(ungetc(_crt, cast(FILE*) _f.p.handle) == _crt); 
     1179            } 
     1180        } 
     1181        return false; 
     1182    } 
     1183 
     1184    dchar front() 
     1185    { 
     1186        enforce(!empty); 
     1187        return _crt; 
     1188    } 
     1189 
     1190    void popFront() 
     1191    { 
     1192        enforce(!empty); 
     1193        if (FGETC(cast(_iobuf*) _f.p.handle) == -1) 
     1194        { 
     1195            enforce(_f.eof); 
     1196        } 
     1197        _crt = _crt.init; 
     1198    } 
     1199 
     1200    // void unget(dchar c) 
     1201    // { 
     1202    //     ungetc(c, cast(FILE*) _f.p.handle); 
     1203    // } 
     1204
    11811205 
    11821206unittest 
    11831207{ 
    1184     // std.file.write("deleteme", "1 2 3"); 
    1185     // int x, y; 
    1186     // auto f = File("deleteme"); 
    1187     // scope(exit) f.close; 
    1188     // //auto input = InputByChar(f); 
    1189     // //std.format.formattedRead(input, "%d ", &x); 
    1190     // f.readf("%d ", &x); 
    1191     // assert(x == 1); 
    1192     // f.readf("%d ", &x); 
    1193     // assert(x == 2); 
    1194     // //f.readf("%d ", &x); 
    1195     // assert(x == 3); 
    1196     pragma(msg, "--- todo: readf ---"); 
     1208    std.file.write("deleteme", "1 2 3"); 
     1209    int x, y; 
     1210    auto f = File("deleteme"); 
     1211    f.readf("%s ", &x); 
     1212    assert(x == 1); 
     1213    f.readf("%d ", &x); 
     1214    assert(x == 2); 
     1215    f.readf("%d ", &x); 
     1216    assert(x == 3); 
     1217    //pragma(msg, "--- todo: readf ---"); 
    11971218} 
    11981219 
     
    14881509} 
    14891510 
     1511/** 
     1512 * Formatted read one line from stdin. 
     1513 */ 
     1514void readf(A...)(in char[] format, A args) 
     1515{ 
     1516    return stdin.readf(format, args); 
     1517} 
     1518 
     1519unittest 
     1520{ 
     1521    float f; 
     1522    if (false) readf("%s", &f); 
     1523} 
     1524 
    14901525/********************************** 
    14911526 * Read line from stream $(D fp). 
     
    20262061        assert(i == 3); 
    20272062    } 
    2028     // { 
    2029     //     std.file.write("deleteme", "1:2 3\n4:1 5\n5:100"); 
    2030     //     File f = File("deleteme"); 
    2031     //     scope(exit) f.close; 
    2032     //     auto t = [ tuple(1, [2,3][]), tuple(4, [1,5][]), tuple(5, [100][]) ]; 
    2033     //     uint i; 
    2034     //     foreach (e; f.byRecord!(int, int[])("%s:%(s )")) 
    2035     //     { 
    2036     //         //writeln(e); 
    2037     //         assert(e == t[i++]); 
    2038     //     } 
    2039     //     assert(i == 3); 
    2040     // } 
    20412063} 
    20422064 
    20432065// Private implementation of readln 
     2066version (DIGITAL_MARS_STDIO) 
    20442067private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator = '\n') 
    20452068{ 
    2046     version (DIGITAL_MARS_STDIO) 
    2047     { 
    2048         FLOCK(fps); 
    2049         scope(exit) FUNLOCK(fps); 
     2069    FLOCK(fps); 
     2070    scope(exit) FUNLOCK(fps); 
    20502071 
    20512072    /* Since fps is now locked, we can create an "unshared" version 
     
    20542075    auto fp = cast(_iobuf*)fps; 
    20552076 
    2056         if (__fhnd_info[fp._file] & FHND_WCHAR) 
    2057         {   /* Stream is in wide characters. 
    2058              * Read them and convert to chars. 
     2077    if (__fhnd_info[fp._file] & FHND_WCHAR) 
     2078    {   /* Stream is in wide characters. 
     2079         * Read them and convert to chars. 
     2080         */ 
     2081        static assert(wchar_t.sizeof == 2); 
     2082        auto app = appender(&buf); 
     2083        buf.length = 0; 
     2084        for (int c = void; (c = FGETWC(fp)) != -1; ) 
     2085        { 
     2086            if ((c & ~0x7F) == 0) 
     2087            {   app.put(cast(char) c); 
     2088                if (c == terminator) 
     2089                    break; 
     2090            } 
     2091            else 
     2092            { 
     2093                if (c >= 0xD800 && c <= 0xDBFF) 
     2094                { 
     2095                    int c2 = void; 
     2096                    if ((c2 = FGETWC(fp)) != -1 || 
     2097                            c2 < 0xDC00 && c2 > 0xDFFF) 
     2098                    { 
     2099                        StdioException("unpaired UTF-16 surrogate"); 
     2100                    } 
     2101                    c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); 
     2102                } 
     2103                std.utf.encode(buf, c); 
     2104            } 
     2105        } 
     2106        if (ferror(fps)) 
     2107            StdioException(); 
     2108        return buf.length; 
     2109    } 
     2110 
     2111    auto sz = GC.sizeOf(buf.ptr); 
     2112    //auto sz = buf.length; 
     2113    buf = buf.ptr[0 .. sz]; 
     2114    if (fp._flag & _IONBF) 
     2115    { 
     2116        /* Use this for unbuffered I/O, when running 
     2117         * across buffer boundaries, or for any but the common 
     2118         * cases. 
     2119         */ 
     2120      L1: 
     2121        if(buf.ptr is null) 
     2122        { 
     2123            sz = 128; 
     2124            auto p = cast(char*) GC.malloc(sz, GC.BlkAttr.NO_SCAN); 
     2125            buf = p[0 .. 0]; 
     2126        } else { 
     2127            buf.length = 0; 
     2128        } 
     2129 
     2130        auto app = appender(&buf); 
     2131        int c; 
     2132        while((c = FGETC(fp)) != -1) { 
     2133            app.put(cast(char) c); 
     2134            if(buf[$ - 1] == terminator) { 
     2135                return buf.length; 
     2136            } 
     2137 
     2138        } 
     2139 
     2140        if (ferror(fps)) 
     2141            StdioException(); 
     2142        return buf.length; 
     2143    } 
     2144    else 
     2145    { 
     2146        int u = fp._cnt; 
     2147        char* p = fp._ptr; 
     2148        int i; 
     2149        if (fp._flag & _IOTRAN) 
     2150        {   /* Translated mode ignores \r and treats ^Z as end-of-file 
    20592151             */ 
    2060             static assert(wchar_t.sizeof == 2); 
    2061             auto app = appender(&buf); 
     2152            char c; 
     2153            while (1) 
     2154            { 
     2155                if (i == u)                // if end of buffer 
     2156                    goto L1;        // give up 
     2157                c = p[i]; 
     2158                i++; 
     2159                if (c != '\r') 
     2160                { 
     2161                    if (c == terminator) 
     2162                        break; 
     2163                    if (c != 0x1A) 
     2164                        continue; 
     2165                    goto L1; 
     2166                } 
     2167                else 
     2168                {   if (i != u && p[i] == terminator) 
     2169                        break; 
     2170                    goto L1; 
     2171                } 
     2172            } 
     2173            if (i > sz) 
     2174            { 
     2175                buf = cast(char[])GC.malloc(i, GC.BlkAttr.NO_SCAN)[0 .. i]; 
     2176            } 
     2177            if (i - 1) 
     2178                memcpy(buf.ptr, p, i - 1); 
     2179            buf[i - 1] = cast(char)terminator; 
     2180            buf = buf[0 .. i]; 
     2181            if (terminator == '\n' && c == '\r') 
     2182                i++; 
     2183        } 
     2184        else 
     2185        { 
     2186            while (1) 
     2187            { 
     2188                if (i == u)                // if end of buffer 
     2189                    goto L1;        // give up 
     2190                auto c = p[i]; 
     2191                i++; 
     2192                if (c == terminator) 
     2193                    break; 
     2194            } 
     2195            if (i > sz) 
     2196            { 
     2197                buf = cast(char[])GC.malloc(i, GC.BlkAttr.NO_SCAN)[0 .. i]; 
     2198            } 
     2199            memcpy(buf.ptr, p, i); 
     2200            buf = buf[0 .. i]; 
     2201        } 
     2202        fp._cnt -= i; 
     2203        fp._ptr += i; 
     2204        return i; 
     2205    } 
     2206
     2207 
     2208version (GCC_IO) 
     2209private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator = '\n') 
     2210
     2211    if (fwide(fps, 0) > 0) 
     2212    {   /* Stream is in wide characters. 
     2213         * Read them and convert to chars. 
     2214         */ 
     2215        FLOCK(fps); 
     2216        scope(exit) FUNLOCK(fps); 
     2217        auto fp = cast(_iobuf*)fps; 
     2218        version (Windows) 
     2219        { 
    20622220            buf.length = 0; 
    2063             int c2; 
    20642221            for (int c = void; (c = FGETWC(fp)) != -1; ) 
    20652222            { 
    20662223                if ((c & ~0x7F) == 0) 
    2067                 {   app.put(cast(char) c)
     2224                {   buf ~= c
    20682225                    if (c == terminator) 
    20692226                        break; 
     
    20732230                    if (c >= 0xD800 && c <= 0xDBFF) 
    20742231                    { 
     2232                        int c2 = void; 
    20752233                        if ((c2 = FGETWC(fp)) != -1 || 
    20762234                                c2 < 0xDC00 && c2 > 0xDFFF) 
     
    20832241                } 
    20842242            } 
     2243            if (ferror(fp)) 
     2244                StdioException(); 
     2245            return buf.length; 
     2246        } 
     2247        else version (Posix) 
     2248        { 
     2249            buf.length = 0; 
     2250            for (int c; (c = FGETWC(fp)) != -1; ) 
     2251            { 
     2252                if ((c & ~0x7F) == 0) 
     2253                    buf ~= cast(char)c; 
     2254                else 
     2255                    std.utf.encode(buf, cast(dchar)c); 
     2256                if (c == terminator) 
     2257                    break; 
     2258            } 
    20852259            if (ferror(fps)) 
    20862260                StdioException(); 
    20872261            return buf.length; 
    20882262        } 
    2089  
    2090         auto sz = GC.sizeOf(buf.ptr); 
    2091         //auto sz = buf.length; 
    2092         buf = buf.ptr[0 .. sz]; 
    2093         if (fp._flag & _IONBF) 
    2094         { 
    2095             /* Use this for unbuffered I/O, when running 
    2096              * across buffer boundaries, or for any but the common 
    2097              * cases. 
    2098              */ 
    2099           L1: 
    2100             if(buf.ptr is null) 
    2101             { 
    2102                 sz = 128; 
    2103                 auto p = cast(char*) GC.malloc(sz, GC.BlkAttr.NO_SCAN); 
    2104                 buf = p[0 .. 0]; 
    2105             } else { 
    2106                 buf.length = 0; 
    2107             } 
    2108  
    2109             auto app = appender(&buf); 
    2110             int c; 
    2111             while((c = FGETC(fp)) != -1) { 
    2112                 app.put(cast(char) c); 
    2113                 if(buf[$ - 1] == terminator) { 
    2114                     return buf.length; 
     2263        else 
     2264        { 
     2265            static assert(0); 
     2266        } 
     2267    } 
     2268 
     2269    char *lineptr = null; 
     2270    size_t n = 0; 
     2271    auto s = getdelim(&lineptr, &n, terminator, fps); 
     2272    scope(exit) free(lineptr); 
     2273    if (s < 0) 
     2274    { 
     2275        if (ferror(fps)) 
     2276            StdioException(); 
     2277        buf.length = 0;                // end of file 
     2278        return 0; 
     2279    } 
     2280    buf = buf.ptr[0 .. GC.sizeOf(buf.ptr)]; 
     2281    if (s <= buf.length) 
     2282    { 
     2283        buf.length = s; 
     2284        buf[] = lineptr[0 .. s]; 
     2285    } 
     2286    else 
     2287    { 
     2288        buf = lineptr[0 .. s].dup; 
     2289    } 
     2290    return s; 
     2291
     2292 
     2293version (GENERIC_IO) 
     2294private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator = '\n') 
     2295
     2296    FLOCK(fps); 
     2297    scope(exit) FUNLOCK(fps); 
     2298    auto fp = cast(_iobuf*)fps; 
     2299    if (fwide(fps, 0) > 0) 
     2300    {   /* Stream is in wide characters. 
     2301         * Read them and convert to chars. 
     2302         */ 
     2303        version (Windows) 
     2304        { 
     2305            buf.length = 0; 
     2306            for (int c; (c = FGETWC(fp)) != -1; ) 
     2307            { 
     2308                if ((c & ~0x7F) == 0) 
     2309                {   buf ~= c; 
     2310                    if (c == terminator) 
     2311                        break; 
    21152312                } 
    2116  
    2117             } 
    2118  
     2313                else 
     2314                { 
     2315                    if (c >= 0xD800 && c <= 0xDBFF) 
     2316                    { 
     2317                        int c2 = void; 
     2318                        if ((c2 = FGETWC(fp)) != -1 || 
     2319                                c2 < 0xDC00 && c2 > 0xDFFF) 
     2320                        { 
     2321                            StdioException("unpaired UTF-16 surrogate"); 
     2322                        } 
     2323                        c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); 
     2324                    } 
     2325                    std.utf.encode(buf, c); 
     2326                } 
     2327            } 
     2328            if (ferror(fp)) 
     2329                StdioException(); 
     2330            return buf.length; 
     2331        } 
     2332        else version (Posix) 
     2333        { 
     2334            buf.length = 0; 
     2335            for (int c; (c = FGETWC(fp)) != -1; ) 
     2336            { 
     2337                if ((c & ~0x7F) == 0) 
     2338                    buf ~= cast(char)c; 
     2339                else 
     2340                    std.utf.encode(buf, cast(dchar)c); 
     2341                if (c == terminator) 
     2342                    break; 
     2343            } 
    21192344            if (ferror(fps)) 
    21202345                StdioException(); 
     
    21232348        else 
    21242349        { 
    2125             int u = fp._cnt; 
    2126             char* p = fp._ptr; 
    2127             int i; 
    2128             if (fp._flag & _IOTRAN) 
    2129             {   /* Translated mode ignores \r and treats ^Z as end-of-file 
    2130                  */ 
    2131                 char c; 
    2132                 while (1) 
    2133                 { 
    2134                     if (i == u)                // if end of buffer 
    2135                         goto L1;        // give up 
    2136                     c = p[i]; 
    2137                     i++; 
    2138                     if (c != '\r') 
    2139                     { 
    2140                         if (c == terminator) 
    2141                             break; 
    2142                         if (c != 0x1A) 
    2143                             continue; 
    2144                         goto L1; 
    2145                     } 
    2146                     else 
    2147                     {   if (i != u && p[i] == terminator) 
    2148                             break; 
    2149                         goto L1; 
    2150                     } 
    2151                 } 
    2152                 if (i > sz) 
    2153                 { 
    2154                     buf = cast(char[])GC.malloc(i, GC.BlkAttr.NO_SCAN)[0 .. i]; 
    2155                 } 
    2156                 if (i - 1) 
    2157                     memcpy(buf.ptr, p, i - 1); 
    2158                 buf[i - 1] = cast(char)terminator; 
    2159                 buf = buf[0 .. i]; 
    2160                 if (terminator == '\n' && c == '\r') 
    2161                     i++; 
    2162             } 
    2163             else 
    2164             { 
    2165                 while (1) 
    2166                 { 
    2167                     if (i == u)                // if end of buffer 
    2168                         goto L1;        // give up 
    2169                     auto c = p[i]; 
    2170                     i++; 
    2171                     if (c == terminator) 
    2172                         break; 
    2173                 } 
    2174                 if (i > sz) 
    2175                 { 
    2176                     buf = cast(char[])GC.malloc(i, GC.BlkAttr.NO_SCAN)[0 .. i]; 
    2177                 } 
    2178                 memcpy(buf.ptr, p, i); 
    2179                 buf = buf[0 .. i]; 
    2180             } 
    2181             fp._cnt -= i; 
    2182             fp._ptr += i; 
    2183             return i; 
    2184         } 
    2185     } 
    2186     else version (GCC_IO) 
    2187     { 
    2188         if (fwide(fps, 0) > 0) 
    2189         {   /* Stream is in wide characters. 
    2190              * Read them and convert to chars. 
    2191              */ 
    2192             FLOCK(fps); 
    2193             scope(exit) FUNLOCK(fps); 
    2194         auto fp = cast(_iobuf*)fps; 
    2195             version (Windows) 
    2196             { 
    2197                 buf.length = 0; 
    2198                 int c2; 
    2199                 for (int c = void; (c = FGETWC(fp)) != -1; ) 
    2200                 { 
    2201                     if ((c & ~0x7F) == 0) 
    2202                     {   buf ~= c; 
    2203                         if (c == terminator) 
    2204                             break; 
    2205                     } 
    2206                     else 
    2207                     { 
    2208                         if (c >= 0xD800 && c <= 0xDBFF) 
    2209                         { 
    2210                             if ((c2 = FGETWC(fp)) != -1 || 
    2211                                     c2 < 0xDC00 && c2 > 0xDFFF) 
    2212                             { 
    2213                                 StdioException("unpaired UTF-16 surrogate"); 
    2214                             } 
    2215                             c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); 
    2216                         } 
    2217                         std.utf.encode(buf, c); 
    2218                     } 
    2219                 } 
    2220                 if (ferror(fp)) 
    2221                     StdioException(); 
    2222                 return buf.length; 
    2223             } 
    2224             else version (Posix) 
    2225             { 
    2226                 buf.length = 0; 
    2227                 for (int c; (c = FGETWC(fp)) != -1; ) 
    2228                 { 
    2229                     if ((c & ~0x7F) == 0) 
    2230                         buf ~= cast(char)c; 
    2231                     else 
    2232                         std.utf.encode(buf, cast(dchar)c); 
    2233                     if (c == terminator) 
    2234                         break; 
    2235                 } 
    2236                 if (ferror(fps)) 
    2237                     StdioException(); 
    2238                 return buf.length; 
    2239             } 
    2240             else 
    2241             { 
    2242                 static assert(0); 
    2243             } 
    2244         } 
    2245  
    2246         char *lineptr = null; 
    2247         size_t n = 0; 
    2248         auto s = getdelim(&lineptr, &n, terminator, fps); 
    2249         scope(exit) free(lineptr); 
    2250         if (s < 0) 
    2251         { 
    2252             if (ferror(fps)) 
    2253                 StdioException(); 
    2254             buf.length = 0;                // end of file 
    2255             return 0; 
    2256         } 
    2257         buf = buf.ptr[0 .. GC.sizeOf(buf.ptr)]; 
    2258         if (s <= buf.length) 
    2259         { 
    2260             buf.length = s; 
    2261             buf[] = lineptr[0 .. s]; 
    2262         } 
    2263         else 
    2264         { 
    2265             buf = lineptr[0 .. s].dup; 
    2266         } 
    2267         return s; 
    2268     } 
    2269     else version (GENERIC_IO) 
    2270     { 
    2271     FLOCK(fps); 
    2272     scope(exit) FUNLOCK(fps); 
    2273     auto fp = cast(_iobuf*)fps; 
    2274         if (fwide(fps, 0) > 0) 
    2275         {   /* Stream is in wide characters. 
    2276              * Read them and convert to chars. 
    2277              */ 
    2278             version (Windows) 
    2279             { 
    2280                 buf.length = 0; 
    2281                 int c2; 
    2282                 for (int c; (c = FGETWC(fp)) != -1; ) 
    2283                 { 
    2284                     if ((c & ~0x7F) == 0) 
    2285                     {   buf ~= c; 
    2286                         if (c == terminator) 
    2287                             break; 
    2288                     } 
    2289                     else 
    2290                     { 
    2291                         if (c >= 0xD800 && c <= 0xDBFF) 
    2292                         { 
    2293                             if ((c2 = FGETWC(fp)) != -1 || 
    2294                                     c2 < 0xDC00 && c2 > 0xDFFF) 
    2295                             { 
    2296                                 StdioException("unpaired UTF-16 surrogate"); 
    2297                             } 
    2298                             c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); 
    2299                         } 
    2300                         std.utf.encode(buf, c); 
    2301                     } 
    2302                 } 
    2303                 if (ferror(fp)) 
    2304                     StdioException(); 
    2305                 return buf.length; 
    2306             } 
    2307             else version (Posix) 
    2308             { 
    2309                 buf.length = 0; 
    2310                 for (int c; (c = FGETWC(fp)) != -1; ) 
    2311                 { 
    2312                     if ((c & ~0x7F) == 0) 
    2313                         buf ~= cast(char)c; 
    2314                     else 
    2315                         std.utf.encode(buf, cast(dchar)c); 
    2316                     if (c == terminator) 
    2317                         break; 
    2318                 } 
    2319                 if (ferror(fps)) 
    2320                     StdioException(); 
    2321                 return buf.length; 
    2322             } 
    2323             else 
    2324             { 
    2325                 static assert(0); 
    2326             } 
    2327         } 
    2328  
    2329         buf.length = 0; 
    2330         for (int c; (c = FGETC(fp)) != -1; ) 
    2331         { 
    2332             buf ~= cast(char)c; 
    2333             if (c == terminator) 
    2334                 break; 
    2335         } 
    2336         if (ferror(fps)) 
    2337             StdioException(); 
    2338         return buf.length; 
    2339     } 
    2340     else 
    2341     { 
    2342         static assert(0); 
    2343     } 
    2344 
     2350            static assert(0); 
     2351        } 
     2352    } 
     2353 
     2354    // Narrow stream 
     2355    buf.length = 0; 
     2356    for (int c; (c = FGETC(fp)) != -1; ) 
     2357    { 
     2358        buf ~= cast(char)c; 
     2359        if (c == terminator) 
     2360            break; 
     2361    } 
     2362    if (ferror(fps)) 
     2363        StdioException(); 
     2364    return buf.length; 
     2365