1 | /* |
---|
2 | * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. |
---|
3 | * |
---|
4 | * This file is part of Jam - see jam.c for Copyright information. |
---|
5 | */ |
---|
6 | |
---|
7 | /* This file is ALSO: |
---|
8 | * Copyright 2001-2004 David Abrahams. |
---|
9 | * Distributed under the Boost Software License, Version 1.0. |
---|
10 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
---|
11 | */ |
---|
12 | |
---|
13 | # include "jam.h" |
---|
14 | # include "pathsys.h" |
---|
15 | |
---|
16 | # ifdef OS_MAC |
---|
17 | |
---|
18 | # define DELIM ':' |
---|
19 | |
---|
20 | /* |
---|
21 | * pathunix.c - manipulate file names on UNIX, NT, OS2 |
---|
22 | * |
---|
23 | * External routines: |
---|
24 | * |
---|
25 | * path_parse() - split a file name into dir/base/suffix/member |
---|
26 | * path_build() - build a filename given dir/base/suffix/member |
---|
27 | * path_parent() - make a PATHNAME point to its parent dir |
---|
28 | * |
---|
29 | * File_parse() and path_build() just manipuate a string and a structure; |
---|
30 | * they do not make system calls. |
---|
31 | * |
---|
32 | * 04/08/94 (seiwald) - Coherent/386 support added. |
---|
33 | * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build() |
---|
34 | * 12/19/94 (mikem) - solaris string table insanity support |
---|
35 | * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way. |
---|
36 | * 02/14/95 (seiwald) - parse and build /xxx properly |
---|
37 | * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we |
---|
38 | * should expect hdr searches to come up with strings |
---|
39 | * like "thing/thing.h". So we need to test for "/" as |
---|
40 | * well as "\" when parsing pathnames. |
---|
41 | * 03/16/95 (seiwald) - fixed accursed typo on line 69. |
---|
42 | * 05/03/96 (seiwald) - split from filent.c, fileunix.c |
---|
43 | * 12/20/96 (seiwald) - when looking for the rightmost . in a file name, |
---|
44 | * don't include the archive member name. |
---|
45 | * 01/10/01 (seiwald) - path_parse now strips the trailing : from the |
---|
46 | * directory name, unless the directory name is all |
---|
47 | * :'s, so that $(d:P) works. |
---|
48 | */ |
---|
49 | |
---|
50 | /* |
---|
51 | * path_parse() - split a file name into dir/base/suffix/member |
---|
52 | */ |
---|
53 | |
---|
54 | void |
---|
55 | path_parse( |
---|
56 | char *file, |
---|
57 | PATHNAME *f ) |
---|
58 | { |
---|
59 | char *p, *q; |
---|
60 | char *end; |
---|
61 | |
---|
62 | memset( (char *)f, 0, sizeof( *f ) ); |
---|
63 | |
---|
64 | /* Look for <grist> */ |
---|
65 | |
---|
66 | if( file[0] == '<' && ( p = strchr( file, '>' ) ) ) |
---|
67 | { |
---|
68 | f->f_grist.ptr = file; |
---|
69 | f->f_grist.len = p - file; |
---|
70 | file = p + 1; |
---|
71 | } |
---|
72 | |
---|
73 | /* Look for dir: */ |
---|
74 | |
---|
75 | if( p = strrchr( file, DELIM ) ) |
---|
76 | { |
---|
77 | f->f_dir.ptr = file; |
---|
78 | f->f_dir.len = p - file; |
---|
79 | file = p + 1; |
---|
80 | |
---|
81 | /* All :'s? Include last : as part of directory name */ |
---|
82 | |
---|
83 | while( p > f->f_dir.ptr && *--p == DELIM ) |
---|
84 | ; |
---|
85 | |
---|
86 | if( p == f->f_dir.ptr ) |
---|
87 | f->f_dir.len++; |
---|
88 | } |
---|
89 | |
---|
90 | end = file + strlen( file ); |
---|
91 | |
---|
92 | /* Look for (member) */ |
---|
93 | |
---|
94 | if( ( p = strchr( file, '(' ) ) && end[-1] == ')' ) |
---|
95 | { |
---|
96 | f->f_member.ptr = p + 1; |
---|
97 | f->f_member.len = end - p - 2; |
---|
98 | end = p; |
---|
99 | } |
---|
100 | |
---|
101 | /* Look for .suffix */ |
---|
102 | /* This would be memrchr() */ |
---|
103 | |
---|
104 | p = 0; |
---|
105 | q = file; |
---|
106 | |
---|
107 | while( q = memchr( q, '.', end - q ) ) |
---|
108 | p = q++; |
---|
109 | |
---|
110 | if( p ) |
---|
111 | { |
---|
112 | f->f_suffix.ptr = p; |
---|
113 | f->f_suffix.len = end - p; |
---|
114 | end = p; |
---|
115 | } |
---|
116 | |
---|
117 | /* Leaves base */ |
---|
118 | |
---|
119 | f->f_base.ptr = file; |
---|
120 | f->f_base.len = end - file; |
---|
121 | } |
---|
122 | |
---|
123 | /* |
---|
124 | * path_build() - build a filename given dir/base/suffix/member |
---|
125 | */ |
---|
126 | |
---|
127 | # define DIR_EMPTY 0 /* "" */ |
---|
128 | # define DIR_DOT 1 /* : */ |
---|
129 | # define DIR_DOTDOT 2 /* :: */ |
---|
130 | # define DIR_ABS 3 /* dira:dirb: */ |
---|
131 | # define DIR_REL 4 /* :dira:dirb: */ |
---|
132 | |
---|
133 | # define G_DIR 0 /* take dir */ |
---|
134 | # define G_ROOT 1 /* take root */ |
---|
135 | # define G_CAT 2 /* prepend root to dir */ |
---|
136 | # define G_DTDR 3 /* :: of rel dir */ |
---|
137 | # define G_DDDD 4 /* make it ::: (../..) */ |
---|
138 | # define G_MT 5 /* leave it empty */ |
---|
139 | |
---|
140 | char grid[5][5] = { |
---|
141 | /* EMPTY DOT DOTDOT ABS REL */ |
---|
142 | /* EMPTY */ { G_MT, G_DIR, G_DIR, G_DIR, G_DIR }, |
---|
143 | /* DOT */ { G_ROOT, G_DIR, G_DIR, G_DIR, G_DIR }, |
---|
144 | /* DOTDOT */ { G_ROOT, G_ROOT, G_DDDD, G_DIR, G_DTDR }, |
---|
145 | /* ABS */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT }, |
---|
146 | /* REL */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT } |
---|
147 | } ; |
---|
148 | |
---|
149 | static int |
---|
150 | file_flags( |
---|
151 | char *ptr, |
---|
152 | int len ) |
---|
153 | { |
---|
154 | if( !len ) |
---|
155 | return DIR_EMPTY; |
---|
156 | if( len == 1 && ptr[0] == DELIM ) |
---|
157 | return DIR_DOT; |
---|
158 | if( len == 2 && ptr[0] == DELIM && ptr[1] == DELIM ) |
---|
159 | return DIR_DOTDOT; |
---|
160 | if( ptr[0] == DELIM ) |
---|
161 | return DIR_REL; |
---|
162 | return DIR_ABS; |
---|
163 | } |
---|
164 | |
---|
165 | void |
---|
166 | path_build( |
---|
167 | PATHNAME *f, |
---|
168 | string* file, |
---|
169 | int binding ) |
---|
170 | { |
---|
171 | int dflag, rflag, act; |
---|
172 | |
---|
173 | file_build1( f, file ); |
---|
174 | |
---|
175 | /* Combine root & directory, according to the grid. */ |
---|
176 | |
---|
177 | dflag = file_flags( f->f_dir.ptr, f->f_dir.len ); |
---|
178 | rflag = file_flags( f->f_root.ptr, f->f_root.len ); |
---|
179 | |
---|
180 | switch( act = grid[ rflag ][ dflag ] ) |
---|
181 | { |
---|
182 | case G_DTDR: |
---|
183 | { |
---|
184 | /* :: of rel dir */ |
---|
185 | string_push_back( file, DELIM ); |
---|
186 | } |
---|
187 | /* fall through */ |
---|
188 | |
---|
189 | case G_DIR: |
---|
190 | /* take dir */ |
---|
191 | string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len ); |
---|
192 | break; |
---|
193 | |
---|
194 | case G_ROOT: |
---|
195 | /* take root */ |
---|
196 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
197 | break; |
---|
198 | |
---|
199 | case G_CAT: |
---|
200 | /* prepend root to dir */ |
---|
201 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
202 | if( file->value[file->size - 1] == DELIM ) |
---|
203 | string_pop_back( file ); |
---|
204 | string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len ); |
---|
205 | break; |
---|
206 | |
---|
207 | case G_DDDD: |
---|
208 | /* make it ::: (../..) */ |
---|
209 | string_append( file, ":::" ); |
---|
210 | break; |
---|
211 | } |
---|
212 | |
---|
213 | /* Put : between dir and file (if none already) */ |
---|
214 | |
---|
215 | if( act != G_MT && |
---|
216 | file->value[file->size - 1] != DELIM && |
---|
217 | ( f->f_base.len || f->f_suffix.len ) ) |
---|
218 | { |
---|
219 | string_push_back( file, DELIM ); |
---|
220 | } |
---|
221 | |
---|
222 | if( f->f_base.len ) |
---|
223 | { |
---|
224 | string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len ); |
---|
225 | } |
---|
226 | |
---|
227 | if( f->f_suffix.len ) |
---|
228 | { |
---|
229 | string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len ); |
---|
230 | } |
---|
231 | |
---|
232 | if( f->f_member.len ) |
---|
233 | { |
---|
234 | string_push_back( file, '(' ); |
---|
235 | string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len ); |
---|
236 | string_push_back( file, ')' ); |
---|
237 | } |
---|
238 | |
---|
239 | if( DEBUG_SEARCH ) |
---|
240 | printf(" -> '%s'\n", file->value); |
---|
241 | } |
---|
242 | |
---|
243 | /* |
---|
244 | * path_parent() - make a PATHNAME point to its parent dir |
---|
245 | */ |
---|
246 | |
---|
247 | void |
---|
248 | path_parent( PATHNAME *f ) |
---|
249 | { |
---|
250 | /* just set everything else to nothing */ |
---|
251 | |
---|
252 | f->f_base.ptr = |
---|
253 | f->f_suffix.ptr = |
---|
254 | f->f_member.ptr = ""; |
---|
255 | |
---|
256 | f->f_base.len = |
---|
257 | f->f_suffix.len = |
---|
258 | f->f_member.len = 0; |
---|
259 | } |
---|
260 | |
---|
261 | # endif /* OS_MAC */ |
---|