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");