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