Update ooo320-m1
[ooovba.git] / dmake / path.c
blob9520686d6f370c13734a29878ffc175318f898c3
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
13 -- WWW
14 -- http://dmake.wticorp.com/
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.
23 -- LOG
24 -- Use cvs log to obtain detailed change logs.
27 #include "extern.h"
28 #if __CYGWIN__
29 #include <sys/cygwin.h>
30 #include <errno.h>
31 #endif
35 ** Return the suffix portion of a filename, assumed to begin with a `.'.
37 PUBLIC char *
38 Get_suffix(name)
39 char *name;
41 char *suff;
43 if(name == NIL(char) || (suff = strrchr(name, '.')) == NIL(char))
44 suff = ".NULL";
46 return (suff);
50 PUBLIC char *
51 Basename(path)/*
52 ================
53 Return pointer to the basename part of path. path itself remains
54 unchanged. */
55 char *path;
57 char *p;
58 char *q;
60 if( path && *(q = path) ) {
61 for(; *(p=DmStrPbrk(q, DirBrkStr)) != '\0'; q = p+1 );
62 if( !*q ) {
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) );
67 path = q;
69 return( path );
73 PUBLIC char *
74 Filedir(path)
75 char *path;
77 char *p;
78 char *q;
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) )
87 break;
89 p[1] = '\0';
92 return(path);
97 PUBLIC 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
109 a copy. */
111 char *dir;
112 char *name;
114 static char *path = NIL(char);
115 static unsigned buflen = 0;
116 int plen = 0;
117 int dlen = 0;
118 int len;
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. */
126 if( len > buflen ) {
127 buflen = (len+16) & ~0xf; /* buf is always multiple of 16 */
129 if( path == NIL(char) )
130 path = MALLOC( buflen, char );
131 else
132 path = realloc( path, (unsigned) (buflen*sizeof(char)) );
135 *path = '\0';
137 if( dlen ) {
138 strcpy( path, dir );
139 if( *path && strchr(DirBrkStr, dir[dlen-1]) == NIL(char) )
140 strcat( path, DirSepStr );
143 if ( plen ) {
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 ));
151 Clean_path( path );
152 DB_PRINT( "path", ("cleaned to: %s", path ));
154 DB_RETURN( path );
158 void
159 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 '/'.
165 The resulting string is shorter than the original, therefore this function
166 works on the original string. */
168 char *path;
170 register char *p;
171 register char *q;
172 char *tpath;
173 int hasdriveletter = 0;
174 int delentry;
175 size_t len;
177 DB_ENTER( "Clean_path" );
179 /* Skip the root part. */
180 tpath=path;
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); )
189 *q = *DirSepStr;
190 else
191 for( q = tpath; (q = strchr(q, '/')) != NIL(char); )
192 *q = *DirSepStr;
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);
204 #endif
206 /* Collapse > 2 ( > 1 if its an absolute DOS path ) into one slash.
207 * Keep // as it is reserved in posix. */
208 q = tpath;
209 for( ; *q == *DirSepStr ; ++q )
211 if( q - tpath > 2 - hasdriveletter ) {
212 strcpy(tpath+1, q);
215 /* Set tpath after leading slash / drive letter. */
216 for( ; *tpath == *DirSepStr ; ++tpath )
218 q = tpath;
220 while( *q ) {
221 char *t;
223 /* p is NULL or greater than q. */
224 p=strchr(q, *DirSepStr);
225 if( !p ) break;
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. */
231 do {
232 p++;
234 while( *p == *DirSepStr);
235 len = strlen(p)+1;
236 memmove(t+1,p,len);
237 continue;
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)) ) {
243 len = strlen(p+1)+1;
244 memmove(q,p+1,len);
245 q = tpath;
246 continue;
249 /* If two '/' are in path check/remove 'foo/../' elements. */
250 t=strchr(p+1, *DirSepStr);
251 if( !t ) break;
253 /* Collaps this only if foo is neither '.' nor '..'. */
254 switch( p-q ) {
255 case 2:
256 delentry = !((q[0] == '.') && (q[1] == '.'));
257 break;
258 case 1:
259 delentry = !(q[0] == '.');
260 break;
261 default:
262 delentry = TRUE;
263 break;
266 if ( delentry
267 && (t-p-1 == 2 && strncmp(p+1,"..",2) == 0) ) {
268 /* Skip one (or possible more) DirSepStr. */
269 do {
270 t++;
272 while( *t == *DirSepStr);
273 /* q points to first letter of the current directory/file. */
274 len = strlen(t)+1;
275 memmove(q,t,len);
276 q = tpath;
278 else
279 q = p+1;
282 DB_PRINT( "path", ("Cleaned path: %s", path ));
284 DB_VOID_RETURN;
288 char *
289 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.
296 Note, the returned path is built in a static buffer, if it is to be used
297 later a copy should be created. */
299 char *path;
301 static char *cpath = NIL(char);
303 DB_ENTER( "normalize_path" );
305 if ( !cpath && ( (cpath = MALLOC( PATH_MAX, char)) == NIL(char) ) )
306 No_ram();
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, '$') ) {
314 DB_RETURN( path );
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);
327 else
328 #endif
330 strcpy( cpath, path );
331 Clean_path( cpath );
334 DB_PRINT( "path", ("normalized: %s", cpath ));
336 DB_RETURN( cpath );