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