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