Line data Source code
1 : /* RCS $Id: path.c,v 1.6 2008-03-05 18:29:34 kz Exp $
2 : --
3 : -- SYNOPSIS
4 : -- Pathname manipulation code
5 : --
6 : -- DESCRIPTION
7 : -- Pathname routines to handle building and pulling appart
8 : -- pathnames.
9 : --
10 : -- AUTHOR
11 : -- Dennis Vadura, dvadura@dmake.wticorp.com
12 : --
13 : -- WWW
14 : -- http://dmake.wticorp.com/
15 : --
16 : -- COPYRIGHT
17 : -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
18 : --
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.
22 : --
23 : -- LOG
24 : -- Use cvs log to obtain detailed change logs.
25 : */
26 :
27 : #include "extern.h"
28 : #if __CYGWIN__
29 : #include <sys/cygwin.h>
30 : #include <errno.h>
31 : #endif
32 :
33 :
34 : /*
35 : ** Return the suffix portion of a filename, assumed to begin with a `.'.
36 : */
37 : PUBLIC char *
38 37761 : Get_suffix(name)
39 : char *name;
40 : {
41 : char *suff;
42 :
43 37761 : if(name == NIL(char) || (suff = strrchr(name, '.')) == NIL(char))
44 1127 : suff = ".NULL";
45 :
46 37761 : return (suff);
47 : }
48 :
49 :
50 : PUBLIC char *
51 120634 : Basename(path)/*
52 : ================
53 : Return pointer to the basename part of path. path itself remains
54 : unchanged. */
55 : char *path;
56 : {
57 : char *p;
58 : char *q;
59 :
60 120634 : if( path && *(q = path) ) {
61 120634 : for(; *(p=DmStrPbrk(q, DirBrkStr)) != '\0'; q = p+1 );
62 120634 : if( !*q ) {
63 0 : for( p=q-1; p != path; --p )
64 0 : if( strchr( DirBrkStr, *p ) == NIL(char) ) return( p+1 );
65 0 : return( strchr(DirBrkStr, *p)?path:(p+1) );
66 : }
67 120634 : path = q;
68 : }
69 120634 : return( path );
70 : }
71 :
72 :
73 : PUBLIC char *
74 37761 : Filedir(path)
75 : char *path;
76 : {
77 : char *p;
78 : char *q;
79 :
80 37761 : if( path && *(q = path) ) {
81 37761 : for(; *(p=DmStrPbrk(q,DirBrkStr)) != '\0'; q=p+1 );
82 :
83 37761 : if (q == path) return("");
84 :
85 75522 : for(p=q-1; p!=path; --p)
86 75522 : if( strchr(DirBrkStr,*p) == NIL(char) )
87 37761 : break;
88 :
89 37761 : p[1] = '\0';
90 : }
91 :
92 37761 : return(path);
93 : }
94 :
95 :
96 :
97 : PUBLIC char *
98 44253 : 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.
103 :
104 : The returned path is also cleaned from unneeded './' and 'foo/../'
105 : elements and also multiple consequtive '/' are removed.
106 :
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
109 : a copy. */
110 :
111 : char *dir;
112 : char *name;
113 : {
114 : static char *path = NIL(char);
115 : static unsigned buflen = 0;
116 44253 : int plen = 0;
117 44253 : int dlen = 0;
118 : int len;
119 :
120 : DB_ENTER( "Build_path" );
121 :
122 44253 : if( dir != NIL(char) ) dlen = strlen( dir );
123 44253 : if( name != NIL(char) ) plen = strlen( name );
124 44253 : len = plen+dlen+1+1; /* Reserve space for extra path separator. */
125 :
126 44253 : if( len > buflen ) {
127 704 : buflen = (len+16) & ~0xf; /* buf is always multiple of 16 */
128 :
129 704 : if( path == NIL(char) )
130 184 : path = MALLOC( buflen, char );
131 : else
132 520 : path = realloc( path, (unsigned) (buflen*sizeof(char)) );
133 : }
134 :
135 44253 : *path = '\0';
136 :
137 44253 : if( dlen ) {
138 44253 : strcpy( path, dir );
139 44253 : if( *path && strchr(DirBrkStr, dir[dlen-1]) == NIL(char) )
140 44253 : strcat( path, DirSepStr );
141 : }
142 :
143 44253 : if ( plen ) {
144 44253 : while ( *name && strchr(DirBrkStr,*name) != 0 ) name++;
145 44253 : strcat( path, name );
146 : }
147 :
148 : DB_PRINT( "path", ("dir: %s name: %s", dir, name ));
149 : DB_PRINT( "path", ("joined to: %s", path ));
150 :
151 44253 : Clean_path( path );
152 : DB_PRINT( "path", ("cleaned to: %s", path ));
153 :
154 44253 : DB_RETURN( path );
155 : }
156 :
157 :
158 : void
159 152263 : Clean_path(path)/*
160 : ==================
161 : Clean the path from irregular directory separators (if more than one are
162 : allowed), remove unneeded './' and 'foo/../' elements and also multiple
163 : consequtive '/'.
164 :
165 : The resulting string is shorter than the original, therefore this function
166 : works on the original string. */
167 :
168 : char *path;
169 : {
170 : register char *p;
171 : register char *q;
172 : char *tpath;
173 152263 : int hasdriveletter = 0;
174 : int delentry;
175 : size_t len;
176 :
177 : DB_ENTER( "Clean_path" );
178 :
179 : /* Skip the root part. */
180 152263 : tpath=path;
181 :
182 : #ifdef HAVE_DRIVE_LETTERS
183 :
184 : /* Change all occurrences 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); )
189 : *q = *DirSepStr;
190 : else
191 : for( q = tpath; (q = strchr(q, '/')) != NIL(char); )
192 : *q = *DirSepStr;
193 :
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) ) {
198 : hasdriveletter = 1;
199 : tpath+=2;
200 : if( *tpath != *DirSepStr )
201 : Warning("Malformed DOS path %s", path);
202 : }
203 :
204 : #endif
205 :
206 : /* Collapse > 2 ( > 1 if its an absolute DOS path ) into one slash.
207 : * Keep // as it is reserved in posix. */
208 152263 : q = tpath;
209 152263 : for( ; *q == *DirSepStr ; ++q )
210 : ;
211 152263 : if( q - tpath > 2 - hasdriveletter ) {
212 0 : strcpy(tpath+1, q);
213 : }
214 :
215 : /* Set tpath after leading slash / drive letter. */
216 152263 : for( ; *tpath == *DirSepStr ; ++tpath )
217 : ;
218 152263 : q = tpath;
219 :
220 1527810 : while( *q ) {
221 : char *t;
222 :
223 : /* p is NULL or greater than q. */
224 1375547 : p=strchr(q, *DirSepStr);
225 1375547 : if( !p ) break;
226 :
227 : /* Remove multiple consequtive DirSepStr. */
228 1334139 : if( p[1] == *DirSepStr ) {
229 26 : t = p++; /* t points to first, p to second DirStrSep. */
230 : /* Move p after the second (or possible more) DirSepStr. */
231 : do {
232 26 : p++;
233 : }
234 26 : while( *p == *DirSepStr);
235 26 : len = strlen(p)+1;
236 26 : memmove(t+1,p,len);
237 26 : continue;
238 : }
239 :
240 : /* Remove './'. If OOODMAKEMODE is set do this only if it is not at
241 : * the start of the path. */
242 1334113 : if ( p-q == 1 && *q == '.' && (q != path || !STOBOOL(OOoDmMode)) ) {
243 54 : len = strlen(p+1)+1;
244 54 : memmove(q,p+1,len);
245 54 : q = tpath;
246 54 : continue;
247 : }
248 :
249 : /* If two '/' are in path check/remove 'foo/../' elements. */
250 1334059 : t=strchr(p+1, *DirSepStr);
251 1334059 : if( !t ) break;
252 :
253 : /* Collaps this only if foo is neither '.' nor '..'. */
254 1223204 : switch( p-q ) {
255 : case 2:
256 177472 : delentry = !((q[0] == '.') && (q[1] == '.'));
257 177472 : break;
258 : case 1:
259 302 : delentry = !(q[0] == '.');
260 302 : break;
261 : default:
262 1045430 : delentry = TRUE;
263 1045430 : break;
264 : }
265 :
266 1223204 : if ( delentry
267 1048186 : && (t-p-1 == 2 && strncmp(p+1,"..",2) == 0) ) {
268 : /* Skip one (or possible more) DirSepStr. */
269 : do {
270 60790 : t++;
271 : }
272 60790 : while( *t == *DirSepStr);
273 : /* q points to first letter of the current directory/file. */
274 60790 : len = strlen(t)+1;
275 60790 : memmove(q,t,len);
276 60790 : q = tpath;
277 : }
278 : else
279 1162414 : q = p+1;
280 : }
281 :
282 : DB_PRINT( "path", ("Cleaned path: %s", path ));
283 :
284 152263 : DB_VOID_RETURN;
285 : }
286 :
287 :
288 : char *
289 126972 : normalize_path(path)/*
290 : =======================
291 : Normalize the given path unless it contains a $ indicating a dynamic
292 : prerequisite.
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.
295 :
296 : Note, the returned path is built in a static buffer, if it is to be used
297 : later a copy should be created. */
298 :
299 : char *path;
300 : {
301 : static char *cpath = NIL(char);
302 :
303 : DB_ENTER( "normalize_path" );
304 :
305 126972 : if ( !cpath && ( (cpath = MALLOC( PATH_MAX, char)) == NIL(char) ) )
306 0 : No_ram();
307 :
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 126972 : if( strchr(path, '$') ) {
314 18962 : DB_RETURN( path );
315 : }
316 :
317 : #if __CYGWIN__
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);
321 : if (err)
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);
326 : }
327 : else
328 : #endif
329 : {
330 108010 : strcpy( cpath, path );
331 108010 : Clean_path( cpath );
332 : }
333 :
334 : DB_PRINT( "path", ("normalized: %s", cpath ));
335 :
336 108010 : DB_RETURN( cpath );
337 : }
|