Commit d3576a9f authored by Jon Griffiths's avatar Jon Griffiths Committed by Alexandre Julliard

- Implemented 73 CRT functions

- Reimplemented file I/O using Win32 calls - Set errno/doserrno in most calls
parent b56a8df9
......@@ -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@
......
#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 <time.h>
#include <stdarg.h>
#include <setjmp.h>
#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
/* _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);
void __cdecl *CRTDLL_malloc( DWORD size );
void __cdecl CRTDLL_free( void *ptr );
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 */
......@@ -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
......
......@@ -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 <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <unistd.h>
#include <time.h>
#include "crtdll.h"
#include <ctype.h>
#define __USE_ISOC9X 1 /* for isfinite */
#include <math.h>
#include <fcntl.h>
#include <setjmp.h>
#include "winbase.h"
#include "windef.h"
#include <errno.h>
#include <stdlib.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
DEFAULT_DEBUG_CHANNEL(crtdll);
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,60 +54,84 @@ 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)
{
return HeapAlloc(GetProcessHeap(),0,size);
}
/*********************************************************************
* _strdup (CRTDLL.285)
*/
LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr)
/* INTERNAL: Set the crt and dos errno's from the OS error given. */
void __CRTDLL__set_errno(ULONG err)
{
LPSTR ret = CRTDLL_malloc(strlen(ptr)+1);
if (ret) strcpy( ret, ptr );
return ret;
/* FIXME: not MT safe */
CRTDLL_doserrno = err;
switch(err)
{
#define ERR_CASE(oserr) case oserr:
#define ERR_MAPS(oserr,crterr) case oserr:CRTDLL_errno = crterr;break;
ERR_CASE(ERROR_ACCESS_DENIED)
ERR_CASE(ERROR_NETWORK_ACCESS_DENIED)
ERR_CASE(ERROR_CANNOT_MAKE)
ERR_CASE(ERROR_SEEK_ON_DEVICE)
ERR_CASE(ERROR_LOCK_FAILED)
ERR_CASE(ERROR_FAIL_I24)
ERR_CASE(ERROR_CURRENT_DIRECTORY)
ERR_CASE(ERROR_DRIVE_LOCKED)
ERR_CASE(ERROR_NOT_LOCKED)
ERR_CASE(ERROR_INVALID_ACCESS)
ERR_MAPS(ERROR_LOCK_VIOLATION, EACCES);
ERR_CASE(ERROR_FILE_NOT_FOUND)
ERR_CASE(ERROR_NO_MORE_FILES)
ERR_CASE(ERROR_BAD_PATHNAME)
ERR_CASE(ERROR_BAD_NETPATH)
ERR_CASE(ERROR_INVALID_DRIVE)
ERR_CASE(ERROR_BAD_NET_NAME)
ERR_CASE(ERROR_FILENAME_EXCED_RANGE)
ERR_MAPS(ERROR_PATH_NOT_FOUND, ENOENT);
ERR_MAPS(ERROR_IO_DEVICE, EIO);
ERR_MAPS(ERROR_BAD_FORMAT, ENOEXEC);
ERR_MAPS(ERROR_INVALID_HANDLE, EBADF);
ERR_CASE(ERROR_OUTOFMEMORY)
ERR_CASE(ERROR_INVALID_BLOCK)
ERR_CASE(ERROR_NOT_ENOUGH_QUOTA);
ERR_MAPS(ERROR_ARENA_TRASHED, ENOMEM);
ERR_MAPS(ERROR_BUSY, EBUSY);
ERR_CASE(ERROR_ALREADY_EXISTS)
ERR_MAPS(ERROR_FILE_EXISTS, EEXIST);
ERR_MAPS(ERROR_BAD_DEVICE, ENODEV);
ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES, EMFILE);
ERR_MAPS(ERROR_DISK_FULL, ENOSPC);
ERR_MAPS(ERROR_BROKEN_PIPE, EPIPE);
ERR_MAPS(ERROR_POSSIBLE_DEADLOCK, EDEADLK);
ERR_MAPS(ERROR_DIR_NOT_EMPTY, ENOTEMPTY);
ERR_MAPS(ERROR_BAD_ENVIRONMENT, E2BIG);
ERR_CASE(ERROR_WAIT_NO_CHILDREN)
ERR_MAPS(ERROR_CHILD_NOT_COMPLETE, ECHILD);
ERR_CASE(ERROR_NO_PROC_SLOTS)
ERR_CASE(ERROR_MAX_THRDS_REACHED)
ERR_MAPS(ERROR_NESTING_NOT_ALLOWED, EAGAIN);
default:
/* Remaining cases map to EINVAL */
/* FIXME: may be missing some errors above */
CRTDLL_errno = EINVAL;
}
}
/*********************************************************************
* _GetMainArgs (CRTDLL.022)
*/
......@@ -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,1501 +256,797 @@ 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)
* srand (CRTDLL.460)
*/
DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file)
void __cdecl CRTDLL_srand(DWORD seed)
{
#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
/* FIXME: should of course be thread? process? local */
srand(seed);
}
/*********************************************************************
* freopen (CRTDLL.379)
*
* BUGS
* Unimplemented
* _beep (CRTDLL.045)
*
* Output a tone using the PC speaker.
*
* PARAMS
* freq [in] Frequency of the tone
*
* duration [in] Length of time the tone should sound
*
* RETURNS
* None.
*/
DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream)
void __cdecl CRTDLL__beep( UINT freq, UINT duration)
{
FIXME(":(%s,%s,%p): stub\n", path, mode, stream);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
TRACE(":Freq %d, Duration %d\n",freq,duration);
Beep(freq, duration);
}
/*********************************************************************
* fscanf (CRTDLL.381)
* rand (CRTDLL.446)
*/
INT __cdecl CRTDLL_fscanf( CRTDLL_FILE *stream, LPSTR format, ... )
INT __cdecl CRTDLL_rand()
{
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;
return (rand() & CRTDLL_RAND_MAX);
}
/*********************************************************************
* _lseek (CRTDLL.179)
* _rotl (CRTDLL.259)
*/
LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence)
UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
{
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 );
unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08x rot %d ret 0x%08x\n", x,shift,ret);
return ret;
}
/*********************************************************************
* fseek (CRTDLL.382)
* _lrotl (CRTDLL.175)
*/
LONG __cdecl CRTDLL_fseek( CRTDLL_FILE *file, LONG offset, INT whence)
DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
{
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;
unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08lx rot %d ret 0x%08lx\n", x,shift,ret);
return ret;
}
/*********************************************************************
* fsetpos (CRTDLL.383)
* _lrotr (CRTDLL.176)
*/
INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE *file, INT *pos )
DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
{
TRACE("file %p pos %d\n", file, *pos );
return CRTDLL_fseek(file, *pos, SEEK_SET);
/* 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;
}
/*********************************************************************
* ftell (CRTDLL.384)
* _rotr (CRTDLL.258)
*/
LONG __cdecl CRTDLL_ftell( CRTDLL_FILE *file )
DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
{
return SetFilePointer( file->handle, 0, NULL, SEEK_CUR );
/* 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;
}
/*********************************************************************
* fwrite (CRTDLL.386)
* vswprintf (CRTDLL.501)
*/
DWORD __cdecl CRTDLL_fwrite( LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file )
INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
{
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;
return wvsprintfW( buffer, spec, args );
}
/*********************************************************************
* setbuf (CRTDLL.452)
* longjmp (CRTDLL.426)
*/
INT __cdecl CRTDLL_setbuf(CRTDLL_FILE *file, LPSTR buf)
VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
{
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;
FIXME("CRTDLL_longjmp semistup, expect crash\n");
longjmp(env, val);
}
/*********************************************************************
* _open_osfhandle (CRTDLL.240)
* setlocale (CRTDLL.453)
*/
HFILE __cdecl CRTDLL__open_osfhandle(LONG osfhandle, INT flags)
LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
{
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;
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";
}
/*********************************************************************
* srand (CRTDLL.460)
* _isctype (CRTDLL.138)
*/
void __cdecl CRTDLL_srand(DWORD seed)
BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
{
/* FIXME: should of course be thread? process? local */
srand(seed);
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;
}
/*********************************************************************
* vfprintf (CRTDLL.373)
* _fullpath (CRTDLL.114)
*/
INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE *file, LPSTR format, va_list args )
LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
{
char buffer[2048]; /* FIXME... */
DOS_FULL_NAME full_name;
vsprintf( buffer, format, args );
return CRTDLL_fwrite( buffer, 1, strlen(buffer), file );
if (!buf)
{
size = 256;
if(!(buf = CRTDLL_malloc(size))) return NULL;
}
if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
lstrcpynA(buf,full_name.short_name,size);
TRACE("CRTDLL_fullpath got %s\n",buf);
return buf;
}
/*********************************************************************
* fprintf (CRTDLL.373)
* _splitpath (CRTDLL.279)
*/
INT __cdecl CRTDLL_fprintf( CRTDLL_FILE *file, LPSTR format, ... )
VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
{
va_list valist;
INT res;
/* drive includes :
directory includes leading and trailing (forward and backward slashes)
filename without dot and slashes
extension with leading dot
*/
char * drivechar,*dirchar,*namechar;
va_start( valist, format );
res = CRTDLL_vfprintf( file, format, valist );
va_end( valist );
return res;
}
TRACE("CRTDLL__splitpath got %s\n",path);
/*********************************************************************
* time (CRTDLL.488)
*/
time_t __cdecl CRTDLL_time(time_t *timeptr)
{
time_t curtime = time(NULL);
drivechar = strchr(path,':');
dirchar = strrchr(path,'/');
namechar = strrchr(path,'\\');
dirchar = max(dirchar,namechar);
if (dirchar)
namechar = strrchr(dirchar,'.');
else
namechar = strrchr(path,'.');
if (drive)
{
*drive = 0x00;
if (drivechar)
{
strncat(drive,path,drivechar-path+1);
path = drivechar+1;
}
}
if (directory)
{
*directory = 0x00;
if (dirchar)
{
strncat(directory,path,dirchar-path+1);
path = dirchar+1;
}
}
if (filename)
{
*filename = 0x00;
if (namechar)
{
strncat(filename,path,namechar-path);
if (extension)
{
*extension = 0x00;
strcat(extension,namechar);
}
}
}
if (timeptr)
*timeptr = curtime;
return curtime;
TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
}
/*********************************************************************
* difftime (CRTDLL.357)
* _makepath (CRTDLL.182)
*/
double __cdecl CRTDLL_difftime (time_t time1, time_t time2)
VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
LPCSTR directory, LPCSTR filename,
LPCSTR extension )
{
double timediff;
char ch;
TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
filename, extension);
timediff = (double)(time1 - time2);
return timediff;
}
if ( !path )
return;
/*********************************************************************
* 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;
}
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);
}
}
/*********************************************************************
* _isatty (CRTDLL.137)
*/
BOOL __cdecl CRTDLL__isatty(DWORD x)
{
TRACE("(%ld)\n",x);
return TRUE;
TRACE("CRTDLL__makepath returns %s\n",path);
}
/*********************************************************************
* _read (CRTDLL.256)
* _errno (CRTDLL.52)
* Return the address of the CRT errno (Not the libc errno).
*
* BUGS
* Not MT safe.
*/
INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count)
LPINT __cdecl CRTDLL__errno( VOID )
{
TRACE("0x%08x bytes fd %d to %p\n", count,fd,buf);
if (!fd) fd = GetStdHandle( STD_INPUT_HANDLE );
return _lread( fd, buf, count );
return &CRTDLL_errno;
}
/*********************************************************************
* _write (CRTDLL.332)
* _doserrno (CRTDLL.26)
*
* Return the address of the DOS errno (holding the last OS error).
*
* BUGS
* Not MT safe.
*/
INT __cdecl CRTDLL__write(INT fd,LPCVOID buf,UINT count)
LPINT __cdecl CRTDLL___doserrno( VOID )
{
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;
return &CRTDLL_doserrno;
}
/*********************************************************************
* _cexit (CRTDLL.49)
/**********************************************************************
* _strerror (CRTDLL.284)
*
* 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)
*
* atexit-processing comes to mind -- MW.
* Return a formatted system error message.
*
* NOTES
* The caller does not own the string returned.
*/
void __cdecl CRTDLL__cexit(INT ret)
{
TRACE("(%d)\n",ret);
ExitProcess(ret);
}
extern int sprintf(char *str, const char *format, ...);
/*********************************************************************
* exit (CRTDLL.359)
*/
void __cdecl CRTDLL_exit(DWORD ret)
LPSTR __cdecl CRTDLL__strerror (LPCSTR err)
{
TRACE("(%ld)\n",ret);
ExitProcess(ret);
static char strerrbuff[256];
sprintf(strerrbuff,"%s: %s\n",err,CRTDLL_strerror(CRTDLL_errno));
return strerrbuff;
}
/*********************************************************************
* _abnormal_termination (CRTDLL.36)
* perror (CRTDLL.435)
*
* Print a formatted system error message to stderr.
*/
INT __cdecl CRTDLL__abnormal_termination(void)
VOID __cdecl CRTDLL_perror (LPCSTR err)
{
TRACE("(void)\n");
return 0;
char *err_str = CRTDLL_strerror(CRTDLL_errno);
CRTDLL_fprintf(CRTDLL_stderr,"%s: %s\n",err,err_str);
CRTDLL_free(err_str);
}
/*********************************************************************
* _access (CRTDLL.37)
* strerror (CRTDLL.465)
*
* Return the text of an error.
*
* NOTES
* The caller does not own the string returned.
*/
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;
}
extern char *strerror(int errnum);
if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
{
errno = EACCES;
return -1;
}
else
return 0;
LPSTR __cdecl CRTDLL_strerror (INT err)
{
return strerror(err);
}
/*********************************************************************
* fflush (CRTDLL.365)
* signal (CRTDLL.455)
*/
INT __cdecl CRTDLL_fflush( CRTDLL_FILE *file )
LPVOID __cdecl CRTDLL_signal(INT sig, sig_handler_type ptr)
{
return FlushFileBuffers( file->handle ) ? 0 : -1;
FIXME("(%d %p):stub.\n", sig, ptr);
return (void*)-1;
}
/*********************************************************************
* rand (CRTDLL.446)
* _sleep (CRTDLL.267)
*/
INT __cdecl CRTDLL_rand()
VOID __cdecl CRTDLL__sleep(ULONG timeout)
{
return (rand() & CRTDLL_RAND_MAX);
TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
Sleep((timeout)?timeout:1);
}
/*********************************************************************
* fputc (CRTDLL.374)
* getenv (CRTDLL.437)
*/
INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE *file )
LPSTR __cdecl CRTDLL_getenv(LPCSTR name)
{
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 );
}
LPSTR environ = GetEnvironmentStringsA();
LPSTR pp,pos = NULL;
unsigned int length;
/*********************************************************************
* 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;
for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
{
pos =strchr(pp,'=');
if (pos)
length = pos -pp;
else
length = strlen(pp);
if (!strncmp(pp,name,length)) break;
}
if ((pp)&& (pos))
{
pp = pos+1;
TRACE("got %s\n",pp);
}
FreeEnvironmentStringsA( environ );
return pp;
}
/*********************************************************************
* puts (CRTDLL.443)
* _except_handler2 (CRTDLL.78)
*/
INT __cdecl CRTDLL_puts(LPCSTR s)
INT __cdecl CRTDLL__except_handler2 (
PEXCEPTION_RECORD rec,
PEXCEPTION_FRAME frame,
PCONTEXT context,
PEXCEPTION_FRAME *dispatcher)
{
TRACE("%s \n",s);
return CRTDLL_fputs(s, CRTDLL_stdout);
FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
frame->Handler, context, dispatcher);
return ExceptionContinueSearch;
}
/*********************************************************************
* putc (CRTDLL.441)
*/
INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE *file )
{
return CRTDLL_fputc( c, file );
}
/*********************************************************************
* fgetc (CRTDLL.366)
* __isascii (CRTDLL.028)
*
*/
INT __cdecl CRTDLL_fgetc( CRTDLL_FILE *file )
INT __cdecl CRTDLL___isascii(INT c)
{
DWORD res;
char ch;
if (!ReadFile( file->handle, &ch, 1, &res, NULL )) return -1;
if (res != 1) return -1;
return ch;
return isascii(c);
}
/*********************************************************************
* getc (CRTDLL.388)
* __toascii (CRTDLL.035)
*
*/
INT __cdecl CRTDLL_getc( CRTDLL_FILE *file )
INT __cdecl CRTDLL___toascii(INT c)
{
return CRTDLL_fgetc( file );
return c & 0x7f;
}
/*********************************************************************
* fgets (CRTDLL.368)
* iswascii (CRTDLL.404)
*
*/
CHAR* __cdecl CRTDLL_fgets( LPSTR s, INT size, CRTDLL_FILE *file )
INT __cdecl CRTDLL_iswascii(LONG c)
{
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;
return ((unsigned)c < 0x80);
}
/*********************************************************************
* gets (CRTDLL.391)
* __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.
*/
LPSTR __cdecl CRTDLL_gets(LPSTR buf)
INT __cdecl CRTDLL___iscsym(LONG c)
{
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;
return (isalnum(c) || c == '_');
}
/*********************************************************************
* _rotl (CRTDLL.259)
* __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.
*/
UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
INT __cdecl CRTDLL___iscsymf(LONG c)
{
unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08x rot %d ret 0x%08x\n",
x,shift,ret);
return ret;
}
/*********************************************************************
* _lrotl (CRTDLL.176)
*/
DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
{
unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));
TRACE("got 0x%08lx rot %d ret 0x%08lx\n",
x,shift,ret);
return ret;
return (isalpha(c) || c == '_');
}
/*********************************************************************
* _mbsicmp (CRTDLL.204)
* _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__mbsicmp(unsigned char *x,unsigned char *y)
INT __cdecl CRTDLL__loaddll(LPSTR dllname)
{
do {
if (!*x)
return !!*y;
if (!*y)
return !!*x;
/* FIXME: MBCS handling... */
if (*x!=*y)
return 1;
x++;
y++;
} while (1);
return LoadLibraryA(dllname);
}
/*********************************************************************
* vswprintf (CRTDLL.501)
* _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_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
INT __cdecl CRTDLL__unloaddll(HANDLE dll)
{
return wvsprintfW( buffer, spec, args );
INT err;
if (FreeLibrary(dll))
return 0;
err = GetLastError();
__CRTDLL__set_errno(err);
return err;
}
/*********************************************************************
* 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)
* _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.
*/
VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
LPVOID __cdecl CRTDLL__lsearch(LPVOID match,LPVOID start, LPUINT array_size,
UINT elem_size, comp_func cf)
{
FIXME("CRTDLL_longjmp semistup, expect crash\n");
longjmp(env, val);
}
UINT size = *array_size;
if (size)
do
{
if (cf(match, start) == 0)
return start; /* found */
start += elem_size;
} while (--size);
/*********************************************************************
* new (CRTDLL.001)
*/
VOID* __cdecl CRTDLL_new(DWORD size)
{
VOID* result;
if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler)
(*new_handler)();
return result;
/* not found, add to end */
memcpy(start, match, elem_size);
array_size[0]++;
return start;
}
/*********************************************************************
* 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)
* _itow (CRTDLL.164)
*
* Convert an integer to a wide char string.
*/
VOID* __cdecl CRTDLL_calloc(DWORD size, DWORD count)
{
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
}
extern LPSTR __cdecl _itoa( long , LPSTR , INT); /* ntdll */
/*********************************************************************
* realloc (CRTDLL.447)
*/
VOID* __cdecl CRTDLL_realloc( VOID *ptr, DWORD size )
WCHAR* __cdecl CRTDLL__itow(INT value,WCHAR* out,INT base)
{
return HeapReAlloc( GetProcessHeap(), 0, ptr, size );
}
char buff[64]; /* FIXME: Whats the maximum buffer size for INT_MAX? */
/*********************************************************************
* free (CRTDLL.427)
*/
VOID __cdecl CRTDLL_free(LPVOID ptr)
{
HeapFree(GetProcessHeap(),0,ptr);
_itoa(value, buff, base);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
return out;
}
/*********************************************************************
* delete (CRTDLL.002)
*/
VOID __cdecl CRTDLL_delete(VOID* ptr)
{
HeapFree(GetProcessHeap(),0,ptr);
}
/*********************************************************************
* fclose (CRTDLL.362)
* _ltow (CRTDLL.??)
*
* Convert a long to a wide char string.
*/
INT __cdecl CRTDLL_fclose( CRTDLL_FILE *file )
{
TRACE("%p\n", file );
if (!CloseHandle( file->handle )) return -1;
HeapFree( GetProcessHeap(), 0, file );
return 0;
}
extern LPSTR __cdecl _ltoa( long , LPSTR , INT); /* ntdll */
/*********************************************************************
* _unlink (CRTDLL.315)
*/
INT __cdecl CRTDLL__unlink(LPCSTR pathname)
WCHAR* __cdecl CRTDLL__ltow(LONG value,WCHAR* out,INT base)
{
return DeleteFileA( pathname ) ? 0 : -1;
}
char buff[64]; /* FIXME: Whats the maximum buffer size for LONG_MAX? */
/*********************************************************************
* rename (CRTDLL.449)
*/
INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath)
{
BOOL ok = MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING );
return ok ? 0 : -1;
_ltoa(value, buff, base);
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
return out;
}
/*********************************************************************
* _stat (CRTDLL.280)
* _ultow (CRTDLL.??)
*
* Convert an unsigned long to a wide char string.
*/
extern LPSTR __cdecl _ultoa( long , LPSTR , INT); /* ntdll */
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)
WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base)
{
int ret=0;
DOS_FULL_NAME full_name;
struct stat mystat;
char buff[64]; /* FIXME: Whats the maximum buffer size for ULONG_MAX? */
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;
_ultoa(value, buff, base);
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
return out;
}
/*********************************************************************
* _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)
* _toupper (CRTDLL.489)
*/
INT __cdecl CRTDLL__close(HFILE fd)
CHAR __cdecl CRTDLL__toupper(CHAR c)
{
int ret=_lclose(fd);
TRACE("(%d)\n",fd);
if(ret)
WARN(" Failed!\n");
return ret;
return toupper(c);
}
/*********************************************************************
* 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)
* _tolower (CRTDLL.490)
*/
LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
CHAR __cdecl CRTDLL__tolower(CHAR c)
{
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";
return tolower(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");
}
/* FP functions */
/*********************************************************************
* atexit (CRTDLL.345)
* _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).
*/
INT __cdecl CRTDLL_atexit(LPVOID x)
double __cdecl CRTDLL__cabs(struct complex c)
{
FIXME("(%p), STUB.\n",x);
return 0; /* successful */
return sqrt(c.real * c.real + c.imaginary * c.imaginary);
}
/*********************************************************************
* _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;
}
/*********************************************************************
* _chdrive (CRTDLL.52)
* _chgsign (CRTDLL.053)
*
* Change the sign of an IEEE double.
*
* newdir [I] drive to change to, A=1
* PARAMS
* d [in] Number to invert.
*
* RETURNS
* Number with sign inverted.
*/
BOOL __cdecl CRTDLL__chdrive(INT newdrive)
double __cdecl CRTDLL__chgsign(double d)
{
/* FIXME: generates errnos */
return DRIVE_SetCurrentDrive(newdrive-1);
/* FIXME: +-infinity,Nan not tested */
return -d;
}
/*********************************************************************
* _chdir (CRTDLL.51)
*/
INT __cdecl CRTDLL__chdir(LPCSTR newdir)
{
if (!SetCurrentDirectoryA(newdir))
return 1;
return 0;
}
/*********************************************************************
* _fullpath (CRTDLL.114)
*/
LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
{
DOS_FULL_NAME full_name;
if (!buf)
{
size = 256;
if(!(buf = CRTDLL_malloc(size))) return NULL;
}
if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
lstrcpynA(buf,full_name.short_name,size);
TRACE("CRTDLL_fullpath got %s\n",buf);
return buf;
}
/*********************************************************************
* _splitpath (CRTDLL.279)
* _control87 (CRTDLL.060)
*
* Unimplemented. Obsolete. Give it up. Use controlfp(), if you must.
*
*/
VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
UINT __cdecl CRTDLL__control87(UINT x, UINT y)
{
/* drive includes :
directory includes leading and trailing (forward and backward slashes)
filename without dot and slashes
extension with leading dot
*/
char * drivechar,*dirchar,*namechar;
TRACE("CRTDLL__splitpath got %s\n",path);
drivechar = strchr(path,':');
dirchar = strrchr(path,'/');
namechar = strrchr(path,'\\');
dirchar = max(dirchar,namechar);
if (dirchar)
namechar = strrchr(dirchar,'.');
else
namechar = strrchr(path,'.');
if (drive)
{
*drive = 0x00;
if (drivechar)
{
strncat(drive,path,drivechar-path+1);
path = drivechar+1;
}
}
if (directory)
{
*directory = 0x00;
if (dirchar)
{
strncat(directory,path,dirchar-path+1);
path = dirchar+1;
}
}
if (filename)
{
*filename = 0x00;
if (namechar)
{
strncat(filename,path,namechar-path);
if (extension)
{
*extension = 0x00;
strcat(extension,namechar);
}
}
}
TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
/* 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;
}
/*********************************************************************
* _makepath (CRTDLL.182)
* _controlfp (CRTDLL.061)
*
* Set the state of the floating point unit.
*
* PARAMS
* FIXME:
*
* RETURNS
* None
*
* BUGS
* Unimplemented.
*/
VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
LPCSTR directory, LPCSTR filename,
LPCSTR extension )
UINT __cdecl CRTDLL__controlfp( UINT x, UINT y)
{
char ch;
TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
filename, extension);
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);
FIXME(":stub!\n");
return 0;
}
/*********************************************************************
* _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)
* _copysign (CRTDLL.062)
*
* Return current drive, 1 for A, 2 for B
* Return the number x with the sign of y.
*/
INT __cdecl CRTDLL__getdrive(VOID)
double __cdecl CRTDLL__copysign(double x, double y)
{
return DRIVE_GetCurrentDrive() + 1;
}
/* FIXME: Behaviour for Nan/Inf etc? */
if (y < 0.0)
return x < 0.0 ? x : -x;
/*********************************************************************
* _mkdir (CRTDLL.234)
*/
INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
{
if (!CreateDirectoryA(newdir,NULL))
return -1;
return 0;
return x < 0.0 ? -x : x;
}
/*********************************************************************
* remove (CRTDLL.448)
*/
INT __cdecl CRTDLL_remove(LPCSTR file)
{
if (!DeleteFileA(file))
return -1;
return 0;
}
/*********************************************************************
* _errno (CRTDLL.52)
* Yes, this is a function.
* _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.
*/
LPINT __cdecl CRTDLL__errno()
INT __cdecl CRTDLL__finite(double d)
{
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;
return (isfinite(d)?1:0); /* See comment for CRTDLL__isnan() */
}
/*********************************************************************
* _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)
* _fpreset (CRTDLL.107)
*
* lcclnk from lcc-win32 relies on a terminating dot in the name returned
* Reset the state of the floating point processor.
*
* PARAMS
* None.
*
* RETURNS
* None.
*
* BUGS
* Unimplemented.
*/
LPSTR __cdecl CRTDLL_tmpnam(LPSTR s)
VOID __cdecl CRTDLL__fpreset(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;
FIXME(":stub!\n");
}
typedef VOID (*sig_handler_type)(VOID);
/*********************************************************************
* signal (CRTDLL.455)
* _isnan (CRTDLL.164)
*
* Determine if an IEEE double is unrepresentable (NaN).
*
* PARAMS
* d [in] Number to check.
*
* RETURNS
* Non zero if number is NaN.
*/
void * __cdecl CRTDLL_signal(int sig, sig_handler_type ptr)
INT __cdecl CRTDLL__isnan(double d)
{
FIXME("(%d %p):stub.\n", sig, ptr);
return (void*)-1;
/* 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;
}
/*********************************************************************
* _sleep (CRTDLL.267)
*/
VOID __cdecl CRTDLL__sleep(unsigned long timeout)
{
TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
Sleep((timeout)?timeout:1);
}
/*********************************************************************
* getenv (CRTDLL.437)
* _j0 (CRTDLL.166)
*/
LPSTR __cdecl CRTDLL_getenv(const char *name)
double CRTDLL__j0(double x)
{
LPSTR environ = GetEnvironmentStringsA();
LPSTR pp,pos = NULL;
unsigned int length;
for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
{
pos =strchr(pp,'=');
if (pos)
length = pos -pp;
else
length = strlen(pp);
if (!strncmp(pp,name,length)) break;
}
if ((pp)&& (pos))
{
pp = pos+1;
TRACE("got %s\n",pp);
}
FreeEnvironmentStringsA( environ );
return pp;
FIXME(":stub!\n");
return x;
}
/*********************************************************************
* _mbsrchr (CRTDLL.223)
* _j1 (CRTDLL.167)
*/
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;
double CRTDLL__j1(double x)
{
FIXME(":stub!\n");
return x;
}
/*********************************************************************
* _except_handler2 (CRTDLL.78)
* _jn (CRTDLL.168)
*/
INT __cdecl CRTDLL__except_handler2 (
PEXCEPTION_RECORD rec,
PEXCEPTION_FRAME frame,
PCONTEXT context,
PEXCEPTION_FRAME *dispatcher)
double CRTDLL__jn(LONG x,double y)
{
FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
frame->Handler, context, dispatcher);
return ExceptionContinueSearch;
FIXME(":stub!\n");
return x;
}
/*
* CRTDLL drive/directory functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
*
* Implementation Notes:
* MT Safe.
*/
#include "crtdll.h"
#include <errno.h>
#include "drive.h"
#include <time.h>
#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;
}
/*
* CRTDLL exit/abort/atexit functions
*
* Copyright 1996,1998 Marcus Meissner
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
*
* exit functions differ in whether they perform cleanup
* and whether they return to the caller (really!).
* return do
* Name to caller? cleanup?
* _c_exit Y N
* _cexit Y Y
* _exit N N
* exit N Y
*
* Implementation Notes:
* Not MT Safe - Adding/Executing exit() functions should be locked
* for MT safety.
*
* FIXME:
* Need a better way of printing errors for GUI programs(MsgBox?).
* Is there really a difference between onexit/atexit?
*/
#include "crtdll.h"
#include <errno.h>
#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;
}
/*
* 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 <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#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 );
}
......@@ -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;
}
/*
* 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 );
}
/*
* 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 <errno.h>
#include "process.h"
#include "options.h"
#include <stdlib.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* Process creation flags */
#define _P_WAIT 0
#define _P_NOWAIT 1
#define _P_OVERLAY 2
#define _P_NOWAITO 3
#define _P_DETACH 4
extern void __CRTDLL__set_errno(ULONG err);
extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count);
extern VOID __cdecl CRTDLL_free(void *ptr);
extern VOID __cdecl CRTDLL__exit(LONG ret);
extern INT CRTDLL_doserrno;
/* INTERNAL: Spawn a child process */
static int __CRTDLL__spawn(INT flags, 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);
}
/*
* 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++;
}
}
}
/*
* 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 <stdlib.h>
#include <sys/times.h>
DEFAULT_DEBUG_CHANNEL(crtdll);
/* INTERNAL: Return formatted current time/date */
static LPSTR __CRTDLL__get_current_time(LPSTR out, const char * format);
static LPSTR __CRTDLL__get_current_time(LPSTR out, const char * format)
{
time_t t;
struct tm *_tm;
if ((time(&t) != ((time_t)-1)) &&
((_tm = localtime(&t)) != 0) &&
(strftime(out,9,format,_tm) == 8))
{
CRTDLL_free(_tm);
return out;
}
return NULL;
}
/*********************************************************************
* _ftime (CRTDLL.112)
*
* Get current time.
*/
VOID __cdecl CRTDLL__ftime (struct _timeb* t)
{
t->time = CRTDLL_time(NULL);
t->millitm = 0; /* FIXME */
t->timezone = 0;
t->dstflag = 0;
}
/**********************************************************************
* _strdate (CRTDLL.283)
*
* Return the current date as MM/DD/YY - (American Format)
*/
LPSTR __cdecl CRTDLL__strdate (LPSTR date)
{
return __CRTDLL__get_current_time(date,"%m/%d/%y");
}
/*********************************************************************
* _strtime (CRTDLL.299)
*
* Return the current time as HH:MM:SS
*/
LPSTR __cdecl CRTDLL__strtime (LPSTR date)
{
return __CRTDLL__get_current_time(date,"%H:%M:%S");
}
/*********************************************************************
* clock (CRTDLL.350)
*/
clock_t __cdecl CRTDLL_clock(void)
{
struct tms alltimes;
clock_t res;
times(&alltimes);
res = alltimes.tms_utime + alltimes.tms_stime+
alltimes.tms_cutime + alltimes.tms_cstime;
/* Fixme: We need some symbolic representation
for (Hostsystem_)CLOCKS_PER_SEC
and (Emulated_system_)CLOCKS_PER_SEC
10 holds only for Windows/Linux_i86)
*/
return 10*res;
}
/*********************************************************************
* difftime (CRTDLL.357)
*/
double __cdecl CRTDLL_difftime (time_t time1, time_t time2)
{
double timediff;
timediff = (double)(time1 - time2);
return timediff;
}
/*********************************************************************
* time (CRTDLL.488)
*/
time_t __cdecl CRTDLL_time(time_t *timeptr)
{
time_t curtime = time(NULL);
if (timeptr)
*timeptr = curtime;
return curtime;
}
......@@ -4,18 +4,13 @@
* Copyright 1999 Alexandre Julliard
*/
#include "config.h"
#include "crtdll.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "crtdll.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment