| /* |
| * 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" |
| |
| #ifdef HAVE_IEEEFP_H |
| #include <ieeefp.h> |
| #endif |
| |
| #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); |
| } |
| |