winex11: Don't reset OpenGL swap interval of window on SetParent().
[wine.git] / dlls / msvcrt / dir.c
blobfa87ac13a361814c33ba76b61a7e325018d5df12
1 /*
2 * msvcrt.dll drive/directory functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.h"
32 #include "wine/unicode.h"
33 #include "msvcrt.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
39 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
41 DWORD dw;
43 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
44 ft->attrib = 0;
45 else
46 ft->attrib = fd->dwFileAttributes;
48 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
49 ft->time_create = dw;
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
51 ft->time_access = dw;
52 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
53 ft->time_write = dw;
54 ft->size = fd->nFileSizeLow;
55 strcpy(ft->name, fd->cFileName);
58 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
59 static void msvcrt_fttofd32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata32_t* ft)
61 DWORD dw;
63 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
64 ft->attrib = 0;
65 else
66 ft->attrib = fd->dwFileAttributes;
68 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
69 ft->time_create = dw;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
71 ft->time_access = dw;
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
73 ft->time_write = dw;
74 ft->size = fd->nFileSizeLow;
75 strcpy(ft->name, fd->cFileName);
78 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
79 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
81 DWORD dw;
83 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
84 ft->attrib = 0;
85 else
86 ft->attrib = fd->dwFileAttributes;
88 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
89 ft->time_create = dw;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
91 ft->time_access = dw;
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
93 ft->time_write = dw;
94 ft->size = fd->nFileSizeLow;
95 strcpyW(ft->name, fd->cFileName);
98 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
99 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata32_t* ft)
101 DWORD dw;
103 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
104 ft->attrib = 0;
105 else
106 ft->attrib = fd->dwFileAttributes;
108 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
109 ft->time_create = dw;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
111 ft->time_access = dw;
112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
113 ft->time_write = dw;
114 ft->size = fd->nFileSizeLow;
115 strcpyW(ft->name, fd->cFileName);
118 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
119 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
121 DWORD dw;
123 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
124 ft->attrib = 0;
125 else
126 ft->attrib = fd->dwFileAttributes;
128 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
129 ft->time_create = dw;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
131 ft->time_access = dw;
132 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
133 ft->time_write = dw;
134 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
135 strcpy(ft->name, fd->cFileName);
138 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
139 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64_t* ft)
141 DWORD dw;
143 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
144 ft->attrib = 0;
145 else
146 ft->attrib = fd->dwFileAttributes;
148 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
149 ft->time_create = dw;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
151 ft->time_access = dw;
152 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
153 ft->time_write = dw;
154 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
155 strcpy(ft->name, fd->cFileName);
158 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
159 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64_t* ft)
161 DWORD dw;
163 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
164 ft->attrib = 0;
165 else
166 ft->attrib = fd->dwFileAttributes;
168 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
169 ft->time_create = dw;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
171 ft->time_access = dw;
172 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
173 ft->time_write = dw;
174 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
175 strcpyW(ft->name, fd->cFileName);
178 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
179 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64i32_t* ft)
181 DWORD dw;
183 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
184 ft->attrib = 0;
185 else
186 ft->attrib = fd->dwFileAttributes;
188 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
189 ft->time_create = dw;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
191 ft->time_access = dw;
192 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
193 ft->time_write = dw;
194 ft->size = fd->nFileSizeLow;
195 strcpy(ft->name, fd->cFileName);
198 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
199 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
201 DWORD dw;
203 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
204 ft->attrib = 0;
205 else
206 ft->attrib = fd->dwFileAttributes;
208 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
209 ft->time_create = dw;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
211 ft->time_access = dw;
212 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
213 ft->time_write = dw;
214 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
215 strcpyW(ft->name, fd->cFileName);
218 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
219 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64i32_t* ft)
221 DWORD dw;
223 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
224 ft->attrib = 0;
225 else
226 ft->attrib = fd->dwFileAttributes;
228 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
229 ft->time_create = dw;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
231 ft->time_access = dw;
232 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
233 ft->time_write = dw;
234 ft->size = fd->nFileSizeLow;
235 strcpyW(ft->name, fd->cFileName);
238 /*********************************************************************
239 * _chdir (MSVCRT.@)
241 * Change the current working directory.
243 * PARAMS
244 * newdir [I] Directory to change to
246 * RETURNS
247 * Success: 0. The current working directory is set to newdir.
248 * Failure: -1. errno indicates the error.
250 * NOTES
251 * See SetCurrentDirectoryA.
253 int CDECL MSVCRT__chdir(const char * newdir)
255 if (!SetCurrentDirectoryA(newdir))
257 msvcrt_set_errno(newdir?GetLastError():0);
258 return -1;
260 return 0;
263 /*********************************************************************
264 * _wchdir (MSVCRT.@)
266 * Unicode version of _chdir.
268 int CDECL MSVCRT__wchdir(const MSVCRT_wchar_t * newdir)
270 if (!SetCurrentDirectoryW(newdir))
272 msvcrt_set_errno(newdir?GetLastError():0);
273 return -1;
275 return 0;
278 /*********************************************************************
279 * _chdrive (MSVCRT.@)
281 * Change the current drive.
283 * PARAMS
284 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
286 * RETURNS
287 * Success: 0. The current drive is set to newdrive.
288 * Failure: -1. errno indicates the error.
290 * NOTES
291 * See SetCurrentDirectoryA.
293 int CDECL MSVCRT__chdrive(int newdrive)
295 WCHAR buffer[] = {'A', ':', 0};
297 buffer[0] += newdrive - 1;
298 if (!SetCurrentDirectoryW( buffer ))
300 msvcrt_set_errno(GetLastError());
301 if (newdrive <= 0)
302 *MSVCRT__errno() = MSVCRT_EACCES;
303 return -1;
305 return 0;
308 /*********************************************************************
309 * _findclose (MSVCRT.@)
311 * Close a handle returned by _findfirst().
313 * PARAMS
314 * hand [I] Handle to close
316 * RETURNS
317 * Success: 0. All resources associated with hand are freed.
318 * Failure: -1. errno indicates the error.
320 * NOTES
321 * See FindClose.
323 int CDECL MSVCRT__findclose(MSVCRT_intptr_t hand)
325 TRACE(":handle %ld\n",hand);
326 if (!FindClose((HANDLE)hand))
328 msvcrt_set_errno(GetLastError());
329 return -1;
331 return 0;
334 /*********************************************************************
335 * _findfirst (MSVCRT.@)
337 * Open a handle for iterating through a directory.
339 * PARAMS
340 * fspec [I] File specification of files to iterate.
341 * ft [O] Information for the first file found.
343 * RETURNS
344 * Success: A handle suitable for passing to _findnext() and _findclose().
345 * ft is populated with the details of the found file.
346 * Failure: -1. errno indicates the error.
348 * NOTES
349 * See FindFirstFileA.
351 MSVCRT_intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
353 WIN32_FIND_DATAA find_data;
354 HANDLE hfind;
356 hfind = FindFirstFileA(fspec, &find_data);
357 if (hfind == INVALID_HANDLE_VALUE)
359 msvcrt_set_errno(GetLastError());
360 return -1;
362 msvcrt_fttofd(&find_data,ft);
363 TRACE(":got handle %p\n",hfind);
364 return (MSVCRT_intptr_t)hfind;
367 /*********************************************************************
368 * _findfirst32 (MSVCRT.@)
370 MSVCRT_intptr_t CDECL MSVCRT__findfirst32(const char * fspec, struct MSVCRT__finddata32_t* ft)
372 WIN32_FIND_DATAA find_data;
373 HANDLE hfind;
375 hfind = FindFirstFileA(fspec, &find_data);
376 if (hfind == INVALID_HANDLE_VALUE)
378 msvcrt_set_errno(GetLastError());
379 return -1;
381 msvcrt_fttofd32(&find_data, ft);
382 TRACE(":got handle %p\n", hfind);
383 return (MSVCRT_intptr_t)hfind;
386 /*********************************************************************
387 * _wfindfirst (MSVCRT.@)
389 * Unicode version of _findfirst.
391 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
393 WIN32_FIND_DATAW find_data;
394 HANDLE hfind;
396 hfind = FindFirstFileW(fspec, &find_data);
397 if (hfind == INVALID_HANDLE_VALUE)
399 msvcrt_set_errno(GetLastError());
400 return -1;
402 msvcrt_wfttofd(&find_data,ft);
403 TRACE(":got handle %p\n",hfind);
404 return (MSVCRT_intptr_t)hfind;
407 /*********************************************************************
408 * _wfindfirst32 (MSVCRT.@)
410 * Unicode version of _findfirst32.
412 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata32_t* ft)
414 WIN32_FIND_DATAW find_data;
415 HANDLE hfind;
417 hfind = FindFirstFileW(fspec, &find_data);
418 if (hfind == INVALID_HANDLE_VALUE)
420 msvcrt_set_errno(GetLastError());
421 return -1;
423 msvcrt_wfttofd32(&find_data, ft);
424 TRACE(":got handle %p\n", hfind);
425 return (MSVCRT_intptr_t)hfind;
428 /*********************************************************************
429 * _findfirsti64 (MSVCRT.@)
431 * 64-bit version of _findfirst.
433 MSVCRT_intptr_t CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
435 WIN32_FIND_DATAA find_data;
436 HANDLE hfind;
438 hfind = FindFirstFileA(fspec, &find_data);
439 if (hfind == INVALID_HANDLE_VALUE)
441 msvcrt_set_errno(GetLastError());
442 return -1;
444 msvcrt_fttofdi64(&find_data,ft);
445 TRACE(":got handle %p\n",hfind);
446 return (MSVCRT_intptr_t)hfind;
449 /*********************************************************************
450 * _findfirst64 (MSVCRT.@)
452 * 64-bit version of _findfirst.
454 MSVCRT_intptr_t CDECL MSVCRT__findfirst64(const char * fspec, struct MSVCRT__finddata64_t* ft)
456 WIN32_FIND_DATAA find_data;
457 HANDLE hfind;
459 hfind = FindFirstFileA(fspec, &find_data);
460 if (hfind == INVALID_HANDLE_VALUE)
462 msvcrt_set_errno(GetLastError());
463 return -1;
465 msvcrt_fttofd64(&find_data,ft);
466 TRACE(":got handle %p\n",hfind);
467 return (MSVCRT_intptr_t)hfind;
470 /*********************************************************************
471 * _wfindfirst64 (MSVCRT.@)
473 * Unicode version of _findfirst64.
475 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64_t* ft)
477 WIN32_FIND_DATAW find_data;
478 HANDLE hfind;
480 hfind = FindFirstFileW(fspec, &find_data);
481 if (hfind == INVALID_HANDLE_VALUE)
483 msvcrt_set_errno(GetLastError());
484 return -1;
486 msvcrt_wfttofd64(&find_data,ft);
487 TRACE(":got handle %p\n",hfind);
488 return (MSVCRT_intptr_t)hfind;
491 /*********************************************************************
492 * _findfirst64i32 (MSVCRT.@)
494 * 64-bit/32-bit version of _findfirst.
496 MSVCRT_intptr_t CDECL MSVCRT__findfirst64i32(const char * fspec, struct MSVCRT__finddata64i32_t* ft)
498 WIN32_FIND_DATAA find_data;
499 HANDLE hfind;
501 hfind = FindFirstFileA(fspec, &find_data);
502 if (hfind == INVALID_HANDLE_VALUE)
504 msvcrt_set_errno(GetLastError());
505 return -1;
507 msvcrt_fttofd64i32(&find_data,ft);
508 TRACE(":got handle %p\n",hfind);
509 return (MSVCRT_intptr_t)hfind;
512 /*********************************************************************
513 * _wfindfirst64i32 (MSVCRT.@)
515 * Unicode version of _findfirst64i32.
517 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64i32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64i32_t* ft)
519 WIN32_FIND_DATAW find_data;
520 HANDLE hfind;
522 hfind = FindFirstFileW(fspec, &find_data);
523 if (hfind == INVALID_HANDLE_VALUE)
525 msvcrt_set_errno(GetLastError());
526 return -1;
528 msvcrt_wfttofd64i32(&find_data,ft);
529 TRACE(":got handle %p\n",hfind);
530 return (MSVCRT_intptr_t)hfind;
533 /*********************************************************************
534 * _wfindfirsti64 (MSVCRT.@)
536 * Unicode version of _findfirsti64.
538 MSVCRT_intptr_t CDECL MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
540 WIN32_FIND_DATAW find_data;
541 HANDLE hfind;
543 hfind = FindFirstFileW(fspec, &find_data);
544 if (hfind == INVALID_HANDLE_VALUE)
546 msvcrt_set_errno(GetLastError());
547 return -1;
549 msvcrt_wfttofdi64(&find_data,ft);
550 TRACE(":got handle %p\n",hfind);
551 return (MSVCRT_intptr_t)hfind;
554 /*********************************************************************
555 * _findnext (MSVCRT.@)
557 * Find the next file from a file search handle.
559 * PARAMS
560 * hand [I] Handle to the search returned from _findfirst().
561 * ft [O] Information for the file found.
563 * RETURNS
564 * Success: 0. ft is populated with the details of the found file.
565 * Failure: -1. errno indicates the error.
567 * NOTES
568 * See FindNextFileA.
570 int CDECL MSVCRT__findnext(MSVCRT_intptr_t hand, struct MSVCRT__finddata_t * ft)
572 WIN32_FIND_DATAA find_data;
574 if (!FindNextFileA((HANDLE)hand, &find_data))
576 *MSVCRT__errno() = MSVCRT_ENOENT;
577 return -1;
580 msvcrt_fttofd(&find_data,ft);
581 return 0;
584 /*********************************************************************
585 * _findnext32 (MSVCRT.@)
587 int CDECL MSVCRT__findnext32(MSVCRT_intptr_t hand, struct MSVCRT__finddata32_t * ft)
589 WIN32_FIND_DATAA find_data;
591 if (!FindNextFileA((HANDLE)hand, &find_data))
593 *MSVCRT__errno() = MSVCRT_ENOENT;
594 return -1;
597 msvcrt_fttofd32(&find_data, ft);
598 return 0;
601 /*********************************************************************
602 * _wfindnext (MSVCRT.@)
604 * Unicode version of _findnext.
606 int CDECL MSVCRT__wfindnext(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata_t * ft)
608 WIN32_FIND_DATAW find_data;
610 if (!FindNextFileW((HANDLE)hand, &find_data))
612 *MSVCRT__errno() = MSVCRT_ENOENT;
613 return -1;
616 msvcrt_wfttofd(&find_data,ft);
617 return 0;
620 /*********************************************************************
621 * _findnexti64 (MSVCRT.@)
623 * 64-bit version of _findnext.
625 int CDECL MSVCRT__findnexti64(MSVCRT_intptr_t hand, struct MSVCRT__finddatai64_t * ft)
627 WIN32_FIND_DATAA find_data;
629 if (!FindNextFileA((HANDLE)hand, &find_data))
631 *MSVCRT__errno() = MSVCRT_ENOENT;
632 return -1;
635 msvcrt_fttofdi64(&find_data,ft);
636 return 0;
639 /*********************************************************************
640 * _findnext64 (MSVCRT.@)
642 * 64-bit version of _findnext.
644 int CDECL MSVCRT__findnext64(MSVCRT_intptr_t hand, struct MSVCRT__finddata64_t * ft)
646 WIN32_FIND_DATAA find_data;
648 if (!FindNextFileA((HANDLE)hand, &find_data))
650 *MSVCRT__errno() = MSVCRT_ENOENT;
651 return -1;
654 msvcrt_fttofd64(&find_data,ft);
655 return 0;
658 /*********************************************************************
659 * _wfindnext64 (MSVCRT.@)
661 * Unicode version of _wfindnext64.
663 int CDECL MSVCRT__wfindnext64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64_t * ft)
665 WIN32_FIND_DATAW find_data;
667 if (!FindNextFileW((HANDLE)hand, &find_data))
669 *MSVCRT__errno() = MSVCRT_ENOENT;
670 return -1;
673 msvcrt_wfttofd64(&find_data,ft);
674 return 0;
677 /*********************************************************************
678 * _findnext64i32 (MSVCRT.@)
680 * 64-bit/32-bit version of _findnext.
682 int CDECL MSVCRT__findnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__finddata64i32_t * ft)
684 WIN32_FIND_DATAA find_data;
686 if (!FindNextFileA((HANDLE)hand, &find_data))
688 *MSVCRT__errno() = MSVCRT_ENOENT;
689 return -1;
692 msvcrt_fttofd64i32(&find_data,ft);
693 return 0;
696 /*********************************************************************
697 * _wfindnexti64 (MSVCRT.@)
699 * Unicode version of _findnexti64.
701 int CDECL MSVCRT__wfindnexti64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
703 WIN32_FIND_DATAW find_data;
705 if (!FindNextFileW((HANDLE)hand, &find_data))
707 *MSVCRT__errno() = MSVCRT_ENOENT;
708 return -1;
711 msvcrt_wfttofdi64(&find_data,ft);
712 return 0;
715 /*********************************************************************
716 * _wfindnext64i32 (MSVCRT.@)
718 * Unicode version of _findnext64i32.
720 int CDECL MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64i32_t * ft)
722 WIN32_FIND_DATAW find_data;
724 if (!FindNextFileW((HANDLE)hand, &find_data))
726 *MSVCRT__errno() = MSVCRT_ENOENT;
727 return -1;
730 msvcrt_wfttofd64i32(&find_data,ft);
731 return 0;
734 /*********************************************************************
735 * _getcwd (MSVCRT.@)
737 * Get the current working directory.
739 * PARAMS
740 * buf [O] Destination for current working directory.
741 * size [I] Size of buf in characters
743 * RETURNS
744 * Success: If buf is NULL, returns an allocated string containing the path.
745 * Otherwise populates buf with the path and returns it.
746 * Failure: NULL. errno indicates the error.
748 char* CDECL MSVCRT__getcwd(char * buf, int size)
750 char dir[MAX_PATH];
751 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
753 if (dir_len < 1)
754 return NULL; /* FIXME: Real return value untested */
756 if (!buf)
758 if (size <= dir_len) size = dir_len + 1;
759 if (!(buf = MSVCRT_malloc( size ))) return NULL;
761 else if (dir_len >= size)
763 *MSVCRT__errno() = MSVCRT_ERANGE;
764 return NULL; /* buf too small */
766 strcpy(buf,dir);
767 return buf;
770 /*********************************************************************
771 * _wgetcwd (MSVCRT.@)
773 * Unicode version of _getcwd.
775 MSVCRT_wchar_t* CDECL MSVCRT__wgetcwd(MSVCRT_wchar_t * buf, int size)
777 MSVCRT_wchar_t dir[MAX_PATH];
778 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
780 if (dir_len < 1)
781 return NULL; /* FIXME: Real return value untested */
783 if (!buf)
785 if (size <= dir_len) size = dir_len + 1;
786 if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
788 if (dir_len >= size)
790 *MSVCRT__errno() = MSVCRT_ERANGE;
791 return NULL; /* buf too small */
793 strcpyW(buf,dir);
794 return buf;
797 /*********************************************************************
798 * _getdrive (MSVCRT.@)
800 * Get the current drive number.
802 * PARAMS
803 * None.
805 * RETURNS
806 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
807 * Failure: 0.
809 int CDECL MSVCRT__getdrive(void)
811 WCHAR buffer[MAX_PATH];
812 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
813 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
814 return toupperW(buffer[0]) - 'A' + 1;
815 return 0;
818 /*********************************************************************
819 * _getdcwd (MSVCRT.@)
821 * Get the current working directory on a given disk.
823 * PARAMS
824 * drive [I] Drive letter to get the current working directory from.
825 * buf [O] Destination for the current working directory.
826 * size [I] Length of drive in characters.
828 * RETURNS
829 * Success: If drive is NULL, returns an allocated string containing the path.
830 * Otherwise populates drive with the path and returns it.
831 * Failure: NULL. errno indicates the error.
833 char* CDECL MSVCRT__getdcwd(int drive, char * buf, int size)
835 static char* dummy;
837 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
839 if (!drive || drive == MSVCRT__getdrive())
840 return MSVCRT__getcwd(buf,size); /* current */
841 else
843 char dir[MAX_PATH];
844 char drivespec[] = {'A', ':', 0};
845 int dir_len;
847 drivespec[0] += drive - 1;
848 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
850 *MSVCRT__errno() = MSVCRT_EACCES;
851 return NULL;
854 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
855 if (dir_len >= size || dir_len < 1)
857 *MSVCRT__errno() = MSVCRT_ERANGE;
858 return NULL; /* buf too small */
861 TRACE(":returning '%s'\n", dir);
862 if (!buf)
863 return MSVCRT__strdup(dir); /* allocate */
865 strcpy(buf,dir);
867 return buf;
870 /*********************************************************************
871 * _wgetdcwd (MSVCRT.@)
873 * Unicode version of _wgetdcwd.
875 MSVCRT_wchar_t* CDECL MSVCRT__wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
877 static MSVCRT_wchar_t* dummy;
879 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
881 if (!drive || drive == MSVCRT__getdrive())
882 return MSVCRT__wgetcwd(buf,size); /* current */
883 else
885 MSVCRT_wchar_t dir[MAX_PATH];
886 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
887 int dir_len;
889 drivespec[0] += drive - 1;
890 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
892 *MSVCRT__errno() = MSVCRT_EACCES;
893 return NULL;
896 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
897 if (dir_len >= size || dir_len < 1)
899 *MSVCRT__errno() = MSVCRT_ERANGE;
900 return NULL; /* buf too small */
903 TRACE(":returning %s\n", debugstr_w(dir));
904 if (!buf)
905 return MSVCRT__wcsdup(dir); /* allocate */
906 strcpyW(buf,dir);
908 return buf;
911 /*********************************************************************
912 * _getdiskfree (MSVCRT.@)
914 * Get information about the free space on a drive.
916 * PARAMS
917 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
918 * info [O] Destination for the resulting information.
920 * RETURNS
921 * Success: 0. info is updated with the free space information.
922 * Failure: An error code from GetLastError().
924 * NOTES
925 * See GetLastError().
927 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
929 WCHAR drivespec[] = {'@', ':', '\\', 0};
930 DWORD ret[4];
931 unsigned int err;
933 if (disk > 26)
934 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
936 drivespec[0] += disk; /* make a drive letter */
938 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
940 d->sectors_per_cluster = ret[0];
941 d->bytes_per_sector = ret[1];
942 d->avail_clusters = ret[2];
943 d->total_clusters = ret[3];
944 return 0;
946 err = GetLastError();
947 msvcrt_set_errno(err);
948 return err;
951 /*********************************************************************
952 * _mkdir (MSVCRT.@)
954 * Create a directory.
956 * PARAMS
957 * newdir [I] Name of directory to create.
959 * RETURNS
960 * Success: 0. The directory indicated by newdir is created.
961 * Failure: -1. errno indicates the error.
963 * NOTES
964 * See CreateDirectoryA.
966 int CDECL MSVCRT__mkdir(const char * newdir)
968 if (CreateDirectoryA(newdir,NULL))
969 return 0;
970 msvcrt_set_errno(GetLastError());
971 return -1;
974 /*********************************************************************
975 * _wmkdir (MSVCRT.@)
977 * Unicode version of _mkdir.
979 int CDECL MSVCRT__wmkdir(const MSVCRT_wchar_t* newdir)
981 if (CreateDirectoryW(newdir,NULL))
982 return 0;
983 msvcrt_set_errno(GetLastError());
984 return -1;
987 /*********************************************************************
988 * _rmdir (MSVCRT.@)
990 * Delete a directory.
992 * PARAMS
993 * dir [I] Name of directory to delete.
995 * RETURNS
996 * Success: 0. The directory indicated by newdir is deleted.
997 * Failure: -1. errno indicates the error.
999 * NOTES
1000 * See RemoveDirectoryA.
1002 int CDECL MSVCRT__rmdir(const char * dir)
1004 if (RemoveDirectoryA(dir))
1005 return 0;
1006 msvcrt_set_errno(GetLastError());
1007 return -1;
1010 /*********************************************************************
1011 * _wrmdir (MSVCRT.@)
1013 * Unicode version of _rmdir.
1015 int CDECL MSVCRT__wrmdir(const MSVCRT_wchar_t * dir)
1017 if (RemoveDirectoryW(dir))
1018 return 0;
1019 msvcrt_set_errno(GetLastError());
1020 return -1;
1023 /******************************************************************
1024 * _splitpath_s (MSVCRT.@)
1026 int CDECL _splitpath_s(const char* inpath,
1027 char* drive, MSVCRT_size_t sz_drive,
1028 char* dir, MSVCRT_size_t sz_dir,
1029 char* fname, MSVCRT_size_t sz_fname,
1030 char* ext, MSVCRT_size_t sz_ext)
1032 const char *p, *end;
1034 if (!inpath || (!drive && sz_drive) ||
1035 (drive && !sz_drive) ||
1036 (!dir && sz_dir) ||
1037 (dir && !sz_dir) ||
1038 (!fname && sz_fname) ||
1039 (fname && !sz_fname) ||
1040 (!ext && sz_ext) ||
1041 (ext && !sz_ext))
1043 *MSVCRT__errno() = MSVCRT_EINVAL;
1044 return MSVCRT_EINVAL;
1047 if (inpath[0] && inpath[1] == ':')
1049 if (drive)
1051 if (sz_drive <= 2) goto do_error;
1052 drive[0] = inpath[0];
1053 drive[1] = inpath[1];
1054 drive[2] = 0;
1056 inpath += 2;
1058 else if (drive) drive[0] = '\0';
1060 /* look for end of directory part */
1061 end = NULL;
1062 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1064 if (end) /* got a directory */
1066 if (dir)
1068 if (sz_dir <= end - inpath) goto do_error;
1069 memcpy( dir, inpath, (end - inpath) );
1070 dir[end - inpath] = 0;
1072 inpath = end;
1074 else if (dir) dir[0] = 0;
1076 /* look for extension: what's after the last dot */
1077 end = NULL;
1078 for (p = inpath; *p; p++) if (*p == '.') end = p;
1080 if (!end) end = p; /* there's no extension */
1082 if (fname)
1084 if (sz_fname <= end - inpath) goto do_error;
1085 memcpy( fname, inpath, (end - inpath) );
1086 fname[end - inpath] = 0;
1088 if (ext)
1090 if (sz_ext <= strlen(end)) goto do_error;
1091 strcpy( ext, end );
1093 return 0;
1094 do_error:
1095 if (drive) drive[0] = '\0';
1096 if (dir) dir[0] = '\0';
1097 if (fname) fname[0]= '\0';
1098 if (ext) ext[0]= '\0';
1099 *MSVCRT__errno() = MSVCRT_ERANGE;
1100 return MSVCRT_ERANGE;
1103 /*********************************************************************
1104 * _splitpath (MSVCRT.@)
1106 void CDECL _splitpath(const char *inpath, char *drv, char *dir,
1107 char *fname, char *ext)
1109 _splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1110 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1113 /******************************************************************
1114 * _wsplitpath_s (MSVCRT.@)
1116 * Secure version of _wsplitpath
1118 int CDECL _wsplitpath_s(const MSVCRT_wchar_t* inpath,
1119 MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
1120 MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
1121 MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
1122 MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
1124 const MSVCRT_wchar_t *p, *end;
1126 if (!inpath || (!drive && sz_drive) ||
1127 (drive && !sz_drive) ||
1128 (!dir && sz_dir) ||
1129 (dir && !sz_dir) ||
1130 (!fname && sz_fname) ||
1131 (fname && !sz_fname) ||
1132 (!ext && sz_ext) ||
1133 (ext && !sz_ext))
1135 *MSVCRT__errno() = MSVCRT_EINVAL;
1136 return MSVCRT_EINVAL;
1139 if (inpath[0] && inpath[1] == ':')
1141 if (drive)
1143 if (sz_drive <= 2) goto do_error;
1144 drive[0] = inpath[0];
1145 drive[1] = inpath[1];
1146 drive[2] = 0;
1148 inpath += 2;
1150 else if (drive) drive[0] = '\0';
1152 /* look for end of directory part */
1153 end = NULL;
1154 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1156 if (end) /* got a directory */
1158 if (dir)
1160 if (sz_dir <= end - inpath) goto do_error;
1161 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1162 dir[end - inpath] = 0;
1164 inpath = end;
1166 else if (dir) dir[0] = 0;
1168 /* look for extension: what's after the last dot */
1169 end = NULL;
1170 for (p = inpath; *p; p++) if (*p == '.') end = p;
1172 if (!end) end = p; /* there's no extension */
1174 if (fname)
1176 if (sz_fname <= end - inpath) goto do_error;
1177 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1178 fname[end - inpath] = 0;
1180 if (ext)
1182 if (sz_ext <= strlenW(end)) goto do_error;
1183 strcpyW( ext, end );
1185 return 0;
1186 do_error:
1187 if (drive) drive[0] = '\0';
1188 if (dir) dir[0] = '\0';
1189 if (fname) fname[0]= '\0';
1190 if (ext) ext[0]= '\0';
1191 *MSVCRT__errno() = MSVCRT_ERANGE;
1192 return MSVCRT_ERANGE;
1195 /*********************************************************************
1196 * _wsplitpath (MSVCRT.@)
1198 * Unicode version of _splitpath.
1200 void CDECL _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
1201 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
1203 _wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1204 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1207 /*********************************************************************
1208 * _wfullpath (MSVCRT.@)
1210 * Unicode version of _fullpath.
1212 MSVCRT_wchar_t * CDECL _wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
1214 DWORD rc;
1215 WCHAR* buffer;
1216 WCHAR* lastpart;
1217 BOOL alloced = FALSE;
1219 if (!relPath || !*relPath)
1220 return MSVCRT__wgetcwd(absPath, size);
1222 if (absPath == NULL)
1224 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
1225 size = MAX_PATH;
1226 alloced = TRUE;
1228 else
1229 buffer = absPath;
1231 if (size < 4)
1233 *MSVCRT__errno() = MSVCRT_ERANGE;
1234 return NULL;
1237 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1239 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1241 if (rc > 0 && rc <= size )
1242 return buffer;
1243 else
1245 if (alloced)
1246 MSVCRT_free(buffer);
1247 return NULL;
1251 /*********************************************************************
1252 * _fullpath (MSVCRT.@)
1254 * Create an absolute path from a relative path.
1256 * PARAMS
1257 * absPath [O] Destination for absolute path
1258 * relPath [I] Relative path to convert to absolute
1259 * size [I] Length of absPath in characters.
1261 * RETURNS
1262 * Success: If absPath is NULL, returns an allocated string containing the path.
1263 * Otherwise populates absPath with the path and returns it.
1264 * Failure: NULL. errno indicates the error.
1266 char * CDECL _fullpath(char * absPath, const char* relPath, unsigned int size)
1268 DWORD rc;
1269 char* lastpart;
1270 char* buffer;
1271 BOOL alloced = FALSE;
1273 if (!relPath || !*relPath)
1274 return MSVCRT__getcwd(absPath, size);
1276 if (absPath == NULL)
1278 buffer = MSVCRT_malloc(MAX_PATH);
1279 size = MAX_PATH;
1280 alloced = TRUE;
1282 else
1283 buffer = absPath;
1285 if (size < 4)
1287 *MSVCRT__errno() = MSVCRT_ERANGE;
1288 return NULL;
1291 TRACE(":resolving relative path '%s'\n",relPath);
1293 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1295 if (rc > 0 && rc <= size)
1296 return buffer;
1297 else
1299 if (alloced)
1300 MSVCRT_free(buffer);
1301 return NULL;
1305 /*********************************************************************
1306 * _makepath (MSVCRT.@)
1308 * Create a pathname.
1310 * PARAMS
1311 * path [O] Destination for created pathname
1312 * drive [I] Drive letter (e.g. "A:")
1313 * directory [I] Directory
1314 * filename [I] Name of the file, excluding extension
1315 * extension [I] File extension (e.g. ".TXT")
1317 * RETURNS
1318 * Nothing. If path is not large enough to hold the resulting pathname,
1319 * random process memory will be overwritten.
1321 VOID CDECL _makepath(char * path, const char * drive,
1322 const char *directory, const char * filename,
1323 const char * extension)
1325 char *p = path;
1327 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1328 debugstr_a(filename), debugstr_a(extension) );
1330 if ( !path )
1331 return;
1333 if (drive && drive[0])
1335 *p++ = drive[0];
1336 *p++ = ':';
1338 if (directory && directory[0])
1340 unsigned int len = strlen(directory);
1341 memmove(p, directory, len);
1342 p += len;
1343 if (p[-1] != '/' && p[-1] != '\\')
1344 *p++ = '\\';
1346 if (filename && filename[0])
1348 unsigned int len = strlen(filename);
1349 memmove(p, filename, len);
1350 p += len;
1352 if (extension && extension[0])
1354 if (extension[0] != '.')
1355 *p++ = '.';
1356 strcpy(p, extension);
1358 else
1359 *p = '\0';
1360 TRACE("returning %s\n",path);
1363 /*********************************************************************
1364 * _wmakepath (MSVCRT.@)
1366 * Unicode version of _wmakepath.
1368 VOID CDECL _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1369 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1371 MSVCRT_wchar_t *p = path;
1373 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1374 debugstr_w(filename), debugstr_w(extension));
1376 if ( !path )
1377 return;
1379 if (drive && drive[0])
1381 *p++ = drive[0];
1382 *p++ = ':';
1384 if (directory && directory[0])
1386 unsigned int len = strlenW(directory);
1387 memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1388 p += len;
1389 if (p[-1] != '/' && p[-1] != '\\')
1390 *p++ = '\\';
1392 if (filename && filename[0])
1394 unsigned int len = strlenW(filename);
1395 memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1396 p += len;
1398 if (extension && extension[0])
1400 if (extension[0] != '.')
1401 *p++ = '.';
1402 strcpyW(p, extension);
1404 else
1405 *p = '\0';
1407 TRACE("returning %s\n", debugstr_w(path));
1410 /*********************************************************************
1411 * _makepath_s (MSVCRT.@)
1413 * Safe version of _makepath.
1415 int CDECL _makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1416 const char *directory, const char *filename,
1417 const char *extension)
1419 char *p = path;
1421 if (!path || !size)
1423 *MSVCRT__errno() = MSVCRT_EINVAL;
1424 return MSVCRT_EINVAL;
1427 if (drive && drive[0])
1429 if (size <= 2)
1430 goto range;
1432 *p++ = drive[0];
1433 *p++ = ':';
1434 size -= 2;
1437 if (directory && directory[0])
1439 unsigned int len = strlen(directory);
1440 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1441 unsigned int copylen = min(size - 1, len);
1443 if (size < 2)
1444 goto range;
1446 memmove(p, directory, copylen);
1448 if (size <= len)
1449 goto range;
1451 p += copylen;
1452 size -= copylen;
1454 if (needs_separator)
1456 if (size < 2)
1457 goto range;
1459 *p++ = '\\';
1460 size -= 1;
1464 if (filename && filename[0])
1466 unsigned int len = strlen(filename);
1467 unsigned int copylen = min(size - 1, len);
1469 if (size < 2)
1470 goto range;
1472 memmove(p, filename, copylen);
1474 if (size <= len)
1475 goto range;
1477 p += len;
1478 size -= len;
1481 if (extension && extension[0])
1483 unsigned int len = strlen(extension);
1484 unsigned int needs_period = extension[0] != '.';
1485 unsigned int copylen;
1487 if (size < 2)
1488 goto range;
1490 if (needs_period)
1492 *p++ = '.';
1493 size -= 1;
1496 copylen = min(size - 1, len);
1497 memcpy(p, extension, copylen);
1499 if (size <= len)
1500 goto range;
1502 p += copylen;
1505 *p = '\0';
1506 return 0;
1508 range:
1509 path[0] = '\0';
1510 *MSVCRT__errno() = MSVCRT_ERANGE;
1511 return MSVCRT_ERANGE;
1514 /*********************************************************************
1515 * _wmakepath_s (MSVCRT.@)
1517 * Safe version of _wmakepath.
1519 int CDECL _wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1520 const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1521 const MSVCRT_wchar_t *extension)
1523 MSVCRT_wchar_t *p = path;
1525 if (!path || !size)
1527 *MSVCRT__errno() = MSVCRT_EINVAL;
1528 return MSVCRT_EINVAL;
1531 if (drive && drive[0])
1533 if (size <= 2)
1534 goto range;
1536 *p++ = drive[0];
1537 *p++ = ':';
1538 size -= 2;
1541 if (directory && directory[0])
1543 unsigned int len = strlenW(directory);
1544 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1545 unsigned int copylen = min(size - 1, len);
1547 if (size < 2)
1548 goto range;
1550 memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1552 if (size <= len)
1553 goto range;
1555 p += copylen;
1556 size -= copylen;
1558 if (needs_separator)
1560 if (size < 2)
1561 goto range;
1563 *p++ = '\\';
1564 size -= 1;
1568 if (filename && filename[0])
1570 unsigned int len = strlenW(filename);
1571 unsigned int copylen = min(size - 1, len);
1573 if (size < 2)
1574 goto range;
1576 memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1578 if (size <= len)
1579 goto range;
1581 p += len;
1582 size -= len;
1585 if (extension && extension[0])
1587 unsigned int len = strlenW(extension);
1588 unsigned int needs_period = extension[0] != '.';
1589 unsigned int copylen;
1591 if (size < 2)
1592 goto range;
1594 if (needs_period)
1596 *p++ = '.';
1597 size -= 1;
1600 copylen = min(size - 1, len);
1601 memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1603 if (size <= len)
1604 goto range;
1606 p += copylen;
1609 *p = '\0';
1610 return 0;
1612 range:
1613 path[0] = '\0';
1614 *MSVCRT__errno() = MSVCRT_ERANGE;
1615 return MSVCRT_ERANGE;
1618 /*********************************************************************
1619 * _searchenv (MSVCRT.@)
1621 * Search for a file in a list of paths from an environment variable.
1623 * PARAMS
1624 * file [I] Name of the file to search for.
1625 * env [I] Name of the environment variable containing a list of paths.
1626 * buf [O] Destination for the found file path.
1628 * RETURNS
1629 * Nothing. If the file is not found, buf will contain an empty string
1630 * and errno is set.
1632 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1634 char*envVal, *penv;
1635 char curPath[MAX_PATH];
1637 *buf = '\0';
1639 /* Try CWD first */
1640 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1642 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1643 /* Sigh. This error is *always* set, regardless of success */
1644 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1645 return;
1648 /* Search given environment variable */
1649 envVal = MSVCRT_getenv(env);
1650 if (!envVal)
1652 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1653 return;
1656 penv = envVal;
1657 TRACE(":searching for %s in paths %s\n", file, envVal);
1661 char *end = penv;
1663 while(*end && *end != ';') end++; /* Find end of next path */
1664 if (penv == end || !*penv)
1666 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1667 return;
1669 memcpy(curPath, penv, end - penv);
1670 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1672 curPath[end - penv] = '\\';
1673 curPath[end - penv + 1] = '\0';
1675 else
1676 curPath[end - penv] = '\0';
1678 strcat(curPath, file);
1679 TRACE("Checking for file %s\n", curPath);
1680 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1682 strcpy(buf, curPath);
1683 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1684 return; /* Found */
1686 penv = *end ? end + 1 : end;
1687 } while(1);
1690 /*********************************************************************
1691 * _searchenv_s (MSVCRT.@)
1693 int CDECL _searchenv_s(const char* file, const char* env, char *buf, MSVCRT_size_t count)
1695 char*envVal, *penv;
1696 char curPath[MAX_PATH];
1698 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1699 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1700 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1702 *buf = '\0';
1704 /* Try CWD first */
1705 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1707 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1708 msvcrt_set_errno(GetLastError());
1709 return 0;
1712 /* Search given environment variable */
1713 envVal = MSVCRT_getenv(env);
1714 if (!envVal)
1716 *MSVCRT__errno() = MSVCRT_ENOENT;
1717 return MSVCRT_ENOENT;
1720 penv = envVal;
1721 TRACE(":searching for %s in paths %s\n", file, envVal);
1725 char *end = penv;
1727 while(*end && *end != ';') end++; /* Find end of next path */
1728 if (penv == end || !*penv)
1730 *MSVCRT__errno() = MSVCRT_ENOENT;
1731 return MSVCRT_ENOENT;
1733 memcpy(curPath, penv, end - penv);
1734 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1736 curPath[end - penv] = '\\';
1737 curPath[end - penv + 1] = '\0';
1739 else
1740 curPath[end - penv] = '\0';
1742 strcat(curPath, file);
1743 TRACE("Checking for file %s\n", curPath);
1744 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1746 if (strlen(curPath) + 1 > count)
1748 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1749 return MSVCRT_ERANGE;
1751 strcpy(buf, curPath);
1752 return 0;
1754 penv = *end ? end + 1 : end;
1755 } while(1);
1758 /*********************************************************************
1759 * _wsearchenv (MSVCRT.@)
1761 * Unicode version of _searchenv
1763 void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1765 MSVCRT_wchar_t *envVal, *penv;
1766 MSVCRT_wchar_t curPath[MAX_PATH];
1768 *buf = '\0';
1770 /* Try CWD first */
1771 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1773 GetFullPathNameW( file, MAX_PATH, buf, NULL );
1774 /* Sigh. This error is *always* set, regardless of success */
1775 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1776 return;
1779 /* Search given environment variable */
1780 envVal = MSVCRT__wgetenv(env);
1781 if (!envVal)
1783 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1784 return;
1787 penv = envVal;
1788 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1792 MSVCRT_wchar_t *end = penv;
1794 while(*end && *end != ';') end++; /* Find end of next path */
1795 if (penv == end || !*penv)
1797 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1798 return;
1800 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1801 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1803 curPath[end - penv] = '\\';
1804 curPath[end - penv + 1] = '\0';
1806 else
1807 curPath[end - penv] = '\0';
1809 strcatW(curPath, file);
1810 TRACE("Checking for file %s\n", debugstr_w(curPath));
1811 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1813 strcpyW(buf, curPath);
1814 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1815 return; /* Found */
1817 penv = *end ? end + 1 : end;
1818 } while(1);
1821 /*********************************************************************
1822 * _wsearchenv_s (MSVCRT.@)
1824 int CDECL _wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env,
1825 MSVCRT_wchar_t *buf, MSVCRT_size_t count)
1827 MSVCRT_wchar_t* envVal, *penv;
1828 MSVCRT_wchar_t curPath[MAX_PATH];
1830 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1831 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1832 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1834 *buf = '\0';
1836 /* Try CWD first */
1837 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1839 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1840 msvcrt_set_errno(GetLastError());
1841 return 0;
1844 /* Search given environment variable */
1845 envVal = MSVCRT__wgetenv(env);
1846 if (!envVal)
1848 *MSVCRT__errno() = MSVCRT_ENOENT;
1849 return MSVCRT_ENOENT;
1852 penv = envVal;
1853 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1857 MSVCRT_wchar_t *end = penv;
1859 while(*end && *end != ';') end++; /* Find end of next path */
1860 if (penv == end || !*penv)
1862 *MSVCRT__errno() = MSVCRT_ENOENT;
1863 return MSVCRT_ENOENT;
1865 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1866 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1868 curPath[end - penv] = '\\';
1869 curPath[end - penv + 1] = '\0';
1871 else
1872 curPath[end - penv] = '\0';
1874 strcatW(curPath, file);
1875 TRACE("Checking for file %s\n", debugstr_w(curPath));
1876 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1878 if (strlenW(curPath) + 1 > count)
1880 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1881 return MSVCRT_ERANGE;
1883 strcpyW(buf, curPath);
1884 return 0;
1886 penv = *end ? end + 1 : end;
1887 } while(1);