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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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