4 * Implements C run-time functionality as known from UNIX.
6 * Copyright 1996,1998 Marcus Meissner
7 * Copyright 1996 Jukka Iivonen
8 * Copyright 1997,2000 Uwe Bonnes
9 * Copyright 2000 Jon Griffiths
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
17 - probably not thread safe
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
30 #define __USE_ISOC9X 1
31 #define __USE_ISOC99 1
40 #ifndef finite /* Could be macro */
42 #define finite(x) isfinite(x)
44 #define finite(x) (!isnan(x)) /* At least catch some cases */
53 DEFAULT_DEBUG_CHANNEL(crtdll);
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;
76 INT CRTDLL__mb_cur_max_dll = 1;
77 const INT CRTDLL__sys_nerr = 43;
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
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
108 /* Internal: Current ctype table for locale */
109 WORD __CRTDLL_current_ctype[257];
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.
116 WORD* CRTDLL_pctype_dll = __CRTDLL_current_ctype + 1;
119 /*********************************************************************
120 * CRTDLL_MainInit (CRTDLL.init)
122 BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
124 TRACE("(0x%08x,%ld,%p)\n",hinstDLL,fdwReason,lpvReserved);
126 if (fdwReason == DLL_PROCESS_ATTACH) {
128 __CRTDLL_init_console();
129 CRTDLL_setlocale( CRTDLL_LC_ALL, "C" );
130 CRTDLL_HUGE_dll = HUGE_VAL;
132 else if (fdwReason == DLL_PROCESS_DETACH)
135 __CRTDLL_free_console();
142 /* INTERNAL: Set the crt and dos errno's from the OS error given. */
143 void __CRTDLL__set_errno(ULONG err)
145 /* FIXME: not MT safe */
146 CRTDLL_doserrno = err;
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);
194 /* Remaining cases map to EINVAL */
195 /* FIXME: may be missing some errors above */
196 CRTDLL_errno = EINVAL;
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) : )
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")
213 /*********************************************************************
214 * _CIacos (CRTDLL.004)
216 double __cdecl CRTDLL__CIacos(void)
219 if (x < -1.0 || x > 1.0 || !finite(x)) CRTDLL_errno = EDOM;
224 /*********************************************************************
225 * _CIasin (CRTDLL.005)
227 double __cdecl CRTDLL__CIasin(void)
230 if (x < -1.0 || x > 1.0 || !finite(x)) CRTDLL_errno = EDOM;
235 /*********************************************************************
236 * _CIatan (CRTDLL.006)
238 double __cdecl CRTDLL__CIatan(void)
241 if (!finite(x)) CRTDLL_errno = EDOM;
245 /*********************************************************************
246 * _CIatan2 (CRTDLL.007)
248 double __cdecl CRTDLL__CIatan2(void)
251 if (!finite(x)) CRTDLL_errno = EDOM;
256 /*********************************************************************
257 * _CIcos (CRTDLL.008)
259 double __cdecl CRTDLL__CIcos(void)
262 if (!finite(x)) CRTDLL_errno = EDOM;
266 /*********************************************************************
267 * _CIcosh (CRTDLL.009)
269 double __cdecl CRTDLL__CIcosh(void)
272 if (!finite(x)) CRTDLL_errno = EDOM;
276 /*********************************************************************
277 * _CIexp (CRTDLL.010)
279 double __cdecl CRTDLL__CIexp(void)
282 if (!finite(x)) CRTDLL_errno = EDOM;
286 /*********************************************************************
287 * _CIfmod (CRTDLL.011)
289 double __cdecl CRTDLL__CIfmod(void)
292 if (!finite(x) || !finite(y)) CRTDLL_errno = EDOM;
296 /*********************************************************************
297 * _CIlog (CRTDLL.012)
299 double __cdecl CRTDLL__CIlog(void)
302 if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
303 if (x == 0.0) CRTDLL_errno = ERANGE;
307 /*********************************************************************
308 * _CIlog10 (CRTDLL.013)
310 double __cdecl CRTDLL__CIlog10(void)
313 if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
314 if (x == 0.0) CRTDLL_errno = ERANGE;
318 /*********************************************************************
319 * _CIpow (CRTDLL.014)
321 double __cdecl CRTDLL__CIpow(void)
325 /* FIXME: If x < 0 and y is not integral, set EDOM */
327 if (!finite(z)) CRTDLL_errno = EDOM;
331 /*********************************************************************
332 * _CIsin (CRTDLL.015)
334 double __cdecl CRTDLL__CIsin(void)
337 if (!finite(x)) CRTDLL_errno = EDOM;
341 /*********************************************************************
342 * _CIsinh (CRTDLL.016)
344 double __cdecl CRTDLL__CIsinh(void)
347 if (!finite(x)) CRTDLL_errno = EDOM;
351 /*********************************************************************
352 * _CIsqrt (CRTDLL.017)
354 double __cdecl CRTDLL__CIsqrt(void)
357 if (x < 0.0 || !finite(x)) CRTDLL_errno = EDOM;
361 /*********************************************************************
362 * _CItan (CRTDLL.018)
364 double __cdecl CRTDLL__CItan(void)
367 if (!finite(x)) CRTDLL_errno = EDOM;
371 /*********************************************************************
372 * _CItanh (CRTDLL.019)
374 double __cdecl CRTDLL__CItanh(void)
377 if (!finite(x)) CRTDLL_errno = EDOM;
381 /*********************************************************************
382 * _GetMainArgs (CRTDLL.022)
384 LPSTR * __cdecl CRTDLL__GetMainArgs(LPDWORD argc,LPSTR **argv,
385 LPSTR *environ,DWORD flag)
389 int xargc,end,last_arg,afterlastspace;
392 TRACE("(%p,%p,%p,%ld).\n",
393 argc,argv,environ,flag
396 if (CRTDLL_acmdln_dll != NULL)
397 HeapFree(GetProcessHeap(), 0, CRTDLL_acmdln_dll);
399 CRTDLL_acmdln_dll = cmdline = CRTDLL__strdup( GetCommandLineA() );
400 TRACE("got '%s'\n", cmdline);
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;
414 /* missing threading init */
416 end=0;last_arg=0;xargv=NULL;xargc=0;afterlastspace=0;
419 if ((cmdline[end]==' ') || (cmdline[end]=='\0'))
421 if (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))
430 xargv[xargc] = CRTDLL__strdup(cmdline+afterlastspace);
432 if (!last_arg) /* need to seek to the next arg ? */
435 while (cmdline[end]==' ')
442 xargv[xargc] = NULL; /* the last entry is NULL */
449 CRTDLL_argc_dll = xargc;
451 CRTDLL_argv_dll = xargv;
454 TRACE("found %d arguments\n",
456 CRTDLL_environ_dll = *environ = GetEnvironmentStringsA();
462 /*********************************************************************
463 * _clearfp (CRTDLL.056)
465 * Clear and return the previous FP status.
467 UINT __cdecl CRTDLL__clearfp( VOID )
469 UINT retVal = CRTDLL__statusfp();
470 #if defined(__GNUC__) && defined(__i386__)
471 __asm__ __volatile__( "fnclex" );
473 FIXME(":Not Implemented!\n");
478 /*********************************************************************
479 * _fpclass (CRTDLL.105)
481 * Return the FP classification of d.
483 INT __cdecl CRTDLL__fpclass(double d)
485 #if defined(HAVE_FPCLASS) || defined(fpclass)
486 switch (fpclass( d ))
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;
499 #elif defined (fpclassify)
500 switch (fpclassify( d ))
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;
507 return signbit(d) ? _FPCLASS_NN : _FPCLASS_PN;
510 return _FPCLASS_QNAN;
511 return d == 0.0 ? _FPCLASS_PZ : (d < 0 ? _FPCLASS_NN : _FPCLASS_PN);
516 /*********************************************************************
517 * _initterm (CRTDLL.135)
519 DWORD __cdecl CRTDLL__initterm(_INITTERMFUN *start,_INITTERMFUN *end)
521 _INITTERMFUN *current;
523 TRACE("(%p,%p)\n",start,end);
525 while (current<end) {
526 if (*current) (*current)();
533 /*******************************************************************
534 * _global_unwind2 (CRTDLL.129)
536 void __cdecl CRTDLL__global_unwind2( PEXCEPTION_FRAME frame )
538 RtlUnwind( frame, 0, NULL, 0 );
542 /*******************************************************************
543 * _local_unwind2 (CRTDLL.173)
545 void __cdecl CRTDLL__local_unwind2( PEXCEPTION_FRAME endframe, DWORD nr )
547 TRACE("(%p,%ld)\n",endframe,nr);
551 /*******************************************************************
552 * _setjmp (CRTDLL.264)
554 INT __cdecl CRTDLL__setjmp(LPDWORD *jmpbuf)
556 FIXME(":(%p): stub\n",jmpbuf);
561 /*********************************************************************
564 * Output a tone using the PC speaker.
567 * freq [in] Frequency of the tone
569 * duration [in] Length of time the tone should sound
574 void __cdecl CRTDLL__beep( UINT freq, UINT duration)
576 TRACE(":Freq %d, Duration %d\n",freq,duration);
577 Beep(freq, duration);
581 /*********************************************************************
584 INT __cdecl CRTDLL_rand()
586 return (rand() & CRTDLL_RAND_MAX);
590 /*********************************************************************
593 UINT __cdecl CRTDLL__rotl(UINT x,INT shift)
596 return (x << shift) | (x >> (32-shift));
600 /*********************************************************************
603 double __cdecl CRTDLL__logb(double x)
605 if (!finite(x)) CRTDLL_errno = EDOM;
610 /*********************************************************************
611 * _lrotl (CRTDLL.175)
613 DWORD __cdecl CRTDLL__lrotl(DWORD x,INT shift)
616 return (x << shift) | (x >> (32-shift));
620 /*********************************************************************
621 * _lrotr (CRTDLL.176)
623 DWORD __cdecl CRTDLL__lrotr(DWORD x,INT shift)
626 return (x >> shift) | (x << (32-shift));
630 /*********************************************************************
633 DWORD __cdecl CRTDLL__rotr(UINT x,INT shift)
636 return (x >> shift) | (x << (32-shift));
640 /*********************************************************************
641 * _scalb (CRTDLL.259)
645 double __cdecl CRTDLL__scalb(double x, LONG y)
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 );
654 /*********************************************************************
655 * longjmp (CRTDLL.426)
657 VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val)
659 FIXME("CRTDLL_longjmp semistup, expect crash\n");
664 /*********************************************************************
665 * _isctype (CRTDLL.138)
667 INT __cdecl CRTDLL__isctype(INT c, UINT type)
669 if (c >= -1 && c <= 255)
670 return CRTDLL_pctype_dll[c] & type;
672 if (CRTDLL__mb_cur_max_dll != 1 && c > 0)
674 /* FIXME: Is there a faster way to do this? */
676 char convert[3], *pconv = convert;
678 if (CRTDLL_pctype_dll[(UINT)c >> 8] & CRTDLL_LEADBYTE)
679 *pconv++ = (UINT)c >> 8;
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;
691 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
692 static void fln_fix(char *path)
694 int dir_flag = 0, root_flag = 0;
698 if (NULL == (r = strrchr(path, ':')))
703 /* Ignore leading slashes */
713 p = r; /* Change "\\" to "\" */
714 while (NULL != (p = strchr(p, '\\')))
720 while ('.' == *r) /* Scrunch leading ".\" */
724 /* Ignore leading ".." */
725 for (p = (r += 2); *p && (*p != '\\'); ++p)
730 for (p = r + 1 ;*p && (*p != '\\'); ++p)
733 strcpy(r, p + ((*p) ? 1 : 0));
736 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
739 path[strlen(path)-1] = '\0';
744 /* Look for "\." in path */
746 while (NULL != (p = strstr(s, "\\.")))
750 /* Execute this section if ".." found */
752 while (q > r) /* Backup one level */
765 strcpy(q + ((*q == '\\') ? 1 : 0),
766 p + 3 + ((*(p + 3)) ? 1 : 0));
773 /* Execute this section if "." found */
775 for ( ;*q && (*q != '\\'); ++q)
781 if (root_flag) /* Embedded ".." could have bubbled up to root */
783 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
794 /*********************************************************************
797 * Convert a partial path into a complete, normalised path.
799 LPSTR __cdecl CRTDLL__fullpath(LPSTR absPath, LPCSTR relPath, INT size)
801 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
807 if (!relPath || !*relPath)
808 return CRTDLL__getcwd(absPath, size);
812 CRTDLL_errno = ERANGE;
816 TRACE(":resolving relative path '%s'\n",relPath);
818 CRTDLL__splitpath(relPath, drive, dir, file, ext);
820 /* Get Directory and drive into 'res' */
821 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
823 /* Relative or no directory given */
824 CRTDLL__getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
829 res[0] = drive[0]; /* If given a drive, preserve the letter case */
843 if (len >= MAX_PATH || len >= size)
844 return NULL; /* FIXME: errno? */
847 return CRTDLL__strdup(res);
853 /*********************************************************************
854 * _splitpath (CRTDLL.279)
856 * Split a path string into components.
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 ""
865 VOID __cdecl CRTDLL__splitpath(LPCSTR inpath, LPSTR drv, LPSTR dir,
866 LPSTR fname, LPSTR ext )
868 /* Modified PD code from 'snippets' collection. */
870 char pathbuff[MAX_PATH],*path=pathbuff;
872 TRACE(":splitting path '%s'\n",path);
873 strcpy(pathbuff, inpath);
875 /* convert slashes to backslashes for searching */
876 for (ptr = (char*)path; *ptr; ++ptr)
880 /* look for drive spec */
881 if ('\0' != (ptr = strchr(path, ':')))
886 strncpy(drv, path, ptr - path);
887 drv[ptr - path] = '\0';
894 /* find rightmost backslash or leftmost colon */
895 if (NULL == (ptr = strrchr(path, '\\')))
896 ptr = (strchr(path, ':'));
900 ptr = (char *)path; /* no path */
906 ++ptr; /* skip the delimiter */
916 if (NULL == (p = strrchr(ptr, '.')))
933 /* Fix pathological case - Win returns ':' as part of the
934 * directory when no drive letter is given.
936 if (drv && drv[0] == ':')
943 strcat(pathbuff,dir);
944 strcpy(dir,pathbuff);
950 /*********************************************************************
951 * _matherr (CRTDLL.181)
953 * Default handler for math errors.
955 INT __cdecl CRTDLL__matherr(struct _exception *e)
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.
961 FIXME(":Unhandled math error!\n");
962 return e == NULL ? 0 : 0;
966 /*********************************************************************
967 * _makepath (CRTDLL.182)
969 VOID __cdecl CRTDLL__makepath(LPSTR path, LPCSTR drive,
970 LPCSTR directory, LPCSTR filename,
974 TRACE("CRTDLL__makepath got %s %s %s %s\n", drive, directory,
975 filename, extension);
981 if (drive && drive[0])
987 if (directory && directory[0])
989 strcat(path, directory);
990 ch = path[strlen(path)-1];
991 if (ch != '/' && ch != '\\')
994 if (filename && filename[0])
996 strcat(path, filename);
997 if (extension && extension[0])
999 if ( extension[0] != '.' ) {
1002 strcat(path,extension);
1006 TRACE("CRTDLL__makepath returns %s\n",path);
1010 /*********************************************************************
1011 * _errno (CRTDLL.52)
1012 * Return the address of the CRT errno (Not the libc errno).
1017 LPINT __cdecl CRTDLL__errno( VOID )
1019 return &CRTDLL_errno;
1023 /*********************************************************************
1024 * __doserrno (CRTDLL.26)
1026 * Return the address of the DOS errno (holding the last OS error).
1031 LPINT __cdecl CRTDLL___doserrno( VOID )
1033 return &CRTDLL_doserrno;
1036 /**********************************************************************
1037 * _statusfp (CRTDLL.279)
1039 * Return the status of the FP control word.
1041 UINT __cdecl CRTDLL__statusfp( VOID )
1044 #if defined(__GNUC__) && defined(__i386__)
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;
1055 FIXME(":Not implemented!\n");
1061 /**********************************************************************
1062 * _strerror (CRTDLL.284)
1064 * Return a formatted system error message.
1067 * The caller does not own the string returned.
1069 extern int sprintf(char *str, const char *format, ...);
1071 LPSTR __cdecl CRTDLL__strerror (LPCSTR err)
1073 static char strerrbuff[256];
1074 sprintf(strerrbuff,"%s: %s\n",err,CRTDLL_strerror(CRTDLL_errno));
1079 /*********************************************************************
1080 * perror (CRTDLL.435)
1082 * Print a formatted system error message to stderr.
1084 VOID __cdecl CRTDLL_perror (LPCSTR err)
1086 char *err_str = CRTDLL_strerror(CRTDLL_errno);
1087 CRTDLL_fprintf(CRTDLL_stderr,"%s: %s\n",err,err_str);
1088 CRTDLL_free(err_str);
1092 /*********************************************************************
1093 * strerror (CRTDLL.465)
1095 * Return the text of an error.
1098 * The caller does not own the string returned.
1100 extern char *strerror(int errnum);
1102 LPSTR __cdecl CRTDLL_strerror (INT err)
1104 return strerror(err);
1108 /*********************************************************************
1109 * signal (CRTDLL.455)
1111 LPVOID __cdecl CRTDLL_signal(INT sig, sig_handler_type ptr)
1113 FIXME("(%d %p):stub.\n", sig, ptr);
1118 /*********************************************************************
1119 * _sleep (CRTDLL.267)
1121 VOID __cdecl CRTDLL__sleep(ULONG timeout)
1123 TRACE("CRTDLL__sleep for %ld milliseconds\n",timeout);
1124 Sleep((timeout)?timeout:1);
1128 /*********************************************************************
1129 * getenv (CRTDLL.437)
1131 LPSTR __cdecl CRTDLL_getenv(LPCSTR name)
1133 LPSTR environ = GetEnvironmentStringsA();
1134 LPSTR pp,pos = NULL;
1135 unsigned int length;
1137 for (pp = environ; (*pp); pp = pp + strlen(pp) +1)
1139 pos =strchr(pp,'=');
1143 length = strlen(pp);
1144 if (!strncmp(pp,name,length)) break;
1149 TRACE("got %s\n",pp);
1151 FreeEnvironmentStringsA( environ );
1156 /*********************************************************************
1157 * isalnum (CRTDLL.442)
1159 INT __cdecl CRTDLL_isalnum(INT c)
1161 return CRTDLL__isctype( c,CRTDLL_ALPHA | CRTDLL_DIGIT );
1165 /*********************************************************************
1166 * isalpha (CRTDLL.443)
1168 INT __cdecl CRTDLL_isalpha(INT c)
1170 return CRTDLL__isctype( c, CRTDLL_ALPHA );
1174 /*********************************************************************
1175 * iscntrl (CRTDLL.444)
1177 INT __cdecl CRTDLL_iscntrl(INT c)
1179 return CRTDLL__isctype( c, CRTDLL_CONTROL );
1183 /*********************************************************************
1184 * isdigit (CRTDLL.445)
1186 INT __cdecl CRTDLL_isdigit(INT c)
1188 return CRTDLL__isctype( c, CRTDLL_DIGIT );
1192 /*********************************************************************
1193 * isgraph (CRTDLL.446)
1195 INT __cdecl CRTDLL_isgraph(INT c)
1197 return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT | CRTDLL_PUNCT );
1201 /*********************************************************************
1202 * isleadbyte (CRTDLL.447)
1204 INT __cdecl CRTDLL_isleadbyte(UCHAR c)
1206 return CRTDLL__isctype( c, CRTDLL_LEADBYTE );
1210 /*********************************************************************
1211 * islower (CRTDLL.447)
1213 INT __cdecl CRTDLL_islower(INT c)
1215 return CRTDLL__isctype( c, CRTDLL_LOWER );
1219 /*********************************************************************
1220 * isprint (CRTDLL.448)
1222 INT __cdecl CRTDLL_isprint(INT c)
1224 return CRTDLL__isctype( c, CRTDLL_ALPHA | CRTDLL_DIGIT |
1225 CRTDLL_BLANK | CRTDLL_PUNCT );
1229 /*********************************************************************
1230 * ispunct (CRTDLL.449)
1232 INT __cdecl CRTDLL_ispunct(INT c)
1234 return CRTDLL__isctype( c, CRTDLL_PUNCT );
1238 /*********************************************************************
1239 * isspace (CRTDLL.450)
1241 INT __cdecl CRTDLL_isspace(INT c)
1243 return CRTDLL__isctype( c, CRTDLL_SPACE );
1247 /*********************************************************************
1248 * isupper (CRTDLL.451)
1250 INT __cdecl CRTDLL_isupper(INT c)
1252 return CRTDLL__isctype( c, CRTDLL_UPPER );
1256 /*********************************************************************
1257 * isxdigit (CRTDLL.452)
1259 INT __cdecl CRTDLL_isxdigit(INT c)
1261 return CRTDLL__isctype( c, CRTDLL_HEX );
1265 /*********************************************************************
1266 * ldexp (CRTDLL.454)
1268 double __cdecl CRTDLL_ldexp(double x, LONG y)
1270 double z = ldexp(x,y);
1273 CRTDLL_errno = ERANGE;
1274 else if (z == 0 && signbit(z))
1275 z = 0.0; /* Convert -0 -> +0 */
1279 /*********************************************************************
1280 * _except_handler2 (CRTDLL.78)
1282 INT __cdecl CRTDLL__except_handler2 (
1283 PEXCEPTION_RECORD rec,
1284 PEXCEPTION_FRAME frame,
1286 PEXCEPTION_FRAME *dispatcher)
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;
1295 /*********************************************************************
1296 * __isascii (CRTDLL.028)
1299 INT __cdecl CRTDLL___isascii(INT c)
1301 return isascii((unsigned)c);
1305 /*********************************************************************
1306 * __toascii (CRTDLL.035)
1309 INT __cdecl CRTDLL___toascii(INT c)
1311 return (unsigned)c & 0x7f;
1315 /*********************************************************************
1316 * iswascii (CRTDLL.404)
1319 INT __cdecl CRTDLL_iswascii(LONG c)
1321 return ((unsigned)c < 0x80);
1325 /*********************************************************************
1326 * __iscsym (CRTDLL.029)
1328 * Is a character valid in a C identifier (a-Z,0-9,_).
1331 * c [I]: Character to check
1334 * Non zero if c is valid as t a C identifier.
1336 INT __cdecl CRTDLL___iscsym(UCHAR c)
1338 return (c < 127 && (isalnum(c) || c == '_'));
1342 /*********************************************************************
1343 * __iscsymf (CRTDLL.030)
1345 * Is a character valid as the first letter in a C identifier (a-Z,_).
1348 * c [in] Character to check
1351 * Non zero if c is valid as the first letter in a C identifier.
1353 INT __cdecl CRTDLL___iscsymf(UCHAR c)
1355 return (c < 127 && (isalpha(c) || c == '_'));
1359 /*********************************************************************
1360 * _lfind (CRTDLL.170)
1362 * Perform a linear search of an array for an element.
1364 LPVOID __cdecl CRTDLL__lfind(LPCVOID match, LPCVOID start, LPUINT array_size,
1365 UINT elem_size, comp_func cf)
1367 UINT size = *array_size;
1371 if (cf(match, start) == 0)
1372 return (LPVOID)start; /* found */
1379 /*********************************************************************
1380 * _loaddll (CRTDLL.171)
1382 * Get a handle to a DLL in memory. The DLL is loaded if it is not already.
1385 * dll [in] Name of DLL to load.
1388 * Success: A handle to the loaded DLL.
1392 INT __cdecl CRTDLL__loaddll(LPSTR dllname)
1394 return LoadLibraryA(dllname);
1398 /*********************************************************************
1399 * _unloaddll (CRTDLL.313)
1401 * Free reference to a DLL handle from loaddll().
1404 * dll [in] Handle to free.
1409 * Failure: Error number.
1411 INT __cdecl CRTDLL__unloaddll(HANDLE dll)
1414 if (FreeLibrary(dll))
1416 err = GetLastError();
1417 __CRTDLL__set_errno(err);
1422 /*********************************************************************
1423 * _lsearch (CRTDLL.177)
1425 * Linear search of an array of elements. Adds the item to the array if
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()).
1436 * Pointer to the location where element was found or added.
1438 LPVOID __cdecl CRTDLL__lsearch(LPVOID match,LPVOID start, LPUINT array_size,
1439 UINT elem_size, comp_func cf)
1441 UINT size = *array_size;
1445 if (cf(match, start) == 0)
1446 return start; /* found */
1450 /* not found, add to end */
1451 memcpy(start, match, elem_size);
1457 /*********************************************************************
1458 * _itow (CRTDLL.164)
1460 * Convert an integer to a wide char string.
1463 extern LPSTR __cdecl _itoa( long , LPSTR , INT); /* ntdll */
1465 /********************************************************************/
1467 WCHAR* __cdecl CRTDLL__itow(INT value,WCHAR* out,INT base)
1469 char buff[64]; /* FIXME: Whats the maximum buffer size for INT_MAX? */
1471 _itoa(value, buff, base);
1472 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1477 /*********************************************************************
1480 * Convert a long to a wide char string.
1483 extern LPSTR __cdecl _ltoa( long , LPSTR , INT); /* ntdll */
1485 /********************************************************************/
1487 WCHAR* __cdecl CRTDLL__ltow(LONG value,WCHAR* out,INT base)
1489 char buff[64]; /* FIXME: Whats the maximum buffer size for LONG_MAX? */
1491 _ltoa(value, buff, base);
1492 MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1497 /*********************************************************************
1498 * _ultow (CRTDLL.??)
1500 * Convert an unsigned long to a wide char string.
1503 extern LPSTR __cdecl _ultoa( long , LPSTR , INT); /* ntdll */
1505 /********************************************************************/
1507 WCHAR* __cdecl CRTDLL__ultow(ULONG value,WCHAR* out,INT base)
1509 char buff[64]; /* FIXME: Whats the maximum buffer size for ULONG_MAX? */
1511 _ultoa(value, buff, base);
1512 MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buff, -1, out, 64);
1517 /*********************************************************************
1518 * _toupper (CRTDLL.489)
1520 CHAR __cdecl CRTDLL__toupper(CHAR c)
1526 /*********************************************************************
1527 * _tolower (CRTDLL.490)
1529 CHAR __cdecl CRTDLL__tolower(CHAR c)
1537 /*********************************************************************
1538 * _cabs (CRTDLL.048)
1540 * Return the absolue value of a complex number.
1543 * c [in] Structure containing real and imaginary parts of complex number.
1546 * Absolute value of complex number (always a positive real number).
1548 double __cdecl CRTDLL__cabs(struct complex c)
1550 return sqrt(c.real * c.real + c.imaginary * c.imaginary);
1554 /*********************************************************************
1555 * _chgsign (CRTDLL.053)
1557 * Change the sign of an IEEE double.
1560 * d [in] Number to invert.
1563 * Number with sign inverted.
1565 double __cdecl CRTDLL__chgsign(double d)
1567 /* FIXME: +-infinity,Nan not tested */
1572 /*********************************************************************
1573 * _control87 (CRTDLL.060)
1575 * X86 implementation of _controlfp.
1578 UINT __cdecl CRTDLL__control87(UINT newVal, UINT mask)
1580 #if defined(__GNUC__) && defined(__i386__)
1581 UINT fpword, flags = 0;
1583 /* Get fp control word */
1584 __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : );
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;
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;
1603 if (fpword & 0x1000) flags |= _IC_AFFINE;
1605 /* Mask with parameters */
1606 flags = (flags & ~mask) | (newVal & mask);
1608 /* Convert (masked) value back to fp word */
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;
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;
1626 if (!(flags & _IC_AFFINE)) fpword |= 0x1000;
1628 /* Put fp control word */
1629 __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
1632 return CRTDLL__controlfp( newVal, mask );
1637 /*********************************************************************
1638 * _controlfp (CRTDLL.061)
1640 * Set the state of the floating point unit.
1642 UINT __cdecl CRTDLL__controlfp( UINT newVal, UINT mask)
1644 #if defined(__GNUC__) && defined(__i386__)
1645 return CRTDLL__control87( newVal, mask );
1647 FIXME(":Not Implemented!\n");
1653 /*********************************************************************
1654 * _copysign (CRTDLL.062)
1656 * Return the number x with the sign of y.
1658 double __cdecl CRTDLL__copysign(double x, double y)
1660 /* FIXME: Behaviour for Nan/Inf etc? */
1662 return x < 0.0 ? x : -x;
1664 return x < 0.0 ? -x : x;
1668 /*********************************************************************
1669 * _finite (CRTDLL.101)
1671 * Determine if an IEEE double is finite (i.e. not +/- Infinity).
1674 * d [in] Number to check.
1677 * Non zero if number is finite.
1679 INT __cdecl CRTDLL__finite(double d)
1681 return (finite(d)?1:0); /* See comment for CRTDLL__isnan() */
1685 /*********************************************************************
1686 * _fpreset (CRTDLL.107)
1688 * Reset the state of the floating point processor.
1690 VOID __cdecl CRTDLL__fpreset(void)
1692 #if defined(__GNUC__) && defined(__i386__)
1693 __asm__ __volatile__( "fninit" );
1695 FIXME(":Not Implemented!\n");
1700 /*********************************************************************
1701 * _isnan (CRTDLL.164)
1703 * Determine if an IEEE double is unrepresentable (NaN).
1706 * d [in] Number to check.
1709 * Non zero if number is NaN.
1711 INT __cdecl CRTDLL__isnan(double d)
1713 /* some implementations return -1 for true(glibc), crtdll returns 1.
1714 * Do the same, as the result may be used in calculations.
1716 return isnan(d)?1:0;
1720 /*********************************************************************
1721 * _purecall (CRTDLL.249)
1723 * Abort program after pure virtual function call.
1725 VOID __cdecl CRTDLL__purecall(VOID)
1727 CRTDLL__amsg_exit( 6025 );
1731 /*********************************************************************
1734 * Return the quotient and remainder of long integer division.
1737 * [i386] Windows binary compatible - returns the struct in eax/edx.
1740 LONGLONG __cdecl CRTDLL_div(INT x, INT y)
1743 div_t dt = div(x,y);
1744 retVal = ((LONGLONG)dt.rem << 32) | dt.quot;
1747 #endif /* !defined(__i386__) */
1750 /*********************************************************************
1753 * Return the quotient and remainder of long integer division.
1756 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1759 div_t __cdecl CRTDLL_div(INT x, INT y)
1763 #endif /* !defined(__i386__) */
1766 /*********************************************************************
1769 * Return the quotient and remainder of long integer division.
1771 * [i386] Windows binary compatible - returns the struct in eax/edx.
1774 LONGLONG __cdecl CRTDLL_ldiv(LONG x, LONG y)
1777 ldiv_t ldt = ldiv(x,y);
1778 retVal = ((LONGLONG)ldt.rem << 32) | ldt.quot;
1781 #endif /* defined(__i386__) */
1784 /*********************************************************************
1787 * Return the quotient and remainder of long integer division.
1790 * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility
1793 ldiv_t __cdecl CRTDLL_ldiv(LONG x, LONG y)
1797 #endif /* !defined(__i386__) */
1800 /*********************************************************************
1804 double __cdecl CRTDLL__y0(double x)
1808 if (!finite(x)) CRTDLL_errno = EDOM;
1810 if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
1812 CRTDLL_errno = EDOM;
1818 /*********************************************************************
1822 double __cdecl CRTDLL__y1(double x)
1826 if (!finite(x)) CRTDLL_errno = EDOM;
1828 if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
1830 CRTDLL_errno = EDOM;
1836 /*********************************************************************
1840 double __cdecl CRTDLL__yn(INT x, double y)
1844 if (!finite(y)) CRTDLL_errno = EDOM;
1846 if (CRTDLL__fpclass(retVal) == _FPCLASS_NINF)
1848 CRTDLL_errno = EDOM;
1855 /*********************************************************************
1856 * _nextafter (CRTDLL.235)
1859 double __cdecl CRTDLL__nextafter(double x, double y)
1862 if (!finite(x) || !finite(y)) CRTDLL_errno = EDOM;
1863 retVal = nextafter(x,y);
1867 /*********************************************************************
1868 * _searchenv (CRTDLL.260)
1870 * Search CWD and each directory of an environment variable for
1871 * location of a file.
1873 VOID __cdecl CRTDLL__searchenv(LPCSTR file, LPCSTR env, LPSTR buff)
1876 char curPath[MAX_PATH];
1881 if (GetFileAttributesA( file ) != 0xFFFFFFFF)
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);
1889 /* Search given environment variable */
1890 envVal = CRTDLL_getenv(env);
1893 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
1898 TRACE(":searching for %s in paths %s\n", file, envVal);
1904 while(*end && *end != ';') end++; /* Find end of next path */
1905 if (penv == end || !*penv)
1907 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
1910 strncpy(curPath, penv, end - penv);
1911 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
1913 curPath[end - penv] = '\\';
1914 curPath[end - penv + 1] = '\0';
1917 curPath[end - penv] = '\0';
1919 strcat(curPath, file);
1920 TRACE("Checking for file %s\n", curPath);
1921 if (GetFileAttributesA( curPath ) != 0xFFFFFFFF)
1923 strcpy(buff, curPath);
1924 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
1927 penv = *end ? end + 1 : end;