diff options
Diffstat (limited to 'jam-files/engine/pathvms.c')
-rw-r--r-- | jam-files/engine/pathvms.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/jam-files/engine/pathvms.c b/jam-files/engine/pathvms.c new file mode 100644 index 00000000..975fe5a5 --- /dev/null +++ b/jam-files/engine/pathvms.c @@ -0,0 +1,406 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +/* This file is ALSO: + * Copyright 2001-2004 David Abrahams. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +# include "jam.h" +# include "pathsys.h" + +# ifdef OS_VMS + +# define DEBUG + +/* + * pathvms.c - manipulate file names on VMS + * + * External routines: + * + * path_parse() - split a file name into dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member + * path_parent() - make a PATHNAME point to its parent dir + * + * File_parse() and path_build() just manipuate a string and a structure; + * they do not make system calls. + * + * WARNING! This file contains voodoo logic, as black magic is + * necessary for wrangling with VMS file name. Woe be to people + * who mess with this code. + * + * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length! + * 05/03/96 (seiwald) - split from filevms.c + */ + +/* + * path_parse() - split a file name into dir/base/suffix/member. + */ + +void path_parse( char * file, PATHNAME * f ) +{ + char * p; + char * q; + char * end; + + memset( (char *)f, 0, sizeof( *f ) ); + + /* Look for <grist> */ + + if ( ( file[0] == '<' ) && ( p = strchr( file, '>' ) ) ) + { + f->f_grist.ptr = file; + f->f_grist.len = p - file; + file = p + 1; + } + + /* Look for dev:[dir] or dev: */ + + if ( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) ) + { + f->f_dir.ptr = file; + f->f_dir.len = p + 1 - file; + file = p + 1; + } + + end = file + strlen( file ); + + /* Look for (member). */ + + if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) ) + { + f->f_member.ptr = p + 1; + f->f_member.len = end - p - 2; + end = p; + } + + /* Look for .suffix */ + /* This would be memrchr(). */ + + p = 0; + q = file; + + while ( q = (char *)memchr( q, '.', end - q ) ) + p = q++; + + if ( p ) + { + f->f_suffix.ptr = p; + f->f_suffix.len = end - p; + end = p; + } + + /* Leaves base. */ + f->f_base.ptr = file; + f->f_base.len = end - file; + + /* Is this a directory without a file spec? */ + f->parent = 0; +} + +/* + * dir mods result + * --- --- ------ + * Rerooting: + * + * (none) :R=dev: dev: + * devd: :R=dev: devd: + * devd:[dir] :R=dev: devd:[dir] + * [.dir] :R=dev: dev:[dir] questionable + * [dir] :R=dev: dev:[dir] + * + * (none) :R=[rdir] [rdir] questionable + * devd: :R=[rdir] devd: + * devd:[dir] :R=[rdir] devd:[dir] + * [.dir] :R=[rdir] [rdir.dir] questionable + * [dir] :R=[rdir] [rdir] + * + * (none) :R=dev:[root] dev:[root] + * devd: :R=dev:[root] devd: + * devd:[dir] :R=dev:[root] devd:[dir] + * [.dir] :R=dev:[root] dev:[root.dir] + * [dir] :R=dev:[root] [dir] + * + * Climbing to parent: + * + */ + +# define DIR_EMPTY 0 /* empty string */ +# define DIR_DEV 1 /* dev: */ +# define DIR_DEVDIR 2 /* dev:[dir] */ +# define DIR_DOTDIR 3 /* [.dir] */ +# define DIR_DASHDIR 4 /* [-] or [-.dir] */ +# define DIR_ABSDIR 5 /* [dir] */ +# define DIR_ROOT 6 /* [000000] or dev:[000000] */ + +# define G_DIR 0 /* take just dir */ +# define G_ROOT 1 /* take just root */ +# define G_VAD 2 /* root's dev: + [abs] */ +# define G_DRD 3 /* root's dev:[dir] + [.rel] */ +# define G_VRD 4 /* root's dev: + [.rel] made [abs] */ +# define G_DDD 5 /* root's dev:[dir] + . + [dir] */ + +static int grid[7][7] = { + +/* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */ +/* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, +/* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD, +/* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD, +/* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, +/* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR, +/* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, +/* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR, + +}; + +struct dirinf +{ + int flags; + + struct + { + char * ptr; + int len; + } dev, dir; +}; + +static char * strnchr( char * buf, int c, int len ) +{ + while ( len-- ) + if ( *buf && ( *buf++ == c ) ) + return buf - 1; + return 0; +} + + +static void dir_flags( char * buf, int len, struct dirinf * i ) +{ + char * p; + + if ( !buf || !len ) + { + i->flags = DIR_EMPTY; + i->dev.ptr = + i->dir.ptr = 0; + i->dev.len = + i->dir.len = 0; + } + else if ( p = strnchr( buf, ':', len ) ) + { + i->dev.ptr = buf; + i->dev.len = p + 1 - buf; + i->dir.ptr = buf + i->dev.len; + i->dir.len = len - i->dev.len; + i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV; + } + else + { + i->dev.ptr = buf; + i->dev.len = 0; + i->dir.ptr = buf; + i->dir.len = len; + + if ( ( *buf == '[' ) && ( buf[1] == ']' ) ) + i->flags = DIR_EMPTY; + else if ( ( *buf == '[' ) && ( buf[1] == '.' ) ) + i->flags = DIR_DOTDIR; + else if ( ( *buf == '[' ) && ( buf[1] == '-' ) ) + i->flags = DIR_DASHDIR; + else + i->flags = DIR_ABSDIR; + } + + /* But if its rooted in any way. */ + + if ( ( i->dir.len == 8 ) && !strncmp( i->dir.ptr, "[000000]", 8 ) ) + i->flags = DIR_ROOT; +} + + +/* + * path_build() - build a filename given dir/base/suffix/member + */ + +void path_build( PATHNAME * f, string * file, int binding ) +{ + struct dirinf root; + struct dirinf dir; + int g; + + file_build1( f, file ); + + /* Get info on root and dir for combining. */ + dir_flags( f->f_root.ptr, f->f_root.len, &root ); + dir_flags( f->f_dir.ptr, f->f_dir.len, &dir ); + + /* Combine. */ + switch ( g = grid[ root.flags ][ dir.flags ] ) + { + case G_DIR: + /* take dir */ + string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len ); + break; + + case G_ROOT: + /* take root */ + string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); + break; + + case G_VAD: + /* root's dev + abs directory */ + string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); + string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len ); + break; + + case G_DRD: + case G_DDD: + /* root's dev:[dir] + rel directory */ + string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); + + /* sanity checks: root ends with ] */ + + if ( file->value[file->size - 1] == ']' ) + string_pop_back( file ); + + /* Add . if separating two -'s */ + + if ( g == G_DDD ) + string_push_back( file, '.' ); + + /* skip [ of dir */ + string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 ); + break; + + case G_VRD: + /* root's dev + rel directory made abs */ + string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); + string_push_back( file, '[' ); + /* skip [. of rel dir */ + string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 ); + break; + } + +# ifdef DEBUG + if ( DEBUG_SEARCH && ( root.flags || dir.flags ) ) + printf( "%d x %d = %d (%s)\n", root.flags, dir.flags, + grid[ root.flags ][ dir.flags ], file->value ); +# endif + + /* + * Now do the special :P modifier when no file was present. + * (none) (none) + * [dir1.dir2] [dir1] + * [dir] [000000] + * [.dir] (none) + * [] [] + */ + + if ( ( file->value[ file->size - 1 ] == ']' ) && f->parent ) + { + char * p = file->value + file->size; + while ( p-- > file->value ) + { + if ( *p == '.' ) + { + /* If we've truncated everything and left with '[', + return empty string. */ + if ( p == file->value + 1 ) + string_truncate( file, 0 ); + else + { + string_truncate( file, p - file->value ); + string_push_back( file, ']' ); + } + break; + } + + if ( *p == '-' ) + { + /* handle .- or - */ + if ( ( p > file->value ) && ( p[ -1 ] == '.' ) ) + --p; + + *p++ = ']'; + break; + } + + if ( *p == '[' ) + { + if ( p[ 1 ] == ']' ) + { + /* CONSIDER: I don't see any use of this code. We immediately + break, and 'p' is a local variable. */ + p += 2; + } + else + { + string_truncate( file, p - file->value ); + string_append( file, "[000000]" ); + } + break; + } + } + } + + /* Now copy the file pieces. */ + if ( f->f_base.len ) + { + string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len ); + } + + /* If there is no suffix, we append a "." onto all generated names. This + * keeps VMS from appending its own (wrong) idea of what the suffix should + * be. + */ + if ( f->f_suffix.len ) + string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len ); + else if ( binding && f->f_base.len ) + string_push_back( file, '.' ); + + if ( f->f_member.len ) + { + string_push_back( file, '(' ); + string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len ); + string_push_back( file, ')' ); + } + +# ifdef DEBUG + if ( DEBUG_SEARCH ) + printf( "built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n", + f->f_root.len, f->f_root.ptr, + f->f_dir.len, f->f_dir.ptr, + f->f_base.len, f->f_base.ptr, + f->f_suffix.len, f->f_suffix.ptr, + f->f_member.len, f->f_member.ptr, + file->value ); +# endif +} + + +/* + * path_parent() - make a PATHNAME point to its parent dir + */ + +void path_parent( PATHNAME * f ) +{ + if ( f->f_base.len ) + { + f->f_base.ptr = + f->f_suffix.ptr = + f->f_member.ptr = ""; + + f->f_base.len = + f->f_suffix.len = + f->f_member.len = 0; + } + else + { + f->parent = 1; + } +} + +# endif /* VMS */ |