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

Contents of /trunk/ascend/general/ospath.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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