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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2334 - (show annotations) (download) (as text)
Fri Dec 24 05:11:35 2010 UTC (9 years, 9 months ago) by jpye
File MIME type: text/x-csrc
File size: 27383 byte(s)
Some work to support cleaning up of importhandler (more work to be done still, don't know how to unload the DLLs yet).
Fixed valgrind issues with ospath, switched to strtok_r for linux.
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 /* to test this code, 'gcc -DTEST ospath.c && ./a' */
43
44 #ifndef __GNUC__
45 # ifndef __FUNCTION__
46 # define __FUNCTION__ "<ospath>"
47 # endif
48 #endif
49
50
51 /* #define VERBOSE */
52
53 #if !defined(TEST) && !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 D(fp);
614
615 if(strlen(fp->path) == 0){
616 fp1 = ospath_getcwd();
617 fp2 = ospath_getparent(fp1);
618 ospath_free(fp1);
619 return fp2;
620 }else if(ospath_isroot(fp)){
621 /* stay at root */
622 return ospath_new("/");
623 }
624
625 /* reverse find a / ignoring the end / if it exists.
626 /// FIXME */
627 length = strlen(fp->path);
628 offset = (
629 fp->path[length - 1] == PATH_SEPARATOR_CHAR /* last char is slash?*/
630 && length > 1 /* and more than just leading slash... */
631 ) ? length - 1 : length; /* then remove last char */
632
633 for(pos = fp->path + offset - 1; *pos!=PATH_SEPARATOR_CHAR && pos>=fp->path; --pos){
634 #if 0
635 fprintf(stderr,"CURRENT CHAR: %c\n",*pos);
636 #endif
637 }
638
639 len1 = pos - (fp->path); len2 = (int)len1;
640 V(len2);
641 /*fprintf(stderr,"POS = %d\n",len2);*/
642
643 if(*pos==PATH_SEPARATOR_CHAR){
644 #ifdef WINPATHS
645 STRCPY(sub,fp->drive);
646 STRNCAT(sub,fp->path,len1);
647 #else
648 STRNCPY(sub,fp->path,len1);
649 sub[len1]='\0';
650 #endif
651 X(sub);
652 if(strcmp(sub,"")==0){
653 M("DIRECTORY IS EMPTY");
654 STRCAT(sub,PATH_SEPARATOR_STR);
655 }
656 }else{
657 /* ie pos<fp->path */
658 M("NO PARENT DIR");
659 if(fp->path[0]==PATH_SEPARATOR_CHAR){
660 E("NO PARENT DIR");
661 return ospath_new_noclean(fp->path);
662 }else{
663 M("RETURNING '.'");
664 #ifdef WINPATHS
665 /* eg 'c:bin' --> 'c:' */
666 STRCPY(sub,fp->drive);
667 return ospath_new_noclean(sub);
668 #else
669 /* eg 'bin' --> '.' */
670 return ospath_new_noclean(".");
671 #endif
672 }
673 }
674
675 M("Creating 'sub'");
676 fp1 = ospath_new_noclean(sub);
677 M("... 'sub'");
678 D(fp1);
679 return fp1;
680 }
681
682 struct FilePath *ospath_getparentatdepthn(struct FilePath *fp, unsigned depth)
683 {
684 int startslash;
685 char path[PATH_MAX];
686 char *temp;
687 char *p;
688 STRTOKVAR(nexttok);
689 #ifdef WINPATHS
690 char temp2[PATH_MAX];
691 #endif
692
693 if(
694 !ospath_isvalid(fp)
695 || depth >= ospath_depth(fp)
696 ){
697 return fp;
698 }
699
700 /* create FilePath object to parent object at depth N relative to this
701 path object.*/
702 startslash = (strlen(fp->path) > 0 && fp->path[0] == PATH_SEPARATOR_CHAR);
703
704 /* create a copy of fp->path.*/
705 STRCPY(path, fp->path);
706
707 /* reset fp->path as required.*/
708 temp = startslash ? PATH_SEPARATOR_STR : "";
709
710 /* split path into it tokens.
711 M("STARTING STRTOK");*/
712 p = STRTOK(path, PATH_SEPARATOR_STR, nexttok);
713
714 while(p && depth > 0)
715 {
716 if(strlen(temp) > 0 && temp[strlen(temp) - 1] != PATH_SEPARATOR_CHAR)
717 {
718 strcat(temp,PATH_SEPARATOR_STR);
719 }
720
721 STRCAT(temp,p);
722 --depth;
723
724 p = STRTOK(NULL, PATH_SEPARATOR_STR, nexttok);
725 }
726 #if 0
727 M("FINISHED STRTOK");
728 #endif
729
730 /* put / on end as required*/
731 if(strlen(temp) > 0 ? (temp[strlen(temp) - 1] != PATH_SEPARATOR_CHAR) : 1)
732 {
733 strcat(temp,PATH_SEPARATOR_STR);
734 }
735
736 #ifdef WINPATHS
737 STRCPY(temp2,fp->drive);
738 STRCAT(temp2,temp);
739 return ospath_new_noclean(temp2);
740 #else
741 return ospath_new_noclean(temp);
742 #endif
743 }
744
745 char *ospath_getbasefilename(struct FilePath *fp){
746 char *temp;
747 unsigned length, offset;
748 char *pos;
749
750 if(fp==NULL)return NULL;
751
752 if(strlen(fp->path) == 0){
753 /* return empty name.*/
754 return "";
755 }
756
757 if(fp->path[strlen(fp->path)-1]==PATH_SEPARATOR_CHAR){
758 return NULL;
759 }
760
761 /* reverse find '/' but DON'T ignore a trailing slash*/
762 /* (this is changed from the original implementation)*/
763 length = strlen(fp->path);
764 offset = length;
765
766 pos = strrchr(fp->path, PATH_SEPARATOR_CHAR); /* OFFSET! */
767
768 /* extract filename given position of find / and return it.*/
769 if(pos != NULL){
770 unsigned length1 = length - ((pos - fp->path));
771 temp = (char *)MALLOC(sizeof(char)*(length1+1));
772
773 V(length1);
774 STRNCPY(temp, pos + 1, length1);
775 *(temp + length1)='\0';
776 return temp;
777 }else{
778 temp = (char *)MALLOC(sizeof(char)*(length+1));
779 STRNCPY(temp, fp->path, length);
780 *(temp+length)='\0';
781 return temp;
782 }
783 }
784
785 char *ospath_getfilestem(struct FilePath *fp){
786 char *temp;
787 char *pos;
788
789 if(!ospath_isvalid(fp)){
790 return NULL;
791 }
792
793 temp = ospath_getbasefilename(fp);
794 if(temp==NULL){
795 /* it's a directory*/
796 return NULL;
797 }
798
799 pos = strrchr(temp,'.');
800
801 if(pos==NULL || pos==temp){
802 /* no extension, or a filename starting with '.'
803 -- return the whole filename*/
804 return temp;
805 }
806
807 /* remove extension.*/
808 *pos = '\0';
809
810 return temp;
811 }
812
813 char *ospath_getfileext(struct FilePath *fp){
814 char *temp, *temp2, *pos;
815 int len1;
816
817 if(!ospath_isvalid(fp)){
818 return NULL;
819 }
820
821 temp = ospath_getbasefilename(fp);
822 if(temp==NULL){
823 /* it's a directory*/
824 return NULL;
825 }
826
827 /* make sure there is no / on the end.
828 FIXME: is this good policy, removing a trailing slash?*/
829 if(temp[strlen(temp) - 1] == PATH_SEPARATOR_CHAR){
830 temp[strlen(temp)-1] = '\0';
831 }
832
833 pos = strrchr(temp,'.');
834
835 if(pos != NULL && pos!=temp){
836 /* extract extension.*/
837 len1 = temp + strlen(temp) - pos + 1;
838 temp2 = (char *)MALLOC(sizeof(char)*len1);
839 STRNCPY(temp2, pos, len1);
840 }else{
841 /* no extension*/
842 temp2 = NULL;
843 }
844 FREE(temp);
845 return temp2;
846 }
847
848 int ospath_isroot(struct FilePath *fp)
849 {
850 if(!ospath_isvalid(fp))
851 {
852 return 0;
853 }
854
855 return strcmp(fp->path, PATH_SEPARATOR_STR) ? 1 : 0;
856 }
857
858 unsigned ospath_depth(struct FilePath *fp){
859 unsigned length;
860 unsigned depth;
861 unsigned i;
862
863 length = strlen(fp->path);
864 depth = 0;
865
866 for(i = 0; i < length; i++){
867 if(fp->path[i] == PATH_SEPARATOR_CHAR){
868 ++depth;
869 }
870 }
871
872 if(
873 depth > 0
874 && length > 0
875 && fp->path[length - 1] == PATH_SEPARATOR_CHAR
876 ){
877 /* PATH_SEPARATOR_CHAR on the end, reduce count by 1*/
878 --depth;
879 }
880
881 return depth;
882 }
883
884 struct FilePath *ospath_root(struct FilePath *fp){
885 #ifdef WINPATHS
886 #if 0
887 M("WIN ROOT");
888 #endif
889 char *temp;
890 struct FilePath *r;
891
892 if(strlen(fp->drive)){
893 temp = (char *)MALLOC(sizeof(char)*strlen(fp->drive)+1);
894 STRCPY(temp,fp->drive);
895 STRCAT(temp,PATH_SEPARATOR_STR);
896 X(temp);
897 r = ospath_new(temp);
898 FREE(temp);
899 }else{
900 r = ospath_new(fp->path);
901 }
902 return r;
903 #else
904 (void)fp;
905 #if 0
906 M("JUST RETURNING PATH SEP");
907 #endif
908 return ospath_new(PATH_SEPARATOR_STR);
909 #endif
910 }
911
912 struct FilePath *ospath_getdir(struct FilePath *fp){
913 char *pos;
914 char s[PATH_MAX];
915 #ifdef WINPATHS
916 int e;
917 #endif
918
919 pos = strrchr(fp->path,PATH_SEPARATOR_CHAR);
920 if(pos==NULL){
921 return ospath_new_noclean("");
922 }
923 #ifdef WINPATHS
924 strncpy(s,fp->drive,PATH_MAX);
925 e = strlen(s);
926 strncat(s,fp->path,pos - fp->path);
927 s[e+pos-fp->path]='\0';
928 #else
929 strncpy(s,fp->path,pos - fp->path);
930 s[pos-fp->path]='\0';
931 /* CONSOLE_DEBUG("DIRECTORY: '%s'",s); */
932 #endif
933 return ospath_new(s);
934 }
935
936 ASC_DLLSPEC struct FilePath *ospath_getabs(struct FilePath *fp){
937 struct FilePath *fp1, *fp2;
938 if(fp->path[0]==PATH_SEPARATOR_CHAR){
939 fp1 = ospath_new_copy(fp);
940 }else{
941 fp2 = ospath_new(".");
942 fp1 = ospath_concat(fp2,fp);
943 ospath_free(fp2);
944 }
945 return fp1;
946 }
947
948 int ospath_cmp(struct FilePath *fp1, struct FilePath *fp2){
949 char temp[2][PATH_MAX];
950 #ifdef WINPATHS
951 char *p;
952 struct FilePath *fp;
953 #endif
954
955 if(!ospath_isvalid(fp1)){
956 if(!ospath_isvalid(fp2)){
957 return 0;
958 }else{
959 return -1;
960 }
961 }else if(!ospath_isvalid(fp2)){
962 return 1;
963 }
964
965 #if 0
966 / now, both are valid...
967 M("BOTH ARE VALID");
968
969 /Check that paths both have drives, if applic.
970 #endif
971 #ifdef WINPATHS
972 if(strcmp(fp1->drive,"")==0){
973 M("PATH IS MISSING DRIVE LETTER");
974 D(fp1);
975 fp = ospath_getcwd();
976 assert(strlen(fp->drive)!=0);
977 X(fp->drive);
978 STRCPY(temp[0],fp->drive);
979 ospath_free(fp);
980 }else{
981 STRCPY(temp[0],fp1->drive);
982 }
983
984 if(strcmp(fp2->drive,"")==0){
985 M("PATH IS MISSING DRIVE LETTER");
986 D(fp2);
987 fp = ospath_getcwd();
988 assert(strlen(fp->drive)!=0);
989 X(fp->drive);
990 STRCPY(temp[1],fp->drive);
991 ospath_free(fp);
992 }else{
993 STRCPY(temp[1],fp2->drive);
994 }
995
996 STRCAT(temp[0],fp1->path);
997 STRCAT(temp[1],fp2->path);
998 #else
999 STRCPY(temp[0], fp1->path);
1000 STRCPY(temp[1], fp2->path);
1001 #endif
1002
1003 #ifdef WINPATHS
1004 X(temp[0]);
1005 for(p=temp[0];*p!='\0';++p){
1006 *p=tolower(*p);
1007 #if 0
1008 C(*p);
1009 #endif
1010 }
1011 X(temp[1]);
1012 for(p=temp[1];*p!='\0';++p){
1013 *p=tolower(*p);
1014 #if 0
1015 C(*p);
1016 #endif
1017 }
1018 X(temp[0]);
1019 X(temp[1]);
1020 #endif
1021
1022 /* we will count two paths that different only in a trailing slash to be the *same*
1023 so we add trailing slashes to both now: */
1024 if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR){
1025 STRCAT(temp[0],PATH_SEPARATOR_STR);
1026 }
1027
1028 if(temp[1][strlen(temp[1]) - 1] != PATH_SEPARATOR_CHAR){
1029 STRCAT(temp[1],PATH_SEPARATOR_STR);
1030 }
1031
1032 #if 0
1033 X(temp[0]);
1034 X(temp[1]);
1035 #endif
1036
1037 return strcmp(temp[0],temp[1]);
1038 }
1039
1040 struct FilePath *ospath_concat(struct FilePath *fp1, struct FilePath *fp2){
1041
1042 struct FilePath *fp;
1043 char temp[2][PATH_MAX];
1044 char temp2[PATH_MAX];
1045 struct FilePath *r;
1046
1047 fp = (struct FilePath *)MALLOC(sizeof(struct FilePath));
1048
1049 if(!ospath_isvalid(fp1)){
1050 if(ospath_isvalid(fp2)){
1051 ospath_copy(fp,fp2);
1052 }else{
1053 /* both invalid*/
1054 ospath_copy(fp,fp1);
1055 }
1056 return fp;
1057 }
1058
1059 if(!ospath_isvalid(fp2)){
1060 ospath_copy(fp,fp1);
1061 return fp;
1062 }
1063
1064 /* not just a copy of one or the other...*/
1065 ospath_free(fp);
1066
1067 /* now, both paths are valid...*/
1068
1069 #ifdef WINPATHS
1070 STRNCPY(temp[0],fp1->drive,PATH_MAX);
1071 STRNCAT(temp[0],fp1->path,PATH_MAX-strlen(temp[0]));
1072 #else
1073 STRNCPY(temp[0], fp1->path,PATH_MAX);
1074 #endif
1075
1076 STRNCPY(temp[1], fp2->path,PATH_MAX);
1077
1078 /* make sure temp has a / on the end. */
1079 if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR)
1080 {
1081 STRNCAT(temp[0],PATH_SEPARATOR_STR,PATH_MAX-strlen(temp[0]));
1082 }
1083
1084 #ifdef DO_FIXSLASHES
1085 ospath_fixslash(temp[0]);
1086 ospath_fixslash(temp[1]);
1087 #endif
1088
1089 #if 0
1090 V(strlen(temp[0]));
1091 X(temp[0]);
1092 V(strlen(temp[1]));
1093 X(temp[1]);
1094 #endif
1095
1096 /* make sure rhs path has NOT got a / at the start. */
1097 if(temp[1][0] == PATH_SEPARATOR_CHAR){
1098 return NULL;
1099 }
1100
1101 /* create a new path object with the two path strings appended together.*/
1102 STRNCPY(temp2,temp[0],PATH_MAX);
1103 STRNCAT(temp2,temp[1],PATH_MAX-strlen(temp2));
1104 #if 0
1105 V(strlen(temp2));
1106 X(temp2);
1107 #endif
1108 r = ospath_new_noclean(temp2);
1109 D(r);
1110
1111 /* ospath_cleanup(r);*/
1112 return r;
1113 }
1114
1115 void ospath_append(struct FilePath *fp, struct FilePath *fp1){
1116 char *p;
1117 char temp[2][PATH_MAX];
1118 struct FilePath fp2;
1119
1120 ospath_copy(&fp2,fp1);
1121 #ifdef DO_FIXSLASHES
1122 ospath_fixslash(fp2.path);
1123 #endif
1124
1125 if(!ospath_isvalid(&fp2)){
1126 M("fp1 invalid");
1127 return;
1128 }
1129
1130 if(!ospath_isvalid(fp) && ospath_isvalid(&fp2)){
1131 /* set this object to be the same as the rhs */
1132 M("fp invalid");
1133 ospath_copy(fp,&fp2);
1134 #ifdef DO_FIXSLASHES
1135 ospath_fixslash(fp->path);
1136 #endif
1137 return;
1138 }
1139
1140 X(fp->path);
1141 X(fp2.path);
1142
1143 /* both paths are valid...*/
1144 #if 0
1145 temp[0] = CALLOC(1+strlen(fp->path), sizeof(char));
1146 #endif
1147 STRNCPY(temp[0], fp->path, PATH_MAX);
1148 #if 0
1149 temp[1] = CALLOC(strlen(fp2.path), sizeof(char));
1150 #endif
1151 STRNCPY(temp[1], fp2.path, PATH_MAX);
1152
1153 X(temp[0]);
1154 X(temp[1]);
1155
1156 /* make sure temp has a / on the end. */
1157 if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR)
1158 {
1159 STRCAT(temp[0],PATH_SEPARATOR_STR);
1160 }
1161
1162 /* make sure rhs path has NOT got a / at the start. */
1163 if(temp[1][0] == PATH_SEPARATOR_CHAR){
1164 for(p=temp[1]+1; *p != '\0'; ++p){
1165 *(p-1)=*p;
1166 }
1167 *(p-1)='\0';
1168 }
1169
1170 X(temp[0]);
1171 X(temp[1]);
1172
1173 /*create new path string.*/
1174 STRNCPY(fp->path,temp[0], PATH_MAX);
1175 STRNCAT(fp->path,temp[1], PATH_MAX-strlen(fp->path));
1176
1177 X(fp->path);
1178
1179 #if 0
1180 FREE(temp[0]);
1181 M("Freed temp[0]");
1182 FREE(temp[1]);
1183 M("Freed temp[1]");
1184 #endif
1185
1186 D(fp);
1187 ospath_cleanup(fp);
1188 }
1189
1190 void ospath_copy(struct FilePath *dest, struct FilePath *src){
1191 STRCPY(dest->path,src->path);
1192 #ifdef WINPATHS
1193 STRCPY(dest->drive,src->drive);
1194 #endif
1195 }
1196
1197 void ospath_debug(struct FilePath *fp){
1198 #ifdef WINPATHS
1199 fprintf(stderr,"{\"%s\",\"%s\"}\n",fp->drive,fp->path);
1200 #else
1201 fprintf(stderr,"{\"%s\"}\n",fp->path);
1202 #endif
1203 }
1204
1205 FILE *ospath_fopen(struct FilePath *fp, const char *mode){
1206 char s[PATH_MAX];
1207 FILE *f;
1208
1209 if(!ospath_isvalid(fp)){
1210 E("Invalid path");
1211 return NULL;
1212 }
1213 ospath_strncpy(fp,s,PATH_MAX);
1214 f = fopen(s,mode);
1215 return f;
1216 }
1217
1218 int ospath_stat(struct FilePath *fp,ospath_stat_t *buf){
1219 char s[PATH_MAX];
1220
1221 if(!ospath_isvalid(fp)){
1222 E("Invalid path");
1223 return -1;
1224 }
1225 ospath_strncpy(fp,s,PATH_MAX);
1226 return STAT(s,buf);
1227 }
1228
1229 /*------------------------
1230 SEARCH PATH FUNCTIONS
1231 */
1232
1233 struct FilePath **ospath_searchpath_new(const char *path){
1234 char *p;
1235 char *list[LISTMAX];
1236 unsigned n=0;
1237 char *c;
1238 unsigned i;
1239 struct FilePath **pp;
1240 char path1[PATH_MAX];
1241
1242 STRTOKVAR(nexttok);
1243
1244 strncpy(path1,path,PATH_MAX);
1245
1246 X(path1);
1247 X(PATH_LISTSEP_STR);
1248
1249 V(strlen(path1));
1250 V(strlen(PATH_LISTSEP_STR));
1251
1252 /*
1253 c = strstr(path,PATH_LISTSEP_CHAR);
1254 if(c==NULL){
1255 E("NO TOKEN FOUND");
1256 }
1257 */
1258
1259 p=STRTOK(path1,PATH_LISTSEP_STR,nexttok);
1260 X(p);
1261 for(; p!= NULL; p=STRTOK(NULL,PATH_LISTSEP_STR,nexttok)){
1262 c = (char *)MALLOC(sizeof(char)*(strlen(p)+1));
1263 X(p);
1264 STRCPY(c,p);
1265 if(n>=LISTMAX){
1266 E("IGNORING SOME PATH COMPONENTS");
1267 break;
1268 }
1269 list[n++]=c;
1270 }
1271
1272
1273 for(i=0;i<n;++i){
1274 X(list[i]);
1275 }
1276 V(n);
1277
1278
1279 pp = (struct FilePath **)MALLOC(sizeof(struct FilePath*)*(n+1));
1280 for(i=0; i<n; ++i){
1281 #if 0
1282 V(i);
1283 X(list[i]);
1284 #endif
1285 pp[i] = ospath_new_noclean(list[i]);
1286 #if 0
1287 D(pp[i]);
1288 #endif
1289 FREE(list[i]);
1290 }
1291 pp[n] = NULL;
1292
1293 for(i=0;i<n;++i){
1294 #ifdef DO_FIXSLASHES
1295 ospath_fixslash(pp[i]->path);
1296 #endif
1297 D(pp[i]);
1298 }
1299
1300 return pp;
1301 }
1302
1303 void ospath_searchpath_free(struct FilePath **searchpath){
1304 struct FilePath **p;
1305 for(p=searchpath; *p!=NULL; ++p){
1306 ospath_free(*p);
1307 }
1308 FREE(searchpath);
1309 }
1310
1311 int ospath_searchpath_length(struct FilePath **searchpath){
1312 int i=0;
1313 struct FilePath **p;
1314 for(p=searchpath; *p!=NULL; ++p){
1315 ++i;
1316 }
1317 return i;
1318 }
1319
1320 struct FilePath *ospath_searchpath_iterate(
1321 struct FilePath **searchpath
1322 , FilePathTestFn *testfn
1323 , void *searchdata
1324 ){
1325 struct FilePath **p;
1326
1327 p = searchpath;
1328
1329 M("SEARCHING IN...");
1330 for(p=searchpath; *p!=NULL; ++p){
1331 D(*p);
1332 }
1333
1334 for(p=searchpath; *p!=NULL; ++p){
1335 D(*p);
1336 assert(*p!=NULL);
1337 if((*testfn)(*p,searchdata)){
1338 return *p;
1339 }
1340 }
1341 return NULL;
1342 }

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