- Add math calls: scalb, fpclass, nextafter, logb, _CI*
[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  * Copyright 2000 Jon Griffiths
10  */
11
12 /*
13 Unresolved issues Uwe Bonnes 970904:
14 - tested with ftp://ftp.remcomp.com/pub/remcomp/lcc-win32.zip, a C-Compiler
15                 for Win32, based on lcc, from Jacob Navia
16 UB 000416:
17 - probably not thread safe
18 */
19
20 /* NOTE: This file also implements the wcs* functions. They _ARE_ in 
21  * the newer Linux libcs, but use 4 byte wide characters, so are unusable,
22  * since we need 2 byte wide characters. - Marcus Meissner, 981031
23  */
24
25 #include "crtdll.h"
26 #include <ctype.h>
27 #define __USE_ISOC9X 1 /* for isfinite */
28 #include <math.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include "ntddk.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34
35
36 DEFAULT_DEBUG_CHANNEL(crtdll);
37
38
39 UINT CRTDLL_argc_dll;         /* CRTDLL.23 */
40 LPSTR *CRTDLL_argv_dll;       /* CRTDLL.24 */
41 LPSTR  CRTDLL_acmdln_dll;     /* CRTDLL.38 */
42 UINT CRTDLL_basemajor_dll;    /* CRTDLL.42 */
43 UINT CRTDLL_baseminor_dll;    /* CRTDLL.43 */
44 UINT CRTDLL_baseversion_dll;  /* CRTDLL.44 */
45 UINT CRTDLL_commode_dll;      /* CRTDLL.59 */
46 LPSTR  CRTDLL_environ_dll;    /* CRTDLL.75 */
47 UINT CRTDLL_fmode_dll;        /* CRTDLL.104 */
48 UINT CRTDLL_osmajor_dll;      /* CRTDLL.241 */
49 UINT CRTDLL_osminor_dll;      /* CRTDLL.242 */
50 UINT CRTDLL_osmode_dll;       /* CRTDLL.243 */
51 UINT CRTDLL_osver_dll;        /* CRTDLL.244 */
52 UINT CRTDLL_osversion_dll;    /* CRTDLL.245 */
53 UINT CRTDLL_winmajor_dll;     /* CRTDLL.329 */
54 UINT CRTDLL_winminor_dll;     /* CRTDLL.330 */
55 UINT CRTDLL_winver_dll;       /* CRTDLL.331 */
56 INT  CRTDLL_doserrno = 0; 
57 INT  CRTDLL_errno = 0;
58 const INT  CRTDLL__sys_nerr = 43;
59
60
61 /*********************************************************************
62  *                  CRTDLL_MainInit  (CRTDLL.init)
63  */
64 BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
65 {
66         TRACE("(0x%08x,%ld,%p)\n",hinstDLL,fdwReason,lpvReserved);
67
68         if (fdwReason == DLL_PROCESS_ATTACH) {
69           __CRTDLL__init_io();
70         }
71         return TRUE;
72 }
73
74
75 /* INTERNAL: Set the crt and dos errno's from the OS error given. */
76 void __CRTDLL__set_errno(ULONG err)
77 {
78   /* FIXME: not MT safe */
79   CRTDLL_doserrno = err;
80
81   switch(err)
82   {
83 #define ERR_CASE(oserr) case oserr:
84 #define ERR_MAPS(oserr,crterr) case oserr:CRTDLL_errno = crterr;break;
85     ERR_CASE(ERROR_ACCESS_DENIED)
86     ERR_CASE(ERROR_NETWORK_ACCESS_DENIED)
87     ERR_CASE(ERROR_CANNOT_MAKE)
88     ERR_CASE(ERROR_SEEK_ON_DEVICE)
89     ERR_CASE(ERROR_LOCK_FAILED)
90     ERR_CASE(ERROR_FAIL_I24)
91     ERR_CASE(ERROR_CURRENT_DIRECTORY)
92     ERR_CASE(ERROR_DRIVE_LOCKED)
93     ERR_CASE(ERROR_NOT_LOCKED)
94     ERR_CASE(ERROR_INVALID_ACCESS)
95     ERR_MAPS(ERROR_LOCK_VIOLATION,       EACCES);
96     ERR_CASE(ERROR_FILE_NOT_FOUND)
97     ERR_CASE(ERROR_NO_MORE_FILES)
98     ERR_CASE(ERROR_BAD_PATHNAME)
99     ERR_CASE(ERROR_BAD_NETPATH)
100     ERR_CASE(ERROR_INVALID_DRIVE)
101     ERR_CASE(ERROR_BAD_NET_NAME)
102     ERR_CASE(ERROR_FILENAME_EXCED_RANGE)
103     ERR_MAPS(ERROR_PATH_NOT_FOUND,       ENOENT);
104     ERR_MAPS(ERROR_IO_DEVICE,            EIO);
105     ERR_MAPS(ERROR_BAD_FORMAT,           ENOEXEC);
106     ERR_MAPS(ERROR_INVALID_HANDLE,       EBADF);
107     ERR_CASE(ERROR_OUTOFMEMORY)
108     ERR_CASE(ERROR_INVALID_BLOCK)
109     ERR_CASE(ERROR_NOT_ENOUGH_QUOTA);
110     ERR_MAPS(ERROR_ARENA_TRASHED,        ENOMEM);
111     ERR_MAPS(ERROR_BUSY,                 EBUSY);
112     ERR_CASE(ERROR_ALREADY_EXISTS)
113     ERR_MAPS(ERROR_FILE_EXISTS,          EEXIST);
114     ERR_MAPS(ERROR_BAD_DEVICE,           ENODEV);
115     ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES,  EMFILE);
116     ERR_MAPS(ERROR_DISK_FULL,            ENOSPC);
117     ERR_MAPS(ERROR_BROKEN_PIPE,          EPIPE);
118     ERR_MAPS(ERROR_POSSIBLE_DEADLOCK,    EDEADLK);
119     ERR_MAPS(ERROR_DIR_NOT_EMPTY,        ENOTEMPTY);
120     ERR_MAPS(ERROR_BAD_ENVIRONMENT,      E2BIG);
121     ERR_CASE(ERROR_WAIT_NO_CHILDREN)
122     ERR_MAPS(ERROR_CHILD_NOT_COMPLETE,   ECHILD);
123     ERR_CASE(ERROR_NO_PROC_SLOTS)
124     ERR_CASE(ERROR_MAX_THRDS_REACHED)
125     ERR_MAPS(ERROR_NESTING_NOT_ALLOWED,  EAGAIN);
126   default:
127     /*  Remaining cases map to EINVAL */
128     /* FIXME: may be missing some errors above */
129     CRTDLL_errno = EINVAL;
130   }
131 }
132
133 #if defined(__GNUC__) && defined(__i386__)
134 #define FPU_DOUBLE(var) double var; \
135   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
136 #define FPU_DOUBLES(var1,var2) double var1,var2; \
137   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
138   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
139 #else
140 #define FPU_DOUBLE(var) double var = quiet_nan(); \
141   FIXME(":not implemented\n");
142 #define FPU_DOUBLES(var1,var2) double var1,var2; \
143   var1=var2=quiet_nan(); FIXME(":not implemented\n")
144 #endif
145
146 /*********************************************************************
147  *                  _CIacos             (CRTDLL.004)
148  */
149 double __cdecl CRTDLL__CIacos(void)
150 {
151   FPU_DOUBLE(x);
152   return acos(x);
153 }
154
155
156 /*********************************************************************
157  *                  _CIasin             (CRTDLL.005)
158  */
159 double __cdecl CRTDLL__CIasin(void)
160 {
161   FPU_DOUBLE(x);
162   return asin(x);
163 }
164
165
166 /*********************************************************************
167  *                  _CIatan             (CRTDLL.006)
168  */
169 double __cdecl CRTDLL__CIatan(void)
170 {
171   FPU_DOUBLE(x);
172   return atan(x);
173 }
174
175 /*********************************************************************
176  *                  _CIatan2            (CRTDLL.007)
177  */
178 double __cdecl CRTDLL__CIatan2(void)
179 {
180   FPU_DOUBLES(x,y);
181   return atan2(x,y);
182 }
183
184
185 /*********************************************************************
186  *                  _CIcos             (CRTDLL.008)
187  */
188 double __cdecl CRTDLL__CIcos(void)
189 {
190   FPU_DOUBLE(x);
191   return cos(x);
192 }
193
194 /*********************************************************************
195  *                  _CIcosh            (CRTDLL.009)
196  */
197 double __cdecl CRTDLL__CIcosh(void)
198 {
199   FPU_DOUBLE(x);
200   return cosh(x);
201 }
202
203 /*********************************************************************
204  *                  _CIexp             (CRTDLL.010)
205  */
206 double __cdecl CRTDLL__CIexp(void)
207 {
208   FPU_DOUBLE(x);
209   return exp(x);
210 }
211
212 /*********************************************************************
213  *                  _CIfmod            (CRTDLL.011)
214  */
215 double __cdecl CRTDLL__CIfmod(void)
216 {
217   FPU_DOUBLES(x,y);
218   return fmod(x,y);
219 }
220
221 /*********************************************************************
222  *                  _CIlog             (CRTDLL.012)
223  */
224 double __cdecl CRTDLL__CIlog(void)
225 {
226   FPU_DOUBLE(x);
227   return log(x);
228 }
229
230 /*********************************************************************
231  *                  _CIlog10           (CRTDLL.013)
232  */
233 double __cdecl CRTDLL__CIlog10(void)
234 {
235   FPU_DOUBLE(x);
236   return log10(x);
237 }
238
239 /*********************************************************************
240  *                  _CIsin             (CRTDLL.015)
241  */
242 double __cdecl CRTDLL__CIsin(void)
243 {
244   FPU_DOUBLE(x);
245   return sin(x);
246 }
247
248 /*********************************************************************
249  *                  _CIsinh            (CRTDLL.016)
250  */
251 double __cdecl CRTDLL__CIsinh(void)
252 {
253   FPU_DOUBLE(x);
254   return sinh(x);
255 }
256
257 /*********************************************************************
258  *                  _CIsqrt            (CRTDLL.017)
259  */
260 double __cdecl CRTDLL__CIsqrt(void)
261 {
262   FPU_DOUBLE(x);
263   return sqrt(x);
264 }
265
266 /*********************************************************************
267  *                  _CItan             (CRTDLL.018)
268  */
269 double __cdecl CRTDLL__CItan(void)
270 {
271   FPU_DOUBLE(x);
272   return tan(x);
273 }
274
275 /*********************************************************************
276  *                  _CItanh            (CRTDLL.019)
277  */
278 double __cdecl CRTDLL__CItanh(void)
279 {
280   FPU_DOUBLE(x);
281   return tanh(x);
282 }
283
284 /*********************************************************************
285  *                  _GetMainArgs  (CRTDLL.022)
286  */
287 LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,
288                                 LPSTR *environ,DWORD flag)
289 {
290         char *cmdline;
291         char  **xargv;
292         int     xargc,end,last_arg,afterlastspace;
293         DWORD   version;
294
295         TRACE("(%p,%p,%p,%ld).\n",
296                 argc,argv,environ,flag
297         );
298
299         if (CRTDLL_acmdln_dll != NULL)
300                 HeapFree(GetProcessHeap(), 0, CRTDLL_acmdln_dll);
301
302         CRTDLL_acmdln_dll = cmdline = CRTDLL__strdup( GetCommandLineA() );
303         TRACE("got '%s'\n", cmdline);
304
305         version = GetVersion();
306         CRTDLL_osver_dll       = version >> 16;
307         CRTDLL_winminor_dll    = version & 0xFF;
308         CRTDLL_winmajor_dll    = (version>>8) & 0xFF;
309         CRTDLL_baseversion_dll = version >> 16;
310         CRTDLL_winver_dll      = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8);
311         CRTDLL_baseminor_dll   = (version >> 16) & 0xFF;
312         CRTDLL_basemajor_dll   = (version >> 24) & 0xFF;
313         CRTDLL_osversion_dll   = version & 0xFFFF;
314         CRTDLL_osminor_dll     = version & 0xFF;
315         CRTDLL_osmajor_dll     = (version>>8) & 0xFF;
316
317         /* missing threading init */
318
319         end=0;last_arg=0;xargv=NULL;xargc=0;afterlastspace=0;
320         while (1)
321         {
322             if ((cmdline[end]==' ') || (cmdline[end]=='\0'))
323             {
324                 if (cmdline[end]=='\0')
325                     last_arg=1;
326                 else
327                     cmdline[end]='\0';
328                 /* alloc xargc + NULL entry */
329                         xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv,
330                                              sizeof(char*)*(xargc+1));
331                 if (strlen(cmdline+afterlastspace))
332                 {
333                     xargv[xargc] = CRTDLL__strdup(cmdline+afterlastspace);
334                     xargc++;
335                     if (!last_arg) /* need to seek to the next arg ? */
336                     {
337                         end++;
338                         while (cmdline[end]==' ')
339                             end++;
340         }
341                     afterlastspace=end;
342                 }
343                 else
344                 {
345                     xargv[xargc] = NULL; /* the last entry is NULL */
346                     break;
347                 }
348             }
349             else
350                 end++;
351         }
352         CRTDLL_argc_dll = xargc;
353         *argc           = xargc;
354         CRTDLL_argv_dll = xargv;
355         *argv           = xargv;
356
357         TRACE("found %d arguments\n",
358                 CRTDLL_argc_dll);
359         CRTDLL_environ_dll = *environ = GetEnvironmentStringsA();
360         return environ;
361 }
362
363
364 /*********************************************************************
365  *                  _fpclass         (CRTDLL.105)
366  *
367  * Return the FP classification of d.
368  */
369 INT __cdecl CRTDLL__fpclass(double d)
370 {
371   switch (fpclassify( d ))
372   {
373   case FP_NAN: return _FPCLASS_QNAN;
374   case FP_INFINITE:
375     if (signbit(d))
376       return _FPCLASS_NINF;
377     return _FPCLASS_PINF;
378   case FP_SUBNORMAL:
379     if (signbit(d))
380       return _FPCLASS_ND;
381     return _FPCLASS_PD;
382   case FP_ZERO:
383     if (signbit(d))
384       return _FPCLASS_NZ;
385     return _FPCLASS_PZ;
386   case FP_NORMAL:
387   default:
388     if (signbit(d))
389       return _FPCLASS_NN;
390     return _FPCLASS_PN;
391   }
392 }
393
394
395 /*********************************************************************
396  *                  _initterm     (CRTDLL.135)
397  */
398 DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
399 {
400         _INITTERMFUN    *current;
401
402         TRACE("(%p,%p)\n",start,end);
403         current=start;
404         while (current<end) {
405                 if (*current) (*current)();
406                 current++;
407         }
408         return 0;
409 }
410
411
412 /*******************************************************************
413  *         _global_unwind2  (CRTDLL.129)
414  */
415 void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame )
416 {
417     RtlUnwind( frame, 0, NULL, 0 );
418 }
419
420
421 /*******************************************************************
422  *         _local_unwind2  (CRTDLL.173)
423  */
424 void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr )
425 {
426     TRACE("(%p,%ld)\n",endframe,nr);
427 }
428
429
430 /*******************************************************************
431  *         _setjmp  (CRTDLL.264)
432  */
433 INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf)
434 {
435   FIXME(":(%p): stub\n",jmpbuf);
436   return 0;
437 }
438
439
440 /*********************************************************************
441  *                  _beep          (CRTDLL.045)
442  *
443  * Output a tone using the PC speaker.
444  *
445  * PARAMS
446  * freq [in]     Frequency of the tone
447  *
448  * duration [in] Length of time the tone should sound
449  *
450  * RETURNS
451  * None.
452  */
453 void __cdecl CRTDLL__beep( UINT freq, UINT duration)
454 {
455     TRACE(":Freq %d, Duration %d\n",freq,duration);
456     Beep(freq, duration);
457 }
458
459
460 /*********************************************************************
461  *                  rand          (CRTDLL.446)
462  */
463 INT __cdecl CRTDLL_rand()
464 {
465     return (rand() & CRTDLL_RAND_MAX); 
466 }
467
468
469 /*********************************************************************
470  *                  _rotl          (CRTDLL.259)
471  */
472 UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
473 {
474     shift &= 31;
475     return (x << shift) | (x >> (32-shift));
476 }
477
478
479 /*********************************************************************
480  *                  _lrotl          (CRTDLL.175)
481  */
482 DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
483 {
484     shift &= 31;
485     return (x << shift) | (x >> (32-shift));
486 }
487
488
489 /*********************************************************************
490  *                  _lrotr          (CRTDLL.176)
491  */
492 DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
493 {
494     shift &= 0x1f;
495     return (x >> shift) | (x << (32-shift));
496 }
497
498
499 /*********************************************************************
500  *                  _rotr          (CRTDLL.258)
501  */
502 DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
503 {
504     shift &= 0x1f;
505     return (x >> shift) | (x << (32-shift));
506 }
507
508
509 /*********************************************************************
510  *                  _scalb          (CRTDLL.259)
511  *
512  * Return x*2^y.
513  */
514 double  __cdecl CRTDLL__scalb(double x, LONG y)
515 {
516   /* Note - Can't forward directly as libc expects y as double */
517   double y2 = (double)y;
518   return scalb( x, y2 );
519 }
520
521
522 /*********************************************************************
523  *                  vswprintf      (CRTDLL.501)
524  */
525 INT __cdecl CRTDLL_vswprintf( LPWSTR buffer, LPCWSTR spec, va_list args )
526 {
527     return wvsprintfW( buffer, spec, args );
528 }
529
530
531 /*********************************************************************
532  *                  longjmp        (CRTDLL.426)
533  */
534 VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
535 {
536     FIXME("CRTDLL_longjmp semistup, expect crash\n");
537     longjmp(env, val);
538 }
539
540
541 /*********************************************************************
542  *                  setlocale           (CRTDLL.453)
543  */
544 LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
545 {
546     LPSTR categorystr;
547
548     switch (category) {
549     case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
550     case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
551     case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
552     case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
553     case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
554     case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
555     default: categorystr = "UNKNOWN?";break;
556     }
557     FIXME("(%s,%s),stub!\n",categorystr,locale);
558     return "C";
559 }
560
561
562 /*********************************************************************
563  *                  _isctype           (CRTDLL.138)
564  */
565 BOOL __cdecl CRTDLL__isctype(CHAR x,CHAR type)
566 {
567     if ((type & CRTDLL_SPACE) && isspace(x))
568         return TRUE;
569     if ((type & CRTDLL_PUNCT) && ispunct(x))
570         return TRUE;
571     if ((type & CRTDLL_LOWER) && islower(x))
572         return TRUE;
573     if ((type & CRTDLL_UPPER) && isupper(x))
574         return TRUE;
575     if ((type & CRTDLL_ALPHA) && isalpha(x))
576         return TRUE;
577     if ((type & CRTDLL_DIGIT) && isdigit(x))
578         return TRUE;
579     if ((type & CRTDLL_CONTROL) && iscntrl(x))
580         return TRUE;
581     /* check CRTDLL_LEADBYTE */
582     return FALSE;
583 }
584
585
586 /*********************************************************************
587  *                  _fullpath           (CRTDLL.114)
588  */
589 LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
590 {
591   if (!buf)
592   {
593       size = 256;
594       if(!(buf = CRTDLL_malloc(size))) return NULL;
595   }
596   if (!GetFullPathNameA( name, size, buf, NULL )) return NULL;
597   TRACE("CRTDLL_fullpath got %s\n",buf);
598   return buf;
599 }
600
601
602 /*********************************************************************
603  *                  _splitpath           (CRTDLL.279)
604  */
605 VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
606 {
607   /* drive includes :
608      directory includes leading and trailing (forward and backward slashes)
609      filename without dot and slashes
610      extension with leading dot
611      */
612   char * drivechar,*dirchar,*namechar;
613
614   TRACE("CRTDLL__splitpath got %s\n",path);
615
616   drivechar  = strchr(path,':');
617   dirchar    = strrchr(path,'/');
618   namechar   = strrchr(path,'\\');
619   dirchar = max(dirchar,namechar);
620   if (dirchar)
621     namechar   = strrchr(dirchar,'.');
622   else
623     namechar   = strrchr(path,'.');
624
625   if (drive)
626     {
627       *drive = 0x00;
628       if (drivechar)
629       {
630           strncat(drive,path,drivechar-path+1);
631           path = drivechar+1;
632       }
633     }
634   if (directory)
635     {
636       *directory = 0x00;
637       if (dirchar)
638       {
639           strncat(directory,path,dirchar-path+1);
640           path = dirchar+1;
641       }
642     }
643   if (filename)
644     {
645       *filename = 0x00;
646       if (namechar)
647       {
648           strncat(filename,path,namechar-path);
649           if (extension)
650           {
651               *extension = 0x00;
652               strcat(extension,namechar);
653           }
654       }
655     }
656
657   TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
658 }
659
660
661 /*********************************************************************
662  *                  _makepath           (CRTDLL.182)
663  */
664
665 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
666                               LPCSTR directory, LPCSTR filename,
667                               LPCSTR extension )
668 {
669     char ch;
670     TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
671           filename, extension);
672
673     if ( !path )
674         return;
675
676     path[0] = 0;
677     if (drive && drive[0])
678     {
679         path[0] = drive[0];
680         path[1] = ':';
681         path[2] = 0;
682     }
683     if (directory && directory[0])
684     {
685         strcat(path, directory);
686         ch = path[strlen(path)-1];
687         if (ch != '/' && ch != '\\')
688             strcat(path,"\\");
689     }
690     if (filename && filename[0])
691     {
692         strcat(path, filename);
693         if (extension && extension[0])
694         {
695             if ( extension[0] != '.' ) {
696                 strcat(path,".");
697             }
698             strcat(path,extension);
699         }
700     }
701
702     TRACE("CRTDLL__makepath returns %s\n",path);
703 }
704
705
706 /*********************************************************************
707  *                  _errno           (CRTDLL.52)
708  * Return the address of the CRT errno (Not the libc errno).
709  *
710  * BUGS
711  * Not MT safe.
712  */
713 LPINT __cdecl CRTDLL__errno( VOID )
714 {
715   return &CRTDLL_errno;
716 }
717
718
719 /*********************************************************************
720  *                  __doserrno       (CRTDLL.26)
721  * 
722  * Return the address of the DOS errno (holding the last OS error).
723  *
724  * BUGS
725  * Not MT safe.
726  */
727 LPINT __cdecl CRTDLL___doserrno( VOID )
728 {
729   return &CRTDLL_doserrno;
730 }
731
732
733 /**********************************************************************
734  *                  _strerror       (CRTDLL.284)
735  *
736  * Return a formatted system error message.
737  *
738  * NOTES
739  * The caller does not own the string returned.
740  */
741 extern int sprintf(char *str, const char *format, ...);
742
743 LPSTR __cdecl CRTDLL__strerror (LPCSTR err)
744 {
745   static char strerrbuff[256];
746   sprintf(strerrbuff,"%s: %s\n",err,CRTDLL_strerror(CRTDLL_errno));
747   return strerrbuff;
748 }
749
750
751 /*********************************************************************
752  *                  perror       (CRTDLL.435)
753  *
754  * Print a formatted system error message to stderr.
755  */
756 VOID __cdecl CRTDLL_perror (LPCSTR err)
757 {
758   char *err_str = CRTDLL_strerror(CRTDLL_errno);
759   CRTDLL_fprintf(CRTDLL_stderr,"%s: %s\n",err,err_str);
760   CRTDLL_free(err_str);
761 }
762  
763
764 /*********************************************************************
765  *                  strerror       (CRTDLL.465)
766  *
767  * Return the text of an error.
768  *
769  * NOTES
770  * The caller does not own the string returned.
771  */
772 extern char *strerror(int errnum); 
773
774 LPSTR __cdecl CRTDLL_strerror (INT err)
775 {
776   return strerror(err);
777 }
778
779
780 /*********************************************************************
781  *                  signal           (CRTDLL.455)
782  */
783 LPVOID __cdecl CRTDLL_signal(INT sig, sig_handler_type ptr)
784 {
785     FIXME("(%d %p):stub.\n", sig, ptr);
786     return (void*)-1;
787 }
788
789
790 /*********************************************************************
791  *                  _sleep           (CRTDLL.267)
792  */
793 VOID __cdecl CRTDLL__sleep(ULONG timeout)
794 {
795   TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
796   Sleep((timeout)?timeout:1);
797 }
798
799
800 /*********************************************************************
801  *                  getenv           (CRTDLL.437)
802  */
803 LPSTR __cdecl CRTDLL_getenv(LPCSTR name)
804 {
805      LPSTR environ = GetEnvironmentStringsA();
806      LPSTR pp,pos = NULL;
807      unsigned int length;
808
809      for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
810        {
811          pos =strchr(pp,'=');
812          if (pos)
813            length = pos -pp;
814          else
815            length = strlen(pp);
816          if (!strncmp(pp,name,length)) break;
817        }
818      if ((pp)&& (pos)) 
819        {
820          pp = pos+1;
821          TRACE("got %s\n",pp);
822        }
823      FreeEnvironmentStringsA( environ );
824      return pp;
825 }
826
827
828 /*********************************************************************
829  *                  _except_handler2  (CRTDLL.78)
830  */
831 INT __cdecl CRTDLL__except_handler2 (
832         PEXCEPTION_RECORD rec,
833         PEXCEPTION_FRAME frame,
834         PCONTEXT context,
835         PEXCEPTION_FRAME  *dispatcher)
836 {
837         FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
838         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
839         frame->Handler, context, dispatcher);
840         return ExceptionContinueSearch;
841 }
842
843
844 /*********************************************************************
845  *                  __isascii           (CRTDLL.028)
846  *
847  */
848 INT __cdecl CRTDLL___isascii(INT c)
849 {
850   return isascii(c);
851 }
852
853
854 /*********************************************************************
855  *                  __toascii           (CRTDLL.035)
856  *
857  */
858 INT __cdecl CRTDLL___toascii(INT c)
859 {
860   return c & 0x7f;
861 }
862
863
864 /*********************************************************************
865  *                  iswascii           (CRTDLL.404)
866  *
867  */
868 INT __cdecl CRTDLL_iswascii(LONG c)
869 {
870   return ((unsigned)c < 0x80);
871 }
872
873
874 /*********************************************************************
875  *                  __iscsym           (CRTDLL.029)
876  *
877  * Is a character valid in a C identifier (a-Z,0-9,_).
878  *
879  * PARAMS
880  *   c       [I]: Character to check
881  *
882  * RETURNS
883  * Non zero if c is valid as t a C identifier.
884  */
885 INT __cdecl CRTDLL___iscsym(LONG c)
886 {
887   return (isalnum(c) || c == '_');
888 }
889
890
891 /*********************************************************************
892  *                  __iscsymf           (CRTDLL.030)
893  *
894  * Is a character valid as the first letter in a C identifier (a-Z,_).
895  *
896  * PARAMS
897  *   c [in]  Character to check
898  *
899  * RETURNS
900  *   Non zero if c is valid as the first letter in a C identifier.
901  */
902 INT __cdecl CRTDLL___iscsymf(LONG c)
903 {
904   return (isalpha(c) || c == '_');
905 }
906
907
908 /*********************************************************************
909  *                  _loaddll        (CRTDLL.171)
910  *
911  * Get a handle to a DLL in memory. The DLL is loaded if it is not already.
912  *
913  * PARAMS
914  * dll [in]  Name of DLL to load.
915  *
916  * RETURNS
917  * Success: A handle to the loaded DLL.
918  *
919  * Failure: FIXME.
920  */
921 INT __cdecl CRTDLL__loaddll(LPSTR dllname)
922 {
923   return LoadLibraryA(dllname);
924 }
925
926
927 /*********************************************************************
928  *                  _unloaddll        (CRTDLL.313)
929  *
930  * Free reference to a DLL handle from loaddll().
931  *
932  * PARAMS
933  *   dll [in] Handle to free.
934  *
935  * RETURNS
936  * Success: 0.
937  *
938  * Failure: Error number.
939  */
940 INT __cdecl CRTDLL__unloaddll(HANDLE dll)
941 {
942   INT err;
943   if (FreeLibrary(dll))
944     return 0;
945   err = GetLastError();
946   __CRTDLL__set_errno(err);
947   return err;
948 }
949
950
951 /*********************************************************************
952  *                  _lsearch        (CRTDLL.177)
953  *
954  * Linear search of an array of elements. Adds the item to the array if
955  * not found.
956  *
957  * PARAMS
958  *   match [in]      Pointer to element to match
959  *   start [in]      Pointer to start of search memory
960  *   array_size [in] Length of search array (element count)
961  *   elem_size [in]  Size of each element in memory
962  *   comp_func [in]  Pointer to comparason function (like qsort()).
963  *
964  * RETURNS
965  *   Pointer to the location where element was found or added.
966  */
967 LPVOID __cdecl CRTDLL__lsearch(LPVOID match,LPVOID start, LPUINT array_size,
968                                UINT elem_size, comp_func cf)
969 {
970   UINT size = *array_size;
971   if (size)
972     do
973     {
974       if (cf(match, start) == 0)
975         return start; /* found */
976       start += elem_size;
977     } while (--size);
978
979   /* not found, add to end */
980   memcpy(start, match, elem_size);
981   array_size[0]++;
982   return start;
983 }
984
985
986 /*********************************************************************
987  *                  _itow           (CRTDLL.164)
988  *
989  * Convert an integer to a wide char string.
990  */
991 extern LPSTR  __cdecl _itoa( long , LPSTR , INT); /* ntdll */
992
993 WCHAR* __cdecl CRTDLL__itow(INT value,WCHAR* out,INT base)
994 {
995   char buff[64]; /* FIXME: Whats the maximum buffer size for INT_MAX? */
996
997   _itoa(value, buff, base);
998   MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
999   return out;
1000 }
1001
1002
1003 /*********************************************************************
1004  *                  _ltow           (CRTDLL.??)
1005  *
1006  * Convert a long to a wide char string.
1007  */
1008 extern LPSTR  __cdecl _ltoa( long , LPSTR , INT); /* ntdll */
1009
1010 WCHAR* __cdecl CRTDLL__ltow(LONG value,WCHAR* out,INT base)
1011 {
1012   char buff[64]; /* FIXME: Whats the maximum buffer size for LONG_MAX? */
1013
1014   _ltoa(value, buff, base);
1015   MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1016   return out;
1017 }
1018
1019
1020 /*********************************************************************
1021  *                  _ultow           (CRTDLL.??)
1022  *
1023  * Convert an unsigned long to a wide char string.
1024  */
1025 extern LPSTR  __cdecl _ultoa( long , LPSTR , INT); /* ntdll */
1026
1027 WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base)
1028 {
1029   char buff[64]; /* FIXME: Whats the maximum buffer size for ULONG_MAX? */
1030
1031   _ultoa(value, buff, base);
1032   MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1033   return out;
1034 }
1035
1036
1037 /*********************************************************************
1038  *                  _toupper           (CRTDLL.489)
1039  */
1040 CHAR __cdecl CRTDLL__toupper(CHAR c)
1041 {
1042   return toupper(c);
1043 }
1044
1045
1046 /*********************************************************************
1047  *                  _tolower           (CRTDLL.490)
1048  */
1049 CHAR __cdecl CRTDLL__tolower(CHAR c)
1050 {
1051   return tolower(c);
1052 }
1053
1054
1055 /* FP functions */
1056
1057 /*********************************************************************
1058  *                  _cabs           (CRTDLL.048)
1059  *
1060  * Return the absolue value of a complex number.
1061  *
1062  * PARAMS
1063  *   c [in] Structure containing real and imaginary parts of complex number.
1064  *
1065  * RETURNS
1066  *   Absolute value of complex number (always a positive real number).
1067  */
1068 double __cdecl CRTDLL__cabs(struct complex c)
1069 {
1070   return sqrt(c.real * c.real + c.imaginary * c.imaginary);
1071 }
1072
1073
1074 /*********************************************************************
1075  *                  _chgsign    (CRTDLL.053)
1076  *
1077  * Change the sign of an IEEE double.
1078  *
1079  * PARAMS
1080  *   d [in] Number to invert.
1081  *
1082  * RETURNS
1083  *   Number with sign inverted.
1084  */
1085 double __cdecl CRTDLL__chgsign(double d)
1086 {
1087   /* FIXME: +-infinity,Nan not tested */
1088   return -d;
1089 }
1090
1091
1092 /*********************************************************************
1093  *                  _control87    (CRTDLL.060)
1094  *
1095  * Unimplemented. Obsolete. Give it up. Use controlfp(), if you must.
1096  *
1097  */
1098 UINT __cdecl CRTDLL__control87(UINT x, UINT y)
1099 {
1100   /* Will never be supported, no possible targets have an 87/287 FP unit */
1101   WARN(":Ignoring control87 call, dont trust any FP results!\n");
1102   return 0;
1103 }
1104
1105
1106 /*********************************************************************
1107  *                  _controlfp    (CRTDLL.061)
1108  *
1109  * Set the state of the floating point unit.
1110  *
1111  * PARAMS
1112  * FIXME:
1113  *
1114  * RETURNS
1115  * None
1116  *
1117  * BUGS
1118  * Unimplemented.
1119  */
1120 UINT __cdecl CRTDLL__controlfp( UINT x, UINT y)
1121 {
1122   FIXME(":stub!\n");
1123   return 0;
1124 }
1125
1126
1127 /*********************************************************************
1128  *                  _copysign           (CRTDLL.062)
1129  *
1130  * Return the number x with the sign of y.
1131  */
1132 double __cdecl CRTDLL__copysign(double x, double y)
1133 {
1134   /* FIXME: Behaviour for Nan/Inf etc? */
1135   if (y < 0.0)
1136     return x < 0.0 ? x : -x;
1137
1138   return x < 0.0 ? -x : x;
1139 }
1140
1141
1142 /*********************************************************************
1143  *                  _finite           (CRTDLL.101)
1144  *
1145  * Determine if an IEEE double is finite (i.e. not +/- Infinity).
1146  *
1147  * PARAMS
1148  *   d [in]  Number to check.
1149  *
1150  * RETURNS
1151  *   Non zero if number is finite.
1152  */
1153 INT __cdecl  CRTDLL__finite(double d)
1154 {
1155   return (isfinite(d)?1:0); /* See comment for CRTDLL__isnan() */
1156 }
1157
1158
1159 /*********************************************************************
1160  *                  _fpreset           (CRTDLL.107)
1161  *
1162  * Reset the state of the floating point processor.
1163  * 
1164  * PARAMS
1165  *   None.
1166  *
1167  * RETURNS
1168  *   None.
1169  *
1170  * BUGS
1171  * Unimplemented.
1172  */
1173 VOID __cdecl CRTDLL__fpreset(void)
1174 {
1175   FIXME(":stub!\n");
1176 }
1177
1178
1179 /*********************************************************************
1180  *                  _isnan           (CRTDLL.164)
1181  *
1182  * Determine if an IEEE double is unrepresentable (NaN).
1183  *
1184  * PARAMS
1185  *   d [in]  Number to check.
1186  *
1187  * RETURNS
1188  *   Non zero if number is NaN.
1189  */
1190 INT __cdecl  CRTDLL__isnan(double d)
1191 {
1192   /* some implementations return -1 for true(glibc), crtdll returns 1.
1193    * Do the same, as the result may be used in calculations.
1194    */
1195   return isnan(d)?1:0;
1196 }
1197
1198
1199 /*********************************************************************
1200  *                  _purecall           (CRTDLL.249)
1201  *
1202  * Abort program after pure virtual function call.
1203  */
1204 VOID __cdecl CRTDLL__purecall(VOID)
1205 {
1206   CRTDLL__amsg_exit( 6025 );
1207 }
1208