errno_t __cdecl _tctime64_s ( _TSCHAR * buffer, size_t sizeInChars, const __time64_t *timp ) { struct tm tmtemp; errno_t e; _VALIDATE_RETURN_ERRCODE( ( ( buffer != NULL ) && ( sizeInChars > 0 ) ), EINVAL ) _RESET_STRING(buffer, sizeInChars); _VALIDATE_RETURN_ERRCODE( ( timp != NULL ), EINVAL ) _VALIDATE_RETURN_ERRCODE_NOEXC( ( *timp >= 0 ), EINVAL ) _VALIDATE_RETURN_ERRCODE_NOEXC( ( *timp <= _MAX__TIME64_T ), EINVAL ) e = _localtime64_s(&tmtemp, timp); if ( e == 0 ) { e = _tasctime_s(buffer, sizeInChars, &tmtemp); } return e; }
static errno_t __cdecl common_freopen( FILE** const result, Character const* const file_name, Character const* const mode, __crt_stdio_stream const stream, int const share_flag ) throw() { typedef __acrt_stdio_char_traits<Character> stdio_traits; _VALIDATE_RETURN_ERRCODE(result != nullptr, EINVAL); *result = nullptr; // C11 7.21.5.4/3: "If filename is a null pointer, the freopen function // attempts to change the mode of the stream to that specified by mode, as // if the name of the file currently associated with the stream had been // used. It is implementation-defined which changes of mode are permitted // (if any), and under what circumstances." // // In our implementation, we do not currently support changing the mode // in this way. In the future, we might consider use of ReOpenFile to // implement support for changing the mode. _VALIDATE_RETURN_ERRCODE_NOEXC(file_name != nullptr, EBADF); _VALIDATE_RETURN_ERRCODE(mode != nullptr, EINVAL); _VALIDATE_RETURN_ERRCODE(stream.valid() , EINVAL); // Just as in the common_fsopen function, we do not hard-validate empty // 'file_name' strings in this function: _VALIDATE_RETURN_ERRCODE_NOEXC(*file_name != 0, EINVAL); errno_t return_value = 0; _lock_file(stream.public_stream()); __try { // If the stream is in use, try to close it, ignoring possible errors: if (stream.is_in_use()) _fclose_nolock(stream.public_stream()); stream->_ptr = nullptr; stream->_base = nullptr; stream->_cnt = 0; stream.unset_flags(-1); // We may have called fclose above, which will deallocate the stream. // We still hold the lock on the stream, though, so we can just reset // the allocated flag to retain ownership. stream.set_flags(_IOALLOCATED); *result = stdio_traits::open_file(file_name, mode, share_flag, stream.public_stream()); if (*result == nullptr) { stream.unset_flags(_IOALLOCATED); return_value = errno; } } __finally { _unlock_file(stream.public_stream()); } return return_value; }
static errno_t __cdecl common_localtime_s( tm* const ptm, TimeType const* const ptime ) throw() { typedef __crt_time_time_t_traits<TimeType> time_traits; _VALIDATE_RETURN_ERRCODE(ptm != nullptr, EINVAL); memset(ptm, 0xff, sizeof(tm)); _VALIDATE_RETURN_ERRCODE(ptime != nullptr, EINVAL); // Check for illegal time_t value: _VALIDATE_RETURN_ERRCODE_NOEXC(*ptime >= 0, EINVAL); _VALIDATE_RETURN_ERRCODE_NOEXC(*ptime <= time_traits::max_time_t, EINVAL); __tzset(); int daylight = 0; long dstbias = 0; long timezone = 0; _ERRCHECK(_get_daylight(&daylight)); _ERRCHECK(_get_dstbias (&dstbias )); _ERRCHECK(_get_timezone(&timezone)); if (*ptime > 3 * _DAY_SEC && *ptime < time_traits::max_time_t - 3 * _DAY_SEC) { // The date does not fall within the first three or last three representable // days; therefore, there is no possibility of overflowing or underflowing // the time_t representation as we compensate for time zone and daylight // savings time. TimeType ltime = *ptime - timezone; errno_t status0 = time_traits::gmtime_s(ptm, <ime); if (status0 != 0) return status0; // Check and adjust for daylight savings time: if (daylight && _isindst(ptm)) { ltime -= dstbias; errno_t const status1 = time_traits::gmtime_s(ptm, <ime); if (status1 != 0) return status1; ptm->tm_isdst = 1; } } else { // The date falls within the first three or last three representable days; // therefore, it is possible that the time_t representation would overflow // or underflow while compensating for time zone and daylight savings time. // Therefore, we make the time zone and daylight savings time adjustments // directly in the tm structure. errno_t const status0 = time_traits::gmtime_s(ptm, ptime); if (status0 != 0) return status0; TimeType ltime = static_cast<TimeType>(ptm->tm_sec); // First, adjust for the time zone: if (daylight && _isindst(ptm)) { ltime -= (timezone + dstbias); ptm->tm_isdst = 1; } else { ltime -= timezone; } ptm->tm_sec = static_cast<int>(ltime % 60); if (ptm->tm_sec < 0) { ptm->tm_sec += 60; ltime -= 60; } ltime = static_cast<TimeType>(ptm->tm_min) + ltime / 60; ptm->tm_min = static_cast<int>(ltime % 60); if (ptm->tm_min < 0) { ptm->tm_min += 60; ltime -= 60; } ltime = static_cast<TimeType>(ptm->tm_hour) + ltime / 60; ptm->tm_hour = static_cast<int>(ltime % 24); if (ptm->tm_hour < 0) { ptm->tm_hour += 24; ltime -=24; } ltime /= 24; if (ltime > 0) { // There is no possibility of overflowing the tm_day and tm_yday // members because the date can be no later than January 19. ptm->tm_wday = (ptm->tm_wday + static_cast<int>(ltime)) % 7; ptm->tm_mday += static_cast<int>(ltime); ptm->tm_yday += static_cast<int>(ltime); } else if (ltime < 0) { // It is possible to underflow the tm_mday and tm_yday fields. If // this happens, then the adjusted date must lie in December 1969: ptm->tm_wday = (ptm->tm_wday + 7 + static_cast<int>(ltime)) % 7; ptm->tm_mday += static_cast<int>(ltime); if (ptm->tm_mday <= 0) { ptm->tm_mday += 31; // Per assumption #4 above, the time zone can cause the date to // underflow the epoch by more than a day. ptm->tm_yday = ptm->tm_yday + static_cast<int>(ltime) + 365; ptm->tm_mon = 11; ptm->tm_year--; } else { ptm->tm_yday += static_cast<int>(ltime); } } } return 0; }
static errno_t __cdecl common_configure_argv(_crt_argv_mode const mode) throw() { typedef __crt_char_traits<Character> traits; _VALIDATE_RETURN_ERRCODE( mode == _crt_argv_expanded_arguments || mode == _crt_argv_unexpanded_arguments, EINVAL); do_locale_initialization(Character()); static Character program_name[MAX_PATH + 1]; traits::get_module_file_name(nullptr, program_name, MAX_PATH); traits::set_program_name(&program_name[0]); // If there's no command line at all, then use the program name as the // command line to parse, so that argv[0] is initialized with the program // name. (This won't happen when the program is run by cmd.exe, but it // could happen if the program is spawned via some other means.) Character* const raw_command_line = get_command_line(Character()); Character* const command_line = raw_command_line == nullptr || raw_command_line[0] == '\0' ? program_name : raw_command_line; size_t argument_count = 0; size_t character_count = 0; parse_command_line( command_line, static_cast<Character**>(nullptr), static_cast<Character*>(nullptr), &argument_count, &character_count); __crt_unique_heap_ptr<unsigned char> buffer(__acrt_allocate_buffer_for_argv( argument_count, character_count, sizeof(Character))); _VALIDATE_RETURN_ERRCODE_NOEXC(buffer, ENOMEM); Character** const first_argument = reinterpret_cast<Character**>(buffer.get()); Character* const first_string = reinterpret_cast<Character*>(buffer.get() + argument_count * sizeof(Character*)); parse_command_line(command_line, first_argument, first_string, &argument_count, &character_count); // If we are not expanding wildcards, then we are done... if (mode == _crt_argv_unexpanded_arguments) { __argc = static_cast<int>(argument_count - 1); get_argv(Character()) = reinterpret_cast<Character**>(buffer.detach()); return 0; } // ... otherwise, we try to do the wildcard expansion: __crt_unique_heap_ptr<Character*> expanded_argv; errno_t const argv_expansion_status = expand_argv_wildcards(first_argument, expanded_argv.get_address_of()); if (argv_expansion_status != 0) return argv_expansion_status; __argc = [&]() { size_t n = 0; for (auto it = expanded_argv.get(); *it; ++it, ++n) { } return static_cast<int>(n); }(); get_argv(Character()) = expanded_argv.detach(); return 0; }