/[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 931 - (show annotations) (download) (as text)
Thu Nov 23 04:31:19 2006 UTC (13 years, 7 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 /* 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
44 /* #define VERBOSE */
45
46 #if !defined(TEST) && !defined(VERBOSE)
47 #ifndef NDEBUG
48 # define NDEBUG
49 #endif
50 #endif
51
52 #ifdef _MSC_VER
53 # define STAT _stat
54 #else
55 # define STAT stat
56 #endif
57
58 //#define TRY_GETPWUID
59
60 #define DO_FIXSLASHES
61
62 #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 /* PATH_MAX is in ospath.h */
105 #define DRIVEMAX 3
106 #define LISTMAX 256
107
108 #ifdef __WIN32__ /* && !defined(__MINGW32__) */
109 # define WINPATHS
110 #endif
111
112 struct FilePath{
113 char path[PATH_MAX]; /** the string version of the represented POSIX path */
114
115 #ifdef WINPATHS
116 char drive[DRIVEMAX]; /** the drive the path resides on (field is absent in POSIX systems) */
117 #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 void ospath_fixslash(char *path);
131 #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 # define PATH_LISTSEP_STR ";"
151 # 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 #if 0
176 D(fp);
177 #endif
178
179 return fp;
180 }
181
182
183
184 /** Create but with no 'cleanup', and no fixing of / vs \. */
185 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 #if 0
191 X(fp->path);
192 #endif
193 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 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
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 #if 0
242 X(fp->path);
243 #endif
244
245 ospath_cleanup(fp);
246
247 return fp;
248 }
249
250 void ospath_free(struct FilePath *fp){
251 if(fp!=NULL){
252 FREE(fp);
253 }
254 fp=NULL;
255 }
256
257 void ospath_free_str(char *str){
258 FREE(str);
259 }
260
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 #if 0
274 X(path);
275 #endif
276
277 startslash = (strlen(temp) > 0 && temp[0] == PATH_WRONGSLASH_CHAR);
278 endslash = (strlen(temp) > 1 && temp[strlen(temp) - 1] == PATH_WRONGSLASH_CHAR);
279
280 #if 0
281 V(startslash);
282 V(endslash);
283
284 #endif
285 /* reset fp->path as required. */
286 STRNCPY(path, (startslash ? PATH_SEPARATOR_STR : ""), PATH_MAX);
287
288 #if 0
289 M("STARTING STRTOK");
290 #endif
291 for(p = STRTOK(temp, PATH_WRONGSLASH_STR,nexttok);
292 p!=NULL;
293 p = STRTOK(NULL,PATH_WRONGSLASH_STR,nexttok)
294 ){
295 /* add a separator if we've already got some stuff */
296 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 #if 0
306 M("FINISHED STRTOK");
307 #endif
308
309 /* put / on end as required, according to what the starting path had */
310 if(endslash && (strlen(path) > 0 ? (path[strlen(path) - 1] != PATH_SEPARATOR_CHAR) : 1))
311 {
312 #if 0
313 M("adding endslash!");
314 #endif
315
316 STRCAT(path, PATH_SEPARATOR_STR);
317 }
318
319 #if 0
320 X(path);
321 #endif
322 }
323 #endif
324
325 struct FilePath *ospath_getcwd(void){
326 struct FilePath *fp = (struct FilePath *)MALLOC(sizeof(struct FilePath));
327 char *cwd;
328
329 /* get current working directory */
330 cwd = (char *)GETCWD(NULL, 0);
331
332 /* create new path with resolved working directory */
333 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 #ifndef __WIN32__
350 # 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 }
360 # endif
361 #endif
362
363 /* create path object from HOME, but don't compress it
364 (because that would lead to an infinite loop) */
365 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 #ifdef WINPATHS
375 void ospath_extractdriveletter(struct FilePath *fp)
376 {
377 char *p;
378 #if 0
379 M("SOURCE");
380 X(fp->path);
381 fprintf(stderr,"CHAR 1 = %c\n",fp->path[1]);
382 #endif
383
384 /* extract the drive the path resides on... */
385 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 #if 0
397 M("RESULT");
398 X(fp->path);
399 X(fp->drive);
400 #endif
401 }
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 int startslash, endslash;
411 STRTOKVAR(nexttok);
412
413 /* 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
417 #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
423 home = ospath_gethomepath();
424
425 /* create a copy of fp->path. */
426 STRCPY(path, fp->path);
427
428 /* reset fp->path as required. */
429 STRCPY(fp->path, (startslash ? PATH_SEPARATOR_STR : ""));
430
431 D(fp);
432 X(path);
433
434 /* split path into it tokens, using STRTOK which is NOT reentrant
435 so be careful! */
436
437 /*M("STARTING STRTOK"); */
438 for(p = STRTOK(path, PATH_SEPARATOR_STR,nexttok);
439 p!=NULL;
440 p = STRTOK(NULL,PATH_SEPARATOR_STR,nexttok)
441 ){
442 #if 0
443 M("NEXT TOKEN");
444 X(p);
445 X(path+strlen(p)+1);
446 #endif
447 if(strcmp(p, "~")==0){
448
449 if(p == path){ /* check that the ~ is the first character in the path */
450 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 if(p==path){/* start of path: */
462 M("EXPANDING LEADING '.' IN PATH");
463 X(path);
464
465 working = ospath_getcwd();
466
467 D(working);
468 #ifdef WINPATHS
469 X(working->drive);
470 #endif
471 X(p);
472 X(path);
473
474 ospath_copy(fp,working);
475
476
477 D(fp);
478 X(p);
479 #if 0
480 X(path+strlen(p)+1);
481 ospath_free(working);
482 #endif
483 continue;
484 }else{/* later in the path: just skip it */
485 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 #if 0
496 ospath_free(parent);
497 #endif
498 continue;
499 }
500
501 /* add a separator if we've already got some stuff */
502 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 /* add the present path component */
510 STRCAT(fp->path, p);
511 }
512 #if 0
513 M("FINISHED STRTOK");
514 #endif
515
516 ospath_free(home);
517
518 // 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 int ospath_isvalid(struct FilePath *fp){
527 /*if(fp==NULL) return 0; */
528 return strlen(fp->path) > 0 ? 1 : 0;
529 }
530
531
532 char *ospath_str(const struct FilePath *fp){
533 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 void ospath_strncpy(struct FilePath *fp, char *dest, int destsize){
546 #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 #endif
552 }
553
554 void ospath_strcat(struct FilePath *fp, char *dest, int destsize){
555 int remaining = destsize - strlen(dest);
556 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 #endif
563 D(fp);
564 }
565
566 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 /* 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 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 if(strlen(fp->path) == 0){
596 fp1 = ospath_getcwd();
597 fp2 = ospath_getparent(fp1);
598 ospath_free(fp1);
599 return fp2;
600 }else if(ospath_isroot(fp)){
601 /* stay at root */
602 return ospath_new("/");
603 }
604
605 /* reverse find a / ignoring the end / if it exists.
606 /// FIXME */
607 length = strlen(fp->path);
608 offset = (
609 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
613 for(pos = fp->path + offset - 1; *pos!=PATH_SEPARATOR_CHAR && pos>=fp->path; --pos){
614 #if 0
615 fprintf(stderr,"CURRENT CHAR: %c\n",*pos);
616 #endif
617 }
618
619 len1 = (int)pos - (int)fp->path;
620 V(len1);
621 /*fprintf(stderr,"POS = %d\n",len1);*/
622
623 if(*pos==PATH_SEPARATOR_CHAR){
624 #ifdef WINPATHS
625 STRCPY(sub,fp->drive);
626 STRNCAT(sub,fp->path,len1);
627 #else
628 STRNCPY(sub,fp->path,len1);
629 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
641 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 /* create FilePath object to parent object at depth N relative to this
665 path object.*/
666 startslash = (strlen(fp->path) > 0 && fp->path[0] == PATH_SEPARATOR_CHAR);
667
668 /* create a copy of fp->path.*/
669 STRCPY(path, fp->path);
670
671 /* reset fp->path as required.*/
672 temp = startslash ? PATH_SEPARATOR_STR : "";
673
674 /* split path into it tokens.
675 M("STARTING STRTOK");*/
676 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 #if 0
691 M("FINISHED STRTOK");
692 #endif
693
694 /* put / on end as required*/
695 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 if(fp==NULL)return NULL;
715
716 if(strlen(fp->path) == 0){
717 /* return empty name.*/
718 return "";
719 }
720
721 if(fp->path[strlen(fp->path)-1]==PATH_SEPARATOR_CHAR){
722 return NULL;
723 }
724
725 /* reverse find '/' but DON'T ignore a trailing slash*/
726 /* (this is changed from the original implementation)*/
727 length = strlen(fp->path);
728 offset = length;
729
730 pos = strrchr(fp->path, PATH_SEPARATOR_CHAR); /* OFFSET! */
731
732 /* extract filename given position of find / and return it.*/
733 if(pos != NULL){
734 unsigned length1 = length - ((pos - fp->path));
735 temp = (char *)MALLOC(sizeof(char)*(length1+1));
736
737 V(length1);
738 STRNCPY(temp, pos + 1, length1);
739 *(temp + length1)='\0';
740 return temp;
741 }else{
742 temp = (char *)MALLOC(sizeof(char)*(length+1));
743 STRNCPY(temp, fp->path, length);
744 *(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 temp = ospath_getbasefilename(fp);
758 if(temp==NULL){
759 /* it's a directory*/
760 return NULL;
761 }
762
763 pos = strrchr(temp,'.');
764
765 if(pos==NULL || pos==temp){
766 /* no extension, or a filename starting with '.'
767 -- return the whole filename*/
768 return temp;
769 }
770
771 /* remove extension.*/
772 *pos = '\0';
773
774 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 temp = ospath_getbasefilename(fp);
786 if(temp==NULL){
787 /* it's a directory*/
788 return NULL;
789 }
790
791 /* make sure there is no / on the end.
792 FIXME: is this good policy, removing a trailing slash?*/
793 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 /* extract extension.*/
801 len1 = temp + strlen(temp) - pos + 1;
802 temp2 = (char *)MALLOC(sizeof(char)*len1);
803 STRNCPY(temp2, pos, len1);
804 }else{
805 /* no extension*/
806 temp2 = NULL;
807 }
808 FREE(temp);
809 return temp2;
810 }
811
812 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 /* PATH_SEPARATOR_CHAR on the end, reduce count by 1*/
842 --depth;
843 }
844
845 return depth;
846 }
847
848 struct FilePath *ospath_root(struct FilePath *fp){
849 #ifdef WINPATHS
850 #if 0
851 M("WIN ROOT");
852 #endif
853 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 (void)fp;
869 #if 0
870 M("JUST RETURNING PATH SEP");
871 #endif
872 return ospath_new(PATH_SEPARATOR_STR);
873 #endif
874 }
875
876 struct FilePath *ospath_getdir(struct FilePath *fp){
877 char *pos;
878 char s[PATH_MAX];
879 #ifdef WINPATHS
880 int e;
881 #endif
882
883 pos = strrchr(fp->path,PATH_SEPARATOR_CHAR);
884 if(pos==NULL){
885 return ospath_new_noclean("");
886 }
887 #ifdef WINPATHS
888 strncpy(s,fp->drive,PATH_MAX);
889 e = strlen(s);
890 strncat(s,fp->path,pos - fp->path);
891 s[e+pos-fp->path]='\0';
892 #else
893 strncpy(s,fp->path,pos - fp->path);
894 s[pos-fp->path]='\0';
895 /* CONSOLE_DEBUG("DIRECTORY: '%s'",s); */
896 #endif
897 return ospath_new(s);
898 }
899
900 ASC_DLLSPEC(struct FilePath *) ospath_getabs(struct FilePath *fp){
901 struct FilePath *fp1, *fp2;
902 if(fp->path[0]==PATH_SEPARATOR_CHAR){
903 fp1 = ospath_new_copy(fp);
904 }else{
905 fp2 = ospath_new(".");
906 fp1 = ospath_concat(fp2,fp);
907 ospath_free(fp2);
908 }
909 return fp1;
910 }
911
912 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 #if 0
930 / now, both are valid...
931 M("BOTH ARE VALID");
932
933 /Check that paths both have drives, if applic.
934 #endif
935 #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 #if 0
972 C(*p);
973 #endif
974 }
975 X(temp[1]);
976 for(p=temp[1];*p!='\0';++p){
977 *p=tolower(*p);
978 #if 0
979 C(*p);
980 #endif
981 }
982 X(temp[0]);
983 X(temp[1]);
984 #endif
985
986 /* 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 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 #if 0
997 X(temp[0]);
998 X(temp[1]);
999 #endif
1000
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 /* both invalid*/
1018 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 /* not just a copy of one or the other...*/
1029 ospath_free(fp);
1030
1031 /* now, both paths are valid...*/
1032
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 /* make sure temp has a / on the end. */
1043 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 #ifdef DO_FIXSLASHES
1049 ospath_fixslash(temp[0]);
1050 ospath_fixslash(temp[1]);
1051 #endif
1052
1053 #if 0
1054 V(strlen(temp[0]));
1055 X(temp[0]);
1056 V(strlen(temp[1]));
1057 X(temp[1]);
1058 #endif
1059
1060 /* make sure rhs path has NOT got a / at the start. */
1061 if(temp[1][0] == PATH_SEPARATOR_CHAR){
1062 return NULL;
1063 }
1064
1065 /* create a new path object with the two path strings appended together.*/
1066 STRNCPY(temp2,temp[0],PATH_MAX);
1067 STRNCAT(temp2,temp[1],PATH_MAX-strlen(temp2));
1068 #if 0
1069 V(strlen(temp2));
1070 X(temp2);
1071 #endif
1072 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 #ifdef DO_FIXSLASHES
1086 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 /* set this object to be the same as the rhs */
1096 M("fp invalid");
1097 ospath_copy(fp,&fp2);
1098 #ifdef DO_FIXSLASHES
1099 ospath_fixslash(fp->path);
1100 #endif
1101 return;
1102 }
1103
1104 X(fp->path);
1105 X(fp2.path);
1106
1107 /* both paths are valid...*/
1108 #if 0
1109 temp[0] = CALLOC(1+strlen(fp->path), sizeof(char));
1110 #endif
1111 STRNCPY(temp[0], fp->path, PATH_MAX);
1112 #if 0
1113 temp[1] = CALLOC(strlen(fp2.path), sizeof(char));
1114 #endif
1115 STRNCPY(temp[1], fp2.path, PATH_MAX);
1116
1117 X(temp[0]);
1118 X(temp[1]);
1119
1120 /* make sure temp has a / on the end. */
1121 if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR)
1122 {
1123 STRCAT(temp[0],PATH_SEPARATOR_STR);
1124 }
1125
1126 /* make sure rhs path has NOT got a / at the start. */
1127 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 /*create new path string.*/
1138 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 #if 0
1144 FREE(temp[0]);
1145 M("Freed temp[0]");
1146 FREE(temp[1]);
1147 M("Freed temp[1]");
1148 #endif
1149
1150 D(fp);
1151 ospath_cleanup(fp);
1152 }
1153
1154 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 FILE *ospath_fopen(struct FilePath *fp, const char *mode){
1170 char s[PATH_MAX];
1171 FILE *f;
1172
1173 if(!ospath_isvalid(fp)){
1174 E("Invalid path");
1175 return NULL;
1176 }
1177 ospath_strncpy(fp,s,PATH_MAX);
1178 f = fopen(s,mode);
1179 return f;
1180 }
1181
1182 int ospath_stat(struct FilePath *fp,ospath_stat_t *buf){
1183 char s[PATH_MAX];
1184
1185 if(!ospath_isvalid(fp)){
1186 E("Invalid path");
1187 return -1;
1188 }
1189 ospath_strncpy(fp,s,PATH_MAX);
1190 return STAT(s,buf);
1191 }
1192
1193 /*------------------------
1194 SEARCH PATH FUNCTIONS
1195 */
1196
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 char path1[PATH_MAX];
1205
1206 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 */
1222
1223 p=STRTOK(path1,PATH_LISTSEP_STR,nexttok);
1224 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
1237 for(i=0;i<n;++i){
1238 X(list[i]);
1239 }
1240 V(n);
1241
1242
1243 pp = (struct FilePath **)MALLOC(sizeof(struct FilePath*)*(n+1));
1244 for(i=0; i<n; ++i){
1245 #if 0
1246 V(i);
1247 X(list[i]);
1248 #endif
1249 pp[i] = ospath_new_noclean(list[i]);
1250 #if 0
1251 D(pp[i]);
1252 #endif
1253 }
1254 pp[n] = NULL;
1255
1256 for(i=0;i<n;++i){
1257 #ifdef DO_FIXSLASHES
1258 ospath_fixslash(pp[i]->path);
1259 #endif
1260 D(pp[i]);
1261 }
1262
1263 return pp;
1264 }
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 }
1273
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
1283 struct FilePath *ospath_searchpath_iterate(
1284 struct FilePath **searchpath
1285 , FilePathTestFn *testfn
1286 , void *searchdata
1287 ){
1288 struct FilePath **p;
1289
1290 p = searchpath;
1291
1292 M("SEARCHING IN...");
1293 for(p=searchpath; *p!=NULL; ++p){
1294 D(*p);
1295 }
1296
1297 for(p=searchpath; *p!=NULL; ++p){
1298 D(*p);
1299 assert(*p!=NULL);
1300 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