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