xref: /reactos/base/shell/cmd/where.c (revision 1734f297)
1 /*
2  *  WHERE.C - file search functions.
3  *
4  *
5  *  History:
6  *
7  *    07/15/95 (Tim Norman)
8  *        started.
9  *
10  *    08/08/95 (Matt Rains)
11  *        i have cleaned up the source code. changes now bring this source
12  *        into guidelines for recommended programming practice.
13  *
14  *    12/12/95 (Steffan Kaiser & Tim Norman)
15  *        added some patches to fix some things and make more efficient
16  *
17  *    1/6/96 (Tim Norman)
18  *        fixed a stupid pointer mistake...
19  *        Thanks to everyone who noticed it!
20  *
21  *    8/1/96 (Tim Norman)
22  *        fixed a bug when getenv returns NULL
23  *
24  *    8/7/96 (Steffan Kaiser and Tim Norman)
25  *        speed improvements and bug fixes
26  *
27  *    8/27/96 (Tim Norman)
28  *        changed code to use pointers directly into PATH environment
29  *        variable rather than making our own copy.  This saves some memory,
30  *        but requires we write our own function to copy pathnames out of
31  *        the variable.
32  *
33  *    12/23/96 (Aaron Kaufman)
34  *        Fixed a bug in get_paths() that did not point to the first PATH
35  *        in the environment variable.
36  *
37  *    7/12/97 (Tim Norman)
38  *        Apparently, Aaron's bugfix got lost, so I fixed it again.
39  *
40  *    16 July 1998 (John P. Price)
41  *        Added stand alone code.
42  *
43  *    17 July 1998 (John P. Price)
44  *        Rewrote find_which to use searchpath function
45  *
46  *    24-Jul-1998 (John P Price <linux-guru@gcfl.net>)
47  *        fixed bug where didn't check all extensions when path was specified
48  *
49  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
50  *        added config.h include
51  *
52  *    30-Jul-1998 (John P Price <linux-guru@gcfl.net>)
53  *        fixed so that it find_which returns NULL if filename is not
54  *        executable (does not have .bat, .com, or .exe extension).
55  *        Before command would to execute any file with any extension (opps!)
56  *
57  *    03-Dec-1998 (Eric Kohl)
58  *        Changed find_which().
59  *
60  *    07-Dec-1998 (Eric Kohl)
61  *        Added ".CMD" extension.
62  *        Replaced numeric constant by _NR_OF_EXTENSIONS.
63  *
64  *    26-Feb-1999 (Eric Kohl)
65  *        Replaced find_which() by SearchForExecutable().
66  *        Now files are searched using the right extension order.
67  *
68  *    20-Apr-1999 (Eric Kohl)
69  *        Some minor changes and improvements.
70  *
71  *    10-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
72  *        Fixed searching for files with specific extensions in PATHEXT order.
73  *
74  */
75 
76 #include "precomp.h"
77 
78 
79 /* initial size of environment variable buffer */
80 #define ENV_BUFFER_SIZE  1024
81 
82 
83 /* searches for file using path info. */
84 
85 BOOL
86 SearchForExecutableSingle (LPCTSTR pFileName, LPTSTR pFullName, LPTSTR pPathExt, LPTSTR pDirectory)
87 {
88     TCHAR  szPathBuffer[CMDLINE_LENGTH], *pszPathEnd;
89     LPTSTR s,f;
90     /* initialize full name buffer */
91     *pFullName = _T('\0');
92 
93     TRACE ("SearchForExecutableSingle: \'%s\' in dir: \'%s\'\n",
94         debugstr_aw(pFileName), debugstr_aw(pDirectory));
95 
96     pszPathEnd = szPathBuffer;
97     if (pDirectory != NULL)
98     {
99         _tcscpy(szPathBuffer, pDirectory);
100         pszPathEnd += _tcslen(pszPathEnd);
101         *pszPathEnd++ = _T('\\');
102     }
103     _tcscpy(pszPathEnd, pFileName);
104     pszPathEnd += _tcslen(pszPathEnd);
105 
106     if (IsExistingFile (szPathBuffer))
107     {
108         TRACE ("Found: \'%s\'\n", debugstr_aw(szPathBuffer));
109         GetFullPathName(szPathBuffer, MAX_PATH, pFullName, NULL);
110         return TRUE;
111     }
112 
113     s = pPathExt;
114     while (s && *s)
115     {
116         f = _tcschr (s, _T(';'));
117 
118         if (f)
119         {
120             _tcsncpy (pszPathEnd, s, (size_t)(f-s));
121             pszPathEnd[f-s] = _T('\0');
122             s = f + 1;
123         }
124         else
125         {
126             _tcscpy (pszPathEnd, s);
127             s = NULL;
128         }
129 
130         if (IsExistingFile (szPathBuffer))
131         {
132             TRACE ("Found: \'%s\'\n", debugstr_aw(szPathBuffer));
133             GetFullPathName(szPathBuffer, MAX_PATH, pFullName, NULL);
134             return TRUE;
135         }
136     }
137     return FALSE;
138 }
139 
140 
141 BOOL
142 SearchForExecutable (LPCTSTR pFileName, LPTSTR pFullName)
143 {
144     static TCHAR pszDefaultPathExt[] = _T(".com;.exe;.bat;.cmd");
145     LPTSTR pszPathExt, pszPath;
146     LPTSTR pCh;
147     DWORD  dwBuffer;
148     TRACE ("SearchForExecutable: \'%s\'\n", debugstr_aw(pFileName));
149 
150     /* load environment variable PATHEXT */
151     pszPathExt = (LPTSTR)cmd_alloc (ENV_BUFFER_SIZE * sizeof(TCHAR));
152     if (!pszPathExt)
153     {
154         WARN("Cannot allocate memory for pszPathExt!\n");
155         return FALSE;
156     }
157 
158     dwBuffer = GetEnvironmentVariable (_T("PATHEXT"), pszPathExt, ENV_BUFFER_SIZE);
159     if (dwBuffer > ENV_BUFFER_SIZE)
160     {
161         LPTSTR pszOldPathExt = pszPathExt;
162         pszPathExt = (LPTSTR)cmd_realloc (pszPathExt, dwBuffer * sizeof (TCHAR));
163         if (!pszPathExt)
164         {
165             WARN("Cannot reallocate memory for pszPathExt!\n");
166             cmd_free(pszOldPathExt);
167             return FALSE;
168         }
169         GetEnvironmentVariable (_T("PATHEXT"), pszPathExt, dwBuffer);
170         _tcslwr(pszPathExt);
171     }
172     else if (0 == dwBuffer)
173     {
174         _tcscpy(pszPathExt, pszDefaultPathExt);
175     }
176     else
177     {
178         _tcslwr(pszPathExt);
179     }
180 
181     /* Check if valid directly on specified path */
182     if (SearchForExecutableSingle(pFileName, pFullName, pszPathExt, NULL))
183     {
184         cmd_free(pszPathExt);
185         return TRUE;
186     }
187 
188     /* If an explicit directory was given, stop here - no need to search PATH. */
189     if (pFileName[1] == _T(':') || _tcschr(pFileName, _T('\\')))
190     {
191         cmd_free(pszPathExt);
192         return FALSE;
193     }
194 
195     /* load environment variable PATH into buffer */
196     pszPath = (LPTSTR)cmd_alloc (ENV_BUFFER_SIZE * sizeof(TCHAR));
197     if (!pszPath)
198     {
199         WARN("Cannot allocate memory for pszPath!\n");
200         return FALSE;
201     }
202 
203     dwBuffer = GetEnvironmentVariable (_T("PATH"), pszPath, ENV_BUFFER_SIZE);
204     if (dwBuffer > ENV_BUFFER_SIZE)
205     {
206         LPTSTR pszOldPath = pszPath;
207         pszPath = (LPTSTR)cmd_realloc (pszPath, dwBuffer * sizeof (TCHAR));
208         if (!pszPath)
209         {
210             WARN("Cannot reallocate memory for pszPath!\n");
211             cmd_free(pszOldPath);
212             cmd_free(pszPathExt);
213             return FALSE;
214         }
215         GetEnvironmentVariable (_T("PATH"), pszPath, dwBuffer);
216     }
217 
218     TRACE ("SearchForExecutable(): Loaded PATH: %s\n", debugstr_aw(pszPath));
219 
220     /* search in PATH */
221     pCh = _tcstok(pszPath, _T(";"));
222     while (pCh)
223     {
224         if (SearchForExecutableSingle(pFileName, pFullName, pszPathExt, pCh))
225         {
226             cmd_free(pszPath);
227             cmd_free(pszPathExt);
228             return TRUE;
229         }
230         pCh = _tcstok(NULL, _T(";"));
231     }
232 
233     cmd_free(pszPath);
234     cmd_free(pszPathExt);
235     return FALSE;
236 }
237 
238 /* EOF */
239