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