1 /** 2 * This module provides MS VC runtime helper functions that 3 * wrap differences between MS C runtime versions. 4 * 5 * Copyright: Copyright Digital Mars 2015. 6 * License: Distributed under the 7 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 8 * (See accompanying file LICENSE) 9 * Source: $(DRUNTIMESRC rt/_msvc.d) 10 * Authors: Rainer Schuetze 11 * Source: $(DRUNTIMESRC rt/_msvc.d) 12 */ 13 module rt.msvc; 14 15 version (CRuntime_Microsoft): 16 17 import core.stdc.stdarg : va_list; 18 import core.stdc.stdio : FILE, stdin, stdout, stderr, _vsnprintf; 19 20 extern(C): 21 nothrow: 22 @nogc: 23 24 // VS2013- FILE. 25 struct _iobuf 26 { 27 char* _ptr; 28 int _cnt; 29 char* _base; 30 int _flag; 31 int _file; 32 int _charbuf; 33 int _bufsiz; 34 char* _tmpfname; 35 } 36 37 FILE* __acrt_iob_func(int hnd); // VS2015+ 38 _iobuf* __iob_func(); // VS2013- 39 40 int _set_output_format(int format); // VS2013- 41 42 immutable void* _nullfunc = null; 43 44 __gshared ubyte msvcUsesUCRT; 45 46 version (X86) 47 enum cPrefix = "_"; 48 else 49 enum cPrefix = ""; 50 51 mixin template declareAlternateName(string name, string alternateName) 52 { 53 mixin(`pragma(linkerDirective, "/alternatename:` ~ cPrefix~name ~ `=` ~ cPrefix~alternateName ~ `");`); 54 } 55 56 mixin declareAlternateName!("__acrt_iob_func", "_msvc_acrt_iob_func"); 57 mixin declareAlternateName!("__iob_func", "_nullfunc"); 58 mixin declareAlternateName!("_set_output_format", "_nullfunc"); 59 60 private bool isAvailable(alias f)() 61 { 62 auto p = cast(void**) &f; // required to prevent frontend 'optimization'... 63 return p != &_nullfunc; 64 } 65 66 void init_msvc() 67 { 68 if (isAvailable!_set_output_format) 69 { 70 enum _TWO_DIGIT_EXPONENT = 1; 71 _set_output_format(_TWO_DIGIT_EXPONENT); 72 } 73 else 74 msvcUsesUCRT = 1; 75 } 76 77 // VS2013- implements stdin/out/err using a macro, VS2015+ provides __acrt_iob_func 78 FILE* _msvc_acrt_iob_func(int hnd) 79 { 80 if (isAvailable!__iob_func) 81 return cast(FILE*) (__iob_func() + hnd); 82 else 83 assert(false); 84 } 85 86 // VS2015+ wraps (v)snprintf into an inlined function calling __stdio_common_vsprintf 87 // wrap it back to the original function if it doesn't exist in the C library 88 int _msvc_stdio_common_vsprintf( 89 ulong options, 90 char* buffer, 91 size_t buffer_count, 92 const char* format, 93 void* locale, 94 va_list arglist 95 ) 96 { 97 enum _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR = 2; 98 int r = _vsnprintf(buffer, buffer_count, format, arglist); 99 if ((options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR) && 100 (buffer_count != 0 && buffer)) 101 { 102 // mimic vsnprintf semantics for most use cases 103 if (r == buffer_count) 104 { 105 buffer[buffer_count - 1] = 0; 106 return r; 107 } 108 if (r == -1) 109 { 110 buffer[buffer_count - 1] = 0; 111 return _vsnprintf(null, 0, format, arglist); 112 } 113 } 114 return r; 115 } 116 117 mixin declareAlternateName!("__stdio_common_vsprintf", "_msvc_stdio_common_vsprintf"); 118 119 // VS2015+ provides C99-conformant (v)snprintf functions, so weakly 120 // link to legacy _(v)snprintf (not C99-conformant!) for VS2013- only 121 122 mixin declareAlternateName!("snprintf", "_snprintf"); 123 mixin declareAlternateName!("vsnprintf", "_vsnprintf"); 124 125 // VS2013- implements these functions as macros, VS2015+ provides symbols 126 127 mixin declareAlternateName!("_fputc_nolock", "_msvc_fputc_nolock"); 128 mixin declareAlternateName!("_fgetc_nolock", "_msvc_fgetc_nolock"); 129 mixin declareAlternateName!("rewind", "_msvc_rewind"); 130 mixin declareAlternateName!("clearerr", "_msvc_clearerr"); 131 mixin declareAlternateName!("feof", "_msvc_feof"); 132 mixin declareAlternateName!("ferror", "_msvc_ferror"); 133 mixin declareAlternateName!("fileno", "_msvc_fileno"); 134 135 // VS2013- helper functions 136 int _filbuf(_iobuf* fp); 137 int _flsbuf(int c, _iobuf* fp); 138 139 mixin declareAlternateName!("_filbuf", "_nullfunc"); 140 mixin declareAlternateName!("_flsbuf", "_nullfunc"); 141 142 int _msvc_fputc_nolock(int c, _iobuf* fp) 143 { 144 fp._cnt--; 145 if (fp._cnt >= 0) 146 { 147 *fp._ptr = cast(char) c; 148 fp._ptr++; 149 return cast(char) c; 150 } 151 else 152 return _flsbuf(c, fp); 153 } 154 155 int _msvc_fgetc_nolock(_iobuf* fp) 156 { 157 fp._cnt--; 158 if (fp._cnt >= 0) 159 { 160 const char c = *fp._ptr; 161 fp._ptr++; 162 return c; 163 } 164 else 165 return _filbuf(fp); 166 } 167 168 enum 169 { 170 SEEK_SET = 0, 171 _IOEOF = 0x10, 172 _IOERR = 0x20 173 } 174 175 int fseek(_iobuf* stream, int offset, int origin); 176 177 void _msvc_rewind(_iobuf* stream) 178 { 179 fseek(stream, 0, SEEK_SET); 180 stream._flag &= ~_IOERR; 181 } 182 183 void _msvc_clearerr(_iobuf* stream) 184 { 185 stream._flag &= ~(_IOERR | _IOEOF); 186 } 187 188 int _msvc_feof(_iobuf* stream) 189 { 190 return stream._flag & _IOEOF; 191 } 192 193 int _msvc_ferror(_iobuf* stream) 194 { 195 return stream._flag & _IOERR; 196 } 197 198 int _msvc_fileno(_iobuf* stream) 199 { 200 return stream._file; 201 } 202 203 204 205 /** 206 * 32-bit x86 MS VC runtimes lack most single-precision math functions. 207 * Declare alternate implementations to be pulled in from msvc_math.d. 208 */ 209 210 version (X86): 211 mixin declareAlternateName!("acosf", "_msvc_acosf"); 212 mixin declareAlternateName!("asinf", "_msvc_asinf"); 213 mixin declareAlternateName!("atanf", "_msvc_atanf"); 214 mixin declareAlternateName!("atan2f", "_msvc_atan2f"); 215 mixin declareAlternateName!("cosf", "_msvc_cosf"); 216 mixin declareAlternateName!("sinf", "_msvc_sinf"); 217 mixin declareAlternateName!("tanf", "_msvc_tanf"); 218 mixin declareAlternateName!("coshf", "_msvc_coshf"); 219 mixin declareAlternateName!("sinhf", "_msvc_sinhf"); 220 mixin declareAlternateName!("tanhf", "_msvc_tanhf"); 221 mixin declareAlternateName!("expf", "_msvc_expf"); 222 mixin declareAlternateName!("logf", "_msvc_logf"); 223 mixin declareAlternateName!("log10f", "_msvc_log10f"); 224 mixin declareAlternateName!("powf", "_msvc_powf"); 225 mixin declareAlternateName!("sqrtf", "_msvc_sqrtf"); 226 mixin declareAlternateName!("ceilf", "_msvc_ceilf"); 227 mixin declareAlternateName!("floorf", "_msvc_floorf"); 228 mixin declareAlternateName!("fmodf", "_msvc_fmodf"); 229 mixin declareAlternateName!("modff", "_msvc_modff");