[m-rev.] for review: binary standard input/output streams on Windows
Peter Wang
novalazy at gmail.com
Fri Apr 20 11:33:48 AEST 2012
Branches: main, 11.07
The binary input and output streams were not necessarily put into binary
translation mode when using MinGW, and probably MSVC.
library/io.m:
Fix the problem by using _setmode() to change the translation
mode after the file is opened.
tests/hard_coded/Mmakefile:
tests/hard_coded/binary_stdin.exp:
tests/hard_coded/binary_stdin.inp:
tests/hard_coded/binary_stdin.m:
tests/hard_coded/binary_stdout.exp:
tests/hard_coded/binary_stdout.m:
Add test cases.
diff --git a/library/io.m b/library/io.m
index 9a13c75..5d12eb3 100644
--- a/library/io.m
+++ b/library/io.m
@@ -6300,6 +6300,22 @@ MR_Unsigned mercury_current_text_output_index;
MR_Unsigned mercury_current_binary_input_index;
MR_Unsigned mercury_current_binary_output_index;
+static void
+mercury_set_binary_mode(FILE *f)
+{
+#if defined(MR_MSVC) || defined(MR_MINGW)
+ /*
+ ** Calling fdopen with 'b' in the mode string does not necessarily put the
+ ** file into binary translation mode on Windows. This is the case with
+ ** MinGW and, reportedly, MSVC. The cause is likely the MSVC CRT.
+ ** The solution is to change the mode on the file after opening.
+ */
+ _setmode(_fileno(f), _O_BINARY);
+#else
+ (void)f;
+#endif
+}
+
void
mercury_init_io(void)
{
@@ -6318,7 +6334,9 @@ mercury_init_io(void)
#if defined(MR_HAVE_FDOPEN) && (defined(MR_HAVE_FILENO) || defined(fileno)) && \
defined(MR_HAVE_DUP)
MR_file(mercury_stdin_binary) = fdopen(dup(fileno(stdin)), ""rb"");
- if (MR_file(mercury_stdin_binary) == NULL) {
+ if (MR_file(mercury_stdin_binary) != NULL) {
+ mercury_set_binary_mode(MR_file(mercury_stdin_binary));
+ } else {
/*
** The call to fdopen() may fail if stdin is not available.
** We don't abort since we still want Mercury programs to be runnable
@@ -6335,7 +6353,9 @@ mercury_init_io(void)
}
MR_file(mercury_stdout_binary) = fdopen(dup(fileno(stdout)), ""wb"");
- if (MR_file(mercury_stdout_binary) == NULL) {
+ if (MR_file(mercury_stdout_binary) != NULL) {
+ mercury_set_binary_mode(MR_file(mercury_stdout_binary));
+ } else {
MR_file(mercury_stdout_binary) = stdout;
}
#else
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 01e08f1..46c610a 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -14,6 +14,8 @@ ORDINARY_PROGS= \
backquoted_qualified_ops \
bag_various \
bidirectional \
+ binary_stdin \
+ binary_stdout \
boyer \
brace \
bug103 \
diff --git a/tests/hard_coded/binary_stdin.exp b/tests/hard_coded/binary_stdin.exp
new file mode 100644
index 0000000..70ff8e5
--- /dev/null
+++ b/tests/hard_coded/binary_stdin.exp
@@ -0,0 +1 @@
+done.
diff --git a/tests/hard_coded/binary_stdin.inp b/tests/hard_coded/binary_stdin.inp
new file mode 100644
index 0000000..553a99f
Binary files /dev/null and b/tests/hard_coded/binary_stdin.inp differ
diff --git a/tests/hard_coded/binary_stdin.m b/tests/hard_coded/binary_stdin.m
new file mode 100644
index 0000000..de5fac8
--- /dev/null
+++ b/tests/hard_coded/binary_stdin.m
@@ -0,0 +1,98 @@
+%-----------------------------------------------------------------------------%
+
+:- module binary_stdin.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module int.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+ int.fold_up(read_byte_test, 0, 255, !IO),
+ io.stdin_binary_stream(Stream, !IO),
+ int.fold_up(read_byte_test(Stream), 0, 255, !IO),
+ expect_eof(Stream, !IO),
+ io.write_string("done.\n", !IO).
+
+:- pred read_byte_test(int::in, io::di, io::uo) is det.
+
+read_byte_test(ExpectedByte, !IO) :-
+ io.read_byte(Res, !IO),
+ (
+ Res = ok(ReadByte),
+ ( ExpectedByte = ReadByte ->
+ true
+ ;
+ Stderr = io.stderr_stream,
+ io.write_string(Stderr, "expected ", !IO),
+ io.write_int(Stderr, ExpectedByte, !IO),
+ io.write_string(Stderr, ", got ", !IO),
+ io.write_int(Stderr, ReadByte, !IO),
+ io.nl(Stderr, !IO),
+ io.set_exit_status(1, !IO)
+ )
+ ;
+ Res = eof,
+ io.write_string(io.stderr_stream, "unexpected eof\n", !IO),
+ io.set_exit_status(1, !IO)
+ ;
+ Res = error(Error),
+ io.write_string(io.stderr_stream, io.error_message(Error), !IO),
+ io.set_exit_status(1, !IO)
+ ).
+
+:- pred read_byte_test(io.binary_input_stream::in, int::in, io::di, io::uo)
+ is det.
+
+read_byte_test(Stream, ExpectedByte, !IO) :-
+ io.read_byte(Stream, Res, !IO),
+ (
+ Res = ok(ReadByte),
+ ( ExpectedByte = ReadByte ->
+ true
+ ;
+ Stderr = io.stderr_stream,
+ io.write_string(Stderr, "expected ", !IO),
+ io.write_int(Stderr, ExpectedByte, !IO),
+ io.write_string(Stderr, ", got ", !IO),
+ io.write_int(Stderr, ReadByte, !IO),
+ io.nl(Stderr, !IO),
+ io.set_exit_status(1, !IO)
+ )
+ ;
+ Res = eof,
+ io.write_string(io.stderr_stream, "unexpected eof\n", !IO),
+ io.set_exit_status(1, !IO)
+ ;
+ Res = error(Error),
+ io.write_string(io.stderr_stream, io.error_message(Error), !IO),
+ io.set_exit_status(1, !IO)
+ ).
+
+:- pred expect_eof(io.binary_input_stream::in, io::di, io::uo) is det.
+
+expect_eof(Stream, !IO) :-
+ io.read_byte(Stream, Res, !IO),
+ (
+ Res = ok(_),
+ io.write_string("expected eof\n", !IO),
+ io.set_exit_status(1, !IO)
+ ;
+ Res = eof
+ ;
+ Res = error(Error),
+ io.write_string(io.stderr_stream, io.error_message(Error), !IO),
+ io.set_exit_status(1, !IO)
+ ).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sts=4 sw=4 et
diff --git a/tests/hard_coded/binary_stdout.exp b/tests/hard_coded/binary_stdout.exp
new file mode 100644
index 0000000..553a99f
Binary files /dev/null and b/tests/hard_coded/binary_stdout.exp differ
diff --git a/tests/hard_coded/binary_stdout.m b/tests/hard_coded/binary_stdout.m
new file mode 100644
index 0000000..8b2bd12
--- /dev/null
+++ b/tests/hard_coded/binary_stdout.m
@@ -0,0 +1,25 @@
+%-----------------------------------------------------------------------------%
+
+:- module binary_stdout.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module int.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+ int.fold_up(io.write_byte, 0, 255, !IO),
+ io.stdout_binary_stream(Stream, !IO),
+ int.fold_up(io.write_byte(Stream), 0, 255, !IO).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sts=4 sw=4 et
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list