/[ascend]/trunk/base/generic/general/ospath.c
ViewVC logotype

Annotation of /trunk/base/generic/general/ospath.c

Parent Directory Parent Directory | Revision Log Revision Log


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

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22