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

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