/********************************************************************* * _gmtime64 (MSVCRT.@) */ struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs) { thread_data_t * const data = msvcrt_get_thread_data(); if(MSVCRT__gmtime64_s(&data->time_buffer, secs)) return NULL; return &data->time_buffer; }
/****************************************************************** * ?set_terminate@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) * * Install a handler to be called when terminate() is called. * * PARAMS * func [I] Handler function to install * * RETURNS * The previously installed handler function, if any. */ MSVCRT_terminate_function CDECL MSVCRT_set_terminate(MSVCRT_terminate_function func) { thread_data_t *data = msvcrt_get_thread_data(); MSVCRT_terminate_function previous = data->terminate_handler; TRACE("(%p) returning %p\n",func,previous); data->terminate_handler = func; return previous; }
/****************************************************************** * ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z (MSVCRT.@) */ MSVCRT__se_translator_function CDECL MSVCRT__set_se_translator(MSVCRT__se_translator_function func) { thread_data_t *data = msvcrt_get_thread_data(); MSVCRT__se_translator_function previous = data->se_translator; TRACE("(%p) returning %p\n",func,previous); data->se_translator = func; return previous; }
/****************************************************************** * ?set_unexpected@@YAP6AXXZP6AXXZ@Z (MSVCRT.@) * * Install a handler to be called when unexpected() is called. * * PARAMS * func [I] Handler function to install * * RETURNS * The previously installed handler function, if any. */ MSVCRT_unexpected_function CDECL MSVCRT_set_unexpected(MSVCRT_unexpected_function func) { thread_data_t *data = msvcrt_get_thread_data(); MSVCRT_unexpected_function previous = data->unexpected_handler; TRACE("(%p) returning %p\n",func,previous); data->unexpected_handler = func; return previous; }
/********************************************************************* * rand (MSVCRT.@) */ int CDECL MSVCRT_rand(void) { thread_data_t *data = msvcrt_get_thread_data(); /* this is the algorithm used by MSVC, according to * http://en.wikipedia.org/wiki/List_of_pseudorandom_number_generators */ data->random_seed = data->random_seed * 214013 + 2531011; return (data->random_seed >> 16) & MSVCRT_RAND_MAX; }
/********************************************************************* * _wcserror (MSVCRT.@) */ MSVCRT_wchar_t* CDECL MSVCRT__wcserror(int err) { thread_data_t *data = msvcrt_get_thread_data(); if (!data->wcserror_buffer) if (!(data->wcserror_buffer = MSVCRT_malloc(256 * sizeof(MSVCRT_wchar_t)))) return NULL; MSVCRT__wcserror_s(data->wcserror_buffer, 256, err); return data->wcserror_buffer; }
/********************************************************************* * __CxxDetectRethrow (MSVCRT.@) */ BOOL CDECL __CxxDetectRethrow(PEXCEPTION_POINTERS ptrs) { PEXCEPTION_RECORD rec; if (!ptrs) return FALSE; rec = ptrs->ExceptionRecord; if (rec->ExceptionCode == CXX_EXCEPTION && rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC_VC6 && rec->ExceptionInformation[2]) { ptrs->ExceptionRecord = msvcrt_get_thread_data()->exc_record; return TRUE; } return (msvcrt_get_thread_data()->exc_record == rec); }
/********************************************************************* * _set_thread_local_invalid_parameter_handler (UCRTBASE.@) */ MSVCRT_invalid_parameter_handler CDECL _set_thread_local_invalid_parameter_handler( MSVCRT_invalid_parameter_handler handler) { thread_data_t *data = msvcrt_get_thread_data(); MSVCRT_invalid_parameter_handler old = data->invalid_parameter_handler; TRACE("(%p)\n", handler); data->invalid_parameter_handler = handler; return old; }
/********************************************************************* * _CreateFrameInfo (MSVCR80.@) */ frame_info* CDECL _CreateFrameInfo(frame_info *fi, void *obj) { thread_data_t *data = msvcrt_get_thread_data(); TRACE("(%p, %p)\n", fi, obj); fi->next = data->frame_info_head; data->frame_info_head = fi; fi->object = obj; return fi; }
/********************************************************************* * strerror (MSVCRT.@) */ char* CDECL MSVCRT_strerror(int err) { thread_data_t *data = msvcrt_get_thread_data(); if (!data->strerror_buffer) if (!(data->strerror_buffer = MSVCRT_malloc(256))) return NULL; if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; strcpy( data->strerror_buffer, MSVCRT__sys_errlist[err] ); return data->strerror_buffer; }
/********************************************************************** * __wcserror (MSVCRT.@) */ MSVCRT_wchar_t* CDECL MSVCRT___wcserror(const MSVCRT_wchar_t* str) { thread_data_t *data = msvcrt_get_thread_data(); int err; if (!data->wcserror_buffer) if (!(data->wcserror_buffer = MSVCRT_malloc(256 * sizeof(MSVCRT_wchar_t)))) return NULL; err = MSVCRT___wcserror_s(data->wcserror_buffer, 256, str); if (err) FIXME("bad wcserror call (%d)\n", err); return data->wcserror_buffer; }
/********************************************************************* * _beginthread_trampoline */ static DWORD CALLBACK _beginthread_trampoline(LPVOID arg) { _beginthread_trampoline_t local_trampoline; thread_data_t *data = msvcrt_get_thread_data(); memcpy(&local_trampoline,arg,sizeof(local_trampoline)); data->handle = local_trampoline.thread; MSVCRT_free(arg); local_trampoline.start_address(local_trampoline.arglist); _endthread(); return 0; }
/********************************************************************* * _IsExceptionObjectToBeDestroyed (MSVCR80.@) */ BOOL __cdecl _IsExceptionObjectToBeDestroyed(const void *obj) { frame_info *cur; TRACE( "%p\n", obj ); for (cur = msvcrt_get_thread_data()->frame_info_head; cur; cur = cur->next) { if (cur->object == obj) return FALSE; } return TRUE; }
/********************************************************************* * __CxxUnregisterExceptionObject (MSVCRT.@) */ void CDECL __CxxUnregisterExceptionObject(cxx_frame_info *frame_info, BOOL in_use) { thread_data_t *data = msvcrt_get_thread_data(); TRACE("(%p)\n", frame_info); if(frame_info->rec == (void*)-1) return; _FindAndUnlinkFrame(&frame_info->frame_info); if(data->exc_record->ExceptionCode == CXX_EXCEPTION && !in_use && _IsExceptionObjectToBeDestroyed((void*)data->exc_record->ExceptionInformation[1])) __DestructExceptionObject(data->exc_record); data->exc_record = frame_info->rec; }
/********************************************************************* * strtok (MSVCRT.@) */ char * CDECL MSVCRT_strtok( char *str, const char *delim ) { thread_data_t *data = msvcrt_get_thread_data(); char *ret; if (!str) if (!(str = data->strtok_next)) return NULL; while (*str && strchr( delim, *str )) str++; if (!*str) return NULL; ret = str++; while (*str && !strchr( delim, *str )) str++; if (*str) *str++ = 0; data->strtok_next = str; return ret; }
/****************************************************************************** * \name _gmtime64 * \brief * \param ptime Pointer to a variable of type __time64_t containing the time. */ struct tm * _gmtime64(const __time64_t * ptime) { thread_data_t *data = msvcrt_get_thread_data(); /* Validate parameters */ if (!ptime || *ptime < 0) { return NULL; } if(!data->time_buffer) data->time_buffer = malloc(sizeof(struct tm)); /* Use _gmtime_worker to do the real work */ return _gmtime_worker(data->time_buffer, *ptime, 0); }
/********************************************************************** * _strerror (MSVCRT.@) */ char* CDECL _strerror(const char* str) { thread_data_t *data = msvcrt_get_thread_data(); int err; if (!data->strerror_buffer) if (!(data->strerror_buffer = MSVCRT_malloc(256))) return NULL; err = data->thread_errno; if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; if (str && *str) sprintf( data->strerror_buffer, "%s: %s\n", str, MSVCRT__sys_errlist[err] ); else sprintf( data->strerror_buffer, "%s\n", MSVCRT__sys_errlist[err] ); return data->strerror_buffer; }
/********************************************************************* * _wasctime (MSVCRT.@) */ MSVCRT_wchar_t * CDECL MSVCRT__wasctime(const struct MSVCRT_tm *mstm) { thread_data_t *data = msvcrt_get_thread_data(); struct tm tm; char buffer[30]; msvcrt_tm_to_unix( &tm, mstm ); if (!data->wasctime_buffer) data->wasctime_buffer = MSVCRT_malloc( 30*sizeof(MSVCRT_wchar_t) ); /* ought to be enough */ #ifdef HAVE_ASCTIME_R asctime_r( &tm, buffer ); #else strcpy( buffer, asctime(&tm) ); #endif MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, data->wasctime_buffer, 30 ); return data->wasctime_buffer; }
/********************************************************************* * __CxxRegisterExceptionObject (MSVCRT.@) */ BOOL CDECL __CxxRegisterExceptionObject(EXCEPTION_RECORD **rec, cxx_frame_info *frame_info) { thread_data_t *data = msvcrt_get_thread_data(); TRACE("(%p, %p)\n", rec, frame_info); if (!rec || !*rec) { frame_info->rec = (void*)-1; frame_info->unk = (void*)-1; return TRUE; } frame_info->rec = data->exc_record; frame_info->unk = 0; data->exc_record = *rec; _CreateFrameInfo(&frame_info->frame_info, (void*)(*rec)->ExceptionInformation[1]); return TRUE; }
/****************************************************************************** * \name _tasctime * \brief Converts a UTC time into a string and returns a pointer to it. * \param ptm Pointer to the UTC time. * \remarks The string is stored in thread local buffer, shared between * ctime, gmtime and localtime (32 and 64 bit versions). */ _TCHAR * _tasctime(const struct tm *ptm) { thread_data_t *data = msvcrt_get_thread_data(); _TCHAR *pstr; #ifndef _UNICODE pstr = data->asctime_buffer; #else pstr = data->wasctime_buffer; #endif if(!pstr) pstr = malloc(sizeof(struct tm)); /* Fill the buffer */ FillBuf((timebuf_t*)pstr, ptm); return pstr; }
/********************************************************************* * _localtime64 (MSVCRT.@) */ struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs) { struct tm *tm; thread_data_t *data; time_t seconds = *secs; if (seconds < 0) return NULL; _mlock(_TIME_LOCK); if (!(tm = localtime( &seconds))) { _munlock(_TIME_LOCK); return NULL; } data = msvcrt_get_thread_data(); unix_tm_to_msvcrt( &data->time_buffer, tm ); _munlock(_TIME_LOCK); return &data->time_buffer; }
/****************************************************************************** * _invalid_parameter (MSVCRT.@) */ void __cdecl MSVCRT__invalid_parameter(const MSVCRT_wchar_t *expr, const MSVCRT_wchar_t *func, const MSVCRT_wchar_t *file, unsigned int line, MSVCRT_uintptr_t arg) { #if _MSVCR_VER >= 140 thread_data_t *data = msvcrt_get_thread_data(); if (data->invalid_parameter_handler) { data->invalid_parameter_handler( expr, func, file, line, arg ); return; } #endif if (invalid_parameter_handler) invalid_parameter_handler( expr, func, file, line, arg ); else { ERR( "%s:%u %s: %s %lx\n", debugstr_w(file), line, debugstr_w(func), debugstr_w(expr), arg ); #if _MSVCR_VER >= 80 RaiseException( STATUS_INVALID_CRUNTIME_PARAMETER, EXCEPTION_NONCONTINUABLE, 0, NULL ); #endif } }
/********************************************************************* * asctime (MSVCRT.@) */ char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm) { char bufferA[30]; WCHAR bufferW[30]; thread_data_t *data = msvcrt_get_thread_data(); struct tm tm; msvcrt_tm_to_unix( &tm, mstm ); if (!data->asctime_buffer) data->asctime_buffer = MSVCRT_malloc( 30 ); /* ought to be enough */ #ifdef HAVE_ASCTIME_R asctime_r( &tm, bufferA ); #else strcpy( bufferA, asctime(&tm) ); #endif MultiByteToWideChar( CP_UNIXCP, 0, bufferA, -1, bufferW, 30 ); WideCharToMultiByte( CP_ACP, 0, bufferW, -1, data->asctime_buffer, 30, NULL, NULL ); return data->asctime_buffer; }
/********************************************************************* * _FindAndUnlinkFrame (MSVCR80.@) */ void CDECL _FindAndUnlinkFrame(frame_info *fi) { thread_data_t *data = msvcrt_get_thread_data(); frame_info *cur = data->frame_info_head; TRACE("(%p)\n", fi); if (cur == fi) { data->frame_info_head = cur->next; return; } for (; cur->next; cur = cur->next) { if (cur->next == fi) { cur->next = fi->next; return; } } ERR("frame not found, native crashes in this case\n"); }
/********************************************************************* * __doserrno (MSVCRT.@) */ MSVCRT_ulong* CDECL MSVCRT___doserrno(void) { return &msvcrt_get_thread_data()->thread_doserrno; }
/********************************************************************* * _errno (MSVCRT.@) */ int* CDECL MSVCRT__errno(void) { return &msvcrt_get_thread_data()->thread_errno; }
/********************************************************************* * srand (MSVCRT.@) */ void CDECL MSVCRT_srand( unsigned int seed ) { thread_data_t *data = msvcrt_get_thread_data(); data->random_seed = seed; }
/****************************************************************** * ?unexpected@@YAXXZ (MSVCRT.@) */ void CDECL MSVCRT_unexpected(void) { thread_data_t *data = msvcrt_get_thread_data(); if (data->unexpected_handler) data->unexpected_handler(); MSVCRT_terminate(); }
/****************************************************************** * ?terminate@@YAXXZ (MSVCRT.@) * * Default handler for an unhandled exception. * * PARAMS * None. * * RETURNS * This function does not return. Either control resumes from any * handler installed by calling set_terminate(), or (by default) abort() * is called. */ void CDECL MSVCRT_terminate(void) { thread_data_t *data = msvcrt_get_thread_data(); if (data->terminate_handler) data->terminate_handler(); MSVCRT_abort(); }
/****************************************************************** * _get_unexpected (MSVCRT.@) */ MSVCRT_unexpected_function CDECL MSVCRT__get_unexpected(void) { thread_data_t *data = msvcrt_get_thread_data(); TRACE("returning %p\n", data->unexpected_handler); return data->unexpected_handler; }