1 /**
2  * D header file for POSIX.
3  *
4  * Copyright: Copyright Sean Kelly 2005 - 2009.
5  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Sean Kelly
7  * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
8  */
9 
10 /*          Copyright Sean Kelly 2005 - 2009.
11  * Distributed under the Boost Software License, Version 1.0.
12  *    (See accompanying file LICENSE or copy at
13  *          http://www.boost.org/LICENSE_1_0.txt)
14  */
15 module core.sys.posix.stdio;
16 
17 import core.sys.posix.config;
18 public import core.stdc.stdio;
19 public import core.sys.posix.sys.types; // for off_t
20 
21 version (OSX)
22     version = Darwin;
23 else version (iOS)
24     version = Darwin;
25 else version (TVOS)
26     version = Darwin;
27 else version (WatchOS)
28     version = Darwin;
29 
30 version (Posix):
31 extern (C):
32 
33 nothrow:
34 @nogc:
35 
36 //
37 // Required (defined in core.stdc.stdio)
38 //
39 /*
40 BUFSIZ
41 _IOFBF
42 _IOLBF
43 _IONBF
44 L_tmpnam
45 SEEK_CUR
46 SEEK_END
47 SEEK_SET
48 FILENAME_MAX
49 FOPEN_MAX
50 TMP_MAX
51 EOF
52 NULL
53 stderr
54 stdin
55 stdout
56 FILE
57 fpos_t
58 size_t
59 
60 void   clearerr(FILE*);
61 int    fclose(FILE*);
62 int    feof(FILE*);
63 int    ferror(FILE*);
64 int    fflush(FILE*);
65 int    fgetc(FILE*);
66 int    fgetpos(FILE*, fpos_t *);
67 char*  fgets(char*, int, FILE*);
68 FILE*  fopen(const scope char*, const scope char*);
69 int    fprintf(FILE*, const scope char*, ...);
70 int    fputc(int, FILE*);
71 int    fputs(const scope char*, FILE*);
72 size_t fread(void *, size_t, size_t, FILE*);
73 FILE*  freopen(const scope char*, const scope char*, FILE*);
74 int    fscanf(FILE*, const scope char*, ...);
75 int    fseek(FILE*, c_long, int);
76 int    fsetpos(FILE*, const scope fpos_t*);
77 c_long ftell(FILE*);
78 size_t fwrite(in void *, size_t, size_t, FILE*);
79 int    getc(FILE*);
80 int    getchar();
81 char*  gets(char*);
82 void   perror(const scope char*);
83 int    printf(const scope char*, ...);
84 int    putc(int, FILE*);
85 int    putchar(int);
86 int    puts(const scope char*);
87 int    remove(const scope char*);
88 int    rename(const scope char*, const scope char*);
89 void   rewind(FILE*);
90 int    scanf(const scope char*, ...);
91 void   setbuf(FILE*, char*);
92 int    setvbuf(FILE*, char*, int, size_t);
93 int    snprintf(char*, size_t, const scope char*, ...);
94 int    sprintf(char*, const scope char*, ...);
95 int    sscanf(const scope char*, const scope char*, int ...);
96 FILE*  tmpfile();
97 char*  tmpnam(char*);
98 int    ungetc(int, FILE*);
99 int    vfprintf(FILE*, const scope char*, va_list);
100 int    vfscanf(FILE*, const scope char*, va_list);
101 int    vprintf(const scope char*, va_list);
102 int    vscanf(const scope char*, va_list);
103 int    vsnprintf(char*, size_t, const scope char*, va_list);
104 int    vsprintf(char*, const scope char*, va_list);
105 int    vsscanf(const scope char*, const scope char*, va_list arg);
106 */
107 
108 version (CRuntime_Glibc)
109 {
110     /*
111      * actually, if __USE_FILE_OFFSET64 && !_LARGEFILE64_SOURCE
112      * the *64 functions shouldn't be visible, but the aliases should
113      * still be supported
114      */
115     static if ( __USE_FILE_OFFSET64 )
116     {
117         int   fgetpos64(FILE*, fpos_t *);
118         alias fgetpos64 fgetpos;
119 
120         FILE* fopen64(const scope char*, const scope char*);
121         alias fopen64 fopen;
122 
123         FILE* freopen64(const scope char*, const scope char*, FILE*);
124         alias freopen64 freopen;
125 
126         int   fseek(FILE*, c_long, int);
127 
128         int   fsetpos64(FILE*, const scope fpos_t*);
129         alias fsetpos64 fsetpos;
130 
131         FILE* tmpfile64();
132         alias tmpfile64 tmpfile;
133     }
134     else
135     {
136         int   fgetpos(FILE*, fpos_t *);
137         FILE* fopen(const scope char*, const scope char*);
138         FILE* freopen(const scope char*, const scope char*, FILE*);
139         int   fseek(FILE*, c_long, int);
140         int   fsetpos(FILE*, const scope fpos_t*);
141         FILE* tmpfile();
142     }
143 }
144 else version (CRuntime_Bionic)
145 {
146     int   fgetpos(FILE*, fpos_t *);
147     FILE* fopen(const scope char*, const scope char*);
148     FILE* freopen(const scope char*, const scope char*, FILE*);
149     int   fseek(FILE*, c_long, int);
150     int   fsetpos(FILE*, const scope fpos_t*);
151 }
152 else version (CRuntime_UClibc)
153 {
154     static if ( __USE_FILE_OFFSET64 )
155     {
156         int   fgetpos64(FILE*, fpos_t *);
157         alias fgetpos64 fgetpos;
158 
159         FILE* fopen64(const scope char*, const scope char*);
160         alias fopen64 fopen;
161 
162         FILE* freopen64(const scope char*, const scope char*, FILE*);
163         alias freopen64 freopen;
164 
165         int   fseek(FILE*, c_long, int);
166 
167         int   fsetpos64(FILE*, const scope fpos_t*);
168         alias fsetpos64 fsetpos;
169 
170         FILE* tmpfile64();
171         alias tmpfile64 tmpfile;
172     }
173     else
174     {
175         int   fgetpos(FILE*, fpos_t *);
176         FILE* fopen(const scope char*, const scope char*);
177         FILE* freopen(const scope char*, const scope char*, FILE*);
178         int   fseek(FILE*, c_long, int);
179         int   fsetpos(FILE*, const scope fpos_t*);
180         FILE* tmpfile();
181     }
182 }
183 else version (CRuntime_Musl)
184 {
185     static if ( __USE_FILE_OFFSET64 )
186     {
187         int   fgetpos64(FILE*, fpos_t *);
188         alias fgetpos64 fgetpos;
189 
190         FILE* fopen64(const scope char*, const scope char*);
191         alias fopen64 fopen;
192 
193         FILE* freopen64(const scope char*, const scope char*, FILE*);
194         alias freopen64 freopen;
195 
196         int   fseek(FILE*, c_long, int);
197 
198         int   fsetpos64(FILE*, const scope fpos_t*);
199         alias fsetpos64 fsetpos;
200 
201         FILE* tmpfile64();
202         alias tmpfile64 tmpfile;
203     }
204     else
205     {
206         int   fgetpos(FILE*, fpos_t *);
207         FILE* fopen(const scope char*, const scope char*);
208         FILE* freopen(const scope char*, const scope char*, FILE*);
209         int   fseek(FILE*, c_long, int);
210         int   fsetpos(FILE*, const scope fpos_t*);
211         FILE* tmpfile();
212     }
213 }
214 else version (Solaris)
215 {
216     static if (__USE_FILE_OFFSET64 && __WORDSIZE != 64)
217     {
218         int   fgetpos64(FILE*, fpos_t *);
219         alias fgetpos = fgetpos64;
220 
221         FILE* fopen64(const scope char*, const scope char*);
222         alias fopen = fopen64;
223 
224         FILE* freopen64(const scope char*, const scope char*, FILE*);
225         alias freopen = freopen64;
226 
227         int   fseek(FILE*, c_long, int);
228 
229         int   fsetpos64(FILE*, const scope fpos_t*);
230         alias fsetpos = fsetpos64;
231 
232         FILE* tmpfile64();
233         alias tmpfile = tmpfile64;
234     }
235     else
236     {
237         int   fgetpos(FILE*, fpos_t *);
238         FILE* fopen(const scope char*, const scope char*);
239         FILE* freopen(const scope char*, const scope char*, FILE*);
240         int   fseek(FILE*, c_long, int);
241         int   fsetpos(FILE*, const scope fpos_t*);
242         FILE* tmpfile();
243     }
244 }
245 
246 //
247 // C Extension (CX)
248 //
249 /*
250 L_ctermid
251 
252 char*   ctermid(char*);
253 FILE*   fdopen(int, const scope char*);
254 int     fileno(FILE*);
255 int     fseeko(FILE*, off_t, int);
256 off_t   ftello(FILE*);
257 ssize_t getdelim(char**, size_t*, int, FILE*);
258 ssize_t getline(char**, size_t*, FILE*);
259 char*   gets(char*);
260 int     pclose(FILE*);
261 FILE*   popen(const scope char*, const scope char*);
262 */
263 
264 version (CRuntime_Glibc)
265 {
266     enum L_ctermid = 9;
267 
268     static if ( __USE_FILE_OFFSET64 )
269     {
270         int   fseeko64(FILE*, off_t, int);
271         alias fseeko64 fseeko;
272     }
273     else
274     {
275         int   fseeko(FILE*, off_t, int);
276     }
277 
278     static if ( __USE_FILE_OFFSET64 )
279     {
280         off_t ftello64(FILE*);
281         alias ftello64 ftello;
282     }
283     else
284     {
285         off_t ftello(FILE*);
286     }
287 
288     ssize_t getdelim(char**, size_t*, int, FILE*);
289     ssize_t getline(char**, size_t*, FILE*);
290 }
291 else version (CRuntime_UClibc)
292 {
293     enum L_ctermid = 9;
294     enum L_cuserid = 9;
295 
296     static if ( __USE_FILE_OFFSET64 )
297     {
298         int   fseeko64(FILE*, off_t, int);
299         alias fseeko64 fseeko;
300     }
301     else
302     {
303         int   fseeko(FILE*, off_t, int);
304     }
305 
306     static if ( __USE_FILE_OFFSET64 )
307     {
308         off_t ftello64(FILE*);
309         alias ftello64 ftello;
310     }
311     else
312     {
313         off_t ftello(FILE*);
314     }
315 
316     ssize_t getdelim(char**, size_t*, int, FILE*);
317     ssize_t getline(char**, size_t*, FILE*);
318 }
319 else version (CRuntime_Musl)
320 {
321     enum L_ctermid = 20;
322 
323     static if ( __USE_FILE_OFFSET64 )
324     {
325         int   fseeko64(FILE*, off_t, int);
326         alias fseeko64 fseeko;
327     }
328     else
329     {
330         int   fseeko(FILE*, off_t, int);
331     }
332 
333     static if ( __USE_FILE_OFFSET64 )
334     {
335         off_t ftello64(FILE*);
336         alias ftello64 ftello;
337     }
338     else
339     {
340         off_t ftello(FILE*);
341     }
342 
343     ssize_t getdelim(char**, size_t*, int, FILE*);
344     ssize_t getline(char**, size_t*, FILE*);
345 }
346 else version (CRuntime_Bionic)
347 {
348     enum L_ctermid = 1024;
349 
350     static if ( __USE_FILE_OFFSET64 )
351     {
352         int   fseeko64(FILE*, off_t, int);
353         alias fseeko64 fseeko;
354     }
355     else
356     {
357         int   fseeko(FILE*, off_t, int);
358     }
359 
360     static if ( __USE_FILE_OFFSET64 )
361     {
362         off_t ftello64(FILE*);
363         alias ftello64 ftello;
364     }
365     else
366     {
367         off_t ftello(FILE*);
368     }
369 
370     ssize_t getdelim(char**, size_t*, int, FILE*);
371     ssize_t getline(char**, size_t*, FILE*);
372 }
373 else version (Darwin)
374 {
375     enum L_ctermid = 1024;
376 
377     int   fseeko(FILE*, off_t, int);
378     off_t ftello(FILE*);
379 
380     ssize_t getdelim(char**, size_t*, int, FILE*);
381     ssize_t getline(char**, size_t*, FILE*);
382 }
383 else version (FreeBSD)
384 {
385     import core.sys.freebsd.config;
386 
387     enum L_ctermid = 1024;
388 
389     int   fseeko(FILE*, off_t, int);
390     off_t ftello(FILE*);
391 
392     static if (__FreeBSD_version >= 800000)
393     {
394         ssize_t getdelim(char**, size_t*, int, FILE*);
395         ssize_t getline(char**, size_t*, FILE*);
396     }
397 }
398 else version (NetBSD)
399 {
400     enum L_ctermid = 1024;
401 
402     int   fseeko(FILE*, off_t, int);
403     off_t ftello(FILE*);
404 
405     ssize_t getdelim(char**, size_t*, int, FILE*);
406     ssize_t getline(char**, size_t*, FILE*);
407 }
408 else version (OpenBSD)
409 {
410     enum L_ctermid = 1024;
411 
412     int   fseeko(FILE*, off_t, int);
413     off_t ftello(FILE*);
414 
415     ssize_t getdelim(char**, size_t*, int, FILE*);
416     ssize_t getline(char**, size_t*, FILE*);
417 }
418 else version (DragonFlyBSD)
419 {
420     enum L_ctermid = 1024;
421 
422     int   fseeko(FILE*, off_t, int);
423     off_t ftello(FILE*);
424 
425     ssize_t getdelim(char**, size_t*, int, FILE*);
426     ssize_t getline(char**, size_t*, FILE*);
427 }
428 else version (Solaris)
429 {
430     enum L_ctermid = 9;
431     enum L_cuserid = 9;
432 
433     static if (__USE_FILE_OFFSET64 && __WORDSIZE != 64)
434     {
435         int   fseeko64(FILE*, off_t, int);
436         alias fseeko = fseeko64;
437     }
438     else
439     {
440         int   fseeko(FILE*, off_t, int);
441     }
442 
443     static if (__USE_FILE_OFFSET64 && __WORDSIZE != 64)
444     {
445         off_t ftello64(FILE*);
446         alias ftello = ftello64;
447     }
448     else
449     {
450         off_t ftello(FILE*);
451     }
452 
453     ssize_t getdelim(char**, size_t*, int, FILE*);
454     ssize_t getline(char**, size_t*, FILE*);
455 }
456 else version (Posix)
457 {
458     int   fseeko(FILE*, off_t, int);
459     off_t ftello(FILE*);
460 }
461 
462 char*  ctermid(char*);
463 FILE*  fdopen(int, const scope char*);
464 int    fileno(FILE*);
465 char*  gets(char*);
466 int    pclose(FILE*);
467 FILE*  popen(const scope char*, const scope char*);
468 
469 
470 // memstream functions are conforming to POSIX.1-2008.  These functions are
471 // not specified in POSIX.1-2001 and are not widely available on other
472 // systems.
473 version (CRuntime_Glibc)                     // as of glibc 1.0x
474     version = HaveMemstream;
475 else version (FreeBSD)                      // as of FreeBSD 9.2
476     version = HaveMemstream;
477 else version (DragonFlyBSD)                 // for DragonFlyBSD
478     version = HaveMemstream;
479 else version (OpenBSD)                      // as of OpenBSD 5.4
480     version = HaveMemstream;
481 else version (CRuntime_UClibc)
482     version = HaveMemstream;
483 // http://git.musl-libc.org/cgit/musl/commit/src/stdio/open_memstream.c?id=b158b32a44d56ef20407d4285b58180447ffff1f
484 else version (CRuntime_Musl)
485     version = HaveMemstream;
486 
487 version (HaveMemstream)
488 {
489     FILE*  fmemopen(const scope void* buf, size_t size, const scope char* mode);
490     FILE*  open_memstream(char** ptr, size_t* sizeloc);
491     version (CRuntime_UClibc) {} else
492     FILE*  open_wmemstream(wchar_t** ptr, size_t* sizeloc);
493 }
494 
495 //
496 // Thread-Safe Functions (TSF)
497 //
498 /*
499 void   flockfile(FILE*);
500 int    ftrylockfile(FILE*);
501 void   funlockfile(FILE*);
502 int    getc_unlocked(FILE*);
503 int    getchar_unlocked();
504 int    putc_unlocked(int, FILE*);
505 int    putchar_unlocked(int);
506 */
507 
508 version (CRuntime_Glibc)
509 {
510     void   flockfile(FILE*);
511     int    ftrylockfile(FILE*);
512     void   funlockfile(FILE*);
513     int    getc_unlocked(FILE*);
514     int    getchar_unlocked();
515     int    putc_unlocked(int, FILE*);
516     int    putchar_unlocked(int);
517 }
518 else version (CRuntime_Musl)
519 {
520     void   flockfile(FILE*);
521     int    ftrylockfile(FILE*);
522     void   funlockfile(FILE*);
523     int    getc_unlocked(FILE*);
524     int    getchar_unlocked();
525     int    putc_unlocked(int, FILE*);
526     int    putchar_unlocked(int);
527 }
528 else version (CRuntime_Bionic)
529 {
530     void   flockfile(FILE*);
531     int    ftrylockfile(FILE*);
532     void   funlockfile(FILE*);
533     int    getc_unlocked(FILE*);
534     int    getchar_unlocked();
535     int    putc_unlocked(int, FILE*);
536     int    putchar_unlocked(int);
537 }
538 else version (Darwin)
539 {
540     void   flockfile(FILE*);
541     int    ftrylockfile(FILE*);
542     void   funlockfile(FILE*);
543     int    getc_unlocked(FILE*);
544     int    getchar_unlocked();
545     int    putc_unlocked(int, FILE*);
546     int    putchar_unlocked(int);
547 }
548 else version (FreeBSD)
549 {
550     void   flockfile(FILE*);
551     int    ftrylockfile(FILE*);
552     void   funlockfile(FILE*);
553     int    getc_unlocked(FILE*);
554     int    getchar_unlocked();
555     int    putc_unlocked(int, FILE*);
556     int    putchar_unlocked(int);
557 }
558 else version (NetBSD)
559 {
560     void   flockfile(FILE*);
561     int    ftrylockfile(FILE*);
562     void   funlockfile(FILE*);
563     int    getc_unlocked(FILE*);
564     int    getchar_unlocked();
565     int    putc_unlocked(int, FILE*);
566     int    putchar_unlocked(int);
567 }
568 else version (OpenBSD)
569 {
570     void   flockfile(FILE*);
571     int    ftrylockfile(FILE*);
572     void   funlockfile(FILE*);
573     int    getc_unlocked(FILE*);
574     int    getchar_unlocked();
575     int    putc_unlocked(int, FILE*);
576     int    putchar_unlocked(int);
577 }
578 else version (DragonFlyBSD)
579 {
580     void   flockfile(FILE*);
581     int    ftrylockfile(FILE*);
582     void   funlockfile(FILE*);
583     int    getc_unlocked(FILE*);
584     int    getchar_unlocked();
585     int    putc_unlocked(int, FILE*);
586     int    putchar_unlocked(int);
587 }
588 else version (Solaris)
589 {
590     void   flockfile(FILE*);
591     int    ftrylockfile(FILE*);
592     void   funlockfile(FILE*);
593     int    getc_unlocked(FILE*);
594     int    getchar_unlocked();
595     int    putc_unlocked(int, FILE*);
596     int    putchar_unlocked(int);
597 }
598 else version (CRuntime_UClibc)
599 {
600     void   flockfile(FILE*);
601     int    ftrylockfile(FILE*);
602     void   funlockfile(FILE*);
603     int    getc_unlocked(FILE*);
604     int    getchar_unlocked();
605     int    putc_unlocked(int, FILE*);
606     int    putchar_unlocked(int);
607 }
608 
609 //
610 // XOpen (XSI)
611 //
612 /*
613 P_tmpdir
614 va_list (defined in core.stdc.stdarg)
615 
616 char*  tempnam(const scope char*, const scope char*);
617 */
618 
619 char*  tempnam(const scope char*, const scope char*);
620 
621 version (CRuntime_Glibc)
622 {
623     enum P_tmpdir  = "/tmp";
624 }
625 else version (CRuntime_Musl)
626 {
627     enum P_tmpdir  = "/tmp";
628 }
629 else version (Darwin)
630 {
631     enum P_tmpdir  = "/var/tmp";
632 }
633 else version (FreeBSD)
634 {
635     enum P_tmpdir  = "/var/tmp/";
636 }
637 else version (NetBSD)
638 {
639     enum P_tmpdir  = "/var/tmp/";
640 }
641 else version (OpenBSD)
642 {
643     enum P_tmpdir  = "/tmp/";
644 }
645 else version (DragonFlyBSD)
646 {
647     enum P_tmpdir  = "/var/tmp/";
648 }
649 else version (Solaris)
650 {
651     enum P_tmpdir  = "/var/tmp/";
652 }
653 else version (CRuntime_UClibc)
654 {
655     enum P_tmpdir  = "/tmp";
656 }
657 
658 version (HaveMemstream)
659 unittest
660 { /* fmemopen */
661     import core.stdc.string : memcmp;
662     byte[10] buf;
663     auto f = fmemopen(buf.ptr, 10, "w");
664     assert(f !is null);
665     assert(fprintf(f, "hello") == "hello".length);
666     assert(fflush(f) == 0);
667     assert(memcmp(buf.ptr, "hello".ptr, "hello".length) == 0);
668     //assert(buf
669     assert(fclose(f) == 0);
670 }
671 
672 version (HaveMemstream)
673 unittest
674 { /* Note: open_memstream is only useful for writing */
675     import core.stdc.string : memcmp;
676     char* ptr = null;
677     char[6] testdata = ['h', 'e', 'l', 'l', 'o', 0];
678     size_t sz = 0;
679     auto f = open_memstream(&ptr, &sz);
680     assert(f !is null);
681     assert(fprintf(f, "%s", testdata.ptr) == 5);
682     assert(fflush(f) == 0);
683     assert(memcmp(ptr, testdata.ptr, testdata.length) == 0);
684     assert(fclose(f) == 0);
685 }
686 
687 version (CRuntime_UClibc) {} else
688 version (HaveMemstream)
689 unittest
690 { /* Note: open_wmemstream is only useful for writing */
691     import core.stdc.string : memcmp;
692     import core.stdc.wchar_ : fwprintf;
693     wchar_t* ptr = null;
694     wchar_t[6] testdata = ['h', 'e', 'l', 'l', 'o', 0];
695     size_t sz = 0;
696     auto f = open_wmemstream(&ptr, &sz);
697     assert(f !is null);
698     assert(fwprintf(f, testdata.ptr) == 5);
699     assert(fflush(f) == 0);
700     assert(memcmp(ptr, testdata.ptr, testdata.length*wchar_t.sizeof) == 0);
701     assert(fclose(f) == 0);
702 }