From d3576a9f85007834a6cbc5aa33839c85681cf455 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 8 Nov 2000 22:42:53 +0000 Subject: [PATCH] - Implemented 73 CRT functions - Reimplemented file I/O using Win32 calls - Set errno/doserrno in most calls --- dlls/crtdll/Makefile.in | 7 + dlls/crtdll/crtdll.h | 356 ++++- dlls/crtdll/crtdll.spec | 158 +- dlls/crtdll/crtdll_main.c | 2085 +++++++++------------------ dlls/crtdll/dir.c | 336 +++++ dlls/crtdll/exit.c | 186 +++ dlls/crtdll/file.c | 1524 ++++++++++++++++++++ dlls/crtdll/mbstring.c | 49 +- dlls/crtdll/memory.c | 131 ++ dlls/crtdll/spawn.c | 225 +++ dlls/crtdll/string.c | 192 +++ dlls/crtdll/time.c | 120 ++ dlls/crtdll/wcstring.c | 9 +- tools/winapi_check/win32/crtdll.api | 13 +- 14 files changed, 3828 insertions(+), 1563 deletions(-) create mode 100644 dlls/crtdll/dir.c create mode 100644 dlls/crtdll/exit.c create mode 100644 dlls/crtdll/file.c create mode 100644 dlls/crtdll/memory.c create mode 100644 dlls/crtdll/spawn.c create mode 100644 dlls/crtdll/string.c create mode 100644 dlls/crtdll/time.c diff --git a/dlls/crtdll/Makefile.in b/dlls/crtdll/Makefile.in index dda4f9e0799..62e2703a98a 100644 --- a/dlls/crtdll/Makefile.in +++ b/dlls/crtdll/Makefile.in @@ -8,7 +8,14 @@ IMPORTS = kernel32 ntdll C_SRCS = \ crtdll_main.c \ + dir.c \ + exit.c \ + file.c \ mbstring.c \ + memory.c \ + spawn.c \ + string.c \ + time.c \ wcstring.c @MAKE_DLL_RULES@ diff --git a/dlls/crtdll/crtdll.h b/dlls/crtdll/crtdll.h index 9d731fff79c..a7f1cd46d01 100644 --- a/dlls/crtdll/crtdll.h +++ b/dlls/crtdll/crtdll.h @@ -1,7 +1,17 @@ #ifndef __WINE_CRTDLL_H #define __WINE_CRTDLL_H +#include "config.h" #include "windef.h" +#include "wine/windef16.h" +#include "debugtools.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include +#include +#include + #define CRTDLL_LC_ALL 0 #define CRTDLL_LC_COLLATE 1 @@ -24,19 +34,324 @@ #define CRTDLL_LEADBYTE 0x8000 #define CRTDLL_ALPHA (0x0100|CRTDLL_UPPER|CRTDLL_LOWER) -/* function prototypes used in crtdll.c */ -extern int LastErrorToErrno(DWORD); +/* stat() mode bits */ +#define _S_IFMT 0170000 +#define _S_IFREG 0100000 +#define _S_IFDIR 0040000 +#define _S_IFCHR 0020000 +#define _S_IFIFO 0010000 +#define _S_IREAD 0000400 +#define _S_IWRITE 0000200 +#define _S_IEXEC 0000100 -void __cdecl *CRTDLL_malloc( DWORD size ); -void __cdecl CRTDLL_free( void *ptr ); +/* _open modes */ +#define _O_RDONLY 0x0000 +#define _O_WRONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_APPEND 0x0008 +#define _O_CREAT 0x0100 +#define _O_TRUNC 0x0200 +#define _O_EXCL 0x0400 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 +/* _access() bit flags FIXME: incomplete */ +#define W_OK 2 + +/* windows.h RAND_MAX is smaller than normal RAND_MAX */ +#define CRTDLL_RAND_MAX 0x7fff + +/* CRTDLL Globals */ +extern INT CRTDLL_doserrno; +extern INT CRTDLL_errno; + + +/* Binary compatable structures, types and defines used + * by CRTDLL. These should move to external header files, + * and in some cases need be renamed (CRTDLL_FILE!) to defs + * as used by lcc/bcc/watcom/vc++ etc, in order to get source + * compatability for winelib. + */ + +typedef struct _crtfile +{ + CHAR* _ptr; + INT _cnt; + CHAR* _base; + INT _flag; + INT _file; /* fd */ + int _charbuf; + int _bufsiz; + char *_tmpfname; +} CRTDLL_FILE; + +/* file._flag flags */ +#define _IOREAD 0x0001 +#define _IOWRT 0x0002 +#define _IOEOF 0x0010 +#define _IOERR 0x0020 +#define _IORW 0x0080 +#define _IOAPPEND 0x0200 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define EOF -1 + +extern CRTDLL_FILE __CRTDLL_iob[3]; + +#define CRTDLL_stdin (&__CRTDLL_iob[0]) +#define CRTDLL_stdout (&__CRTDLL_iob[1]) +#define CRTDLL_stderr (&__CRTDLL_iob[2]) + +typedef struct _find_t +{ + unsigned attrib; + time_t time_create; /* -1 when N/A */ + time_t time_access; /* -1 when N/A */ + time_t time_write; + unsigned long size; /* FIXME: 64 bit ??*/ + char name[MAX_PATH]; +} find_t; + +typedef struct _diskfree_t { + unsigned num_clusters; + unsigned available; + unsigned cluster_sectors; + unsigned sector_bytes; +} diskfree_t; + +struct _stat +{ + UINT16 st_dev; + UINT16 st_ino; + UINT16 st_mode; + INT16 st_nlink; + INT16 st_uid; + INT16 st_gid; + UINT st_rdev; + INT st_size; + INT st_atime; + INT st_mtime; + INT st_ctime; +}; + +struct _timeb +{ + time_t time; + UINT16 millitm; + INT16 timezone; + INT16 dstflag; +}; + +typedef long fpos_t; + +struct complex +{ + double real; + double imaginary; +}; + +typedef VOID (*sig_handler_type)(VOID); + +typedef VOID (*new_handler_type)(VOID); + +typedef VOID (*_INITTERMFUN)(); + +typedef VOID (*atexit_function)(VOID); + +typedef INT (__cdecl *comp_func)(LPVOID *,LPVOID *); + +/* CRTDLL functions */ + +/* CRTDLL_dir.c */ +INT __cdecl CRTDLL__chdir( LPCSTR newdir ); +BOOL __cdecl CRTDLL__chdrive( INT newdrive ); +INT __cdecl CRTDLL__findclose( DWORD hand ); +DWORD __cdecl CRTDLL__findfirst( LPCSTR fspec, find_t* ft ); +INT __cdecl CRTDLL__findnext( DWORD hand, find_t * ft ); +CHAR* __cdecl CRTDLL__getcwd( LPSTR buf, INT size ); +CHAR* __cdecl CRTDLL__getdcwd( INT drive,LPSTR buf, INT size ); +UINT __cdecl CRTDLL__getdiskfree( UINT disk, diskfree_t* d ); +INT __cdecl CRTDLL__getdrive( VOID ); +INT __cdecl CRTDLL__mkdir( LPCSTR newdir ); +INT __cdecl CRTDLL__rmdir( LPSTR dir ); + +/* CRTDLL_exit.c */ +INT __cdecl CRTDLL__abnormal_termination( VOID ); +VOID __cdecl CRTDLL__amsg_exit( INT err ); +VOID __cdecl CRTDLL__assert( LPVOID str, LPVOID file, UINT line ); +VOID __cdecl CRTDLL__c_exit( VOID ); +VOID __cdecl CRTDLL__cexit( VOID ); +void __cdecl CRTDLL_exit( DWORD ret ); +VOID __cdecl CRTDLL__exit( LONG ret ); +VOID __cdecl CRTDLL_abort( VOID ); +INT __cdecl CRTDLL_atexit( atexit_function x ); +atexit_function __cdecl CRTDLL__onexit( atexit_function func); + +/* CRTDLL_file.c */ +CRTDLL_FILE* __cdecl CRTDLL__iob( VOID ); +CRTDLL_FILE* __cdecl CRTDLL__fsopen( LPCSTR path, LPCSTR mode, INT share ); +CRTDLL_FILE* __cdecl CRTDLL__fdopen( INT fd, LPCSTR mode ); +CRTDLL_FILE* __cdecl CRTDLL_fopen( LPCSTR path, LPCSTR mode ); +CRTDLL_FILE* __cdecl CRTDLL_freopen( LPCSTR path,LPCSTR mode,CRTDLL_FILE* f ); +INT __cdecl CRTDLL__fgetchar( VOID ); +DWORD __cdecl CRTDLL_fread( LPVOID ptr,INT size,INT nmemb,CRTDLL_FILE* file ); +INT __cdecl CRTDLL_fscanf( CRTDLL_FILE* stream, LPSTR format, ... ); +INT __cdecl CRTDLL__filbuf( CRTDLL_FILE* file ); +INT __cdecl CRTDLL__fileno( CRTDLL_FILE* file ); +INT __cdecl CRTDLL__flsbuf( INT c, CRTDLL_FILE* file ); +INT __cdecl CRTDLL__fputchar( INT c ); +INT __cdecl CRTDLL__flushall( VOID ); +INT __cdecl CRTDLL__fcloseall( VOID ); +LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence ); +LONG __cdecl CRTDLL_fseek( CRTDLL_FILE* file, LONG offset, INT whence ); +VOID __cdecl CRTDLL_rewind( CRTDLL_FILE* file ); +INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE* file, fpos_t *pos ); +LONG __cdecl CRTDLL_ftell( CRTDLL_FILE* file ); +UINT __cdecl CRTDLL_fwrite( LPCVOID ptr,INT size,INT nmemb,CRTDLL_FILE*file); +INT __cdecl CRTDLL_setbuf( CRTDLL_FILE* file, LPSTR buf ); +INT __cdecl CRTDLL__open_osfhandle( HANDLE osfhandle, INT flags ); +INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE* file, LPCSTR format,va_list args); +INT __cdecl CRTDLL_fprintf( CRTDLL_FILE* file, LPCSTR format, ... ); +INT __cdecl CRTDLL__read( INT fd, LPVOID buf, UINT count ); +UINT __cdecl CRTDLL__write( INT fd,LPCVOID buf,UINT count ); +INT __cdecl CRTDLL__access( LPCSTR filename, INT mode ); +INT __cdecl CRTDLL_fflush( CRTDLL_FILE* file ); +INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE* file ); +VOID __cdecl CRTDLL_putchar( INT x ); +INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE* file ); +INT __cdecl CRTDLL_puts( LPCSTR s ); +INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE* file ); +INT __cdecl CRTDLL_fgetc( CRTDLL_FILE* file ); +INT __cdecl CRTDLL_getchar( VOID ); +INT __cdecl CRTDLL_getc( CRTDLL_FILE* file ); +CHAR* __cdecl CRTDLL_fgets( LPSTR s, INT size, CRTDLL_FILE* file ); +LPSTR __cdecl CRTDLL_gets( LPSTR buf ); +INT __cdecl CRTDLL_fclose( CRTDLL_FILE* file ); +INT __cdecl CTRDLL__creat( LPCSTR path, INT flags ); +INT __cdecl CRTDLL__eof( INT fd ); +LONG __cdecl CRTDLL__tell(INT fd); +INT __cdecl CRTDLL__umask(INT umask); +INT __cdecl CRTDLL__unlink( LPCSTR pathname ); +INT __cdecl CRTDLL_rename( LPCSTR oldpath,LPCSTR newpath ); +int __cdecl CRTDLL__stat( LPCSTR filename, struct _stat * buf ); +INT __cdecl CRTDLL__open( LPCSTR path,INT flags ); +INT __cdecl CRTDLL__close( INT fd ); +INT __cdecl CRTDLL_feof( CRTDLL_FILE* file ); +INT __cdecl CRTDLL__setmode( INT fh,INT mode ); +INT __cdecl CRTDLL_remove( LPCSTR path ); +INT __cdecl CRTDLL__commit( INT fd ); +INT __cdecl CRTDLL__fstat( int file, struct _stat* buf ); +HANDLE __cdecl CRTDLL__get_osfhandle( INT fd ); + +/* CRTDLL_main.c */ +DWORD __cdecl CRTDLL__initterm( _INITTERMFUN *start,_INITTERMFUN *end ); +VOID __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame ); +VOID __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr ); +INT __cdecl CRTDLL__setjmp( LPDWORD *jmpbuf ); +VOID __cdecl CRTDLL_srand( DWORD seed ); +INT __cdecl CRTDLL__isatty(INT fd); +VOID __cdecl CRTDLL__beep( UINT freq, UINT duration ); +INT __cdecl CRTDLL_rand( VOID ); +UINT __cdecl CRTDLL__rotl( UINT x,INT shift ); +DWORD __cdecl CRTDLL__lrotl( DWORD x,INT shift ); +DWORD __cdecl CRTDLL__lrotr( DWORD x,INT shift ); +DWORD __cdecl CRTDLL__rotr( UINT x,INT shift ); +INT __cdecl CRTDLL__mbsicmp( unsigned char *x,unsigned char *y ); +INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args ); +VOID __cdecl CRTDLL_longjmp( jmp_buf env, int val ); +LPSTR __cdecl CRTDLL_setlocale( INT category,LPCSTR locale ); +BOOL __cdecl CRTDLL__isctype( CHAR x,CHAR type ); +LPSTR __cdecl CRTDLL__fullpath( LPSTR buf, LPCSTR name, INT size ); +VOID __cdecl CRTDLL__splitpath( LPCSTR path, LPSTR drive, LPSTR directory, + LPSTR filename, LPSTR extension ); +LPINT __cdecl CRTDLL__errno( VOID ); +LPINT __cdecl CRTDLL___doserrno( VOID ); +LPCSTR**__cdecl CRTDLL__sys_errlist( VOID ); +VOID __cdecl CRTDLL_perror( LPCSTR err ); +LPSTR __cdecl CRTDLL__strerror( LPCSTR err ); +LPSTR __cdecl CRTDLL_strerror( INT err ); +LPSTR __cdecl CRTDLL__tempnam( LPCSTR dir, LPCSTR prefix ); +LPSTR __cdecl CRTDLL_tmpnam( LPSTR s ); +LPVOID __cdecl CRTDLL_signal( INT sig, sig_handler_type ptr ); +VOID __cdecl CRTDLL__sleep( ULONG timeout ); +LPSTR __cdecl CRTDLL_getenv( LPCSTR name ); +LPSTR __cdecl CRTDLL__mbsrchr( LPSTR s,CHAR x ); +VOID __cdecl CRTDLL___dllonexit ( VOID ); +VOID __cdecl CRTDLL__mbccpy( LPSTR dest, LPSTR src ); +INT __cdecl CRTDLL___isascii( INT c ); +INT __cdecl CRTDLL___toascii( INT c ); +INT __cdecl CRTDLL_iswascii( LONG c ); +INT __cdecl CRTDLL___iscsym( LONG c ); +INT __cdecl CRTDLL___iscsymf( LONG c ); +INT __cdecl CRTDLL__loaddll( LPSTR dllname ); +INT __cdecl CRTDLL__unloaddll( HANDLE dll ); +WCHAR* __cdecl CRTDLL__itow( INT value,WCHAR* out,INT base ); +WCHAR* __cdecl CRTDLL__ltow( LONG value,WCHAR* out,INT base ); +WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base); +CHAR __cdecl CRTDLL__toupper( CHAR c ); +CHAR __cdecl CRTDLL__tolower( CHAR c ); +double __cdecl CRTDLL__cabs( struct complex c ); +double __cdecl CRTDLL__chgsign( double d ); +UINT __cdecl CRTDLL__control87( UINT, UINT ); +UINT __cdecl CRTDLL__controlfp( UINT, UINT ); +double __cdecl CRTDLL__copysign(double x, double sign); +INT __cdecl CRTDLL__finite( double d ); +VOID __cdecl CRTDLL__fpreset( void ); +INT __cdecl CRTDLL__isnan( double d ); +LPVOID __cdecl CRTDLL__lsearch( LPVOID match, LPVOID start, LPUINT array_size, + UINT elem_size, comp_func cf ); + +/* CRTDLL_mem.c */ +LPVOID __cdecl CRTDLL_new( DWORD size ); +VOID __cdecl CRTDLL_delete( LPVOID ptr ); +new_handler_type __cdecl CRTDLL_set_new_handler( new_handler_type func ); +LPVOID __cdecl CRTDLL__expand( LPVOID ptr, INT size ); +LONG __cdecl CRTDLL__msize( LPVOID mem ); +LPVOID __cdecl CRTDLL_calloc( DWORD size, DWORD count ); +VOID __cdecl CRTDLL_free( LPVOID ptr ); +LPVOID __cdecl CRTDLL_malloc( DWORD size ); +LPVOID __cdecl CRTDLL_realloc( VOID *ptr, DWORD size ); + +/* CRTDLL_spawn.c */ +HANDLE __cdecl CRTDLL__spawnve( INT flags, LPSTR name, LPSTR *argv, LPSTR *envv); +INT __cdecl CRTDLL_system( LPSTR x ); + +/* CRTDLL_str.c */ +LPSTR __cdecl CRTDLL__strdec( LPSTR str1, LPSTR str2 ); +LPSTR __cdecl CRTDLL__strdup( LPCSTR ptr ); +LPSTR __cdecl CRTDLL__strinc( LPSTR str ); +LPSTR __cdecl CRTDLL__strninc( LPSTR str, INT n ); +LPSTR __cdecl CRTDLL__strnset( LPSTR str, INT c, INT len ); +LPSTR __cdecl CRTDLL__strrev ( LPSTR str ); +LPSTR __cdecl CRTDLL__strset ( LPSTR str, INT set ); +LONG __cdecl CRTDLL__strncnt( LPSTR str, LONG max ); +LPSTR __cdecl CRTDLL__strspnp( LPSTR str1, LPSTR str2 ); +VOID __cdecl CRTDLL__swab( LPSTR src, LPSTR dst, INT len ); + +/* CRTDLL_time.c */ +LPSTR __cdecl CRTDLL__strdate ( LPSTR date ); +LPSTR __cdecl CRTDLL__strtime ( LPSTR date ); +clock_t __cdecl CRTDLL_clock ( void ); +double __cdecl CRTDLL_difftime ( time_t time1, time_t time2 ); +time_t __cdecl CRTDLL_time ( time_t *timeptr ); + +/* mbstring.c */ LPSTR __cdecl CRTDLL__mbsinc( LPCSTR str ); INT __cdecl CRTDLL__mbslen( LPCSTR str ); +INT __cdecl CRTDLL_mbtowc( WCHAR *dst, LPCSTR str, INT n ); LPWSTR __cdecl CRTDLL__wcsdup( LPCWSTR str ); INT __cdecl CRTDLL__wcsicoll( LPCWSTR str1, LPCWSTR str2 ); LPWSTR __cdecl CRTDLL__wcsnset( LPWSTR str, WCHAR c, INT n ); LPWSTR __cdecl CRTDLL__wcsrev( LPWSTR str ); LPWSTR __cdecl CRTDLL__wcsset( LPWSTR str, WCHAR c ); +DWORD __cdecl CRTDLL_wcscoll( LPCWSTR str1, LPCWSTR str2 ); +LPWSTR __cdecl CRTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept ); +INT __cdecl CRTDLL_wctomb( LPSTR dst, WCHAR ch ); + +/* wcstring.c */ INT __cdecl CRTDLL_iswalnum( WCHAR wc ); INT __cdecl CRTDLL_iswalpha( WCHAR wc ); INT __cdecl CRTDLL_iswcntrl( WCHAR wc ); @@ -48,35 +363,10 @@ INT __cdecl CRTDLL_iswpunct( WCHAR wc ); INT __cdecl CRTDLL_iswspace( WCHAR wc ); INT __cdecl CRTDLL_iswupper( WCHAR wc ); INT __cdecl CRTDLL_iswxdigit( WCHAR wc ); -INT __cdecl CRTDLL_iswctype( WCHAR wc, WCHAR wct ); -INT __cdecl CRTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n ); -INT __cdecl CRTDLL_mbtowc( WCHAR *dst, LPCSTR str, INT n ); -DWORD __cdecl CRTDLL_wcscoll( LPCWSTR str1, LPCWSTR str2 ); -LPWSTR __cdecl CRTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept ); -INT __cdecl CRTDLL_wctomb( LPSTR dst, WCHAR ch ); -#ifdef notyet -#define _mbsinc CRTDLL__mbsinc -#define _mbslen CRTDLL__mbslen -#define _wcsdup CRTDLL__wcsdup -#define _wcsicoll CRTDLL__wcsicoll -#define _wcsnset CRTDLL__wcsnset -#define _wcsrev CRTDLL__wcsrev -#define _wcsset CRTDLL__wcsset -#define iswalnum CRTDLL_iswalnum -#define iswalpha CRTDLL_iswalpha -#define iswcntrl CRTDLL_iswcntrl -#define iswdigit CRTDLL_iswdigit -#define iswgraph CRTDLL_iswgraph -#define iswlower CRTDLL_iswlower -#define iswprint CRTDLL_iswprint -#define iswpunct CRTDLL_iswpunct -#define iswspace CRTDLL_iswspace -#define iswupper CRTDLL_iswupper -#define iswxdigit CRTDLL_iswxdigit -#define mbtowc CRTDLL_mbtowc -#define wcscoll CRTDLL_wcscoll -#define wctomb CRTDLL_wctomb -#endif +/* INTERNAL: Shared internal functions */ +void __CRTDLL__set_errno(ULONG err); +LPSTR __CRTDLL__strndup(LPSTR buf, INT size); +VOID __CRTDLL__init_io(VOID); #endif /* __WINE_CRTDLL_H */ diff --git a/dlls/crtdll/crtdll.spec b/dlls/crtdll/crtdll.spec index c29c1868b20..06344357517 100644 --- a/dlls/crtdll/crtdll.spec +++ b/dlls/crtdll/crtdll.spec @@ -33,47 +33,47 @@ debug_channels (crtdll) @ extern __argc_dll CRTDLL_argc_dll @ extern __argv_dll CRTDLL_argv_dll @ cdecl __dllonexit() CRTDLL___dllonexit -@ stub __doserrno +@ cdecl __doserrno() CRTDLL___doserrno @ stub __fpecode -@ stub __isascii -@ stub __iscsym -@ stub __iscsymf +@ cdecl __isascii(long) CRTDLL___isascii +@ cdecl __iscsym(long) CRTDLL___iscsym +@ cdecl __iscsymf(long) CRTDLL___iscsymf @ stub __mb_cur_max_dll @ stub __pxcptinfoptrs @ cdecl __threadhandle() GetCurrentThread @ cdecl __threadid() GetCurrentThreadId -@ stub __toascii +@ cdecl __toascii(long) CRTDLL___toascii @ cdecl _abnormal_termination() CRTDLL__abnormal_termination @ cdecl _access(str long) CRTDLL__access @ extern _acmdln_dll CRTDLL_acmdln_dll @ stub _aexit_rtn_dll -@ stub _amsg_exit -@ stub _assert +@ cdecl _amsg_exit(long) CRTDLL__amsg_exit +@ cdecl _assert(ptr ptr long) CRTDLL__assert @ extern _basemajor_dll CRTDLL_basemajor_dll @ extern _baseminor_dll CRTDLL_baseminor_dll @ extern _baseversion_dll CRTDLL_baseversion_dll -@ stub _beep +@ cdecl _beep(long long) CRTDLL__beep @ stub _beginthread -@ stub _c_exit -@ stub _cabs -@ cdecl _cexit(long) CRTDLL__cexit +@ cdecl _c_exit() CRTDLL__c_exit +@ cdecl _cabs(long) CRTDLL__cabs +@ cdecl _cexit() CRTDLL__cexit @ stub _cgets @ cdecl _chdir(str) CRTDLL__chdir @ cdecl _chdrive(long) CRTDLL__chdrive -@ stub _chgsign +@ cdecl _chgsign(double) CRTDLL__chgsign @ stub _chmod @ stub _chsize @ stub _clearfp @ cdecl _close(long) CRTDLL__close -@ stub _commit +@ cdecl _commit(long) CRTDLL__commit @ extern _commode_dll CRTDLL_commode_dll -@ stub _control87 -@ stub _controlfp -@ stub _copysign +@ cdecl _control87(long long) CRTDLL__control87 +@ cdecl _controlfp(long long) CRTDLL__controlfp +@ cdecl _copysign(double double) CRTDLL__copysign @ stub _cprintf @ stub _cpumode_dll @ stub _cputs -@ stub _creat +@ cdecl _creat(str long) CTRDLL__creat @ stub _cscanf @ stub _ctype @ stub _cwait @@ -83,7 +83,7 @@ debug_channels (crtdll) @ stub _ecvt @ stub _endthread @ extern _environ_dll CRTDLL_environ_dll -@ stub _eof +@ cdecl _eof(long) CRTDLL__eof @ cdecl _errno() CRTDLL__errno @ cdecl _except_handler2(ptr ptr ptr ptr) CRTDLL__except_handler2 @ stub _execl @@ -94,45 +94,45 @@ debug_channels (crtdll) @ stub _execve @ stub _execvp @ stub _execvpe -@ stub _exit -@ stub _expand -@ stub _fcloseall +@ cdecl _exit(long) CRTDLL__exit +@ cdecl _expand(ptr long) CRTDLL__expand +@ cdecl _fcloseall() CRTDLL__fcloseall @ stub _fcvt @ cdecl _fdopen(long ptr) CRTDLL__fdopen -@ stub _fgetchar +@ cdecl _fgetchar() CRTDLL__fgetchar @ stub _fgetwchar -@ stub _filbuf +@ cdecl _filbuf(ptr) CRTDLL__filbuf @ stub _fileinfo_dll @ stub _filelength -@ stub _fileno -@ stub _findclose +@ cdecl _fileno(ptr) CRTDLL__fileno +@ cdecl _findclose(long) CRTDLL__findclose @ cdecl _findfirst(str ptr) CRTDLL__findfirst @ cdecl _findnext(long ptr) CRTDLL__findnext -@ stub _finite -@ stub _flsbuf -@ stub _flushall +@ cdecl _finite(double) CRTDLL__finite +@ cdecl _flsbuf(long ptr) CRTDLL__flsbuf +@ cdecl _flushall() CRTDLL__flushall @ extern _fmode_dll CRTDLL_fmode_dll @ stub _fpclass @ stub _fpieee_flt @ cdecl _fpreset() CRTDLL__fpreset -@ stub _fputchar +@ cdecl _fputchar(long) CRTDLL__fputchar @ stub _fputwchar @ cdecl _fsopen(str str long) CRTDLL__fsopen @ cdecl _fstat(long ptr) CRTDLL__fstat -@ stub _ftime +@ cdecl _ftime(ptr) CRTDLL__ftime @ forward _ftol ntdll._ftol @ cdecl _fullpath(ptr str long) CRTDLL__fullpath @ stub _futime @ stub _gcvt -@ stub _get_osfhandle +@ cdecl _get_osfhandle(long) CRTDLL__get_osfhandle @ stub _getch @ stub _getche @ cdecl _getcwd(ptr long) CRTDLL__getcwd @ cdecl _getdcwd(long ptr long) CRTDLL__getdcwd -@ stub _getdiskfree -@ stub _getdllprocaddr +@ cdecl _getdiskfree(long ptr) CRTDLL__getdiskfree +@ forward _getdllprocaddr kernel32.GetProcAddress @ cdecl _getdrive() CRTDLL__getdrive -@ stub _getdrives +@ forward _getdrives kernel32.GetLogicalDrives @ stub _getpid @ stub _getsystime @ stub _getw @@ -143,7 +143,7 @@ debug_channels (crtdll) @ stub _heapwalk @ cdecl _hypot(double double) hypot @ cdecl _initterm(ptr ptr) CRTDLL__initterm -@ extern _iob CRTDLL_iob +@ extern _iob __CRTDLL_iob @ cdecl _isatty(long) CRTDLL__isatty @ cdecl _isctype(long long) CRTDLL__isctype @ stub _ismbbalnum @@ -171,29 +171,29 @@ debug_channels (crtdll) @ stub _ismbcupper @ stub _ismbslead @ stub _ismbstrail -@ stub _isnan +@ cdecl _isnan(double) CRTDLL__isnan @ forward _itoa ntdll._itoa -@ stub _itow -@ cdecl _j0(double) j0 -@ cdecl _j1(double) j1 -@ cdecl _jn(long double) jn +@ cdecl _itow(long str long) CRTDLL__itow +@ cdecl _j0(double) CRTDLL__j0 +@ cdecl _j1(double) CRTDLL__j1 +@ cdecl _jn(long double) CRTDLL__jn @ stub _kbhit @ stub _lfind -@ stub _loaddll +@ cdecl _loaddll(str) CRTDLL__loaddll @ cdecl _local_unwind2(ptr long) CRTDLL__local_unwind2 @ stub _locking @ stub _logb @ cdecl _lrotl (long long) CRTDLL__lrotl -@ stub _lrotr -@ stub _lsearch +@ cdecl _lrotr (long long) CRTDLL__lrotr +@ cdecl _lsearch(ptr ptr long long ptr) CRTDLL__lsearch @ cdecl _lseek(long long long) CRTDLL__lseek @ forward _ltoa ntdll._ltoa -@ stub _ltow +@ cdecl _ltow(long str long) CRTDLL__ltow @ cdecl _makepath (ptr str str str str) CRTDLL__makepath @ stub _matherr @ stub _mbbtombc @ stub _mbbtype -@ stub _mbccpy +@ cdecl _mbccpy (str str) CRTDLL__mbccpy @ stub _mbcjistojms @ stub _mbcjmstojis @ stub _mbclen @@ -239,13 +239,13 @@ debug_channels (crtdll) @ stub _mbstok @ stub _mbstrlen @ stub _mbsupr -@ stub _memccpy +@ cdecl _memccpy(ptr ptr long long) memccpy @ forward _memicmp ntdll._memicmp @ cdecl _mkdir(str) CRTDLL__mkdir @ stub _mktemp -@ stub _msize +@ cdecl _msize(ptr) CRTDLL__msize @ stub _nextafter -@ stub _onexit +@ cdecl _onexit(ptr) CRTDLL__onexit @ cdecl _open(str long) CRTDLL__open @ cdecl _open_osfhandle(long long) CRTDLL__open_osfhandle @ extern _osmajor_dll CRTDLL_osmajor_dll @@ -264,10 +264,10 @@ debug_channels (crtdll) @ stub _putw @ stub _pwctype_dll @ cdecl _read(long ptr long) CRTDLL__read -@ stub _rmdir +@ cdecl _rmdir(str) CRTDLL__rmdir @ stub _rmtmp @ cdecl _rotl (long long) CRTDLL__rotl -@ stub _rotr +@ cdecl _rotr (long long) CRTDLL__rotr @ stub _scalb @ stub _searchenv @ stub _seterrormode @@ -283,7 +283,7 @@ debug_channels (crtdll) @ stub _spawnlp @ stub _spawnlpe @ stub _spawnv -@ stub _spawnve +@ cdecl _spawnve(long str ptr ptr) CRTDLL__spawnve @ stub _spawnvp @ stub _spawnvpe @ cdecl _splitpath (str ptr ptr ptr ptr) CRTDLL__splitpath @@ -291,39 +291,39 @@ debug_channels (crtdll) @ stub _statusfp @ cdecl _strcmpi(str str) strcasecmp @ cdecl _strdate(str) CRTDLL__strdate -@ stub _strdec +@ cdecl _strdec(str str) CRTDLL__strdec @ cdecl _strdup(str) CRTDLL__strdup -@ stub _strerror +@ cdecl _strerror(long) CRTDLL__strerror @ cdecl _stricmp(str str) strcasecmp @ stub _stricoll -@ stub _strinc +@ cdecl _strinc(str) CRTDLL__strinc @ forward _strlwr ntdll._strlwr -@ stub _strncnt +@ cdecl _strncnt(str long) CRTDLL__strncnt @ stub _strnextc @ cdecl _strnicmp(str str long) strncasecmp -@ stub _strninc -@ stub _strnset -@ stub _strrev -@ stub _strset -@ stub _strspnp +@ cdecl _strninc(str long) CRTDLL__strninc +@ cdecl _strnset(str long long) CRTDLL__strnset +@ cdecl _strrev(str) CRTDLL__strrev +@ cdecl _strset(str long) CRTDLL__strset +@ cdecl _strspnp(str str) CRTDLL__strspnp @ cdecl _strtime(str) CRTDLL__strtime @ forward _strupr ntdll._strupr -@ stub _swab -@ stub _sys_errlist -@ stub _sys_nerr_dll -@ stub _tell +@ cdecl _swab(str str long) CRTDLL__swab +@ extern _sys_errlist sys_errlist +@ extern _sys_nerr_dll CRTDLL__sys_nerr +@ cdecl _tell(long) CRTDLL__tell @ cdecl _tempnam(str ptr) CRTDLL__tempnam @ stub _timezone_dll -@ stub _tolower -@ stub _toupper +@ cdecl _tolower(long) CRTDLL__toupper +@ cdecl _toupper(long) CRTDLL__tolower @ stub _tzname @ stub _tzset @ forward _ultoa ntdll._ultoa -@ stub _ultow -@ stub _umask +@ cdecl _ultow(long str long) CRTDLL__ultow +@ cdecl _umask(long) CRTDLL__umask @ stub _ungetch @ cdecl _unlink(str) CRTDLL__unlink -@ stub _unloaddll +@ cdecl _unloaddll(long) CRTDLL__unloaddll @ stub _utime @ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf @ stub _vsnwprintf @@ -345,7 +345,7 @@ debug_channels (crtdll) @ cdecl _y0(double) y0 @ cdecl _y1(double) y1 @ cdecl _yn(long double) yn -@ stub abort +@ cdecl abort() CRTDLL_abort @ cdecl abs(long) abs @ cdecl acos(double) acos @ cdecl asctime(ptr) asctime @@ -359,7 +359,7 @@ debug_channels (crtdll) @ cdecl bsearch(ptr ptr long long ptr) bsearch @ cdecl calloc(long long) CRTDLL_calloc @ cdecl ceil(double) ceil -@ stub clearerr +@ cdecl clearerr(ptr) CRTDLL_clearerr @ cdecl clock() CRTDLL_clock @ cdecl cos(double) cos @ cdecl cosh(double) cosh @@ -371,10 +371,10 @@ debug_channels (crtdll) @ cdecl fabs(double) fabs @ cdecl fclose(ptr) CRTDLL_fclose @ cdecl feof(ptr) CRTDLL_feof -@ stub ferror +@ cdecl ferror(ptr) CRTDLL_ferror @ cdecl fflush(ptr) CRTDLL_fflush @ cdecl fgetc(ptr) CRTDLL_fgetc -@ stub fgetpos +@ cdecl fgetpos(ptr ptr) CRTDLL_fgetpos @ cdecl fgets(ptr long ptr) CRTDLL_fgets @ stub fgetwc @ cdecl floor(double) floor @@ -396,11 +396,11 @@ debug_channels (crtdll) @ cdecl fwrite(ptr long long ptr) CRTDLL_fwrite @ stub fwscanf @ cdecl getc(ptr) CRTDLL_getc -@ stub getchar +@ cdecl getchar() CRTDLL_getchar @ cdecl getenv (str) CRTDLL_getenv @ cdecl gets(ptr) CRTDLL_gets @ cdecl gmtime(ptr) gmtime -@ stub is_wctype +@ forward is_wctype ntdll.iswctype @ cdecl isalnum(long) isalnum @ cdecl isalpha(long) isalpha @ cdecl iscntrl(long) iscntrl @@ -414,7 +414,7 @@ debug_channels (crtdll) @ cdecl isupper(long) isupper @ cdecl iswalnum(long) CRTDLL_iswalnum @ forward iswalpha ntdll.iswalpha -@ stub iswascii +@ cdecl iswascii(long) CRTDLL_iswascii @ cdecl iswcntrl(long) CRTDLL_iswcntrl @ forward iswctype ntdll.iswctype @ cdecl iswdigit(long) CRTDLL_iswdigit @@ -445,7 +445,7 @@ debug_channels (crtdll) @ cdecl memset(ptr long long) memset @ cdecl mktime(ptr) mktime @ cdecl modf(double ptr) modf -@ stub perror +@ cdecl perror(str) CRTDLL_perror @ cdecl pow(double double) pow @ varargs printf() printf @ cdecl putc(long ptr) CRTDLL_putc @@ -457,7 +457,7 @@ debug_channels (crtdll) @ cdecl realloc(ptr long) CRTDLL_realloc @ cdecl remove(str) CRTDLL_remove @ cdecl rename(str str) CRTDLL_rename -@ stub rewind +@ cdecl rewind(ptr) CRTDLL_rewind @ stub scanf @ cdecl setbuf(ptr ptr) CRTDLL_setbuf @ cdecl setlocale(long ptr) CRTDLL_setlocale @@ -475,7 +475,7 @@ debug_channels (crtdll) @ cdecl strcoll(str str) strcoll @ cdecl strcpy(ptr str) strcpy @ cdecl strcspn(str str) strcspn -@ cdecl strerror(long) strerror +@ cdecl strerror(long) CRTDLL_strerror @ cdecl strftime(ptr long str ptr) strftime @ cdecl strlen(str) strlen @ cdecl strncat(str str long) strncat diff --git a/dlls/crtdll/crtdll_main.c b/dlls/crtdll/crtdll_main.c index 993669d0b50..7422e3b3d75 100644 --- a/dlls/crtdll/crtdll_main.c +++ b/dlls/crtdll/crtdll_main.c @@ -6,19 +6,13 @@ * Copyright 1996,1998 Marcus Meissner * Copyright 1996 Jukka Iivonen * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths */ /* Unresolved issues Uwe Bonnes 970904: -- Handling of Binary/Text Files is crude. If in doubt, use fromdos or recode -- Arguments in crtdll.spec for functions with double argument -- system-call calls another wine process, but without debugging arguments - and uses the first wine executable in the path - tested with ftp://ftp.remcomp.com/pub/remcomp/lcc-win32.zip, a C-Compiler for Win32, based on lcc, from Jacob Navia -AJ 990101: -- needs a proper stdio emulation based on Win32 file handles -- should set CRTDLL errno from GetLastError() in every function UB 000416: - probably not thread safe */ @@ -28,50 +22,29 @@ UB 000416: * since we need 2 byte wide characters. - Marcus Meissner, 981031 */ -#include "config.h" - +#include "crtdll.h" +#include +#define __USE_ISOC9X 1 /* for isfinite */ +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "winbase.h" -#include "windef.h" +#include "file.h" +#include "ntddk.h" #include "wingdi.h" #include "winuser.h" -#include "winerror.h" -#include "ntddk.h" -#include "debugtools.h" -#include "heap.h" -#include "crtdll.h" -#include "drive.h" -#include "file.h" -#include "options.h" -#include "winnls.h" + DEFAULT_DEBUG_CHANNEL(crtdll); -/* windows.h RAND_MAX is smaller than normal RAND_MAX */ -#define CRTDLL_RAND_MAX 0x7fff - -static DOS_FULL_NAME CRTDLL_tmpname; UINT CRTDLL_argc_dll; /* CRTDLL.23 */ -LPSTR *CRTDLL_argv_dll; /* CRTDLL.24 */ -LPSTR CRTDLL_acmdln_dll; /* CRTDLL.38 */ +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 */ +LPSTR CRTDLL_environ_dll; /* CRTDLL.75 */ UINT CRTDLL_fmode_dll; /* CRTDLL.104 */ UINT CRTDLL_osmajor_dll; /* CRTDLL.241 */ UINT CRTDLL_osminor_dll; /* CRTDLL.242 */ @@ -81,59 +54,83 @@ 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; -/* FIXME: structure layout is obviously not correct */ -typedef struct -{ - HANDLE handle; - int pad[7]; -} CRTDLL_FILE; - -CRTDLL_FILE CRTDLL_iob[3]; - -static CRTDLL_FILE * const CRTDLL_stdin = &CRTDLL_iob[0]; -static CRTDLL_FILE * const CRTDLL_stdout = &CRTDLL_iob[1]; -static CRTDLL_FILE * const CRTDLL_stderr = &CRTDLL_iob[2]; - -typedef VOID (*new_handler_type)(VOID); - -static new_handler_type new_handler; - -CRTDLL_FILE * __cdecl CRTDLL__fdopen(INT handle, LPCSTR mode); -INT __cdecl CRTDLL_fgetc( CRTDLL_FILE *file ); /********************************************************************* * CRTDLL_MainInit (CRTDLL.init) */ -BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +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__fdopen(0,"r"); - CRTDLL__fdopen(1,"w"); - CRTDLL__fdopen(2,"w"); + __CRTDLL__init_io(); } return TRUE; } -/********************************************************************* - * malloc (CRTDLL.427) - */ -VOID* __cdecl CRTDLL_malloc(DWORD size) + +/* INTERNAL: Set the crt and dos errno's from the OS error given. */ +void __CRTDLL__set_errno(ULONG err) { - return HeapAlloc(GetProcessHeap(),0,size); + /* 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; + } } -/********************************************************************* - * _strdup (CRTDLL.285) - */ -LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr) -{ - LPSTR ret = CRTDLL_malloc(strlen(ptr)+1); - if (ret) strcpy( ret, ptr ); - return ret; -} /********************************************************************* * _GetMainArgs (CRTDLL.022) @@ -215,56 +212,6 @@ LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv, } -typedef void (*_INITTERMFUN)(); - -/* fixme: move to header */ -struct find_t -{ unsigned attrib; - time_t time_create; /* -1 when not avaiable */ - time_t time_access; /* -1 when not avaiable */ - time_t time_write; - unsigned long size; /* fixme: 64 bit ??*/ - char name[260]; -}; - /********************************************************************* - * _findfirst (CRTDLL.099) - * - * BUGS - * Unimplemented - */ -DWORD __cdecl CRTDLL__findfirst(LPCSTR fname, struct find_t * x2) -{ - FIXME(":(%s,%p): stub\n",fname,x2); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/********************************************************************* - * _findnext (CRTDLL.100) - * - * BUGS - * Unimplemented - */ -INT __cdecl CRTDLL__findnext(DWORD hand, struct find_t * x2) -{ - FIXME(":(%ld,%p): stub\n",hand,x2); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/********************************************************************* - * _fstat (CRTDLL.111) - * - * BUGS - * Unimplemented - */ -int __cdecl CRTDLL__fstat(int file, struct stat* buf) -{ - FIXME(":(%d,%p): stub\n",file,buf); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - /********************************************************************* * _initterm (CRTDLL.135) */ @@ -281,45 +228,6 @@ DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end) return 0; } -/********************************************************************* - * _fsopen (CRTDLL.110) - */ -CRTDLL_FILE * __cdecl CRTDLL__fsopen(LPCSTR x, LPCSTR y, INT z) { - FIXME("(%s,%s,%d),stub!\n",x,y,z); - return NULL; -} - -/********************************************************************* - * _fdopen (CRTDLL.91) - */ -CRTDLL_FILE * __cdecl CRTDLL__fdopen(INT handle, LPCSTR mode) -{ - CRTDLL_FILE *file; - - switch (handle) - { - case 0: - file = CRTDLL_stdin; - if (!file->handle) file->handle = GetStdHandle( STD_INPUT_HANDLE ); - break; - case 1: - file = CRTDLL_stdout; - if (!file->handle) file->handle = GetStdHandle( STD_OUTPUT_HANDLE ); - break; - case 2: - file=CRTDLL_stderr; - if (!file->handle) file->handle = GetStdHandle( STD_ERROR_HANDLE ); - break; - default: - file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) ); - file->handle = handle; - break; - } - TRACE("open handle %d mode %s got file %p\n", - handle, mode, file); - return file; -} - /******************************************************************* * _global_unwind2 (CRTDLL.129) @@ -329,6 +237,7 @@ void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame ) RtlUnwind( frame, 0, NULL, 0 ); } + /******************************************************************* * _local_unwind2 (CRTDLL.173) */ @@ -336,6 +245,8 @@ void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr ) { TRACE("(%p,%ld)\n",endframe,nr); } + + /******************************************************************* * _setjmp (CRTDLL.264) */ @@ -345,344 +256,6 @@ INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf) return 0; } -/********************************************************************* - * fopen (CRTDLL.372) - */ -CRTDLL_FILE * __cdecl CRTDLL_fopen(LPCSTR path, LPCSTR mode) -{ - CRTDLL_FILE *file = NULL; - HFILE handle; -#if 0 - DOS_FULL_NAME full_name; - - if (!DOSFS_GetFullName( path, FALSE, &full_name )) { - WARN("file %s bad name\n",path); - return 0; - } - - file=fopen(full_name.long_name ,mode); -#endif - DWORD access = 0, creation = 0; - - if ((strchr(mode,'r')&&strchr(mode,'a'))|| - (strchr(mode,'r')&&strchr(mode,'w'))|| - (strchr(mode,'w')&&strchr(mode,'a'))) - return NULL; - - if (mode[0] == 'r') - { - access = GENERIC_READ; - creation = OPEN_EXISTING; - if (mode[1] == '+') access |= GENERIC_WRITE; - } - else if (mode[0] == 'w') - { - access = GENERIC_WRITE; - creation = CREATE_ALWAYS; - if (mode[1] == '+') access |= GENERIC_READ; - } - else if (mode[0] == 'a') - { - access = GENERIC_WRITE; - creation = OPEN_ALWAYS; - if (mode[1] == '+') access |= GENERIC_READ; - } - /* FIXME: should handle text/binary mode */ - - if ((handle = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, creation, FILE_ATTRIBUTE_NORMAL, - -1 )) != INVALID_HANDLE_VALUE) - { - file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) ); - file->handle = handle; - } - TRACE("file %s mode %s got handle %d file %p\n", - path,mode,handle,file); - if (mode[0] == 'a') - { - /* if appending, seek to end of file */ - SetFilePointer( handle, 0, NULL, FILE_END ); - } - return file; -} - -/********************************************************************* - * fread (CRTDLL.377) - */ -DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file) -{ -#if 0 - int i=0; - void *temp=ptr; - - /* If we would honour CR/LF <-> LF translation, we could do it like this. - We should keep track of all files opened, and probably files with \ - known binary extensions must be unchanged */ - while ( (i < (nmemb*size)) && (ret==1)) { - ret=fread(temp,1,1,file); - TRACE("got %c 0x%02x ret %d\n", - (isalpha(*(unsigned char*)temp))? *(unsigned char*)temp: - ' ',*(unsigned char*)temp, ret); - if (*(unsigned char*)temp != 0xd) { /* skip CR */ - temp++; - i++; - } - else - TRACE("skipping ^M\n"); - } - TRACE("0x%08x items of size %d from file %p to %p\n", - nmemb,size,file,ptr,); - if(i!=nmemb) - WARN(" failed!\n"); - - return i; -#else - DWORD ret; - - TRACE("0x%08x items of size %d from file %p to %p\n", - nmemb,size,file,ptr); - if (!ReadFile( file->handle, ptr, size * nmemb, &ret, NULL )) - WARN(" failed!\n"); - - return ret / size; -#endif -} -/********************************************************************* - * freopen (CRTDLL.379) - * - * BUGS - * Unimplemented - */ -DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream) -{ - FIXME(":(%s,%s,%p): stub\n", path, mode, stream); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/********************************************************************* - * fscanf (CRTDLL.381) - */ -INT __cdecl CRTDLL_fscanf( CRTDLL_FILE *stream, LPSTR format, ... ) -{ - INT rd = 0; - int nch; - va_list ap; - if (!*format) return 0; - WARN("%p (\"%s\"): semi-stub\n", stream, format); - nch = CRTDLL_fgetc(stream); - va_start(ap, format); - while (*format) { - if (*format == ' ') { - /* skip whitespace */ - while ((nch!=EOF) && isspace(nch)) - nch = CRTDLL_fgetc(stream); - } - else if (*format == '%') { - int st = 0; - format++; - switch(*format) { - case 'd': { /* read an integer */ - int*val = va_arg(ap, int*); - int cur = 0; - /* skip initial whitespace */ - while ((nch!=EOF) && isspace(nch)) - nch = CRTDLL_fgetc(stream); - /* get sign and first digit */ - if (nch == '-') { - nch = CRTDLL_fgetc(stream); - if (isdigit(nch)) - cur = -(nch - '0'); - else break; - } else { - if (isdigit(nch)) - cur = nch - '0'; - else break; - } - nch = CRTDLL_fgetc(stream); - /* read until no more digits */ - while ((nch!=EOF) && isdigit(nch)) { - cur = cur*10 + (nch - '0'); - nch = CRTDLL_fgetc(stream); - } - st = 1; - *val = cur; - } - break; - case 'f': { /* read a float */ - float*val = va_arg(ap, float*); - float cur = 0; - /* skip initial whitespace */ - while ((nch!=EOF) && isspace(nch)) - nch = CRTDLL_fgetc(stream); - /* get sign and first digit */ - if (nch == '-') { - nch = CRTDLL_fgetc(stream); - if (isdigit(nch)) - cur = -(nch - '0'); - else break; - } else { - if (isdigit(nch)) - cur = nch - '0'; - else break; - } - /* read until no more digits */ - while ((nch!=EOF) && isdigit(nch)) { - cur = cur*10 + (nch - '0'); - nch = CRTDLL_fgetc(stream); - } - if (nch == '.') { - /* handle decimals */ - float dec = 1; - nch = CRTDLL_fgetc(stream); - while ((nch!=EOF) && isdigit(nch)) { - dec /= 10; - cur += dec * (nch - '0'); - nch = CRTDLL_fgetc(stream); - } - } - st = 1; - *val = cur; - } - break; - case 's': { /* read a word */ - char*str = va_arg(ap, char*); - char*sptr = str; - /* skip initial whitespace */ - while ((nch!=EOF) && isspace(nch)) - nch = CRTDLL_fgetc(stream); - /* read until whitespace */ - while ((nch!=EOF) && !isspace(nch)) { - *sptr++ = nch; st++; - nch = CRTDLL_fgetc(stream); - } - /* terminate */ - *sptr = 0; - TRACE("read word: %s\n", str); - } - break; - default: FIXME("unhandled: %%%c\n", *format); - } - if (st) rd++; - else break; - } - else { - /* check for character match */ - if (nch == *format) - nch = CRTDLL_fgetc(stream); - else break; - } - format++; - } - va_end(ap); - if (nch!=EOF) { - WARN("need ungetch\n"); - } - TRACE("returning %d\n", rd); - return rd; -} - -/********************************************************************* - * _lseek (CRTDLL.179) - */ -LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence) -{ - TRACE("fd %d to 0x%08lx pos %s\n", - fd,offset,(whence==SEEK_SET)?"SEEK_SET": - (whence==SEEK_CUR)?"SEEK_CUR": - (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); - return SetFilePointer( fd, offset, NULL, whence ); -} - -/********************************************************************* - * fseek (CRTDLL.382) - */ -LONG __cdecl CRTDLL_fseek( CRTDLL_FILE *file, LONG offset, INT whence) -{ - TRACE("file %p to 0x%08lx pos %s\n", - file,offset,(whence==SEEK_SET)?"SEEK_SET": - (whence==SEEK_CUR)?"SEEK_CUR": - (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); - if (SetFilePointer( file->handle, offset, NULL, whence ) != 0xffffffff) - return 0; - WARN(" failed!\n"); - return -1; -} - -/********************************************************************* - * fsetpos (CRTDLL.383) - */ -INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE *file, INT *pos ) -{ - TRACE("file %p pos %d\n", file, *pos ); - return CRTDLL_fseek(file, *pos, SEEK_SET); -} - -/********************************************************************* - * ftell (CRTDLL.384) - */ -LONG __cdecl CRTDLL_ftell( CRTDLL_FILE *file ) -{ - return SetFilePointer( file->handle, 0, NULL, SEEK_CUR ); -} - -/********************************************************************* - * fwrite (CRTDLL.386) - */ -DWORD __cdecl CRTDLL_fwrite( LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file ) -{ - DWORD ret; - - TRACE("0x%08x items of size %d to file %p(%d) from %p\n", - nmemb,size,file,file-(CRTDLL_FILE*)CRTDLL_iob,ptr); - - - if (!WriteFile( file->handle, ptr, size * nmemb, &ret, NULL )) - WARN(" failed!\n"); - return ret / size; -} - -/********************************************************************* - * setbuf (CRTDLL.452) - */ -INT __cdecl CRTDLL_setbuf(CRTDLL_FILE *file, LPSTR buf) -{ - TRACE("(file %p buf %p)\n", file, buf); - /* this doesn't work:"void value not ignored as it ought to be" - return setbuf(file,buf); - */ - /* FIXME: no buffering for now */ - return 0; -} - -/********************************************************************* - * _open_osfhandle (CRTDLL.240) - */ -HFILE __cdecl CRTDLL__open_osfhandle(LONG osfhandle, INT flags) -{ -HFILE handle; - - switch (osfhandle) { - case STD_INPUT_HANDLE : - case 0 : - handle=0; - break; - case STD_OUTPUT_HANDLE: - case 1: - handle=1; - break; - case STD_ERROR_HANDLE: - case 2: - handle=2; - break; - default: - return (-1); - } - TRACE("(handle %08lx,flags %d) return %d\n", - osfhandle,flags,handle); - return handle; - -} /********************************************************************* * srand (CRTDLL.460) @@ -693,183 +266,24 @@ void __cdecl CRTDLL_srand(DWORD seed) srand(seed); } -/********************************************************************* - * vfprintf (CRTDLL.373) - */ -INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE *file, LPSTR format, va_list args ) -{ - char buffer[2048]; /* FIXME... */ - - vsprintf( buffer, format, args ); - return CRTDLL_fwrite( buffer, 1, strlen(buffer), file ); -} /********************************************************************* - * fprintf (CRTDLL.373) - */ -INT __cdecl CRTDLL_fprintf( CRTDLL_FILE *file, LPSTR format, ... ) -{ - va_list valist; - INT res; - - va_start( valist, format ); - res = CRTDLL_vfprintf( file, format, valist ); - va_end( valist ); - return res; -} - -/********************************************************************* - * time (CRTDLL.488) - */ -time_t __cdecl CRTDLL_time(time_t *timeptr) -{ - time_t curtime = time(NULL); - - if (timeptr) - *timeptr = curtime; - return curtime; -} - -/********************************************************************* - * difftime (CRTDLL.357) - */ -double __cdecl CRTDLL_difftime (time_t time1, time_t time2) -{ - double timediff; - - timediff = (double)(time1 - time2); - return timediff; -} - -/********************************************************************* - * 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; -} - -/********************************************************************* - * _isatty (CRTDLL.137) - */ -BOOL __cdecl CRTDLL__isatty(DWORD x) -{ - TRACE("(%ld)\n",x); - return TRUE; -} - -/********************************************************************* - * _read (CRTDLL.256) + * _beep (CRTDLL.045) * - */ -INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count) -{ - TRACE("0x%08x bytes fd %d to %p\n", count,fd,buf); - if (!fd) fd = GetStdHandle( STD_INPUT_HANDLE ); - return _lread( fd, buf, count ); -} - -/********************************************************************* - * _write (CRTDLL.332) - */ -INT __cdecl CRTDLL__write(INT fd,LPCVOID buf,UINT count) -{ - INT len=0; - - if (fd == -1) - len = -1; - else if (fd<=2) - len = (UINT)write(fd,buf,(LONG)count); - else - len = _lwrite(fd,buf,count); - TRACE("%d/%d byte to dfh %d from %p,\n", - len,count,fd,buf); - return len; -} - - -/********************************************************************* - * _cexit (CRTDLL.49) + * Output a tone using the PC speaker. * - * FIXME: What the heck is the difference between - * FIXME _c_exit (CRTDLL.47) - * FIXME _cexit (CRTDLL.49) - * FIXME _exit (CRTDLL.87) - * FIXME exit (CRTDLL.359) + * PARAMS + * freq [in] Frequency of the tone * - * atexit-processing comes to mind -- MW. + * duration [in] Length of time the tone should sound * + * RETURNS + * None. */ -void __cdecl CRTDLL__cexit(INT ret) +void __cdecl CRTDLL__beep( UINT freq, UINT duration) { - TRACE("(%d)\n",ret); - ExitProcess(ret); -} - - -/********************************************************************* - * exit (CRTDLL.359) - */ -void __cdecl CRTDLL_exit(DWORD ret) -{ - TRACE("(%ld)\n",ret); - ExitProcess(ret); -} - - -/********************************************************************* - * _abnormal_termination (CRTDLL.36) - */ -INT __cdecl CRTDLL__abnormal_termination(void) -{ - TRACE("(void)\n"); - return 0; -} - - -/********************************************************************* - * _access (CRTDLL.37) - */ -INT __cdecl CRTDLL__access(LPCSTR filename, INT mode) -{ - DWORD attr = GetFileAttributesA(filename); - - if (attr == -1) - { - if (GetLastError() == ERROR_INVALID_ACCESS) - errno = EACCES; - else - errno = ENOENT; - return -1; - } - - if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) - { - errno = EACCES; - return -1; - } - else - return 0; -} - - -/********************************************************************* - * fflush (CRTDLL.365) - */ -INT __cdecl CRTDLL_fflush( CRTDLL_FILE *file ) -{ - return FlushFileBuffers( file->handle ) ? 0 : -1; + TRACE(":Freq %d, Duration %d\n",freq,duration); + Beep(freq, duration); } @@ -882,132 +296,6 @@ INT __cdecl CRTDLL_rand() } -/********************************************************************* - * fputc (CRTDLL.374) - */ -INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE *file ) -{ - char ch = (char)c; - DWORD res; - TRACE("%c to file %p\n",c,file); - if (!WriteFile( file->handle, &ch, 1, &res, NULL )) return -1; - return c; -} - - -/********************************************************************* - * putchar (CRTDLL.442) - */ -void __cdecl CRTDLL_putchar( INT x ) -{ - CRTDLL_fputc( x, CRTDLL_stdout ); -} - - -/********************************************************************* - * fputs (CRTDLL.375) - */ -INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE *file ) -{ - DWORD res; - TRACE("%s to file %p\n",s,file); - if (!WriteFile( file->handle, s, strlen(s), &res, NULL )) return -1; - return res; -} - - -/********************************************************************* - * puts (CRTDLL.443) - */ -INT __cdecl CRTDLL_puts(LPCSTR s) -{ - TRACE("%s \n",s); - return CRTDLL_fputs(s, CRTDLL_stdout); -} - - -/********************************************************************* - * putc (CRTDLL.441) - */ -INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE *file ) -{ - return CRTDLL_fputc( c, file ); -} - -/********************************************************************* - * fgetc (CRTDLL.366) - */ -INT __cdecl CRTDLL_fgetc( CRTDLL_FILE *file ) -{ - DWORD res; - char ch; - if (!ReadFile( file->handle, &ch, 1, &res, NULL )) return -1; - if (res != 1) return -1; - return ch; -} - - -/********************************************************************* - * getc (CRTDLL.388) - */ -INT __cdecl CRTDLL_getc( CRTDLL_FILE *file ) -{ - return CRTDLL_fgetc( file ); -} - - -/********************************************************************* - * fgets (CRTDLL.368) - */ -CHAR* __cdecl CRTDLL_fgets( LPSTR s, INT size, CRTDLL_FILE *file ) -{ - int cc; - LPSTR buf_start = s; - - /* BAD, for the whole WINE process blocks... just done this way to test - * windows95's ftp.exe. - */ - - for(cc = CRTDLL_fgetc(file); cc != EOF && cc != '\n'; cc = CRTDLL_fgetc(file)) - if (cc != '\r') - { - if (--size <= 0) break; - *s++ = (char)cc; - } - if ((cc == EOF) &&(s == buf_start)) /* If nothing read, return 0*/ - return 0; - if (cc == '\n') - if (--size > 0) - *s++ = '\n'; - *s = '\0'; - - TRACE("got '%s'\n", buf_start); - return buf_start; -} - - -/********************************************************************* - * gets (CRTDLL.391) - */ -LPSTR __cdecl CRTDLL_gets(LPSTR buf) -{ - int cc; - LPSTR buf_start = buf; - - /* BAD, for the whole WINE process blocks... just done this way to test - * windows95's ftp.exe. - */ - - for(cc = CRTDLL_fgetc(CRTDLL_stdin); cc != EOF && cc != '\n'; cc = CRTDLL_fgetc(CRTDLL_stdin)) - if(cc != '\r') *buf++ = (char)cc; - - *buf = '\0'; - - TRACE("got '%s'\n", buf_start); - return buf_start; -} - - /********************************************************************* * _rotl (CRTDLL.259) */ @@ -1015,41 +303,44 @@ 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); + TRACE("got 0x%08x rot %d ret 0x%08x\n", x,shift,ret); return ret; - } + + /********************************************************************* - * _lrotl (CRTDLL.176) + * _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); + TRACE("got 0x%08lx rot %d ret 0x%08lx\n", x,shift,ret); return ret; - } /********************************************************************* - * _mbsicmp (CRTDLL.204) + * _lrotr (CRTDLL.176) */ -int __cdecl CRTDLL__mbsicmp(unsigned char *x,unsigned char *y) +DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift) { - do { - if (!*x) - return !!*y; - if (!*y) - return !!*x; - /* FIXME: MBCS handling... */ - if (*x!=*y) - return 1; - x++; - y++; - } while (1); + /* 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; } @@ -1062,50 +353,6 @@ INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args ) } -/********************************************************************* - * system (CRTDLL.485) - */ -INT __cdecl CRTDLL_system(LPSTR x) -{ -#define SYSBUF_LENGTH 1500 - char buffer[SYSBUF_LENGTH]; - unsigned char *y = x; - unsigned char *bp; - int i; - - sprintf( buffer, "%s \"", argv0 ); - bp = buffer + strlen(buffer); - i = strlen(buffer) + strlen(x) +2; - - /* Calculate needed buffer size to prevent overflow. */ - while (*y) { - if (*y =='\\') i++; - y++; - } - /* If buffer too short, exit. */ - if (i > SYSBUF_LENGTH) { - TRACE("_system buffer to small\n"); - return 127; - } - - y =x; - - while (*y) { - *bp = *y; - bp++; y++; - if (*(y-1) =='\\') *bp++ = '\\'; - } - /* Remove spaces from end of string. */ - while (*(y-1) == ' ') { - bp--;y--; - } - *bp++ = '"'; - *bp = 0; - TRACE("_system got '%s', executing '%s'\n",x,buffer); - - return system(buffer); -} - /********************************************************************* * longjmp (CRTDLL.426) */ @@ -1115,322 +362,51 @@ VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val) longjmp(env, val); } -/********************************************************************* - * new (CRTDLL.001) - */ -VOID* __cdecl CRTDLL_new(DWORD size) -{ - VOID* result; - if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler) - (*new_handler)(); - return result; -} - -/********************************************************************* - * 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; -} - -/********************************************************************* - * calloc (CRTDLL.350) - */ -VOID* __cdecl CRTDLL_calloc(DWORD size, DWORD count) -{ - return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); -} - -/********************************************************************* - * realloc (CRTDLL.447) - */ -VOID* __cdecl CRTDLL_realloc( VOID *ptr, DWORD size ) -{ - return HeapReAlloc( GetProcessHeap(), 0, ptr, size ); -} - -/********************************************************************* - * free (CRTDLL.427) - */ -VOID __cdecl CRTDLL_free(LPVOID ptr) -{ - HeapFree(GetProcessHeap(),0,ptr); -} - -/********************************************************************* - * delete (CRTDLL.002) - */ -VOID __cdecl CRTDLL_delete(VOID* ptr) -{ - HeapFree(GetProcessHeap(),0,ptr); -} - -/********************************************************************* - * fclose (CRTDLL.362) - */ -INT __cdecl CRTDLL_fclose( CRTDLL_FILE *file ) -{ - TRACE("%p\n", file ); - if (!CloseHandle( file->handle )) return -1; - HeapFree( GetProcessHeap(), 0, file ); - return 0; -} - -/********************************************************************* - * _unlink (CRTDLL.315) - */ -INT __cdecl CRTDLL__unlink(LPCSTR pathname) -{ - return DeleteFileA( pathname ) ? 0 : -1; -} - -/********************************************************************* - * rename (CRTDLL.449) - */ -INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath) -{ - BOOL ok = MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING ); - return ok ? 0 : -1; -} - - -/********************************************************************* - * _stat (CRTDLL.280) - */ - -struct win_stat -{ - UINT16 win_st_dev; - UINT16 win_st_ino; - UINT16 win_st_mode; - INT16 win_st_nlink; - INT16 win_st_uid; - INT16 win_st_gid; - UINT win_st_rdev; - INT win_st_size; - INT win_st_atime; - INT win_st_mtime; - INT win_st_ctime; -}; - -int __cdecl CRTDLL__stat(const char * filename, struct win_stat * buf) -{ - int ret=0; - DOS_FULL_NAME full_name; - struct stat mystat; - - if (!DOSFS_GetFullName( filename, TRUE, &full_name )) - { - WARN("CRTDLL__stat filename %s bad name\n",filename); - return -1; - } - ret=stat(full_name.long_name,&mystat); - TRACE("CRTDLL__stat %s\n", filename); - if(ret) - WARN(" Failed!\n"); - - /* FIXME: should check what Windows returns */ - - buf->win_st_dev = mystat.st_dev; - buf->win_st_ino = mystat.st_ino; - buf->win_st_mode = mystat.st_mode; - buf->win_st_nlink = mystat.st_nlink; - buf->win_st_uid = mystat.st_uid; - buf->win_st_gid = mystat.st_gid; - buf->win_st_rdev = mystat.st_rdev; - buf->win_st_size = mystat.st_size; - buf->win_st_atime = mystat.st_atime; - buf->win_st_mtime = mystat.st_mtime; - buf->win_st_ctime = mystat.st_ctime; - return ret; -} - -/********************************************************************* - * _open (CRTDLL.239) - */ -HFILE __cdecl CRTDLL__open(LPCSTR path,INT flags) -{ - DWORD access = 0, creation = 0; - HFILE ret; - - /* FIXME: - the flags in lcc's header differ from the ones in Linux, e.g. - Linux: define O_APPEND 02000 (= 0x400) - lcc: define _O_APPEND 0x0008 - so here a scheme to translate them - Probably lcc is wrong here, but at least a hack to get is going - */ - switch(flags & 3) - { - case O_RDONLY: access |= GENERIC_READ; break; - case O_WRONLY: access |= GENERIC_WRITE; break; - case O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break; - } - - if (flags & 0x0100) /* O_CREAT */ - { - if (flags & 0x0400) /* O_EXCL */ - creation = CREATE_NEW; - else if (flags & 0x0200) /* O_TRUNC */ - creation = CREATE_ALWAYS; - else - creation = OPEN_ALWAYS; - } - else /* no O_CREAT */ - { - if (flags & 0x0200) /* O_TRUNC */ - creation = TRUNCATE_EXISTING; - else - creation = OPEN_EXISTING; - } - if (flags & 0x0008) /* O_APPEND */ - FIXME("O_APPEND not supported\n" ); - if (!(flags & 0x8000 /* O_BINARY */ ) || (flags & 0x4000 /* O_TEXT */)) - FIXME(":text mode not supported\n"); - if (flags & 0xf0f4) - TRACE("CRTDLL_open file unsupported flags 0x%04x\n",flags); - /* End Fixme */ - - ret = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, creation, FILE_ATTRIBUTE_NORMAL, -1 ); - TRACE("CRTDLL_open file %s mode 0x%04x got handle %d\n", path,flags,ret); - return ret; -} - -/********************************************************************* - * _close (CRTDLL.57) - */ -INT __cdecl CRTDLL__close(HFILE fd) -{ - int ret=_lclose(fd); - - TRACE("(%d)\n",fd); - if(ret) - WARN(" Failed!\n"); - - return ret; -} - -/********************************************************************* - * feof (CRTDLL.363) - * FIXME: Care for large files - * FIXME: Check errors - */ -INT __cdecl CRTDLL_feof( CRTDLL_FILE *file ) -{ - DWORD curpos=SetFilePointer( file->handle, 0, NULL, SEEK_CUR ); - DWORD endpos=SetFilePointer( file->handle, 0, NULL, FILE_END ); - - if (curpos==endpos) - return TRUE; - else - SetFilePointer( file->handle, curpos,0,FILE_BEGIN); - return FALSE; -} /********************************************************************* * setlocale (CRTDLL.453) */ LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale) { - LPSTR categorystr; + 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"; + 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"; } -/********************************************************************* - * _setmode (CRTDLL.265) - * FIXME: At present we ignore the request to translate CR/LF to LF. - * - * We allways translate when we read with fgets, we never do with fread - * - */ -INT __cdecl CRTDLL__setmode( INT fh,INT mode) -{ - /* FIXME */ -#define O_TEXT 0x4000 -#define O_BINARY 0x8000 - - FIXME("on fhandle %d mode %s, STUB.\n", - fh,(mode=O_TEXT)?"O_TEXT": - (mode=O_BINARY)?"O_BINARY":"UNKNOWN"); - return -1; -} - -/********************************************************************* - * _fpreset (CRTDLL.107) - */ -VOID __cdecl CRTDLL__fpreset(void) -{ - FIXME(" STUB.\n"); -} - -/********************************************************************* - * atexit (CRTDLL.345) - */ -INT __cdecl CRTDLL_atexit(LPVOID x) -{ - FIXME("(%p), STUB.\n",x); - return 0; /* successful */ -} /********************************************************************* * _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; + 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; } -/********************************************************************* - * _chdrive (CRTDLL.52) - * - * newdir [I] drive to change to, A=1 - * - */ -BOOL __cdecl CRTDLL__chdrive(INT newdrive) -{ - /* FIXME: generates errnos */ - return DRIVE_SetCurrentDrive(newdrive-1); -} - -/********************************************************************* - * _chdir (CRTDLL.51) - */ -INT __cdecl CRTDLL__chdir(LPCSTR newdir) -{ - if (!SetCurrentDirectoryA(newdir)) - return 1; - return 0; -} /********************************************************************* * _fullpath (CRTDLL.114) @@ -1450,6 +426,7 @@ LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size) return buf; } + /********************************************************************* * _splitpath (CRTDLL.279) */ @@ -1472,42 +449,40 @@ VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR namechar = strrchr(dirchar,'.'); else namechar = strrchr(path,'.'); - - - if (drive) + + if (drive) { *drive = 0x00; - if (drivechar) - { - strncat(drive,path,drivechar-path+1); - path = drivechar+1; - } + if (drivechar) + { + strncat(drive,path,drivechar-path+1); + path = drivechar+1; + } } - if (directory) + if (directory) { *directory = 0x00; if (dirchar) - { - strncat(directory,path,dirchar-path+1); - path = dirchar+1; - } + { + 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); - } - } + { + 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); - } @@ -1515,270 +490,150 @@ VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR * _makepath (CRTDLL.182) */ -VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive, - LPCSTR directory, LPCSTR filename, - LPCSTR extension ) +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); + char ch; + TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory, + filename, extension); - if ( !path ) - return; + if ( !path ) + return; - path[0] = 0; - if ( drive ) - if ( drive[0] ) { - sprintf(path, "%c:", drive[0]); - } - if ( directory ) - if ( directory[0] ) { - strcat(path, directory); - ch = path[strlen(path)-1]; - if (ch != '/' && ch != '\\') - strcat(path,"\\"); - } - if ( filename ) - if ( filename[0] ) { - strcat(path, filename); - if ( extension ) { - if ( extension[0] ) { - if ( extension[0] != '.' ) { - strcat(path,"."); - } - strcat(path,extension); - } - } - } - - TRACE("CRTDLL__makepath returns %s\n",path); + 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); } -/********************************************************************* - * _getcwd (CRTDLL.120) - */ -CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size) -{ - char test[1]; - int len; - - len = size; - if (!buf) { - if (size < 0) /* allocate as big as nescessary */ - len =GetCurrentDirectoryA(1,test) + 1; - if(!(buf = CRTDLL_malloc(len))) - { - /* set error to OutOfRange */ - return( NULL ); - } - } - size = len; - if(!(len =GetCurrentDirectoryA(len,buf))) - { - return NULL; - } - if (len > size) - { - /* set error to ERANGE */ - TRACE("CRTDLL_getcwd buffer to small\n"); - return NULL; - } - return buf; - -} - -/********************************************************************* - * _getdcwd (CRTDLL.121) - */ -CHAR* __cdecl CRTDLL__getdcwd(INT drive,LPSTR buf, INT size) -{ - char test[1]; - int len; - - FIXME("(\"%c:\",%s,%d)\n",drive+'A',buf,size); - len = size; - if (!buf) { - if (size < 0) /* allocate as big as nescessary */ - len =GetCurrentDirectoryA(1,test) + 1; - if(!(buf = CRTDLL_malloc(len))) - { - /* set error to OutOfRange */ - return( NULL ); - } - } - size = len; - if(!(len =GetCurrentDirectoryA(len,buf))) - { - return NULL; - } - if (len > size) - { - /* set error to ERANGE */ - TRACE("buffer to small\n"); - return NULL; - } - return buf; - -} - -/********************************************************************* - * _getdrive (CRTDLL.124) - * - * Return current drive, 1 for A, 2 for B - */ -INT __cdecl CRTDLL__getdrive(VOID) -{ - return DRIVE_GetCurrentDrive() + 1; -} - -/********************************************************************* - * _mkdir (CRTDLL.234) - */ -INT __cdecl CRTDLL__mkdir(LPCSTR newdir) -{ - if (!CreateDirectoryA(newdir,NULL)) - return -1; - return 0; -} - -/********************************************************************* - * remove (CRTDLL.448) - */ -INT __cdecl CRTDLL_remove(LPCSTR file) -{ - if (!DeleteFileA(file)) - return -1; - return 0; -} /********************************************************************* * _errno (CRTDLL.52) - * Yes, this is a function. - */ -LPINT __cdecl CRTDLL__errno() -{ - static int crtdllerrno; - - /* FIXME: we should set the error at the failing function call time */ - - switch(GetLastError()) - { - case ERROR_ACCESS_DENIED: crtdllerrno = EPERM; break; - case ERROR_FILE_NOT_FOUND: crtdllerrno = ENOENT; break; - case ERROR_INVALID_PARAMETER: crtdllerrno = EINVAL; break; - case ERROR_IO_DEVICE: crtdllerrno = EIO; break; - case ERROR_BAD_FORMAT: crtdllerrno = ENOEXEC; break; - case ERROR_INVALID_HANDLE: crtdllerrno = EBADF; break; - case ERROR_OUTOFMEMORY: crtdllerrno = ENOMEM; break; - case ERROR_BUSY: crtdllerrno = EBUSY; break; - case ERROR_FILE_EXISTS: crtdllerrno = EEXIST; break; - case ERROR_BAD_DEVICE: crtdllerrno = ENODEV; break; - case ERROR_TOO_MANY_OPEN_FILES: crtdllerrno = EMFILE; break; - case ERROR_DISK_FULL: crtdllerrno = ENOSPC; break; - case ERROR_SEEK_ON_DEVICE: crtdllerrno = ESPIPE; break; - case ERROR_BROKEN_PIPE: crtdllerrno = EPIPE; break; - case ERROR_POSSIBLE_DEADLOCK: crtdllerrno = EDEADLK; break; - case ERROR_FILENAME_EXCED_RANGE: crtdllerrno = ENAMETOOLONG; break; - case ERROR_DIR_NOT_EMPTY: crtdllerrno = ENOTEMPTY; break; - } - return &crtdllerrno; -} - -/********************************************************************* - * _tempnam (CRTDLL.305) - * - */ -LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix) -{ - - char *ret; - DOS_FULL_NAME tempname; - - if ((ret = tempnam(dir,prefix))==NULL) { - WARN("Unable to get unique filename\n"); - return NULL; - } - if (!DOSFS_GetFullName(ret,FALSE,&tempname)) - { - TRACE("Wrong path?\n"); - return NULL; - } - free(ret); - if ((ret = CRTDLL_malloc(strlen(tempname.short_name)+1)) == NULL) { - WARN("CRTDL_malloc for shortname failed\n"); - return NULL; - } - if ((ret = strcpy(ret,tempname.short_name)) == NULL) { - WARN("Malloc for shortname failed\n"); - return NULL; - } - - TRACE("dir %s prefix %s got %s\n", - dir,prefix,ret); - return ret; - -} -/********************************************************************* - * tmpnam (CRTDLL.490) + * Return the address of the CRT errno (Not the libc errno). * - * lcclnk from lcc-win32 relies on a terminating dot in the name returned - * + * BUGS + * Not MT safe. */ -LPSTR __cdecl CRTDLL_tmpnam(LPSTR s) +LPINT __cdecl CRTDLL__errno( VOID ) { - char *ret; - - if ((ret =tmpnam(s))== NULL) { - WARN("Unable to get unique filename\n"); - return NULL; - } - if (!DOSFS_GetFullName(ret,FALSE,&CRTDLL_tmpname)) - { - TRACE("Wrong path?\n"); - return NULL; - } - strcat(CRTDLL_tmpname.short_name,"."); - TRACE("for buf %p got %s\n", - s,CRTDLL_tmpname.short_name); - TRACE("long got %s\n", - CRTDLL_tmpname.long_name); - if ( s != NULL) - return strcpy(s,CRTDLL_tmpname.short_name); - else - return CRTDLL_tmpname.short_name; - + return &CRTDLL_errno; } -typedef VOID (*sig_handler_type)(VOID); +/********************************************************************* + * _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) */ -void * __cdecl CRTDLL_signal(int sig, sig_handler_type ptr) +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(unsigned long timeout) +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(const char *name) +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,'='); @@ -1797,37 +652,6 @@ LPSTR __cdecl CRTDLL_getenv(const char *name) return pp; } -/********************************************************************* - * _mbsrchr (CRTDLL.223) - */ -LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) { - /* FIXME: handle multibyte strings */ - return strrchr(s,x); -} - -/********************************************************************* - * __dllonexit (CRTDLL.25) - */ -VOID __cdecl CRTDLL___dllonexit () -{ - FIXME("stub\n"); -} - -/********************************************************************* - * _strdate (CRTDLL.283) - */ -LPSTR __cdecl CRTDLL__strdate (LPSTR date) -{ FIXME("%p stub\n", date); - return 0; -} - -/********************************************************************* - * _strtime (CRTDLL.299) - */ -LPSTR __cdecl CRTDLL__strtime (LPSTR date) -{ FIXME("%p stub\n", date); - return 0; -} /********************************************************************* * _except_handler2 (CRTDLL.78) @@ -1843,3 +667,386 @@ INT __cdecl CRTDLL__except_handler2 ( 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; +} diff --git a/dlls/crtdll/dir.c b/dlls/crtdll/dir.c new file mode 100644 index 00000000000..5122cb490b9 --- /dev/null +++ b/dlls/crtdll/dir.c @@ -0,0 +1,336 @@ +/* + * 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 + +#include "drive.h" +#include +#include "file.h" + +DEFAULT_DEBUG_CHANNEL(crtdll); + +/* INTERNAL: Translate find_t to PWIN32_FIND_DATAA */ +static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft); +static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft) +{ + static DWORD dummy; + + /* 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; + + ft->time_create = DOSFS_FileTimeToUnixTime(&fd->ftCreationTime,&dummy); + ft->time_access = DOSFS_FileTimeToUnixTime(&fd->ftLastAccessTime,&dummy); + ft->time_write = DOSFS_FileTimeToUnixTime(&fd->ftLastWriteTime,&dummy); + 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) +{ + if (!DRIVE_SetCurrentDrive(newdrive-1)) + { + __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)) + { + SetLastError(ERROR_INVALID_DRIVE); + __CRTDLL__set_errno(GetLastError()); + 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 */ + + 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; + + if (!drive || --drive == DRIVE_GetCurrentDrive()) + return CRTDLL__getcwd(buf,size); /* current */ + else + { + char dir[_MAX_PATH]; + char drivespec[4] = {'A', ':', '\\', 0}; + int dir_len; + + drivespec[0] += drive; + 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 */ + } + + 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) +{ + return DRIVE_GetCurrentDrive() + 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; +} diff --git a/dlls/crtdll/exit.c b/dlls/crtdll/exit.c new file mode 100644 index 00000000000..362f8823966 --- /dev/null +++ b/dlls/crtdll/exit.c @@ -0,0 +1,186 @@ +/* + * 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 +#include "process.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) +{ + CRTDLL_fprintf(CRTDLL_stderr,"\nrun-time error:\nError Code %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) +{ + FIXME("not calling CRTDLL cleanup\n"); + /* dont exit, return to caller */ +} + + +/********************************************************************* + * _cexit (CRTDLL.049) + */ +VOID __cdecl CRTDLL__cexit(VOID) +{ + FIXME("not calling CRTDLL cleanup\n"); + /* dont exit, 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; +} diff --git a/dlls/crtdll/file.c b/dlls/crtdll/file.c new file mode 100644 index 00000000000..bcad9951b5f --- /dev/null +++ b/dlls/crtdll/file.c @@ -0,0 +1,1524 @@ +/* + * CRTDLL file functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + * + * Implementation Notes: + * Mapping is performed between FILE*, fd and HANDLE's. This allows us to + * implement all calls using the Win32 API, support remapping fd's to + * FILES and do some other tricks as well (like closeall, _get_osfhandle). + * For mix and matching with the host libc, processes can use the Win32 HANDLE + * to get a real unix fd from the wineserver. Or we could do this once + * on create, and provide a function to return it quickly (store it + * in the mapping table). Note that If you actuall _do_ this, you should + * call rewind() before using any other crt functions on the file. To avoid + * the confusion I got when reading the API docs, fd is always refered + * to as a file descriptor here. In the API docs its called a file handle + * which is confusing with Win32 HANDLES. + * M$ CRT includes inline versions of some of these functions (like feof()). + * These inlines check/modify bitfields in the FILE structure, so we set + * _flags/_file/_cnt in the FILE* to be binary compatable with the win dll. + * lcc defines _IOAPPEND as one of the flags for a FILE*, but testing shows + * that M$ CRT never sets it. So we keep the flag in our mapping table but + * mask it out when we populate a FILE* with it. Then when we write we seek + * to EOF if _IOAPPEND is set for the underlying fd. + * + * FIXME: + * Not MT safe. Need locking around file access and allocation for this. + * NT has no effective limit on files - neither should we. This will be fixed + * with dynamic allocation of the file mapping array. + * Buffering is handled differently. Have to investigate a) how much control + * we have over buffering in win32, and b) if we care ;-) + */ + +#include "crtdll.h" +#include +#include +#include +#include +#include "drive.h" +#include "file.h" + + +DEFAULT_DEBUG_CHANNEL(crtdll); + +/* FIXME: Make this dynamic */ +#define CRTDLL_MAX_FILES 257 + +HANDLE __CRTDLL_handles[CRTDLL_MAX_FILES]; +CRTDLL_FILE* __CRTDLL_files[CRTDLL_MAX_FILES]; +INT __CRTDLL_flags[CRTDLL_MAX_FILES]; +CRTDLL_FILE __CRTDLL_iob[3]; + +static int __CRTDLL_fdstart = 3; /* first unallocated fd */ +static int __CRTDLL_fdend = 3; /* highest allocated fd */ + +/* INTERNAL: process umask */ +static INT __CRTDLL_umask = 0; + +/* INTERNAL: Static buffer for temp file name */ +static char CRTDLL_tmpname[MAX_PATH]; + +/* file extentions recognised as executables */ +static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e'; +static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't'; +static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd'; +static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm'; + +/* for stat mode, permissions apply to all,owner and group */ +#define CRTDLL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)) +#define CRTDLL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) +#define CRTDLL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)) + + +/* INTERNAL: Get the HANDLE for a fd */ +static HANDLE __CRTDLL__fdtoh(INT fd); +static HANDLE __CRTDLL__fdtoh(INT fd) +{ + if (fd < 0 || fd >= __CRTDLL_fdend || + __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE) + { + WARN(":fd (%d) - no handle!\n",fd); + CRTDLL_doserrno = 0; + CRTDLL_errno = EBADF; + return INVALID_HANDLE_VALUE; + } + return __CRTDLL_handles[fd]; +} + + +/* INTERNAL: free a file entry fd */ +static void __CRTDLL__free_fd(INT fd); +static void __CRTDLL__free_fd(INT fd) +{ + __CRTDLL_handles[fd] = INVALID_HANDLE_VALUE; + __CRTDLL_files[fd] = 0; + __CRTDLL_flags[fd] = 0; + TRACE(":fd (%d) freed\n",fd); + if (fd < 3) + return; /* dont use 0,1,2 for user files */ + if (fd == __CRTDLL_fdend - 1) + __CRTDLL_fdend--; + if (fd < __CRTDLL_fdstart) + __CRTDLL_fdstart = fd; +} + + +/* INTERNAL: Allocate an fd slot from a Win32 HANDLE */ +static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag); +static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag) +{ + INT fd = __CRTDLL_fdstart; + + TRACE(":handle (%d) allocating fd (%d)\n",hand,fd); + if (fd >= CRTDLL_MAX_FILES) + { + WARN(":files exhausted!\n"); + return -1; + } + __CRTDLL_handles[fd] = hand; + __CRTDLL_flags[fd] = flag; + + /* locate next free slot */ + if (fd == __CRTDLL_fdend) + __CRTDLL_fdstart = ++__CRTDLL_fdend; + else + while(__CRTDLL_fdstart < __CRTDLL_fdend && + __CRTDLL_handles[__CRTDLL_fdstart] != INVALID_HANDLE_VALUE) + __CRTDLL_fdstart++; + + return fd; +} + + +/* INTERNAL: Allocate a FILE* for an fd slot + * This is done lazily to avoid memory wastage for low level open/write + * usage when a FILE* is not requested (but may be later). + */ +static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd); +static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd) +{ + TRACE(":fd (%d) allocating FILE*\n",fd); + if (fd < 0 || fd >= __CRTDLL_fdend || + __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE) + { + WARN(":invalid fd %d\n",fd); + CRTDLL_doserrno = 0; + CRTDLL_errno = EBADF; + return NULL; + } + if (!__CRTDLL_files[fd]) + { + if ((__CRTDLL_files[fd] = CRTDLL_calloc(sizeof(CRTDLL_FILE),1))) + { + __CRTDLL_files[fd]->_file = fd; + __CRTDLL_files[fd]->_flag = __CRTDLL_flags[fd]; + __CRTDLL_files[fd]->_flag &= ~_IOAPPEND; /* mask out, see above */ + } + } + TRACE(":got FILE* (%p)\n",__CRTDLL_files[fd]); + return __CRTDLL_files[fd]; +} + + +/* INTERNAL: Set up stdin, stderr and stdout */ +VOID __CRTDLL__init_io(VOID) +{ + int i; + memset(__CRTDLL_iob,0,3*sizeof(CRTDLL_FILE)); + __CRTDLL_handles[0] = GetStdHandle(STD_INPUT_HANDLE); + __CRTDLL_flags[0] = __CRTDLL_iob[0]._flag = _IOREAD; + __CRTDLL_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE); + __CRTDLL_flags[1] = __CRTDLL_iob[1]._flag = _IOWRT; + __CRTDLL_handles[2] = GetStdHandle(STD_ERROR_HANDLE); + __CRTDLL_flags[2] = __CRTDLL_iob[2]._flag = _IOWRT; + + TRACE(":handles (%d)(%d)(%d)\n",__CRTDLL_handles[0], + __CRTDLL_handles[1],__CRTDLL_handles[2]); + + for (i = 0; i < 3; i++) + { + /* FILE structs for stdin/out/err are static and never deleted */ + __CRTDLL_files[i] = &__CRTDLL_iob[i]; + __CRTDLL_iob[i]._file = i; + } +} + + +/********************************************************************* + * _access (CRTDLL.37) + */ +INT __cdecl CRTDLL__access(LPCSTR filename, INT mode) +{ + DWORD attr = GetFileAttributesA(filename); + + if (attr == -1) + { + if (!filename) + { + /* FIXME: Should GetFileAttributesA() return this? */ + __CRTDLL__set_errno(ERROR_INVALID_DATA); + return -1; + } + __CRTDLL__set_errno(GetLastError()); + return -1; + } + if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) + { + __CRTDLL__set_errno(ERROR_ACCESS_DENIED); + return -1; + } + TRACE(":file %s, mode (%d) ok\n",filename,mode); + return 0; +} + + +/********************************************************************* + * _close (CRTDLL.57) + * + * Close an open file descriptor. + */ +INT __cdecl CRTDLL__close(INT fd) +{ + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* Dont free std FILE*'s, they are not dynamic */ + if (fd > 2 && __CRTDLL_files[fd]) + CRTDLL_free(__CRTDLL_files[fd]); + + __CRTDLL__free_fd(fd); + + if (!CloseHandle(hand)) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; + } + TRACE(":ok\n"); + return 0; +} + + +/********************************************************************* + * _commit (CRTDLL.58) + * + * Ensure all file operations have been flushed to the drive. + */ +INT __cdecl CRTDLL__commit(INT fd) +{ + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (!FlushFileBuffers(hand)) + { + if (GetLastError() == ERROR_INVALID_HANDLE) + { + /* FlushFileBuffers fails for console handles + * so we ignore this error. + */ + return 0; + } + TRACE(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; + } + TRACE(":ok\n"); + return 0; +} + + +/********************************************************************* + * _creat (CRTDLL.66) + * + * Open a file, creating it if it is not present. + */ +INT __cdecl CTRDLL__creat(LPCSTR path, INT flags) +{ + return CRTDLL__open(path,_O_CREAT|_O_WRONLY|_O_TRUNC); +} + + +/********************************************************************* + * _eof (CRTDLL.076) + * + * Determine if the file pointer is at the end of a file. + */ +/* FIXME: Care for large files */ +INT __cdecl CRTDLL__eof( INT fd ) +{ + DWORD curpos,endpos; + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* If we have a FILE* for this file, the EOF flag + * will be set by the read()/write() functions. + */ + if (__CRTDLL_files[fd]) + return __CRTDLL_files[fd]->_flag & _IOEOF; + + /* Otherwise we do it the hard way */ + curpos = SetFilePointer( hand, 0, NULL, SEEK_CUR ); + endpos = SetFilePointer( hand, 0, NULL, FILE_END ); + + if (curpos == endpos) + return TRUE; + + SetFilePointer( hand, curpos, 0, FILE_BEGIN); + return FALSE; +} + + +/********************************************************************* + * _fcloseall (CRTDLL.089) + * + * Close all open files except stdin/stdout/stderr. + */ +INT __cdecl CRTDLL__fcloseall(VOID) +{ + int num_closed = 0, i = 3; + + while(i < __CRTDLL_fdend) + if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE) + { + CRTDLL__close(i); + num_closed++; + } + + TRACE(":closed (%d) handles\n",num_closed); + return num_closed; +} + + +/********************************************************************* + * _fdopen (CRTDLL.091) + * + * Get a FILE* from a low level file descriptor. + */ +CRTDLL_FILE* __cdecl CRTDLL__fdopen(INT fd, LPCSTR mode) +{ + CRTDLL_FILE* file = __CRTDLL__alloc_fp(fd); + + TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file); + if (file) + CRTDLL_rewind(file); + + return file; +} + + +/********************************************************************* + * _fgetchar (CRTDLL.092) + */ +INT __cdecl CRTDLL__fgetchar( VOID ) +{ + return CRTDLL_fgetc(CRTDLL_stdin); +} + + +/********************************************************************* + * _filbuf (CRTDLL.094) + * + * NOTES + * The macro version of getc calls this function whenever FILE->_cnt + * becomes negative. We ensure that _cnt is always 0 after any read + * so this function is always called. Our implementation simply calls + * fgetc as all the underlying buffering is handled by Wines + * implementation of the Win32 file I/O calls. + */ +INT __cdecl CRTDLL__filbuf(CRTDLL_FILE* file) +{ + return CRTDLL_fgetc(file); +} + + +/********************************************************************* + * _fileno (CRTDLL.097) + * + * Get the file descriptor from a FILE*. + * + * NOTES + * This returns the CRTDLL fd, _not_ the underlying *nix fd. + */ +INT __cdecl CRTDLL__fileno(CRTDLL_FILE* file) +{ + TRACE(":FILE* (%p) fd (%d)\n",file,file->_file); + return file->_file; +} + + +/********************************************************************* + * _flsbuf (CRTDLL.102) + * + * NOTES + * The macro version of putc calls this function whenever FILE->_cnt + * becomes negative. We ensure that _cnt is always 0 after any write + * so this function is always called. Our implementation simply calls + * fputc as all the underlying buffering is handled by Wines + * implementation of the Win32 file I/O calls. + */ +INT __cdecl CRTDLL__flsbuf(INT c, CRTDLL_FILE* file) +{ + return CRTDLL_fputc(c,file); +} + + +/********************************************************************* + * _flushall (CRTDLL.103) + * + * Flush all open files. + */ +INT __cdecl CRTDLL__flushall(VOID) +{ + int num_flushed = 0, i = 3; + + while(i < __CRTDLL_fdend) + if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE) + { + if (CRTDLL__commit(i) == -1) + if (__CRTDLL_files[i]) + __CRTDLL_files[i]->_flag |= _IOERR; + num_flushed++; + } + + TRACE(":flushed (%d) handles\n",num_flushed); + return num_flushed; +} + + +/********************************************************************* + * _fputchar (CRTDLL.108) + * + * Put a character to a file. + */ +INT __cdecl CRTDLL__fputchar(INT c) +{ + return CRTDLL_fputc(c, CRTDLL_stdout); +} + + +/********************************************************************* + * _fsopen (CRTDLL.110) + * + * Open a FILE* with sharing. + */ +CRTDLL_FILE* __cdecl CRTDLL__fsopen(LPCSTR path, LPCSTR mode, INT share) +{ + FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share); + return CRTDLL_fopen(path,mode); +} + + +/********************************************************************* + * _fstat (CRTDLL.111) + * + * Get information about an open file. + */ +int __cdecl CRTDLL__fstat(int fd, struct _stat* buf) +{ + static DWORD dummy; + BY_HANDLE_FILE_INFORMATION hfi; + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) stat (%p)\n",fd,buf); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (!buf) + { + WARN(":failed-NULL buf\n"); + __CRTDLL__set_errno(ERROR_INVALID_PARAMETER); + return -1; + } + + memset(&hfi, 0, sizeof(hfi)); + memset(buf, 0, sizeof(struct _stat)); + if (!GetFileInformationByHandle(hand, &hfi)) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(ERROR_INVALID_PARAMETER); + return -1; + } + FIXME(":dwFileAttributes = %d, mode set to 0",hfi.dwFileAttributes); + buf->st_nlink = hfi.nNumberOfLinks; + buf->st_size = hfi.nFileSizeLow; + buf->st_atime = DOSFS_FileTimeToUnixTime(&hfi.ftCreationTime,&dummy); + buf->st_mtime = DOSFS_FileTimeToUnixTime(&hfi.ftLastAccessTime,&dummy); + buf->st_ctime = DOSFS_FileTimeToUnixTime(&hfi.ftLastWriteTime,&dummy); + return 0; +} + + +/********************************************************************* + * _get_osfhandle (CRTDLL.117) + * + * Return a Win32 HANDLE from a file descriptor. + * + * PARAMS + * fd [in] A valid file descriptor + * + * RETURNS + * Success: A Win32 HANDLE + * + * Failure: INVALID_HANDLE_VALUE. + * + */ +HANDLE CRTDLL__get_osfhandle(INT fd) +{ + HANDLE hand = __CRTDLL__fdtoh(fd); + HANDLE newhand = hand; + TRACE(":fd (%d) handle (%d)\n",fd,hand); + + if (hand != INVALID_HANDLE_VALUE) + { + /* FIXME: I'm not convinced that I should be copying the + * handle here - it may be leaked if the app doesn't + * close it (and the API docs dont say that it should) + * Not duplicating it means that it can't be inherited + * and so lcc's wedit doesn't cope when it passes it to + * child processes. I've an idea that it should either + * be copied by CreateProcess, or marked as inheritable + * when initialised, or maybe both? JG 21-9-00. + */ + DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(), + &newhand,0,TRUE,DUPLICATE_SAME_ACCESS ); + } + return newhand; +} + + +/********************************************************************* + * _isatty (CRTDLL.137) + * + * Return non zero if fd is a character device (e.g console). + */ +INT __cdecl CRTDLL__isatty(INT fd) +{ + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return 0; + + return GetFileType(fd) == FILE_TYPE_CHAR? 1 : 0; +} + + +/********************************************************************* + * _lseek (CRTDLL.179) + * + * Move the file pointer within a file. + */ +LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence) +{ + LONG ret; + HANDLE hand = __CRTDLL__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (whence < 0 || whence > 2) + { + CRTDLL_errno = EINVAL; + return -1; + } + + TRACE(":fd (%d) to 0x%08lx pos %s\n", + fd,offset,(whence==SEEK_SET)?"SEEK_SET": + (whence==SEEK_CUR)?"SEEK_CUR": + (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); + + if ((ret = SetFilePointer( hand, offset, NULL, whence )) != 0xffffffff) + { + if ( __CRTDLL_files[fd]) + __CRTDLL_files[fd]->_flag &= ~_IOEOF; + /* FIXME: What if we seek _to_ EOF - is EOF set? */ + return ret; + } + TRACE(":error-last error (%ld)\n",GetLastError()); + if ( __CRTDLL_files[fd]) + switch(GetLastError()) + { + case ERROR_NEGATIVE_SEEK: + case ERROR_SEEK_ON_DEVICE: + __CRTDLL__set_errno(GetLastError()); + __CRTDLL_files[fd]->_flag |= _IOERR; + break; + default: + break; + } + return -1; +} + + +/********************************************************************* + * _open (CRTDLL.239) + * Open a file. + */ +INT __cdecl CRTDLL__open(LPCSTR path,INT flags) +{ + DWORD access = 0, creation = 0; + INT ioflag = 0, fd; + HANDLE hand; + + TRACE(":file (%s) mode 0x%04x\n",path,flags); + + switch(flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) + { + case _O_RDONLY: + access |= GENERIC_READ; + ioflag |= _IOREAD; + break; + case _O_WRONLY: + access |= GENERIC_WRITE; + ioflag |= _IOWRT; + break; + case _O_RDWR: + access |= GENERIC_WRITE | GENERIC_READ; + ioflag |= _IORW; + break; + } + + if (flags & _O_CREAT) + { + if (flags & _O_EXCL) + creation = CREATE_NEW; + else if (flags & _O_TRUNC) + creation = CREATE_ALWAYS; + else + creation = OPEN_ALWAYS; + } + else /* no _O_CREAT */ + { + if (flags & _O_TRUNC) + creation = TRUNCATE_EXISTING; + else + creation = OPEN_EXISTING; + } + if (flags & _O_APPEND) + ioflag |= _IOAPPEND; + + + flags |= _O_BINARY; /* FIXME: Default to text */ + + if (flags & _O_TEXT) + { + /* Dont warn when writing */ + if (ioflag & GENERIC_READ) + FIXME(":TEXT node not implemented\n"); + flags &= ~_O_TEXT; + } + + if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL|_O_CREAT|_O_RDWR)) + TRACE(":unsupported flags 0x%04x\n",flags); + + /* clear those pesky flags ;-) */ + flags &= (_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL|_O_CREAT|_O_RDWR); + + hand = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, creation, FILE_ATTRIBUTE_NORMAL, -1); + + if (hand == INVALID_HANDLE_VALUE) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; + } + + fd = __CRTDLL__alloc_fd(hand,ioflag); + + TRACE(":fd (%d) handle (%d)\n",fd, hand); + + if (flags & _IOAPPEND && fd > 0) + CRTDLL__lseek(fd, 0, FILE_END ); + + return fd; +} + + +/********************************************************************* + * _open_osfhandle (CRTDLL.240) + * + * Create a file descriptor for a file HANDLE. + */ +INT __cdecl CRTDLL__open_osfhandle(HANDLE hand, INT flags) +{ + INT fd = __CRTDLL__alloc_fd(hand,flags); + TRACE(":handle (%d) fd (%d)\n",hand,fd); + return fd; +} + + +/********************************************************************* + * _read (CRTDLL.256) + * + * Read data from a file. + */ +INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count) +{ + DWORD num_read; + HANDLE hand = __CRTDLL__fdtoh(fd); + + /* Dont trace small reads, it gets *very* annoying */ + if (count > 4) + TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* Set _cnt to 0 so optimised binaries will call our implementation + * of putc/getc. See _filbuf/_flsbuf comments. + */ + if (__CRTDLL_files[fd]) + __CRTDLL_files[fd]->_cnt = 0; + + if (ReadFile(hand, buf, count, &num_read, NULL)) + { + if (num_read != count && __CRTDLL_files[fd]) + { + TRACE(":EOF\n"); + __CRTDLL_files[fd]->_flag |= _IOEOF; + } + return num_read; + } + TRACE(":failed-last error (%ld)\n",GetLastError()); + if ( __CRTDLL_files[fd]) + __CRTDLL_files[fd]->_flag |= _IOERR; + return -1; +} + + +/********************************************************************* + * _setmode (CRTDLL.265) + * + * FIXME: At present we ignore the request to translate CR/LF to LF. + * + * We always translate when we read with fgets, we never do with fread + * + */ +INT __cdecl CRTDLL__setmode(INT fd,INT mode) +{ + if (mode & _O_TEXT) + FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode); + return 0; +} + + +/********************************************************************* + * _stat (CRTDLL.280) + */ +INT __cdecl CRTDLL__stat(const char* path, struct _stat * buf) +{ + static DWORD dummy; + DOS_FULL_NAME full_name; + BY_HANDLE_FILE_INFORMATION hfi; + unsigned short mode = CRTDLL_S_IREAD; + int plen; + + TRACE(":file (%s) buf(%p)\n",path,buf); + if (!DOSFS_GetFullName( path, TRUE, &full_name )) + { + TRACE("failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return -1; + } + + memset(&hfi,0,sizeof(hfi)); + + if (!FILE_Stat(full_name.long_name,&hfi)) + { + TRACE("failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return -1; + } + + memset(buf,0,sizeof(struct _stat)); + + /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */ + if (isalpha(*path)) + buf->st_dev = buf->st_rdev = toupper(*path - 'A'); /* drive num */ + else + buf->st_dev = buf->st_rdev = DRIVE_GetCurrentDrive(); + + plen = strlen(path); + + /* Dir, or regular file? */ + if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || + (path[plen-1] == '\\')) + mode |= (_S_IFDIR | CRTDLL_S_IEXEC); + else + { + mode |= _S_IFREG; + /* executable? */ + if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */ + { + unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) + | (tolower(path[plen-3]) << 16); + if (ext == EXE || ext == BAT || ext == CMD || ext == COM) + mode |= CRTDLL_S_IEXEC; + } + } + + if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + mode |= CRTDLL_S_IWRITE; + + buf->st_mode = mode; + buf->st_nlink = hfi.nNumberOfLinks; + buf->st_size = hfi.nFileSizeLow; + buf->st_atime = DOSFS_FileTimeToUnixTime(&hfi.ftCreationTime,&dummy); + buf->st_mtime = + buf->st_ctime = DOSFS_FileTimeToUnixTime(&hfi.ftLastWriteTime,&dummy); + TRACE("\n%d %d %d %d %d %d\n", buf->st_mode,buf->st_nlink,buf->st_size, + buf->st_atime,buf->st_mtime, buf->st_ctime); + return 0; +} + + +/********************************************************************* + * _tell (CRTDLL.302) + * + * Get current file position. + */ +LONG __cdecl CRTDLL__tell(INT fd) +{ + return CRTDLL__lseek(fd, 0, SEEK_CUR); +} + + +/********************************************************************* + * _tempnam (CRTDLL.305) + * + */ +LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix) +{ + char tmpbuf[MAX_PATH]; + + TRACE("dir (%s) prefix (%s)\n",dir,prefix); + if (GetTempFileNameA(dir,prefix,0,tmpbuf)) + { + TRACE("got name (%s)\n",tmpbuf); + return CRTDLL__strdup(tmpbuf); + } + TRACE("failed-last error (%ld)\n",GetLastError()); + return NULL; +} + + +/********************************************************************* + * _umask (CRTDLL.310) + * + * Set the process-wide umask. + */ +INT __cdecl CRTDLL__umask(INT umask) +{ + INT old_umask = __CRTDLL_umask; + TRACE("umask (%d)\n",umask); + __CRTDLL_umask = umask; + return old_umask; +} + + +/********************************************************************* + * _unlink (CRTDLL.315) + * + * Delete a file. + */ +INT __cdecl CRTDLL__unlink(LPCSTR path) +{ + TRACE("path (%s)\n",path); + if(DeleteFileA( path )) + return 0; + + TRACE("failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; +} + + +/********************************************************************* + * _write (CRTDLL.332) + * + * Write data to a file. + */ +UINT __cdecl CRTDLL__write(INT fd, LPCVOID buf, UINT count) +{ + DWORD num_written; + HANDLE hand = __CRTDLL__fdtoh(fd); + + /* Dont trace small writes, it gets *very* annoying */ + if (count > 4) + TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* If appending, go to EOF */ + if (__CRTDLL_flags[fd] & _IOAPPEND) + CRTDLL__lseek(fd, 0, FILE_END ); + + /* Set _cnt to 0 so optimised binaries will call our implementation + * of putc/getc. See _filbuf/_flsbuf comments. + */ + if (__CRTDLL_files[fd]) + __CRTDLL_files[fd]->_cnt = 0; + + if (WriteFile(hand, buf, count, &num_written, NULL) + && (num_written == count)) + return num_written; + + TRACE(":failed-last error (%ld)\n",GetLastError()); + if ( __CRTDLL_files[fd]) + __CRTDLL_files[fd]->_flag |= _IOERR; + + return -1; +} + + +/********************************************************************* + * clearerr (CRTDLL.349) + * + * Clear a FILE's error indicator. + */ +VOID __cdecl CRTDLL_clearerr(CRTDLL_FILE* file) +{ + TRACE(":file (%p) fd (%d)\n",file,file->_file); + file->_flag &= ~(_IOERR | _IOEOF); +} + + +/********************************************************************* + * fclose (CRTDLL.362) + * + * Close an open file. + */ +INT __cdecl CRTDLL_fclose( CRTDLL_FILE* file ) +{ + return CRTDLL__close(file->_file); +} + + +/********************************************************************* + * feof (CRTDLL.363) + * + * Check the eof indicator on a file. + */ +INT __cdecl CRTDLL_feof( CRTDLL_FILE* file ) +{ + return file->_flag & _IOEOF; +} + + +/********************************************************************* + * ferror (CRTDLL.361) + * + * Check the error indicator on a file. + */ +INT __cdecl CRTDLL_ferror( CRTDLL_FILE* file ) +{ + return file->_flag & _IOERR; +} + + +/********************************************************************* + * fflush (CRTDLL.362) + */ +INT __cdecl CRTDLL_fflush( CRTDLL_FILE* file ) +{ + return CRTDLL__commit(file->_file); +} + + +/********************************************************************* + * fgetc (CRTDLL.363) + */ +INT __cdecl CRTDLL_fgetc( CRTDLL_FILE* file ) +{ + char c; + if (CRTDLL__read(file->_file,&c,1) != 1) + return EOF; + return c; +} + + +/********************************************************************* + * fgetpos (CRTDLL.364) + */ +INT __cdecl CRTDLL_fgetpos( CRTDLL_FILE* file, fpos_t *pos) +{ + *pos = CRTDLL__tell(file->_file); + return (*pos == -1? -1 : 0); +} + + +/********************************************************************* + * fgets (CRTDLL.365) + */ +CHAR* __cdecl CRTDLL_fgets(LPSTR s, INT size, CRTDLL_FILE* file) +{ + int cc; + LPSTR buf_start = s; + + TRACE(":file(%p) fd (%d) str (%p) len (%d)\n", + file,file->_file,s,size); + + /* BAD, for the whole WINE process blocks... just done this way to test + * windows95's ftp.exe. + * JG - Is this true now we use ReadFile() on stdin too? + */ + for(cc = CRTDLL_fgetc(file); cc != EOF && cc != '\n'; + cc = CRTDLL_fgetc(file)) + if (cc != '\r') + { + if (--size <= 0) break; + *s++ = (char)cc; + } + if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/ + { + TRACE(":nothing read\n"); + return 0; + } + if (cc == '\n') + if (--size > 0) + *s++ = '\n'; + *s = '\0'; + TRACE(":got '%s'\n", buf_start); + return buf_start; +} + + +/********************************************************************* + * fputs (CRTDLL.375) + */ +INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE* file ) +{ + return CRTDLL_fwrite(s,strlen(s),1,file); +} + + +/********************************************************************* + * fprintf (CRTDLL.370) + */ +INT __cdecl CRTDLL_fprintf( CRTDLL_FILE* file, LPCSTR format, ... ) +{ + va_list valist; + INT res; + + va_start( valist, format ); + res = CRTDLL_vfprintf( file, format, valist ); + va_end( valist ); + return res; +} + + +/********************************************************************* + * fopen (CRTDLL.372) + * + * Open a file. + */ +CRTDLL_FILE* __cdecl CRTDLL_fopen(LPCSTR path, LPCSTR mode) +{ + CRTDLL_FILE* file; + INT flags = 0, plus = 0, fd; + const char* search = mode; + + TRACE(":path (%s) mode (%s)\n",path,mode); + + while (*search) + if (*search++ == '+') + plus = 1; + + /* map mode string to open() flags. "man fopen" for possibilities. */ + switch(*mode++) + { + case 'R': case 'r': + flags = (plus ? _O_RDWR : _O_RDONLY); + break; + case 'W': case 'w': + flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY); + break; + case 'A': case 'a': + flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY); + break; + default: + return NULL; + } + + while (*mode) + switch (*mode++) + { + case 'B': case 'b': + flags |= _O_BINARY; + flags &= ~_O_TEXT; + break; + case 'T': case 't': + flags |= _O_TEXT; + flags &= ~_O_BINARY; + break; + case '+': + break; + default: + FIXME(":unknown flag %c not supported\n",mode[-1]); + } + + fd = CRTDLL__open(path, flags); + + if (fd < 0) + return NULL; + + file = __CRTDLL__alloc_fp(fd); + TRACE(":get file (%p)\n",file); + if (!file) + CRTDLL__close(fd); + + return file; +} + + +/********************************************************************* + * fputc (CRTDLL.374) + */ +INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE* file ) +{ + return CRTDLL__write(file->_file, &c, 1) == 1? c : EOF; +} + + +/********************************************************************* + * fread (CRTDLL.377) + */ +DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file) +{ + DWORD read = CRTDLL__read(file->_file,ptr, size * nmemb); + if (read <= 0) + return 0; + return read / size; +} + + +/********************************************************************* + * freopen (CRTDLL.379) + * + */ +CRTDLL_FILE* __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode,CRTDLL_FILE* file) +{ + CRTDLL_FILE* newfile; + INT fd; + + TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file); + if (!file || ((fd = file->_file) < 0) || fd > __CRTDLL_fdend) + return NULL; + + if (fd > 2) + { + FIXME(":reopen on user file not implemented!\n"); + __CRTDLL__set_errno(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; + } + + /* first, create the new file */ + if ((newfile = CRTDLL_fopen(path,mode)) == NULL) + return NULL; + + if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE : + (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), + __CRTDLL_handles[newfile->_file])) + { + /* Redirecting std handle to file , copy over.. */ + __CRTDLL_handles[fd] = __CRTDLL_handles[newfile->_file]; + __CRTDLL_flags[fd] = __CRTDLL_flags[newfile->_file]; + memcpy(&__CRTDLL_iob[fd], newfile, sizeof (CRTDLL_FILE)); + __CRTDLL_iob[fd]._file = fd; + /* And free up the resources allocated by fopen, but + * not the HANDLE we copied. */ + CRTDLL_free(__CRTDLL_files[fd]); + __CRTDLL__free_fd(newfile->_file); + return &__CRTDLL_iob[fd]; + } + + WARN(":failed-last error (%ld)\n",GetLastError()); + CRTDLL_fclose(newfile); + __CRTDLL__set_errno(GetLastError()); + return NULL; +} + + +/********************************************************************* + * fsetpos (CRTDLL.380) + */ +INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE* file, fpos_t *pos) +{ + return CRTDLL__lseek(file->_file,*pos,SEEK_SET); +} + + +/********************************************************************* + * fscanf (CRTDLL.381) + */ +INT __cdecl CRTDLL_fscanf( CRTDLL_FILE* file, LPSTR format, ... ) +{ + INT rd = 0; + int nch; + va_list ap; + if (!*format) return 0; + WARN("%p (\"%s\"): semi-stub\n", file, format); + nch = CRTDLL_fgetc(file); + va_start(ap, format); + while (*format) { + if (*format == ' ') { + /* skip whitespace */ + while ((nch!=EOF) && isspace(nch)) + nch = CRTDLL_fgetc(file); + } + else if (*format == '%') { + int st = 0; + format++; + switch(*format) { + case 'd': { /* read an integer */ + int*val = va_arg(ap, int*); + int cur = 0; + /* skip initial whitespace */ + while ((nch!=EOF) && isspace(nch)) + nch = CRTDLL_fgetc(file); + /* get sign and first digit */ + if (nch == '-') { + nch = CRTDLL_fgetc(file); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + nch = CRTDLL_fgetc(file); + /* read until no more digits */ + while ((nch!=EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = CRTDLL_fgetc(file); + } + st = 1; + *val = cur; + } + break; + case 'f': { /* read a float */ + float*val = va_arg(ap, float*); + float cur = 0; + /* skip initial whitespace */ + while ((nch!=EOF) && isspace(nch)) + nch = CRTDLL_fgetc(file); + /* get sign and first digit */ + if (nch == '-') { + nch = CRTDLL_fgetc(file); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + /* read until no more digits */ + while ((nch!=EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = CRTDLL_fgetc(file); + } + if (nch == '.') { + /* handle decimals */ + float dec = 1; + nch = CRTDLL_fgetc(file); + while ((nch!=EOF) && isdigit(nch)) { + dec /= 10; + cur += dec * (nch - '0'); + nch = CRTDLL_fgetc(file); + } + } + st = 1; + *val = cur; + } + break; + case 's': { /* read a word */ + char*str = va_arg(ap, char*); + char*sptr = str; + /* skip initial whitespace */ + while ((nch!=EOF) && isspace(nch)) + nch = CRTDLL_fgetc(file); + /* read until whitespace */ + while ((nch!=EOF) && !isspace(nch)) { + *sptr++ = nch; st++; + nch = CRTDLL_fgetc(file); + } + /* terminate */ + *sptr = 0; + TRACE("read word: %s\n", str); + } + break; + default: FIXME("unhandled: %%%c\n", *format); + } + if (st) rd++; + else break; + } + else { + /* check for character match */ + if (nch == *format) + nch = CRTDLL_fgetc(file); + else break; + } + format++; + } + va_end(ap); + if (nch!=EOF) { + WARN("need ungetch\n"); + } + TRACE("returning %d\n", rd); + return rd; +} + + +/********************************************************************* + * fseek (CRTDLL.382) + */ +LONG __cdecl CRTDLL_fseek( CRTDLL_FILE* file, LONG offset, INT whence) +{ + return CRTDLL__lseek(file->_file,offset,whence); +} + + +/********************************************************************* + * ftell (CRTDLL.381) + */ +LONG __cdecl CRTDLL_ftell( CRTDLL_FILE* file ) +{ + return CRTDLL__tell(file->_file); +} + + +/********************************************************************* + * fwrite (CRTDLL.383) + */ +UINT __cdecl CRTDLL_fwrite( LPCVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file ) +{ + UINT written = CRTDLL__write(file->_file, ptr, size * nmemb); + if (written <= 0) + return 0; + return written / size; +} + + +/********************************************************************* + * getchar (CRTDLL.386) + */ +INT __cdecl CRTDLL_getchar( VOID ) +{ + return CRTDLL_fgetc(CRTDLL_stdin); +} + + +/********************************************************************* + * getc (CRTDLL.388) + */ +INT __cdecl CRTDLL_getc( CRTDLL_FILE* file ) +{ + return CRTDLL_fgetc( file ); +} + + +/********************************************************************* + * gets (CRTDLL.391) + */ +LPSTR __cdecl CRTDLL_gets(LPSTR buf) +{ + int cc; + LPSTR buf_start = buf; + + /* BAD, for the whole WINE process blocks... just done this way to test + * windows95's ftp.exe. + * JG 19/9/00: Is this still true, now we are using ReadFile? + */ + for(cc = CRTDLL_fgetc(CRTDLL_stdin); cc != EOF && cc != '\n'; + cc = CRTDLL_fgetc(CRTDLL_stdin)) + if(cc != '\r') *buf++ = (char)cc; + + *buf = '\0'; + + TRACE("got '%s'\n", buf_start); + return buf_start; +} + + +/********************************************************************* + * putc (CRTDLL.441) + */ +INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE* file ) +{ + return CRTDLL_fputc( c, file ); +} + + +/********************************************************************* + * putchar (CRTDLL.442) + */ +void __cdecl CRTDLL_putchar( INT c ) +{ + CRTDLL_fputc(c, CRTDLL_stdout); +} + + +/********************************************************************* + * puts (CRTDLL.443) + */ +INT __cdecl CRTDLL_puts(LPCSTR s) +{ + return CRTDLL_fputs(s, CRTDLL_stdout); +} + + +/********************************************************************* + * rewind (CRTDLL.447) + * + * Set the file pointer to the start of a file and clear any error + * indicators. + */ +VOID __cdecl CRTDLL_rewind(CRTDLL_FILE* file) +{ + TRACE(":file (%p) fd (%d)\n",file,file->_file); + CRTDLL__lseek(file->_file,0,SEEK_SET); + file->_flag &= ~(_IOEOF | _IOERR); +} + + +/********************************************************************* + * remove (CRTDLL.448) + */ +INT __cdecl CRTDLL_remove(LPCSTR path) +{ + TRACE(":path (%s)\n",path); + if (DeleteFileA(path)) + return 0; + TRACE(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; +} + + +/********************************************************************* + * rename (CRTDLL.449) + */ +INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath) +{ + TRACE(":from %s to %s\n",oldpath,newpath); + if (MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) + return 0; + TRACE(":failed-last error (%ld)\n",GetLastError()); + __CRTDLL__set_errno(GetLastError()); + return -1; +} + + +/********************************************************************* + * setbuf (CRTDLL.452) + */ +INT __cdecl CRTDLL_setbuf(CRTDLL_FILE* file, LPSTR buf) +{ + TRACE(":file (%p) fd (%d) buf (%p)\n", file, file->_file,buf); + if (buf) + WARN(":user buffer will not be used!\n"); + /* FIXME: no buffering for now */ + return 0; +} + + +/********************************************************************* + * tmpnam (CRTDLL.490) + * + * lcclnk from lcc-win32 relies on a terminating dot in the name returned + * + */ +LPSTR __cdecl CRTDLL_tmpnam(LPSTR s) +{ + char tmpbuf[MAX_PATH]; + char* prefix = "TMP"; + if (!GetTempPathA(MAX_PATH,tmpbuf) || + !GetTempFileNameA(tmpbuf,prefix,0,CRTDLL_tmpname)) + { + TRACE(":failed-last error (%ld)\n",GetLastError()); + return NULL; + } + TRACE(":got tmpnam %s\n",CRTDLL_tmpname); + return CRTDLL_tmpname; +} + + +/********************************************************************* + * vfprintf (CRTDLL.494) + * + * Write formatted output to a file. + */ +/* we have avoided libc stdio.h so far, lets not start now */ +extern int vsprintf(void *, const void *, va_list); + +INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE* file, LPCSTR format, va_list args ) +{ + /* FIXME: We should parse the format string, calculate the maximum, + * length of each arg, malloc a buffer, print to it, and fwrite that. + * Yes this sucks, but not as much as crashing 1/2 way through an + * app writing to a file :-( + */ + char buffer[2048]; + TRACE(":file (%p) fd (%d) fmt (%s)\n",file,file->_file,format); + + vsprintf( buffer, format, args ); + return CRTDLL_fwrite( buffer, 1, strlen(buffer), file ); +} + diff --git a/dlls/crtdll/mbstring.c b/dlls/crtdll/mbstring.c index 4927d21d193..f61d7702421 100644 --- a/dlls/crtdll/mbstring.c +++ b/dlls/crtdll/mbstring.c @@ -4,12 +4,31 @@ * Copyright 1999 Alexandre Julliard */ -#include "windef.h" -#include "winbase.h" -#include "winnls.h" #include "crtdll.h" +DEFAULT_DEBUG_CHANNEL(crtdll); + + +/********************************************************************* + * _mbsicmp (CRTDLL.204) + */ +int __cdecl CRTDLL__mbsicmp(unsigned char *x,unsigned char *y) +{ + do { + if (!*x) + return !!*y; + if (!*y) + return !!*x; + /* FIXME: MBCS handling... */ + if (*x!=*y) + return 1; + x++; + y++; + } while (1); +} + + /********************************************************************* * CRTDLL__mbsinc (CRTDLL.205) */ @@ -31,6 +50,17 @@ INT __cdecl CRTDLL__mbslen( LPCSTR str ) } + +/********************************************************************* + * _mbsrchr (CRTDLL.223) + */ +LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) +{ + /* FIXME: handle multibyte strings */ + return strrchr(s,x); +} + + /********************************************************************* * CRTDLL_mbtowc (CRTDLL.430) */ @@ -44,3 +74,16 @@ INT __cdecl CRTDLL_mbtowc( WCHAR *dst, LPCSTR str, INT n ) if (n >= 2 && IsDBCSLeadByte(*str) && str[1]) return 2; return 1; } + + +/********************************************************************* + * _mbccpy (CRTDLL.??) + * + * Copy one multibyte character to another + */ +VOID __cdecl CRTDLL__mbccpy(LPSTR dest, LPSTR src) +{ + FIXME("MBCS copy treated as ASCII\n"); + *dest = *src; +} + diff --git a/dlls/crtdll/memory.c b/dlls/crtdll/memory.c new file mode 100644 index 00000000000..b6192e047fb --- /dev/null +++ b/dlls/crtdll/memory.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#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 ); +} + + +/********************************************************************* + * _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 ); +} diff --git a/dlls/crtdll/spawn.c b/dlls/crtdll/spawn.c new file mode 100644 index 00000000000..20c308e068f --- /dev/null +++ b/dlls/crtdll/spawn.c @@ -0,0 +1,225 @@ +/* + * 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. + * -Wine has a "process.h" which is not the same as any crt version. + * 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 +#include "process.h" +#include "options.h" +#include + + +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, LPSTR exe, LPSTR args, LPSTR env); +static int __CRTDLL__spawn(INT flags, LPSTR 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(LPSTR *arg, CHAR delim); +static LPSTR __CRTDLL__argvtos(LPSTR *arg, CHAR delim) +{ + LPSTR *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; +} + + +/********************************************************************* + * _spawnve (CRTDLL.274) + * + * Spawn a process. + * + */ +HANDLE __cdecl CRTDLL__spawnve(INT flags, LPSTR name, LPSTR *argv, LPSTR *envv) +{ + LPSTR args = __CRTDLL__argvtos(argv,' '); + LPSTR envs = __CRTDLL__argvtos(envv,0); + LPSTR fullname = name; + + 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) + { + HANDLE ret = __CRTDLL__spawn(flags, fullname, args, envs); + CRTDLL_free(args); + CRTDLL_free(envs); + return ret; + } + if (envs) + CRTDLL_free(envs); + + WARN(":No argv[0] passed - process will not be executed"); + return -1; +} + + +/********************************************************************* + * system (CRTDLL.485) + */ +INT __cdecl CRTDLL_system(LPSTR x) +{ +#define SYSBUF_LENGTH 1500 + char buffer[SYSBUF_LENGTH]; + unsigned char *y = x; + unsigned char *bp; + int i; + + strcpy(buffer, argv0); + bp = buffer + strlen(buffer); + *bp++ = ' '; + *bp++ = '"'; + *bp++ = 0; + i = strlen(buffer) + strlen(x) +2; + + /* Calculate needed buffer size to prevent overflow. */ + while (*y) { + if (*y =='\\') i++; + y++; + } + /* If buffer too short, exit. */ + if (i > SYSBUF_LENGTH) { + TRACE("_system buffer to small\n"); + return 127; + } + + y =x; + + while (*y) { + *bp = *y; + bp++; y++; + if (*(y-1) =='\\') *bp++ = '\\'; + } + /* Remove spaces from end of string. */ + while (*(y-1) == ' ') { + bp--;y--; + } + *bp++ = '"'; + *bp = 0; + TRACE("_system got '%s', executing '%s'\n",x,buffer); + + return system(buffer); +} diff --git a/dlls/crtdll/string.c b/dlls/crtdll/string.c new file mode 100644 index 00000000000..1e5099e6f66 --- /dev/null +++ b/dlls/crtdll/string.c @@ -0,0 +1,192 @@ +/* + * 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! */ + 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; +} + + +/********************************************************************* + * _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++; + } + } +} diff --git a/dlls/crtdll/time.c b/dlls/crtdll/time.c new file mode 100644 index 00000000000..cc2b026c738 --- /dev/null +++ b/dlls/crtdll/time.c @@ -0,0 +1,120 @@ +/* + * 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 "process.h" +#include "options.h" +#include +#include + + +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; +} diff --git a/dlls/crtdll/wcstring.c b/dlls/crtdll/wcstring.c index cbc480526d6..09e28e19d44 100644 --- a/dlls/crtdll/wcstring.c +++ b/dlls/crtdll/wcstring.c @@ -4,18 +4,13 @@ * Copyright 1999 Alexandre Julliard */ -#include "config.h" - +#include "crtdll.h" #include #include #include - -#include "windef.h" -#include "winbase.h" #include "winnls.h" #include "wine/unicode.h" -#include "crtdll.h" -#include "debugtools.h" + DEFAULT_DEBUG_CHANNEL(crtdll); diff --git a/tools/winapi_check/win32/crtdll.api b/tools/winapi_check/win32/crtdll.api index 3b25e00d154..bc898a4c359 100644 --- a/tools/winapi_check/win32/crtdll.api +++ b/tools/winapi_check/win32/crtdll.api @@ -11,6 +11,7 @@ HANDLE HFILE INT LONG +ULONG UINT WCHAR clock_t @@ -32,6 +33,7 @@ LPCVOID LPDWORD LPDWORD * LPINT +LPUINT LPSTR * LPSTR ** LPVOID @@ -44,10 +46,13 @@ WCHAR * _INITTERMFUN * char * jmp_buf -struct find_t * -struct stat * +find_t * +struct _stat * struct win_stat * +struct _timeb * time_t * +fpos_t * +diskfree_t * unsigned char * va_list void * @@ -71,3 +76,7 @@ LPWSTR new_handler_type sig_handler_type +comp_func +struct complex +atexit_function +