No longer directly accessing debuggee memory.
[wine] / dlls / crtdll / crtdll_main.c
1 /*
2  * The C RunTime DLL
3  * 
4  * Implements C run-time functionality as known from UNIX.
5  *
6  * Copyright 1996,1998 Marcus Meissner
7  * Copyright 1996 Jukka Iivonen
8  * Copyright 1997 Uwe Bonnes
9  */
10
11 /*
12 Unresolved issues Uwe Bonnes 970904:
13 - Handling of Binary/Text Files is crude. If in doubt, use fromdos or recode
14 - Arguments in crtdll.spec for functions with double argument
15 - system-call calls another wine process, but without debugging arguments
16               and uses the first wine executable in the path
17 - tested with ftp://ftp.remcomp.com/pub/remcomp/lcc-win32.zip, a C-Compiler
18                 for Win32, based on lcc, from Jacob Navia
19 AJ 990101:
20 - needs a proper stdio emulation based on Win32 file handles
21 - should set CRTDLL errno from GetLastError() in every function
22 */
23
24 /* NOTE: This file also implements the wcs* functions. They _ARE_ in 
25  * the newer Linux libcs, but use 4 byte wide characters, so are unusable,
26  * since we need 2 byte wide characters. - Marcus Meissner, 981031
27  */
28
29 #include "config.h"
30
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <sys/times.h>
38 #include <unistd.h>
39 #include <time.h>
40 #include <ctype.h>
41 #include <math.h>
42 #include <fcntl.h>
43 #include <setjmp.h>
44 #include "winbase.h"
45 #include "windef.h"
46 #include "wingdi.h"
47 #include "winuser.h"
48 #include "winerror.h"
49 #include "ntddk.h"
50 #include "debugtools.h"
51 #include "module.h"
52 #include "heap.h"
53 #include "crtdll.h"
54 #include "drive.h"
55 #include "file.h"
56 #include "options.h"
57 #include "winnls.h"
58
59 DEFAULT_DEBUG_CHANNEL(crtdll);
60
61 /* windows.h RAND_MAX is smaller than normal RAND_MAX */
62 #define CRTDLL_RAND_MAX         0x7fff 
63
64 static DOS_FULL_NAME CRTDLL_tmpname;
65
66 UINT CRTDLL_argc_dll;         /* CRTDLL.23 */
67 LPSTR *CRTDLL_argv_dll;         /* CRTDLL.24 */
68 LPSTR  CRTDLL_acmdln_dll;       /* CRTDLL.38 */
69 UINT CRTDLL_basemajor_dll;    /* CRTDLL.42 */
70 UINT CRTDLL_baseminor_dll;    /* CRTDLL.43 */
71 UINT CRTDLL_baseversion_dll;  /* CRTDLL.44 */
72 UINT CRTDLL_commode_dll;      /* CRTDLL.59 */
73 LPSTR  CRTDLL_environ_dll;      /* CRTDLL.75 */
74 UINT CRTDLL_fmode_dll;        /* CRTDLL.104 */
75 UINT CRTDLL_osmajor_dll;      /* CRTDLL.241 */
76 UINT CRTDLL_osminor_dll;      /* CRTDLL.242 */
77 UINT CRTDLL_osmode_dll;       /* CRTDLL.243 */
78 UINT CRTDLL_osver_dll;        /* CRTDLL.244 */
79 UINT CRTDLL_osversion_dll;    /* CRTDLL.245 */
80 UINT CRTDLL_winmajor_dll;     /* CRTDLL.329 */
81 UINT CRTDLL_winminor_dll;     /* CRTDLL.330 */
82 UINT CRTDLL_winver_dll;       /* CRTDLL.331 */
83
84 /* FIXME: structure layout is obviously not correct */
85 typedef struct
86 {
87     HANDLE handle;
88     int      pad[7];
89 } CRTDLL_FILE;
90
91 CRTDLL_FILE CRTDLL_iob[3];
92
93 static CRTDLL_FILE * const CRTDLL_stdin  = &CRTDLL_iob[0];
94 static CRTDLL_FILE * const CRTDLL_stdout = &CRTDLL_iob[1];
95 static CRTDLL_FILE * const CRTDLL_stderr = &CRTDLL_iob[2];
96
97 typedef VOID (*new_handler_type)(VOID);
98
99 static new_handler_type new_handler;
100
101 #if defined(__GNUC__) && defined(__i386__)
102 #define USING_REAL_FPU
103 #define DO_FPU(x,y) __asm__ __volatile__( x " %0;fwait" : "=m" (y) : )
104 #define POP_FPU(x) DO_FPU("fstpl",x)
105 #endif
106
107 CRTDLL_FILE * __cdecl CRTDLL__fdopen(INT handle, LPCSTR mode);
108
109 /*********************************************************************
110  *                  CRTDLL_MainInit  (CRTDLL.init)
111  */
112 BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
113 {
114         TRACE("(0x%08x,%ld,%p)\n",hinstDLL,fdwReason,lpvReserved);
115
116         if (fdwReason == DLL_PROCESS_ATTACH) {
117                 CRTDLL__fdopen(0,"r");
118                 CRTDLL__fdopen(1,"w");
119                 CRTDLL__fdopen(2,"w");
120         }
121         return TRUE;
122 }
123
124 /*********************************************************************
125  *                  _GetMainArgs  (CRTDLL.022)
126  */
127 LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,
128                                 LPSTR *environ,DWORD flag)
129 {
130         char *cmdline;
131         char  **xargv;
132         int     xargc,end,last_arg,afterlastspace;
133         DWORD   version;
134
135         TRACE("(%p,%p,%p,%ld).\n",
136                 argc,argv,environ,flag
137         );
138
139         if (CRTDLL_acmdln_dll != NULL)
140                 HeapFree(GetProcessHeap(), 0, CRTDLL_acmdln_dll);
141
142         CRTDLL_acmdln_dll = cmdline = HEAP_strdupA( GetProcessHeap(), 0,
143                                                     GetCommandLineA() );
144         TRACE("got '%s'\n", cmdline);
145
146         version = GetVersion();
147         CRTDLL_osver_dll       = version >> 16;
148         CRTDLL_winminor_dll    = version & 0xFF;
149         CRTDLL_winmajor_dll    = (version>>8) & 0xFF;
150         CRTDLL_baseversion_dll = version >> 16;
151         CRTDLL_winver_dll      = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8);
152         CRTDLL_baseminor_dll   = (version >> 16) & 0xFF;
153         CRTDLL_basemajor_dll   = (version >> 24) & 0xFF;
154         CRTDLL_osversion_dll   = version & 0xFFFF;
155         CRTDLL_osminor_dll     = version & 0xFF;
156         CRTDLL_osmajor_dll     = (version>>8) & 0xFF;
157
158         /* missing threading init */
159
160         end=0;last_arg=0;xargv=NULL;xargc=0;afterlastspace=0;
161         while (1)
162         {
163             if ((cmdline[end]==' ') || (cmdline[end]=='\0'))
164             {
165                 if (cmdline[end]=='\0')
166                     last_arg=1;
167                 else
168                     cmdline[end]='\0';
169                 /* alloc xargc + NULL entry */
170                         xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv,
171                                              sizeof(char*)*(xargc+1));
172                 if (strlen(cmdline+afterlastspace))
173                 {
174                     xargv[xargc] = HEAP_strdupA( GetProcessHeap(), 0,
175                                                        cmdline+afterlastspace);
176                     xargc++;
177                     if (!last_arg) /* need to seek to the next arg ? */
178                     {
179                         end++;
180                         while (cmdline[end]==' ')
181                             end++;
182         }
183                     afterlastspace=end;
184                 }
185                 else
186                 {
187                     xargv[xargc] = NULL; /* the last entry is NULL */
188                     break;
189                 }
190             }
191             else
192                 end++;
193         }
194         CRTDLL_argc_dll = xargc;
195         *argc           = xargc;
196         CRTDLL_argv_dll = xargv;
197         *argv           = xargv;
198
199         TRACE("found %d arguments\n",
200                 CRTDLL_argc_dll);
201         CRTDLL_environ_dll = *environ = GetEnvironmentStringsA();
202         return environ;
203 }
204
205
206 typedef void (*_INITTERMFUN)();
207
208 /* fixme: move to header */
209 struct find_t 
210 {   unsigned    attrib;
211     time_t      time_create;    /* -1 when not avaiable */
212     time_t      time_access;    /* -1 when not avaiable */
213     time_t      time_write;
214     unsigned long       size;   /* fixme: 64 bit ??*/
215     char        name[260];
216 };
217  /*********************************************************************
218  *                  _findfirst    (CRTDLL.099)
219  * 
220  * BUGS
221  *   Unimplemented
222  */
223 DWORD __cdecl CRTDLL__findfirst(LPCSTR fname,  struct find_t * x2)
224 {
225   FIXME(":(%s,%p): stub\n",fname,x2);
226   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
227   return FALSE;
228 }
229
230 /*********************************************************************
231  *                  _findnext     (CRTDLL.100)
232  * 
233  * BUGS
234  *   Unimplemented
235  */
236 INT __cdecl CRTDLL__findnext(DWORD hand, struct find_t * x2)
237 {
238   FIXME(":(%ld,%p): stub\n",hand,x2);
239   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
240   return FALSE;
241 }
242
243 /*********************************************************************
244  *                  _fstat        (CRTDLL.111)
245  * 
246  * BUGS
247  *   Unimplemented
248  */
249 int __cdecl CRTDLL__fstat(int file, struct stat* buf)
250 {
251   FIXME(":(%d,%p): stub\n",file,buf);
252   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
253   return FALSE;
254 }
255
256 /*********************************************************************
257  *                  _initterm     (CRTDLL.135)
258  */
259 DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
260 {
261         _INITTERMFUN    *current;
262
263         TRACE("(%p,%p)\n",start,end);
264         current=start;
265         while (current<end) {
266                 if (*current) (*current)();
267                 current++;
268         }
269         return 0;
270 }
271
272 /*********************************************************************
273  *                  _fsopen     (CRTDLL.110)
274  */
275 CRTDLL_FILE * __cdecl CRTDLL__fsopen(LPCSTR x, LPCSTR y, INT z) {
276         FIXME("(%s,%s,%d),stub!\n",x,y,z);
277         return NULL;
278 }
279
280 /*********************************************************************
281  *                  _fdopen     (CRTDLL.91)
282  */
283 CRTDLL_FILE * __cdecl CRTDLL__fdopen(INT handle, LPCSTR mode)
284 {
285     CRTDLL_FILE *file;
286
287     switch (handle) 
288     {
289     case 0:
290         file = CRTDLL_stdin;
291         if (!file->handle) file->handle = GetStdHandle( STD_INPUT_HANDLE );
292         break;
293     case 1:
294         file = CRTDLL_stdout;
295         if (!file->handle) file->handle = GetStdHandle( STD_OUTPUT_HANDLE );
296         break;
297     case 2:
298         file=CRTDLL_stderr;
299         if (!file->handle) file->handle = GetStdHandle( STD_ERROR_HANDLE );
300         break;
301     default:
302         file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) );
303         file->handle = handle;
304         break;
305     }
306   TRACE("open handle %d mode %s  got file %p\n",
307                handle, mode, file);
308   return file;
309 }
310
311
312 /*******************************************************************
313  *         _global_unwind2  (CRTDLL.129)
314  */
315 void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame )
316 {
317     RtlUnwind( frame, 0, NULL, 0 );
318 }
319
320 /*******************************************************************
321  *         _local_unwind2  (CRTDLL.173)
322  */
323 void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr )
324 {
325     TRACE("(%p,%ld)\n",endframe,nr);
326 }
327 /*******************************************************************
328  *         _setjmp  (CRTDLL.264)
329  */
330 INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf)
331 {
332   FIXME(":(%p): stub\n",jmpbuf);
333   return 0;
334 }
335 /*********************************************************************
336  *                  _read     (CRTDLL.256)
337  * 
338  * BUGS
339  *   Unimplemented
340  */
341 INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count)
342 {
343   FIXME(":(%d,%p,%d): stub\n",fd,buf,count);
344   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
345   return FALSE;
346 }
347
348 /*********************************************************************
349  *                  fopen     (CRTDLL.372)
350  */
351 CRTDLL_FILE * __cdecl CRTDLL_fopen(LPCSTR path, LPCSTR mode)
352 {
353   CRTDLL_FILE *file = NULL;
354   HFILE handle;
355 #if 0
356   DOS_FULL_NAME full_name;
357   
358   if (!DOSFS_GetFullName( path, FALSE, &full_name )) {
359     WARN("file %s bad name\n",path);
360    return 0;
361   }
362   
363   file=fopen(full_name.long_name ,mode);
364 #endif
365   DWORD access = 0, creation = 0;
366
367   if ((strchr(mode,'r')&&strchr(mode,'a'))||
368       (strchr(mode,'r')&&strchr(mode,'w'))||
369       (strchr(mode,'w')&&strchr(mode,'a')))
370     return NULL;
371        
372   if (mode[0] == 'r')
373   {
374       access = GENERIC_READ;
375       creation = OPEN_EXISTING;
376       if (mode[1] == '+') access |= GENERIC_WRITE;
377   }
378   else if (mode[0] == 'w')
379   {
380       access = GENERIC_WRITE;
381       creation = CREATE_ALWAYS;
382       if (mode[1] == '+') access |= GENERIC_READ;
383   }
384   else if (mode[0] == 'a')
385   {
386       /* FIXME: there is no O_APPEND in CreateFile, should emulate it */
387       access = GENERIC_WRITE;
388       creation = OPEN_ALWAYS;
389       if (mode[1] == '+') access |= GENERIC_READ;
390   }
391   /* FIXME: should handle text/binary mode */
392
393   if ((handle = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
394                                NULL, creation, FILE_ATTRIBUTE_NORMAL,
395                                -1 )) != INVALID_HANDLE_VALUE)
396   {
397       file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) );
398       file->handle = handle;
399   }
400   TRACE("file %s mode %s got handle %d file %p\n",
401                  path,mode,handle,file);
402   return file;
403 }
404
405 /*********************************************************************
406  *                  fread     (CRTDLL.377)
407  */
408 DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file)
409 {
410 #if 0
411   int i=0;
412   void *temp=ptr;
413
414   /* If we would honour CR/LF <-> LF translation, we could do it like this.
415      We should keep track of all files opened, and probably files with \
416      known binary extensions must be unchanged */
417   while ( (i < (nmemb*size)) && (ret==1)) {
418     ret=fread(temp,1,1,file);
419     TRACE("got %c 0x%02x ret %d\n",
420                  (isalpha(*(unsigned char*)temp))? *(unsigned char*)temp:
421                  ' ',*(unsigned char*)temp, ret);
422     if (*(unsigned char*)temp != 0xd) { /* skip CR */
423       temp++;
424       i++;
425     }
426     else
427       TRACE("skipping ^M\n");
428   }
429   TRACE("0x%08x items of size %d from file %p to %p\n",
430                nmemb,size,file,ptr,);
431   if(i!=nmemb)
432     WARN(" failed!\n");
433
434   return i;
435 #else
436   DWORD ret;
437
438   TRACE("0x%08x items of size %d from file %p to %p\n",
439                nmemb,size,file,ptr);
440   if (!ReadFile( file->handle, ptr, size * nmemb, &ret, NULL ))
441       WARN(" failed!\n");
442
443   return ret / size;
444 #endif
445 }
446 /*********************************************************************
447  *                  freopen    (CRTDLL.379)
448  * 
449  * BUGS
450  *   Unimplemented
451  */
452 DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream)
453 {
454   FIXME(":(%s,%s,%p): stub\n", path, mode, stream);
455   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
456   return FALSE;
457 }
458
459 /*********************************************************************
460  *                  fscanf     (CRTDLL.381)
461  */
462 INT __cdecl CRTDLL_fscanf( CRTDLL_FILE *stream, LPSTR format, ... )
463 {
464 #if 0
465     va_list valist;
466     INT res;
467
468     va_start( valist, format );
469 #ifdef HAVE_VFSCANF
470     res = vfscanf( xlat_file_ptr(stream), format, valist );
471 #endif
472     va_end( valist );
473     return res;
474 #endif
475     FIXME("broken\n");
476     return 0;
477 }
478
479 /*********************************************************************
480  *                  fseek     (CRTDLL.382)
481  */
482 LONG __cdecl CRTDLL_fseek( CRTDLL_FILE *file, LONG offset, INT whence)
483 {
484   TRACE("file %p to 0x%08lx pos %s\n",
485         file,offset,(whence==SEEK_SET)?"SEEK_SET":
486         (whence==SEEK_CUR)?"SEEK_CUR":
487         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
488   if (SetFilePointer( file->handle, offset, NULL, whence ) != 0xffffffff)
489       return 0;
490   WARN(" failed!\n");
491   return -1;
492 }
493   
494 /*********************************************************************
495  *                  fsetpos     (CRTDLL.383)
496  */
497 INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE *file, INT *pos )
498 {
499     TRACE("file %p pos %d\n", file, *pos );
500     return CRTDLL_fseek(file, *pos, SEEK_SET);
501 }
502
503 /*********************************************************************
504  *                  ftell     (CRTDLL.384)
505  */
506 LONG __cdecl CRTDLL_ftell( CRTDLL_FILE *file )
507 {
508     return SetFilePointer( file->handle, 0, NULL, SEEK_CUR );
509 }
510   
511 /*********************************************************************
512  *                  fwrite     (CRTDLL.386)
513  */
514 DWORD __cdecl CRTDLL_fwrite( LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file )
515 {
516     DWORD ret;
517
518     TRACE("0x%08x items of size %d to file %p(%d) from %p\n",
519           nmemb,size,file,file-(CRTDLL_FILE*)CRTDLL_iob,ptr);
520         
521     
522     if (!WriteFile( file->handle, ptr, size * nmemb, &ret, NULL ))
523         WARN(" failed!\n");
524     return ret / size;
525 }
526
527 /*********************************************************************
528  *                  setbuf     (CRTDLL.452)
529  */
530 INT __cdecl CRTDLL_setbuf(CRTDLL_FILE *file, LPSTR buf)
531 {
532   TRACE("(file %p buf %p)\n", file, buf);
533   /* this doesn't work:"void value not ignored as it ought to be" 
534   return setbuf(file,buf); 
535   */
536   /* FIXME: no buffering for now */
537   return 0;
538 }
539
540 /*********************************************************************
541  *                  _open_osfhandle         (CRTDLL.240)
542  */
543 HFILE __cdecl CRTDLL__open_osfhandle(LONG osfhandle, INT flags)
544 {
545 HFILE handle;
546  
547         switch (osfhandle) {
548         case STD_INPUT_HANDLE :
549         case 0 :
550           handle=0;
551           break;
552         case STD_OUTPUT_HANDLE:
553         case 1:
554           handle=1;
555           break;
556         case STD_ERROR_HANDLE:
557         case 2:
558           handle=2;
559           break;
560         default:
561           return (-1);
562         }
563         TRACE("(handle %08lx,flags %d) return %d\n",
564                      osfhandle,flags,handle);
565         return handle;
566         
567 }
568
569 /*********************************************************************
570  *                  srand         (CRTDLL.460)
571  */
572 void __cdecl CRTDLL_srand(DWORD seed)
573 {
574         /* FIXME: should of course be thread? process? local */
575         srand(seed);
576 }
577
578 /*********************************************************************
579  *                  vfprintf       (CRTDLL.373)
580  */
581 INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE *file, LPSTR format, va_list args )
582 {
583     char buffer[2048];  /* FIXME... */
584
585     vsprintf( buffer, format, args );
586     return CRTDLL_fwrite( buffer, 1, strlen(buffer), file );
587 }
588
589 /*********************************************************************
590  *                  fprintf       (CRTDLL.373)
591  */
592 INT __cdecl CRTDLL_fprintf( CRTDLL_FILE *file, LPSTR format, ... )
593 {
594     va_list valist;
595     INT res;
596
597     va_start( valist, format );
598     res = CRTDLL_vfprintf( file, format, valist );
599     va_end( valist );
600     return res;
601 }
602
603 /*********************************************************************
604  *                  time          (CRTDLL.488)
605  */
606 time_t __cdecl CRTDLL_time(time_t *timeptr)
607 {
608         time_t  curtime = time(NULL);
609
610         if (timeptr)
611                 *timeptr = curtime;
612         return curtime;
613 }
614
615 /*********************************************************************
616  *                  clock         (CRTDLL.350)
617  */
618 clock_t __cdecl CRTDLL_clock(void)
619 {
620         struct tms alltimes;
621         clock_t res;
622
623         times(&alltimes);
624         res = alltimes.tms_utime + alltimes.tms_stime+
625                alltimes.tms_cutime + alltimes.tms_cstime;
626         /* Fixme: We need some symbolic representation
627            for (Hostsystem_)CLOCKS_PER_SEC 
628            and (Emulated_system_)CLOCKS_PER_SEC
629            10 holds only for Windows/Linux_i86)
630            */
631         return 10*res;
632 }
633
634 /*********************************************************************
635  *                  _isatty       (CRTDLL.137)
636  */
637 BOOL __cdecl CRTDLL__isatty(DWORD x)
638 {
639         TRACE("(%ld)\n",x);
640         return TRUE;
641 }
642
643 /*********************************************************************
644  *                  _write        (CRTDLL.332)
645  */
646 INT __cdecl CRTDLL__write(INT fd,LPCVOID buf,UINT count)
647 {
648         INT len=0;
649
650         if (fd == -1)
651           len = -1;
652         else if (fd<=2)
653           len = (UINT)write(fd,buf,(LONG)count);
654         else
655           len = _lwrite(fd,buf,count);
656         TRACE("%d/%d byte to dfh %d from %p,\n",
657                        len,count,fd,buf);
658         return len;
659 }
660
661
662 /*********************************************************************
663  *                  _cexit          (CRTDLL.49)
664  *
665  *  FIXME: What the heck is the difference between 
666  *  FIXME           _c_exit         (CRTDLL.47)
667  *  FIXME           _cexit          (CRTDLL.49)
668  *  FIXME           _exit           (CRTDLL.87)
669  *  FIXME           exit            (CRTDLL.359)
670  *
671  * atexit-processing comes to mind -- MW.
672  *
673  */
674 void __cdecl CRTDLL__cexit(INT ret)
675 {
676         TRACE("(%d)\n",ret);
677         ExitProcess(ret);
678 }
679
680
681 /*********************************************************************
682  *                  exit          (CRTDLL.359)
683  */
684 void __cdecl CRTDLL_exit(DWORD ret)
685 {
686         TRACE("(%ld)\n",ret);
687         ExitProcess(ret);
688 }
689
690
691 /*********************************************************************
692  *                  _abnormal_termination          (CRTDLL.36)
693  */
694 INT __cdecl CRTDLL__abnormal_termination(void)
695 {
696         TRACE("(void)\n");
697         return 0;
698 }
699
700
701 /*********************************************************************
702  *                  _access          (CRTDLL.37)
703  */
704 INT __cdecl CRTDLL__access(LPCSTR filename, INT mode)
705 {
706     DWORD attr = GetFileAttributesA(filename);
707
708     if (attr == -1)
709     {
710         if (GetLastError() == ERROR_INVALID_ACCESS)
711             errno = EACCES;
712         else
713             errno = ENOENT;
714         return -1;
715     }
716
717     if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
718     {
719         errno = EACCES;
720         return -1;
721     }
722     else
723         return 0;
724 }
725
726
727 /*********************************************************************
728  *                  fflush        (CRTDLL.365)
729  */
730 INT __cdecl CRTDLL_fflush( CRTDLL_FILE *file )
731 {
732     return FlushFileBuffers( file->handle ) ? 0 : -1;
733 }
734
735
736 /*********************************************************************
737  *                  rand          (CRTDLL.446)
738  */
739 INT __cdecl CRTDLL_rand()
740 {
741     return (rand() & CRTDLL_RAND_MAX); 
742 }
743
744
745 /*********************************************************************
746  *                  putchar       (CRTDLL.442)
747  */
748 void __cdecl CRTDLL_putchar( INT x )
749 {
750     putchar(x);
751 }
752
753
754 /*********************************************************************
755  *                  fputc       (CRTDLL.374)
756  */
757 INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE *file )
758 {
759     char ch = (char)c;
760     DWORD res;
761     TRACE("%c to file %p\n",c,file);
762     if (!WriteFile( file->handle, &ch, 1, &res, NULL )) return -1;
763     return c;
764 }
765
766
767 /*********************************************************************
768  *                  fputs       (CRTDLL.375)
769  */
770 INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE *file )
771 {
772     DWORD res;
773     TRACE("%s to file %p\n",s,file);
774     if (!WriteFile( file->handle, s, strlen(s), &res, NULL )) return -1;
775     return res;
776 }
777
778
779 /*********************************************************************
780  *                  puts       (CRTDLL.443)
781  */
782 INT __cdecl CRTDLL_puts(LPCSTR s)
783 {
784     TRACE("%s \n",s);
785     return puts(s);
786 }
787
788
789 /*********************************************************************
790  *                  putc       (CRTDLL.441)
791  */
792 INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE *file )
793 {
794     return CRTDLL_fputc( c, file );
795 }
796
797 /*********************************************************************
798  *                  fgetc       (CRTDLL.366)
799  */
800 INT __cdecl CRTDLL_fgetc( CRTDLL_FILE *file )
801 {
802     DWORD res;
803     char ch;
804     if (!ReadFile( file->handle, &ch, 1, &res, NULL )) return -1;
805     if (res != 1) return -1;
806     return ch;
807 }
808
809
810 /*********************************************************************
811  *                  getc       (CRTDLL.388)
812  */
813 INT __cdecl CRTDLL_getc( CRTDLL_FILE *file )
814 {
815     return CRTDLL_fgetc( file );
816 }
817
818
819 /*********************************************************************
820  *                  fgets       (CRTDLL.368)
821  */
822 CHAR* __cdecl CRTDLL_fgets( LPSTR s, INT size, CRTDLL_FILE *file )
823 {
824     int    cc;
825     LPSTR  buf_start = s;
826
827     /* BAD, for the whole WINE process blocks... just done this way to test
828      * windows95's ftp.exe.
829      */
830
831     for(cc = CRTDLL_fgetc(file); cc != EOF && cc != '\n'; cc = CRTDLL_fgetc(file))
832         if (cc != '\r')
833         {
834             if (--size <= 0) break;
835             *s++ = (char)cc;
836         }
837
838     *s = '\0';
839
840     TRACE("got '%s'\n", buf_start);
841     return buf_start;
842 }
843
844
845 /*********************************************************************
846  *                  gets          (CRTDLL.391)
847  */
848 LPSTR __cdecl CRTDLL_gets(LPSTR buf)
849 {
850     int    cc;
851     LPSTR  buf_start = buf;
852
853     /* BAD, for the whole WINE process blocks... just done this way to test
854      * windows95's ftp.exe.
855      */
856
857     for(cc = fgetc(stdin); cc != EOF && cc != '\n'; cc = fgetc(stdin))
858         if(cc != '\r') *buf++ = (char)cc;
859
860     *buf = '\0';
861
862     TRACE("got '%s'\n", buf_start);
863     return buf_start;
864 }
865
866
867 /*********************************************************************
868  *                  _rotl          (CRTDLL.259)
869  */
870 UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
871 {
872    unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift));
873
874    TRACE("got 0x%08x rot %d ret 0x%08x\n",
875                   x,shift,ret);
876    return ret;
877     
878 }
879 /*********************************************************************
880  *                  _lrotl          (CRTDLL.176)
881  */
882 DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
883 {
884    unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));
885
886    TRACE("got 0x%08lx rot %d ret 0x%08lx\n",
887                   x,shift,ret);
888    return ret;
889     
890 }
891
892
893 /*********************************************************************
894  *                  _mbsicmp      (CRTDLL.204)
895  */
896 int __cdecl CRTDLL__mbsicmp(unsigned char *x,unsigned char *y)
897 {
898     do {
899         if (!*x)
900             return !!*y;
901         if (!*y)
902             return !!*x;
903         /* FIXME: MBCS handling... */
904         if (*x!=*y)
905             return 1;
906         x++;
907         y++;
908     } while (1);
909 }
910
911
912 /*********************************************************************
913  *                  vsprintf      (CRTDLL.500)
914  */
915 INT __cdecl CRTDLL_vsprintf( LPSTR buffer, LPCSTR spec, va_list args )
916 {
917     return wvsprintfA( buffer, spec, args );
918 }
919
920 /*********************************************************************
921  *                  vswprintf      (CRTDLL.501)
922  */
923 INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
924 {
925     return wvsprintfW( buffer, spec, args );
926 }
927
928 /*********************************************************************
929  *                  _strcmpi   (CRTDLL.282) (CRTDLL.287)
930  */
931 INT __cdecl CRTDLL__strcmpi( LPCSTR s1, LPCSTR s2 )
932 {
933     return lstrcmpiA( s1, s2 );
934 }
935
936
937 /*********************************************************************
938  *                  _strnicmp   (CRTDLL.293)
939  */
940 INT __cdecl CRTDLL__strnicmp( LPCSTR s1, LPCSTR s2, INT n )
941 {
942     return lstrncmpiA( s1, s2, n );
943 }
944
945
946 /*********************************************************************
947  *                  _strlwr      (CRTDLL.293)
948  *
949  * convert a string in place to lowercase 
950  */
951 LPSTR __cdecl CRTDLL__strlwr(LPSTR x)
952 {
953   unsigned char *y =x;
954   
955   TRACE("CRTDLL_strlwr got %s\n", x);
956   while (*y) {
957     if ((*y > 0x40) && (*y< 0x5b))
958       *y = *y + 0x20;
959     y++;
960   }
961   TRACE("   returned %s\n", x);
962                  
963   return x;
964 }
965
966 /*********************************************************************
967  *                  system       (CRTDLL.485)
968  */
969 INT __cdecl CRTDLL_system(LPSTR x)
970 {
971 #define SYSBUF_LENGTH 1500
972   char buffer[SYSBUF_LENGTH];
973   unsigned char *y = x;
974   unsigned char *bp;
975   int i;
976
977   sprintf( buffer, "%s \"", argv0 );
978   bp = buffer + strlen(buffer);
979   i = strlen(buffer) + strlen(x) +2;
980
981   /* Calculate needed buffer size to prevent overflow.  */
982   while (*y) {
983     if (*y =='\\') i++;
984     y++;
985   }
986   /* If buffer too short, exit.  */
987   if (i > SYSBUF_LENGTH) {
988     TRACE("_system buffer to small\n");
989     return 127;
990   }
991   
992   y =x;
993
994   while (*y) {
995     *bp = *y;
996     bp++; y++;
997     if (*(y-1) =='\\') *bp++ = '\\';
998   }
999   /* Remove spaces from end of string.  */
1000   while (*(y-1) == ' ') {
1001     bp--;y--;
1002   }
1003   *bp++ = '"';
1004   *bp = 0;
1005   TRACE("_system got '%s', executing '%s'\n",x,buffer);
1006
1007   return system(buffer);
1008 }
1009
1010 /*********************************************************************
1011  *                  _strupr       (CRTDLL.300)
1012  */
1013 LPSTR __cdecl CRTDLL__strupr(LPSTR x)
1014 {
1015         LPSTR   y=x;
1016
1017         while (*y) {
1018                 *y=toupper(*y);
1019                 y++;
1020         }
1021         return x;
1022 }
1023
1024 /*********************************************************************
1025  *                  longjmp        (CRTDLL.426)
1026  */
1027 VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
1028 {
1029     FIXME("CRTDLL_longjmp semistup, expect crash\n");
1030     longjmp(env, val);
1031 }
1032
1033 /*********************************************************************
1034  *                  malloc        (CRTDLL.427)
1035  */
1036 VOID* __cdecl CRTDLL_malloc(DWORD size)
1037 {
1038     return HeapAlloc(GetProcessHeap(),0,size);
1039 }
1040
1041 /*********************************************************************
1042  *                  new           (CRTDLL.001)
1043  */
1044 VOID* __cdecl CRTDLL_new(DWORD size)
1045 {
1046     VOID* result;
1047     if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler)
1048         (*new_handler)();
1049     return result;
1050 }
1051
1052 /*********************************************************************
1053  *                  set_new_handler(CRTDLL.003)
1054  */
1055 new_handler_type __cdecl CRTDLL_set_new_handler(new_handler_type func)
1056 {
1057     new_handler_type old_handler = new_handler;
1058     new_handler = func;
1059     return old_handler;
1060 }
1061
1062 /*********************************************************************
1063  *                  calloc        (CRTDLL.350)
1064  */
1065 VOID* __cdecl CRTDLL_calloc(DWORD size, DWORD count)
1066 {
1067     return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
1068 }
1069
1070 /*********************************************************************
1071  *                  realloc        (CRTDLL.447)
1072  */
1073 VOID* __cdecl CRTDLL_realloc( VOID *ptr, DWORD size )
1074 {
1075     return HeapReAlloc( GetProcessHeap(), 0, ptr, size );
1076 }
1077
1078 /*********************************************************************
1079  *                  free          (CRTDLL.427)
1080  */
1081 VOID __cdecl CRTDLL_free(LPVOID ptr)
1082 {
1083     HeapFree(GetProcessHeap(),0,ptr);
1084 }
1085
1086 /*********************************************************************
1087  *                  delete       (CRTDLL.002)
1088  */
1089 VOID __cdecl CRTDLL_delete(VOID* ptr)
1090 {
1091     HeapFree(GetProcessHeap(),0,ptr);
1092 }
1093
1094 /*********************************************************************
1095  *                  _strdup          (CRTDLL.285)
1096  */
1097 LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr)
1098 {
1099     return HEAP_strdupA(GetProcessHeap(),0,ptr);
1100 }
1101
1102 /*********************************************************************
1103  *                  fclose           (CRTDLL.362)
1104  */
1105 INT __cdecl CRTDLL_fclose( CRTDLL_FILE *file )
1106 {
1107     TRACE("%p\n", file );
1108     if (!CloseHandle( file->handle )) return -1;
1109     HeapFree( GetProcessHeap(), 0, file );
1110     return 0;
1111 }
1112
1113 /*********************************************************************
1114  *                  _unlink           (CRTDLL.315)
1115  */
1116 INT __cdecl CRTDLL__unlink(LPCSTR pathname)
1117 {
1118     int ret=0;
1119     DOS_FULL_NAME full_name;
1120
1121     if (!DOSFS_GetFullName( pathname, FALSE, &full_name )) {
1122       WARN("CRTDLL_unlink file %s bad name\n",pathname);
1123       return EOF;
1124     }
1125   
1126     ret=unlink(full_name.long_name);
1127     TRACE("(%s unix %s)\n",
1128                    pathname,full_name.long_name);
1129     if(ret)
1130       WARN(" Failed!\n");
1131
1132     return ret;
1133 }
1134
1135 /*********************************************************************
1136  *                  rename           (CRTDLL.449)
1137  */
1138 INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath)
1139 {
1140     BOOL ok = MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING );
1141     return ok ? 0 : -1;
1142 }
1143
1144
1145 /*********************************************************************
1146  *                  _stat          (CRTDLL.280)
1147  */
1148
1149 struct win_stat
1150 {
1151     UINT16 win_st_dev;
1152     UINT16 win_st_ino;
1153     UINT16 win_st_mode;
1154     INT16  win_st_nlink;
1155     INT16  win_st_uid;
1156     INT16  win_st_gid;
1157     UINT win_st_rdev;
1158     INT  win_st_size;
1159     INT  win_st_atime;
1160     INT  win_st_mtime;
1161     INT  win_st_ctime;
1162 };
1163
1164 int __cdecl CRTDLL__stat(const char * filename, struct win_stat * buf)
1165 {
1166     int ret=0;
1167     DOS_FULL_NAME full_name;
1168     struct stat mystat;
1169
1170     if (!DOSFS_GetFullName( filename, TRUE, &full_name ))
1171     {
1172       WARN("CRTDLL__stat filename %s bad name\n",filename);
1173       return -1;
1174     }
1175     ret=stat(full_name.long_name,&mystat);
1176     TRACE("CRTDLL__stat %s\n", filename);
1177     if(ret) 
1178       WARN(" Failed!\n");
1179
1180     /* FIXME: should check what Windows returns */
1181
1182     buf->win_st_dev   = mystat.st_dev;
1183     buf->win_st_ino   = mystat.st_ino;
1184     buf->win_st_mode  = mystat.st_mode;
1185     buf->win_st_nlink = mystat.st_nlink;
1186     buf->win_st_uid   = mystat.st_uid;
1187     buf->win_st_gid   = mystat.st_gid;
1188     buf->win_st_rdev  = mystat.st_rdev;
1189     buf->win_st_size  = mystat.st_size;
1190     buf->win_st_atime = mystat.st_atime;
1191     buf->win_st_mtime = mystat.st_mtime;
1192     buf->win_st_ctime = mystat.st_ctime;
1193     return ret;
1194 }
1195
1196 /*********************************************************************
1197  *                  _open           (CRTDLL.239)
1198  */
1199 HFILE __cdecl CRTDLL__open(LPCSTR path,INT flags)
1200 {
1201     DWORD access = 0, creation = 0;
1202     HFILE ret;
1203     
1204     /* FIXME:
1205        the flags in lcc's header differ from the ones in Linux, e.g.
1206        Linux: define O_APPEND         02000   (= 0x400)
1207        lcc:  define _O_APPEND       0x0008  
1208        so here a scheme to translate them
1209        Probably lcc is wrong here, but at least a hack to get is going
1210        */
1211     switch(flags & 3)
1212     {
1213     case O_RDONLY: access |= GENERIC_READ; break;
1214     case O_WRONLY: access |= GENERIC_WRITE; break;
1215     case O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1216     }
1217
1218     if (flags & 0x0100) /* O_CREAT */
1219     {
1220         if (flags & 0x0400) /* O_EXCL */
1221             creation = CREATE_NEW;
1222         else if (flags & 0x0200) /* O_TRUNC */
1223             creation = CREATE_ALWAYS;
1224         else
1225             creation = OPEN_ALWAYS;
1226     }
1227     else  /* no O_CREAT */
1228     {
1229         if (flags & 0x0200) /* O_TRUNC */
1230             creation = TRUNCATE_EXISTING;
1231         else
1232             creation = OPEN_EXISTING;
1233     }
1234     if (flags & 0x0008) /* O_APPEND */
1235         FIXME("O_APPEND not supported\n" );
1236     if (flags & 0xf0f4) 
1237       TRACE("CRTDLL_open file unsupported flags 0x%04x\n",flags);
1238     /* End Fixme */
1239
1240     ret = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
1241                          NULL, creation, FILE_ATTRIBUTE_NORMAL, -1 );
1242     TRACE("CRTDLL_open file %s mode 0x%04x got handle %d\n", path,flags,ret);
1243     return ret;
1244 }
1245
1246 /*********************************************************************
1247  *                  _close           (CRTDLL.57)
1248  */
1249 INT __cdecl CRTDLL__close(HFILE fd)
1250 {
1251     int ret=_lclose(fd);
1252
1253     TRACE("(%d)\n",fd);
1254     if(ret)
1255       WARN(" Failed!\n");
1256
1257     return ret;
1258 }
1259
1260 /*********************************************************************
1261  *                  feof           (CRTDLL.363)
1262  */
1263 INT __cdecl CRTDLL_feof( CRTDLL_FILE *file )
1264 {
1265     FIXME("stub\n" );
1266     return 0;
1267 }
1268
1269 /*********************************************************************
1270  *                  setlocale           (CRTDLL.453)
1271  */
1272 LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
1273 {
1274         LPSTR categorystr;
1275
1276         switch (category) {
1277         case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
1278         case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
1279         case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
1280         case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
1281         case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
1282         case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
1283         default: categorystr = "UNKNOWN?";break;
1284         }
1285         FIXME("(%s,%s),stub!\n",categorystr,locale);
1286         return "C";
1287 }
1288
1289 /*********************************************************************
1290  *                  _setmode           (CRTDLL.265)
1291  * FIXME: At present we ignore the request to translate CR/LF to LF.
1292  *
1293  * We allways translate when we read with fgets, we never do with fread
1294  *
1295  */
1296 INT __cdecl CRTDLL__setmode( INT fh,INT mode)
1297 {
1298         /* FIXME */
1299 #define O_TEXT     0x4000
1300 #define O_BINARY   0x8000
1301
1302         FIXME("on fhandle %d mode %s, STUB.\n",
1303                       fh,(mode=O_TEXT)?"O_TEXT":
1304                       (mode=O_BINARY)?"O_BINARY":"UNKNOWN");
1305         return -1;
1306 }
1307
1308 /*********************************************************************
1309  *                  _fpreset           (CRTDLL.107)
1310  */
1311 VOID __cdecl CRTDLL__fpreset(void)
1312 {
1313        FIXME(" STUB.\n");
1314 }
1315
1316 /*********************************************************************
1317  *                  atexit           (CRTDLL.345)
1318  */
1319 INT __cdecl CRTDLL_atexit(LPVOID x)
1320 {
1321         FIXME("(%p), STUB.\n",x);
1322         return 0; /* successful */
1323 }
1324
1325 /*********************************************************************
1326  *                  _isctype           (CRTDLL.138)
1327  */
1328 BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
1329 {
1330         if ((type & CRTDLL_SPACE) && isspace(x))
1331                 return TRUE;
1332         if ((type & CRTDLL_PUNCT) && ispunct(x))
1333                 return TRUE;
1334         if ((type & CRTDLL_LOWER) && islower(x))
1335                 return TRUE;
1336         if ((type & CRTDLL_UPPER) && isupper(x))
1337                 return TRUE;
1338         if ((type & CRTDLL_ALPHA) && isalpha(x))
1339                 return TRUE;
1340         if ((type & CRTDLL_DIGIT) && isdigit(x))
1341                 return TRUE;
1342         if ((type & CRTDLL_CONTROL) && iscntrl(x))
1343                 return TRUE;
1344         /* check CRTDLL_LEADBYTE */
1345         return FALSE;
1346 }
1347
1348 /*********************************************************************
1349  *                  _chdrive           (CRTDLL.52)
1350  *
1351  *  newdir      [I] drive to change to, A=1
1352  *
1353  */
1354 BOOL __cdecl CRTDLL__chdrive(INT newdrive)
1355 {
1356         /* FIXME: generates errnos */
1357         return DRIVE_SetCurrentDrive(newdrive-1);
1358 }
1359
1360 /*********************************************************************
1361  *                  _chdir           (CRTDLL.51)
1362  */
1363 INT __cdecl CRTDLL__chdir(LPCSTR newdir)
1364 {
1365         if (!SetCurrentDirectoryA(newdir))
1366                 return 1;
1367         return 0;
1368 }
1369
1370 /*********************************************************************
1371  *                  _fullpath           (CRTDLL.114)
1372  */
1373 LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
1374 {
1375   DOS_FULL_NAME full_name;
1376
1377   if (!buf)
1378   {
1379       size = 256;
1380       if(!(buf = CRTDLL_malloc(size))) return NULL;
1381   }
1382   if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
1383   lstrcpynA(buf,full_name.short_name,size);
1384   TRACE("CRTDLL_fullpath got %s\n",buf);
1385   return buf;
1386 }
1387
1388 /*********************************************************************
1389  *                  _splitpath           (CRTDLL.279)
1390  */
1391 VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
1392 {
1393   /* drive includes :
1394      directory includes leading and trailing (forward and backward slashes)
1395      filename without dot and slashes
1396      extension with leading dot
1397      */
1398   char * drivechar,*dirchar,*namechar;
1399
1400   TRACE("CRTDLL__splitpath got %s\n",path);
1401
1402   drivechar  = strchr(path,':');
1403   dirchar    = strrchr(path,'/');
1404   namechar   = strrchr(path,'\\');
1405   dirchar = MAX(dirchar,namechar);
1406   if (dirchar)
1407     namechar   = strrchr(dirchar,'.');
1408   else
1409     namechar   = strrchr(path,'.');
1410   
1411   
1412   if (drive) 
1413     {
1414       *drive = 0x00;
1415       if (drivechar) 
1416         {
1417           strncat(drive,path,drivechar-path+1);
1418           path = drivechar+1;
1419         }
1420     }
1421   if (directory) 
1422     {
1423       *directory = 0x00;
1424       if (dirchar)
1425         {
1426           strncat(directory,path,dirchar-path+1);
1427           path = dirchar+1;
1428         }
1429     }
1430   if (filename)
1431     {
1432       *filename = 0x00;
1433       if (namechar)
1434         {
1435           strncat(filename,path,namechar-path);
1436           if (extension) 
1437             {
1438               *extension = 0x00;
1439               strcat(extension,namechar);
1440             }
1441         }
1442     }
1443
1444   TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
1445   
1446 }
1447
1448
1449 /*********************************************************************
1450  *                  _makepath           (CRTDLL.182)
1451  */
1452
1453 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive, 
1454                               LPCSTR directory, LPCSTR filename, 
1455                               LPCSTR extension )
1456 {
1457         char ch;
1458         TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory, 
1459               filename, extension);
1460
1461         if ( !path )
1462                 return;
1463
1464         path[0] = 0;
1465         if ( drive ) 
1466                 if ( drive[0] ) {
1467                         sprintf(path, "%c:", drive[0]);
1468                 }
1469         if ( directory ) 
1470                 if ( directory[0] ) {
1471                         strcat(path, directory);
1472                         ch = path[strlen(path)-1];
1473                         if (ch != '/' && ch != '\\')
1474                                 strcat(path,"\\");
1475                 }
1476         if ( filename ) 
1477                 if ( filename[0] ) {
1478                         strcat(path, filename);
1479                         if ( extension ) {
1480                                 if ( extension[0] ) {
1481                                         if ( extension[0] != '.' ) {
1482                                                 strcat(path,".");
1483                                         } 
1484                                         strcat(path,extension);
1485                                 }
1486                         }
1487                 }
1488         
1489         TRACE("CRTDLL__makepath returns %s\n",path);  
1490 }
1491
1492 /*********************************************************************
1493  *                  _getcwd           (CRTDLL.120)
1494  */
1495 CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size)
1496 {
1497   char test[1];
1498   int len;
1499
1500   len = size;
1501   if (!buf) {
1502     if (size < 0) /* allocate as big as nescessary */
1503       len =GetCurrentDirectoryA(1,test) + 1;
1504     if(!(buf = CRTDLL_malloc(len)))
1505     {
1506         /* set error to OutOfRange */
1507         return( NULL );
1508     }
1509   }
1510   size = len;
1511   if(!(len =GetCurrentDirectoryA(len,buf)))
1512     {
1513       return NULL;
1514     }
1515   if (len > size)
1516     {
1517       /* set error to ERANGE */
1518       TRACE("CRTDLL_getcwd buffer to small\n");
1519       return NULL;
1520     }
1521   return buf;
1522
1523 }
1524
1525 /*********************************************************************
1526  *                  _getdcwd           (CRTDLL.121)
1527  */
1528 CHAR* __cdecl CRTDLL__getdcwd(INT drive,LPSTR buf, INT size)
1529 {
1530   char test[1];
1531   int len;
1532
1533   FIXME("(\"%c:\",%s,%d)\n",drive+'A',buf,size);
1534   len = size;
1535   if (!buf) {
1536     if (size < 0) /* allocate as big as nescessary */
1537       len =GetCurrentDirectoryA(1,test) + 1;
1538     if(!(buf = CRTDLL_malloc(len)))
1539     {
1540         /* set error to OutOfRange */
1541         return( NULL );
1542     }
1543   }
1544   size = len;
1545   if(!(len =GetCurrentDirectoryA(len,buf)))
1546     {
1547       return NULL;
1548     }
1549   if (len > size)
1550     {
1551       /* set error to ERANGE */
1552       TRACE("buffer to small\n");
1553       return NULL;
1554     }
1555   return buf;
1556
1557 }
1558
1559 /*********************************************************************
1560  *                  _getdrive           (CRTDLL.124)
1561  *
1562  *  Return current drive, 1 for A, 2 for B
1563  */
1564 INT __cdecl CRTDLL__getdrive(VOID)
1565 {
1566     return DRIVE_GetCurrentDrive() + 1;
1567 }
1568
1569 /*********************************************************************
1570  *                  _mkdir           (CRTDLL.234)
1571  */
1572 INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
1573 {
1574         if (!CreateDirectoryA(newdir,NULL))
1575                 return -1;
1576         return 0;
1577 }
1578
1579 /*********************************************************************
1580  *                  remove           (CRTDLL.448)
1581  */
1582 INT __cdecl CRTDLL_remove(LPCSTR file)
1583 {
1584         if (!DeleteFileA(file))
1585                 return -1;
1586         return 0;
1587 }
1588
1589 /*********************************************************************
1590  *                  _errno           (CRTDLL.52)
1591  * Yes, this is a function.
1592  */
1593 LPINT __cdecl CRTDLL__errno()
1594 {
1595         static  int crtdllerrno;
1596         
1597         /* FIXME: we should set the error at the failing function call time */
1598         crtdllerrno = LastErrorToErrno(GetLastError());
1599         return &crtdllerrno;
1600 }
1601
1602 /*********************************************************************
1603  *                  _tempnam           (CRTDLL.305)
1604  * 
1605  */
1606 LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix)
1607 {
1608
1609      char *ret;
1610      DOS_FULL_NAME tempname;
1611      
1612      if ((ret = tempnam(dir,prefix))==NULL) {
1613        WARN("Unable to get unique filename\n");
1614        return NULL;
1615      }
1616      if (!DOSFS_GetFullName(ret,FALSE,&tempname))
1617      {
1618        TRACE("Wrong path?\n");
1619        return NULL;
1620      }
1621      free(ret);
1622      if ((ret = CRTDLL_malloc(strlen(tempname.short_name)+1)) == NULL) {
1623          WARN("CRTDL_malloc for shortname failed\n");
1624          return NULL;
1625      }
1626      if ((ret = strcpy(ret,tempname.short_name)) == NULL) { 
1627        WARN("Malloc for shortname failed\n");
1628        return NULL;
1629      }
1630      
1631      TRACE("dir %s prefix %s got %s\n",
1632                     dir,prefix,ret);
1633      return ret;
1634
1635 }
1636 /*********************************************************************
1637  *                  tmpnam           (CRTDLL.490)
1638  *
1639  * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1640  * 
1641  */
1642 LPSTR __cdecl CRTDLL_tmpnam(LPSTR s)
1643 {
1644      char *ret;
1645
1646      if ((ret =tmpnam(s))== NULL) {
1647        WARN("Unable to get unique filename\n");
1648        return NULL;
1649      }
1650      if (!DOSFS_GetFullName(ret,FALSE,&CRTDLL_tmpname))
1651      {
1652        TRACE("Wrong path?\n");
1653        return NULL;
1654      }
1655      strcat(CRTDLL_tmpname.short_name,".");
1656      TRACE("for buf %p got %s\n",
1657                     s,CRTDLL_tmpname.short_name);
1658      TRACE("long got %s\n",
1659                     CRTDLL_tmpname.long_name);
1660      if ( s != NULL) 
1661        return strcpy(s,CRTDLL_tmpname.short_name);
1662      else 
1663        return CRTDLL_tmpname.short_name;
1664
1665 }
1666
1667 /*********************************************************************
1668  *                  _itoa           (CRTDLL.165)
1669  */
1670 LPSTR  __cdecl CRTDLL__itoa(INT x,LPSTR buf,INT buflen)
1671 {
1672     wsnprintfA(buf,buflen,"%d",x);
1673     return buf;
1674 }
1675
1676 /*********************************************************************
1677  *                  _ltoa           (CRTDLL.180)
1678  */
1679 LPSTR  __cdecl CRTDLL__ltoa(long x,LPSTR buf,INT radix)
1680 {
1681     switch(radix) {
1682         case  2: FIXME("binary format not implemented !\n");
1683                  break;
1684         case  8: wsnprintfA(buf,0x80,"%o",x);
1685                  break;
1686         case 10: wsnprintfA(buf,0x80,"%d",x);
1687                  break;
1688         case 16: wsnprintfA(buf,0x80,"%x",x);
1689                  break;
1690         default: FIXME("radix %d not implemented !\n", radix);
1691     }
1692     return buf;
1693 }
1694
1695 /*********************************************************************
1696  *                  _ultoa           (CRTDLL.311)
1697  */
1698 LPSTR  __cdecl CRTDLL__ultoa(long x,LPSTR buf,INT radix)
1699 {
1700     switch(radix) {
1701         case  2: FIXME("binary format not implemented !\n");
1702                  break;
1703         case  8: wsnprintfA(buf,0x80,"%lo",x);
1704                  break;
1705         case 10: wsnprintfA(buf,0x80,"%ld",x);
1706                  break;
1707         case 16: wsnprintfA(buf,0x80,"%lx",x);
1708                  break;
1709         default: FIXME("radix %d not implemented !\n", radix);
1710     }
1711     return buf;
1712 }
1713
1714 typedef VOID (*sig_handler_type)(VOID);
1715
1716 /*********************************************************************
1717  *                  signal           (CRTDLL.455)
1718  */
1719 VOID __cdecl CRTDLL_signal(int sig, sig_handler_type ptr)
1720 {
1721     FIXME("(%d %p):stub.\n", sig, ptr);
1722 }
1723
1724 /*********************************************************************
1725  *                  _ftol            (CRTDLL.113)
1726  */
1727 #ifdef USING_REAL_FPU
1728 LONG __cdecl CRTDLL__ftol(void) {
1729         /* don't just do DO_FPU("fistp",retval), because the rounding
1730          * mode must also be set to "round towards zero"... */
1731         double fl;
1732         POP_FPU(fl);
1733         return (LONG)fl;
1734 }
1735 #else
1736 LONG __cdecl CRTDLL__ftol(double fl) {
1737         FIXME("should be register function\n");
1738         return (LONG)fl;
1739 }
1740 #endif
1741
1742 /*********************************************************************
1743  *                  _CIpow           (CRTDLL.14)
1744  */
1745 #ifdef USING_REAL_FPU
1746 LONG __cdecl CRTDLL__CIpow(void) {
1747         double x,y;
1748         POP_FPU(y);
1749         POP_FPU(x);
1750         return pow(x,y);
1751 }
1752 #else
1753 LONG __cdecl CRTDLL__CIpow(double x,double y) {
1754         FIXME("should be register function\n");
1755         return pow(x,y);
1756 }
1757 #endif
1758
1759 /*********************************************************************
1760  *                  _sleep           (CRTDLL.267)
1761  */
1762 VOID __cdecl CRTDLL__sleep(unsigned long timeout) 
1763 {
1764   TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
1765   Sleep((timeout)?timeout:1);
1766 }
1767
1768 /*********************************************************************
1769  *                  getenv           (CRTDLL.437)
1770  */
1771 LPSTR __cdecl CRTDLL_getenv(const char *name) 
1772 {
1773      LPSTR environ = GetEnvironmentStringsA();
1774      LPSTR pp,pos = NULL;
1775      unsigned int length;
1776   
1777      for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
1778        {
1779          pos =strchr(pp,'=');
1780          if (pos)
1781            length = pos -pp;
1782          else
1783            length = strlen(pp);
1784          if (!strncmp(pp,name,length)) break;
1785        }
1786      if ((pp)&& (pos)) 
1787        {
1788          pp = pos+1;
1789          TRACE("got %s\n",pp);
1790        }
1791      FreeEnvironmentStringsA( environ );
1792      return pp;
1793 }
1794
1795 /*********************************************************************
1796  *                  _mbsrchr           (CRTDLL.223)
1797  */
1798 LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) {
1799         /* FIXME: handle multibyte strings */
1800         return strrchr(s,x);
1801 }
1802
1803 /*********************************************************************
1804  *                  _memicmp           (CRTDLL.233)(NTDLL.868)
1805  * A stringcompare, without \0 check
1806  * RETURNS
1807  *      -1:if first string is alphabetically before second string
1808  *      1:if second ''    ''      ''          ''   first   ''
1809  *      0:if both are equal.
1810  */
1811 INT __cdecl CRTDLL__memicmp(
1812         LPCSTR s1,      /* [in] first string */
1813         LPCSTR s2,      /* [in] second string */
1814         DWORD len       /* [in] length to compare */
1815 ) { 
1816         int     i;
1817
1818         for (i=0;i<len;i++) {
1819                 if (tolower(s1[i])<tolower(s2[i]))
1820                         return -1;
1821                 if (tolower(s1[i])>tolower(s2[i]))
1822                         return  1;
1823         }
1824         return 0;
1825 }
1826 /*********************************************************************
1827  *                  __dllonexit           (CRTDLL.25)
1828  */
1829 VOID __cdecl CRTDLL__dllonexit ()
1830 {       
1831         FIXME("stub\n");
1832 }
1833
1834 /*********************************************************************
1835  *                  wcstol           (CRTDLL.520)
1836  * Like strtol, but for wide character strings.
1837  */
1838 INT __cdecl CRTDLL_wcstol(LPWSTR s,LPWSTR *end,INT base) {
1839         LPSTR   sA = HEAP_strdupWtoA(GetProcessHeap(),0,s),endA;
1840         INT     ret = strtol(sA,&endA,base);
1841
1842         HeapFree(GetProcessHeap(),0,sA);
1843         if (end) *end = s+(endA-sA); /* pointer magic checked. */
1844         return ret;
1845 }
1846 /*********************************************************************
1847  *                  _strdate          (CRTDLL.283)
1848  */
1849 LPSTR __cdecl CRTDLL__strdate (LPSTR date)
1850 {       FIXME("%p stub\n", date);
1851         return 0;
1852 }
1853
1854 /*********************************************************************
1855  *                  _strtime          (CRTDLL.299)
1856  */
1857 LPSTR __cdecl CRTDLL__strtime (LPSTR date)
1858 {       FIXME("%p stub\n", date);
1859         return 0;
1860 }
1861
1862 /*********************************************************************
1863  *                  _except_handler2  (CRTDLL.78)
1864  */
1865 INT __cdecl CRTDLL__except_handler2 (
1866         PEXCEPTION_RECORD rec,
1867         PEXCEPTION_FRAME frame,
1868         PCONTEXT context,
1869         PEXCEPTION_FRAME  *dispatcher)
1870 {
1871         FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
1872         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
1873         frame->Handler, context, dispatcher);
1874         return ExceptionContinueSearch;
1875 }