Showing with 152 additions and 0 deletions.
  1. +1 −0 mak/MANIFEST
  2. +1 −0 mak/SRCS
  3. +105 −0 src/core/sys/linux/stdio.d
  4. +45 −0 src/core/sys/posix/stdio.d
1 change: 1 addition & 0 deletions mak/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ MANIFEST=\
src\core\sys\linux\errno.d \
src\core\sys\linux\execinfo.d \
src\core\sys\linux\link.d \
src\core\sys\linux\stdio.d \
src\core\sys\linux\termios.d \
src\core\sys\linux\time.d \
src\core\sys\linux\tipc.d \
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ SRCS=\
src\core\sys\freebsd\execinfo.d \
src\core\sys\freebsd\sys\event.d \
\
src\core\sys\linux\stdio.d \
src\core\sys\linux\tipc.d \
\
src\core\sys\posix\signal.d \
Expand Down
105 changes: 105 additions & 0 deletions src/core/sys/linux/stdio.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* D header file for GNU stdio.
*
* Copyright: Danny Milosavljevic 2014
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
* Authors: Danny Milosavljevic
*/
module core.sys.linux.stdio;
version (linux):
public import core.sys.posix.stdio;
import core.sys.posix.sys.types : ssize_t, off64_t = off_t;
import core.sys.linux.config : __USE_FILE_OFFSET64;
import core.stdc.stdio : FILE;
import core.stdc.stddef : wchar_t, size_t;

extern(C) nothrow
{
alias ssize_t function(void *cookie, char *buf, size_t size) cookie_read_function_t;
alias ssize_t function(void *cookie, const(char) *buf, size_t size) cookie_write_function_t;
alias int function(void *cookie, off64_t *offset, int whence) cookie_seek_function_t;
alias int function(void *cookie) cookie_close_function_t;

struct cookie_io_functions_t
{
cookie_read_function_t read;
cookie_write_function_t write;
cookie_seek_function_t seek;
cookie_close_function_t close;
}
FILE* fopencookie(in void* cookie, in char* mode, cookie_io_functions_t io_funcs);
void setbuffer(FILE *stream, char *buf, size_t size); // note: _BSD_SOURCE
}

unittest
{
static int flag = 0;
static int written = 0;
static int closed = 0;
// Note: this test needs to run on both a 32 and a 64 bit machine, both have to pass.
import core.stdc.errno : errno, EBADF;
//import core.sys.posix.sys.stat : off64_t;
import core.stdc.stdio : FILE, fflush, fileno, fprintf, fgetc, EOF, fclose;
import core.stdc.string : memcpy, memset;
extern (C) ssize_t specialRead(void *cookie, char *buf, size_t size) nothrow
{
memset(buf, 'a', size);
return size;
}
extern (C) int specialClose(void* cookie) nothrow
{
++closed;
return 0;
}
extern (C) ssize_t specialWrite(void *cookie, const(char) *buf, size_t size) nothrow
{
int* c = cast(int*) cookie;
flag = *c;
written += size;
return size;
}
int dummy = 42;
cookie_io_functions_t fns =
{
read: &specialRead,
write: &specialWrite,
close: &specialClose,
};
FILE* f = fopencookie(&dummy, "r+", fns);
assert(f !is null);
//File.open();
//auto g = File(f);
assert(fileno(f) == -1 && errno == EBADF);
assert(fprintf(f, "hello") == "hello".length);
//assert(errno == EBADF);
assert(fflush(f) == 0);
assert(written == "hello".length);
// Note: do not swap reading and writing here.
int c = 0;
while((c = fgetc(f)) != EOF)
{
assert(c == 'a');
break; // endless otherwise
}
assert(c == 'a');
assert(fclose(f) == 0);
assert(closed == 1);
assert(flag == dummy);
//stdin.getFP();
//assert(stdin.fileno() == 0);
}

unittest
{ /* setbuffer */
char buf;
int c;
byte[10] dummy = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
FILE* f = fmemopen(dummy.ptr, 10, "r");
assert(f !is null);
setbuffer(f, &buf, 1);
assert(fgetc(f) == 1);
assert(fgetc(f) == 2);
assert(fgetc(f) == 3);
assert(fgetc(f) == 4);
assert(fclose(f) == 0);
}
45 changes: 45 additions & 0 deletions src/core/sys/posix/stdio.d
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ int fileno(FILE*);
char* gets(char*);
int pclose(FILE*);
FILE* popen(in char*, in char*);
FILE* fmemopen(in void* buf, in size_t size, in char* mode);
FILE* open_memstream(char** ptr, size_t* sizeloc);
FILE* open_wmemstream(wchar_t** ptr, size_t* sizeloc);

//
// Thread-Safe Functions (TSF)
Expand Down Expand Up @@ -258,3 +261,45 @@ version( Solaris )
{
enum P_tmpdir = "/var/tmp/";
}

unittest
{ /* fmemopen */
import core.stdc.string : memcmp;
byte[10] buf;
auto f = fmemopen(buf.ptr, 10, "w");
assert(f !is null);
assert(fprintf(f, "hello") == "hello".length);
assert(fflush(f) == 0);
assert(memcmp(buf.ptr, "hello".ptr, "hello".length) == 0);
//assert(buf
assert(fclose(f) == 0);
}

unittest
{ /* Note: open_memstream is only useful for writing */
import core.stdc.string : memcmp;
char* ptr = null;
char[] testdata = ['h', 'e', 'l', 'l', 'o', 0];
size_t sz = 0;
auto f = open_memstream(&ptr, &sz);
assert(f !is null);
assert(fprintf(f, "%s", testdata.ptr) == 5);
assert(fflush(f) == 0);
assert(memcmp(ptr, testdata.ptr, testdata.length) == 0);
assert(fclose(f) == 0);
}

unittest
{ /* Note: open_wmemstream is only useful for writing */
import core.stdc.string : memcmp;
import core.stdc.wchar_ : fwprintf;
wchar_t* ptr = null;
wchar_t[] testdata = ['h', 'e', 'l', 'l', 'o', 0];
size_t sz = 0;
auto f = open_wmemstream(&ptr, &sz);
assert(f !is null);
assert(fwprintf(f, testdata.ptr) == 5);
assert(fflush(f) == 0);
assert(memcmp(ptr, testdata.ptr, testdata.length*wchar_t.sizeof) == 0);
assert(fclose(f) == 0);
}