Define __fastcall.
[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 /*********************************************************************
337  *                  fopen     (CRTDLL.372)
338  */
339 CRTDLL_FILE * __cdecl CRTDLL_fopen(LPCSTR path, LPCSTR mode)
340 {
341   CRTDLL_FILE *file = NULL;
342   HFILE handle;
343 #if 0
344   DOS_FULL_NAME full_name;
345   
346   if (!DOSFS_GetFullName( path, FALSE, &full_name )) {
347     WARN("file %s bad name\n",path);
348    return 0;
349   }
350   
351   file=fopen(full_name.long_name ,mode);
352 #endif
353   DWORD access = 0, creation = 0;
354
355   if ((strchr(mode,'r')&&strchr(mode,'a'))||
356       (strchr(mode,'r')&&strchr(mode,'w'))||
357       (strchr(mode,'w')&&strchr(mode,'a')))
358     return NULL;
359        
360   if (mode[0] == 'r')
361   {
362       access = GENERIC_READ;
363       creation = OPEN_EXISTING;
364       if (mode[1] == '+') access |= GENERIC_WRITE;
365   }
366   else if (mode[0] == 'w')
367   {
368       access = GENERIC_WRITE;
369       creation = CREATE_ALWAYS;
370       if (mode[1] == '+') access |= GENERIC_READ;
371   }
372   else if (mode[0] == 'a')
373   {
374       /* FIXME: there is no O_APPEND in CreateFile, should emulate it */
375       access = GENERIC_WRITE;
376       creation = OPEN_ALWAYS;
377       if (mode[1] == '+') access |= GENERIC_READ;
378   }
379   /* FIXME: should handle text/binary mode */
380
381   if ((handle = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
382                                NULL, creation, FILE_ATTRIBUTE_NORMAL,
383                                -1 )) != INVALID_HANDLE_VALUE)
384   {
385       file = HeapAlloc( GetProcessHeap(), 0, sizeof(*file) );
386       file->handle = handle;
387   }
388   TRACE("file %s mode %s got handle %d file %p\n",
389                  path,mode,handle,file);
390   return file;
391 }
392
393 /*********************************************************************
394  *                  fread     (CRTDLL.377)
395  */
396 DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE *file)
397 {
398 #if 0
399   int i=0;
400   void *temp=ptr;
401
402   /* If we would honour CR/LF <-> LF translation, we could do it like this.
403      We should keep track of all files opened, and probably files with \
404      known binary extensions must be unchanged */
405   while ( (i < (nmemb*size)) && (ret==1)) {
406     ret=fread(temp,1,1,file);
407     TRACE("got %c 0x%02x ret %d\n",
408                  (isalpha(*(unsigned char*)temp))? *(unsigned char*)temp:
409                  ' ',*(unsigned char*)temp, ret);
410     if (*(unsigned char*)temp != 0xd) { /* skip CR */
411       temp++;
412       i++;
413     }
414     else
415       TRACE("skipping ^M\n");
416   }
417   TRACE("0x%08x items of size %d from file %p to %p\n",
418                nmemb,size,file,ptr,);
419   if(i!=nmemb)
420     WARN(" failed!\n");
421
422   return i;
423 #else
424   DWORD ret;
425
426   TRACE("0x%08x items of size %d from file %p to %p\n",
427                nmemb,size,file,ptr);
428   if (!ReadFile( file->handle, ptr, size * nmemb, &ret, NULL ))
429       WARN(" failed!\n");
430
431   return ret / size;
432 #endif
433 }
434 /*********************************************************************
435  *                  freopen    (CRTDLL.379)
436  * 
437  * BUGS
438  *   Unimplemented
439  */
440 DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream)
441 {
442   FIXME(":(%s,%s,%p): stub\n", path, mode, stream);
443   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
444   return FALSE;
445 }
446
447 /*********************************************************************
448  *                  fscanf     (CRTDLL.381)
449  */
450 INT __cdecl CRTDLL_fscanf( CRTDLL_FILE *stream, LPSTR format, ... )
451 {
452 #if 0
453     va_list valist;
454     INT res;
455
456     va_start( valist, format );
457 #ifdef HAVE_VFSCANF
458     res = vfscanf( xlat_file_ptr(stream), format, valist );
459 #endif
460     va_end( valist );
461     return res;
462 #endif
463     FIXME("broken\n");
464     return 0;
465 }
466
467 /*********************************************************************
468  *                  _lseek     (CRTDLL.179)
469  */
470 LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence)
471 {
472   TRACE("fd %d to 0x%08lx pos %s\n",
473         fd,offset,(whence==SEEK_SET)?"SEEK_SET":
474         (whence==SEEK_CUR)?"SEEK_CUR":
475         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
476   return SetFilePointer( fd, offset, NULL, whence );
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  *                  _read     (CRTDLL.256)
645  *
646  */
647 INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count)
648 {
649     TRACE("0x%08x bytes fd %d to %p\n", count,fd,buf);
650     if (!fd) fd = GetStdHandle( STD_INPUT_HANDLE );
651     return _lread( fd, buf, count );
652 }
653
654 /*********************************************************************
655  *                  _write        (CRTDLL.332)
656  */
657 INT __cdecl CRTDLL__write(INT fd,LPCVOID buf,UINT count)
658 {
659         INT len=0;
660
661         if (fd == -1)
662           len = -1;
663         else if (fd<=2)
664           len = (UINT)write(fd,buf,(LONG)count);
665         else
666           len = _lwrite(fd,buf,count);
667         TRACE("%d/%d byte to dfh %d from %p,\n",
668                        len,count,fd,buf);
669         return len;
670 }
671
672
673 /*********************************************************************
674  *                  _cexit          (CRTDLL.49)
675  *
676  *  FIXME: What the heck is the difference between 
677  *  FIXME           _c_exit         (CRTDLL.47)
678  *  FIXME           _cexit          (CRTDLL.49)
679  *  FIXME           _exit           (CRTDLL.87)
680  *  FIXME           exit            (CRTDLL.359)
681  *
682  * atexit-processing comes to mind -- MW.
683  *
684  */
685 void __cdecl CRTDLL__cexit(INT ret)
686 {
687         TRACE("(%d)\n",ret);
688         ExitProcess(ret);
689 }
690
691
692 /*********************************************************************
693  *                  exit          (CRTDLL.359)
694  */
695 void __cdecl CRTDLL_exit(DWORD ret)
696 {
697         TRACE("(%ld)\n",ret);
698         ExitProcess(ret);
699 }
700
701
702 /*********************************************************************
703  *                  _abnormal_termination          (CRTDLL.36)
704  */
705 INT __cdecl CRTDLL__abnormal_termination(void)
706 {
707         TRACE("(void)\n");
708         return 0;
709 }
710
711
712 /*********************************************************************
713  *                  _access          (CRTDLL.37)
714  */
715 INT __cdecl CRTDLL__access(LPCSTR filename, INT mode)
716 {
717     DWORD attr = GetFileAttributesA(filename);
718
719     if (attr == -1)
720     {
721         if (GetLastError() == ERROR_INVALID_ACCESS)
722             errno = EACCES;
723         else
724             errno = ENOENT;
725         return -1;
726     }
727
728     if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
729     {
730         errno = EACCES;
731         return -1;
732     }
733     else
734         return 0;
735 }
736
737
738 /*********************************************************************
739  *                  fflush        (CRTDLL.365)
740  */
741 INT __cdecl CRTDLL_fflush( CRTDLL_FILE *file )
742 {
743     return FlushFileBuffers( file->handle ) ? 0 : -1;
744 }
745
746
747 /*********************************************************************
748  *                  rand          (CRTDLL.446)
749  */
750 INT __cdecl CRTDLL_rand()
751 {
752     return (rand() & CRTDLL_RAND_MAX); 
753 }
754
755
756 /*********************************************************************
757  *                  putchar       (CRTDLL.442)
758  */
759 void __cdecl CRTDLL_putchar( INT x )
760 {
761     putchar(x);
762 }
763
764
765 /*********************************************************************
766  *                  fputc       (CRTDLL.374)
767  */
768 INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE *file )
769 {
770     char ch = (char)c;
771     DWORD res;
772     TRACE("%c to file %p\n",c,file);
773     if (!WriteFile( file->handle, &ch, 1, &res, NULL )) return -1;
774     return c;
775 }
776
777
778 /*********************************************************************
779  *                  fputs       (CRTDLL.375)
780  */
781 INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE *file )
782 {
783     DWORD res;
784     TRACE("%s to file %p\n",s,file);
785     if (!WriteFile( file->handle, s, strlen(s), &res, NULL )) return -1;
786     return res;
787 }
788
789
790 /*********************************************************************
791  *                  puts       (CRTDLL.443)
792  */
793 INT __cdecl CRTDLL_puts(LPCSTR s)
794 {
795     TRACE("%s \n",s);
796     return puts(s);
797 }
798
799
800 /*********************************************************************
801  *                  putc       (CRTDLL.441)
802  */
803 INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE *file )
804 {
805     return CRTDLL_fputc( c, file );
806 }
807
808 /*********************************************************************
809  *                  fgetc       (CRTDLL.366)
810  */
811 INT __cdecl CRTDLL_fgetc( CRTDLL_FILE *file )
812 {
813     DWORD res;
814     char ch;
815     if (!ReadFile( file->handle, &ch, 1, &res, NULL )) return -1;
816     if (res != 1) return -1;
817     return ch;
818 }
819
820
821 /*********************************************************************
822  *                  getc       (CRTDLL.388)
823  */
824 INT __cdecl CRTDLL_getc( CRTDLL_FILE *file )
825 {
826     return CRTDLL_fgetc( file );
827 }
828
829
830 /*********************************************************************
831  *                  fgets       (CRTDLL.368)
832  */
833 CHAR* __cdecl CRTDLL_fgets( LPSTR s, INT size, CRTDLL_FILE *file )
834 {
835     int    cc;
836     LPSTR  buf_start = s;
837
838     /* BAD, for the whole WINE process blocks... just done this way to test
839      * windows95's ftp.exe.
840      */
841
842     for(cc = CRTDLL_fgetc(file); cc != EOF && cc != '\n'; cc = CRTDLL_fgetc(file))
843         if (cc != '\r')
844         {
845             if (--size <= 0) break;
846             *s++ = (char)cc;
847         }
848
849     *s = '\0';
850
851     TRACE("got '%s'\n", buf_start);
852     return buf_start;
853 }
854
855
856 /*********************************************************************
857  *                  gets          (CRTDLL.391)
858  */
859 LPSTR __cdecl CRTDLL_gets(LPSTR buf)
860 {
861     int    cc;
862     LPSTR  buf_start = buf;
863
864     /* BAD, for the whole WINE process blocks... just done this way to test
865      * windows95's ftp.exe.
866      */
867
868     for(cc = fgetc(stdin); cc != EOF && cc != '\n'; cc = fgetc(stdin))
869         if(cc != '\r') *buf++ = (char)cc;
870
871     *buf = '\0';
872
873     TRACE("got '%s'\n", buf_start);
874     return buf_start;
875 }
876
877
878 /*********************************************************************
879  *                  _rotl          (CRTDLL.259)
880  */
881 UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
882 {
883    unsigned int ret = (x >> shift)|( x >>((sizeof(x))-shift));
884
885    TRACE("got 0x%08x rot %d ret 0x%08x\n",
886                   x,shift,ret);
887    return ret;
888     
889 }
890 /*********************************************************************
891  *                  _lrotl          (CRTDLL.176)
892  */
893 DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
894 {
895    unsigned long ret = (x >> shift)|( x >>((sizeof(x))-shift));
896
897    TRACE("got 0x%08lx rot %d ret 0x%08lx\n",
898                   x,shift,ret);
899    return ret;
900     
901 }
902
903
904 /*********************************************************************
905  *                  _mbsicmp      (CRTDLL.204)
906  */
907 int __cdecl CRTDLL__mbsicmp(unsigned char *x,unsigned char *y)
908 {
909     do {
910         if (!*x)
911             return !!*y;
912         if (!*y)
913             return !!*x;
914         /* FIXME: MBCS handling... */
915         if (*x!=*y)
916             return 1;
917         x++;
918         y++;
919     } while (1);
920 }
921
922
923 /*********************************************************************
924  *                  vsprintf      (CRTDLL.500)
925  */
926 INT __cdecl CRTDLL_vsprintf( LPSTR buffer, LPCSTR spec, va_list args )
927 {
928     return wvsprintfA( buffer, spec, args );
929 }
930
931 /*********************************************************************
932  *                  vswprintf      (CRTDLL.501)
933  */
934 INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
935 {
936     return wvsprintfW( buffer, spec, args );
937 }
938
939 /*********************************************************************
940  *                  _strcmpi   (CRTDLL.282) (CRTDLL.287)
941  */
942 INT __cdecl CRTDLL__strcmpi( LPCSTR s1, LPCSTR s2 )
943 {
944     return lstrcmpiA( s1, s2 );
945 }
946
947
948 /*********************************************************************
949  *                  _strnicmp   (CRTDLL.293)
950  */
951 INT __cdecl CRTDLL__strnicmp( LPCSTR s1, LPCSTR s2, INT n )
952 {
953     return lstrncmpiA( s1, s2, n );
954 }
955
956
957 /*********************************************************************
958  *                  _strlwr      (CRTDLL.293)
959  *
960  * convert a string in place to lowercase 
961  */
962 LPSTR __cdecl CRTDLL__strlwr(LPSTR x)
963 {
964   unsigned char *y =x;
965   
966   TRACE("CRTDLL_strlwr got %s\n", x);
967   while (*y) {
968     if ((*y > 0x40) && (*y< 0x5b))
969       *y = *y + 0x20;
970     y++;
971   }
972   TRACE("   returned %s\n", x);
973                  
974   return x;
975 }
976
977 /*********************************************************************
978  *                  system       (CRTDLL.485)
979  */
980 INT __cdecl CRTDLL_system(LPSTR x)
981 {
982 #define SYSBUF_LENGTH 1500
983   char buffer[SYSBUF_LENGTH];
984   unsigned char *y = x;
985   unsigned char *bp;
986   int i;
987
988   sprintf( buffer, "%s \"", argv0 );
989   bp = buffer + strlen(buffer);
990   i = strlen(buffer) + strlen(x) +2;
991
992   /* Calculate needed buffer size to prevent overflow.  */
993   while (*y) {
994     if (*y =='\\') i++;
995     y++;
996   }
997   /* If buffer too short, exit.  */
998   if (i > SYSBUF_LENGTH) {
999     TRACE("_system buffer to small\n");
1000     return 127;
1001   }
1002   
1003   y =x;
1004
1005   while (*y) {
1006     *bp = *y;
1007     bp++; y++;
1008     if (*(y-1) =='\\') *bp++ = '\\';
1009   }
1010   /* Remove spaces from end of string.  */
1011   while (*(y-1) == ' ') {
1012     bp--;y--;
1013   }
1014   *bp++ = '"';
1015   *bp = 0;
1016   TRACE("_system got '%s', executing '%s'\n",x,buffer);
1017
1018   return system(buffer);
1019 }
1020
1021 /*********************************************************************
1022  *                  _strupr       (CRTDLL.300)
1023  */
1024 LPSTR __cdecl CRTDLL__strupr(LPSTR x)
1025 {
1026         LPSTR   y=x;
1027
1028         while (*y) {
1029                 *y=toupper(*y);
1030                 y++;
1031         }
1032         return x;
1033 }
1034
1035 /*********************************************************************
1036  *                  longjmp        (CRTDLL.426)
1037  */
1038 VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
1039 {
1040     FIXME("CRTDLL_longjmp semistup, expect crash\n");
1041     longjmp(env, val);
1042 }
1043
1044 /*********************************************************************
1045  *                  malloc        (CRTDLL.427)
1046  */
1047 VOID* __cdecl CRTDLL_malloc(DWORD size)
1048 {
1049     return HeapAlloc(GetProcessHeap(),0,size);
1050 }
1051
1052 /*********************************************************************
1053  *                  new           (CRTDLL.001)
1054  */
1055 VOID* __cdecl CRTDLL_new(DWORD size)
1056 {
1057     VOID* result;
1058     if(!(result = HeapAlloc(GetProcessHeap(),0,size)) && new_handler)
1059         (*new_handler)();
1060     return result;
1061 }
1062
1063 /*********************************************************************
1064  *                  set_new_handler(CRTDLL.003)
1065  */
1066 new_handler_type __cdecl CRTDLL_set_new_handler(new_handler_type func)
1067 {
1068     new_handler_type old_handler = new_handler;
1069     new_handler = func;
1070     return old_handler;
1071 }
1072
1073 /*********************************************************************
1074  *                  calloc        (CRTDLL.350)
1075  */
1076 VOID* __cdecl CRTDLL_calloc(DWORD size, DWORD count)
1077 {
1078     return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count );
1079 }
1080
1081 /*********************************************************************
1082  *                  realloc        (CRTDLL.447)
1083  */
1084 VOID* __cdecl CRTDLL_realloc( VOID *ptr, DWORD size )
1085 {
1086     return HeapReAlloc( GetProcessHeap(), 0, ptr, size );
1087 }
1088
1089 /*********************************************************************
1090  *                  free          (CRTDLL.427)
1091  */
1092 VOID __cdecl CRTDLL_free(LPVOID ptr)
1093 {
1094     HeapFree(GetProcessHeap(),0,ptr);
1095 }
1096
1097 /*********************************************************************
1098  *                  delete       (CRTDLL.002)
1099  */
1100 VOID __cdecl CRTDLL_delete(VOID* ptr)
1101 {
1102     HeapFree(GetProcessHeap(),0,ptr);
1103 }
1104
1105 /*********************************************************************
1106  *                  _strdup          (CRTDLL.285)
1107  */
1108 LPSTR __cdecl CRTDLL__strdup(LPCSTR ptr)
1109 {
1110     return HEAP_strdupA(GetProcessHeap(),0,ptr);
1111 }
1112
1113 /*********************************************************************
1114  *                  fclose           (CRTDLL.362)
1115  */
1116 INT __cdecl CRTDLL_fclose( CRTDLL_FILE *file )
1117 {
1118     TRACE("%p\n", file );
1119     if (!CloseHandle( file->handle )) return -1;
1120     HeapFree( GetProcessHeap(), 0, file );
1121     return 0;
1122 }
1123
1124 /*********************************************************************
1125  *                  _unlink           (CRTDLL.315)
1126  */
1127 INT __cdecl CRTDLL__unlink(LPCSTR pathname)
1128 {
1129     return DeleteFileA( pathname ) ? 0 : -1;
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 & 0x8000 /* O_BINARY */ ) || (flags & 0x4000 /* O_TEXT */))
1234         FIXME(":text mode not supported\n");
1235     if (flags & 0xf0f4) 
1236       TRACE("CRTDLL_open file unsupported flags 0x%04x\n",flags);
1237     /* End Fixme */
1238
1239     ret = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
1240                          NULL, creation, FILE_ATTRIBUTE_NORMAL, -1 );
1241     TRACE("CRTDLL_open file %s mode 0x%04x got handle %d\n", path,flags,ret);
1242     return ret;
1243 }
1244
1245 /*********************************************************************
1246  *                  _close           (CRTDLL.57)
1247  */
1248 INT __cdecl CRTDLL__close(HFILE fd)
1249 {
1250     int ret=_lclose(fd);
1251
1252     TRACE("(%d)\n",fd);
1253     if(ret)
1254       WARN(" Failed!\n");
1255
1256     return ret;
1257 }
1258
1259 /*********************************************************************
1260  *                  feof           (CRTDLL.363)
1261  */
1262 INT __cdecl CRTDLL_feof( CRTDLL_FILE *file )
1263 {
1264     FIXME("stub\n" );
1265     return 0;
1266 }
1267
1268 /*********************************************************************
1269  *                  setlocale           (CRTDLL.453)
1270  */
1271 LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
1272 {
1273         LPSTR categorystr;
1274
1275         switch (category) {
1276         case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
1277         case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
1278         case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
1279         case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
1280         case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
1281         case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
1282         default: categorystr = "UNKNOWN?";break;
1283         }
1284         FIXME("(%s,%s),stub!\n",categorystr,locale);
1285         return "C";
1286 }
1287
1288 /*********************************************************************
1289  *                  _setmode           (CRTDLL.265)
1290  * FIXME: At present we ignore the request to translate CR/LF to LF.
1291  *
1292  * We allways translate when we read with fgets, we never do with fread
1293  *
1294  */
1295 INT __cdecl CRTDLL__setmode( INT fh,INT mode)
1296 {
1297         /* FIXME */
1298 #define O_TEXT     0x4000
1299 #define O_BINARY   0x8000
1300
1301         FIXME("on fhandle %d mode %s, STUB.\n",
1302                       fh,(mode=O_TEXT)?"O_TEXT":
1303                       (mode=O_BINARY)?"O_BINARY":"UNKNOWN");
1304         return -1;
1305 }
1306
1307 /*********************************************************************
1308  *                  _fpreset           (CRTDLL.107)
1309  */
1310 VOID __cdecl CRTDLL__fpreset(void)
1311 {
1312        FIXME(" STUB.\n");
1313 }
1314
1315 /*********************************************************************
1316  *                  atexit           (CRTDLL.345)
1317  */
1318 INT __cdecl CRTDLL_atexit(LPVOID x)
1319 {
1320         FIXME("(%p), STUB.\n",x);
1321         return 0; /* successful */
1322 }
1323
1324 /*********************************************************************
1325  *                  _isctype           (CRTDLL.138)
1326  */
1327 BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
1328 {
1329         if ((type & CRTDLL_SPACE) && isspace(x))
1330                 return TRUE;
1331         if ((type & CRTDLL_PUNCT) && ispunct(x))
1332                 return TRUE;
1333         if ((type & CRTDLL_LOWER) && islower(x))
1334                 return TRUE;
1335         if ((type & CRTDLL_UPPER) && isupper(x))
1336                 return TRUE;
1337         if ((type & CRTDLL_ALPHA) && isalpha(x))
1338                 return TRUE;
1339         if ((type & CRTDLL_DIGIT) && isdigit(x))
1340                 return TRUE;
1341         if ((type & CRTDLL_CONTROL) && iscntrl(x))
1342                 return TRUE;
1343         /* check CRTDLL_LEADBYTE */
1344         return FALSE;
1345 }
1346
1347 /*********************************************************************
1348  *                  _chdrive           (CRTDLL.52)
1349  *
1350  *  newdir      [I] drive to change to, A=1
1351  *
1352  */
1353 BOOL __cdecl CRTDLL__chdrive(INT newdrive)
1354 {
1355         /* FIXME: generates errnos */
1356         return DRIVE_SetCurrentDrive(newdrive-1);
1357 }
1358
1359 /*********************************************************************
1360  *                  _chdir           (CRTDLL.51)
1361  */
1362 INT __cdecl CRTDLL__chdir(LPCSTR newdir)
1363 {
1364         if (!SetCurrentDirectoryA(newdir))
1365                 return 1;
1366         return 0;
1367 }
1368
1369 /*********************************************************************
1370  *                  _fullpath           (CRTDLL.114)
1371  */
1372 LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
1373 {
1374   DOS_FULL_NAME full_name;
1375
1376   if (!buf)
1377   {
1378       size = 256;
1379       if(!(buf = CRTDLL_malloc(size))) return NULL;
1380   }
1381   if (!DOSFS_GetFullName( name, FALSE, &full_name )) return NULL;
1382   lstrcpynA(buf,full_name.short_name,size);
1383   TRACE("CRTDLL_fullpath got %s\n",buf);
1384   return buf;
1385 }
1386
1387 /*********************************************************************
1388  *                  _splitpath           (CRTDLL.279)
1389  */
1390 VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
1391 {
1392   /* drive includes :
1393      directory includes leading and trailing (forward and backward slashes)
1394      filename without dot and slashes
1395      extension with leading dot
1396      */
1397   char * drivechar,*dirchar,*namechar;
1398
1399   TRACE("CRTDLL__splitpath got %s\n",path);
1400
1401   drivechar  = strchr(path,':');
1402   dirchar    = strrchr(path,'/');
1403   namechar   = strrchr(path,'\\');
1404   dirchar = max(dirchar,namechar);
1405   if (dirchar)
1406     namechar   = strrchr(dirchar,'.');
1407   else
1408     namechar   = strrchr(path,'.');
1409   
1410   
1411   if (drive) 
1412     {
1413       *drive = 0x00;
1414       if (drivechar) 
1415         {
1416           strncat(drive,path,drivechar-path+1);
1417           path = drivechar+1;
1418         }
1419     }
1420   if (directory) 
1421     {
1422       *directory = 0x00;
1423       if (dirchar)
1424         {
1425           strncat(directory,path,dirchar-path+1);
1426           path = dirchar+1;
1427         }
1428     }
1429   if (filename)
1430     {
1431       *filename = 0x00;
1432       if (namechar)
1433         {
1434           strncat(filename,path,namechar-path);
1435           if (extension) 
1436             {
1437               *extension = 0x00;
1438               strcat(extension,namechar);
1439             }
1440         }
1441     }
1442
1443   TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
1444   
1445 }
1446
1447
1448 /*********************************************************************
1449  *                  _makepath           (CRTDLL.182)
1450  */
1451
1452 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive, 
1453                               LPCSTR directory, LPCSTR filename, 
1454                               LPCSTR extension )
1455 {
1456         char ch;
1457         TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory, 
1458               filename, extension);
1459
1460         if ( !path )
1461                 return;
1462
1463         path[0] = 0;
1464         if ( drive ) 
1465                 if ( drive[0] ) {
1466                         sprintf(path, "%c:", drive[0]);
1467                 }
1468         if ( directory ) 
1469                 if ( directory[0] ) {
1470                         strcat(path, directory);
1471                         ch = path[strlen(path)-1];
1472                         if (ch != '/' && ch != '\\')
1473                                 strcat(path,"\\");
1474                 }
1475         if ( filename ) 
1476                 if ( filename[0] ) {
1477                         strcat(path, filename);
1478                         if ( extension ) {
1479                                 if ( extension[0] ) {
1480                                         if ( extension[0] != '.' ) {
1481                                                 strcat(path,".");
1482                                         } 
1483                                         strcat(path,extension);
1484                                 }
1485                         }
1486                 }
1487         
1488         TRACE("CRTDLL__makepath returns %s\n",path);  
1489 }
1490
1491 /*********************************************************************
1492  *                  _getcwd           (CRTDLL.120)
1493  */
1494 CHAR* __cdecl CRTDLL__getcwd(LPSTR buf, INT size)
1495 {
1496   char test[1];
1497   int len;
1498
1499   len = size;
1500   if (!buf) {
1501     if (size < 0) /* allocate as big as nescessary */
1502       len =GetCurrentDirectoryA(1,test) + 1;
1503     if(!(buf = CRTDLL_malloc(len)))
1504     {
1505         /* set error to OutOfRange */
1506         return( NULL );
1507     }
1508   }
1509   size = len;
1510   if(!(len =GetCurrentDirectoryA(len,buf)))
1511     {
1512       return NULL;
1513     }
1514   if (len > size)
1515     {
1516       /* set error to ERANGE */
1517       TRACE("CRTDLL_getcwd buffer to small\n");
1518       return NULL;
1519     }
1520   return buf;
1521
1522 }
1523
1524 /*********************************************************************
1525  *                  _getdcwd           (CRTDLL.121)
1526  */
1527 CHAR* __cdecl CRTDLL__getdcwd(INT drive,LPSTR buf, INT size)
1528 {
1529   char test[1];
1530   int len;
1531
1532   FIXME("(\"%c:\",%s,%d)\n",drive+'A',buf,size);
1533   len = size;
1534   if (!buf) {
1535     if (size < 0) /* allocate as big as nescessary */
1536       len =GetCurrentDirectoryA(1,test) + 1;
1537     if(!(buf = CRTDLL_malloc(len)))
1538     {
1539         /* set error to OutOfRange */
1540         return( NULL );
1541     }
1542   }
1543   size = len;
1544   if(!(len =GetCurrentDirectoryA(len,buf)))
1545     {
1546       return NULL;
1547     }
1548   if (len > size)
1549     {
1550       /* set error to ERANGE */
1551       TRACE("buffer to small\n");
1552       return NULL;
1553     }
1554   return buf;
1555
1556 }
1557
1558 /*********************************************************************
1559  *                  _getdrive           (CRTDLL.124)
1560  *
1561  *  Return current drive, 1 for A, 2 for B
1562  */
1563 INT __cdecl CRTDLL__getdrive(VOID)
1564 {
1565     return DRIVE_GetCurrentDrive() + 1;
1566 }
1567
1568 /*********************************************************************
1569  *                  _mkdir           (CRTDLL.234)
1570  */
1571 INT __cdecl CRTDLL__mkdir(LPCSTR newdir)
1572 {
1573         if (!CreateDirectoryA(newdir,NULL))
1574                 return -1;
1575         return 0;
1576 }
1577
1578 /*********************************************************************
1579  *                  remove           (CRTDLL.448)
1580  */
1581 INT __cdecl CRTDLL_remove(LPCSTR file)
1582 {
1583         if (!DeleteFileA(file))
1584                 return -1;
1585         return 0;
1586 }
1587
1588 /*********************************************************************
1589  *                  _errno           (CRTDLL.52)
1590  * Yes, this is a function.
1591  */
1592 LPINT __cdecl CRTDLL__errno()
1593 {
1594         static  int crtdllerrno;
1595         
1596         /* FIXME: we should set the error at the failing function call time */
1597         crtdllerrno = LastErrorToErrno(GetLastError());
1598         return &crtdllerrno;
1599 }
1600
1601 /*********************************************************************
1602  *                  _tempnam           (CRTDLL.305)
1603  * 
1604  */
1605 LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix)
1606 {
1607
1608      char *ret;
1609      DOS_FULL_NAME tempname;
1610      
1611      if ((ret = tempnam(dir,prefix))==NULL) {
1612        WARN("Unable to get unique filename\n");
1613        return NULL;
1614      }
1615      if (!DOSFS_GetFullName(ret,FALSE,&tempname))
1616      {
1617        TRACE("Wrong path?\n");
1618        return NULL;
1619      }
1620      free(ret);
1621      if ((ret = CRTDLL_malloc(strlen(tempname.short_name)+1)) == NULL) {
1622          WARN("CRTDL_malloc for shortname failed\n");
1623          return NULL;
1624      }
1625      if ((ret = strcpy(ret,tempname.short_name)) == NULL) { 
1626        WARN("Malloc for shortname failed\n");
1627        return NULL;
1628      }
1629      
1630      TRACE("dir %s prefix %s got %s\n",
1631                     dir,prefix,ret);
1632      return ret;
1633
1634 }
1635 /*********************************************************************
1636  *                  tmpnam           (CRTDLL.490)
1637  *
1638  * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1639  * 
1640  */
1641 LPSTR __cdecl CRTDLL_tmpnam(LPSTR s)
1642 {
1643      char *ret;
1644
1645      if ((ret =tmpnam(s))== NULL) {
1646        WARN("Unable to get unique filename\n");
1647        return NULL;
1648      }
1649      if (!DOSFS_GetFullName(ret,FALSE,&CRTDLL_tmpname))
1650      {
1651        TRACE("Wrong path?\n");
1652        return NULL;
1653      }
1654      strcat(CRTDLL_tmpname.short_name,".");
1655      TRACE("for buf %p got %s\n",
1656                     s,CRTDLL_tmpname.short_name);
1657      TRACE("long got %s\n",
1658                     CRTDLL_tmpname.long_name);
1659      if ( s != NULL) 
1660        return strcpy(s,CRTDLL_tmpname.short_name);
1661      else 
1662        return CRTDLL_tmpname.short_name;
1663
1664 }
1665
1666 /*********************************************************************
1667  *                  _itoa           (CRTDLL.165)
1668  */
1669 LPSTR  __cdecl CRTDLL__itoa(INT x,LPSTR buf,INT buflen)
1670 {
1671     wsnprintfA(buf,buflen,"%d",x);
1672     return buf;
1673 }
1674
1675 /*********************************************************************
1676  *                  _ltoa           (CRTDLL.180)
1677  */
1678 LPSTR  __cdecl CRTDLL__ltoa(long x,LPSTR buf,INT radix)
1679 {
1680     switch(radix) {
1681         case  2: FIXME("binary format not implemented !\n");
1682                  break;
1683         case  8: wsnprintfA(buf,0x80,"%o",x);
1684                  break;
1685         case 10: wsnprintfA(buf,0x80,"%d",x);
1686                  break;
1687         case 16: wsnprintfA(buf,0x80,"%x",x);
1688                  break;
1689         default: FIXME("radix %d not implemented !\n", radix);
1690     }
1691     return buf;
1692 }
1693
1694 /*********************************************************************
1695  *                  _ultoa           (CRTDLL.311)
1696  */
1697 LPSTR  __cdecl CRTDLL__ultoa(long x,LPSTR buf,INT radix)
1698 {
1699     switch(radix) {
1700         case  2: FIXME("binary format not implemented !\n");
1701                  break;
1702         case  8: wsnprintfA(buf,0x80,"%lo",x);
1703                  break;
1704         case 10: wsnprintfA(buf,0x80,"%ld",x);
1705                  break;
1706         case 16: wsnprintfA(buf,0x80,"%lx",x);
1707                  break;
1708         default: FIXME("radix %d not implemented !\n", radix);
1709     }
1710     return buf;
1711 }
1712
1713 typedef VOID (*sig_handler_type)(VOID);
1714
1715 /*********************************************************************
1716  *                  signal           (CRTDLL.455)
1717  */
1718 VOID __cdecl CRTDLL_signal(int sig, sig_handler_type ptr)
1719 {
1720     FIXME("(%d %p):stub.\n", sig, ptr);
1721 }
1722
1723 /*********************************************************************
1724  *                  _ftol            (CRTDLL.113)
1725  */
1726 #ifdef USING_REAL_FPU
1727 LONG __cdecl CRTDLL__ftol(void) {
1728         /* don't just do DO_FPU("fistp",retval), because the rounding
1729          * mode must also be set to "round towards zero"... */
1730         double fl;
1731         POP_FPU(fl);
1732         return (LONG)fl;
1733 }
1734 #else
1735 LONG __cdecl CRTDLL__ftol(double fl) {
1736         FIXME("should be register function\n");
1737         return (LONG)fl;
1738 }
1739 #endif
1740
1741 /*********************************************************************
1742  *                  _CIpow           (CRTDLL.14)
1743  */
1744 #ifdef USING_REAL_FPU
1745 LONG __cdecl CRTDLL__CIpow(void) {
1746         double x,y;
1747         POP_FPU(y);
1748         POP_FPU(x);
1749         return pow(x,y);
1750 }
1751 #else
1752 LONG __cdecl CRTDLL__CIpow(double x,double y) {
1753         FIXME("should be register function\n");
1754         return pow(x,y);
1755 }
1756 #endif
1757
1758 /*********************************************************************
1759  *                  _sleep           (CRTDLL.267)
1760  */
1761 VOID __cdecl CRTDLL__sleep(unsigned long timeout) 
1762 {
1763   TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
1764   Sleep((timeout)?timeout:1);
1765 }
1766
1767 /*********************************************************************
1768  *                  getenv           (CRTDLL.437)
1769  */
1770 LPSTR __cdecl CRTDLL_getenv(const char *name) 
1771 {
1772      LPSTR environ = GetEnvironmentStringsA();
1773      LPSTR pp,pos = NULL;
1774      unsigned int length;
1775   
1776      for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
1777        {
1778          pos =strchr(pp,'=');
1779          if (pos)
1780            length = pos -pp;
1781          else
1782            length = strlen(pp);
1783          if (!strncmp(pp,name,length)) break;
1784        }
1785      if ((pp)&& (pos)) 
1786        {
1787          pp = pos+1;
1788          TRACE("got %s\n",pp);
1789        }
1790      FreeEnvironmentStringsA( environ );
1791      return pp;
1792 }
1793
1794 /*********************************************************************
1795  *                  _mbsrchr           (CRTDLL.223)
1796  */
1797 LPSTR __cdecl CRTDLL__mbsrchr(LPSTR s,CHAR x) {
1798         /* FIXME: handle multibyte strings */
1799         return strrchr(s,x);
1800 }
1801
1802 /*********************************************************************
1803  *                  _memicmp           (CRTDLL.233)(NTDLL.868)
1804  * A stringcompare, without \0 check
1805  * RETURNS
1806  *      -1:if first string is alphabetically before second string
1807  *      1:if second ''    ''      ''          ''   first   ''
1808  *      0:if both are equal.
1809  */
1810 INT __cdecl CRTDLL__memicmp(
1811         LPCSTR s1,      /* [in] first string */
1812         LPCSTR s2,      /* [in] second string */
1813         DWORD len       /* [in] length to compare */
1814 ) { 
1815         int     i;
1816
1817         for (i=0;i<len;i++) {
1818                 if (tolower(s1[i])<tolower(s2[i]))
1819                         return -1;
1820                 if (tolower(s1[i])>tolower(s2[i]))
1821                         return  1;
1822         }
1823         return 0;
1824 }
1825 /*********************************************************************
1826  *                  __dllonexit           (CRTDLL.25)
1827  */
1828 VOID __cdecl CRTDLL___dllonexit ()
1829 {       
1830         FIXME("stub\n");
1831 }
1832
1833 /*********************************************************************
1834  *                  wcstol           (CRTDLL.520)
1835  * Like strtol, but for wide character strings.
1836  */
1837 INT __cdecl CRTDLL_wcstol(LPWSTR s,LPWSTR *end,INT base) {
1838         LPSTR   sA = HEAP_strdupWtoA(GetProcessHeap(),0,s),endA;
1839         INT     ret = strtol(sA,&endA,base);
1840
1841         HeapFree(GetProcessHeap(),0,sA);
1842         if (end) *end = s+(endA-sA); /* pointer magic checked. */
1843         return ret;
1844 }
1845 /*********************************************************************
1846  *                  _strdate          (CRTDLL.283)
1847  */
1848 LPSTR __cdecl CRTDLL__strdate (LPSTR date)
1849 {       FIXME("%p stub\n", date);
1850         return 0;
1851 }
1852
1853 /*********************************************************************
1854  *                  _strtime          (CRTDLL.299)
1855  */
1856 LPSTR __cdecl CRTDLL__strtime (LPSTR date)
1857 {       FIXME("%p stub\n", date);
1858         return 0;
1859 }
1860
1861 /*********************************************************************
1862  *                  _except_handler2  (CRTDLL.78)
1863  */
1864 INT __cdecl CRTDLL__except_handler2 (
1865         PEXCEPTION_RECORD rec,
1866         PEXCEPTION_FRAME frame,
1867         PCONTEXT context,
1868         PEXCEPTION_FRAME  *dispatcher)
1869 {
1870         FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
1871         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
1872         frame->Handler, context, dispatcher);
1873         return ExceptionContinueSearch;
1874 }