1/*****************************************************************************/
2/* */
3/* searchpath.h */
4/* */
5/* Handling of search paths */
6/* */
7/* */
8/* */
9/* (C) 2000-2013, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdlib.h>
37#include <string.h>
38#if defined(_WIN32)
39# include <windows.h>
40#endif
41#if defined(_MSC_VER)
42/* Microsoft compiler */
43# include <io.h>
44#else
45/* Anyone else */
46# include <unistd.h>
47#endif
48
49/* common */
50#include "coll.h"
51#include "searchpath.h"
52#include "strbuf.h"
53#include "xmalloc.h"
54
55
56
57/*****************************************************************************/
58/* Code */
59/*****************************************************************************/
60
61
62
63static char* CleanupPath (const char* Path)
64/* Prepare and return a clean copy of Path */
65{
66 unsigned Len;
67 char* NewPath;
68
69 /* Get the length of the path */
70 Len = strlen (Path);
71
72 /* Check for a trailing path separator and remove it */
73 if (Len > 0 && (Path[Len-1] == '\\' || Path[Len-1] == '/')) {
74 --Len;
75 }
76
77 /* Allocate memory for the new string */
78 NewPath = (char*) xmalloc (Len + 1);
79
80 /* Copy the path and terminate it, then return the copy */
81 memcpy (NewPath, Path, Len);
82 NewPath [Len] = '\0';
83 return NewPath;
84}
85
86
87
88static void Add (SearchPaths* P, const char* New)
89/* Cleanup a new search path and add it to the list */
90{
91 /* Add a clean copy of the path to the collection */
92 CollAppend (P, CleanupPath (New));
93}
94
95
96
97SearchPaths* NewSearchPath (void)
98/* Create a new, empty search path list */
99{
100 return NewCollection ();
101}
102
103
104
105void AddSearchPath (SearchPaths* P, const char* NewPath)
106/* Add a new search path to the end of an existing list */
107{
108 /* Allow a NULL path */
109 if (NewPath) {
110 Add (P, NewPath);
111 }
112}
113
114
115
116void AddSearchPathFromEnv (SearchPaths* P, const char* EnvVar)
117/* Add a search path from an environment variable to the end of an existing
118** list.
119*/
120{
121 AddSearchPath (P, getenv (EnvVar));
122}
123
124
125
126void AddSubSearchPathFromEnv (SearchPaths* P, const char* EnvVar, const char* SubDir)
127/* Add a search path from an environment variable, adding a subdirectory to
128** the environment variable value.
129*/
130{
131 StrBuf Dir = AUTO_STRBUF_INITIALIZER;
132
133 const char* EnvVal = getenv (EnvVar);
134 if (EnvVal == 0) {
135 /* Not found */
136 return;
137 }
138
139 /* Copy the environment variable to the buffer */
140 SB_CopyStr (&Dir, EnvVal);
141
142 /* Add a path separator if necessary */
143 if (SB_NotEmpty (&Dir)) {
144 if (SB_LookAtLast (&Dir) != '\\' && SB_LookAtLast (&Dir) != '/') {
145 SB_AppendChar (&Dir, '/');
146 }
147 }
148
149 /* Add the subdirectory and terminate the string */
150 SB_AppendStr (&Dir, SubDir);
151 SB_Terminate (&Dir);
152
153 /* Add the search path */
154 AddSearchPath (P, SB_GetConstBuf (&Dir));
155
156 /* Free the temp buffer */
157 SB_Done (&Dir);
158}
159
160
161
162void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir)
163{
164/* Windows only:
165** Add a search path from the running binary, adding a subdirectory to
166** the parent directory of the directory containing the binary.
167*/
168#if defined(_WIN32)
169
170 char Dir[_MAX_PATH];
171 char* Ptr;
172
173 if (GetModuleFileName (NULL, Dir, _MAX_PATH) == 0) {
174 return;
175 }
176
177 /* Remove binary name */
178 Ptr = strrchr (Dir, '\\');
179 if (Ptr == 0) {
180 return;
181 }
182 *Ptr = '\0';
183
184 /* Check for 'bin' directory */
185 Ptr = strrchr (Dir, '\\');
186 if (Ptr == 0) {
187 return;
188 }
189 if (strcmp (Ptr++, "\\bin") != 0) {
190 return;
191 }
192
193 /* Append SubDir */
194 strcpy (Ptr, SubDir);
195
196 /* Add the search path */
197 AddSearchPath (P, Dir);
198
199#else
200
201 (void) P;
202 (void) SubDir;
203
204#endif
205}
206
207
208int PushSearchPath (SearchPaths* P, const char* NewPath)
209/* Add a new search path to the head of an existing search path list, provided
210** that it's not already there. If the path is already at the first position,
211** return zero, otherwise return a non zero value.
212*/
213{
214 /* Generate a clean copy of NewPath */
215 char* Path = CleanupPath (NewPath);
216
217 /* If we have paths, check if Path is already at position zero */
218 if (CollCount (P) > 0 && strcmp (CollConstAt (P, 0), Path) == 0) {
219 /* Match. Delete the copy and return to the caller */
220 xfree (Path);
221 return 0;
222 }
223
224 /* Insert a clean copy of the path at position 0, return success */
225 CollInsert (P, Path, 0);
226 return 1;
227}
228
229
230
231void PopSearchPath (SearchPaths* P)
232/* Remove a search path from the head of an existing search path list */
233{
234 /* Remove the path at position 0 */
235 xfree (CollAt (P, 0));
236 CollDelete (P, 0);
237}
238
239
240
241char* GetSearchPath (SearchPaths* P, unsigned Index)
242/* Return the search path at the given index, if the index is valid, return an
243** empty string otherwise.
244*/
245{
246 if (Index < CollCount (P))
247 return CollAtUnchecked (P, Index);
248 return "";
249}
250
251
252
253char* SearchFile (const SearchPaths* P, const char* File)
254/* Search for a file in a list of directories. Return a pointer to a malloced
255** area that contains the complete path, if found, return 0 otherwise.
256*/
257{
258 char* Name = 0;
259 StrBuf PathName = AUTO_STRBUF_INITIALIZER;
260
261 /* Start the search */
262 unsigned I;
263 for (I = 0; I < CollCount (P); ++I) {
264
265 /* Copy the next path element into the buffer */
266 SB_CopyStr (&PathName, CollConstAt (P, I));
267
268 /* Add a path separator and the filename */
269 if (SB_NotEmpty (&PathName)) {
270 SB_AppendChar (&PathName, '/');
271 }
272 SB_AppendStr (&PathName, File);
273 SB_Terminate (&PathName);
274
275 /* Check if this file exists */
276 if (access (SB_GetBuf (&PathName), 0) == 0) {
277 /* The file exists, we're done */
278 Name = xstrdup (SB_GetBuf (&PathName));
279 break;
280 }
281 }
282
283 /* Cleanup and return the result of the search */
284 SB_Done (&PathName);
285 return Name;
286}
287