comparison lphobos/std/cstream.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents
children
comparison
equal deleted inserted replaced
472:15c804b6ce77 473:373489eeaf90
1 /**
2 * The std.cstream module bridges std.c.stdio (or std.stdio) and std.stream.
3 * Both std.c.stdio and std.stream are publicly imported by std.cstream.
4 * Authors: Ben Hinkle
5 * License: Public Domain
6 * Macros:
7 * WIKI=Phobos/StdCstream
8 */
9
10 module std.cstream;
11
12 import std.stream;
13 import std.c.stdio;
14
15 /**
16 * A Stream wrapper for a C file of type FILE*.
17 */
18 class CFile : Stream {
19 FILE* cfile;
20
21 /**
22 * Create the stream wrapper for the given C file.
23 * Params:
24 * mode = a bitwise combination of $(B FileMode.In) for a readable file
25 * and $(B FileMode.Out) for a writeable file.
26 * seekable = indicates if the stream should be _seekable.
27 */
28 this(FILE* cfile, FileMode mode, bool seekable = false) {
29 super();
30 this.file = cfile;
31 readable = cast(bool)(mode & FileMode.In);
32 writeable = cast(bool)(mode & FileMode.Out);
33 this.seekable = seekable;
34 }
35
36 /**
37 * Closes the stream.
38 */
39 ~this() { close(); }
40
41 /**
42 * Property to get or set the underlying file for this stream.
43 * Setting the file marks the stream as open.
44 */
45 FILE* file() { return cfile; }
46
47 /**
48 * Ditto
49 */
50 void file(FILE* cfile) {
51 this.cfile = cfile;
52 isopen = true;
53 }
54
55 /**
56 * Overrides of the $(B Stream) methods to call the underlying $(B FILE*)
57 * C functions.
58 */
59 override void flush() { fflush(cfile); }
60
61 /**
62 * Ditto
63 */
64 override void close() {
65 if (isopen)
66 fclose(cfile);
67 isopen = readable = writeable = seekable = false;
68 }
69
70 /**
71 * Ditto
72 */
73 override bool eof() {
74 return cast(bool)(readEOF || feof(cfile));
75 }
76
77 /**
78 * Ditto
79 */
80 override char getc() {
81 return cast(char)fgetc(cfile);
82 }
83
84 /**
85 * Ditto
86 */
87 override char ungetc(char c) {
88 return cast(char)std.c.stdio.ungetc(c,cfile);
89 }
90
91 /**
92 * Ditto
93 */
94 override size_t readBlock(void* buffer, size_t size) {
95 size_t n = fread(buffer,1,size,cfile);
96 readEOF = cast(bool)(n == 0);
97 return n;
98 }
99
100 /**
101 * Ditto
102 */
103 override size_t writeBlock(void* buffer, size_t size) {
104 return fwrite(buffer,1,size,cfile);
105 }
106
107 /**
108 * Ditto
109 */
110 override ulong seek(long offset, SeekPos rel) {
111 readEOF = false;
112 if (fseek(cfile,cast(int)offset,rel) != 0)
113 throw new SeekException("unable to move file pointer");
114 return ftell(cfile);
115 }
116
117 /**
118 * Ditto
119 */
120 override void writeLine(char[] s) {
121 writeString(s);
122 writeString("\n");
123 }
124
125 /**
126 * Ditto
127 */
128 override void writeLineW(wchar[] s) {
129 writeStringW(s);
130 writeStringW("\n");
131 }
132
133 // run a few tests
134 unittest {
135 FILE* f = fopen("stream.txt","w");
136 assert(f !is null);
137 CFile file = new CFile(f,FileMode.Out);
138 int i = 666;
139 // should be ok to write
140 assert(file.writeable);
141 file.writeLine("Testing stream.d:");
142 file.writeString("Hello, world!");
143 file.write(i);
144 // string#1 + string#2 + int should give exacly that
145 version (Win32)
146 assert(file.position() == 19 + 13 + 4);
147 version (linux)
148 assert(file.position() == 18 + 13 + 4);
149 file.close();
150 // no operations are allowed when file is closed
151 assert(!file.readable && !file.writeable && !file.seekable);
152 f = fopen("stream.txt","r");
153 file = new CFile(f,FileMode.In,true);
154 // should be ok to read
155 assert(file.readable);
156 char[] line = file.readLine();
157 char[] exp = "Testing stream.d:";
158 assert(line[0] == 'T');
159 assert(line.length == exp.length);
160 assert(!std.string.cmp(line, "Testing stream.d:"));
161 // jump over "Hello, "
162 file.seek(7, SeekPos.Current);
163 version (Win32)
164 assert(file.position() == 19 + 7);
165 version (linux)
166 assert(file.position() == 18 + 7);
167 assert(!std.string.cmp(file.readString(6), "world!"));
168 i = 0; file.read(i);
169 assert(i == 666);
170 // string#1 + string#2 + int should give exacly that
171 version (Win32)
172 assert(file.position() == 19 + 13 + 4);
173 version (linux)
174 assert(file.position() == 18 + 13 + 4);
175 // we must be at the end of file
176 file.close();
177 f = fopen("stream.txt","w+");
178 file = new CFile(f,FileMode.In|FileMode.Out,true);
179 file.writeLine("Testing stream.d:");
180 file.writeLine("Another line");
181 file.writeLine("");
182 file.writeLine("That was blank");
183 file.position = 0;
184 char[][] lines;
185 foreach(char[] line; file) {
186 lines ~= line.dup;
187 }
188 assert( lines.length == 5 );
189 assert( lines[0] == "Testing stream.d:");
190 assert( lines[1] == "Another line");
191 assert( lines[2] == "");
192 assert( lines[3] == "That was blank");
193 file.position = 0;
194 lines = new char[][5];
195 foreach(ulong n, char[] line; file) {
196 lines[cast(size_t)(n-1)] = line.dup;
197 }
198 assert( lines[0] == "Testing stream.d:");
199 assert( lines[1] == "Another line");
200 assert( lines[2] == "");
201 assert( lines[3] == "That was blank");
202 file.close();
203 remove("stream.txt");
204 }
205 }
206
207 /**
208 * CFile wrapper of std.c.stdio.stdin (not seekable).
209 */
210 CFile din;
211
212 /**
213 * CFile wrapper of std.c.stdio.stdout (not seekable).
214 */
215 CFile dout;
216
217 /**
218 * CFile wrapper of std.c.stdio.stderr (not seekable).
219 */
220 CFile derr;
221
222 static this() {
223 // open standard I/O devices
224 din = new CFile(std.c.stdio.stdin,FileMode.In);
225 dout = new CFile(std.c.stdio.stdout,FileMode.Out);
226 derr = new CFile(std.c.stdio.stderr,FileMode.Out);
227 }
228