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