diff --git a/dlls/crtdll/Makefile.in b/dlls/crtdll/Makefile.in index 10b626b6945..4bce1c718cb 100644 --- a/dlls/crtdll/Makefile.in +++ b/dlls/crtdll/Makefile.in @@ -9,6 +9,7 @@ LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ + console.c \ crtdll_main.c \ dir.c \ exit.c \ diff --git a/dlls/crtdll/console.c b/dlls/crtdll/console.c new file mode 100644 index 00000000000..91df6455c2c --- /dev/null +++ b/dlls/crtdll/console.c @@ -0,0 +1,220 @@ +/* + * CRTDLL console functions + * + * Copyright 2000 Jon Griffiths + * + * NOTES + * Only a one byte ungetch buffer is implemented, as per MS docs. + * Output is not redirectable using these functions, as per MS docs. + * + * FIXME: + * There are several problems with the console input mechanism as + * currently implemented in Wine. When these are ironed out the + * getch() function will work correctly (gets() is currently fine). + * The problem is that opening CONIN$ does not work, and + * reading from STD_INPUT_HANDLE is line buffered. + */ +#include "crtdll.h" +#include "wincon.h" + +DEFAULT_DEBUG_CHANNEL(crtdll); + +static HANDLE __CRTDLL_console_in = INVALID_HANDLE_VALUE; +static HANDLE __CRTDLL_console_out = INVALID_HANDLE_VALUE; +static int __CRTDLL_console_buffer = EOF; + + +/* INTERNAL: Initialise console handles */ +VOID __CRTDLL_init_console(VOID) +{ + TRACE(":Opening console handles\n"); + + __CRTDLL_console_in = GetStdHandle(STD_INPUT_HANDLE); + +/* FIXME: Should be initialised with: + * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ, + * NULL, OPEN_EXISTING, 0, (HANDLE)NULL); + */ + + __CRTDLL_console_out = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, (HANDLE)NULL); + + if ((__CRTDLL_console_in == INVALID_HANDLE_VALUE) || + (__CRTDLL_console_out == INVALID_HANDLE_VALUE)) + WARN(":Console handle Initialisation FAILED!\n"); +} + +/* INTERNAL: Free console handles */ +void __CRTDLL_free_console(void) +{ + TRACE(":Closing console handles\n"); + CloseHandle(__CRTDLL_console_in); + CloseHandle(__CRTDLL_console_out); +} + + +/********************************************************************* + * _cgets (CRTDLL.050) + * + * Get a string from CONIN$. + */ +LPSTR __cdecl CRTDLL__cgets(LPSTR str) +{ + char *buf = str + 2; + int c; + str[1] = 0; /* Length */ + /* FIXME: No editing of string supported */ + do + { + if (str[1] >= str[0] || (str[1]++, c = CRTDLL__getche()) == EOF || c == '\n') + { + *buf = '\0'; + return str + 2; + } + *buf++ = c & 0xff; + } while(1); +} + + +/********************************************************************* + * _cputs (CRTDLL.065) + * + * Write a string to CONOUT$. + */ +INT __cdecl CRTDLL__cputs(LPCSTR str) +{ + DWORD count; + if (WriteConsoleA(__CRTDLL_console_out, str, strlen(str), &count, NULL) + && count == 1) + return 0; + return EOF; +} + + +/********************************************************************* + * _getch (CRTDLL.118) + * + * Get a character from CONIN$. + */ +INT __cdecl CRTDLL__getch(VOID) +{ + if (__CRTDLL_console_buffer != EOF) + { + INT retVal = __CRTDLL_console_buffer; + __CRTDLL_console_buffer = EOF; + return retVal; + } + else + { + INPUT_RECORD ir; + DWORD count; + DWORD mode = 0; + + GetConsoleMode(__CRTDLL_console_in, &mode); + if(mode) SetConsoleMode(__CRTDLL_console_in, 0); + + do { + if (ReadConsoleInputA(__CRTDLL_console_in, &ir, 1, &count)) + { + /* Only interested in ASCII chars */ + if (ir.EventType == KEY_EVENT && + ir.Event.KeyEvent.bKeyDown && + ir.Event.KeyEvent.uChar.AsciiChar) + { + if(mode) SetConsoleMode(__CRTDLL_console_in, mode); + return ir.Event.KeyEvent.uChar.AsciiChar; + } + } + else + break; + } while(1); + if (mode) SetConsoleMode(__CRTDLL_console_in, mode); + } + return EOF; +} + + +/********************************************************************* + * _getche (CRTDLL.119) + * + * Get a character from CONIN$ and echo it to CONOUT$. + */ +INT __cdecl CRTDLL__getche(VOID) +{ + INT res = CRTDLL__getch(); + if (res != EOF && CRTDLL__putch(res) != EOF) + return res; + return EOF; +} + + +/********************************************************************* + * _kbhit (CRTDLL.169) + * + * Check if a character is waiting in CONIN$. + */ +INT __cdecl CRTDLL__kbhit(VOID) +{ + if (__CRTDLL_console_buffer != EOF) + return 1; + else + { + /* FIXME: There has to be a faster way than this in Win32.. */ + INPUT_RECORD *ir; + DWORD count = 0; + int retVal = 0, i; + + GetNumberOfConsoleInputEvents(__CRTDLL_console_in, &count); + if (!count) + return 0; + + if (!(ir = CRTDLL_malloc(count * sizeof(INPUT_RECORD)))) + return 0; + + if (!PeekConsoleInputA(__CRTDLL_console_in, ir, count, &count)) + return 0; + + for(i = 0; i < count - 1; i++) + { + if (ir[i].EventType == KEY_EVENT && + ir[i].Event.KeyEvent.bKeyDown && + ir[i].Event.KeyEvent.uChar.AsciiChar) + { + retVal = 1; + break; + } + } + CRTDLL_free(ir); + return retVal; + } +} + + +/********************************************************************* + * _putch (CRTDLL.250) + * + * Write a character to CONOUT$. + */ +INT __cdecl CRTDLL__putch(INT c) +{ + DWORD count; + if (WriteConsoleA(__CRTDLL_console_out, &c, 1, &count, NULL) && + count == 1) + return c; + return EOF; +} + + +/********************************************************************* + * _ungetch (CRTDLL.311) + * + * Un-get a character from CONIN$. + */ +INT __cdecl CRTDLL__ungetch(INT c) +{ + if (c == EOF || __CRTDLL_console_buffer != EOF) + return EOF; + + return __CRTDLL_console_buffer = c; +} + diff --git a/dlls/crtdll/crtdll.h b/dlls/crtdll/crtdll.h index 30bfc6b69e0..cf08ef082a6 100644 --- a/dlls/crtdll/crtdll.h +++ b/dlls/crtdll/crtdll.h @@ -55,6 +55,8 @@ #define _O_TEXT 0x4000 #define _O_BINARY 0x8000 +#define _O_TEMPORARY 0x0040 /* Will be closed and deleted on exit */ + /* _access() bit flags FIXME: incomplete */ #define W_OK 2 @@ -246,7 +248,7 @@ typedef INT (__cdecl *comp_func)(LPCVOID, LPCVOID ); /* CRTDLL functions */ -/* CRTDLL_dir.c */ +/* dir.c */ INT __cdecl CRTDLL__chdir( LPCSTR newdir ); BOOL __cdecl CRTDLL__chdrive( INT newdrive ); INT __cdecl CRTDLL__findclose( DWORD hand ); @@ -259,7 +261,7 @@ INT __cdecl CRTDLL__getdrive( VOID ); INT __cdecl CRTDLL__mkdir( LPCSTR newdir ); INT __cdecl CRTDLL__rmdir( LPSTR dir ); -/* CRTDLL_exit.c */ +/* 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 ); @@ -271,13 +273,14 @@ VOID __cdecl CRTDLL_abort( VOID ); INT __cdecl CRTDLL_atexit( atexit_function x ); atexit_function __cdecl CRTDLL__onexit( atexit_function func); -/* CRTDLL_file.c */ +/* 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 ); LPSTR __cdecl CRTDLL__mktemp( LPSTR pattern ); CRTDLL_FILE* __cdecl CRTDLL_fopen( LPCSTR path, LPCSTR mode ); CRTDLL_FILE* __cdecl CRTDLL_freopen( LPCSTR path,LPCSTR mode,CRTDLL_FILE* f ); +CRTDLL_FILE* __cdecl CRTDLL_tmpfile( void ); 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, ... ); @@ -300,6 +303,7 @@ INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE* file, LPCSTR format,va_list args); INT __cdecl CRTDLL_fprintf( CRTDLL_FILE* file, LPCSTR format, ... ); INT __cdecl CRTDLL__putw( INT val, CRTDLL_FILE* file ); INT __cdecl CRTDLL__read( INT fd, LPVOID buf, UINT count ); +INT __cdecl CRTDLL__rmtmp( void ); 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 ); @@ -417,8 +421,9 @@ double __cdecl CRTDLL__y0( double x ); double __cdecl CRTDLL__y1( double x ); double __cdecl CRTDLL__yn( INT x, double y ); double __cdecl CRTDLL__nextafter( double x, double y ); +VOID __cdecl CRTDLL__searchenv(LPCSTR file, LPCSTR env, LPSTR buff); -/* CRTDLL_mem.c */ +/* memory.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 ); @@ -433,11 +438,15 @@ 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 ); +/* spawn.c */ +HANDLE __cdecl CRTDLL__spawnv( INT flags, LPCSTR name, LPCSTR *argv); +HANDLE __cdecl CRTDLL__spawnve( INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv); +HANDLE __cdecl CRTDLL__spawnvp( INT flags, LPCSTR name, LPCSTR *argv); +HANDLE __cdecl CRTDLL__spawnvpe( INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv); +INT __cdecl CRTDLL_system( LPCSTR cmd ); +INT __cdecl CRTDLL__cwait( PINT status, INT pid, INT action ); -/* CRTDLL_str.c */ +/* str.c */ LPSTR __cdecl CRTDLL__strdec( LPSTR str1, LPSTR str2 ); LPSTR __cdecl CRTDLL__strdup( LPCSTR ptr ); LPSTR __cdecl CRTDLL__strinc( LPSTR str ); @@ -450,7 +459,7 @@ 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 */ +/* time.c */ LPSTR __cdecl CRTDLL__strdate ( LPSTR date ); LPSTR __cdecl CRTDLL__strtime ( LPSTR date ); clock_t __cdecl CRTDLL_clock ( void ); @@ -483,10 +492,22 @@ INT __cdecl CRTDLL_iswspace( WCHAR wc ); INT __cdecl CRTDLL_iswupper( WCHAR wc ); INT __cdecl CRTDLL_iswxdigit( WCHAR wc ); +/* console.c */ +LPSTR __cdecl CRTDLL__cgets( LPSTR str ); +INT __cdecl CRTDLL__cputs( LPCSTR str ); +INT __cdecl CRTDLL__getch( VOID ); +INT __cdecl CRTDLL__getche( VOID ); +INT __cdecl CRTDLL__kbhit( VOID ); +INT __cdecl CRTDLL__putch( INT c ); +INT __cdecl CRTDLL__ungetch( INT c ); + + /* INTERNAL: Shared internal functions */ void __CRTDLL__set_errno(ULONG err); LPSTR __CRTDLL__strndup(LPSTR buf, INT size); VOID __CRTDLL__init_io(VOID); +VOID __CRTDLL_init_console(VOID); +VOID __CRTDLL_free_console(VOID); extern WORD CRTDLL_ctype [257]; extern WORD __CRTDLL_current_ctype[257]; diff --git a/dlls/crtdll/crtdll.spec b/dlls/crtdll/crtdll.spec index 2327d32bbae..6cac3e142c0 100644 --- a/dlls/crtdll/crtdll.spec +++ b/dlls/crtdll/crtdll.spec @@ -57,7 +57,7 @@ debug_channels (crtdll) @ cdecl _c_exit() CRTDLL__c_exit @ cdecl _cabs(long) CRTDLL__cabs @ cdecl _cexit() CRTDLL__cexit -@ stub _cgets +@ cdecl _cgets(str) CRTDLL__cgets @ cdecl _chdir(str) CRTDLL__chdir @ cdecl _chdrive(long) CRTDLL__chdrive @ cdecl _chgsign(double) CRTDLL__chgsign @@ -72,11 +72,11 @@ debug_channels (crtdll) @ cdecl _copysign(double double) CRTDLL__copysign @ stub _cprintf @ stub _cpumode_dll -@ stub _cputs +@ cdecl _cputs(str) CRTDLL__cputs @ cdecl _creat(str long) CRTDLL__creat @ stub _cscanf @ extern _ctype CRTDLL_ctype -@ stub _cwait +@ cdecl _cwait(ptr long long) CRTDLL__cwait @ stub _daylight_dll @ stub _dup @ stub _dup2 @@ -125,8 +125,8 @@ debug_channels (crtdll) @ cdecl _futime(long ptr) CRTDLL__futime @ cdecl _gcvt(double long str) gcvt @ cdecl _get_osfhandle(long) CRTDLL__get_osfhandle -@ stub _getch -@ stub _getche +@ cdecl _getch() CRTDLL__getch +@ cdecl _getche() CRTDLL__getche @ cdecl _getcwd(ptr long) CRTDLL__getcwd @ cdecl _getdcwd(long ptr long) CRTDLL__getdcwd @ cdecl _getdiskfree(long ptr) CRTDLL__getdiskfree @@ -177,7 +177,7 @@ debug_channels (crtdll) @ cdecl _j0(double) j0 @ cdecl _j1(double) j1 @ cdecl _jn(long double) jn -@ stub _kbhit +@ cdecl _kbhit() CRTDLL__kbhit @ cdecl _lfind(ptr ptr ptr long ptr) CRTDLL__lfind @ cdecl _loaddll(str) CRTDLL__loaddll @ cdecl _local_unwind2(ptr long) CRTDLL__local_unwind2 @@ -259,17 +259,17 @@ debug_channels (crtdll) @ stub _pipe @ stub _popen @ cdecl _purecall() CRTDLL__purecall -@ stub _putch +@ cdecl _putch(long) CRTDLL__putch @ stub _putenv @ cdecl _putw(long ptr) CRTDLL__putw @ stub _pwctype_dll @ cdecl _read(long ptr long) CRTDLL__read @ cdecl _rmdir(str) CRTDLL__rmdir -@ stub _rmtmp +@ cdecl _rmtmp() CRTDLL__rmtmp @ cdecl _rotl (long long) CRTDLL__rotl @ cdecl _rotr (long long) CRTDLL__rotr @ cdecl _scalb (double long) CRTDLL__scalb -@ stub _searchenv +@ cdecl _searchenv(str str str) CRTDLL__searchenv @ stub _seterrormode @ cdecl _setjmp (ptr) CRTDLL__setjmp @ cdecl _setmode(long long) CRTDLL__setmode @@ -282,10 +282,10 @@ debug_channels (crtdll) @ stub _spawnle @ stub _spawnlp @ stub _spawnlpe -@ stub _spawnv +@ cdecl _spawnv(long str ptr) CRTDLL__spawnv @ cdecl _spawnve(long str ptr ptr) CRTDLL__spawnve -@ stub _spawnvp -@ stub _spawnvpe +@ cdecl _spawnvp(long str ptr) CRTDLL__spawnvp +@ cdecl _spawnvpe(long str ptr ptr) CRTDLL__spawnvpe @ cdecl _splitpath (str ptr ptr ptr ptr) CRTDLL__splitpath @ cdecl _stat (str ptr) CRTDLL__stat @ cdecl _statusfp() CRTDLL__statusfp @@ -321,7 +321,7 @@ debug_channels (crtdll) @ forward _ultoa ntdll._ultoa @ cdecl _ultow(long str long) CRTDLL__ultow @ cdecl _umask(long) CRTDLL__umask -@ stub _ungetch +@ cdecl _ungetch(long) CRTDLL__ungetch @ cdecl _unlink(str) CRTDLL__unlink @ cdecl _unloaddll(long) CRTDLL__unloaddll @ cdecl _utime(str ptr) CRTDLL__utime @@ -496,7 +496,7 @@ debug_channels (crtdll) @ cdecl tan(double) tan @ cdecl tanh(double) tanh @ cdecl time(ptr) CRTDLL_time -@ stub tmpfile +@ cdecl tmpfile() CRTDLL_tmpfile @ cdecl tmpnam(str) CRTDLL_tmpnam @ cdecl tolower(long) tolower @ cdecl toupper(long) toupper diff --git a/dlls/crtdll/crtdll_main.c b/dlls/crtdll/crtdll_main.c index cdf2e886ed0..01a7dbeebdd 100644 --- a/dlls/crtdll/crtdll_main.c +++ b/dlls/crtdll/crtdll_main.c @@ -124,9 +124,16 @@ BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) if (fdwReason == DLL_PROCESS_ATTACH) { __CRTDLL__init_io(); + __CRTDLL_init_console(); CRTDLL_setlocale( CRTDLL_LC_ALL, "C" ); CRTDLL_HUGE_dll = HUGE_VAL; } + else if (fdwReason == DLL_PROCESS_DETACH) + { + CRTDLL__fcloseall(); + __CRTDLL_free_console(); + } + return TRUE; } @@ -1672,3 +1679,67 @@ double __cdecl CRTDLL__nextafter(double x, double y) return retVal; } +/********************************************************************* + * _searchenv (CRTDLL.260) + * + * Search CWD and each directory of an environment variable for + * location of a file. + */ +VOID __cdecl CRTDLL__searchenv(LPCSTR file, LPCSTR env, LPSTR buff) +{ + LPSTR envVal, penv; + char curPath[MAX_PATH]; + + *buff = '\0'; + + /* Try CWD first */ + if (GetFileAttributesA( file ) != 0xFFFFFFFF) + { + GetFullPathNameA( file, MAX_PATH, buff, NULL ); + /* Sigh. This error is *always* set, regardless of sucess */ + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + + /* Search given environment variable */ + envVal = CRTDLL_getenv(env); + if (!envVal) + { + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + + penv = envVal; + TRACE(":searching for %s in paths %s\n", file, envVal); + + do + { + LPSTR end = penv; + + while(*end && *end != ';') end++; /* Find end of next path */ + if (penv == end || !*penv) + { + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + strncpy(curPath, penv, end - penv); + if (curPath[end - penv] != '/' || curPath[end - penv] != '\\') + { + curPath[end - penv] = '\\'; + curPath[end - penv + 1] = '\0'; + } + else + curPath[end - penv] = '\0'; + + strcat(curPath, file); + TRACE("Checking for file %s\n", curPath); + if (GetFileAttributesA( curPath ) != 0xFFFFFFFF) + { + strcpy(buff, curPath); + __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND); + return; /* Found */ + } + penv = *end ? end + 1 : end; + } while(1); +} + diff --git a/dlls/crtdll/dir.c b/dlls/crtdll/dir.c index 4251bba22a6..8fabdb17f7d 100644 --- a/dlls/crtdll/dir.c +++ b/dlls/crtdll/dir.c @@ -20,7 +20,6 @@ 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) { DWORD dw; @@ -28,7 +27,7 @@ static void __CRTDLL__fttofd(LPWIN32_FIND_DATAA fd, find_t* ft) /* 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) + if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ft->attrib = 0; else ft->attrib = fd->dwFileAttributes; @@ -341,3 +340,4 @@ INT __cdecl CRTDLL__rmdir(LPSTR dir) __CRTDLL__set_errno(GetLastError()); return -1; } + diff --git a/dlls/crtdll/exit.c b/dlls/crtdll/exit.c index fc02cca5621..367b858ec3d 100644 --- a/dlls/crtdll/exit.c +++ b/dlls/crtdll/exit.c @@ -105,8 +105,7 @@ VOID __cdecl CRTDLL__assert(LPVOID str, LPVOID file, UINT line) */ VOID __cdecl CRTDLL__c_exit(VOID) { - FIXME("not calling CRTDLL cleanup\n"); - /* dont exit, return to caller */ + /* All cleanup is done on DLL detach; Return to caller */ } @@ -115,8 +114,7 @@ VOID __cdecl CRTDLL__c_exit(VOID) */ VOID __cdecl CRTDLL__cexit(VOID) { - FIXME("not calling CRTDLL cleanup\n"); - /* dont exit, return to caller */ + /* All cleanup is done on DLL detach; Return to caller */ } diff --git a/dlls/crtdll/file.c b/dlls/crtdll/file.c index efd91a59eb4..2b3151190b2 100644 --- a/dlls/crtdll/file.c +++ b/dlls/crtdll/file.c @@ -49,6 +49,7 @@ DEFAULT_DEBUG_CHANNEL(crtdll); HANDLE __CRTDLL_handles[CRTDLL_MAX_FILES]; CRTDLL_FILE* __CRTDLL_files[CRTDLL_MAX_FILES]; INT __CRTDLL_flags[CRTDLL_MAX_FILES]; +LPSTR __CRTDLL_tempfiles[CRTDLL_MAX_FILES]; CRTDLL_FILE __CRTDLL_iob[3]; static int __CRTDLL_fdstart = 3; /* first unallocated fd */ @@ -182,6 +183,7 @@ VOID __CRTDLL__init_io(VOID) /* FILE structs for stdin/out/err are static and never deleted */ __CRTDLL_files[i] = &__CRTDLL_iob[i]; __CRTDLL_iob[i]._file = i; + __CRTDLL_tempfiles[i] = NULL; } } @@ -261,6 +263,14 @@ INT __cdecl CRTDLL__close(INT fd) __CRTDLL__set_errno(GetLastError()); return -1; } + if (__CRTDLL_tempfiles[fd]) + { + TRACE("deleting temporary file '%s'\n",__CRTDLL_tempfiles[fd]); + CRTDLL__unlink(__CRTDLL_tempfiles[fd]); + CRTDLL_free(__CRTDLL_tempfiles[fd]); + __CRTDLL_tempfiles[fd] = NULL; + } + TRACE(":ok\n"); return 0; } @@ -361,7 +371,8 @@ INT __cdecl CRTDLL__fcloseall(VOID) num_closed++; } - TRACE(":closed (%d) handles\n",num_closed); + if (num_closed) + TRACE(":closed (%d) handles\n",num_closed); return num_closed; } @@ -792,12 +803,10 @@ INT __cdecl CRTDLL__open(LPCSTR path,INT flags) flags &= ~_O_TEXT; } - if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL|_O_CREAT|_O_RDWR)) + if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL + |_O_CREAT|_O_RDWR|_O_TEMPORARY)) 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); @@ -808,12 +817,17 @@ INT __cdecl CRTDLL__open(LPCSTR path,INT flags) return -1; } - fd = __CRTDLL__alloc_fd(hand,ioflag); + 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 ); + if (fd > 0) + { + if (flags & _O_TEMPORARY) + __CRTDLL_tempfiles[fd] = CRTDLL__strdup(path); + if (ioflag & _IOAPPEND) + CRTDLL__lseek(fd, 0, FILE_END ); + } return fd; } @@ -843,6 +857,28 @@ INT __cdecl CRTDLL__putw(INT val, CRTDLL_FILE* file) } +/********************************************************************* + * _rmtmp (CRTDLL.256) + * + * Remove all temporary files created by tmpfile(). + */ +INT __cdecl CRTDLL__rmtmp(void) +{ + int num_removed = 0, i = 3; + + while(i < __CRTDLL_fdend) + if (__CRTDLL_tempfiles[i]) + { + CRTDLL__close(i); + num_removed++; + } + + if (num_removed) + TRACE(":removed (%d) temp files\n",num_removed); + return num_removed; +} + + /********************************************************************* * _read (CRTDLL.256) * @@ -1630,6 +1666,24 @@ INT __cdecl CRTDLL_setbuf(CRTDLL_FILE* file, LPSTR buf) } +/********************************************************************* + * tmpfile (CRTDLL.486) + * + * Create and return a temporary file. + */ +CRTDLL_FILE* __cdecl CRTDLL_tmpfile(void) +{ + LPSTR filename = CRTDLL_tmpnam(NULL); + int fd = CRTDLL__open(filename, _O_CREAT | _O_BINARY | + _O_RDWR | _O_TEMPORARY); + + if (fd != -1) + return __CRTDLL__alloc_fp(fd); + + return NULL; +} + + /********************************************************************* * tmpnam (CRTDLL.490) * diff --git a/dlls/crtdll/spawn.c b/dlls/crtdll/spawn.c index 835bf5779a0..c13c5ba0a7a 100644 --- a/dlls/crtdll/spawn.c +++ b/dlls/crtdll/spawn.c @@ -60,8 +60,7 @@ 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) +static int __CRTDLL__spawn(INT flags, LPCSTR exe, LPSTR args, LPSTR env) { STARTUPINFOA si; PROCESS_INFORMATION pi; @@ -109,10 +108,9 @@ static int __CRTDLL__spawn(INT flags, LPSTR exe, LPSTR args, LPSTR env) /* 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) +static LPSTR __CRTDLL__argvtos(LPCSTR *arg, CHAR delim) { - LPSTR *search = arg; + LPCSTR *search = arg; LONG size = 0; LPSTR ret; @@ -145,40 +143,107 @@ static LPSTR __CRTDLL__argvtos(LPSTR *arg, CHAR delim) /********************************************************************* - * _spawnve (CRTDLL.274) + * _cwait (CRTDLL.069) + * + * Wait for a spawned process to finish. + */ +INT __cdecl CRTDLL__cwait(PINT status, INT pid, INT action) +{ + HANDLE hPid = (HANDLE)pid; + + action = action; /* Remove warning */ + + if (!WaitForSingleObject(hPid, -1)) /* wait forvever */ + { + if (status) + { + DWORD stat; + GetExitCodeProcess(hPid, &stat); + *status = (INT)stat; + } + return pid; + } + CRTDLL_doserrno = GetLastError(); + + if (CRTDLL_doserrno == ERROR_INVALID_HANDLE) + CRTDLL_errno = ECHILD; + else + __CRTDLL__set_errno(CRTDLL_doserrno); + + return status ? *status = -1 : -1; +} + + +/********************************************************************* + * _spawnv (CRTDLL.273) * * Spawn a process. - * */ -HANDLE __cdecl CRTDLL__spawnve(INT flags, LPSTR name, LPSTR *argv, LPSTR *envv) +HANDLE __cdecl CRTDLL__spawnv(INT flags, LPCSTR name, LPCSTR *argv) +{ + return CRTDLL__spawnve(flags, name, argv, NULL); +} + + +/********************************************************************* + * _spawnve (CRTDLL.274) + * + * Spawn a process. + */ +HANDLE __cdecl CRTDLL__spawnve(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv) { LPSTR args = __CRTDLL__argvtos(argv,' '); LPSTR envs = __CRTDLL__argvtos(envv,0); - LPSTR fullname = name; + LPCSTR fullname = name; + HANDLE ret = -1; FIXME(":not translating name %s to locate program\n",fullname); TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null"); if (args) { - HANDLE ret = __CRTDLL__spawn(flags, fullname, args, envs); + 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; + return ret; +} + + +/********************************************************************* + * _spawnvp (CRTDLL.275) + * + * Spawn a process. + */ +HANDLE __cdecl CRTDLL__spawnvp(INT flags, LPCSTR name, LPCSTR *argv) +{ + return CRTDLL__spawnvpe(flags, name, argv, NULL); +} + + +/********************************************************************* + * _spawnvpe (CRTDLL.276) + * + * Spawn a process. + */ +HANDLE __cdecl CRTDLL__spawnvpe(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv) +{ + char fullname[MAX_PATH]; + + CRTDLL__searchenv(name, "PATH", fullname); + return CRTDLL__spawnve(flags, fullname[0] ? fullname : name, argv, envv); } /********************************************************************* * system (CRTDLL.485) + * + * Spawn an O/S process. */ -INT __cdecl CRTDLL_system(LPSTR x) +INT __cdecl CRTDLL_system(LPCSTR cmd) { /* FIXME: should probably launch cmd interpreter in COMSPEC */ - return __CRTDLL__spawn(_P_WAIT, NULL, x, NULL); + return __CRTDLL__spawn(_P_WAIT, cmd, NULL, NULL); }