🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: net.decus
Article #49

Reading TAR from VMS

#49
From: ramin
Date: Sat, 06 Sep 1986 23:18
1607 lines
51908 bytes
Well... my recent inquiry about TAR programs in VMS garnished me
the following responses... The last two have actual programs
that were enclosed and I have included them verbatim (though
it seems they are closely related... but I thought I'd throw them
both in anyway...) I also have another FORTRAN one here that someone at
a sister company wrote. I haven't included it since I don't know
if he wants it distributed...

I have not fully tested any of them. But since this machine is
shortly due to go off the net I figured I should send it out
before they pull the plug...(:-( Barring circumstances I should be
back on the net via another system in about a month and I might
fix up the programs to allow subdirectory creations, etc...)

Again, thanks to all who responded.

P.S. John Gilmore (hoptoad!gnu) has also offered a copy of a C TAR program
he has... Hopefully I'll get it soon enough... If someone needs to
try it out they could contact him directly if I'm not around...

ramin

***************************************************************************

From: H}vard Eidnes <lll-lcc!caip!seismo!mcvax!vax.runit.unit.uninett!H_Eidnes>

I saw your recent request for some TAR program on VMS. It just
happens that a friend of mine recently wrote such a program.
The program is written in VMS Pascal. It has mainly been used
to read TAR tapes down to TAR files on disk to be transferred
to a Unix system to be unpacked. We've used Kermit to transfer
from our VMS computer to a MicroVAX II (without 1/2" tape), and
that has worked, but is slow, eg. it took 12hrs transferring
TeX, but it worked...

The Pascal program is capable of just extracting a part of a tape
by giving it a starting and ending filename prefix. It also has
routines to do actual extraction on VMS, but we haven't used these
routines much. NB: the program only handles TAR files blocked 20.

I will be happy to send you the program if you want it.

***************************************************************************

From: lll-lcc!caip!uw-beaver!uw-june!gordon (Gordon Davisson)

Here's a program that does what you want.  It did get into a recent decus
tape (VAX85C?), but that version happens to not work.  Use this instead.

-- 
Human:    Gordon Davisson
ARPA:     gordon@uw-june.ARPA
UUCP:     {ihnp4,decvax,tektronix}!uw-beaver!uw-june!gordon
Bitnet:   gordon@uwaphast
ATT:      (206) 527-0832
USnail:   5008 12th NE, Seattle, WA, 98105

--------------- cut here, then run the file (with an @) ---------------
$!
$ write sys$output "creating CVT.FOR"
$ create CVT.FOR
$ deck
c
c this subroutine converts a complete filespec (directory+file) name from
c unix format to VMS
c
      subroutine cvt_dir_uv( unix, vms, vlen )

      parameter reserved = 10
      character*(*) unix, vms
      integer*2 vlen, i, j

      vms( 1:1 ) = '['
      vlen = 1
      i = 1
      if ( unix( 1:1 ) .eq. '/' ) i = 2
      j = index( unix( i: ), '/' )
      do while ( j .ne. 0 )
         vms( vlen+1:vlen+1 ) = '.'
         call cvt_string_uv( unix( i : i+j-2 ), vms( vlen+2: ), k )
         i = i + j
         j = index( unix( i: ), '/' )
         vlen = vlen + k + 1
         if ( vlen + reserved .gt. len( vms )) then
            vlen = len( vms ) - reserved
            if ( vms( vlen:vlen ) .eq. '.' ) vlen = vlen - 1
            do while ( j .ne. 0 )
               i = i + j
               j = index( unix( i: ), '/' )
            end do
         end if
      end do

      if ( vlen .eq. 1 ) then
         vlen = 0
      else
         vlen = vlen + 1
         vms( vlen:vlen ) = ']'
      end if

      call cvt_file_uv( unix( i: ), vms( vlen+1: ), k )
      vlen = vlen + k
      return

      end      

c
c this subroutine converts an individual file name from unix format to VMS
c
      subroutine cvt_file_uv( unix, vms, vlen )

      parameter mlen1 = 64, mlen2 = 64
c     parameter mlen1 = 9, mlen2 = 3       ! for version 3 and before
      character*(*) unix, vms
      integer*2 vlen, i, j

      i = index( unix, '.' )
      if ( i .eq. 0 ) i = len( unix ) + 1

      call cvt_string_uv( unix( :i-1 ), vms, j )
      if ( j .gt. mlen1 ) j = mlen1
      vlen = j + 1
      if ( vlen .gt. len( vms )) vlen = len( vms )
      vms( vlen:vlen ) = '.'

      if ( i .ge. len( unix )) return

      call cvt_string_uv( unix( i+1: ), vms( vlen+1: ), j )
      if ( j .gt. mlen2 ) j = mlen2
      vlen = vlen + j
      return

      end

c
c this subroutine converts a string to characters that can appear in
c VMS filenames
c
c if you're using a version 3 or pervious VMS system, you'll have to
c rewrite this to avoid _ and $.
c
      subroutine cvt_string_uv( unix, vms, vlen )

      character*(*) unix, vms, c*1
      integer*2 vlen, i

      vms = unix
      vlen = min( len( unix ), len( vms ))
      do i = 1, vlen
         c = vms( i:i )
         if ( 'A' .le. c .and. c .le. 'Z' .or.
     -        '0' .le. c .and. c .le. '9' .or.
     -        c .eq. '_' .or. c .eq. '$'  ) then
            continue
         else if ( 'a' .le. c .and. c .le. 'z' ) then
            vms( i:i ) = char( ichar( c ) - 32 )
         else if ( c .eq. '-' ) then
            vms( i:i ) = '_'
         else
            vms( i:i ) = '$'
         end if
      end do

      return

      end

c
c this souroutine converts an octal digit to a 3-character protection mask
c
      subroutine cvt_prot( c, out )

      character c*1, out*3, mask( 8 )*3
      data mask / '---', '--x', '-w-', '-wx',
     -            'r--', 'r-x', 'rw-', 'rwx' /

      out = mask( ichar( c ) - ichar( '0' ) + 1 )
      return

      end

$ eod
$!
$ write sys$output "creating TAPEIO.DCK"
$ create TAPEIO.DCK
$ deck
c
c parameters:
c   blocklen is the size of the units tar works with
c   saveblocks is the number of blocks into the file saved for a second chance
c   maxrecl is the maximum length of record a text can have
c   maxblockfactor is the maximum blocking factor this program can deal with
c
      parameter blocklen = 512, saveblocks = 5, maxrecl = 512,
     -    maxblockfactor = 20

c secondary parameters calculated from those above
      parameter recblocks = 2 + maxrecl/blocklen,
     -   maxblocks = maxblockfactor + saveblocks + recblocks,
     -   maxlen = blocklen*maxblocks

c these are numbers for fortran units to be used for various files
      parameter inunit = 1, outunit = 2, listunit = 3, nameunit = 4

c
c variables:
c
c i/o control stuff
      integer*2 channel
      logical*1 tape_file

c this is the buffer records get read into
      character buffer*( maxlen ), block( maxblocks )*( blocklen )
      equivalence ( buffer, block )

c control info for the buffer
      integer*2 using, using2, curr
      logical*1 eof


      common /commonbuf/ buffer
      common /commonints/ using, using2, curr, eof, tape_file, channel
$ eod
$!
$ write sys$output "creating TAPEIO.FOR"
$ create TAPEIO.FOR
$ deck
c
c this routine accesses, checks, and rewinds the specified tape (or file,
c if tape_file is true.
c
      subroutine open_tape( name )

      include 'tapeio.dck/list'
      include '($iodef)/nolist'
      include '($dvidef)/nolist'
      include '($devdef)/nolist'
      character*(*) name

      integer*2 iosb( 2 ), devreq_w( 2 )
      integer*4 stat, devreq( 4 ), devchar, sys$assign, sys$qiow,
     -    sys$getdvi

      equivalence ( devreq, devreq_w )
      data devreq_w, devreq( 3 ), devreq( 4 )
     -    / 4, dvi$_devchar, 0, 0 /

      if ( tape_file ) then
         stat = sys$assign( name, channel,, )
         if ( .not. stat ) goto 900
         devreq( 2 ) = %loc( devchar )
         stat = sys$getdvi( , %val( channel ),, devreq, iosb,,, )
         if ( .not. stat ) goto 900
         stat = iosb( 1 )
         if ( .not. stat ) goto 900
         if ( .not. btest( devchar, dev$v_avl )) goto 910
         if ( .not. btest( devchar, dev$v_for )) goto 920
         stat = sys$qiow( , %val( channel ), %val( io$_rewind ),
     -       iosb,,,,,,,, )
         if ( .not. stat ) goto 930
         stat = iosb( 1 )
         if ( .not. stat ) goto 930
      else
         open( inunit, err=950, name=name,
     -       type='old', readonly )
      end if

      return

c
c fatal errors
c
  900 type *, 'Error accessing tape, ', name
      call exit( stat )
  910 type *, 'Tape offline or not available.'
      call exit
  920 type *, 'Tape must be mounted /foreign.'
      call exit
  930 type *, 'Error rewinding tape.'
      call exit( stat )

  950 type *, 'Error opening input file, ', name
      call exit

      end

c
c this routine makes sure the next block is available, reading it from
c tape if necessary.
c
      subroutine next_block
      include 'tapeio.dck'
      include '($iodef)/nolist'
      integer*2 blen, u, i, iosb( 4 )
      integer*4 stat, sys$qiow
      data curr, blen / 0, 0 /

      eof = .false.
      curr = curr + 1
      if ( curr .le. blen / blocklen ) return

      if ( using2 .le. 0 ) then
         u = using
      else if ( using .le. 0 ) then
         u = using2
      else
         u = min( using, using2 )
      end if

      if ( u .gt. blen / blocklen ) then
         type *, 'Internal error.  Call the debugger.'
         call exit
      else if ( u .gt. 1 ) then
         buffer( 1 : blen - blocklen*(u-1)) =
     -       buffer( 1+blocklen*(u-1) : blen )
         blen = blen - blocklen*(u-1)
         curr = curr - u + 1
         using = using - u + 1
         using2 = using2 - u + 1
      else if ( u .lt. 1 ) then
         blen = 0
         curr = 1
      end if

      do while ( curr .gt. blen / blocklen )
         if ( tape_file ) then
            stat = sys$qiow( , %val( channel ), %val( io$_readlblk ),
     -          iosb,,, %ref( buffer( blen+1: )), %val( maxlen-blen )
     -          ,,,, )
            if ( .not. stat ) then
               type *, 'Error reading from tape'
               call exit( stat )
            else if ( .not. iosb( 1 )) then
               type *, 'Error reading from tape'
               call exit( iosb( 1 ))
            else if ( iosb( 2 ) .eq. 0 ) then
               goto 99
            endif
            blen = blen + iosb( 2 )
         else
            read( inunit, 10, end=99 ) i, buffer( blen+1: )
   10       format( q, a )
            blen = blen + i
         end if
         if ( blen .gt. maxlen ) then
            type *, 'Blocking factor too large.'
            call exit
         end if
      end do
      return

99    curr = curr - 1
      eof = .true.
      return
      end
$ eod
$!
$ write sys$output "creating TAR.CLD"
$ create TAR.CLD
$ deck
!**************************************TAR**************************************
define verb TAR
   image drc0:[gordon.decus.tar]TAR
   parameter P1 , label=TAPE , prompt="Tape drive"
      value (required,type=$infile)
   qualifier FILE
   qualifier EXTRACT
   qualifier BINARY
   qualifier INQUIRE
   qualifier SECOND_CHANCE
      default
   qualifier NAMES
      value (default="sys$output:",type=$outfile)
   qualifier LIST
      value (default="sys$output:",type=$outfile)
   qualifier VERBOSE
   qualifier FLATTEN
      default
$ eod
$!
$ write sys$output "creating TAR.FOR"
$ create TAR.FOR
$ deck
c
c This is tar for VMS, by Gordon Davisson (gordon@uw-june).  It is
c not based on any liscenced software, and is completely in the
c public domain.
c
c Version 1.0, Gordon Davisson, July 24 1985
c revised by G.D. July 29 1985 to use io$_rewind right and not abuse rms$_eof
c revised by G.D. Oct 17 1985 to make sure tape is mounted
c
      program tar

      parameter bell = char( 7 ), lf = char( 10 )
      external cli$_present, cli$_negated, cli$_locpres, cli$_locneg,
     -    cli$_absent, cli$_defaulted, cli$_normal,
     -    cli$_comma, cli$_concat
      include 'tapeio.dck/list'
      character fname*100, out*128, pstr*9, prot*3, link*1, tmp*1
      integer*2 i, j, start, finish, flen, olen, files,
     -    stuff1, stuff2, stuff3, iosb( 2 )
      integer*4 size, blocks, time, stat,
     -    cli$get_value, cli$present, sys$assign, sys$qiow
      logical*1 listing, naming, extracting, binary, inquiring,
     -    verbose, second_chance, flatten, absent

      absent( stat ) = ( stat .eq. %loc( cli$_absent ) .or.
     -                   stat .eq. %loc( cli$_negated ))
c
c parse command line
c
c file -- read from normal file, not a tape
      stat = cli$present( 'file' )
      if ( absent( stat )) then
         tape_file = .true.
      else if ( .not. stat ) then
         goto 900
      else
        tape_file = .false.
      end if

c p1 -- tape drive name
      stat = cli$get_value( 'tape', fname, flen )
      if ( .not. stat ) goto 900
      call open_tape( fname( :flen ))

c p2 -- files to extract/list/whatever.  NOT IMPLEMENTED
c     files = 0
c     stat = cli$get_value( 'match', fname, flen )
c     do while ( .not. absent( stat ))
c        if ( .not. stat ) goto 900
c        type *, 'File selector: ', fname( :flen )
c        files = files + 1
c        stat = cli$get_value( 'match', fname, flen )
c     end do

c extract -- copy files to disk
      stat = cli$present( 'extract' )
      if ( absent( stat )) then
         extracting = .false.
      else if ( .not. stat ) then
         goto 900
      else
        extracting = .true.
      end if

c binary -- copy to disk in block mode
      stat = cli$present( 'binary' )
      if ( absent( stat )) then
         binary = .false.
      else if ( .not. stat ) then
         goto 900
      else
        binary = .true.
      end if

c inquire -- ask what to do to each file
      stat = cli$present( 'inquire' )
      if ( absent( stat )) then
         inquiring = .false.
      else if ( .not. stat ) then
         goto 900
      else
        inquiring = .true.
      end if

c second_chance -- try to recognize binary files and save them as such
      stat = cli$present( 'second_chance' )
      if ( absent( stat )) then
         second_chance = .false.
      else if ( .not. stat ) then
         goto 900
      else
        second_chance = .true.
      end if

c list -- list files on tape
      stat = cli$get_value( 'list', fname, flen )     
      if ( absent( stat )) then
         listing = .false.
      else if ( .not. stat ) then
         goto 900
      else
         open( listunit, err=920, name=fname( :flen ), type='new',
     -       defaultfile='tar.lis', carriagecontrol='list' )
         listing = .true.
      end if

c verbose -- make a verbose list
      stat = cli$present( 'verbose' )
      if ( absent( stat )) then
         verbose = .false.
      else if ( .not. stat ) then
         goto 900
      else
        verbose = .true.
      end if

c flatten -- extract all files to the current directory
      stat = cli$present( 'flatten' )
      if ( absent( stat )) then
         flatten = .false.
      else if ( .not. stat ) then
         goto 900
      else
        flatten = .true.
      end if

c names -- make a list of what unix filenames mapped to what VMS filenames
      stat = cli$get_value( 'names', fname, flen )     
      if ( absent( stat )) then
         naming = .false.
      else if ( .not. stat ) then
         goto 900
      else
         open( nameunit, err=930, name=fname( :flen ), type='new',
     -       defaultfile='tar.nam', carriagecontrol='list' )
         naming = .true.
      end if

c
c file loop: executed for each file in the archive
c
      do while ( .true. )
   10    using = 0
         using2 = 0
         call next_block
         if ( eof .or. block( curr ) (1:1) .eq. char( 0 )) goto 899

c start parsing out a file entry -- parse the header
         read( block( curr ), 1001 ) fname, prot, stuff1, stuff2,
     -      size, time, stuff3, link
 1001    format( a100, 3x, a3, 2x, 2(o6,2x), 2(o11,1x), o6, 2x, a1 )
         blocks = ( size + blocklen - 1 ) / blocklen
         flen = index( fname, char( 0 )) - 1
         if ( flen .lt. 0 ) flen = len( fname )

c add it to the list
         if ( listing .and. verbose ) then
            call cvt_prot( prot( 1:1 ), pstr( 1:3 ))
            call cvt_prot( prot( 2:2 ), pstr( 4:6 ))
            call cvt_prot( prot( 3:3 ), pstr( 7:9 ))
            write( listunit, 2001 ) pstr, stuff1, stuff2, size,
     -          time, fname( :flen )
 2001       format( a9, i3, '/', i3, i7, i11, 1x, a )
         else if ( listing ) then
            write( listunit, 2002 ) fname( :flen )
 2002       format( a )
         end if

c ignore links
         if ( link .eq. '1' ) goto 10

c skip if not extracting
         if ( .not. extracting ) goto 40

c figure out what to do with the file
         if ( inquiring ) then
            call lib$get_input( tmp, fname( :flen ) // ': [ynbtq]' )
            do while ( index( ' yYnNbBtTqQ', tmp ) .eq. 0 )
               call lib$get_input( tmp,
     -             bell // fname( :flen ) // ': [ynbtq]' )
            end do
            call str$upcase( tmp, tmp )
            if ( tmp .eq. 'Q' ) goto 899
         else
            tmp = 'Y'
         end if

         if ( tmp .eq. 'Y' .or. tmp .eq. ' ' ) then
            tmp = 'T'
            if ( binary ) tmp = 'B'
         else if ( tmp .eq. 'N' ) then
            goto 40
         end if

c parse file name
         call cvt_dir_uv( fname( :flen ), out, olen )
         if ( flatten ) then
            i = index( out( :olen ), ']' )
            out = out( i+1:olen )
            olen = olen - i
         end if
         if ( tmp .eq. 'B' ) goto 30

c create a text file
   20    open( outunit, name=out( :olen ), type='new', recl=maxrecl,
     -       defaultfile='.', carriagecontrol='list', err=38 )
         if ( size .le. 0 ) then
            close( outunit )
            goto 99
         end if

c copy the file to disk
         if ( second_chance ) using2 = curr
         call next_block
         blocks = blocks - 1
         start = 1
         do while ( size .gt. 0 )
            using = curr
            finish = index( block( curr ) ( start: ), lf )
            do while ( finish .eq. 0 .and. blocks .gt. 0 .and.
     -          curr - using + 1 .lt. recblocks )
               call next_block
               blocks = blocks - 1
               if ( eof ) goto 990
               finish = index( block( curr ), lf )
            end do
            if ( finish .eq. 0 ) finish = 2 * blocklen + 1
            if ( using .eq. curr ) finish = finish + start - 1
            i = start + blocklen * (using-1)
            j = finish + blocklen * (curr-1)
            start = finish + 1
            size = size - j + i - 1
            if ( size .lt. 0 ) then
               j = j + size
               size = 0
            end if
            if ( using2 .ne. 0 .and. j - i .gt. maxrecl ) then
               type *, 'Giving ', fname( :flen ), ' a second chance...'
               blocks = blocks + curr - using2
               curr = using2
               using = 0
               using2 = 0
               close( outunit, dispose='delete' )
               goto 30
            end if
            write( outunit, 2005, err=39, iostat=stat )
     -          buffer( i : j-1 )
2005        format( a )
            if ( curr - using2 .ge. saveblocks ) using2 = 0
         end do

         close( outunit )
         goto 99

c create a binary file
   30    using = 0
         using2 = 0
         open( outunit, name=out( :olen ), type='new',
     -       recl=blocklen, recordtype='fixed', defaultfile='.',
     -       carriagecontrol='none', err=39 )

         do while ( blocks .gt. 0 )
            call next_block
            blocks = blocks - 1
            write( outunit, 3001, err=39, iostat=stat ) block( curr )
 3001       format( a )
         end do
         close( outunit )
         goto 99

c got an error creating the file: skip it.
   38    type *, 'Error creating ', out( :olen ), ' skipping...'
         goto 40

c got an error writing the file: skip the rest of it.
   39    type *, 'Error writing ', out( :olen ), ' skipping...'
         close( outunit, dispose='delete' )

c skip the file
   40    using = 0
         using2 = 0
         do i = 1, blocks
            call next_block
            if ( eof ) goto 990
         end do
         goto 10

c successfully copied file to disk: enter it in the names file
   99    if ( naming ) write( nameunit, 2000 ) out( :olen ),
     -       fname( :flen )
 2000    format( a, ' -> ', a )

      end do

c end of tape: close it and exit!
  899 close( inunit )
      call exit

c
c fatal errors
c
  900 type *, 'Error parsing command line'
      call exit

  920 type *, 'Error opening listing file, ', fname( :flen )
      call exit

  930 type *, 'Error opening names file, ', fname( :flen )
      call exit

  990 type *, 'Premature end of tape while reading ', fname( :flen )
      call exit

      end
$ eod
$!
$ write sys$output "creating TAR.HLP"
$ create TAR.HLP
$ deck
1 TAR
  Invokes the tape archive reader to read unix-format tapes.

  Format:

    TAR tape-name[:]
2 Parameter

 tape-name[:]

  Specifies the device name of the tape drive the archive is mounted on.
  The archive must be mounted foreign.

  If the /FILE qualifier is specified, this parameter is interpreted as
  the file name for the archive.
2 Command_Qualifiers

/BINARY

  Specifies that the files extracted should be put into fixed-length-512-
  byte-record files and that no interpretation should be preformed on
  the contents.

/EXTRACT

  Specifies that the files in the archive should be copied into the
  directory, or subdirectories (depending on the /FLATTEN qualifier).

/FILE

  Specifies that, instead of a tape, the archive is contained in a normal
  file.

/FLATTEN (D)

  Specifies that files extracted from the archive should be put in the
  default directory even when the files would normally be put in
  subdirectories.

  This qualifier is on by default because the program is incapable of
  creating subdirectories to put the extracted files in, so unless they
  exist already, /NOFLATTEN in a pure loss.

/INQUIRE

  Tells the program to ask the user what to do with each file it has been
  told to extract.  The program prompts with the filename followed by a
  list of options.  The options are:

     y - extract the file normally
     n - skip the file
     t - extract the file in text (not binary) mode
     b - extract the file in binary mode
     q - exit the program

  The y option is equivalent t or b depending on whether the /BINARY
  qualifier was given.

/LIST

 /LIST=filename (default = sys$output:)

  Tells the program to create a list of all of the files on the tape.
  If the /VERBOSE qualifier is also specified, the list contains more
  than just the file names.

/NAMES

 /NAMES=filename (default = sys$output:)

  If files are extracted, the program creates a file giving the names
  of the files on the tape and the VMS filenames they were mapped into
  when extracted.

/SECOND_CHANCE (D)

  This specifies that if a file is being extracted in text mode, and
  a line longer then 512 bytes in encountered sufficiently near the
  beginning of the file, it should be re-extracted in binary mode.

  If negated, files with long lines are discarded in text mode.

/VERBOSE

  This specifies that lists should contain more information than just
  the filename.

2 Bugs
  Here's a list of some of the more noticable bugs and deficiencies:
     - It can't write tar tapes.
     - It can't operate on only some of the files on a tape.
     - Verbose listings contain the date in seconds since 1970 or so,
         rather than any reasonable format.
     - It can't create subdirectories to put files in. (that's why
         /FLATTEN is the default)
     - Error recovery and reporting could use improvement.
     - probably others I can't think of at the moment.

  If you discover more bugs, fix them, or just have suggestions, mail
  them to Gordon Davisson ({ihnp4|decvax}!uw-beaver!uw-june!gordon,
  gordon@uw-june.ARPA, or gordon@uwaphast.BITNET).
$ eod

***************************************************************************

From: lll-lcc!ucdavis!vega!ccrdave (Lord Kahless)

I received this program from somebody, who received this program
from somebody.  I don't know if it works because I've been to busy
to test it.  Just substitute out the X@X@'s and go for it. Tell
me how it works...
X@X@From:	ALCOR::CCRDAN       "DAN GOLD" 11-AUG-1986 10:01
X@X@To:	CCRDAVE
X@X@Subj:	
X@X@
X@X@From ucbvax!sdcsvax.ucsd.edu!gr66@sdcc12 Sun Aug 10 13:41:14 1986
X@X@Received: by deneb.UCDAVIS.EDU (4.12/4.7)
X@X@	id AA28769; Sun, 10 Aug 86 13:40:07 pdt
X@X@From: ucbvax!sdcsvax.ucsd.edu!gr66@sdcc12
X@X@Received: by ucdavis.UCDAVIS.EDU (4.12/4.7)
X@X@	id AA24315; Sun, 10 Aug 86 13:41:25 pdt
X@X@Received: by ucbvax.Berkeley.EDU (5.53/1.14)
X@X@	id AA08804; Sun, 10 Aug 86 13:14:35 PDT
X@X@Received: by sdcsvax.ucsd.edu (5.31/4.42)
X@X@	id AA20134; Sun, 10 Aug 86 13:15:05 PDT hops=0
X@X@Received: by sdcc12.ARPA (5.5/4.41)
X@X@	id AA17718; Sun, 10 Aug 86 13:14:43 PDT
X@X@Date: Sun, 10 Aug 86 13:14:43 PDT
X@X@Message-Id: <8608102014.AA17718@sdcc12.ARPA>
X@X@To: ucdavis!deneb!ccrdan
X@X@Status: R
X@X@
X@X@-----------------------------------------------------------------
X@X@
X@X@Dan Gold:
X@X@
X@X@   Here are the 7 files I received in response to my tar read/write
X@X@program request.  This is a DECUS program from Fall, 1985 I think.i
X@X@As TAR.HLP explains, it does not write TAR tapes
X@X@(just reads them) and has a no. of shortcomings.  I tried it and
X@X@it works nicely.  I plan to improve on it a bit so if you 
X@X@ask later I may have more to send you.  Send any questions you have
X@X@about bugs to gordon (address in TAR.HLP).
X@X@
X@X@steve piper
X@X@gr66%sdcc12@sdcsvax.ARPA
X@X@
X@X@TAR.COM
X@X@-------
X@X@
X@X@$ fortran tar
X@X@$ fortran cvt
X@X@$ fortran tapeio
X@X@$ link tar,cvt,tapeio
X@X@
X@X@TAR.CLD
X@X@-------
X@X@
X@X@!**************************************TAR**************************************
X@X@define verb TAR
X@X@   image u$dir:TAR
X@X@   parameter P1 , label=TAPE , prompt="Tape drive"
X@X@      value (required,type=$infile)
X@X@   qualifier FILE
X@X@   qualifier EXTRACT
X@X@   qualifier BINARY
X@X@   qualifier INQUIRE
X@X@   qualifier SECOND_CHANCE
X@X@      default
X@X@   qualifier NAMES
X@X@      value (default="sys$output:",type=$outfile)
X@X@   qualifier LIST
X@X@      value (default="sys$output:",type=$outfile)
X@X@   qualifier VERBOSE
X@X@   qualifier FLATTEN
X@X@      default
X@X@
X@X@TAR.FOR
X@X@-------
X@X@
X@X@c
X@X@c This is tar for VMS, by Gordon Davisson (gordon@uw-june).  It is
X@X@c not based on any liscenced software, and is completely in the
X@X@c public domain.
X@X@c
X@X@c Version 1.0, Gordon Davisson, July 24 1985
X@X@c revised by G.D. July 29 1985 to use io$_rewind right and not abuse rms$_eof
X@X@c revised by G.D. Oct 17 1985 to make sure tape is mounted
X@X@c
X@X@      program tar
X@X@
X@X@      parameter bell = char( 7 ), lf = char( 10 )
X@X@      external cli$_present, cli$_negated, cli$_locpres, cli$_locneg,
X@X@     -    cli$_absent, cli$_defaulted, cli$_normal,
X@X@     -    cli$_comma, cli$_concat
X@X@      include 'tapeio.dck/list'
X@X@      character fname*100, out*128, pstr*9, prot*3, link*1, tmp*1
X@X@      integer*2 i, j, start, finish, flen, olen, files,
X@X@     -    stuff1, stuff2, stuff3, iosb( 2 )
X@X@      integer*4 size, blocks, time, stat,
X@X@     -    cli$get_value, cli$present, sys$assign, sys$qiow
X@X@      logical*1 listing, naming, extracting, binary, inquiring,
X@X@     -    verbose, second_chance, flatten, absent
X@X@
X@X@      absent( stat ) = ( stat .eq. %loc( cli$_absent ) .or.
X@X@     -                   stat .eq. %loc( cli$_negated ))
X@X@c
X@X@c parse command line
X@X@c
X@X@c file -- read from normal file, not a tape
X@X@      stat = cli$present( 'file' )
X@X@      if ( absent( stat )) then
X@X@         tape_file = .true.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        tape_file = .false.
X@X@      end if
X@X@
X@X@c p1 -- tape drive name
X@X@      stat = cli$get_value( 'tape', fname, flen )
X@X@      if ( .not. stat ) goto 900
X@X@      call open_tape( fname( :flen ))
X@X@
X@X@c p2 -- files to extract/list/whatever.  NOT IMPLEMENTED
X@X@c     files = 0
X@X@c     stat = cli$get_value( 'match', fname, flen )
X@X@c     do while ( .not. absent( stat ))
X@X@c        if ( .not. stat ) goto 900
X@X@c        type *, 'File selector: ', fname( :flen )
X@X@c        files = files + 1
X@X@c        stat = cli$get_value( 'match', fname, flen )
X@X@c     end do
X@X@
X@X@c extract -- copy files to disk
X@X@      stat = cli$present( 'extract' )
X@X@      if ( absent( stat )) then
X@X@         extracting = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        extracting = .true.
X@X@      end if
X@X@
X@X@c binary -- copy to disk in block mode
X@X@      stat = cli$present( 'binary' )
X@X@      if ( absent( stat )) then
X@X@         binary = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        binary = .true.
X@X@      end if
X@X@
X@X@c inquire -- ask what to do to each file
X@X@      stat = cli$present( 'inquire' )
X@X@      if ( absent( stat )) then
X@X@         inquiring = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        inquiring = .true.
X@X@      end if
X@X@
X@X@c second_chance -- try to recognize binary files and save them as such
X@X@      stat = cli$present( 'second_chance' )
X@X@      if ( absent( stat )) then
X@X@         second_chance = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        second_chance = .true.
X@X@      end if
X@X@
X@X@c list -- list files on tape
X@X@      stat = cli$get_value( 'list', fname, flen )     
X@X@      if ( absent( stat )) then
X@X@         listing = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@         open( listunit, err=920, name=fname( :flen ), type='new',
X@X@     -       defaultfile='tar.lis', carriagecontrol='list' )
X@X@         listing = .true.
X@X@      end if
X@X@
X@X@c verbose -- make a verbose list
X@X@      stat = cli$present( 'verbose' )
X@X@      if ( absent( stat )) then
X@X@         verbose = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        verbose = .true.
X@X@      end if
X@X@
X@X@c flatten -- extract all files to the current directory
X@X@      stat = cli$present( 'flatten' )
X@X@      if ( absent( stat )) then
X@X@         flatten = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@        flatten = .true.
X@X@      end if
X@X@
X@X@c names -- make a list of what unix filenames mapped to what VMS filenames
X@X@      stat = cli$get_value( 'names', fname, flen )     
X@X@      if ( absent( stat )) then
X@X@         naming = .false.
X@X@      else if ( .not. stat ) then
X@X@         goto 900
X@X@      else
X@X@         open( nameunit, err=930, name=fname( :flen ), type='new',
X@X@     -       defaultfile='tar.nam', carriagecontrol='list' )
X@X@         naming = .true.
X@X@      end if
X@X@
X@X@c
X@X@c file loop: executed for each file in the archive
X@X@c
X@X@      do while ( .true. )
X@X@   10    using = 0
X@X@         using2 = 0
X@X@         call next_block
X@X@         if ( eof .or. block( curr ) (1:1) .eq. char( 0 )) goto 899
X@X@
X@X@c start parsing out a file entry -- parse the header
X@X@         read( block( curr ), 1001 ) fname, prot, stuff1, stuff2,
X@X@     -      size, time, stuff3, link
X@X@ 1001    format( a100, 3x, a3, 2x, 2(o6,2x), 2(o11,1x), o6, 2x, a1 )
X@X@         blocks = ( size + blocklen - 1 ) / blocklen
X@X@         flen = index( fname, char( 0 )) - 1
X@X@         if ( flen .lt. 0 ) flen = len( fname )
X@X@
X@X@c add it to the list
X@X@         if ( listing .and. verbose ) then
X@X@            call cvt_prot( prot( 1:1 ), pstr( 1:3 ))
X@X@            call cvt_prot( prot( 2:2 ), pstr( 4:6 ))
X@X@            call cvt_prot( prot( 3:3 ), pstr( 7:9 ))
X@X@            write( listunit, 2001 ) pstr, stuff1, stuff2, size,
X@X@     -          time, fname( :flen )
X@X@ 2001       format( a9, i3, '/', i3, i7, i11, 1x, a )
X@X@         else if ( listing ) then
X@X@            write( listunit, 2002 ) fname( :flen )
X@X@ 2002       format( a )
X@X@         end if
X@X@
X@X@c ignore links
X@X@         if ( link .eq. '1' ) goto 10
X@X@
X@X@c skip if not extracting
X@X@         if ( .not. extracting ) goto 40
X@X@
X@X@c figure out what to do with the file
X@X@         if ( inquiring ) then
X@X@            call lib$get_input( tmp, fname( :flen ) // ': [ynbtq]' )
X@X@            do while ( index( ' yYnNbBtTqQ', tmp ) .eq. 0 )
X@X@               call lib$get_input( tmp,
X@X@     -             bell // fname( :flen ) // ': [ynbtq]' )
X@X@            end do
X@X@            call str$upcase( tmp, tmp )
X@X@            if ( tmp .eq. 'Q' ) goto 899
X@X@         else
X@X@            tmp = 'Y'
X@X@         end if
X@X@
X@X@         if ( tmp .eq. 'Y' .or. tmp .eq. ' ' ) then
X@X@            tmp = 'T'
X@X@            if ( binary ) tmp = 'B'
X@X@         else if ( tmp .eq. 'N' ) then
X@X@            goto 40
X@X@         end if
X@X@
X@X@c parse file name
X@X@         call cvt_dir_uv( fname( :flen ), out, olen )
X@X@         if ( flatten ) then
X@X@            i = index( out( :olen ), ']' )
X@X@            out = out( i+1:olen )
X@X@            olen = olen - i
X@X@         end if
X@X@         if ( tmp .eq. 'B' ) goto 30
X@X@
X@X@c create a text file
X@X@   20    open( outunit, name=out( :olen ), type='new', recl=maxrecl,
X@X@     -       defaultfile='.', carriagecontrol='list', err=38 )
X@X@         if ( size .le. 0 ) then
X@X@            close( outunit )
X@X@            goto 99
X@X@         end if
X@X@
X@X@c copy the file to disk
X@X@         if ( second_chance ) using2 = curr
X@X@         call next_block
X@X@         blocks = blocks - 1
X@X@         start = 1
X@X@         do while ( size .gt. 0 )
X@X@            using = curr
X@X@            finish = index( block( curr ) ( start: ), lf )
X@X@            do while ( finish .eq. 0 .and. blocks .gt. 0 .and.
X@X@     -          curr - using + 1 .lt. recblocks )
X@X@               call next_block
X@X@               blocks = blocks - 1
X@X@               if ( eof ) goto 990
X@X@               finish = index( block( curr ), lf )
X@X@            end do
X@X@            if ( finish .eq. 0 ) finish = 2 * blocklen + 1
X@X@            if ( using .eq. curr ) finish = finish + start - 1
X@X@            i = start + blocklen * (using-1)
X@X@            j = finish + blocklen * (curr-1)
X@X@            start = finish + 1
X@X@            size = size - j + i - 1
X@X@            if ( size .lt. 0 ) then
X@X@               j = j + size
X@X@               size = 0
X@X@            end if
X@X@            if ( using2 .ne. 0 .and. j - i .gt. maxrecl ) then
X@X@               type *, 'Giving ', fname( :flen ), ' a second chance...'
X@X@               blocks = blocks + curr - using2
X@X@               curr = using2
X@X@               using = 0
X@X@               using2 = 0
X@X@               close( outunit, dispose='delete' )
X@X@               goto 30
X@X@            end if
X@X@            write( outunit, 2005, err=39, iostat=stat )
X@X@     -          buffer( i : j-1 )
X@X@2005        format( a )
X@X@            if ( curr - using2 .ge. saveblocks ) using2 = 0
X@X@         end do
X@X@
X@X@         close( outunit )
X@X@         goto 99
X@X@
X@X@c create a binary file
X@X@   30    using = 0
X@X@         using2 = 0
X@X@         open( outunit, name=out( :olen ), type='new',
X@X@     -       recl=blocklen, recordtype='fixed', defaultfile='.',
X@X@     -       carriagecontrol='none', err=39 )
X@X@
X@X@         do while ( blocks .gt. 0 )
X@X@            call next_block
X@X@            blocks = blocks - 1
X@X@            write( outunit, 3001, err=39, iostat=stat ) block( curr )
X@X@ 3001       format( a )
X@X@         end do
X@X@         close( outunit )
X@X@         goto 99
X@X@
X@X@c got an error creating the file: skip it.
X@X@   38    type *, 'Error creating ', out( :olen ), ' skipping...'
X@X@         goto 40
X@X@
X@X@c got an error writing the file: skip the rest of it.
X@X@   39    type *, 'Error writing ', out( :olen ), ' skipping...'
X@X@         close( outunit, dispose='delete' )
X@X@
X@X@c skip the file
X@X@   40    using = 0
X@X@         using2 = 0
X@X@         do i = 1, blocks
X@X@            call next_block
X@X@            if ( eof ) goto 990
X@X@         end do
X@X@         goto 10
X@X@
X@X@c successfully copied file to disk: enter it in the names file
X@X@   99    if ( naming ) write( nameunit, 2000 ) out( :olen ),
X@X@     -       fname( :flen )
X@X@ 2000    format( a, ' -> ', a )
X@X@
X@X@      end do
X@X@
X@X@c end of tape: close it and exit!
X@X@  899 close( inunit )
X@X@      call exit
X@X@
X@X@c
X@X@c fatal errors
X@X@c
X@X@  900 type *, 'Error parsing command line'
X@X@      call exit
X@X@
X@X@  920 type *, 'Error opening listing file, ', fname( :flen )
X@X@      call exit
X@X@
X@X@  930 type *, 'Error opening names file, ', fname( :flen )
X@X@      call exit
X@X@
X@X@  990 type *, 'Premature end of tape while reading ', fname( :flen )
X@X@      call exit
X@X@
X@X@      end
X@X@
X@X@
X@X@
X@X@TAPEIO.FOR
X@X@----------
X@X@
X@X@c
X@X@c this routine accesses, checks, and rewinds the specified tape (or file,
X@X@c if tape_file is true.
X@X@c
X@X@      subroutine open_tape( name )
X@X@
X@X@      include 'tapeio.dck/list'
X@X@      include '($iodef)/nolist'
X@X@      include '($dvidef)/nolist'
X@X@      include '($devdef)/nolist'
X@X@      character*(*) name
X@X@
X@X@      integer*2 iosb( 2 ), devreq_w( 2 )
X@X@      integer*4 stat, devreq( 4 ), devchar, sys$assign, sys$qiow,
X@X@     -    sys$getdvi
X@X@
X@X@      equivalence ( devreq, devreq_w )
X@X@      data devreq_w, devreq( 3 ), devreq( 4 )
X@X@     -    / 4, dvi$_devchar, 0, 0 /
X@X@
X@X@      if ( tape_file ) then
X@X@         stat = sys$assign( name, channel,, )
X@X@         if ( .not. stat ) goto 900
X@X@         devreq( 2 ) = %loc( devchar )
X@X@         stat = sys$getdvi( , channel,, devreq, iosb,,, )
X@X@         if ( .not. stat ) goto 900
X@X@         stat = iosb( 1 )
X@X@         if ( .not. stat ) goto 900
X@X@         if ( .not. btest( devchar, dev$v_avl )) goto 910
X@X@         if ( .not. btest( devchar, dev$v_for )) goto 920
X@X@         stat = sys$qiow( , %val( channel ), %val( io$_rewind ),
X@X@     -       iosb,,,,,,,, )
X@X@         if ( .not. stat ) goto 930
X@X@         stat = iosb( 1 )
X@X@         if ( .not. stat ) goto 930
X@X@      else
X@X@         open( inunit, err=950, name=name,
X@X@     -       type='old', readonly )
X@X@      end if
X@X@
X@X@      return
X@X@
X@X@c
X@X@c fatal errors
X@X@c
X@X@  900 type *, 'Error accessing tape, ', name( :flen )
X@X@      call exit( stat )
X@X@  910 type *, 'Tape offline or not available.'
X@X@      call exit
X@X@  920 type *, 'Tape must be mounted /foreign.'
X@X@      call exit
X@X@  930 type *, 'Error rewinding tape.'
X@X@      call exit( stat )
X@X@
X@X@  950 type *, 'Error opening input file, ', name( :flen )
X@X@      call exit
X@X@
X@X@      end
X@X@
X@X@c
X@X@c this routine makes sure the next block is available, reading it from
X@X@c tape if necessary.
X@X@c
X@X@      subroutine next_block
X@X@      include 'tapeio.dck'
X@X@      integer*2 blen, u, i, iosb( 4 )
X@X@      integer*4 stat, sys$qiow
X@X@      data curr, blen / 0, 0 /
X@X@
X@X@      eof = .false.
X@X@      curr = curr + 1
X@X@      if ( curr .le. blen / blocklen ) return
X@X@
X@X@      if ( using2 .le. 0 ) then
X@X@         u = using
X@X@      else if ( using .le. 0 ) then
X@X@         u = using2
X@X@      else
X@X@         u = min( using, using2 )
X@X@      end if
X@X@
X@X@      if ( u .gt. blen / blocklen ) then
X@X@         type *, 'Internal error.  Call the debugger.'
X@X@         call exit
X@X@      else if ( u .gt. 1 ) then
X@X@         buffer( 1 : blen - blocklen*(u-1)) =
X@X@     -       buffer( 1+blocklen*(u-1) : blen )
X@X@         blen = blen - blocklen*(u-1)
X@X@         curr = curr - u + 1
X@X@         using = using - u + 1
X@X@         using2 = using2 - u + 1
X@X@      else if ( u .lt. 1 ) then
X@X@         blen = 0
X@X@         curr = 1
X@X@      end if
X@X@
X@X@      do while ( curr .gt. blen / blocklen )
X@X@         if ( tape_file ) then
X@X@            stat = sys$qiow( , %val( channel ), %val( io$_readlblk ),
X@X@     -          iosb,,, %ref( buffer( blen+1: )), %val( maxlen-blen )
X@X@     -          ,,,, )
X@X@            if ( .not. stat ) then
X@X@               type *, 'Error reading from tape'
X@X@               call exit( stat )
X@X@            else if ( .not. iosb( 1 )) then
X@X@               type *, 'Error reading from tape'
X@X@               call exit( iosb( 1 ))
X@X@            else if ( iosb( 2 ) .eq. 0 ) then
X@X@               goto 99
X@X@            endif
X@X@            blen = blen + iosb( 2 )
X@X@         else
X@X@            read( inunit, 10, end=99 ) i, buffer( blen+1: )
X@X@   10       format( q, a )
X@X@            blen = blen + i
X@X@         end if
X@X@         if ( blen .gt. maxlen ) then
X@X@            type *, 'Blocking factor too large.'
X@X@            call exit
X@X@         end if
X@X@      end do
X@X@      return
X@X@
X@X@99    curr = curr - 1
X@X@      eof = .true.
X@X@      return
X@X@      end
X@X@
X@X@
X@X@
X@X@TAPEIO.DCK
X@X@----------
X@X@c
X@X@c parameters:
X@X@c   blocklen is the size of the units tar works with
X@X@c   saveblocks is the number of blocks into the file saved for a second chance
X@X@c   maxrecl is the maximum length of record a text can have
X@X@c   maxblockfactor is the maximum blocking factor this program can deal with
X@X@c
X@X@      parameter blocklen = 512, saveblocks = 5, maxrecl = 512,
X@X@     -    maxblockfactor = 20
X@X@
X@X@c secondary parameters calculated from those above
X@X@      parameter recblocks = 2 + maxrecl/blocklen,
X@X@     -   maxblocks = maxblockfactor + saveblocks + recblocks,
X@X@     -   maxlen = blocklen*maxblocks
X@X@
X@X@c these are numbers for fortran units to be used for various files
X@X@      parameter inunit = 1, outunit = 2, listunit = 3, nameunit = 4
X@X@
X@X@c
X@X@c variables:
X@X@c
X@X@c i/o control stuff
X@X@      integer*2 channel
X@X@      logical*1 tape_file
X@X@
X@X@c this is the buffer records get read into
X@X@      character buffer*( maxlen ), block( maxblocks )*( blocklen )
X@X@      equivalence ( buffer, block )
X@X@
X@X@c control info for the buffer
X@X@      integer*2 using, using2, curr
X@X@      logical*1 eof
X@X@
X@X@
X@X@      common /commonbuf/ buffer
X@X@      common /commonints/ using, using2, curr, eof, tape_file, channel
X@X@
X@X@
X@X@CVT.FOR
X@X@-------
X@X@
X@X@c
X@X@c this subroutine converts a complete filespec (directory+file) name from
X@X@c unix format to VMS
X@X@c
X@X@      subroutine cvt_dir_uv( unix, vms, vlen )
X@X@
X@X@      parameter reserved = 10
X@X@      character*(*) unix, vms
X@X@      integer*2 vlen, i, j
X@X@
X@X@      vms( 1:1 ) = '['
X@X@      vlen = 1
X@X@      i = 1
X@X@      if ( unix( 1:1 ) .eq. '/' ) i = 2
X@X@      j = index( unix( i: ), '/' )
X@X@      do while ( j .ne. 0 )
X@X@         vms( vlen+1:vlen+1 ) = '.'
X@X@         call cvt_string_uv( unix( i : i+j-2 ), vms( vlen+2: ), k )
X@X@         i = i + j
X@X@         j = index( unix( i: ), '/' )
X@X@         vlen = vlen + k + 1
X@X@         if ( vlen + reserved .gt. len( vms )) then
X@X@            vlen = len( vms ) - reserved
X@X@            if ( vms( vlen:vlen ) .eq. '.' ) vlen = vlen - 1
X@X@            do while ( j .ne. 0 )
X@X@               i = i + j
X@X@               j = index( unix( i: ), '/' )
X@X@            end do
X@X@         end if
X@X@      end do
X@X@
X@X@      if ( vlen .eq. 1 ) then
X@X@         vlen = 0
X@X@      else
X@X@         vlen = vlen + 1
X@X@         vms( vlen:vlen ) = ']'
X@X@      end if
X@X@
X@X@      call cvt_file_uv( unix( i: ), vms( vlen+1: ), k )
X@X@      vlen = vlen + k
X@X@      return
X@X@
X@X@      end      
X@X@
X@X@c
X@X@c this subroutine converts an individual file name from unix format to VMS
X@X@c
X@X@      subroutine cvt_file_uv( unix, vms, vlen )
X@X@
X@X@      parameter mlen1 = 64, mlen2 = 64
X@X@c     parameter mlen1 = 9, mlen2 = 3       ! for version 3 and before
X@X@      character*(*) unix, vms
X@X@      integer*2 vlen, i, j
X@X@
X@X@      i = index( unix, '.' )
X@X@      if ( i .eq. 0 ) i = len( unix ) + 1
X@X@
X@X@      call cvt_string_uv( unix( :i-1 ), vms, j )
X@X@      if ( j .gt. mlen1 ) j = mlen1
X@X@      vlen = j + 1
X@X@      if ( vlen .gt. len( vms )) vlen = len( vms )
X@X@      vms( vlen:vlen ) = '.'
X@X@
X@X@      if ( i .ge. len( unix )) return
X@X@
X@X@      call cvt_string_uv( unix( i+1: ), vms( vlen+1: ), j )
X@X@      if ( j .gt. mlen2 ) j = mlen2
X@X@      vlen = vlen + j
X@X@      return
X@X@
X@X@      end
X@X@
X@X@c
X@X@c this subroutine converts a string to characters that can appear in
X@X@c VMS filenames
X@X@c
X@X@c if you're using a version 3 or pervious VMS system, you'll have to
X@X@c rewrite this to avoid _ and $.
X@X@c
X@X@      subroutine cvt_string_uv( unix, vms, vlen )
X@X@
X@X@      character*(*) unix, vms, c*1
X@X@      integer*2 vlen, i
X@X@
X@X@      vms = unix
X@X@      vlen = min( len( unix ), len( vms ))
X@X@      do i = 1, vlen
X@X@         c = vms( i:i )
X@X@         if ( 'A' .le. c .and. c .le. 'Z' .or.
X@X@     -        '0' .le. c .and. c .le. '9' .or.
X@X@     -        c .eq. '_' .or. c .eq. '$'  ) then
X@X@            continue
X@X@         else if ( 'a' .le. c .and. c .le. 'z' ) then
X@X@            vms( i:i ) = char( ichar( c ) - 32 )
X@X@         else if ( c .eq. '-' ) then
X@X@            vms( i:i ) = '_'
X@X@         else
X@X@            vms( i:i ) = '$'
X@X@         end if
X@X@      end do
X@X@
X@X@      return
X@X@
X@X@      end
X@X@
X@X@c
X@X@c this souroutine converts an octal digit to a 3-character protection mask
X@X@c
X@X@      subroutine cvt_prot( c, out )
X@X@
X@X@      character c*1, out*3, mask( 8 )*3
X@X@      data mask / '---', '--x', '-w-', '-wx',
X@X@     -            'r--', 'r-x', 'rw-', 'rwx' /
X@X@
X@X@      out = mask( ichar( c ) - ichar( '0' ) + 1 )
X@X@      return
X@X@
X@X@      end
X@X@
X@X@
X@X@
X@X@TAR.HLP
X@X@-------
X@X@
X@X@
X@X@1 TAR
X@X@  Invokes the tape archive reader to read unix-format tapes.
X@X@
X@X@  Format:
X@X@
X@X@    TAR tape-name[:]
X@X@2 Parameter
X@X@
X@X@ tape-name[:]
X@X@
X@X@  Specifies the device name of the tape drive the archive is mounted on.
X@X@  The archive must be mounted foreign.
X@X@
X@X@  If the /FILE qualifier is specified, this parameter is interpreted as
X@X@  the file name for the archive.
X@X@2 Command_Qualifiers
X@X@
X@X@/BINARY
X@X@
X@X@  Specifies that the files extracted should be put into fixed-length-512-
X@X@  byte-record files and that no interpretation should be preformed on
X@X@  the contents.
X@X@
X@X@/EXTRACT
X@X@
X@X@  Specifies that the files in the archive should be copied into the
X@X@  directory, or subdirectories (depending on the /FLATTEN qualifier).
X@X@
X@X@/FILE
X@X@
X@X@  Specifies that, instead of a tape, the archive is contained in a normal
X@X@  file.
X@X@
X@X@/FLATTEN (D)
X@X@
X@X@  Specifies that files extracted from the archive should be put in the
X@X@  default directory even when the files would normally be put in
X@X@  subdirectories.
X@X@
X@X@  This qualifier is on by default because the program is incapable of
X@X@  creating subdirectories to put the extracted files in, so unless they
X@X@  exist already, /NOFLATTEN in a pure loss.
X@X@
X@X@/INQUIRE
X@X@
X@X@  Tells the program to ask the user what to do with each file it has been
X@X@  told to extract.  The program prompts with the filename followed by a
X@X@  list of options.  The options are:
X@X@
X@X@     y - extract the file normally
X@X@     n - skip the file
X@X@     t - extract the file in text (not binary) mode
X@X@     b - extract the file in binary mode
X@X@     q - exit the program
X@X@
X@X@  The y option is equivalent t or b depending on whether the /BINARY
X@X@  qualifier was given.
X@X@
X@X@/LIST
X@X@
X@X@ /LIST=filename (default = sys$output:)
X@X@
X@X@  Tells the program to create a list of all of the files on the tape.
X@X@  If the /VERBOSE qualifier is also specified, the list contains more
X@X@  than just the file names.
X@X@
X@X@/NAMES
X@X@
X@X@ /NAMES=filename (default = sys$output:)
X@X@
X@X@  If files are extracted, the program creates a file giving the names
X@X@  of the files on the tape and the VMS filenames they were mapped into
X@X@  when extracted.
X@X@
X@X@/SECOND_CHANCE (D)
X@X@
X@X@  This specifies that if a file is being extracted in text mode, and
X@X@  a line longer then 512 bytes in encountered sufficiently near the
X@X@  beginning of the file, it should be re-extracted in binary mode.
X@X@
X@X@  If negated, files with long lines are discarded in text mode.
X@X@
X@X@/VERBOSE
X@X@
X@X@  This specifies that lists should contain more information than just
X@X@  the filename.
X@X@
X@X@2 Bugs
X@X@  Here's a list of some of the more noticable bugs and deficiencies:
X@X@     - It can't write tar tapes.
X@X@     - It can't operate on only some of the files on a tape.
X@X@     - Verbose listings contain the date in seconds since 1970 or so,
X@X@         rather than any reasonable format.
X@X@     - It can't create subdirectories to put files in. (that's why
X@X@         /FLATTEN is the default)
X@X@     - Error recovery and reporting could use improvement.
X@X@     - probably others I can't think of at the moment.
X@X@
X@X@  If you discover more bugs, fix them, or just have suggestions, mail
X@X@  them to Gordon Davisson ({ihnp4|decvax}!uw-beaver!uw-june!gordon, or
X@X@  gordon@uw-june.ARPA).
X@X@
X@X@  I'll probably fix some of these eventually, in which case I'll post
X@X@  the new version to net.sources.
X@X@----------------------------------------------------------------
X@X@
Technical Details
Message-ID: <91@rtgvax.UUCP>
Path: arc1-ca.pugleaf.net!beno!seismo!uwvax!husc6!panda!genrad!decvax!decwrl!amdcad!cae780!leadsv!rtgvax!ramin

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!beno!seismo!uwvax!husc6!panda!genrad!decvax!decwrl!amdcad!cae780!leadsv!rtgvax!ramin
From: ramin@rtgvax.UUCP
Newsgroups: net.decus
Subject: Reading TAR from VMS
Message-ID: <91@rtgvax.UUCP>
Date: 6 Sep 86 23:18:04 GMT
Organization: Erewhon Travel
Lines: 1607
Keywords: Summaries, *ACTUAL PROGRAMS* (yow!)
Posted: Sat Sep  6 19:18:04 1986