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

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