Logo Search packages:      
Sourcecode: jam version File versions  Download package

pathvms.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 */

Generated by  Doxygen 1.6.0   Back to index