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