Moved UTSelectorOffsetToLinear and UTLinearToSelectorOffset to
[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 #define __USE_ISOC99 1 /* for isfinite */
29 #include <math.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include "ntddk.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35
36
37 DEFAULT_DEBUG_CHANNEL(crtdll);
38
39
40 double CRTDLL_HUGE_dll;       /* CRTDLL.20 */
41 UINT CRTDLL_argc_dll;         /* CRTDLL.23 */
42 LPSTR *CRTDLL_argv_dll;       /* CRTDLL.24 */
43 LPSTR  CRTDLL_acmdln_dll;     /* CRTDLL.38 */
44 UINT CRTDLL_basemajor_dll;    /* CRTDLL.42 */
45 UINT CRTDLL_baseminor_dll;    /* CRTDLL.43 */
46 UINT CRTDLL_baseversion_dll;  /* CRTDLL.44 */
47 UINT CRTDLL_commode_dll;      /* CRTDLL.59 */
48 LPSTR  CRTDLL_environ_dll;    /* CRTDLL.75 */
49 UINT CRTDLL_fmode_dll;        /* CRTDLL.104 */
50 UINT CRTDLL_osmajor_dll;      /* CRTDLL.241 */
51 UINT CRTDLL_osminor_dll;      /* CRTDLL.242 */
52 UINT CRTDLL_osmode_dll;       /* CRTDLL.243 */
53 UINT CRTDLL_osver_dll;        /* CRTDLL.244 */
54 UINT CRTDLL_osversion_dll;    /* CRTDLL.245 */
55 UINT CRTDLL_winmajor_dll;     /* CRTDLL.329 */
56 UINT CRTDLL_winminor_dll;     /* CRTDLL.330 */
57 UINT CRTDLL_winver_dll;       /* CRTDLL.331 */
58 INT  CRTDLL_doserrno = 0; 
59 INT  CRTDLL_errno = 0;
60 const INT  CRTDLL__sys_nerr = 43;
61
62 /* ASCII char classification flags - binary compatible */
63 #define _C_ CRTDLL_CONTROL
64 #define _S_ CRTDLL_SPACE
65 #define _P_ CRTDLL_PUNCT
66 #define _D_ CRTDLL_DIGIT
67 #define _H_ CRTDLL_HEX
68 #define _U_ CRTDLL_UPPER
69 #define _L_ CRTDLL_LOWER
70
71 WORD CRTDLL_ctype [257] = {
72   0, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_C_, _S_|_C_,
73   _S_|_C_, _S_|_C_, _S_|_C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_,
74   _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|CRTDLL_BLANK,
75   _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_,
76   _P_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_,
77   _D_|_H_, _D_|_H_, _D_|_H_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _U_|_H_,
78   _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_, _U_, _U_, _U_, _U_,
79   _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_,
80   _U_, _P_, _P_, _P_, _P_, _P_, _P_, _L_|_H_, _L_|_H_, _L_|_H_, _L_|_H_,
81   _L_|_H_, _L_|_H_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_,
82   _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _P_, _P_, _P_, _P_,
83   _C_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
89 };
90
91 /*********************************************************************
92  *                  CRTDLL_MainInit  (CRTDLL.init)
93  */
94 BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
95 {
96         TRACE("(0x%08x,%ld,%p)\n",hinstDLL,fdwReason,lpvReserved);
97
98         if (fdwReason == DLL_PROCESS_ATTACH) {
99           __CRTDLL__init_io();
100           CRTDLL_HUGE_dll = HUGE_VAL;
101         }
102         return TRUE;
103 }
104
105
106 /* INTERNAL: Set the crt and dos errno's from the OS error given. */
107 void __CRTDLL__set_errno(ULONG err)
108 {
109   /* FIXME: not MT safe */
110   CRTDLL_doserrno = err;
111
112   switch(err)
113   {
114 #define ERR_CASE(oserr) case oserr:
115 #define ERR_MAPS(oserr,crterr) case oserr:CRTDLL_errno = crterr;break;
116     ERR_CASE(ERROR_ACCESS_DENIED)
117     ERR_CASE(ERROR_NETWORK_ACCESS_DENIED)
118     ERR_CASE(ERROR_CANNOT_MAKE)
119     ERR_CASE(ERROR_SEEK_ON_DEVICE)
120     ERR_CASE(ERROR_LOCK_FAILED)
121     ERR_CASE(ERROR_FAIL_I24)
122     ERR_CASE(ERROR_CURRENT_DIRECTORY)
123     ERR_CASE(ERROR_DRIVE_LOCKED)
124     ERR_CASE(ERROR_NOT_LOCKED)
125     ERR_CASE(ERROR_INVALID_ACCESS)
126     ERR_MAPS(ERROR_LOCK_VIOLATION,       EACCES);
127     ERR_CASE(ERROR_FILE_NOT_FOUND)
128     ERR_CASE(ERROR_NO_MORE_FILES)
129     ERR_CASE(ERROR_BAD_PATHNAME)
130     ERR_CASE(ERROR_BAD_NETPATH)
131     ERR_CASE(ERROR_INVALID_DRIVE)
132     ERR_CASE(ERROR_BAD_NET_NAME)
133     ERR_CASE(ERROR_FILENAME_EXCED_RANGE)
134     ERR_MAPS(ERROR_PATH_NOT_FOUND,       ENOENT);
135     ERR_MAPS(ERROR_IO_DEVICE,            EIO);
136     ERR_MAPS(ERROR_BAD_FORMAT,           ENOEXEC);
137     ERR_MAPS(ERROR_INVALID_HANDLE,       EBADF);
138     ERR_CASE(ERROR_OUTOFMEMORY)
139     ERR_CASE(ERROR_INVALID_BLOCK)
140     ERR_CASE(ERROR_NOT_ENOUGH_QUOTA);
141     ERR_MAPS(ERROR_ARENA_TRASHED,        ENOMEM);
142     ERR_MAPS(ERROR_BUSY,                 EBUSY);
143     ERR_CASE(ERROR_ALREADY_EXISTS)
144     ERR_MAPS(ERROR_FILE_EXISTS,          EEXIST);
145     ERR_MAPS(ERROR_BAD_DEVICE,           ENODEV);
146     ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES,  EMFILE);
147     ERR_MAPS(ERROR_DISK_FULL,            ENOSPC);
148     ERR_MAPS(ERROR_BROKEN_PIPE,          EPIPE);
149     ERR_MAPS(ERROR_POSSIBLE_DEADLOCK,    EDEADLK);
150     ERR_MAPS(ERROR_DIR_NOT_EMPTY,        ENOTEMPTY);
151     ERR_MAPS(ERROR_BAD_ENVIRONMENT,      E2BIG);
152     ERR_CASE(ERROR_WAIT_NO_CHILDREN)
153     ERR_MAPS(ERROR_CHILD_NOT_COMPLETE,   ECHILD);
154     ERR_CASE(ERROR_NO_PROC_SLOTS)
155     ERR_CASE(ERROR_MAX_THRDS_REACHED)
156     ERR_MAPS(ERROR_NESTING_NOT_ALLOWED,  EAGAIN);
157   default:
158     /*  Remaining cases map to EINVAL */
159     /* FIXME: may be missing some errors above */
160     CRTDLL_errno = EINVAL;
161   }
162 }
163
164 #if defined(__GNUC__) && defined(__i386__)
165 #define FPU_DOUBLE(var) double var; \
166   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : )
167 #define FPU_DOUBLES(var1,var2) double var1,var2; \
168   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \
169   __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : )
170 #else
171 #define FPU_DOUBLE(var) double var = quiet_nan(0); \
172   FIXME(":not implemented\n");
173 #define FPU_DOUBLES(var1,var2) double var1,var2; \
174   var1=var2=quiet_nan(0); FIXME(":not implemented\n")
175 #endif
176
177 /*********************************************************************
178  *                  _CIacos             (CRTDLL.004)
179  */
180 double __cdecl CRTDLL__CIacos(void)
181 {
182   FPU_DOUBLE(x);
183   if (x < -1.0 || x > 1.0) CRTDLL_errno = EDOM;
184   return acos(x);
185 }
186
187
188 /*********************************************************************
189  *                  _CIasin             (CRTDLL.005)
190  */
191 double __cdecl CRTDLL__CIasin(void)
192 {
193   FPU_DOUBLE(x);
194   if (x < -1.0 || x > 1.0) CRTDLL_errno = EDOM;
195   return asin(x);
196 }
197
198
199 /*********************************************************************
200  *                  _CIatan             (CRTDLL.006)
201  */
202 double __cdecl CRTDLL__CIatan(void)
203 {
204   FPU_DOUBLE(x);
205   if (!isfinite(x)) CRTDLL_errno = EDOM;
206   return atan(x);
207 }
208
209 /*********************************************************************
210  *                  _CIatan2            (CRTDLL.007)
211  */
212 double __cdecl CRTDLL__CIatan2(void)
213 {
214   FPU_DOUBLES(x,y);
215   if (!isfinite(x)) CRTDLL_errno = EDOM;
216   return atan2(x,y);
217 }
218
219
220 /*********************************************************************
221  *                  _CIcos             (CRTDLL.008)
222  */
223 double __cdecl CRTDLL__CIcos(void)
224 {
225   FPU_DOUBLE(x);
226   if (!isfinite(x)) CRTDLL_errno = EDOM;
227   return cos(x);
228 }
229
230 /*********************************************************************
231  *                  _CIcosh            (CRTDLL.009)
232  */
233 double __cdecl CRTDLL__CIcosh(void)
234 {
235   FPU_DOUBLE(x);
236   if (!isfinite(x)) CRTDLL_errno = EDOM;
237   return cosh(x);
238 }
239
240 /*********************************************************************
241  *                  _CIexp             (CRTDLL.010)
242  */
243 double __cdecl CRTDLL__CIexp(void)
244 {
245   FPU_DOUBLE(x);
246   if (!isfinite(x)) CRTDLL_errno = EDOM;
247   return exp(x);
248 }
249
250 /*********************************************************************
251  *                  _CIfmod            (CRTDLL.011)
252  */
253 double __cdecl CRTDLL__CIfmod(void)
254 {
255   FPU_DOUBLES(x,y);
256   if (!isfinite(x) | !isfinite(y)) CRTDLL_errno = EDOM;
257   return fmod(x,y);
258 }
259
260 /*********************************************************************
261  *                  _CIlog             (CRTDLL.012)
262  */
263 double __cdecl CRTDLL__CIlog(void)
264 {
265   FPU_DOUBLE(x);
266   if (x < 0.0 || !isfinite(x)) CRTDLL_errno = EDOM;
267   if (x == 0.0) CRTDLL_errno = ERANGE;
268   return log(x);
269 }
270
271 /*********************************************************************
272  *                  _CIlog10           (CRTDLL.013)
273  */
274 double __cdecl CRTDLL__CIlog10(void)
275 {
276   FPU_DOUBLE(x);
277   if (x < 0.0 || !isfinite(x)) CRTDLL_errno = EDOM;
278   if (x == 0.0) CRTDLL_errno = ERANGE;
279   return log10(x);
280 }
281
282 /*********************************************************************
283  *                  _CIpow             (CRTDLL.014)
284  */
285 double __cdecl CRTDLL__CIpow(void)
286 {
287   double z;
288   FPU_DOUBLES(x,y);
289   /* FIXME: If x < 0 and y is not integral, set EDOM */
290   z = pow(x,y);
291   if (!isfinite(z)) CRTDLL_errno = EDOM;
292   return z;
293 }
294
295 /*********************************************************************
296  *                  _CIsin             (CRTDLL.015)
297  */
298 double __cdecl CRTDLL__CIsin(void)
299 {
300   FPU_DOUBLE(x);
301   if (!isfinite(x)) CRTDLL_errno = EDOM;
302   return sin(x);
303 }
304
305 /*********************************************************************
306  *                  _CIsinh            (CRTDLL.016)
307  */
308 double __cdecl CRTDLL__CIsinh(void)
309 {
310   FPU_DOUBLE(x);
311   if (!isfinite(x)) CRTDLL_errno = EDOM;
312   return sinh(x);
313 }
314
315 /*********************************************************************
316  *                  _CIsqrt            (CRTDLL.017)
317  */
318 double __cdecl CRTDLL__CIsqrt(void)
319 {
320   FPU_DOUBLE(x);
321   if (x < 0.0) CRTDLL_errno = EDOM;
322   return sqrt(x);
323 }
324
325 /*********************************************************************
326  *                  _CItan             (CRTDLL.018)
327  */
328 double __cdecl CRTDLL__CItan(void)
329 {
330   FPU_DOUBLE(x);
331   if (!isfinite(x)) CRTDLL_errno = EDOM;
332   return tan(x);
333 }
334
335 /*********************************************************************
336  *                  _CItanh            (CRTDLL.019)
337  */
338 double __cdecl CRTDLL__CItanh(void)
339 {
340   FPU_DOUBLE(x);
341   if (!isfinite(x)) CRTDLL_errno = EDOM;
342   return tanh(x);
343 }
344
345 /*********************************************************************
346  *                  _GetMainArgs  (CRTDLL.022)
347  */
348 LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,
349                                 LPSTR *environ,DWORD flag)
350 {
351         char *cmdline;
352         char  **xargv;
353         int     xargc,end,last_arg,afterlastspace;
354         DWORD   version;
355
356         TRACE("(%p,%p,%p,%ld).\n",
357                 argc,argv,environ,flag
358         );
359
360         if (CRTDLL_acmdln_dll != NULL)
361                 HeapFree(GetProcessHeap(), 0, CRTDLL_acmdln_dll);
362
363         CRTDLL_acmdln_dll = cmdline = CRTDLL__strdup( GetCommandLineA() );
364         TRACE("got '%s'\n", cmdline);
365
366         version = GetVersion();
367         CRTDLL_osver_dll       = version >> 16;
368         CRTDLL_winminor_dll    = version & 0xFF;
369         CRTDLL_winmajor_dll    = (version>>8) & 0xFF;
370         CRTDLL_baseversion_dll = version >> 16;
371         CRTDLL_winver_dll      = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8);
372         CRTDLL_baseminor_dll   = (version >> 16) & 0xFF;
373         CRTDLL_basemajor_dll   = (version >> 24) & 0xFF;
374         CRTDLL_osversion_dll   = version & 0xFFFF;
375         CRTDLL_osminor_dll     = version & 0xFF;
376         CRTDLL_osmajor_dll     = (version>>8) & 0xFF;
377
378         /* missing threading init */
379
380         end=0;last_arg=0;xargv=NULL;xargc=0;afterlastspace=0;
381         while (1)
382         {
383             if ((cmdline[end]==' ') || (cmdline[end]=='\0'))
384             {
385                 if (cmdline[end]=='\0')
386                     last_arg=1;
387                 else
388                     cmdline[end]='\0';
389                 /* alloc xargc + NULL entry */
390                         xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv,
391                                              sizeof(char*)*(xargc+1));
392                 if (strlen(cmdline+afterlastspace))
393                 {
394                     xargv[xargc] = CRTDLL__strdup(cmdline+afterlastspace);
395                     xargc++;
396                     if (!last_arg) /* need to seek to the next arg ? */
397                     {
398                         end++;
399                         while (cmdline[end]==' ')
400                             end++;
401         }
402                     afterlastspace=end;
403                 }
404                 else
405                 {
406                     xargv[xargc] = NULL; /* the last entry is NULL */
407                     break;
408                 }
409             }
410             else
411                 end++;
412         }
413         CRTDLL_argc_dll = xargc;
414         *argc           = xargc;
415         CRTDLL_argv_dll = xargv;
416         *argv           = xargv;
417
418         TRACE("found %d arguments\n",
419                 CRTDLL_argc_dll);
420         CRTDLL_environ_dll = *environ = GetEnvironmentStringsA();
421         return environ;
422 }
423
424
425
426 /*********************************************************************
427  *                  _clearfp         (CRTDLL.056)
428  *
429  * Clear and return the previous FP status.
430  */
431 UINT __cdecl CRTDLL__clearfp( VOID )
432 {
433   UINT retVal = CRTDLL__statusfp();
434 #if defined(__GNUC__) && defined(__i386__)
435   __asm__ __volatile__( "fnclex" );
436 #else
437   FIXME(":Not Implemented!\n");
438 #endif
439   return retVal;
440 }
441
442 /*********************************************************************
443  *                  _fpclass         (CRTDLL.105)
444  *
445  * Return the FP classification of d.
446  */
447 INT __cdecl CRTDLL__fpclass(double d)
448 {
449   switch (fpclassify( d ))
450   {
451   case FP_NAN: return _FPCLASS_QNAN;
452   case FP_INFINITE:
453     if (signbit(d))
454       return _FPCLASS_NINF;
455     return _FPCLASS_PINF;
456   case FP_SUBNORMAL:
457     if (signbit(d))
458       return _FPCLASS_ND;
459     return _FPCLASS_PD;
460   case FP_ZERO:
461     if (signbit(d))
462       return _FPCLASS_NZ;
463     return _FPCLASS_PZ;
464   case FP_NORMAL:
465   default:
466     if (signbit(d))
467       return _FPCLASS_NN;
468     return _FPCLASS_PN;
469   }
470 }
471
472
473 /*********************************************************************
474  *                  _initterm     (CRTDLL.135)
475  */
476 DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
477 {
478         _INITTERMFUN    *current;
479
480         TRACE("(%p,%p)\n",start,end);
481         current=start;
482         while (current<end) {
483                 if (*current) (*current)();
484                 current++;
485         }
486         return 0;
487 }
488
489
490 /*******************************************************************
491  *         _global_unwind2  (CRTDLL.129)
492  */
493 void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame )
494 {
495     RtlUnwind( frame, 0, NULL, 0 );
496 }
497
498
499 /*******************************************************************
500  *         _local_unwind2  (CRTDLL.173)
501  */
502 void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr )
503 {
504     TRACE("(%p,%ld)\n",endframe,nr);
505 }
506
507
508 /*******************************************************************
509  *         _setjmp  (CRTDLL.264)
510  */
511 INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf)
512 {
513   FIXME(":(%p): stub\n",jmpbuf);
514   return 0;
515 }
516
517
518 /*********************************************************************
519  *                  _beep          (CRTDLL.045)
520  *
521  * Output a tone using the PC speaker.
522  *
523  * PARAMS
524  * freq [in]     Frequency of the tone
525  *
526  * duration [in] Length of time the tone should sound
527  *
528  * RETURNS
529  * None.
530  */
531 void __cdecl CRTDLL__beep( UINT freq, UINT duration)
532 {
533     TRACE(":Freq %d, Duration %d\n",freq,duration);
534     Beep(freq, duration);
535 }
536
537
538 /*********************************************************************
539  *                  rand          (CRTDLL.446)
540  */
541 INT __cdecl CRTDLL_rand()
542 {
543     return (rand() & CRTDLL_RAND_MAX); 
544 }
545
546
547 /*********************************************************************
548  *                  _rotl          (CRTDLL.259)
549  */
550 UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
551 {
552     shift &= 31;
553     return (x << shift) | (x >> (32-shift));
554 }
555
556
557 /*********************************************************************
558  *                  _lrotl          (CRTDLL.175)
559  */
560 DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
561 {
562     shift &= 31;
563     return (x << shift) | (x >> (32-shift));
564 }
565
566
567 /*********************************************************************
568  *                  _lrotr          (CRTDLL.176)
569  */
570 DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
571 {
572     shift &= 0x1f;
573     return (x >> shift) | (x << (32-shift));
574 }
575
576
577 /*********************************************************************
578  *                  _rotr          (CRTDLL.258)
579  */
580 DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
581 {
582     shift &= 0x1f;
583     return (x >> shift) | (x << (32-shift));
584 }
585
586
587 /*********************************************************************
588  *                  _scalb          (CRTDLL.259)
589  *
590  * Return x*2^y.
591  */
592 double  __cdecl CRTDLL__scalb(double x, LONG y)
593 {
594   /* Note - Can't forward directly as libc expects y as double */
595   double y2 = (double)y;
596   return scalb( x, y2 );
597 }
598
599
600 /*********************************************************************
601  *                  longjmp        (CRTDLL.426)
602  */
603 VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
604 {
605     FIXME("CRTDLL_longjmp semistup, expect crash\n");
606     longjmp(env, val);
607 }
608
609
610 /*********************************************************************
611  *                  setlocale           (CRTDLL.453)
612  */
613 LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale)
614 {
615     LPSTR categorystr;
616
617     switch (category) {
618     case CRTDLL_LC_ALL: categorystr="LC_ALL";break;
619     case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break;
620     case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break;
621     case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break;
622     case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break;
623     case CRTDLL_LC_TIME: categorystr="LC_TIME";break;
624     default: categorystr = "UNKNOWN?";break;
625     }
626     FIXME("(%s,%s),stub!\n",categorystr,locale);
627     return "C";
628 }
629
630
631 /*********************************************************************
632  *                  _isctype           (CRTDLL.138)
633  */
634 INT __cdecl CRTDLL__isctype(INT c,UINT type)
635 {
636   return CRTDLL_ctype[(UINT)c+1] & type;
637 }
638
639
640 /*********************************************************************
641  *                  _fullpath           (CRTDLL.114)
642  */
643 LPSTR __cdecl CRTDLL__fullpath(LPSTR buf, LPCSTR name, INT size)
644 {
645   if (!buf)
646   {
647       size = 256;
648       if(!(buf = CRTDLL_malloc(size))) return NULL;
649   }
650   if (!GetFullPathNameA( name, size, buf, NULL )) return NULL;
651   TRACE("CRTDLL_fullpath got %s\n",buf);
652   return buf;
653 }
654
655
656 /*********************************************************************
657  *                  _splitpath           (CRTDLL.279)
658  */
659 VOID __cdecl CRTDLL__splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension )
660 {
661   /* drive includes :
662      directory includes leading and trailing (forward and backward slashes)
663      filename without dot and slashes
664      extension with leading dot
665      */
666   char * drivechar,*dirchar,*namechar;
667
668   TRACE("CRTDLL__splitpath got %s\n",path);
669
670   drivechar  = strchr(path,':');
671   dirchar    = strrchr(path,'/');
672   namechar   = strrchr(path,'\\');
673   dirchar = max(dirchar,namechar);
674   if (dirchar)
675     namechar   = strrchr(dirchar,'.');
676   else
677     namechar   = strrchr(path,'.');
678
679   if (drive)
680     {
681       *drive = 0x00;
682       if (drivechar)
683       {
684           strncat(drive,path,drivechar-path+1);
685           path = drivechar+1;
686       }
687     }
688   if (directory)
689     {
690       *directory = 0x00;
691       if (dirchar)
692       {
693           strncat(directory,path,dirchar-path+1);
694           path = dirchar+1;
695       }
696     }
697   if (filename)
698     {
699       *filename = 0x00;
700       if (namechar)
701       {
702           strncat(filename,path,namechar-path);
703           if (extension)
704           {
705               *extension = 0x00;
706               strcat(extension,namechar);
707           }
708       }
709     }
710
711   TRACE("CRTDLL__splitpath found %s %s %s %s\n",drive,directory,filename,extension);
712 }
713
714
715 /*********************************************************************
716  *                  _matherr            (CRTDLL.181)
717  *
718  * Default handler for math errors.
719 */
720 INT __cdecl CRTDLL__matherr(struct _exception *e)
721 {
722   /* FIXME: Supposedly this can be user overridden, but
723    * currently it will never be called anyway.
724    */
725   FIXME(":Unhandled math error!\n");
726   return e == NULL ? 0 : 0;
727 }
728
729
730 /*********************************************************************
731  *                  _makepath           (CRTDLL.182)
732  */
733
734 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
735                               LPCSTR directory, LPCSTR filename,
736                               LPCSTR extension )
737 {
738     char ch;
739     TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
740           filename, extension);
741
742     if ( !path )
743         return;
744
745     path[0] = 0;
746     if (drive && drive[0])
747     {
748         path[0] = drive[0];
749         path[1] = ':';
750         path[2] = 0;
751     }
752     if (directory && directory[0])
753     {
754         strcat(path, directory);
755         ch = path[strlen(path)-1];
756         if (ch != '/' && ch != '\\')
757             strcat(path,"\\");
758     }
759     if (filename && filename[0])
760     {
761         strcat(path, filename);
762         if (extension && extension[0])
763         {
764             if ( extension[0] != '.' ) {
765                 strcat(path,".");
766             }
767             strcat(path,extension);
768         }
769     }
770
771     TRACE("CRTDLL__makepath returns %s\n",path);
772 }
773
774
775 /*********************************************************************
776  *                  _errno           (CRTDLL.52)
777  * Return the address of the CRT errno (Not the libc errno).
778  *
779  * BUGS
780  * Not MT safe.
781  */
782 LPINT __cdecl CRTDLL__errno( VOID )
783 {
784   return &CRTDLL_errno;
785 }
786
787
788 /*********************************************************************
789  *                  __doserrno       (CRTDLL.26)
790  * 
791  * Return the address of the DOS errno (holding the last OS error).
792  *
793  * BUGS
794  * Not MT safe.
795  */
796 LPINT __cdecl CRTDLL___doserrno( VOID )
797 {
798   return &CRTDLL_doserrno;
799 }
800
801 /**********************************************************************
802  *                  _statusfp       (CRTDLL.279)
803  *
804  * Return the status of the FP control word.
805  */
806 UINT __cdecl CRTDLL__statusfp( VOID )
807 {
808   UINT retVal = 0;
809 #if defined(__GNUC__) && defined(__i386__)
810   UINT fpword;
811
812   __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
813   if (fpword & 0x1)  retVal |= _SW_INVALID;
814   if (fpword & 0x2)  retVal |= _SW_DENORMAL;
815   if (fpword & 0x4)  retVal |= _SW_ZERODIVIDE;
816   if (fpword & 0x8)  retVal |= _SW_OVERFLOW;
817   if (fpword & 0x10) retVal |= _SW_UNDERFLOW;
818   if (fpword & 0x20) retVal |= _SW_INEXACT;
819 #else
820   FIXME(":Not implemented!\n");
821 #endif
822   return retVal;
823 }
824
825
826 /**********************************************************************
827  *                  _strerror       (CRTDLL.284)
828  *
829  * Return a formatted system error message.
830  *
831  * NOTES
832  * The caller does not own the string returned.
833  */
834 extern int sprintf(char *str, const char *format, ...);
835
836 LPSTR __cdecl CRTDLL__strerror (LPCSTR err)
837 {
838   static char strerrbuff[256];
839   sprintf(strerrbuff,"%s: %s\n",err,CRTDLL_strerror(CRTDLL_errno));
840   return strerrbuff;
841 }
842
843
844 /*********************************************************************
845  *                  perror       (CRTDLL.435)
846  *
847  * Print a formatted system error message to stderr.
848  */
849 VOID __cdecl CRTDLL_perror (LPCSTR err)
850 {
851   char *err_str = CRTDLL_strerror(CRTDLL_errno);
852   CRTDLL_fprintf(CRTDLL_stderr,"%s: %s\n",err,err_str);
853   CRTDLL_free(err_str);
854 }
855  
856
857 /*********************************************************************
858  *                  strerror       (CRTDLL.465)
859  *
860  * Return the text of an error.
861  *
862  * NOTES
863  * The caller does not own the string returned.
864  */
865 extern char *strerror(int errnum); 
866
867 LPSTR __cdecl CRTDLL_strerror (INT err)
868 {
869   return strerror(err);
870 }
871
872
873 /*********************************************************************
874  *                  signal           (CRTDLL.455)
875  */
876 LPVOID __cdecl CRTDLL_signal(INT sig, sig_handler_type ptr)
877 {
878     FIXME("(%d %p):stub.\n", sig, ptr);
879     return (void*)-1;
880 }
881
882
883 /*********************************************************************
884  *                  _sleep           (CRTDLL.267)
885  */
886 VOID __cdecl CRTDLL__sleep(ULONG timeout)
887 {
888   TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
889   Sleep((timeout)?timeout:1);
890 }
891
892
893 /*********************************************************************
894  *                  getenv           (CRTDLL.437)
895  */
896 LPSTR __cdecl CRTDLL_getenv(LPCSTR name)
897 {
898      LPSTR environ = GetEnvironmentStringsA();
899      LPSTR pp,pos = NULL;
900      unsigned int length;
901
902      for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
903        {
904          pos =strchr(pp,'=');
905          if (pos)
906            length = pos -pp;
907          else
908            length = strlen(pp);
909          if (!strncmp(pp,name,length)) break;
910        }
911      if ((pp)&& (pos)) 
912        {
913          pp = pos+1;
914          TRACE("got %s\n",pp);
915        }
916      FreeEnvironmentStringsA( environ );
917      return pp;
918 }
919
920
921 /*********************************************************************
922  *                  isalnum          (CRTDLL.442)
923  */
924 INT __cdecl CRTDLL_isalnum(INT c)
925 {
926   return CRTDLL__isctype( c,CRTDLL_ALPHA | CRTDLL_DIGIT );
927 }
928
929
930 /*********************************************************************
931  *                  isalpha          (CRTDLL.443)
932  */
933 INT __cdecl CRTDLL_isalpha(INT c)
934 {
935   return CRTDLL__isctype( c, CRTDLL_ALPHA );
936 }
937
938
939 /*********************************************************************
940  *                  iscntrl          (CRTDLL.444)
941  */
942 INT __cdecl CRTDLL_iscntrl(INT c)
943 {
944   return CRTDLL__isctype( c, CRTDLL_CONTROL );
945 }
946
947
948 /*********************************************************************
949  *                  isdigit          (CRTDLL.445)
950  */
951 INT __cdecl CRTDLL_isdigit(INT c)
952 {
953   return CRTDLL__isctype( c, CRTDLL_DIGIT );
954 }
955
956
957 /*********************************************************************
958  *                  isgraph          (CRTDLL.446)
959  */
960 INT __cdecl CRTDLL_isgraph(INT c)
961 {
962   return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT  | CRTDLL_PUNCT );
963 }
964
965
966 /*********************************************************************
967  *                  islower          (CRTDLL.447)
968  */
969 INT __cdecl CRTDLL_islower(INT c)
970 {
971   return CRTDLL__isctype( c, CRTDLL_LOWER );
972 }
973
974
975 /*********************************************************************
976  *                  isprint          (CRTDLL.448)
977  */
978 INT __cdecl CRTDLL_isprint(INT c)
979 {
980   return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT |
981                           CRTDLL_BLANK | CRTDLL_PUNCT );
982 }
983
984
985 /*********************************************************************
986  *                  ispunct           (CRTDLL.449)
987  */
988 INT __cdecl CRTDLL_ispunct(INT c)
989 {
990   return CRTDLL__isctype( c, CRTDLL_PUNCT );
991 }
992
993
994 /*********************************************************************
995  *                  isspace           (CRTDLL.450)
996  */
997 INT __cdecl CRTDLL_isspace(INT c)
998 {
999   return CRTDLL__isctype( c, CRTDLL_SPACE );
1000 }
1001
1002
1003 /*********************************************************************
1004  *                  isupper           (CRTDLL.451)
1005  */
1006 INT __cdecl CRTDLL_isupper(INT c)
1007 {
1008   return CRTDLL__isctype( c, CRTDLL_UPPER );
1009 }
1010
1011
1012 /*********************************************************************
1013  *                  isxdigit           (CRTDLL.452)
1014  */
1015 INT __cdecl CRTDLL_isxdigit(INT c)
1016 {
1017   return CRTDLL__isctype( c, CRTDLL_HEX );
1018 }
1019
1020
1021 /*********************************************************************
1022  *                  ldexp            (CRTDLL.454)
1023  */
1024 double __cdecl CRTDLL_ldexp(double x, LONG y)
1025 {
1026   double z;
1027   z = ldexp(x,y);
1028   /* FIXME: MS doesn't return -0 or very large/small (e=298+) numbers */
1029   if (!isfinite(z)) CRTDLL_errno = ERANGE;
1030   return z;
1031 }
1032
1033 /*********************************************************************
1034  *                  _except_handler2  (CRTDLL.78)
1035  */
1036 INT __cdecl CRTDLL__except_handler2 (
1037         PEXCEPTION_RECORD rec,
1038         PEXCEPTION_FRAME frame,
1039         PCONTEXT context,
1040         PEXCEPTION_FRAME  *dispatcher)
1041 {
1042         FIXME ("exception %lx flags=%lx at %p handler=%p %p %p stub\n",
1043         rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
1044         frame->Handler, context, dispatcher);
1045         return ExceptionContinueSearch;
1046 }
1047
1048
1049 /*********************************************************************
1050  *                  __isascii           (CRTDLL.028)
1051  *
1052  */
1053 INT __cdecl CRTDLL___isascii(INT c)
1054 {
1055   return isascii((unsigned)c);
1056 }
1057
1058
1059 /*********************************************************************
1060  *                  __toascii           (CRTDLL.035)
1061  *
1062  */
1063 INT __cdecl CRTDLL___toascii(INT c)
1064 {
1065   return (unsigned)c & 0x7f;
1066 }
1067
1068
1069 /*********************************************************************
1070  *                  iswascii           (CRTDLL.404)
1071  *
1072  */
1073 INT __cdecl CRTDLL_iswascii(LONG c)
1074 {
1075   return ((unsigned)c < 0x80);
1076 }
1077
1078
1079 /*********************************************************************
1080  *                  __iscsym           (CRTDLL.029)
1081  *
1082  * Is a character valid in a C identifier (a-Z,0-9,_).
1083  *
1084  * PARAMS
1085  *   c       [I]: Character to check
1086  *
1087  * RETURNS
1088  * Non zero if c is valid as t a C identifier.
1089  */
1090 INT __cdecl CRTDLL___iscsym(UCHAR c)
1091 {
1092   return (c < 127 && (isalnum(c) || c == '_'));
1093 }
1094
1095
1096 /*********************************************************************
1097  *                  __iscsymf           (CRTDLL.030)
1098  *
1099  * Is a character valid as the first letter in a C identifier (a-Z,_).
1100  *
1101  * PARAMS
1102  *   c [in]  Character to check
1103  *
1104  * RETURNS
1105  *   Non zero if c is valid as the first letter in a C identifier.
1106  */
1107 INT __cdecl CRTDLL___iscsymf(UCHAR c)
1108 {
1109   return (c < 127 && (isalpha(c) || c == '_'));
1110 }
1111
1112
1113 /*********************************************************************
1114  *                  _lfind          (CRTDLL.170)
1115  *
1116  * Perform a linear search of an array for an element.
1117  */
1118 LPVOID __cdecl CRTDLL__lfind(LPCVOID match, LPCVOID start, LPUINT array_size,
1119                              UINT elem_size, comp_func cf)
1120 {
1121   UINT size = *array_size;
1122   if (size)
1123     do
1124     {
1125       if (cf(match, start) == 0)
1126         return (LPVOID)start; /* found */
1127       start += elem_size;
1128     } while (--size);
1129   return NULL;
1130 }
1131
1132
1133 /*********************************************************************
1134  *                  _loaddll        (CRTDLL.171)
1135  *
1136  * Get a handle to a DLL in memory. The DLL is loaded if it is not already.
1137  *
1138  * PARAMS
1139  * dll [in]  Name of DLL to load.
1140  *
1141  * RETURNS
1142  * Success: A handle to the loaded DLL.
1143  *
1144  * Failure: FIXME.
1145  */
1146 INT __cdecl CRTDLL__loaddll(LPSTR dllname)
1147 {
1148   return LoadLibraryA(dllname);
1149 }
1150
1151
1152 /*********************************************************************
1153  *                  _unloaddll        (CRTDLL.313)
1154  *
1155  * Free reference to a DLL handle from loaddll().
1156  *
1157  * PARAMS
1158  *   dll [in] Handle to free.
1159  *
1160  * RETURNS
1161  * Success: 0.
1162  *
1163  * Failure: Error number.
1164  */
1165 INT __cdecl CRTDLL__unloaddll(HANDLE dll)
1166 {
1167   INT err;
1168   if (FreeLibrary(dll))
1169     return 0;
1170   err = GetLastError();
1171   __CRTDLL__set_errno(err);
1172   return err;
1173 }
1174
1175
1176 /*********************************************************************
1177  *                  _lsearch        (CRTDLL.177)
1178  *
1179  * Linear search of an array of elements. Adds the item to the array if
1180  * not found.
1181  *
1182  * PARAMS
1183  *   match [in]      Pointer to element to match
1184  *   start [in]      Pointer to start of search memory
1185  *   array_size [in] Length of search array (element count)
1186  *   elem_size [in]  Size of each element in memory
1187  *   cf [in]         Pointer to comparison function (like qsort()).
1188  *
1189  * RETURNS
1190  *   Pointer to the location where element was found or added.
1191  */
1192 LPVOID __cdecl CRTDLL__lsearch(LPVOID match,LPVOID start, LPUINT array_size,
1193                                UINT elem_size, comp_func cf)
1194 {
1195   UINT size = *array_size;
1196   if (size)
1197     do
1198     {
1199       if (cf(match, start) == 0)
1200         return start; /* found */
1201       start += elem_size;
1202     } while (--size);
1203
1204   /* not found, add to end */
1205   memcpy(start, match, elem_size);
1206   array_size[0]++;
1207   return start;
1208 }
1209
1210
1211 /*********************************************************************
1212  *                  _itow           (CRTDLL.164)
1213  *
1214  * Convert an integer to a wide char string.
1215  */
1216 extern LPSTR  __cdecl _itoa( long , LPSTR , INT); /* ntdll */
1217
1218 WCHAR* __cdecl CRTDLL__itow(INT value,WCHAR* out,INT base)
1219 {
1220   char buff[64]; /* FIXME: Whats the maximum buffer size for INT_MAX? */
1221
1222   _itoa(value, buff, base);
1223   MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1224   return out;
1225 }
1226
1227
1228 /*********************************************************************
1229  *                  _ltow           (CRTDLL.??)
1230  *
1231  * Convert a long to a wide char string.
1232  */
1233 extern LPSTR  __cdecl _ltoa( long , LPSTR , INT); /* ntdll */
1234
1235 WCHAR* __cdecl CRTDLL__ltow(LONG value,WCHAR* out,INT base)
1236 {
1237   char buff[64]; /* FIXME: Whats the maximum buffer size for LONG_MAX? */
1238
1239   _ltoa(value, buff, base);
1240   MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1241   return out;
1242 }
1243
1244
1245 /*********************************************************************
1246  *                  _ultow           (CRTDLL.??)
1247  *
1248  * Convert an unsigned long to a wide char string.
1249  */
1250 extern LPSTR  __cdecl _ultoa( long , LPSTR , INT); /* ntdll */
1251
1252 WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base)
1253 {
1254   char buff[64]; /* FIXME: Whats the maximum buffer size for ULONG_MAX? */
1255
1256   _ultoa(value, buff, base);
1257   MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1258   return out;
1259 }
1260
1261
1262 /*********************************************************************
1263  *                  _toupper           (CRTDLL.489)
1264  */
1265 CHAR __cdecl CRTDLL__toupper(CHAR c)
1266 {
1267   return toupper(c);
1268 }
1269
1270
1271 /*********************************************************************
1272  *                  _tolower           (CRTDLL.490)
1273  */
1274 CHAR __cdecl CRTDLL__tolower(CHAR c)
1275 {
1276   return tolower(c);
1277 }
1278
1279
1280 /* FP functions */
1281
1282 /*********************************************************************
1283  *                  _cabs           (CRTDLL.048)
1284  *
1285  * Return the absolue value of a complex number.
1286  *
1287  * PARAMS
1288  *   c [in] Structure containing real and imaginary parts of complex number.
1289  *
1290  * RETURNS
1291  *   Absolute value of complex number (always a positive real number).
1292  */
1293 double __cdecl CRTDLL__cabs(struct complex c)
1294 {
1295   return sqrt(c.real * c.real + c.imaginary * c.imaginary);
1296 }
1297
1298
1299 /*********************************************************************
1300  *                  _chgsign    (CRTDLL.053)
1301  *
1302  * Change the sign of an IEEE double.
1303  *
1304  * PARAMS
1305  *   d [in] Number to invert.
1306  *
1307  * RETURNS
1308  *   Number with sign inverted.
1309  */
1310 double __cdecl CRTDLL__chgsign(double d)
1311 {
1312   /* FIXME: +-infinity,Nan not tested */
1313   return -d;
1314 }
1315
1316
1317 /*********************************************************************
1318  *                  _control87    (CRTDLL.060)
1319  *
1320  * X86 implementation of _controlfp.
1321  *
1322  */
1323 UINT __cdecl CRTDLL__control87(UINT newVal, UINT mask)
1324 {
1325 #if defined(__GNUC__) && defined(__i386__)
1326    UINT fpword, flags = 0;
1327
1328   /* Get fp control word */
1329   __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
1330
1331   /* Convert into mask constants */
1332   if (fpword & 0x1)  flags |= _EM_INVALID;
1333   if (fpword & 0x2)  flags |= _EM_DENORMAL;
1334   if (fpword & 0x4)  flags |= _EM_ZERODIVIDE;
1335   if (fpword & 0x8)  flags |= _EM_OVERFLOW;
1336   if (fpword & 0x10) flags |= _EM_UNDERFLOW;
1337   if (fpword & 0x20) flags |= _EM_INEXACT;
1338   switch(fpword & 0xC00) {
1339   case 0xC00: flags |= _RC_UP|_RC_DOWN; break;
1340   case 0x800: flags |= _RC_UP; break;
1341   case 0x400: flags |= _RC_DOWN; break;
1342   }
1343   switch(fpword & 0x300) {
1344   case 0x0:   flags |= _PC_24; break;
1345   case 0x200: flags |= _PC_53; break;
1346   case 0x300: flags |= _PC_64; break;
1347   }
1348   if (fpword & 0x1000) flags |= _IC_AFFINE;
1349
1350   /* Mask with parameters */
1351   flags = (flags & ~mask) | (newVal & mask);
1352
1353   /* Convert (masked) value back to fp word */
1354   fpword = 0;
1355   if (flags & _EM_INVALID)    fpword |= 0x1;
1356   if (flags & _EM_DENORMAL)   fpword |= 0x2;
1357   if (flags & _EM_ZERODIVIDE) fpword |= 0x4;
1358   if (flags & _EM_OVERFLOW)   fpword |= 0x8;
1359   if (flags & _EM_UNDERFLOW)  fpword |= 0x10;
1360   if (flags & _EM_INEXACT)    fpword |= 0x20;
1361   switch(flags & (_RC_UP | _RC_DOWN)) {
1362   case _RC_UP|_RC_DOWN: fpword |= 0xC00; break;
1363   case _RC_UP:          fpword |= 0x800; break;
1364   case _RC_DOWN:        fpword |= 0x400; break;
1365   }
1366   switch (flags & (_PC_24 | _PC_53)) {
1367   case _PC_64: fpword |= 0x300; break;
1368   case _PC_53: fpword |= 0x200; break;
1369   case _PC_24: fpword |= 0x0; break;
1370   }
1371   if (!(flags & _IC_AFFINE)) fpword |= 0x1000;
1372
1373   /* Put fp control word */
1374   __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1375   return fpword;
1376 #else
1377   return  CRTDLL__controlfp( newVal, mask );
1378 #endif
1379 }
1380
1381
1382 /*********************************************************************
1383  *                  _controlfp    (CRTDLL.061)
1384  *
1385  * Set the state of the floating point unit.
1386  */
1387 UINT __cdecl CRTDLL__controlfp( UINT newVal, UINT mask)
1388 {
1389 #if defined(__GNUC__) && defined(__i386__)
1390   return CRTDLL__control87( newVal, mask );
1391 #else
1392   FIXME(":Not Implemented!\n");
1393   return 0;
1394 #endif
1395 }
1396
1397
1398 /*********************************************************************
1399  *                  _copysign           (CRTDLL.062)
1400  *
1401  * Return the number x with the sign of y.
1402  */
1403 double __cdecl CRTDLL__copysign(double x, double y)
1404 {
1405   /* FIXME: Behaviour for Nan/Inf etc? */
1406   if (y < 0.0)
1407     return x < 0.0 ? x : -x;
1408
1409   return x < 0.0 ? -x : x;
1410 }
1411
1412
1413 /*********************************************************************
1414  *                  _finite           (CRTDLL.101)
1415  *
1416  * Determine if an IEEE double is finite (i.e. not +/- Infinity).
1417  *
1418  * PARAMS
1419  *   d [in]  Number to check.
1420  *
1421  * RETURNS
1422  *   Non zero if number is finite.
1423  */
1424 INT __cdecl  CRTDLL__finite(double d)
1425 {
1426   return (isfinite(d)?1:0); /* See comment for CRTDLL__isnan() */
1427 }
1428
1429
1430 /*********************************************************************
1431  *                  _fpreset           (CRTDLL.107)
1432  *
1433  * Reset the state of the floating point processor.
1434  */
1435 VOID __cdecl CRTDLL__fpreset(void)
1436 {
1437 #if defined(__GNUC__) && defined(__i386__)
1438   __asm__ __volatile__( "fninit" );
1439 #else
1440   FIXME(":Not Implemented!\n");
1441 #endif
1442 }
1443
1444
1445 /*********************************************************************
1446  *                  _isnan           (CRTDLL.164)
1447  *
1448  * Determine if an IEEE double is unrepresentable (NaN).
1449  *
1450  * PARAMS
1451  *   d [in]  Number to check.
1452  *
1453  * RETURNS
1454  *   Non zero if number is NaN.
1455  */
1456 INT __cdecl  CRTDLL__isnan(double d)
1457 {
1458   /* some implementations return -1 for true(glibc), crtdll returns 1.
1459    * Do the same, as the result may be used in calculations.
1460    */
1461   return isnan(d)?1:0;
1462 }
1463
1464
1465 /*********************************************************************
1466  *                  _purecall           (CRTDLL.249)
1467  *
1468  * Abort program after pure virtual function call.
1469  */
1470 VOID __cdecl CRTDLL__purecall(VOID)
1471 {
1472   CRTDLL__amsg_exit( 6025 );
1473 }
1474
1475
1476 /*********************************************************************
1477  *                  _div               (CRTDLL.@)
1478  *
1479  * Return the quotient and remainder of long integer division.
1480  */
1481 #ifdef __i386__
1482 /* Windows binary compatible - returns the struct in eax/edx. */
1483 LONGLONG __cdecl CRTDLL_div(int x, int y)
1484 {
1485   LONGLONG retVal;
1486   div_t dt = div(x,y);
1487   retVal = ((LONGLONG)dt.rem << 32) | dt.quot;
1488   return retVal;
1489 }
1490 #else
1491 /* Non-x86 cant run win32 apps so dont need binary compatibility */
1492 div_t __cdecl CRTDLL_div(int x, int y)
1493 {
1494   return div(x,y);
1495 }
1496 #endif /* __i386__ */
1497
1498
1499 /*********************************************************************
1500  *                  _ldiv               (CRTDLL.249)
1501  *
1502  * Return the quotient and remainder of long integer division.
1503  */
1504 #ifdef __i386__
1505 /* Windows binary compatible - returns the struct in eax/edx. */
1506 LONGLONG __cdecl CRTDLL_ldiv(long x, long y)
1507 {
1508   LONGLONG retVal;
1509   ldiv_t ldt = ldiv(x,y);
1510   retVal = ((LONGLONG)ldt.rem << 32) | ldt.quot;
1511   return retVal;
1512 }
1513 #else
1514 /* Non-x86 cant run win32 apps so dont need binary compatibility */
1515 ldiv_t __cdecl CRTDLL_ldiv(long x, long y)
1516 {
1517   return ldiv(x,y);
1518 }
1519 #endif /* __i386__ */
1520