Commit 0b47b289 authored by Jon Griffiths's avatar Jon Griffiths Committed by Alexandre Julliard

Turn crtdll into forwards to msvcrt.

parent 5f308d3c
...@@ -412,7 +412,7 @@ advapi32/libadvapi32.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ ...@@ -412,7 +412,7 @@ advapi32/libadvapi32.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@
avifil32/libavifil32.@LIBEXT@: libmsvfw32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ avifil32/libavifil32.@LIBEXT@: libmsvfw32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@
comctl32/libcomctl32.@LIBEXT@: libmsvfw32.@LIBEXT@ libwinmm.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ libadvapi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ comctl32/libcomctl32.@LIBEXT@: libmsvfw32.@LIBEXT@ libwinmm.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ libadvapi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@
commdlg/libcomdlg32.@LIBEXT@: libshell32.@LIBEXT@ libshlwapi.@LIBEXT@ libcomctl32.@LIBEXT@ libwinspool.drv.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ commdlg/libcomdlg32.@LIBEXT@: libshell32.@LIBEXT@ libshlwapi.@LIBEXT@ libcomctl32.@LIBEXT@ libwinspool.drv.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@
crtdll/libcrtdll.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ crtdll/libcrtdll.@LIBEXT@: libmsvcrt.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@
dciman32/libdciman32.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ dciman32/libdciman32.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@
ddraw/libddraw.@LIBEXT@: libuser32.@LIBEXT@ libx11drv.@LIBEXT@ libgdi32.@LIBEXT@ libkernel32.@LIBEXT@ ddraw/libddraw.@LIBEXT@: libuser32.@LIBEXT@ libx11drv.@LIBEXT@ libgdi32.@LIBEXT@ libkernel32.@LIBEXT@
dinput/libdinput.@LIBEXT@: libuser32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ dinput/libdinput.@LIBEXT@: libuser32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@
......
...@@ -9,18 +9,7 @@ LDDLLFLAGS = @LDDLLFLAGS@ ...@@ -9,18 +9,7 @@ LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o SYMBOLFILE = $(MODULE).tmp.o
C_SRCS = \ C_SRCS = \
console.c \ crtdll_main.c
crtdll_main.c \
dir.c \
exit.c \
file.c \
locale.c \
mbstring.c \
memory.c \
spawn.c \
string.c \
time.c \
wcstring.c
@MAKE_DLL_RULES@ @MAKE_DLL_RULES@
......
/*
* CRTDLL drive/directory functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
*
* Implementation Notes:
* MT Safe.
*/
#include "crtdll.h"
#include <errno.h>
#include "ntddk.h"
#include <time.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* INTERNAL: Translate find_t to PWIN32_FIND_DATAA */
static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft)
{
DWORD dw;
/* Tested with crtdll.dll Version 2.50.4170 (NT) from win98 SE:
* attrib 0x80 (FILE_ATTRIBUTE_NORMAL)is returned as 0.
*/
if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
ft->attrib = 0;
else
ft->attrib = fd->dwFileAttributes;
RtlTimeToSecondsSince1970( &fd->ftCreationTime, &dw );
ft->time_create = dw;
RtlTimeToSecondsSince1970( &fd->ftLastAccessTime, &dw );
ft->time_access = dw;
RtlTimeToSecondsSince1970( &fd->ftLastWriteTime, &dw );
ft->time_write = dw;
ft->size = fd->nFileSizeLow;
strcpy(ft->name, fd->cFileName);
}
/*********************************************************************
* _chdir (CRTDLL.51)
*
* Change the current directory.
*
* PARAMS
* newdir [in] Directory to change to
*
* RETURNS
* Sucess: 0
*
* Failure: -1
*/
INT __cdecl CRTDLL__chdir(LPCSTR newdir)
{
if (!SetCurrentDirectoryA(newdir))
{
__CRTDLL__set_errno(newdir?GetLastError():0);
return -1;
}
return 0;
}
/*********************************************************************
* _chdrive (CRTDLL.52)
*
* Change the current drive.
*
* PARAMS
* newdrive [in] new drive to change to, A: =1, B: =2, etc
*
* RETURNS
* Sucess: 0
*
* Failure: 1
*/
BOOL __cdecl CRTDLL__chdrive(INT newdrive)
{
char buffer[3] = "A:";
buffer[0] += newdrive - 1;
if (!SetCurrentDirectoryA( buffer ))
{
__CRTDLL__set_errno(GetLastError());
if (newdrive <= 0)
CRTDLL_errno = EACCES;
return -1;
}
return 0;
}
/*********************************************************************
* _findclose (CRTDLL.098)
*
* Free the resources from a search handle created from _findfirst.
*
* PARAMS
* hand [in]: Search handle to close
*
* RETURNS
* Success: 0
*
* Failure: -1
*/
INT __cdecl CRTDLL__findclose(DWORD hand)
{
TRACE(":handle %ld\n",hand);
if (!FindClose((HANDLE)hand))
{
__CRTDLL__set_errno(GetLastError());
return -1;
}
return 0;
}
/*********************************************************************
* _findfirst (CRTDLL.099)
*
* Create and return a search handle for iterating through a file and
* directory list.
*
* PARAMS
* fspec [in] File specification string for search, e.g "C:\*.BAT"
*
* ft [out] A pointer to a find_t structure to populate.
*
* RETURNS
* Success: A handle for the search, suitable for passing to _findnext
* or _findclose. Populates the members of ft with the details
* of the first matching file.
*
* Failure: -1.
*/
DWORD __cdecl CRTDLL__findfirst(LPCSTR fspec, find_t* ft)
{
WIN32_FIND_DATAA find_data;
HANDLE hfind;
hfind = FindFirstFileA(fspec, &find_data);
if (hfind == INVALID_HANDLE_VALUE)
{
__CRTDLL__set_errno(GetLastError());
return -1;
}
__CRTDLL__fttofd(&find_data,ft);
TRACE(":got handle %d\n",hfind);
return hfind;
}
/*********************************************************************
* _findnext (CRTDLL.100)
*
* Return the next matching file/directory from a search hadle.
*
* PARAMS
* hand [in] Search handle from a pervious call to _findfirst
*
* ft [out] A pointer to a find_t structure to populate.
*
* RETURNS
* Success: 0. Populates the members of ft with the details
* of the first matching file
*
* Failure: -1
*/
INT __cdecl CRTDLL__findnext(DWORD hand, find_t * ft)
{
WIN32_FIND_DATAA find_data;
if (!FindNextFileA(hand, &find_data))
{
CRTDLL_errno = ENOENT;
return -1;
}
__CRTDLL__fttofd(&find_data,ft);
return 0;
}
/*********************************************************************
* _getcwd (CRTDLL.120)
*
* Get the current directory.
*
* PARAMS
* buf [out] A buffer to place the current directory name in
*
* size [in] The size of buf.
*
* RETURNS
* Success: buf, or if buf is NULL, an allocated buffer
*
* Failure: NULL
*/
CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size)
{
char dir[_MAX_PATH];
int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
if (dir_len < 1)
return NULL; /* FIXME: Real return value untested */
TRACE(":returning '%s'\n", dir);
if (!buf)
{
if (size < 0)
return CRTDLL__strdup(dir);
return __CRTDLL__strndup(dir,size);
}
if (dir_len >= size)
{
CRTDLL_errno = ERANGE;
return NULL; /* buf too small */
}
strcpy(buf,dir);
return buf;
}
/*********************************************************************
* _getdcwd (CRTDLL.121)
*
* Get the current directory on a drive. A: =1, B: =2, etc.
* Passing drive 0 means the current drive.
*/
CHAR* __cdecl CRTDLL__getdcwd(INT drive, LPSTR buf, INT size)
{
static CHAR* dummy;
TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
if (!drive || drive == CRTDLL__getdrive())
return CRTDLL__getcwd(buf,size); /* current */
else
{
char dir[_MAX_PATH];
char drivespec[4] = {'A', ':', '\\', 0};
int dir_len;
drivespec[0] += drive - 1;
if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
{
CRTDLL_errno = EACCES;
return NULL;
}
dir_len = GetFullPathNameA(drivespec,_MAX_PATH,dir,&dummy);
if (dir_len >= size || dir_len < 1)
{
CRTDLL_errno = ERANGE;
return NULL; /* buf too small */
}
TRACE(":returning '%s'\n", dir);
if (!buf)
return CRTDLL__strdup(dir); /* allocate */
strcpy(buf,dir);
}
return buf;
}
/*********************************************************************
* _getdiskfree (CRTDLL.122)
*
* Get free disk space on given drive or the current drive.
*
*/
UINT __cdecl CRTDLL__getdiskfree(UINT disk, diskfree_t* d)
{
char drivespec[4] = {'@', ':', '\\', 0};
DWORD ret[4];
UINT err;
if (disk > 26)
return ERROR_INVALID_PARAMETER; /* CRTDLL doesn't set errno here */
drivespec[0] += disk; /* make a drive letter */
if (GetDiskFreeSpaceA(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
{
d->cluster_sectors = (unsigned)ret[0];
d->sector_bytes = (unsigned)ret[1];
d->available = (unsigned)ret[2];
d->num_clusters = (unsigned)ret[3];
return 0;
}
err = GetLastError();
__CRTDLL__set_errno(err);
return err;
}
/*********************************************************************
* _getdrive (CRTDLL.124)
*
* Return current drive, A: =1, B: =2, etc
*/
INT __cdecl CRTDLL__getdrive(VOID)
{
char buffer[MAX_PATH];
if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0;
if (buffer[1] != ':') return 0;
return toupper(buffer[0]) - 'A' + 1;
}
/*********************************************************************
* _mkdir (CRTDLL.234)
*
* Create a directory.
*/
INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
{
if (CreateDirectoryA(newdir,NULL))
return 0;
__CRTDLL__set_errno(GetLastError());
return -1;
}
/*********************************************************************
* _rmdir (CRTDLL.255)
*
* Delete a directory
*
*/
INT __cdecl CRTDLL__rmdir(LPSTR dir)
{
if (RemoveDirectoryA(dir))
return 0;
__CRTDLL__set_errno(GetLastError());
return -1;
}
/*
* CRTDLL exit/abort/atexit functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* exit functions differ in whether they perform cleanup
* and whether they return to the caller (really!).
* return do
* Name to caller? cleanup?
* _c_exit Y N
* _cexit Y Y
* _exit N N
* exit N Y
*
* Implementation Notes:
* Not MT Safe - Adding/Executing exit() functions should be locked
* for MT safety.
*
* FIXME:
* Need a better way of printing errors for GUI programs(MsgBox?).
* Is there really a difference between onexit/atexit?
*/
#include "crtdll.h"
#include <errno.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* INTERNAL: Table of registered atexit() functions */
/* FIXME: This should be dynamically allocated */
#define CRTDLL_ATEXIT_TABLE_SIZE 16
static atexit_function atexit_table[CRTDLL_ATEXIT_TABLE_SIZE];
static int atexit_registered = 0; /* Points to free slot */
/* INTERNAL: call atexit functions */
void __CRTDLL__call_atexit(VOID);
void __CRTDLL__call_atexit(VOID)
{
/* Last registered gets executed first */
while (atexit_registered > 0)
{
atexit_registered--;
TRACE(":call function (%p)\n",atexit_table[atexit_registered]);
(*atexit_table[atexit_registered])();
}
}
/*********************************************************************
* __dllonexit (CRTDLL.25)
*/
VOID __cdecl CRTDLL___dllonexit ()
{
FIXME("stub\n");
}
/*********************************************************************
* _abnormal_termination (CRTDLL.36)
*
* Check if execution is processing during an exception.
*/
INT __cdecl CRTDLL__abnormal_termination(VOID)
{
TRACE("(void)\n");
return 0; /* FIME: Can we determine if we are in an exception? */
}
/*********************************************************************
* _amsg_exit (CRTDLL.040)
*
* Print an error message and terminate execution. Returns 255 to the
* host OS.
*/
VOID __cdecl CRTDLL__amsg_exit(INT err)
{
/* FIXME: Should be a popup for msvcrt gui executables, and should have
* text for the error number.
*/
CRTDLL_fprintf(CRTDLL_stderr,"\nruntime error R60%d\n",err);
CRTDLL__exit(255);
}
/*********************************************************************
* _assert (CRTDLL.041)
*
* Print an assertion message and call abort(). Really only present
* for win binaries. Winelib programs would typically use libc's
* version.
*/
VOID __cdecl CRTDLL__assert(LPVOID str, LPVOID file, UINT line)
{
CRTDLL_fprintf(CRTDLL_stderr,"Assertion failed: %s, file %s, line %d\n\n",
(char*)str,(char*)file, line);
CRTDLL_abort();
}
/*********************************************************************
* _c_exit (CRTDLL.047)
*/
VOID __cdecl CRTDLL__c_exit(VOID)
{
/* All cleanup is done on DLL detach; Return to caller */
}
/*********************************************************************
* _cexit (CRTDLL.049)
*/
VOID __cdecl CRTDLL__cexit(VOID)
{
/* All cleanup is done on DLL detach; Return to caller */
}
/*********************************************************************
* _exit (CRTDLL.087)
*/
VOID __cdecl CRTDLL__exit(LONG ret)
{
TRACE(":exit code %ld\n",ret);
CRTDLL__c_exit();
ExitProcess(ret);
}
/*********************************************************************
* _onexit (CRTDLL.236)
*
* Register a function to be called when the process terminates.
*/
atexit_function __cdecl CRTDLL__onexit( atexit_function func)
{
TRACE("registering function (%p)\n",func);
if (func && atexit_registered <= CRTDLL_ATEXIT_TABLE_SIZE - 1)
{
atexit_table[atexit_registered] = (atexit_function)func;
atexit_registered++;
return func; /* successful */
}
ERR(":Too many onexit() functions, or NULL function - not registered!\n");
return NULL;
}
/*********************************************************************
* exit (CRTDLL.359)
*/
void __cdecl CRTDLL_exit(DWORD ret)
{
TRACE(":exit code %ld\n",ret);
__CRTDLL__call_atexit();
CRTDLL__cexit();
ExitProcess(ret);
}
/*********************************************************************
* abort (CRTDLL.335)
*
* Terminate the progam with an abnormal termination message. Returns
* 3 to the host OS.
*/
VOID __cdecl CRTDLL_abort()
{
CRTDLL_fprintf(CRTDLL_stderr,"\nabnormal program termination\n");
CRTDLL__exit(3);
}
/*********************************************************************
* atexit (CRTDLL.345)
*
* Register a function to be called when the process terminates.
*/
INT __cdecl CRTDLL_atexit( atexit_function func)
{
return CRTDLL__onexit(func) == func ? 0 : -1;
}
/*
* CRTDLL memory functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* Implementation Notes:
* MT Safe.
* heapwalk from win does not work. This is most likely due to internal
* differences between wine and win (see memory/heap.c comments). This
* version works fine, however.
*/
#include "crtdll.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
static new_handler_type new_handler;
/*********************************************************************
* new (CRTDLL.001)
*
* Allocate memory.
*/
LPVOID __cdecl CRTDLL_new(DWORD size)
{
VOID* result;
if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler)
(*new_handler)();
return result;
}
/*********************************************************************
* delete (CRTDLL.002)
*
* Free memory created with new.
*/
VOID __cdecl CRTDLL_delete(LPVOID ptr)
{
HeapFree(GetProcessHeap(),0,ptr);
}
/*********************************************************************
* set_new_handler(CRTDLL.003)
*/
new_handler_type __cdecl CRTDLL_set_new_handler(new_handler_type func)
{
new_handler_type old_handler = new_handler;
new_handler = func;
return old_handler;
}
/*********************************************************************
* _expand (CRTDLL.088)
*
* Increase the size of a block of memory allocated with malloc()
* or realloc().
*/
LPVOID __cdecl CRTDLL__expand(LPVOID ptr, INT size)
{
return HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr, size );
}
/*********************************************************************
* _heapchk (CRTDLL.130)
*
* Check the consistency of the process heap.
*/
INT __cdecl CRTDLL__heapchk(VOID)
{
if (!HeapValidate( GetProcessHeap(), 0, NULL))
{
__CRTDLL__set_errno(GetLastError());
return _HEAPBADNODE;
}
return _HEAPOK;
}
/*********************************************************************
* _heapmin (CRTDLL.131)
*
* Minimise the size of the heap.
*/
INT __cdecl CRTDLL__heapmin(VOID)
{
if (!HeapCompact( GetProcessHeap(), 0 ))
{
if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
__CRTDLL__set_errno(GetLastError());
return -1;
}
return 0;
}
/*********************************************************************
* _heapset (CRTDLL.132)
*
* Fill free memory in the heap with a given value.
*/
INT __cdecl CRTDLL__heapset(UINT value)
{
INT retVal;
struct _heapinfo heap;
memset( &heap, 0, sizeof(heap) );
while ((retVal = CRTDLL__heapwalk(&heap)) == _HEAPOK)
{
if (heap._useflag == _FREEENTRY)
memset(heap._pentry, value, heap._size);
}
return retVal == _HEAPEND? _HEAPOK : retVal;
}
/*********************************************************************
* _heapwalk (CRTDLL.133)
*
* Walk the heap block by block.
*/
INT __cdecl CRTDLL__heapwalk(struct _heapinfo *next)
{
PROCESS_HEAP_ENTRY phe;
phe.lpData = next->_pentry;
phe.cbData = next->_size;
phe.wFlags = next->_useflag == _USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0;
if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY &&
!HeapValidate( GetProcessHeap(), 0, phe.lpData ))
{
__CRTDLL__set_errno(GetLastError());
return _HEAPBADNODE;
}
do
{
if (!HeapWalk( GetProcessHeap(), &phe ))
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
return _HEAPEND;
__CRTDLL__set_errno(GetLastError());
if (!phe.lpData)
return _HEAPBADBEGIN;
return _HEAPBADNODE;
}
} while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE));
next->_pentry = phe.lpData;
next->_size = phe.cbData;
next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? _USEDENTRY : _FREEENTRY;
return _HEAPOK;
}
/*********************************************************************
* _msize (CRTDLL.234)
*
* Return the actual used size of an allocated block of memory.
*
*/
LONG __cdecl CRTDLL__msize(LPVOID mem)
{
LONG size = HeapSize(GetProcessHeap(),0,mem);
if (size == -1)
{
WARN(":Probably called with non wine-allocated memory, ret = -1\n");
/* At least the win98/nt crtdlls also return -1 in this case */
}
return size;
}
/*********************************************************************
* calloc (CRTDLL.350)
*
* Allocate memory from the heap and initialise it to zero.
*/
LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count)
{
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
}
/*********************************************************************
* free (CRTDLL.375)
*
* Free a block of memory allocated with malloc()
*/
VOID __cdecl CRTDLL_free(LPVOID ptr)
{
HeapFree(GetProcessHeap(),0,ptr);
}
/*********************************************************************
* malloc (CRTDLL.424)
*
* Alocate memory from the heap.
*/
LPVOID __cdecl CRTDLL_malloc(DWORD size)
{
LPVOID ret = HeapAlloc(GetProcessHeap(),0,size);
if (!ret)
__CRTDLL__set_errno(GetLastError());
return ret;
}
/*********************************************************************
* realloc (CRTDLL.444)
*
* Resize a block of memory allocated with malloc() or realloc().
*/
LPVOID __cdecl CRTDLL_realloc( VOID *ptr, DWORD size )
{
return HeapReAlloc( GetProcessHeap(), 0, ptr, size );
}
/*
* CRTDLL spawn functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* These functions differ in whether they pass arguments as an array
* (v in the name) or as varags (l in the name), whether they
* seach the path (p in the name) and/or whether they take an
* environment (e in the name) or pass the parents environment.
* Args as Search Take
* Name varargs? path? environment?
* spawnl N N N
* spawnle N N Y
* spawnlp N Y N
* spawnlpe N Y Y
* spawnv Y N N
* spawnve Y N Y
* spawnvp Y Y N
* spawnvpe Y Y Y
*
* Implementation Notes:
* MT Safe - But only because of missing functionality.
*
* After translating input arguments into the required format for
* CreateProcess(), the internal function __CRTDLL__spawn() is
* called to perform the actual spawning.
*
* FIXME:
* -File handles need some special handling. Sometimes children get
* open file handles, sometimes not. The docs are confusing.
* -No check for maximum path/argument/environment size is done.
* Unresolved issues Uwe Bonnes 970904:
* -system-call calls another wine process, but without debugging arguments
* and uses the first wine executable in the path
*/
#include "crtdll.h"
#include <errno.h>
#include <stdlib.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* Process creation flags */
#define _P_WAIT 0
#define _P_NOWAIT 1
#define _P_OVERLAY 2
#define _P_NOWAITO 3
#define _P_DETACH 4
extern void __CRTDLL__set_errno(ULONG err);
extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count);
extern VOID __cdecl CRTDLL_free(void *ptr);
extern VOID __cdecl CRTDLL__exit(LONG ret);
extern INT CRTDLL_doserrno;
/* INTERNAL: Spawn a child process */
static int __CRTDLL__spawn(INT flags, LPCSTR exe, LPSTR args, LPSTR env)
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
if ((unsigned)flags > _P_DETACH)
{
CRTDLL_errno = EINVAL;
return -1;
}
FIXME(":must dup/kill streams for child process\n");
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
flags == _P_DETACH ? DETACHED_PROCESS : 0,
env, NULL, &si, &pi))
{
__CRTDLL__set_errno(GetLastError());
return -1;
}
switch(flags)
{
case _P_WAIT:
WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return pi.dwProcessId;
case _P_DETACH:
CloseHandle(pi.hProcess);
pi.hProcess = 0;
/* fall through */
case _P_NOWAIT:
case _P_NOWAITO:
CloseHandle(pi.hThread);
return pi.hProcess;
case _P_OVERLAY:
CRTDLL__exit(0);
}
return -1; /* cant reach here */
}
/* INTERNAL: Convert argv list to a single 'delim'-seperated string */
static LPSTR __CRTDLL__argvtos(LPCSTR *arg, CHAR delim)
{
LPCSTR *search = arg;
LONG size = 0;
LPSTR ret;
if (!arg && !delim)
return NULL;
/* get length */
while(*search)
{
size += strlen(*search) + 1;
search++;
}
if (!(ret = (LPSTR)CRTDLL_calloc(size + 1, 1)))
return NULL;
/* fill string */
search = arg;
size = 0;
while(*search)
{
int strsize = strlen(*search);
memcpy(ret+size,*search,strsize);
ret[size+strsize] = delim;
size += strsize + 1;
search++;
}
return ret;
}
/*********************************************************************
* _cwait (CRTDLL.069)
*
* Wait for a spawned process to finish.
*/
INT __cdecl CRTDLL__cwait(LPINT status, INT pid, INT action)
{
HANDLE hPid = (HANDLE)pid;
action = action; /* Remove warning */
if (!WaitForSingleObject(hPid, -1)) /* wait forvever */
{
if (status)
{
DWORD stat;
GetExitCodeProcess(hPid, &stat);
*status = (INT)stat;
}
return pid;
}
CRTDLL_doserrno = GetLastError();
if (CRTDLL_doserrno == ERROR_INVALID_HANDLE)
CRTDLL_errno = ECHILD;
else
__CRTDLL__set_errno(CRTDLL_doserrno);
return status ? *status = -1 : -1;
}
/*********************************************************************
* _spawnv (CRTDLL.273)
*
* Spawn a process.
*/
HANDLE __cdecl CRTDLL__spawnv(INT flags, LPCSTR name, LPCSTR *argv)
{
return CRTDLL__spawnve(flags, name, argv, NULL);
}
/*********************************************************************
* _spawnve (CRTDLL.274)
*
* Spawn a process.
*/
HANDLE __cdecl CRTDLL__spawnve(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
{
LPSTR args = __CRTDLL__argvtos(argv,' ');
LPSTR envs = __CRTDLL__argvtos(envv,0);
LPCSTR fullname = name;
HANDLE ret = -1;
FIXME(":not translating name %s to locate program\n",fullname);
TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
if (args)
{
ret = __CRTDLL__spawn(flags, fullname, args, envs);
CRTDLL_free(args);
}
if (envs)
CRTDLL_free(envs);
return ret;
}
/*********************************************************************
* _spawnvp (CRTDLL.275)
*
* Spawn a process.
*/
HANDLE __cdecl CRTDLL__spawnvp(INT flags, LPCSTR name, LPCSTR *argv)
{
return CRTDLL__spawnvpe(flags, name, argv, NULL);
}
/*********************************************************************
* _spawnvpe (CRTDLL.276)
*
* Spawn a process.
*/
HANDLE __cdecl CRTDLL__spawnvpe(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
{
char fullname[MAX_PATH];
CRTDLL__searchenv(name, "PATH", fullname);
return CRTDLL__spawnve(flags, fullname[0] ? fullname : name, argv, envv);
}
/*********************************************************************
* system (CRTDLL.485)
*
* Spawn an O/S process.
*/
INT __cdecl CRTDLL_system(LPCSTR cmd)
{
/* FIXME: should probably launch cmd interpreter in COMSPEC */
return __CRTDLL__spawn(_P_WAIT, cmd, NULL, NULL);
}
/*
* CRTDLL string functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* Implementation Notes:
* MT Safe.
*/
#include "crtdll.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
/* INTERNAL: CRTDLL_malloc() based strndup */
LPSTR __CRTDLL__strndup(LPSTR buf, INT size);
LPSTR __CRTDLL__strndup(LPSTR buf, INT size)
{
char* ret;
int len = strlen(buf);
int max_len;
max_len = size <= len? size : len + 1;
ret = CRTDLL_malloc(max_len);
if (ret)
{
memcpy(ret,buf,max_len);
ret[max_len] = 0;
}
return ret;
}
/*********************************************************************
* _strdec (CRTDLL.282)
*
* Return the byte before str2 while it is >= to str1.
*
* PARAMS
* str1 [in] Terminating string
*
* sre2 [in] string to start searching from
*
* RETURNS
* The byte before str2, or str1, whichever is greater
*
* NOTES
* This function is implemented as tested with windows, which means
* it does not have a terminating condition. It always returns
* the byte before str2. Use with extreme caution!
*/
LPSTR __cdecl CRTDLL__strdec(LPSTR str1, LPSTR str2)
{
/* Hmm. While the docs suggest that the following should work... */
/* return (str2<=str1?0:str2-1); */
/* ...Version 2.50.4170 (NT) from win98 constantly decrements! */
str1 = str1; /* remove warning */
return str2-1;
}
/*********************************************************************
* _strdup (CRTDLL.285)
*
* Duplicate a string.
*/
LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr)
{
LPSTR ret = CRTDLL_malloc(strlen(ptr)+1);
if (ret) strcpy( ret, ptr );
return ret;
}
/*********************************************************************
* _strinc (CRTDLL.287)
*
* Return a pointer to the next character in a string
*/
LPSTR __cdecl CRTDLL__strinc(LPSTR str)
{
return str+1;
}
/*********************************************************************
* _strnextc (CRTDLL.290)
*
* Return an unsigned int from a string.
*/
UINT __cdecl CRTDLL__strnextc(LPCSTR str)
{
return (UINT)*str;
}
/*********************************************************************
* _strninc (CRTDLL.292)
*
* Return a pointer to the 'n'th character in a string
*/
LPSTR __cdecl CRTDLL__strninc(LPSTR str, INT n)
{
return str+n;
}
/*********************************************************************
* _strnset (CRTDLL.293)
*
* Fill a string with a character up to a certain length
*/
LPSTR __cdecl CRTDLL__strnset(LPSTR str, INT c, INT len)
{
if (len > 0 && str)
while (*str && len--)
*str++ = c;
return str;
}
/*********************************************************************
* _strrev (CRTDLL.294)
*
* Reverse a string in place
*/
LPSTR __cdecl CRTDLL__strrev (LPSTR str)
{
LPSTR p1;
LPSTR p2;
if (str && *str)
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
/*********************************************************************
* _strset (CRTDLL.295)
*
* Fill a string with a value.
*/
LPSTR __cdecl CRTDLL__strset (LPSTR str, INT set)
{
char *ptr = str;
while (*ptr)
*ptr++ = set;
return str;
}
/*********************************************************************
* _strncnt (CRTDLL.289)
*
* Return the length of a string or the maximum given length.
*/
LONG __cdecl CRTDLL__strncnt(LPSTR str, LONG max)
{
LONG len = strlen(str);
return (len > max? max : len);
}
/*********************************************************************
* _strspnp (CRTDLL.296)
*
*/
LPSTR __cdecl CRTDLL__strspnp(LPSTR str1, LPSTR str2)
{
str1 += strspn(str1,str2);
return *str1? str1 : 0;
}
/*********************************************************************
* _swab (CRTDLL.299)
*
* Copy from source to dest alternating bytes (i.e 16 bit big-to-little
* endian or vice versa).
*/
void __cdecl CRTDLL__swab(LPSTR src, LPSTR dst, INT len)
{
if (len > 1)
{
len = (unsigned)len >> 1;
while (len--) {
*dst++ = src[1];
*dst++ = *src++;
src++;
}
}
}
/*
* CRTDLL date/time functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* Implementation Notes:
* MT Safe.
*/
#include "crtdll.h"
#include <stdlib.h>
#include <sys/times.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* INTERNAL: Return formatted current time/date */
static LPSTR __CRTDLL__get_current_time(LPSTR out, const char * format);
static LPSTR __CRTDLL__get_current_time(LPSTR out, const char * format)
{
time_t t;
struct tm *_tm;
if ((time(&t) != ((time_t)-1)) &&
((_tm = localtime(&t)) != 0) &&
(strftime(out,9,format,_tm) == 8))
{
CRTDLL_free(_tm);
return out;
}
return NULL;
}
/*********************************************************************
* _ftime (CRTDLL.112)
*
* Get current time.
*/
VOID __cdecl CRTDLL__ftime (struct _timeb* t)
{
t->time = CRTDLL_time(NULL);
t->millitm = 0; /* FIXME */
t->timezone = 0;
t->dstflag = 0;
}
/**********************************************************************
* _strdate (CRTDLL.283)
*
* Return the current date as MM/DD/YY - (American Format)
*/
LPSTR __cdecl CRTDLL__strdate (LPSTR date)
{
return __CRTDLL__get_current_time(date,"%m/%d/%y");
}
/*********************************************************************
* _strtime (CRTDLL.299)
*
* Return the current time as HH:MM:SS
*/
LPSTR __cdecl CRTDLL__strtime (LPSTR date)
{
return __CRTDLL__get_current_time(date,"%H:%M:%S");
}
/*********************************************************************
* clock (CRTDLL.350)
*/
clock_t __cdecl CRTDLL_clock(void)
{
struct tms alltimes;
clock_t res;
times(&alltimes);
res = alltimes.tms_utime + alltimes.tms_stime+
alltimes.tms_cutime + alltimes.tms_cstime;
/* FIXME: We need some symbolic representation
for (Hostsystem_)CLOCKS_PER_SEC
and (Emulated_system_)CLOCKS_PER_SEC
10 holds only for Windows/Linux_i86)
*/
return 10*res;
}
/*********************************************************************
* difftime (CRTDLL.357)
*/
double __cdecl CRTDLL_difftime (time_t time1, time_t time2)
{
double timediff;
timediff = (double)(time1 - time2);
return timediff;
}
/*********************************************************************
* time (CRTDLL.488)
*/
time_t __cdecl CRTDLL_time(time_t *timeptr)
{
time_t curtime = time(NULL);
if (timeptr)
*timeptr = curtime;
return curtime;
}
/*
* CRTDLL wide-char functions
*
* Copyright 1999 Alexandre Julliard
*/
#include "crtdll.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "winnls.h"
#include "wine/unicode.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
/*********************************************************************
* CRTDLL__wcsdup (CRTDLL.320)
*/
LPWSTR __cdecl CRTDLL__wcsdup( LPCWSTR str )
{
LPWSTR ret = NULL;
if (str)
{
int size = (strlenW(str) + 1) * sizeof(WCHAR);
ret = CRTDLL_malloc( size );
if (ret) memcpy( ret, str, size );
}
return ret;
}
/*********************************************************************
* CRTDLL__wcsicoll (CRTDLL.322)
*/
INT __cdecl CRTDLL__wcsicoll( LPCWSTR str1, LPCWSTR str2 )
{
/* FIXME: handle collates */
return strcmpiW( str1, str2 );
}
/*********************************************************************
* CRTDLL__wcsnset (CRTDLL.325)
*/
LPWSTR __cdecl CRTDLL__wcsnset( LPWSTR str, WCHAR c, INT n )
{
LPWSTR ret = str;
while ((n-- > 0) && *str) *str++ = c;
return ret;
}
/*********************************************************************
* CRTDLL__wcsrev (CRTDLL.326)
*/
LPWSTR __cdecl CRTDLL__wcsrev( LPWSTR str )
{
LPWSTR ret = str;
LPWSTR end = str + strlenW(str) - 1;
while (end > str)
{
WCHAR t = *end;
*end-- = *str;
*str++ = t;
}
return ret;
}
/*********************************************************************
* CRTDLL__wcsset (CRTDLL.327)
*/
LPWSTR __cdecl CRTDLL__wcsset( LPWSTR str, WCHAR c )
{
LPWSTR ret = str;
while (*str) *str++ = c;
return ret;
}
/*********************************************************************
* CRTDLL_wcscoll (CRTDLL.506)
*/
DWORD __cdecl CRTDLL_wcscoll( LPCWSTR str1, LPCWSTR str2 )
{
/* FIXME: handle collates */
return strcmpW( str1, str2 );
}
/*********************************************************************
* CRTDLL_wcspbrk (CRTDLL.514)
*/
LPWSTR __cdecl CRTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept )
{
LPCWSTR p;
while (*str)
{
for (p = accept; *p; p++) if (*p == *str) return (LPWSTR)str;
str++;
}
return NULL;
}
/*********************************************************************
* CRTDLL_wctomb (CRTDLL.524)
*/
INT __cdecl CRTDLL_wctomb( LPSTR dst, WCHAR ch )
{
return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
}
/*********************************************************************
* CRTDLL_iswalnum (CRTDLL.405)
*/
INT __cdecl CRTDLL_iswalnum( WCHAR wc )
{
return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER);
}
/*********************************************************************
* CRTDLL_iswalpha (CRTDLL.406)
*/
INT __cdecl CRTDLL_iswalpha( WCHAR wc )
{
return get_char_typeW(wc) & (C1_ALPHA|C1_LOWER|C1_UPPER);
}
/*********************************************************************
* CRTDLL_iswcntrl (CRTDLL.408)
*/
INT __cdecl CRTDLL_iswcntrl( WCHAR wc )
{
return get_char_typeW(wc) & C1_CNTRL;
}
/*********************************************************************
* CRTDLL_iswdigit (CRTDLL.410)
*/
INT __cdecl CRTDLL_iswdigit( WCHAR wc )
{
return get_char_typeW(wc) & C1_DIGIT;
}
/*********************************************************************
* CRTDLL_iswgraph (CRTDLL.411)
*/
INT __cdecl CRTDLL_iswgraph( WCHAR wc )
{
return get_char_typeW(wc) & (C1_ALPHA|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER);
}
/*********************************************************************
* CRTDLL_iswlower (CRTDLL.412)
*/
INT __cdecl CRTDLL_iswlower( WCHAR wc )
{
return get_char_typeW(wc) & C1_LOWER;
}
/*********************************************************************
* CRTDLL_iswprint (CRTDLL.413)
*/
INT __cdecl CRTDLL_iswprint( WCHAR wc )
{
return get_char_typeW(wc) & (C1_ALPHA|C1_BLANK|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER);
}
/*********************************************************************
* CRTDLL_iswpunct (CRTDLL.414)
*/
INT __cdecl CRTDLL_iswpunct( WCHAR wc )
{
return get_char_typeW(wc) & C1_PUNCT;
}
/*********************************************************************
* CRTDLL_iswspace (CRTDLL.415)
*/
INT __cdecl CRTDLL_iswspace( WCHAR wc )
{
return get_char_typeW(wc) & C1_SPACE;
}
/*********************************************************************
* CRTDLL_iswupper (CRTDLL.416)
*/
INT __cdecl CRTDLL_iswupper( WCHAR wc )
{
return get_char_typeW(wc) & C1_UPPER;
}
/*********************************************************************
* CRTDLL_iswxdigit (CRTDLL.417)
*/
INT __cdecl CRTDLL_iswxdigit( WCHAR wc )
{
return get_char_typeW(wc) & C1_XDIGIT;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment