Mercurial > projects > ldc
annotate lphobos/std/stdio.d @ 837:331a176c1f4f
Removed error on naked, not fully complete, but I'll be doing more work on it during this Christmas, and some things do work.
Fixed taking delegate of final class method. see mini/delegate3.d.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 09 Dec 2008 14:07:30 +0100 |
parents | 5825d48b27d1 |
children |
rev | line source |
---|---|
131 | 1 |
2 // Written in the D programming language. | |
3 | |
4 /* Written by Walter Bright and Andrei Alexandrescu | |
5 * www.digitalmars.com | |
6 * Placed in the Public Domain. | |
7 */ | |
8 | |
9 /******************************** | |
10 * Standard I/O functions that extend $(B std.c.stdio). | |
11 * $(B std.c.stdio) is automatically imported when importing | |
12 * $(B std.stdio). | |
13 * Macros: | |
14 * WIKI=Phobos/StdStdio | |
15 */ | |
16 | |
18 | 17 module std.stdio; |
18 | |
131 | 19 public import std.c.stdio; |
20 | |
21 import std.format; | |
22 import std.utf; | |
23 import std.string; | |
24 import std.gc; | |
25 import std.c.stdlib; | |
26 import std.c.string; | |
27 import std.c.stddef; | |
28 | |
29 | |
30 version (DigitalMars) | |
31 { | |
32 version (Windows) | |
33 { | |
34 // Specific to the way Digital Mars C does stdio | |
35 version = DIGITAL_MARS_STDIO; | |
36 } | |
37 } | |
22
a6360e68134a
[svn r26] * Fixed templates defining a constant value
lindquist
parents:
21
diff
changeset
|
38 |
131 | 39 version (DIGITAL_MARS_STDIO) |
40 { | |
41 } | |
42 else | |
43 { | |
44 // Specific to the way Gnu C does stdio | |
45 version = GCC_IO; | |
46 import std.c.linux.linux; | |
47 } | |
48 | |
49 version (DIGITAL_MARS_STDIO) | |
50 { | |
51 extern (C) | |
52 { | |
53 /* ** | |
54 * Digital Mars under-the-hood C I/O functions | |
55 */ | |
56 int _fputc_nlock(int, FILE*); | |
57 int _fputwc_nlock(int, FILE*); | |
58 int _fgetc_nlock(FILE*); | |
59 int _fgetwc_nlock(FILE*); | |
60 int __fp_lock(FILE*); | |
61 void __fp_unlock(FILE*); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
62 } |
131 | 63 alias _fputc_nlock FPUTC; |
64 alias _fputwc_nlock FPUTWC; | |
65 alias _fgetc_nlock FGETC; | |
66 alias _fgetwc_nlock FGETWC; | |
67 | |
68 alias __fp_lock FLOCK; | |
69 alias __fp_unlock FUNLOCK; | |
70 } | |
71 else version (GCC_IO) | |
72 { | |
73 /* ** | |
74 * Gnu under-the-hood C I/O functions; see | |
75 * http://www.gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html#I_002fO-on-Streams | |
76 */ | |
77 extern (C) | |
78 { | |
79 int fputc_unlocked(int, FILE*); | |
80 int fputwc_unlocked(wchar_t, FILE*); | |
81 int fgetc_unlocked(FILE*); | |
82 int fgetwc_unlocked(FILE*); | |
83 void flockfile(FILE*); | |
84 void funlockfile(FILE*); | |
85 ssize_t getline(char**, size_t*, FILE*); | |
86 ssize_t getdelim (char**, size_t*, int, FILE*); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
87 } |
131 | 88 |
89 alias fputc_unlocked FPUTC; | |
90 alias fputwc_unlocked FPUTWC; | |
91 alias fgetc_unlocked FGETC; | |
92 alias fgetwc_unlocked FGETWC; | |
93 | |
94 alias flockfile FLOCK; | |
95 alias funlockfile FUNLOCK; | |
96 } | |
97 else | |
98 { | |
99 static assert(0, "unsupported C I/O system"); | |
100 } | |
101 | |
102 | |
103 /********************* | |
104 * Thrown if I/O errors happen. | |
105 */ | |
106 class StdioException : Exception | |
107 { | |
108 uint errno; // operating system error code | |
109 | |
110 this(char[] msg) | |
111 { | |
112 super(msg); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
113 } |
131 | 114 |
115 this(uint errno) | |
116 { char* s = strerror(errno); | |
117 super(std.string.toString(s).dup); | |
118 } | |
119 | |
120 static void opCall(char[] msg) | |
121 { | |
122 throw new StdioException(msg); | |
123 } | |
124 | |
125 static void opCall() | |
126 { | |
127 throw new StdioException(getErrno()); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
128 } |
131 | 129 } |
130 | |
131 private | |
132 void writefx(FILE* fp, TypeInfo[] arguments, void* argptr, int newline=false) | |
133 { int orientation; | |
134 | |
135 orientation = fwide(fp, 0); | |
136 | |
137 /* Do the file stream locking at the outermost level | |
138 * rather than character by character. | |
139 */ | |
140 FLOCK(fp); | |
141 scope(exit) FUNLOCK(fp); | |
142 | |
143 if (orientation <= 0) // byte orientation or no orientation | |
144 { | |
145 void putc(dchar c) | |
146 { | |
147 if (c <= 0x7F) | |
148 { | |
149 FPUTC(c, fp); | |
150 } | |
151 else | |
152 { char[4] buf; | |
153 char[] b; | |
154 | |
155 b = std.utf.toUTF8(buf, c); | |
156 for (size_t i = 0; i < b.length; i++) | |
157 FPUTC(b[i], fp); | |
158 } | |
159 } | |
160 | |
161 std.format.doFormat(&putc, arguments, argptr); | |
162 if (newline) | |
163 FPUTC('\n', fp); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
164 } |
131 | 165 else if (orientation > 0) // wide orientation |
166 { | |
167 version (Windows) | |
168 { | |
169 void putcw(dchar c) | |
170 { | |
171 assert(isValidDchar(c)); | |
172 if (c <= 0xFFFF) | |
173 { | |
174 FPUTWC(c, fp); | |
175 } | |
176 else | |
177 { wchar[2] buf; | |
178 | |
179 buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); | |
180 buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); | |
181 FPUTWC(buf[0], fp); | |
182 FPUTWC(buf[1], fp); | |
183 } | |
184 } | |
185 } | |
186 else version (linux) | |
187 { | |
188 void putcw(dchar c) | |
189 { | |
190 FPUTWC(c, fp); | |
191 } | |
192 } | |
193 else | |
194 { | |
195 static assert(0); | |
196 } | |
197 | |
198 std.format.doFormat(&putcw, arguments, argptr); | |
199 if (newline) | |
200 FPUTWC('\n', fp); | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
201 } |
131 | 202 } |
203 | |
204 | |
205 /*********************************** | |
206 * Arguments are formatted per the | |
207 * $(LINK2 std_format.html#format-string, format strings) | |
208 * and written to $(B stdout). | |
209 */ | |
210 | |
211 void writef(...) | |
212 { | |
213 writefx(stdout, _arguments, _argptr, 0); | |
214 } | |
215 | |
216 /*********************************** | |
217 * Same as $(B writef), but a newline is appended | |
218 * to the output. | |
219 */ | |
220 | |
221 void writefln(...) | |
222 { | |
223 writefx(stdout, _arguments, _argptr, 1); | |
224 } | |
225 | |
226 /*********************************** | |
227 * Same as $(B writef), but output is sent to the | |
228 * stream fp instead of $(B stdout). | |
229 */ | |
230 | |
231 void fwritef(FILE* fp, ...) | |
232 { | |
233 writefx(fp, _arguments, _argptr, 0); | |
234 } | |
235 | |
236 /*********************************** | |
237 * Same as $(B writefln), but output is sent to the | |
238 * stream fp instead of $(B stdout). | |
239 */ | |
240 | |
241 void fwritefln(FILE* fp, ...) | |
242 { | |
243 writefx(fp, _arguments, _argptr, 1); | |
244 } | |
245 | |
246 /********************************** | |
247 * Read line from stream fp. | |
248 * Returns: | |
249 * null for end of file, | |
250 * char[] for line read from fp, including terminating '\n' | |
251 * Params: | |
252 * fp = input stream | |
253 * Throws: | |
254 * $(B StdioException) on error | |
255 * Example: | |
256 * Reads $(B stdin) and writes it to $(B stdout). | |
257 --- | |
258 import std.stdio; | |
259 | |
260 int main() | |
261 { | |
262 char[] buf; | |
263 while ((buf = readln()) != null) | |
264 writef("%s", buf); | |
265 return 0; | |
266 } | |
267 --- | |
268 */ | |
269 char[] readln(FILE* fp = stdin) | |
270 { | |
271 char[] buf; | |
272 readln(fp, buf); | |
273 return buf; | |
18 | 274 } |
275 | |
131 | 276 /********************************** |
277 * Read line from stream fp and write it to buf[], | |
278 * including terminating '\n'. | |
279 * | |
280 * This is often faster than readln(FILE*) because the buffer | |
281 * is reused each call. Note that reusing the buffer means that | |
282 * the previous contents of it need to be copied if needed. | |
283 * Params: | |
284 * fp = input stream | |
285 * buf = buffer used to store the resulting line data. buf | |
286 * is resized as necessary. | |
287 * Returns: | |
288 * 0 for end of file, otherwise | |
289 * number of characters read | |
290 * Throws: | |
291 * $(B StdioException) on error | |
292 * Example: | |
293 * Reads $(B stdin) and writes it to $(B stdout). | |
294 --- | |
295 import std.stdio; | |
296 | |
297 int main() | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
298 { |
131 | 299 char[] buf; |
300 while (readln(stdin, buf)) | |
301 writef("%s", buf); | |
302 return 0; | |
18 | 303 } |
131 | 304 --- |
305 */ | |
306 size_t readln(FILE* fp, inout char[] buf) | |
94
61615fa85940
[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca").
lindquist
parents:
58
diff
changeset
|
307 { |
131 | 308 version (DIGITAL_MARS_STDIO) |
309 { | |
310 FLOCK(fp); | |
311 scope(exit) FUNLOCK(fp); | |
312 | |
313 if (__fhnd_info[fp._file] & FHND_WCHAR) | |
314 { /* Stream is in wide characters. | |
315 * Read them and convert to chars. | |
316 */ | |
317 static assert(wchar_t.sizeof == 2); | |
318 buf.length = 0; | |
319 int c2; | |
320 for (int c; (c = FGETWC(fp)) != -1; ) | |
321 { | |
322 if ((c & ~0x7F) == 0) | |
323 { buf ~= c; | |
324 if (c == '\n') | |
325 break; | |
326 } | |
327 else | |
328 { | |
329 if (c >= 0xD800 && c <= 0xDBFF) | |
330 { | |
331 if ((c2 = FGETWC(fp)) != -1 || | |
332 c2 < 0xDC00 && c2 > 0xDFFF) | |
333 { | |
334 StdioException("unpaired UTF-16 surrogate"); | |
335 } | |
336 c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); | |
337 } | |
338 std.utf.encode(buf, c); | |
339 } | |
340 } | |
341 if (ferror(fp)) | |
342 StdioException(); | |
343 return buf.length; | |
344 } | |
345 | |
346 auto sz = std.gc.capacity(buf.ptr); | |
347 //auto sz = buf.length; | |
348 buf = buf.ptr[0 .. sz]; | |
349 if (fp._flag & _IONBF) | |
350 { | |
351 /* Use this for unbuffered I/O, when running | |
352 * across buffer boundaries, or for any but the common | |
353 * cases. | |
354 */ | |
355 L1: | |
356 char *p; | |
357 | |
358 if (sz) | |
359 { | |
360 p = buf.ptr; | |
361 } | |
362 else | |
363 { | |
364 sz = 64; | |
365 p = cast(char*) std.gc.malloc(sz); | |
366 std.gc.hasNoPointers(p); | |
367 buf = p[0 .. sz]; | |
368 } | |
369 size_t i = 0; | |
370 for (int c; (c = FGETC(fp)) != -1; ) | |
371 { | |
372 if ((p[i] = c) != '\n') | |
373 { | |
374 i++; | |
375 if (i < sz) | |
376 continue; | |
377 buf = p[0 .. i] ~ readln(fp); | |
378 return buf.length; | |
379 } | |
380 else | |
381 { | |
382 buf = p[0 .. i + 1]; | |
383 return i + 1; | |
384 } | |
385 } | |
386 if (ferror(fp)) | |
387 StdioException(); | |
388 buf = p[0 .. i]; | |
389 return i; | |
390 } | |
391 else | |
392 { | |
393 int u = fp._cnt; | |
394 char* p = fp._ptr; | |
395 int i; | |
396 if (fp._flag & _IOTRAN) | |
397 { /* Translated mode ignores \r and treats ^Z as end-of-file | |
398 */ | |
399 char c; | |
400 while (1) | |
401 { | |
402 if (i == u) // if end of buffer | |
403 goto L1; // give up | |
404 c = p[i]; | |
405 i++; | |
406 if (c != '\r') | |
407 { | |
408 if (c == '\n') | |
409 break; | |
410 if (c != 0x1A) | |
411 continue; | |
412 goto L1; | |
413 } | |
414 else | |
415 { if (i != u && p[i] == '\n') | |
416 break; | |
417 goto L1; | |
418 } | |
419 } | |
420 if (i > sz) | |
421 { | |
422 buf = cast(char[])std.gc.malloc(i); | |
423 std.gc.hasNoPointers(buf.ptr); | |
424 } | |
425 if (i - 1) | |
426 memcpy(buf.ptr, p, i - 1); | |
427 buf[i - 1] = '\n'; | |
428 if (c == '\r') | |
429 i++; | |
430 } | |
431 else | |
432 { | |
433 while (1) | |
434 { | |
435 if (i == u) // if end of buffer | |
436 goto L1; // give up | |
437 auto c = p[i]; | |
438 i++; | |
439 if (c == '\n') | |
440 break; | |
441 } | |
442 if (i > sz) | |
443 { | |
444 buf = cast(char[])std.gc.malloc(i); | |
445 std.gc.hasNoPointers(buf.ptr); | |
446 } | |
447 memcpy(buf.ptr, p, i); | |
448 } | |
449 fp._cnt -= i; | |
450 fp._ptr += i; | |
451 buf = buf[0 .. i]; | |
452 return i; | |
453 } | |
454 } | |
455 else version (GCC_IO) | |
456 { | |
457 if (fwide(fp, 0) > 0) | |
458 { /* Stream is in wide characters. | |
459 * Read them and convert to chars. | |
460 */ | |
461 FLOCK(fp); | |
462 scope(exit) FUNLOCK(fp); | |
463 version (Windows) | |
464 { | |
465 buf.length = 0; | |
466 int c2; | |
467 for (int c; (c = FGETWC(fp)) != -1; ) | |
468 { | |
469 if ((c & ~0x7F) == 0) | |
470 { buf ~= c; | |
471 if (c == '\n') | |
472 break; | |
473 } | |
474 else | |
475 { | |
476 if (c >= 0xD800 && c <= 0xDBFF) | |
477 { | |
478 if ((c2 = FGETWC(fp)) != -1 || | |
479 c2 < 0xDC00 && c2 > 0xDFFF) | |
480 { | |
481 StdioException("unpaired UTF-16 surrogate"); | |
482 } | |
483 c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00); | |
484 } | |
485 std.utf.encode(buf, c); | |
486 } | |
487 } | |
488 if (ferror(fp)) | |
489 StdioException(); | |
490 return buf.length; | |
491 } | |
492 else version (linux) | |
493 { | |
494 buf.length = 0; | |
495 for (int c; (c = FGETWC(fp)) != -1; ) | |
496 { | |
497 if ((c & ~0x7F) == 0) | |
498 buf ~= c; | |
499 else | |
500 std.utf.encode(buf, cast(dchar)c); | |
501 if (c == '\n') | |
502 break; | |
503 } | |
504 if (ferror(fp)) | |
505 StdioException(); | |
506 return buf.length; | |
507 } | |
508 else | |
509 { | |
510 static assert(0); | |
511 } | |
512 } | |
513 | |
514 char *lineptr = null; | |
515 size_t n = 0; | |
516 auto s = getdelim(&lineptr, &n, '\n', fp); | |
517 scope(exit) free(lineptr); | |
518 if (s < 0) | |
519 { | |
520 if (ferror(fp)) | |
521 StdioException(); | |
522 buf.length = 0; // end of file | |
523 return 0; | |
524 } | |
525 buf = buf.ptr[0 .. std.gc.capacity(buf.ptr)]; | |
526 if (s <= buf.length) | |
527 { | |
528 buf.length = s; | |
529 buf[] = lineptr[0 .. s]; | |
530 } | |
531 else | |
532 { | |
533 buf = lineptr[0 .. s].dup; | |
534 } | |
535 return s; | |
536 } | |
537 else | |
538 { | |
539 static assert(0); | |
540 } | |
18 | 541 } |
131 | 542 |
543 /** ditto */ | |
544 size_t readln(inout char[] buf) | |
545 { | |
546 return readln(stdin, buf); | |
547 } | |
548 |