/* * The C RunTime DLL * * Implements C run-time functionality as known from UNIX. * * Copyright 1996,1998 Marcus Meissner * Copyright 1996 Jukka Iivonen * Copyright 1997 Uwe Bonnes */ /* 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 */ /* NOTE: This file also implements the wcs* functions. They _ARE_ in * the newer Linux libcs, but use 4 byte wide characters, so are unusable, * since we need 2 byte wide characters. - Marcus Meissner, 981031 */ /* FIXME: all the file handling is hopelessly broken -- AJ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "win.h" #include "windows.h" #include "winerror.h" #include "debug.h" #include "module.h" #include "heap.h" #include "crtdll.h" #include "drive.h" #include "file.h" #include "except.h" #include "options.h" #include "winnls.h" extern int FILE_GetUnixHandle( HFILE32 ); static DOS_FULL_NAME CRTDLL_tmpname; UINT32 CRTDLL_argc_dll; /* CRTDLL.23 */ LPSTR *CRTDLL_argv_dll; /* CRTDLL.24 */ LPSTR CRTDLL_acmdln_dll; /* CRTDLL.38 */ UINT32 CRTDLL_basemajor_dll; /* CRTDLL.42 */ UINT32 CRTDLL_baseminor_dll; /* CRTDLL.43 */ UINT32 CRTDLL_baseversion_dll; /* CRTDLL.44 */ UINT32 CRTDLL_commode_dll; /* CRTDLL.59 */ LPSTR CRTDLL_environ_dll; /* CRTDLL.75 */ UINT32 CRTDLL_fmode_dll; /* CRTDLL.104 */ UINT32 CRTDLL_osmajor_dll; /* CRTDLL.241 */ UINT32 CRTDLL_osminor_dll; /* CRTDLL.242 */ UINT32 CRTDLL_osmode_dll; /* CRTDLL.243 */ UINT32 CRTDLL_osver_dll; /* CRTDLL.244 */ UINT32 CRTDLL_osversion_dll; /* CRTDLL.245 */ UINT32 CRTDLL_winmajor_dll; /* CRTDLL.329 */ UINT32 CRTDLL_winminor_dll; /* CRTDLL.330 */ UINT32 CRTDLL_winver_dll; /* CRTDLL.331 */ BYTE CRTDLL_iob[32*3]; /* FIXME */ typedef VOID (*new_handler_type)(VOID); static new_handler_type new_handler; /********************************************************************* * _GetMainArgs (CRTDLL.022) */ DWORD __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv, LPSTR *environ,DWORD flag) { char *cmdline; char **xargv; int xargc,i,afterlastspace; DWORD version; TRACE(crtdll,"(%p,%p,%p,%ld).\n", argc,argv,environ,flag ); CRTDLL_acmdln_dll = cmdline = HEAP_strdupA( GetProcessHeap(), 0, GetCommandLine32A() ); TRACE(crtdll,"got '%s'\n", cmdline); version = GetVersion32(); CRTDLL_osver_dll = version >> 16; CRTDLL_winminor_dll = version & 0xFF; CRTDLL_winmajor_dll = (version>>8) & 0xFF; CRTDLL_baseversion_dll = version >> 16; CRTDLL_winver_dll = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8); CRTDLL_baseminor_dll = (version >> 16) & 0xFF; CRTDLL_basemajor_dll = (version >> 24) & 0xFF; CRTDLL_osversion_dll = version & 0xFFFF; CRTDLL_osminor_dll = version & 0xFF; CRTDLL_osmajor_dll = (version>>8) & 0xFF; /* missing threading init */ i=0;xargv=NULL;xargc=0;afterlastspace=0; while (cmdline[i]) { if (cmdline[i]==' ') { xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv, sizeof(char*)*(++xargc)); cmdline[i]='\0'; xargv[xargc-1] = HEAP_strdupA( GetProcessHeap(), 0, cmdline+afterlastspace); i++; while (cmdline[i]==' ') i++; if (cmdline[i]) afterlastspace=i; } else i++; } xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv, sizeof(char*)*(++xargc)); cmdline[i]='\0'; xargv[xargc-1] = HEAP_strdupA( GetProcessHeap(), 0, cmdline+afterlastspace); CRTDLL_argc_dll = xargc; *argc = xargc; CRTDLL_argv_dll = xargv; *argv = xargv; TRACE(crtdll,"found %d arguments\n", CRTDLL_argc_dll); CRTDLL_environ_dll = *environ = GetEnvironmentStrings32A(); return 0; } 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(crtdll, ":(%s,%p): stub\n",fname,x2); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /********************************************************************* * _findnext (CRTDLL.100) * * BUGS * Unimplemented */ INT32 __cdecl CRTDLL__findnext(DWORD hand, struct find_t * x2) { FIXME(crtdll, ":(%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(crtdll, ":(%d,%p): stub\n",file,buf); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /********************************************************************* * _initterm (CRTDLL.135) */ DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end) { _INITTERMFUN *current; TRACE(crtdll,"(%p,%p)\n",start,end); current=start; while (current 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(crtdll, "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(crtdll, "skipping ^M\n"); } TRACE(crtdll, "0x%08x items of size %d from file %p to %p\n", nmemb,size,file,ptr,); if(i!=nmemb) WARN(crtdll, " failed!\n"); return i; #else ret=fread(ptr,size,nmemb,file); TRACE(crtdll, "0x%08x items of size %d from file %p to %p\n", nmemb,size,file,ptr); if(ret!=nmemb) WARN(crtdll, " failed!\n"); return ret; #endif } /********************************************************************* * freopen (CRTDLL.379) * * BUGS * Unimplemented */ DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream) { FIXME(crtdll, ":(%s,%s,%p): stub\n", path, mode, stream); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /********************************************************************* * fscanf (CRTDLL.381) */ INT32 __cdecl CRTDLL_fscanf( LPVOID stream, LPSTR format, ... ) { va_list valist; INT32 res; va_start( valist, format ); #ifdef HAVE_VFSCANF res = vfscanf( xlat_file_ptr(stream), format, valist ); #endif va_end( valist ); return res; } /********************************************************************* * fseek (CRTDLL.382) */ LONG __cdecl CRTDLL_fseek(LPVOID stream, LONG offset, INT32 whence) { long ret; ret=fseek(xlat_file_ptr(stream),offset,whence); TRACE(crtdll, "file %p to 0x%08lx pos %s\n", stream,offset,(whence==SEEK_SET)?"SEEK_SET": (whence==SEEK_CUR)?"SEEK_CUR": (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); if(ret) WARN(crtdll, " failed!\n"); return ret; } /********************************************************************* * fsetpos (CRTDLL.383) */ INT32 __cdecl CRTDLL_fsetpos(LPVOID stream, fpos_t *pos) { TRACE(crtdll, "file %p\n", stream); return fseek(xlat_file_ptr(stream), *pos, SEEK_SET); } /********************************************************************* * ftell (CRTDLL.384) */ LONG __cdecl CRTDLL_ftell(LPVOID stream) { long ret; ret=ftell(xlat_file_ptr(stream)); TRACE(crtdll, "file %p at 0x%08lx\n", stream,ret); return ret; } /********************************************************************* * fwrite (CRTDLL.386) */ DWORD __cdecl CRTDLL_fwrite(LPVOID ptr, INT32 size, INT32 nmemb, LPVOID vfile) { size_t ret; FILE *file=xlat_file_ptr(vfile); ret=fwrite(ptr,size,nmemb,file); TRACE(crtdll, "0x%08x items of size %d from %p to file %p\n", nmemb,size,ptr,file); if(ret!=nmemb) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * setbuf (CRTDLL.452) */ INT32 __cdecl CRTDLL_setbuf(LPVOID file, LPSTR buf) { TRACE(crtdll, "(file %p buf %p)\n", file, buf); /* this doesn't work:"void value not ignored as it ought to be" return setbuf(file,buf); */ setbuf(xlat_file_ptr(file),buf); return 0; } /********************************************************************* * _open_osfhandle (CRTDLL.240) */ HFILE32 __cdecl CRTDLL__open_osfhandle(LONG osfhandle, INT32 flags) { HFILE32 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(crtdll, "(handle %08lx,flags %d) return %d\n", osfhandle,flags,handle); return handle; } /********************************************************************* * srand (CRTDLL.460) */ void __cdecl CRTDLL_srand(DWORD seed) { /* FIXME: should of course be thread? process? local */ srand(seed); } /********************************************************************* * fprintf (CRTDLL.373) */ INT32 __cdecl CRTDLL_fprintf( FILE *file, LPSTR format, ... ) { va_list valist; INT32 res; va_start( valist, format ); res = vfprintf( xlat_file_ptr(file), format, valist ); va_end( valist ); return res; } /********************************************************************* * vfprintf (CRTDLL.373) */ INT32 __cdecl CRTDLL_vfprintf( FILE *file, LPSTR format, va_list args ) { return vfprintf( xlat_file_ptr(file), format, args ); } /********************************************************************* * time (CRTDLL.488) */ time_t __cdecl CRTDLL_time(time_t *timeptr) { time_t curtime = time(NULL); if (timeptr) *timeptr = curtime; return curtime; } /********************************************************************* * (CRTDLL.350) */ clock_t __cdecl CRTDLL_clock(void) { struct tms alltimes; clock_t res; times(&alltimes); res = alltimes.tms_utime + alltimes.tms_stime+ alltimes.tms_cutime + alltimes.tms_cstime; /* Fixme: We need some symbolic representation for (Hostsystem_)CLOCKS_PER_SEC and (Emulated_system_)CLOCKS_PER_SEC 10 holds only for Windows/Linux_i86) */ return 10*res; } /********************************************************************* * _isatty (CRTDLL.137) */ BOOL32 __cdecl CRTDLL__isatty(DWORD x) { TRACE(crtdll,"(%ld)\n",x); return TRUE; } /********************************************************************* * _write (CRTDLL.332) */ INT32 __cdecl CRTDLL__write(INT32 fd,LPCVOID buf,UINT32 count) { INT32 len=0; if (fd == -1) len = -1; else if (fd<=2) len = (UINT32)write(fd,buf,(LONG)count); else len = _lwrite32(fd,buf,count); TRACE(crtdll,"%d/%d byte to dfh %d from %p,\n", len,count,fd,buf); return len; } /********************************************************************* * _cexit (CRTDLL.49) * * 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. * */ void __cdecl CRTDLL__cexit(INT32 ret) { TRACE(crtdll,"(%d)\n",ret); ExitProcess(ret); } /********************************************************************* * exit (CRTDLL.359) */ void __cdecl CRTDLL_exit(DWORD ret) { TRACE(crtdll,"(%ld)\n",ret); ExitProcess(ret); } /********************************************************************* * _abnormal_termination (CRTDLL.36) */ INT32 __cdecl CRTDLL__abnormal_termination(void) { TRACE(crtdll,"(void)\n"); return 0; } /********************************************************************* * _access (CRTDLL.37) */ INT32 __cdecl CRTDLL__access(LPCSTR filename, INT32 mode) { DWORD attr = GetFileAttributes32A(filename); if (attr == -1) { if (GetLastError() == ERROR_INVALID_ACCESS) errno = EACCES; else errno = ENOENT; return -1; } if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) { errno = EACCES; return -1; } else return 0; } /********************************************************************* * fflush (CRTDLL.365) */ INT32 __cdecl CRTDLL_fflush(LPVOID stream) { int ret; ret = fflush(xlat_file_ptr(stream)); TRACE(crtdll,"%p returnd %d\n",stream,ret); if(ret) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * gets (CRTDLL.391) */ LPSTR __cdecl CRTDLL_gets(LPSTR buf) { int cc; LPSTR buf_start = buf; /* BAD, for the whole WINE process blocks... just done this way to test * windows95's ftp.exe. */ for(cc = fgetc(stdin); cc != EOF && cc != '\n'; cc = fgetc(stdin)) if(cc != '\r') *buf++ = (char)cc; *buf = '\0'; TRACE(crtdll,"got '%s'\n", buf_start); return buf_start; } /********************************************************************* * rand (CRTDLL.446) */ INT32 __cdecl CRTDLL_rand() { return rand(); } /********************************************************************* * putchar (CRTDLL.442) */ void __cdecl CRTDLL_putchar( INT32 x ) { putchar(x); } /********************************************************************* * fputc (CRTDLL.374) */ INT32 __cdecl CRTDLL_fputc( INT32 c, FILE *stream ) { TRACE(crtdll, "%c to file %p\n",c,stream); return fputc(c,xlat_file_ptr(stream)); } /********************************************************************* * fputs (CRTDLL.375) */ INT32 __cdecl CRTDLL_fputs( LPCSTR s, FILE *stream ) { TRACE(crtdll, "%s to file %p\n",s,stream); return fputs(s,xlat_file_ptr(stream)); } /********************************************************************* * puts (CRTDLL.443) */ INT32 __cdecl CRTDLL_puts(LPCSTR s) { TRACE(crtdll, "%s \n",s); return puts(s); } /********************************************************************* * putc (CRTDLL.441) */ INT32 __cdecl CRTDLL_putc(INT32 c, FILE *stream) { TRACE(crtdll, " %c to file %p\n",c,stream); return fputc(c,xlat_file_ptr(stream)); } /********************************************************************* * fgetc (CRTDLL.366) */ INT32 __cdecl CRTDLL_fgetc( FILE *stream ) { int ret= fgetc(xlat_file_ptr(stream)); TRACE(crtdll, "got %d\n",ret); return ret; } /********************************************************************* * getc (CRTDLL.388) */ INT32 __cdecl CRTDLL_getc( FILE *stream ) { int ret= fgetc(xlat_file_ptr(stream)); TRACE(crtdll, "got %d\n",ret); return ret; } /********************************************************************* * _rotl (CRTDLL.259) */ UINT32 __cdecl CRTDLL__rotl(UINT32 x,INT32 shift) { unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift)); TRACE(crtdll, "got 0x%08x rot %d ret 0x%08x\n", x,shift,ret); return ret; } /********************************************************************* * _lrotl (CRTDLL.176) */ DWORD __cdecl CRTDLL__lrotl(DWORD x,INT32 shift) { unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift)); TRACE(crtdll, "got 0x%08lx rot %d ret 0x%08lx\n", x,shift,ret); return ret; } /********************************************************************* * fgets (CRTDLL.368) */ CHAR* __cdecl CRTDLL_fgets(LPSTR s,INT32 size, LPVOID stream) { char * ret; char * control_M; ret=fgets(s, size,xlat_file_ptr(stream)); /*FIXME: Control with CRTDLL_setmode */ control_M= strrchr(s,'\r'); /*delete CR if we read a DOS File */ if (control_M) { *control_M='\n'; *(control_M+1)=0; } TRACE(crtdll, "got %s for %d chars from file %p\n", s,size,stream); if(ret) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * _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); } /********************************************************************* * _mbsinc (CRTDLL.205) */ unsigned char * __cdecl CRTDLL__mbsinc(unsigned char *x) { /* FIXME: mbcs */ return x++; } /********************************************************************* * vsprintf (CRTDLL.500) */ INT32 __cdecl CRTDLL_vsprintf( LPSTR buffer, LPCSTR spec, va_list args ) { return wvsprintf32A( buffer, spec, args ); } /********************************************************************* * vswprintf (CRTDLL.501) */ INT32 __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args ) { return wvsprintf32W( buffer, spec, args ); } /********************************************************************* * _mbscpy (CRTDLL.200) */ unsigned char* __cdecl CRTDLL__mbscpy(unsigned char *x,unsigned char *y) { TRACE(crtdll,"CRTDLL_mbscpy %s and %s\n",x,y); return strcpy(x,y); } /********************************************************************* * _mbscat (CRTDLL.197) */ unsigned char* __cdecl CRTDLL__mbscat(unsigned char *x,unsigned char *y) { return strcat(x,y); } /********************************************************************* * _strcmpi (CRTDLL.282) (CRTDLL.287) */ INT32 __cdecl CRTDLL__strcmpi( LPCSTR s1, LPCSTR s2 ) { return lstrcmpi32A( s1, s2 ); } /********************************************************************* * _strnicmp (CRTDLL.293) */ INT32 __cdecl CRTDLL__strnicmp( LPCSTR s1, LPCSTR s2, INT32 n ) { return lstrncmpi32A( s1, s2, n ); } /********************************************************************* * _strlwr (CRTDLL.293) * * convert a string in place to lowercase */ LPSTR __cdecl CRTDLL__strlwr(LPSTR x) { unsigned char *y =x; TRACE(crtdll, "CRTDLL_strlwr got %s\n", x); while (*y) { if ((*y > 0x40) && (*y< 0x5b)) *y = *y + 0x20; y++; } TRACE(crtdll, " returned %s\n", x); return x; } /********************************************************************* * system (CRTDLL.485) */ INT32 __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 \"", Options.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(crtdll,"_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(crtdll, "_system got '%s', executing '%s'\n",x,buffer); return system(buffer); } /********************************************************************* * _strupr (CRTDLL.300) */ LPSTR __cdecl CRTDLL__strupr(LPSTR x) { LPSTR y=x; while (*y) { *y=toupper(*y); y++; } return x; } /********************************************************************* * _wcsupr (CRTDLL.328) */ LPWSTR __cdecl CRTDLL__wcsupr(LPWSTR x) { LPWSTR y=x; while (*y) { *y=towupper(*y); y++; } return x; } /********************************************************************* * _wcslwr (CRTDLL.323) */ LPWSTR __cdecl CRTDLL__wcslwr(LPWSTR x) { LPWSTR y=x; while (*y) { *y=towlower(*y); y++; } return x; } /********************************************************************* * longjmp (CRTDLL.426) */ VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val) { FIXME(crtdll,"CRTDLL_longjmp semistup, expect crash\n"); return longjmp(env, val); } /********************************************************************* * malloc (CRTDLL.427) */ VOID* __cdecl CRTDLL_malloc(DWORD size) { return HeapAlloc(GetProcessHeap(),0,size); } /********************************************************************* * new (CRTDLL.001) */ VOID* __cdecl CRTDLL_new(DWORD size) { VOID* result; if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler) (*new_handler)(); return result; } /********************************************************************* * set_new_handler(CRTDLL.003) */ new_handler_type __cdecl CRTDLL_set_new_handler(new_handler_type func) { new_handler_type old_handler = new_handler; new_handler = func; return old_handler; } /********************************************************************* * calloc (CRTDLL.350) */ VOID* __cdecl CRTDLL_calloc(DWORD size, DWORD count) { return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); } /********************************************************************* * realloc (CRTDLL.447) */ VOID* __cdecl CRTDLL_realloc( VOID *ptr, DWORD size ) { return HeapReAlloc( GetProcessHeap(), 0, ptr, size ); } /********************************************************************* * free (CRTDLL.427) */ VOID __cdecl CRTDLL_free(LPVOID ptr) { HeapFree(GetProcessHeap(),0,ptr); } /********************************************************************* * delete (CRTDLL.002) */ VOID __cdecl CRTDLL_delete(VOID* ptr) { HeapFree(GetProcessHeap(),0,ptr); } /********************************************************************* * _strdup (CRTDLL.285) */ LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr) { return HEAP_strdupA(GetProcessHeap(),0,ptr); } /********************************************************************* * _wcsdup (CRTDLL.320) */ LPWSTR __cdecl CRTDLL__wcsdup(LPCWSTR ptr) { return HEAP_strdupW(GetProcessHeap(),0,ptr); } /********************************************************************* * fclose (CRTDLL.362) */ INT32 __cdecl CRTDLL_fclose( FILE *stream ) { int unix_handle; HFILE32 dos_handle=1; HFILE32 ret=EOF; stream=xlat_file_ptr(stream); unix_handle=fileno(stream); if (unix_handle<4) ret= fclose(stream); else { while(FILE_GetUnixHandle(dos_handle) != unix_handle) dos_handle++; fclose(stream); ret = _lclose32( dos_handle); } TRACE(crtdll,"(%p) ufh %d dfh %d\n", stream,unix_handle,dos_handle); if(ret) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * _unlink (CRTDLL.315) */ INT32 __cdecl CRTDLL__unlink(LPCSTR pathname) { int ret=0; DOS_FULL_NAME full_name; if (!DOSFS_GetFullName( pathname, FALSE, &full_name )) { WARN(crtdll, "CRTDLL_unlink file %s bad name\n",pathname); return EOF; } ret=unlink(full_name.long_name); TRACE(crtdll,"(%s unix %s)\n", pathname,full_name.long_name); if(ret) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * rename (CRTDLL.449) */ INT32 __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath) { BOOL32 ok = MoveFileEx32A( oldpath, newpath, MOVEFILE_REPLACE_EXISTING ); return ok ? 0 : -1; } /********************************************************************* * _stat (CRTDLL.280) */ struct win_stat { UINT16 win_st_dev; UINT16 win_st_ino; UINT16 win_st_mode; INT16 win_st_nlink; INT16 win_st_uid; INT16 win_st_gid; UINT32 win_st_rdev; INT32 win_st_size; INT32 win_st_atime; INT32 win_st_mtime; INT32 win_st_ctime; }; int __cdecl CRTDLL__stat(const char * filename, struct win_stat * buf) { int ret=0; DOS_FULL_NAME full_name; struct stat mystat; if (!DOSFS_GetFullName( filename, TRUE, &full_name )) { WARN(crtdll, "CRTDLL__stat filename %s bad name\n",filename); return -1; } ret=stat(full_name.long_name,&mystat); TRACE(crtdll,"CRTDLL__stat %s\n", filename); if(ret) WARN(crtdll, " Failed!\n"); /* FIXME: should check what Windows returns */ buf->win_st_dev = mystat.st_dev; buf->win_st_ino = mystat.st_ino; buf->win_st_mode = mystat.st_mode; buf->win_st_nlink = mystat.st_nlink; buf->win_st_uid = mystat.st_uid; buf->win_st_gid = mystat.st_gid; buf->win_st_rdev = mystat.st_rdev; buf->win_st_size = mystat.st_size; buf->win_st_atime = mystat.st_atime; buf->win_st_mtime = mystat.st_mtime; buf->win_st_ctime = mystat.st_ctime; return ret; } /********************************************************************* * _open (CRTDLL.239) */ HFILE32 __cdecl CRTDLL__open(LPCSTR path,INT32 flags) { HFILE32 ret=0; int wineflags=0; /* 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 */ wineflags = (flags & 3); if (flags & 0x0008 ) wineflags |= O_APPEND; if (flags & 0x0100 ) wineflags |= O_CREAT; if (flags & 0x0200 ) wineflags |= O_TRUNC; if (flags & 0x0400 ) wineflags |= O_EXCL; if (flags & 0xf0f4 ) TRACE(crtdll,"CRTDLL_open file unsupported flags 0x%04x\n",flags); /* End Fixme */ ret = FILE_Open(path,wineflags,0); TRACE(crtdll,"CRTDLL_open file %s mode 0x%04x (lccmode 0x%04x) got dfh %d\n", path,wineflags,flags,ret); return ret; } /********************************************************************* * _close (CRTDLL.57) */ INT32 __cdecl CRTDLL__close(HFILE32 fd) { int ret=_lclose32(fd); TRACE(crtdll,"(%d)\n",fd); if(ret) WARN(crtdll, " Failed!\n"); return ret; } /********************************************************************* * feof (CRTDLL.363) */ INT32 __cdecl CRTDLL_feof( FILE *stream ) { int ret; ret=feof(xlat_file_ptr(stream)); TRACE(crtdll,"(%p) %s\n",stream,(ret)?"true":"false"); return ret; } /********************************************************************* * setlocale (CRTDLL.453) */ LPSTR __cdecl CRTDLL_setlocale(INT32 category,LPCSTR locale) { LPSTR categorystr; switch (category) { case CRTDLL_LC_ALL: categorystr="LC_ALL";break; case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break; case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break; case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break; case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break; case CRTDLL_LC_TIME: categorystr="LC_TIME";break; default: categorystr = "UNKNOWN?";break; } FIXME(crtdll,"(%s,%s),stub!\n",categorystr,locale); return "C"; } /********************************************************************* * wcscat (CRTDLL.503) */ LPWSTR __cdecl CRTDLL_wcscat( LPWSTR s1, LPCWSTR s2 ) { return lstrcat32W( s1, s2 ); } /********************************************************************* * wcschr (CRTDLL.504) */ LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar) { LPCWSTR s; s=str; do { if (*s==xchar) return (LPWSTR)s; } while (*s++); return NULL; } /********************************************************************* * wcscmp (CRTDLL.505) */ INT32 __cdecl CRTDLL_wcscmp( LPCWSTR s1, LPCWSTR s2 ) { return lstrcmp32W( s1, s2 ); } /********************************************************************* * wcscpy (CRTDLL.507) */ LPWSTR __cdecl CRTDLL_wcscpy( LPWSTR s1, LPCWSTR s2 ) { return lstrcpy32W( s1, s2 ); } /********************************************************************* * wcscspn (CRTDLL.508) */ INT32 __cdecl CRTDLL_wcscspn(LPWSTR str,LPWSTR reject) { LPWSTR s,t; s=str; do { t=reject; while (*t) { if (*t==*s) break;t++;} if (*t) break; s++; } while (*s); return s-str; /* nr of wchars */ } /********************************************************************* * wcslen (CRTDLL.510) */ INT32 __cdecl CRTDLL_wcslen( LPCWSTR s ) { return lstrlen32W( s ); } /********************************************************************* * wcsncat (CRTDLL.511) */ LPWSTR __cdecl CRTDLL_wcsncat( LPWSTR s1, LPCWSTR s2, INT32 n ) { return lstrcatn32W( s1, s2, n ); } /********************************************************************* * wcsncmp (CRTDLL.512) */ INT32 __cdecl CRTDLL_wcsncmp( LPCWSTR s1, LPCWSTR s2, INT32 n ) { return lstrncmp32W( s1, s2, n ); } /********************************************************************* * wcsncpy (CRTDLL.513) */ LPWSTR __cdecl CRTDLL_wcsncpy( LPWSTR s1, LPCWSTR s2, INT32 n ) { return lstrcpyn32W( s1, s2, n ); } /********************************************************************* * wcsspn (CRTDLL.516) */ INT32 __cdecl CRTDLL_wcsspn(LPWSTR str,LPWSTR accept) { LPWSTR s,t; s=str; do { t=accept; while (*t) { if (*t==*s) break;t++;} if (!*t) break; s++; } while (*s); return s-str; /* nr of wchars */ } /********************************************************************* * _wcsicmp (CRTDLL.321) */ DWORD __cdecl CRTDLL__wcsicmp( LPCWSTR s1, LPCWSTR s2 ) { return lstrcmpi32W( s1, s2 ); } /********************************************************************* * _wcsicoll (CRTDLL.322) */ DWORD __cdecl CRTDLL__wcsicoll(LPCWSTR a1,LPCWSTR a2) { /* FIXME: handle collates */ return lstrcmpi32W(a1,a2); } /********************************************************************* * _wcsnicmp (CRTDLL.324) */ DWORD __cdecl CRTDLL__wcsnicmp( LPCWSTR s1, LPCWSTR s2, INT32 len ) { return lstrncmpi32W( s1, s2, len ); } /********************************************************************* * wcscoll (CRTDLL.506) */ DWORD __cdecl CRTDLL_wcscoll(LPWSTR a1,LPWSTR a2) { /* FIXME: handle collates */ return lstrcmp32W(a1,a2); } /********************************************************************* * _wcsrev (CRTDLL.326) */ VOID __cdecl CRTDLL__wcsrev(LPWSTR s) { LPWSTR e; e=s; while (*e) e++; while (s=str); return NULL; } /********************************************************************* * _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 * */ INT32 __cdecl CRTDLL__setmode( INT32 fh,INT32 mode) { /* FIXME */ #define O_TEXT 0x4000 #define O_BINARY 0x8000 FIXME(crtdll, "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(crtdll," STUB.\n"); } /********************************************************************* * atexit (CRTDLL.345) */ INT32 __cdecl CRTDLL_atexit(LPVOID x) { FIXME(crtdll,"(%p), STUB.\n",x); return 0; /* successful */ } /********************************************************************* * mblen (CRTDLL.428) * FIXME: check multibyte support */ WCHAR __cdecl CRTDLL_mblen(CHAR *mb,INT32 size) { int ret=1; if (!mb) ret = 0; else if ((size<1)||(!*(mb+1))) ret = -1; else if (!(*mb)) ret =0; TRACE(crtdll,"CRTDLL_mlen %s for max %d bytes ret %d\n",mb,size,ret); return ret; } /********************************************************************* * mbstowcs (CRTDLL.429) * FIXME: check multibyte support */ INT32 __cdecl CRTDLL_mbstowcs(LPWSTR wcs, LPCSTR mbs, INT32 size) { /* Slightly modified lstrcpynAtoW functions from memory/strings.c * We need the number of characters transfered * FIXME: No multibyte support yet */ LPWSTR p = wcs; LPCSTR src= mbs; int ret, n=size; while ((n-- > 0) && *src) { *p++ = (WCHAR)(unsigned char)*src++; } p++; ret = (p -wcs); TRACE(crtdll,"CRTDLL_mbstowcs %s for %d chars put %d wchars\n", mbs,size,ret); return ret; } /********************************************************************* * mbtowc (CRTDLL.430) * FIXME: check multibyte support */ WCHAR __cdecl CRTDLL_mbtowc(WCHAR* wc,CHAR* mb,INT32 size) { int ret; if (!mb) ret = 0; else if (!wc) ret =-1; else if ( (ret = mblen(mb,size)) != -1 ) { if (ret <= sizeof(char)) *wc = (WCHAR) ((unsigned char)*mb); else ret= -1; } else ret = -1; TRACE(crtdll,"CRTDLL_mbtowc %s for %d chars\n",mb,size); return ret; } /********************************************************************* * _isctype (CRTDLL.138) */ BOOL32 __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) * * newdir [I] drive to change to, A=1 * */ BOOL32 __cdecl CRTDLL__chdrive(INT32 newdrive) { /* FIXME: generates errnos */ return DRIVE_SetCurrentDrive(newdrive-1); } /********************************************************************* * _chdir (CRTDLL.51) */ INT32 __cdecl CRTDLL__chdir(LPCSTR newdir) { if (!SetCurrentDirectory32A(newdir)) return 1; return 0; } /********************************************************************* * _fullpath (CRTDLL.114) */ LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT32 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; lstrcpyn32A(buf,full_name.short_name,size); TRACE(crtdll,"CRTDLL_fullpath got %s\n",buf); return buf; } /********************************************************************* * _splitpath (CRTDLL.279) */ VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension ) { /* drive includes : directory includes leading and trailing (forward and backward slashes) filename without dot and slashes extension with leading dot */ char * drivechar,*dirchar,*namechar; TRACE(crtdll,"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,"CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension); } /********************************************************************* * _getcwd (CRTDLL.120) */ CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT32 size) { char test[1]; int len; len = size; if (!buf) { if (size < 0) /* allocate as big as nescessary */ len =GetCurrentDirectory32A(1,test) + 1; if(!(buf = CRTDLL_malloc(len))) { /* set error to OutOfRange */ return( NULL ); } } size = len; if(!(len =GetCurrentDirectory32A(len,buf))) { return NULL; } if (len > size) { /* set error to ERANGE */ TRACE(crtdll,"CRTDLL_getcwd buffer to small\n"); return NULL; } return buf; } /********************************************************************* * _getdcwd (CRTDLL.121) */ CHAR* __cdecl CRTDLL__getdcwd(INT32 drive,LPSTR buf, INT32 size) { char test[1]; int len; FIXME(crtdll,"(\"%c:\",%s,%d)\n",drive+'A',buf,size); len = size; if (!buf) { if (size < 0) /* allocate as big as nescessary */ len =GetCurrentDirectory32A(1,test) + 1; if(!(buf = CRTDLL_malloc(len))) { /* set error to OutOfRange */ return( NULL ); } } size = len; if(!(len =GetCurrentDirectory32A(len,buf))) { return NULL; } if (len > size) { /* set error to ERANGE */ TRACE(crtdll,"buffer to small\n"); return NULL; } return buf; } /********************************************************************* * _getdrive (CRTDLL.124) * * Return current drive, 1 for A, 2 for B */ INT32 __cdecl CRTDLL__getdrive(VOID) { return DRIVE_GetCurrentDrive() + 1; } /********************************************************************* * _mkdir (CRTDLL.234) */ INT32 __cdecl CRTDLL__mkdir(LPCSTR newdir) { if (!CreateDirectory32A(newdir,NULL)) return -1; return 0; } /********************************************************************* * remove (CRTDLL.448) */ INT32 __cdecl CRTDLL_remove(LPCSTR file) { if (!DeleteFile32A(file)) return -1; return 0; } /********************************************************************* * _errno (CRTDLL.52) * Yes, this is a function. */ LPINT32 __cdecl CRTDLL__errno() { static int crtdllerrno; /* FIXME: we should set the error at the failing function call time */ crtdllerrno = LastErrorToErrno(GetLastError()); return &crtdllerrno; } /********************************************************************* * _tempnam (CRTDLL.305) * */ LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix) { char *ret; DOS_FULL_NAME tempname; if ((ret = tempnam(dir,prefix))==NULL) { WARN(crtdll, "Unable to get unique filename\n"); return NULL; } if (!DOSFS_GetFullName(ret,FALSE,&tempname)) { TRACE(crtdll, "Wrong path?\n"); return NULL; } free(ret); if ((ret = CRTDLL_malloc(strlen(tempname.short_name)+1)) == NULL) { WARN(crtdll, "CRTDL_malloc for shortname failed\n"); return NULL; } if ((ret = strcpy(ret,tempname.short_name)) == NULL) { WARN(crtdll, "Malloc for shortname failed\n"); return NULL; } TRACE(crtdll,"dir %s prefix %s got %s\n", dir,prefix,ret); return ret; } /********************************************************************* * tmpnam (CRTDLL.490) * * lcclnk from lcc-win32 relies on a terminating dot in the name returned * */ LPSTR __cdecl CRTDLL_tmpnam(LPSTR s) { char *ret; if ((ret =tmpnam(s))== NULL) { WARN(crtdll, "Unable to get unique filename\n"); return NULL; } if (!DOSFS_GetFullName(ret,FALSE,&CRTDLL_tmpname)) { TRACE(crtdll, "Wrong path?\n"); return NULL; } strcat(CRTDLL_tmpname.short_name,"."); TRACE(crtdll,"for buf %p got %s\n", s,CRTDLL_tmpname.short_name); TRACE(crtdll,"long got %s\n", CRTDLL_tmpname.long_name); if ( s != NULL) return strcpy(s,CRTDLL_tmpname.short_name); else return CRTDLL_tmpname.short_name; } /********************************************************************* * _itoa (CRTDLL.165) */ LPSTR __cdecl CRTDLL__itoa(INT32 x,LPSTR buf,INT32 buflen) { wsnprintf32A(buf,buflen,"%d",x); return buf; } /********************************************************************* * _ltoa (CRTDLL.180) */ LPSTR __cdecl CRTDLL__ltoa(long x,LPSTR buf,INT32 radix) { switch(radix) { case 2: FIXME(crtdll, "binary format not implemented !\n"); break; case 8: wsnprintf32A(buf,0x80,"%o",x); break; case 10: wsnprintf32A(buf,0x80,"%d",x); break; case 16: wsnprintf32A(buf,0x80,"%x",x); break; default: FIXME(crtdll, "radix %d not implemented !\n", radix); } return buf; } typedef VOID (*sig_handler_type)(VOID); /********************************************************************* * signal (CRTDLL.455) */ VOID __cdecl CRTDLL_signal(int sig, sig_handler_type ptr) { FIXME(crtdll, "(%d %p):stub.\n", sig, ptr); } /********************************************************************* * _ftol (CRTDLL.113) */ LONG __cdecl CRTDLL__ftol(double fl) { return (LONG)fl; } /********************************************************************* * _sleep (CRTDLL.267) */ VOID __cdecl CRTDLL__sleep(unsigned long timeout) { TRACE(crtdll,"CRTDLL__sleep for %ld milliseconds\n",timeout); Sleep((timeout)?timeout:1); } /********************************************************************* * getenv (CRTDLL.437) */ LPSTR __cdecl CRTDLL_getenv(const char *name) { LPSTR environ = GetEnvironmentStrings32A(); 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(crtdll,"got %s\n",pp); } FreeEnvironmentStrings32A( environ ); return pp; } /********************************************************************* * _mbsrchr (CRTDLL.223) */ LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) { /* FIXME: handle multibyte strings */ return strrchr(s,x); } /********************************************************************* * _memicmp (CRTDLL.233)(NTDLL.868) * A stringcompare, without \0 check * RETURNS * -1:if first string is alphabetically before second string * 1:if second '' '' '' '' first '' * 0:if both are equal. */ INT32 __cdecl CRTDLL__memicmp( LPCSTR s1, /* [in] first string */ LPCSTR s2, /* [in] second string */ DWORD len /* [in] length to compare */ ) { int i; for (i=0;itolower(s2[i])) return 1; } return 0; } /********************************************************************* * __dllonexit (CRTDLL.25) */ VOID __cdecl CRTDLL__dllonexit () { FIXME(crtdll,"stub\n"); } /********************************************************************* * wcstok (CRTDLL.519) * Like strtok, but for wide character strings. s is modified, yes. */ LPWSTR CRTDLL_wcstok(LPWSTR s,LPCWSTR delim) { static LPWSTR nexttok = NULL; LPWSTR x,ret; if (!s) s = nexttok; if (!s) return NULL; x = s; while (*x && !CRTDLL_wcschr(delim,*x)) x++; ret = nexttok; if (*x) { *x='\0'; nexttok = x+1; } else nexttok = NULL; return ret; } /********************************************************************* * wcstol (CRTDLL.520) * Like strtol, but for wide character strings. */ INT32 CRTDLL_wcstol(LPWSTR s,LPWSTR *end,INT32 base) { LPSTR sA = HEAP_strdupWtoA(GetProcessHeap(),0,s),endA; INT32 ret = strtol(sA,&endA,base); HeapFree(GetProcessHeap(),0,sA); if (end) *end = s+(endA-sA); /* pointer magic checked. */ return ret; } /********************************************************************* * strdate (CRTDLL.283) */ LPSTR __cdecl CRTDLL__strdate (LPSTR date) { FIXME (crtdll,"%p stub\n", date); return 0; } /********************************************************************* * strtime (CRTDLL.299) */ LPSTR __cdecl CRTDLL__strtime (LPSTR date) { FIXME (crtdll,"%p stub\n", date); return 0; } /********************************************************************* * _ultoa (CRTDLL.311) */ LPSTR __cdecl CRTDLL__ultoa(UINT32 x, LPSTR buf, INT32 buflen) { wsnprintf32A(buf,buflen,"%d",x); return buf; }