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