mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
1929 lines
47 KiB
C
1929 lines
47 KiB
C
/*
|
|
* The C RunTime DLL
|
|
*
|
|
* Implements C run-time functionality as known from UNIX.
|
|
*
|
|
* Copyright 1996,1998 Marcus Meissner
|
|
* Copyright 1996 Jukka Iivonen
|
|
* Copyright 1997,2000 Uwe Bonnes
|
|
* Copyright 2000 Jon Griffiths
|
|
*/
|
|
|
|
/*
|
|
Unresolved issues Uwe Bonnes 970904:
|
|
- tested with ftp://ftp.remcomp.com/pub/remcomp/lcc-win32.zip, a C-Compiler
|
|
for Win32, based on lcc, from Jacob Navia
|
|
UB 000416:
|
|
- probably not thread safe
|
|
*/
|
|
|
|
/* NOTE: This file also implements the wcs* functions. They _ARE_ in
|
|
* the newer Linux libcs, but use 4 byte wide characters, so are unusable,
|
|
* since we need 2 byte wide characters. - Marcus Meissner, 981031
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "crtdll.h"
|
|
|
|
#include <ctype.h>
|
|
#define __USE_ISOC9X 1
|
|
#define __USE_ISOC99 1
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include "ntddk.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
|
|
#ifndef HAVE_FINITE
|
|
#ifndef finite /* Could be macro */
|
|
#ifdef isfinite
|
|
#define finite(x) isfinite(x)
|
|
#else
|
|
#define finite(x) (!isnan(x)) /* At least catch some cases */
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef signbit
|
|
#define signbit(x) 0
|
|
#endif
|
|
|
|
DEFAULT_DEBUG_CHANNEL(crtdll);
|
|
|
|
double CRTDLL_HUGE_dll; /* CRTDLL.20 */
|
|
UINT CRTDLL_argc_dll; /* CRTDLL.23 */
|
|
LPSTR *CRTDLL_argv_dll; /* CRTDLL.24 */
|
|
LPSTR CRTDLL_acmdln_dll; /* CRTDLL.38 */
|
|
UINT CRTDLL_basemajor_dll; /* CRTDLL.42 */
|
|
UINT CRTDLL_baseminor_dll; /* CRTDLL.43 */
|
|
UINT CRTDLL_baseversion_dll; /* CRTDLL.44 */
|
|
UINT CRTDLL_commode_dll; /* CRTDLL.59 */
|
|
LPSTR CRTDLL_environ_dll; /* CRTDLL.75 */
|
|
UINT CRTDLL_fmode_dll; /* CRTDLL.104 */
|
|
UINT CRTDLL_osmajor_dll; /* CRTDLL.241 */
|
|
UINT CRTDLL_osminor_dll; /* CRTDLL.242 */
|
|
UINT CRTDLL_osmode_dll; /* CRTDLL.243 */
|
|
UINT CRTDLL_osver_dll; /* CRTDLL.244 */
|
|
UINT CRTDLL_osversion_dll; /* CRTDLL.245 */
|
|
LONG CRTDLL_timezone_dll = 0; /* CRTDLL.304 */
|
|
UINT CRTDLL_winmajor_dll; /* CRTDLL.329 */
|
|
UINT CRTDLL_winminor_dll; /* CRTDLL.330 */
|
|
UINT CRTDLL_winver_dll; /* CRTDLL.331 */
|
|
INT CRTDLL_doserrno = 0;
|
|
INT CRTDLL_errno = 0;
|
|
INT CRTDLL__mb_cur_max_dll = 1;
|
|
const INT CRTDLL__sys_nerr = 43;
|
|
|
|
/* ASCII char classification flags - binary compatible */
|
|
#define _C_ CRTDLL_CONTROL
|
|
#define _S_ CRTDLL_SPACE
|
|
#define _P_ CRTDLL_PUNCT
|
|
#define _D_ CRTDLL_DIGIT
|
|
#define _H_ CRTDLL_HEX
|
|
#define _U_ CRTDLL_UPPER
|
|
#define _L_ CRTDLL_LOWER
|
|
|
|
WORD CRTDLL_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_|CRTDLL_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
|
|
};
|
|
|
|
/* Internal: Current ctype table for locale */
|
|
WORD __CRTDLL_current_ctype[257];
|
|
|
|
/* pctype is used by macros in the Win32 headers. It must point
|
|
* To a table of flags exactly like ctype. To allow locale
|
|
* changes to affect ctypes (i.e. isleadbyte), we use a second table
|
|
* and update its flags whenever the current locale changes.
|
|
*/
|
|
WORD* CRTDLL_pctype_dll = __CRTDLL_current_ctype + 1;
|
|
|
|
|
|
/*********************************************************************
|
|
* CRTDLL_MainInit (CRTDLL.init)
|
|
*/
|
|
BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
|
|
{
|
|
TRACE("(0x%08x,%ld,%p)\n",hinstDLL,fdwReason,lpvReserved);
|
|
|
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
|
__CRTDLL__init_io();
|
|
__CRTDLL_init_console();
|
|
CRTDLL_setlocale( CRTDLL_LC_ALL, "C" );
|
|
CRTDLL_HUGE_dll = HUGE_VAL;
|
|
}
|
|
else if (fdwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
CRTDLL__fcloseall();
|
|
__CRTDLL_free_console();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* INTERNAL: Set the crt and dos errno's from the OS error given. */
|
|
void __CRTDLL__set_errno(ULONG err)
|
|
{
|
|
/* FIXME: not MT safe */
|
|
CRTDLL_doserrno = err;
|
|
|
|
switch(err)
|
|
{
|
|
#define ERR_CASE(oserr) case oserr:
|
|
#define ERR_MAPS(oserr,crterr) case oserr:CRTDLL_errno = 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_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 */
|
|
CRTDLL_errno = EINVAL;
|
|
}
|
|
}
|
|
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
#define FPU_DOUBLE(var) double var; \
|
|
__asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
|
|
#define FPU_DOUBLES(var1,var2) double var1,var2; \
|
|
__asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
|
|
__asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
|
|
#else
|
|
#define FPU_DOUBLE(var) double var = sqrt(-1); \
|
|
FIXME(":not implemented\n");
|
|
#define FPU_DOUBLES(var1,var2) double var1,var2; \
|
|
var1=var2=sqrt(-1); FIXME(":not implemented\n")
|
|
#endif
|
|
|
|
/*********************************************************************
|
|
* _CIacos (CRTDLL.004)
|
|
*/
|
|
double __cdecl CRTDLL__CIacos(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (x < -1.0 || x > 1.0 || !finite(x)) CRTDLL_errno = EDOM;
|
|
return acos(x);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _CIasin (CRTDLL.005)
|
|
*/
|
|
double __cdecl CRTDLL__CIasin(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (x < -1.0 || x > 1.0 || !finite(x)) CRTDLL_errno = EDOM;
|
|
return asin(x);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _CIatan (CRTDLL.006)
|
|
*/
|
|
double __cdecl CRTDLL__CIatan(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return atan(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIatan2 (CRTDLL.007)
|
|
*/
|
|
double __cdecl CRTDLL__CIatan2(void)
|
|
{
|
|
FPU_DOUBLES(x,y);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return atan2(x,y);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _CIcos (CRTDLL.008)
|
|
*/
|
|
double __cdecl CRTDLL__CIcos(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return cos(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIcosh (CRTDLL.009)
|
|
*/
|
|
double __cdecl CRTDLL__CIcosh(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return cosh(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIexp (CRTDLL.010)
|
|
*/
|
|
double __cdecl CRTDLL__CIexp(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return exp(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIfmod (CRTDLL.011)
|
|
*/
|
|
double __cdecl CRTDLL__CIfmod(void)
|
|
{
|
|
FPU_DOUBLES(x,y);
|
|
if (!finite(x) || !finite(y)) CRTDLL_errno = EDOM;
|
|
return fmod(x,y);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIlog (CRTDLL.012)
|
|
*/
|
|
double __cdecl CRTDLL__CIlog(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
|
|
if (x == 0.0) CRTDLL_errno = ERANGE;
|
|
return log(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIlog10 (CRTDLL.013)
|
|
*/
|
|
double __cdecl CRTDLL__CIlog10(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
|
|
if (x == 0.0) CRTDLL_errno = ERANGE;
|
|
return log10(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIpow (CRTDLL.014)
|
|
*/
|
|
double __cdecl CRTDLL__CIpow(void)
|
|
{
|
|
double z;
|
|
FPU_DOUBLES(x,y);
|
|
/* FIXME: If x < 0 and y is not integral, set EDOM */
|
|
z = pow(x,y);
|
|
if (!finite(z)) CRTDLL_errno = EDOM;
|
|
return z;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIsin (CRTDLL.015)
|
|
*/
|
|
double __cdecl CRTDLL__CIsin(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return sin(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIsinh (CRTDLL.016)
|
|
*/
|
|
double __cdecl CRTDLL__CIsinh(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return sinh(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CIsqrt (CRTDLL.017)
|
|
*/
|
|
double __cdecl CRTDLL__CIsqrt(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
|
|
return sqrt(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CItan (CRTDLL.018)
|
|
*/
|
|
double __cdecl CRTDLL__CItan(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return tan(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _CItanh (CRTDLL.019)
|
|
*/
|
|
double __cdecl CRTDLL__CItanh(void)
|
|
{
|
|
FPU_DOUBLE(x);
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return tanh(x);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _GetMainArgs (CRTDLL.022)
|
|
*/
|
|
LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,
|
|
LPSTR *environ,DWORD flag)
|
|
{
|
|
char *cmdline;
|
|
char **xargv;
|
|
int xargc,end,last_arg,afterlastspace;
|
|
DWORD version;
|
|
|
|
TRACE("(%p,%p,%p,%ld).\n",
|
|
argc,argv,environ,flag
|
|
);
|
|
|
|
if (CRTDLL_acmdln_dll != NULL)
|
|
HeapFree(GetProcessHeap(), 0, CRTDLL_acmdln_dll);
|
|
|
|
CRTDLL_acmdln_dll = cmdline = CRTDLL__strdup( GetCommandLineA() );
|
|
TRACE("got '%s'\n", cmdline);
|
|
|
|
version = GetVersion();
|
|
CRTDLL_osver_dll = version >> 16;
|
|
CRTDLL_winminor_dll = version & 0xFF;
|
|
CRTDLL_winmajor_dll = (version>>8) & 0xFF;
|
|
CRTDLL_baseversion_dll = version >> 16;
|
|
CRTDLL_winver_dll = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8);
|
|
CRTDLL_baseminor_dll = (version >> 16) & 0xFF;
|
|
CRTDLL_basemajor_dll = (version >> 24) & 0xFF;
|
|
CRTDLL_osversion_dll = version & 0xFFFF;
|
|
CRTDLL_osminor_dll = version & 0xFF;
|
|
CRTDLL_osmajor_dll = (version>>8) & 0xFF;
|
|
|
|
/* missing threading init */
|
|
|
|
end=0;last_arg=0;xargv=NULL;xargc=0;afterlastspace=0;
|
|
while (1)
|
|
{
|
|
if ((cmdline[end]==' ') || (cmdline[end]=='\0'))
|
|
{
|
|
if (cmdline[end]=='\0')
|
|
last_arg=1;
|
|
else
|
|
cmdline[end]='\0';
|
|
/* alloc xargc + NULL entry */
|
|
xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv,
|
|
sizeof(char*)*(xargc+1));
|
|
if (strlen(cmdline+afterlastspace))
|
|
{
|
|
xargv[xargc] = CRTDLL__strdup(cmdline+afterlastspace);
|
|
xargc++;
|
|
if (!last_arg) /* need to seek to the next arg ? */
|
|
{
|
|
end++;
|
|
while (cmdline[end]==' ')
|
|
end++;
|
|
}
|
|
afterlastspace=end;
|
|
}
|
|
else
|
|
{
|
|
xargv[xargc] = NULL; /* the last entry is NULL */
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
end++;
|
|
}
|
|
CRTDLL_argc_dll = xargc;
|
|
*argc = xargc;
|
|
CRTDLL_argv_dll = xargv;
|
|
*argv = xargv;
|
|
|
|
TRACE("found %d arguments\n",
|
|
CRTDLL_argc_dll);
|
|
CRTDLL_environ_dll = *environ = GetEnvironmentStringsA();
|
|
return environ;
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
* _clearfp (CRTDLL.056)
|
|
*
|
|
* Clear and return the previous FP status.
|
|
*/
|
|
UINT __cdecl CRTDLL__clearfp( VOID )
|
|
{
|
|
UINT retVal = CRTDLL__statusfp();
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
__asm__ __volatile__( "fnclex" );
|
|
#else
|
|
FIXME(":Not Implemented!\n");
|
|
#endif
|
|
return retVal;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _fpclass (CRTDLL.105)
|
|
*
|
|
* Return the FP classification of d.
|
|
*/
|
|
INT __cdecl CRTDLL__fpclass(double d)
|
|
{
|
|
#if defined(HAVE_FPCLASS) || defined(fpclass)
|
|
switch (fpclass( d ))
|
|
{
|
|
case FP_SNAN: return _FPCLASS_SNAN;
|
|
case FP_QNAN: return _FPCLASS_QNAN;
|
|
case FP_NINF: return _FPCLASS_NINF;
|
|
case FP_PINF: return _FPCLASS_PINF;
|
|
case FP_NDENORM: return _FPCLASS_ND;
|
|
case FP_PDENORM: return _FPCLASS_PD;
|
|
case FP_NZERO: return _FPCLASS_NZ;
|
|
case FP_PZERO: return _FPCLASS_PZ;
|
|
case FP_NNORM: return _FPCLASS_NN;
|
|
}
|
|
return _FPCLASS_PN;
|
|
#elif defined (fpclassify)
|
|
switch (fpclassify( d ))
|
|
{
|
|
case FP_NAN: return _FPCLASS_QNAN;
|
|
case FP_INFINITE: return signbit(d) ? _FPCLASS_NINF : _FPCLASS_PINF;
|
|
case FP_SUBNORMAL: return signbit(d) ?_FPCLASS_ND : _FPCLASS_PD;
|
|
case FP_ZERO: return signbit(d) ? _FPCLASS_NZ : _FPCLASS_PZ;
|
|
}
|
|
return signbit(d) ? _FPCLASS_NN : _FPCLASS_PN;
|
|
#else
|
|
if (!finite(d))
|
|
return _FPCLASS_QNAN;
|
|
return d == 0.0 ? _FPCLASS_PZ : (d < 0 ? _FPCLASS_NN : _FPCLASS_PN);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _initterm (CRTDLL.135)
|
|
*/
|
|
DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
|
|
{
|
|
_INITTERMFUN *current;
|
|
|
|
TRACE("(%p,%p)\n",start,end);
|
|
current=start;
|
|
while (current<end) {
|
|
if (*current) (*current)();
|
|
current++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* _global_unwind2 (CRTDLL.129)
|
|
*/
|
|
void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame )
|
|
{
|
|
RtlUnwind( frame, 0, NULL, 0 );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* _local_unwind2 (CRTDLL.173)
|
|
*/
|
|
void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr )
|
|
{
|
|
TRACE("(%p,%ld)\n",endframe,nr);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* _setjmp (CRTDLL.264)
|
|
*/
|
|
INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf)
|
|
{
|
|
FIXME(":(%p): stub\n",jmpbuf);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _beep (CRTDLL.045)
|
|
*
|
|
* Output a tone using the PC speaker.
|
|
*
|
|
* PARAMS
|
|
* freq [in] Frequency of the tone
|
|
*
|
|
* duration [in] Length of time the tone should sound
|
|
*
|
|
* RETURNS
|
|
* None.
|
|
*/
|
|
void __cdecl CRTDLL__beep( UINT freq, UINT duration)
|
|
{
|
|
TRACE(":Freq %d, Duration %d\n",freq,duration);
|
|
Beep(freq, duration);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* rand (CRTDLL.446)
|
|
*/
|
|
INT __cdecl CRTDLL_rand()
|
|
{
|
|
return (rand() & CRTDLL_RAND_MAX);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _rotl (CRTDLL.259)
|
|
*/
|
|
UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
|
|
{
|
|
shift &= 31;
|
|
return (x << shift) | (x >> (32-shift));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _logb (CRTDLL.174)
|
|
*/
|
|
double __cdecl CRTDLL__logb(double x)
|
|
{
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return logb(x);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _lrotl (CRTDLL.175)
|
|
*/
|
|
DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
|
|
{
|
|
shift &= 31;
|
|
return (x << shift) | (x >> (32-shift));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _lrotr (CRTDLL.176)
|
|
*/
|
|
DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
|
|
{
|
|
shift &= 0x1f;
|
|
return (x >> shift) | (x << (32-shift));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _rotr (CRTDLL.258)
|
|
*/
|
|
DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
|
|
{
|
|
shift &= 0x1f;
|
|
return (x >> shift) | (x << (32-shift));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _scalb (CRTDLL.259)
|
|
*
|
|
* Return x*2^y.
|
|
*/
|
|
double __cdecl CRTDLL__scalb(double x, LONG y)
|
|
{
|
|
/* Note - Can't forward directly as libc expects y as double */
|
|
double y2 = (double)y;
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
return scalb( x, y2 );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* longjmp (CRTDLL.426)
|
|
*/
|
|
VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
|
|
{
|
|
FIXME("CRTDLL_longjmp semistup, expect crash\n");
|
|
longjmp(env, val);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _isctype (CRTDLL.138)
|
|
*/
|
|
INT __cdecl CRTDLL__isctype(INT c, UINT type)
|
|
{
|
|
if (c >= -1 && c <= 255)
|
|
return CRTDLL_pctype_dll[c] & type;
|
|
|
|
if (CRTDLL__mb_cur_max_dll != 1 && c > 0)
|
|
{
|
|
/* FIXME: Is there a faster way to do this? */
|
|
WORD typeInfo;
|
|
char convert[3], *pconv = convert;
|
|
|
|
if (CRTDLL_pctype_dll[(UINT)c >> 8] & CRTDLL_LEADBYTE)
|
|
*pconv++ = (UINT)c >> 8;
|
|
*pconv++ = c & 0xff;
|
|
*pconv = 0;
|
|
/* FIXME: Use ctype LCID */
|
|
if (GetStringTypeExA(__CRTDLL_current_lc_all_lcid, CT_CTYPE1,
|
|
convert, convert[1] ? 2 : 1, &typeInfo))
|
|
return typeInfo & type;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
|
|
static void fln_fix(char *path)
|
|
{
|
|
int dir_flag = 0, root_flag = 0;
|
|
char *r, *p, *q, *s;
|
|
|
|
/* Skip drive */
|
|
if (NULL == (r = strrchr(path, ':')))
|
|
r = path;
|
|
else
|
|
++r;
|
|
|
|
/* Ignore leading slashes */
|
|
while ('\\' == *r)
|
|
if ('\\' == r[1])
|
|
strcpy(r, &r[1]);
|
|
else
|
|
{
|
|
root_flag = 1;
|
|
++r;
|
|
}
|
|
|
|
p = r; /* Change "\\" to "\" */
|
|
while (NULL != (p = strchr(p, '\\')))
|
|
if ('\\' == p[1])
|
|
strcpy(p, &p[1]);
|
|
else
|
|
++p;
|
|
|
|
while ('.' == *r) /* Scrunch leading ".\" */
|
|
{
|
|
if ('.' == r[1])
|
|
{
|
|
/* Ignore leading ".." */
|
|
for (p = (r += 2); *p && (*p != '\\'); ++p)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
for (p = r + 1 ;*p && (*p != '\\'); ++p)
|
|
;
|
|
}
|
|
strcpy(r, p + ((*p) ? 1 : 0));
|
|
}
|
|
|
|
while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
|
|
{
|
|
dir_flag = 1;
|
|
path[strlen(path)-1] = '\0';
|
|
}
|
|
|
|
s = r;
|
|
|
|
/* Look for "\." in path */
|
|
|
|
while (NULL != (p = strstr(s, "\\.")))
|
|
{
|
|
if ('.' == p[2])
|
|
{
|
|
/* Execute this section if ".." found */
|
|
q = p - 1;
|
|
while (q > r) /* Backup one level */
|
|
{
|
|
if (*q == '\\')
|
|
break;
|
|
--q;
|
|
}
|
|
if (q > r)
|
|
{
|
|
strcpy(q, p + 3);
|
|
s = q;
|
|
}
|
|
else if ('.' != *q)
|
|
{
|
|
strcpy(q + ((*q == '\\') ? 1 : 0),
|
|
p + 3 + ((*(p + 3)) ? 1 : 0));
|
|
s = q;
|
|
}
|
|
else s = ++p;
|
|
}
|
|
else
|
|
{
|
|
/* Execute this section if "." found */
|
|
q = p + 2;
|
|
for ( ;*q && (*q != '\\'); ++q)
|
|
;
|
|
strcpy (p, q);
|
|
}
|
|
}
|
|
|
|
if (root_flag) /* Embedded ".." could have bubbled up to root */
|
|
{
|
|
for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
|
|
;
|
|
if (r != p)
|
|
strcpy(r, p);
|
|
}
|
|
|
|
if (dir_flag)
|
|
strcat(path, "\\");
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _fullpath
|
|
*
|
|
* Convert a partial path into a complete, normalised path.
|
|
*/
|
|
LPSTR __cdecl CRTDLL__fullpath(LPSTR absPath, LPCSTR relPath, INT size)
|
|
{
|
|
char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
|
|
char res[MAX_PATH];
|
|
size_t len;
|
|
|
|
res[0] = '\0';
|
|
|
|
if (!relPath || !*relPath)
|
|
return CRTDLL__getcwd(absPath, size);
|
|
|
|
if (size < 4)
|
|
{
|
|
CRTDLL_errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
|
|
TRACE(":resolving relative path '%s'\n",relPath);
|
|
|
|
CRTDLL__splitpath(relPath, drive, dir, file, ext);
|
|
|
|
/* Get Directory and drive into 'res' */
|
|
if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
|
|
{
|
|
/* Relative or no directory given */
|
|
CRTDLL__getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
|
|
strcat(res,"\\");
|
|
if (dir[0])
|
|
strcat(res,dir);
|
|
if (drive[0])
|
|
res[0] = drive[0]; /* If given a drive, preserve the letter case */
|
|
}
|
|
else
|
|
{
|
|
strcpy(res,drive);
|
|
strcat(res,dir);
|
|
}
|
|
|
|
strcat(res,"\\");
|
|
strcat(res, file);
|
|
strcat(res, ext);
|
|
fln_fix(res);
|
|
|
|
len = strlen(res);
|
|
if (len >= MAX_PATH || len >= (size_t)size)
|
|
return NULL; /* FIXME: errno? */
|
|
|
|
if (!absPath)
|
|
return CRTDLL__strdup(res);
|
|
strcpy(absPath,res);
|
|
return absPath;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _splitpath (CRTDLL.279)
|
|
*
|
|
* Split a path string into components.
|
|
*
|
|
* PARAMETERS
|
|
* inpath [in] Path to split
|
|
* drive [out] "x:" or ""
|
|
* directory [out] "\dir", "\dir\", "/dir", "/dir/", "./" etc
|
|
* filename [out] filename, without dot or slashes
|
|
* extension [out] ".ext" or ""
|
|
*/
|
|
VOID __cdecl CRTDLL__splitpath(LPCSTR inpath, LPSTR drv, LPSTR dir,
|
|
LPSTR fname, LPSTR ext )
|
|
{
|
|
/* Modified PD code from 'snippets' collection. */
|
|
char ch, *ptr, *p;
|
|
char pathbuff[MAX_PATH],*path=pathbuff;
|
|
|
|
TRACE(":splitting path '%s'\n",path);
|
|
strcpy(pathbuff, inpath);
|
|
|
|
/* convert slashes to backslashes for searching */
|
|
for (ptr = (char*)path; *ptr; ++ptr)
|
|
if ('/' == *ptr)
|
|
*ptr = '\\';
|
|
|
|
/* look for drive spec */
|
|
if ('\0' != (ptr = strchr(path, ':')))
|
|
{
|
|
++ptr;
|
|
if (drv)
|
|
{
|
|
strncpy(drv, path, ptr - path);
|
|
drv[ptr - path] = '\0';
|
|
}
|
|
path = ptr;
|
|
}
|
|
else if (drv)
|
|
*drv = '\0';
|
|
|
|
/* find rightmost backslash or leftmost colon */
|
|
if (NULL == (ptr = strrchr(path, '\\')))
|
|
ptr = (strchr(path, ':'));
|
|
|
|
if (!ptr)
|
|
{
|
|
ptr = (char *)path; /* no path */
|
|
if (dir)
|
|
*dir = '\0';
|
|
}
|
|
else
|
|
{
|
|
++ptr; /* skip the delimiter */
|
|
if (dir)
|
|
{
|
|
ch = *ptr;
|
|
*ptr = '\0';
|
|
strcpy(dir, path);
|
|
*ptr = ch;
|
|
}
|
|
}
|
|
|
|
if (NULL == (p = strrchr(ptr, '.')))
|
|
{
|
|
if (fname)
|
|
strcpy(fname, ptr);
|
|
if (ext)
|
|
*ext = '\0';
|
|
}
|
|
else
|
|
{
|
|
*p = '\0';
|
|
if (fname)
|
|
strcpy(fname, ptr);
|
|
*p = '.';
|
|
if (ext)
|
|
strcpy(ext, p);
|
|
}
|
|
|
|
/* Fix pathological case - Win returns ':' as part of the
|
|
* directory when no drive letter is given.
|
|
*/
|
|
if (drv && drv[0] == ':')
|
|
{
|
|
*drv = '\0';
|
|
if (dir)
|
|
{
|
|
pathbuff[0] = ':';
|
|
pathbuff[1] = '\0';
|
|
strcat(pathbuff,dir);
|
|
strcpy(dir,pathbuff);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _matherr (CRTDLL.181)
|
|
*
|
|
* Default handler for math errors.
|
|
*/
|
|
INT __cdecl CRTDLL__matherr(struct _exception *e)
|
|
{
|
|
/* FIXME: Supposedly this can be user overridden, but
|
|
* currently it will never be called anyway. User will
|
|
* need to use .spec ignore directive to override.
|
|
*/
|
|
FIXME(":Unhandled math error!\n");
|
|
return e == NULL ? 0 : 0;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _makepath (CRTDLL.182)
|
|
*/
|
|
VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
|
|
LPCSTR directory, LPCSTR filename,
|
|
LPCSTR extension )
|
|
{
|
|
char ch;
|
|
TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
|
|
filename, extension);
|
|
|
|
if ( !path )
|
|
return;
|
|
|
|
path[0] = 0;
|
|
if (drive && drive[0])
|
|
{
|
|
path[0] = drive[0];
|
|
path[1] = ':';
|
|
path[2] = 0;
|
|
}
|
|
if (directory && directory[0])
|
|
{
|
|
strcat(path, directory);
|
|
ch = path[strlen(path)-1];
|
|
if (ch != '/' && ch != '\\')
|
|
strcat(path,"\\");
|
|
}
|
|
if (filename && filename[0])
|
|
{
|
|
strcat(path, filename);
|
|
if (extension && extension[0])
|
|
{
|
|
if ( extension[0] != '.' ) {
|
|
strcat(path,".");
|
|
}
|
|
strcat(path,extension);
|
|
}
|
|
}
|
|
|
|
TRACE("CRTDLL__makepath returns %s\n",path);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _errno (CRTDLL.52)
|
|
* Return the address of the CRT errno (Not the libc errno).
|
|
*
|
|
* BUGS
|
|
* Not MT safe.
|
|
*/
|
|
LPINT __cdecl CRTDLL__errno( VOID )
|
|
{
|
|
return &CRTDLL_errno;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* __doserrno (CRTDLL.26)
|
|
*
|
|
* Return the address of the DOS errno (holding the last OS error).
|
|
*
|
|
* BUGS
|
|
* Not MT safe.
|
|
*/
|
|
LPINT __cdecl CRTDLL___doserrno( VOID )
|
|
{
|
|
return &CRTDLL_doserrno;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* _statusfp (CRTDLL.279)
|
|
*
|
|
* Return the status of the FP control word.
|
|
*/
|
|
UINT __cdecl CRTDLL__statusfp( VOID )
|
|
{
|
|
UINT retVal = 0;
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
UINT fpword;
|
|
|
|
__asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
|
|
if (fpword & 0x1) retVal |= _SW_INVALID;
|
|
if (fpword & 0x2) retVal |= _SW_DENORMAL;
|
|
if (fpword & 0x4) retVal |= _SW_ZERODIVIDE;
|
|
if (fpword & 0x8) retVal |= _SW_OVERFLOW;
|
|
if (fpword & 0x10) retVal |= _SW_UNDERFLOW;
|
|
if (fpword & 0x20) retVal |= _SW_INEXACT;
|
|
#else
|
|
FIXME(":Not implemented!\n");
|
|
#endif
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* _strerror (CRTDLL.284)
|
|
*
|
|
* Return a formatted system error message.
|
|
*
|
|
* NOTES
|
|
* The caller does not own the string returned.
|
|
*/
|
|
extern int sprintf(char *str, const char *format, ...);
|
|
|
|
LPSTR __cdecl CRTDLL__strerror (LPCSTR err)
|
|
{
|
|
static char strerrbuff[256];
|
|
sprintf(strerrbuff,"%s: %s\n",err,CRTDLL_strerror(CRTDLL_errno));
|
|
return strerrbuff;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* perror (CRTDLL.435)
|
|
*
|
|
* Print a formatted system error message to stderr.
|
|
*/
|
|
VOID __cdecl CRTDLL_perror (LPCSTR err)
|
|
{
|
|
char *err_str = CRTDLL_strerror(CRTDLL_errno);
|
|
CRTDLL_fprintf(CRTDLL_stderr,"%s: %s\n",err,err_str);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* strerror (CRTDLL.465)
|
|
*
|
|
* Return the text of an error.
|
|
*
|
|
* NOTES
|
|
* The caller does not own the string returned.
|
|
*/
|
|
extern char *strerror(int errnum);
|
|
|
|
LPSTR __cdecl CRTDLL_strerror (INT err)
|
|
{
|
|
return strerror(err);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* signal (CRTDLL.455)
|
|
*/
|
|
LPVOID __cdecl CRTDLL_signal(INT sig, sig_handler_type ptr)
|
|
{
|
|
FIXME("(%d %p):stub.\n", sig, ptr);
|
|
return (void*)-1;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _sleep (CRTDLL.267)
|
|
*/
|
|
VOID __cdecl CRTDLL__sleep(ULONG timeout)
|
|
{
|
|
TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
|
|
Sleep((timeout)?timeout:1);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* getenv (CRTDLL.437)
|
|
*/
|
|
LPSTR __cdecl CRTDLL_getenv(LPCSTR name)
|
|
{
|
|
LPSTR environ = GetEnvironmentStringsA();
|
|
LPSTR pp,pos = NULL;
|
|
unsigned int length;
|
|
|
|
for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
|
|
{
|
|
pos =strchr(pp,'=');
|
|
if (pos)
|
|
length = pos -pp;
|
|
else
|
|
length = strlen(pp);
|
|
if (!strncmp(pp,name,length)) break;
|
|
}
|
|
if ((pp)&& (pos))
|
|
{
|
|
pp = pos+1;
|
|
TRACE("got %s\n",pp);
|
|
}
|
|
FreeEnvironmentStringsA( environ );
|
|
return pp;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isalnum (CRTDLL.442)
|
|
*/
|
|
INT __cdecl CRTDLL_isalnum(INT c)
|
|
{
|
|
return CRTDLL__isctype( c,CRTDLL_ALPHA | CRTDLL_DIGIT );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isalpha (CRTDLL.443)
|
|
*/
|
|
INT __cdecl CRTDLL_isalpha(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_ALPHA );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* iscntrl (CRTDLL.444)
|
|
*/
|
|
INT __cdecl CRTDLL_iscntrl(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_CONTROL );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isdigit (CRTDLL.445)
|
|
*/
|
|
INT __cdecl CRTDLL_isdigit(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_DIGIT );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isgraph (CRTDLL.446)
|
|
*/
|
|
INT __cdecl CRTDLL_isgraph(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT | CRTDLL_PUNCT );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isleadbyte (CRTDLL.447)
|
|
*/
|
|
INT __cdecl CRTDLL_isleadbyte(UCHAR c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_LEADBYTE );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* islower (CRTDLL.447)
|
|
*/
|
|
INT __cdecl CRTDLL_islower(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_LOWER );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isprint (CRTDLL.448)
|
|
*/
|
|
INT __cdecl CRTDLL_isprint(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT |
|
|
CRTDLL_BLANK | CRTDLL_PUNCT );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* ispunct (CRTDLL.449)
|
|
*/
|
|
INT __cdecl CRTDLL_ispunct(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_PUNCT );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isspace (CRTDLL.450)
|
|
*/
|
|
INT __cdecl CRTDLL_isspace(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_SPACE );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isupper (CRTDLL.451)
|
|
*/
|
|
INT __cdecl CRTDLL_isupper(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_UPPER );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* isxdigit (CRTDLL.452)
|
|
*/
|
|
INT __cdecl CRTDLL_isxdigit(INT c)
|
|
{
|
|
return CRTDLL__isctype( c, CRTDLL_HEX );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* ldexp (CRTDLL.454)
|
|
*/
|
|
double __cdecl CRTDLL_ldexp(double x, LONG y)
|
|
{
|
|
double z = ldexp(x,y);
|
|
|
|
if (!finite(z))
|
|
CRTDLL_errno = ERANGE;
|
|
else if (z == 0 && signbit(z))
|
|
z = 0.0; /* Convert -0 -> +0 */
|
|
return z;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _except_handler2 (CRTDLL.78)
|
|
*/
|
|
INT __cdecl CRTDLL__except_handler2 (
|
|
PEXCEPTION_RECORD rec,
|
|
PEXCEPTION_FRAME frame,
|
|
PCONTEXT context,
|
|
PEXCEPTION_FRAME *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;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* __isascii (CRTDLL.028)
|
|
*
|
|
*/
|
|
INT __cdecl CRTDLL___isascii(INT c)
|
|
{
|
|
return isascii((unsigned)c);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* __toascii (CRTDLL.035)
|
|
*
|
|
*/
|
|
INT __cdecl CRTDLL___toascii(INT c)
|
|
{
|
|
return (unsigned)c & 0x7f;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* iswascii (CRTDLL.404)
|
|
*
|
|
*/
|
|
INT __cdecl CRTDLL_iswascii(LONG c)
|
|
{
|
|
return ((unsigned)c < 0x80);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* __iscsym (CRTDLL.029)
|
|
*
|
|
* Is a character valid in a C identifier (a-Z,0-9,_).
|
|
*
|
|
* PARAMS
|
|
* c [I]: Character to check
|
|
*
|
|
* RETURNS
|
|
* Non zero if c is valid as t a C identifier.
|
|
*/
|
|
INT __cdecl CRTDLL___iscsym(UCHAR c)
|
|
{
|
|
return (c < 127 && (isalnum(c) || c == '_'));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* __iscsymf (CRTDLL.030)
|
|
*
|
|
* Is a character valid as the first letter in a C identifier (a-Z,_).
|
|
*
|
|
* PARAMS
|
|
* c [in] Character to check
|
|
*
|
|
* RETURNS
|
|
* Non zero if c is valid as the first letter in a C identifier.
|
|
*/
|
|
INT __cdecl CRTDLL___iscsymf(UCHAR c)
|
|
{
|
|
return (c < 127 && (isalpha(c) || c == '_'));
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _lfind (CRTDLL.170)
|
|
*
|
|
* Perform a linear search of an array for an element.
|
|
*/
|
|
LPVOID __cdecl CRTDLL__lfind(LPCVOID match, LPCVOID start, LPUINT array_size,
|
|
UINT elem_size, comp_func cf)
|
|
{
|
|
UINT size = *array_size;
|
|
if (size)
|
|
do
|
|
{
|
|
if (cf(match, start) == 0)
|
|
return (LPVOID)start; /* found */
|
|
start += elem_size;
|
|
} while (--size);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _loaddll (CRTDLL.171)
|
|
*
|
|
* Get a handle to a DLL in memory. The DLL is loaded if it is not already.
|
|
*
|
|
* PARAMS
|
|
* dll [in] Name of DLL to load.
|
|
*
|
|
* RETURNS
|
|
* Success: A handle to the loaded DLL.
|
|
*
|
|
* Failure: FIXME.
|
|
*/
|
|
INT __cdecl CRTDLL__loaddll(LPSTR dllname)
|
|
{
|
|
return LoadLibraryA(dllname);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _unloaddll (CRTDLL.313)
|
|
*
|
|
* Free reference to a DLL handle from loaddll().
|
|
*
|
|
* PARAMS
|
|
* dll [in] Handle to free.
|
|
*
|
|
* RETURNS
|
|
* Success: 0.
|
|
*
|
|
* Failure: Error number.
|
|
*/
|
|
INT __cdecl CRTDLL__unloaddll(HANDLE dll)
|
|
{
|
|
INT err;
|
|
if (FreeLibrary(dll))
|
|
return 0;
|
|
err = GetLastError();
|
|
__CRTDLL__set_errno(err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _lsearch (CRTDLL.177)
|
|
*
|
|
* Linear search of an array of elements. Adds the item to the array if
|
|
* not found.
|
|
*
|
|
* PARAMS
|
|
* match [in] Pointer to element to match
|
|
* start [in] Pointer to start of search memory
|
|
* array_size [in] Length of search array (element count)
|
|
* elem_size [in] Size of each element in memory
|
|
* cf [in] Pointer to comparison function (like qsort()).
|
|
*
|
|
* RETURNS
|
|
* Pointer to the location where element was found or added.
|
|
*/
|
|
LPVOID __cdecl CRTDLL__lsearch(LPVOID match,LPVOID start, LPUINT array_size,
|
|
UINT elem_size, comp_func cf)
|
|
{
|
|
UINT size = *array_size;
|
|
if (size)
|
|
do
|
|
{
|
|
if (cf(match, start) == 0)
|
|
return start; /* found */
|
|
start += elem_size;
|
|
} while (--size);
|
|
|
|
/* not found, add to end */
|
|
memcpy(start, match, elem_size);
|
|
array_size[0]++;
|
|
return start;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _itow (CRTDLL.164)
|
|
*
|
|
* Convert an integer to a wide char string.
|
|
*/
|
|
|
|
extern LPSTR __cdecl _itoa( long , LPSTR , INT); /* ntdll */
|
|
|
|
/********************************************************************/
|
|
|
|
WCHAR* __cdecl CRTDLL__itow(INT value,WCHAR* out,INT base)
|
|
{
|
|
char buff[64]; /* FIXME: Whats the maximum buffer size for INT_MAX? */
|
|
|
|
_itoa(value, buff, base);
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
|
|
return out;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _ltow (CRTDLL.??)
|
|
*
|
|
* Convert a long to a wide char string.
|
|
*/
|
|
|
|
extern LPSTR __cdecl _ltoa( long , LPSTR , INT); /* ntdll */
|
|
|
|
/********************************************************************/
|
|
|
|
WCHAR* __cdecl CRTDLL__ltow(LONG value,WCHAR* out,INT base)
|
|
{
|
|
char buff[64]; /* FIXME: Whats the maximum buffer size for LONG_MAX? */
|
|
|
|
_ltoa(value, buff, base);
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
|
|
return out;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _ultow (CRTDLL.??)
|
|
*
|
|
* Convert an unsigned long to a wide char string.
|
|
*/
|
|
|
|
extern LPSTR __cdecl _ultoa( long , LPSTR , INT); /* ntdll */
|
|
|
|
/********************************************************************/
|
|
|
|
WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base)
|
|
{
|
|
char buff[64]; /* FIXME: Whats the maximum buffer size for ULONG_MAX? */
|
|
|
|
_ultoa(value, buff, base);
|
|
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
|
|
return out;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _toupper (CRTDLL.489)
|
|
*/
|
|
CHAR __cdecl CRTDLL__toupper(CHAR c)
|
|
{
|
|
return toupper(c);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _tolower (CRTDLL.490)
|
|
*/
|
|
CHAR __cdecl CRTDLL__tolower(CHAR c)
|
|
{
|
|
return tolower(c);
|
|
}
|
|
|
|
|
|
/* FP functions */
|
|
|
|
/*********************************************************************
|
|
* _cabs (CRTDLL.048)
|
|
*
|
|
* Return the absolue value of a complex number.
|
|
*
|
|
* PARAMS
|
|
* c [in] Structure containing real and imaginary parts of complex number.
|
|
*
|
|
* RETURNS
|
|
* Absolute value of complex number (always a positive real number).
|
|
*/
|
|
double __cdecl CRTDLL__cabs(struct complex c)
|
|
{
|
|
return sqrt(c.real * c.real + c.imaginary * c.imaginary);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _chgsign (CRTDLL.053)
|
|
*
|
|
* Change the sign of an IEEE double.
|
|
*
|
|
* PARAMS
|
|
* d [in] Number to invert.
|
|
*
|
|
* RETURNS
|
|
* Number with sign inverted.
|
|
*/
|
|
double __cdecl CRTDLL__chgsign(double d)
|
|
{
|
|
/* FIXME: +-infinity,Nan not tested */
|
|
return -d;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _control87 (CRTDLL.060)
|
|
*
|
|
* X86 implementation of _controlfp.
|
|
*
|
|
*/
|
|
UINT __cdecl CRTDLL__control87(UINT newVal, UINT mask)
|
|
{
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
UINT fpword, flags = 0;
|
|
|
|
/* Get fp control word */
|
|
__asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
|
|
|
|
/* Convert into mask constants */
|
|
if (fpword & 0x1) flags |= _EM_INVALID;
|
|
if (fpword & 0x2) flags |= _EM_DENORMAL;
|
|
if (fpword & 0x4) flags |= _EM_ZERODIVIDE;
|
|
if (fpword & 0x8) flags |= _EM_OVERFLOW;
|
|
if (fpword & 0x10) flags |= _EM_UNDERFLOW;
|
|
if (fpword & 0x20) flags |= _EM_INEXACT;
|
|
switch(fpword & 0xC00) {
|
|
case 0xC00: flags |= _RC_UP|_RC_DOWN; break;
|
|
case 0x800: flags |= _RC_UP; break;
|
|
case 0x400: flags |= _RC_DOWN; break;
|
|
}
|
|
switch(fpword & 0x300) {
|
|
case 0x0: flags |= _PC_24; break;
|
|
case 0x200: flags |= _PC_53; break;
|
|
case 0x300: flags |= _PC_64; break;
|
|
}
|
|
if (fpword & 0x1000) flags |= _IC_AFFINE;
|
|
|
|
/* Mask with parameters */
|
|
flags = (flags & ~mask) | (newVal & mask);
|
|
|
|
/* Convert (masked) value back to fp word */
|
|
fpword = 0;
|
|
if (flags & _EM_INVALID) fpword |= 0x1;
|
|
if (flags & _EM_DENORMAL) fpword |= 0x2;
|
|
if (flags & _EM_ZERODIVIDE) fpword |= 0x4;
|
|
if (flags & _EM_OVERFLOW) fpword |= 0x8;
|
|
if (flags & _EM_UNDERFLOW) fpword |= 0x10;
|
|
if (flags & _EM_INEXACT) fpword |= 0x20;
|
|
switch(flags & (_RC_UP | _RC_DOWN)) {
|
|
case _RC_UP|_RC_DOWN: fpword |= 0xC00; break;
|
|
case _RC_UP: fpword |= 0x800; break;
|
|
case _RC_DOWN: fpword |= 0x400; break;
|
|
}
|
|
switch (flags & (_PC_24 | _PC_53)) {
|
|
case _PC_64: fpword |= 0x300; break;
|
|
case _PC_53: fpword |= 0x200; break;
|
|
case _PC_24: fpword |= 0x0; break;
|
|
}
|
|
if (!(flags & _IC_AFFINE)) fpword |= 0x1000;
|
|
|
|
/* Put fp control word */
|
|
__asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
|
|
return fpword;
|
|
#else
|
|
return CRTDLL__controlfp( newVal, mask );
|
|
#endif
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _controlfp (CRTDLL.061)
|
|
*
|
|
* Set the state of the floating point unit.
|
|
*/
|
|
UINT __cdecl CRTDLL__controlfp( UINT newVal, UINT mask)
|
|
{
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
return CRTDLL__control87( newVal, mask );
|
|
#else
|
|
FIXME(":Not Implemented!\n");
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _copysign (CRTDLL.062)
|
|
*
|
|
* Return the number x with the sign of y.
|
|
*/
|
|
double __cdecl CRTDLL__copysign(double x, double y)
|
|
{
|
|
/* FIXME: Behaviour for Nan/Inf etc? */
|
|
if (y < 0.0)
|
|
return x < 0.0 ? x : -x;
|
|
|
|
return x < 0.0 ? -x : x;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _finite (CRTDLL.101)
|
|
*
|
|
* Determine if an IEEE double is finite (i.e. not +/- Infinity).
|
|
*
|
|
* PARAMS
|
|
* d [in] Number to check.
|
|
*
|
|
* RETURNS
|
|
* Non zero if number is finite.
|
|
*/
|
|
INT __cdecl CRTDLL__finite(double d)
|
|
{
|
|
return (finite(d)?1:0); /* See comment for CRTDLL__isnan() */
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _fpreset (CRTDLL.107)
|
|
*
|
|
* Reset the state of the floating point processor.
|
|
*/
|
|
VOID __cdecl CRTDLL__fpreset(void)
|
|
{
|
|
#if defined(__GNUC__) && defined(__i386__)
|
|
__asm__ __volatile__( "fninit" );
|
|
#else
|
|
FIXME(":Not Implemented!\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _isnan (CRTDLL.164)
|
|
*
|
|
* Determine if an IEEE double is unrepresentable (NaN).
|
|
*
|
|
* PARAMS
|
|
* d [in] Number to check.
|
|
*
|
|
* RETURNS
|
|
* Non zero if number is NaN.
|
|
*/
|
|
INT __cdecl CRTDLL__isnan(double d)
|
|
{
|
|
/* some implementations return -1 for true(glibc), crtdll returns 1.
|
|
* Do the same, as the result may be used in calculations.
|
|
*/
|
|
return isnan(d)?1:0;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _purecall (CRTDLL.249)
|
|
*
|
|
* Abort program after pure virtual function call.
|
|
*/
|
|
VOID __cdecl CRTDLL__purecall(VOID)
|
|
{
|
|
CRTDLL__amsg_exit( 25 );
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* div (CRTDLL.358)
|
|
*
|
|
* Return the quotient and remainder of long integer division.
|
|
*
|
|
* VERSION
|
|
* [i386] Windows binary compatible - returns the struct in eax/edx.
|
|
*/
|
|
#ifdef __i386__
|
|
LONGLONG __cdecl CRTDLL_div(INT x, INT y)
|
|
{
|
|
LONGLONG retVal;
|
|
div_t dt = div(x,y);
|
|
retVal = ((LONGLONG)dt.rem << 32) | dt.quot;
|
|
return retVal;
|
|
}
|
|
#endif /* !defined(__i386__) */
|
|
|
|
|
|
/*********************************************************************
|
|
* div (CRTDLL.358)
|
|
*
|
|
* Return the quotient and remainder of long integer division.
|
|
*
|
|
* VERSION
|
|
* [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
|
|
*/
|
|
#ifndef __i386__
|
|
div_t __cdecl CRTDLL_div(INT x, INT y)
|
|
{
|
|
return div(x,y);
|
|
}
|
|
#endif /* !defined(__i386__) */
|
|
|
|
|
|
/*********************************************************************
|
|
* ldiv (CRTDLL.249)
|
|
*
|
|
* Return the quotient and remainder of long integer division.
|
|
* VERSION
|
|
* [i386] Windows binary compatible - returns the struct in eax/edx.
|
|
*/
|
|
#ifdef __i386__
|
|
ULONGLONG __cdecl CRTDLL_ldiv(LONG x, LONG y)
|
|
{
|
|
ULONGLONG retVal;
|
|
ldiv_t ldt = ldiv(x,y);
|
|
retVal = ((ULONGLONG)ldt.rem << 32) | (ULONG)ldt.quot;
|
|
return retVal;
|
|
}
|
|
#endif /* defined(__i386__) */
|
|
|
|
|
|
/*********************************************************************
|
|
* ldiv (CRTDLL.249)
|
|
*
|
|
* Return the quotient and remainder of long integer division.
|
|
*
|
|
* VERSION
|
|
* [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
|
|
*/
|
|
#ifndef __i386__
|
|
ldiv_t __cdecl CRTDLL_ldiv(LONG x, LONG y)
|
|
{
|
|
return ldiv(x,y);
|
|
}
|
|
#endif /* !defined(__i386__) */
|
|
|
|
|
|
/*********************************************************************
|
|
* _y0 (CRTDLL.332)
|
|
*
|
|
*/
|
|
double __cdecl CRTDLL__y0(double x)
|
|
{
|
|
double retVal;
|
|
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
retVal = y0(x);
|
|
if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
|
|
{
|
|
CRTDLL_errno = EDOM;
|
|
retVal = sqrt(-1);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _y1 (CRTDLL.333)
|
|
*
|
|
*/
|
|
double __cdecl CRTDLL__y1(double x)
|
|
{
|
|
double retVal;
|
|
|
|
if (!finite(x)) CRTDLL_errno = EDOM;
|
|
retVal = y1(x);
|
|
if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
|
|
{
|
|
CRTDLL_errno = EDOM;
|
|
retVal = sqrt(-1);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _yn (CRTDLL.334)
|
|
*
|
|
*/
|
|
double __cdecl CRTDLL__yn(INT x, double y)
|
|
{
|
|
double retVal;
|
|
|
|
if (!finite(y)) CRTDLL_errno = EDOM;
|
|
retVal = yn(x,y);
|
|
if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
|
|
{
|
|
CRTDLL_errno = EDOM;
|
|
retVal = sqrt(-1);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* _nextafter (CRTDLL.235)
|
|
*
|
|
*/
|
|
double __cdecl CRTDLL__nextafter(double x, double y)
|
|
{
|
|
double retVal;
|
|
if (!finite(x) || !finite(y)) CRTDLL_errno = EDOM;
|
|
retVal = nextafter(x,y);
|
|
return retVal;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* _searchenv (CRTDLL.260)
|
|
*
|
|
* Search CWD and each directory of an environment variable for
|
|
* location of a file.
|
|
*/
|
|
VOID __cdecl CRTDLL__searchenv(LPCSTR file, LPCSTR env, LPSTR buff)
|
|
{
|
|
LPSTR envVal, penv;
|
|
char curPath[MAX_PATH];
|
|
|
|
*buff = '\0';
|
|
|
|
/* Try CWD first */
|
|
if (GetFileAttributesA( file ) != 0xFFFFFFFF)
|
|
{
|
|
GetFullPathNameA( file, MAX_PATH, buff, NULL );
|
|
/* Sigh. This error is *always* set, regardless of sucess */
|
|
__CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
|
|
return;
|
|
}
|
|
|
|
/* Search given environment variable */
|
|
envVal = CRTDLL_getenv(env);
|
|
if (!envVal)
|
|
{
|
|
__CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
|
|
return;
|
|
}
|
|
|
|
penv = envVal;
|
|
TRACE(":searching for %s in paths %s\n", file, envVal);
|
|
|
|
do
|
|
{
|
|
LPSTR end = penv;
|
|
|
|
while(*end && *end != ';') end++; /* Find end of next path */
|
|
if (penv == end || !*penv)
|
|
{
|
|
__CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
|
|
return;
|
|
}
|
|
strncpy(curPath, penv, end - penv);
|
|
if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
|
|
{
|
|
curPath[end - penv] = '\\';
|
|
curPath[end - penv + 1] = '\0';
|
|
}
|
|
else
|
|
curPath[end - penv] = '\0';
|
|
|
|
strcat(curPath, file);
|
|
TRACE("Checking for file %s\n", curPath);
|
|
if (GetFileAttributesA( curPath ) != 0xFFFFFFFF)
|
|
{
|
|
strcpy(buff, curPath);
|
|
__CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
|
|
return; /* Found */
|
|
}
|
|
penv = *end ? end + 1 : end;
|
|
} while(1);
|
|
}
|
|
|