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