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