mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[MSVCRT] Import msvcrt from wine-10.0
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2020 Piotr Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __WINE_BNUM_H
|
||||
#define __WINE_BNUM_H
|
||||
|
||||
#define EXP_BITS 11
|
||||
#define MANT_BITS 53
|
||||
|
||||
static const int p10s[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
|
||||
#define LIMB_DIGITS 9 /* each DWORD stores up to 9 digits */
|
||||
#define LIMB_MAX 1000000000 /* 10^9 */
|
||||
|
||||
#define BNUM_PREC64 128 /* data size needed to store 64-bit double */
|
||||
#define BNUM_PREC80 2048 /* data size needed to store 80-bit double */
|
||||
|
||||
/* bnum represents real number with fixed decimal point */
|
||||
struct bnum {
|
||||
int b; /* least significant digit position */
|
||||
int e; /* most significant digit position + 1 */
|
||||
int size; /* data buffer size in DWORDS (power of 2) */
|
||||
DWORD data[1]; /* circular buffer, base 10 number */
|
||||
};
|
||||
|
||||
static inline int bnum_idx(struct bnum *b, int idx)
|
||||
{
|
||||
return idx & (b->size - 1);
|
||||
}
|
||||
|
||||
/* Returns TRUE if new most significant limb was added */
|
||||
static inline BOOL bnum_lshift(struct bnum *b, int shift)
|
||||
{
|
||||
DWORD rest = 0;
|
||||
ULONGLONG tmp;
|
||||
int i;
|
||||
|
||||
/* The limbs number can change by up to 1 so shift <= 29 */
|
||||
assert(shift <= 29);
|
||||
|
||||
for(i=b->b; i<b->e; i++) {
|
||||
tmp = ((ULONGLONG)b->data[bnum_idx(b, i)] << shift) + rest;
|
||||
rest = tmp / LIMB_MAX;
|
||||
b->data[bnum_idx(b, i)] = tmp % LIMB_MAX;
|
||||
|
||||
if(i == b->b && !b->data[bnum_idx(b, i)])
|
||||
b->b++;
|
||||
}
|
||||
|
||||
if(rest) {
|
||||
b->data[bnum_idx(b, b->e)] = rest;
|
||||
b->e++;
|
||||
|
||||
if(bnum_idx(b, b->b) == bnum_idx(b, b->e)) {
|
||||
if(b->data[bnum_idx(b, b->b)]) b->data[bnum_idx(b, b->b+1)] |= 1;
|
||||
b->b++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Returns TRUE if most significant limb was removed */
|
||||
static inline BOOL bnum_rshift(struct bnum *b, int shift)
|
||||
{
|
||||
DWORD tmp, rest = 0;
|
||||
BOOL ret = FALSE;
|
||||
int i;
|
||||
|
||||
/* Compute LIMB_MAX << shift without accuracy loss */
|
||||
assert(shift <= 9);
|
||||
|
||||
for(i=b->e-1; i>=b->b; i--) {
|
||||
tmp = b->data[bnum_idx(b, i)] & ((1<<shift)-1);
|
||||
b->data[bnum_idx(b, i)] = (b->data[bnum_idx(b, i)] >> shift) + rest;
|
||||
rest = (LIMB_MAX >> shift) * tmp;
|
||||
if(i==b->e-1 && !b->data[bnum_idx(b, i)]) {
|
||||
b->e--;
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(rest) {
|
||||
if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) {
|
||||
if(rest) b->data[bnum_idx(b, b->b)] |= 1;
|
||||
} else {
|
||||
b->b--;
|
||||
b->data[bnum_idx(b, b->b)] = rest;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void bnum_mult(struct bnum *b, int mult)
|
||||
{
|
||||
DWORD rest = 0;
|
||||
ULONGLONG tmp;
|
||||
int i;
|
||||
|
||||
assert(mult <= LIMB_MAX);
|
||||
|
||||
for(i=b->b; i<b->e; i++) {
|
||||
tmp = ((ULONGLONG)b->data[bnum_idx(b, i)] * mult) + rest;
|
||||
rest = tmp / LIMB_MAX;
|
||||
b->data[bnum_idx(b, i)] = tmp % LIMB_MAX;
|
||||
|
||||
if(i == b->b && !b->data[bnum_idx(b, i)])
|
||||
b->b++;
|
||||
}
|
||||
|
||||
if(rest) {
|
||||
b->data[bnum_idx(b, b->e)] = rest;
|
||||
b->e++;
|
||||
|
||||
if(bnum_idx(b, b->b) == bnum_idx(b, b->e)) {
|
||||
if(b->data[bnum_idx(b, b->b)]) b->data[bnum_idx(b, b->b+1)] |= 1;
|
||||
b->b++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __WINE_BNUM_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
* msvcrt.dll console functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* Note: init and free don't need MT locking since they are called at DLL
|
||||
* (de)attachment time, which is synchronised for us
|
||||
*/
|
||||
|
||||
#include "msvcrt.h"
|
||||
#include "winnls.h"
|
||||
#include "wincon.h"
|
||||
#include "mtdll.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* MT */
|
||||
#define LOCK_CONSOLE _lock(_CONIO_LOCK)
|
||||
#define UNLOCK_CONSOLE _unlock(_CONIO_LOCK)
|
||||
|
||||
static HANDLE MSVCRT_console_in;
|
||||
static HANDLE MSVCRT_console_out;
|
||||
static int __MSVCRT_console_buffer = EOF;
|
||||
static wchar_t __MSVCRT_console_buffer_w = WEOF;
|
||||
|
||||
/* INTERNAL: Initialise console handles, _CONIO_LOCK must be held */
|
||||
static HANDLE msvcrt_input_console(void)
|
||||
{
|
||||
if (!MSVCRT_console_in)
|
||||
{
|
||||
MSVCRT_console_in = CreateFileA("CONIN$", GENERIC_WRITE|GENERIC_READ,
|
||||
FILE_SHARE_WRITE|FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (MSVCRT_console_in == INVALID_HANDLE_VALUE)
|
||||
WARN("Input console handle initialization failed!\n");
|
||||
}
|
||||
return MSVCRT_console_in;
|
||||
}
|
||||
|
||||
static HANDLE msvcrt_output_console(void)
|
||||
{
|
||||
if (!MSVCRT_console_out)
|
||||
{
|
||||
MSVCRT_console_out = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (MSVCRT_console_out == INVALID_HANDLE_VALUE)
|
||||
WARN("Output console handle initialization failed!\n");
|
||||
}
|
||||
return MSVCRT_console_out;
|
||||
}
|
||||
|
||||
/* INTERNAL: Free console handles */
|
||||
void msvcrt_free_console(void)
|
||||
{
|
||||
TRACE(":Closing console handles\n");
|
||||
CloseHandle(MSVCRT_console_in);
|
||||
CloseHandle(MSVCRT_console_out);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cputs (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _cputs(const char* str)
|
||||
{
|
||||
DWORD count;
|
||||
int len, retval = -1;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
|
||||
len = strlen(str);
|
||||
|
||||
LOCK_CONSOLE;
|
||||
if (WriteConsoleA(msvcrt_output_console(), str, len, &count, NULL)
|
||||
&& count == len)
|
||||
retval = 0;
|
||||
UNLOCK_CONSOLE;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cputws (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _cputws(const wchar_t* str)
|
||||
{
|
||||
DWORD count;
|
||||
int len, retval = -1;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
|
||||
len = wcslen(str);
|
||||
|
||||
LOCK_CONSOLE;
|
||||
if (WriteConsoleW(msvcrt_output_console(), str, len, &count, NULL)
|
||||
&& count == len)
|
||||
retval = 0;
|
||||
UNLOCK_CONSOLE;
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define NORMAL_CHAR 0
|
||||
#define ALT_CHAR 1
|
||||
#define CTRL_CHAR 2
|
||||
#define SHIFT_CHAR 3
|
||||
|
||||
static const struct {unsigned short vk; unsigned char ch[4][2];} enh_map[] = {
|
||||
{0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
|
||||
{0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
|
||||
{0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
|
||||
{0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
|
||||
{0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
|
||||
{0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
|
||||
{0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
|
||||
{0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
|
||||
{0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
|
||||
{0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
|
||||
};
|
||||
|
||||
static BOOL handle_enhanced_keys(INPUT_RECORD *ir, unsigned char *ch1, unsigned char *ch2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(enh_map); i++)
|
||||
{
|
||||
if (ir->Event.KeyEvent.wVirtualScanCode == enh_map[i].vk)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
||||
idx = ALT_CHAR;
|
||||
else if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
|
||||
idx = CTRL_CHAR;
|
||||
else if (ir->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
||||
idx = SHIFT_CHAR;
|
||||
else
|
||||
idx = NORMAL_CHAR;
|
||||
|
||||
*ch1 = enh_map[i].ch[idx][0];
|
||||
*ch2 = enh_map[i].ch[idx][1];
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
WARN("Unmapped char keyState=%lx vk=%x\n",
|
||||
ir->Event.KeyEvent.dwControlKeyState, ir->Event.KeyEvent.wVirtualScanCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getch_nolock (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _getch_nolock(void)
|
||||
{
|
||||
int retval = EOF;
|
||||
|
||||
if (__MSVCRT_console_buffer != EOF)
|
||||
{
|
||||
retval = __MSVCRT_console_buffer;
|
||||
__MSVCRT_console_buffer = EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
DWORD count;
|
||||
DWORD mode = 0;
|
||||
|
||||
GetConsoleMode(msvcrt_input_console(), &mode);
|
||||
if(mode)
|
||||
SetConsoleMode(msvcrt_input_console(), 0);
|
||||
|
||||
do {
|
||||
if (ReadConsoleInputA(msvcrt_input_console(), &ir, 1, &count))
|
||||
{
|
||||
/* Only interested in ASCII chars */
|
||||
if (ir.EventType == KEY_EVENT &&
|
||||
ir.Event.KeyEvent.bKeyDown)
|
||||
{
|
||||
unsigned char ch1, ch2;
|
||||
|
||||
if (ir.Event.KeyEvent.uChar.AsciiChar)
|
||||
{
|
||||
retval = ir.Event.KeyEvent.uChar.AsciiChar;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle_enhanced_keys(&ir, &ch1, &ch2))
|
||||
{
|
||||
retval = ch1;
|
||||
__MSVCRT_console_buffer = ch2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
if (mode)
|
||||
SetConsoleMode(msvcrt_input_console(), mode);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getch (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _getch(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCK_CONSOLE;
|
||||
ret = _getch_nolock();
|
||||
UNLOCK_CONSOLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getwch_nolock (MSVCR80.@)
|
||||
*/
|
||||
wchar_t CDECL _getwch_nolock(void)
|
||||
{
|
||||
wchar_t retval = WEOF;
|
||||
|
||||
if (__MSVCRT_console_buffer_w != WEOF)
|
||||
{
|
||||
retval = __MSVCRT_console_buffer_w;
|
||||
__MSVCRT_console_buffer_w = WEOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
DWORD count;
|
||||
DWORD mode = 0;
|
||||
|
||||
GetConsoleMode(msvcrt_input_console(), &mode);
|
||||
if(mode)
|
||||
SetConsoleMode(msvcrt_input_console(), 0);
|
||||
|
||||
do {
|
||||
if (ReadConsoleInputW(msvcrt_input_console(), &ir, 1, &count))
|
||||
{
|
||||
/* Only interested in ASCII chars */
|
||||
if (ir.EventType == KEY_EVENT &&
|
||||
ir.Event.KeyEvent.bKeyDown)
|
||||
{
|
||||
unsigned char ch1, ch2;
|
||||
|
||||
if (ir.Event.KeyEvent.uChar.UnicodeChar)
|
||||
{
|
||||
retval = ir.Event.KeyEvent.uChar.UnicodeChar;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle_enhanced_keys(&ir, &ch1, &ch2))
|
||||
{
|
||||
retval = ch1;
|
||||
__MSVCRT_console_buffer_w = ch2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
if (mode)
|
||||
SetConsoleMode(msvcrt_input_console(), mode);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getwch (MSVCRT.@)
|
||||
*/
|
||||
wchar_t CDECL _getwch(void)
|
||||
{
|
||||
wchar_t ret;
|
||||
|
||||
LOCK_CONSOLE;
|
||||
ret = _getwch_nolock();
|
||||
UNLOCK_CONSOLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putch_nolock (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _putch_nolock(int c)
|
||||
{
|
||||
DWORD count;
|
||||
if (WriteConsoleA(msvcrt_output_console(), &c, 1, &count, NULL) && count == 1)
|
||||
return c;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putch (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _putch(int c)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
c = _putch_nolock(c);
|
||||
UNLOCK_CONSOLE;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putwch_nolock (MSVCR80.@)
|
||||
*/
|
||||
wchar_t CDECL _putwch_nolock(wchar_t c)
|
||||
{
|
||||
DWORD count;
|
||||
if (WriteConsoleW(msvcrt_output_console(), &c, 1, &count, NULL) && count==1)
|
||||
return c;
|
||||
return WEOF;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putwch (MSVCRT.@)
|
||||
*/
|
||||
wchar_t CDECL _putwch(wchar_t c)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
c = _putwch_nolock(c);
|
||||
UNLOCK_CONSOLE;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getche_nolock (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _getche_nolock(void)
|
||||
{
|
||||
int retval;
|
||||
retval = _getch_nolock();
|
||||
if (retval != EOF)
|
||||
retval = _putch_nolock(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getche (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _getche(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCK_CONSOLE;
|
||||
ret = _getche_nolock();
|
||||
UNLOCK_CONSOLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getwche_nolock (MSVCR80.@)
|
||||
*/
|
||||
wchar_t CDECL _getwche_nolock(void)
|
||||
{
|
||||
wchar_t wch;
|
||||
wch = _getch_nolock();
|
||||
if (wch == WEOF)
|
||||
return wch;
|
||||
return _putwch_nolock(wch);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _getwche (MSVCRT.@)
|
||||
*/
|
||||
wchar_t CDECL _getwche(void)
|
||||
{
|
||||
wchar_t ret;
|
||||
|
||||
LOCK_CONSOLE;
|
||||
ret = _getwche_nolock();
|
||||
UNLOCK_CONSOLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cgets (MSVCRT.@)
|
||||
*/
|
||||
char* CDECL _cgets(char* str)
|
||||
{
|
||||
char *buf = str + 2;
|
||||
DWORD got;
|
||||
DWORD conmode = 0;
|
||||
|
||||
TRACE("(%p)\n", str);
|
||||
str[1] = 0; /* Length */
|
||||
LOCK_CONSOLE;
|
||||
GetConsoleMode(msvcrt_input_console(), &conmode);
|
||||
SetConsoleMode(msvcrt_input_console(), ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
|
||||
|
||||
if(ReadConsoleA(msvcrt_input_console(), buf, str[0], &got, NULL)) {
|
||||
if(buf[got-2] == '\r') {
|
||||
buf[got-2] = 0;
|
||||
str[1] = got-2;
|
||||
}
|
||||
else if(got == 1 && buf[got-1] == '\n') {
|
||||
buf[0] = 0;
|
||||
str[1] = 0;
|
||||
}
|
||||
else if(got == str[0] && buf[got-1] == '\r') {
|
||||
buf[got-1] = 0;
|
||||
str[1] = got-1;
|
||||
}
|
||||
else
|
||||
str[1] = got;
|
||||
}
|
||||
else
|
||||
buf = NULL;
|
||||
SetConsoleMode(msvcrt_input_console(), conmode);
|
||||
UNLOCK_CONSOLE;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _ungetch_nolock (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _ungetch_nolock(int c)
|
||||
{
|
||||
int retval = EOF;
|
||||
if (c != EOF && __MSVCRT_console_buffer == EOF)
|
||||
retval = __MSVCRT_console_buffer = c;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _ungetch (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _ungetch(int c)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
c = _ungetch_nolock(c);
|
||||
UNLOCK_CONSOLE;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _ungetwch_nolock (MSVCR80.@)
|
||||
*/
|
||||
wchar_t CDECL _ungetwch_nolock(wchar_t c)
|
||||
{
|
||||
wchar_t retval = WEOF;
|
||||
if (c != WEOF && __MSVCRT_console_buffer_w == WEOF)
|
||||
retval = __MSVCRT_console_buffer_w = c;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _ungetwch (MSVCRT.@)
|
||||
*/
|
||||
wchar_t CDECL _ungetwch(wchar_t c)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
c = _ungetwch_nolock(c);
|
||||
UNLOCK_CONSOLE;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _kbhit (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _kbhit(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
LOCK_CONSOLE;
|
||||
if (__MSVCRT_console_buffer != EOF)
|
||||
retval = 1;
|
||||
else
|
||||
{
|
||||
/* FIXME: There has to be a faster way than this in Win32.. */
|
||||
INPUT_RECORD *ir = NULL;
|
||||
DWORD count = 0, i;
|
||||
|
||||
GetNumberOfConsoleInputEvents(msvcrt_input_console(), &count);
|
||||
|
||||
if (count && (ir = malloc(count * sizeof(INPUT_RECORD))) &&
|
||||
PeekConsoleInputA(msvcrt_input_console(), ir, count, &count))
|
||||
for(i = 0; i < count; i++)
|
||||
{
|
||||
if (ir[i].EventType == KEY_EVENT &&
|
||||
ir[i].Event.KeyEvent.bKeyDown &&
|
||||
ir[i].Event.KeyEvent.uChar.AsciiChar)
|
||||
{
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(ir);
|
||||
}
|
||||
UNLOCK_CONSOLE;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int puts_clbk_console_a(void *ctx, int len, const char *str)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
if(!WriteConsoleA(msvcrt_output_console(), str, len, NULL, NULL))
|
||||
len = -1;
|
||||
UNLOCK_CONSOLE;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int puts_clbk_console_w(void *ctx, int len, const wchar_t *str)
|
||||
{
|
||||
LOCK_CONSOLE;
|
||||
if(!WriteConsoleW(msvcrt_output_console(), str, len, NULL, NULL))
|
||||
len = -1;
|
||||
UNLOCK_CONSOLE;
|
||||
return len;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER<=120
|
||||
/*********************************************************************
|
||||
* _vcprintf_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _vcprintf_l(const char* format, _locale_t locale, va_list valist)
|
||||
{
|
||||
return pf_printf_a(puts_clbk_console_a, NULL, format, locale, 0, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _vcprintf (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _vcprintf(const char* format, va_list valist)
|
||||
{
|
||||
return pf_printf_a(puts_clbk_console_a, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER<=120
|
||||
/*********************************************************************
|
||||
* _cprintf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cprintf_l(const char* format, _locale_t locale, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list valist;
|
||||
|
||||
va_start(valist, locale);
|
||||
retval = _vcprintf_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _cprintf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cprintf(const char* format, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list valist;
|
||||
|
||||
va_start( valist, format );
|
||||
retval = _vcprintf(format, valist);
|
||||
va_end(valist);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER<=120
|
||||
/*********************************************************************
|
||||
* _vcwprintf_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _vcwprintf_l(const wchar_t* format, _locale_t locale, va_list valist)
|
||||
{
|
||||
return pf_printf_w(puts_clbk_console_w, NULL, format, locale, 0, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _vcwprintf (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _vcwprintf(const wchar_t* format, va_list valist)
|
||||
{
|
||||
return pf_printf_w(puts_clbk_console_w, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwprintf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwprintf_l(const wchar_t* format, _locale_t locale, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list valist;
|
||||
|
||||
va_start(valist, locale);
|
||||
retval = _vcwprintf_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwprintf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwprintf(const wchar_t* format, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list valist;
|
||||
|
||||
va_start( valist, format );
|
||||
retval = _vcwprintf(format, valist);
|
||||
va_end(valist);
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
|
||||
/*********************************************************************
|
||||
* __conio_common_vcprintf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __conio_common_vcprintf(unsigned __int64 options, const char* format,
|
||||
_locale_t locale, va_list valist)
|
||||
{
|
||||
if (options & ~UCRTBASE_PRINTF_MASK)
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
return pf_printf_a(puts_clbk_console_a, NULL, format, locale,
|
||||
options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __conio_common_vcwprintf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __conio_common_vcwprintf(unsigned __int64 options, const wchar_t* format,
|
||||
_locale_t locale, va_list valist)
|
||||
{
|
||||
if (options & ~UCRTBASE_PRINTF_MASK)
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
return pf_printf_w(puts_clbk_console_w, NULL, format, locale,
|
||||
options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=140 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2002 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __MSVCRT_CPPEXCEPT_H
|
||||
#define __MSVCRT_CPPEXCEPT_H
|
||||
|
||||
#include <fpieee.h>
|
||||
#include "cxx.h"
|
||||
|
||||
#define CXX_FRAME_MAGIC_VC6 0x19930520
|
||||
#define CXX_FRAME_MAGIC_VC7 0x19930521
|
||||
#define CXX_FRAME_MAGIC_VC8 0x19930522
|
||||
#define CXX_EXCEPTION 0xe06d7363
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT ip;
|
||||
int state;
|
||||
} ipmap_info;
|
||||
|
||||
#ifndef RTTI_USE_RVA
|
||||
|
||||
#define CXX_EXCEPTION_PARAMS 3
|
||||
|
||||
/* info about a single catch {} block */
|
||||
typedef struct
|
||||
{
|
||||
UINT flags; /* flags (see below) */
|
||||
const type_info *type_info; /* C++ type caught by this block */
|
||||
int offset; /* stack offset to copy exception object to */
|
||||
void * (*handler)(void);/* catch block handler code */
|
||||
} catchblock_info;
|
||||
|
||||
/* info about a single try {} block */
|
||||
typedef struct
|
||||
{
|
||||
int start_level; /* start trylevel of that block */
|
||||
int end_level; /* end trylevel of that block */
|
||||
int catch_level; /* initial trylevel of the catch block */
|
||||
unsigned int catchblock_count; /* count of catch blocks in array */
|
||||
const catchblock_info *catchblock; /* array of catch blocks */
|
||||
} tryblock_info;
|
||||
|
||||
/* info about the unwind handler for a given trylevel */
|
||||
typedef struct
|
||||
{
|
||||
int prev; /* prev trylevel unwind handler, to run after this one */
|
||||
void * (*handler)(void);/* unwind handler */
|
||||
} unwind_info;
|
||||
|
||||
/* descriptor of all try blocks of a given function */
|
||||
typedef struct
|
||||
{
|
||||
UINT magic : 29; /* must be CXX_FRAME_MAGIC */
|
||||
UINT bbt_flags : 3;
|
||||
UINT unwind_count; /* number of unwind handlers */
|
||||
const unwind_info *unwind_table; /* array of unwind handlers */
|
||||
UINT tryblock_count; /* number of try blocks */
|
||||
const tryblock_info *tryblock; /* array of try blocks */
|
||||
UINT ipmap_count;
|
||||
const ipmap_info *ipmap;
|
||||
const void *expect_list; /* expected exceptions list when magic >= VC7 */
|
||||
UINT flags; /* flags when magic >= VC8 */
|
||||
} cxx_function_descr;
|
||||
|
||||
#else /* RTTI_USE_RVA */
|
||||
|
||||
#define CXX_EXCEPTION_PARAMS 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT flags;
|
||||
UINT type_info;
|
||||
int offset;
|
||||
UINT handler;
|
||||
#ifdef _WIN64
|
||||
UINT frame;
|
||||
#endif
|
||||
} catchblock_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int start_level;
|
||||
int end_level;
|
||||
int catch_level;
|
||||
UINT catchblock_count;
|
||||
UINT catchblock;
|
||||
} tryblock_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int prev;
|
||||
UINT handler;
|
||||
} unwind_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT magic : 29;
|
||||
UINT bbt_flags : 3;
|
||||
UINT unwind_count;
|
||||
UINT unwind_table;
|
||||
UINT tryblock_count;
|
||||
UINT tryblock;
|
||||
UINT ipmap_count;
|
||||
UINT ipmap;
|
||||
int unwind_help;
|
||||
UINT expect_list;
|
||||
UINT flags;
|
||||
} cxx_function_descr;
|
||||
|
||||
#endif /* RTTI_USE_RVA */
|
||||
|
||||
#define FUNC_DESCR_SYNCHRONOUS 1 /* synchronous exceptions only (built with /EHs and /EHsc) */
|
||||
#define FUNC_DESCR_NOEXCEPT 4 /* noexcept function */
|
||||
|
||||
#define CLASS_IS_SIMPLE_TYPE 1
|
||||
#define CLASS_HAS_VIRTUAL_BASE_CLASS 4
|
||||
|
||||
#define TYPE_FLAG_CONST 1
|
||||
#define TYPE_FLAG_VOLATILE 2
|
||||
#define TYPE_FLAG_REFERENCE 8
|
||||
|
||||
void WINAPI DECLSPEC_NORETURN _CxxThrowException(void*,const cxx_exception_type*);
|
||||
|
||||
static inline BOOL is_cxx_exception( EXCEPTION_RECORD *rec )
|
||||
{
|
||||
if (rec->ExceptionCode != CXX_EXCEPTION) return FALSE;
|
||||
if (rec->NumberParameters != CXX_EXCEPTION_PARAMS) return FALSE;
|
||||
return (rec->ExceptionInformation[0] >= CXX_FRAME_MAGIC_VC6 &&
|
||||
rec->ExceptionInformation[0] <= CXX_FRAME_MAGIC_VC8);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EXCEPTION_RECORD *rec;
|
||||
LONG *ref; /* not binary compatible with native msvcr100 */
|
||||
} exception_ptr;
|
||||
|
||||
void throw_exception(const char*);
|
||||
void exception_ptr_from_record(exception_ptr*,EXCEPTION_RECORD*);
|
||||
|
||||
void __cdecl __ExceptionPtrCreate(exception_ptr*);
|
||||
void __cdecl __ExceptionPtrDestroy(exception_ptr*);
|
||||
void __cdecl __ExceptionPtrRethrow(const exception_ptr*);
|
||||
|
||||
BOOL __cdecl __uncaught_exception(void);
|
||||
|
||||
static inline const char *dbgstr_type_info( const type_info *info )
|
||||
{
|
||||
if (!info) return "{}";
|
||||
return wine_dbg_sprintf( "{vtable=%p name=%s (%s)}",
|
||||
info->vtable, info->mangled, info->name ? info->name : "" );
|
||||
}
|
||||
|
||||
/* compute the this pointer for a base class of a given type */
|
||||
static inline void *get_this_pointer( const this_ptr_offsets *off, void *object )
|
||||
{
|
||||
if (!object) return NULL;
|
||||
|
||||
if (off->vbase_descr >= 0)
|
||||
{
|
||||
int *offset_ptr;
|
||||
|
||||
/* move this ptr to vbase descriptor */
|
||||
object = (char *)object + off->vbase_descr;
|
||||
/* and fetch additional offset from vbase descriptor */
|
||||
offset_ptr = (int *)(*(char **)object + off->vbase_offset);
|
||||
object = (char *)object + *offset_ptr;
|
||||
}
|
||||
|
||||
object = (char *)object + off->this_offset;
|
||||
return object;
|
||||
}
|
||||
|
||||
#ifdef __ASM_USE_THISCALL_WRAPPER
|
||||
extern void call_copy_ctor( void *func, void *this, void *src, int has_vbase );
|
||||
extern void call_dtor( void *func, void *this );
|
||||
#else
|
||||
static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase )
|
||||
{
|
||||
if (has_vbase)
|
||||
((void (__thiscall*)(void*, void*, BOOL))func)(this, src, 1);
|
||||
else
|
||||
((void (__thiscall*)(void*, void*))func)(this, src);
|
||||
}
|
||||
static inline void call_dtor( void *func, void *this )
|
||||
{
|
||||
((void (__thiscall*)(void*))func)( this );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if the exception type is caught by a given catch block, and return the type that matched */
|
||||
static inline const cxx_type_info *find_caught_type( cxx_exception_type *exc_type, uintptr_t base,
|
||||
const type_info *catch_ti, UINT catch_flags )
|
||||
{
|
||||
const cxx_type_info_table *type_info_table = rtti_rva( exc_type->type_info_table, base );
|
||||
UINT i;
|
||||
|
||||
for (i = 0; i < type_info_table->count; i++)
|
||||
{
|
||||
const cxx_type_info *type = rtti_rva( type_info_table->info[i], base );
|
||||
const type_info *ti = rtti_rva( type->type_info, base );
|
||||
|
||||
if (!catch_ti) return type; /* catch(...) matches any type */
|
||||
if (catch_ti != ti)
|
||||
{
|
||||
if (strcmp( catch_ti->mangled, ti->mangled )) continue;
|
||||
}
|
||||
/* type is the same, now check the flags */
|
||||
if ((exc_type->flags & TYPE_FLAG_CONST) &&
|
||||
!(catch_flags & TYPE_FLAG_CONST)) continue;
|
||||
if ((exc_type->flags & TYPE_FLAG_VOLATILE) &&
|
||||
!(catch_flags & TYPE_FLAG_VOLATILE)) continue;
|
||||
return type; /* it matched */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy the exception object where the catch block wants it */
|
||||
static inline void copy_exception( void *object, void **dest, UINT catch_flags,
|
||||
const cxx_type_info *type, uintptr_t base )
|
||||
{
|
||||
if (catch_flags & TYPE_FLAG_REFERENCE)
|
||||
{
|
||||
*dest = get_this_pointer( &type->offsets, object );
|
||||
}
|
||||
else if (type->flags & CLASS_IS_SIMPLE_TYPE)
|
||||
{
|
||||
memmove( dest, object, type->size );
|
||||
/* if it is a pointer, adjust it */
|
||||
if (type->size == sizeof(void*)) *dest = get_this_pointer( &type->offsets, *dest );
|
||||
}
|
||||
else /* copy the object */
|
||||
{
|
||||
if (type->copy_ctor)
|
||||
call_copy_ctor( rtti_rva( type->copy_ctor, base ), dest,
|
||||
get_this_pointer( &type->offsets, object ),
|
||||
(type->flags & CLASS_HAS_VIRTUAL_BASE_CLASS) );
|
||||
else
|
||||
memmove( dest, get_this_pointer( &type->offsets, object ), type->size );
|
||||
}
|
||||
}
|
||||
|
||||
#define TRACE_EXCEPTION_TYPE(type,base) do { \
|
||||
const cxx_type_info_table *table = rtti_rva( type->type_info_table, base ); \
|
||||
unsigned int i; \
|
||||
TRACE( "flags %x destr %p handler %p type info %p\n", \
|
||||
type->flags, rtti_rva( type->destructor, base ), \
|
||||
type->custom_handler ? rtti_rva( type->custom_handler, base ) : NULL, table ); \
|
||||
for (i = 0; i < table->count; i++) \
|
||||
{ \
|
||||
const cxx_type_info *type = rtti_rva( table->info[i], base ); \
|
||||
const type_info *info = rtti_rva( type->type_info, base ); \
|
||||
TRACE( " %d: flags %x type %p %s offsets %d,%d,%d size %d copy ctor %p\n", \
|
||||
i, type->flags, info, dbgstr_type_info( info ), \
|
||||
type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset, \
|
||||
type->size, rtti_rva( type->copy_ctor, base )); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
extern void dump_function_descr( const cxx_function_descr *descr, uintptr_t base );
|
||||
extern void *find_catch_handler( void *object, uintptr_t frame, uintptr_t exc_base,
|
||||
const tryblock_info *tryblock,
|
||||
cxx_exception_type *exc_type, uintptr_t image_base );
|
||||
extern int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) );
|
||||
#ifndef __i386__
|
||||
extern void *call_catch_handler( EXCEPTION_RECORD *rec );
|
||||
extern void *call_unwind_handler( void *func, uintptr_t frame, DISPATCHER_CONTEXT *dispatch );
|
||||
extern ULONG_PTR get_exception_pc( DISPATCHER_CONTEXT *dispatch );
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER >= 80
|
||||
#define EXCEPTION_MANGLED_NAME ".?AVexception@std@@"
|
||||
#else
|
||||
#define EXCEPTION_MANGLED_NAME ".?AVexception@@"
|
||||
#endif
|
||||
|
||||
#define CREATE_EXCEPTION_OBJECT(exception_name) \
|
||||
static exception* __exception_ctor(exception *this, const char *str, const vtable_ptr *vtbl) \
|
||||
{ \
|
||||
if (str) \
|
||||
{ \
|
||||
unsigned int len = strlen(str) + 1; \
|
||||
this->name = malloc(len); \
|
||||
memcpy(this->name, str, len); \
|
||||
this->do_free = TRUE; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
this->name = NULL; \
|
||||
this->do_free = FALSE; \
|
||||
} \
|
||||
this->vtable = vtbl; \
|
||||
return this; \
|
||||
} \
|
||||
\
|
||||
static exception* __exception_copy_ctor(exception *this, const exception *rhs, const vtable_ptr *vtbl) \
|
||||
{ \
|
||||
if (rhs->do_free) \
|
||||
{ \
|
||||
__exception_ctor(this, rhs->name, vtbl); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*this = *rhs; \
|
||||
this->vtable = vtbl; \
|
||||
} \
|
||||
return this; \
|
||||
} \
|
||||
extern const vtable_ptr exception_name ## _vtable; \
|
||||
DEFINE_THISCALL_WRAPPER(exception_name ## _copy_ctor,8) \
|
||||
exception* __thiscall exception_name ## _copy_ctor(exception *this, const exception *rhs) \
|
||||
{ \
|
||||
return __exception_copy_ctor(this, rhs, & exception_name ## _vtable); \
|
||||
} \
|
||||
\
|
||||
DEFINE_THISCALL_WRAPPER(exception_name ## _dtor,4) \
|
||||
void __thiscall exception_name ## _dtor(exception *this) \
|
||||
{ \
|
||||
if (this->do_free) free(this->name); \
|
||||
} \
|
||||
\
|
||||
DEFINE_THISCALL_WRAPPER(exception_name ## _vector_dtor,8) \
|
||||
void* __thiscall exception_name ## _vector_dtor(exception *this, unsigned int flags) \
|
||||
{ \
|
||||
if (flags & 2) \
|
||||
{ \
|
||||
INT_PTR i, *ptr = (INT_PTR *)this - 1; \
|
||||
\
|
||||
for (i = *ptr - 1; i >= 0; i--) exception_name ## _dtor(this + i); \
|
||||
operator_delete(ptr); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
exception_name ## _dtor(this); \
|
||||
if (flags & 1) operator_delete(this); \
|
||||
} \
|
||||
return this; \
|
||||
} \
|
||||
\
|
||||
DEFINE_THISCALL_WRAPPER(exception_name ## _what,4) \
|
||||
const char* __thiscall exception_name ## _what(exception *this) \
|
||||
{ \
|
||||
return this->name ? this->name : "Unknown exception"; \
|
||||
} \
|
||||
\
|
||||
__ASM_BLOCK_BEGIN(exception_name ## _vtables) \
|
||||
__ASM_VTABLE(exception_name, \
|
||||
VTABLE_ADD_FUNC(exception_name ## _vector_dtor) \
|
||||
VTABLE_ADD_FUNC(exception_name ## _what)); \
|
||||
__ASM_BLOCK_END \
|
||||
\
|
||||
DEFINE_RTTI_DATA0(exception_name, 0, EXCEPTION_MANGLED_NAME)
|
||||
|
||||
#endif /* __MSVCRT_CPPEXCEPT_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* __main entry point
|
||||
*
|
||||
* Copyright 2019 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#ifdef __WINE_PE_BUILD
|
||||
|
||||
/* mingw compilers emit call to __main() when main() function is defined.
|
||||
* it's used by crt to call global constructors and register global destructors. */
|
||||
void __cdecl __main(void) {}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* mainCRTStartup default entry point
|
||||
*
|
||||
* Copyright 2019 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
|
||||
int __cdecl main(int argc, char **argv, char **env);
|
||||
|
||||
static const IMAGE_NT_HEADERS *get_nt_header( void )
|
||||
{
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)NtCurrentTeb()->Peb->ImageBaseAddress;
|
||||
return (const IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
|
||||
}
|
||||
|
||||
int __cdecl mainCRTStartup(void)
|
||||
{
|
||||
int argc, ret;
|
||||
char **argv, **env;
|
||||
|
||||
#ifdef _UCRT
|
||||
_configure_narrow_argv(_crt_argv_unexpanded_arguments);
|
||||
_initialize_narrow_environment();
|
||||
argc = *__p___argc();
|
||||
argv = *__p___argv();
|
||||
env = _get_initial_narrow_environment();
|
||||
#else
|
||||
int new_mode = 0;
|
||||
__getmainargs(&argc, &argv, &env, 0, &new_mode);
|
||||
#endif
|
||||
_set_app_type(get_nt_header()->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? _crt_gui_app : _crt_console_app);
|
||||
|
||||
ret = main(argc, argv, env);
|
||||
|
||||
exit(ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* main default entry point for exe files
|
||||
*
|
||||
* Copyright 2005 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
int __cdecl main( int argc, char *argv[] )
|
||||
{
|
||||
STARTUPINFOA info;
|
||||
char *cmdline = GetCommandLineA();
|
||||
int bcount = 0;
|
||||
BOOL in_quotes = FALSE;
|
||||
|
||||
while (*cmdline)
|
||||
{
|
||||
if ((*cmdline == '\t' || *cmdline == ' ') && !in_quotes) break;
|
||||
else if (*cmdline == '\\') bcount++;
|
||||
else if (*cmdline == '\"')
|
||||
{
|
||||
if (!(bcount & 1)) in_quotes = !in_quotes;
|
||||
bcount = 0;
|
||||
}
|
||||
else bcount = 0;
|
||||
cmdline++;
|
||||
}
|
||||
while (*cmdline == '\t' || *cmdline == ' ') cmdline++;
|
||||
|
||||
GetStartupInfoA( &info );
|
||||
if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWNORMAL;
|
||||
return WinMain( GetModuleHandleA(0), 0, cmdline, info.wShowWindow );
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* wmainCRTStartup default entry point
|
||||
*
|
||||
* Copyright 2019 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
|
||||
int __cdecl wmain(int argc, WCHAR **argv, WCHAR **env);
|
||||
|
||||
static const IMAGE_NT_HEADERS *get_nt_header( void )
|
||||
{
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)NtCurrentTeb()->Peb->ImageBaseAddress;
|
||||
return (const IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
|
||||
}
|
||||
|
||||
int __cdecl wmainCRTStartup(void)
|
||||
{
|
||||
int argc, ret;
|
||||
WCHAR **argv, **env;
|
||||
|
||||
#ifdef _UCRT
|
||||
_configure_wide_argv(_crt_argv_unexpanded_arguments);
|
||||
_initialize_wide_environment();
|
||||
argc = *__p___argc();
|
||||
argv = *__p___wargv();
|
||||
env = _get_initial_wide_environment();
|
||||
#else
|
||||
int new_mode = 0;
|
||||
__wgetmainargs(&argc, &argv, &env, 0, &new_mode);
|
||||
#endif
|
||||
_set_app_type(get_nt_header()->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? _crt_gui_app : _crt_console_app);
|
||||
|
||||
ret = wmain(argc, argv, env);
|
||||
|
||||
exit(ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* main default entry point for Unicode exe files
|
||||
*
|
||||
* Copyright 2005 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
int WINAPI wWinMain(HINSTANCE,HINSTANCE,LPWSTR,int);
|
||||
|
||||
int __cdecl wmain( int argc, WCHAR *argv[] )
|
||||
{
|
||||
STARTUPINFOW info;
|
||||
WCHAR *cmdline = GetCommandLineW();
|
||||
int bcount = 0;
|
||||
BOOL in_quotes = FALSE;
|
||||
|
||||
while (*cmdline)
|
||||
{
|
||||
if ((*cmdline == '\t' || *cmdline == ' ') && !in_quotes) break;
|
||||
else if (*cmdline == '\\') bcount++;
|
||||
else if (*cmdline == '\"')
|
||||
{
|
||||
if (!(bcount & 1)) in_quotes = !in_quotes;
|
||||
bcount = 0;
|
||||
}
|
||||
else bcount = 0;
|
||||
cmdline++;
|
||||
}
|
||||
while (*cmdline == '\t' || *cmdline == ' ') cmdline++;
|
||||
|
||||
GetStartupInfoW( &info );
|
||||
if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = SW_SHOWNORMAL;
|
||||
return wWinMain( GetModuleHandleW(0), 0, cmdline, info.wShowWindow );
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* msvcrt.dll ctype functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
#include "msvcrt.h"
|
||||
#include "winnls.h"
|
||||
|
||||
/* Some abbreviations to make the following table readable */
|
||||
#define _C_ _CONTROL
|
||||
#define _S_ _SPACE
|
||||
#define _P_ _PUNCT
|
||||
#define _D_ _DIGIT
|
||||
#define _H_ _HEX
|
||||
#define _U_ _UPPER
|
||||
#define _L_ _LOWER
|
||||
|
||||
WORD MSVCRT__ctype [257] = {
|
||||
0, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_C_, _S_|_C_,
|
||||
_S_|_C_, _S_|_C_, _S_|_C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_,
|
||||
_C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_BLANK,
|
||||
_P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_,
|
||||
_P_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_,
|
||||
_D_|_H_, _D_|_H_, _D_|_H_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _U_|_H_,
|
||||
_U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_, _U_, _U_, _U_, _U_,
|
||||
_U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_,
|
||||
_U_, _P_, _P_, _P_, _P_, _P_, _P_, _L_|_H_, _L_|_H_, _L_|_H_, _L_|_H_,
|
||||
_L_|_H_, _L_|_H_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_,
|
||||
_L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _P_, _P_, _P_, _P_,
|
||||
_C_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
#if _MSVCR_VER <= 110
|
||||
# define B110 _BLANK
|
||||
#else
|
||||
# define B110 0
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER == 120
|
||||
# define D120 0
|
||||
#else
|
||||
# define D120 4
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
# define S140 _SPACE
|
||||
# define L140 _LOWER | 0x100
|
||||
# define C140 _CONTROL
|
||||
#else
|
||||
# define S140 0
|
||||
# define L140 0
|
||||
# define C140 0
|
||||
#endif
|
||||
WORD MSVCRT__wctype[257] =
|
||||
{
|
||||
0,
|
||||
/* 00 */
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
0x0020, 0x0028 | B110, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
|
||||
/* 10 */
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
/* 20 */
|
||||
0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
/* 30 */
|
||||
0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
|
||||
0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
/* 40 */
|
||||
0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
|
||||
/* 50 */
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
|
||||
0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
/* 60 */
|
||||
0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
|
||||
/* 70 */
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
|
||||
0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
|
||||
/* 80 */
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 | S140, 0x0020, 0x0020,
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
/* 90 */
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
|
||||
/* a0 */
|
||||
0x0008 | B110, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
0x0010, 0x0010, 0x0010 | L140, 0x0010, 0x0010, 0x0010 | C140, 0x0010, 0x0010,
|
||||
/* b0 */
|
||||
0x0010, 0x0010, 0x0010 | D120, 0x0010 | D120, 0x0010, 0x0010 | L140, 0x0010, 0x0010,
|
||||
0x0010, 0x0010 | D120, 0x0010 | L140, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
|
||||
/* c0 */
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
|
||||
/* d0 */
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
|
||||
0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
|
||||
/* e0 */
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
|
||||
/* f0 */
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
|
||||
0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
|
||||
};
|
||||
|
||||
WORD *MSVCRT__pwctype = MSVCRT__wctype + 1;
|
||||
|
||||
/*********************************************************************
|
||||
* __p__pctype (MSVCRT.@)
|
||||
*/
|
||||
unsigned short** CDECL __p__pctype(void)
|
||||
{
|
||||
return &get_locinfo()->pctype;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __pctype_func (MSVCRT.@)
|
||||
*/
|
||||
const unsigned short* CDECL __pctype_func(void)
|
||||
{
|
||||
return get_locinfo()->pctype;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __p__pwctype (MSVCRT.@)
|
||||
*/
|
||||
unsigned short** CDECL __p__pwctype(void)
|
||||
{
|
||||
return &MSVCRT__pwctype;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __pwctype_func (MSVCRT.@)
|
||||
*/
|
||||
const unsigned short* CDECL __pwctype_func(void)
|
||||
{
|
||||
return MSVCRT__pwctype;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isctype_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isctype_l(int c, int type, _locale_t locale)
|
||||
{
|
||||
pthreadlocinfo locinfo;
|
||||
|
||||
if(!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = locale->locinfo;
|
||||
|
||||
if (c >= -1 && c <= 255)
|
||||
return locinfo->pctype[c] & type;
|
||||
|
||||
if (locinfo->mb_cur_max != 1 && c > 0)
|
||||
{
|
||||
/* FIXME: Is there a faster way to do this? */
|
||||
WORD typeInfo;
|
||||
char convert[3], *pconv = convert;
|
||||
|
||||
if (locinfo->pctype[(UINT)c >> 8] & _LEADBYTE)
|
||||
*pconv++ = (UINT)c >> 8;
|
||||
*pconv++ = c & 0xff;
|
||||
*pconv = 0;
|
||||
|
||||
if (GetStringTypeExA(locinfo->lc_handle[LC_CTYPE],
|
||||
CT_CTYPE1, convert, convert[1] ? 2 : 1, &typeInfo))
|
||||
return typeInfo & type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isctype (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isctype(int c, int type)
|
||||
{
|
||||
return _isctype_l(c, type, NULL);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isalnum_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isalnum_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _ALPHA | _DIGIT, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isalnum (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isalnum(int c)
|
||||
{
|
||||
return _isctype( c, _ALPHA | _DIGIT );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isalpha_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isalpha_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _ALPHA, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isalpha (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isalpha(int c)
|
||||
{
|
||||
return _isctype( c, _ALPHA );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _iscntrl_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _iscntrl_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _CONTROL, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* iscntrl (MSVCRT.@)
|
||||
*/
|
||||
int CDECL iscntrl(int c)
|
||||
{
|
||||
return _isctype( c, _CONTROL );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isdigit_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isdigit_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _DIGIT, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isdigit (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isdigit(int c)
|
||||
{
|
||||
return _isctype( c, _DIGIT );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isgraph_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isgraph_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _ALPHA | _DIGIT | _PUNCT, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isgraph (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isgraph(int c)
|
||||
{
|
||||
return _isctype( c, _ALPHA | _DIGIT | _PUNCT );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isleadbyte_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isleadbyte_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _LEADBYTE, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isleadbyte (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isleadbyte(int c)
|
||||
{
|
||||
return _isctype( c, _LEADBYTE );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _islower_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _islower_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _LOWER, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* islower (MSVCRT.@)
|
||||
*/
|
||||
int CDECL islower(int c)
|
||||
{
|
||||
return _isctype( c, _LOWER );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isprint_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isprint_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _ALPHA | _DIGIT | _BLANK | _PUNCT, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isprint (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isprint(int c)
|
||||
{
|
||||
return _isctype( c, _ALPHA | _DIGIT | _BLANK | _PUNCT );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ispunct (MSVCRT.@)
|
||||
*/
|
||||
int CDECL ispunct(int c)
|
||||
{
|
||||
return _isctype( c, _PUNCT );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _ispunct_l (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _ispunct_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _PUNCT, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isspace_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isspace_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _SPACE, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isspace (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isspace(int c)
|
||||
{
|
||||
return _isctype( c, _SPACE );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isupper_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isupper_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _UPPER, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isupper (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isupper(int c)
|
||||
{
|
||||
return _isctype( c, _UPPER );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isxdigit_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isxdigit_l(int c, _locale_t locale)
|
||||
{
|
||||
return _isctype_l( c, _HEX, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isxdigit (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isxdigit(int c)
|
||||
{
|
||||
return _isctype( c, _HEX );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _isblank_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _isblank_l(int c, _locale_t locale)
|
||||
{
|
||||
#if _MSVCR_VER < 140
|
||||
if (c == '\t') return _BLANK;
|
||||
#endif
|
||||
return _isctype_l( c, _BLANK, locale );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* isblank (MSVCRT.@)
|
||||
*/
|
||||
int CDECL isblank(int c)
|
||||
{
|
||||
return c == '\t' || _isctype( c, _BLANK );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __isascii (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __isascii(int c)
|
||||
{
|
||||
return ((unsigned)c < 0x80);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __toascii (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __toascii(int c)
|
||||
{
|
||||
return (unsigned)c & 0x7f;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* iswascii (MSVCRT.@)
|
||||
*
|
||||
*/
|
||||
int CDECL iswascii(wchar_t c)
|
||||
{
|
||||
return ((unsigned)c < 0x80);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __iscsym (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __iscsym(int c)
|
||||
{
|
||||
return (c < 127 && (isalnum(c) || c == '_'));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __iscsymf (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __iscsymf(int c)
|
||||
{
|
||||
return (c < 127 && (isalpha(c) || c == '_'));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __iswcsym (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __iswcsym(wint_t c)
|
||||
{
|
||||
return (iswalnum(c) || c == '_');
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __iswcsymf (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __iswcsymf(wint_t c)
|
||||
{
|
||||
return (iswalpha(c) || c == '_');
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _toupper_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _toupper_l(int c, _locale_t locale)
|
||||
{
|
||||
pthreadlocinfo locinfo;
|
||||
unsigned char str[2], *p = str, ret[2];
|
||||
|
||||
if(!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = locale->locinfo;
|
||||
|
||||
if((unsigned)c < 256)
|
||||
{
|
||||
if(locinfo->pctype[c] & _LEADBYTE)
|
||||
return c;
|
||||
return locinfo->pcumap[c];
|
||||
}
|
||||
|
||||
if(locinfo->pctype[(c>>8)&255] & _LEADBYTE)
|
||||
*p++ = (c>>8) & 255;
|
||||
else {
|
||||
*_errno() = EILSEQ;
|
||||
str[1] = 0;
|
||||
}
|
||||
*p++ = c & 255;
|
||||
|
||||
switch(__crtLCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE,
|
||||
(char*)str, p-str, (char*)ret, 2, locinfo->lc_codepage, 0))
|
||||
{
|
||||
case 0:
|
||||
return c;
|
||||
case 1:
|
||||
return ret[0];
|
||||
default:
|
||||
return ret[0] + (ret[1]<<8);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* toupper (MSVCRT.@)
|
||||
*/
|
||||
int CDECL toupper(int c)
|
||||
{
|
||||
if(initial_locale)
|
||||
return c>='a' && c<='z' ? c-'a'+'A' : c;
|
||||
return _toupper_l(c, NULL);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _toupper (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _toupper(int c)
|
||||
{
|
||||
return c - 0x20; /* sic */
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _tolower_l (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _tolower_l(int c, _locale_t locale)
|
||||
{
|
||||
pthreadlocinfo locinfo;
|
||||
unsigned char str[2], *p = str, ret[2];
|
||||
|
||||
if(!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = locale->locinfo;
|
||||
|
||||
if((unsigned)c < 256)
|
||||
{
|
||||
if(locinfo->pctype[c] & _LEADBYTE)
|
||||
return c;
|
||||
return locinfo->pclmap[c];
|
||||
}
|
||||
|
||||
if(locinfo->pctype[(c>>8)&255] & _LEADBYTE)
|
||||
*p++ = (c>>8) & 255;
|
||||
else {
|
||||
*_errno() = EILSEQ;
|
||||
str[1] = 0;
|
||||
}
|
||||
*p++ = c & 255;
|
||||
|
||||
switch(__crtLCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE,
|
||||
(char*)str, p-str, (char*)ret, 2, locinfo->lc_codepage, 0))
|
||||
{
|
||||
case 0:
|
||||
return c;
|
||||
case 1:
|
||||
return ret[0];
|
||||
default:
|
||||
return ret[0] + (ret[1]<<8);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* tolower (MSVCRT.@)
|
||||
*/
|
||||
int CDECL tolower(int c)
|
||||
{
|
||||
if(initial_locale)
|
||||
return c>='A' && c<='Z' ? c-'A'+'a' : c;
|
||||
return _tolower_l(c, NULL);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _tolower (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _tolower(int c)
|
||||
{
|
||||
return c + 0x20; /* sic */
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=120
|
||||
/*********************************************************************
|
||||
* wctype (MSVCR120.@)
|
||||
*/
|
||||
unsigned short __cdecl wctype(const char *property)
|
||||
{
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned short mask;
|
||||
} properties[] = {
|
||||
{ "alnum", _DIGIT|_ALPHA },
|
||||
{ "alpha", _ALPHA },
|
||||
{ "cntrl", _CONTROL },
|
||||
{ "digit", _DIGIT },
|
||||
{ "graph", _DIGIT|_PUNCT|_ALPHA },
|
||||
{ "lower", _LOWER },
|
||||
{ "print", _DIGIT|_PUNCT|_BLANK|_ALPHA },
|
||||
{ "punct", _PUNCT },
|
||||
{ "space", _SPACE },
|
||||
{ "upper", _UPPER },
|
||||
{ "xdigit", _HEX }
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
for(i=0; i<ARRAY_SIZE(properties); i++)
|
||||
if(!strcmp(property, properties[i].name))
|
||||
return properties[i].mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright 2012 Piotr Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "rtlsupportapi.h"
|
||||
#include "wine/asm.h"
|
||||
|
||||
#ifdef __i386__
|
||||
#undef RTTI_USE_RVA
|
||||
#else
|
||||
#define RTTI_USE_RVA 1
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
#define VTABLE_ADD_FUNC(name) "\t.quad " THISCALL_NAME(name) "\n"
|
||||
|
||||
#define __ASM_VTABLE(name,funcs) \
|
||||
__asm__(".data\n" \
|
||||
"\t.balign 8\n" \
|
||||
"\t.quad " __ASM_NAME(#name "_rtti") "\n" \
|
||||
"\t.globl " __ASM_NAME(#name "_vtable") "\n" \
|
||||
__ASM_NAME(#name "_vtable") ":\n" \
|
||||
funcs "\n\t.text")
|
||||
|
||||
#else
|
||||
|
||||
#define VTABLE_ADD_FUNC(name) "\t.long " THISCALL_NAME(name) "\n"
|
||||
|
||||
#define __ASM_VTABLE(name,funcs) \
|
||||
__asm__(".data\n" \
|
||||
"\t.balign 4\n" \
|
||||
"\t.long " __ASM_NAME(#name "_rtti") "\n" \
|
||||
"\t.globl " __ASM_NAME(#name "_vtable") "\n" \
|
||||
__ASM_NAME(#name "_vtable") ":\n" \
|
||||
funcs "\n\t.text")
|
||||
|
||||
#endif /* _WIN64 */
|
||||
|
||||
#ifndef RTTI_USE_RVA
|
||||
|
||||
#define DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
static type_info name ## _type_info = { \
|
||||
&type_info_vtable, \
|
||||
NULL, \
|
||||
mangled_name \
|
||||
}; \
|
||||
\
|
||||
static const rtti_base_descriptor name ## _rtti_base_descriptor = { \
|
||||
&name ##_type_info, \
|
||||
base_classes_no, \
|
||||
{ 0, -1, 0}, \
|
||||
64 \
|
||||
};
|
||||
|
||||
#define DEFINE_RTTI_DATA(name, off, base_classes_no, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, cl9, mangled_name) \
|
||||
DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
\
|
||||
static const rtti_base_array name ## _rtti_base_array = { \
|
||||
{ \
|
||||
&name ## _rtti_base_descriptor, \
|
||||
cl1, \
|
||||
cl2, \
|
||||
cl3, \
|
||||
cl4, \
|
||||
cl5, \
|
||||
cl6, \
|
||||
cl7, \
|
||||
cl8, \
|
||||
cl9, \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
static const rtti_object_hierarchy name ## _hierarchy = { \
|
||||
0, \
|
||||
0, \
|
||||
base_classes_no+1, \
|
||||
&name ## _rtti_base_array \
|
||||
}; \
|
||||
\
|
||||
const rtti_object_locator name ## _rtti = { \
|
||||
0, \
|
||||
off, \
|
||||
0, \
|
||||
&name ## _type_info, \
|
||||
&name ## _hierarchy \
|
||||
};
|
||||
|
||||
#define DEFINE_CXX_TYPE_INFO(type) \
|
||||
static const cxx_type_info type ## _cxx_type_info = { \
|
||||
0, \
|
||||
& type ##_type_info, \
|
||||
{ 0, -1, 0 }, \
|
||||
sizeof(type), \
|
||||
THISCALL(type ##_copy_ctor) \
|
||||
};
|
||||
|
||||
#define DEFINE_CXX_DATA(type, base_no, cl1, cl2, cl3, cl4, dtor) \
|
||||
DEFINE_CXX_TYPE_INFO(type) \
|
||||
\
|
||||
static const cxx_type_info_table type ## _cxx_type_table = { \
|
||||
base_no+1, \
|
||||
{ \
|
||||
& type ## _cxx_type_info, \
|
||||
cl1, \
|
||||
cl2, \
|
||||
cl3, \
|
||||
cl4 \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
static const cxx_exception_type type ## _exception_type = { \
|
||||
0, \
|
||||
THISCALL(dtor), \
|
||||
NULL, \
|
||||
& type ## _cxx_type_table \
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define __DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
static type_info name ## _type_info = { \
|
||||
&type_info_vtable, \
|
||||
NULL, \
|
||||
mangled_name \
|
||||
}; \
|
||||
\
|
||||
static rtti_base_descriptor name ## _rtti_base_descriptor = { \
|
||||
0xdeadbeef, \
|
||||
base_classes_no, \
|
||||
{ 0, -1, 0}, \
|
||||
64 \
|
||||
};
|
||||
|
||||
#define DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
__DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
\
|
||||
static void init_ ## name ## _rtti(char *base) \
|
||||
{ \
|
||||
name ## _rtti_base_descriptor.type_descriptor = (char*)&name ## _type_info - base; \
|
||||
}
|
||||
|
||||
#define DEFINE_RTTI_DATA(name, off, base_classes_no, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, cl9, mangled_name) \
|
||||
__DEFINE_RTTI_BASE(name, base_classes_no, mangled_name) \
|
||||
\
|
||||
static rtti_base_array name ## _rtti_base_array = { \
|
||||
{ \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
static rtti_object_hierarchy name ## _hierarchy = { \
|
||||
0, \
|
||||
0, \
|
||||
base_classes_no+1, \
|
||||
0xdeadbeef \
|
||||
}; \
|
||||
\
|
||||
rtti_object_locator name ## _rtti = { \
|
||||
1, \
|
||||
off, \
|
||||
0, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef \
|
||||
};\
|
||||
\
|
||||
static void init_ ## name ## _rtti(char *base) \
|
||||
{ \
|
||||
name ## _rtti_base_descriptor.type_descriptor = (char*)&name ## _type_info - base; \
|
||||
name ## _rtti_base_array.bases[0] = (char*)&name ## _rtti_base_descriptor - base; \
|
||||
name ## _rtti_base_array.bases[1] = (char*)cl1 - base; \
|
||||
name ## _rtti_base_array.bases[2] = (char*)cl2 - base; \
|
||||
name ## _rtti_base_array.bases[3] = (char*)cl3 - base; \
|
||||
name ## _rtti_base_array.bases[4] = (char*)cl4 - base; \
|
||||
name ## _rtti_base_array.bases[5] = (char*)cl5 - base; \
|
||||
name ## _rtti_base_array.bases[6] = (char*)cl6 - base; \
|
||||
name ## _rtti_base_array.bases[7] = (char*)cl7 - base; \
|
||||
name ## _rtti_base_array.bases[8] = (char*)cl8 - base; \
|
||||
name ## _rtti_base_array.bases[9] = (char*)cl9 - base; \
|
||||
name ## _hierarchy.base_classes = (char*)&name ## _rtti_base_array - base; \
|
||||
name ## _rtti.type_descriptor = (char*)&name ## _type_info - base; \
|
||||
name ## _rtti.type_hierarchy = (char*)&name ## _hierarchy - base; \
|
||||
name ## _rtti.object_locator = (char*)&name ## _rtti - base; \
|
||||
}
|
||||
|
||||
#define DEFINE_CXX_TYPE_INFO(type) \
|
||||
static cxx_type_info type ## _cxx_type_info = { \
|
||||
0, \
|
||||
0xdeadbeef, \
|
||||
{ 0, -1, 0 }, \
|
||||
sizeof(type), \
|
||||
0xdeadbeef \
|
||||
}; \
|
||||
\
|
||||
static void init_ ## type ## _cxx_type_info(char *base) \
|
||||
{ \
|
||||
type ## _cxx_type_info.type_info = (char *)&type ## _type_info - base; \
|
||||
type ## _cxx_type_info.copy_ctor = (char *)type ## _copy_ctor - base; \
|
||||
}
|
||||
|
||||
#define DEFINE_CXX_DATA(type, base_no, cl1, cl2, cl3, cl4, dtor) \
|
||||
\
|
||||
DEFINE_CXX_TYPE_INFO(type) \
|
||||
\
|
||||
static cxx_type_info_table type ## _cxx_type_table = { \
|
||||
base_no+1, \
|
||||
{ \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef, \
|
||||
0xdeadbeef \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
static cxx_exception_type type ##_exception_type = { \
|
||||
0, \
|
||||
0xdeadbeef, \
|
||||
0, \
|
||||
0xdeadbeef \
|
||||
}; \
|
||||
\
|
||||
static void init_ ## type ## _cxx(char *base) \
|
||||
{ \
|
||||
init_ ## type ## _cxx_type_info(base); \
|
||||
type ## _cxx_type_table.info[0] = (char *)&type ## _cxx_type_info - base; \
|
||||
type ## _cxx_type_table.info[1] = (char *)cl1 - base; \
|
||||
type ## _cxx_type_table.info[2] = (char *)cl2 - base; \
|
||||
type ## _cxx_type_table.info[3] = (char *)cl3 - base; \
|
||||
type ## _cxx_type_table.info[4] = (char *)cl4 - base; \
|
||||
type ## _exception_type.destructor = (char *)dtor - base; \
|
||||
type ## _exception_type.type_info_table = (char *)&type ## _cxx_type_table - base; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define DEFINE_RTTI_DATA0(name, off, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA1(name, off, cl1, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 1, cl1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA2(name, off, cl1, cl2, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 2, cl1, cl2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA3(name, off, cl1, cl2, cl3, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 3, cl1, cl2, cl3, NULL, NULL, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA4(name, off, cl1, cl2, cl3, cl4, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 4, cl1, cl2, cl3, cl4, NULL, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA5(name, off, cl1, cl2, cl3, cl4, cl5, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 5, cl1, cl2, cl3, cl4, cl5, NULL, NULL, NULL, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA8(name, off, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 8, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, NULL, mangled_name)
|
||||
#define DEFINE_RTTI_DATA9(name, off, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, cl9, mangled_name) \
|
||||
DEFINE_RTTI_DATA(name, off, 9, cl1, cl2, cl3, cl4, cl5, cl6, cl7, cl8, cl9, mangled_name)
|
||||
|
||||
#define DEFINE_CXX_DATA0(name, dtor) \
|
||||
DEFINE_CXX_DATA(name, 0, NULL, NULL, NULL, NULL, dtor)
|
||||
#define DEFINE_CXX_DATA1(name, cl1, dtor) \
|
||||
DEFINE_CXX_DATA(name, 1, cl1, NULL, NULL, NULL, dtor)
|
||||
#define DEFINE_CXX_DATA2(name, cl1, cl2, dtor) \
|
||||
DEFINE_CXX_DATA(name, 2, cl1, cl2, NULL, NULL, dtor)
|
||||
#define DEFINE_CXX_DATA3(name, cl1, cl2, cl3, dtor) \
|
||||
DEFINE_CXX_DATA(name, 3, cl1, cl2, cl3, NULL, dtor)
|
||||
#define DEFINE_CXX_DATA4(name, cl1, cl2, cl3, cl4, dtor) \
|
||||
DEFINE_CXX_DATA(name, 4, cl1, cl2, cl3, cl4, dtor)
|
||||
|
||||
#ifdef __ASM_USE_THISCALL_WRAPPER
|
||||
|
||||
#define CALL_VTBL_FUNC(this, off, ret, type, args) ((ret (WINAPI*)type)&vtbl_wrapper_##off)args
|
||||
|
||||
extern void *vtbl_wrapper_0;
|
||||
extern void *vtbl_wrapper_4;
|
||||
extern void *vtbl_wrapper_8;
|
||||
extern void *vtbl_wrapper_12;
|
||||
extern void *vtbl_wrapper_16;
|
||||
extern void *vtbl_wrapper_20;
|
||||
extern void *vtbl_wrapper_24;
|
||||
extern void *vtbl_wrapper_28;
|
||||
extern void *vtbl_wrapper_32;
|
||||
extern void *vtbl_wrapper_36;
|
||||
extern void *vtbl_wrapper_40;
|
||||
extern void *vtbl_wrapper_44;
|
||||
extern void *vtbl_wrapper_48;
|
||||
extern void *vtbl_wrapper_52;
|
||||
extern void *vtbl_wrapper_56;
|
||||
|
||||
#else
|
||||
|
||||
#define CALL_VTBL_FUNC(this, off, ret, type, args) ((ret (__thiscall***)type)this)[0][off/4]args
|
||||
|
||||
#endif
|
||||
|
||||
/* exception object */
|
||||
typedef void (*vtable_ptr)(void);
|
||||
typedef struct __exception
|
||||
{
|
||||
const vtable_ptr *vtable;
|
||||
char *name; /* Name of this exception, always a new copy for each object */
|
||||
int do_free; /* Whether to free 'name' in our dtor */
|
||||
} exception;
|
||||
|
||||
/* rtti */
|
||||
typedef struct __type_info
|
||||
{
|
||||
const vtable_ptr *vtable;
|
||||
char *name; /* Unmangled name, allocated lazily */
|
||||
char mangled[128]; /* Variable length, but we declare it large enough for static RTTI */
|
||||
} type_info;
|
||||
|
||||
/* offsets for computing the this pointer */
|
||||
typedef struct
|
||||
{
|
||||
int this_offset; /* offset of base class this pointer from start of object */
|
||||
int vbase_descr; /* offset of virtual base class descriptor */
|
||||
int vbase_offset; /* offset of this pointer offset in virtual base class descriptor */
|
||||
} this_ptr_offsets;
|
||||
|
||||
#ifndef RTTI_USE_RVA
|
||||
|
||||
typedef struct _rtti_base_descriptor
|
||||
{
|
||||
const type_info *type_descriptor;
|
||||
int num_base_classes;
|
||||
this_ptr_offsets offsets; /* offsets for computing the this pointer */
|
||||
unsigned int attributes;
|
||||
} rtti_base_descriptor;
|
||||
|
||||
typedef struct _rtti_base_array
|
||||
{
|
||||
const rtti_base_descriptor *bases[10]; /* First element is the class itself */
|
||||
} rtti_base_array;
|
||||
|
||||
typedef struct _rtti_object_hierarchy
|
||||
{
|
||||
unsigned int signature;
|
||||
unsigned int attributes;
|
||||
int array_len; /* Size of the array pointed to by 'base_classes' */
|
||||
const rtti_base_array *base_classes;
|
||||
} rtti_object_hierarchy;
|
||||
|
||||
typedef struct _rtti_object_locator
|
||||
{
|
||||
unsigned int signature;
|
||||
int base_class_offset;
|
||||
unsigned int flags;
|
||||
const type_info *type_descriptor;
|
||||
const rtti_object_hierarchy *type_hierarchy;
|
||||
} rtti_object_locator;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT flags;
|
||||
const type_info *type_info;
|
||||
this_ptr_offsets offsets;
|
||||
unsigned int size;
|
||||
void *copy_ctor;
|
||||
} cxx_type_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT count;
|
||||
const cxx_type_info *info[5];
|
||||
} cxx_type_info_table;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT flags;
|
||||
void *destructor;
|
||||
void *custom_handler;
|
||||
const cxx_type_info_table *type_info_table;
|
||||
} cxx_exception_type;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int type_descriptor;
|
||||
int num_base_classes;
|
||||
this_ptr_offsets offsets; /* offsets for computing the this pointer */
|
||||
unsigned int attributes;
|
||||
} rtti_base_descriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int bases[10]; /* First element is the class itself */
|
||||
} rtti_base_array;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int signature;
|
||||
unsigned int attributes;
|
||||
int array_len; /* Size of the array pointed to by 'base_classes' */
|
||||
unsigned int base_classes;
|
||||
} rtti_object_hierarchy;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int signature;
|
||||
int base_class_offset;
|
||||
unsigned int flags;
|
||||
unsigned int type_descriptor;
|
||||
unsigned int type_hierarchy;
|
||||
unsigned int object_locator;
|
||||
} rtti_object_locator;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT flags;
|
||||
unsigned int type_info;
|
||||
this_ptr_offsets offsets;
|
||||
unsigned int size;
|
||||
unsigned int copy_ctor;
|
||||
} cxx_type_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT count;
|
||||
unsigned int info[5];
|
||||
} cxx_type_info_table;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT flags;
|
||||
unsigned int destructor;
|
||||
unsigned int custom_handler;
|
||||
unsigned int type_info_table;
|
||||
} cxx_exception_type;
|
||||
|
||||
#endif
|
||||
|
||||
extern const vtable_ptr type_info_vtable;
|
||||
|
||||
#ifdef RTTI_USE_RVA
|
||||
|
||||
static inline uintptr_t rtti_rva_base( const void *ptr )
|
||||
{
|
||||
void *base;
|
||||
return (uintptr_t)RtlPcToFileHeader( (void *)ptr, &base );
|
||||
}
|
||||
|
||||
static inline void *rtti_rva( unsigned int rva, uintptr_t base )
|
||||
{
|
||||
return (void *)(base + rva);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uintptr_t rtti_rva_base( const void *ptr )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *rtti_rva( const void *ptr, uintptr_t base )
|
||||
{
|
||||
return (void *)ptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define CREATE_TYPE_INFO_VTABLE \
|
||||
DEFINE_THISCALL_WRAPPER(type_info_vector_dtor,8) \
|
||||
void * __thiscall type_info_vector_dtor(type_info * _this, unsigned int flags) \
|
||||
{ \
|
||||
if (flags & 2) \
|
||||
{ \
|
||||
/* we have an array, with the number of elements stored before the first object */ \
|
||||
INT_PTR i, *ptr = (INT_PTR *)_this - 1; \
|
||||
\
|
||||
for (i = *ptr - 1; i >= 0; i--) free(_this[i].name); \
|
||||
free(ptr); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
free(_this->name); \
|
||||
if (flags & 1) free(_this); \
|
||||
} \
|
||||
return _this; \
|
||||
} \
|
||||
\
|
||||
DEFINE_RTTI_DATA0( type_info, 0, ".?AVtype_info@@" ) \
|
||||
\
|
||||
__ASM_BLOCK_BEGIN(type_info_vtables) \
|
||||
__ASM_VTABLE(type_info, \
|
||||
VTABLE_ADD_FUNC(type_info_vector_dtor)); \
|
||||
__ASM_BLOCK_END
|
||||
@@ -0,0 +1,735 @@
|
||||
/*
|
||||
* msvcrt.dll dll data items
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include "msvcrt.h"
|
||||
#include <winnls.h>
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
static WCHAR **initial_wargv;
|
||||
static int initial_argc;
|
||||
int MSVCRT___argc = 0;
|
||||
static int wargc_expand;
|
||||
unsigned int MSVCRT__commode = 0;
|
||||
int MSVCRT__fmode = 0;
|
||||
unsigned int MSVCRT__osver = 0;
|
||||
unsigned int MSVCRT__osplatform = 0;
|
||||
unsigned int MSVCRT__winmajor = 0;
|
||||
unsigned int MSVCRT__winminor = 0;
|
||||
unsigned int MSVCRT__winver = 0;
|
||||
#ifdef _CRTDLL
|
||||
unsigned int CRTDLL__basemajor_dll = 0;
|
||||
unsigned int CRTDLL__baseminor_dll = 0;
|
||||
unsigned int CRTDLL__baseversion_dll = 0;
|
||||
unsigned int CRTDLL__cpumode_dll = 1;
|
||||
unsigned int CRTDLL__osmode_dll = 1;
|
||||
#endif
|
||||
unsigned int MSVCRT___setlc_active = 0;
|
||||
unsigned int MSVCRT___unguarded_readlc_active = 0;
|
||||
double MSVCRT__HUGE = 0;
|
||||
char **MSVCRT___argv = NULL;
|
||||
wchar_t **MSVCRT___wargv = NULL;
|
||||
static wchar_t **wargv_expand;
|
||||
char *MSVCRT__acmdln = NULL;
|
||||
wchar_t *MSVCRT__wcmdln = NULL;
|
||||
char **MSVCRT__environ = NULL;
|
||||
wchar_t **MSVCRT__wenviron = NULL;
|
||||
char **MSVCRT___initenv = NULL;
|
||||
wchar_t **MSVCRT___winitenv = NULL;
|
||||
int MSVCRT_app_type = 0;
|
||||
char* MSVCRT__pgmptr = NULL;
|
||||
WCHAR* MSVCRT__wpgmptr = NULL;
|
||||
|
||||
static char **build_argv( WCHAR **wargv )
|
||||
{
|
||||
int argc;
|
||||
char *p, **argv;
|
||||
DWORD total = 0;
|
||||
|
||||
for (argc = 0; wargv[argc]; argc++)
|
||||
total += WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, NULL, 0, NULL, NULL );
|
||||
|
||||
argv = HeapAlloc( GetProcessHeap(), 0, total + (argc + 1) * sizeof(*argv) );
|
||||
p = (char *)(argv + argc + 1);
|
||||
for (argc = 0; wargv[argc]; argc++)
|
||||
{
|
||||
DWORD reslen = WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, p, total, NULL, NULL );
|
||||
argv[argc] = p;
|
||||
p += reslen;
|
||||
total -= reslen;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
static WCHAR **cmdline_to_argv( const WCHAR *src, int *ret_argc )
|
||||
{
|
||||
WCHAR **argv, *arg, *dst;
|
||||
int argc, in_quotes = 0, bcount = 0, len = wcslen(src) + 1;
|
||||
|
||||
argc = 2 + len / 2;
|
||||
argv = HeapAlloc( GetProcessHeap(), 0, argc * sizeof(*argv) + len * sizeof(WCHAR) );
|
||||
arg = dst = (WCHAR *)(argv + argc);
|
||||
argc = 0;
|
||||
while (*src)
|
||||
{
|
||||
if ((*src == ' ' || *src == '\t') && !in_quotes)
|
||||
{
|
||||
/* skip the remaining spaces */
|
||||
while (*src == ' ' || *src == '\t') src++;
|
||||
if (!*src) break;
|
||||
/* close the argument and copy it */
|
||||
*dst++ = 0;
|
||||
argv[argc++] = arg;
|
||||
/* start with a new argument */
|
||||
arg = dst;
|
||||
bcount = 0;
|
||||
}
|
||||
else if (*src == '\\')
|
||||
{
|
||||
*dst++ = *src++;
|
||||
bcount++;
|
||||
}
|
||||
else if (*src == '"')
|
||||
{
|
||||
if ((bcount & 1) == 0)
|
||||
{
|
||||
/* Preceded by an even number of '\', this is half that
|
||||
* number of '\', plus a '"' which we discard.
|
||||
*/
|
||||
dst -= bcount / 2;
|
||||
src++;
|
||||
if (in_quotes && *src == '"') *dst++ = *src++;
|
||||
else in_quotes = !in_quotes;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Preceded by an odd number of '\', this is half that
|
||||
* number of '\' followed by a '"'
|
||||
*/
|
||||
dst -= bcount / 2 + 1;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
bcount = 0;
|
||||
}
|
||||
else /* a regular character */
|
||||
{
|
||||
*dst++ = *src++;
|
||||
bcount = 0;
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
argv[argc++] = arg;
|
||||
argv[argc] = NULL;
|
||||
*ret_argc = argc;
|
||||
return argv;
|
||||
}
|
||||
|
||||
typedef void (CDECL *_INITTERMFUN)(void);
|
||||
typedef int (CDECL *_INITTERM_E_FN)(void);
|
||||
|
||||
/***********************************************************************
|
||||
* __p___argc (MSVCRT.@)
|
||||
*/
|
||||
int* CDECL __p___argc(void) { return &MSVCRT___argc; }
|
||||
|
||||
/***********************************************************************
|
||||
* __p__commode (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__commode(void) { return &MSVCRT__commode; }
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* __p__pgmptr (MSVCRT.@)
|
||||
*/
|
||||
char** CDECL __p__pgmptr(void) { return &MSVCRT__pgmptr; }
|
||||
|
||||
/***********************************************************************
|
||||
* __p__wpgmptr (MSVCRT.@)
|
||||
*/
|
||||
WCHAR** CDECL __p__wpgmptr(void) { return &MSVCRT__wpgmptr; }
|
||||
|
||||
/***********************************************************************
|
||||
* _get_pgmptr (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_pgmptr(char** p)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(p)) return EINVAL;
|
||||
|
||||
*p = MSVCRT__pgmptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* _get_wpgmptr (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_wpgmptr(WCHAR** p)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(p)) return EINVAL;
|
||||
*p = MSVCRT__wpgmptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* __p__fmode (MSVCRT.@)
|
||||
*/
|
||||
int* CDECL __p__fmode(void) { return &MSVCRT__fmode; }
|
||||
|
||||
/***********************************************************************
|
||||
* _set_fmode (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _set_fmode(int mode)
|
||||
{
|
||||
/* TODO: support _O_WTEXT */
|
||||
if(!MSVCRT_CHECK_PMT(mode==_O_TEXT || mode==_O_BINARY))
|
||||
return EINVAL;
|
||||
|
||||
MSVCRT__fmode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* _get_fmode (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_fmode(int *mode)
|
||||
{
|
||||
if(!MSVCRT_CHECK_PMT(mode))
|
||||
return EINVAL;
|
||||
|
||||
*mode = MSVCRT__fmode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* __p__osver (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__osver(void) { return &MSVCRT__osver; }
|
||||
|
||||
/***********************************************************************
|
||||
* __p__winmajor (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__winmajor(void) { return &MSVCRT__winmajor; }
|
||||
|
||||
/***********************************************************************
|
||||
* __p__winminor (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__winminor(void) { return &MSVCRT__winminor; }
|
||||
|
||||
/***********************************************************************
|
||||
* __p__winver (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__winver(void) { return &MSVCRT__winver; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p__acmdln (MSVCRT.@)
|
||||
*/
|
||||
char** CDECL __p__acmdln(void) { return &MSVCRT__acmdln; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p__wcmdln (MSVCRT.@)
|
||||
*/
|
||||
wchar_t** CDECL __p__wcmdln(void) { return &MSVCRT__wcmdln; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p___argv (MSVCRT.@)
|
||||
*/
|
||||
char*** CDECL __p___argv(void) { return &MSVCRT___argv; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p___wargv (MSVCRT.@)
|
||||
*/
|
||||
wchar_t*** CDECL __p___wargv(void) { return &MSVCRT___wargv; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p__environ (MSVCRT.@)
|
||||
*/
|
||||
char*** CDECL __p__environ(void)
|
||||
{
|
||||
return &MSVCRT__environ;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __p__wenviron (MSVCRT.@)
|
||||
*/
|
||||
wchar_t*** CDECL __p__wenviron(void)
|
||||
{
|
||||
return &MSVCRT__wenviron;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __p___initenv (MSVCRT.@)
|
||||
*/
|
||||
char*** CDECL __p___initenv(void) { return &MSVCRT___initenv; }
|
||||
|
||||
/*********************************************************************
|
||||
* __p___winitenv (MSVCRT.@)
|
||||
*/
|
||||
wchar_t*** CDECL __p___winitenv(void) { return &MSVCRT___winitenv; }
|
||||
|
||||
/*********************************************************************
|
||||
* _get_osplatform (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_osplatform(int *pValue)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(pValue != NULL)) return EINVAL;
|
||||
*pValue = MSVCRT__osplatform;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* INTERNAL: Create a wide string from an ascii string */
|
||||
wchar_t *msvcrt_wstrdupa(const char *str)
|
||||
{
|
||||
const unsigned int len = strlen(str) + 1 ;
|
||||
wchar_t *wstr = malloc(len* sizeof (wchar_t));
|
||||
if (!wstr)
|
||||
return NULL;
|
||||
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
|
||||
return wstr;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ___unguarded_readlc_active_add_func (MSVCRT.@)
|
||||
*/
|
||||
unsigned int * CDECL ___unguarded_readlc_active_add_func(void)
|
||||
{
|
||||
return &MSVCRT___unguarded_readlc_active;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ___setlc_active_func (MSVCRT.@)
|
||||
*/
|
||||
unsigned int CDECL ___setlc_active_func(void)
|
||||
{
|
||||
return MSVCRT___setlc_active;
|
||||
}
|
||||
|
||||
/* INTERNAL: Since we can't rely on Winelib startup code calling w/getmainargs,
|
||||
* we initialise data values during DLL loading. When called by a native
|
||||
* program we simply return the data we've already initialised. This also means
|
||||
* you can call multiple times without leaking
|
||||
*/
|
||||
void msvcrt_init_args(void)
|
||||
{
|
||||
OSVERSIONINFOW osvi;
|
||||
|
||||
MSVCRT__acmdln = _strdup( GetCommandLineA() );
|
||||
MSVCRT__wcmdln = _wcsdup( GetCommandLineW() );
|
||||
initial_wargv = cmdline_to_argv( GetCommandLineW(), &initial_argc );
|
||||
MSVCRT___argc = initial_argc;
|
||||
MSVCRT___wargv = initial_wargv;
|
||||
MSVCRT___argv = build_argv( initial_wargv );
|
||||
|
||||
TRACE("got %s, wide = %s argc=%d\n", debugstr_a(MSVCRT__acmdln),
|
||||
debugstr_w(MSVCRT__wcmdln),MSVCRT___argc);
|
||||
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
||||
GetVersionExW( &osvi );
|
||||
MSVCRT__winver = (osvi.dwMajorVersion << 8) | osvi.dwMinorVersion;
|
||||
MSVCRT__winmajor = osvi.dwMajorVersion;
|
||||
MSVCRT__winminor = osvi.dwMinorVersion;
|
||||
MSVCRT__osver = osvi.dwBuildNumber;
|
||||
MSVCRT__osplatform = osvi.dwPlatformId;
|
||||
TRACE( "winver %08x winmajor %08x winminor %08x osver %08x\n",
|
||||
MSVCRT__winver, MSVCRT__winmajor, MSVCRT__winminor, MSVCRT__osver);
|
||||
#ifdef _CRTDLL
|
||||
CRTDLL__baseversion_dll = (GetVersion() >> 16);
|
||||
CRTDLL__basemajor_dll = CRTDLL__baseversion_dll >> 8;
|
||||
CRTDLL__baseminor_dll = CRTDLL__baseversion_dll & 0xff;
|
||||
#endif
|
||||
|
||||
MSVCRT__HUGE = HUGE_VAL;
|
||||
MSVCRT___setlc_active = 0;
|
||||
MSVCRT___unguarded_readlc_active = 0;
|
||||
MSVCRT__fmode = _O_TEXT;
|
||||
|
||||
env_init(FALSE, FALSE);
|
||||
|
||||
MSVCRT__pgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
|
||||
if (MSVCRT__pgmptr)
|
||||
{
|
||||
if (!GetModuleFileNameA(0, MSVCRT__pgmptr, MAX_PATH))
|
||||
MSVCRT__pgmptr[0] = '\0';
|
||||
else
|
||||
MSVCRT__pgmptr[MAX_PATH - 1] = '\0';
|
||||
}
|
||||
|
||||
MSVCRT__wpgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
|
||||
if (MSVCRT__wpgmptr)
|
||||
{
|
||||
if (!GetModuleFileNameW(0, MSVCRT__wpgmptr, MAX_PATH))
|
||||
MSVCRT__wpgmptr[0] = '\0';
|
||||
else
|
||||
MSVCRT__wpgmptr[MAX_PATH - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* INTERNAL: free memory used by args */
|
||||
void msvcrt_free_args(void)
|
||||
{
|
||||
/* FIXME: more things to free */
|
||||
HeapFree(GetProcessHeap(), 0, MSVCRT___argv);
|
||||
HeapFree(GetProcessHeap(), 0, MSVCRT__pgmptr);
|
||||
HeapFree(GetProcessHeap(), 0, MSVCRT__wpgmptr);
|
||||
HeapFree(GetProcessHeap(), 0, wargv_expand);
|
||||
}
|
||||
|
||||
static int build_expanded_wargv(int *argc, wchar_t **argv)
|
||||
{
|
||||
int i, size=0, args_no=0, path_len;
|
||||
BOOL is_expandable;
|
||||
HANDLE h;
|
||||
|
||||
args_no = 0;
|
||||
for(i=0; i < initial_argc; i++) {
|
||||
WIN32_FIND_DATAW data;
|
||||
int len = 0;
|
||||
|
||||
is_expandable = FALSE;
|
||||
for(path_len = wcslen(initial_wargv[i])-1; path_len>=0; path_len--) {
|
||||
if(initial_wargv[i][path_len]=='*' || initial_wargv[i][path_len]=='?')
|
||||
is_expandable = TRUE;
|
||||
else if(initial_wargv[i][path_len]=='\\' || initial_wargv[i][path_len]=='/')
|
||||
break;
|
||||
}
|
||||
path_len++;
|
||||
|
||||
if(is_expandable)
|
||||
h = FindFirstFileW(initial_wargv[i], &data);
|
||||
else
|
||||
h = INVALID_HANDLE_VALUE;
|
||||
|
||||
if(h != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if(data.cFileName[0]=='.' && (data.cFileName[1]=='\0' ||
|
||||
(data.cFileName[1]=='.' && data.cFileName[2]=='\0')))
|
||||
continue;
|
||||
|
||||
len = wcslen(data.cFileName)+1;
|
||||
if(argv) {
|
||||
argv[args_no] = (wchar_t*)(argv+*argc+1)+size;
|
||||
memcpy(argv[args_no], initial_wargv[i], path_len*sizeof(wchar_t));
|
||||
memcpy(argv[args_no]+path_len, data.cFileName, len*sizeof(wchar_t));
|
||||
}
|
||||
args_no++;
|
||||
size += len+path_len;
|
||||
}while(FindNextFileW(h, &data));
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
if(!len) {
|
||||
len = wcslen(initial_wargv[i])+1;
|
||||
if(argv) {
|
||||
argv[args_no] = (wchar_t*)(argv+*argc+1)+size;
|
||||
memcpy(argv[args_no], initial_wargv[i], len*sizeof(wchar_t));
|
||||
}
|
||||
args_no++;
|
||||
size += len;
|
||||
}
|
||||
}
|
||||
|
||||
if(argv)
|
||||
argv[args_no] = NULL;
|
||||
size *= sizeof(wchar_t);
|
||||
size += (args_no+1)*sizeof(wchar_t*);
|
||||
*argc = args_no;
|
||||
return size;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __wgetmainargs (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __wgetmainargs(int *argc, wchar_t** *wargv, wchar_t** *wenvp,
|
||||
int expand_wildcards, int *new_mode)
|
||||
{
|
||||
TRACE("(%p,%p,%p,%d,%p).\n", argc, wargv, wenvp, expand_wildcards, new_mode);
|
||||
|
||||
if (expand_wildcards) {
|
||||
HeapFree(GetProcessHeap(), 0, wargv_expand);
|
||||
wargv_expand = HeapAlloc(GetProcessHeap(), 0,
|
||||
build_expanded_wargv(&wargc_expand, NULL));
|
||||
if (wargv_expand) {
|
||||
build_expanded_wargv(&wargc_expand, wargv_expand);
|
||||
|
||||
MSVCRT___argc = wargc_expand;
|
||||
MSVCRT___wargv = wargv_expand;
|
||||
}else {
|
||||
expand_wildcards = 0;
|
||||
}
|
||||
}
|
||||
if (!expand_wildcards) {
|
||||
MSVCRT___argc = initial_argc;
|
||||
MSVCRT___wargv = initial_wargv;
|
||||
}
|
||||
|
||||
env_init(TRUE, FALSE);
|
||||
|
||||
*argc = MSVCRT___argc;
|
||||
*wargv = MSVCRT___wargv;
|
||||
*wenvp = MSVCRT__wenviron;
|
||||
if (new_mode)
|
||||
_set_new_mode( *new_mode );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __getmainargs (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __getmainargs(int *argc, char** *argv, char** *envp,
|
||||
int expand_wildcards, int *new_mode)
|
||||
{
|
||||
TRACE("(%p,%p,%p,%d,%p).\n", argc, argv, envp, expand_wildcards, new_mode);
|
||||
|
||||
if (expand_wildcards) {
|
||||
HeapFree(GetProcessHeap(), 0, wargv_expand);
|
||||
wargv_expand = HeapAlloc(GetProcessHeap(), 0,
|
||||
build_expanded_wargv(&wargc_expand, NULL));
|
||||
if (wargv_expand) {
|
||||
build_expanded_wargv(&wargc_expand, wargv_expand);
|
||||
|
||||
MSVCRT___argc = wargc_expand;
|
||||
MSVCRT___argv = build_argv( wargv_expand );
|
||||
}else {
|
||||
expand_wildcards = 0;
|
||||
}
|
||||
}
|
||||
if (!expand_wildcards) {
|
||||
MSVCRT___argc = initial_argc;
|
||||
MSVCRT___argv = build_argv( initial_wargv );
|
||||
}
|
||||
|
||||
*argc = MSVCRT___argc;
|
||||
*argv = MSVCRT___argv;
|
||||
*envp = MSVCRT__environ;
|
||||
|
||||
if (new_mode)
|
||||
_set_new_mode( *new_mode );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _CRTDLL
|
||||
/*********************************************************************
|
||||
* __GetMainArgs (CRTDLL.@)
|
||||
*/
|
||||
void CDECL __GetMainArgs( int *argc, char ***argv, char ***envp, int expand_wildcards )
|
||||
{
|
||||
int new_mode = 0;
|
||||
__getmainargs( argc, argv, envp, expand_wildcards, &new_mode );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _initterm (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _initterm(_INITTERMFUN *start,_INITTERMFUN *end)
|
||||
{
|
||||
_INITTERMFUN* current = start;
|
||||
|
||||
TRACE("(%p,%p)\n",start,end);
|
||||
while (current<end)
|
||||
{
|
||||
if (*current)
|
||||
{
|
||||
TRACE("Call init function %p\n",*current);
|
||||
(**current)();
|
||||
TRACE("returned\n");
|
||||
}
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _initterm_e (MSVCRT.@)
|
||||
*
|
||||
* call an array of application initialization functions and report the return value
|
||||
*/
|
||||
int CDECL _initterm_e(_INITTERM_E_FN *table, _INITTERM_E_FN *end)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE("(%p, %p)\n", table, end);
|
||||
|
||||
while (!res && table < end) {
|
||||
if (*table) {
|
||||
TRACE("calling %p\n", **table);
|
||||
res = (**table)();
|
||||
if (res)
|
||||
TRACE("function %p failed: %#x\n", *table, res);
|
||||
|
||||
}
|
||||
table++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __set_app_type (MSVCRT.@)
|
||||
*/
|
||||
void CDECL __set_app_type(int app_type)
|
||||
{
|
||||
TRACE("(%d) %s application\n", app_type, app_type == 2 ? "Gui" : "Console");
|
||||
MSVCRT_app_type = app_type;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
|
||||
/*********************************************************************
|
||||
* _configure_narrow_argv (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _configure_narrow_argv(int mode)
|
||||
{
|
||||
TRACE("(%d)\n", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _initialize_narrow_environment (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _initialize_narrow_environment(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
return env_init(FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_initial_narrow_environment (UCRTBASE.@)
|
||||
*/
|
||||
char** CDECL _get_initial_narrow_environment(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
_initialize_narrow_environment();
|
||||
return MSVCRT___initenv;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _configure_wide_argv (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _configure_wide_argv(int mode)
|
||||
{
|
||||
WARN("(%d) stub\n", mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _initialize_wide_environment (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _initialize_wide_environment(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
return env_init(TRUE, FALSE);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_initial_wide_environment (UCRTBASE.@)
|
||||
*/
|
||||
wchar_t** CDECL _get_initial_wide_environment(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
_initialize_wide_environment();
|
||||
return MSVCRT___winitenv;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_narrow_winmain_command_line (UCRTBASE.@)
|
||||
*/
|
||||
char* CDECL _get_narrow_winmain_command_line(void)
|
||||
{
|
||||
static char *narrow_command_line;
|
||||
char *s;
|
||||
|
||||
if (narrow_command_line)
|
||||
return narrow_command_line;
|
||||
|
||||
s = GetCommandLineA();
|
||||
while (*s && *s != ' ' && *s != '\t')
|
||||
{
|
||||
if (*s++ == '"')
|
||||
{
|
||||
while (*s && *s++ != '"')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
while (*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
|
||||
return narrow_command_line = s;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_wide_winmain_command_line (UCRTBASE.@)
|
||||
*/
|
||||
wchar_t* CDECL _get_wide_winmain_command_line(void)
|
||||
{
|
||||
static wchar_t *wide_command_line;
|
||||
wchar_t *s;
|
||||
|
||||
if (wide_command_line)
|
||||
return wide_command_line;
|
||||
|
||||
s = GetCommandLineW();
|
||||
while (*s && *s != ' ' && *s != '\t')
|
||||
{
|
||||
if (*s++ == '"')
|
||||
{
|
||||
while (*s && *s++ != '"')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
while (*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
|
||||
return wide_command_line = s;
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=140 */
|
||||
|
||||
/*********************************************************************
|
||||
* _get_winmajor (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_winmajor(int* value)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
|
||||
*value = MSVCRT__winmajor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_winminor (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_winminor(int* value)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
|
||||
*value = MSVCRT__winminor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_osver (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_osver(int* value)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
|
||||
*value = MSVCRT__osver;
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* msvcrt.dll environment functions
|
||||
*
|
||||
* Copyright 1996,1998 Marcus Meissner
|
||||
* Copyright 1996 Jukka Iivonen
|
||||
* Copyright 1997,2000 Uwe Bonnes
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
#include <winnls.h>
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
int env_init(BOOL unicode, BOOL modif)
|
||||
{
|
||||
if (!unicode && !MSVCRT___initenv)
|
||||
{
|
||||
char *environ_strings = GetEnvironmentStringsA();
|
||||
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
|
||||
char *ptr;
|
||||
|
||||
for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
|
||||
{
|
||||
/* Don't count environment variables starting with '=' which are command shell specific */
|
||||
if (*ptr != '=') count++;
|
||||
len += strlen(ptr) + 1;
|
||||
}
|
||||
MSVCRT___initenv = malloc(count * sizeof(*MSVCRT___initenv) + len);
|
||||
if (!MSVCRT___initenv)
|
||||
{
|
||||
FreeEnvironmentStringsA(environ_strings);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&MSVCRT___initenv[count], environ_strings, len);
|
||||
for (ptr = (char *)&MSVCRT___initenv[count]; *ptr; ptr += strlen(ptr) + 1)
|
||||
{
|
||||
/* Skip special environment strings set by the command shell */
|
||||
if (*ptr != '=') MSVCRT___initenv[i++] = ptr;
|
||||
}
|
||||
MSVCRT___initenv[i] = NULL;
|
||||
FreeEnvironmentStringsA(environ_strings);
|
||||
|
||||
MSVCRT__environ = MSVCRT___initenv;
|
||||
}
|
||||
|
||||
if (!unicode && modif && MSVCRT__environ == MSVCRT___initenv)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(MSVCRT___initenv[i]) i++;
|
||||
MSVCRT__environ = malloc((i + 1) * sizeof(char *));
|
||||
if (!MSVCRT__environ) return -1;
|
||||
for (i = 0; MSVCRT___initenv[i]; i++)
|
||||
MSVCRT__environ[i] = strdup(MSVCRT___initenv[i]);
|
||||
MSVCRT__environ[i] = NULL;
|
||||
}
|
||||
|
||||
if (unicode && !MSVCRT___winitenv)
|
||||
{
|
||||
wchar_t *wenviron_strings = GetEnvironmentStringsW();
|
||||
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
|
||||
wchar_t *wptr;
|
||||
|
||||
for (wptr = wenviron_strings; *wptr; wptr += wcslen(wptr) + 1)
|
||||
{
|
||||
/* Don't count environment variables starting with '=' which are command shell specific */
|
||||
if (*wptr != '=') count++;
|
||||
len += wcslen(wptr) + 1;
|
||||
}
|
||||
MSVCRT___winitenv = malloc(count * sizeof(*MSVCRT___winitenv) + len * sizeof(wchar_t));
|
||||
if (!MSVCRT___winitenv)
|
||||
{
|
||||
FreeEnvironmentStringsW(wenviron_strings);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&MSVCRT___winitenv[count], wenviron_strings, len * sizeof(wchar_t));
|
||||
for (wptr = (wchar_t *)&MSVCRT___winitenv[count]; *wptr; wptr += wcslen(wptr) + 1)
|
||||
{
|
||||
/* Skip special environment strings set by the command shell */
|
||||
if (*wptr != '=') MSVCRT___winitenv[i++] = wptr;
|
||||
}
|
||||
MSVCRT___winitenv[i] = NULL;
|
||||
FreeEnvironmentStringsW(wenviron_strings);
|
||||
|
||||
MSVCRT__wenviron = MSVCRT___winitenv;
|
||||
}
|
||||
|
||||
if (unicode && modif && MSVCRT__wenviron == MSVCRT___winitenv)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(MSVCRT___winitenv[i]) i++;
|
||||
MSVCRT__wenviron = malloc((i + 1) * sizeof(wchar_t *));
|
||||
if (!MSVCRT__wenviron) return -1;
|
||||
for (i = 0; MSVCRT___winitenv[i]; i++)
|
||||
MSVCRT__wenviron[i] = wcsdup(MSVCRT___winitenv[i]);
|
||||
MSVCRT__wenviron[i] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int env_get_index(const char *name)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
len = strlen(name);
|
||||
for (i = 0; MSVCRT__environ[i]; i++)
|
||||
{
|
||||
if (!strnicmp(name, MSVCRT__environ[i], len) && MSVCRT__environ[i][len] == '=')
|
||||
return i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int wenv_get_index(const wchar_t *name)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
len = wcslen(name);
|
||||
for (i = 0; MSVCRT__wenviron[i]; i++)
|
||||
{
|
||||
if (!wcsnicmp(name, MSVCRT__wenviron[i], len) && MSVCRT__wenviron[i][len] == '=')
|
||||
return i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int env_set(char **env, wchar_t **wenv)
|
||||
{
|
||||
wchar_t *weq = wcschr(*wenv, '=');
|
||||
char *eq = strchr(*env, '=');
|
||||
int idx;
|
||||
|
||||
*weq = 0;
|
||||
if (!SetEnvironmentVariableW(*wenv, weq[1] ? weq + 1 : NULL) &&
|
||||
GetLastError() != ERROR_ENVVAR_NOT_FOUND)
|
||||
return -1;
|
||||
|
||||
if (env_init(FALSE, TRUE)) return -1;
|
||||
*eq = 0;
|
||||
idx = env_get_index(*env);
|
||||
*eq = '=';
|
||||
if (!eq[1])
|
||||
{
|
||||
free(MSVCRT__environ[idx]);
|
||||
for(; MSVCRT__environ[idx]; idx++)
|
||||
MSVCRT__environ[idx] = MSVCRT__environ[idx + 1];
|
||||
}
|
||||
else if (MSVCRT__environ[idx])
|
||||
{
|
||||
free(MSVCRT__environ[idx]);
|
||||
MSVCRT__environ[idx] = *env;
|
||||
*env = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char **new_env = realloc(MSVCRT__environ, (idx + 2) * sizeof(*MSVCRT__environ));
|
||||
if (!new_env) return -1;
|
||||
MSVCRT__environ = new_env;
|
||||
MSVCRT__environ[idx] = *env;
|
||||
MSVCRT__environ[idx + 1] = NULL;
|
||||
*env = NULL;
|
||||
}
|
||||
|
||||
if (!MSVCRT__wenviron) return 0;
|
||||
if (MSVCRT__wenviron == MSVCRT___winitenv)
|
||||
if (env_init(TRUE, TRUE)) return -1;
|
||||
idx = wenv_get_index(*wenv);
|
||||
*weq = '=';
|
||||
if (!weq[1])
|
||||
{
|
||||
free(MSVCRT__wenviron[idx]);
|
||||
for(; MSVCRT__wenviron[idx]; idx++)
|
||||
MSVCRT__wenviron[idx] = MSVCRT__wenviron[idx + 1];
|
||||
}
|
||||
else if (MSVCRT__wenviron[idx])
|
||||
{
|
||||
free(MSVCRT__wenviron[idx]);
|
||||
MSVCRT__wenviron[idx] = *wenv;
|
||||
*wenv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t **new_env = realloc(MSVCRT__wenviron, (idx + 2) * sizeof(*MSVCRT__wenviron));
|
||||
if (!new_env) return -1;
|
||||
MSVCRT__wenviron = new_env;
|
||||
MSVCRT__wenviron[idx] = *wenv;
|
||||
MSVCRT__wenviron[idx + 1] = NULL;
|
||||
*wenv = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char * getenv_helper(const char *name)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (!name) return NULL;
|
||||
|
||||
idx = env_get_index(name);
|
||||
if (!MSVCRT__environ[idx]) return NULL;
|
||||
return strchr(MSVCRT__environ[idx], '=') + 1;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* getenv (MSVCRT.@)
|
||||
*/
|
||||
char * CDECL getenv(const char *name)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(name != NULL)) return NULL;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
ret = getenv_helper(name);
|
||||
_unlock(_ENV_LOCK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static wchar_t * wgetenv_helper(const wchar_t *name)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (!name) return NULL;
|
||||
if (env_init(TRUE, FALSE)) return NULL;
|
||||
|
||||
idx = wenv_get_index(name);
|
||||
if (!MSVCRT__wenviron[idx]) return NULL;
|
||||
return wcschr(MSVCRT__wenviron[idx], '=') + 1;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wgetenv (MSVCRT.@)
|
||||
*/
|
||||
wchar_t * CDECL _wgetenv(const wchar_t *name)
|
||||
{
|
||||
wchar_t *ret;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(name != NULL)) return NULL;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
ret = wgetenv_helper(name);
|
||||
_unlock(_ENV_LOCK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int putenv_helper(const char *name, const char *val, const char *eq)
|
||||
{
|
||||
wchar_t *wenv;
|
||||
char *env;
|
||||
int r;
|
||||
|
||||
if (eq)
|
||||
{
|
||||
env = strdup(name);
|
||||
if (!env) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int name_len = strlen(name);
|
||||
|
||||
r = strlen(val);
|
||||
env = malloc(name_len + r + 2);
|
||||
if (!env) return -1;
|
||||
memcpy(env, name, name_len);
|
||||
env[name_len] = '=';
|
||||
strcpy(env + name_len + 1, val);
|
||||
}
|
||||
|
||||
wenv = msvcrt_wstrdupa(env);
|
||||
if (!wenv)
|
||||
{
|
||||
free(env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
r = env_set(&env, &wenv);
|
||||
_unlock(_ENV_LOCK);
|
||||
free(env);
|
||||
free(wenv);
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *msvcrt_astrdupw(const wchar_t *wstr)
|
||||
{
|
||||
const unsigned int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
char *str = malloc(len * sizeof(char));
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static int wputenv_helper(const wchar_t *name, const wchar_t *val, const wchar_t *eq)
|
||||
{
|
||||
wchar_t *wenv;
|
||||
char *env;
|
||||
int r;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
r = env_init(TRUE, TRUE);
|
||||
_unlock(_ENV_LOCK);
|
||||
if (r) return -1;
|
||||
|
||||
if (eq)
|
||||
{
|
||||
wenv = wcsdup(name);
|
||||
if (!wenv) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int name_len = wcslen(name);
|
||||
|
||||
r = wcslen(val);
|
||||
wenv = malloc((name_len + r + 2) * sizeof(wchar_t));
|
||||
if (!wenv) return -1;
|
||||
memcpy(wenv, name, name_len * sizeof(wchar_t));
|
||||
wenv[name_len] = '=';
|
||||
wcscpy(wenv + name_len + 1, val);
|
||||
}
|
||||
|
||||
env = msvcrt_astrdupw(wenv);
|
||||
if (!env)
|
||||
{
|
||||
free(wenv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
r = env_set(&env, &wenv);
|
||||
_unlock(_ENV_LOCK);
|
||||
free(env);
|
||||
free(wenv);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putenv (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _putenv(const char *str)
|
||||
{
|
||||
const char *eq;
|
||||
|
||||
TRACE("%s\n", debugstr_a(str));
|
||||
|
||||
if (!str || !(eq = strchr(str, '=')))
|
||||
return -1;
|
||||
|
||||
return putenv_helper(str, NULL, eq);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wputenv (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _wputenv(const wchar_t *str)
|
||||
{
|
||||
const wchar_t *eq;
|
||||
|
||||
TRACE("%s\n", debugstr_w(str));
|
||||
|
||||
if (!str || !(eq = wcschr(str, '=')))
|
||||
return -1;
|
||||
|
||||
return wputenv_helper(str, NULL, eq);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _putenv_s (MSVCRT.@)
|
||||
*/
|
||||
errno_t CDECL _putenv_s(const char *name, const char *value)
|
||||
{
|
||||
errno_t ret = 0;
|
||||
|
||||
TRACE("%s %s\n", debugstr_a(name), debugstr_a(value));
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(name != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
|
||||
|
||||
if (putenv_helper(name, value, NULL) < 0)
|
||||
{
|
||||
msvcrt_set_errno(GetLastError());
|
||||
ret = *_errno();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wputenv_s (MSVCRT.@)
|
||||
*/
|
||||
errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value)
|
||||
{
|
||||
errno_t ret = 0;
|
||||
|
||||
TRACE("%s %s\n", debugstr_w(name), debugstr_w(value));
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(name != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
|
||||
|
||||
if (wputenv_helper(name, value, NULL) < 0)
|
||||
{
|
||||
msvcrt_set_errno(GetLastError());
|
||||
ret = *_errno();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
|
||||
/******************************************************************
|
||||
* _dupenv_s (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _dupenv_s(char **buffer, size_t *numberOfElements, const char *varname)
|
||||
{
|
||||
char *e;
|
||||
size_t sz;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
if (!(e = getenv(varname)))
|
||||
{
|
||||
_unlock(_ENV_LOCK);
|
||||
*buffer = NULL;
|
||||
if (numberOfElements) *numberOfElements = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sz = strlen(e) + 1;
|
||||
*buffer = malloc(sz);
|
||||
if (*buffer) strcpy(*buffer, e);
|
||||
_unlock(_ENV_LOCK);
|
||||
|
||||
if (!*buffer)
|
||||
{
|
||||
if (numberOfElements) *numberOfElements = 0;
|
||||
return *_errno() = ENOMEM;
|
||||
}
|
||||
if (numberOfElements) *numberOfElements = sz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* _wdupenv_s (MSVCR80.@)
|
||||
*/
|
||||
int CDECL _wdupenv_s(wchar_t **buffer, size_t *numberOfElements,
|
||||
const wchar_t *varname)
|
||||
{
|
||||
wchar_t *e;
|
||||
size_t sz;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
if (!(e = _wgetenv(varname)))
|
||||
{
|
||||
_unlock(_ENV_LOCK);
|
||||
*buffer = NULL;
|
||||
if (numberOfElements) *numberOfElements = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sz = wcslen(e) + 1;
|
||||
*buffer = malloc(sz * sizeof(wchar_t));
|
||||
if (*buffer) wcscpy(*buffer, e);
|
||||
_unlock(_ENV_LOCK);
|
||||
|
||||
if (!*buffer)
|
||||
{
|
||||
if (numberOfElements) *numberOfElements = 0;
|
||||
return *_errno() = ENOMEM;
|
||||
}
|
||||
if (numberOfElements) *numberOfElements = sz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=80 */
|
||||
|
||||
/******************************************************************
|
||||
* getenv_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL getenv_s(size_t *ret_len, char* buffer, size_t len, const char *varname)
|
||||
{
|
||||
char *e;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(ret_len != NULL)) return EINVAL;
|
||||
*ret_len = 0;
|
||||
if (!MSVCRT_CHECK_PMT((buffer && len > 0) || (!buffer && !len))) return EINVAL;
|
||||
if (buffer) buffer[0] = 0;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
e = getenv_helper(varname);
|
||||
if (e)
|
||||
{
|
||||
*ret_len = strlen(e) + 1;
|
||||
if (len >= *ret_len) strcpy(buffer, e);
|
||||
}
|
||||
_unlock(_ENV_LOCK);
|
||||
|
||||
if (!e || !len) return 0;
|
||||
if (len < *ret_len) return ERANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* _wgetenv_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _wgetenv_s(size_t *ret_len, wchar_t *buffer, size_t len,
|
||||
const wchar_t *varname)
|
||||
{
|
||||
wchar_t *e;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(ret_len != NULL)) return EINVAL;
|
||||
*ret_len = 0;
|
||||
if (!MSVCRT_CHECK_PMT((buffer && len > 0) || (!buffer && !len))) return EINVAL;
|
||||
if (buffer) buffer[0] = 0;
|
||||
|
||||
_lock(_ENV_LOCK);
|
||||
e = wgetenv_helper(varname);
|
||||
if (e)
|
||||
{
|
||||
*ret_len = wcslen(e) + 1;
|
||||
if (len >= *ret_len) wcscpy(buffer, e);
|
||||
}
|
||||
_unlock(_ENV_LOCK);
|
||||
|
||||
if (!e || !len) return 0;
|
||||
if (len < *ret_len) return ERANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_environ (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _get_environ(char ***ptr)
|
||||
{
|
||||
*ptr = MSVCRT__environ;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_wenviron (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _get_wenviron(wchar_t ***ptr)
|
||||
{
|
||||
*ptr = MSVCRT__wenviron;
|
||||
}
|
||||
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* msvcrt.dll errno functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "winnls.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* error strings generated with glibc strerror */
|
||||
static char str_success[] = "Success";
|
||||
static char str_EPERM[] = "Operation not permitted";
|
||||
static char str_ENOENT[] = "No such file or directory";
|
||||
static char str_ESRCH[] = "No such process";
|
||||
static char str_EINTR[] = "Interrupted system call";
|
||||
static char str_EIO[] = "Input/output error";
|
||||
static char str_ENXIO[] = "No such device or address";
|
||||
static char str_E2BIG[] = "Argument list too long";
|
||||
static char str_ENOEXEC[] = "Exec format error";
|
||||
static char str_EBADF[] = "Bad file descriptor";
|
||||
static char str_ECHILD[] = "No child processes";
|
||||
static char str_EAGAIN[] = "Resource temporarily unavailable";
|
||||
static char str_ENOMEM[] = "Cannot allocate memory";
|
||||
static char str_EACCES[] = "Permission denied";
|
||||
static char str_EFAULT[] = "Bad address";
|
||||
static char str_EBUSY[] = "Device or resource busy";
|
||||
static char str_EEXIST[] = "File exists";
|
||||
static char str_EXDEV[] = "Invalid cross-device link";
|
||||
static char str_ENODEV[] = "No such device";
|
||||
static char str_ENOTDIR[] = "Not a directory";
|
||||
static char str_EISDIR[] = "Is a directory";
|
||||
static char str_EINVAL[] = "Invalid argument";
|
||||
static char str_ENFILE[] = "Too many open files in system";
|
||||
static char str_EMFILE[] = "Too many open files";
|
||||
static char str_ENOTTY[] = "Inappropriate ioctl for device";
|
||||
static char str_EFBIG[] = "File too large";
|
||||
static char str_ENOSPC[] = "No space left on device";
|
||||
static char str_ESPIPE[] = "Illegal seek";
|
||||
static char str_EROFS[] = "Read-only file system";
|
||||
static char str_EMLINK[] = "Too many links";
|
||||
static char str_EPIPE[] = "Broken pipe";
|
||||
static char str_EDOM[] = "Numerical argument out of domain";
|
||||
static char str_ERANGE[] = "Numerical result out of range";
|
||||
static char str_EDEADLK[] = "Resource deadlock avoided";
|
||||
static char str_ENAMETOOLONG[] = "File name too long";
|
||||
static char str_ENOLCK[] = "No locks available";
|
||||
static char str_ENOSYS[] = "Function not implemented";
|
||||
static char str_ENOTEMPTY[] = "Directory not empty";
|
||||
static char str_EILSEQ[] = "Invalid or incomplete multibyte or wide character";
|
||||
static char str_generic_error[] = "Unknown error";
|
||||
|
||||
char *MSVCRT__sys_errlist[] =
|
||||
{
|
||||
str_success,
|
||||
str_EPERM,
|
||||
str_ENOENT,
|
||||
str_ESRCH,
|
||||
str_EINTR,
|
||||
str_EIO,
|
||||
str_ENXIO,
|
||||
str_E2BIG,
|
||||
str_ENOEXEC,
|
||||
str_EBADF,
|
||||
str_ECHILD,
|
||||
str_EAGAIN,
|
||||
str_ENOMEM,
|
||||
str_EACCES,
|
||||
str_EFAULT,
|
||||
str_generic_error,
|
||||
str_EBUSY,
|
||||
str_EEXIST,
|
||||
str_EXDEV,
|
||||
str_ENODEV,
|
||||
str_ENOTDIR,
|
||||
str_EISDIR,
|
||||
str_EINVAL,
|
||||
str_ENFILE,
|
||||
str_EMFILE,
|
||||
str_ENOTTY,
|
||||
str_generic_error,
|
||||
str_EFBIG,
|
||||
str_ENOSPC,
|
||||
str_ESPIPE,
|
||||
str_EROFS,
|
||||
str_EMLINK,
|
||||
str_EPIPE,
|
||||
str_EDOM,
|
||||
str_ERANGE,
|
||||
str_generic_error,
|
||||
str_EDEADLK,
|
||||
str_generic_error,
|
||||
str_ENAMETOOLONG,
|
||||
str_ENOLCK,
|
||||
str_ENOSYS,
|
||||
str_ENOTEMPTY,
|
||||
str_EILSEQ,
|
||||
str_generic_error
|
||||
};
|
||||
|
||||
unsigned int MSVCRT__sys_nerr = ARRAY_SIZE(MSVCRT__sys_errlist) - 1;
|
||||
|
||||
static _invalid_parameter_handler invalid_parameter_handler = NULL;
|
||||
|
||||
/* INTERNAL: Set the crt and dos errno's from the OS error given. */
|
||||
void msvcrt_set_errno(int err)
|
||||
{
|
||||
int *errno_ptr = _errno();
|
||||
__msvcrt_ulong *doserrno = __doserrno();
|
||||
|
||||
*doserrno = err;
|
||||
|
||||
switch(err)
|
||||
{
|
||||
#define ERR_CASE(oserr) case oserr:
|
||||
#define ERR_MAPS(oserr, crterr) case oserr: *errno_ptr = crterr; break
|
||||
ERR_CASE(ERROR_ACCESS_DENIED)
|
||||
ERR_CASE(ERROR_NETWORK_ACCESS_DENIED)
|
||||
ERR_CASE(ERROR_CANNOT_MAKE)
|
||||
ERR_CASE(ERROR_SEEK_ON_DEVICE)
|
||||
ERR_CASE(ERROR_LOCK_FAILED)
|
||||
ERR_CASE(ERROR_FAIL_I24)
|
||||
ERR_CASE(ERROR_CURRENT_DIRECTORY)
|
||||
ERR_CASE(ERROR_DRIVE_LOCKED)
|
||||
ERR_CASE(ERROR_NOT_LOCKED)
|
||||
ERR_CASE(ERROR_INVALID_ACCESS)
|
||||
ERR_CASE(ERROR_SHARING_VIOLATION)
|
||||
ERR_MAPS(ERROR_LOCK_VIOLATION, EACCES);
|
||||
ERR_CASE(ERROR_FILE_NOT_FOUND)
|
||||
ERR_CASE(ERROR_NO_MORE_FILES)
|
||||
ERR_CASE(ERROR_BAD_PATHNAME)
|
||||
ERR_CASE(ERROR_BAD_NETPATH)
|
||||
ERR_CASE(ERROR_INVALID_DRIVE)
|
||||
ERR_CASE(ERROR_BAD_NET_NAME)
|
||||
ERR_CASE(ERROR_FILENAME_EXCED_RANGE)
|
||||
ERR_MAPS(ERROR_PATH_NOT_FOUND, ENOENT);
|
||||
ERR_MAPS(ERROR_IO_DEVICE, EIO);
|
||||
ERR_MAPS(ERROR_BAD_FORMAT, ENOEXEC);
|
||||
ERR_MAPS(ERROR_INVALID_HANDLE, EBADF);
|
||||
ERR_CASE(ERROR_OUTOFMEMORY)
|
||||
ERR_CASE(ERROR_INVALID_BLOCK)
|
||||
ERR_CASE(ERROR_NOT_ENOUGH_QUOTA)
|
||||
ERR_MAPS(ERROR_ARENA_TRASHED, ENOMEM);
|
||||
ERR_MAPS(ERROR_BUSY, EBUSY);
|
||||
ERR_CASE(ERROR_ALREADY_EXISTS)
|
||||
ERR_MAPS(ERROR_FILE_EXISTS, EEXIST);
|
||||
ERR_MAPS(ERROR_BAD_DEVICE, ENODEV);
|
||||
ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES, EMFILE);
|
||||
ERR_MAPS(ERROR_DISK_FULL, ENOSPC);
|
||||
ERR_MAPS(ERROR_BROKEN_PIPE, EPIPE);
|
||||
ERR_MAPS(ERROR_POSSIBLE_DEADLOCK, EDEADLK);
|
||||
ERR_MAPS(ERROR_DIR_NOT_EMPTY, ENOTEMPTY);
|
||||
ERR_MAPS(ERROR_BAD_ENVIRONMENT, E2BIG);
|
||||
ERR_CASE(ERROR_WAIT_NO_CHILDREN)
|
||||
ERR_MAPS(ERROR_CHILD_NOT_COMPLETE, ECHILD);
|
||||
ERR_CASE(ERROR_NO_PROC_SLOTS)
|
||||
ERR_CASE(ERROR_MAX_THRDS_REACHED)
|
||||
ERR_MAPS(ERROR_NESTING_NOT_ALLOWED, EAGAIN);
|
||||
default:
|
||||
/* Remaining cases map to EINVAL */
|
||||
/* FIXME: may be missing some errors above */
|
||||
*errno_ptr = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 80
|
||||
|
||||
/*********************************************************************
|
||||
* __sys_nerr (MSVCR80.@)
|
||||
*/
|
||||
int* CDECL __sys_nerr(void)
|
||||
{
|
||||
return (int*)&MSVCRT__sys_nerr;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __sys_errlist (MSVCR80.@)
|
||||
*/
|
||||
char** CDECL __sys_errlist(void)
|
||||
{
|
||||
return MSVCRT__sys_errlist;
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER >= 80 */
|
||||
|
||||
/*********************************************************************
|
||||
* _errno (MSVCRT.@)
|
||||
*/
|
||||
int* CDECL _errno(void)
|
||||
{
|
||||
return &msvcrt_get_thread_data()->thread_errno;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __doserrno (MSVCRT.@)
|
||||
*/
|
||||
__msvcrt_ulong* CDECL __doserrno(void)
|
||||
{
|
||||
return &msvcrt_get_thread_data()->thread_doserrno;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_errno (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_errno(int *pValue)
|
||||
{
|
||||
if (!pValue)
|
||||
return EINVAL;
|
||||
|
||||
*pValue = *_errno();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_doserrno (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _get_doserrno(int *pValue)
|
||||
{
|
||||
if (!pValue)
|
||||
return EINVAL;
|
||||
|
||||
*pValue = *__doserrno();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_errno (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _set_errno(int value)
|
||||
{
|
||||
*_errno() = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_doserrno (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _set_doserrno(int value)
|
||||
{
|
||||
*__doserrno() = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* strerror (MSVCRT.@)
|
||||
*/
|
||||
char* CDECL strerror(int err)
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
|
||||
if (!data->strerror_buffer)
|
||||
if (!(data->strerror_buffer = 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;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* strerror_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL strerror_s(char *buffer, size_t numberOfElements, int errnum)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!buffer || !numberOfElements)
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (errnum < 0 || errnum > MSVCRT__sys_nerr)
|
||||
errnum = MSVCRT__sys_nerr;
|
||||
|
||||
ptr = MSVCRT__sys_errlist[errnum];
|
||||
while (*ptr && numberOfElements > 1)
|
||||
{
|
||||
*buffer++ = *ptr++;
|
||||
numberOfElements--;
|
||||
}
|
||||
|
||||
*buffer = '\0';
|
||||
return 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 = 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;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* perror (MSVCRT.@)
|
||||
*/
|
||||
void CDECL perror(const char* str)
|
||||
{
|
||||
int err = *_errno();
|
||||
if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr;
|
||||
|
||||
if (str && *str)
|
||||
{
|
||||
_write( 2, str, strlen(str) );
|
||||
_write( 2, ": ", 2 );
|
||||
}
|
||||
_write( 2, MSVCRT__sys_errlist[err], strlen(MSVCRT__sys_errlist[err]) );
|
||||
_write( 2, "\n", 1 );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wperror (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _wperror(const wchar_t* str)
|
||||
{
|
||||
size_t size;
|
||||
char *buffer = NULL;
|
||||
|
||||
if (str && *str)
|
||||
{
|
||||
size = wcstombs(NULL, str, 0);
|
||||
if (size == -1) return;
|
||||
size++;
|
||||
buffer = malloc(size);
|
||||
if (!buffer) return;
|
||||
if (wcstombs(buffer, str, size) == -1)
|
||||
{
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
perror(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wcserror_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _wcserror_s(wchar_t* buffer, size_t nc, int err)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(nc > 0)) return EINVAL;
|
||||
|
||||
if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr;
|
||||
MultiByteToWideChar(CP_ACP, 0, MSVCRT__sys_errlist[err], -1, buffer, nc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wcserror (MSVCRT.@)
|
||||
*/
|
||||
wchar_t* CDECL _wcserror(int err)
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
|
||||
if (!data->wcserror_buffer)
|
||||
if (!(data->wcserror_buffer = malloc(256 * sizeof(wchar_t)))) return NULL;
|
||||
_wcserror_s(data->wcserror_buffer, 256, err);
|
||||
return data->wcserror_buffer;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* __wcserror_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL __wcserror_s(wchar_t* buffer, size_t nc, const wchar_t* str)
|
||||
{
|
||||
int err;
|
||||
size_t len;
|
||||
|
||||
err = *_errno();
|
||||
if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr;
|
||||
|
||||
len = MultiByteToWideChar(CP_ACP, 0, MSVCRT__sys_errlist[err], -1, NULL, 0) + 1 /* \n */;
|
||||
if (str && *str) len += wcslen(str) + 2 /* ': ' */;
|
||||
if (len > nc)
|
||||
{
|
||||
MSVCRT_INVALID_PMT("buffer[nc] is too small", ERANGE);
|
||||
return ERANGE;
|
||||
}
|
||||
if (str && *str)
|
||||
{
|
||||
lstrcpyW(buffer, str);
|
||||
lstrcatW(buffer, L": ");
|
||||
}
|
||||
else buffer[0] = '\0';
|
||||
len = wcslen(buffer);
|
||||
MultiByteToWideChar(CP_ACP, 0, MSVCRT__sys_errlist[err], -1, buffer + len, 256 - len);
|
||||
lstrcatW(buffer, L"\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* __wcserror (MSVCRT.@)
|
||||
*/
|
||||
wchar_t* CDECL __wcserror(const wchar_t* str)
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
int err;
|
||||
|
||||
if (!data->wcserror_buffer)
|
||||
if (!(data->wcserror_buffer = malloc(256 * sizeof(wchar_t)))) return NULL;
|
||||
|
||||
err = __wcserror_s(data->wcserror_buffer, 256, str);
|
||||
if (err) FIXME("bad wcserror call (%d)\n", err);
|
||||
|
||||
return data->wcserror_buffer;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* _seterrormode (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _seterrormode(int mode)
|
||||
{
|
||||
SetErrorMode( mode );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* _invalid_parameter (MSVCRT.@)
|
||||
*/
|
||||
void __cdecl _invalid_parameter(const wchar_t *expr, const wchar_t *func,
|
||||
const wchar_t *file, unsigned int line, 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 %Ix\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
|
||||
}
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 80
|
||||
|
||||
/*********************************************************************
|
||||
* _invalid_parameter_noinfo (MSVCR80.@)
|
||||
*/
|
||||
void CDECL _invalid_parameter_noinfo(void)
|
||||
{
|
||||
_invalid_parameter( NULL, NULL, NULL, 0, 0 );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _invalid_parameter_noinfo_noreturn (MSVCR80.@)
|
||||
*/
|
||||
void CDECL _invalid_parameter_noinfo_noreturn(void)
|
||||
{
|
||||
_invalid_parameter( NULL, NULL, NULL, 0, 0 );
|
||||
_exit( STATUS_INVALID_CRUNTIME_PARAMETER );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_invalid_parameter_handler (MSVCR80.@)
|
||||
*/
|
||||
_invalid_parameter_handler CDECL _get_invalid_parameter_handler(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
return invalid_parameter_handler;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_invalid_parameter_handler (MSVCR80.@)
|
||||
*/
|
||||
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(
|
||||
_invalid_parameter_handler handler)
|
||||
{
|
||||
_invalid_parameter_handler old = invalid_parameter_handler;
|
||||
|
||||
TRACE("(%p)\n", handler);
|
||||
|
||||
invalid_parameter_handler = handler;
|
||||
return old;
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER >= 80 */
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
|
||||
/*********************************************************************
|
||||
* _get_thread_local_invalid_parameter_handler (UCRTBASE.@)
|
||||
*/
|
||||
_invalid_parameter_handler CDECL _get_thread_local_invalid_parameter_handler(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
return msvcrt_get_thread_data()->invalid_parameter_handler;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_thread_local_invalid_parameter_handler (UCRTBASE.@)
|
||||
*/
|
||||
_invalid_parameter_handler CDECL _set_thread_local_invalid_parameter_handler(
|
||||
_invalid_parameter_handler handler)
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
_invalid_parameter_handler old = data->invalid_parameter_handler;
|
||||
|
||||
TRACE("(%p)\n", handler);
|
||||
|
||||
data->invalid_parameter_handler = handler;
|
||||
return old;
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER >= 140 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2011 Alexandre Julliard
|
||||
* Copyright 2013 André Hentschel
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <fpieee.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "cppexcept.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
extern void *call_exc_handler( void *handler, ULONG_PTR frame, UINT flags, BYTE *nonvol_regs );
|
||||
__ASM_GLOBAL_FUNC( call_exc_handler,
|
||||
"push {r1,r4-r11,lr}\n\t"
|
||||
".seh_save_regs_w {r1,r4-r11,lr}\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"ldm r3, {r4-r11}\n\t"
|
||||
"blx r0\n\t"
|
||||
"pop {r3-r11,pc}" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_catch_handler
|
||||
*/
|
||||
void *call_catch_handler( EXCEPTION_RECORD *rec )
|
||||
{
|
||||
ULONG_PTR frame = rec->ExceptionInformation[1];
|
||||
void *handler = (void *)rec->ExceptionInformation[5];
|
||||
BYTE *nonvol_regs = (BYTE *)rec->ExceptionInformation[10];
|
||||
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100, nonvol_regs );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_unwind_handler
|
||||
*/
|
||||
void *call_unwind_handler( void *handler, ULONG_PTR frame, DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100, dispatch->NonVolatileRegisters );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_exception_pc
|
||||
*/
|
||||
ULONG_PTR get_exception_pc( DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
ULONG_PTR pc = dispatch->ControlPc;
|
||||
if (dispatch->ControlPcIsUnwound) pc -= 2;
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* handle_fpieee_flt
|
||||
*/
|
||||
int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) )
|
||||
{
|
||||
FIXME("(%lx %p %p)\n", exception_code, ep, handler);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2011 Alexandre Julliard
|
||||
* Copyright 2013 André Hentschel
|
||||
* Copyright 2017 Martin Storsjo
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef __aarch64__
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <fpieee.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "cppexcept.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
extern void *call_exc_handler( void *handler, ULONG_PTR frame, UINT flags, BYTE *nonvol_regs );
|
||||
__ASM_GLOBAL_FUNC( call_exc_handler,
|
||||
"stp x29, x30, [sp, #-96]!\n\t"
|
||||
".seh_save_fplr_x 96\n\t"
|
||||
"stp x19, x20, [sp, #16]\n\t"
|
||||
".seh_save_regp x19, 16\n\t"
|
||||
"stp x21, x22, [sp, #32]\n\t"
|
||||
".seh_save_regp x21, 32\n\t"
|
||||
"stp x23, x24, [sp, #48]\n\t"
|
||||
".seh_save_regp x23, 48\n\t"
|
||||
"stp x25, x26, [sp, #64]\n\t"
|
||||
".seh_save_regp x25, 64\n\t"
|
||||
"stp x27, x28, [sp, #80]\n\t"
|
||||
".seh_save_regp x27, 80\n\t"
|
||||
"str x1, [sp, #-16]!\n\t"
|
||||
".seh_stackalloc 16\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */
|
||||
"ldp x21, x22, [x3, #16]\n\t"
|
||||
"ldp x23, x24, [x3, #32]\n\t"
|
||||
"ldp x25, x26, [x3, #48]\n\t"
|
||||
"ldp x27, x28, [x3, #64]\n\t"
|
||||
"ldr x29, [x3, #80]\n\t"
|
||||
"blr x0\n\t"
|
||||
"add sp, sp, 16\n\t"
|
||||
"ldp x19, x20, [sp, #16]\n\t"
|
||||
"ldp x21, x22, [sp, #32]\n\t"
|
||||
"ldp x23, x24, [sp, #48]\n\t"
|
||||
"ldp x25, x26, [sp, #64]\n\t"
|
||||
"ldp x27, x28, [sp, #80]\n\t"
|
||||
"ldp x29, x30, [sp], #96\n\t"
|
||||
"ret" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_catch_handler
|
||||
*/
|
||||
void *call_catch_handler( EXCEPTION_RECORD *rec )
|
||||
{
|
||||
ULONG_PTR frame = rec->ExceptionInformation[1];
|
||||
void *handler = (void *)rec->ExceptionInformation[5];
|
||||
BYTE *nonvol_regs = (BYTE *)rec->ExceptionInformation[10];
|
||||
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100, nonvol_regs );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_unwind_handler
|
||||
*/
|
||||
void *call_unwind_handler( void *handler, ULONG_PTR frame, DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100, dispatch->NonVolatileRegisters );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_exception_pc
|
||||
*/
|
||||
ULONG_PTR get_exception_pc( DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
ULONG_PTR pc = dispatch->ControlPc;
|
||||
if (dispatch->ControlPcIsUnwound) pc -= 4;
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* _setjmp (MSVCRT.@)
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( _setjmp, "b _setjmpex" );
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* handle_fpieee_flt
|
||||
*/
|
||||
int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) )
|
||||
{
|
||||
FIXME("(%lx %p %p)\n", exception_code, ep, handler);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2011 Alexandre Julliard
|
||||
* Copyright 2013 André Hentschel
|
||||
* Copyright 2017 Martin Storsjo
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef __arm64ec__
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <fpieee.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "cppexcept.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
static void * __attribute__((naked,used)) call_handler_arm64( void *func, uintptr_t frame,
|
||||
UINT flags, BYTE *nonvol_regs )
|
||||
{
|
||||
asm( ".seh_proc \"#call_handler_arm64\"\n\t"
|
||||
"stp x29, x30, [sp, #-80]!\n\t"
|
||||
".seh_save_fplr_x 80\n\t"
|
||||
"stp x19, x20, [sp, #16]\n\t"
|
||||
".seh_save_regp x19, 16\n\t"
|
||||
"stp x21, x22, [sp, #32]\n\t"
|
||||
".seh_save_regp x21, 32\n\t"
|
||||
"stp x25, x26, [sp, #48]\n\t"
|
||||
".seh_save_regp x25, 48\n\t"
|
||||
"str x27, [sp, #64]\n\t"
|
||||
".seh_save_reg x27, 64\n\t"
|
||||
"str x1, [sp, #-16]!\n\t"
|
||||
".seh_stackalloc 16\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */
|
||||
"ldp x21, x22, [x3, #16]\n\t"
|
||||
"ldp x25, x26, [x3, #48]\n\t"
|
||||
"ldr x27, [x3, #64]\n\t"
|
||||
"ldr x29, [x3, #80]\n\t"
|
||||
"blr x0\n\t"
|
||||
"add sp, sp, 16\n\t"
|
||||
"ldp x19, x20, [sp, #16]\n\t"
|
||||
"ldp x21, x22, [sp, #32]\n\t"
|
||||
"ldp x25, x26, [sp, #48]\n\t"
|
||||
"ldr x27, [sp, #64]\n\t"
|
||||
"ldp x29, x30, [sp], #80\n\t"
|
||||
"ret\n\t"
|
||||
".seh_endproc" );
|
||||
}
|
||||
|
||||
static void * __attribute__((naked,used)) call_handler_x64( void *func, uintptr_t frame, UINT flags )
|
||||
{
|
||||
asm( ".seh_proc \"#call_handler_x64\"\n\t"
|
||||
"stp x29, x30, [sp, #-16]!\n\t"
|
||||
".seh_save_fplr_x 16\n\t"
|
||||
".seh_endprologue\n\t"
|
||||
"mov x11, x0\n\t"
|
||||
"adr x10, $iexit_thunk$cdecl$i8$i8i8i8\n\t"
|
||||
"adrp x16, __os_arm64x_dispatch_icall\n\t"
|
||||
"ldr x16, [x16, #:lo12:__os_arm64x_dispatch_icall]\n\t"
|
||||
"blr x16\n\t"
|
||||
"blr x11\n\t"
|
||||
"ldp x29, x30, [sp], #16\n\t"
|
||||
"ret\n\t"
|
||||
".seh_endproc" );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_catch_handler
|
||||
*/
|
||||
void *call_catch_handler( EXCEPTION_RECORD *rec )
|
||||
{
|
||||
ULONG_PTR frame = rec->ExceptionInformation[1];
|
||||
void *handler = (void *)rec->ExceptionInformation[5];
|
||||
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
if (!RtlIsEcCode( (ULONG_PTR)handler )) return call_handler_x64( handler, frame, 0x100 );
|
||||
return call_handler_arm64( handler, frame, 0x100, (BYTE *)rec->ExceptionInformation[10] );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_unwind_handler
|
||||
*/
|
||||
void *call_unwind_handler( void *handler, ULONG_PTR frame, DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
if (!RtlIsEcCode( (ULONG_PTR)handler )) return call_handler_x64( handler, frame, 0x100 );
|
||||
return call_handler_arm64( handler, frame, 0x100,
|
||||
((DISPATCHER_CONTEXT_ARM64EC *)dispatch)->NonVolatileRegisters );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_exception_pc
|
||||
*/
|
||||
ULONG_PTR get_exception_pc( DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
ULONG_PTR pc = dispatch->ControlPc;
|
||||
if (RtlIsEcCode( pc ) && ((DISPATCHER_CONTEXT_ARM64EC *)dispatch)->ControlPcIsUnwound) pc -= 4;
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* handle_fpieee_flt
|
||||
*/
|
||||
int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) )
|
||||
{
|
||||
FIXME("(%lx %p %p)\n", exception_code, ep, handler);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=110 && _MSVCR_VER<=120
|
||||
/*********************************************************************
|
||||
* __crtCapturePreviousContext (MSVCR110.@)
|
||||
*/
|
||||
void __cdecl __crtCapturePreviousContext( CONTEXT *ctx )
|
||||
{
|
||||
UNWIND_HISTORY_TABLE table;
|
||||
RUNTIME_FUNCTION *func;
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
ULONG_PTR pc, frame, base;
|
||||
void *data;
|
||||
ULONG i;
|
||||
|
||||
RtlCaptureContext( ctx );
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
pc = ctx->Rip;
|
||||
if ((ctx->ContextFlags & CONTEXT_UNWOUND_TO_CALL) && RtlIsEcCode( pc )) pc -= 4;
|
||||
if (!(func = RtlLookupFunctionEntry( pc, &base, &table ))) break;
|
||||
if (RtlVirtualUnwind2( UNW_FLAG_NHANDLER, base, pc, func, ctx, NULL,
|
||||
&data, &frame, NULL, NULL, NULL, &handler, 0 ))
|
||||
break;
|
||||
if (!ctx->Rip) break;
|
||||
if (!frame) break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __arm64ec__ */
|
||||
@@ -0,0 +1,923 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
* Copyright 2002 Alexandre Julliard
|
||||
* Copyright 2005 Juan Lang
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* NOTES
|
||||
* A good reference is the article "How a C++ compiler implements
|
||||
* exception handling" by Vishal Kochhar, available on
|
||||
* www.thecodeproject.com.
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <fpieee.h>
|
||||
#define longjmp ms_longjmp /* avoid prototype mismatch */
|
||||
#include <setjmp.h>
|
||||
#undef longjmp
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "wine/exception.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "cppexcept.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
|
||||
/* the exception frame used by CxxFrameHandler */
|
||||
typedef struct __cxx_exception_frame
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD frame; /* the standard exception frame */
|
||||
int trylevel;
|
||||
DWORD ebp;
|
||||
} cxx_exception_frame;
|
||||
|
||||
/* exception frame for nested exceptions in catch block */
|
||||
typedef struct
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD frame; /* standard exception frame */
|
||||
cxx_exception_frame *cxx_frame; /* frame of parent exception */
|
||||
const cxx_function_descr *descr; /* descriptor of parent exception */
|
||||
int trylevel; /* current try level */
|
||||
cxx_frame_info frame_info;
|
||||
} catch_func_nested_frame;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cxx_exception_frame *frame;
|
||||
const cxx_function_descr *descr;
|
||||
catch_func_nested_frame *nested_frame;
|
||||
} se_translator_ctx;
|
||||
|
||||
typedef struct _SCOPETABLE
|
||||
{
|
||||
int previousTryLevel;
|
||||
int (*lpfnFilter)(PEXCEPTION_POINTERS);
|
||||
void * (*lpfnHandler)(void);
|
||||
} SCOPETABLE, *PSCOPETABLE;
|
||||
|
||||
typedef struct MSVCRT_EXCEPTION_FRAME
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD *prev;
|
||||
void (*handler)(PEXCEPTION_RECORD, EXCEPTION_REGISTRATION_RECORD*,
|
||||
PCONTEXT, PEXCEPTION_RECORD);
|
||||
PSCOPETABLE scopetable;
|
||||
int trylevel;
|
||||
int _ebp;
|
||||
PEXCEPTION_POINTERS xpointers;
|
||||
} MSVCRT_EXCEPTION_FRAME;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int gs_cookie_offset;
|
||||
ULONG gs_cookie_xor;
|
||||
int eh_cookie_offset;
|
||||
ULONG eh_cookie_xor;
|
||||
SCOPETABLE entries[1];
|
||||
} SCOPETABLE_V4;
|
||||
|
||||
#define TRYLEVEL_END (-1) /* End of trylevel list */
|
||||
|
||||
typedef DWORD (CDECL *cxx_exc_custom_handler)( PEXCEPTION_RECORD, cxx_exception_frame*,
|
||||
PCONTEXT, EXCEPTION_REGISTRATION_RECORD**,
|
||||
const cxx_function_descr*, int nested_trylevel,
|
||||
EXCEPTION_REGISTRATION_RECORD *nested_frame, DWORD unknown );
|
||||
|
||||
DWORD CDECL cxx_frame_handler( PEXCEPTION_RECORD rec, cxx_exception_frame* frame,
|
||||
PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch,
|
||||
const cxx_function_descr *descr,
|
||||
catch_func_nested_frame* nested_frame );
|
||||
|
||||
/* continue execution to the specified address after exception is caught */
|
||||
extern void DECLSPEC_NORETURN continue_after_catch( cxx_exception_frame* frame, void *addr );
|
||||
|
||||
__ASM_GLOBAL_FUNC( continue_after_catch,
|
||||
"movl 4(%esp), %edx\n\t"
|
||||
"movl 8(%esp), %eax\n\t"
|
||||
"movl -4(%edx), %esp\n\t"
|
||||
"leal 12(%edx), %ebp\n\t"
|
||||
"jmp *%eax" );
|
||||
|
||||
extern void DECLSPEC_NORETURN call_finally_block( void *code_block, void *base_ptr );
|
||||
|
||||
__ASM_GLOBAL_FUNC( call_finally_block,
|
||||
"movl 8(%esp), %ebp\n\t"
|
||||
"jmp *4(%esp)" );
|
||||
|
||||
extern int call_filter( int (*func)(PEXCEPTION_POINTERS), void *arg, void *ebp );
|
||||
|
||||
__ASM_GLOBAL_FUNC( call_filter,
|
||||
"pushl %ebp\n\t"
|
||||
"pushl 12(%esp)\n\t"
|
||||
"movl 20(%esp), %ebp\n\t"
|
||||
"call *12(%esp)\n\t"
|
||||
"popl %ebp\n\t"
|
||||
"popl %ebp\n\t"
|
||||
"ret" );
|
||||
|
||||
extern void *call_handler( void * (*func)(void), void *ebp );
|
||||
|
||||
__ASM_GLOBAL_FUNC( call_handler,
|
||||
"pushl %ebp\n\t"
|
||||
"pushl %ebx\n\t"
|
||||
"pushl %esi\n\t"
|
||||
"pushl %edi\n\t"
|
||||
"movl 24(%esp), %ebp\n\t"
|
||||
"call *20(%esp)\n\t"
|
||||
"popl %edi\n\t"
|
||||
"popl %esi\n\t"
|
||||
"popl %ebx\n\t"
|
||||
"popl %ebp\n\t"
|
||||
"ret" );
|
||||
|
||||
/* unwind the local function up to a given trylevel */
|
||||
static void cxx_local_unwind( cxx_exception_frame* frame, const cxx_function_descr *descr, int last_level)
|
||||
{
|
||||
void * (*handler)(void);
|
||||
int trylevel = frame->trylevel;
|
||||
|
||||
while (trylevel != last_level)
|
||||
{
|
||||
if (trylevel < 0 || trylevel >= descr->unwind_count)
|
||||
{
|
||||
ERR( "invalid trylevel %d\n", trylevel );
|
||||
terminate();
|
||||
}
|
||||
handler = descr->unwind_table[trylevel].handler;
|
||||
if (handler)
|
||||
{
|
||||
TRACE( "calling unwind handler %p trylevel %d last %d ebp %p\n",
|
||||
handler, trylevel, last_level, &frame->ebp );
|
||||
call_handler( handler, &frame->ebp );
|
||||
}
|
||||
trylevel = descr->unwind_table[trylevel].prev;
|
||||
}
|
||||
frame->trylevel = last_level;
|
||||
}
|
||||
|
||||
/* handler for exceptions happening while calling a catch function */
|
||||
static DWORD catch_function_nested_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
||||
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
||||
{
|
||||
catch_func_nested_frame *nested_frame = (catch_func_nested_frame *)frame;
|
||||
|
||||
if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
|
||||
{
|
||||
__CxxUnregisterExceptionObject(&nested_frame->frame_info, FALSE);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
TRACE( "got nested exception in catch function\n" );
|
||||
|
||||
if(rec->ExceptionCode == CXX_EXCEPTION)
|
||||
{
|
||||
PEXCEPTION_RECORD prev_rec = msvcrt_get_thread_data()->exc_record;
|
||||
|
||||
if((rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0) ||
|
||||
(prev_rec->ExceptionCode == CXX_EXCEPTION &&
|
||||
rec->ExceptionInformation[1] == prev_rec->ExceptionInformation[1] &&
|
||||
rec->ExceptionInformation[2] == prev_rec->ExceptionInformation[2]))
|
||||
{
|
||||
/* exception was rethrown */
|
||||
*rec = *prev_rec;
|
||||
rec->ExceptionFlags &= ~EXCEPTION_UNWINDING;
|
||||
if(TRACE_ON(seh)) {
|
||||
TRACE("detect rethrow: exception code: %lx\n", rec->ExceptionCode);
|
||||
if(rec->ExceptionCode == CXX_EXCEPTION)
|
||||
TRACE("re-propagate: obj: %Ix, type: %Ix\n",
|
||||
rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("detect threw new exception in catch block\n");
|
||||
}
|
||||
}
|
||||
|
||||
return cxx_frame_handler( rec, nested_frame->cxx_frame, context,
|
||||
NULL, nested_frame->descr, nested_frame );
|
||||
}
|
||||
|
||||
/* find and call the appropriate catch block for an exception */
|
||||
/* returns the address to continue execution to after the catch block was called */
|
||||
static inline void call_catch_block( PEXCEPTION_RECORD rec, CONTEXT *context,
|
||||
cxx_exception_frame *frame,
|
||||
const cxx_function_descr *descr,
|
||||
catch_func_nested_frame *catch_frame,
|
||||
cxx_exception_type *info )
|
||||
{
|
||||
UINT i;
|
||||
void *addr, *handler, *object = (void *)rec->ExceptionInformation[1];
|
||||
catch_func_nested_frame nested_frame;
|
||||
int trylevel = frame->trylevel;
|
||||
DWORD save_esp = ((DWORD*)frame)[-1];
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
|
||||
data->processing_throw++;
|
||||
for (i = 0; i < descr->tryblock_count; i++)
|
||||
{
|
||||
const tryblock_info *tryblock = &descr->tryblock[i];
|
||||
|
||||
/* only handle try blocks inside current catch block */
|
||||
if (catch_frame && catch_frame->trylevel > tryblock->start_level) continue;
|
||||
|
||||
if (trylevel < tryblock->start_level) continue;
|
||||
if (trylevel > tryblock->end_level) continue;
|
||||
|
||||
handler = find_catch_handler( object, (uintptr_t)&frame->ebp, 0, tryblock, info, 0 );
|
||||
if (!handler) continue;
|
||||
|
||||
/* Add frame info here so exception is not freed inside RtlUnwind call */
|
||||
_CreateFrameInfo(&nested_frame.frame_info.frame_info, object);
|
||||
|
||||
/* unwind the stack */
|
||||
RtlUnwind( catch_frame ? &catch_frame->frame : &frame->frame, 0, rec, 0 );
|
||||
cxx_local_unwind( frame, descr, tryblock->start_level );
|
||||
frame->trylevel = tryblock->end_level + 1;
|
||||
|
||||
nested_frame.frame_info.rec = data->exc_record;
|
||||
nested_frame.frame_info.context = data->ctx_record;
|
||||
data->exc_record = rec;
|
||||
data->ctx_record = context;
|
||||
data->processing_throw--;
|
||||
|
||||
/* call the catch block */
|
||||
TRACE( "calling handler %p ebp %p\n", handler, &frame->ebp );
|
||||
|
||||
/* setup an exception block for nested exceptions */
|
||||
nested_frame.frame.Handler = catch_function_nested_handler;
|
||||
nested_frame.cxx_frame = frame;
|
||||
nested_frame.descr = descr;
|
||||
nested_frame.trylevel = tryblock->end_level + 1;
|
||||
|
||||
__wine_push_frame( &nested_frame.frame );
|
||||
addr = call_handler( handler, &frame->ebp );
|
||||
__wine_pop_frame( &nested_frame.frame );
|
||||
|
||||
((DWORD*)frame)[-1] = save_esp;
|
||||
__CxxUnregisterExceptionObject(&nested_frame.frame_info, FALSE);
|
||||
TRACE( "done, continuing at %p\n", addr );
|
||||
|
||||
continue_after_catch( frame, addr );
|
||||
}
|
||||
data->processing_throw--;
|
||||
}
|
||||
|
||||
static LONG CALLBACK se_translation_filter( EXCEPTION_POINTERS *ep, void *c )
|
||||
{
|
||||
se_translator_ctx *ctx = (se_translator_ctx *)c;
|
||||
EXCEPTION_RECORD *rec = ep->ExceptionRecord;
|
||||
cxx_exception_type *exc_type;
|
||||
|
||||
if (rec->ExceptionCode != CXX_EXCEPTION)
|
||||
{
|
||||
TRACE( "non-c++ exception thrown in SEH handler: %lx\n", rec->ExceptionCode );
|
||||
terminate();
|
||||
}
|
||||
|
||||
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||
call_catch_block( rec, ep->ContextRecord, ctx->frame, ctx->descr,
|
||||
ctx->nested_frame, exc_type );
|
||||
|
||||
__DestructExceptionObject( rec );
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
static void check_noexcept( PEXCEPTION_RECORD rec,
|
||||
const cxx_function_descr *descr, BOOL nested )
|
||||
{
|
||||
if (!nested && rec->ExceptionCode == CXX_EXCEPTION &&
|
||||
descr->magic >= CXX_FRAME_MAGIC_VC8 &&
|
||||
(descr->flags & FUNC_DESCR_NOEXCEPT))
|
||||
{
|
||||
ERR("noexcept function propagating exception\n");
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* cxx_frame_handler
|
||||
*
|
||||
* Implementation of __CxxFrameHandler.
|
||||
*/
|
||||
DWORD CDECL cxx_frame_handler( PEXCEPTION_RECORD rec, cxx_exception_frame* frame,
|
||||
PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch,
|
||||
const cxx_function_descr *descr,
|
||||
catch_func_nested_frame* nested_frame )
|
||||
{
|
||||
cxx_exception_type *exc_type;
|
||||
|
||||
if (descr->magic < CXX_FRAME_MAGIC_VC6 || descr->magic > CXX_FRAME_MAGIC_VC8)
|
||||
{
|
||||
ERR( "invalid frame magic %x\n", descr->magic );
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
if (descr->magic >= CXX_FRAME_MAGIC_VC8 &&
|
||||
(descr->flags & FUNC_DESCR_SYNCHRONOUS) &&
|
||||
(rec->ExceptionCode != CXX_EXCEPTION))
|
||||
return ExceptionContinueSearch; /* handle only c++ exceptions */
|
||||
|
||||
if (rec->ExceptionFlags & (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND))
|
||||
{
|
||||
if (descr->unwind_count && !nested_frame) cxx_local_unwind( frame, descr, -1 );
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
if (!descr->tryblock_count)
|
||||
{
|
||||
check_noexcept(rec, descr, nested_frame != NULL);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
if(rec->ExceptionCode == CXX_EXCEPTION &&
|
||||
rec->ExceptionInformation[1] == 0 && rec->ExceptionInformation[2] == 0)
|
||||
{
|
||||
*rec = *msvcrt_get_thread_data()->exc_record;
|
||||
rec->ExceptionFlags &= ~EXCEPTION_UNWINDING;
|
||||
if(TRACE_ON(seh)) {
|
||||
TRACE("detect rethrow: exception code: %lx\n", rec->ExceptionCode);
|
||||
if(rec->ExceptionCode == CXX_EXCEPTION)
|
||||
TRACE("re-propagate: obj: %Ix, type: %Ix\n",
|
||||
rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if(rec->ExceptionCode == CXX_EXCEPTION)
|
||||
{
|
||||
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||
|
||||
if (rec->ExceptionInformation[0] > CXX_FRAME_MAGIC_VC8 &&
|
||||
exc_type->custom_handler)
|
||||
{
|
||||
cxx_exc_custom_handler handler = exc_type->custom_handler;
|
||||
return handler( rec, frame, context, dispatch, descr,
|
||||
nested_frame ? nested_frame->trylevel : 0,
|
||||
nested_frame ? &nested_frame->frame : NULL, 0 );
|
||||
}
|
||||
|
||||
if (TRACE_ON(seh))
|
||||
{
|
||||
TRACE("handling C++ exception rec %p frame %p trylevel %d descr %p nested_frame %p\n",
|
||||
rec, frame, frame->trylevel, descr, nested_frame );
|
||||
TRACE_EXCEPTION_TYPE( exc_type, 0 );
|
||||
dump_function_descr( descr, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
|
||||
exc_type = NULL;
|
||||
TRACE("handling C exception code %lx rec %p frame %p trylevel %d descr %p nested_frame %p\n",
|
||||
rec->ExceptionCode, rec, frame, frame->trylevel, descr, nested_frame );
|
||||
|
||||
if (data->se_translator) {
|
||||
EXCEPTION_POINTERS except_ptrs;
|
||||
se_translator_ctx ctx;
|
||||
|
||||
ctx.frame = frame;
|
||||
ctx.descr = descr;
|
||||
ctx.nested_frame = nested_frame;
|
||||
__TRY
|
||||
{
|
||||
except_ptrs.ExceptionRecord = rec;
|
||||
except_ptrs.ContextRecord = context;
|
||||
data->se_translator( rec->ExceptionCode, &except_ptrs );
|
||||
}
|
||||
__EXCEPT_CTX(se_translation_filter, &ctx)
|
||||
{
|
||||
}
|
||||
__ENDTRY
|
||||
}
|
||||
}
|
||||
|
||||
call_catch_block( rec, context, frame, descr,
|
||||
nested_frame, exc_type );
|
||||
check_noexcept(rec, descr, nested_frame != NULL);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* __CxxFrameHandler (MSVCRT.@)
|
||||
*/
|
||||
extern DWORD CDECL __CxxFrameHandler( PEXCEPTION_RECORD rec, EXCEPTION_REGISTRATION_RECORD* frame,
|
||||
PCONTEXT context, EXCEPTION_REGISTRATION_RECORD** dispatch );
|
||||
__ASM_GLOBAL_FUNC( __CxxFrameHandler,
|
||||
"pushl $0\n\t" /* nested_frame */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl %eax\n\t" /* descr */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl 24(%esp)\n\t" /* dispatch */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl 24(%esp)\n\t" /* context */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl 24(%esp)\n\t" /* frame */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl 24(%esp)\n\t" /* rec */
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"call " __ASM_NAME("cxx_frame_handler") "\n\t"
|
||||
"add $24,%esp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset -24\n\t")
|
||||
"ret" )
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* __CxxLongjmpUnwind (MSVCRT.@)
|
||||
*
|
||||
* Callback meant to be used as UnwindFunc for setjmp/longjmp.
|
||||
*/
|
||||
void __stdcall __CxxLongjmpUnwind( const _JUMP_BUFFER *buf )
|
||||
{
|
||||
cxx_exception_frame *frame = (cxx_exception_frame *)buf->Registration;
|
||||
const cxx_function_descr *descr = (const cxx_function_descr *)buf->UnwindData[0];
|
||||
|
||||
TRACE( "unwinding frame %p descr %p trylevel %ld\n", frame, descr, buf->TryLevel );
|
||||
cxx_local_unwind( frame, descr, buf->TryLevel );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _EH_prolog (MSVCRT.@)
|
||||
*/
|
||||
|
||||
/* Provided for VC++ binary compatibility only */
|
||||
__ASM_GLOBAL_FUNC(_EH_prolog,
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") /* skip ret addr */
|
||||
"pushl $-1\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl %eax\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"pushl %fs:0\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"movl %esp, %fs:0\n\t"
|
||||
"movl 12(%esp), %eax\n\t"
|
||||
"movl %ebp, 12(%esp)\n\t"
|
||||
"leal 12(%esp), %ebp\n\t"
|
||||
"pushl %eax\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"ret")
|
||||
|
||||
static const SCOPETABLE_V4 *get_scopetable_v4( MSVCRT_EXCEPTION_FRAME *frame, ULONG_PTR cookie )
|
||||
{
|
||||
return (const SCOPETABLE_V4 *)((ULONG_PTR)frame->scopetable ^ cookie);
|
||||
}
|
||||
|
||||
static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec,
|
||||
EXCEPTION_REGISTRATION_RECORD* frame,
|
||||
PCONTEXT context,
|
||||
EXCEPTION_REGISTRATION_RECORD** dispatch)
|
||||
{
|
||||
if (!(rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)))
|
||||
return ExceptionContinueSearch;
|
||||
*dispatch = frame;
|
||||
return ExceptionCollidedUnwind;
|
||||
}
|
||||
|
||||
static void msvcrt_local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp)
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD reg;
|
||||
|
||||
TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
|
||||
|
||||
/* Register a handler in case of a nested exception */
|
||||
reg.Handler = MSVCRT_nested_handler;
|
||||
reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
|
||||
__wine_push_frame(®);
|
||||
|
||||
while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel)
|
||||
{
|
||||
int level = frame->trylevel;
|
||||
frame->trylevel = frame->scopetable[level].previousTryLevel;
|
||||
if (!frame->scopetable[level].lpfnFilter)
|
||||
{
|
||||
TRACE( "__try block cleanup level %d handler %p ebp %p\n",
|
||||
level, frame->scopetable[level].lpfnHandler, ebp );
|
||||
call_handler( frame->scopetable[level].lpfnHandler, ebp );
|
||||
}
|
||||
}
|
||||
__wine_pop_frame(®);
|
||||
TRACE("unwound OK\n");
|
||||
}
|
||||
|
||||
static void msvcrt_local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp )
|
||||
{
|
||||
EXCEPTION_REGISTRATION_RECORD reg;
|
||||
const SCOPETABLE_V4 *scopetable = get_scopetable_v4( frame, *cookie );
|
||||
|
||||
TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel);
|
||||
|
||||
/* Register a handler in case of a nested exception */
|
||||
reg.Handler = MSVCRT_nested_handler;
|
||||
reg.Prev = NtCurrentTeb()->Tib.ExceptionList;
|
||||
__wine_push_frame(®);
|
||||
|
||||
while (frame->trylevel != -2 && frame->trylevel != trylevel)
|
||||
{
|
||||
int level = frame->trylevel;
|
||||
frame->trylevel = scopetable->entries[level].previousTryLevel;
|
||||
if (!scopetable->entries[level].lpfnFilter)
|
||||
{
|
||||
TRACE( "__try block cleanup level %d handler %p ebp %p\n",
|
||||
level, scopetable->entries[level].lpfnHandler, ebp );
|
||||
call_handler( scopetable->entries[level].lpfnHandler, ebp );
|
||||
}
|
||||
}
|
||||
__wine_pop_frame(®);
|
||||
TRACE("unwound OK\n");
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* _local_unwind2 (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel)
|
||||
{
|
||||
msvcrt_local_unwind2( frame, trylevel, &frame->_ebp );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* _local_unwind4 (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel )
|
||||
{
|
||||
msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* _global_unwind2 (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame)
|
||||
{
|
||||
TRACE("(%p)\n",frame);
|
||||
RtlUnwind( frame, 0, 0, 0 );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _except_handler2 (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _except_handler2(PEXCEPTION_RECORD rec,
|
||||
EXCEPTION_REGISTRATION_RECORD* frame,
|
||||
PCONTEXT context,
|
||||
EXCEPTION_REGISTRATION_RECORD** dispatcher)
|
||||
{
|
||||
FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
frame->Handler, context, dispatcher);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _except_handler3 (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _except_handler3(PEXCEPTION_RECORD rec,
|
||||
MSVCRT_EXCEPTION_FRAME* frame,
|
||||
PCONTEXT context, void* dispatcher)
|
||||
{
|
||||
int retval, trylevel;
|
||||
EXCEPTION_POINTERS exceptPtrs;
|
||||
PSCOPETABLE pScopeTable;
|
||||
|
||||
TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
frame->handler, context, dispatcher);
|
||||
|
||||
__asm__ __volatile__ ("cld");
|
||||
|
||||
if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
|
||||
{
|
||||
/* Unwinding the current frame */
|
||||
msvcrt_local_unwind2(frame, TRYLEVEL_END, &frame->_ebp);
|
||||
TRACE("unwound current frame, returning ExceptionContinueSearch\n");
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Hunting for handler */
|
||||
exceptPtrs.ExceptionRecord = rec;
|
||||
exceptPtrs.ContextRecord = context;
|
||||
*((DWORD *)frame-1) = (DWORD)&exceptPtrs;
|
||||
trylevel = frame->trylevel;
|
||||
pScopeTable = frame->scopetable;
|
||||
|
||||
while (trylevel != TRYLEVEL_END)
|
||||
{
|
||||
TRACE( "level %d prev %d filter %p\n", trylevel, pScopeTable[trylevel].previousTryLevel,
|
||||
pScopeTable[trylevel].lpfnFilter );
|
||||
if (pScopeTable[trylevel].lpfnFilter)
|
||||
{
|
||||
retval = call_filter( pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
|
||||
|
||||
TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
|
||||
"CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
|
||||
"EXECUTE_HANDLER" : "CONTINUE_SEARCH");
|
||||
|
||||
if (retval == EXCEPTION_CONTINUE_EXECUTION)
|
||||
return ExceptionContinueExecution;
|
||||
|
||||
if (retval == EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
/* Unwind all higher frames, this one will handle the exception */
|
||||
_global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
|
||||
msvcrt_local_unwind2(frame, trylevel, &frame->_ebp);
|
||||
|
||||
/* Set our trylevel to the enclosing block, and call the __finally
|
||||
* code, which won't return
|
||||
*/
|
||||
frame->trylevel = pScopeTable[trylevel].previousTryLevel;
|
||||
TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler);
|
||||
call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
|
||||
}
|
||||
}
|
||||
trylevel = pScopeTable[trylevel].previousTryLevel;
|
||||
}
|
||||
}
|
||||
TRACE("reached TRYLEVEL_END, returning ExceptionContinueSearch\n");
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _except_handler4_common (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _except_handler4_common( ULONG *cookie, void (*check_cookie)(void),
|
||||
EXCEPTION_RECORD *rec, MSVCRT_EXCEPTION_FRAME *frame,
|
||||
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
||||
{
|
||||
int retval, trylevel;
|
||||
EXCEPTION_POINTERS exceptPtrs;
|
||||
const SCOPETABLE_V4 *scope_table = get_scopetable_v4( frame, *cookie );
|
||||
|
||||
TRACE( "exception %lx flags=%lx at %p handler=%p %p %p cookie=%lx scope table=%p cookies=%d/%lx,%d/%lx\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
frame->handler, context, dispatcher, *cookie, scope_table,
|
||||
scope_table->gs_cookie_offset, scope_table->gs_cookie_xor,
|
||||
scope_table->eh_cookie_offset, scope_table->eh_cookie_xor );
|
||||
|
||||
/* FIXME: no cookie validation yet */
|
||||
|
||||
if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
|
||||
{
|
||||
/* Unwinding the current frame */
|
||||
msvcrt_local_unwind4( cookie, frame, -2, &frame->_ebp );
|
||||
TRACE("unwound current frame, returning ExceptionContinueSearch\n");
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Hunting for handler */
|
||||
exceptPtrs.ExceptionRecord = rec;
|
||||
exceptPtrs.ContextRecord = context;
|
||||
*((DWORD *)frame-1) = (DWORD)&exceptPtrs;
|
||||
trylevel = frame->trylevel;
|
||||
|
||||
while (trylevel != -2)
|
||||
{
|
||||
TRACE( "level %d prev %d filter %p\n", trylevel,
|
||||
scope_table->entries[trylevel].previousTryLevel,
|
||||
scope_table->entries[trylevel].lpfnFilter );
|
||||
if (scope_table->entries[trylevel].lpfnFilter)
|
||||
{
|
||||
retval = call_filter( scope_table->entries[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp );
|
||||
|
||||
TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ?
|
||||
"CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
|
||||
"EXECUTE_HANDLER" : "CONTINUE_SEARCH");
|
||||
|
||||
if (retval == EXCEPTION_CONTINUE_EXECUTION)
|
||||
return ExceptionContinueExecution;
|
||||
|
||||
if (retval == EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
__DestructExceptionObject(rec);
|
||||
|
||||
/* Unwind all higher frames, this one will handle the exception */
|
||||
_global_unwind2((EXCEPTION_REGISTRATION_RECORD*)frame);
|
||||
msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp );
|
||||
|
||||
/* Set our trylevel to the enclosing block, and call the __finally
|
||||
* code, which won't return
|
||||
*/
|
||||
frame->trylevel = scope_table->entries[trylevel].previousTryLevel;
|
||||
TRACE("__finally block %p\n",scope_table->entries[trylevel].lpfnHandler);
|
||||
call_finally_block(scope_table->entries[trylevel].lpfnHandler, &frame->_ebp);
|
||||
}
|
||||
}
|
||||
trylevel = scope_table->entries[trylevel].previousTryLevel;
|
||||
}
|
||||
}
|
||||
TRACE("reached -2, returning ExceptionContinueSearch\n");
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setjmp/longjmp implementation
|
||||
*/
|
||||
|
||||
#define MSVCRT_JMP_MAGIC 0x56433230 /* ID value for new jump structure */
|
||||
typedef void (__stdcall *MSVCRT_unwind_function)(const _JUMP_BUFFER *);
|
||||
|
||||
/* define an entrypoint for setjmp/setjmp3 that stores the registers in the jmp buf */
|
||||
/* and then jumps to the C backend function */
|
||||
#define DEFINE_SETJMP_ENTRYPOINT(name) \
|
||||
__ASM_GLOBAL_FUNC( name, \
|
||||
"movl 4(%esp),%ecx\n\t" /* jmp_buf */ \
|
||||
"movl %ebp,0(%ecx)\n\t" /* jmp_buf.Ebp */ \
|
||||
"movl %ebx,4(%ecx)\n\t" /* jmp_buf.Ebx */ \
|
||||
"movl %edi,8(%ecx)\n\t" /* jmp_buf.Edi */ \
|
||||
"movl %esi,12(%ecx)\n\t" /* jmp_buf.Esi */ \
|
||||
"movl %esp,16(%ecx)\n\t" /* jmp_buf.Esp */ \
|
||||
"movl 0(%esp),%eax\n\t" \
|
||||
"movl %eax,20(%ecx)\n\t" /* jmp_buf.Eip */ \
|
||||
"jmp " __ASM_NAME("__regs_") # name )
|
||||
|
||||
/*******************************************************************
|
||||
* _setjmp (MSVCRT.@)
|
||||
*/
|
||||
#undef _setjmp
|
||||
DEFINE_SETJMP_ENTRYPOINT( _setjmp )
|
||||
int CDECL __regs__setjmp(_JUMP_BUFFER *jmp)
|
||||
{
|
||||
jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
|
||||
if (jmp->Registration == ~0UL)
|
||||
jmp->TryLevel = TRYLEVEL_END;
|
||||
else
|
||||
jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
|
||||
|
||||
TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
|
||||
jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* _setjmp3 (MSVCRT.@)
|
||||
*/
|
||||
DEFINE_SETJMP_ENTRYPOINT( _setjmp3 )
|
||||
int WINAPIV __regs__setjmp3(_JUMP_BUFFER *jmp, int nb_args, ...)
|
||||
{
|
||||
jmp->Cookie = MSVCRT_JMP_MAGIC;
|
||||
jmp->UnwindFunc = 0;
|
||||
jmp->Registration = (unsigned long)NtCurrentTeb()->Tib.ExceptionList;
|
||||
if (jmp->Registration == ~0UL)
|
||||
{
|
||||
jmp->TryLevel = TRYLEVEL_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
|
||||
va_start( args, nb_args );
|
||||
if (nb_args > 0) jmp->UnwindFunc = va_arg( args, unsigned long );
|
||||
if (nb_args > 1) jmp->TryLevel = va_arg( args, unsigned long );
|
||||
else jmp->TryLevel = ((MSVCRT_EXCEPTION_FRAME*)jmp->Registration)->trylevel;
|
||||
for (i = 0; i < 6 && i < nb_args - 2; i++)
|
||||
jmp->UnwindData[i] = va_arg( args, unsigned long );
|
||||
va_end( args );
|
||||
}
|
||||
|
||||
TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx\n",
|
||||
jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* longjmp (MSVCRT.@)
|
||||
*/
|
||||
void __cdecl longjmp(_JUMP_BUFFER *jmp, int retval)
|
||||
{
|
||||
unsigned long cur_frame = 0;
|
||||
|
||||
TRACE("buf=%p ebx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx eip=%08lx frame=%08lx retval=%08x\n",
|
||||
jmp, jmp->Ebx, jmp->Esi, jmp->Edi, jmp->Ebp, jmp->Esp, jmp->Eip, jmp->Registration, retval );
|
||||
|
||||
cur_frame=(unsigned long)NtCurrentTeb()->Tib.ExceptionList;
|
||||
TRACE("cur_frame=%lx\n",cur_frame);
|
||||
|
||||
if (cur_frame != jmp->Registration)
|
||||
_global_unwind2((EXCEPTION_REGISTRATION_RECORD*)jmp->Registration);
|
||||
|
||||
if (jmp->Registration)
|
||||
{
|
||||
if (IsBadReadPtr(&jmp->Cookie, sizeof(long)) || jmp->Cookie != MSVCRT_JMP_MAGIC)
|
||||
{
|
||||
msvcrt_local_unwind2((MSVCRT_EXCEPTION_FRAME*)jmp->Registration,
|
||||
jmp->TryLevel, (void *)jmp->Ebp);
|
||||
}
|
||||
else if(jmp->UnwindFunc)
|
||||
{
|
||||
MSVCRT_unwind_function unwind_func;
|
||||
|
||||
unwind_func=(MSVCRT_unwind_function)jmp->UnwindFunc;
|
||||
unwind_func(jmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!retval)
|
||||
retval = 1;
|
||||
|
||||
__wine_longjmp( (__wine_jmp_buf *)jmp, retval );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _seh_longjmp_unwind (MSVCRT.@)
|
||||
*/
|
||||
void __stdcall _seh_longjmp_unwind(_JUMP_BUFFER *jmp)
|
||||
{
|
||||
msvcrt_local_unwind2( (MSVCRT_EXCEPTION_FRAME *)jmp->Registration, jmp->TryLevel, (void *)jmp->Ebp );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _seh_longjmp_unwind4 (MSVCRT.@)
|
||||
*/
|
||||
void __stdcall _seh_longjmp_unwind4(_JUMP_BUFFER *jmp)
|
||||
{
|
||||
msvcrt_local_unwind4( (ULONG *)&jmp->Cookie, (MSVCRT_EXCEPTION_FRAME *)jmp->Registration,
|
||||
jmp->TryLevel, (void *)jmp->Ebp );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* handle_fpieee_flt
|
||||
*/
|
||||
int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) )
|
||||
{
|
||||
FLOATING_SAVE_AREA *ctx = &ep->ContextRecord->FloatSave;
|
||||
_FPIEEE_RECORD rec;
|
||||
int ret;
|
||||
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.RoundingMode = ctx->ControlWord >> 10;
|
||||
switch((ctx->ControlWord >> 8) & 0x3) {
|
||||
case 0: rec.Precision = 2; break;
|
||||
case 1: rec.Precision = 3; break;
|
||||
case 2: rec.Precision = 1; break;
|
||||
case 3: rec.Precision = 0; break;
|
||||
}
|
||||
rec.Status.InvalidOperation = ctx->StatusWord & 0x1;
|
||||
rec.Status.ZeroDivide = ((ctx->StatusWord & 0x4) != 0);
|
||||
rec.Status.Overflow = ((ctx->StatusWord & 0x8) != 0);
|
||||
rec.Status.Underflow = ((ctx->StatusWord & 0x10) != 0);
|
||||
rec.Status.Inexact = ((ctx->StatusWord & 0x20) != 0);
|
||||
rec.Enable.InvalidOperation = ((ctx->ControlWord & 0x1) == 0);
|
||||
rec.Enable.ZeroDivide = ((ctx->ControlWord & 0x4) == 0);
|
||||
rec.Enable.Overflow = ((ctx->ControlWord & 0x8) == 0);
|
||||
rec.Enable.Underflow = ((ctx->ControlWord & 0x10) == 0);
|
||||
rec.Enable.Inexact = ((ctx->ControlWord & 0x20) == 0);
|
||||
rec.Cause.InvalidOperation = rec.Enable.InvalidOperation & rec.Status.InvalidOperation;
|
||||
rec.Cause.ZeroDivide = rec.Enable.ZeroDivide & rec.Status.ZeroDivide;
|
||||
rec.Cause.Overflow = rec.Enable.Overflow & rec.Status.Overflow;
|
||||
rec.Cause.Underflow = rec.Enable.Underflow & rec.Status.Underflow;
|
||||
rec.Cause.Inexact = rec.Enable.Inexact & rec.Status.Inexact;
|
||||
|
||||
TRACE("code %lx handler %p opcode %lx\n", exception_code, handler,
|
||||
*(ULONG*)ep->ContextRecord->FloatSave.ErrorOffset);
|
||||
|
||||
if(*(WORD*)ctx->ErrorOffset == 0x35dc) { /* fdiv m64fp */
|
||||
if(exception_code==STATUS_FLOAT_DIVIDE_BY_ZERO || exception_code==STATUS_FLOAT_INVALID_OPERATION) {
|
||||
rec.Operand1.OperandValid = 1;
|
||||
rec.Result.OperandValid = 0;
|
||||
} else {
|
||||
rec.Operand1.OperandValid = 0;
|
||||
rec.Result.OperandValid = 1;
|
||||
}
|
||||
rec.Operand2.OperandValid = 1;
|
||||
rec.Operation = _FpCodeDivide;
|
||||
rec.Operand1.Format = _FpFormatFp80;
|
||||
memcpy(&rec.Operand1.Value.Fp80Value, ctx->RegisterArea, sizeof(rec.Operand1.Value.Fp80Value));
|
||||
rec.Operand2.Format = _FpFormatFp64;
|
||||
rec.Operand2.Value.Fp64Value = *(double*)ctx->DataOffset;
|
||||
rec.Result.Format = _FpFormatFp80;
|
||||
memcpy(&rec.Result.Value.Fp80Value, ctx->RegisterArea, sizeof(rec.Operand1.Value.Fp80Value));
|
||||
|
||||
ret = handler(&rec);
|
||||
|
||||
if(ret == EXCEPTION_CONTINUE_EXECUTION)
|
||||
memcpy(ctx->RegisterArea, &rec.Result.Value.Fp80Value, sizeof(rec.Operand1.Value.Fp80Value));
|
||||
return ret;
|
||||
}
|
||||
|
||||
FIXME("unsupported opcode: %lx\n", *(ULONG*)ep->ContextRecord->FloatSave.ErrorOffset);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#endif /* __i386__ */
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* msvcrt C++ exception handling
|
||||
*
|
||||
* Copyright 2011 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if defined(__x86_64__) && !defined(__arm64ec__)
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <fpieee.h>
|
||||
#define longjmp ms_longjmp /* avoid prototype mismatch */
|
||||
#include <setjmp.h>
|
||||
#undef longjmp
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "wine/exception.h"
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "cppexcept.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
extern void *call_exc_handler( void *handler, ULONG_PTR frame, UINT flags );
|
||||
__ASM_GLOBAL_FUNC( call_exc_handler,
|
||||
"subq $0x28,%rsp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
|
||||
__ASM_SEH(".seh_stackalloc 0x28\n\t")
|
||||
__ASM_SEH(".seh_endprologue\n\t")
|
||||
"movq %rcx, 0x0(%rsp)\n\t"
|
||||
"movl %r8d, 0x8(%rsp)\n\t"
|
||||
"movq %rdx, 0x10(%rsp)\n\t"
|
||||
"callq *%rcx\n\t"
|
||||
"addq $0x28,%rsp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
|
||||
"ret" )
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_catch_handler
|
||||
*/
|
||||
void *call_catch_handler( EXCEPTION_RECORD *rec )
|
||||
{
|
||||
ULONG_PTR frame = rec->ExceptionInformation[1];
|
||||
void *handler = (void *)rec->ExceptionInformation[5];
|
||||
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100 );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* call_unwind_handler
|
||||
*/
|
||||
void *call_unwind_handler( void *handler, ULONG_PTR frame, DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
TRACE( "calling %p frame %Ix\n", handler, frame );
|
||||
return call_exc_handler( handler, frame, 0x100 );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_exception_pc
|
||||
*/
|
||||
ULONG_PTR get_exception_pc( DISPATCHER_CONTEXT *dispatch )
|
||||
{
|
||||
return dispatch->ControlPc;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* longjmp (MSVCRT.@)
|
||||
*/
|
||||
#ifndef __WINE_PE_BUILD
|
||||
void __cdecl longjmp( _JUMP_BUFFER *jmp, int retval )
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
|
||||
if (!retval) retval = 1;
|
||||
if (jmp->Frame)
|
||||
{
|
||||
rec.ExceptionCode = STATUS_LONGJUMP;
|
||||
rec.ExceptionFlags = 0;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = NULL;
|
||||
rec.NumberParameters = 1;
|
||||
rec.ExceptionInformation[0] = (DWORD_PTR)jmp;
|
||||
RtlUnwind( (void *)jmp->Frame, (void *)jmp->Rip, &rec, IntToPtr(retval) );
|
||||
}
|
||||
__wine_longjmp( (__wine_jmp_buf *)jmp, retval );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************
|
||||
* _local_unwind (MSVCRT.@)
|
||||
*/
|
||||
void __cdecl _local_unwind( void *frame, void *target )
|
||||
{
|
||||
RtlUnwind( frame, target, NULL, 0 );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* handle_fpieee_flt
|
||||
*/
|
||||
int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep,
|
||||
int (__cdecl *handler)(_FPIEEE_RECORD*) )
|
||||
{
|
||||
FIXME("(%lx %p %p) opcode: %#I64x\n", exception_code, ep, handler,
|
||||
*(ULONG64*)ep->ContextRecord->Rip);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=110 && _MSVCR_VER<=120
|
||||
/*********************************************************************
|
||||
* __crtCapturePreviousContext (MSVCR110.@)
|
||||
*/
|
||||
void __cdecl __crtCapturePreviousContext( CONTEXT *ctx )
|
||||
{
|
||||
UNWIND_HISTORY_TABLE table;
|
||||
RUNTIME_FUNCTION *func;
|
||||
PEXCEPTION_ROUTINE handler;
|
||||
ULONG_PTR frame, base;
|
||||
void *data;
|
||||
ULONG i;
|
||||
|
||||
RtlCaptureContext( ctx );
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (!(func = RtlLookupFunctionEntry( ctx->Rip, &base, &table ))) break;
|
||||
if (RtlVirtualUnwind2( UNW_FLAG_NHANDLER, base, ctx->Rip, func, ctx, NULL,
|
||||
&data, &frame, NULL, NULL, NULL, &handler, 0 )) break;
|
||||
if (!ctx->Rip) break;
|
||||
if (!frame) break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* std::exception_ptr helper functions
|
||||
*
|
||||
* Copyright 2022 Torge Matthies for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msvcrt.h"
|
||||
#include "cppexcept.h"
|
||||
|
||||
/* call a copy constructor */
|
||||
#ifdef __ASM_USE_THISCALL_WRAPPER
|
||||
__ASM_GLOBAL_FUNC( call_copy_ctor,
|
||||
"pushl %ebp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
|
||||
"movl %esp, %ebp\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
|
||||
"pushl $1\n\t"
|
||||
"movl 12(%ebp), %ecx\n\t"
|
||||
"pushl 16(%ebp)\n\t"
|
||||
"call *8(%ebp)\n\t"
|
||||
"leave\n"
|
||||
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
|
||||
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
||||
"ret" )
|
||||
__ASM_GLOBAL_FUNC( call_dtor,
|
||||
"movl 8(%esp),%ecx\n\t"
|
||||
"call *4(%esp)\n\t"
|
||||
"ret" )
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER >= 100
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrCreate@@YAXPAX@Z
|
||||
* ?__ExceptionPtrCreate@@YAXPEAX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrCreate(exception_ptr *ep)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
|
||||
ep->rec = NULL;
|
||||
ep->ref = NULL;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrDestroy@@YAXPAX@Z
|
||||
* ?__ExceptionPtrDestroy@@YAXPEAX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrDestroy(exception_ptr *ep)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
|
||||
if (!ep->rec)
|
||||
return;
|
||||
|
||||
if (!InterlockedDecrement(ep->ref))
|
||||
{
|
||||
if (ep->rec->ExceptionCode == CXX_EXCEPTION)
|
||||
{
|
||||
const cxx_exception_type *type = (void*)ep->rec->ExceptionInformation[2];
|
||||
void *obj = (void*)ep->rec->ExceptionInformation[1];
|
||||
uintptr_t base = rtti_rva_base( type );
|
||||
|
||||
if (type && type->destructor) call_dtor( rtti_rva(type->destructor, base), obj );
|
||||
HeapFree(GetProcessHeap(), 0, obj);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, ep->rec);
|
||||
HeapFree(GetProcessHeap(), 0, ep->ref);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _CONCRT
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrCopy@@YAXPAXPBX@Z
|
||||
* ?__ExceptionPtrCopy@@YAXPEAXPEBX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrCopy(exception_ptr *ep, const exception_ptr *copy)
|
||||
{
|
||||
TRACE("(%p %p)\n", ep, copy);
|
||||
|
||||
/* don't destroy object stored in ep */
|
||||
*ep = *copy;
|
||||
if (ep->ref)
|
||||
InterlockedIncrement(copy->ref);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrAssign@@YAXPAXPBX@Z
|
||||
* ?__ExceptionPtrAssign@@YAXPEAXPEBX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrAssign(exception_ptr *ep, const exception_ptr *assign)
|
||||
{
|
||||
TRACE("(%p %p)\n", ep, assign);
|
||||
|
||||
/* don't destroy object stored in ep */
|
||||
if (ep->ref)
|
||||
InterlockedDecrement(ep->ref);
|
||||
|
||||
*ep = *assign;
|
||||
if (ep->ref)
|
||||
InterlockedIncrement(ep->ref);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrRethrow@@YAXPBX@Z
|
||||
* ?__ExceptionPtrRethrow@@YAXPEBX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrRethrow(const exception_ptr *ep)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
|
||||
if (!ep->rec)
|
||||
{
|
||||
throw_exception("bad exception");
|
||||
return;
|
||||
}
|
||||
|
||||
RaiseException(ep->rec->ExceptionCode, ep->rec->ExceptionFlags & ~EXCEPTION_UNWINDING,
|
||||
ep->rec->NumberParameters, ep->rec->ExceptionInformation);
|
||||
}
|
||||
|
||||
void exception_ptr_from_record(exception_ptr *ep, EXCEPTION_RECORD *rec)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
|
||||
if (!rec)
|
||||
{
|
||||
ep->rec = NULL;
|
||||
ep->ref = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD));
|
||||
ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int));
|
||||
|
||||
*ep->rec = *rec;
|
||||
*ep->ref = 1;
|
||||
|
||||
if (ep->rec->ExceptionCode == CXX_EXCEPTION)
|
||||
{
|
||||
void *obj = (void*)ep->rec->ExceptionInformation[1];
|
||||
const cxx_exception_type *et = (void*)ep->rec->ExceptionInformation[2];
|
||||
uintptr_t base = rtti_rva_base( et );
|
||||
const cxx_type_info_table *table = rtti_rva( et->type_info_table, base );
|
||||
const cxx_type_info *ti = rtti_rva( table->info[0], base );
|
||||
void **data = HeapAlloc(GetProcessHeap(), 0, ti->size);
|
||||
|
||||
if (ti->flags & CLASS_IS_SIMPLE_TYPE)
|
||||
{
|
||||
memcpy(data, obj, ti->size);
|
||||
if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data);
|
||||
}
|
||||
else if (ti->copy_ctor)
|
||||
{
|
||||
call_copy_ctor(rtti_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, obj),
|
||||
ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS);
|
||||
}
|
||||
else
|
||||
memcpy(data, get_this_pointer(&ti->offsets, obj), ti->size);
|
||||
ep->rec->ExceptionInformation[1] = (ULONG_PTR)data;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef _CONCRT
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrCurrentException@@YAXPAX@Z
|
||||
* ?__ExceptionPtrCurrentException@@YAXPEAX@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrCurrentException(exception_ptr *ep)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
exception_ptr_from_record(ep, msvcrt_get_thread_data()->exc_record);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 110
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrToBool@@YA_NPBX@Z
|
||||
* ?__ExceptionPtrToBool@@YA_NPEBX@Z
|
||||
*/
|
||||
bool __cdecl __ExceptionPtrToBool(exception_ptr *ep)
|
||||
{
|
||||
return !!ep->rec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrCopyException@@YAXPAXPBX1@Z
|
||||
* ?__ExceptionPtrCopyException@@YAXPEAXPEBX1@Z
|
||||
*/
|
||||
void __cdecl __ExceptionPtrCopyException(exception_ptr *ep,
|
||||
exception *object, const cxx_exception_type *type)
|
||||
{
|
||||
const cxx_type_info_table *table;
|
||||
const cxx_type_info *ti;
|
||||
void **data;
|
||||
uintptr_t base = rtti_rva_base( type );
|
||||
|
||||
__ExceptionPtrDestroy(ep);
|
||||
|
||||
ep->rec = HeapAlloc(GetProcessHeap(), 0, sizeof(EXCEPTION_RECORD));
|
||||
ep->ref = HeapAlloc(GetProcessHeap(), 0, sizeof(int));
|
||||
*ep->ref = 1;
|
||||
|
||||
memset(ep->rec, 0, sizeof(EXCEPTION_RECORD));
|
||||
ep->rec->ExceptionCode = CXX_EXCEPTION;
|
||||
ep->rec->ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
ep->rec->NumberParameters = CXX_EXCEPTION_PARAMS;
|
||||
ep->rec->ExceptionInformation[0] = CXX_FRAME_MAGIC_VC6;
|
||||
ep->rec->ExceptionInformation[2] = (ULONG_PTR)type;
|
||||
if (CXX_EXCEPTION_PARAMS == 4) ep->rec->ExceptionInformation[3] = base;
|
||||
|
||||
table = rtti_rva( type->type_info_table, base );
|
||||
ti = rtti_rva( table->info[0], base );
|
||||
data = HeapAlloc(GetProcessHeap(), 0, ti->size);
|
||||
if (ti->flags & CLASS_IS_SIMPLE_TYPE)
|
||||
{
|
||||
memcpy(data, object, ti->size);
|
||||
if (ti->size == sizeof(void *)) *data = get_this_pointer(&ti->offsets, *data);
|
||||
}
|
||||
else if (ti->copy_ctor)
|
||||
{
|
||||
call_copy_ctor( rtti_rva(ti->copy_ctor, base), data, get_this_pointer(&ti->offsets, object),
|
||||
ti->flags & CLASS_HAS_VIRTUAL_BASE_CLASS);
|
||||
}
|
||||
else
|
||||
memcpy(data, get_this_pointer(&ti->offsets, object), ti->size);
|
||||
ep->rec->ExceptionInformation[1] = (ULONG_PTR)data;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?__ExceptionPtrCompare@@YA_NPBX0@Z
|
||||
* ?__ExceptionPtrCompare@@YA_NPEBX0@Z
|
||||
*/
|
||||
bool __cdecl __ExceptionPtrCompare(const exception_ptr *ep1, const exception_ptr *ep2)
|
||||
{
|
||||
return ep1->rec == ep2->rec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _MSVCR_VER >= 100 */
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* msvcrt.dll exit functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include <conio.h>
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* MT */
|
||||
#define LOCK_EXIT _lock(_EXIT_LOCK1)
|
||||
#define UNLOCK_EXIT _unlock(_EXIT_LOCK1)
|
||||
|
||||
static _purecall_handler purecall_handler = NULL;
|
||||
|
||||
static _onexit_table_t MSVCRT_atexit_table;
|
||||
|
||||
typedef void (__stdcall *_tls_callback_type)(void*,ULONG,void*);
|
||||
static _tls_callback_type tls_atexit_callback;
|
||||
|
||||
static CRITICAL_SECTION MSVCRT_onexit_cs;
|
||||
static CRITICAL_SECTION_DEBUG MSVCRT_onexit_cs_debug =
|
||||
{
|
||||
0, 0, &MSVCRT_onexit_cs,
|
||||
{ &MSVCRT_onexit_cs_debug.ProcessLocksList, &MSVCRT_onexit_cs_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_onexit_cs") }
|
||||
};
|
||||
static CRITICAL_SECTION MSVCRT_onexit_cs = { &MSVCRT_onexit_cs_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
extern int MSVCRT_app_type;
|
||||
extern wchar_t *MSVCRT__wpgmptr;
|
||||
|
||||
#if _MSVCR_VER > 0 || defined(_DEBUG)
|
||||
static unsigned int MSVCRT_abort_behavior = _WRITE_ABORT_MSG | _CALL_REPORTFAULT;
|
||||
#endif
|
||||
|
||||
static int MSVCRT_error_mode = _OUT_TO_DEFAULT;
|
||||
|
||||
void (*CDECL _aexit_rtn)(int) = _exit;
|
||||
|
||||
static int initialize_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (table->_first == table->_end)
|
||||
table->_last = table->_end = table->_first = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_onexit_function(_onexit_table_t *table, _onexit_t func)
|
||||
{
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
EnterCriticalSection(&MSVCRT_onexit_cs);
|
||||
if (!table->_first)
|
||||
{
|
||||
table->_first = calloc(32, sizeof(void *));
|
||||
if (!table->_first)
|
||||
{
|
||||
WARN("failed to allocate initial table.\n");
|
||||
LeaveCriticalSection(&MSVCRT_onexit_cs);
|
||||
return -1;
|
||||
}
|
||||
table->_last = table->_first;
|
||||
table->_end = table->_first + 32;
|
||||
}
|
||||
|
||||
/* grow if full */
|
||||
if (table->_last == table->_end)
|
||||
{
|
||||
int len = table->_end - table->_first;
|
||||
_PVFV *tmp = realloc(table->_first, 2 * len * sizeof(void *));
|
||||
if (!tmp)
|
||||
{
|
||||
WARN("failed to grow table.\n");
|
||||
LeaveCriticalSection(&MSVCRT_onexit_cs);
|
||||
return -1;
|
||||
}
|
||||
table->_first = tmp;
|
||||
table->_end = table->_first + 2 * len;
|
||||
table->_last = table->_first + len;
|
||||
}
|
||||
|
||||
*table->_last = (_PVFV)func;
|
||||
table->_last++;
|
||||
LeaveCriticalSection(&MSVCRT_onexit_cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int execute_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
_onexit_table_t copy;
|
||||
_PVFV *func;
|
||||
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
EnterCriticalSection(&MSVCRT_onexit_cs);
|
||||
if (!table->_first || table->_first >= table->_last)
|
||||
{
|
||||
LeaveCriticalSection(&MSVCRT_onexit_cs);
|
||||
return 0;
|
||||
}
|
||||
copy._first = table->_first;
|
||||
copy._last = table->_last;
|
||||
copy._end = table->_end;
|
||||
memset(table, 0, sizeof(*table));
|
||||
initialize_onexit_table(table);
|
||||
LeaveCriticalSection(&MSVCRT_onexit_cs);
|
||||
|
||||
for (func = copy._last - 1; func >= copy._first; func--)
|
||||
{
|
||||
if (*func)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
free(copy._first);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void call_atexit(void)
|
||||
{
|
||||
/* Note: should only be called with the exit lock held */
|
||||
if (tls_atexit_callback) tls_atexit_callback(NULL, DLL_PROCESS_DETACH, NULL);
|
||||
execute_onexit_table(&MSVCRT_atexit_table);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __dllonexit (MSVCRT.@)
|
||||
*/
|
||||
_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **start, _onexit_t **end)
|
||||
{
|
||||
_onexit_t *tmp;
|
||||
int len;
|
||||
|
||||
TRACE("(%p,%p,%p)\n", func, start, end);
|
||||
|
||||
if (!start || !*start || !end || !*end)
|
||||
{
|
||||
FIXME("bad table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = (*end - *start);
|
||||
|
||||
TRACE("table start %p-%p, %d entries\n", *start, *end, len);
|
||||
|
||||
if (++len <= 0)
|
||||
return NULL;
|
||||
|
||||
tmp = realloc(*start, len * sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
*start = tmp;
|
||||
*end = tmp + len;
|
||||
tmp[len - 1] = func;
|
||||
TRACE("new table start %p-%p, %d entries\n", *start, *end, len);
|
||||
return func;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _exit (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _exit(int exitcode)
|
||||
{
|
||||
TRACE("(%d)\n", exitcode);
|
||||
ExitProcess(exitcode);
|
||||
}
|
||||
|
||||
/* Print out an error message with an option to debug */
|
||||
static void DoMessageBoxW(const wchar_t *lead, const wchar_t *message)
|
||||
{
|
||||
MSGBOXPARAMSW msgbox;
|
||||
wchar_t text[2048];
|
||||
INT ret;
|
||||
|
||||
_snwprintf(text, ARRAY_SIZE(text), L"%ls\n\nProgram: %ls\n%ls\n\n"
|
||||
L"Press OK to exit the program, or Cancel to start the Wine debugger.\n",
|
||||
lead, MSVCRT__wpgmptr, message);
|
||||
|
||||
msgbox.cbSize = sizeof(msgbox);
|
||||
msgbox.hwndOwner = GetActiveWindow();
|
||||
msgbox.hInstance = 0;
|
||||
msgbox.lpszText = text;
|
||||
msgbox.lpszCaption = L"Wine C++ Runtime Library";
|
||||
msgbox.dwStyle = MB_OKCANCEL|MB_ICONERROR;
|
||||
msgbox.lpszIcon = NULL;
|
||||
msgbox.dwContextHelpId = 0;
|
||||
msgbox.lpfnMsgBoxCallback = NULL;
|
||||
msgbox.dwLanguageId = LANG_NEUTRAL;
|
||||
|
||||
ret = MessageBoxIndirectW(&msgbox);
|
||||
if (ret == IDCANCEL)
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
static void DoMessageBox(const char *lead, const char *message)
|
||||
{
|
||||
wchar_t leadW[1024], messageW[1024];
|
||||
|
||||
mbstowcs(leadW, lead, 1024);
|
||||
mbstowcs(messageW, message, 1024);
|
||||
|
||||
DoMessageBoxW(leadW, messageW);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _amsg_exit (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _amsg_exit(int errnum)
|
||||
{
|
||||
TRACE("(%d)\n", errnum);
|
||||
|
||||
if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
|
||||
((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
|
||||
{
|
||||
char text[32];
|
||||
sprintf(text, "Error: R60%d",errnum);
|
||||
DoMessageBox("Runtime error!", text);
|
||||
}
|
||||
else
|
||||
_cprintf("\nruntime error R60%d\n",errnum);
|
||||
_aexit_rtn(255);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* abort (MSVCRT.@)
|
||||
*/
|
||||
void CDECL abort(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
|
||||
#if (_MSVCR_VER > 0 && _MSVCR_VER < 100) || _MSVCR_VER == 120 || defined(_DEBUG)
|
||||
if (MSVCRT_abort_behavior & _WRITE_ABORT_MSG)
|
||||
{
|
||||
if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
|
||||
((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
|
||||
{
|
||||
DoMessageBox("Runtime error!", "abnormal program termination");
|
||||
}
|
||||
else
|
||||
_cputs("\nabnormal program termination\n");
|
||||
}
|
||||
#endif
|
||||
raise(SIGABRT);
|
||||
/* in case raise() returns */
|
||||
_exit(3);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _set_abort_behavior (MSVCR80.@)
|
||||
*/
|
||||
unsigned int CDECL _set_abort_behavior(unsigned int flags, unsigned int mask)
|
||||
{
|
||||
unsigned int old = MSVCRT_abort_behavior;
|
||||
|
||||
TRACE("%x, %x\n", flags, mask);
|
||||
if (mask & _CALL_REPORTFAULT)
|
||||
FIXME("_WRITE_CALL_REPORTFAULT unhandled\n");
|
||||
|
||||
MSVCRT_abort_behavior = (MSVCRT_abort_behavior & ~mask) | (flags & mask);
|
||||
return old;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _wassert (MSVCRT.@)
|
||||
*/
|
||||
void DECLSPEC_NORETURN CDECL _wassert(const wchar_t* str, const wchar_t* file, unsigned int line)
|
||||
{
|
||||
ERR("(%s,%s,%d)\n", debugstr_w(str), debugstr_w(file), line);
|
||||
|
||||
if ((MSVCRT_error_mode == _OUT_TO_MSGBOX) ||
|
||||
((MSVCRT_error_mode == _OUT_TO_DEFAULT) && (MSVCRT_app_type == 2)))
|
||||
{
|
||||
wchar_t text[2048];
|
||||
_snwprintf(text, sizeof(text), L"File: %ls\nLine: %d\n\nExpression: \"%ls\"", file, line, str);
|
||||
DoMessageBoxW(L"Assertion failed!", text);
|
||||
}
|
||||
else
|
||||
fwprintf(stderr, L"Assertion failed: %ls, file %ls, line %d\n\n", str, file, line);
|
||||
|
||||
raise(SIGABRT);
|
||||
_exit(3);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _assert (MSVCRT.@)
|
||||
*/
|
||||
void DECLSPEC_NORETURN CDECL _assert(const char* str, const char* file, unsigned int line)
|
||||
{
|
||||
wchar_t strW[1024], fileW[1024];
|
||||
|
||||
mbstowcs(strW, str, 1024);
|
||||
mbstowcs(fileW, file, 1024);
|
||||
|
||||
_wassert(strW, fileW, line);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _c_exit (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _c_exit(void)
|
||||
{
|
||||
TRACE("(void)\n");
|
||||
/* All cleanup is done on DLL detach; Return to caller */
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cexit (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _cexit(void)
|
||||
{
|
||||
TRACE("(void)\n");
|
||||
LOCK_EXIT;
|
||||
call_atexit();
|
||||
UNLOCK_EXIT;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _onexit (MSVCRT.@)
|
||||
*/
|
||||
_onexit_t CDECL _onexit(_onexit_t func)
|
||||
{
|
||||
TRACE("(%p)\n",func);
|
||||
|
||||
if (!func)
|
||||
return NULL;
|
||||
|
||||
LOCK_EXIT;
|
||||
register_onexit_function(&MSVCRT_atexit_table, func);
|
||||
UNLOCK_EXIT;
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* exit (MSVCRT.@)
|
||||
*/
|
||||
void CDECL exit(int exitcode)
|
||||
{
|
||||
HMODULE hmscoree;
|
||||
void (WINAPI *pCorExitProcess)(int);
|
||||
|
||||
TRACE("(%d)\n",exitcode);
|
||||
_cexit();
|
||||
|
||||
hmscoree = GetModuleHandleW(L"mscoree");
|
||||
|
||||
if (hmscoree)
|
||||
{
|
||||
pCorExitProcess = (void*)GetProcAddress(hmscoree, "CorExitProcess");
|
||||
|
||||
if (pCorExitProcess)
|
||||
pCorExitProcess(exitcode);
|
||||
}
|
||||
|
||||
ExitProcess(exitcode);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* atexit (MSVCRT.@)
|
||||
*/
|
||||
int CDECL MSVCRT_atexit(void (__cdecl *func)(void))
|
||||
{
|
||||
TRACE("(%p)\n", func);
|
||||
return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
static _onexit_table_t MSVCRT_quick_exit_table;
|
||||
|
||||
/*********************************************************************
|
||||
* _crt_at_quick_exit (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _crt_at_quick_exit(void (__cdecl *func)(void))
|
||||
{
|
||||
TRACE("(%p)\n", func);
|
||||
return register_onexit_function(&MSVCRT_quick_exit_table, (_onexit_t)func);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* quick_exit (UCRTBASE.@)
|
||||
*/
|
||||
void CDECL quick_exit(int exitcode)
|
||||
{
|
||||
TRACE("(%d)\n", exitcode);
|
||||
|
||||
execute_onexit_table(&MSVCRT_quick_exit_table);
|
||||
_exit(exitcode);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _crt_atexit (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _crt_atexit(void (__cdecl *func)(void))
|
||||
{
|
||||
TRACE("(%p)\n", func);
|
||||
return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _initialize_onexit_table (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _initialize_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
TRACE("(%p)\n", table);
|
||||
|
||||
return initialize_onexit_table(table);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _register_onexit_function (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func)
|
||||
{
|
||||
TRACE("(%p %p)\n", table, func);
|
||||
|
||||
return register_onexit_function(table, func);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _execute_onexit_table (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL _execute_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
TRACE("(%p)\n", table);
|
||||
|
||||
return execute_onexit_table(table);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _register_thread_local_exe_atexit_callback (UCRTBASE.@)
|
||||
*/
|
||||
void CDECL _register_thread_local_exe_atexit_callback(_tls_callback_type callback)
|
||||
{
|
||||
TRACE("(%p)\n", callback);
|
||||
tls_atexit_callback = callback;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=71
|
||||
/*********************************************************************
|
||||
* _set_purecall_handler (MSVCR71.@)
|
||||
*/
|
||||
_purecall_handler CDECL _set_purecall_handler(_purecall_handler function)
|
||||
{
|
||||
_purecall_handler ret = purecall_handler;
|
||||
|
||||
TRACE("(%p)\n", function);
|
||||
purecall_handler = function;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _get_purecall_handler (MSVCR80.@)
|
||||
*/
|
||||
_purecall_handler CDECL _get_purecall_handler(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
return purecall_handler;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* _purecall (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _purecall(void)
|
||||
{
|
||||
TRACE("(void)\n");
|
||||
|
||||
if(purecall_handler)
|
||||
purecall_handler();
|
||||
_amsg_exit( 25 );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* _set_error_mode (MSVCRT.@)
|
||||
*
|
||||
* Set the error mode, which describes where the C run-time writes error messages.
|
||||
*
|
||||
* PARAMS
|
||||
* mode - the new error mode
|
||||
*
|
||||
* RETURNS
|
||||
* The old error mode.
|
||||
*
|
||||
*/
|
||||
int CDECL _set_error_mode(int mode)
|
||||
{
|
||||
|
||||
const int old = MSVCRT_error_mode;
|
||||
if ( _REPORT_ERRMODE != mode ) {
|
||||
MSVCRT_error_mode = mode;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* C++ exception handling (ver. 4)
|
||||
*
|
||||
* Copyright 2020 Piotr Caban
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <corecrt.h>
|
||||
|
||||
#if defined(__x86_64__) && _MSVCR_VER>=140
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
#include "cppexcept.h"
|
||||
#include "msvcrt.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
|
||||
static DWORD fls_index;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE header;
|
||||
UINT bbt_flags;
|
||||
UINT unwind_count;
|
||||
UINT unwind_map;
|
||||
UINT tryblock_count;
|
||||
UINT tryblock_map;
|
||||
UINT ip_count;
|
||||
UINT ip_map;
|
||||
UINT frame;
|
||||
} cxx_function_descr_v4;
|
||||
#define FUNC_DESCR_IS_CATCH 0x01
|
||||
#define FUNC_DESCR_IS_SEPARATED 0x02
|
||||
#define FUNC_DESCR_BBT 0x04
|
||||
#define FUNC_DESCR_UNWIND_MAP 0x08
|
||||
#define FUNC_DESCR_TRYBLOCK_MAP 0x10
|
||||
#define FUNC_DESCR_EHS 0x20
|
||||
#define FUNC_DESCR_NO_EXCEPT 0x40
|
||||
#define FUNC_DESCR_RESERVED 0x80
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT type;
|
||||
BYTE *prev;
|
||||
UINT handler;
|
||||
UINT object;
|
||||
} unwind_info_v4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE header;
|
||||
UINT flags;
|
||||
UINT type_info;
|
||||
int offset;
|
||||
UINT handler;
|
||||
UINT ret_addr[2];
|
||||
} catchblock_info_v4;
|
||||
#define CATCHBLOCK_FLAGS 0x01
|
||||
#define CATCHBLOCK_TYPE_INFO 0x02
|
||||
#define CATCHBLOCK_OFFSET 0x04
|
||||
#define CATCHBLOCK_SEPARATED 0x08
|
||||
#define CATCHBLOCK_RET_ADDR_MASK 0x30
|
||||
#define CATCHBLOCK_RET_ADDR 0x10
|
||||
#define CATCHBLOCK_TWO_RET_ADDRS 0x20
|
||||
|
||||
#define UNWIND_TYPE_NO_HANDLER 0
|
||||
#define UNWIND_TYPE_DTOR_OBJ 1
|
||||
#define UNWIND_TYPE_DTOR_PTR 2
|
||||
#define UNWIND_TYPE_FRAME 3
|
||||
|
||||
#define CONSOLIDATE_UNWIND_PARAMETER_COUNT 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cxx_frame_info frame_info;
|
||||
BOOL rethrow;
|
||||
INT search_state;
|
||||
INT unwind_state;
|
||||
EXCEPTION_RECORD *prev_rec;
|
||||
} cxx_catch_ctx;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG64 dest_frame;
|
||||
ULONG64 orig_frame;
|
||||
EXCEPTION_RECORD *seh_rec;
|
||||
DISPATCHER_CONTEXT *dispatch;
|
||||
const cxx_function_descr_v4 *descr;
|
||||
int trylevel;
|
||||
} se_translator_ctx;
|
||||
|
||||
static UINT decode_uint(BYTE **b)
|
||||
{
|
||||
UINT ret;
|
||||
BYTE *p = *b;
|
||||
|
||||
if ((*p & 1) == 0)
|
||||
{
|
||||
ret = p[0] >> 1;
|
||||
p += 1;
|
||||
}
|
||||
else if ((*p & 3) == 1)
|
||||
{
|
||||
ret = (p[0] >> 2) + (p[1] << 6);
|
||||
p += 2;
|
||||
}
|
||||
else if ((*p & 7) == 3)
|
||||
{
|
||||
ret = (p[0] >> 3) + (p[1] << 5) + (p[2] << 13);
|
||||
p += 3;
|
||||
}
|
||||
else if ((*p & 15) == 7)
|
||||
{
|
||||
ret = (p[0] >> 4) + (p[1] << 4) + (p[2] << 12) + (p[3] << 20);
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("not implemented - expect crash\n");
|
||||
ret = 0;
|
||||
p += 5;
|
||||
}
|
||||
|
||||
*b = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UINT read_rva(BYTE **b)
|
||||
{
|
||||
UINT ret = *(UINT*)(*b);
|
||||
*b += sizeof(UINT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void read_unwind_info(BYTE **b, unwind_info_v4 *ui)
|
||||
{
|
||||
BYTE *p = *b;
|
||||
|
||||
memset(ui, 0, sizeof(*ui));
|
||||
ui->type = decode_uint(b);
|
||||
ui->prev = p - (ui->type >> 2);
|
||||
ui->type &= 0x3;
|
||||
|
||||
switch (ui->type)
|
||||
{
|
||||
case UNWIND_TYPE_NO_HANDLER:
|
||||
break;
|
||||
case UNWIND_TYPE_DTOR_OBJ:
|
||||
ui->handler = read_rva(b);
|
||||
ui->object = decode_uint(b); /* frame offset to object */
|
||||
break;
|
||||
case UNWIND_TYPE_DTOR_PTR:
|
||||
ui->handler = read_rva(b);
|
||||
ui->object = decode_uint(b); /* frame offset to pointer to object */
|
||||
break;
|
||||
case UNWIND_TYPE_FRAME:
|
||||
ui->handler = read_rva(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_tryblock_info(BYTE **b, tryblock_info *ti, ULONG64 image_base)
|
||||
{
|
||||
BYTE *count, *count_end;
|
||||
|
||||
ti->start_level = decode_uint(b);
|
||||
ti->end_level = decode_uint(b);
|
||||
ti->catch_level = decode_uint(b);
|
||||
ti->catchblock = read_rva(b);
|
||||
|
||||
if (ti->catchblock)
|
||||
{
|
||||
count = count_end = rtti_rva(ti->catchblock, image_base);
|
||||
ti->catchblock_count = decode_uint(&count_end);
|
||||
ti->catchblock += count_end - count;
|
||||
}
|
||||
else
|
||||
{
|
||||
ti->catchblock_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL read_catchblock_info(BYTE **b, catchblock_info_v4 *ci, DWORD func_rva)
|
||||
{
|
||||
BYTE ret_addr_type;
|
||||
memset(ci, 0, sizeof(*ci));
|
||||
ci->header = **b;
|
||||
(*b)++;
|
||||
if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET |
|
||||
CATCHBLOCK_SEPARATED | CATCHBLOCK_RET_ADDR_MASK))
|
||||
{
|
||||
FIXME("unknown header: %x\n", ci->header);
|
||||
return FALSE;
|
||||
}
|
||||
ret_addr_type = ci->header & CATCHBLOCK_RET_ADDR_MASK;
|
||||
if (ret_addr_type == (CATCHBLOCK_RET_ADDR | CATCHBLOCK_TWO_RET_ADDRS))
|
||||
{
|
||||
FIXME("unsupported ret addr type.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ci->header & CATCHBLOCK_FLAGS) ci->flags = decode_uint(b);
|
||||
if (ci->header & CATCHBLOCK_TYPE_INFO) ci->type_info = read_rva(b);
|
||||
if (ci->header & CATCHBLOCK_OFFSET) ci->offset = decode_uint(b);
|
||||
ci->handler = read_rva(b);
|
||||
if (ci->header & CATCHBLOCK_SEPARATED)
|
||||
{
|
||||
if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
|
||||
ci->ret_addr[0] = read_rva(b);
|
||||
if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
|
||||
ci->ret_addr[1] = read_rva(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
|
||||
ci->ret_addr[0] = decode_uint(b) + func_rva;
|
||||
if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
|
||||
ci->ret_addr[1] = decode_uint(b) + func_rva;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void read_ipmap_info(BYTE **b, ipmap_info *ii)
|
||||
{
|
||||
ii->ip = decode_uint(b);
|
||||
ii->state = (INT)decode_uint(b) - 1;
|
||||
}
|
||||
|
||||
static BOOL validate_cxx_function_descr4(const cxx_function_descr_v4 *descr, DISPATCHER_CONTEXT *dispatch)
|
||||
{
|
||||
ULONG64 image_base = dispatch->ImageBase;
|
||||
BYTE *unwind_map = rtti_rva(descr->unwind_map, image_base);
|
||||
BYTE *tryblock_map = rtti_rva(descr->tryblock_map, image_base);
|
||||
BYTE *ip_map = rtti_rva(descr->ip_map, image_base);
|
||||
UINT i, j;
|
||||
char *ip;
|
||||
|
||||
TRACE("header 0x%x\n", descr->header);
|
||||
TRACE("basic block transformations flags: 0x%x\n", descr->bbt_flags);
|
||||
|
||||
TRACE("unwind table: 0x%x(%p) %d\n", descr->unwind_map, unwind_map, descr->unwind_count);
|
||||
for (i = 0; i < descr->unwind_count; i++)
|
||||
{
|
||||
BYTE *entry = unwind_map;
|
||||
unwind_info_v4 ui;
|
||||
|
||||
read_unwind_info(&unwind_map, &ui);
|
||||
if (ui.prev < (BYTE*)rtti_rva(descr->unwind_map, image_base)) ui.prev = NULL;
|
||||
TRACE(" %d (%p): type 0x%x prev %p func 0x%x object 0x%x\n",
|
||||
i, entry, ui.type, ui.prev, ui.handler, ui.object);
|
||||
}
|
||||
|
||||
TRACE("try table: 0x%x(%p) %d\n", descr->tryblock_map, tryblock_map, descr->tryblock_count);
|
||||
for (i = 0; i < descr->tryblock_count; i++)
|
||||
{
|
||||
tryblock_info ti;
|
||||
BYTE *catchblock;
|
||||
|
||||
read_tryblock_info(&tryblock_map, &ti, image_base);
|
||||
catchblock = rtti_rva(ti.catchblock, image_base);
|
||||
TRACE(" %d: start %d end %d catchlevel %d catch 0x%x(%p) %d\n",
|
||||
i, ti.start_level, ti.end_level, ti.catch_level,
|
||||
ti.catchblock, catchblock, ti.catchblock_count);
|
||||
for (j = 0; j < ti.catchblock_count; j++)
|
||||
{
|
||||
catchblock_info_v4 ci;
|
||||
if (!read_catchblock_info(&catchblock, &ci,
|
||||
dispatch->FunctionEntry->BeginAddress)) return FALSE;
|
||||
TRACE(" %d: header 0x%x offset %d handler 0x%x "
|
||||
"ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j, ci.header, ci.offset,
|
||||
ci.handler, ci.ret_addr[0], ci.ret_addr[1], ci.type_info,
|
||||
dbgstr_type_info(ci.type_info ? rtti_rva(ci.type_info, image_base) : NULL));
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("ipmap: 0x%x(%p) %d\n", descr->ip_map, ip_map, descr->ip_count);
|
||||
ip = rtti_rva(dispatch->FunctionEntry->BeginAddress, image_base);
|
||||
for (i = 0; i < descr->ip_count; i++)
|
||||
{
|
||||
ipmap_info ii;
|
||||
|
||||
read_ipmap_info(&ip_map, &ii);
|
||||
ip += ii.ip;
|
||||
TRACE(" %d: ip offset 0x%x (%p) state %d\n", i, ii.ip, ip, ii.state);
|
||||
}
|
||||
|
||||
TRACE("establisher frame: %x\n", descr->frame);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline int ip_to_state4(const cxx_function_descr_v4 *descr, DISPATCHER_CONTEXT *dispatch, ULONG64 ip)
|
||||
{
|
||||
BYTE *ip_map = rtti_rva( descr->ip_map, dispatch->ImageBase );
|
||||
ULONG64 state_ip;
|
||||
ipmap_info ii;
|
||||
int ret = -1;
|
||||
UINT i;
|
||||
|
||||
state_ip = dispatch->ImageBase + dispatch->FunctionEntry->BeginAddress;
|
||||
for (i = 0; i < descr->ip_count; i++)
|
||||
{
|
||||
read_ipmap_info(&ip_map, &ii);
|
||||
state_ip += ii.ip;
|
||||
if (ip < state_ip) break;
|
||||
ret = ii.state;
|
||||
}
|
||||
|
||||
TRACE("%I64x -> state %d\n", ip, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cxx_local_unwind4(ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
|
||||
const cxx_function_descr_v4 *descr, int trylevel, int last_level)
|
||||
{
|
||||
void (__cdecl *handler_dtor)(void *obj, ULONG64 frame);
|
||||
BYTE *unwind_data, *last;
|
||||
unwind_info_v4 ui;
|
||||
void *obj;
|
||||
int i;
|
||||
|
||||
if (trylevel == -2) trylevel = ip_to_state4( descr, dispatch, get_exception_pc(dispatch) );
|
||||
|
||||
TRACE("current level: %d, last level: %d\n", trylevel, last_level);
|
||||
|
||||
if (trylevel<-1 || trylevel>=(int)descr->unwind_count)
|
||||
{
|
||||
ERR("invalid trylevel %d\n", trylevel);
|
||||
terminate();
|
||||
}
|
||||
|
||||
if (trylevel <= last_level) return;
|
||||
|
||||
unwind_data = rtti_rva(descr->unwind_map, dispatch->ImageBase);
|
||||
last = unwind_data - 1;
|
||||
for (i = 0; i < trylevel; i++)
|
||||
{
|
||||
BYTE *addr = unwind_data;
|
||||
read_unwind_info(&unwind_data, &ui);
|
||||
if (i == last_level) last = addr;
|
||||
}
|
||||
|
||||
while (unwind_data > last)
|
||||
{
|
||||
read_unwind_info(&unwind_data, &ui);
|
||||
unwind_data = ui.prev;
|
||||
|
||||
if (ui.handler)
|
||||
{
|
||||
handler_dtor = rtti_rva(ui.handler, dispatch->ImageBase);
|
||||
obj = (void *)(frame + ui.object);
|
||||
if(ui.type == UNWIND_TYPE_DTOR_PTR)
|
||||
obj = *(void**)obj;
|
||||
TRACE("handler: %p object: %p\n", handler_dtor, obj);
|
||||
handler_dtor(obj, frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LONG CALLBACK cxx_rethrow_filter(PEXCEPTION_POINTERS eptrs, void *c)
|
||||
{
|
||||
EXCEPTION_RECORD *rec = eptrs->ExceptionRecord;
|
||||
cxx_catch_ctx *ctx = c;
|
||||
|
||||
if (rec->ExceptionCode == CXX_EXCEPTION && !rec->ExceptionInformation[1] && !rec->ExceptionInformation[2])
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
|
||||
FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->search_state);
|
||||
if (rec->ExceptionCode != CXX_EXCEPTION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
if (rec->ExceptionInformation[1] == ctx->prev_rec->ExceptionInformation[1])
|
||||
ctx->rethrow = TRUE;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
static void CALLBACK cxx_catch_cleanup(BOOL normal, void *c)
|
||||
{
|
||||
cxx_catch_ctx *ctx = c;
|
||||
__CxxUnregisterExceptionObject(&ctx->frame_info, ctx->rethrow);
|
||||
|
||||
FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx->unwind_state);
|
||||
}
|
||||
|
||||
static void* WINAPI call_catch_block4(EXCEPTION_RECORD *rec)
|
||||
{
|
||||
EXCEPTION_RECORD *untrans_rec = (void*)rec->ExceptionInformation[4];
|
||||
EXCEPTION_RECORD *prev_rec = (void*)rec->ExceptionInformation[6];
|
||||
CONTEXT *context = (void*)rec->ExceptionInformation[7];
|
||||
EXCEPTION_POINTERS ep = { prev_rec, context };
|
||||
cxx_catch_ctx ctx;
|
||||
void *ret_addr = NULL;
|
||||
|
||||
ctx.rethrow = FALSE;
|
||||
__CxxRegisterExceptionObject(&ep, &ctx.frame_info);
|
||||
ctx.search_state = rec->ExceptionInformation[2];
|
||||
ctx.unwind_state = rec->ExceptionInformation[3];
|
||||
ctx.prev_rec = prev_rec;
|
||||
(*__processing_throw())--;
|
||||
__TRY
|
||||
{
|
||||
__TRY
|
||||
{
|
||||
ret_addr = call_catch_handler( rec );
|
||||
}
|
||||
__EXCEPT_CTX(cxx_rethrow_filter, &ctx)
|
||||
{
|
||||
TRACE("detect rethrow: exception code: %lx\n", prev_rec->ExceptionCode);
|
||||
ctx.rethrow = TRUE;
|
||||
FlsSetValue(fls_index, (void*)(DWORD_PTR)ctx.search_state);
|
||||
|
||||
if (untrans_rec)
|
||||
{
|
||||
__DestructExceptionObject(prev_rec);
|
||||
RaiseException(untrans_rec->ExceptionCode, untrans_rec->ExceptionFlags,
|
||||
untrans_rec->NumberParameters, untrans_rec->ExceptionInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseException(prev_rec->ExceptionCode, prev_rec->ExceptionFlags,
|
||||
prev_rec->NumberParameters, prev_rec->ExceptionInformation);
|
||||
}
|
||||
}
|
||||
__ENDTRY
|
||||
}
|
||||
__FINALLY_CTX(cxx_catch_cleanup, &ctx)
|
||||
|
||||
FlsSetValue(fls_index, (void*)-2);
|
||||
TRACE("handler returned %p, ret_addr[0] %#Ix, ret_addr[1] %#Ix.\n",
|
||||
ret_addr, rec->ExceptionInformation[8], rec->ExceptionInformation[9]);
|
||||
|
||||
if (rec->ExceptionInformation[9])
|
||||
{
|
||||
if ((ULONG_PTR)ret_addr > 1)
|
||||
{
|
||||
ERR("unexpected handler result %p.\n", ret_addr);
|
||||
abort();
|
||||
}
|
||||
return (void*)rec->ExceptionInformation[8 + (ULONG_PTR)ret_addr];
|
||||
}
|
||||
return rec->ExceptionInformation[8] ? (void *)rec->ExceptionInformation[8] : ret_addr;
|
||||
}
|
||||
|
||||
static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec)
|
||||
{
|
||||
return rec->ExceptionCode == STATUS_UNWIND_CONSOLIDATE
|
||||
&& rec->NumberParameters == CONSOLIDATE_UNWIND_PARAMETER_COUNT
|
||||
&& rec->ExceptionInformation[0] == (ULONG_PTR)call_catch_block4;
|
||||
}
|
||||
|
||||
static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||
EXCEPTION_RECORD *untrans_rec, ULONG64 frame, DISPATCHER_CONTEXT *dispatch,
|
||||
const cxx_function_descr_v4 *descr, cxx_exception_type *info,
|
||||
ULONG64 orig_frame, int trylevel)
|
||||
{
|
||||
ULONG64 exc_base = (rec->NumberParameters == 4 ? rec->ExceptionInformation[3] : 0);
|
||||
int *processing_throw = __processing_throw();
|
||||
EXCEPTION_RECORD catch_record;
|
||||
BYTE *tryblock_map;
|
||||
CONTEXT ctx;
|
||||
UINT i, j;
|
||||
|
||||
(*processing_throw)++;
|
||||
|
||||
if (trylevel == -2) trylevel = ip_to_state4( descr, dispatch, get_exception_pc(dispatch) );
|
||||
TRACE("current trylevel: %d\n", trylevel);
|
||||
|
||||
tryblock_map = rtti_rva(descr->tryblock_map, dispatch->ImageBase);
|
||||
for (i=0; i<descr->tryblock_count; i++)
|
||||
{
|
||||
tryblock_info tryblock;
|
||||
BYTE *catchblock;
|
||||
|
||||
read_tryblock_info(&tryblock_map, &tryblock, dispatch->ImageBase);
|
||||
|
||||
if (trylevel < tryblock.start_level) continue;
|
||||
if (trylevel > tryblock.end_level) continue;
|
||||
|
||||
/* got a try block */
|
||||
catchblock = rtti_rva(tryblock.catchblock, dispatch->ImageBase);
|
||||
for (j=0; j<tryblock.catchblock_count; j++)
|
||||
{
|
||||
catchblock_info_v4 ci;
|
||||
|
||||
read_catchblock_info(&catchblock, &ci, dispatch->FunctionEntry->BeginAddress);
|
||||
|
||||
if (info)
|
||||
{
|
||||
const type_info *catch_ti = NULL;
|
||||
const cxx_type_info *type;
|
||||
|
||||
if (ci.type_info) catch_ti = rtti_rva( ci.type_info, dispatch->ImageBase );
|
||||
if (!(type = find_caught_type( info, exc_base, catch_ti, ci.flags ))) continue;
|
||||
|
||||
TRACE("matched type %p in tryblock %d catchblock %d\n", type, i, j);
|
||||
|
||||
if (catch_ti && catch_ti->mangled[0] && ci.offset)
|
||||
{
|
||||
/* copy the exception to its destination on the stack */
|
||||
void **dest = (void **)(orig_frame + ci.offset);
|
||||
copy_exception( (void *)rec->ExceptionInformation[1], dest, ci.flags, type, exc_base );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no CXX_EXCEPTION only proceed with a catch(...) block*/
|
||||
if (ci.type_info)
|
||||
continue;
|
||||
TRACE("found catch(...) block\n");
|
||||
}
|
||||
|
||||
/* unwind stack and call catch */
|
||||
memset(&catch_record, 0, sizeof(catch_record));
|
||||
catch_record.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
|
||||
catch_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
catch_record.NumberParameters = CONSOLIDATE_UNWIND_PARAMETER_COUNT;
|
||||
catch_record.ExceptionInformation[0] = (ULONG_PTR)call_catch_block4;
|
||||
catch_record.ExceptionInformation[1] = orig_frame;
|
||||
catch_record.ExceptionInformation[2] = tryblock.catch_level;
|
||||
catch_record.ExceptionInformation[3] = tryblock.start_level;
|
||||
catch_record.ExceptionInformation[4] = (ULONG_PTR)untrans_rec;
|
||||
catch_record.ExceptionInformation[5] = (ULONG_PTR)rtti_rva(ci.handler, dispatch->ImageBase);
|
||||
/* 3ds Max plugin expect ExceptionInformation[6] to contain exception record */
|
||||
catch_record.ExceptionInformation[6] = (ULONG_PTR)rec;
|
||||
catch_record.ExceptionInformation[7] = (ULONG_PTR)context;
|
||||
if (ci.ret_addr[0])
|
||||
{
|
||||
catch_record.ExceptionInformation[8] = (ULONG_PTR)rtti_rva(
|
||||
ci.ret_addr[0], dispatch->ImageBase);
|
||||
}
|
||||
if (ci.ret_addr[1])
|
||||
{
|
||||
catch_record.ExceptionInformation[9] = (ULONG_PTR)rtti_rva(
|
||||
ci.ret_addr[1], dispatch->ImageBase);
|
||||
}
|
||||
RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("no matching catch block found\n");
|
||||
(*processing_throw)--;
|
||||
}
|
||||
|
||||
static LONG CALLBACK se_translation_filter(EXCEPTION_POINTERS *ep, void *c)
|
||||
{
|
||||
se_translator_ctx *ctx = (se_translator_ctx *)c;
|
||||
EXCEPTION_RECORD *rec = ep->ExceptionRecord;
|
||||
cxx_exception_type *exc_type;
|
||||
|
||||
if (rec->ExceptionCode != CXX_EXCEPTION)
|
||||
{
|
||||
TRACE("non-c++ exception thrown in SEH handler: %lx\n", rec->ExceptionCode);
|
||||
terminate();
|
||||
}
|
||||
|
||||
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||
find_catch_block4(rec, ep->ContextRecord, ctx->seh_rec, ctx->dest_frame, ctx->dispatch,
|
||||
ctx->descr, exc_type, ctx->orig_frame, ctx->trylevel);
|
||||
|
||||
__DestructExceptionObject(rec);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
/* Hacky way to obtain se_translator */
|
||||
static inline _se_translator_function get_se_translator(void)
|
||||
{
|
||||
return __current_exception()[-2];
|
||||
}
|
||||
|
||||
static void check_noexcept( PEXCEPTION_RECORD rec, const cxx_function_descr_v4 *descr )
|
||||
{
|
||||
if (!(descr->header & FUNC_DESCR_IS_CATCH) &&
|
||||
rec->ExceptionCode == CXX_EXCEPTION &&
|
||||
(descr->header & FUNC_DESCR_NO_EXCEPT))
|
||||
{
|
||||
ERR("noexcept function propagating exception\n");
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD cxx_frame_handler4(EXCEPTION_RECORD *rec, ULONG64 frame,
|
||||
CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
|
||||
const cxx_function_descr_v4 *descr, int trylevel)
|
||||
{
|
||||
cxx_exception_type *exc_type;
|
||||
ULONG64 orig_frame = frame;
|
||||
|
||||
if (descr->header & FUNC_DESCR_IS_CATCH)
|
||||
{
|
||||
TRACE("nested exception detected\n");
|
||||
orig_frame = *(ULONG64 *)(frame + descr->frame);
|
||||
TRACE("setting orig_frame to %Ix\n", orig_frame);
|
||||
}
|
||||
|
||||
if (rec->ExceptionFlags & (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND))
|
||||
{
|
||||
int last_level = -1;
|
||||
if ((rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND) && cxx_is_consolidate(rec))
|
||||
last_level = rec->ExceptionInformation[3];
|
||||
else if ((rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND) && rec->ExceptionCode == STATUS_LONGJUMP)
|
||||
last_level = ip_to_state4( descr, dispatch, dispatch->TargetIp );
|
||||
|
||||
cxx_local_unwind4(orig_frame, dispatch, descr, trylevel, last_level);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
if (!descr->tryblock_map)
|
||||
{
|
||||
check_noexcept(rec, descr);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
if (rec->ExceptionCode == CXX_EXCEPTION)
|
||||
{
|
||||
if (!rec->ExceptionInformation[1] && !rec->ExceptionInformation[2])
|
||||
{
|
||||
TRACE("rethrow detected.\n");
|
||||
*rec = *(EXCEPTION_RECORD*)*__current_exception();
|
||||
}
|
||||
|
||||
exc_type = (cxx_exception_type *)rec->ExceptionInformation[2];
|
||||
|
||||
if (TRACE_ON(seh))
|
||||
{
|
||||
TRACE("handling C++ exception rec %p frame %Ix descr %p\n", rec, frame, descr);
|
||||
TRACE_EXCEPTION_TYPE(exc_type, rec->ExceptionInformation[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_se_translator_function se_translator = get_se_translator();
|
||||
|
||||
exc_type = NULL;
|
||||
TRACE("handling C exception code %lx rec %p frame %Ix descr %p\n",
|
||||
rec->ExceptionCode, rec, frame, descr);
|
||||
|
||||
if (se_translator) {
|
||||
EXCEPTION_POINTERS except_ptrs;
|
||||
se_translator_ctx ctx;
|
||||
|
||||
ctx.dest_frame = frame;
|
||||
ctx.orig_frame = orig_frame;
|
||||
ctx.seh_rec = rec;
|
||||
ctx.dispatch = dispatch;
|
||||
ctx.descr = descr;
|
||||
ctx.trylevel = trylevel;
|
||||
__TRY
|
||||
{
|
||||
except_ptrs.ExceptionRecord = rec;
|
||||
except_ptrs.ContextRecord = context;
|
||||
se_translator(rec->ExceptionCode, &except_ptrs);
|
||||
}
|
||||
__EXCEPT_CTX(se_translation_filter, &ctx)
|
||||
{
|
||||
}
|
||||
__ENDTRY
|
||||
}
|
||||
}
|
||||
|
||||
find_catch_block4(rec, context, NULL, frame, dispatch, descr, exc_type, orig_frame, trylevel);
|
||||
check_noexcept(rec, descr);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler4(EXCEPTION_RECORD *rec,
|
||||
ULONG64 frame, CONTEXT *context, DISPATCHER_CONTEXT *dispatch)
|
||||
{
|
||||
cxx_function_descr_v4 descr;
|
||||
BYTE *p, *count, *count_end;
|
||||
int trylevel;
|
||||
|
||||
TRACE("%p %Ix %p %p\n", rec, frame, context, dispatch);
|
||||
|
||||
trylevel = (DWORD_PTR)FlsGetValue(fls_index);
|
||||
FlsSetValue(fls_index, (void*)-2);
|
||||
|
||||
memset(&descr, 0, sizeof(descr));
|
||||
p = rtti_rva(*(UINT*)dispatch->HandlerData, dispatch->ImageBase);
|
||||
descr.header = *p++;
|
||||
|
||||
if ((descr.header & FUNC_DESCR_EHS) &&
|
||||
rec->ExceptionCode != CXX_EXCEPTION &&
|
||||
!cxx_is_consolidate(rec) &&
|
||||
rec->ExceptionCode != STATUS_LONGJUMP)
|
||||
return ExceptionContinueSearch; /* handle only c++ exceptions */
|
||||
|
||||
if (descr.header & ~(FUNC_DESCR_IS_CATCH | FUNC_DESCR_IS_SEPARATED |
|
||||
FUNC_DESCR_UNWIND_MAP | FUNC_DESCR_TRYBLOCK_MAP | FUNC_DESCR_EHS |
|
||||
FUNC_DESCR_NO_EXCEPT))
|
||||
{
|
||||
FIXME("unsupported flags: %x\n", descr.header);
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
|
||||
if (descr.header & FUNC_DESCR_BBT) descr.bbt_flags = decode_uint(&p);
|
||||
if (descr.header & FUNC_DESCR_UNWIND_MAP)
|
||||
{
|
||||
descr.unwind_map = read_rva(&p);
|
||||
count_end = count = rtti_rva(descr.unwind_map, dispatch->ImageBase);
|
||||
descr.unwind_count = decode_uint(&count_end);
|
||||
descr.unwind_map += count_end - count;
|
||||
}
|
||||
if (descr.header & FUNC_DESCR_TRYBLOCK_MAP)
|
||||
{
|
||||
descr.tryblock_map = read_rva(&p);
|
||||
count_end = count = rtti_rva(descr.tryblock_map, dispatch->ImageBase);
|
||||
descr.tryblock_count = decode_uint(&count_end);
|
||||
descr.tryblock_map += count_end - count;
|
||||
}
|
||||
descr.ip_map = read_rva(&p);
|
||||
if (descr.header & FUNC_DESCR_IS_SEPARATED)
|
||||
{
|
||||
UINT i, num, func;
|
||||
BYTE *map = rtti_rva(descr.ip_map, dispatch->ImageBase);
|
||||
|
||||
num = decode_uint(&map);
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
func = read_rva(&map);
|
||||
descr.ip_map = read_rva(&map);
|
||||
if (func == dispatch->FunctionEntry->BeginAddress)
|
||||
break;
|
||||
}
|
||||
if (i == num)
|
||||
{
|
||||
FIXME("function ip_map not found\n");
|
||||
return ExceptionContinueSearch;
|
||||
}
|
||||
}
|
||||
count_end = count = rtti_rva(descr.ip_map, dispatch->ImageBase);
|
||||
descr.ip_count = decode_uint(&count_end);
|
||||
descr.ip_map += count_end - count;
|
||||
if (descr.header & FUNC_DESCR_IS_CATCH) descr.frame = decode_uint(&p);
|
||||
|
||||
if (!validate_cxx_function_descr4(&descr, dispatch))
|
||||
return ExceptionContinueSearch;
|
||||
|
||||
return cxx_frame_handler4(rec, frame, context, dispatch, &descr, trylevel);
|
||||
}
|
||||
|
||||
BOOL msvcrt_init_handler4(void)
|
||||
{
|
||||
fls_index = FlsAlloc(NULL);
|
||||
if (fls_index == FLS_OUT_OF_INDEXES)
|
||||
return FALSE;
|
||||
msvcrt_attach_handler4();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void msvcrt_attach_handler4(void)
|
||||
{
|
||||
FlsSetValue(fls_index, (void*)-2);
|
||||
}
|
||||
|
||||
void msvcrt_free_handler4(void)
|
||||
{
|
||||
FlsFree(fls_index);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,847 @@
|
||||
/*
|
||||
* msvcrt.dll heap functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* Note: Win32 heap operations are MT safe. We only lock the new
|
||||
* handler and non atomic heap operations
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* MT */
|
||||
#define LOCK_HEAP _lock( _HEAP_LOCK )
|
||||
#define UNLOCK_HEAP _unlock( _HEAP_LOCK )
|
||||
|
||||
/* _aligned */
|
||||
#define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
|
||||
~(sizeof(void *) - 1)))
|
||||
#define ALIGN_PTR(ptr, alignment, offset) ((void *) \
|
||||
((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \
|
||||
~(alignment - 1)) - offset))
|
||||
|
||||
#define SB_HEAP_ALIGN 16
|
||||
|
||||
static HANDLE heap, sb_heap;
|
||||
|
||||
typedef int (CDECL *MSVCRT_new_handler_func)(size_t size);
|
||||
|
||||
static MSVCRT_new_handler_func MSVCRT_new_handler;
|
||||
static LONG MSVCRT_new_mode;
|
||||
|
||||
/* FIXME - According to documentation it should be 8*1024, at runtime it returns 16 */
|
||||
static unsigned int MSVCRT_amblksiz = 16;
|
||||
/* FIXME - According to documentation it should be 480 bytes, at runtime default is 0 */
|
||||
static size_t MSVCRT_sbh_threshold = 0;
|
||||
|
||||
static void* msvcrt_heap_alloc(DWORD flags, size_t size)
|
||||
{
|
||||
if(size < MSVCRT_sbh_threshold)
|
||||
{
|
||||
void *memblock, *temp, **saved;
|
||||
|
||||
temp = HeapAlloc(sb_heap, flags, size+sizeof(void*)+SB_HEAP_ALIGN);
|
||||
if(!temp) return NULL;
|
||||
|
||||
memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
|
||||
saved = SAVED_PTR(memblock);
|
||||
*saved = temp;
|
||||
return memblock;
|
||||
}
|
||||
|
||||
return HeapAlloc(heap, flags, size);
|
||||
}
|
||||
|
||||
static void* msvcrt_heap_realloc(DWORD flags, void *ptr, size_t size)
|
||||
{
|
||||
if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
|
||||
{
|
||||
/* TODO: move data to normal heap if it exceeds sbh_threshold limit */
|
||||
void *memblock, *temp, **saved;
|
||||
size_t old_padding, new_padding, old_size;
|
||||
|
||||
saved = SAVED_PTR(ptr);
|
||||
old_padding = (char*)ptr - (char*)*saved;
|
||||
old_size = HeapSize(sb_heap, 0, *saved);
|
||||
if(old_size == -1)
|
||||
return NULL;
|
||||
old_size -= old_padding;
|
||||
|
||||
temp = HeapReAlloc(sb_heap, flags, *saved, size+sizeof(void*)+SB_HEAP_ALIGN);
|
||||
if(!temp) return NULL;
|
||||
|
||||
memblock = ALIGN_PTR(temp, SB_HEAP_ALIGN, 0);
|
||||
saved = SAVED_PTR(memblock);
|
||||
new_padding = (char*)memblock - (char*)temp;
|
||||
|
||||
if(new_padding != old_padding)
|
||||
memmove(memblock, (char*)temp+old_padding, old_size>size ? size : old_size);
|
||||
|
||||
*saved = temp;
|
||||
return memblock;
|
||||
}
|
||||
|
||||
return HeapReAlloc(heap, flags, ptr, size);
|
||||
}
|
||||
|
||||
static BOOL msvcrt_heap_free(void *ptr)
|
||||
{
|
||||
if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
|
||||
{
|
||||
void **saved = SAVED_PTR(ptr);
|
||||
return HeapFree(sb_heap, 0, *saved);
|
||||
}
|
||||
|
||||
return HeapFree(heap, 0, ptr);
|
||||
}
|
||||
|
||||
static size_t msvcrt_heap_size(void *ptr)
|
||||
{
|
||||
if(sb_heap && ptr && !HeapValidate(heap, 0, ptr))
|
||||
{
|
||||
void **saved = SAVED_PTR(ptr);
|
||||
return HeapSize(sb_heap, 0, *saved);
|
||||
}
|
||||
|
||||
return HeapSize(heap, 0, ptr);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _callnewh (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _callnewh(size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
MSVCRT_new_handler_func handler = MSVCRT_new_handler;
|
||||
if(handler)
|
||||
ret = (*handler)(size) ? 1 : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ??2@YAPAXI@Z (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL DECLSPEC_HOTPATCH operator_new(size_t size)
|
||||
{
|
||||
void *retval;
|
||||
|
||||
do
|
||||
{
|
||||
retval = msvcrt_heap_alloc(0, size);
|
||||
if(retval)
|
||||
{
|
||||
TRACE("(%Iu) returning %p\n", size, retval);
|
||||
return retval;
|
||||
}
|
||||
} while(_callnewh(size));
|
||||
|
||||
TRACE("(%Iu) out of memory\n", size);
|
||||
#if _MSVCR_VER >= 80
|
||||
throw_bad_alloc();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* ??2@YAPAXIHPBDH@Z (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL operator_new_dbg(size_t size, int type, const char *file, int line)
|
||||
{
|
||||
return operator_new( size );
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* ??3@YAXPAX@Z (MSVCRT.@)
|
||||
*/
|
||||
void CDECL DECLSPEC_HOTPATCH operator_delete(void *mem)
|
||||
{
|
||||
TRACE("(%p)\n", mem);
|
||||
msvcrt_heap_free(mem);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@)
|
||||
*/
|
||||
MSVCRT_new_handler_func CDECL _query_new_handler(void)
|
||||
{
|
||||
return MSVCRT_new_handler;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* ?_query_new_mode@@YAHXZ (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _query_new_mode(void)
|
||||
{
|
||||
return MSVCRT_new_mode;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@)
|
||||
*/
|
||||
MSVCRT_new_handler_func CDECL _set_new_handler(MSVCRT_new_handler_func func)
|
||||
{
|
||||
MSVCRT_new_handler_func old_handler;
|
||||
LOCK_HEAP;
|
||||
old_handler = MSVCRT_new_handler;
|
||||
MSVCRT_new_handler = func;
|
||||
UNLOCK_HEAP;
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?set_new_handler@@YAP6AXXZP6AXXZ@Z (MSVCRT.@)
|
||||
*/
|
||||
MSVCRT_new_handler_func CDECL set_new_handler(void *func)
|
||||
{
|
||||
TRACE("(%p)\n",func);
|
||||
_set_new_handler(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* ?_set_new_mode@@YAHH@Z (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _set_new_mode(int mode)
|
||||
{
|
||||
if(!MSVCRT_CHECK_PMT(mode == 0 || mode == 1)) return -1;
|
||||
return InterlockedExchange(&MSVCRT_new_mode, mode);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _expand (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL _expand(void* mem, size_t size)
|
||||
{
|
||||
return msvcrt_heap_realloc(HEAP_REALLOC_IN_PLACE_ONLY, mem, size);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _heapchk (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _heapchk(void)
|
||||
{
|
||||
if (!HeapValidate(heap, 0, NULL) ||
|
||||
(sb_heap && !HeapValidate(sb_heap, 0, NULL)))
|
||||
{
|
||||
msvcrt_set_errno(GetLastError());
|
||||
return _HEAPBADNODE;
|
||||
}
|
||||
return _HEAPOK;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _heapmin (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _heapmin(void)
|
||||
{
|
||||
if (!HeapCompact( heap, 0 ) ||
|
||||
(sb_heap && !HeapCompact( sb_heap, 0 )))
|
||||
{
|
||||
if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
|
||||
msvcrt_set_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _heapwalk (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _heapwalk(_HEAPINFO *next)
|
||||
{
|
||||
PROCESS_HEAP_ENTRY phe;
|
||||
|
||||
if (sb_heap)
|
||||
FIXME("small blocks heap not supported\n");
|
||||
|
||||
LOCK_HEAP;
|
||||
phe.lpData = next->_pentry;
|
||||
phe.cbData = next->_size;
|
||||
phe.wFlags = next->_useflag == _USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0;
|
||||
|
||||
if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY &&
|
||||
!HeapValidate( heap, 0, phe.lpData ))
|
||||
{
|
||||
UNLOCK_HEAP;
|
||||
msvcrt_set_errno(GetLastError());
|
||||
return _HEAPBADNODE;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (!HeapWalk( heap, &phe ))
|
||||
{
|
||||
UNLOCK_HEAP;
|
||||
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
||||
return _HEAPEND;
|
||||
msvcrt_set_errno(GetLastError());
|
||||
if (!phe.lpData)
|
||||
return _HEAPBADBEGIN;
|
||||
return _HEAPBADNODE;
|
||||
}
|
||||
} while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE));
|
||||
|
||||
UNLOCK_HEAP;
|
||||
next->_pentry = phe.lpData;
|
||||
next->_size = phe.cbData;
|
||||
next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? _USEDENTRY : _FREEENTRY;
|
||||
return _HEAPOK;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _heapset (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _heapset(unsigned int value)
|
||||
{
|
||||
int retval;
|
||||
_HEAPINFO heap;
|
||||
|
||||
memset( &heap, 0, sizeof(heap) );
|
||||
LOCK_HEAP;
|
||||
while ((retval = _heapwalk(&heap)) == _HEAPOK)
|
||||
{
|
||||
if (heap._useflag == _FREEENTRY)
|
||||
memset(heap._pentry, value, heap._size);
|
||||
}
|
||||
UNLOCK_HEAP;
|
||||
return retval == _HEAPEND ? _HEAPOK : retval;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _heapadd (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _heapadd(void* mem, size_t size)
|
||||
{
|
||||
TRACE("(%p,%Iu) unsupported in Win32\n", mem,size);
|
||||
*_errno() = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_heap_handle (MSVCRT.@)
|
||||
*/
|
||||
intptr_t CDECL _get_heap_handle(void)
|
||||
{
|
||||
return (intptr_t)heap;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _msize (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL _msize(void* mem)
|
||||
{
|
||||
size_t size = msvcrt_heap_size(mem);
|
||||
if (size == ~(size_t)0)
|
||||
{
|
||||
WARN(":Probably called with non wine-allocated memory, ret = -1\n");
|
||||
/* At least the Win32 crtdll/msvcrt also return -1 in this case */
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _aligned_msize (MSVCR80.@)
|
||||
*/
|
||||
size_t CDECL _aligned_msize(void *p, size_t alignment, size_t offset)
|
||||
{
|
||||
void **alloc_ptr;
|
||||
|
||||
if(!MSVCRT_CHECK_PMT(p)) return -1;
|
||||
|
||||
if(alignment < sizeof(void*))
|
||||
alignment = sizeof(void*);
|
||||
|
||||
alloc_ptr = SAVED_PTR(p);
|
||||
return _msize(*alloc_ptr)-alignment-sizeof(void*);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* calloc (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL DECLSPEC_HOTPATCH calloc(size_t count, size_t size)
|
||||
{
|
||||
size_t bytes = count*size;
|
||||
|
||||
if (size && bytes / size != count)
|
||||
{
|
||||
*_errno() = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msvcrt_heap_alloc(HEAP_ZERO_MEMORY, bytes);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
/*********************************************************************
|
||||
* _calloc_base (UCRTBASE.@)
|
||||
*/
|
||||
void* CDECL _calloc_base(size_t count, size_t size)
|
||||
{
|
||||
return calloc(count, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* free (MSVCRT.@)
|
||||
*/
|
||||
void CDECL DECLSPEC_HOTPATCH free(void* ptr)
|
||||
{
|
||||
msvcrt_heap_free(ptr);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
/*********************************************************************
|
||||
* _free_base (UCRTBASE.@)
|
||||
*/
|
||||
void CDECL _free_base(void* ptr)
|
||||
{
|
||||
msvcrt_heap_free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* malloc (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL malloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = msvcrt_heap_alloc(0, size);
|
||||
if (ret || !MSVCRT_new_mode)
|
||||
break;
|
||||
} while(_callnewh(size));
|
||||
|
||||
if (!ret)
|
||||
*_errno() = ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
/*********************************************************************
|
||||
* _malloc_base (UCRTBASE.@)
|
||||
*/
|
||||
void* CDECL _malloc_base(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* realloc (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL DECLSPEC_HOTPATCH realloc(void* ptr, size_t size)
|
||||
{
|
||||
if (!ptr) return malloc(size);
|
||||
if (size) return msvcrt_heap_realloc(0, ptr, size);
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=140
|
||||
/*********************************************************************
|
||||
* _realloc_base (UCRTBASE.@)
|
||||
*/
|
||||
void* CDECL _realloc_base(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _recalloc (MSVCR80.@)
|
||||
*/
|
||||
void* CDECL _recalloc(void *mem, size_t num, size_t size)
|
||||
{
|
||||
size_t old_size;
|
||||
void *ret;
|
||||
|
||||
if(!mem)
|
||||
return calloc(num, size);
|
||||
|
||||
size = num*size;
|
||||
old_size = _msize(mem);
|
||||
|
||||
ret = realloc(mem, size);
|
||||
if(!ret) {
|
||||
*_errno() = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(size>old_size)
|
||||
memset((BYTE*)ret+old_size, 0, size-old_size);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* __p__amblksiz (MSVCRT.@)
|
||||
*/
|
||||
unsigned int* CDECL __p__amblksiz(void)
|
||||
{
|
||||
return &MSVCRT_amblksiz;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_sbh_threshold (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL _get_sbh_threshold(void)
|
||||
{
|
||||
return MSVCRT_sbh_threshold;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_sbh_threshold (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _set_sbh_threshold(size_t threshold)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return 0;
|
||||
#else
|
||||
if(threshold > 1016)
|
||||
return 0;
|
||||
|
||||
if(!sb_heap)
|
||||
{
|
||||
sb_heap = HeapCreate(0, 0, 0);
|
||||
if(!sb_heap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MSVCRT_sbh_threshold = (threshold+0xf) & ~0xf;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _aligned_free (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _aligned_free(void *memblock)
|
||||
{
|
||||
TRACE("(%p)\n", memblock);
|
||||
|
||||
if (memblock)
|
||||
{
|
||||
void **saved = SAVED_PTR(memblock);
|
||||
free(*saved);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _aligned_offset_malloc (MSVCRT.@)
|
||||
*/
|
||||
void * CDECL _aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
|
||||
{
|
||||
void *memblock, *temp, **saved;
|
||||
TRACE("(%Iu, %Iu, %Iu)\n", size, alignment, offset);
|
||||
|
||||
/* alignment must be a power of 2 */
|
||||
if ((alignment & (alignment - 1)) != 0)
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* offset must be less than size */
|
||||
if (offset && offset >= size)
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* don't align to less than void pointer size */
|
||||
if (alignment < sizeof(void *))
|
||||
alignment = sizeof(void *);
|
||||
|
||||
/* allocate enough space for void pointer and alignment */
|
||||
temp = malloc(size + alignment + sizeof(void *));
|
||||
|
||||
if (!temp)
|
||||
return NULL;
|
||||
|
||||
/* adjust pointer for proper alignment and offset */
|
||||
memblock = ALIGN_PTR(temp, alignment, offset);
|
||||
|
||||
/* Save the real allocation address below returned address */
|
||||
/* so it can be found later to free. */
|
||||
saved = SAVED_PTR(memblock);
|
||||
*saved = temp;
|
||||
|
||||
return memblock;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _aligned_malloc (MSVCRT.@)
|
||||
*/
|
||||
void * CDECL _aligned_malloc(size_t size, size_t alignment)
|
||||
{
|
||||
TRACE("(%Iu, %Iu)\n", size, alignment);
|
||||
return _aligned_offset_malloc(size, alignment, 0);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _aligned_offset_realloc (MSVCRT.@)
|
||||
*/
|
||||
void * CDECL _aligned_offset_realloc(void *memblock, size_t size,
|
||||
size_t alignment, size_t offset)
|
||||
{
|
||||
void * temp, **saved;
|
||||
size_t old_padding, new_padding, old_size;
|
||||
TRACE("(%p, %Iu, %Iu, %Iu)\n", memblock, size, alignment, offset);
|
||||
|
||||
if (!memblock)
|
||||
return _aligned_offset_malloc(size, alignment, offset);
|
||||
|
||||
/* alignment must be a power of 2 */
|
||||
if ((alignment & (alignment - 1)) != 0)
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* offset must be less than size */
|
||||
if (offset >= size)
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
_aligned_free(memblock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* don't align to less than void pointer size */
|
||||
if (alignment < sizeof(void *))
|
||||
alignment = sizeof(void *);
|
||||
|
||||
/* make sure alignment and offset didn't change */
|
||||
saved = SAVED_PTR(memblock);
|
||||
if (memblock != ALIGN_PTR(*saved, alignment, offset))
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
old_padding = (char *)memblock - (char *)*saved;
|
||||
|
||||
/* Get previous size of block */
|
||||
old_size = _msize(*saved);
|
||||
if (old_size == -1)
|
||||
{
|
||||
/* It seems this function was called with an invalid pointer. Bail out. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Adjust old_size to get amount of actual data in old block. */
|
||||
if (old_size < old_padding)
|
||||
{
|
||||
/* Shouldn't happen. Something's weird, so bail out. */
|
||||
return NULL;
|
||||
}
|
||||
old_size -= old_padding;
|
||||
|
||||
temp = realloc(*saved, size + alignment + sizeof(void *));
|
||||
|
||||
if (!temp)
|
||||
return NULL;
|
||||
|
||||
/* adjust pointer for proper alignment and offset */
|
||||
memblock = ALIGN_PTR(temp, alignment, offset);
|
||||
|
||||
/* Save the real allocation address below returned address */
|
||||
/* so it can be found later to free. */
|
||||
saved = SAVED_PTR(memblock);
|
||||
|
||||
new_padding = (char *)memblock - (char *)temp;
|
||||
|
||||
/*
|
||||
Memory layout of old block is as follows:
|
||||
+-------+---------------------+-+--------------------------+-----------+
|
||||
| ... | "old_padding" bytes | | ... "old_size" bytes ... | ... |
|
||||
+-------+---------------------+-+--------------------------+-----------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
*saved saved memblock
|
||||
|
||||
Memory layout of new block is as follows:
|
||||
+-------+-----------------------------+-+----------------------+-------+
|
||||
| ... | "new_padding" bytes | | ... "size" bytes ... | ... |
|
||||
+-------+-----------------------------+-+----------------------+-------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
temp saved memblock
|
||||
|
||||
However, in the new block, actual data is still written as follows
|
||||
(because it was copied by realloc):
|
||||
+-------+---------------------+--------------------------------+-------+
|
||||
| ... | "old_padding" bytes | ... "old_size" bytes ... | ... |
|
||||
+-------+---------------------+--------------------------------+-------+
|
||||
^ ^ ^
|
||||
| | |
|
||||
temp saved memblock
|
||||
|
||||
Therefore, min(old_size,size) bytes of actual data have to be moved
|
||||
from the offset they were at in the old block (temp + old_padding),
|
||||
to the offset they have to be in the new block (temp + new_padding == memblock).
|
||||
*/
|
||||
if (new_padding != old_padding)
|
||||
memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
|
||||
|
||||
*saved = temp;
|
||||
|
||||
return memblock;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _aligned_realloc (MSVCRT.@)
|
||||
*/
|
||||
void * CDECL _aligned_realloc(void *memblock, size_t size, size_t alignment)
|
||||
{
|
||||
TRACE("(%p, %Iu, %Iu)\n", memblock, size, alignment);
|
||||
return _aligned_offset_realloc(memblock, size, alignment, 0);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* memmove_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL memmove_s(void *dest, size_t numberOfElements, const void *src, size_t count)
|
||||
{
|
||||
TRACE("(%p %Iu %p %Iu)\n", dest, numberOfElements, src, count);
|
||||
|
||||
if(!count)
|
||||
return 0;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(dest != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(src != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, ERANGE )) return ERANGE;
|
||||
|
||||
memmove(dest, src, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=100
|
||||
/*********************************************************************
|
||||
* wmemmove_s (MSVCR100.@)
|
||||
*/
|
||||
int CDECL wmemmove_s(wchar_t *dest, size_t numberOfElements,
|
||||
const wchar_t *src, size_t count)
|
||||
{
|
||||
TRACE("(%p %Iu %p %Iu)\n", dest, numberOfElements, src, count);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
/* Native does not seem to conform to 6.7.1.2.3 in
|
||||
* http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf
|
||||
* in that it does not zero the output buffer on constraint violation.
|
||||
*/
|
||||
if (!MSVCRT_CHECK_PMT(dest != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(src != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, ERANGE)) return ERANGE;
|
||||
|
||||
memmove(dest, src, sizeof(wchar_t)*count);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* memcpy_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL memcpy_s(void *dest, size_t numberOfElements, const void *src, size_t count)
|
||||
{
|
||||
TRACE("(%p %Iu %p %Iu)\n", dest, numberOfElements, src, count);
|
||||
|
||||
if(!count)
|
||||
return 0;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(dest != NULL)) return EINVAL;
|
||||
if (!MSVCRT_CHECK_PMT(src != NULL))
|
||||
{
|
||||
memset(dest, 0, numberOfElements);
|
||||
return EINVAL;
|
||||
}
|
||||
if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, ERANGE ))
|
||||
{
|
||||
memset(dest, 0, numberOfElements);
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
memmove(dest, src, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=100
|
||||
/*********************************************************************
|
||||
* wmemcpy_s (MSVCR100.@)
|
||||
*/
|
||||
int CDECL wmemcpy_s(wchar_t *dest, size_t numberOfElements,
|
||||
const wchar_t *src, size_t count)
|
||||
{
|
||||
TRACE("(%p %Iu %p %Iu)\n", dest, numberOfElements, src, count);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(dest != NULL)) return EINVAL;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(src != NULL)) {
|
||||
memset(dest, 0, numberOfElements*sizeof(wchar_t));
|
||||
return EINVAL;
|
||||
}
|
||||
if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, ERANGE)) {
|
||||
memset(dest, 0, numberOfElements*sizeof(wchar_t));
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
memmove(dest, src, sizeof(wchar_t)*count);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL msvcrt_init_heap(void)
|
||||
{
|
||||
#if _MSVCR_VER <= 100
|
||||
heap = HeapCreate(0, 0, 0);
|
||||
#else
|
||||
heap = GetProcessHeap();
|
||||
#endif
|
||||
return heap != NULL;
|
||||
}
|
||||
|
||||
void msvcrt_destroy_heap(void)
|
||||
{
|
||||
#if _MSVCR_VER <= 100
|
||||
HeapDestroy(heap);
|
||||
#endif
|
||||
if(sb_heap)
|
||||
HeapDestroy(sb_heap);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* acrt function needed for compatibility with mingw
|
||||
*
|
||||
* Copyright 2019 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* this function is part of the import lib for compatibility with ucrt runtime */
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wine/asm.h>
|
||||
|
||||
#undef __iob_func
|
||||
extern FILE * __cdecl __iob_func(void);
|
||||
|
||||
/*********************************************************************
|
||||
* __acrt_iob_func(UCRTBASE.@)
|
||||
*/
|
||||
FILE * __cdecl __acrt_iob_func(unsigned idx)
|
||||
{
|
||||
return __iob_func() + idx;
|
||||
}
|
||||
__ASM_GLOBAL_IMPORT(__acrt_iob_func)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2002, TransGaming Technologies Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
#include "cxx.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL bInit;
|
||||
CRITICAL_SECTION crit;
|
||||
} LOCKTABLEENTRY;
|
||||
|
||||
static LOCKTABLEENTRY lock_table[ _TOTAL_LOCKS ];
|
||||
|
||||
static inline void msvcrt_mlock_set_entry_initialized( int locknum, BOOL initialized )
|
||||
{
|
||||
lock_table[ locknum ].bInit = initialized;
|
||||
}
|
||||
|
||||
static inline void msvcrt_initialize_mlock( int locknum )
|
||||
{
|
||||
InitializeCriticalSectionEx( &(lock_table[ locknum ].crit), 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
|
||||
lock_table[ locknum ].crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": LOCKTABLEENTRY.crit");
|
||||
msvcrt_mlock_set_entry_initialized( locknum, TRUE );
|
||||
}
|
||||
|
||||
static inline void msvcrt_uninitialize_mlock( int locknum )
|
||||
{
|
||||
lock_table[ locknum ].crit.DebugInfo->Spare[0] = 0;
|
||||
DeleteCriticalSection( &(lock_table[ locknum ].crit) );
|
||||
msvcrt_mlock_set_entry_initialized( locknum, FALSE );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* msvcrt_init_mt_locks (internal)
|
||||
*
|
||||
* Initialize the table lock. All other locks will be initialized
|
||||
* upon first use.
|
||||
*
|
||||
*/
|
||||
void msvcrt_init_mt_locks(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
TRACE( "initializing mtlocks\n" );
|
||||
|
||||
/* Initialize the table */
|
||||
for( i=0; i < _TOTAL_LOCKS; i++ )
|
||||
{
|
||||
msvcrt_mlock_set_entry_initialized( i, FALSE );
|
||||
}
|
||||
|
||||
/* Initialize our lock table lock */
|
||||
msvcrt_initialize_mlock( _LOCKTAB_LOCK );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* _lock (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _lock( int locknum )
|
||||
{
|
||||
TRACE( "(%d)\n", locknum );
|
||||
|
||||
/* If the lock doesn't exist yet, create it */
|
||||
if( lock_table[ locknum ].bInit == FALSE )
|
||||
{
|
||||
/* Lock while we're changing the lock table */
|
||||
_lock( _LOCKTAB_LOCK );
|
||||
|
||||
/* Check again if we've got a bit of a race on lock creation */
|
||||
if( lock_table[ locknum ].bInit == FALSE )
|
||||
{
|
||||
TRACE( ": creating lock #%d\n", locknum );
|
||||
msvcrt_initialize_mlock( locknum );
|
||||
}
|
||||
|
||||
/* Unlock ourselves */
|
||||
_unlock( _LOCKTAB_LOCK );
|
||||
}
|
||||
|
||||
EnterCriticalSection( &(lock_table[ locknum ].crit) );
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* _unlock (MSVCRT.@)
|
||||
*
|
||||
* NOTE: There is no error detection to make sure the lock exists and is acquired.
|
||||
*/
|
||||
void CDECL _unlock( int locknum )
|
||||
{
|
||||
TRACE( "(%d)\n", locknum );
|
||||
|
||||
LeaveCriticalSection( &(lock_table[ locknum ].crit) );
|
||||
}
|
||||
|
||||
#if _MSVCR_VER == 110
|
||||
static LONG shared_ptr_lock;
|
||||
|
||||
void __cdecl _Lock_shared_ptr_spin_lock(void)
|
||||
{
|
||||
LONG l = 0;
|
||||
|
||||
while(InterlockedCompareExchange(&shared_ptr_lock, 1, 0) != 0) {
|
||||
if(l++ == 1000) {
|
||||
Sleep(0);
|
||||
l = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __cdecl _Unlock_shared_ptr_spin_lock(void)
|
||||
{
|
||||
shared_ptr_lock = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
* msvcrt_free_locks (internal)
|
||||
*
|
||||
* Uninitialize all mt locks. Assume that neither _lock or _unlock will
|
||||
* be called once we're calling this routine (ie _LOCKTAB_LOCK can be deleted)
|
||||
*
|
||||
*/
|
||||
void msvcrt_free_locks(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
TRACE( ": uninitializing all mtlocks\n" );
|
||||
|
||||
/* Uninitialize the table */
|
||||
for( i=0; i < _TOTAL_LOCKS; i++ )
|
||||
{
|
||||
if( lock_table[ i ].bInit )
|
||||
{
|
||||
msvcrt_uninitialize_mlock( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* msvcrt.dll initialisation functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include <locale.h>
|
||||
#include "msvcrt.h"
|
||||
#include "winternl.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* Index to TLS */
|
||||
DWORD msvcrt_tls_index;
|
||||
|
||||
static const char* msvcrt_get_reason(DWORD reason)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH: return "DLL_PROCESS_ATTACH";
|
||||
case DLL_PROCESS_DETACH: return "DLL_PROCESS_DETACH";
|
||||
case DLL_THREAD_ATTACH: return "DLL_THREAD_ATTACH";
|
||||
case DLL_THREAD_DETACH: return "DLL_THREAD_DETACH";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static inline BOOL msvcrt_init_tls(void)
|
||||
{
|
||||
msvcrt_tls_index = TlsAlloc();
|
||||
|
||||
if (msvcrt_tls_index == TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
ERR("TlsAlloc() failed!\n");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL msvcrt_free_tls(void)
|
||||
{
|
||||
if (!TlsFree(msvcrt_tls_index))
|
||||
{
|
||||
ERR("TlsFree() failed!\n");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void msvcrt_free_tls_mem(void)
|
||||
{
|
||||
thread_data_t *tls = TlsGetValue(msvcrt_tls_index);
|
||||
|
||||
if (tls)
|
||||
{
|
||||
free(tls->efcvt_buffer);
|
||||
free(tls->asctime_buffer);
|
||||
free(tls->wasctime_buffer);
|
||||
free(tls->strerror_buffer);
|
||||
free(tls->wcserror_buffer);
|
||||
free(tls->time_buffer);
|
||||
free(tls->tmpnam_buffer);
|
||||
free(tls->wtmpnam_buffer);
|
||||
if(tls->locale_flags & LOCALE_FREE) {
|
||||
free_locinfo(tls->locinfo);
|
||||
free_mbcinfo(tls->mbcinfo);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, tls);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Init
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
TRACE("(%p, %s, %p) pid(%lx), tid(%lx), tls(%lu)\n",
|
||||
hinstDLL, msvcrt_get_reason(fdwReason), lpvReserved,
|
||||
GetCurrentProcessId(), GetCurrentThreadId(),
|
||||
msvcrt_tls_index);
|
||||
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
msvcrt_init_exception(hinstDLL);
|
||||
if(!msvcrt_init_heap())
|
||||
return FALSE;
|
||||
if(!msvcrt_init_tls()) {
|
||||
msvcrt_destroy_heap();
|
||||
return FALSE;
|
||||
}
|
||||
msvcrt_init_mt_locks();
|
||||
if(!msvcrt_init_locale()) {
|
||||
msvcrt_free_locks();
|
||||
msvcrt_free_tls_mem();
|
||||
msvcrt_destroy_heap();
|
||||
return FALSE;
|
||||
}
|
||||
#if defined(__x86_64__) && _MSVCR_VER>=140
|
||||
if(!msvcrt_init_handler4()) {
|
||||
msvcrt_free_locks();
|
||||
msvcrt_free_tls_mem();
|
||||
msvcrt_destroy_heap();
|
||||
_free_locale(MSVCRT_locale);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
msvcrt_init_math(hinstDLL);
|
||||
msvcrt_init_io();
|
||||
msvcrt_init_args();
|
||||
msvcrt_init_signals();
|
||||
#if _MSVCR_VER >= 100 && _MSVCR_VER <= 120
|
||||
msvcrt_init_concurrency(hinstDLL);
|
||||
#endif
|
||||
#if _MSVCR_VER == 0
|
||||
/* don't allow unloading msvcrt, we can't setup file handles twice */
|
||||
LdrAddRefDll( LDR_ADDREF_DLL_PIN, hinstDLL );
|
||||
#elif _MSVCR_VER >= 80
|
||||
_set_printf_count_output(0);
|
||||
#endif
|
||||
msvcrt_init_clock();
|
||||
TRACE("finished process init\n");
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
#if defined(__x86_64__) && _MSVCR_VER>=140
|
||||
msvcrt_attach_handler4();
|
||||
#endif
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
msvcrt_free_io();
|
||||
if (lpvReserved) break;
|
||||
msvcrt_free_popen_data();
|
||||
msvcrt_free_locks();
|
||||
msvcrt_free_console();
|
||||
msvcrt_free_args();
|
||||
msvcrt_free_signals();
|
||||
msvcrt_free_tls_mem();
|
||||
if (!msvcrt_free_tls())
|
||||
return FALSE;
|
||||
#if defined(__x86_64__) && _MSVCR_VER>=140
|
||||
msvcrt_free_handler4();
|
||||
#endif
|
||||
_free_locale(MSVCRT_locale);
|
||||
#if _MSVCR_VER >= 100 && _MSVCR_VER <= 120
|
||||
msvcrt_free_scheduler_thread();
|
||||
msvcrt_free_concurrency();
|
||||
#endif
|
||||
msvcrt_destroy_heap();
|
||||
TRACE("finished process free\n");
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
msvcrt_free_tls_mem();
|
||||
#if _MSVCR_VER >= 100 && _MSVCR_VER <= 120
|
||||
msvcrt_free_scheduler_thread();
|
||||
#endif
|
||||
TRACE("finished thread free\n");
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* msvcrt float functions
|
||||
*
|
||||
* Copyright 2019 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* this function is part of the import lib to provide floating */
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <corecrt.h>
|
||||
#include <wine/asm.h>
|
||||
|
||||
double __cdecl sin(double);
|
||||
double __cdecl cos(double);
|
||||
double __cdecl tan(double);
|
||||
double __cdecl atan2(double, double);
|
||||
double __cdecl exp(double);
|
||||
double __cdecl log(double);
|
||||
double __cdecl pow(double, double);
|
||||
double __cdecl sqrt(double);
|
||||
double __cdecl floor(double);
|
||||
double __cdecl ceil(double);
|
||||
float __cdecl powf(float, float);
|
||||
|
||||
#if defined(__i386__) || (_MSVCR_VER > 0 && _MSVCR_VER < 80)
|
||||
float sinf(float x) { return sin(x); }
|
||||
float cosf(float x) { return cos(x); }
|
||||
float tanf(float x) { return tan(x); }
|
||||
float atan2f(float x, float y) { return atan2(x, y); }
|
||||
float expf(float x) { return exp(x); }
|
||||
float logf(float x) { return log(x); }
|
||||
float sqrtf(float x) { return sqrt(x); }
|
||||
float floorf(float x) { return floor(x); }
|
||||
float ceilf(float x) { return ceil(x); }
|
||||
__ASM_GLOBAL_IMPORT(sinf)
|
||||
__ASM_GLOBAL_IMPORT(cosf)
|
||||
__ASM_GLOBAL_IMPORT(tanf)
|
||||
__ASM_GLOBAL_IMPORT(atan2f)
|
||||
__ASM_GLOBAL_IMPORT(expf)
|
||||
__ASM_GLOBAL_IMPORT(logf)
|
||||
__ASM_GLOBAL_IMPORT(sqrtf)
|
||||
__ASM_GLOBAL_IMPORT(floorf)
|
||||
__ASM_GLOBAL_IMPORT(ceilf)
|
||||
|
||||
#if _MSVCR_VER < 140
|
||||
float powf(float x, float y) { return pow(x, y); }
|
||||
__ASM_GLOBAL_IMPORT(powf)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER < 120
|
||||
double exp2(double x) { return pow(2.0, x); }
|
||||
float exp2f(float x) { return powf(2.0f, x); }
|
||||
__ASM_GLOBAL_IMPORT(exp2)
|
||||
__ASM_GLOBAL_IMPORT(exp2f)
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* msvcrt.dll misc functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "msvcrt.h"
|
||||
#include "wine/debug.h"
|
||||
#include "ntsecapi.h"
|
||||
#include "windows.h"
|
||||
#include "wine/asm.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
static unsigned int output_format;
|
||||
|
||||
/*********************************************************************
|
||||
* _beep (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _beep( unsigned int freq, unsigned int duration)
|
||||
{
|
||||
TRACE(":Freq %d, Duration %d\n",freq,duration);
|
||||
Beep(freq, duration);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* srand (MSVCRT.@)
|
||||
*/
|
||||
void CDECL srand( unsigned int seed )
|
||||
{
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
data->random_seed = seed;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* rand (MSVCRT.@)
|
||||
*/
|
||||
int CDECL 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) & RAND_MAX;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* rand_s (MSVCRT.@)
|
||||
*/
|
||||
int CDECL rand_s(unsigned int *pval)
|
||||
{
|
||||
if (!pval || !RtlGenRandom(pval, sizeof(*pval)))
|
||||
{
|
||||
*_errno() = EINVAL;
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _sleep (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _sleep(__msvcrt_ulong timeout)
|
||||
{
|
||||
TRACE("_sleep for %ld milliseconds\n",timeout);
|
||||
Sleep((timeout)?timeout:1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _lfind (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL _lfind(const void* match, const void* start,
|
||||
unsigned int* array_size, unsigned int elem_size,
|
||||
int (CDECL *cf)(const void*,const void*) )
|
||||
{
|
||||
unsigned int size = *array_size;
|
||||
if (size)
|
||||
do
|
||||
{
|
||||
if (cf(match, start) == 0)
|
||||
return (void *)start; /* found */
|
||||
start = (const char *)start + elem_size;
|
||||
} while (--size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _lfind_s (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL _lfind_s(const void* match, const void* start,
|
||||
unsigned int* array_size, unsigned int elem_size,
|
||||
int (CDECL *cf)(void*,const void*,const void*),
|
||||
void* context)
|
||||
{
|
||||
unsigned int size;
|
||||
if (!MSVCRT_CHECK_PMT(match != NULL)) return NULL;
|
||||
if (!MSVCRT_CHECK_PMT(array_size != NULL)) return NULL;
|
||||
if (!MSVCRT_CHECK_PMT(start != NULL || *array_size == 0)) return NULL;
|
||||
if (!MSVCRT_CHECK_PMT(cf != NULL)) return NULL;
|
||||
if (!MSVCRT_CHECK_PMT(elem_size != 0)) return NULL;
|
||||
|
||||
size = *array_size;
|
||||
if (size)
|
||||
do
|
||||
{
|
||||
if (cf(context, match, start) == 0)
|
||||
return (void *)start; /* found */
|
||||
start = (const char *)start + elem_size;
|
||||
} while (--size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _lsearch (MSVCRT.@)
|
||||
*/
|
||||
void* CDECL _lsearch(const void* match, void* start,
|
||||
unsigned int* array_size, unsigned int elem_size,
|
||||
int (CDECL *cf)(const void*,const void*) )
|
||||
{
|
||||
unsigned int size = *array_size;
|
||||
if (size)
|
||||
do
|
||||
{
|
||||
if (cf(match, start) == 0)
|
||||
return start; /* found */
|
||||
start = (char*)start + elem_size;
|
||||
} while (--size);
|
||||
|
||||
/* not found, add to end */
|
||||
memcpy(start, match, elem_size);
|
||||
array_size[0]++;
|
||||
return start;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* bsearch_s (msvcrt.@)
|
||||
*/
|
||||
void* CDECL bsearch_s(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int (__cdecl *compare)(void *, const void *, const void *), void *ctx)
|
||||
{
|
||||
ssize_t min = 0;
|
||||
ssize_t max = nmemb - 1;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(size != 0)) return NULL;
|
||||
if (!MSVCRT_CHECK_PMT(compare != NULL)) return NULL;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
ssize_t cursor = min + (max - min) / 2;
|
||||
int ret = compare(ctx, key,(const char *)base+(cursor*size));
|
||||
if (!ret)
|
||||
return (char*)base+(cursor*size);
|
||||
if (ret < 0)
|
||||
max = cursor - 1;
|
||||
else
|
||||
min = cursor + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int CDECL compare_wrapper(void *ctx, const void *e1, const void *e2)
|
||||
{
|
||||
int (__cdecl *compare)(const void *, const void *) = ctx;
|
||||
return compare(e1, e2);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* bsearch (msvcrt.@)
|
||||
*/
|
||||
void* CDECL bsearch(const void *key, const void *base, size_t nmemb,
|
||||
size_t size, int (__cdecl *compar)(const void *, const void *))
|
||||
{
|
||||
return bsearch_s(key, base, nmemb, size, compare_wrapper, compar);
|
||||
}
|
||||
/*********************************************************************
|
||||
* _chkesp (MSVCRT.@)
|
||||
*
|
||||
* Trap to a debugger if the value of the stack pointer has changed.
|
||||
*
|
||||
* PARAMS
|
||||
* None.
|
||||
*
|
||||
* RETURNS
|
||||
* Does not return.
|
||||
*
|
||||
* NOTES
|
||||
* This function is available for iX86 only.
|
||||
*
|
||||
* When VC++ generates debug code, it stores the value of the stack pointer
|
||||
* before calling any external function, and checks the value following
|
||||
* the call. It then calls this function, which will trap if the values are
|
||||
* not the same. Usually this means that the prototype used to call
|
||||
* the function is incorrect. It can also mean that the .spec entry has
|
||||
* the wrong calling convention or parameters.
|
||||
*/
|
||||
#ifdef __i386__
|
||||
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
__ASM_GLOBAL_FUNC(_chkesp,
|
||||
"jnz 1f\n\t"
|
||||
"ret\n"
|
||||
"1:\tpushl %ebp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
|
||||
"movl %esp,%ebp\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
|
||||
"subl $12,%esp\n\t"
|
||||
"pushl %eax\n\t"
|
||||
"pushl %ecx\n\t"
|
||||
"pushl %edx\n\t"
|
||||
"call " __ASM_NAME("chkesp_fail") "\n\t"
|
||||
"popl %edx\n\t"
|
||||
"popl %ecx\n\t"
|
||||
"popl %eax\n\t"
|
||||
"leave\n\t"
|
||||
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
|
||||
__ASM_CFI(".cfi_same_value %ebp\n\t")
|
||||
"ret")
|
||||
|
||||
void CDECL chkesp_fail(void)
|
||||
{
|
||||
ERR("Stack pointer incorrect after last function call - Bad prototype/spec entry?\n");
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
# else /* __GNUC__ || __clang__ */
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void CDECL _chkesp(void)
|
||||
{
|
||||
}
|
||||
|
||||
# endif /* __GNUC__ || __clang__ */
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
static inline void swap(char *l, char *r, size_t size)
|
||||
{
|
||||
char tmp;
|
||||
|
||||
while(size--) {
|
||||
tmp = *l;
|
||||
*l++ = *r;
|
||||
*r++ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void small_sort(void *base, size_t nmemb, size_t size,
|
||||
int (CDECL *compar)(void *, const void *, const void *), void *context)
|
||||
{
|
||||
size_t e, i;
|
||||
char *max, *p;
|
||||
|
||||
for(e=nmemb; e>1; e--) {
|
||||
max = base;
|
||||
for(i=1; i<e; i++) {
|
||||
p = (char*)base + i*size;
|
||||
if(compar(context, p, max) > 0)
|
||||
max = p;
|
||||
}
|
||||
|
||||
if(p != max)
|
||||
swap(p, max, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void quick_sort(void *base, size_t nmemb, size_t size,
|
||||
int (CDECL *compar)(void *, const void *, const void *), void *context)
|
||||
{
|
||||
size_t stack_lo[8*sizeof(size_t)], stack_hi[8*sizeof(size_t)];
|
||||
size_t beg, end, lo, hi, med;
|
||||
int stack_pos;
|
||||
|
||||
stack_pos = 0;
|
||||
stack_lo[stack_pos] = 0;
|
||||
stack_hi[stack_pos] = nmemb-1;
|
||||
|
||||
#define X(i) ((char*)base+size*(i))
|
||||
while(stack_pos >= 0) {
|
||||
beg = stack_lo[stack_pos];
|
||||
end = stack_hi[stack_pos--];
|
||||
|
||||
if(end-beg < 8) {
|
||||
small_sort(X(beg), end-beg+1, size, compar, context);
|
||||
continue;
|
||||
}
|
||||
|
||||
lo = beg;
|
||||
hi = end;
|
||||
med = lo + (hi-lo+1)/2;
|
||||
if(compar(context, X(lo), X(med)) > 0)
|
||||
swap(X(lo), X(med), size);
|
||||
if(compar(context, X(lo), X(hi)) > 0)
|
||||
swap(X(lo), X(hi), size);
|
||||
if(compar(context, X(med), X(hi)) > 0)
|
||||
swap(X(med), X(hi), size);
|
||||
|
||||
lo++;
|
||||
hi--;
|
||||
while(1) {
|
||||
while(lo <= hi) {
|
||||
if(lo!=med && compar(context, X(lo), X(med))>0)
|
||||
break;
|
||||
lo++;
|
||||
}
|
||||
|
||||
while(med != hi) {
|
||||
if(compar(context, X(hi), X(med)) <= 0)
|
||||
break;
|
||||
hi--;
|
||||
}
|
||||
|
||||
if(hi < lo)
|
||||
break;
|
||||
|
||||
swap(X(lo), X(hi), size);
|
||||
if(hi == med)
|
||||
med = lo;
|
||||
lo++;
|
||||
hi--;
|
||||
}
|
||||
|
||||
while(hi > beg) {
|
||||
if(hi!=med && compar(context, X(hi), X(med))!=0)
|
||||
break;
|
||||
hi--;
|
||||
}
|
||||
|
||||
if(hi-beg >= end-lo) {
|
||||
stack_lo[++stack_pos] = beg;
|
||||
stack_hi[stack_pos] = hi;
|
||||
stack_lo[++stack_pos] = lo;
|
||||
stack_hi[stack_pos] = end;
|
||||
}else {
|
||||
stack_lo[++stack_pos] = lo;
|
||||
stack_hi[stack_pos] = end;
|
||||
stack_lo[++stack_pos] = beg;
|
||||
stack_hi[stack_pos] = hi;
|
||||
}
|
||||
}
|
||||
#undef X
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* qsort_s (MSVCRT.@)
|
||||
*
|
||||
* This function is trying to sort data doing identical comparisons
|
||||
* as native does. There are still cases where it behaves differently.
|
||||
*/
|
||||
void CDECL qsort_s(void *base, size_t nmemb, size_t size,
|
||||
int (CDECL *compar)(void *, const void *, const void *), void *context)
|
||||
{
|
||||
const size_t total_size = nmemb*size;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(base != NULL || (base == NULL && nmemb == 0))) return;
|
||||
if (!MSVCRT_CHECK_PMT(size > 0)) return;
|
||||
if (!MSVCRT_CHECK_PMT(compar != NULL)) return;
|
||||
if (total_size / size != nmemb) return;
|
||||
|
||||
if (nmemb < 2) return;
|
||||
|
||||
quick_sort(base, nmemb, size, compar, context);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* qsort (MSVCRT.@)
|
||||
*/
|
||||
void CDECL qsort(void *base, size_t nmemb, size_t size,
|
||||
int (CDECL *compar)(const void*, const void*))
|
||||
{
|
||||
qsort_s(base, nmemb, size, compare_wrapper, compar);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _get_output_format (MSVCRT.@)
|
||||
*/
|
||||
unsigned int CDECL _get_output_format(void)
|
||||
{
|
||||
return output_format;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _set_output_format (MSVCRT.@)
|
||||
*/
|
||||
unsigned int CDECL _set_output_format(unsigned int new_output_format)
|
||||
{
|
||||
unsigned int ret = output_format;
|
||||
|
||||
if(!MSVCRT_CHECK_PMT(new_output_format==0 || new_output_format==_TWO_DIGIT_EXPONENT))
|
||||
return ret;
|
||||
|
||||
output_format = new_output_format;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _resetstkoflw (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _resetstkoflw(void)
|
||||
{
|
||||
int stack_addr;
|
||||
DWORD oldprot;
|
||||
|
||||
/* causes stack fault that updates NtCurrentTeb()->Tib.StackLimit */
|
||||
return VirtualProtect(&stack_addr, 1, PAGE_GUARD|PAGE_READWRITE, &oldprot);
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=80 && _MSVCR_VER<=90
|
||||
|
||||
/*********************************************************************
|
||||
* _decode_pointer (MSVCR80.@)
|
||||
*/
|
||||
void * CDECL _decode_pointer(void * ptr)
|
||||
{
|
||||
return DecodePointer(ptr);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _encode_pointer (MSVCR80.@)
|
||||
*/
|
||||
void * CDECL _encode_pointer(void * ptr)
|
||||
{
|
||||
return EncodePointer(ptr);
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=80 && _MSVCR_VER<=90 */
|
||||
|
||||
#if _MSVCR_VER>=80 && _MSVCR_VER<=100
|
||||
/*********************************************************************
|
||||
* _encoded_null (MSVCR80.@)
|
||||
*/
|
||||
void * CDECL _encoded_null(void)
|
||||
{
|
||||
TRACE("\n");
|
||||
|
||||
return EncodePointer(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=70
|
||||
/*********************************************************************
|
||||
* _CRT_RTC_INIT (MSVCR70.@)
|
||||
*/
|
||||
void* CDECL _CRT_RTC_INIT(void *unk1, void *unk2, int unk3, int unk4, int unk5)
|
||||
{
|
||||
TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
|
||||
/*********************************************************************
|
||||
* _CRT_RTC_INITW (MSVCR80.@)
|
||||
*/
|
||||
void* CDECL _CRT_RTC_INITW(void *unk1, void *unk2, int unk3, int unk4, int unk5)
|
||||
{
|
||||
TRACE("%p %p %x %x %x\n", unk1, unk2, unk3, unk4, unk5);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _byteswap_ushort (MSVCR80.@)
|
||||
*/
|
||||
unsigned short CDECL _byteswap_ushort(unsigned short s)
|
||||
{
|
||||
return (s<<8) + (s>>8);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _byteswap_ulong (MSVCR80.@)
|
||||
*/
|
||||
__msvcrt_ulong CDECL _byteswap_ulong(__msvcrt_ulong l)
|
||||
{
|
||||
return (l<<24) + ((l<<8)&0xFF0000) + ((l>>8)&0xFF00) + (l>>24);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _byteswap_uint64 (MSVCR80.@)
|
||||
*/
|
||||
unsigned __int64 CDECL _byteswap_uint64(unsigned __int64 i)
|
||||
{
|
||||
return (i<<56) + ((i&0xFF00)<<40) + ((i&0xFF0000)<<24) + ((i&0xFF000000)<<8) +
|
||||
((i>>8)&0xFF000000) + ((i>>24)&0xFF0000) + ((i>>40)&0xFF00) + (i>>56);
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=80 */
|
||||
|
||||
#if _MSVCR_VER>=110
|
||||
|
||||
/*********************************************************************
|
||||
* __crtGetShowWindowMode (MSVCR110.@)
|
||||
*/
|
||||
int CDECL __crtGetShowWindowMode(void)
|
||||
{
|
||||
STARTUPINFOW si;
|
||||
|
||||
GetStartupInfoW(&si);
|
||||
TRACE("flags=%lx window=%d\n", si.dwFlags, si.wShowWindow);
|
||||
return si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __crtInitializeCriticalSectionEx (MSVCR110.@)
|
||||
*/
|
||||
BOOL CDECL __crtInitializeCriticalSectionEx(
|
||||
CRITICAL_SECTION *cs, DWORD spin_count, DWORD flags)
|
||||
{
|
||||
TRACE("(%p %lx %lx)\n", cs, spin_count, flags);
|
||||
return InitializeCriticalSectionEx(cs, spin_count, flags);
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=110 */
|
||||
|
||||
#if _MSVCR_VER>=120
|
||||
/*********************************************************************
|
||||
* _vacopy (MSVCR120.@)
|
||||
*/
|
||||
void CDECL _vacopy(va_list *dest, va_list src)
|
||||
{
|
||||
va_copy(*dest, src);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _crt_debugger_hook (MSVCR80.@)
|
||||
*/
|
||||
void CDECL _crt_debugger_hook(int reserved)
|
||||
{
|
||||
WARN("(%x)\n", reserved);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=110
|
||||
/*********************************************************************
|
||||
* __crtUnhandledException (MSVCR110.@)
|
||||
*/
|
||||
LONG CDECL __crtUnhandledException(EXCEPTION_POINTERS *ep)
|
||||
{
|
||||
TRACE("(%p)\n", ep);
|
||||
SetUnhandledExceptionFilter(NULL);
|
||||
return UnhandledExceptionFilter(ep);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _MSVCR_VER>=120
|
||||
/*********************************************************************
|
||||
* __crtSleep (MSVCR120.@)
|
||||
*/
|
||||
void CDECL __crtSleep(DWORD timeout)
|
||||
{
|
||||
TRACE("(%lu)\n", timeout);
|
||||
Sleep(timeout);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _SetWinRTOutOfMemoryExceptionCallback (MSVCR120.@)
|
||||
*/
|
||||
void CDECL _SetWinRTOutOfMemoryExceptionCallback(void *callback)
|
||||
{
|
||||
FIXME("(%p): stub\n", callback);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright 2001 Jon Griffiths
|
||||
* Copyright 2004 Dimitrie O. Paun
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __WINE_MSVCRT_H
|
||||
#define __WINE_MSVCRT_H
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
#ifndef _FILE_DEFINED
|
||||
#define _FILE_DEFINED
|
||||
typedef struct _iobuf
|
||||
{
|
||||
char* _ptr;
|
||||
char* _base;
|
||||
int _cnt;
|
||||
int _flag;
|
||||
int _file;
|
||||
int _charbuf;
|
||||
int _bufsiz;
|
||||
char* _tmpfname;
|
||||
} FILE;
|
||||
|
||||
#define _IOREAD 0x0001
|
||||
#define _IOWRT 0x0002
|
||||
#define _IORW 0x0004
|
||||
#define _IOEOF 0x0008
|
||||
#define _IOERR 0x0010
|
||||
#define _IOMYBUF 0x0040
|
||||
#define _IOSTRG 0x1000
|
||||
#endif
|
||||
|
||||
#define MSVCRT__NOBUF 0x0400
|
||||
|
||||
#else
|
||||
|
||||
#define MSVCRT__NOBUF _IONBF
|
||||
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#define _NO_CRT_STDIO_INLINE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
#undef strncpy
|
||||
#undef wcsncpy
|
||||
|
||||
extern BOOL sse2_supported;
|
||||
|
||||
#define DBL80_MAX_10_EXP 4932
|
||||
#define DBL80_MIN_10_EXP -4951
|
||||
|
||||
typedef void (__cdecl *terminate_function)(void);
|
||||
typedef void (__cdecl *unexpected_function)(void);
|
||||
typedef void (__cdecl *_se_translator_function)(unsigned int code, struct _EXCEPTION_POINTERS *info);
|
||||
void __cdecl terminate(void);
|
||||
|
||||
typedef void (__cdecl *MSVCRT_security_error_handler)(int, void *);
|
||||
|
||||
typedef struct {ULONG x80[3];} MSVCRT__LDOUBLE; /* Intel 80 bit FP format has sizeof() 12 */
|
||||
|
||||
typedef struct __lc_time_data {
|
||||
union {
|
||||
const char *str[43];
|
||||
struct {
|
||||
const char *short_wday[7];
|
||||
const char *wday[7];
|
||||
const char *short_mon[12];
|
||||
const char *mon[12];
|
||||
const char *am;
|
||||
const char *pm;
|
||||
const char *short_date;
|
||||
const char *date;
|
||||
const char *time;
|
||||
} names;
|
||||
} str;
|
||||
#if _MSVCR_VER < 110
|
||||
LCID lcid;
|
||||
#endif
|
||||
int unk;
|
||||
LONG refcount;
|
||||
#if _MSVCR_VER == 0 || _MSVCR_VER >= 100
|
||||
union {
|
||||
const wchar_t *wstr[43];
|
||||
struct {
|
||||
const wchar_t *short_wday[7];
|
||||
const wchar_t *wday[7];
|
||||
const wchar_t *short_mon[12];
|
||||
const wchar_t *mon[12];
|
||||
const wchar_t *am;
|
||||
const wchar_t *pm;
|
||||
const wchar_t *short_date;
|
||||
const wchar_t *date;
|
||||
const wchar_t *time;
|
||||
} names;
|
||||
} wstr;
|
||||
#endif
|
||||
#if _MSVCR_VER >= 110
|
||||
const wchar_t *locname;
|
||||
#endif
|
||||
char data[1];
|
||||
} __lc_time_data;
|
||||
|
||||
typedef struct threadmbcinfostruct {
|
||||
LONG refcount;
|
||||
int mbcodepage;
|
||||
int ismbcodepage;
|
||||
int mblcid;
|
||||
unsigned short mbulinfo[6];
|
||||
unsigned char mbctype[257];
|
||||
unsigned char mbcasemap[256];
|
||||
} threadmbcinfo;
|
||||
|
||||
typedef struct _frame_info
|
||||
{
|
||||
void *object;
|
||||
struct _frame_info *next;
|
||||
} frame_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
frame_info frame_info;
|
||||
EXCEPTION_RECORD *rec;
|
||||
CONTEXT *context;
|
||||
} cxx_frame_info;
|
||||
|
||||
frame_info* __cdecl _CreateFrameInfo(frame_info *fi, void *obj);
|
||||
BOOL __cdecl __CxxRegisterExceptionObject(EXCEPTION_POINTERS*, cxx_frame_info*);
|
||||
void __cdecl __CxxUnregisterExceptionObject(cxx_frame_info*, BOOL);
|
||||
void CDECL __DestructExceptionObject(EXCEPTION_RECORD*);
|
||||
|
||||
void** __cdecl __current_exception(void);
|
||||
int* __cdecl __processing_throw(void);
|
||||
|
||||
#if defined(__x86_64__) && _MSVCR_VER>=140
|
||||
BOOL msvcrt_init_handler4(void);
|
||||
void msvcrt_attach_handler4(void);
|
||||
void msvcrt_free_handler4(void);
|
||||
#endif
|
||||
|
||||
/* TLS data */
|
||||
extern DWORD msvcrt_tls_index;
|
||||
|
||||
#define LOCALE_FREE 0x1
|
||||
#define LOCALE_THREAD 0x2
|
||||
|
||||
/* Keep in sync with msvcr90/tests/msvcr90.c */
|
||||
struct __thread_data {
|
||||
DWORD tid;
|
||||
HANDLE handle;
|
||||
int thread_errno;
|
||||
__msvcrt_ulong thread_doserrno;
|
||||
int unk1;
|
||||
unsigned int random_seed; /* seed for rand() */
|
||||
char *strtok_next; /* next ptr for strtok() */
|
||||
wchar_t *wcstok_next; /* next ptr for wcstok() */
|
||||
unsigned char *mbstok_next; /* next ptr for mbstok() */
|
||||
char *strerror_buffer; /* buffer for strerror */
|
||||
wchar_t *wcserror_buffer; /* buffer for wcserror */
|
||||
char *tmpnam_buffer; /* buffer for tmpname() */
|
||||
wchar_t *wtmpnam_buffer; /* buffer for wtmpname() */
|
||||
void *unk2[2];
|
||||
char *asctime_buffer; /* buffer for asctime */
|
||||
wchar_t *wasctime_buffer; /* buffer for wasctime */
|
||||
struct tm *time_buffer; /* buffer for localtime/gmtime */
|
||||
char *efcvt_buffer; /* buffer for ecvt/fcvt */
|
||||
int unk3[2];
|
||||
void *unk4[3];
|
||||
EXCEPTION_POINTERS *xcptinfo;
|
||||
int fpecode;
|
||||
pthreadmbcinfo mbcinfo;
|
||||
pthreadlocinfo locinfo;
|
||||
int locale_flags;
|
||||
int unk5[1];
|
||||
terminate_function terminate_handler;
|
||||
unexpected_function unexpected_handler;
|
||||
_se_translator_function se_translator; /* preserve offset to exc_record and processing_throw */
|
||||
void *unk6;
|
||||
EXCEPTION_RECORD *exc_record;
|
||||
CONTEXT *ctx_record;
|
||||
int processing_throw;
|
||||
frame_info *frame_info_head;
|
||||
void *unk8[6];
|
||||
BOOL cached_sname_match;
|
||||
WCHAR cached_sname[LOCALE_NAME_MAX_LENGTH];
|
||||
int unk9[2];
|
||||
DWORD cached_cp;
|
||||
char cached_locale[131];
|
||||
void *unk10[100];
|
||||
#if _MSVCR_VER >= 140
|
||||
_invalid_parameter_handler invalid_parameter_handler;
|
||||
HMODULE module;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct __thread_data thread_data_t;
|
||||
|
||||
extern thread_data_t *CDECL msvcrt_get_thread_data(void);
|
||||
|
||||
BOOL locale_to_sname(const char*, unsigned short*, BOOL*, WCHAR*);
|
||||
extern _locale_t MSVCRT_locale;
|
||||
extern __lc_time_data cloc_time_data;
|
||||
extern unsigned int MSVCRT___lc_codepage;
|
||||
extern int MSVCRT___lc_collate_cp;
|
||||
extern WORD MSVCRT__ctype [257];
|
||||
extern BOOL initial_locale;
|
||||
extern WORD *MSVCRT__pwctype;
|
||||
|
||||
void msvcrt_set_errno(int);
|
||||
#if _MSVCR_VER >= 80
|
||||
void throw_bad_alloc(void);
|
||||
#endif
|
||||
|
||||
void __cdecl _purecall(void);
|
||||
void __cdecl _amsg_exit(int errnum);
|
||||
|
||||
extern char **MSVCRT__environ;
|
||||
extern wchar_t **MSVCRT__wenviron;
|
||||
extern char **MSVCRT___initenv;
|
||||
extern wchar_t **MSVCRT___winitenv;
|
||||
|
||||
int env_init(BOOL, BOOL);
|
||||
|
||||
wchar_t *msvcrt_wstrdupa(const char *);
|
||||
|
||||
extern unsigned int MSVCRT__commode;
|
||||
|
||||
/* FIXME: This should be declared in new.h but it's not an extern "C" so
|
||||
* it would not be much use anyway. Even for Winelib applications.
|
||||
*/
|
||||
void* __cdecl operator_new(size_t);
|
||||
void __cdecl operator_delete(void*);
|
||||
int __cdecl _set_new_mode(int mode);
|
||||
|
||||
typedef void* (__cdecl *malloc_func_t)(size_t);
|
||||
typedef void (__cdecl *free_func_t)(void*);
|
||||
|
||||
/* Setup and teardown multi threaded locks */
|
||||
extern void msvcrt_init_mt_locks(void);
|
||||
extern void msvcrt_free_locks(void);
|
||||
|
||||
extern void msvcrt_init_exception(void*);
|
||||
extern BOOL msvcrt_init_locale(void);
|
||||
extern void msvcrt_init_math(void*);
|
||||
extern void msvcrt_init_io(void);
|
||||
extern void msvcrt_free_io(void);
|
||||
extern void msvcrt_free_console(void);
|
||||
extern void msvcrt_init_args(void);
|
||||
extern void msvcrt_free_args(void);
|
||||
extern void msvcrt_init_signals(void);
|
||||
extern void msvcrt_free_signals(void);
|
||||
extern void msvcrt_free_popen_data(void);
|
||||
extern BOOL msvcrt_init_heap(void);
|
||||
extern void msvcrt_destroy_heap(void);
|
||||
extern void msvcrt_init_clock(void);
|
||||
|
||||
#if _MSVCR_VER >= 100
|
||||
extern void msvcrt_init_concurrency(void*);
|
||||
extern void msvcrt_free_concurrency(void);
|
||||
extern void msvcrt_free_scheduler_thread(void);
|
||||
#endif
|
||||
|
||||
extern BOOL msvcrt_create_io_inherit_block(WORD*, BYTE**);
|
||||
|
||||
/* run-time error codes */
|
||||
#define _RT_STACK 0
|
||||
#define _RT_NULLPTR 1
|
||||
#define _RT_FLOAT 2
|
||||
#define _RT_INTDIV 3
|
||||
#define _RT_EXECMEM 5
|
||||
#define _RT_EXECFORM 6
|
||||
#define _RT_EXECENV 7
|
||||
#define _RT_SPACEARG 8
|
||||
#define _RT_SPACEENV 9
|
||||
#define _RT_ABORT 10
|
||||
#define _RT_NPTR 12
|
||||
#define _RT_FPTR 13
|
||||
#define _RT_BREAK 14
|
||||
#define _RT_INT 15
|
||||
#define _RT_THREAD 16
|
||||
#define _RT_LOCK 17
|
||||
#define _RT_HEAP 18
|
||||
#define _RT_OPENCON 19
|
||||
#define _RT_QWIN 20
|
||||
#define _RT_NOMAIN 21
|
||||
#define _RT_NONCONT 22
|
||||
#define _RT_INVALDISP 23
|
||||
#define _RT_ONEXIT 24
|
||||
#define _RT_PUREVIRT 25
|
||||
#define _RT_STDIOINIT 26
|
||||
#define _RT_LOWIOINIT 27
|
||||
#define _RT_HEAPINIT 28
|
||||
#define _RT_DOMAIN 120
|
||||
#define _RT_SING 121
|
||||
#define _RT_TLOSS 122
|
||||
#define _RT_CRNL 252
|
||||
#define _RT_BANNER 255
|
||||
|
||||
#define MSVCRT_NO_CONSOLE_FD (-2)
|
||||
#define MSVCRT_NO_CONSOLE ((HANDLE)MSVCRT_NO_CONSOLE_FD)
|
||||
|
||||
#if _MSVCR_VER < 140
|
||||
extern FILE MSVCRT__iob[];
|
||||
#define __acrt_iob_func(idx) (MSVCRT__iob+(idx))
|
||||
#endif
|
||||
|
||||
/* internal file._flag flags */
|
||||
#define MSVCRT__USERBUF 0x0100
|
||||
#define MSVCRT__IOCOMMIT 0x4000
|
||||
|
||||
#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF)
|
||||
|
||||
_locale_t CDECL get_current_locale_noalloc(_locale_t locale);
|
||||
void CDECL free_locale_noalloc(_locale_t locale);
|
||||
pthreadlocinfo CDECL get_locinfo(void);
|
||||
pthreadmbcinfo CDECL get_mbcinfo(void);
|
||||
threadmbcinfo* create_mbcinfo(int, LCID, threadmbcinfo*);
|
||||
void free_locinfo(pthreadlocinfo);
|
||||
void free_mbcinfo(pthreadmbcinfo);
|
||||
int __cdecl __crtLCMapStringA(LCID, DWORD, const char*, int, char*, int, unsigned int, int);
|
||||
|
||||
enum fpmod {
|
||||
FP_ROUND_ZERO, /* only used when dropped part contains only zeros */
|
||||
FP_ROUND_DOWN,
|
||||
FP_ROUND_EVEN,
|
||||
FP_ROUND_UP,
|
||||
FP_VAL_INFINITY,
|
||||
FP_VAL_NAN
|
||||
};
|
||||
|
||||
struct fpnum {
|
||||
int sign;
|
||||
int exp;
|
||||
ULONGLONG m;
|
||||
enum fpmod mod;
|
||||
};
|
||||
struct fpnum fpnum_parse(wchar_t (*)(void*), void (*)(void*),
|
||||
void*, pthreadlocinfo, BOOL);
|
||||
int fpnum_double(struct fpnum*, double*);
|
||||
/* Maybe one day we'll enable the invalid parameter handlers with the full set of information (msvcrXXd)
|
||||
* #define MSVCRT_INVALID_PMT(x) MSVCRT_call_invalid_parameter_handler(x, __FUNCTION__, __FILE__, __LINE__, 0)
|
||||
* #define MSVCRT_CHECK_PMT(x) ((x) ? TRUE : MSVCRT_INVALID_PMT(#x),FALSE)
|
||||
* Until this is done, just keep the same semantics for CHECK_PMT(), but without generating / sending
|
||||
* any information
|
||||
* NB : MSVCRT_call_invalid_parameter_handler is a wrapper around _invalid_parameter in order
|
||||
* to do the Ansi to Unicode transformation
|
||||
*/
|
||||
#define MSVCRT_INVALID_PMT(x,err) (*_errno() = (err), _invalid_parameter(NULL, NULL, NULL, 0, 0))
|
||||
#define MSVCRT_CHECK_PMT_ERR(x,err) ((x) || (MSVCRT_INVALID_PMT( 0, (err) ), FALSE))
|
||||
#define MSVCRT_CHECK_PMT(x) MSVCRT_CHECK_PMT_ERR((x), EINVAL)
|
||||
|
||||
typedef int (*puts_clbk_a)(void*, int, const char*);
|
||||
typedef int (*puts_clbk_w)(void*, int, const wchar_t*);
|
||||
typedef union _printf_arg
|
||||
{
|
||||
void *get_ptr;
|
||||
int get_int;
|
||||
LONGLONG get_longlong;
|
||||
double get_double;
|
||||
} printf_arg;
|
||||
typedef printf_arg (*args_clbk)(void*, int, int, va_list*);
|
||||
int pf_printf_a(puts_clbk_a, void*, const char*, _locale_t,
|
||||
DWORD, args_clbk, void*, va_list*);
|
||||
int pf_printf_w(puts_clbk_w, void*, const wchar_t*, _locale_t,
|
||||
DWORD, args_clbk, void*, va_list*);
|
||||
int create_positional_ctx_a(void*, const char*, va_list);
|
||||
int create_positional_ctx_w(void*, const wchar_t*, va_list);
|
||||
printf_arg arg_clbk_valist(void*, int, int, va_list*);
|
||||
printf_arg arg_clbk_positional(void*, int, int, va_list*);
|
||||
|
||||
extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t,unsigned short int);
|
||||
|
||||
#define UCRTBASE_PRINTF_MASK ( \
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION | \
|
||||
_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR | \
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS | \
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY | \
|
||||
_CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS | \
|
||||
_CRT_INTERNAL_PRINTF_STANDARD_ROUNDING )
|
||||
|
||||
#define MSVCRT_PRINTF_POSITIONAL_PARAMS (0x0100)
|
||||
#define MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER (0x0200)
|
||||
|
||||
#define UCRTBASE_SCANF_MASK ( \
|
||||
_CRT_INTERNAL_SCANF_SECURECRT | \
|
||||
_CRT_INTERNAL_SCANF_LEGACY_WIDE_SPECIFIERS | \
|
||||
_CRT_INTERNAL_SCANF_LEGACY_MSVCRT_COMPATIBILITY )
|
||||
|
||||
#define COOPERATIVE_TIMEOUT_INFINITE ((unsigned int)-1)
|
||||
#define COOPERATIVE_WAIT_TIMEOUT ~0
|
||||
|
||||
#define INHERIT_THREAD_PRIORITY 0xF000
|
||||
|
||||
static inline UINT get_aw_cp(void)
|
||||
{
|
||||
#if _MSVCR_VER>=140
|
||||
if (___lc_codepage_func() == CP_UTF8) return CP_UTF8;
|
||||
#endif
|
||||
return CP_ACP;
|
||||
}
|
||||
|
||||
static inline int convert_acp_utf8_to_wcs(const char *str, wchar_t *wstr, int len)
|
||||
{
|
||||
return MultiByteToWideChar(get_aw_cp(), MB_PRECOMPOSED, str, -1, wstr, len);
|
||||
}
|
||||
|
||||
static inline int convert_wcs_to_acp_utf8(const wchar_t *wstr, char *str, int len)
|
||||
{
|
||||
return WideCharToMultiByte(get_aw_cp(), 0, wstr, -1, str, len, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline wchar_t* wstrdupa_utf8(const char *str)
|
||||
{
|
||||
int len = convert_acp_utf8_to_wcs(str, NULL, 0);
|
||||
wchar_t *wstr;
|
||||
|
||||
if (!len) return NULL;
|
||||
wstr = malloc(len * sizeof(wchar_t));
|
||||
if (!wstr) return NULL;
|
||||
convert_acp_utf8_to_wcs(str, wstr, len);
|
||||
return wstr;
|
||||
}
|
||||
|
||||
static inline char* astrdupw_utf8(const wchar_t *wstr)
|
||||
{
|
||||
int len = convert_wcs_to_acp_utf8(wstr, NULL, 0);
|
||||
char *str;
|
||||
|
||||
if (!len) return NULL;
|
||||
str = malloc(len * sizeof(char));
|
||||
if (!str) return NULL;
|
||||
convert_wcs_to_acp_utf8(wstr, str, len);
|
||||
return str;
|
||||
}
|
||||
|
||||
#endif /* __WINE_MSVCRT_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2002, TransGaming Technologies Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef WINE_MTDLL_H
|
||||
#define WINE_MTDLL_H
|
||||
|
||||
void __cdecl _unlock( int locknum );
|
||||
void __cdecl _lock( int locknum );
|
||||
|
||||
#define _SIGNAL_LOCK 1
|
||||
#define _IOB_SCAN_LOCK 2
|
||||
#define _TMPNAM_LOCK 3
|
||||
#define _INPUT_LOCK 4
|
||||
#define _OUTPUT_LOCK 5
|
||||
#define _CSCANF_LOCK 6
|
||||
#define _CPRINTF_LOCK 7
|
||||
#define _CONIO_LOCK 8
|
||||
#define _HEAP_LOCK 9
|
||||
#define _BHEAP_LOCK 10 /* No longer used? */
|
||||
#define _TIME_LOCK 11
|
||||
#define _ENV_LOCK 12
|
||||
#define _EXIT_LOCK1 13
|
||||
#define _EXIT_LOCK2 14
|
||||
#define _THREADDATA_LOCK 15 /* No longer used? */
|
||||
#define _POPEN_LOCK 16
|
||||
#define _LOCKTAB_LOCK 17
|
||||
#define _OSFHND_LOCK 18
|
||||
#define _SETLOCALE_LOCK 19
|
||||
#define _LC_COLLATE_LOCK 20 /* No longer used? */
|
||||
#define _LC_CTYPE_LOCK 21 /* No longer used? */
|
||||
#define _LC_MONETARY_LOCK 22 /* No longer used? */
|
||||
#define _LC_NUMERIC_LOCK 23 /* No longer used? */
|
||||
#define _LC_TIME_LOCK 24 /* No longer used? */
|
||||
#define _MB_CP_LOCK 25
|
||||
#define _NLG_LOCK 26
|
||||
#define _TYPEINFO_LOCK 27
|
||||
#define _STREAM_LOCKS 28
|
||||
|
||||
/* Must match definition in msvcrt/stdio.h */
|
||||
#define _IOB_ENTRIES 20
|
||||
|
||||
#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_IOB_ENTRIES-1)
|
||||
|
||||
#define _TOTAL_LOCKS (_LAST_STREAM_LOCK+1)
|
||||
|
||||
#endif /* WINE_MTDLL_H */
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* msvcrt onexit functions
|
||||
*
|
||||
* Copyright 2016 Nikolay Sivov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* these functions are part of the import lib for compatibility with the Mingw runtime */
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <process.h>
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _initialize_onexit_table (UCRTBASE.@)
|
||||
*/
|
||||
int __cdecl _initialize_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (table->_first == table->_end)
|
||||
table->_last = table->_end = table->_first = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _register_onexit_function (UCRTBASE.@)
|
||||
*/
|
||||
int __cdecl _register_onexit_function(_onexit_table_t *table, _onexit_t func)
|
||||
{
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
_lock(_EXIT_LOCK1);
|
||||
if (!table->_first)
|
||||
{
|
||||
table->_first = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32 * sizeof(void *));
|
||||
if (!table->_first)
|
||||
{
|
||||
_unlock(_EXIT_LOCK1);
|
||||
return -1;
|
||||
}
|
||||
table->_last = table->_first;
|
||||
table->_end = table->_first + 32;
|
||||
}
|
||||
|
||||
/* grow if full */
|
||||
if (table->_last == table->_end)
|
||||
{
|
||||
int len = table->_end - table->_first;
|
||||
_PVFV *tmp = HeapReAlloc(GetProcessHeap(), 0, table->_first, 2 * len * sizeof(void *));
|
||||
if (!tmp)
|
||||
{
|
||||
_unlock(_EXIT_LOCK1);
|
||||
return -1;
|
||||
}
|
||||
table->_first = tmp;
|
||||
table->_end = table->_first + 2 * len;
|
||||
table->_last = table->_first + len;
|
||||
}
|
||||
|
||||
*table->_last = (_PVFV)func;
|
||||
table->_last++;
|
||||
_unlock(_EXIT_LOCK1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* _execute_onexit_table (UCRTBASE.@)
|
||||
*/
|
||||
int __cdecl _execute_onexit_table(_onexit_table_t *table)
|
||||
{
|
||||
_PVFV *func;
|
||||
_onexit_table_t copy;
|
||||
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
_lock(_EXIT_LOCK1);
|
||||
if (!table->_first || table->_first >= table->_last)
|
||||
{
|
||||
_unlock(_EXIT_LOCK1);
|
||||
return 0;
|
||||
}
|
||||
copy._first = table->_first;
|
||||
copy._last = table->_last;
|
||||
copy._end = table->_end;
|
||||
memset(table, 0, sizeof(*table));
|
||||
_initialize_onexit_table(table);
|
||||
_unlock(_EXIT_LOCK1);
|
||||
|
||||
for (func = copy._last - 1; func >= copy._first; func--)
|
||||
{
|
||||
if (*func)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, copy._first);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Top level resource file for msvcrt.dll
|
||||
*
|
||||
* Copyright 2005 Marcus Meissner
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "winresrc.h"
|
||||
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
|
||||
#define WINE_FILEDESCRIPTION_STR "Wine CRT library"
|
||||
#define WINE_FILENAME_STR "msvcrt.dll"
|
||||
#define WINE_FILEVERSION 7,0,2600,2180
|
||||
#define WINE_FILEVERSION_STR "7.0.2600"
|
||||
|
||||
#include "wine/wine_common_ver.rc"
|
||||
@@ -0,0 +1,820 @@
|
||||
/*
|
||||
* general implementation of scanf used by scanf, sscanf, fscanf,
|
||||
* _cscanf, wscanf, swscanf and fwscanf
|
||||
*
|
||||
* Copyright 1996,1998 Marcus Meissner
|
||||
* Copyright 1996 Jukka Iivonen
|
||||
* Copyright 1997,2000 Uwe Bonnes
|
||||
* Copyright 2000 Jon Griffiths
|
||||
* Copyright 2002 Daniel Gudbjartsson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <conio.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "msvcrt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/* helper function for *scanf. Returns the value of character c in the
|
||||
* given base, or -1 if the given character is not a digit of the base.
|
||||
*/
|
||||
static int char2digit(char c, int base) {
|
||||
if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0');
|
||||
if (base<=10) return -1;
|
||||
if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10);
|
||||
if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* helper function for *wscanf. Returns the value of character c in the
|
||||
* given base, or -1 if the given character is not a digit of the base.
|
||||
*/
|
||||
static int wchar2digit(wchar_t c, int base) {
|
||||
if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0');
|
||||
if (base<=10) return -1;
|
||||
if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10);
|
||||
if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* vfscanf_l */
|
||||
#undef WIDE_SCANF
|
||||
#undef CONSOLE
|
||||
#undef STRING
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vfscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vfwscanf_l */
|
||||
#define WIDE_SCANF 1
|
||||
#undef CONSOLE
|
||||
#undef STRING
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vfwscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsscanf_l */
|
||||
#undef WIDE_SCANF
|
||||
#undef CONSOLE
|
||||
#define STRING 1
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsnscanf_l */
|
||||
#undef SECURE
|
||||
#define STRING_LEN 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsnscanf_s_l */
|
||||
#define SECURE
|
||||
#include "scanf.h"
|
||||
#undef STRING_LEN
|
||||
|
||||
/* vswscanf_l */
|
||||
#define WIDE_SCANF 1
|
||||
#undef CONSOLE
|
||||
#define STRING 1
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsnwscanf_l */
|
||||
#define STRING_LEN 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vsnwscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
#undef STRING_LEN
|
||||
|
||||
/* vswscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vcscanf_l */
|
||||
#undef WIDE_SCANF
|
||||
#define CONSOLE 1
|
||||
#undef STRING
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vcscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
/* vcwscanf_l */
|
||||
#define WIDE_SCANF 1
|
||||
#define CONSOLE 1
|
||||
#undef STRING
|
||||
#undef SECURE
|
||||
#include "scanf.h"
|
||||
|
||||
/* vcwscanf_s_l */
|
||||
#define SECURE 1
|
||||
#include "scanf.h"
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* fscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV fscanf(FILE *file, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfscanf_l(file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _fscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _fscanf_l(FILE *file, const char *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfscanf_l(file, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* fscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV fscanf_s(FILE *file, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfscanf_s_l(file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _fscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _fscanf_s_l(FILE *file, const char *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfscanf_s_l(file, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* scanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV scanf(const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfscanf_l(stdin, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _scanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _scanf_l(const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfscanf_l(stdin, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* scanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV scanf_s(const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfscanf_s_l(stdin, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _scanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _scanf_s_l(const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfscanf_s_l(stdin, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* fwscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV fwscanf(FILE *file, const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfwscanf_l(file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _fwscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _fwscanf_l(FILE *file, const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfwscanf_l(file, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* fwscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV fwscanf_s(FILE *file, const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfwscanf_s_l(file, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _fwscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _fwscanf_s_l(FILE *file, const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfwscanf_s_l(file, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV wscanf(const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfwscanf_l(stdin, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _wscanf_l(const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfwscanf_l(stdin, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV wscanf_s(const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vfwscanf_s_l(stdin, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _wscanf_s_l(const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vfwscanf_s_l(stdin, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* sscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV sscanf(const char *str, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsscanf_l(str, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _sscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _sscanf_l(const char *str, const char *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsscanf_l(str, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* sscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV sscanf_s(const char *str, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsscanf_s_l(str, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _sscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _sscanf_s_l(const char *str, const char *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsscanf_s_l(str, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* swscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV swscanf(const wchar_t *str, const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vswscanf_l(str, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _swscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _swscanf_l(const wchar_t *str, const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vswscanf_l(str, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* swscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV swscanf_s(const wchar_t *str, const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vswscanf_s_l(str, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _swscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _swscanf_s_l(const wchar_t *str, const wchar_t *format,
|
||||
_locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vswscanf_s_l(str, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cscanf(const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vcscanf_l(format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cscanf_l(const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vcscanf_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cscanf_s(const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vcscanf_s_l(format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cscanf_s_l(const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vcscanf_s_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwscanf(const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vcwscanf_l(format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwscanf_l(const wchar_t *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vcwscanf_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwscanf_s(const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vcwscanf_s_l(format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _cwscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _cwscanf_s_l(const wchar_t *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vcwscanf_s_l(format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snscanf(const char *input, size_t length, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsnscanf_l(input, length, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snscanf_l(const char *input, size_t length,
|
||||
const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsnscanf_l(input, length, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snscanf_s(const char *input, size_t length, const char *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsnscanf_s_l(input, length, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snscanf_s_l(const char *input, size_t length,
|
||||
const char *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsnscanf_s_l(input, length, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* __stdio_common_vsscanf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __stdio_common_vsscanf(unsigned __int64 options,
|
||||
const char *input, size_t length,
|
||||
const char *format,
|
||||
_locale_t locale,
|
||||
va_list valist)
|
||||
{
|
||||
/* LEGACY_WIDE_SPECIFIERS only has got an effect on the wide
|
||||
* scanf. LEGACY_MSVCRT_COMPATIBILITY affects parsing of nan/inf,
|
||||
* but parsing of those isn't implemented at all yet. */
|
||||
if (options & ~UCRTBASE_SCANF_MASK)
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
if (options & _CRT_INTERNAL_SCANF_SECURECRT)
|
||||
return vsnscanf_s_l(input, length, format, locale, valist);
|
||||
else
|
||||
return vsnscanf_l(input, length, format, locale, valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __stdio_common_vswscanf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __stdio_common_vswscanf(unsigned __int64 options,
|
||||
const wchar_t *input, size_t length,
|
||||
const wchar_t *format,
|
||||
_locale_t locale,
|
||||
va_list valist)
|
||||
{
|
||||
/* LEGACY_WIDE_SPECIFIERS only has got an effect on the wide
|
||||
* scanf. LEGACY_MSVCRT_COMPATIBILITY affects parsing of nan/inf,
|
||||
* but parsing of those isn't implemented at all yet. */
|
||||
if (options & ~UCRTBASE_SCANF_MASK)
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
if (options & _CRT_INTERNAL_SCANF_SECURECRT)
|
||||
return vsnwscanf_s_l(input, length, format, locale, valist);
|
||||
else
|
||||
return vsnwscanf_l(input, length, format, locale, valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __stdio_common_vfscanf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __stdio_common_vfscanf(unsigned __int64 options,
|
||||
FILE *file,
|
||||
const char *format,
|
||||
_locale_t locale,
|
||||
va_list valist)
|
||||
{
|
||||
if (options & ~(_CRT_INTERNAL_SCANF_SECURECRT | _CRT_INTERNAL_SCANF_LEGACY_WIDE_SPECIFIERS))
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
if (options & _CRT_INTERNAL_SCANF_SECURECRT)
|
||||
return vfscanf_s_l(file, format, locale, valist);
|
||||
else
|
||||
return vfscanf_l(file, format, locale, valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* __stdio_common_vfwscanf (UCRTBASE.@)
|
||||
*/
|
||||
int CDECL __stdio_common_vfwscanf(unsigned __int64 options,
|
||||
FILE *file,
|
||||
const wchar_t *format,
|
||||
_locale_t locale,
|
||||
va_list valist)
|
||||
{
|
||||
if (options & ~_CRT_INTERNAL_SCANF_SECURECRT)
|
||||
FIXME("options %#I64x not handled\n", options);
|
||||
if (options & _CRT_INTERNAL_SCANF_SECURECRT)
|
||||
return vfwscanf_s_l(file, format, locale, valist);
|
||||
else
|
||||
return vfwscanf_l(file, format, locale, valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snwscanf (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snwscanf(wchar_t *input, size_t length,
|
||||
const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsnwscanf_l(input, length, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snwscanf_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snwscanf_l(wchar_t *input, size_t length,
|
||||
const wchar_t *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsnwscanf_l(input, length, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snwscanf_s (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snwscanf_s(wchar_t *input, size_t length,
|
||||
const wchar_t *format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, format);
|
||||
res = vsnwscanf_s_l(input, length, format, NULL, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _snscanf_s_l (MSVCRT.@)
|
||||
*/
|
||||
int WINAPIV _snwscanf_s_l(wchar_t *input, size_t length,
|
||||
const wchar_t *format, _locale_t locale, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int res;
|
||||
|
||||
va_start(valist, locale);
|
||||
res = vsnwscanf_s_l(input, length, format, locale, valist);
|
||||
va_end(valist);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER==120
|
||||
|
||||
/*********************************************************************
|
||||
* vsscanf (MSVCRT120.@)
|
||||
*/
|
||||
int CDECL MSVCRT_vsscanf(const char *buffer, const char *format, va_list valist)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(buffer != NULL && format != NULL)) return -1;
|
||||
|
||||
return vsscanf_l(buffer, format, NULL, valist);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* vswscanf (MSVCRT120.@)
|
||||
*/
|
||||
int CDECL vswscanf(const wchar_t *buffer, const wchar_t *format, va_list valist)
|
||||
{
|
||||
if (!MSVCRT_CHECK_PMT(buffer != NULL && format != NULL)) return -1;
|
||||
|
||||
return vswscanf_l(buffer, format, NULL, valist);
|
||||
}
|
||||
|
||||
#endif /* _MSVCR_VER>=120 */
|
||||
@@ -0,0 +1,743 @@
|
||||
/*
|
||||
* general implementation of scanf used by scanf, sscanf, fscanf,
|
||||
* _cscanf, wscanf, swscanf and fwscanf
|
||||
*
|
||||
* Copyright 1996,1998 Marcus Meissner
|
||||
* Copyright 1996 Jukka Iivonen
|
||||
* Copyright 1997,2000, 2003 Uwe Bonnes
|
||||
* Copyright 2000 Jon Griffiths
|
||||
* Copyright 2002 Daniel Gudbjartsson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef WIDE_SCANF
|
||||
#define _CHAR_ wchar_t
|
||||
#define _EOF_ WEOF
|
||||
#define _EOF_RET (short)WEOF
|
||||
#define _ISSPACE_(c) iswspace(c)
|
||||
#define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */
|
||||
#define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */
|
||||
#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base))
|
||||
#define _BITMAPSIZE_ 256*256
|
||||
#else /* WIDE_SCANF */
|
||||
#define _CHAR_ char
|
||||
#define _EOF_ EOF
|
||||
#define _EOF_RET EOF
|
||||
#define _ISSPACE_(c) isspace(c)
|
||||
#define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */
|
||||
#define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */
|
||||
#define _CHAR2DIGIT_(c, base) char2digit((c), (base))
|
||||
#define _BITMAPSIZE_ 256
|
||||
#endif /* WIDE_SCANF */
|
||||
|
||||
#ifdef CONSOLE
|
||||
#define _GETC_FUNC_(file) _getch()
|
||||
#define _STRTOD_NAME_(func) console_ ## func
|
||||
#define _GETC_(file) (consumed++, _getch())
|
||||
#define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0)
|
||||
#define _LOCK_FILE_(file) _lock_file(stdin)
|
||||
#define _UNLOCK_FILE_(file) _unlock_file(stdin)
|
||||
#ifdef WIDE_SCANF
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vcwscanf_s_l(const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vcwscanf_l(const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#else /* WIDE_SCANF */
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vcscanf_s_l(const char *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vcscanf_l(const char *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#endif /* WIDE_SCANF */
|
||||
#else
|
||||
#ifdef STRING
|
||||
#undef _EOF_
|
||||
#define _EOF_ 0
|
||||
#define _GETC_FUNC_(file) (*file++)
|
||||
#ifdef WIDE_SCANF
|
||||
#define _STRTOD_NAME_(func) wstr_ ## func
|
||||
#else
|
||||
#define _STRTOD_NAME_(func) str_ ## func
|
||||
#endif
|
||||
#ifdef STRING_LEN
|
||||
#ifdef WIDE_SCANF
|
||||
#define _GETC_(file) (consumed++, consumed>length ? '\0' : *file++)
|
||||
#else /* WIDE_SCANF */
|
||||
#define _GETC_(file) (consumed++, consumed>length ? '\0' : (unsigned char)*file++)
|
||||
#endif /* WIDE_SCANF */
|
||||
#define _UNGETC_(nch, file) do { file--; consumed--; } while(0)
|
||||
#define _LOCK_FILE_(file) do {} while(0)
|
||||
#define _UNLOCK_FILE_(file) do {} while(0)
|
||||
#ifdef WIDE_SCANF
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vsnwscanf_s_l(const wchar_t *file, size_t length, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vsnwscanf_l(const wchar_t *file, size_t length, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#else /* WIDE_SCANF */
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vsnscanf_s_l(const char *file, size_t length, const char *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vsnscanf_l(const char *file, size_t length, const char *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#endif /* WIDE_SCANF */
|
||||
#else /* STRING_LEN */
|
||||
#ifdef WIDE_SCANF
|
||||
#define _GETC_(file) (consumed++, *file++)
|
||||
#else /* WIDE_SCANF */
|
||||
#define _GETC_(file) (consumed++, (unsigned char)*file++)
|
||||
#endif /* WIDE_SCANF */
|
||||
#define _UNGETC_(nch, file) do { file--; consumed--; } while(0)
|
||||
#define _LOCK_FILE_(file) do {} while(0)
|
||||
#define _UNLOCK_FILE_(file) do {} while(0)
|
||||
#ifdef WIDE_SCANF
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vswscanf_s_l(const wchar_t *file, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vswscanf_l(const wchar_t *file, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#else /* WIDE_SCANF */
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vsscanf_s_l(const char *file, const char *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vsscanf_l(const char *file, const char *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#endif /* WIDE_SCANF */
|
||||
#endif /* STRING_LEN */
|
||||
#else /* STRING */
|
||||
#ifdef WIDE_SCANF
|
||||
#define _GETC_FUNC_(file) fgetwc(file)
|
||||
#define _STRTOD_NAME_(func) filew_ ## func
|
||||
#define _GETC_(file) (consumed++, fgetwc(file))
|
||||
#define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0)
|
||||
#define _LOCK_FILE_(file) _lock_file(file)
|
||||
#define _UNLOCK_FILE_(file) _unlock_file(file)
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vfwscanf_s_l(FILE* file, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vfwscanf_l(FILE* file, const wchar_t *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#else /* WIDE_SCANF */
|
||||
#define _GETC_FUNC_(file) fgetc(file)
|
||||
#define _STRTOD_NAME_(func) file_ ## func
|
||||
#define _GETC_(file) (consumed++, fgetc(file))
|
||||
#define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0)
|
||||
#define _LOCK_FILE_(file) _lock_file(file)
|
||||
#define _UNLOCK_FILE_(file) _unlock_file(file)
|
||||
#ifdef SECURE
|
||||
#define _FUNCTION_ static int vfscanf_s_l(FILE* file, const char *format, _locale_t locale, va_list ap)
|
||||
#else /* SECURE */
|
||||
#define _FUNCTION_ static int vfscanf_l(FILE* file, const char *format, _locale_t locale, va_list ap)
|
||||
#endif /* SECURE */
|
||||
#endif /* WIDE_SCANF */
|
||||
#endif /* STRING */
|
||||
#endif /* CONSOLE */
|
||||
|
||||
#if (!defined(SECURE) && !defined(STRING_LEN) && (!defined(CONSOLE) || !defined(WIDE_SCANF)))
|
||||
struct _STRTOD_NAME_(strtod_scanf_ctx) {
|
||||
pthreadlocinfo locinfo;
|
||||
#ifdef STRING
|
||||
const _CHAR_ *file;
|
||||
#else
|
||||
FILE *file;
|
||||
#endif
|
||||
int length;
|
||||
int read;
|
||||
int cur;
|
||||
int unget;
|
||||
BOOL err;
|
||||
};
|
||||
|
||||
static wchar_t _STRTOD_NAME_(strtod_scanf_get)(void *ctx)
|
||||
{
|
||||
struct _STRTOD_NAME_(strtod_scanf_ctx) *context = ctx;
|
||||
|
||||
context->cur = _EOF_;
|
||||
if (!context->length) return WEOF;
|
||||
if (context->unget != _EOF_) {
|
||||
context->cur = context->unget;
|
||||
context->unget = _EOF_;
|
||||
} else {
|
||||
context->cur = _GETC_FUNC_(context->file);
|
||||
if (context->cur == _EOF_) return WEOF;
|
||||
}
|
||||
|
||||
if (context->length > 0) context->length--;
|
||||
context->read++;
|
||||
return context->cur;
|
||||
}
|
||||
|
||||
static void _STRTOD_NAME_(strtod_scanf_unget)(void *ctx)
|
||||
{
|
||||
struct _STRTOD_NAME_(strtod_scanf_ctx) *context = ctx;
|
||||
|
||||
if (context->length >= 0) context->length++;
|
||||
context->read--;
|
||||
if (context->unget != _EOF_ || context->cur == _EOF_) {
|
||||
context->err = TRUE;
|
||||
return;
|
||||
}
|
||||
context->unget = context->cur;
|
||||
}
|
||||
#endif
|
||||
|
||||
_FUNCTION_ {
|
||||
pthreadlocinfo locinfo;
|
||||
int rd = 0, consumed = 0;
|
||||
int nch;
|
||||
if (!*format) return 0;
|
||||
#ifndef WIDE_SCANF
|
||||
#ifdef CONSOLE
|
||||
TRACE("(%s):\n", debugstr_a(format));
|
||||
#else /* CONSOLE */
|
||||
#ifdef STRING
|
||||
TRACE("%s (%s)\n", debugstr_a(file), debugstr_a(format));
|
||||
#else /* STRING */
|
||||
TRACE("%p (%s)\n", file, debugstr_a(format));
|
||||
#endif /* STRING */
|
||||
#endif /* CONSOLE */
|
||||
#endif /* WIDE_SCANF */
|
||||
_LOCK_FILE_(file);
|
||||
|
||||
nch = _GETC_(file);
|
||||
if (nch == _EOF_) {
|
||||
_UNLOCK_FILE_(file);
|
||||
return _EOF_RET;
|
||||
}
|
||||
|
||||
if(!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = locale->locinfo;
|
||||
|
||||
while (*format) {
|
||||
/* a whitespace character in the format string causes scanf to read,
|
||||
* but not store, all consecutive white-space characters in the input
|
||||
* up to the next non-white-space character. One white space character
|
||||
* in the input matches any number (including zero) and combination of
|
||||
* white-space characters in the input. */
|
||||
if (_ISSPACE_(*format)) {
|
||||
/* skip whitespace */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
}
|
||||
/* a format specification causes scanf to read and convert characters
|
||||
* in the input into values of a specified type. The value is assigned
|
||||
* to an argument in the argument list. Format specifications have
|
||||
* the form %[*][width][{h | l | I64 | L}]type */
|
||||
else if (*format == '%') {
|
||||
int st = 0; int suppress = 0; int width = 0;
|
||||
int base;
|
||||
int h_prefix = 0;
|
||||
int l_prefix = 0;
|
||||
int L_prefix = 0;
|
||||
int w_prefix = 0;
|
||||
int prefix_finished = 0;
|
||||
int I64_prefix = 0;
|
||||
format++;
|
||||
/* look for leading asterisk, which means 'suppress assignment of
|
||||
* this field'. */
|
||||
if (*format=='*') {
|
||||
format++;
|
||||
suppress=1;
|
||||
}
|
||||
/* read prefix (if any) */
|
||||
while (!prefix_finished) {
|
||||
/* look for width specification */
|
||||
while (*format >= '0' && *format <= '9') {
|
||||
width *= 10;
|
||||
width += *format++ - '0';
|
||||
}
|
||||
|
||||
switch(*format) {
|
||||
case 'h': h_prefix++; break;
|
||||
case 'l':
|
||||
if(*(format+1) == 'l') {
|
||||
I64_prefix = 1;
|
||||
format++;
|
||||
}
|
||||
l_prefix = 1;
|
||||
break;
|
||||
case 'w': w_prefix = 1; break;
|
||||
case 'L': L_prefix = 1; break;
|
||||
case 'I':
|
||||
if (*(format + 1) == '6' &&
|
||||
*(format + 2) == '4') {
|
||||
I64_prefix = 1;
|
||||
format += 2;
|
||||
break;
|
||||
}
|
||||
else if (*(format + 1) == '3' &&
|
||||
*(format + 2) == '2') {
|
||||
format += 2;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
#if _MSVCR_VER == 0 || _MSVCR_VER >= 140
|
||||
case 'z':
|
||||
#endif
|
||||
if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1;
|
||||
break;
|
||||
default:
|
||||
prefix_finished = 1;
|
||||
}
|
||||
if (!prefix_finished) format++;
|
||||
}
|
||||
if (width==0) width=-1; /* no width spec seen */
|
||||
/* read type */
|
||||
switch(*format) {
|
||||
case 'p':
|
||||
case 'P': /* pointer. */
|
||||
if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1;
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'X': /* hexadecimal integer. */
|
||||
base = 16;
|
||||
goto number;
|
||||
case 'o': /* octal integer */
|
||||
base = 8;
|
||||
goto number;
|
||||
case 'u': /* unsigned decimal integer */
|
||||
base = 10;
|
||||
goto number;
|
||||
case 'd': /* signed decimal integer */
|
||||
base = 10;
|
||||
goto number;
|
||||
case 'i': /* generic integer */
|
||||
base = 0;
|
||||
number: {
|
||||
/* read an integer */
|
||||
ULONGLONG cur = 0;
|
||||
int negative = 0;
|
||||
int seendigit=0;
|
||||
/* skip initial whitespace */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
/* get sign */
|
||||
if (nch == '-' || nch == '+') {
|
||||
negative = (nch=='-');
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
}
|
||||
/* look for leading indication of base */
|
||||
if (width!=0 && nch == '0' && *format != 'p' && *format != 'P') {
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
seendigit=1;
|
||||
if (width!=0 && (nch=='x' || nch=='X')) {
|
||||
if (base==0)
|
||||
base=16;
|
||||
if (base==16) {
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
seendigit=0;
|
||||
}
|
||||
} else if (base==0)
|
||||
base = 8;
|
||||
}
|
||||
/* format %i without indication of base */
|
||||
if (base==0)
|
||||
base = 10;
|
||||
/* throw away leading zeros */
|
||||
while (width!=0 && nch=='0') {
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
seendigit=1;
|
||||
}
|
||||
if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) {
|
||||
cur = _CHAR2DIGIT_(nch, base);
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
seendigit=1;
|
||||
}
|
||||
/* read until no more digits */
|
||||
while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) {
|
||||
cur = cur*base + _CHAR2DIGIT_(nch, base);
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
seendigit=1;
|
||||
}
|
||||
/* okay, done! */
|
||||
if (!seendigit) break; /* not a valid number */
|
||||
st = 1;
|
||||
if (!suppress) {
|
||||
#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur
|
||||
if (I64_prefix) _SET_NUMBER_(LONGLONG);
|
||||
else if (l_prefix) _SET_NUMBER_(LONG);
|
||||
else if (h_prefix == 1) _SET_NUMBER_(short int);
|
||||
#if _MSVCR_VER >= 140
|
||||
else if (h_prefix == 2) _SET_NUMBER_(char);
|
||||
#endif
|
||||
else _SET_NUMBER_(int);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G': { /* read a float */
|
||||
#ifdef CONSOLE
|
||||
struct _STRTOD_NAME_(strtod_scanf_ctx) ctx = {locinfo, 0, width};
|
||||
#else
|
||||
struct _STRTOD_NAME_(strtod_scanf_ctx) ctx = {locinfo, file, width};
|
||||
#endif
|
||||
int negative = 0;
|
||||
struct fpnum fp;
|
||||
double cur;
|
||||
|
||||
/* skip initial whitespace */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
if (nch == _EOF_)
|
||||
break;
|
||||
ctx.unget = nch;
|
||||
#ifdef STRING
|
||||
ctx.file = file;
|
||||
#endif
|
||||
#ifdef STRING_LEN
|
||||
if(ctx.length > length-consumed+1) ctx.length = length-consumed+1;
|
||||
#endif
|
||||
|
||||
fp = fpnum_parse(_STRTOD_NAME_(strtod_scanf_get),
|
||||
_STRTOD_NAME_(strtod_scanf_unget), &ctx, locinfo, FALSE);
|
||||
fpnum_double(&fp, &cur);
|
||||
if(!rd && ctx.err) {
|
||||
_UNLOCK_FILE_(file);
|
||||
return _EOF_RET;
|
||||
}
|
||||
if(ctx.err || !ctx.read)
|
||||
break;
|
||||
consumed += ctx.read;
|
||||
#ifdef STRING
|
||||
file = ctx.file;
|
||||
#endif
|
||||
nch = ctx.cur;
|
||||
|
||||
st = 1;
|
||||
if (!suppress) {
|
||||
if (L_prefix || l_prefix) _SET_NUMBER_(double);
|
||||
else _SET_NUMBER_(float);
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* According to msdn,
|
||||
* 's' reads a character string in a call to fscanf
|
||||
* and 'S' a wide character string and vice versa in a
|
||||
* call to fwscanf. The 'h', 'w' and 'l' prefixes override
|
||||
* this behaviour. 'h' forces reading char * but 'l' and 'w'
|
||||
* force reading WCHAR. */
|
||||
case 's':
|
||||
if (w_prefix || l_prefix) goto widecharstring;
|
||||
else if (h_prefix) goto charstring;
|
||||
#ifdef WIDE_SCANF
|
||||
else goto widecharstring;
|
||||
#else /* WIDE_SCANF */
|
||||
else goto charstring;
|
||||
#endif /* WIDE_SCANF */
|
||||
case 'S':
|
||||
if (w_prefix || l_prefix) goto widecharstring;
|
||||
else if (h_prefix) goto charstring;
|
||||
#ifdef WIDE_SCANF
|
||||
else goto charstring;
|
||||
#else /* WIDE_SCANF */
|
||||
else goto widecharstring;
|
||||
#endif /* WIDE_SCANF */
|
||||
charstring: { /* read a word into a char */
|
||||
char *sptr = suppress ? NULL : va_arg(ap, char*);
|
||||
char *sptr_beg = sptr;
|
||||
#ifdef SECURE
|
||||
unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
|
||||
#else
|
||||
unsigned size = UINT_MAX;
|
||||
#endif
|
||||
/* skip initial whitespace */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
/* read until whitespace */
|
||||
while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
|
||||
if (!suppress) {
|
||||
*sptr++ = _CHAR2SUPPORTED_(nch);
|
||||
if(size>1) size--;
|
||||
else {
|
||||
_UNLOCK_FILE_(file);
|
||||
*sptr_beg = 0;
|
||||
return rd;
|
||||
}
|
||||
}
|
||||
st++;
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
}
|
||||
/* if we have reached the EOF and output nothing then report EOF */
|
||||
if (nch==_EOF_ && rd==0 && st==0) {
|
||||
_UNLOCK_FILE_(file);
|
||||
return _EOF_RET;
|
||||
}
|
||||
/* terminate */
|
||||
if (st && !suppress) *sptr = 0;
|
||||
}
|
||||
break;
|
||||
widecharstring: { /* read a word into a wchar_t* */
|
||||
wchar_t *sptr = suppress ? NULL : va_arg(ap, wchar_t*);
|
||||
wchar_t *sptr_beg = sptr;
|
||||
#ifdef SECURE
|
||||
unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
|
||||
#else
|
||||
unsigned size = UINT_MAX;
|
||||
#endif
|
||||
/* skip initial whitespace */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
/* read until whitespace */
|
||||
while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
|
||||
if (!suppress) {
|
||||
*sptr++ = _WIDE2SUPPORTED_(nch);
|
||||
if(size>1) size--;
|
||||
else {
|
||||
_UNLOCK_FILE_(file);
|
||||
*sptr_beg = 0;
|
||||
return rd;
|
||||
}
|
||||
}
|
||||
st++;
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
}
|
||||
#if _MSVCR_VER >= 80
|
||||
/* if we have reached the EOF and output nothing then report EOF */
|
||||
if (nch==_EOF_ && rd==0 && st==0) {
|
||||
_UNLOCK_FILE_(file);
|
||||
return _EOF_RET;
|
||||
}
|
||||
#endif
|
||||
/* terminate */
|
||||
if (st && !suppress) *sptr = 0;
|
||||
}
|
||||
break;
|
||||
/* 'c' and 'C work analogously to 's' and 'S' as described
|
||||
* above */
|
||||
case 'c':
|
||||
if (w_prefix || l_prefix) goto widecharacter;
|
||||
else if (h_prefix) goto character;
|
||||
#ifdef WIDE_SCANF
|
||||
else goto widecharacter;
|
||||
#else /* WIDE_SCANF */
|
||||
else goto character;
|
||||
#endif /* WIDE_SCANF */
|
||||
case 'C':
|
||||
if (w_prefix || l_prefix) goto widecharacter;
|
||||
else if (h_prefix) goto character;
|
||||
#ifdef WIDE_SCANF
|
||||
else goto character;
|
||||
#else /* WIDE_SCANF */
|
||||
else goto widecharacter;
|
||||
#endif /* WIDE_SCANF */
|
||||
character: { /* read single character into char */
|
||||
char *str = suppress ? NULL : va_arg(ap, char*);
|
||||
char *pstr = str;
|
||||
#ifdef SECURE
|
||||
unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
|
||||
#else
|
||||
unsigned size = UINT_MAX;
|
||||
#endif
|
||||
if (width == -1) width = 1;
|
||||
while (width && (nch != _EOF_))
|
||||
{
|
||||
if (!suppress) {
|
||||
if(size) size--;
|
||||
else {
|
||||
_UNLOCK_FILE_(file);
|
||||
*pstr = 0;
|
||||
return rd;
|
||||
}
|
||||
*str++ = _CHAR2SUPPORTED_(nch);
|
||||
}
|
||||
st++;
|
||||
width--;
|
||||
nch = _GETC_(file);
|
||||
}
|
||||
}
|
||||
break;
|
||||
widecharacter: { /* read single character into a wchar_t */
|
||||
wchar_t *str = suppress ? NULL : va_arg(ap, wchar_t*);
|
||||
wchar_t *pstr = str;
|
||||
#ifdef SECURE
|
||||
unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
|
||||
#else
|
||||
unsigned size = UINT_MAX;
|
||||
#endif
|
||||
if (width == -1) width = 1;
|
||||
while (width && (nch != _EOF_))
|
||||
{
|
||||
if (!suppress) {
|
||||
if(size) size--;
|
||||
else {
|
||||
_UNLOCK_FILE_(file);
|
||||
*pstr = 0;
|
||||
return rd;
|
||||
}
|
||||
*str++ = _WIDE2SUPPORTED_(nch);
|
||||
}
|
||||
st++;
|
||||
width--;
|
||||
nch = _GETC_(file);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'n': {
|
||||
if (!suppress) {
|
||||
int*n = va_arg(ap, int*);
|
||||
*n = consumed - 1;
|
||||
}
|
||||
/* This is an odd one: according to the standard,
|
||||
* "Execution of a %n directive does not increment the
|
||||
* assignment count returned at the completion of
|
||||
* execution" even if it wasn't suppressed with the
|
||||
* '*' flag. The Corrigendum to the standard seems
|
||||
* to contradict this (comment out the assignment to
|
||||
* suppress below if you want to implement these
|
||||
* alternate semantics) but the windows program I'm
|
||||
* looking at expects the behavior I've coded here
|
||||
* (which happens to be what glibc does as well).
|
||||
*/
|
||||
suppress = 1;
|
||||
st = 1;
|
||||
}
|
||||
break;
|
||||
case '[': {
|
||||
_CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*);
|
||||
_CHAR_ *sptr = str;
|
||||
RTL_BITMAP bitMask;
|
||||
ULONG *Mask;
|
||||
int invert = 0; /* Set if we are NOT to find the chars */
|
||||
#ifdef SECURE
|
||||
unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
|
||||
#else
|
||||
unsigned size = UINT_MAX;
|
||||
#endif
|
||||
|
||||
/* Init our bitmap */
|
||||
Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8);
|
||||
RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_);
|
||||
|
||||
/* Read the format */
|
||||
format++;
|
||||
if(*format == '^') {
|
||||
invert = 1;
|
||||
format++;
|
||||
}
|
||||
if(*format == ']') {
|
||||
RtlSetBits(&bitMask, ']', 1);
|
||||
format++;
|
||||
}
|
||||
while(*format && (*format != ']')) {
|
||||
/* According to msdn:
|
||||
* "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
|
||||
if(format[1] == '-' && format[2] && format[2] != ']') {
|
||||
if (format[0] < format[2])
|
||||
RtlSetBits(&bitMask, format[0], format[2] - format[0] + 1);
|
||||
else
|
||||
RtlSetBits(&bitMask, format[2], format[0] - format[2] + 1);
|
||||
format += 2;
|
||||
} else
|
||||
RtlSetBits(&bitMask, *format, 1);
|
||||
format++;
|
||||
}
|
||||
/* read until char is not suitable */
|
||||
while ((width != 0) && (nch != _EOF_)) {
|
||||
if(!invert) {
|
||||
if(RtlAreBitsSet(&bitMask, nch, 1)) {
|
||||
if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
|
||||
} else
|
||||
break;
|
||||
} else {
|
||||
if(RtlAreBitsClear(&bitMask, nch, 1)) {
|
||||
if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
st++;
|
||||
nch = _GETC_(file);
|
||||
if (width>0) width--;
|
||||
if(size>1) size--;
|
||||
else {
|
||||
_UNLOCK_FILE_(file);
|
||||
*str = 0;
|
||||
HeapFree(GetProcessHeap(), 0, Mask);
|
||||
return rd;
|
||||
}
|
||||
}
|
||||
/* terminate */
|
||||
if (!suppress) *sptr = 0;
|
||||
HeapFree(GetProcessHeap(), 0, Mask);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* From spec: "if a percent sign is followed by a character
|
||||
* that has no meaning as a format-control character, that
|
||||
* character and the following characters are treated as
|
||||
* an ordinary sequence of characters, that is, a sequence
|
||||
* of characters that must match the input. For example,
|
||||
* to specify that a percent-sign character is to be input,
|
||||
* use %%." */
|
||||
while ((nch!=_EOF_) && _ISSPACE_(nch))
|
||||
nch = _GETC_(file);
|
||||
if ((_CHAR_)nch == *format) {
|
||||
suppress = 1; /* whoops no field to be read */
|
||||
st = 1; /* but we got what we expected */
|
||||
nch = _GETC_(file);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (st && !suppress) rd++;
|
||||
else if (!st) break;
|
||||
}
|
||||
/* a non-white-space character causes scanf to read, but not store,
|
||||
* a matching non-white-space character. */
|
||||
else {
|
||||
/* check for character match */
|
||||
if ((_CHAR_)nch == *format) {
|
||||
nch = _GETC_(file);
|
||||
} else break;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
if (nch!=_EOF_) {
|
||||
_UNGETC_(nch, file);
|
||||
}
|
||||
|
||||
TRACE("returning %d\n", rd);
|
||||
_UNLOCK_FILE_(file);
|
||||
return rd;
|
||||
}
|
||||
|
||||
#undef _CHAR_
|
||||
#undef _EOF_
|
||||
#undef _EOF_RET
|
||||
#undef _ISSPACE_
|
||||
#undef _CHAR2SUPPORTED_
|
||||
#undef _WIDE2SUPPORTED_
|
||||
#undef _CHAR2DIGIT_
|
||||
#undef _GETC_FUNC_
|
||||
#undef _STRTOD_NAME_
|
||||
#undef _GETC_
|
||||
#undef _UNGETC_
|
||||
#undef _LOCK_FILE_
|
||||
#undef _UNLOCK_FILE_
|
||||
#undef _FUNCTION_
|
||||
#undef _BITMAPSIZE_
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* sincos implementation
|
||||
*
|
||||
* Copyright 2021 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep implib
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* GCC may optimize a pair of sin(), cos() calls to a single sincos() call,
|
||||
* which is not exported by any msvcrt version. */
|
||||
|
||||
void sincos(double x, double *s, double *c)
|
||||
{
|
||||
*s = sin(x);
|
||||
*c = cos(x);
|
||||
}
|
||||
|
||||
void sincosf(float x, float *s, float *c)
|
||||
{
|
||||
*s = sinf(x);
|
||||
*c = cosf(x);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* msvcrt.dll thread functions
|
||||
*
|
||||
* Copyright 2000 Jon Griffiths
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include <process.h>
|
||||
#include "msvcrt.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
typedef struct {
|
||||
HANDLE thread;
|
||||
union {
|
||||
_beginthread_start_routine_t start_address;
|
||||
_beginthreadex_start_routine_t start_address_ex;
|
||||
};
|
||||
void *arglist;
|
||||
#if _MSVCR_VER >= 140
|
||||
HMODULE module;
|
||||
#endif
|
||||
} _beginthread_trampoline_t;
|
||||
|
||||
/*********************************************************************
|
||||
* msvcrt_get_thread_data
|
||||
*
|
||||
* Return the thread local storage structure.
|
||||
*/
|
||||
thread_data_t *CDECL msvcrt_get_thread_data(void)
|
||||
{
|
||||
thread_data_t *ptr;
|
||||
DWORD err = GetLastError(); /* need to preserve last error */
|
||||
|
||||
if (!(ptr = TlsGetValue( msvcrt_tls_index )))
|
||||
{
|
||||
if (!(ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptr) )))
|
||||
_amsg_exit( _RT_THREAD );
|
||||
if (!TlsSetValue( msvcrt_tls_index, ptr )) _amsg_exit( _RT_THREAD );
|
||||
ptr->tid = GetCurrentThreadId();
|
||||
ptr->handle = INVALID_HANDLE_VALUE;
|
||||
ptr->random_seed = 1;
|
||||
ptr->locinfo = MSVCRT_locale->locinfo;
|
||||
ptr->mbcinfo = MSVCRT_locale->mbcinfo;
|
||||
ptr->cached_locale[0] = 'C';
|
||||
ptr->cached_locale[1] = 0;
|
||||
#if _MSVCR_VER >= 140
|
||||
ptr->module = NULL;
|
||||
#endif
|
||||
}
|
||||
SetLastError( err );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _endthread (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _endthread(void)
|
||||
{
|
||||
thread_data_t *tls;
|
||||
|
||||
TRACE("(void)\n");
|
||||
|
||||
tls = TlsGetValue(msvcrt_tls_index);
|
||||
if (tls && tls->handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(tls->handle);
|
||||
tls->handle = INVALID_HANDLE_VALUE;
|
||||
} else
|
||||
WARN("tls=%p tls->handle=%p\n", tls, tls ? tls->handle : INVALID_HANDLE_VALUE);
|
||||
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _endthreadex (MSVCRT.@)
|
||||
*/
|
||||
void CDECL _endthreadex(
|
||||
unsigned int retval) /* [in] Thread exit code */
|
||||
{
|
||||
TRACE("(%d)\n", retval);
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
{
|
||||
thread_data_t *tls = TlsGetValue(msvcrt_tls_index);
|
||||
|
||||
if (tls && tls->module != NULL)
|
||||
FreeLibraryAndExitThread(tls->module, retval);
|
||||
else
|
||||
WARN("tls=%p tls->module=%p\n", tls, tls ? tls->module : NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
ExitThread(retval);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _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));
|
||||
free(arg);
|
||||
data->handle = local_trampoline.thread;
|
||||
#if _MSVCR_VER >= 140
|
||||
data->module = local_trampoline.module;
|
||||
#endif
|
||||
|
||||
local_trampoline.start_address(local_trampoline.arglist);
|
||||
_endthread();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _beginthread (MSVCRT.@)
|
||||
*/
|
||||
uintptr_t CDECL _beginthread(
|
||||
_beginthread_start_routine_t start_address, /* [in] Start address of routine that begins execution of new thread */
|
||||
unsigned int stack_size, /* [in] Stack size for new thread or 0 */
|
||||
void *arglist) /* [in] Argument list to be passed to new thread or NULL */
|
||||
{
|
||||
_beginthread_trampoline_t* trampoline;
|
||||
HANDLE thread;
|
||||
|
||||
TRACE("(%p, %d, %p)\n", start_address, stack_size, arglist);
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(start_address)) return -1;
|
||||
|
||||
trampoline = malloc(sizeof(*trampoline));
|
||||
if(!trampoline) {
|
||||
*_errno() = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread = CreateThread(NULL, stack_size, _beginthread_trampoline,
|
||||
trampoline, CREATE_SUSPENDED, NULL);
|
||||
if(!thread) {
|
||||
free(trampoline);
|
||||
msvcrt_set_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
trampoline->thread = thread;
|
||||
trampoline->start_address = start_address;
|
||||
trampoline->arglist = arglist;
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(void*)start_address, &trampoline->module))
|
||||
{
|
||||
trampoline->module = NULL;
|
||||
WARN("failed to get module for the start_address: %lu\n", GetLastError());
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ResumeThread(thread) == -1) {
|
||||
#if _MSVCR_VER >= 140
|
||||
FreeLibrary(trampoline->module);
|
||||
#endif
|
||||
free(trampoline);
|
||||
*_errno() = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (uintptr_t)thread;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _beginthreadex_trampoline
|
||||
*/
|
||||
static DWORD CALLBACK _beginthreadex_trampoline(LPVOID arg)
|
||||
{
|
||||
unsigned int retval;
|
||||
_beginthread_trampoline_t local_trampoline;
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
|
||||
memcpy(&local_trampoline, arg, sizeof(local_trampoline));
|
||||
free(arg);
|
||||
data->handle = local_trampoline.thread;
|
||||
#if _MSVCR_VER >= 140
|
||||
data->module = local_trampoline.module;
|
||||
#endif
|
||||
|
||||
retval = local_trampoline.start_address_ex(local_trampoline.arglist);
|
||||
_endthreadex(retval);
|
||||
}
|
||||
/*********************************************************************
|
||||
* _beginthreadex (MSVCRT.@)
|
||||
*/
|
||||
uintptr_t CDECL _beginthreadex(
|
||||
void *security, /* [in] Security descriptor for new thread; must be NULL for Windows 9x applications */
|
||||
unsigned int stack_size, /* [in] Stack size for new thread or 0 */
|
||||
_beginthreadex_start_routine_t start_address, /* [in] Start address of routine that begins execution of new thread */
|
||||
void *arglist, /* [in] Argument list to be passed to new thread or NULL */
|
||||
unsigned int initflag, /* [in] Initial state of new thread (0 for running or CREATE_SUSPEND for suspended) */
|
||||
unsigned int *thrdaddr) /* [out] Points to a 32-bit variable that receives the thread identifier */
|
||||
{
|
||||
_beginthread_trampoline_t* trampoline;
|
||||
HANDLE thread;
|
||||
|
||||
TRACE("(%p, %d, %p, %p, %d, %p)\n", security, stack_size, start_address, arglist, initflag, thrdaddr);
|
||||
|
||||
/* FIXME: may use different errno / return values */
|
||||
if (!MSVCRT_CHECK_PMT(start_address)) return 0;
|
||||
|
||||
if (!(trampoline = malloc(sizeof(*trampoline))))
|
||||
return 0;
|
||||
|
||||
trampoline->thread = INVALID_HANDLE_VALUE;
|
||||
trampoline->start_address_ex = start_address;
|
||||
trampoline->arglist = arglist;
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(void*)start_address, &trampoline->module))
|
||||
{
|
||||
trampoline->module = NULL;
|
||||
WARN("failed to get module for the start_address: %lu\n", GetLastError());
|
||||
}
|
||||
#endif
|
||||
|
||||
thread = CreateThread(security, stack_size, _beginthreadex_trampoline,
|
||||
trampoline, initflag, (DWORD *)thrdaddr);
|
||||
if(!thread) {
|
||||
#if _MSVCR_VER >= 140
|
||||
FreeLibrary(trampoline->module);
|
||||
#endif
|
||||
free(trampoline);
|
||||
msvcrt_set_errno(GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uintptr_t)thread;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER>=80
|
||||
/*********************************************************************
|
||||
* _getptd (MSVCR80.@)
|
||||
*/
|
||||
thread_data_t* CDECL _getptd(void)
|
||||
{
|
||||
FIXME("returns undocumented/not fully filled data\n");
|
||||
return msvcrt_get_thread_data();
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user