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