diff --git a/mak/MANIFEST b/mak/MANIFEST index af2dfa21c8..abe9f591b3 100644 --- a/mak/MANIFEST +++ b/mak/MANIFEST @@ -183,6 +183,8 @@ MANIFEST=\ src\core\sys\windows\threadaux.d \ src\core\sys\windows\windows.d \ src\core\sys\windows\winsock2.d \ + src\core\sys\windows\stdio_msvc12.d \ + src\core\sys\windows\stdio_msvc14.d \ \ src\gc\bits.d \ src\gc\config.d \ diff --git a/src/core/stdc/stdio.d b/src/core/stdc/stdio.d index e78034fda6..bb284f3cb3 100644 --- a/src/core/stdc/stdio.d +++ b/src/core/stdc/stdio.d @@ -76,7 +76,7 @@ else version( CRuntime_Microsoft ) FOPEN_MAX = 20, /// FILENAME_MAX = 260, - /// + /// Actually int.max since Visual Studio 2015. TMP_MAX = 32767, /// _SYS_OPEN = 20, // non-standard @@ -84,11 +84,11 @@ else version( CRuntime_Microsoft ) /// enum int _NFILE = 512; // non-standard - /// + /// Removed since Visual Studio 2015. enum string _P_tmpdir = "\\"; // non-standard - /// + /// Removed since Visual Studio 2015. enum wstring _wP_tmpdir = "\\"; // non-standard - /// + /// Actually 260 since Visual Studio 2015. enum int L_tmpnam = _P_tmpdir.length + 12; } else version( linux ) @@ -264,14 +264,7 @@ else version( CRuntime_Microsoft ) /// struct _iobuf { - char* _ptr; - int _cnt; - char* _base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char* _tmpfname; + void* undefined; } /// @@ -549,32 +542,28 @@ else version( CRuntime_Microsoft ) _IOLBF = 0x40, /// _IONBF = 4, - /// + /// Removed since Visual Studio 2015. _IOREAD = 1, // non-standard - /// + /// Removed since Visual Studio 2015. _IOWRT = 2, // non-standard - /// + /// Removed since Visual Studio 2015. _IOMYBUF = 8, // non-standard - /// + /// Removed since Visual Studio 2015. _IOEOF = 0x10, // non-standard - /// + /// Removed since Visual Studio 2015. _IOERR = 0x20, // non-standard - /// + /// Removed since Visual Studio 2015. _IOSTRG = 0x40, // non-standard - /// + /// Removed since Visual Studio 2015. _IORW = 0x80, // non-standard - /// + /// Removed since Visual Studio 2015. _IOAPP = 0x200, // non-standard - /// + /// Removed since Visual Studio 2015. _IOAPPEND = 0x200, // non-standard } extern shared void function() _fcloseallp; - private extern shared FILE[_NFILE] _iob; - - shared(FILE)* __iob_func(); - /// shared FILE* stdin; // = &__iob_func()[0]; /// @@ -942,66 +931,34 @@ else version( CRuntime_DigitalMars ) else version( CRuntime_Microsoft ) { // No unsafe pointer manipulation. - extern (D) @trusted + @trusted { /// - void rewind(FILE* stream) { fseek(stream,0L,SEEK_SET); stream._flag = stream._flag & ~_IOERR; } + void rewind(FILE* stream); /// - pure void clearerr(FILE* stream) { stream._flag = stream._flag & ~(_IOERR|_IOEOF); } + pure void clearerr(FILE* stream); /// - pure int feof(FILE* stream) { return stream._flag&_IOEOF; } + pure int feof(FILE* stream); /// - pure int ferror(FILE* stream) { return stream._flag&_IOERR; } + pure int ferror(FILE* stream); /// - pure int fileno(FILE* stream) { return stream._file; } + pure int fileno(FILE* stream); } - /// - int _snprintf(char* s, size_t n, in char* fmt, ...); - /// - alias _snprintf snprintf; + /// + int _snprintf(char* s, size_t n, in char* format, ...); /// - int _vsnprintf(char* s, size_t n, in char* format, va_list arg); - /// - alias _vsnprintf vsnprintf; - - /// - uint _set_output_format(uint format); - /// - enum _TWO_DIGIT_EXPONENT = 1; + int snprintf(char* s, size_t n, in char* format, ...); /// - int _filbuf(FILE *fp); + int _vsnprintf(char* s, size_t n, in char* format, va_list arg); /// - int _flsbuf(int c, FILE *fp); + int vsnprintf(char* s, size_t n, in char* format, va_list arg); /// - int _fputc_nolock(int c, FILE *fp) - { - fp._cnt = fp._cnt - 1; - if (fp._cnt >= 0) - { - *fp._ptr = cast(char)c; - fp._ptr = fp._ptr + 1; - return cast(char)c; - } - else - return _flsbuf(c, fp); - } - + int _fputc_nolock(int c, FILE *fp); /// - int _fgetc_nolock(FILE *fp) - { - fp._cnt = fp._cnt - 1; - if (fp._cnt >= 0) - { - char c = *fp._ptr; - fp._ptr = fp._ptr + 1; - return c; - } - else - return _filbuf(fp); - } + int _fgetc_nolock(FILE *fp); /// int _lock_file(FILE *fp); diff --git a/src/rt/dmain2.d b/src/rt/dmain2.d index 77edcd592b..8392d3633e 100644 --- a/src/rt/dmain2.d +++ b/src/rt/dmain2.d @@ -57,6 +57,11 @@ version (OSX) extern (C) __gshared void* __osx_stack_end = cast(void*)0xC0000000; } +version(CRuntime_Microsoft) +{ + extern(C) void init_msvc(); +} + /*********************************** * These are a temporary means of providing a GC hook for DLL use. They may be * replaced with some other similar functionality later. @@ -270,13 +275,7 @@ extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc) } version (CRuntime_Microsoft) { - auto fp = __iob_func(); - stdin = &fp[0]; - stdout = &fp[1]; - stderr = &fp[2]; - - // ensure that sprintf generates only 2 digit exponent when writing floating point values - _set_output_format(_TWO_DIGIT_EXPONENT); + init_msvc(); // enable full precision for reals version(Win64) diff --git a/src/rt/stdio_msvc.c b/src/rt/stdio_msvc.c new file mode 100644 index 0000000000..a81042643f --- /dev/null +++ b/src/rt/stdio_msvc.c @@ -0,0 +1,147 @@ +/** +* This module provides MS VC runtime helper function that +* wrap differences between different versions of the MS C runtime +* +* Copyright: Copyright Digital Mars 2015. +* License: Distributed under the +* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). +* (See accompanying file LICENSE) +* Source: $(DRUNTIMESRC rt/_stdio_msvc.d) +* Authors: Rainer Schuetze +*/ + +struct _iobuf +{ + char* _ptr; + int _cnt; // _cnt and _base exchanged for VS2015 + char* _base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char* _tmpfname; + // additional members in VS2015 +}; + +typedef struct _iobuf FILE; +extern FILE* stdin; +extern FILE* stdout; +extern FILE* stderr; + +FILE* __acrt_iob_func(int hnd); // VS2015+ +FILE* __iob_func(); // VS2013- + +int _set_output_format(int format); // VS2013- + +//extern const char* __acrt_iob_func; +extern const char* _nullfunc = 0; + +#pragma comment(linker, "/alternatename:__acrt_iob_func=_nullfunc") +#pragma comment(linker, "/alternatename:__iob_func=_nullfunc") +#pragma comment(linker, "/alternatename:_set_output_format=_nullfunc") + +void init_msvc() +{ + if (&__acrt_iob_func != (void*) &_nullfunc) + { + stdin = __acrt_iob_func(0); + stdout = __acrt_iob_func(1); + stderr = __acrt_iob_func(2); + } + else if (&__iob_func != (void*) &_nullfunc) + { + FILE* fp = __iob_func(); + stdin = fp; + stdout = fp + 1; + stderr = fp + 2; + } + if (&_set_output_format != (void*) &_nullfunc) + { + const int _TWO_DIGIT_EXPONENT = 1; + _set_output_format(_TWO_DIGIT_EXPONENT); + } +} + +// VS2015+ provides C99-conformant (v)snprintf functions, so weakly +// link to legacy _(v)snprintf (not C99-conformant!) for VS2013- only + +#pragma comment(linker, "/alternatename:snprintf=_snprintf") +#pragma comment(linker, "/alternatename:vsnprintf=_vsnprintf") + +// VS2013- implements these functions as macros, VS2015+ provides symbols + +#pragma comment(linker, "/alternatename:_fputc_nolock=_msvc_fputc_nolock") +#pragma comment(linker, "/alternatename:_fgetc_nolock=_msvc_fgetc_nolock") +#pragma comment(linker, "/alternatename:rewind=_msvc_rewind") +#pragma comment(linker, "/alternatename:clearerr=_msvc_clearerr") +#pragma comment(linker, "/alternatename:feof=_msvc_feof") +#pragma comment(linker, "/alternatename:ferror=_msvc_ferror") +#pragma comment(linker, "/alternatename:fileno=_msvc_fileno") + +// VS2013- helper functions +int _filbuf(FILE* fp); +int _flsbuf(int c, FILE* fp); + +#pragma comment(linker, "/alternatename:_filbuf=_nullfunc") +#pragma comment(linker, "/alternatename:_flsbuf=_nullfunc") + +int _msvc_fputc_nolock(int c, FILE* fp) +{ + fp->_cnt = fp->_cnt - 1; + if (fp->_cnt >= 0) + { + *(fp->_ptr) = (char)c; + fp->_ptr = fp->_ptr + 1; + return (char)c; + } + else + return _flsbuf(c, fp); +} + +int _msvc_fgetc_nolock(FILE* fp) +{ + fp->_cnt = fp->_cnt - 1; + if (fp->_cnt >= 0) + { + char c = *(fp->_ptr); + fp->_ptr = fp->_ptr + 1; + return c; + } + else + return _filbuf(fp); +} + +enum +{ + SEEK_SET = 0, + _IOEOF = 0x10, + _IOERR = 0x20 +}; + +int fseek(FILE* fp, long off, int whence); + +void _msvc_rewind(FILE* stream) +{ + fseek(stream, 0L, SEEK_SET); + stream->_flag = stream->_flag & ~_IOERR; +} + +void _msvc_clearerr(FILE* stream) +{ + stream->_flag = stream->_flag & ~(_IOERR | _IOEOF); +} + +int _msvc_feof(FILE* stream) +{ + return stream->_flag & _IOEOF; +} + +int _msvc_ferror(FILE* stream) +{ + return stream->_flag & _IOERR; +} + +int _msvc_fileno(FILE* stream) +{ + return stream->_file; +} diff --git a/win64.mak b/win64.mak index b55d433d18..86871c2c8e 100644 --- a/win64.mak +++ b/win64.mak @@ -41,8 +41,8 @@ $(mak\SRCS) # NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and # minit.asm is not used by dmd for Linux -OBJS= errno_c.obj -OBJS_TO_DELETE= errno_c.obj +OBJS= errno_c.obj stdio_msvc_$(MODEL).obj +OBJS_TO_DELETE= errno_c.obj stdio_msvc_$(MODEL).obj ######################## Doc .html file generation ############################## @@ -640,6 +640,10 @@ $(IMPDIR)\etc\linux\memoryerror.d : src\etc\linux\memoryerror.d errno_c.obj : src\core\stdc\errno.c $(CC) -c $(CFLAGS) src\core\stdc\errno.c -Foerrno_c.obj +stdio_msvc_$(MODEL).obj : src\rt\stdio_msvc.c win64.mak + $(CC) -c -Fo$@ $(CFLAGS) src\rt\stdio_msvc.c + + src\rt\minit.obj : src\rt\minit.asm $(CC) -c $(CFLAGS) src\rt\minit.asm @@ -648,6 +652,7 @@ src\rt\minit.obj : src\rt\minit.asm $(GCSTUB) : src\gcstub\gc.d win64.mak $(DMD) -c -of$(GCSTUB) src\gcstub\gc.d $(DFLAGS) + ################### Library generation ######################### $(DRUNTIME): $(OBJS) $(SRCS) win64.mak