1 //
2 // corecrt_internal_traits.h
3 //
4 //      Copyright (c) Microsoft Corporation.  All rights reserved.
5 //
6 // This internal header defines template-based utilities for implementing sets
7 // of functions that are largely similar but which operate on different kinds of
8 // strings (narrow or wide) or different kinds of integers (32-bit or 64-bit).
9 // It is similar in some respects to the macro-based <tchar.h>.
10 //
11 #pragma once
12 
13 #include <corecrt_internal.h>
14 #include <corecrt_internal_win32_buffer.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #pragma pack(push, _CRT_PACKING)
19 
20 #if defined(__GNUC__) || defined(__clang__)
21 // We have to declare them here, because GCC expects them to be declared,
22 // when the template specializations below are instanciated!
23 #include <corecrt_io.h>
24 extern "C" {
25 errno_t __cdecl _access_s(char const* const path, int const access_mode);
26 errno_t __cdecl _waccess_s(wchar_t const* const path, int const access_mode);
27 __time32_t __cdecl __loctotime32_t(int, int, int, int, int, int, int);
28 __time64_t __cdecl __loctotime64_t(int, int, int, int, int, int, int);
29 _Check_return_opt_ long __cdecl _lseek_nolock(_In_ int _FileHandle, _In_ long _Offset, _In_ int _Origin);
30 _Check_return_opt_ __int64 __cdecl _lseeki64_nolock(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin);
31 _ACRTIMP __time32_t __cdecl _time32(_Out_opt_ __time32_t* _Time);
32 _ACRTIMP __time64_t __cdecl _time64(_Out_opt_ __time64_t* _Time);
33 _Success_(return == 0)
34 errno_t __cdecl _sopen_nolock(
35     _Out_  int*        _UnlockFlag,
36     _Out_  int*        _FileHandle,
37     _In_z_ char const* _FileName,
38     _In_   int         _OpenFlag,
39     _In_   int         _ShareFlag,
40     _In_   int         _PermissionFlag,
41     _In_   int         _SecureFlag
42     );
43 _Success_(return == 0)
44 errno_t __cdecl _wsopen_nolock(
45     _Out_  int*           _UnlockFlag,
46     _Out_  int*           _FileHandle,
47     _In_z_ wchar_t const* _FileName,
48     _In_   int            _OpenFlag,
49     _In_   int            _ShareFlag,
50     _In_   int            _PermissionFlag,
51     _In_   int            _SecureFlag
52     );
53 } // extern "C"
54 #endif // __GNUC__
55 
56 #ifdef __clang__
57 // Hack for broken Clang, which crashes, when using __cdecl on a static template function.
58 // See CORE-19902
59 #undef __cdecl
60 #define __cdecl
61 #endif // __clang__
62 
63 
64 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 //
66 // Character Traits
67 //
68 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 template <typename Character>
70 struct __crt_char_traits;
71 
72 #define _CORECRT_APPLY_TO_MAPPINGS(_APPLY)                                                                                                       \
73     _APPLY(capture_argv,                       __acrt_capture_narrow_argv,                       __acrt_capture_wide_argv                      ) \
74     _APPLY(create_process,                     __acrt_CreateProcessA,                            CreateProcessW                                ) \
75     _APPLY(find_first_file_ex,                 __acrt_FindFirstFileExA,                          FindFirstFileExW                              ) \
76     _APPLY(find_next_file,                     __acrt_FindNextFileA,                             FindNextFileW                                 ) \
77     _APPLY(free_environment_strings,           FreeEnvironmentStringsA,                          FreeEnvironmentStringsW                       ) \
78     _APPLY(ftprintf,                           fprintf,                                          fwprintf                                      ) \
79     _APPLY(get_current_directory,              __acrt_get_current_directory_narrow_acp_or_utf8,  __acrt_get_current_directory_wide             ) \
80     _APPLY(get_environment_from_os,            __dcrt_get_narrow_environment_from_os,            __dcrt_get_wide_environment_from_os           ) \
81     _APPLY(get_full_path_name,                 __acrt_get_full_path_name_narrow_acp_or_utf8,     __acrt_get_full_path_name_wide                ) \
82     _APPLY(get_module_file_name,               __acrt_GetModuleFileNameA,                        GetModuleFileNameW                            ) \
83     _APPLY(get_or_create_environment_nolock,   __dcrt_get_or_create_narrow_environment_nolock,   __dcrt_get_or_create_wide_environment_nolock  ) \
84     _APPLY(get_temp_path,                      __acrt_GetTempPath2A,                             __acrt_GetTempPath2W                           ) \
85     _APPLY(getc_nolock,                        _getc_nolock,                                     _getwc_nolock                                 ) \
86     _APPLY(gettche_nolock,                     _getche_nolock,                                   _getwche_nolock                               ) \
87     _APPLY(initialize_environment_nolock,      _initialize_narrow_environment,                   _initialize_wide_environment                  ) \
88     _APPLY(istspace,                           isspace,                                          iswspace                                      ) \
89     _APPLY(itot_s,                             _itoa_s,                                          _itow_s                                       ) \
90     _APPLY(message_box,                        __acrt_MessageBoxA,                               __acrt_MessageBoxW                            ) \
91     _APPLY(open_file,                          _openfile,                                        _wopenfile                                    ) \
92     _APPLY(output_debug_string,                __acrt_OutputDebugStringA,                        OutputDebugStringW                            ) \
93     _APPLY(pack_command_line_and_environment,  __acrt_pack_narrow_command_line_and_environment,  __acrt_pack_wide_command_line_and_environment ) \
94     _APPLY(puttc_nolock_internal,              _fputc_nolock_internal,                           _fputwc_nolock_internal                       ) \
95     _APPLY(puttch_nolock_internal,             _putch_nolock_internal,                           _putwch_nolock_internal                       ) \
96     _APPLY(set_current_directory,              __acrt_SetCurrentDirectoryA,                      SetCurrentDirectoryW                          ) \
97     _APPLY(set_environment_variable,           __acrt_SetEnvironmentVariableA,                   SetEnvironmentVariableW                       ) \
98     _APPLY(set_program_name,                   _set_pgmptr,                                      _set_wpgmptr                                  ) \
99     _APPLY(set_variable_in_environment_nolock, __dcrt_set_variable_in_narrow_environment_nolock, __dcrt_set_variable_in_wide_environment_nolock) \
100     _APPLY(show_message_box,                   __acrt_show_narrow_message_box,                   __acrt_show_wide_message_box                  ) \
101     _APPLY(sntprintf_s,                        _snprintf_s,                                      _snwprintf_s                                  ) \
102     _APPLY(taccess_s,                          _access_s,                                        _waccess_s                                    ) \
103     _APPLY(tasctime,                           asctime,                                          _wasctime                                     ) \
104     _APPLY(tasctime_s,                         asctime_s,                                        _wasctime_s                                   ) \
105     _APPLY(tcscat_s,                           strcat_s,                                         wcscat_s                                      ) \
106     _APPLY(tcschr,                             strchr,                                           wcschr                                        ) \
107     _APPLY(tcscmp,                             strcmp,                                           wcscmp                                        ) \
108     _APPLY(tcscpy_s,                           strcpy_s,                                         wcscpy_s                                      ) \
109     _APPLY(tcserror_s,                         strerror_s,                                       _wcserror_s                                   ) \
110     _APPLY(tcsicmp,                            _stricmp,                                         _wcsicmp                                      ) \
111     _APPLY(tcslen,                             strlen,                                           wcslen                                        ) \
112     _APPLY(tcsnlen_s,                          strnlen_s,                                        wcsnlen_s                                     ) \
113     _APPLY(tcsncat_s,                          strncat_s,                                        wcsncat_s                                     ) \
114     _APPLY(tcsncmp,                            strncmp,                                          wcsncmp                                       ) \
115     _APPLY(tcsncpy_s,                          strncpy_s,                                        wcsncpy_s                                     ) \
116     _APPLY(tcsnicmp,                           _strnicmp,                                        _wcsnicmp                                     ) \
117     _APPLY(tcsnicoll,                          _strnicoll,                                       _wcsnicoll                                    ) \
118     _APPLY(tcsnlen,                            strnlen,                                          wcsnlen                                       ) \
119     _APPLY(tcspbrk,                            strpbrk,                                          wcspbrk                                       ) \
120     _APPLY(tcsrchr,                            strrchr,                                          wcsrchr                                       ) \
121     _APPLY(tcstoull,                           strtoull,                                         wcstoull                                      ) \
122     _APPLY(tdupenv_s_crt,                      _dupenv_s,                                        _wdupenv_s                                    ) \
123     _APPLY(texecve,                            _execve,                                          _wexecve                                      ) \
124     _APPLY(tfdopen,                            _fdopen,                                          _wfdopen                                      ) \
125     _APPLY(tfullpath,                          _fullpath,                                        _wfullpath                                    ) \
126     _APPLY(tgetcwd,                            _getcwd,                                          _wgetcwd                                      ) \
127     _APPLY(tgetpath,                           __acrt_getpath,                                   __acrt_wgetpath                               ) \
128     _APPLY(tmktemp_s,                          _mktemp_s,                                        _wmktemp_s                                    ) \
129     _APPLY(tsopen_nolock,                      _sopen_nolock,                                    _wsopen_nolock                                ) \
130     _APPLY(tsopen_s,                           _sopen_s,                                         _wsopen_s                                     ) \
131     _APPLY(tspawnve,                           _spawnve,                                         _wspawnve                                     ) \
132     _APPLY(tspawnvpe,                          _spawnvpe,                                        _wspawnvpe                                    ) \
133     _APPLY(ulltot_s,                           _ui64toa_s,                                       _ui64tow_s                                    ) \
134     _APPLY(ultot_s,                            _ultoa_s,                                         _ultow_s                                      ) \
135     _APPLY(ungettc_nolock,                     _ungetc_nolock,                                   _ungetwc_nolock                               ) \
136     _APPLY(ungettch_nolock,                    _ungetch_nolock,                                  _ungetwch_nolock                              )
137 
138 template <>
139 struct __crt_char_traits<char>
140 {
141     typedef char           char_type;
142     typedef unsigned char  unsigned_char_type;
143     typedef wchar_t        other_char_type;
144     typedef int            int_type;
145     typedef STARTUPINFOA   startup_info_type;
146     typedef WIN32_FIND_DATAA win32_find_data_type;
147 
148     #define _APPLY(name, narrow_name, wide_name) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, narrow_name)
149     _CORECRT_APPLY_TO_MAPPINGS(_APPLY)
150     #undef _APPLY
151 };
152 
153 template <>
154 struct __crt_char_traits<wchar_t>
155 {
156     typedef wchar_t        char_type;
157     typedef wchar_t        unsigned_char_type;
158     typedef char           other_char_type;
159     typedef wint_t         int_type;
160     typedef STARTUPINFOW   startup_info_type;
161     typedef WIN32_FIND_DATAW win32_find_data_type;
162 
163     #define _APPLY(name, narrow_name, wide_name) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, wide_name)
164     _CORECRT_APPLY_TO_MAPPINGS(_APPLY)
165     #undef _APPLY
166 };
167 
168 #undef _CORECRT_APPLY_TO_MAPPINGS
169 
170 
171 
172 #define _GENERATE_TCHAR_STRING_FUNCTIONS(name, string)                                                        \
173     static char    const* __cdecl _CRT_CONCATENATE(get_, name)(char)    throw() { return string; }            \
174     static wchar_t const* __cdecl _CRT_CONCATENATE(get_, name)(wchar_t) throw() { return _CRT_WIDE(string); } \
175     static size_t const _CRT_CONCATENATE(name, _length) = _countof(string) - 1;                               \
176     static size_t const _CRT_CONCATENATE(name, _count ) = _countof(string);
177 
178 
179 
180 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181 //
182 // Integer Traits
183 //
184 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185 template <typename Integer>
186 struct __crt_integer_traits;
187 
188 #define _CORECRT_APPLY_TO_MAPPINGS(_APPLY)                  \
189     _APPLY(ftell_nolock, _ftell_nolock,   _ftelli64_nolock) \
190     _APPLY(lseek,        _lseek,          _lseeki64       ) \
191     _APPLY(lseek_nolock, _lseek_nolock,   _lseeki64_nolock) \
192     _APPLY(futime,       _futime32,       _futime64       ) \
193     _APPLY(gmtime_s,     _gmtime32_s,     _gmtime64_s     ) \
194     _APPLY(localtime_s,  _localtime32_s,  _localtime64_s  ) \
195     _APPLY(loctotime,    __loctotime32_t, __loctotime64_t ) \
196     _APPLY(time,         _time32,         _time64         )
197 
198 template <>
199 struct __crt_integer_traits<long>
200 {
201     #define _APPLY(name, name_32, name_64) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, name_32)
202     _CORECRT_APPLY_TO_MAPPINGS(_APPLY)
203     #undef _APPLY
204 };
205 
206 template <>
207 struct __crt_integer_traits<long long>
208 {
209     #define _APPLY(name, name_32, name_64) _CORECRT_GENERATE_FORWARDER(static, __cdecl, name, name_64)
210     _CORECRT_APPLY_TO_MAPPINGS(_APPLY)
211     #undef _APPLY
212 };
213 
214 #undef _CORECRT_APPLY_TO_MAPPINGS
215 
216 
217 
218 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219 //
220 // char <=> wchar_t conversion utilities
221 //
222 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
223 // Complete list of internal conversion functions (only some defined here):
224 // * __acrt_WideCharToMultiByte / __acrt_MultiByteToWideChar
225 //     * Provides option compatibility to ensure we don't get ERROR_INVALID_FLAGS due to code page changes.
226 //     * Other functions in this list use this to be implemented.
227 // * wcstombs / mbstowcs
228 //     * Public conversion functions, also used internally.
229 //     * Should try to use _l variants when possible to avoid overhead of grabbing per-thread data.
230 // * __acrt_mbs_to_wcs / __acrt_wcs_to_mbs
231 //     * Should be used by default - uses wcstombs / mbstowcs.
232 //     * Provides automatic space allocation with __crt_win32_buffer.
233 // * __acrt_mbs_to_wcs_cp / __acrt_wcs_to_mbs_cp
234 //     * Should be used by default, using code page instead of _locale_t.
235 //     * Less optimizations - can't detect "C" locale for quick conversion.
236 //     * Provides automatic space allocation with __crt_win32_buffer.
237 //     * Uses __acrt_WideChartoMultiByte / __acrt_MultiByteToWideChar.
238 // * __crt_compute_required_transform_buffer_count / __crt_transform_string
239 //     * Used by environment initialization.
240 //     * Only one (narrow or wide) environment may be available from the OS,
241 //       the other needs to be cloned into the other.
242 //
243 // Places where we don't use current global locale, user-supplied locale, or ACP/UTF-8 adapter:
244 // CP_ACP - __acrt_GetTempPath2A (via tmpnam)
245 //     * Documented to do so on MSDN.
246 //     * Required by API design - static buffer returned to user
247 //     * Therefore, characters cannot be modified according to locale.
248 // CP_ACP - Environment Initialization
249 //     * This is done at startup and does not change based off of locale, so using the ACP is correct.
250 // GetConsoleOutputCP() - write_double_translated_ansi_nolock (via _write)
251 // GetConsoleCP() - _getch
252 // CP_UTF8 - write_text_utf8_nolock (via _write)
253 //
254 // The following functions previous to UTF-8 awareness used the ACP for char conversions.
255 // To avoid backwards compatibility issues, they will still use the ACP, except when the currently
256 // set locale is CP_UTF8.
257 // * _access
258 // * _chdir
259 // * _chmod
260 // * _exec*
261 // * _findfile*
262 // * _fullpath
263 // * _loaddll
264 // * _mkdir
265 // * _popen
266 // * _remove
267 // * _rename
268 // * _rmdir
269 // * _sopen
270 // * _spawn*
271 // * _stat*
272 // * _unlink
273 // * Wildcard parsing in argv with setargv.obj
274 // * Calls to get the current module name for debug pop-up windows and assert messages (via __acrt_GetModuleFileNameA)
275 // * Setting _tzname when value provided via TZ environment variable.
276 //
277 
278 inline size_t __crt_compute_required_transform_buffer_count(
279             unsigned    const code_page,
280     _In_z_  char const* const string
281     )
282 {
283     return static_cast<size_t>(__acrt_MultiByteToWideChar(code_page, 0, string, -1, nullptr, 0));
284 }
285 
286 inline size_t __crt_compute_required_transform_buffer_count(
287             unsigned        const code_page,
288     _In_z_  wchar_t const*  const string
289     )
290 {
291     return static_cast<size_t>(__acrt_WideCharToMultiByte(code_page, 0, string, -1, nullptr, 0, nullptr, nullptr));
292 }
293 
294 _Success_(return > 0 && return <= buffer_count)
295 inline size_t __crt_transform_string(
296                                     unsigned    const   code_page,
297     _In_z_                          char const* const   string,
298     _Out_writes_z_(buffer_count)    wchar_t*    const   buffer,
299     size_t      const buffer_count
300     )
301 {
302     int const int_count = static_cast<int>(buffer_count);
303     return static_cast<size_t>(__acrt_MultiByteToWideChar(code_page, 0, string, -1, buffer, int_count));
304 }
305 
306 _Success_(return > 0 && return <= buffer_count)
307 inline size_t __crt_transform_string(
308                                     unsigned        const   code_page,
309     _In_z_                          wchar_t const*  const   string,
310     _Out_writes_z_(buffer_count)    char*           const   buffer,
311     size_t                                          const   buffer_count
312     )
313 {
314     int const int_count = static_cast<int>(buffer_count);
315     return static_cast<size_t>(__acrt_WideCharToMultiByte(code_page, 0, string, -1, buffer, int_count, nullptr, nullptr));
316 }
317 
318 #pragma pack(pop)
319