1 /* RCS $Id: path.c,v 1.6 2008-03-05 18:29:34 kz Exp $
4 -- Pathname manipulation code
7 -- Pathname routines to handle building and pulling appart
11 -- Dennis Vadura, dvadura@dmake.wticorp.com
14 -- http://dmake.wticorp.com/
17 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
19 -- This program is NOT free software; you can redistribute it and/or
20 -- modify it under the terms of the Software License Agreement Provided
21 -- in the file <distribution-root>/readme/license.txt.
24 -- Use cvs log to obtain detailed change logs.
29 #include <sys/cygwin.h>
35 ** Return the suffix portion of a filename, assumed to begin with a `.'.
43 if(name
== NIL(char) || (suff
= strrchr(name
, '.')) == NIL(char))
53 Return pointer to the basename part of path. path itself remains
60 if( path
&& *(q
= path
) ) {
61 for(; *(p
=DmStrPbrk(q
, DirBrkStr
)) != '\0'; q
= p
+1 );
63 for( p
=q
-1; p
!= path
; --p
)
64 if( strchr( DirBrkStr
, *p
) == NIL(char) ) return( p
+1 );
65 return( strchr(DirBrkStr
, *p
)?path
:(p
+1) );
80 if( path
&& *(q
= path
) ) {
81 for(; *(p
=DmStrPbrk(q
,DirBrkStr
)) != '\0'; q
=p
+1 );
83 if (q
== path
) return("");
85 for(p
=q
-1; p
!=path
; --p
)
86 if( strchr(DirBrkStr
,*p
) == NIL(char) )
98 Build_path(dir
, name
)/*
99 =======================
100 Return a path that is created by concatenating dir and name. A directory
101 separater is added between them if needed. If dir is empty name is stripped
102 of leading slashes (if there) and returned.
104 The returned path is also cleaned from unneeded './' and 'foo/../'
105 elements and also multiple consequtive '/' are removed.
107 Note, the returned path is built in a static buffer, if it is to be used
108 later strdup should be used on the result returned by Build_path to create
114 static char *path
= NIL(char);
115 static unsigned buflen
= 0;
120 DB_ENTER( "Build_path" );
122 if( dir
!= NIL(char) ) dlen
= strlen( dir
);
123 if( name
!= NIL(char) ) plen
= strlen( name
);
124 len
= plen
+dlen
+1+1; /* Reserve space for extra path separator. */
127 buflen
= (len
+16) & ~0xf; /* buf is always multiple of 16 */
129 if( path
== NIL(char) )
130 path
= MALLOC( buflen
, char );
132 path
= realloc( path
, (unsigned) (buflen
*sizeof(char)) );
139 if( *path
&& strchr(DirBrkStr
, dir
[dlen
-1]) == NIL(char) )
140 strcat( path
, DirSepStr
);
144 while ( *name
&& strchr(DirBrkStr
,*name
) != 0 ) name
++;
145 strcat( path
, name
);
148 DB_PRINT( "path", ("dir: %s name: %s", dir
, name
));
149 DB_PRINT( "path", ("joined to: %s", path
));
152 DB_PRINT( "path", ("cleaned to: %s", path
));
161 Clean the path from irregular directory separators (if more than one are
162 allowed), remove unneeded './' and 'foo/../' elements and also multiple
165 The resulting string is shorter than the original, therefore this function
166 works on the original string. */
173 int hasdriveletter
= 0;
177 DB_ENTER( "Clean_path" );
179 /* Skip the root part. */
182 #ifdef HAVE_DRIVE_LETTERS
184 /* Change all occurences from DirBrkStr to *DirSepStr. This assumes
185 * that when HAVE_DRIVE_LETTERS is set the directory separator is
186 * either '\' or '/'. */
187 if (*DirSepStr
== '/')
188 for( q
= tpath
; (q
= strchr(q
, '\\')) != NIL(char); )
191 for( q
= tpath
; (q
= strchr(q
, '/')) != NIL(char); )
194 /* The following dosn't trigger often because normalize_path() uses
195 * a cygwin function and bypasses Clean_path() if it encounters a path
196 * with a drive letter. */
197 if( *tpath
&& tpath
[1] == ':' && isalpha(*tpath
) ) {
200 if( *tpath
!= *DirSepStr
)
201 Warning("Malformed DOS path %s", path
);
206 /* Collapse > 2 ( > 1 if its an absolute DOS path ) into one slash.
207 * Keep // as it is reserved in posix. */
209 for( ; *q
== *DirSepStr
; ++q
)
211 if( q
- tpath
> 2 - hasdriveletter
) {
215 /* Set tpath after leading slash / drive letter. */
216 for( ; *tpath
== *DirSepStr
; ++tpath
)
223 /* p is NULL or greater than q. */
224 p
=strchr(q
, *DirSepStr
);
227 /* Remove multiple consequtive DirSepStr. */
228 if( p
[1] == *DirSepStr
) {
229 t
= p
++; /* t points to first, p to second DirStrSep. */
230 /* Move p after the second (or possible more) DirSepStr. */
234 while( *p
== *DirSepStr
);
240 /* Remove './'. If OOODMAKEMODE is set do this only if it is not at
241 * the start of the path. */
242 if ( p
-q
== 1 && *q
== '.' && (q
!= path
|| !STOBOOL(OOoDmMode
)) ) {
249 /* If two '/' are in path check/remove 'foo/../' elements. */
250 t
=strchr(p
+1, *DirSepStr
);
253 /* Collaps this only if foo is neither '.' nor '..'. */
256 delentry
= !((q
[0] == '.') && (q
[1] == '.'));
259 delentry
= !(q
[0] == '.');
267 && (t
-p
-1 == 2 && strncmp(p
+1,"..",2) == 0) ) {
268 /* Skip one (or possible more) DirSepStr. */
272 while( *t
== *DirSepStr
);
273 /* q points to first letter of the current directory/file. */
282 DB_PRINT( "path", ("Cleaned path: %s", path
));
289 normalize_path(path
)/*
290 =======================
291 Normalize the given path unless it contains a $ indicating a dynamic
293 Special case: For absolute DOSish paths under cygwin a cygwin API
294 function is used to normalize the path optherwise Clean_path() is used.
296 Note, the returned path is built in a static buffer, if it is to be used
297 later a copy should be created. */
301 static char *cpath
= NIL(char);
303 DB_ENTER( "normalize_path" );
305 if ( !cpath
&& ( (cpath
= MALLOC( PATH_MAX
, char)) == NIL(char) ) )
308 /* If there is a $ in the path this can either mean a '$' character in
309 * a target definition or a dynamic macro expression in a prerequisite
310 * list. As dynamic macro expression must not be normalized and is
311 * indistinguishable from a literal $ characters at this point we skip
312 * the normalization if a $ is found. */
313 if( strchr(path
, '$') ) {
318 /* Use cygwin function to convert a DOS path to a POSIX path. */
319 if( *path
&& path
[1] == ':' && isalpha(*path
) ) {
320 int err
= cygwin_conv_to_posix_path(path
, cpath
);
322 Fatal( "error converting \"%s\" - %s\n",
323 path
, strerror (errno
));
324 if( path
[2] != '/' && path
[2] != '\\' )
325 Warning("Malformed DOS path %s converted to %s", path
, cpath
);
330 strcpy( cpath
, path
);
334 DB_PRINT( "path", ("normalized: %s", cpath
));