138032Speter/**
238032Speter * D header file for POSIX.
3261363Sgshapiro *
464562Sgshapiro * Copyright: Copyright Sean Kelly 2005 - 2009.
538032Speter * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
638032Speter * Authors:   Sean Kelly
738032Speter * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
838032Speter */
938032Speter
1038032Speter/*          Copyright Sean Kelly 2005 - 2009.
1138032Speter * Distributed under the Boost Software License, Version 1.0.
1238032Speter *    (See accompanying file LICENSE or copy at
1338032Speter *          http://www.boost.org/LICENSE_1_0.txt)
1438032Speter */
1538032Spetermodule core.sys.posix.stdio;
1664562Sgshapiro
1738032Speterimport core.sys.posix.config;
1890792Sgshapiropublic import core.stdc.stdio;
1938032Speterpublic import core.sys.posix.sys.types; // for off_t
2038032Speter
2138032Speterversion (OSX)
2238032Speter    version = Darwin;
2338032Speterelse version (iOS)
24266692Sgshapiro    version = Darwin;
2538032Speterelse version (TVOS)
2664562Sgshapiro    version = Darwin;
27112810Sgshapiroelse version (WatchOS)
2838032Speter    version = Darwin;
29
30version (Posix):
31extern (C):
32
33nothrow:
34@nogc:
35@system:
36
37//
38// Required (defined in core.stdc.stdio)
39//
40/*
41BUFSIZ
42_IOFBF
43_IOLBF
44_IONBF
45L_tmpnam
46SEEK_CUR
47SEEK_END
48SEEK_SET
49FILENAME_MAX
50FOPEN_MAX
51TMP_MAX
52EOF
53NULL
54stderr
55stdin
56stdout
57FILE
58fpos_t
59size_t
60
61void   clearerr(FILE*);
62int    fclose(FILE*);
63int    feof(FILE*);
64int    ferror(FILE*);
65int    fflush(FILE*);
66int    fgetc(FILE*);
67int    fgetpos(FILE*, fpos_t *);
68char*  fgets(char*, int, FILE*);
69FILE*  fopen(const scope char*, const scope char*);
70int    fprintf(FILE*, const scope char*, ...);
71int    fputc(int, FILE*);
72int    fputs(const scope char*, FILE*);
73size_t fread(void *, size_t, size_t, FILE*);
74FILE*  freopen(const scope char*, const scope char*, FILE*);
75int    fscanf(FILE*, const scope char*, ...);
76int    fseek(FILE*, c_long, int);
77int    fsetpos(FILE*, const scope fpos_t*);
78c_long ftell(FILE*);
79size_t fwrite(in void *, size_t, size_t, FILE*);
80int    getc(FILE*);
81int    getchar();
82char*  gets(char*);
83void   perror(const scope char*);
84int    printf(const scope char*, ...);
85int    putc(int, FILE*);
86int    putchar(int);
87int    puts(const scope char*);
88int    remove(const scope char*);
89int    rename(const scope char*, const scope char*);
90void   rewind(FILE*);
91int    scanf(const scope char*, ...);
92void   setbuf(FILE*, char*);
93int    setvbuf(FILE*, char*, int, size_t);
94int    snprintf(char*, size_t, const scope char*, ...);
95int    sprintf(char*, const scope char*, ...);
96int    sscanf(const scope char*, const scope char*, int ...);
97FILE*  tmpfile();
98char*  tmpnam(char*);
99int    ungetc(int, FILE*);
100int    vfprintf(FILE*, const scope char*, va_list);
101int    vfscanf(FILE*, const scope char*, va_list);
102int    vprintf(const scope char*, va_list);
103int    vscanf(const scope char*, va_list);
104int    vsnprintf(char*, size_t, const scope char*, va_list);
105int    vsprintf(char*, const scope char*, va_list);
106int    vsscanf(const scope char*, const scope char*, va_list arg);
107*/
108
109version (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}
145else 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}
153else 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}
184else 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}
215else 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/*
251L_ctermid
252
253char*   ctermid(char*);
254FILE*   fdopen(int, const scope char*);
255int     fileno(FILE*);
256int     fseeko(FILE*, off_t, int);
257off_t   ftello(FILE*);
258ssize_t getdelim(char**, size_t*, int, FILE*);
259ssize_t getline(char**, size_t*, FILE*);
260char*   gets(char*);
261int     pclose(FILE*);
262FILE*   popen(const scope char*, const scope char*);
263*/
264
265version (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}
292else 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}
320else 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}
347else 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}
374else 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}
384else 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}
399else 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}
409else 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}
419else 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}
429else 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}
457else version (Posix)
458{
459    int   fseeko(FILE*, off_t, int);
460    off_t ftello(FILE*);
461}
462
463char*  ctermid(char*);
464FILE*  fdopen(int, const scope char*);
465int    fileno(FILE*);
466char*  gets(char*);
467int    pclose(FILE*);
468FILE*  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.
474version (CRuntime_Glibc)                     // as of glibc 1.0x
475    version = HaveMemstream;
476else version (FreeBSD)                      // as of FreeBSD 9.2
477    version = HaveMemstream;
478else version (DragonFlyBSD)                 // for DragonFlyBSD
479    version = HaveMemstream;
480else version (OpenBSD)                      // as of OpenBSD 5.4
481    version = HaveMemstream;
482else version (CRuntime_UClibc)
483    version = HaveMemstream;
484// http://git.musl-libc.org/cgit/musl/commit/src/stdio/open_memstream.c?id=b158b32a44d56ef20407d4285b58180447ffff1f
485else version (CRuntime_Musl)
486    version = HaveMemstream;
487
488version (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/*
500void   flockfile(FILE*);
501int    ftrylockfile(FILE*);
502void   funlockfile(FILE*);
503int    getc_unlocked(FILE*);
504int    getchar_unlocked();
505int    putc_unlocked(int, FILE*);
506int    putchar_unlocked(int);
507*/
508
509version (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}
519else 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}
529else 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}
539else 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}
549else 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}
559else 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}
569else 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}
579else 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}
589else 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}
599else 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/*
614P_tmpdir
615va_list (defined in core.stdc.stdarg)
616
617char*  tempnam(const scope char*, const scope char*);
618*/
619
620char*  tempnam(const scope char*, const scope char*);
621
622version (CRuntime_Glibc)
623{
624    enum P_tmpdir  = "/tmp";
625}
626else version (CRuntime_Musl)
627{
628    enum P_tmpdir  = "/tmp";
629}
630else version (Darwin)
631{
632    enum P_tmpdir  = "/var/tmp";
633}
634else version (FreeBSD)
635{
636    enum P_tmpdir  = "/var/tmp/";
637}
638else version (NetBSD)
639{
640    enum P_tmpdir  = "/var/tmp/";
641}
642else version (OpenBSD)
643{
644    enum P_tmpdir  = "/tmp/";
645}
646else version (DragonFlyBSD)
647{
648    enum P_tmpdir  = "/var/tmp/";
649}
650else version (Solaris)
651{
652    enum P_tmpdir  = "/var/tmp/";
653}
654else version (CRuntime_UClibc)
655{
656    enum P_tmpdir  = "/tmp";
657}
658
659version (HaveMemstream)
660unittest
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
673version (HaveMemstream)
674unittest
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
688version (CRuntime_UClibc) {} else
689version (HaveMemstream)
690unittest
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