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;
176 DB_ENTER( "Clean_path" );
178 /* Skip the root part. */
181 #ifdef HAVE_DRIVE_LETTERS
183 /* Change all occurences from DirBrkStr to *DirSepStr. This assumes
184 * that when HAVE_DRIVE_LETTERS is set the directory separator is
185 * either '\' or '/'. */
186 if (*DirSepStr
== '/')
187 for( q
= tpath
; (q
= strchr(q
, '\\')) != NIL(char); )
190 for( q
= tpath
; (q
= strchr(q
, '/')) != NIL(char); )
193 /* The following dosn't trigger often because normalize_path() uses
194 * a cygwin function and bypasses Clean_path() if it encounters a path
195 * with a drive letter. */
196 if( *tpath
&& tpath
[1] == ':' && isalpha(*tpath
) ) {
199 if( *tpath
!= *DirSepStr
)
200 Warning("Malformed DOS path %s", path
);
205 /* Collapse > 2 ( > 1 if its an absolute DOS path ) into one slash.
206 * Keep // as it is reserved in posix. */
208 for( ; *q
== *DirSepStr
; ++q
)
210 if( q
- tpath
> 2 - hasdriveletter
) {
214 /* Set tpath after leading slash / drive letter. */
215 for( ; *tpath
== *DirSepStr
; ++tpath
)
222 /* p is NULL or greater than q. */
223 p
=strchr(q
, *DirSepStr
);
226 /* Remove multiple consequtive DirSepStr. */
227 if( p
[1] == *DirSepStr
) {
228 t
= p
++; /* t points to first, p to second DirStrSep. */
229 /* Move p after the second (or possible more) DirSepStr. */
233 while( *p
== *DirSepStr
);
238 /* Remove './'. If OOODMAKEMODE is set do this only if it is not at
239 * the start of the path. */
240 if ( p
-q
== 1 && *q
== '.' && (q
!= path
|| !STOBOOL(OOoDmMode
)) ) {
246 /* If two '/' are in path check/remove 'foo/../' elements. */
247 t
=strchr(p
+1, *DirSepStr
);
250 /* Collaps this only if foo is neither '.' nor '..'. */
253 delentry
= !((q
[0] == '.') && (q
[1] == '.'));
256 delentry
= !(q
[0] == '.');
264 && (t
-p
-1 == 2 && strncmp(p
+1,"..",2) == 0) ) {
265 /* Skip one (or possible more) DirSepStr. */
269 while( *t
== *DirSepStr
);
270 /* q points to first letter of the current directory/file. */
278 DB_PRINT( "path", ("Cleaned path: %s", path
));
285 normalize_path(path
)/*
286 =======================
287 Normalize the given path unless it contains a $ indicating a dynamic
289 Special case: For absolute DOSish paths under cygwin a cygwin API
290 function is used to normalize the path optherwise Clean_path() is used.
292 Note, the returned path is built in a static buffer, if it is to be used
293 later a copy should be created. */
297 static char *cpath
= NIL(char);
299 DB_ENTER( "normalize_path" );
301 if ( !cpath
&& ( (cpath
= MALLOC( PATH_MAX
, char)) == NIL(char) ) )
304 /* If there is a $ in the path this can either mean a '$' character in
305 * a target definition or a dynamic macro expression in a prerequisite
306 * list. As dynamic macro expression must not be normalized and is
307 * indistinguishable from a literal $ characters at this point we skip
308 * the normalization if a $ is found. */
309 if( strchr(path
, '$') ) {
314 /* Use cygwin function to convert a DOS path to a POSIX path. */
315 if( *path
&& path
[1] == ':' && isalpha(*path
) ) {
316 int err
= cygwin_conv_to_posix_path(path
, cpath
);
318 Fatal( "error converting \"%s\" - %s\n",
319 path
, strerror (errno
));
320 if( path
[2] != '/' && path
[2] != '\\' )
321 Warning("Malformed DOS path %s converted to %s", path
, cpath
);
326 strcpy( cpath
, path
);
330 DB_PRINT( "path", ("normalized: %s", cpath
));