1 |
johnpye |
607 |
/* ASCEND modelling environment |
2 |
jpye |
2326 |
Copyright (C) 2006-2010 Carnegie Mellon University |
3 |
johnpye |
607 |
|
4 |
|
|
This program is free software; you can redistribute it and/or modify |
5 |
|
|
it under the terms of the GNU General Public License as published by |
6 |
|
|
the Free Software Foundation; either version 2, or (at your option) |
7 |
|
|
any later version. |
8 |
|
|
|
9 |
|
|
This program is distributed in the hope that it will be useful, |
10 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
|
|
GNU General Public License for more details. |
13 |
|
|
|
14 |
|
|
You should have received a copy of the GNU General Public License |
15 |
|
|
along with this program; if not, write to the Free Software |
16 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330, |
17 |
|
|
Boston, MA 02111-1307, USA. |
18 |
ben.allan |
704 |
*//** |
19 |
johnpye |
607 |
@file |
20 |
|
|
Platform-agnostic filesystem path manipulation functions. |
21 |
|
|
By John Pye. |
22 |
|
|
*/ |
23 |
|
|
|
24 |
johnpye |
741 |
#if defined(WIN32) || defined(__WIN32) || defined(_MSC_VER) |
25 |
|
|
# ifndef __WIN32__ |
26 |
|
|
# define __WIN32__ |
27 |
|
|
# endif |
28 |
|
|
#endif |
29 |
|
|
|
30 |
ben.allan |
704 |
#include <string.h> |
31 |
jpye |
1660 |
#include <stdlib.h> |
32 |
ballan |
2036 |
#include <stddef.h> |
33 |
ben.allan |
704 |
#include <stdio.h> |
34 |
|
|
#include <ctype.h> |
35 |
johnpye |
542 |
|
36 |
johnpye |
741 |
#ifndef __WIN32__ |
37 |
|
|
# include <unistd.h> |
38 |
|
|
#endif |
39 |
|
|
|
40 |
ben.allan |
704 |
#include "ospath.h" |
41 |
|
|
|
42 |
jpye |
2335 |
//#define OSPATH_DEBUG |
43 |
ben.allan |
704 |
|
44 |
johnpye |
998 |
#ifndef __GNUC__ |
45 |
|
|
# ifndef __FUNCTION__ |
46 |
|
|
# define __FUNCTION__ "<ospath>" |
47 |
|
|
# endif |
48 |
johnpye |
954 |
#endif |
49 |
ben.allan |
704 |
|
50 |
johnpye |
954 |
|
51 |
johnpye |
662 |
/* #define VERBOSE */ |
52 |
johnpye |
542 |
|
53 |
jpye |
2335 |
#if !defined(VERBOSE) |
54 |
ben.allan |
704 |
#ifndef NDEBUG |
55 |
|
|
# define NDEBUG |
56 |
|
|
#endif |
57 |
|
|
#endif |
58 |
|
|
|
59 |
johnpye |
741 |
#ifdef _MSC_VER |
60 |
|
|
# define STAT _stat |
61 |
|
|
#else |
62 |
|
|
# define STAT stat |
63 |
|
|
#endif |
64 |
|
|
|
65 |
johnpye |
542 |
//#define TRY_GETPWUID |
66 |
|
|
|
67 |
|
|
#define DO_FIXSLASHES |
68 |
|
|
|
69 |
ben.allan |
704 |
#ifndef NDEBUG |
70 |
|
|
# include <assert.h> |
71 |
|
|
# define M(MSG) fprintf(stderr,"%s:%d: (%s) %s\n",__FILE__,__LINE__,__FUNCTION__,MSG);fflush(stderr);fflush(stderr) |
72 |
|
|
# define MC(CLR,MSG) fprintf(stderr,"%c[%sm%s:%d: (%s) %s%c[0m\n",27,CLR,__FILE__,__LINE__,__FUNCTION__,MSG,27);fflush(stderr) |
73 |
|
|
# define MM(MSG) MC("34",MSG) |
74 |
|
|
# define X(VAR) fprintf(stderr,"%s:%d: (%s) %s=%s\n",__FILE__,__LINE__,__FUNCTION__,#VAR,VAR);fflush(stderr) |
75 |
|
|
# define C(VAR) fprintf(stderr,"%s:%d: (%s) %s=%c\n",__FILE__,__LINE__,__FUNCTION__,#VAR,VAR);fflush(stderr) |
76 |
|
|
# define V(VAR) fprintf(stderr,"%s:%d: (%s) %s=%d\n",__FILE__,__LINE__,__FUNCTION__,#VAR,(VAR));fflush(stderr) |
77 |
johnpye |
998 |
# define P(VAR) fprintf(stderr,"%s:%d: (%s) %s=%p\n",__FILE__,__LINE__,__FUNCTION__,#VAR,(VAR));fflush(stderr) |
78 |
ben.allan |
704 |
# define D(VAR) fprintf(stderr,"%s:%d: (%s) %s=",__FILE__,__LINE__,__FUNCTION__,#VAR);ospath_debug(VAR);fflush(stderr) |
79 |
|
|
# define DD(VAR) fprintf(stderr,"%c[34;1m%s:%d: (%s)%c[0m %s=",27,__FILE__,__LINE__,__FUNCTION__,27,#VAR);ospath_debug(VAR);fflush(stderr) |
80 |
|
|
#else |
81 |
|
|
# include <assert.h> |
82 |
|
|
# define M(MSG) ((void)0) |
83 |
|
|
# define MC(CLR,MSG) ((void)0) |
84 |
|
|
# define X(VAR) ((void)0) |
85 |
|
|
# define C(VAR) ((void)0) |
86 |
|
|
# define V(VAR) ((void)0) |
87 |
|
|
# define D(VAR) ((void)0) |
88 |
johnpye |
998 |
# define P(VAR) ((void)0) |
89 |
ben.allan |
704 |
# define DD(VAR) ((void)0) |
90 |
|
|
# define MM(VAR) ((void)0) |
91 |
|
|
#endif |
92 |
|
|
|
93 |
|
|
#if defined(__WIN32__) && !defined(__MINGW32__) |
94 |
|
|
# define STRCPY strcpy |
95 |
|
|
# define STRNCPY(dest,src,n) strncpy_s(dest,n,src,n) |
96 |
|
|
# define STRCAT strcat |
97 |
|
|
# define STRNCAT strncat |
98 |
|
|
# define STRTOK(STR,PAT,VAR) strtok_s(STR,PAT,&VAR) |
99 |
|
|
# define STRTOKVAR(VAR) char *VAR |
100 |
|
|
# define GETCWD _getcwd |
101 |
|
|
# define GETENV(VAR) getenv(VAR) |
102 |
jpye |
2334 |
#elif defined(linux) |
103 |
|
|
# define STRCPY strcpy |
104 |
|
|
# define STRNCPY(dest,src,n) strncpy(dest,src,n) |
105 |
|
|
# define STRCAT strcat |
106 |
|
|
# define STRNCAT strncat |
107 |
|
|
# define STRTOK(STR,PAT,VAR) strtok_r(STR,PAT,&VAR) |
108 |
|
|
# define STRTOKVAR(VAR) char *VAR |
109 |
|
|
# define GETCWD getcwd |
110 |
|
|
# define GETENV(VAR) getenv(VAR) |
111 |
ben.allan |
704 |
#else |
112 |
|
|
# define STRCPY strcpy |
113 |
|
|
# define STRNCPY(dest,src,n) strncpy(dest,src,n) |
114 |
|
|
# define STRCAT strcat |
115 |
|
|
# define STRNCAT strncat |
116 |
|
|
# define STRTOK(STR,PAT,VAR) strtok(STR,PAT) |
117 |
|
|
# define STRTOKVAR(VAR) ((void)0) |
118 |
|
|
# define GETCWD getcwd |
119 |
|
|
# define GETENV(VAR) getenv(VAR) |
120 |
|
|
#endif |
121 |
|
|
|
122 |
johnpye |
908 |
/* PATH_MAX is in ospath.h */ |
123 |
ben.allan |
704 |
#define DRIVEMAX 3 |
124 |
|
|
#define LISTMAX 256 |
125 |
|
|
|
126 |
|
|
#ifdef __WIN32__ /* && !defined(__MINGW32__) */ |
127 |
|
|
# define WINPATHS |
128 |
|
|
#endif |
129 |
|
|
|
130 |
|
|
struct FilePath{ |
131 |
johnpye |
908 |
char path[PATH_MAX]; /** the string version of the represented POSIX path */ |
132 |
ben.allan |
704 |
|
133 |
johnpye |
965 |
#ifdef WINPATHS |
134 |
johnpye |
908 |
char drive[DRIVEMAX]; /** the drive the path resides on (field is absent in POSIX systems) */ |
135 |
ben.allan |
704 |
#endif |
136 |
|
|
}; |
137 |
|
|
|
138 |
|
|
#include <string.h> |
139 |
|
|
|
140 |
|
|
#if !defined(MALLOC) && !defined(FREE) |
141 |
|
|
# define MALLOC malloc |
142 |
|
|
# define FREE free |
143 |
|
|
#endif |
144 |
|
|
|
145 |
|
|
#define E(MSG) fprintf(stderr,"%s:%d: (%s) ERROR: %s\n",__FILE__,__LINE__,__FUNCTION__,MSG) |
146 |
|
|
|
147 |
|
|
#ifdef DO_FIXSLASHES |
148 |
johnpye |
542 |
void ospath_fixslash(char *path); |
149 |
ben.allan |
704 |
#endif |
150 |
|
|
|
151 |
|
|
struct FilePath *ospath_getcwd(); |
152 |
|
|
|
153 |
|
|
void ospath_copy(struct FilePath *dest, struct FilePath *src); |
154 |
|
|
|
155 |
|
|
|
156 |
|
|
#ifdef WINPATHS |
157 |
|
|
/** |
158 |
|
|
This function splits out the drive letter in the path string, thus completing |
159 |
|
|
the correct construction of a FilePath object under Win32. |
160 |
|
|
*/ |
161 |
|
|
void ospath_extractdriveletter(struct FilePath *); |
162 |
|
|
#endif |
163 |
|
|
|
164 |
|
|
#ifdef WINPATHS |
165 |
|
|
# define PATH_SEPARATOR_STR "\\" |
166 |
|
|
# define PATH_SEPARATOR_CHAR '\\' |
167 |
|
|
# define PATH_LISTSEP_CHAR ';' |
168 |
johnpye |
542 |
# define PATH_LISTSEP_STR ";" |
169 |
ben.allan |
704 |
# define PATH_WRONGSLASH_CHAR '/' |
170 |
|
|
# define PATH_WRONGSLASH_STR "/" |
171 |
|
|
#else |
172 |
|
|
# define PATH_SEPARATOR_STR "/" |
173 |
|
|
# define PATH_SEPARATOR_CHAR '/' |
174 |
|
|
# define PATH_LISTSEP_CHAR ':' |
175 |
|
|
# define PATH_LISTSEP_STR ":" |
176 |
|
|
# define PATH_WRONGSLASH_CHAR '\\' |
177 |
|
|
# define PATH_WRONGSLASH_STR "\\" |
178 |
|
|
#endif |
179 |
|
|
|
180 |
|
|
/** |
181 |
|
|
Create a new path structure from a string |
182 |
|
|
*/ |
183 |
|
|
struct FilePath *ospath_new(const char *path){ |
184 |
|
|
struct FilePath *fp; |
185 |
|
|
fp = ospath_new_noclean(path); |
186 |
|
|
|
187 |
|
|
#ifdef DO_FIXSLASHES |
188 |
|
|
ospath_fixslash(fp->path); |
189 |
|
|
#endif |
190 |
|
|
|
191 |
|
|
ospath_cleanup(fp); |
192 |
|
|
|
193 |
johnpye |
908 |
#if 0 |
194 |
|
|
D(fp); |
195 |
|
|
#endif |
196 |
ben.allan |
704 |
|
197 |
|
|
return fp; |
198 |
|
|
} |
199 |
|
|
|
200 |
|
|
|
201 |
|
|
|
202 |
johnpye |
908 |
/** Create but with no 'cleanup', and no fixing of / vs \. */ |
203 |
ben.allan |
704 |
struct FilePath *ospath_new_noclean(const char *path){ |
204 |
|
|
struct FilePath *fp = (struct FilePath *)MALLOC(sizeof(struct FilePath)); |
205 |
johnpye |
998 |
P(fp); |
206 |
|
|
X(path); |
207 |
ben.allan |
704 |
STRNCPY(fp->path,path,PATH_MAX); |
208 |
|
|
assert(strcmp(fp->path,path)==0); |
209 |
|
|
#ifdef WINPATHS |
210 |
johnpye |
908 |
#if 0 |
211 |
|
|
X(fp->path); |
212 |
|
|
#endif |
213 |
ben.allan |
704 |
ospath_extractdriveletter(fp); |
214 |
|
|
#endif |
215 |
|
|
|
216 |
|
|
return fp; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
struct FilePath *ospath_new_expand_env(const char *path, GetEnvFn *getenvptr){ |
220 |
|
|
struct FilePath *fp; |
221 |
|
|
|
222 |
|
|
char *pathnew = env_subst(path,getenvptr); |
223 |
|
|
fp = ospath_new(pathnew); |
224 |
|
|
FREE(pathnew); |
225 |
|
|
|
226 |
|
|
return fp; |
227 |
|
|
} |
228 |
|
|
|
229 |
johnpye |
741 |
struct FilePath *ospath_new_copy(struct FilePath *fp){ |
230 |
|
|
struct FilePath *fp1 = (struct FilePath *)MALLOC(sizeof(struct FilePath)); |
231 |
|
|
ospath_copy(fp1,fp); |
232 |
|
|
return fp1; |
233 |
|
|
} |
234 |
ben.allan |
704 |
|
235 |
|
|
/** |
236 |
|
|
This function will serve to allow #include-style file paths |
237 |
|
|
to be specified with platform-independent forward slashes then |
238 |
|
|
translated into the local filesystem format for subsequent use. |
239 |
|
|
|
240 |
|
|
This method should be identical to ospath_new on posix, right? |
241 |
|
|
|
242 |
|
|
@NOTE: on windows, we also want: |
243 |
|
|
C:dir/file --> c:$PWD\dir\file |
244 |
|
|
e:/hello --> e:\hello |
245 |
|
|
here/i/am --> here\i\am |
246 |
|
|
|
247 |
|
|
@NOTE: |
248 |
|
|
A path-search function should create full file paths by |
249 |
|
|
appending relative file to each component of the search path |
250 |
|
|
then performing a callback on each one to determine if the |
251 |
|
|
match is OK or not. |
252 |
|
|
*/ |
253 |
|
|
struct FilePath *ospath_new_from_posix(const char *posixpath){ |
254 |
|
|
struct FilePath *fp; |
255 |
|
|
fp = ospath_new_noclean(posixpath); |
256 |
|
|
|
257 |
|
|
#ifdef DO_FIXSLASHES |
258 |
|
|
ospath_fixslash(fp->path); |
259 |
|
|
#endif |
260 |
|
|
|
261 |
johnpye |
908 |
#if 0 |
262 |
|
|
X(fp->path); |
263 |
|
|
#endif |
264 |
ben.allan |
704 |
|
265 |
|
|
ospath_cleanup(fp); |
266 |
|
|
|
267 |
|
|
return fp; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
void ospath_free(struct FilePath *fp){ |
271 |
johnpye |
662 |
if(fp!=NULL){ |
272 |
johnpye |
998 |
P(fp); |
273 |
johnpye |
662 |
FREE(fp); |
274 |
|
|
} |
275 |
johnpye |
664 |
fp=NULL; |
276 |
ben.allan |
704 |
} |
277 |
johnpye |
542 |
|
278 |
ben.allan |
704 |
void ospath_free_str(char *str){ |
279 |
|
|
FREE(str); |
280 |
johnpye |
542 |
} |
281 |
ben.allan |
704 |
|
282 |
|
|
|
283 |
|
|
#ifdef DO_FIXSLASHES |
284 |
|
|
void ospath_fixslash(char *path){ |
285 |
|
|
|
286 |
|
|
char *p; |
287 |
|
|
char temp[PATH_MAX]; |
288 |
|
|
int startslash; |
289 |
|
|
int endslash; |
290 |
|
|
STRTOKVAR(nexttok); |
291 |
|
|
|
292 |
|
|
STRNCPY(temp,path,PATH_MAX); |
293 |
|
|
|
294 |
johnpye |
908 |
#if 0 |
295 |
|
|
X(path); |
296 |
|
|
#endif |
297 |
ben.allan |
704 |
|
298 |
|
|
startslash = (strlen(temp) > 0 && temp[0] == PATH_WRONGSLASH_CHAR); |
299 |
|
|
endslash = (strlen(temp) > 1 && temp[strlen(temp) - 1] == PATH_WRONGSLASH_CHAR); |
300 |
|
|
|
301 |
johnpye |
908 |
#if 0 |
302 |
|
|
V(startslash); |
303 |
|
|
V(endslash); |
304 |
ben.allan |
704 |
|
305 |
johnpye |
908 |
#endif |
306 |
|
|
/* reset fp->path as required. */ |
307 |
ben.allan |
704 |
STRNCPY(path, (startslash ? PATH_SEPARATOR_STR : ""), PATH_MAX); |
308 |
|
|
|
309 |
johnpye |
908 |
#if 0 |
310 |
|
|
M("STARTING STRTOK"); |
311 |
|
|
#endif |
312 |
ben.allan |
704 |
for(p = STRTOK(temp, PATH_WRONGSLASH_STR,nexttok); |
313 |
|
|
p!=NULL; |
314 |
|
|
p = STRTOK(NULL,PATH_WRONGSLASH_STR,nexttok) |
315 |
|
|
){ |
316 |
johnpye |
908 |
/* add a separator if we've already got some stuff */ |
317 |
ben.allan |
704 |
if( |
318 |
|
|
strlen(path) > 0 |
319 |
|
|
&& path[strlen(path) - 1] != PATH_SEPARATOR_CHAR |
320 |
|
|
){ |
321 |
|
|
STRCAT(path,PATH_SEPARATOR_STR); |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
STRCAT(path,p); |
325 |
|
|
} |
326 |
johnpye |
908 |
#if 0 |
327 |
|
|
M("FINISHED STRTOK"); |
328 |
|
|
#endif |
329 |
ben.allan |
704 |
|
330 |
johnpye |
908 |
/* put / on end as required, according to what the starting path had */ |
331 |
ben.allan |
704 |
if(endslash && (strlen(path) > 0 ? (path[strlen(path) - 1] != PATH_SEPARATOR_CHAR) : 1)) |
332 |
|
|
{ |
333 |
johnpye |
908 |
#if 0 |
334 |
|
|
M("adding endslash!"); |
335 |
|
|
#endif |
336 |
ben.allan |
704 |
|
337 |
|
|
STRCAT(path, PATH_SEPARATOR_STR); |
338 |
|
|
} |
339 |
|
|
|
340 |
johnpye |
908 |
#if 0 |
341 |
|
|
X(path); |
342 |
|
|
#endif |
343 |
ben.allan |
704 |
} |
344 |
|
|
#endif |
345 |
|
|
|
346 |
|
|
struct FilePath *ospath_getcwd(void){ |
347 |
johnpye |
998 |
struct FilePath *fp; |
348 |
ben.allan |
704 |
char *cwd; |
349 |
|
|
|
350 |
johnpye |
908 |
/* get current working directory */ |
351 |
ben.allan |
704 |
cwd = (char *)GETCWD(NULL, 0); |
352 |
|
|
|
353 |
johnpye |
908 |
/* create new path with resolved working directory */ |
354 |
ben.allan |
704 |
fp = ospath_new_noclean(cwd != NULL ? cwd : "."); |
355 |
|
|
|
356 |
jpye |
2334 |
ASC_FREE(cwd); |
357 |
ben.allan |
704 |
D(fp); |
358 |
|
|
|
359 |
|
|
return fp; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
/** |
363 |
|
|
Use getenv() function to retrieve HOME path, or if not set, use |
364 |
|
|
the password database and try to retrieve it that way (???) |
365 |
|
|
*/ |
366 |
|
|
struct FilePath *ospath_gethomepath(void){ |
367 |
|
|
|
368 |
|
|
const char *pfx = (const char *)getenv("HOME"); |
369 |
|
|
struct FilePath *fp; |
370 |
|
|
|
371 |
johnpye |
542 |
#ifndef __WIN32__ |
372 |
ben.allan |
704 |
# ifdef TRY_GETPWUID |
373 |
|
|
struct passwd *pw; |
374 |
|
|
|
375 |
|
|
if(pfx==NULL){ |
376 |
|
|
pw = (struct passwd*)getpwuid(getuid()); |
377 |
|
|
|
378 |
|
|
if(pw){ |
379 |
|
|
pfx = pw->pw_dir; |
380 |
|
|
} |
381 |
johnpye |
542 |
} |
382 |
ben.allan |
704 |
# endif |
383 |
|
|
#endif |
384 |
|
|
|
385 |
johnpye |
908 |
/* create path object from HOME, but don't compress it |
386 |
|
|
(because that would lead to an infinite loop) */ |
387 |
ben.allan |
704 |
fp = ospath_new_noclean(pfx ? pfx : ""); |
388 |
|
|
|
389 |
|
|
#ifdef DO_FIXSLASHES |
390 |
|
|
ospath_fixslash(fp->path); |
391 |
|
|
#endif |
392 |
|
|
|
393 |
|
|
return fp; |
394 |
|
|
} |
395 |
|
|
|
396 |
johnpye |
542 |
#ifdef WINPATHS |
397 |
ben.allan |
704 |
void ospath_extractdriveletter(struct FilePath *fp) |
398 |
|
|
{ |
399 |
|
|
char *p; |
400 |
johnpye |
908 |
#if 0 |
401 |
|
|
M("SOURCE"); |
402 |
|
|
X(fp->path); |
403 |
|
|
fprintf(stderr,"CHAR 1 = %c\n",fp->path[1]); |
404 |
|
|
#endif |
405 |
ben.allan |
704 |
|
406 |
johnpye |
908 |
/* extract the drive the path resides on... */ |
407 |
ben.allan |
704 |
if(strlen(fp->path) >= 2 && fp->path[1] == ':') |
408 |
|
|
{ |
409 |
|
|
STRNCPY(fp->drive,fp->path,2); |
410 |
|
|
fp->drive[2]='\0'; |
411 |
|
|
for(p=fp->path+2; *p!='\0'; ++p){ |
412 |
|
|
*(p-2)=*p; |
413 |
|
|
} |
414 |
|
|
*(p-2)='\0'; |
415 |
|
|
}else{ |
416 |
|
|
STRNCPY(fp->drive,"",DRIVEMAX); |
417 |
|
|
} |
418 |
johnpye |
908 |
#if 0 |
419 |
|
|
M("RESULT"); |
420 |
|
|
X(fp->path); |
421 |
|
|
X(fp->drive); |
422 |
|
|
#endif |
423 |
ben.allan |
704 |
} |
424 |
|
|
#endif |
425 |
|
|
|
426 |
|
|
void ospath_cleanup(struct FilePath *fp){ |
427 |
|
|
char path[PATH_MAX]; |
428 |
|
|
char *p; |
429 |
|
|
struct FilePath *home; |
430 |
|
|
struct FilePath *working; |
431 |
|
|
struct FilePath *parent; |
432 |
johnpye |
908 |
int startslash, endslash; |
433 |
ben.allan |
704 |
STRTOKVAR(nexttok); |
434 |
|
|
|
435 |
johnpye |
908 |
/* compress the path, and resolve ~ */ |
436 |
|
|
startslash = (strlen(fp->path) > 0 && fp->path[0] == PATH_SEPARATOR_CHAR); |
437 |
|
|
endslash = (strlen(fp->path) > 1 && fp->path[strlen(fp->path) - 1] == PATH_SEPARATOR_CHAR); |
438 |
ben.allan |
704 |
|
439 |
johnpye |
908 |
#if 0 |
440 |
|
|
fprintf(stderr,"FS ON START = %d\n",startslash); |
441 |
|
|
fprintf(stderr,"FS ON END = %d\n",endslash); |
442 |
|
|
fprintf(stderr,"FIRST CHAR = %c\n",fp->path[0]); |
443 |
|
|
#endif |
444 |
ben.allan |
704 |
|
445 |
|
|
home = ospath_gethomepath(); |
446 |
|
|
|
447 |
johnpye |
908 |
/* create a copy of fp->path. */ |
448 |
ben.allan |
704 |
STRCPY(path, fp->path); |
449 |
|
|
|
450 |
johnpye |
908 |
/* reset fp->path as required. */ |
451 |
ben.allan |
704 |
STRCPY(fp->path, (startslash ? PATH_SEPARATOR_STR : "")); |
452 |
|
|
|
453 |
|
|
D(fp); |
454 |
|
|
X(path); |
455 |
|
|
|
456 |
johnpye |
908 |
/* split path into it tokens, using STRTOK which is NOT reentrant |
457 |
|
|
so be careful! */ |
458 |
ben.allan |
704 |
|
459 |
johnpye |
908 |
/*M("STARTING STRTOK"); */ |
460 |
ben.allan |
704 |
for(p = STRTOK(path, PATH_SEPARATOR_STR,nexttok); |
461 |
|
|
p!=NULL; |
462 |
|
|
p = STRTOK(NULL,PATH_SEPARATOR_STR,nexttok) |
463 |
|
|
){ |
464 |
johnpye |
908 |
#if 0 |
465 |
|
|
M("NEXT TOKEN"); |
466 |
|
|
X(p); |
467 |
|
|
X(path+strlen(p)+1); |
468 |
|
|
#endif |
469 |
ben.allan |
704 |
if(strcmp(p, "~")==0){ |
470 |
|
|
|
471 |
johnpye |
908 |
if(p == path){ /* check that the ~ is the first character in the path */ |
472 |
ben.allan |
704 |
if(ospath_isvalid(home)){ |
473 |
|
|
ospath_copy(fp,home); |
474 |
|
|
continue; |
475 |
|
|
}else{ |
476 |
|
|
E("HOME does not resolve to valid path"); |
477 |
|
|
} |
478 |
|
|
}else{ |
479 |
|
|
E("A tilde (~) present as a component in a file path must be at the start!"); |
480 |
|
|
} |
481 |
|
|
}else if(strcmp(p, ".") == 0){ |
482 |
|
|
|
483 |
johnpye |
908 |
if(p==path){/* start of path: */ |
484 |
ben.allan |
704 |
M("EXPANDING LEADING '.' IN PATH"); |
485 |
|
|
X(path); |
486 |
|
|
|
487 |
|
|
working = ospath_getcwd(); |
488 |
|
|
|
489 |
|
|
D(working); |
490 |
|
|
#ifdef WINPATHS |
491 |
johnpye |
542 |
X(working->drive); |
492 |
ben.allan |
704 |
#endif |
493 |
|
|
X(p); |
494 |
|
|
X(path); |
495 |
|
|
|
496 |
|
|
ospath_copy(fp,working); |
497 |
|
|
|
498 |
|
|
|
499 |
|
|
D(fp); |
500 |
|
|
X(p); |
501 |
johnpye |
908 |
X(path+strlen(p)+1); |
502 |
johnpye |
998 |
|
503 |
johnpye |
908 |
ospath_free(working); |
504 |
ben.allan |
704 |
continue; |
505 |
johnpye |
908 |
}else{/* later in the path: just skip it */ |
506 |
ben.allan |
704 |
M("SKIPPING '.' IN PATH"); |
507 |
|
|
continue; |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
}else if(strcmp(p, "..") == 0){ |
511 |
|
|
M("GOING TO PARENT"); |
512 |
|
|
parent = ospath_getparent(fp); |
513 |
|
|
if(ospath_isvalid(parent)){ |
514 |
|
|
ospath_copy(fp,parent); |
515 |
|
|
} |
516 |
johnpye |
908 |
ospath_free(parent); |
517 |
ben.allan |
704 |
continue; |
518 |
|
|
} |
519 |
|
|
|
520 |
johnpye |
908 |
/* add a separator if we've already got some stuff */ |
521 |
ben.allan |
704 |
if( |
522 |
|
|
strlen(fp->path) > 0 |
523 |
|
|
&& fp->path[strlen(fp->path) - 1] != PATH_SEPARATOR_CHAR |
524 |
|
|
){ |
525 |
|
|
STRCAT(fp->path,PATH_SEPARATOR_STR); |
526 |
|
|
} |
527 |
|
|
|
528 |
johnpye |
908 |
/* add the present path component */ |
529 |
ben.allan |
704 |
STRCAT(fp->path, p); |
530 |
|
|
} |
531 |
johnpye |
908 |
#if 0 |
532 |
|
|
M("FINISHED STRTOK"); |
533 |
|
|
#endif |
534 |
ben.allan |
704 |
|
535 |
johnpye |
715 |
ospath_free(home); |
536 |
|
|
|
537 |
ben.allan |
704 |
// put / on end as required, according to what the starting path had |
538 |
|
|
if(endslash && (strlen(fp->path) > 0 ? (fp->path[strlen(fp->path) - 1] != PATH_SEPARATOR_CHAR) : 1)) |
539 |
|
|
{ |
540 |
|
|
STRCAT(fp->path, PATH_SEPARATOR_STR); |
541 |
|
|
} |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
|
545 |
johnpye |
542 |
int ospath_isvalid(struct FilePath *fp){ |
546 |
johnpye |
908 |
/*if(fp==NULL) return 0; */ |
547 |
ben.allan |
704 |
return strlen(fp->path) > 0 ? 1 : 0; |
548 |
|
|
} |
549 |
johnpye |
542 |
|
550 |
ben.allan |
704 |
|
551 |
johnpye |
864 |
char *ospath_str(const struct FilePath *fp){ |
552 |
ben.allan |
704 |
char *s; |
553 |
|
|
#ifdef WINPATHS |
554 |
|
|
s = (char *)MALLOC(sizeof(char)*(strlen(fp->drive)+strlen(fp->path) +1) ); |
555 |
|
|
STRCPY(s,fp->drive); |
556 |
|
|
STRCAT(s,fp->path); |
557 |
|
|
#else |
558 |
|
|
s = MALLOC(sizeof(char)*(strlen(fp->path)+1)); |
559 |
|
|
STRCPY(s,fp->path); |
560 |
|
|
#endif |
561 |
|
|
return s; |
562 |
|
|
} |
563 |
|
|
|
564 |
johnpye |
741 |
void ospath_strncpy(struct FilePath *fp, char *dest, int destsize){ |
565 |
ben.allan |
704 |
#ifdef WINPATHS |
566 |
|
|
STRNCPY(dest,fp->drive,destsize); |
567 |
|
|
STRNCAT(dest,fp->path,destsize-strlen(dest)); |
568 |
|
|
#else |
569 |
|
|
STRNCPY(dest,fp->path,destsize); |
570 |
johnpye |
542 |
#endif |
571 |
|
|
} |
572 |
ben.allan |
704 |
|
573 |
|
|
void ospath_strcat(struct FilePath *fp, char *dest, int destsize){ |
574 |
johnpye |
588 |
int remaining = destsize - strlen(dest); |
575 |
ben.allan |
704 |
V(remaining); |
576 |
|
|
#ifdef WINPATHS |
577 |
|
|
STRNCAT(dest,fp->drive,remaining); |
578 |
|
|
STRNCAT(dest,fp->path,remaining-strlen(dest)); |
579 |
|
|
#else |
580 |
|
|
STRNCAT(dest,fp->path,remaining); |
581 |
johnpye |
588 |
#endif |
582 |
ben.allan |
704 |
D(fp); |
583 |
|
|
} |
584 |
johnpye |
585 |
|
585 |
ben.allan |
704 |
void ospath_fwrite(struct FilePath *fp, FILE *dest){ |
586 |
|
|
#ifdef WINPATHS |
587 |
|
|
fprintf(dest,"%s%s",fp->drive,fp->path); |
588 |
|
|
#else |
589 |
|
|
fprintf(dest,"%s",fp->path); |
590 |
|
|
#endif |
591 |
|
|
} |
592 |
|
|
|
593 |
|
|
unsigned ospath_length(struct FilePath *fp){ |
594 |
|
|
#ifdef WINPATHS |
595 |
johnpye |
908 |
/* we've already validated this path, so it's on to just add it up |
596 |
|
|
(unless someone has been tinkering with the internal structure here)*/ |
597 |
ben.allan |
704 |
return (unsigned) (strlen(fp->drive) + strlen(fp->path)); |
598 |
|
|
#else |
599 |
|
|
return (unsigned) (strlen(fp->path)); |
600 |
|
|
#endif |
601 |
|
|
} |
602 |
|
|
|
603 |
|
|
struct FilePath *ospath_getparent(struct FilePath *fp) |
604 |
|
|
{ |
605 |
|
|
int length; |
606 |
|
|
int offset; |
607 |
|
|
char *pos; |
608 |
ballan |
2036 |
ptrdiff_t len1; |
609 |
|
|
int len2; |
610 |
ben.allan |
704 |
char sub[PATH_MAX]; |
611 |
|
|
struct FilePath *fp1, *fp2; |
612 |
|
|
|
613 |
jpye |
2335 |
#ifdef OSPATH_DEBUG |
614 |
|
|
fprintf(stderr,"finding parent of %s\n",fp->path); |
615 |
|
|
#endif |
616 |
ben.allan |
704 |
D(fp); |
617 |
|
|
|
618 |
johnpye |
589 |
if(strlen(fp->path) == 0){ |
619 |
|
|
fp1 = ospath_getcwd(); |
620 |
|
|
fp2 = ospath_getparent(fp1); |
621 |
|
|
ospath_free(fp1); |
622 |
|
|
return fp2; |
623 |
ben.allan |
704 |
}else if(ospath_isroot(fp)){ |
624 |
jpye |
2335 |
#ifdef OSPATH_DEBUG |
625 |
|
|
fprintf(stderr,"path is root\n"); |
626 |
|
|
#endif |
627 |
johnpye |
908 |
/* stay at root */ |
628 |
ben.allan |
704 |
return ospath_new("/"); |
629 |
|
|
} |
630 |
|
|
|
631 |
johnpye |
908 |
/* reverse find a / ignoring the end / if it exists. |
632 |
|
|
/// FIXME */ |
633 |
ben.allan |
704 |
length = strlen(fp->path); |
634 |
|
|
offset = ( |
635 |
johnpye |
908 |
fp->path[length - 1] == PATH_SEPARATOR_CHAR /* last char is slash?*/ |
636 |
|
|
&& length > 1 /* and more than just leading slash... */ |
637 |
|
|
) ? length - 1 : length; /* then remove last char */ |
638 |
ben.allan |
704 |
|
639 |
|
|
for(pos = fp->path + offset - 1; *pos!=PATH_SEPARATOR_CHAR && pos>=fp->path; --pos){ |
640 |
jpye |
2335 |
#ifdef OSPATH_DEBUG |
641 |
|
|
CONSOLE_DEBUG("CURRENT CHAR: %c\n",*pos); |
642 |
johnpye |
908 |
#endif |
643 |
ben.allan |
704 |
} |
644 |
|
|
|
645 |
ballan |
2036 |
len1 = pos - (fp->path); len2 = (int)len1; |
646 |
|
|
V(len2); |
647 |
|
|
/*fprintf(stderr,"POS = %d\n",len2);*/ |
648 |
ben.allan |
704 |
|
649 |
|
|
if(*pos==PATH_SEPARATOR_CHAR){ |
650 |
|
|
#ifdef WINPATHS |
651 |
|
|
STRCPY(sub,fp->drive); |
652 |
johnpye |
542 |
STRNCAT(sub,fp->path,len1); |
653 |
|
|
#else |
654 |
|
|
STRNCPY(sub,fp->path,len1); |
655 |
ben.allan |
704 |
sub[len1]='\0'; |
656 |
|
|
#endif |
657 |
|
|
X(sub); |
658 |
|
|
if(strcmp(sub,"")==0){ |
659 |
|
|
M("DIRECTORY IS EMPTY"); |
660 |
|
|
STRCAT(sub,PATH_SEPARATOR_STR); |
661 |
|
|
} |
662 |
|
|
}else{ |
663 |
johnpye |
1314 |
/* ie pos<fp->path */ |
664 |
|
|
M("NO PARENT DIR"); |
665 |
|
|
if(fp->path[0]==PATH_SEPARATOR_CHAR){ |
666 |
|
|
E("NO PARENT DIR"); |
667 |
|
|
return ospath_new_noclean(fp->path); |
668 |
|
|
}else{ |
669 |
|
|
M("RETURNING '.'"); |
670 |
|
|
#ifdef WINPATHS |
671 |
|
|
/* eg 'c:bin' --> 'c:' */ |
672 |
|
|
STRCPY(sub,fp->drive); |
673 |
|
|
return ospath_new_noclean(sub); |
674 |
|
|
#else |
675 |
|
|
/* eg 'bin' --> '.' */ |
676 |
|
|
return ospath_new_noclean("."); |
677 |
|
|
#endif |
678 |
|
|
} |
679 |
ben.allan |
704 |
} |
680 |
johnpye |
662 |
|
681 |
johnpye |
998 |
M("Creating 'sub'"); |
682 |
ben.allan |
704 |
fp1 = ospath_new_noclean(sub); |
683 |
johnpye |
998 |
M("... 'sub'"); |
684 |
ben.allan |
704 |
D(fp1); |
685 |
|
|
return fp1; |
686 |
|
|
} |
687 |
|
|
|
688 |
|
|
struct FilePath *ospath_getparentatdepthn(struct FilePath *fp, unsigned depth) |
689 |
|
|
{ |
690 |
|
|
int startslash; |
691 |
|
|
char path[PATH_MAX]; |
692 |
|
|
char *temp; |
693 |
|
|
char *p; |
694 |
|
|
STRTOKVAR(nexttok); |
695 |
|
|
#ifdef WINPATHS |
696 |
|
|
char temp2[PATH_MAX]; |
697 |
|
|
#endif |
698 |
|
|
|
699 |
|
|
if( |
700 |
|
|
!ospath_isvalid(fp) |
701 |
|
|
|| depth >= ospath_depth(fp) |
702 |
|
|
){ |
703 |
|
|
return fp; |
704 |
|
|
} |
705 |
|
|
|
706 |
johnpye |
908 |
/* create FilePath object to parent object at depth N relative to this |
707 |
|
|
path object.*/ |
708 |
ben.allan |
704 |
startslash = (strlen(fp->path) > 0 && fp->path[0] == PATH_SEPARATOR_CHAR); |
709 |
|
|
|
710 |
johnpye |
908 |
/* create a copy of fp->path.*/ |
711 |
ben.allan |
704 |
STRCPY(path, fp->path); |
712 |
|
|
|
713 |
johnpye |
908 |
/* reset fp->path as required.*/ |
714 |
ben.allan |
704 |
temp = startslash ? PATH_SEPARATOR_STR : ""; |
715 |
|
|
|
716 |
johnpye |
908 |
/* split path into it tokens. |
717 |
|
|
M("STARTING STRTOK");*/ |
718 |
ben.allan |
704 |
p = STRTOK(path, PATH_SEPARATOR_STR, nexttok); |
719 |
|
|
|
720 |
|
|
while(p && depth > 0) |
721 |
|
|
{ |
722 |
|
|
if(strlen(temp) > 0 && temp[strlen(temp) - 1] != PATH_SEPARATOR_CHAR) |
723 |
|
|
{ |
724 |
|
|
strcat(temp,PATH_SEPARATOR_STR); |
725 |
|
|
} |
726 |
|
|
|
727 |
|
|
STRCAT(temp,p); |
728 |
|
|
--depth; |
729 |
|
|
|
730 |
|
|
p = STRTOK(NULL, PATH_SEPARATOR_STR, nexttok); |
731 |
|
|
} |
732 |
johnpye |
908 |
#if 0 |
733 |
|
|
M("FINISHED STRTOK"); |
734 |
|
|
#endif |
735 |
ben.allan |
704 |
|
736 |
johnpye |
908 |
/* put / on end as required*/ |
737 |
ben.allan |
704 |
if(strlen(temp) > 0 ? (temp[strlen(temp) - 1] != PATH_SEPARATOR_CHAR) : 1) |
738 |
|
|
{ |
739 |
|
|
strcat(temp,PATH_SEPARATOR_STR); |
740 |
|
|
} |
741 |
|
|
|
742 |
|
|
#ifdef WINPATHS |
743 |
|
|
STRCPY(temp2,fp->drive); |
744 |
|
|
STRCAT(temp2,temp); |
745 |
|
|
return ospath_new_noclean(temp2); |
746 |
|
|
#else |
747 |
|
|
return ospath_new_noclean(temp); |
748 |
|
|
#endif |
749 |
|
|
} |
750 |
|
|
|
751 |
|
|
char *ospath_getbasefilename(struct FilePath *fp){ |
752 |
|
|
char *temp; |
753 |
|
|
unsigned length, offset; |
754 |
|
|
char *pos; |
755 |
|
|
|
756 |
johnpye |
662 |
if(fp==NULL)return NULL; |
757 |
johnpye |
542 |
|
758 |
ben.allan |
704 |
if(strlen(fp->path) == 0){ |
759 |
johnpye |
908 |
/* return empty name.*/ |
760 |
ben.allan |
704 |
return ""; |
761 |
|
|
} |
762 |
|
|
|
763 |
johnpye |
542 |
if(fp->path[strlen(fp->path)-1]==PATH_SEPARATOR_CHAR){ |
764 |
|
|
return NULL; |
765 |
|
|
} |
766 |
|
|
|
767 |
johnpye |
908 |
/* reverse find '/' but DON'T ignore a trailing slash*/ |
768 |
|
|
/* (this is changed from the original implementation)*/ |
769 |
ben.allan |
704 |
length = strlen(fp->path); |
770 |
|
|
offset = length; |
771 |
johnpye |
543 |
|
772 |
ben.allan |
704 |
pos = strrchr(fp->path, PATH_SEPARATOR_CHAR); /* OFFSET! */ |
773 |
|
|
|
774 |
johnpye |
908 |
/* extract filename given position of find / and return it.*/ |
775 |
ben.allan |
704 |
if(pos != NULL){ |
776 |
|
|
unsigned length1 = length - ((pos - fp->path)); |
777 |
|
|
temp = (char *)MALLOC(sizeof(char)*(length1+1)); |
778 |
|
|
|
779 |
|
|
V(length1); |
780 |
johnpye |
662 |
STRNCPY(temp, pos + 1, length1); |
781 |
ben.allan |
704 |
*(temp + length1)='\0'; |
782 |
|
|
return temp; |
783 |
|
|
}else{ |
784 |
|
|
temp = (char *)MALLOC(sizeof(char)*(length+1)); |
785 |
johnpye |
662 |
STRNCPY(temp, fp->path, length); |
786 |
ben.allan |
704 |
*(temp+length)='\0'; |
787 |
|
|
return temp; |
788 |
|
|
} |
789 |
|
|
} |
790 |
|
|
|
791 |
|
|
char *ospath_getfilestem(struct FilePath *fp){ |
792 |
|
|
char *temp; |
793 |
|
|
char *pos; |
794 |
|
|
|
795 |
|
|
if(!ospath_isvalid(fp)){ |
796 |
|
|
return NULL; |
797 |
|
|
} |
798 |
|
|
|
799 |
johnpye |
542 |
temp = ospath_getbasefilename(fp); |
800 |
|
|
if(temp==NULL){ |
801 |
johnpye |
908 |
/* it's a directory*/ |
802 |
johnpye |
542 |
return NULL; |
803 |
|
|
} |
804 |
|
|
|
805 |
ben.allan |
704 |
pos = strrchr(temp,'.'); |
806 |
|
|
|
807 |
johnpye |
542 |
if(pos==NULL || pos==temp){ |
808 |
johnpye |
908 |
/* no extension, or a filename starting with '.' |
809 |
|
|
-- return the whole filename*/ |
810 |
johnpye |
542 |
return temp; |
811 |
|
|
} |
812 |
|
|
|
813 |
johnpye |
908 |
/* remove extension.*/ |
814 |
johnpye |
542 |
*pos = '\0'; |
815 |
|
|
|
816 |
ben.allan |
704 |
return temp; |
817 |
|
|
} |
818 |
|
|
|
819 |
|
|
char *ospath_getfileext(struct FilePath *fp){ |
820 |
|
|
char *temp, *temp2, *pos; |
821 |
|
|
int len1; |
822 |
|
|
|
823 |
|
|
if(!ospath_isvalid(fp)){ |
824 |
|
|
return NULL; |
825 |
|
|
} |
826 |
|
|
|
827 |
johnpye |
542 |
temp = ospath_getbasefilename(fp); |
828 |
|
|
if(temp==NULL){ |
829 |
johnpye |
908 |
/* it's a directory*/ |
830 |
johnpye |
542 |
return NULL; |
831 |
ben.allan |
704 |
} |
832 |
|
|
|
833 |
johnpye |
908 |
/* make sure there is no / on the end. |
834 |
|
|
FIXME: is this good policy, removing a trailing slash?*/ |
835 |
ben.allan |
704 |
if(temp[strlen(temp) - 1] == PATH_SEPARATOR_CHAR){ |
836 |
|
|
temp[strlen(temp)-1] = '\0'; |
837 |
|
|
} |
838 |
|
|
|
839 |
|
|
pos = strrchr(temp,'.'); |
840 |
|
|
|
841 |
|
|
if(pos != NULL && pos!=temp){ |
842 |
johnpye |
908 |
/* extract extension.*/ |
843 |
ben.allan |
704 |
len1 = temp + strlen(temp) - pos + 1; |
844 |
|
|
temp2 = (char *)MALLOC(sizeof(char)*len1); |
845 |
|
|
STRNCPY(temp2, pos, len1); |
846 |
|
|
}else{ |
847 |
johnpye |
908 |
/* no extension*/ |
848 |
ben.allan |
704 |
temp2 = NULL; |
849 |
|
|
} |
850 |
|
|
FREE(temp); |
851 |
|
|
return temp2; |
852 |
johnpye |
542 |
} |
853 |
|
|
|
854 |
ben.allan |
704 |
int ospath_isroot(struct FilePath *fp) |
855 |
|
|
{ |
856 |
jpye |
2335 |
if(!ospath_isvalid(fp)){ |
857 |
|
|
#ifdef OSPATH_DEBUG |
858 |
|
|
fprintf(stderr,"path is invalid\n"); |
859 |
|
|
#endif |
860 |
ben.allan |
704 |
return 0; |
861 |
|
|
} |
862 |
|
|
|
863 |
jpye |
2335 |
return strcmp(fp->path, PATH_SEPARATOR_STR) ? 0 : 1; |
864 |
ben.allan |
704 |
} |
865 |
|
|
|
866 |
|
|
unsigned ospath_depth(struct FilePath *fp){ |
867 |
|
|
unsigned length; |
868 |
|
|
unsigned depth; |
869 |
|
|
unsigned i; |
870 |
|
|
|
871 |
|
|
length = strlen(fp->path); |
872 |
|
|
depth = 0; |
873 |
|
|
|
874 |
|
|
for(i = 0; i < length; i++){ |
875 |
|
|
if(fp->path[i] == PATH_SEPARATOR_CHAR){ |
876 |
|
|
++depth; |
877 |
|
|
} |
878 |
|
|
} |
879 |
|
|
|
880 |
|
|
if( |
881 |
|
|
depth > 0 |
882 |
|
|
&& length > 0 |
883 |
|
|
&& fp->path[length - 1] == PATH_SEPARATOR_CHAR |
884 |
|
|
){ |
885 |
johnpye |
908 |
/* PATH_SEPARATOR_CHAR on the end, reduce count by 1*/ |
886 |
ben.allan |
704 |
--depth; |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
return depth; |
890 |
|
|
} |
891 |
|
|
|
892 |
|
|
struct FilePath *ospath_root(struct FilePath *fp){ |
893 |
|
|
#ifdef WINPATHS |
894 |
johnpye |
908 |
#if 0 |
895 |
|
|
M("WIN ROOT"); |
896 |
|
|
#endif |
897 |
ben.allan |
704 |
char *temp; |
898 |
|
|
struct FilePath *r; |
899 |
|
|
|
900 |
|
|
if(strlen(fp->drive)){ |
901 |
|
|
temp = (char *)MALLOC(sizeof(char)*strlen(fp->drive)+1); |
902 |
|
|
STRCPY(temp,fp->drive); |
903 |
|
|
STRCAT(temp,PATH_SEPARATOR_STR); |
904 |
|
|
X(temp); |
905 |
|
|
r = ospath_new(temp); |
906 |
|
|
FREE(temp); |
907 |
|
|
}else{ |
908 |
|
|
r = ospath_new(fp->path); |
909 |
|
|
} |
910 |
|
|
return r; |
911 |
|
|
#else |
912 |
johnpye |
908 |
(void)fp; |
913 |
|
|
#if 0 |
914 |
|
|
M("JUST RETURNING PATH SEP"); |
915 |
|
|
#endif |
916 |
ben.allan |
704 |
return ospath_new(PATH_SEPARATOR_STR); |
917 |
|
|
#endif |
918 |
|
|
} |
919 |
|
|
|
920 |
johnpye |
542 |
struct FilePath *ospath_getdir(struct FilePath *fp){ |
921 |
|
|
char *pos; |
922 |
|
|
char s[PATH_MAX]; |
923 |
johnpye |
864 |
#ifdef WINPATHS |
924 |
johnpye |
866 |
int e; |
925 |
johnpye |
864 |
#endif |
926 |
johnpye |
542 |
|
927 |
|
|
pos = strrchr(fp->path,PATH_SEPARATOR_CHAR); |
928 |
|
|
if(pos==NULL){ |
929 |
johnpye |
721 |
return ospath_new_noclean(""); |
930 |
johnpye |
542 |
} |
931 |
|
|
#ifdef WINPATHS |
932 |
|
|
strncpy(s,fp->drive,PATH_MAX); |
933 |
johnpye |
864 |
e = strlen(s); |
934 |
johnpye |
542 |
strncat(s,fp->path,pos - fp->path); |
935 |
johnpye |
864 |
s[e+pos-fp->path]='\0'; |
936 |
johnpye |
542 |
#else |
937 |
|
|
strncpy(s,fp->path,pos - fp->path); |
938 |
johnpye |
864 |
s[pos-fp->path]='\0'; |
939 |
johnpye |
931 |
/* CONSOLE_DEBUG("DIRECTORY: '%s'",s); */ |
940 |
johnpye |
542 |
#endif |
941 |
|
|
return ospath_new(s); |
942 |
|
|
} |
943 |
|
|
|
944 |
johnpye |
1063 |
ASC_DLLSPEC struct FilePath *ospath_getabs(struct FilePath *fp){ |
945 |
johnpye |
721 |
struct FilePath *fp1, *fp2; |
946 |
johnpye |
741 |
if(fp->path[0]==PATH_SEPARATOR_CHAR){ |
947 |
|
|
fp1 = ospath_new_copy(fp); |
948 |
johnpye |
721 |
}else{ |
949 |
|
|
fp2 = ospath_new("."); |
950 |
|
|
fp1 = ospath_concat(fp2,fp); |
951 |
|
|
ospath_free(fp2); |
952 |
|
|
} |
953 |
|
|
return fp1; |
954 |
|
|
} |
955 |
|
|
|
956 |
ben.allan |
704 |
int ospath_cmp(struct FilePath *fp1, struct FilePath *fp2){ |
957 |
|
|
char temp[2][PATH_MAX]; |
958 |
|
|
#ifdef WINPATHS |
959 |
|
|
char *p; |
960 |
|
|
struct FilePath *fp; |
961 |
|
|
#endif |
962 |
|
|
|
963 |
|
|
if(!ospath_isvalid(fp1)){ |
964 |
|
|
if(!ospath_isvalid(fp2)){ |
965 |
|
|
return 0; |
966 |
|
|
}else{ |
967 |
|
|
return -1; |
968 |
|
|
} |
969 |
|
|
}else if(!ospath_isvalid(fp2)){ |
970 |
|
|
return 1; |
971 |
|
|
} |
972 |
|
|
|
973 |
johnpye |
908 |
#if 0 |
974 |
|
|
/ now, both are valid... |
975 |
|
|
M("BOTH ARE VALID"); |
976 |
ben.allan |
704 |
|
977 |
johnpye |
908 |
/Check that paths both have drives, if applic. |
978 |
|
|
#endif |
979 |
ben.allan |
704 |
#ifdef WINPATHS |
980 |
|
|
if(strcmp(fp1->drive,"")==0){ |
981 |
|
|
M("PATH IS MISSING DRIVE LETTER"); |
982 |
|
|
D(fp1); |
983 |
|
|
fp = ospath_getcwd(); |
984 |
|
|
assert(strlen(fp->drive)!=0); |
985 |
|
|
X(fp->drive); |
986 |
|
|
STRCPY(temp[0],fp->drive); |
987 |
|
|
ospath_free(fp); |
988 |
|
|
}else{ |
989 |
|
|
STRCPY(temp[0],fp1->drive); |
990 |
|
|
} |
991 |
|
|
|
992 |
|
|
if(strcmp(fp2->drive,"")==0){ |
993 |
|
|
M("PATH IS MISSING DRIVE LETTER"); |
994 |
|
|
D(fp2); |
995 |
|
|
fp = ospath_getcwd(); |
996 |
|
|
assert(strlen(fp->drive)!=0); |
997 |
|
|
X(fp->drive); |
998 |
|
|
STRCPY(temp[1],fp->drive); |
999 |
|
|
ospath_free(fp); |
1000 |
|
|
}else{ |
1001 |
|
|
STRCPY(temp[1],fp2->drive); |
1002 |
|
|
} |
1003 |
|
|
|
1004 |
|
|
STRCAT(temp[0],fp1->path); |
1005 |
|
|
STRCAT(temp[1],fp2->path); |
1006 |
|
|
#else |
1007 |
|
|
STRCPY(temp[0], fp1->path); |
1008 |
|
|
STRCPY(temp[1], fp2->path); |
1009 |
|
|
#endif |
1010 |
|
|
|
1011 |
|
|
#ifdef WINPATHS |
1012 |
|
|
X(temp[0]); |
1013 |
|
|
for(p=temp[0];*p!='\0';++p){ |
1014 |
|
|
*p=tolower(*p); |
1015 |
johnpye |
908 |
#if 0 |
1016 |
|
|
C(*p); |
1017 |
|
|
#endif |
1018 |
ben.allan |
704 |
} |
1019 |
|
|
X(temp[1]); |
1020 |
|
|
for(p=temp[1];*p!='\0';++p){ |
1021 |
|
|
*p=tolower(*p); |
1022 |
johnpye |
908 |
#if 0 |
1023 |
|
|
C(*p); |
1024 |
|
|
#endif |
1025 |
ben.allan |
704 |
} |
1026 |
|
|
X(temp[0]); |
1027 |
|
|
X(temp[1]); |
1028 |
|
|
#endif |
1029 |
|
|
|
1030 |
johnpye |
908 |
/* we will count two paths that different only in a trailing slash to be the *same* |
1031 |
|
|
so we add trailing slashes to both now: */ |
1032 |
ben.allan |
704 |
if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR){ |
1033 |
|
|
STRCAT(temp[0],PATH_SEPARATOR_STR); |
1034 |
|
|
} |
1035 |
|
|
|
1036 |
|
|
if(temp[1][strlen(temp[1]) - 1] != PATH_SEPARATOR_CHAR){ |
1037 |
|
|
STRCAT(temp[1],PATH_SEPARATOR_STR); |
1038 |
|
|
} |
1039 |
|
|
|
1040 |
johnpye |
908 |
#if 0 |
1041 |
|
|
X(temp[0]); |
1042 |
|
|
X(temp[1]); |
1043 |
|
|
#endif |
1044 |
ben.allan |
704 |
|
1045 |
|
|
return strcmp(temp[0],temp[1]); |
1046 |
|
|
} |
1047 |
|
|
|
1048 |
|
|
struct FilePath *ospath_concat(struct FilePath *fp1, struct FilePath *fp2){ |
1049 |
|
|
|
1050 |
|
|
struct FilePath *fp; |
1051 |
|
|
char temp[2][PATH_MAX]; |
1052 |
|
|
char temp2[PATH_MAX]; |
1053 |
|
|
struct FilePath *r; |
1054 |
|
|
|
1055 |
|
|
fp = (struct FilePath *)MALLOC(sizeof(struct FilePath)); |
1056 |
|
|
|
1057 |
|
|
if(!ospath_isvalid(fp1)){ |
1058 |
|
|
if(ospath_isvalid(fp2)){ |
1059 |
|
|
ospath_copy(fp,fp2); |
1060 |
|
|
}else{ |
1061 |
johnpye |
908 |
/* both invalid*/ |
1062 |
ben.allan |
704 |
ospath_copy(fp,fp1); |
1063 |
|
|
} |
1064 |
|
|
return fp; |
1065 |
|
|
} |
1066 |
|
|
|
1067 |
|
|
if(!ospath_isvalid(fp2)){ |
1068 |
|
|
ospath_copy(fp,fp1); |
1069 |
|
|
return fp; |
1070 |
|
|
} |
1071 |
|
|
|
1072 |
johnpye |
908 |
/* not just a copy of one or the other...*/ |
1073 |
ben.allan |
704 |
ospath_free(fp); |
1074 |
|
|
|
1075 |
johnpye |
908 |
/* now, both paths are valid...*/ |
1076 |
ben.allan |
704 |
|
1077 |
|
|
#ifdef WINPATHS |
1078 |
|
|
STRNCPY(temp[0],fp1->drive,PATH_MAX); |
1079 |
|
|
STRNCAT(temp[0],fp1->path,PATH_MAX-strlen(temp[0])); |
1080 |
|
|
#else |
1081 |
|
|
STRNCPY(temp[0], fp1->path,PATH_MAX); |
1082 |
|
|
#endif |
1083 |
|
|
|
1084 |
|
|
STRNCPY(temp[1], fp2->path,PATH_MAX); |
1085 |
|
|
|
1086 |
johnpye |
908 |
/* make sure temp has a / on the end. */ |
1087 |
ben.allan |
704 |
if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR) |
1088 |
|
|
{ |
1089 |
|
|
STRNCAT(temp[0],PATH_SEPARATOR_STR,PATH_MAX-strlen(temp[0])); |
1090 |
|
|
} |
1091 |
|
|
|
1092 |
johnpye |
542 |
#ifdef DO_FIXSLASHES |
1093 |
ben.allan |
704 |
ospath_fixslash(temp[0]); |
1094 |
|
|
ospath_fixslash(temp[1]); |
1095 |
johnpye |
542 |
#endif |
1096 |
ben.allan |
704 |
|
1097 |
johnpye |
908 |
#if 0 |
1098 |
|
|
V(strlen(temp[0])); |
1099 |
|
|
X(temp[0]); |
1100 |
|
|
V(strlen(temp[1])); |
1101 |
|
|
X(temp[1]); |
1102 |
|
|
#endif |
1103 |
ben.allan |
704 |
|
1104 |
johnpye |
908 |
/* make sure rhs path has NOT got a / at the start. */ |
1105 |
ben.allan |
704 |
if(temp[1][0] == PATH_SEPARATOR_CHAR){ |
1106 |
|
|
return NULL; |
1107 |
|
|
} |
1108 |
|
|
|
1109 |
johnpye |
908 |
/* create a new path object with the two path strings appended together.*/ |
1110 |
ben.allan |
704 |
STRNCPY(temp2,temp[0],PATH_MAX); |
1111 |
|
|
STRNCAT(temp2,temp[1],PATH_MAX-strlen(temp2)); |
1112 |
johnpye |
908 |
#if 0 |
1113 |
|
|
V(strlen(temp2)); |
1114 |
|
|
X(temp2); |
1115 |
|
|
#endif |
1116 |
ben.allan |
704 |
r = ospath_new_noclean(temp2); |
1117 |
|
|
D(r); |
1118 |
|
|
|
1119 |
|
|
/* ospath_cleanup(r);*/ |
1120 |
|
|
return r; |
1121 |
|
|
} |
1122 |
|
|
|
1123 |
|
|
void ospath_append(struct FilePath *fp, struct FilePath *fp1){ |
1124 |
|
|
char *p; |
1125 |
|
|
char temp[2][PATH_MAX]; |
1126 |
|
|
struct FilePath fp2; |
1127 |
|
|
|
1128 |
|
|
ospath_copy(&fp2,fp1); |
1129 |
johnpye |
542 |
#ifdef DO_FIXSLASHES |
1130 |
ben.allan |
704 |
ospath_fixslash(fp2.path); |
1131 |
|
|
#endif |
1132 |
|
|
|
1133 |
|
|
if(!ospath_isvalid(&fp2)){ |
1134 |
|
|
M("fp1 invalid"); |
1135 |
|
|
return; |
1136 |
|
|
} |
1137 |
|
|
|
1138 |
|
|
if(!ospath_isvalid(fp) && ospath_isvalid(&fp2)){ |
1139 |
johnpye |
908 |
/* set this object to be the same as the rhs */ |
1140 |
ben.allan |
704 |
M("fp invalid"); |
1141 |
|
|
ospath_copy(fp,&fp2); |
1142 |
|
|
#ifdef DO_FIXSLASHES |
1143 |
johnpye |
542 |
ospath_fixslash(fp->path); |
1144 |
ben.allan |
704 |
#endif |
1145 |
|
|
return; |
1146 |
|
|
} |
1147 |
|
|
|
1148 |
|
|
X(fp->path); |
1149 |
|
|
X(fp2.path); |
1150 |
|
|
|
1151 |
johnpye |
908 |
/* both paths are valid...*/ |
1152 |
|
|
#if 0 |
1153 |
|
|
temp[0] = CALLOC(1+strlen(fp->path), sizeof(char)); |
1154 |
|
|
#endif |
1155 |
ben.allan |
704 |
STRNCPY(temp[0], fp->path, PATH_MAX); |
1156 |
johnpye |
908 |
#if 0 |
1157 |
|
|
temp[1] = CALLOC(strlen(fp2.path), sizeof(char)); |
1158 |
|
|
#endif |
1159 |
ben.allan |
704 |
STRNCPY(temp[1], fp2.path, PATH_MAX); |
1160 |
|
|
|
1161 |
|
|
X(temp[0]); |
1162 |
|
|
X(temp[1]); |
1163 |
|
|
|
1164 |
johnpye |
908 |
/* make sure temp has a / on the end. */ |
1165 |
ben.allan |
704 |
if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR) |
1166 |
|
|
{ |
1167 |
|
|
STRCAT(temp[0],PATH_SEPARATOR_STR); |
1168 |
|
|
} |
1169 |
|
|
|
1170 |
johnpye |
908 |
/* make sure rhs path has NOT got a / at the start. */ |
1171 |
ben.allan |
704 |
if(temp[1][0] == PATH_SEPARATOR_CHAR){ |
1172 |
|
|
for(p=temp[1]+1; *p != '\0'; ++p){ |
1173 |
|
|
*(p-1)=*p; |
1174 |
|
|
} |
1175 |
|
|
*(p-1)='\0'; |
1176 |
|
|
} |
1177 |
|
|
|
1178 |
|
|
X(temp[0]); |
1179 |
|
|
X(temp[1]); |
1180 |
|
|
|
1181 |
johnpye |
908 |
/*create new path string.*/ |
1182 |
ben.allan |
704 |
STRNCPY(fp->path,temp[0], PATH_MAX); |
1183 |
|
|
STRNCAT(fp->path,temp[1], PATH_MAX-strlen(fp->path)); |
1184 |
|
|
|
1185 |
|
|
X(fp->path); |
1186 |
|
|
|
1187 |
johnpye |
908 |
#if 0 |
1188 |
|
|
FREE(temp[0]); |
1189 |
|
|
M("Freed temp[0]"); |
1190 |
|
|
FREE(temp[1]); |
1191 |
|
|
M("Freed temp[1]"); |
1192 |
|
|
#endif |
1193 |
ben.allan |
704 |
|
1194 |
|
|
D(fp); |
1195 |
|
|
ospath_cleanup(fp); |
1196 |
johnpye |
542 |
} |
1197 |
|
|
|
1198 |
ben.allan |
704 |
void ospath_copy(struct FilePath *dest, struct FilePath *src){ |
1199 |
|
|
STRCPY(dest->path,src->path); |
1200 |
|
|
#ifdef WINPATHS |
1201 |
|
|
STRCPY(dest->drive,src->drive); |
1202 |
|
|
#endif |
1203 |
|
|
} |
1204 |
|
|
|
1205 |
|
|
void ospath_debug(struct FilePath *fp){ |
1206 |
|
|
#ifdef WINPATHS |
1207 |
|
|
fprintf(stderr,"{\"%s\",\"%s\"}\n",fp->drive,fp->path); |
1208 |
|
|
#else |
1209 |
|
|
fprintf(stderr,"{\"%s\"}\n",fp->path); |
1210 |
|
|
#endif |
1211 |
|
|
} |
1212 |
|
|
|
1213 |
johnpye |
542 |
FILE *ospath_fopen(struct FilePath *fp, const char *mode){ |
1214 |
|
|
char s[PATH_MAX]; |
1215 |
johnpye |
635 |
FILE *f; |
1216 |
|
|
|
1217 |
johnpye |
542 |
if(!ospath_isvalid(fp)){ |
1218 |
|
|
E("Invalid path"); |
1219 |
|
|
return NULL; |
1220 |
|
|
} |
1221 |
johnpye |
741 |
ospath_strncpy(fp,s,PATH_MAX); |
1222 |
johnpye |
635 |
f = fopen(s,mode); |
1223 |
ben.allan |
704 |
return f; |
1224 |
johnpye |
542 |
} |
1225 |
johnpye |
662 |
|
1226 |
johnpye |
741 |
int ospath_stat(struct FilePath *fp,ospath_stat_t *buf){ |
1227 |
johnpye |
662 |
char s[PATH_MAX]; |
1228 |
|
|
|
1229 |
|
|
if(!ospath_isvalid(fp)){ |
1230 |
|
|
E("Invalid path"); |
1231 |
|
|
return -1; |
1232 |
|
|
} |
1233 |
johnpye |
741 |
ospath_strncpy(fp,s,PATH_MAX); |
1234 |
johnpye |
742 |
return STAT(s,buf); |
1235 |
johnpye |
741 |
} |
1236 |
ben.allan |
704 |
|
1237 |
johnpye |
908 |
/*------------------------ |
1238 |
|
|
SEARCH PATH FUNCTIONS |
1239 |
|
|
*/ |
1240 |
ben.allan |
704 |
|
1241 |
|
|
struct FilePath **ospath_searchpath_new(const char *path){ |
1242 |
|
|
char *p; |
1243 |
|
|
char *list[LISTMAX]; |
1244 |
|
|
unsigned n=0; |
1245 |
|
|
char *c; |
1246 |
|
|
unsigned i; |
1247 |
|
|
struct FilePath **pp; |
1248 |
johnpye |
908 |
char path1[PATH_MAX]; |
1249 |
|
|
|
1250 |
johnpye |
542 |
STRTOKVAR(nexttok); |
1251 |
|
|
|
1252 |
|
|
strncpy(path1,path,PATH_MAX); |
1253 |
|
|
|
1254 |
|
|
X(path1); |
1255 |
|
|
X(PATH_LISTSEP_STR); |
1256 |
|
|
|
1257 |
|
|
V(strlen(path1)); |
1258 |
|
|
V(strlen(PATH_LISTSEP_STR)); |
1259 |
|
|
|
1260 |
|
|
/* |
1261 |
|
|
c = strstr(path,PATH_LISTSEP_CHAR); |
1262 |
|
|
if(c==NULL){ |
1263 |
|
|
E("NO TOKEN FOUND"); |
1264 |
|
|
} |
1265 |
ben.allan |
704 |
*/ |
1266 |
johnpye |
542 |
|
1267 |
|
|
p=STRTOK(path1,PATH_LISTSEP_STR,nexttok); |
1268 |
ben.allan |
704 |
X(p); |
1269 |
|
|
for(; p!= NULL; p=STRTOK(NULL,PATH_LISTSEP_STR,nexttok)){ |
1270 |
|
|
c = (char *)MALLOC(sizeof(char)*(strlen(p)+1)); |
1271 |
|
|
X(p); |
1272 |
|
|
STRCPY(c,p); |
1273 |
|
|
if(n>=LISTMAX){ |
1274 |
|
|
E("IGNORING SOME PATH COMPONENTS"); |
1275 |
|
|
break; |
1276 |
|
|
} |
1277 |
|
|
list[n++]=c; |
1278 |
|
|
} |
1279 |
|
|
|
1280 |
johnpye |
866 |
|
1281 |
johnpye |
542 |
for(i=0;i<n;++i){ |
1282 |
ben.allan |
704 |
X(list[i]); |
1283 |
|
|
} |
1284 |
|
|
V(n); |
1285 |
|
|
|
1286 |
johnpye |
866 |
|
1287 |
ben.allan |
704 |
pp = (struct FilePath **)MALLOC(sizeof(struct FilePath*)*(n+1)); |
1288 |
|
|
for(i=0; i<n; ++i){ |
1289 |
johnpye |
908 |
#if 0 |
1290 |
|
|
V(i); |
1291 |
|
|
X(list[i]); |
1292 |
|
|
#endif |
1293 |
ben.allan |
704 |
pp[i] = ospath_new_noclean(list[i]); |
1294 |
johnpye |
908 |
#if 0 |
1295 |
|
|
D(pp[i]); |
1296 |
|
|
#endif |
1297 |
johnpye |
998 |
FREE(list[i]); |
1298 |
ben.allan |
704 |
} |
1299 |
|
|
pp[n] = NULL; |
1300 |
|
|
|
1301 |
|
|
for(i=0;i<n;++i){ |
1302 |
johnpye |
542 |
#ifdef DO_FIXSLASHES |
1303 |
|
|
ospath_fixslash(pp[i]->path); |
1304 |
ben.allan |
704 |
#endif |
1305 |
|
|
D(pp[i]); |
1306 |
|
|
} |
1307 |
|
|
|
1308 |
|
|
return pp; |
1309 |
johnpye |
542 |
} |
1310 |
|
|
|
1311 |
|
|
void ospath_searchpath_free(struct FilePath **searchpath){ |
1312 |
|
|
struct FilePath **p; |
1313 |
|
|
for(p=searchpath; *p!=NULL; ++p){ |
1314 |
|
|
ospath_free(*p); |
1315 |
|
|
} |
1316 |
|
|
FREE(searchpath); |
1317 |
ben.allan |
704 |
} |
1318 |
johnpye |
662 |
|
1319 |
|
|
int ospath_searchpath_length(struct FilePath **searchpath){ |
1320 |
|
|
int i=0; |
1321 |
|
|
struct FilePath **p; |
1322 |
|
|
for(p=searchpath; *p!=NULL; ++p){ |
1323 |
|
|
++i; |
1324 |
|
|
} |
1325 |
|
|
return i; |
1326 |
|
|
} |
1327 |
ben.allan |
704 |
|
1328 |
|
|
struct FilePath *ospath_searchpath_iterate( |
1329 |
|
|
struct FilePath **searchpath |
1330 |
|
|
, FilePathTestFn *testfn |
1331 |
|
|
, void *searchdata |
1332 |
|
|
){ |
1333 |
|
|
struct FilePath **p; |
1334 |
|
|
|
1335 |
johnpye |
542 |
p = searchpath; |
1336 |
|
|
|
1337 |
|
|
M("SEARCHING IN..."); |
1338 |
|
|
for(p=searchpath; *p!=NULL; ++p){ |
1339 |
|
|
D(*p); |
1340 |
ben.allan |
704 |
} |
1341 |
|
|
|
1342 |
|
|
for(p=searchpath; *p!=NULL; ++p){ |
1343 |
johnpye |
542 |
D(*p); |
1344 |
johnpye |
662 |
assert(*p!=NULL); |
1345 |
ben.allan |
704 |
if((*testfn)(*p,searchdata)){ |
1346 |
|
|
return *p; |
1347 |
|
|
} |
1348 |
|
|
} |
1349 |
|
|
return NULL; |
1350 |
|
|
} |