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

Annotation of /trunk/base/generic/general/ospath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 541 - (hide 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 johnpye 541 #include <string.h>
2     #include <malloc.h>
3 johnpye 534 #include <stdio.h>
4 johnpye 535 #include <ctype.h>
5 johnpye 534
6     #include "ospath.h"
7    
8 johnpye 541 // 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 johnpye 534 # 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 johnpye 541 char drive[DRIVEMAX]; /// the drive the path resides on (field is absent in POSIX systems)
69 johnpye 534 #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 johnpye 541 void ospath_fixslash(char *path);
81 johnpye 534
82 johnpye 541 struct FilePath *ospath_getcwd();
83    
84 johnpye 534 /**
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 johnpye 535 2. Resolve a leading tilde (~) to the current user's HOME path
91 johnpye 534
92 johnpye 535 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 johnpye 534 */
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 johnpye 541 # define PATH_LISTSEP_CHAR ';'
119     # define PATH_LISTSEP_STR ";"
120 johnpye 534 #else
121     # define PATH_SEPARATOR_STR "/"
122     # define PATH_SEPARATOR_CHAR '/'
123 johnpye 541 # define PATH_LISTSEP_CHAR ':'
124     # define PATH_LISTSEP_STR ":"
125 johnpye 534 #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 johnpye 541 STRNCPY(fp->path, path, PATHMAX);
134     //X(fp->path);
135     //X(path);
136     assert(strcmp(fp->path,path)==0);
137 johnpye 534 #ifdef WINPATHS
138 johnpye 541 //X(fp->drive);
139 johnpye 534 ospath_extractdriveletter(fp);
140     #endif
141    
142 johnpye 541 //X(fp->drive);
143    
144     #ifdef __MINGW32__
145     ospath_fixslash(fp->path);
146     #endif
147    
148 johnpye 534 ospath_cleanup(fp);
149    
150 johnpye 541 //D(fp);
151    
152 johnpye 534 return fp;
153     }
154    
155 johnpye 541 void ospath_free(struct FilePath *fp){
156     FREE(fp);
157     }
158    
159 johnpye 534 /**
160 johnpye 535 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 johnpye 541 STRNCPY(fp->path,posixpath,PATHMAX);
180 johnpye 535 #ifdef WINPATHS
181     X(fp->path);
182     ospath_extractdriveletter(fp);
183     #endif
184    
185 johnpye 541 #ifdef __WIN32__
186     ospath_fixslash(fp->path);
187     #endif
188 johnpye 535
189 johnpye 541 //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 johnpye 535 //X(path);
207    
208 johnpye 541 startslash = (strlen(temp) > 0 && temp[0] == '/');
209     endslash = (strlen(temp) > 1 && temp[strlen(temp) - 1] == '/');
210 johnpye 535
211     //V(startslash);
212     //V(endslash);
213    
214     // reset fp->path as required.
215 johnpye 541 STRNCPY(path, (startslash ? PATH_SEPARATOR_STR : ""), PATHMAX);
216 johnpye 535
217 johnpye 541 //M("STARTING STRTOK");
218     for(p = STRTOK(temp, "/",nexttok);
219 johnpye 535 p!=NULL;
220 johnpye 541 p = STRTOK(NULL,"/",nexttok)
221 johnpye 535 ){
222     // add a separator if we've already got some stuff
223     if(
224 johnpye 541 strlen(path) > 0
225     && path[strlen(path) - 1] != PATH_SEPARATOR_CHAR
226 johnpye 535 ){
227 johnpye 541 STRCAT(path,PATH_SEPARATOR_STR);
228 johnpye 535 }
229    
230 johnpye 541 STRCAT(path,p);
231 johnpye 535 }
232 johnpye 541 //M("FINISHED STRTOK");
233 johnpye 535
234     // put / on end as required, according to what the starting path had
235 johnpye 541 if(endslash && (strlen(path) > 0 ? (path[strlen(path) - 1] != PATH_SEPARATOR_CHAR) : 1))
236 johnpye 535 {
237     //M("adding endslash!");
238    
239 johnpye 541 STRCAT(path, PATH_SEPARATOR_STR);
240 johnpye 535 }
241    
242 johnpye 541 //X(path);
243 johnpye 535 }
244    
245 johnpye 541 /// Create but with no 'cleanup' call
246 johnpye 534 struct FilePath *ospath_new_noclean(const char *path){
247     struct FilePath *fp = MALLOC(sizeof(struct FilePath));
248 johnpye 541 STRNCPY(fp->path,path,PATHMAX);
249 johnpye 534
250     #ifdef WINPATHS
251 johnpye 541 //X(fp->path);
252 johnpye 534 ospath_extractdriveletter(fp);
253     #endif
254    
255 johnpye 541 //D(fp);
256    
257     /*
258     #ifdef __MINGW32__
259     ospath_fixslash(fp->path);
260     D(fp);
261     #endif
262     */
263 johnpye 534 return fp;
264     }
265    
266 johnpye 541 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 johnpye 534 /**
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 johnpye 541 struct FilePath *fp;
289 johnpye 534
290     #ifndef __WIN32__
291 johnpye 541 struct passwd *pw;
292    
293 johnpye 534 if(pfx==NULL){
294 johnpye 541 pw = getpwuid(getuid());
295 johnpye 534
296     if(pw){
297     pfx = pw -> pw_dir;
298     }
299     }
300     #endif
301    
302 johnpye 541 // 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 johnpye 534 }
312    
313     #ifdef WINPATHS
314     void ospath_extractdriveletter(struct FilePath *fp)
315     {
316 johnpye 541 char *p;
317     //M("SOURCE");
318     //X(fp->path);
319     //fprintf(stderr,"CHAR 1 = %c\n",fp->path[1]);
320    
321 johnpye 534 // extract the drive the path resides on...
322     if(strlen(fp->path) >= 2 && fp->path[1] == ':')
323     {
324 johnpye 541 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 johnpye 534 }
329 johnpye 541 *(p-2)='\0';
330 johnpye 535 }else{
331 johnpye 541 STRNCPY(fp->drive,"",DRIVEMAX);
332 johnpye 534 }
333 johnpye 541 //M("RESULT");
334     //X(fp->path);
335     //X(fp->drive);
336 johnpye 534 }
337     #endif
338    
339     void ospath_cleanup(struct FilePath *fp){
340     char path[PATHMAX];
341     char *p;
342     struct FilePath *home;
343 johnpye 541 struct FilePath *working;
344 johnpye 534 struct FilePath *parent;
345 johnpye 541 STRTOKVAR(nexttok);
346 johnpye 534
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 johnpye 535 //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 johnpye 534
355     home = ospath_gethomepath();
356    
357     // create a copy of fp->path.
358 johnpye 541 STRCPY(path, fp->path);
359 johnpye 534
360     // reset fp->path as required.
361 johnpye 541 STRCPY(fp->path, (startslash ? PATH_SEPARATOR_STR : ""));
362 johnpye 534
363 johnpye 541 X(path);
364 johnpye 534
365 johnpye 541 // split path into it tokens, using STRTOK which is NOT reentrant
366 johnpye 534 // so be careful!
367    
368 johnpye 541 //M("STARTING STRTOK");
369     for(p = STRTOK(path, PATH_SEPARATOR_STR,nexttok);
370 johnpye 534 p!=NULL;
371 johnpye 541 p = STRTOK(NULL,PATH_SEPARATOR_STR,nexttok)
372 johnpye 534 ){
373 johnpye 541 //M("NEXT TOKEN");
374 johnpye 535 //X(p);
375 johnpye 541 //X(path+strlen(p)+1);
376 johnpye 534 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 johnpye 541 X(path);
393 johnpye 534
394 johnpye 541 working = ospath_getcwd();
395 johnpye 534
396 johnpye 541 D(working);
397     X(working->drive);
398     X(p);
399     X(path);
400 johnpye 534
401 johnpye 541 ospath_copy(fp,working);
402    
403    
404     D(fp);
405     X(p);
406     //X(path+strlen(p)+1);
407    
408     //ospath_free(working);
409 johnpye 534 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 johnpye 541 //ospath_free(parent);
422 johnpye 534 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 johnpye 541 STRCAT(fp->path,PATH_SEPARATOR_STR);
431 johnpye 534 }
432    
433     // add the present path component
434 johnpye 541 STRCAT(fp->path, p);
435 johnpye 534 }
436 johnpye 541 //M("FINISHED STRTOK");
437 johnpye 534
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 johnpye 541 STRCAT(fp->path, PATH_SEPARATOR_STR);
442 johnpye 534 }
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 johnpye 541 STRCPY(s,fp->drive);
456     STRCAT(s,fp->path);
457 johnpye 534 #else
458     s = CALLOC(strlen(fp->path),sizeof(char));
459 johnpye 541 STRCPY(s,fp->path);
460 johnpye 534 #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 johnpye 541 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 johnpye 534 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 johnpye 541 /// 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 johnpye 534
507 johnpye 541 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 johnpye 534 #ifdef WINPATHS
516 johnpye 541 STRCPY(sub,fp->drive);
517 johnpye 534 #endif
518 johnpye 541 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 johnpye 534 }else{
525 johnpye 541 E("NO PARENT DIR");
526     return ospath_new_noclean(fp->path);
527 johnpye 534 }
528 johnpye 541
529     fp1 = ospath_new_noclean(sub);
530     D(fp1);
531     return fp1;
532 johnpye 534 }
533    
534     struct FilePath *ospath_getparentatdepthn(struct FilePath *fp, unsigned depth)
535     {
536 johnpye 541 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 johnpye 534 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 johnpye 541 startslash = (strlen(fp->path) > 0 && fp->path[0] == PATH_SEPARATOR_CHAR);
555 johnpye 534
556     // create a copy of fp->path.
557 johnpye 541 STRCPY(path, fp->path);
558 johnpye 534
559     // reset fp->path as required.
560 johnpye 541 temp = startslash ? PATH_SEPARATOR_STR : "";
561 johnpye 534
562     // split path into it tokens.
563 johnpye 541 //M("STARTING STRTOK");
564     p = STRTOK(path, PATH_SEPARATOR_STR, nexttok);
565 johnpye 534
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 johnpye 541 STRCAT(temp,p);
574 johnpye 534 --depth;
575    
576 johnpye 541 p = STRTOK(NULL, PATH_SEPARATOR_STR, nexttok);
577 johnpye 534 }
578 johnpye 541 //M("FINISHED STRTOK");
579 johnpye 534
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 johnpye 541 STRCPY(temp2,fp->drive);
588     STRCAT(temp2,temp);
589 johnpye 534 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 johnpye 541 unsigned length, offset;
598     char *pos;
599 johnpye 534
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 johnpye 541 length = strlen(fp->path);
607     offset = (
608 johnpye 534 fp->path[length - 1] == PATH_SEPARATOR_CHAR
609     && length - 2 > 0
610     ) ? length - 2
611     : length;
612    
613 johnpye 541 pos = strrchr(fp->path, PATH_SEPARATOR_CHAR); /* OFFSET! */
614 johnpye 534
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 johnpye 541 STRNCPY(temp, pos + 1, length1);
621 johnpye 534 return temp;
622     }else{
623     temp = CALLOC(length,sizeof(char));
624 johnpye 541 STRNCPY(temp, fp->path, length);
625 johnpye 534 return temp;
626     }
627     }
628    
629     char *ospath_getbasefiletitle(struct FilePath *fp){
630 johnpye 541 char *temp;
631     char *pos;
632    
633 johnpye 534 if(!ospath_isvalid(fp)){
634     return NULL;
635     }
636    
637 johnpye 541 temp = ospath_getbasefilename(fp);
638     pos = strrchr(temp,'.');
639 johnpye 534
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 johnpye 541 char *temp, *temp2, *pos;
650     int len1;
651    
652 johnpye 534 if(!ospath_isvalid(fp)){
653     return NULL;
654     }
655    
656 johnpye 541 temp = ospath_getbasefilename(fp);
657 johnpye 534
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 johnpye 541 pos = strrchr(temp,'.');
664 johnpye 534
665     if(pos != NULL)
666     {
667     // extract extension.
668 johnpye 541 len1 = temp + strlen(temp) - pos;
669 johnpye 534 temp2 = CALLOC(len1, sizeof(char));
670 johnpye 541 STRNCPY(temp2, pos, len1);
671 johnpye 534 }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 johnpye 541 //M("WIN ROOT");
718 johnpye 534 char *temp;
719     struct FilePath *r;
720 johnpye 541
721 johnpye 534 if(strlen(fp->drive)){
722     temp = CALLOC(strlen(fp->drive)+1, sizeof(char));
723 johnpye 541 STRCPY(temp,fp->drive);
724     STRCAT(temp,PATH_SEPARATOR_STR);
725     X(temp);
726 johnpye 534 r = ospath_new(temp);
727     FREE(temp);
728     }else{
729 johnpye 541 r = ospath_new(fp->path);
730 johnpye 534 }
731     return r;
732     #else
733 johnpye 541 //M("JUST RETURNING PATH SEP");
734 johnpye 534 return ospath_new(PATH_SEPARATOR_STR);
735     #endif
736     }
737    
738 johnpye 541 int ospath_cmp(struct FilePath *fp1, struct FilePath *fp2){
739     char temp[2][PATHMAX];
740     #ifdef WINPATHS
741     char *p;
742     #endif
743    
744 johnpye 534 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 johnpye 535 //M("BOTH ARE VALID");
756 johnpye 534
757     #ifdef WINPATHS
758 johnpye 541 //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 johnpye 534 #else
767 johnpye 541 STRCPY(temp[0], fp1->path);
768     STRCPY(temp[1], fp2->path);
769 johnpye 534 #endif
770    
771 johnpye 541 #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 johnpye 534 // 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 johnpye 541 STRCAT(temp[0],PATH_SEPARATOR_STR);
786 johnpye 534 }
787    
788     if(temp[1][strlen(temp[1]) - 1] != PATH_SEPARATOR_CHAR){
789 johnpye 541 STRCAT(temp[1],PATH_SEPARATOR_STR);
790 johnpye 534 }
791    
792 johnpye 541 //X(temp[0]);
793     //X(temp[1]);
794 johnpye 534
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 johnpye 541 char *temp[2];
802     char *temp2;
803     struct FilePath *r;
804    
805 johnpye 534 fp = MALLOC(sizeof(struct FilePath));
806    
807 johnpye 541 D(fp1);
808     D(fp2);
809    
810 johnpye 534 if(!ospath_isvalid(fp1)){
811     if(ospath_isvalid(fp2)){
812 johnpye 541 ospath_copy(fp,fp2);
813 johnpye 534 }else{
814     // both invalid
815 johnpye 541 ospath_copy(fp,fp1);
816 johnpye 534 }
817     return fp;
818     }
819    
820     if(!ospath_isvalid(fp2)){
821 johnpye 541 ospath_copy(fp,fp1);
822 johnpye 534 return fp;
823     }
824    
825     // not just a copy of one or the other...
826 johnpye 541 ospath_free(fp);
827 johnpye 534
828     // now, both paths are valid...
829    
830     #ifdef WINPATHS
831 johnpye 541 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 johnpye 534 #else
835 johnpye 541 temp[0] = CALLOC(2 + strlen(fp1->path), sizeof(char));
836     STRCPY(temp[0], fp1->path);
837 johnpye 534 #endif
838    
839 johnpye 541 temp[1] = CALLOC(2 + strlen(fp2->path), sizeof(char));
840     STRCPY(temp[1], fp2->path);
841    
842 johnpye 534 // make sure temp has a / on the end.
843     if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR)
844     {
845 johnpye 541 STRCAT(temp[0],PATH_SEPARATOR_STR);
846 johnpye 534 }
847    
848 johnpye 541 #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 johnpye 534 // 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 johnpye 541 STRCPY(temp2,temp[0]);
868     STRCAT(temp2,temp[1]);
869     //V(strlen(temp2));
870     //X(temp2);
871 johnpye 534 r = ospath_new_noclean(temp2);
872     FREE(temp2);
873     FREE(temp[0]);
874     FREE(temp[1]);
875 johnpye 541 D(r);
876     /* ospath_cleanup(r);*/
877 johnpye 534 return r;
878     }
879    
880     void ospath_append(struct FilePath *fp, struct FilePath *fp1){
881     char *p;
882 johnpye 541 char *temp[2];
883     struct FilePath fp2;
884 johnpye 534
885 johnpye 541 ospath_copy(&fp2,fp1);
886     ospath_fixslash(fp2.path);
887    
888     if(!ospath_isvalid(&fp2)){
889 johnpye 534 M("fp1 invalid");
890     return;
891     }
892    
893 johnpye 541 if(!ospath_isvalid(fp) && ospath_isvalid(&fp2)){
894 johnpye 534 // set this object to be the same as the rhs
895     M("fp invalid");
896 johnpye 541 ospath_copy(fp,&fp2);
897     ospath_fixslash(fp->path);
898 johnpye 534 return;
899     }
900    
901 johnpye 541 //X(fp->path);
902     //X(fp2.path);
903 johnpye 534
904     // both paths are valid...
905     temp[0] = CALLOC(1+strlen(fp->path), sizeof(char));
906 johnpye 541 STRCPY(temp[0], fp->path);
907     temp[1] = CALLOC(strlen(fp2.path), sizeof(char));
908     STRCPY(temp[1], fp2.path);
909 johnpye 534
910 johnpye 541 //X(temp[0]);
911     //X(temp[1]);
912 johnpye 534
913     // make sure temp has a / on the end.
914     if(temp[0][strlen(temp[0]) - 1] != PATH_SEPARATOR_CHAR)
915     {
916 johnpye 541 STRCAT(temp[0],PATH_SEPARATOR_STR);
917 johnpye 534 }
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 johnpye 541 //X(temp[0]);
928     //X(temp[1]);
929 johnpye 534
930     // create new path string.
931 johnpye 541 STRCPY(fp->path,temp[0]);
932     STRCAT(fp->path,temp[1]);
933 johnpye 534
934     FREE(temp[0]);
935     FREE(temp[1]);
936 johnpye 541
937     X(fp);
938     ospath_cleanup(fp);
939 johnpye 534 }
940    
941     void ospath_copy(struct FilePath *dest, struct FilePath *src){
942 johnpye 541 STRCPY(dest->path,src->path);
943 johnpye 534 #ifdef WINPATHS
944 johnpye 541 STRCPY(dest->drive,src->drive);
945 johnpye 534 #endif
946     }
947    
948 johnpye 541 void ospath_debug(struct FilePath *fp){
949 johnpye 534 #ifdef WINPATHS
950 johnpye 541 fprintf(stderr,"{\"%s\",\"%s\"}\n",fp->drive,fp->path);
951     #else
952     fprintf(stderr,"{\"%s\"}\n",fp->path);
953 johnpye 534 #endif
954     }
955    
956 johnpye 541 //------------------------
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 johnpye 534 /*--------------------------------
1023     some simple test routines...
1024     */
1025     #ifdef TEST
1026 johnpye 541
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 johnpye 534 #include <assert.h>
1042    
1043     int main(void){
1044     struct FilePath *fp1, *fp2, *fp3, *fp4;
1045 johnpye 541 struct FilePath **pp, **p1;// will be returned null-terminated
1046     char pathtext[]="c:\\Program Files\\GnuWin32\\bin;c:\\GTK\\bin;e:\\ascend\\;..\\..\\pygtk";
1047 johnpye 534
1048 johnpye 541 //------------------------
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 johnpye 535 fp1 = ospath_new_from_posix("models/johnpye/extfn/extfntest");
1062     D(fp1);
1063     fp2 = ospath_new("models\\johnpye\\extfn\\extfntest");
1064     D(fp2);
1065 johnpye 541 D(fp1);
1066 johnpye 535 assert(ospath_cmp(fp1,fp2)==0);
1067 johnpye 541 M("Passed 'new_from_posix' test\n");
1068 johnpye 535
1069 johnpye 541 ospath_free(fp1);
1070     ospath_free(fp2);
1071 johnpye 535
1072     //------------------------
1073 johnpye 541 fp1 = ospath_new(".\\src/.\\images\\..\\\\movies\\");
1074 johnpye 534 fp2 = ospath_new(".\\src\\movies");
1075    
1076     D(fp1);
1077     D(fp2);
1078    
1079     assert(ospath_cmp(fp1,fp2)==0);
1080 johnpye 541 M("Passed mid-path '..' cleanup test\n");
1081 johnpye 534
1082 johnpye 541 ospath_free(fp2);
1083 johnpye 534
1084 johnpye 541 fp2 = ospath_new("./src/movies\\kubrick");
1085 johnpye 534 fp3 = ospath_getparent(fp2);
1086    
1087 johnpye 541 D(fp2);
1088     D(fp3);
1089    
1090 johnpye 534 assert(ospath_cmp(fp1,fp3)==0);
1091 johnpye 541 M("Passed 'second cleanup' test\n");
1092 johnpye 534
1093 johnpye 535 //------------------------
1094 johnpye 534
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 johnpye 541 D(fp2);
1104    
1105 johnpye 535 fp4 = ospath_new("\\home\\john\\where\\mojo\\");
1106 johnpye 534
1107     D(fp2);
1108 johnpye 535 assert(ospath_cmp(fp2,fp4)==0);
1109 johnpye 541 M("Passed 'append' test\n");
1110 johnpye 534
1111 johnpye 541 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 johnpye 534 ospath_append(fp2,fp3);
1124 johnpye 541 M("AFTER APPENDING ../..");
1125     D(fp2);
1126    
1127     M("GETTING ROOT");
1128 johnpye 534 fp4 = ospath_root(fp2);
1129 johnpye 541 M("ROOT FOUND:");
1130 johnpye 534 D(fp4);
1131    
1132     assert(ospath_cmp(fp2,fp4)==0);
1133 johnpye 541 M("Passed 'append ../..' test\n");
1134 johnpye 535
1135 johnpye 541 ospath_free(fp2);
1136     ospath_free(fp3);
1137     ospath_free(fp4);
1138 johnpye 534
1139 johnpye 541 //-------------------------
1140 johnpye 534
1141 johnpye 541 fp1 = ospath_new("~\\somewhere\\..");
1142 johnpye 534 fp2 = ospath_new("~/.");
1143    
1144     assert(ospath_cmp(fp1,fp2)==0);
1145    
1146     D(fp2);
1147    
1148 johnpye 541 ospath_free(fp1);
1149     ospath_free(fp2);
1150 johnpye 534
1151     fp1 = ospath_new("/usr/local/include");
1152     fp2 = ospath_new("/usr/include/../local/include");
1153    
1154     D(fp1);
1155     D(fp2);
1156    
1157 johnpye 541 assert(ospath_cmp(fp1,fp2)==0);
1158     M("Passed another mid-path '..' test\n");
1159 johnpye 535
1160 johnpye 541 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 johnpye 534 }
1237    
1238     #endif

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