Mercurial > projects > ldc
annotate lphobos/std/stdio.d @ 1419:a6dfd3cb5b99 0.9.1
Error instead of assert on delegate literals as constant expressions.
Make function literal linkage internal inside functions and external otherwise.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Wed, 27 May 2009 19:20:18 +0200 |
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 |