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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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