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_VMS |
---|
17 | |
---|
18 | # define DEBUG |
---|
19 | |
---|
20 | /* |
---|
21 | * pathvms.c - manipulate file names on VMS |
---|
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 | * WARNING! This file contains voodoo logic, as black magic is |
---|
33 | * necessary for wrangling with VMS file name. Woe be to people |
---|
34 | * who mess with this code. |
---|
35 | * |
---|
36 | * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length! |
---|
37 | * 05/03/96 (seiwald) - split from filevms.c |
---|
38 | */ |
---|
39 | |
---|
40 | /* |
---|
41 | * path_parse() - split a file name into dir/base/suffix/member |
---|
42 | */ |
---|
43 | |
---|
44 | void |
---|
45 | path_parse( |
---|
46 | char *file, |
---|
47 | PATHNAME *f ) |
---|
48 | { |
---|
49 | char *p, *q; |
---|
50 | char *end; |
---|
51 | |
---|
52 | memset( (char *)f, 0, sizeof( *f ) ); |
---|
53 | |
---|
54 | /* Look for <grist> */ |
---|
55 | |
---|
56 | if( file[0] == '<' && ( p = strchr( file, '>' ) ) ) |
---|
57 | { |
---|
58 | f->f_grist.ptr = file; |
---|
59 | f->f_grist.len = p - file; |
---|
60 | file = p + 1; |
---|
61 | } |
---|
62 | |
---|
63 | /* Look for dev:[dir] or dev: */ |
---|
64 | |
---|
65 | if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) ) |
---|
66 | { |
---|
67 | f->f_dir.ptr = file; |
---|
68 | f->f_dir.len = p + 1 - file; |
---|
69 | file = p + 1; |
---|
70 | } |
---|
71 | |
---|
72 | end = file + strlen( file ); |
---|
73 | |
---|
74 | /* Look for (member) */ |
---|
75 | |
---|
76 | if( ( p = strchr( file, '(' ) ) && end[-1] == ')' ) |
---|
77 | { |
---|
78 | f->f_member.ptr = p + 1; |
---|
79 | f->f_member.len = end - p - 2; |
---|
80 | end = p; |
---|
81 | } |
---|
82 | |
---|
83 | /* Look for .suffix */ |
---|
84 | /* This would be memrchr() */ |
---|
85 | |
---|
86 | p = 0; |
---|
87 | q = file; |
---|
88 | |
---|
89 | while( q = (char *)memchr( q, '.', end - q ) ) |
---|
90 | p = q++; |
---|
91 | |
---|
92 | if( p ) |
---|
93 | { |
---|
94 | f->f_suffix.ptr = p; |
---|
95 | f->f_suffix.len = end - p; |
---|
96 | end = p; |
---|
97 | } |
---|
98 | |
---|
99 | /* Leaves base */ |
---|
100 | |
---|
101 | f->f_base.ptr = file; |
---|
102 | f->f_base.len = end - file; |
---|
103 | |
---|
104 | /* Is this a directory without a file spec? */ |
---|
105 | |
---|
106 | f->parent = 0; |
---|
107 | } |
---|
108 | |
---|
109 | /* |
---|
110 | * dir mods result |
---|
111 | * --- --- ------ |
---|
112 | * Rerooting: |
---|
113 | * |
---|
114 | * (none) :R=dev: dev: |
---|
115 | * devd: :R=dev: devd: |
---|
116 | * devd:[dir] :R=dev: devd:[dir] |
---|
117 | * [.dir] :R=dev: dev:[dir] questionable |
---|
118 | * [dir] :R=dev: dev:[dir] |
---|
119 | * |
---|
120 | * (none) :R=[rdir] [rdir] questionable |
---|
121 | * devd: :R=[rdir] devd: |
---|
122 | * devd:[dir] :R=[rdir] devd:[dir] |
---|
123 | * [.dir] :R=[rdir] [rdir.dir] questionable |
---|
124 | * [dir] :R=[rdir] [rdir] |
---|
125 | * |
---|
126 | * (none) :R=dev:[root] dev:[root] |
---|
127 | * devd: :R=dev:[root] devd: |
---|
128 | * devd:[dir] :R=dev:[root] devd:[dir] |
---|
129 | * [.dir] :R=dev:[root] dev:[root.dir] |
---|
130 | * [dir] :R=dev:[root] [dir] |
---|
131 | * |
---|
132 | * Climbing to parent: |
---|
133 | * |
---|
134 | */ |
---|
135 | |
---|
136 | # define DIR_EMPTY 0 /* empty string */ |
---|
137 | # define DIR_DEV 1 /* dev: */ |
---|
138 | # define DIR_DEVDIR 2 /* dev:[dir] */ |
---|
139 | # define DIR_DOTDIR 3 /* [.dir] */ |
---|
140 | # define DIR_DASHDIR 4 /* [-] or [-.dir] */ |
---|
141 | # define DIR_ABSDIR 5 /* [dir] */ |
---|
142 | # define DIR_ROOT 6 /* [000000] or dev:[000000] */ |
---|
143 | |
---|
144 | # define G_DIR 0 /* take just dir */ |
---|
145 | # define G_ROOT 1 /* take just root */ |
---|
146 | # define G_VAD 2 /* root's dev: + [abs] */ |
---|
147 | # define G_DRD 3 /* root's dev:[dir] + [.rel] */ |
---|
148 | # define G_VRD 4 /* root's dev: + [.rel] made [abs] */ |
---|
149 | # define G_DDD 5 /* root's dev:[dir] + . + [dir] */ |
---|
150 | |
---|
151 | static int grid[7][7] = { |
---|
152 | |
---|
153 | /* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */ |
---|
154 | /* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, |
---|
155 | /* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD, |
---|
156 | /* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD, |
---|
157 | /* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, |
---|
158 | /* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR, |
---|
159 | /* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, |
---|
160 | /* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR, |
---|
161 | |
---|
162 | } ; |
---|
163 | |
---|
164 | struct dirinf { |
---|
165 | int flags; |
---|
166 | |
---|
167 | struct { |
---|
168 | char *ptr; |
---|
169 | int len; |
---|
170 | } dev, dir; |
---|
171 | } ; |
---|
172 | |
---|
173 | static char * |
---|
174 | strnchr( |
---|
175 | char *buf, |
---|
176 | int c, |
---|
177 | int len ) |
---|
178 | { |
---|
179 | while( len-- ) |
---|
180 | if( *buf && *buf++ == c ) |
---|
181 | return buf - 1; |
---|
182 | |
---|
183 | return 0; |
---|
184 | } |
---|
185 | |
---|
186 | static void |
---|
187 | dir_flags( |
---|
188 | char *buf, |
---|
189 | int len, |
---|
190 | struct dirinf *i ) |
---|
191 | { |
---|
192 | char *p; |
---|
193 | |
---|
194 | if( !buf || !len ) |
---|
195 | { |
---|
196 | i->flags = DIR_EMPTY; |
---|
197 | i->dev.ptr = |
---|
198 | i->dir.ptr = 0; |
---|
199 | i->dev.len = |
---|
200 | i->dir.len = 0; |
---|
201 | } |
---|
202 | else if( p = strnchr( buf, ':', len ) ) |
---|
203 | { |
---|
204 | i->dev.ptr = buf; |
---|
205 | i->dev.len = p + 1 - buf; |
---|
206 | i->dir.ptr = buf + i->dev.len; |
---|
207 | i->dir.len = len - i->dev.len; |
---|
208 | i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV; |
---|
209 | } |
---|
210 | else |
---|
211 | { |
---|
212 | i->dev.ptr = buf; |
---|
213 | i->dev.len = 0; |
---|
214 | i->dir.ptr = buf; |
---|
215 | i->dir.len = len; |
---|
216 | |
---|
217 | if( *buf == '[' && buf[1] == ']' ) |
---|
218 | i->flags = DIR_EMPTY; |
---|
219 | else if( *buf == '[' && buf[1] == '.' ) |
---|
220 | i->flags = DIR_DOTDIR; |
---|
221 | else if( *buf == '[' && buf[1] == '-' ) |
---|
222 | i->flags = DIR_DASHDIR; |
---|
223 | else |
---|
224 | i->flags = DIR_ABSDIR; |
---|
225 | } |
---|
226 | |
---|
227 | /* But if its rooted in any way */ |
---|
228 | |
---|
229 | if( i->dir.len == 8 && !strncmp( i->dir.ptr, "[000000]", 8 ) ) |
---|
230 | i->flags = DIR_ROOT; |
---|
231 | } |
---|
232 | |
---|
233 | /* |
---|
234 | * path_build() - build a filename given dir/base/suffix/member |
---|
235 | */ |
---|
236 | |
---|
237 | void |
---|
238 | path_build( |
---|
239 | PATHNAME *f, |
---|
240 | string *file, |
---|
241 | int binding ) |
---|
242 | { |
---|
243 | struct dirinf root, dir; |
---|
244 | int g; |
---|
245 | |
---|
246 | file_build1( f, file ); |
---|
247 | |
---|
248 | /* Get info on root and dir for combining. */ |
---|
249 | |
---|
250 | dir_flags( f->f_root.ptr, f->f_root.len, &root ); |
---|
251 | dir_flags( f->f_dir.ptr, f->f_dir.len, &dir ); |
---|
252 | |
---|
253 | /* Combine */ |
---|
254 | |
---|
255 | switch( g = grid[ root.flags ][ dir.flags ] ) |
---|
256 | { |
---|
257 | case G_DIR: |
---|
258 | /* take dir */ |
---|
259 | string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len ); |
---|
260 | break; |
---|
261 | |
---|
262 | case G_ROOT: |
---|
263 | /* take root */ |
---|
264 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
265 | break; |
---|
266 | |
---|
267 | case G_VAD: |
---|
268 | /* root's dev + abs directory */ |
---|
269 | string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); |
---|
270 | string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len ); |
---|
271 | break; |
---|
272 | |
---|
273 | case G_DRD: |
---|
274 | case G_DDD: |
---|
275 | /* root's dev:[dir] + rel directory */ |
---|
276 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
277 | |
---|
278 | /* sanity checks: root ends with ] */ |
---|
279 | |
---|
280 | if( file->value[file->size - 1] == ']' ) |
---|
281 | string_pop_back( file ); |
---|
282 | |
---|
283 | /* Add . if separating two -'s */ |
---|
284 | |
---|
285 | if( g == G_DDD ) |
---|
286 | string_push_back( file, '.' ); |
---|
287 | |
---|
288 | /* skip [ of dir */ |
---|
289 | string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 ); |
---|
290 | break; |
---|
291 | |
---|
292 | case G_VRD: |
---|
293 | /* root's dev + rel directory made abs */ |
---|
294 | string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); |
---|
295 | string_push_back( file, '[' ); |
---|
296 | /* skip [. of rel dir */ |
---|
297 | string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 ); |
---|
298 | break; |
---|
299 | } |
---|
300 | |
---|
301 | # ifdef DEBUG |
---|
302 | if( DEBUG_SEARCH && ( root.flags || dir.flags ) ) |
---|
303 | { |
---|
304 | printf( "%d x %d = %d (%s)\n", root.flags, dir.flags, |
---|
305 | grid[ root.flags ][ dir.flags ], file->value ); |
---|
306 | } |
---|
307 | # endif |
---|
308 | |
---|
309 | /* |
---|
310 | * Now do the special :P modifier when no file was present. |
---|
311 | * (none) (none) |
---|
312 | * [dir1.dir2] [dir1] |
---|
313 | * [dir] [000000] |
---|
314 | * [.dir] (none) |
---|
315 | * [] [] |
---|
316 | */ |
---|
317 | |
---|
318 | if( file->value[file->size - 1] == ']' && f->parent ) |
---|
319 | { |
---|
320 | char* p = file->value + file->size; |
---|
321 | while( p-- > file->value ) |
---|
322 | { |
---|
323 | if( *p == '.' ) |
---|
324 | { |
---|
325 | /* If we've truncated everything and left with '[', |
---|
326 | return empty string. */ |
---|
327 | if (p == file->value + 1) |
---|
328 | string_truncate( file, 0 ); |
---|
329 | else { |
---|
330 | string_truncate( file, p - file->value ); |
---|
331 | string_push_back( file, ']' ); |
---|
332 | } |
---|
333 | break; |
---|
334 | } |
---|
335 | else if( *p == '-' ) |
---|
336 | { |
---|
337 | /* handle .- or - */ |
---|
338 | if( p > file->value && p[-1] == '.' ) |
---|
339 | --p; |
---|
340 | |
---|
341 | *p++ = ']'; |
---|
342 | break; |
---|
343 | } |
---|
344 | else if( *p == '[' ) |
---|
345 | { |
---|
346 | if( p[1] == ']' ) |
---|
347 | { |
---|
348 | /* CONSIDER: I don't see any use of this code. We immediately |
---|
349 | break, and 'p' is a local variable. */ |
---|
350 | p += 2; |
---|
351 | } |
---|
352 | else |
---|
353 | { |
---|
354 | string_truncate( file, p - file->value ); |
---|
355 | string_append( file, "[000000]" ); |
---|
356 | } |
---|
357 | break; |
---|
358 | } |
---|
359 | } |
---|
360 | } |
---|
361 | |
---|
362 | /* Now copy the file pieces. */ |
---|
363 | |
---|
364 | if( f->f_base.len ) |
---|
365 | { |
---|
366 | string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len ); |
---|
367 | } |
---|
368 | |
---|
369 | /* If there is no suffix, we append a "." onto all generated */ |
---|
370 | /* names. This keeps VMS from appending its own (wrong) idea */ |
---|
371 | /* of what the suffix should be. */ |
---|
372 | |
---|
373 | if( f->f_suffix.len ) |
---|
374 | { |
---|
375 | string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len ); |
---|
376 | } |
---|
377 | else if( binding && f->f_base.len ) |
---|
378 | { |
---|
379 | string_push_back( file, '.' ); |
---|
380 | } |
---|
381 | |
---|
382 | if( f->f_member.len ) |
---|
383 | { |
---|
384 | string_push_back( file, '(' ); |
---|
385 | string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len ); |
---|
386 | string_push_back( file, ')' ); |
---|
387 | } |
---|
388 | |
---|
389 | # ifdef DEBUG |
---|
390 | if( DEBUG_SEARCH ) |
---|
391 | printf("built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n", |
---|
392 | f->f_root.len, f->f_root.ptr, |
---|
393 | f->f_dir.len, f->f_dir.ptr, |
---|
394 | f->f_base.len, f->f_base.ptr, |
---|
395 | f->f_suffix.len, f->f_suffix.ptr, |
---|
396 | f->f_member.len, f->f_member.ptr, |
---|
397 | file->value ); |
---|
398 | # endif |
---|
399 | } |
---|
400 | |
---|
401 | /* |
---|
402 | * path_parent() - make a PATHNAME point to its parent dir |
---|
403 | */ |
---|
404 | |
---|
405 | void |
---|
406 | path_parent( PATHNAME *f ) |
---|
407 | { |
---|
408 | if( f->f_base.len ) |
---|
409 | { |
---|
410 | f->f_base.ptr = |
---|
411 | f->f_suffix.ptr = |
---|
412 | f->f_member.ptr = ""; |
---|
413 | |
---|
414 | f->f_base.len = |
---|
415 | f->f_suffix.len = |
---|
416 | f->f_member.len = 0; |
---|
417 | } |
---|
418 | else |
---|
419 | { |
---|
420 | f->parent = 1; |
---|
421 | } |
---|
422 | } |
---|
423 | |
---|
424 | # endif /* VMS */ |
---|