C99 allows to pass NULL path into freopen() function which just changes the
mode of FILE*. Both msvcrt and UCRT returns error when NULL path is passed.
The primary use case of this C99 feature is to change stdin / stdout mode
from text to binary and so allow processing of binary data on stdin or
stdout.
Implement support for NULL path by renaming existing freopen symbol to
_freopen and then providing mingw-w64 wrapper function freopen() which will
either call renamed _freopen() or just changes the mode on existing FILE*
stream.
Because FILE struct has different offsets to members between msvcrt and
UCRT builds, it is needed to have separate compilation unit for msvcrt and
UCRT builds.
---
mingw-w64-crt/Makefile.am | 2 +
mingw-w64-crt/def-include/crt-aliases.def.in | 2 +-
.../api-ms-win-crt-stdio-l1-1-0.def | 4 +-
mingw-w64-crt/lib-common/msvcr120_app.def.in | 2 +-
mingw-w64-crt/lib-common/msvcrt.def.in | 2 +-
.../lib-common/ucrtbase-common.def.in | 2 +-
mingw-w64-crt/lib32/crtdll.def.in | 2 +-
mingw-w64-crt/lib32/msvcr100.def.in | 2 +-
mingw-w64-crt/lib32/msvcr100d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr110.def.in | 2 +-
mingw-w64-crt/lib32/msvcr110d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr120.def.in | 2 +-
mingw-w64-crt/lib32/msvcr120d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr40d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr70.def.in | 2 +-
mingw-w64-crt/lib32/msvcr70d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr71.def.in | 2 +-
mingw-w64-crt/lib32/msvcr71d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr80.def.in | 2 +-
mingw-w64-crt/lib32/msvcr80d.def.in | 2 +-
mingw-w64-crt/lib32/msvcr90.def.in | 2 +-
mingw-w64-crt/lib32/msvcr90d.def.in | 2 +-
mingw-w64-crt/lib32/msvcrt10.def.in | 2 +-
mingw-w64-crt/lib32/msvcrt20.def.in | 2 +-
mingw-w64-crt/lib32/msvcrt40.def.in | 2 +-
mingw-w64-crt/lib32/msvcrtd.def.in | 2 +-
mingw-w64-crt/lib64/msvcr100.def.in | 2 +-
mingw-w64-crt/lib64/msvcr100d.def.in | 2 +-
mingw-w64-crt/lib64/msvcr110.def.in | 2 +-
mingw-w64-crt/lib64/msvcr110d.def.in | 2 +-
mingw-w64-crt/lib64/msvcr120.def.in | 2 +-
mingw-w64-crt/lib64/msvcr120d.def.in | 2 +-
mingw-w64-crt/lib64/msvcr80.def.in | 2 +-
mingw-w64-crt/lib64/msvcr80d.def.in | 2 +-
mingw-w64-crt/lib64/msvcr90.def.in | 2 +-
mingw-w64-crt/lib64/msvcr90d.def.in | 2 +-
mingw-w64-crt/libarm32/msvcr110.def.in | 2 +-
mingw-w64-crt/libarm32/msvcr110d.def.in | 2 +-
mingw-w64-crt/libarm32/msvcr120.def.in | 2 +-
mingw-w64-crt/libarm32/msvcr120d.def.in | 2 +-
mingw-w64-crt/stdio/freopen.c | 315 ++++++++++++++++++
mingw-w64-crt/stdio/ucrt_freopen.c | 3 +
mingw-w64-crt/testcases/Makefile.am | 1 +
mingw-w64-crt/testcases/t_freopen.c | 9 +
44 files changed, 370 insertions(+), 40 deletions(-)
create mode 100644 mingw-w64-crt/stdio/freopen.c
create mode 100644 mingw-w64-crt/stdio/ucrt_freopen.c
create mode 100644 mingw-w64-crt/testcases/t_freopen.c
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index afb8aa10ed73..1ca8520ea119 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -185,6 +185,7 @@ src_msvcrt_common=\
stdio/_strtof_l.c \
stdio/_wcstof_l.c \
stdio/acrt_iob_func.c \
+ stdio/freopen.c \
stdio/strtof.c \
stdio/snprintf_alias.c \
stdio/snwprintf_alias.c \
@@ -443,6 +444,7 @@ src_ucrtbase=\
stdio/ucrt__vsnwprintf.c \
stdio/ucrt__vswprintf.c \
stdio/ucrt_fprintf.c \
+ stdio/ucrt_freopen.c \
stdio/ucrt_fscanf.c \
stdio/ucrt_fwprintf.c \
stdio/ucrt_fwscanf.c \
diff --git a/mingw-w64-crt/def-include/crt-aliases.def.in
b/mingw-w64-crt/def-include/crt-aliases.def.in
index 65675ecbc1c9..d952c96f0248 100644
--- a/mingw-w64-crt/def-include/crt-aliases.def.in
+++ b/mingw-w64-crt/def-include/crt-aliases.def.in
@@ -301,7 +301,7 @@ ftello == ftell
creat64 == _creat
open64 == _open
fopen64 == fopen
-freopen64 == freopen
+; freopen64 function is provided by stdio/freopen.c
tmpfile64 == tmpfile
#ifndef NO_FPOS64_ALIASES
; fgetpos and fsetpos are already 64-bit
diff --git a/mingw-w64-crt/lib-common/api-ms-win-crt-stdio-l1-1-0.def
b/mingw-w64-crt/lib-common/api-ms-win-crt-stdio-l1-1-0.def
index 2f31884e8009..d4858eb55d55 100644
--- a/mingw-w64-crt/lib-common/api-ms-win-crt-stdio-l1-1-0.def
+++ b/mingw-w64-crt/lib-common/api-ms-win-crt-stdio-l1-1-0.def
@@ -173,8 +173,8 @@ fputwc
fputws
fread
fread_s
-freopen
-freopen64 == freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
+; freopen64 function is provided by stdio/freopen.c
freopen_s
fseek
fseeko == fseek
diff --git a/mingw-w64-crt/lib-common/msvcr120_app.def.in
b/mingw-w64-crt/lib-common/msvcr120_app.def.in
index 32a85cde7913..e853e761d9dd 100644
--- a/mingw-w64-crt/lib-common/msvcr120_app.def.in
+++ b/mingw-w64-crt/lib-common/msvcr120_app.def.in
@@ -2028,7 +2028,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fscanf
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in
b/mingw-w64-crt/lib-common/msvcrt.def.in
index a86e5680c3d9..16b422976585 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -975,7 +975,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp F_X86_NATIVE(DATA)
fscanf
fseek
diff --git a/mingw-w64-crt/lib-common/ucrtbase-common.def.in
b/mingw-w64-crt/lib-common/ucrtbase-common.def.in
index c0a273e0f280..47b96b489aca 100644
--- a/mingw-w64-crt/lib-common/ucrtbase-common.def.in
+++ b/mingw-w64-crt/lib-common/ucrtbase-common.def.in
@@ -2385,7 +2385,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fseek
diff --git a/mingw-w64-crt/lib32/crtdll.def.in
b/mingw-w64-crt/lib32/crtdll.def.in
index 8ffaa3adf385..bcc0ee7eb8ba 100644
--- a/mingw-w64-crt/lib32/crtdll.def.in
+++ b/mingw-w64-crt/lib32/crtdll.def.in
@@ -467,7 +467,7 @@ fputs
fputwc
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr100.def.in
b/mingw-w64-crt/lib32/msvcr100.def.in
index 2d00f87f0d07..b07af4a991dc 100644
--- a/mingw-w64-crt/lib32/msvcr100.def.in
+++ b/mingw-w64-crt/lib32/msvcr100.def.in
@@ -1697,7 +1697,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr100d.def.in
b/mingw-w64-crt/lib32/msvcr100d.def.in
index e1f6b4770127..6f6f2a0a5a47 100644
--- a/mingw-w64-crt/lib32/msvcr100d.def.in
+++ b/mingw-w64-crt/lib32/msvcr100d.def.in
@@ -1763,7 +1763,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr110.def.in
b/mingw-w64-crt/lib32/msvcr110.def.in
index be2491f6fd85..bebd0aa6558b 100644
--- a/mingw-w64-crt/lib32/msvcr110.def.in
+++ b/mingw-w64-crt/lib32/msvcr110.def.in
@@ -1829,7 +1829,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr110d.def.in
b/mingw-w64-crt/lib32/msvcr110d.def.in
index 16d06696c574..ed917c9ca08a 100644
--- a/mingw-w64-crt/lib32/msvcr110d.def.in
+++ b/mingw-w64-crt/lib32/msvcr110d.def.in
@@ -1896,7 +1896,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr120.def.in
b/mingw-w64-crt/lib32/msvcr120.def.in
index aaa965780e67..03cc0002fb2b 100644
--- a/mingw-w64-crt/lib32/msvcr120.def.in
+++ b/mingw-w64-crt/lib32/msvcr120.def.in
@@ -1997,7 +1997,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr120d.def.in
b/mingw-w64-crt/lib32/msvcr120d.def.in
index f670d0bbffa8..7173d07dce7a 100644
--- a/mingw-w64-crt/lib32/msvcr120d.def.in
+++ b/mingw-w64-crt/lib32/msvcr120d.def.in
@@ -2064,7 +2064,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr40d.def.in
b/mingw-w64-crt/lib32/msvcr40d.def.in
index 1590e659077b..345b4c9fdb85 100644
--- a/mingw-w64-crt/lib32/msvcr40d.def.in
+++ b/mingw-w64-crt/lib32/msvcr40d.def.in
@@ -1497,7 +1497,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr70.def.in
b/mingw-w64-crt/lib32/msvcr70.def.in
index ec64df727c37..9d16adf7207d 100644
--- a/mingw-w64-crt/lib32/msvcr70.def.in
+++ b/mingw-w64-crt/lib32/msvcr70.def.in
@@ -747,7 +747,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr70d.def.in
b/mingw-w64-crt/lib32/msvcr70d.def.in
index 408f1e9194ce..ee0c89f6926d 100644
--- a/mingw-w64-crt/lib32/msvcr70d.def.in
+++ b/mingw-w64-crt/lib32/msvcr70d.def.in
@@ -791,7 +791,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr71.def.in
b/mingw-w64-crt/lib32/msvcr71.def.in
index 6e3f54069999..c35494696887 100644
--- a/mingw-w64-crt/lib32/msvcr71.def.in
+++ b/mingw-w64-crt/lib32/msvcr71.def.in
@@ -741,7 +741,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr71d.def.in
b/mingw-w64-crt/lib32/msvcr71d.def.in
index 7f70c52095a2..801ce1b2bc24 100644
--- a/mingw-w64-crt/lib32/msvcr71d.def.in
+++ b/mingw-w64-crt/lib32/msvcr71d.def.in
@@ -785,7 +785,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcr80.def.in
b/mingw-w64-crt/lib32/msvcr80.def.in
index 981870755ae8..5b37f1e50107 100644
--- a/mingw-w64-crt/lib32/msvcr80.def.in
+++ b/mingw-w64-crt/lib32/msvcr80.def.in
@@ -1336,7 +1336,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr80d.def.in
b/mingw-w64-crt/lib32/msvcr80d.def.in
index a98c5dd36dc1..a65513dcf922 100644
--- a/mingw-w64-crt/lib32/msvcr80d.def.in
+++ b/mingw-w64-crt/lib32/msvcr80d.def.in
@@ -1419,7 +1419,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr90.def.in
b/mingw-w64-crt/lib32/msvcr90.def.in
index 6f626415f7fc..a4c1eddb3acc 100644
--- a/mingw-w64-crt/lib32/msvcr90.def.in
+++ b/mingw-w64-crt/lib32/msvcr90.def.in
@@ -1331,7 +1331,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcr90d.def.in
b/mingw-w64-crt/lib32/msvcr90d.def.in
index 8bca8f485a4a..6c1d7dfd50a0 100644
--- a/mingw-w64-crt/lib32/msvcr90d.def.in
+++ b/mingw-w64-crt/lib32/msvcr90d.def.in
@@ -1403,7 +1403,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib32/msvcrt10.def.in
b/mingw-w64-crt/lib32/msvcrt10.def.in
index 9d4db9f811e7..7576391c9ea6 100644
--- a/mingw-w64-crt/lib32/msvcrt10.def.in
+++ b/mingw-w64-crt/lib32/msvcrt10.def.in
@@ -1146,7 +1146,7 @@ fputs
fputwc
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcrt20.def.in
b/mingw-w64-crt/lib32/msvcrt20.def.in
index 94dcdb2fab49..ad1962864163 100644
--- a/mingw-w64-crt/lib32/msvcrt20.def.in
+++ b/mingw-w64-crt/lib32/msvcrt20.def.in
@@ -1365,7 +1365,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcrt40.def.in
b/mingw-w64-crt/lib32/msvcrt40.def.in
index a061b15a8a65..1bfac1a19857 100644
--- a/mingw-w64-crt/lib32/msvcrt40.def.in
+++ b/mingw-w64-crt/lib32/msvcrt40.def.in
@@ -1465,7 +1465,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib32/msvcrtd.def.in
b/mingw-w64-crt/lib32/msvcrtd.def.in
index 36e9fa45eda0..5274e7d49582 100644
--- a/mingw-w64-crt/lib32/msvcrtd.def.in
+++ b/mingw-w64-crt/lib32/msvcrtd.def.in
@@ -691,7 +691,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
frexp
fscanf
fseek
diff --git a/mingw-w64-crt/lib64/msvcr100.def.in
b/mingw-w64-crt/lib64/msvcr100.def.in
index df860c09d27c..291718638f98 100644
--- a/mingw-w64-crt/lib64/msvcr100.def.in
+++ b/mingw-w64-crt/lib64/msvcr100.def.in
@@ -1652,7 +1652,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr100d.def.in
b/mingw-w64-crt/lib64/msvcr100d.def.in
index 6fd09a5886e4..185c173580b9 100644
--- a/mingw-w64-crt/lib64/msvcr100d.def.in
+++ b/mingw-w64-crt/lib64/msvcr100d.def.in
@@ -1717,7 +1717,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr110.def.in
b/mingw-w64-crt/lib64/msvcr110.def.in
index 80f9fa554c71..810b4cb22e6d 100644
--- a/mingw-w64-crt/lib64/msvcr110.def.in
+++ b/mingw-w64-crt/lib64/msvcr110.def.in
@@ -1776,7 +1776,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr110d.def.in
b/mingw-w64-crt/lib64/msvcr110d.def.in
index 3bb047b4cd3c..01c5650cde64 100644
--- a/mingw-w64-crt/lib64/msvcr110d.def.in
+++ b/mingw-w64-crt/lib64/msvcr110d.def.in
@@ -1841,7 +1841,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr120.def.in
b/mingw-w64-crt/lib64/msvcr120.def.in
index 4f19699b1771..383aea6910fa 100644
--- a/mingw-w64-crt/lib64/msvcr120.def.in
+++ b/mingw-w64-crt/lib64/msvcr120.def.in
@@ -1943,7 +1943,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr120d.def.in
b/mingw-w64-crt/lib64/msvcr120d.def.in
index f4a1d6b24a68..2c8ef5498ae4 100644
--- a/mingw-w64-crt/lib64/msvcr120d.def.in
+++ b/mingw-w64-crt/lib64/msvcr120d.def.in
@@ -2008,7 +2008,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr80.def.in
b/mingw-w64-crt/lib64/msvcr80.def.in
index 362ca3efe409..13f81391f280 100644
--- a/mingw-w64-crt/lib64/msvcr80.def.in
+++ b/mingw-w64-crt/lib64/msvcr80.def.in
@@ -1274,7 +1274,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr80d.def.in
b/mingw-w64-crt/lib64/msvcr80d.def.in
index 66ff58201d8f..72cc448e5792 100644
--- a/mingw-w64-crt/lib64/msvcr80d.def.in
+++ b/mingw-w64-crt/lib64/msvcr80d.def.in
@@ -1351,7 +1351,7 @@ fputwc
fputws
fread
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA ; overwritten
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr90.def.in
b/mingw-w64-crt/lib64/msvcr90.def.in
index d04136ed004a..fe07c215e220 100644
--- a/mingw-w64-crt/lib64/msvcr90.def.in
+++ b/mingw-w64-crt/lib64/msvcr90.def.in
@@ -1272,7 +1272,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/lib64/msvcr90d.def.in
b/mingw-w64-crt/lib64/msvcr90d.def.in
index 1a25264437f1..e5369f325b51 100644
--- a/mingw-w64-crt/lib64/msvcr90d.def.in
+++ b/mingw-w64-crt/lib64/msvcr90d.def.in
@@ -1338,7 +1338,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp DATA
fscanf
diff --git a/mingw-w64-crt/libarm32/msvcr110.def.in
b/mingw-w64-crt/libarm32/msvcr110.def.in
index d863b64340a5..0be317154872 100644
--- a/mingw-w64-crt/libarm32/msvcr110.def.in
+++ b/mingw-w64-crt/libarm32/msvcr110.def.in
@@ -1763,7 +1763,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fscanf
diff --git a/mingw-w64-crt/libarm32/msvcr110d.def.in
b/mingw-w64-crt/libarm32/msvcr110d.def.in
index 699f0e8de058..560beb37cd26 100644
--- a/mingw-w64-crt/libarm32/msvcr110d.def.in
+++ b/mingw-w64-crt/libarm32/msvcr110d.def.in
@@ -1828,7 +1828,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fscanf
diff --git a/mingw-w64-crt/libarm32/msvcr120.def.in
b/mingw-w64-crt/libarm32/msvcr120.def.in
index 3218c4897b44..29f351e1b876 100644
--- a/mingw-w64-crt/libarm32/msvcr120.def.in
+++ b/mingw-w64-crt/libarm32/msvcr120.def.in
@@ -1911,7 +1911,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fscanf
diff --git a/mingw-w64-crt/libarm32/msvcr120d.def.in
b/mingw-w64-crt/libarm32/msvcr120d.def.in
index 096f4d17d9ca..4ba59334d6c9 100644
--- a/mingw-w64-crt/libarm32/msvcr120d.def.in
+++ b/mingw-w64-crt/libarm32/msvcr120d.def.in
@@ -1976,7 +1976,7 @@ fputws
fread
fread_s
free
-freopen
+_freopen == freopen ; freopen replaced by emu because is not C99 compatible
freopen_s
frexp
fscanf
diff --git a/mingw-w64-crt/stdio/freopen.c b/mingw-w64-crt/stdio/freopen.c
new file mode 100644
index 000000000000..237c295de0d0
--- /dev/null
+++ b/mingw-w64-crt/stdio/freopen.c
@@ -0,0 +1,315 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+#include <internal.h>
+#include <windows.h>
+#include <winternl.h>
+#include <ntstatus.h>
+
+static NTSTATUS NTAPI MyNtQueryInformationFile(HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass)
+{
+ static NTSTATUS (NTAPI *NtQueryInformationFilePtr)(HANDLE, PIO_STATUS_BLOCK,
PVOID, ULONG, FILE_INFORMATION_CLASS);
+ static volatile LONG init = 0;
+
+ if (!init) {
+ HMODULE ntdll = GetModuleHandleA("ntdll.dll");
+ FARPROC func = ntdll ? GetProcAddress(ntdll, "NtQueryInformationFile") :
NULL;
+ (void)InterlockedExchangePointer((PVOID volatile
*)&NtQueryInformationFilePtr, func);
+ (void)InterlockedExchange(&init, 1);
+ }
+
+ if (!NtQueryInformationFilePtr)
+ return STATUS_NOT_IMPLEMENTED;
+ else
+ return NtQueryInformationFilePtr(FileHandle, IoStatusBlock,
FileInformation, Length, FileInformationClass);
+}
+#define NtQueryInformationFile MyNtQueryInformationFile
+
+static NTSTATUS NTAPI MyNtSetInformationFile(HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass)
+{
+ static NTSTATUS (NTAPI *NtSetInformationFilePtr)(HANDLE, PIO_STATUS_BLOCK,
PVOID, ULONG, FILE_INFORMATION_CLASS);
+ static volatile LONG init = 0;
+
+ if (!init) {
+ HMODULE ntdll = GetModuleHandleA("ntdll.dll");
+ FARPROC func = ntdll ? GetProcAddress(ntdll, "NtSetInformationFile") :
NULL;
+ (void)InterlockedExchangePointer((PVOID volatile
*)&NtSetInformationFilePtr, func);
+ (void)InterlockedExchange(&init, 1);
+ }
+
+ if (!NtSetInformationFilePtr)
+ return STATUS_NOT_IMPLEMENTED;
+ else
+ return NtSetInformationFilePtr(FileHandle, IoStatusBlock, FileInformation,
Length, FileInformationClass);
+}
+#define NtSetInformationFile MyNtSetInformationFile
+
+
+_CRTIMP FILE *__cdecl _freopen(const char *restrict filename, const char
*restrict mode, FILE *restrict file);
+
+FILE *__cdecl freopen(const char *restrict filename, const char *restrict
mode, FILE *restrict file)
+{
+ int new_stream_flags;
+ int new_mode_flags;
+ int new_mode;
+ int change_iocommit;
+ int fd;
+ HANDLE handle;
+ FILE_MODE_INFORMATION file_mode_information;
+ IO_STATUS_BLOCK io_status_block;
+ NTSTATUS status;
+
+ /* This mingw-w64 function handles only case when the filename is NULL and
+ * both mode and file are specified. Forward all other cases to the original
+ * msvcrt freopen function.
+ */
+ if (!(!filename && mode && file))
+ return _freopen(filename, mode, file);
+
+
+ /* As a first step parse freopen mode and reject any invalid combinations
+ * in the same way and same behavior as the original msvcrt freopen function.
+ */
+
+ while (*mode == ' ')
+ mode++;
+
+ new_stream_flags = _commode; /* default stream flags are in global variable
_commode */
+ new_mode_flags = 0;
+ change_iocommit = 0;
+
+ if (*mode == 'r')
+ new_stream_flags |= _IOREAD;
+ else if (*mode == 'w' || *mode == 'a') /* FIXME: changing between 'w' and
'a' is ignored and does not trigger any error */
+ new_stream_flags |= _IOWRT;
+ else
+ goto err_inval;
+
+ while (*++mode) {
+ if (*mode == ' ')
+ continue;
+
+ if (*mode == '+') {
+ if (new_stream_flags & _IORW)
+ goto err_inval;
+ new_stream_flags |= _IORW;
+ new_stream_flags &= ~(_IOREAD | _IOWRT);
+ } else if (*mode == 'b') {
+ if (new_mode_flags & (_O_TEXT | _O_BINARY))
+ goto err_inval;
+ new_mode_flags |= _O_BINARY;
+ } else if (*mode == 't') {
+ if (new_mode_flags & (_O_TEXT | _O_BINARY))
+ goto err_inval;
+ new_mode_flags |= _O_TEXT;
+ } else if (*mode == 'c') {
+ if (change_iocommit)
+ goto err_inval;
+ new_stream_flags |= _IOCOMMIT;
+ change_iocommit = 1;
+ } else if (*mode == 'n') {
+ if (change_iocommit)
+ goto err_inval;
+ new_stream_flags &= ~_IOCOMMIT;
+ change_iocommit = 1;
+ } else if (*mode == 'S') {
+ if (new_mode_flags & (_O_SEQUENTIAL | _O_RANDOM))
+ goto err_inval;
+ new_mode_flags |= _O_SEQUENTIAL;
+ } else if (*mode == 'R') {
+ if (new_mode_flags & (_O_SEQUENTIAL | _O_RANDOM))
+ goto err_inval;
+ new_mode_flags |= _O_RANDOM;
+ } else if (*mode == 'T') {
+ if (new_mode_flags & _O_SHORT_LIVED)
+ goto err_inval;
+ new_mode_flags |= _O_SHORT_LIVED;
+ } else if (*mode == 'D') {
+ if (new_mode_flags & _O_TEMPORARY)
+ goto err_inval;
+ new_mode_flags |= _O_TEMPORARY;
+ } else if (*mode == 'N') {
+ /* msvcrt does not check for duplicate N characters */
+ new_mode_flags |= _O_NOINHERIT;
+ } else if (*mode == ',') {
+ while (*mode == ' ')
+ mode++;
+ if (strncmp(mode, "ccs", 3) != 0)
+ goto err_inval;
+ mode += 3;
+ while (*mode == ' ')
+ mode++;
+ if (*mode != '=')
+ goto err_inval;
+ while (*mode == ' ')
+ mode++;
+ if (stricmp(mode, "UTF-8") == 0)
+ new_mode_flags |= _O_U8TEXT;
+ else if (stricmp(mode, "UTF-16LE") == 0)
+ new_mode_flags |= _O_U16TEXT;
+ else if (stricmp(mode, "UNICODE") == 0)
+ new_mode_flags |= _O_WTEXT;
+ else
+ goto err_inval;
+ /* after ",css=" there is no other mode specifier, stricmp checks for
this */
+ } else {
+ goto err_inval;
+ }
+ }
+
+ /* If mode is not specified then the default one from the global variable
_fmode is used */
+ if (!(new_mode_flags & (_O_BINARY | _O_TEXT | _O_U8TEXT | _O_U16TEXT |
_O_WTEXT)))
+ new_mode_flags |= _fmode & (_O_BINARY | _O_TEXT | _O_U8TEXT | _O_U16TEXT |
_O_WTEXT);
+
+ /* If mode is not specified neither in _fmode then the fallback value is
always _O_TEXT */
+ if (!(new_mode_flags & (_O_BINARY | _O_TEXT | _O_U8TEXT | _O_U16TEXT |
_O_WTEXT)))
+ new_mode_flags |= _O_TEXT;
+
+ /* Changing of _IOREAD, _IOWRT and _IORW is not possible */
+ if ((new_stream_flags & (_IOREAD | _IOWRT | _IORW)) != (file->_flags &
(_IOREAD | _IOWRT | _IORW)))
+ goto err_inval;
+
+
+ /* As a second step take CRT file descriptor and WINAPI handle */
+
+ fd = fileno(file);
+ if (fd < 0)
+ return NULL;
+
+ handle = (HANDLE)_get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return NULL;
+
+
+ /* As a third step before changing any FILE*, fd or HANDLE characteristics,
flush all buffers */
+ /* This ensures that data in buffer are processed by existing settings */
+ fflush(file);
+
+
+ /* As a fourth step process _O_SEQUENTIAL, _O_TEMPORARY, _O_NOINHERIT,
_O_SHORT_LIVED and _O_RANDOM flags */
+
+ /* CRT _O_SEQUENTIAL flag is mapped to WINAPI FILE_FLAG_SEQUENTIAL_SCAN flag
+ * which is mapped to NT FILE_SEQUENTIAL_ONLY flag. WINAPI does not provide
+ * API to query or change this flag on already opened file handle. NT API
+ * provides functions NtQueryInformationFile() and NtSetInformationFile()
+ * with class FileModeInformation which allows that. WINAPI functions
+ * GetFileInformationByHandleEx() and SetFileInformationByHandle() do not
+ * support FileModeInfo level yet.
+ * Our NtQueryInformationFile wrapper returns STATUS_NOT_IMPLEMENTED when
+ * the NtQueryInformationFile function is not supported.
+ * For console handle: wine returns STATUS_OBJECT_TYPE_MISMATCH,
+ * Windows XP returns STATUS_INVALID_HANDLE and Windows 10 returns
+ * STATUS_SUCCESS.
+ * Treat STATUS_NOT_IMPLEMENTED, STATUS_OBJECT_TYPE_MISMATCH and
+ * STATUS_INVALID_HANDLE codes as if the FILE_SEQUENTIAL_ONLY was not set
+ * and setting it is not supported.
+ */
+ status = NtQueryInformationFile(handle, &io_status_block,
&file_mode_information, sizeof(file_mode_information), FileModeInformation);
+ if (status == STATUS_NOT_IMPLEMENTED || status ==
STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE) {
+ if (new_mode_flags & _O_SEQUENTIAL)
+ goto err_inval;
+ } else if (status == STATUS_SUCCESS) {
+ if (!!(new_mode_flags & _O_SEQUENTIAL) != !!(file_mode_information.Mode &
FILE_SEQUENTIAL_ONLY)) {
+ if (new_mode_flags & _O_SEQUENTIAL)
+ file_mode_information.Mode |= FILE_SEQUENTIAL_ONLY;
+ else
+ file_mode_information.Mode &= ~FILE_SEQUENTIAL_ONLY;
+ status = NtSetInformationFile(handle, &io_status_block,
&file_mode_information, sizeof(file_mode_information), FileModeInformation);
+ if (status != STATUS_SUCCESS)
+ goto err_inval;
+ }
+ } else {
+ goto err_inval;
+ }
+
+ /* CRT _O_TEMPORARY flag is mapped to WINAPI FILE_FLAG_DELETE_ON_CLOSE flag
+ * which is mapped to NT FILE_DELETE_ON_CLOSE flag. There is no API which
+ * allows to query that flag. Function GetFileInformationByHandleEx() does
+ * not support levels FileDispositionInfo and FileDispositionInfoEx. And
+ * function NtQueryInformationFile() does not support classes
+ * FileDispositionInformation and FileDispositionInformationEx.
+ * Setting or clearing this flag on already opened file handle is possible
+ * only on filesystem which supports FileDispositionInformationEx
+ * FILE_DISPOSITION_ON_CLOSE flag (e.g. on NTFS since Windows 10 1607)
+ * via either WINAPI SetFileInformationByHandle() function with level
+ * FileDispositionInfoEx or via NT NtSetInformationFile() function with class
+ * FileDispositionInformationEx, together with specifying
+ * FILE_DISPOSITION_ON_CLOSE flag. According to MS-FSCC documentation,
+ * setting of this flag will fail with STATUS_NOT_SUPPORTED if the
+ * NT FILE_DELETE_ON_CLOSE flag was not specified during opening the file.
+ * So there is no reliable way to query, clear or set FILE_DELETE_ON_CLOSE
+ * flag. Therefore ignore the CRT _O_TEMPORARY flag.
+ */
+
+ /* CRT _O_NOINHERIT flag is mapped to CRT ioinfo osfile flag FNOINHERIT and
+ * also to WINAPI SecurityAttributes bInheritHandle. WINAPI inheritance can
+ * be queried or changed by GetHandleInformation() and SetHandleInformation()
+ * functions with HANDLE_FLAG_INHERIT mask.
+ * Changing of CRT ioinfo osfile flag FNOINHERIT is not possible without
+ * touching CRT internals. So ignore the CRT _O_NOINHERIT flag.
+ */
+
+
+ /* CRT _O_SHORT_LIVED flag is mapped to WINAPI FILE_ATTRIBUTE_TEMPORARY flag
+ * which applies only when creating a new file. msvcrt and UCRT accepts the
+ * _O_SHORT_LIVED also when opening an existing file and in this case the
+ * flag is ignored. freopen with NULL filename re-opens an existing file,
+ * so always ignore the CRT _O_SHORT_LIVED flag.
+ */
+
+ /* CRT _O_RANDOM flag is mapped to WINAPI FILE_FLAG_RANDOM_ACCESS flag which
+ * is mapped to NT FILE_RANDOM_ACCESS flag. There is no WINAPI or NT function
+ * which allows to query, clear or set this flag. So ignore any attempt to
set
+ * or to clear this CRT flag without throwing any error.
+ */
+
+
+ /* As a fifth step process _O_BINARY, _O_TEXT, _O_WTEXT, _O_U16TEXT,
_O_U8TEXT flags */
+
+ /* Choose the correct new mode. If more mode flags are specified then msvcrt
chooses the first in this order. */
+ if (new_mode_flags & _O_BINARY)
+ new_mode = _O_BINARY;
+ else if (new_mode_flags & _O_TEXT)
+ new_mode = _O_TEXT;
+ else if (new_mode_flags & _O_WTEXT)
+ new_mode = _O_WTEXT;
+ else if (new_mode_flags & _O_U16TEXT)
+ new_mode = _O_U16TEXT;
+ else if (new_mode_flags & _O_U8TEXT)
+ new_mode = _O_U8TEXT;
+ else
+ goto err_inval; /* should not happen */
+
+ if (_setmode(fd, new_mode) < 0)
+ return NULL;
+
+
+ /* As a sixth step process _IOCOMMIT flag */
+
+ /* CRT _IOCOMMIT flag is set only in the FILE* structure. So atomically set
or clear it. */
+ if (change_iocommit) {
+ if (new_stream_flags & _IOCOMMIT)
+ InterlockedOr((LONG volatile *)&file->_flags, _IOCOMMIT);
+ else
+ InterlockedAnd((LONG volatile *)&file->_flags, ~_IOCOMMIT);
+ }
+
+
+ /* All done */
+ return file;
+
+err_inval:
+ errno = EINVAL;
+ return NULL;
+}
+FILE * (__cdecl *__MINGW_IMP_SYMBOL(freopen))(const char *restrict, const char
*restrict, FILE *restrict) = freopen;
+
+FILE * __attribute__((alias("freopen"))) __cdecl freopen64(const char
*restrict filename, const char *restrict mode, FILE *restrict file);
+extern FILE * (__cdecl * __attribute__((alias
(__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(freopen)))))
__MINGW_IMP_SYMBOL(freopen64))(const char *restrict, const char *restrict, FILE
*restrict);
diff --git a/mingw-w64-crt/stdio/ucrt_freopen.c
b/mingw-w64-crt/stdio/ucrt_freopen.c
new file mode 100644
index 000000000000..d00ff8ed3c9d
--- /dev/null
+++ b/mingw-w64-crt/stdio/ucrt_freopen.c
@@ -0,0 +1,3 @@
+/* _flags member of FILE struct has different offset in UCRT builds */
+#define _UCRT
+#include "freopen.c"
diff --git a/mingw-w64-crt/testcases/Makefile.am
b/mingw-w64-crt/testcases/Makefile.am
index 6ebb7f6babab..6e1248293419 100644
--- a/mingw-w64-crt/testcases/Makefile.am
+++ b/mingw-w64-crt/testcases/Makefile.am
@@ -21,6 +21,7 @@ testcase_progs = \
t_btowc \
t_findfirst \
t_float \
+ t_freopen \
t_fstat \
t_intrinc \
t_imagebase \
diff --git a/mingw-w64-crt/testcases/t_freopen.c
b/mingw-w64-crt/testcases/t_freopen.c
new file mode 100644
index 000000000000..8adb5f878a2d
--- /dev/null
+++ b/mingw-w64-crt/testcases/t_freopen.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <assert.h>
+
+int main() {
+ assert(freopen(NULL, "rb", stdin) != NULL);
+ assert(freopen(NULL, "ab", stdout) != NULL);
+ assert(freopen(NULL, "ab", stderr) != NULL);
+ return 0;
+}
--
2.20.1
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public