Cleaned up debug channels a bit.
[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     return DeleteFileA( pathname ) ? 0 : -1;
1119 }
1120
1121 /*********************************************************************
1122  *                  rename           (CRTDLL.449)
1123  */
1124 INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath)
1125 {
1126     BOOL ok = MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING );
1127     return ok ? 0 : -1;
1128 }
1129
1130
1131 /*********************************************************************
1132  *                  _stat          (CRTDLL.280)
1133  */
1134
1135 struct win_stat
1136 {
1137     UINT16 win_st_dev;
1138     UINT16 win_st_ino;
1139     UINT16 win_st_mode;
1140     INT16  win_st_nlink;
1141     INT16  win_st_uid;
1142     INT16  win_st_gid;
1143     UINT win_st_rdev;
1144     INT  win_st_size;
1145     INT  win_st_atime;
1146     INT  win_st_mtime;
1147     INT  win_st_ctime;
1148 };
1149
1150 int __cdecl CRTDLL__stat(const char * filename, struct win_stat * buf)
1151 {
1152     int ret=0;
1153     DOS_FULL_NAME full_name;
1154     struct stat mystat;
1155
1156     if (!DOSFS_GetFullName( filename, TRUE, &full_name ))
1157     {
1158       WARN("CRTDLL__stat filename %s bad name\n",filename);
1159       return -1;
1160     }
1161     ret=stat(full_name.long_name,&mystat);
1162     TRACE("CRTDLL__stat %s\n", filename);
1163     if(ret) 
1164       WARN(" Failed!\n");
1165
1166     /* FIXME: should check what Windows returns */
1167
1168     buf->win_st_dev   = mystat.st_dev;
1169     buf->win_st_ino   = mystat.st_ino;
1170     buf->win_st_mode  = mystat.st_mode;
1171     buf->win_st_nlink = mystat.st_nlink;
1172     buf->win_st_uid   = mystat.st_uid;
1173     buf->win_st_gid   = mystat.st_gid;
1174     buf->win_st_rdev  = mystat.st_rdev;
1175     buf->win_st_size  = mystat.st_size;
1176     buf->win_st_atime = mystat.st_atime;
1177     buf->win_st_mtime = mystat.st_mtime;
1178     buf->win_st_ctime = mystat.st_ctime;
1179     return ret;
1180 }
1181
1182 /*********************************************************************
1183  *                  _open           (CRTDLL.239)
1184  */
1185 HFILE __cdecl CRTDLL__open(LPCSTR path,INT flags)
1186 {
1187     DWORD access = 0, creation = 0;
1188     HFILE ret;
1189     
1190     /* FIXME:
1191        the flags in lcc's header differ from the ones in Linux, e.g.
1192        Linux: define O_APPEND         02000   (= 0x400)
1193        lcc:  define _O_APPEND       0x0008  
1194        so here a scheme to translate them
1195        Probably lcc is wrong here, but at least a hack to get is going
1196        */
1197     switch(flags & 3)
1198     {
1199     case O_RDONLY: access |= GENERIC_READ; break;
1200     case O_WRONLY: access |= GENERIC_WRITE; break;
1201     case O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1202     }
1203
1204     if (flags & 0x0100) /* O_CREAT */
1205     {
1206         if (flags & 0x0400) /* O_EXCL */
1207             creation = CREATE_NEW;
1208         else if (flags & 0x0200) /* O_TRUNC */
1209             creation = CREATE_ALWAYS;
1210         else
1211             creation = OPEN_ALWAYS;
1212     }
1213     else  /* no O_CREAT */
1214     {
1215         if (flags & 0x0200) /* O_TRUNC */
1216             creation = TRUNCATE_EXISTING;
1217         else
1218             creation = OPEN_EXISTING;
1219     }
1220     if (flags & 0x0008) /* O_APPEND */
1221         FIXME("O_APPEND not supported\n" );
1222     if (flags & 0xf0f4) 
1223       TRACE("CRTDLL_open file unsupported flags 0x%04x\n",flags);
1224     /* End Fixme */
1225
1226     ret = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
1227                          NULL, creation, FILE_ATTRIBUTE_NORMAL, -1 );
1228     TRACE("CRTDLL_open file %s mode 0x%04x got handle %d\n", path,flags,ret);
1229     return ret;
1230 }
1231
1232 /*********************************************************************
1233  *                  _close           (CRTDLL.57)
1234  */
1235 INT __cdecl CRTDLL__close(HFILE fd)
1236 {
1237     int ret=_lclose(fd);
1238
1239     TRACE("(%d)\n",fd);
1240     if(ret)
1241       WARN(" Failed!\n");
1242
1243     return ret;
1244 }
1245
1246 /*********************************************************************
1247  *                  feof           (CRTDLL.363)
1248  */
1249 INT __cdecl CRTDLL_feof( CRTDLL_FILE *file )
1250 {
1251     FIXME("stub\n" );
1252     return 0;
1253 }
1254
1255 /*********************************************************************
1256  *                  setlocale           (CRTDLL.453)
1257  */
1258 LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
1259 {
1260         LPSTR categorystr;
1261
1262         switch (category) {
1263         case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
1264         case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
1265         case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
1266         case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
1267         case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
1268         case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
1269         default: categorystr = "UNKNOWN?";break;
1270         }
1271         FIXME("(%s,%s),stub!\n",categorystr,locale);
1272         return "C";
1273 }
1274
1275 /*********************************************************************
1276  *                  _setmode           (CRTDLL.265)
1277  * FIXME: At present we ignore the request to translate CR/LF to LF.
1278  *
1279  * We allways translate when we read with fgets, we never do with fread
1280  *
1281  */
1282 INT __cdecl CRTDLL__setmode( INT fh,INT mode)
1283 {
1284         /* FIXME */
1285 #define O_TEXT     0x4000
1286 #define O_BINARY   0x8000
1287
1288         FIXME("on fhandle %d mode %s, STUB.\n",
1289                       fh,(mode=O_TEXT)?"O_TEXT":
1290                       (mode=O_BINARY)?"O_BINARY":"UNKNOWN");
1291         return -1;
1292 }
1293
1294 /*********************************************************************
1295  *                  _fpreset           (CRTDLL.107)
1296  */
1297 VOID __cdecl CRTDLL__fpreset(void)
1298 {
1299        FIXME(" STUB.\n");
1300 }
1301
1302 /*********************************************************************
1303  *                  atexit           (CRTDLL.345)
1304  */
1305 INT __cdecl CRTDLL_atexit(LPVOID x)
1306 {
1307         FIXME("(%p), STUB.\n",x);
1308         return 0; /* successful */
1309 }
1310
1311 /*********************************************************************
1312  *                  _isctype           (CRTDLL.138)
1313  */
1314 BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
1315 {
1316         if ((type & CRTDLL_SPACE) && isspace(x))
1317                 return TRUE;
1318         if ((type & CRTDLL_PUNCT) && ispunct(x))
1319                 return TRUE;
1320         if ((type & CRTDLL_LOWER) && islower(x))
1321                 return TRUE;
1322         if ((type & CRTDLL_UPPER) && isupper(x))
1323                 return TRUE;
1324         if ((type & CRTDLL_ALPHA) && isalpha(x))
1325                 return TRUE;
1326         if ((type & CRTDLL_DIGIT) && isdigit(x))
1327                 return TRUE;
1328         if ((type & CRTDLL_CONTROL) && iscntrl(x))
1329                 return TRUE;
1330         /* check CRTDLL_LEADBYTE */
1331         return FALSE;
1332 }
1333
1334 /*********************************************************************
1335  *                  _chdrive           (CRTDLL.52)
1336  *
1337  *  newdir      [I] drive to change to, A=1
1338  *
1339  */
1340 BOOL __cdecl CRTDLL__chdrive(INT newdrive)
1341 {
1342         /* FIXME: generates errnos */
1343         return DRIVE_SetCurrentDrive(newdrive-1);
1344 }
1345
1346 /*********************************************************************
1347  *                  _chdir           (CRTDLL.51)
1348  */
1349 INT __cdecl CRTDLL__chdir(LPCSTR newdir)
1350 {
1351         if (!SetCurrentDirectoryA(newdir))
1352                 return 1;
1353         return 0;
1354 }
1355
1356 /*********************************************************************
1357  *                  _fullpath           (CRTDLL.114)
1358  */
1359 LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
1360 {
1361   DOS_FULL_NAME full_name;
1362
1363   if (!buf)
1364   {
1365       size = 256;
1366       if(!(buf = CRTDLL_malloc(size))) return NULL;
1367   }
1368   if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
1369   lstrcpynA(buf,full_name.short_name,size);
1370   TRACE("CRTDLL_fullpath got %s\n",buf);
1371   return buf;
1372 }
1373
1374 /*********************************************************************
1375  *                  _splitpath           (CRTDLL.279)
1376  */
1377 VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
1378 {
1379   /* drive includes :
1380      directory includes leading and trailing (forward and backward slashes)
1381      filename without dot and slashes
1382      extension with leading dot
1383      */
1384   char * drivechar,*dirchar,*namechar;
1385
1386   TRACE("CRTDLL__splitpath got %s\n",path);
1387
1388   drivechar  = strchr(path,':');
1389   dirchar    = strrchr(path,'/');
1390   namechar   = strrchr(path,'\\');
1391   dirchar = MAX(dirchar,namechar);
1392   if (dirchar)
1393     namechar   = strrchr(dirchar,'.');
1394   else
1395     namechar   = strrchr(path,'.');
1396   
1397   
1398   if (drive) 
1399     {
1400       *drive = 0x00;
1401       if (drivechar) 
1402         {
1403           strncat(drive,path,drivechar-path+1);
1404           path = drivechar+1;
1405         }
1406     }
1407   if (directory) 
1408     {
1409       *directory = 0x00;
1410       if (dirchar)
1411         {
1412           strncat(directory,path,dirchar-path+1);
1413           path = dirchar+1;
1414         }
1415     }
1416   if (filename)
1417     {
1418       *filename = 0x00;
1419       if (namechar)
1420         {
1421           strncat(filename,path,namechar-path);
1422           if (extension) 
1423             {
1424               *extension = 0x00;
1425               strcat(extension,namechar);
1426             }
1427         }
1428     }
1429
1430   TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
1431   
1432 }
1433
1434
1435 /*********************************************************************
1436  *                  _makepath           (CRTDLL.182)
1437  */
1438
1439 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive, 
1440                               LPCSTR directory, LPCSTR filename, 
1441                               LPCSTR extension )
1442 {
1443         char ch;
1444         TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory, 
1445               filename, extension);
1446
1447         if ( !path )
1448                 return;
1449
1450         path[0] = 0;
1451         if ( drive ) 
1452                 if ( drive[0] ) {
1453                         sprintf(path, "%c:", drive[0]);
1454                 }
1455         if ( directory ) 
1456                 if ( directory[0] ) {
1457                         strcat(path, directory);
1458                         ch = path[strlen(path)-1];
1459                         if (ch != '/' && ch != '\\')
1460                                 strcat(path,"\\");
1461                 }
1462         if ( filename ) 
1463                 if ( filename[0] ) {
1464                         strcat(path, filename);
1465                         if ( extension ) {
1466                                 if ( extension[0] ) {
1467                                         if ( extension[0] != '.' ) {
1468                                                 strcat(path,".");
1469                                         } 
1470                                         strcat(path,extension);
1471                                 }
1472                         }
1473                 }
1474         
1475         TRACE("CRTDLL__makepath returns %s\n",path);  
1476 }
1477
1478 /*********************************************************************
1479  *                  _getcwd           (CRTDLL.120)
1480  */
1481 CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size)
1482 {
1483   char test[1];
1484   int len;
1485
1486   len = size;
1487   if (!buf) {
1488     if (size < 0) /* allocate as big as nescessary */
1489       len =GetCurrentDirectoryA(1,test) + 1;
1490     if(!(buf = CRTDLL_malloc(len)))
1491     {
1492         /* set error to OutOfRange */
1493         return( NULL );
1494     }
1495   }
1496   size = len;
1497   if(!(len =GetCurrentDirectoryA(len,buf)))
1498     {
1499       return NULL;
1500     }
1501   if (len > size)
1502     {
1503       /* set error to ERANGE */
1504       TRACE("CRTDLL_getcwd buffer to small\n");
1505       return NULL;
1506     }
1507   return buf;
1508
1509 }
1510
1511 /*********************************************************************
1512  *                  _getdcwd           (CRTDLL.121)
1513  */
1514 CHAR* __cdecl CRTDLL__getdcwd(INT drive,LPSTR buf, INT size)
1515 {
1516   char test[1];
1517   int len;
1518
1519   FIXME("(\"%c:\",%s,%d)\n",drive+'A',buf,size);
1520   len = size;
1521   if (!buf) {
1522     if (size < 0) /* allocate as big as nescessary */
1523       len =GetCurrentDirectoryA(1,test) + 1;
1524     if(!(buf = CRTDLL_malloc(len)))
1525     {
1526         /* set error to OutOfRange */
1527         return( NULL );
1528     }
1529   }
1530   size = len;
1531   if(!(len =GetCurrentDirectoryA(len,buf)))
1532     {
1533       return NULL;
1534     }
1535   if (len > size)
1536     {
1537       /* set error to ERANGE */
1538       TRACE("buffer to small\n");
1539       return NULL;
1540     }
1541   return buf;
1542
1543 }
1544
1545 /*********************************************************************
1546  *                  _getdrive           (CRTDLL.124)
1547  *
1548  *  Return current drive, 1 for A, 2 for B
1549  */
1550 INT __cdecl CRTDLL__getdrive(VOID)
1551 {
1552     return DRIVE_GetCurrentDrive() + 1;
1553 }
1554
1555 /*********************************************************************
1556  *                  _mkdir           (CRTDLL.234)
1557  */
1558 INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
1559 {
1560         if (!CreateDirectoryA(newdir,NULL))
1561                 return -1;
1562         return 0;
1563 }
1564
1565 /*********************************************************************
1566  *                  remove           (CRTDLL.448)
1567  */
1568 INT __cdecl CRTDLL_remove(LPCSTR file)
1569 {
1570         if (!DeleteFileA(file))
1571                 return -1;
1572         return 0;
1573 }
1574
1575 /*********************************************************************
1576  *                  _errno           (CRTDLL.52)
1577  * Yes, this is a function.
1578  */
1579 LPINT __cdecl CRTDLL__errno()
1580 {
1581         static  int crtdllerrno;
1582         
1583         /* FIXME: we should set the error at the failing function call time */
1584         crtdllerrno = LastErrorToErrno(GetLastError());
1585         return &crtdllerrno;
1586 }
1587
1588 /*********************************************************************
1589  *                  _tempnam           (CRTDLL.305)
1590  * 
1591  */
1592 LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix)
1593 {
1594
1595      char *ret;
1596      DOS_FULL_NAME tempname;
1597      
1598      if ((ret = tempnam(dir,prefix))==NULL) {
1599        WARN("Unable to get unique filename\n");
1600        return NULL;
1601      }
1602      if (!DOSFS_GetFullName(ret,FALSE,&tempname))
1603      {
1604        TRACE("Wrong path?\n");
1605        return NULL;
1606      }
1607      free(ret);
1608      if ((ret = CRTDLL_malloc(strlen(tempname.short_name)+1)) == NULL) {
1609          WARN("CRTDL_malloc for shortname failed\n");
1610          return NULL;
1611      }
1612      if ((ret = strcpy(ret,tempname.short_name)) == NULL) { 
1613        WARN("Malloc for shortname failed\n");
1614        return NULL;
1615      }
1616      
1617      TRACE("dir %s prefix %s got %s\n",
1618                     dir,prefix,ret);
1619      return ret;
1620
1621 }
1622 /*********************************************************************
1623  *                  tmpnam           (CRTDLL.490)
1624  *
1625  * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1626  * 
1627  */
1628 LPSTR __cdecl CRTDLL_tmpnam(LPSTR s)
1629 {
1630      char *ret;
1631
1632      if ((ret =tmpnam(s))== NULL) {
1633        WARN("Unable to get unique filename\n");
1634        return NULL;
1635      }
1636      if (!DOSFS_GetFullName(ret,FALSE,&CRTDLL_tmpname))
1637      {
1638        TRACE("Wrong path?\n");
1639        return NULL;
1640      }
1641      strcat(CRTDLL_tmpname.short_name,".");
1642      TRACE("for buf %p got %s\n",
1643                     s,CRTDLL_tmpname.short_name);
1644      TRACE("long got %s\n",
1645                     CRTDLL_tmpname.long_name);
1646      if ( s != NULL) 
1647        return strcpy(s,CRTDLL_tmpname.short_name);
1648      else 
1649        return CRTDLL_tmpname.short_name;
1650
1651 }
1652
1653 /*********************************************************************
1654  *                  _itoa           (CRTDLL.165)
1655  */
1656 LPSTR  __cdecl CRTDLL__itoa(INT x,LPSTR buf,INT buflen)
1657 {
1658     wsnprintfA(buf,buflen,"%d",x);
1659     return buf;
1660 }
1661
1662 /*********************************************************************
1663  *                  _ltoa           (CRTDLL.180)
1664  */
1665 LPSTR  __cdecl CRTDLL__ltoa(long x,LPSTR buf,INT radix)
1666 {
1667     switch(radix) {
1668         case  2: FIXME("binary format not implemented !\n");
1669                  break;
1670         case  8: wsnprintfA(buf,0x80,"%o",x);
1671                  break;
1672         case 10: wsnprintfA(buf,0x80,"%d",x);
1673                  break;
1674         case 16: wsnprintfA(buf,0x80,"%x",x);
1675                  break;
1676         default: FIXME("radix %d not implemented !\n", radix);
1677     }
1678     return buf;
1679 }
1680
1681 /*********************************************************************
1682  *                  _ultoa           (CRTDLL.311)
1683  */
1684 LPSTR  __cdecl CRTDLL__ultoa(long x,LPSTR buf,INT radix)
1685 {
1686     switch(radix) {
1687         case  2: FIXME("binary format not implemented !\n");
1688                  break;
1689         case  8: wsnprintfA(buf,0x80,"%lo",x);
1690                  break;
1691         case 10: wsnprintfA(buf,0x80,"%ld",x);
1692                  break;
1693         case 16: wsnprintfA(buf,0x80,"%lx",x);
1694                  break;
1695         default: FIXME("radix %d not implemented !\n", radix);
1696     }
1697     return buf;
1698 }
1699
1700 typedef VOID (*sig_handler_type)(VOID);
1701
1702 /*********************************************************************
1703  *                  signal           (CRTDLL.455)
1704  */
1705 VOID __cdecl CRTDLL_signal(int sig, sig_handler_type ptr)
1706 {
1707     FIXME("(%d %p):stub.\n", sig, ptr);
1708 }
1709
1710 /*********************************************************************
1711  *                  _ftol            (CRTDLL.113)
1712  */
1713 #ifdef USING_REAL_FPU
1714 LONG __cdecl CRTDLL__ftol(void) {
1715         /* don't just do DO_FPU("fistp",retval), because the rounding
1716          * mode must also be set to "round towards zero"... */
1717         double fl;
1718         POP_FPU(fl);
1719         return (LONG)fl;
1720 }
1721 #else
1722 LONG __cdecl CRTDLL__ftol(double fl) {
1723         FIXME("should be register function\n");
1724         return (LONG)fl;
1725 }
1726 #endif
1727
1728 /*********************************************************************
1729  *                  _CIpow           (CRTDLL.14)
1730  */
1731 #ifdef USING_REAL_FPU
1732 LONG __cdecl CRTDLL__CIpow(void) {
1733         double x,y;
1734         POP_FPU(y);
1735         POP_FPU(x);
1736         return pow(x,y);
1737 }
1738 #else
1739 LONG __cdecl CRTDLL__CIpow(double x,double y) {
1740         FIXME("should be register function\n");
1741         return pow(x,y);
1742 }
1743 #endif
1744
1745 /*********************************************************************
1746  *                  _sleep           (CRTDLL.267)
1747  */
1748 VOID __cdecl CRTDLL__sleep(unsigned long timeout) 
1749 {
1750   TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
1751   Sleep((timeout)?timeout:1);
1752 }
1753
1754 /*********************************************************************
1755  *                  getenv           (CRTDLL.437)
1756  */
1757 LPSTR __cdecl CRTDLL_getenv(const char *name) 
1758 {
1759      LPSTR environ = GetEnvironmentStringsA();
1760      LPSTR pp,pos = NULL;
1761      unsigned int length;
1762   
1763      for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
1764        {
1765          pos =strchr(pp,'=');
1766          if (pos)
1767            length = pos -pp;
1768          else
1769            length = strlen(pp);
1770          if (!strncmp(pp,name,length)) break;
1771        }
1772      if ((pp)&& (pos)) 
1773        {
1774          pp = pos+1;
1775          TRACE("got %s\n",pp);
1776        }
1777      FreeEnvironmentStringsA( environ );
1778      return pp;
1779 }
1780
1781 /*********************************************************************
1782  *                  _mbsrchr           (CRTDLL.223)
1783  */
1784 LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) {
1785         /* FIXME: handle multibyte strings */
1786         return strrchr(s,x);
1787 }
1788
1789 /*********************************************************************
1790  *                  _memicmp           (CRTDLL.233)(NTDLL.868)
1791  * A stringcompare, without \0 check
1792  * RETURNS
1793  *      -1:if first string is alphabetically before second string
1794  *      1:if second ''    ''      ''          ''   first   ''
1795  *      0:if both are equal.
1796  */
1797 INT __cdecl CRTDLL__memicmp(
1798         LPCSTR s1,      /* [in] first string */
1799         LPCSTR s2,      /* [in] second string */
1800         DWORD len       /* [in] length to compare */
1801 ) { 
1802         int     i;
1803
1804         for (i=0;i<len;i++) {
1805                 if (tolower(s1[i])<tolower(s2[i]))
1806                         return -1;
1807                 if (tolower(s1[i])>tolower(s2[i]))
1808                         return  1;
1809         }
1810         return 0;
1811 }
1812 /*********************************************************************
1813  *                  __dllonexit           (CRTDLL.25)
1814  */
1815 VOID __cdecl CRTDLL__dllonexit ()
1816 {       
1817         FIXME("stub\n");
1818 }
1819
1820 /*********************************************************************
1821  *                  wcstol           (CRTDLL.520)
1822  * Like strtol, but for wide character strings.
1823  */
1824 INT __cdecl CRTDLL_wcstol(LPWSTR s,LPWSTR *end,INT base) {
1825         LPSTR   sA = HEAP_strdupWtoA(GetProcessHeap(),0,s),endA;
1826         INT     ret = strtol(sA,&endA,base);
1827
1828         HeapFree(GetProcessHeap(),0,sA);
1829         if (end) *end = s+(endA-sA); /* pointer magic checked. */
1830         return ret;
1831 }
1832 /*********************************************************************
1833  *                  _strdate          (CRTDLL.283)
1834  */
1835 LPSTR __cdecl CRTDLL__strdate (LPSTR date)
1836 {       FIXME("%p stub\n", date);
1837         return 0;
1838 }
1839
1840 /*********************************************************************
1841  *                  _strtime          (CRTDLL.299)
1842  */
1843 LPSTR __cdecl CRTDLL__strtime (LPSTR date)
1844 {       FIXME("%p stub\n", date);
1845         return 0;
1846 }
1847
1848 /*********************************************************************
1849  *                  _except_handler2  (CRTDLL.78)
1850  */
1851 INT __cdecl CRTDLL__except_handler2 (
1852         PEXCEPTION_RECORD rec,
1853         PEXCEPTION_FRAME frame,
1854         PCONTEXT context,
1855         PEXCEPTION_FRAME  *dispatcher)
1856 {
1857         FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
1858         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
1859         frame->Handler, context, dispatcher);
1860         return ExceptionContinueSearch;
1861 }