xref: /reactos/base/shell/cmd/where.c (revision c2c66aff)
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         _tcscpy (pFullName, szPathBuffer);
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             _tcscpy (pFullName, szPathBuffer);
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     dwBuffer = GetEnvironmentVariable (_T("PATHEXT"), pszPathExt, ENV_BUFFER_SIZE);
153     if (dwBuffer > ENV_BUFFER_SIZE)
154     {
155         LPTSTR pszOldPathExt = pszPathExt;
156         pszPathExt = (LPTSTR)cmd_realloc (pszPathExt, dwBuffer * sizeof (TCHAR));
157         if (pszPathExt == NULL)
158         {
159             cmd_free(pszOldPathExt);
160             return FALSE;
161         }
162         GetEnvironmentVariable (_T("PATHEXT"), pszPathExt, dwBuffer);
163         _tcslwr(pszPathExt);
164     }
165     else if (0 == dwBuffer)
166     {
167         _tcscpy(pszPathExt, pszDefaultPathExt);
168     }
169     else
170     {
171         _tcslwr(pszPathExt);
172     }
173 
174     /* Check if valid directly on specified path */
175     if (SearchForExecutableSingle(pFileName, pFullName, pszPathExt, NULL))
176     {
177         cmd_free(pszPathExt);
178         return TRUE;
179     }
180 
181     /* If an explicit directory was given, stop here - no need to search PATH. */
182     if (pFileName[1] == _T(':') || _tcschr(pFileName, _T('\\')))
183     {
184         cmd_free(pszPathExt);
185         return FALSE;
186     }
187 
188     /* load environment variable PATH into buffer */
189     pszPath = (LPTSTR)cmd_alloc (ENV_BUFFER_SIZE * sizeof(TCHAR));
190     dwBuffer = GetEnvironmentVariable (_T("PATH"), pszPath, ENV_BUFFER_SIZE);
191     if (dwBuffer > ENV_BUFFER_SIZE)
192     {
193         LPTSTR pszOldPath = pszPath;
194         pszPath = (LPTSTR)cmd_realloc (pszPath, dwBuffer * sizeof (TCHAR));
195         if (pszPath == NULL)
196         {
197             cmd_free(pszOldPath);
198             cmd_free(pszPathExt);
199             return FALSE;
200         }
201         GetEnvironmentVariable (_T("PATH"), pszPath, dwBuffer);
202     }
203 
204     TRACE ("SearchForExecutable(): Loaded PATH: %s\n", debugstr_aw(pszPath));
205 
206     /* search in PATH */
207     pCh = _tcstok(pszPath, _T(";"));
208     while (pCh)
209     {
210         if (SearchForExecutableSingle(pFileName, pFullName, pszPathExt, pCh))
211         {
212             cmd_free(pszPath);
213             cmd_free(pszPathExt);
214             return TRUE;
215         }
216         pCh = _tcstok(NULL, _T(";"));
217     }
218 
219     cmd_free(pszPath);
220     cmd_free(pszPathExt);
221     return FALSE;
222 }
223 
224 /* EOF */
225