Mercurial > projects > ldc
comparison 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 |
comparison
equal
deleted
inserted
replaced
130:a7dfa0ed966c | 131:5825d48b27d1 |
---|---|
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 | |
1 module std.stdio; | 17 module std.stdio; |
2 | 18 |
3 import std.traits; | 19 public import std.c.stdio; |
4 | 20 |
5 void _writef(T)(T t) { | 21 import std.format; |
6 static if (is(T == char)) { | 22 import std.utf; |
7 printf("%c", t); | 23 import std.string; |
8 } | 24 import std.gc; |
9 else static if (is(T : char[])) { | 25 import std.c.stdlib; |
10 printf("%.*s", t.length, t.ptr); | 26 import std.c.string; |
11 } | 27 import std.c.stddef; |
12 else static if (is(T : long)) { | 28 |
13 printf("%ld", t); | 29 |
14 } | 30 version (DigitalMars) |
15 else static if (is(T : ulong)) { | 31 { |
16 printf("%lu", t); | 32 version (Windows) |
17 } | 33 { |
18 else static if (is(T : real)) { | 34 // Specific to the way Digital Mars C does stdio |
19 printf("%f", t); | 35 version = DIGITAL_MARS_STDIO; |
20 } | 36 } |
21 else static if (is(T : Object)) { | 37 } |
22 _writef(t.toString()); | 38 |
23 } | 39 version (DIGITAL_MARS_STDIO) |
24 else static if(isArray!(T)) { | 40 { |
25 _writef('['); | 41 } |
26 if (t.length) { | 42 else |
27 _writef(t[0]); | 43 { |
28 foreach(v; t[1..$]) { | 44 // Specific to the way Gnu C does stdio |
29 _writef(','); _writef(v); | 45 version = GCC_IO; |
30 } | 46 import std.c.linux.linux; |
31 } | 47 } |
32 _writef(']'); | 48 |
33 } | 49 version (DIGITAL_MARS_STDIO) |
34 else static assert(0, "Cannot writef:"~T.tostring); | 50 { |
35 } | 51 extern (C) |
36 | 52 { |
37 void writef(T...)(T t) | 53 /* ** |
38 { | 54 * Digital Mars under-the-hood C I/O functions |
39 foreach(v;t) _writef(v); | 55 */ |
40 } | 56 int _fputc_nlock(int, FILE*); |
41 void writefln(T...)(T t) | 57 int _fputwc_nlock(int, FILE*); |
42 { | 58 int _fgetc_nlock(FILE*); |
43 writef(t, '\n'); | 59 int _fgetwc_nlock(FILE*); |
44 } | 60 int __fp_lock(FILE*); |
61 void __fp_unlock(FILE*); | |
62 } | |
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*); | |
87 } | |
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); | |
113 } | |
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()); | |
128 } | |
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); | |
164 } | |
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); | |
201 } | |
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; | |
274 } | |
275 | |
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() | |
298 { | |
299 char[] buf; | |
300 while (readln(stdin, buf)) | |
301 writef("%s", buf); | |
302 return 0; | |
303 } | |
304 --- | |
305 */ | |
306 size_t readln(FILE* fp, inout char[] buf) | |
307 { | |
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 } | |
541 } | |
542 | |
543 /** ditto */ | |
544 size_t readln(inout char[] buf) | |
545 { | |
546 return readln(stdin, buf); | |
547 } | |
548 |