Pwd built-in added
[k8jam.git] / pathvms.c
blobe1aedaee4f6fde1bd146836360f6f68be8ede9b2
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
7 /*
8 * pathvms.c - manipulate file names on VMS
10 * External routines:
12 * path_parse() - split a file name into dir/base/suffix/member
13 * path_build() - build a filename given dir/base/suffix/member
14 * path_parent() - make a PATHNAME point to its parent dir
16 * File_parse() and path_build() just manipuate a string and a structure;
17 * they do not make system calls.
19 * WARNING! This file contains voodoo logic, as black magic is
20 * necessary for wrangling with VMS file name. Woe be to people
21 * who mess with this code.
23 * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
24 * 05/03/96 (seiwald) - split from filevms.c
25 * 11/04/02 (seiwald) - const-ing for string literals
28 # include "jam.h"
29 # include "pathsys.h"
31 # ifdef OS_VMS
33 # define DEBUG
36 * path_parse() - split a file name into dir/base/suffix/member
39 void
40 path_parse(
41 const char *file,
42 PATHNAME *f )
44 const char *p, *q;
45 const char *end;
47 memset( (char *)f, 0, sizeof( *f ) );
49 /* Look for <grist> */
51 if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
53 f->f_grist.ptr = file;
54 f->f_grist.len = p - file;
55 file = p + 1;
58 /* Look for dev:[dir] or dev: */
60 if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
62 f->f_dir.ptr = file;
63 f->f_dir.len = p + 1 - file;
64 file = p + 1;
67 end = file + strlen( file );
69 /* Look for (member) */
71 if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
73 f->f_member.ptr = p + 1;
74 f->f_member.len = end - p - 2;
75 end = p;
78 /* Look for .suffix */
79 /* This would be memrchr() */
81 p = 0;
82 q = file;
84 while( q = (char *)memchr( q, '.', end - q ) )
85 p = q++;
87 if( p )
89 f->f_suffix.ptr = p;
90 f->f_suffix.len = end - p;
91 end = p;
94 /* Leaves base */
96 f->f_base.ptr = file;
97 f->f_base.len = end - file;
99 /* Is this a directory without a file spec? */
101 f->parent = 0;
105 * dir mods result
106 * --- --- ------
107 * Rerooting:
109 * (none) :R=dev: dev:
110 * devd: :R=dev: devd:
111 * devd:[dir] :R=dev: devd:[dir]
112 * [.dir] :R=dev: dev:[dir] questionable
113 * [dir] :R=dev: dev:[dir]
115 * (none) :R=[rdir] [rdir] questionable
116 * devd: :R=[rdir] devd:
117 * devd:[dir] :R=[rdir] devd:[dir]
118 * [.dir] :R=[rdir] [rdir.dir] questionable
119 * [dir] :R=[rdir] [rdir]
121 * (none) :R=dev:[root] dev:[root]
122 * devd: :R=dev:[root] devd:
123 * devd:[dir] :R=dev:[root] devd:[dir]
124 * [.dir] :R=dev:[root] dev:[root.dir]
125 * [dir] :R=dev:[root] [dir]
127 * Climbing to parent:
131 # define DIR_EMPTY 0 /* empty string */
132 # define DIR_DEV 1 /* dev: */
133 # define DIR_DEVDIR 2 /* dev:[dir] */
134 # define DIR_DOTDIR 3 /* [.dir] */
135 # define DIR_DASHDIR 4 /* [-] or [-.dir] */
136 # define DIR_ABSDIR 5 /* [dir] */
137 # define DIR_ROOT 6 /* [000000] or dev:[000000] */
139 # define G_DIR 0 /* take just dir */
140 # define G_ROOT 1 /* take just root */
141 # define G_VAD 2 /* root's dev: + [abs] */
142 # define G_DRD 3 /* root's dev:[dir] + [.rel] */
143 # define G_VRD 4 /* root's dev: + [.rel] made [abs] */
144 # define G_DDD 5 /* root's dev:[dir] + . + [dir] */
146 static int grid[7][7] = {
148 /* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */
149 /* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR,
150 /* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD,
151 /* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD,
152 /* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
153 /* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR,
154 /* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
155 /* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR,
159 struct dirinf {
160 int flags;
162 struct {
163 char *ptr;
164 int len;
165 } dev, dir;
168 static char *
169 strnchr(
170 char *buf,
171 int c,
172 int len )
174 while( len-- )
175 if( *buf && *buf++ == c )
176 return buf - 1;
178 return 0;
181 static void
182 dir_flags(
183 const char *buf,
184 int len,
185 struct dirinf *i )
187 const char *p;
189 if( !buf || !len )
191 i->flags = DIR_EMPTY;
192 i->dev.ptr =
193 i->dir.ptr = 0;
194 i->dev.len =
195 i->dir.len = 0;
197 else if( p = strnchr( (char *)buf, ':', len ) )
199 i->dev.ptr = (char *)buf;
200 i->dev.len = p + 1 - buf;
201 i->dir.ptr = (char *)buf + i->dev.len;
202 i->dir.len = len - i->dev.len;
203 i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV;
205 else
207 i->dev.ptr = (char *)buf;
208 i->dev.len = 0;
209 i->dir.ptr = (char *)buf;
210 i->dir.len = len;
212 if( *buf == '[' && buf[1] == ']' )
213 i->flags = DIR_EMPTY;
214 else if( *buf == '[' && buf[1] == '.' )
215 i->flags = DIR_DOTDIR;
216 else if( *buf == '[' && buf[1] == '-' )
217 i->flags = DIR_DASHDIR;
218 else
219 i->flags = DIR_ABSDIR;
222 /* But if its rooted in any way */
224 if( i->dir.len == 8 && !strncmp( i->dir.ptr, "[000000]", 8 ) )
225 i->flags = DIR_ROOT;
229 * path_build() - build a filename given dir/base/suffix/member
232 void
233 path_build(
234 PATHNAME *f,
235 char *file,
236 int binding )
238 char *ofile = file;
239 struct dirinf root, dir;
240 int g;
242 /* Start with the grist. If the current grist isn't */
243 /* surrounded by <>'s, add them. */
245 if( f->f_grist.len )
247 if( f->f_grist.ptr[0] != '<' ) *file++ = '<';
248 memcpy( file, f->f_grist.ptr, f->f_grist.len );
249 file += f->f_grist.len;
250 if( file[-1] != '>' ) *file++ = '>';
253 /* Get info on root and dir for combining. */
255 dir_flags( f->f_root.ptr, f->f_root.len, &root );
256 dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );
258 /* Combine */
260 switch( g = grid[ root.flags ][ dir.flags ] )
262 case G_DIR:
263 /* take dir */
264 memcpy( file, f->f_dir.ptr, f->f_dir.len );
265 file += f->f_dir.len;
266 break;
268 case G_ROOT:
269 /* take root */
270 memcpy( file, f->f_root.ptr, f->f_root.len );
271 file += f->f_root.len;
272 break;
274 case G_VAD:
275 /* root's dev + abs directory */
276 memcpy( file, root.dev.ptr, root.dev.len );
277 file += root.dev.len;
278 memcpy( file, dir.dir.ptr, dir.dir.len );
279 file += dir.dir.len;
280 break;
282 case G_DRD:
283 case G_DDD:
284 /* root's dev:[dir] + rel directory */
285 memcpy( file, f->f_root.ptr, f->f_root.len );
286 file += f->f_root.len;
288 /* sanity checks: root ends with ] */
290 if( file[-1] == ']' )
291 --file;
293 /* Add . if separating two -'s */
295 if( g == G_DDD )
296 *file++ = '.';
298 /* skip [ of dir */
299 memcpy( file, dir.dir.ptr + 1, dir.dir.len - 1 );
300 file += dir.dir.len - 1;
301 break;
303 case G_VRD:
304 /* root's dev + rel directory made abs */
305 memcpy( file, root.dev.ptr, root.dev.len );
306 file += root.dev.len;
307 *file++ = '[';
308 /* skip [. of rel dir */
309 memcpy( file, dir.dir.ptr + 2, dir.dir.len - 2 );
310 file += dir.dir.len - 2;
311 break;
314 # ifdef DEBUG
315 if( DEBUG_SEARCH && ( root.flags || dir.flags ) )
317 *file = 0;
318 printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
319 grid[ root.flags ][ dir.flags ], ofile );
321 # endif
324 * Now do the special :P modifier when no file was present.
325 * (none) (none)
326 * [dir1.dir2] [dir1]
327 * [dir] [000000]
328 * [.dir] []
329 * [] []
332 if( file[-1] == ']' && f->parent )
334 while( file-- > ofile )
336 if( *file == '.' )
338 *file++ = ']';
339 break;
341 else if( *file == '-' )
343 /* handle .- or - */
344 if( file > ofile && file[-1] == '.' )
345 --file;
346 *file++ = ']';
347 break;
349 else if( *file == '[' )
351 if( file[1] == ']' )
353 file += 2;
355 else
357 strcpy( file, "[000000]" );
358 file += 8;
360 break;
365 /* Now copy the file pieces. */
367 if( f->f_base.len )
369 memcpy( file, f->f_base.ptr, f->f_base.len );
370 file += f->f_base.len;
373 /* If there is no suffix, we append a "." onto all generated */
374 /* names. This keeps VMS from appending its own (wrong) idea */
375 /* of what the suffix should be. */
377 if( f->f_suffix.len )
379 memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
380 file += f->f_suffix.len;
382 else if( binding && f->f_base.len )
384 *file++ = '.';
387 if( f->f_member.len )
389 *file++ = '(';
390 memcpy( file, f->f_member.ptr, f->f_member.len );
391 file += f->f_member.len;
392 *file++ = ')';
394 *file = 0;
396 # ifdef DEBUG
397 if( DEBUG_SEARCH )
398 printf("built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
399 f->f_root.len, f->f_root.ptr,
400 f->f_dir.len, f->f_dir.ptr,
401 f->f_base.len, f->f_base.ptr,
402 f->f_suffix.len, f->f_suffix.ptr,
403 f->f_member.len, f->f_member.ptr,
404 ofile );
405 # endif
409 * path_parent() - make a PATHNAME point to its parent dir
412 void
413 path_parent( PATHNAME *f )
415 if( f->f_base.len )
417 f->f_base.ptr =
418 f->f_suffix.ptr =
419 f->f_member.ptr = "";
421 f->f_base.len =
422 f->f_suffix.len =
423 f->f_member.len = 0;
425 else
427 f->parent = 1;
431 # endif /* VMS */