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