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