mirror of
https://review.haiku-os.org/buildtools
synced 2024-11-23 07:18:49 +01:00
ecc89c9a6a
git-svn-id: file:///srv/svn/repos/haiku/buildtools/trunk@15729 a95241bf-73f2-0310-859d-f6bbb57e9c96
432 lines
8.7 KiB
C
432 lines
8.7 KiB
C
/*
|
|
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
|
*
|
|
* This file is part of Jam - see jam.c for Copyright information.
|
|
*/
|
|
|
|
/*
|
|
* 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
|
|
* 11/04/02 (seiwald) - const-ing for string literals
|
|
*/
|
|
|
|
# include "jam.h"
|
|
# include "pathsys.h"
|
|
|
|
# ifdef OS_VMS
|
|
|
|
# define DEBUG
|
|
|
|
/*
|
|
* path_parse() - split a file name into dir/base/suffix/member
|
|
*/
|
|
|
|
void
|
|
path_parse(
|
|
const char *file,
|
|
PATHNAME *f )
|
|
{
|
|
const char *p, *q;
|
|
const 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(
|
|
const char *buf,
|
|
int len,
|
|
struct dirinf *i )
|
|
{
|
|
const 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( (char *)buf, ':', len ) )
|
|
{
|
|
i->dev.ptr = (char *)buf;
|
|
i->dev.len = p + 1 - buf;
|
|
i->dir.ptr = (char *)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 = (char *)buf;
|
|
i->dev.len = 0;
|
|
i->dir.ptr = (char *)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,
|
|
char *file,
|
|
int binding )
|
|
{
|
|
char *ofile = file;
|
|
struct dirinf root, dir;
|
|
int g;
|
|
|
|
/* Start with the grist. If the current grist isn't */
|
|
/* surrounded by <>'s, add them. */
|
|
|
|
if( f->f_grist.len )
|
|
{
|
|
if( f->f_grist.ptr[0] != '<' ) *file++ = '<';
|
|
memcpy( file, f->f_grist.ptr, f->f_grist.len );
|
|
file += f->f_grist.len;
|
|
if( file[-1] != '>' ) *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 */
|
|
memcpy( file, f->f_dir.ptr, f->f_dir.len );
|
|
file += f->f_dir.len;
|
|
break;
|
|
|
|
case G_ROOT:
|
|
/* take root */
|
|
memcpy( file, f->f_root.ptr, f->f_root.len );
|
|
file += f->f_root.len;
|
|
break;
|
|
|
|
case G_VAD:
|
|
/* root's dev + abs directory */
|
|
memcpy( file, root.dev.ptr, root.dev.len );
|
|
file += root.dev.len;
|
|
memcpy( file, dir.dir.ptr, dir.dir.len );
|
|
file += dir.dir.len;
|
|
break;
|
|
|
|
case G_DRD:
|
|
case G_DDD:
|
|
/* root's dev:[dir] + rel directory */
|
|
memcpy( file, f->f_root.ptr, f->f_root.len );
|
|
file += f->f_root.len;
|
|
|
|
/* sanity checks: root ends with ] */
|
|
|
|
if( file[-1] == ']' )
|
|
--file;
|
|
|
|
/* Add . if separating two -'s */
|
|
|
|
if( g == G_DDD )
|
|
*file++ = '.';
|
|
|
|
/* skip [ of dir */
|
|
memcpy( file, dir.dir.ptr + 1, dir.dir.len - 1 );
|
|
file += dir.dir.len - 1;
|
|
break;
|
|
|
|
case G_VRD:
|
|
/* root's dev + rel directory made abs */
|
|
memcpy( file, root.dev.ptr, root.dev.len );
|
|
file += root.dev.len;
|
|
*file++ = '[';
|
|
/* skip [. of rel dir */
|
|
memcpy( file, dir.dir.ptr + 2, dir.dir.len - 2 );
|
|
file += dir.dir.len - 2;
|
|
break;
|
|
}
|
|
|
|
# ifdef DEBUG
|
|
if( DEBUG_SEARCH && ( root.flags || dir.flags ) )
|
|
{
|
|
*file = 0;
|
|
printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
|
|
grid[ root.flags ][ dir.flags ], ofile );
|
|
}
|
|
# endif
|
|
|
|
/*
|
|
* Now do the special :P modifier when no file was present.
|
|
* (none) (none)
|
|
* [dir1.dir2] [dir1]
|
|
* [dir] [000000]
|
|
* [.dir] []
|
|
* [] []
|
|
*/
|
|
|
|
if( file[-1] == ']' && f->parent )
|
|
{
|
|
while( file-- > ofile )
|
|
{
|
|
if( *file == '.' )
|
|
{
|
|
*file++ = ']';
|
|
break;
|
|
}
|
|
else if( *file == '-' )
|
|
{
|
|
/* handle .- or - */
|
|
if( file > ofile && file[-1] == '.' )
|
|
--file;
|
|
*file++ = ']';
|
|
break;
|
|
}
|
|
else if( *file == '[' )
|
|
{
|
|
if( file[1] == ']' )
|
|
{
|
|
file += 2;
|
|
}
|
|
else
|
|
{
|
|
strcpy( file, "[000000]" );
|
|
file += 8;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now copy the file pieces. */
|
|
|
|
if( f->f_base.len )
|
|
{
|
|
memcpy( file, f->f_base.ptr, f->f_base.len );
|
|
file += 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 )
|
|
{
|
|
memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
|
|
file += f->f_suffix.len;
|
|
}
|
|
else if( binding && f->f_base.len )
|
|
{
|
|
*file++ = '.';
|
|
}
|
|
|
|
if( f->f_member.len )
|
|
{
|
|
*file++ = '(';
|
|
memcpy( file, f->f_member.ptr, f->f_member.len );
|
|
file += f->f_member.len;
|
|
*file++ = ')';
|
|
}
|
|
*file = 0;
|
|
|
|
# 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,
|
|
ofile );
|
|
# 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 */
|