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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/port.h"
34 #include "wine/unicode.h"
36 #include "msvcrt/errno.h"
38 #include "wine/unicode.h"
39 #include "msvcrt/direct.h"
40 #include "msvcrt/dos.h"
41 #include "msvcrt/io.h"
42 #include "msvcrt/stdlib.h"
43 #include "msvcrt/string.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
49 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
50 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct _finddata_t* ft)
54 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
57 ft->attrib = fd->dwFileAttributes;
59 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
61 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
63 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
65 ft->size = fd->nFileSizeLow;
66 strcpy(ft->name, fd->cFileName);
69 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
70 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct _wfinddata_t* ft)
74 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
77 ft->attrib = fd->dwFileAttributes;
79 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
81 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
83 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
85 ft->size = fd->nFileSizeLow;
86 strcpyW(ft->name, fd->cFileName);
89 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
90 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct _finddatai64_t* ft)
94 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
97 ft->attrib = fd->dwFileAttributes;
99 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
100 ft->time_create = dw;
101 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
102 ft->time_access = dw;
103 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
105 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
106 strcpy(ft->name, fd->cFileName);
109 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
110 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct _wfinddatai64_t* ft)
114 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
117 ft->attrib = fd->dwFileAttributes;
119 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
120 ft->time_create = dw;
121 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
122 ft->time_access = dw;
123 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
125 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
126 strcpyW(ft->name, fd->cFileName);
129 /*********************************************************************
132 * Change the current working directory.
135 * newdir [I] Directory to change to
138 * Success: 0. The current working directory is set to newdir.
139 * Failure: -1. errno indicates the error.
142 * See SetCurrentDirectoryA.
144 int _chdir(const char * newdir)
146 if (!SetCurrentDirectoryA(newdir))
148 MSVCRT__set_errno(newdir?GetLastError():0);
154 /*********************************************************************
157 * Unicode version of _chdir.
159 int _wchdir(const MSVCRT_wchar_t * newdir)
161 if (!SetCurrentDirectoryW(newdir))
163 MSVCRT__set_errno(newdir?GetLastError():0);
169 /*********************************************************************
170 * _chdrive (MSVCRT.@)
172 * Change the current drive.
175 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
178 * Success: 0. The current drive is set to newdrive.
179 * Failure: -1. errno indicates the error.
182 * See SetCurrentDirectoryA.
184 int _chdrive(int newdrive)
186 WCHAR buffer[3] = {'A', ':', 0};
188 buffer[0] += newdrive - 1;
189 if (!SetCurrentDirectoryW( buffer ))
191 MSVCRT__set_errno(GetLastError());
193 *MSVCRT__errno() = MSVCRT_EACCES;
199 /*********************************************************************
200 * _findclose (MSVCRT.@)
202 * Close a handle returned by _findfirst().
205 * hand [I] Handle to close
208 * Success: 0. All resources associated with hand are freed.
209 * Failure: -1. errno indicates the error.
214 int _findclose(long hand)
216 TRACE(":handle %ld\n",hand);
217 if (!FindClose((HANDLE)hand))
219 MSVCRT__set_errno(GetLastError());
225 /*********************************************************************
226 * _findfirst (MSVCRT.@)
228 * Open a handle for iterating through a directory.
231 * fspec [I] File specification of files to iterate.
232 * ft [O] Information for the first file found.
235 * Success: A handle suitable for passing to _findnext() and _findclose().
236 * ft is populated with the details of the found file.
237 * Failure: -1. errno indicates the error.
240 * See FindFirstFileA.
242 long _findfirst(const char * fspec, struct _finddata_t* ft)
244 WIN32_FIND_DATAA find_data;
247 hfind = FindFirstFileA(fspec, &find_data);
248 if (hfind == INVALID_HANDLE_VALUE)
250 MSVCRT__set_errno(GetLastError());
253 msvcrt_fttofd(&find_data,ft);
254 TRACE(":got handle %p\n",hfind);
258 /*********************************************************************
259 * _wfindfirst (MSVCRT.@)
261 * Unicode version of _findfirst.
263 long _wfindfirst(const MSVCRT_wchar_t * fspec, struct _wfinddata_t* ft)
265 WIN32_FIND_DATAW find_data;
268 hfind = FindFirstFileW(fspec, &find_data);
269 if (hfind == INVALID_HANDLE_VALUE)
271 MSVCRT__set_errno(GetLastError());
274 msvcrt_wfttofd(&find_data,ft);
275 TRACE(":got handle %p\n",hfind);
279 /*********************************************************************
280 * _findfirsti64 (MSVCRT.@)
282 * 64-bit version of _findfirst.
284 long _findfirsti64(const char * fspec, struct _finddatai64_t* ft)
286 WIN32_FIND_DATAA find_data;
289 hfind = FindFirstFileA(fspec, &find_data);
290 if (hfind == INVALID_HANDLE_VALUE)
292 MSVCRT__set_errno(GetLastError());
295 msvcrt_fttofdi64(&find_data,ft);
296 TRACE(":got handle %p\n",hfind);
300 /*********************************************************************
301 * _wfindfirsti64 (MSVCRT.@)
303 * Unicode version of _findfirsti64.
305 long _wfindfirsti64(const MSVCRT_wchar_t * fspec, struct _wfinddatai64_t* ft)
307 WIN32_FIND_DATAW find_data;
310 hfind = FindFirstFileW(fspec, &find_data);
311 if (hfind == INVALID_HANDLE_VALUE)
313 MSVCRT__set_errno(GetLastError());
316 msvcrt_wfttofdi64(&find_data,ft);
317 TRACE(":got handle %p\n",hfind);
321 /*********************************************************************
322 * _findnext (MSVCRT.@)
324 * Find the next file from a file search handle.
327 * hand [I] Handle to the search returned from _findfirst().
328 * ft [O] Information for the file found.
331 * Success: 0. ft is populated with the details of the found file.
332 * Failure: -1. errno indicates the error.
337 int _findnext(long hand, struct _finddata_t * ft)
339 WIN32_FIND_DATAA find_data;
341 if (!FindNextFileA((HANDLE)hand, &find_data))
343 *MSVCRT__errno() = MSVCRT_ENOENT;
347 msvcrt_fttofd(&find_data,ft);
351 /*********************************************************************
352 * _wfindnext (MSVCRT.@)
354 * Unicode version of _findnext.
356 int _wfindnext(long hand, struct _wfinddata_t * ft)
358 WIN32_FIND_DATAW find_data;
360 if (!FindNextFileW((HANDLE)hand, &find_data))
362 *MSVCRT__errno() = MSVCRT_ENOENT;
366 msvcrt_wfttofd(&find_data,ft);
370 /*********************************************************************
371 * _findnexti64 (MSVCRT.@)
373 * 64-bit version of _findnext.
375 int _findnexti64(long hand, struct _finddatai64_t * ft)
377 WIN32_FIND_DATAA find_data;
379 if (!FindNextFileA((HANDLE)hand, &find_data))
381 *MSVCRT__errno() = MSVCRT_ENOENT;
385 msvcrt_fttofdi64(&find_data,ft);
389 /*********************************************************************
390 * _wfindnexti64 (MSVCRT.@)
392 * Unicode version of _findnexti64.
394 int _wfindnexti64(long hand, struct _wfinddatai64_t * ft)
396 WIN32_FIND_DATAW find_data;
398 if (!FindNextFileW((HANDLE)hand, &find_data))
400 *MSVCRT__errno() = MSVCRT_ENOENT;
404 msvcrt_wfttofdi64(&find_data,ft);
408 /*********************************************************************
411 * Get the current working directory.
414 * buf [O] Destination for current working directory.
415 * size [I] Size of buf in characters
418 * Success: If buf is NULL, returns an allocated string containing the path.
419 * Otherwise populates buf with the path and returns it.
420 * Failure: NULL. errno indicates the error.
422 char* _getcwd(char * buf, int size)
425 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
428 return NULL; /* FIXME: Real return value untested */
434 return msvcrt_strndup(dir,size);
438 *MSVCRT__errno() = MSVCRT_ERANGE;
439 return NULL; /* buf too small */
445 /*********************************************************************
446 * _wgetcwd (MSVCRT.@)
448 * Unicode version of _getcwd.
450 MSVCRT_wchar_t* _wgetcwd(MSVCRT_wchar_t * buf, int size)
452 MSVCRT_wchar_t dir[MAX_PATH];
453 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
456 return NULL; /* FIXME: Real return value untested */
462 return msvcrt_wstrndup(dir,size);
466 *MSVCRT__errno() = MSVCRT_ERANGE;
467 return NULL; /* buf too small */
473 /*********************************************************************
474 * _getdrive (MSVCRT.@)
476 * Get the current drive number.
482 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
487 WCHAR buffer[MAX_PATH];
488 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
489 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
490 return toupperW(buffer[0]) - 'A' + 1;
494 /*********************************************************************
495 * _getdcwd (MSVCRT.@)
497 * Get the current working directory on a given disk.
500 * drive [I] Drive letter to get the current working directory from.
501 * buf [O] Destination for the current working directory.
502 * size [I] Length of drive in characters.
505 * Success: If drive is NULL, returns an allocated string containing the path.
506 * Otherwise populates drive with the path and returns it.
507 * Failure: NULL. errno indicates the error.
509 char* _getdcwd(int drive, char * buf, int size)
513 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
515 if (!drive || drive == _getdrive())
516 return _getcwd(buf,size); /* current */
520 char drivespec[4] = {'A', ':', '\\', 0};
523 drivespec[0] += drive - 1;
524 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
526 *MSVCRT__errno() = MSVCRT_EACCES;
530 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
531 if (dir_len >= size || dir_len < 1)
533 *MSVCRT__errno() = MSVCRT_ERANGE;
534 return NULL; /* buf too small */
537 TRACE(":returning '%s'\n", dir);
539 return _strdup(dir); /* allocate */
546 /*********************************************************************
547 * _wgetdcwd (MSVCRT.@)
549 * Unicode version of _wgetdcwd.
551 MSVCRT_wchar_t* _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
553 static MSVCRT_wchar_t* dummy;
555 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
557 if (!drive || drive == _getdrive())
558 return _wgetcwd(buf,size); /* current */
561 MSVCRT_wchar_t dir[MAX_PATH];
562 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
565 drivespec[0] += drive - 1;
566 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
568 *MSVCRT__errno() = MSVCRT_EACCES;
572 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
573 if (dir_len >= size || dir_len < 1)
575 *MSVCRT__errno() = MSVCRT_ERANGE;
576 return NULL; /* buf too small */
579 TRACE(":returning %s\n", debugstr_w(dir));
581 return _wcsdup(dir); /* allocate */
587 /*********************************************************************
588 * _getdiskfree (MSVCRT.@)
590 * Get information about the free space on a drive.
593 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
594 * info [O] Destination for the resulting information.
597 * Success: 0. info is updated with the free space information.
598 * Failure: An error code from GetLastError().
601 * See GetLastError().
603 unsigned int _getdiskfree(unsigned int disk, struct _diskfree_t* d)
605 WCHAR drivespec[4] = {'@', ':', '\\', 0};
610 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
612 drivespec[0] += disk; /* make a drive letter */
614 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
616 d->sectors_per_cluster = (unsigned)ret[0];
617 d->bytes_per_sector = (unsigned)ret[1];
618 d->avail_clusters = (unsigned)ret[2];
619 d->total_clusters = (unsigned)ret[3];
622 err = GetLastError();
623 MSVCRT__set_errno(err);
627 /*********************************************************************
630 * Create a directory.
633 * newdir [I] Name of directory to create.
636 * Success: 0. The directory indicated by newdir is created.
637 * Failure: -1. errno indicates the error.
640 * See CreateDirectoryA.
642 int _mkdir(const char * newdir)
644 if (CreateDirectoryA(newdir,NULL))
646 MSVCRT__set_errno(GetLastError());
650 /*********************************************************************
653 * Unicode version of _mkdir.
655 int _wmkdir(const MSVCRT_wchar_t* newdir)
657 if (CreateDirectoryW(newdir,NULL))
659 MSVCRT__set_errno(GetLastError());
663 /*********************************************************************
666 * Delete a directory.
669 * dir [I] Name of directory to delete.
672 * Success: 0. The directory indicated by newdir is deleted.
673 * Failure: -1. errno indicates the error.
676 * See RemoveDirectoryA.
678 int _rmdir(const char * dir)
680 if (RemoveDirectoryA(dir))
682 MSVCRT__set_errno(GetLastError());
686 /*********************************************************************
689 * Unicode version of _rmdir.
691 int _wrmdir(const MSVCRT_wchar_t * dir)
693 if (RemoveDirectoryW(dir))
695 MSVCRT__set_errno(GetLastError());
699 /*********************************************************************
700 * _wsplitpath (MSVCRT.@)
702 * Unicode version of _splitpath.
704 void _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
705 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
707 const MSVCRT_wchar_t *p, *end;
709 if (inpath[0] && inpath[1] == ':')
719 else if (drv) drv[0] = 0;
721 /* look for end of directory part */
723 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
725 if (end) /* got a directory */
729 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
730 dir[end - inpath] = 0;
734 else if (dir) dir[0] = 0;
736 /* look for extension: what's after the last dot */
738 for (p = inpath; *p; p++) if (*p == '.') end = p;
740 if (!end) end = p; /* there's no extension */
744 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
745 fname[end - inpath] = 0;
747 if (ext) strcpyW( ext, end );
750 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
751 static void wmsvcrt_fln_fix(MSVCRT_wchar_t *path)
753 int dir_flag = 0, root_flag = 0;
754 MSVCRT_wchar_t *r, *p, *q, *s;
755 MSVCRT_wchar_t szbsdot[] = { '\\', '.', 0 };
758 if (NULL == (r = strrchrW(path, ':')))
763 /* Ignore leading slashes */
773 p = r; /* Change "\\" to "\" */
774 while (NULL != (p = strchrW(p, '\\')))
780 while ('.' == *r) /* Scrunch leading ".\" */
784 /* Ignore leading ".." */
785 for (p = (r += 2); *p && (*p != '\\'); ++p)
790 for (p = r + 1 ;*p && (*p != '\\'); ++p)
793 strcpyW(r, p + ((*p) ? 1 : 0));
796 while ('\\' == path[strlenW(path)-1]) /* Strip last '\\' */
799 path[strlenW(path)-1] = '\0';
804 /* Look for "\." in path */
806 while (NULL != (p = strstrW(s, szbsdot)))
810 /* Execute this section if ".." found */
812 while (q > r) /* Backup one level */
825 strcpyW(q + ((*q == '\\') ? 1 : 0),
826 p + 3 + ((*(p + 3)) ? 1 : 0));
833 /* Execute this section if "." found */
835 for ( ;*q && (*q != '\\'); ++q)
841 if (root_flag) /* Embedded ".." could have bubbled up to root */
843 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
851 MSVCRT_wchar_t szbs[] = { '\\', 0 };
857 /*********************************************************************
858 * _wfullpath (MSVCRT.@)
860 * Unicode version of _fullpath.
862 MSVCRT_wchar_t *_wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
864 MSVCRT_wchar_t drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
865 MSVCRT_wchar_t res[MAX_PATH];
867 MSVCRT_wchar_t szbs[] = { '\\', 0 };
872 if (!relPath || !*relPath)
873 return _wgetcwd(absPath, size);
877 *MSVCRT__errno() = MSVCRT_ERANGE;
881 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath));
883 _wsplitpath(relPath, drive, dir, file, ext);
885 /* Get Directory and drive into 'res' */
886 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
888 /* Relative or no directory given */
889 _wgetdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
894 res[0] = drive[0]; /* If given a drive, preserve the letter case */
905 wmsvcrt_fln_fix(res);
908 if (len >= MAX_PATH || len >= (size_t)size)
909 return NULL; /* FIXME: errno? */
913 strcpyW(absPath,res);
917 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
918 static void msvcrt_fln_fix(char *path)
920 int dir_flag = 0, root_flag = 0;
924 if (NULL == (r = strrchr(path, ':')))
929 /* Ignore leading slashes */
939 p = r; /* Change "\\" to "\" */
940 while (NULL != (p = strchr(p, '\\')))
946 while ('.' == *r) /* Scrunch leading ".\" */
950 /* Ignore leading ".." */
951 for (p = (r += 2); *p && (*p != '\\'); ++p)
956 for (p = r + 1 ;*p && (*p != '\\'); ++p)
959 strcpy(r, p + ((*p) ? 1 : 0));
962 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
965 path[strlen(path)-1] = '\0';
970 /* Look for "\." in path */
972 while (NULL != (p = strstr(s, "\\.")))
976 /* Execute this section if ".." found */
978 while (q > r) /* Backup one level */
991 strcpy(q + ((*q == '\\') ? 1 : 0),
992 p + 3 + ((*(p + 3)) ? 1 : 0));
999 /* Execute this section if "." found */
1001 for ( ;*q && (*q != '\\'); ++q)
1007 if (root_flag) /* Embedded ".." could have bubbled up to root */
1009 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
1019 /*********************************************************************
1020 * _fullpath (MSVCRT.@)
1022 * Create an absolute path from a relative path.
1025 * absPath [O] Destination for absolute path
1026 * relPath [I] Relative path to convert to absolute
1027 * size [I] Length of absPath in characters.
1030 * Success: If absPath is NULL, returns an allocated string containing the path.
1031 * Otherwise populates absPath with the path and returns it.
1032 * Failure: NULL. errno indicates the error.
1034 char *_fullpath(char * absPath, const char* relPath, unsigned int size)
1036 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
1042 if (!relPath || !*relPath)
1043 return _getcwd(absPath, size);
1047 *MSVCRT__errno() = MSVCRT_ERANGE;
1051 TRACE(":resolving relative path '%s'\n",relPath);
1053 _splitpath(relPath, drive, dir, file, ext);
1055 /* Get Directory and drive into 'res' */
1056 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
1058 /* Relative or no directory given */
1059 _getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
1064 res[0] = drive[0]; /* If given a drive, preserve the letter case */
1075 msvcrt_fln_fix(res);
1078 if (len >= MAX_PATH || len >= (size_t)size)
1079 return NULL; /* FIXME: errno? */
1082 return _strdup(res);
1083 strcpy(absPath,res);
1087 /*********************************************************************
1088 * _makepath (MSVCRT.@)
1090 * Create a pathname.
1093 * path [O] Destination for created pathname
1094 * drive [I] Drive letter (e.g. "A:")
1095 * directory [I] Directory
1096 * filename [I] Name of the file, excluding extension
1097 * extension [I] File extension (e.g. ".TXT")
1100 * Nothing. If path is not large enough to hold the resulting pathname,
1101 * random process memory will be overwritten.
1103 VOID _makepath(char * path, const char * drive,
1104 const char *directory, const char * filename,
1105 const char * extension)
1108 char tmpPath[MAX_PATH];
1109 TRACE("got %s %s %s %s\n", debugstr_a(drive), debugstr_a(directory),
1110 debugstr_a(filename), debugstr_a(extension) );
1116 if (drive && drive[0])
1118 tmpPath[0] = drive[0];
1122 if (directory && directory[0])
1124 strcat(tmpPath, directory);
1125 ch = tmpPath[strlen(tmpPath)-1];
1126 if (ch != '/' && ch != '\\')
1127 strcat(tmpPath,"\\");
1129 if (filename && filename[0])
1131 strcat(tmpPath, filename);
1132 if (extension && extension[0])
1134 if ( extension[0] != '.' )
1135 strcat(tmpPath,".");
1136 strcat(tmpPath,extension);
1140 strcpy( path, tmpPath );
1142 TRACE("returning %s\n",path);
1145 /*********************************************************************
1146 * _wmakepath (MSVCRT.@)
1148 * Unicode version of _wmakepath.
1150 VOID _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1151 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1154 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1155 debugstr_w(filename), debugstr_w(extension));
1161 if (drive && drive[0])
1167 if (directory && directory[0])
1169 strcatW(path, directory);
1170 ch = path[strlenW(path) - 1];
1171 if (ch != '/' && ch != '\\')
1173 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
1174 strcatW(path, backslashW);
1177 if (filename && filename[0])
1179 strcatW(path, filename);
1180 if (extension && extension[0])
1182 if ( extension[0] != '.' )
1184 static const MSVCRT_wchar_t dotW[] = {'.',0};
1185 strcatW(path, dotW);
1187 strcatW(path, extension);
1191 TRACE("returning %s\n", debugstr_w(path));
1194 /*********************************************************************
1195 * _searchenv (MSVCRT.@)
1197 * Search for a file in a list of paths from an envronment variable.
1200 * file [I] Name of the file to search for.
1201 * env [I] Name of the environment variable containing a list of paths.
1202 * buf [O] Destination for the found file path.
1205 * Nothing. If the file is not found, buf will contain an empty string
1208 void _searchenv(const char* file, const char* env, char *buf)
1211 char curPath[MAX_PATH];
1216 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1218 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1219 /* Sigh. This error is *always* set, regardless of success */
1220 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1224 /* Search given environment variable */
1225 envVal = MSVCRT_getenv(env);
1228 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1233 TRACE(":searching for %s in paths %s\n", file, envVal);
1239 while(*end && *end != ';') end++; /* Find end of next path */
1240 if (penv == end || !*penv)
1242 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1245 strncpy(curPath, penv, end - penv);
1246 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
1248 curPath[end - penv] = '\\';
1249 curPath[end - penv + 1] = '\0';
1252 curPath[end - penv] = '\0';
1254 strcat(curPath, file);
1255 TRACE("Checking for file %s\n", curPath);
1256 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1258 strcpy(buf, curPath);
1259 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1262 penv = *end ? end + 1 : end;