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