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