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