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

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