sync master with lastest vba changes
[ooovba.git] / dmake / path.c
blobed53df442b89536743e3dd7f55077d62857af0b1
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;
176 DB_ENTER( "Clean_path" );
178 /* Skip the root part. */
179 tpath=path;
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); )
188 *q = *DirSepStr;
189 else
190 for( q = tpath; (q = strchr(q, '/')) != NIL(char); )
191 *q = *DirSepStr;
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) ) {
197 hasdriveletter = 1;
198 tpath+=2;
199 if( *tpath != *DirSepStr )
200 Warning("Malformed DOS path %s", path);
203 #endif
205 /* Collapse > 2 ( > 1 if its an absolute DOS path ) into one slash.
206 * Keep // as it is reserved in posix. */
207 q = tpath;
208 for( ; *q == *DirSepStr ; ++q )
210 if( q - tpath > 2 - hasdriveletter ) {
211 strcpy(tpath+1, q);
214 /* Set tpath after leading slash / drive letter. */
215 for( ; *tpath == *DirSepStr ; ++tpath )
217 q = tpath;
219 while( *q ) {
220 char *t;
222 /* p is NULL or greater than q. */
223 p=strchr(q, *DirSepStr);
224 if( !p ) break;
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. */
230 do {
231 p++;
233 while( *p == *DirSepStr);
234 strcpy(t+1,p);
235 continue;
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)) ) {
241 strcpy(q,p+1);
242 q = tpath;
243 continue;
246 /* If two '/' are in path check/remove 'foo/../' elements. */
247 t=strchr(p+1, *DirSepStr);
248 if( !t ) break;
250 /* Collaps this only if foo is neither '.' nor '..'. */
251 switch( p-q ) {
252 case 2:
253 delentry = !((q[0] == '.') && (q[1] == '.'));
254 break;
255 case 1:
256 delentry = !(q[0] == '.');
257 break;
258 default:
259 delentry = TRUE;
260 break;
263 if ( delentry
264 && (t-p-1 == 2 && strncmp(p+1,"..",2) == 0) ) {
265 /* Skip one (or possible more) DirSepStr. */
266 do {
267 t++;
269 while( *t == *DirSepStr);
270 /* q points to first letter of the current directory/file. */
271 strcpy(q,t);
272 q = tpath;
274 else
275 q = p+1;
278 DB_PRINT( "path", ("Cleaned path: %s", path ));
280 DB_VOID_RETURN;
284 char *
285 normalize_path(path)/*
286 =======================
287 Normalize the given path unless it contains a $ indicating a dynamic
288 prerequisite.
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. */
295 char *path;
297 static char *cpath = NIL(char);
299 DB_ENTER( "normalize_path" );
301 if ( !cpath && ( (cpath = MALLOC( PATH_MAX, char)) == NIL(char) ) )
302 No_ram();
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, '$') ) {
310 DB_RETURN( path );
313 #if __CYGWIN__
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);
317 if (err)
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);
323 else
324 #endif
326 strcpy( cpath, path );
327 Clean_path( cpath );
330 DB_PRINT( "path", ("normalized: %s", cpath ));
332 DB_RETURN( cpath );