Sweden-Number/dlls/crtdll/crtdll_main.c

1053 lines
26 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 "crtdll.h"
#include <ctype.h>
#define __USE_ISOC9X 1 /* for isfinite */
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include "file.h"
#include "ntddk.h"
#include "wingdi.h"
#include "winuser.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
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 */
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;
const INT CRTDLL__sys_nerr = 43;
/*********************************************************************
* 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();
}
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;
}
}
/*********************************************************************
* _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;
}
/*********************************************************************
* _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;
}
/*********************************************************************
* srand (CRTDLL.460)
*/
void __cdecl CRTDLL_srand(DWORD seed)
{
/* FIXME: should of course be thread? process? local */
srand(seed);
}
/*********************************************************************
* _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)
{
unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08x rot %d ret 0x%08x\n", x,shift,ret);
return ret;
}
/*********************************************************************
* _lrotl (CRTDLL.175)
*/
DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
{
unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08lx rot %d ret 0x%08lx\n", x,shift,ret);
return ret;
}
/*********************************************************************
* _lrotr (CRTDLL.176)
*/
DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
{
/* Depends on "long long" being 64 bit or greater */
unsigned long long arg = x;
unsigned long long ret = (arg << 32 | (x & 0xFFFFFFFF)) >> (shift & 0x1f);
return ret & 0xFFFFFFFF;
}
/*********************************************************************
* _rotr (CRTDLL.258)
*/
DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
{
/* Depends on "long long" being 64 bit or greater */
unsigned long long arg = x;
unsigned long long ret = (arg << 32 | (x & 0xFFFFFFFF)) >> (shift & 0x1f);
return ret & 0xFFFFFFFF;
}
/*********************************************************************
* vswprintf (CRTDLL.501)
*/
INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
{
return wvsprintfW( buffer, spec, args );
}
/*********************************************************************
* longjmp (CRTDLL.426)
*/
VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
{
FIXME("CRTDLL_longjmp semistup, expect crash\n");
longjmp(env, val);
}
/*********************************************************************
* setlocale (CRTDLL.453)
*/
LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
{
LPSTR categorystr;
switch (category) {
case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
default: categorystr = "UNKNOWN?";break;
}
FIXME("(%s,%s),stub!\n",categorystr,locale);
return "C";
}
/*********************************************************************
* _isctype (CRTDLL.138)
*/
BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
{
if ((type & CRTDLL_SPACE) && isspace(x))
return TRUE;
if ((type & CRTDLL_PUNCT) && ispunct(x))
return TRUE;
if ((type & CRTDLL_LOWER) && islower(x))
return TRUE;
if ((type & CRTDLL_UPPER) && isupper(x))
return TRUE;
if ((type & CRTDLL_ALPHA) && isalpha(x))
return TRUE;
if ((type & CRTDLL_DIGIT) && isdigit(x))
return TRUE;
if ((type & CRTDLL_CONTROL) && iscntrl(x))
return TRUE;
/* check CRTDLL_LEADBYTE */
return FALSE;
}
/*********************************************************************
* _fullpath (CRTDLL.114)
*/
LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
{
DOS_FULL_NAME full_name;
if (!buf)
{
size = 256;
if(!(buf = CRTDLL_malloc(size))) return NULL;
}
if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
lstrcpynA(buf,full_name.short_name,size);
TRACE("CRTDLL_fullpath got %s\n",buf);
return buf;
}
/*********************************************************************
* _splitpath (CRTDLL.279)
*/
VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
{
/* drive includes :
directory includes leading and trailing (forward and backward slashes)
filename without dot and slashes
extension with leading dot
*/
char * drivechar,*dirchar,*namechar;
TRACE("CRTDLL__splitpath got %s\n",path);
drivechar = strchr(path,':');
dirchar = strrchr(path,'/');
namechar = strrchr(path,'\\');
dirchar = max(dirchar,namechar);
if (dirchar)
namechar = strrchr(dirchar,'.');
else
namechar = strrchr(path,'.');
if (drive)
{
*drive = 0x00;
if (drivechar)
{
strncat(drive,path,drivechar-path+1);
path = drivechar+1;
}
}
if (directory)
{
*directory = 0x00;
if (dirchar)
{
strncat(directory,path,dirchar-path+1);
path = dirchar+1;
}
}
if (filename)
{
*filename = 0x00;
if (namechar)
{
strncat(filename,path,namechar-path);
if (extension)
{
*extension = 0x00;
strcat(extension,namechar);
}
}
}
TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
}
/*********************************************************************
* _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;
}
/**********************************************************************
* _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);
CRTDLL_free(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;
}
/*********************************************************************
* _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(c);
}
/*********************************************************************
* __toascii (CRTDLL.035)
*
*/
INT __cdecl CRTDLL___toascii(INT c)
{
return 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(LONG c)
{
return (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(LONG c)
{
return (isalpha(c) || c == '_');
}
/*********************************************************************
* _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
* comp_func [in] Pointer to comparason 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)
*
* Unimplemented. Obsolete. Give it up. Use controlfp(), if you must.
*
*/
UINT __cdecl CRTDLL__control87(UINT x, UINT y)
{
/* Will never be supported, no possible targets have an 87/287 FP unit */
WARN(":Ignoring control87 call, dont trust any FP results!\n");
return 0;
}
/*********************************************************************
* _controlfp (CRTDLL.061)
*
* Set the state of the floating point unit.
*
* PARAMS
* FIXME:
*
* RETURNS
* None
*
* BUGS
* Unimplemented.
*/
UINT __cdecl CRTDLL__controlfp( UINT x, UINT y)
{
FIXME(":stub!\n");
return 0;
}
/*********************************************************************
* _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 (isfinite(d)?1:0); /* See comment for CRTDLL__isnan() */
}
/*********************************************************************
* _fpreset (CRTDLL.107)
*
* Reset the state of the floating point processor.
*
* PARAMS
* None.
*
* RETURNS
* None.
*
* BUGS
* Unimplemented.
*/
VOID __cdecl CRTDLL__fpreset(void)
{
FIXME(":stub!\n");
}
/*********************************************************************
* _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;
}
/*********************************************************************
* _j0 (CRTDLL.166)
*/
double CRTDLL__j0(double x)
{
FIXME(":stub!\n");
return x;
}
/*********************************************************************
* _j1 (CRTDLL.167)
*/
double CRTDLL__j1(double x)
{
FIXME(":stub!\n");
return x;
}
/*********************************************************************
* _jn (CRTDLL.168)
*/
double CRTDLL__jn(LONG x,double y)
{
FIXME(":stub!\n");
return x;
}