From:	MERC::"uunet!FRSIM51.BITNET!FAUCONNE" 14-JUN-1992 06:01:06.30
To:	EVERHART
CC:	
Subj:	VMSTAR.SHARE (V1.6-BETA)

$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On 14-JUN-1992 11:48:35.39   By user FAUCONNET
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER
$! AND EXECUTE AS A COMMAND PROCEDURE  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. VMSTAR.C;69
$!       2. VMSTAR.HLP;10
$!       3. BUILD.COM;1
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ ve=f$getsyi("version")
$ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ if .not. f$verify() then $ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")=
1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF";
POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r);
ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1;
COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE,
"output_file"));ENDPROCEDURE;Unpacker;QUIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
X/*
X *`09VMSTAR.C - a Un*x-like tar reader/writer for VMS
X *`09           based on TAR2VMS and VMS2TAR
X *
X * Usage:
X * `09tar x`7Ct`7Cc`5Bv`5D`5Bw`5D`5Bb`5D`5Bz`5D`5Bd`5D`5Bf tarfile`5D `5Bfil
Ve `5Bfile...`5D`5D
X *`09x - extract from tarfile
X *`09t - type contents of tarfile
X *`09c - create tarfile, archive VMS files
X *`09v - verbose
X *`09w - wait for confirmation before extracting/archiving
X *`09b - force binary mode extract, create (rfm=fixed, rat=none, mrs=512)
X *          files
X *`09z - automatic mode, try to guess if files are text or binary, extract
X *          text files as (rfm=stream-LF, rat=cr) binary files as
X *          (rfm=fixed, rat=none, mrs=512)
X *`09d - keep trailing dots in file names
X *`09f - specify tarfile name, default is $TAPE
X *`09file - space-separated list of file names, can include VMS-style
X *`09       string wildcards on extract, can be any VMS file name
X *             specification (except DECnet) on create archive.
X *
X * Original author of the VMS2TAR and TAR2VMS programs:
X * Copyright 1986, Sid Penstone,
X *  Department of Electrical Engineering,
X *  Queen's University,
X *  Kingston, Ontario, Canada K7L3N6
X * (613)-545-2925
X * BITNET:   PENSTONE@QUCDNEE1
X *
X * Deeply modified by:
X * Alain Fauconnet
X * System Manager
X * SIM - Public Health Research Laboratories
X * 91 Boulevard de l'Hopital
X * 75634 PARIS CEDEX 13 - FRANCE
X * Bitnet: FAUCONNE@FRSIM51
X *
X * PROBLEMS SHOULD BE REPORTED TO ME. PLEASE DON'T BOTHER SID PENSTONE
X * WITH MY OWN BUGS !
X *
X * Version 1.6-BETA 12-JUN-1992
X * Based on TAR2VMS V2.2 21-OCT-1986 and VMS2TAR V1.8 23-DEC-1986
X *
X * Sid Penstone did not include any copyright information in his program so
X * this only applies if Sid Penstone agrees: you may use VMSTAR, distribute
V it,
X * modify it freely provided you don't use it for commercial
X * or military purposes. Please include the two above author names in the
X * source file of any modified version of VMSTAR.
X *
X * Modification history:
X *
X * 1.6-0 - added 'z' option for automatic determination of file type on
X *         extraction
X *       - reworked copyfile() to close files and exit on fatal error -
X *         error status not returned, they weren't checked anyway
X *`09 - some code cleanup (much, much more to do...)
X * 1.5-3 - removed duplicate error message
X * 1.5-2 - removed duplicate #include iodef
X *       - added write status checking in copyfile and cleaned up error
X *         handling (avoids duplicate messages)
X * 1.5-1 - fix by Mark Parisi <MPARISI@RIPPLE.JPL.NASA.GOV>
X *         fixed bug in out_file: if the length of a text file was an
X *         exact multiple of RECSIZE, flushout was called an additional
X *         time.
X *       - added some code for empty files handling.
X * 1.5  - when archiving a non-text file with rfm=stream_lf, rat=cr
X *        attributes, VMSTAR truncated the file. Modified out_file
X *        to more cleanly handle various RMS file formats: only
X *        variable and stream_cr record formats need two passes to compute`2
V0
X *        the actual file size and need to be read record by record.
X *        All other formats should by read buffer by buffer and written
X *        as-is in the tar archive, thus out_file now fopens the file
X *        in binary mode and freads buffers.
X *        In the case of a stream_cr file, if a single record cannot fit in
X *        our buffers (probably because the file is non-text and has
X *        incorrect RMS attributes) out_file now error exits.
X * 1.4`09- fixed a bug in scan_title that caused VMSTAR to fail on
X *`09  extraction of absolute tarfiles (thanks to Tom Allebrandi
X *`09  for this one)
X *`09- added some code in scan_title to correctly handle dots in
X *`09  directory names found in tarfile (replaced by "_")
X * 1.3  - changed tar2vms to use standard IO calls (fopen, fread) to
X *        read input tarfile in binary mode i.e. no translation of
X *        RMS record attributes done by C RTL. This fixes problem reading
X *        tarfiles created with rfm=fix, rat=cr
X *      - more room for file size in output formats
X * 1.2  - fixed bug in out_file not closing input VMS file, limited
X *        maximum number of files archived to FILLM quota
X *      - added mapping to underscores of some more characters found
X *        in Un*x file names illegal in VMS file names
X * 1.1  - reworked handling of current VMS default
X *      - will now create *relative* tarfiles (i.e. files known
X *        as "./..." in tar archive directory) except when
X *        device name is specified or wilcard search gives filenames
X *        located above current default (tar cvf foo.tar `5B-...`5D*.* will
X *        lead to this kind of situation)
X *      - attempt to handle more than 8 levels of directories upon
X *        extract : .../d7/d8/d9 will be mapped to `5B...D7.D8$D9`5D
X *      - greatly simplified make_new() because mkdir() creates
X *        intermediate levels of directories if missing
X * 1.0`09Original version from Sid Penstone's code
X *`09- merged VMS2TAR & TAR2VMS into a single source file
X *`09- code reworked, messages cleaned up
X *`09- added support for 'f tarfile' option, changed default to $TAPE
X *`09- added support for VMS style wildcard file names on extract
X *`09- added support for 'b' (binary file extract) option
X *`09- suppressed usage of intermediate scratch file for create operation
X *`09- file list on create should now be space separated (removed difficult
X *`09  support of comma-separated list with context "a la BACKUP")
X *`09- global code simplification attempt, may have broken some
X *`09  odd case handling
X *`09- added some error handling in tarfile write operations
X *`09- probably millions of bugs introduced... sorry.
X */
X
X#module VMSTAR "V1.6-BETA"
X
X#include stdio
X#include time
X#include ssdef
X#include iodef
X#include descrip
X#include ctype
X#include strdef
X#include rms
X#include stsdef
X#include file
X#include stat
X#include types
X#include string
X#include errno
X
X#define ERROR1 -1
X#define ISDIRE 1
X#define ISFILE 0
X#define NAMSIZE 100
X#define BLKSIZE 10240           /* Block size */
X#define RECSIZE 512             /* Data block size */
X
Xstruct tarhdr                   /* A tar header */
X`7B
X    char title`5BNAMSIZE`5D;
X    char protection`5B8`5D;
X    char uid`5B8`5D;                /* this is the user id */
X    char gid`5B8`5D;                /* this is the group id */
X    char count`5B12`5D;             /* was 11 in error */
X    char time`5B12`5D;              /* UNIX format date  */
X    char chksum`5B8`5D;             /* header checksum */
X    char linkcount;             /* hope this is right */
X    char linkname`5BNAMSIZE`5D;     /* Space for the name of the link */
X    char dummy`5B255`5D;            /* and the rest */
X`7D header;
X
Xunsigned char buffer`5BRECSIZE`5D;             /* buffer for a tarfile recor
Vd */
X
X/* Function flags, options */
X
Xint extract,            /* x option, extract */
X    list,               /* t option, list tape contents */
X    verbose,            /* v option, report actions */
X    wait,               /* w option, prompt */
X    dot,                /* d option, suppress dots */
X    create,             /* c option, create */
X    binmode,            /* b option, binary mode */
X    automode,`09`09/* z option, automatic mode */
X    foption;`09`09/* f option, specify tarfile */
X
X/* Miscellaneous globals, etc. */
X
Xchar tarfile`5BNAMSIZE`5D,  /* Tarfile name  */
X    pathname`5BNAMSIZE`5D,  /* File name as found on tape (UNIX) */
X    curdir`5BNAMSIZE`5D,    /* Current directory */
X    topdir`5BNAMSIZE`5D,    /* Top level directory of current default */
X    curdev`5BNAMSIZE`5D,    /* Current device */
X    new_directory`5BNAMSIZE`5D,     /* Directory of current file */
X    newfile`5BNAMSIZE`5D,   /* VMS format of file name */
X    outfile`5BNAMSIZE`5D,   /* Complete output file specification */
X    temp`5BNAMSIZE`5D,      /* Scratch */
X    creation`5BNAMSIZE`5D,  /* Date as extracted from the TAR file */
X    *ctime(),           /* System function */
X    linkname`5BNAMSIZE`5D,  /* Linked file name  */
X    searchname`5BNAMSIZE`5D, /* used in the NAM block for SYS$SEARCH */
X    dbuffer`5BRECSIZE`5D,     /* input file buffer for create operation */
X    badchars`5B`5D = `7B",+`7E`60@#%`5E*?`7C\&`5B`5D`7B`7D"`7D;
X                        /* Chars found in Un*x file names, illegal in VMS */
X
Xstruct stat sblock;     /* structure returned from stat() */
Xstruct FAB fblock;      /* File attribute block */
Xstruct NAM nblock;      /* Name attribute block for rms */
X
Xint bytecount,  mode, uic1, uic2, linktype; /* Data from header */
Xint uid, gid, bufferpointer;    /* current values used by create */
XFILE *tarfp;                      /* The input file pointer */
X
X/* Global file characteristics */
X
XFILE *vmsfile;
Xint vmsfd, outfd;
Xunsigned int vmsmrs, vmstime;       /* maximum record size */
Xint vmsrat,vmsorg,vmsrfm;           /* other format (as integers) */
Xchar default_name`5B`5D = `7B"*.*;"`7D;     /* only get the most recent vers
Vion */
Xint binfile;`09`09`09    /* "extract as binary" flag */
X
X/* main -- parses options, dispacthes to tar2vms and vms2tar */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv`5B`5D;
X`7B
Xchar *cp, c;
X
X/* Decode the options and parameters: */
X
X    if(argc ==1)
X        usage();
X    extract = 0;            /* Defaults for now */
X    verbose = 0;
X    wait = 0;               /* Don't wait for prompt */
X    binmode = 0;
X    automode = 0;
X    create = 0;
X    dot = 0;
X    foption = 0;
X    strcpy(tarfile,"$TAPE");
X
X        cp = argv`5B1`5D;
X        while(c = *cp++)
X            `7B
X            switch(c)
X            `7B
X            case 't':
X                list=1;
X                break;
X            case 'x':
X                extract=1;
X                break;
X            case 'c':
X                create=1;
X                break;
X            case 'v':
X                verbose=1;
X                break;
X            case 'w':
X                wait=1;
X                break;
X            case 'd':
X                dot=1;
X                break;
X            case 'b':
X                binmode=1;
X                break;
X`09    case 'z':
X`09`09automode=1;
X`09`09break;
X            case 'f':
X                if (*cp != '\0' `7C`7C argc < 3)
X                    usage();
X                else
X                    foption = 1;
X                    strcpy(tarfile,argv`5B2`5D);
X                break;
X            case '-':
X                    break;
X            default:
X                printf("tar: option '%c' not recognized.\n",c);
X                usage();
X            `7D
X       `7D
X
X
X/* Check options are coherent */
X
X    if (extract + list + create == 0)
X    `7B
X        printf("tar: no action specified.\n");
X        exit(1);
X    `7D
X    if (extract + create == 2)
X    `7B
X        printf("tar: incompatible options 'x' and 'c' specified.\n");
X        exit(1);
X    `7D
X    if (binmode + automode == 2)
X    `7B
X`09printf("tar: incompatible options 'b' and 'z' specified.\n");
X    `7D
X
X/* Set up directory names - current and top level */
X
X    strcpy(curdev, getenv("PATH"));
X    for (cp = curdev; *cp != '\0'; ++cp)
X        *cp = toupper(*cp);`09`09/* map to uppercase */
X
X    cp = strchr(curdev, ':');    /* split into device and directory */
X    *cp++ = '\0';
X    strcpy(curdir, cp);
X
X    strcpy(topdir, curdir);
X    cp = strchr(topdir,'.');`09`09/* isolate top level directory */
X    if (cp != NULL)
X    `7B
X        *cp = '`5D';
X        *++cp = '\0';
X    `7D
X
X    if (create == 0)
X        tar2vms(argc,argv);
X    else
X        vms2tar(argc,argv);
X`7D
X
X/* tar2vms -- handles extract and list options */
X
Xtar2vms(argc,argv)
Xint argc;
Xchar **argv;
X
X`7B
Xint status,file_type,j, flag, argi, process;
Xchar *make_directory(), *argp, *ptr;
Xstruct dsc$descriptor pattern, candidate;
XFILE *opentar();
X
X/* open the file for reading */
X
X    if((tarfp = opentar()) == NULL)
X        `7B
X        printf("tar: error opening tarfile.\n");
X        exit(1);
X        `7D
X
X/* Now keep reading headers from this file, and decode the names, etc. */
X
X    while((status=hdr_read(&header))==RECSIZE)    /* 0 on end of file */
X    `7B
X        process = 0;
X        if(strlen(header.title)!=0)     /* Valid header */
X        `7B
X            decode_header();
X            process = 1;
X
X/* Now if file names were specified on the command line, check if they
X   match the current one */
X
X            if ((foption == 0 && argc > 2) `7C`7C argc > 3)
X            `7B
X                process = 0;
X                argi = foption ? 3 : 2;
X                while (argi < argc)
X                `7B
X                    pattern.dsc$w_length = strlen(argv`5Bargi`5D);
X                    pattern.dsc$a_pointer = argv`5Bargi`5D;
X                    pattern.dsc$b_dtype = DSC$K_DTYPE_T;
X                    pattern.dsc$b_class = DSC$K_CLASS_S;
X                    candidate.dsc$w_length = strlen(pathname);
X                    candidate.dsc$a_pointer = pathname;
X                    candidate.dsc$b_dtype = DSC$K_DTYPE_T;
X                    candidate.dsc$b_class = DSC$K_CLASS_S;
X
X                    ++argi;
X
X                    if (STR$MATCH_WILD(&candidate, &pattern) == STR$_MATCH)
X                    `7B
X                        process = 1;
X                        break;
X                    `7D
X                `7D
X            `7D
X        `7D
X        else
X        `7B
X             status = 1;
X             break;
X        `7D `20
X        if (process && wait)
X        `7B
X            *temp = '\0';
X            while (*temp != 'y' && *temp != 'n')
X            `7B
X                printf("%s   (y/n) ? ", pathname);
X                scanf("%s", temp);
X                *temp = tolower(*temp);
X            `7D
X            process = (*temp == 'y');
X        `7D
X        if (process && extract)
X        `7B              `20
X                file_type=scan_title(pathname,new_directory,newfile);
X                cleanup_dire(new_directory);
X                if( make_new(new_directory)!=0)
X                    printf("tar: error creating %s\n",new_directory);
X                if(file_type == ISDIRE)
X                    `7B`7D
X                if(file_type == ISFILE)
X
X/*  Now move the data into the output file */
X
X                    if(bytecount>0)
X                    `7B
X                        strcpy(outfile,new_directory);
X                        strcat(outfile,newfile);
X                        copyfile(outfile,bytecount);
X                    `7D
X        `7D
X        else
X        `7B
X            if (process && list)               /* listing only */
X            `7B
X                printf("%6o %8d %s %s\n",
X                    mode,bytecount,creation+4,pathname);
X                if (linktype == 1 `7C`7C linktype == 2)
X                 printf("                                --->  %s\n",linknam
Ve);
X            `7D
X            if(linktype == 0)
X                tarskip(bytecount);
X        `7D
X    `7D       /* end while  */
X    if(status == 1)                     /* Empty header */
X    `7B
X
X/*        printf("Do you wish to move past the EOF mark (y/n) ? ");
X**        fflush(stdout);
X**        gets(temp);
X**        if(tolower(*temp) == 'y')
X**            while((status=hdr_read(&header)) >0);
X**        else
X*/
X`09    fclose(tarfp);
X            exit(SS$_NORMAL);
X    `7D
X    if(status==0)                       /* End of tar file  */
X    `7B
X        printf("tar: EOF hit on tarfile.\n");
X`09fclose(tarfp);
X        exit(SS$_NORMAL);
X    `7D
X    if(status<0)                        /* An error  */
X    `7B
X        printf("tar: error reading tarfile.\n");
X`09fclose(tarfp);
X        exit(SS$_NORMAL);
X    `7D
X`7D
X
X
X/* This function simply copies the file to the output, no conversion */
X
Xint copyfile(outfile,nbytes)
Xchar outfile`5B`5D; /* name of output version */
Xint nbytes;
X`7B
Xint inbytes, fil, s, i, ctlchars, eightbitchars, nchars;
Xregister unsigned char c;
X
X/* Read the first block of the tarred file */
X
X    binfile = binmode;
X    inbytes = 0;
X    if (linktype == 0 && nbytes != 0) `7B
X        if((inbytes=fread(buffer,1,RECSIZE,tarfp)) < 0)
X        `7B
X`09   printf("tar: error reading tar file.\n");
X`09   fclose(tarfp);
X`09   exit(SS$_NORMAL);
X        `7D
X
X/* If automatic mode is set, then try to figure out what kind of file this
X   is */
X
X        if (automode && inbytes != 0) `7B
X            ctlchars = 0;
X`09    eightbitchars = 0;
X
X/* Scan the buffer, counting chars with msb set and control chars
X   not CR, LF or FF */
X
X`09    nchars = nbytes < inbytes ? nbytes : inbytes;
X`09    for (i = 0; i < nchars; ++i) `7B
X`09`09c = buffer`5Bi`5D;
X`09        if (c < ' ' &&`20
X                    c != 0x0a && c != 0x0c &&
X                    c != 0x0d && c != 0x09)
X`09`09     ctlchars++;
X`09        if (c > 127)
X`09`09    eightbitchars++;
X`09    `7D
X
X/* Now apply some heuristics to determine file is text or binary */
X
X`09    ctlchars = ctlchars * 100 / nchars;
X`09    eightbitchars = eightbitchars * 100 / nchars;
X`09    if (ctlchars > 10 `7C`7C eightbitchars > 30 `7C`7C
X                (ctlchars > 5 && eightbitchars > 20))
X                binfile = 1;
X        `7D
X    `7D
X
X/*  Open the output file */
X
X    if (binfile)
X        fil = creat(outfile,0,"rfm=fix","mrs=512","alq=5");
X    else
X        fil = creat(outfile,0,"rfm=stmlf","rat=cr");
X
X    if(fil == ERROR1)
X    `7B
X        printf("tar: error creating %s \n",outfile);
X`09tarskip(nbytes - inbytes);
X    `7D
X    s = 0;
X    if(linktype !=0)
X    `7B
X        sprintf(buffer,"*** This file is a link to %s\n",linkname);
X        s = write(fil,buffer,strlen(buffer));
X    `7D
X    else
X    `7B
X        while(nbytes > 0 && s >= 0 && inbytes > 0)
X        `7B
X            s = write(fil,buffer,(binmode `7C`7C (nbytes>RECSIZE)) ? RECSIZE
V : nbytes);
X            nbytes -= inbytes;
X            if (nbytes > 0)
X`09`09inbytes = fread(buffer,1,RECSIZE,tarfp);
X        `7D
X
X/* Close the extracted file, check results */
X
X`09close (fil);
X        if (inbytes == 0 && nbytes != 0) `7B
X                printf("tar: unexpected EOF on tar file.\n");
X`09        fclose(tarfp);
X                exit(SS$_NORMAL);
X`09`7D
X`09if (inbytes < 0) `7B
X`09`09printf("tar: error reading tar file.\n");
X`09        fclose(tarfp);
X                exit(SS$_NORMAL);
X        `7D
X    `7D
X    if (s < 0)
X    `7B
X        printf("tar: error writing file %s\n",outfile);
X`09fclose(tarfp);
X        exit(SS$_NORMAL);
X    `7D
X
X    if(verbose)
X    `7B
X        printf("%s %8d%c%s\n",
X               creation+4,bytecount,
X`09       binfile ? '*' : ' ',outfile);
X        if(linktype!=0)
X            printf("                         --> %s\n",linkname);
X    `7D
X`7D
X
X/* scan_title -- decode a Un*x file name into the directory and name */
X
X/* Return a value to indicate if this is a directory name, or another file
X* We return the extracted directory string in "dire", and the
X* filename (if it exists) in "fname". The full title is in "line"
X* at input.
X*/
X
Xint scan_title(line,dire,fname)
Xchar line`5B`5D,dire`5B`5D,fname`5B`5D;
X`7B
Xchar *end1;
Xint len,len2,i,ind;
X/* The format will be UNIX at input, so we have to scan for the
X* UNIX directory separator '/'
X* If the name ends with '/' then it is actually a directory name.
X* If the directory consists only of '.', then don't add a subdirectory
X* The output directory will be a complete file spec, based on the default
X* directory.
X*/
X
X    strcpy(dire,curdir);                /* Start with the current dir */
X    if(strncmp(line,"./",2)==0)
X        strcpy(line,line+2);            /* ignore "./" */
X    strcpy(temp,line);                  /* Start in local buffer */
X    ind=vms_cleanup(temp);              /* Remove illegal vms characters */
X    if((end1=strrchr(temp,'/'))==0)     /* No directory at all  ? */
X        strcpy(fname,temp);             /* Only a file name */
X    else
X    `7B                                   /* End of directory name is '/' */
X        *end1 = 0;                      /* Terminate directory name */
X        strcpy(fname,end1+1);           /* File name without directory */
X        for (i=1;temp`5Bi`5D;i++)           /* Change '/' to '.' in director
Vy */
X            if(temp`5Bi`5D=='/')`09`09/* and '.' to '_' */
X                temp`5Bi`5D='.';
X`09    else if (temp`5Bi`5D == '.')
X`09        temp`5Bi`5D = '_';
X        if (*temp == '/')               /* absolute path ? */
X        `7B
X            *temp = '`5B';`09`09/* yes, build absolute VMS path */
X            strcpy(dire,temp);
X        `7D
X        else
X        `7B
X            dire`5Bstrlen(dire)-1`5D = (*temp=='.')?0:'.' ;
X                 /* "." to indicate a subdirectory (unless already there )*/
X            strcat(dire,temp);      /* Add on the new directory  */
X        `7D
X        strcat(dire,"`5D") ;              /* And close with '`5D' */
X    `7D
X    if(strlen(fname)==0)        /* Could this cause problems ? */
X    `7B
X        return(ISDIRE);
X    `7D
X    else
X        for(i=0,end1=fname;*end1;end1++) /* Replace multiple . */
X            if(*end1 == '.')
X                if(i++)*end1 = '_'; /* After the first */
X    return(ISFILE);
X`7D
X
X/* make_new -- create a new directory */
X
Xint make_new(want)
Xchar want`5B`5D;
X`7B
Xint status, created;
Xchar *dotp;
X
X    created = 1;
X    status = mkdir(want, 0);   /* mkdir in VAX C creates all missing levels
V */
X    if (status != 0)
X    `7B
X        if (errno == EEXIST)
X            return (0);
X        if (errno != EINVAL)
X            return (-1);          /* unknown error, simply return */
X        else                      /* maybe too many levels of directories */
X        `7B                         /* change "`5B...FOO.BAR`5D" to "`5B...F
VOO$BAR`5D" */
X        for (dotp = &want`5Bstrlen(want) - 1`5D;dotp > want && status != 0;)
X            if (*--dotp == '.')`20
X            `7B
X                *dotp = '$';
X                status = mkdir(want, 0);
X                if (status != 0 && errno == EEXIST)
X                `7B
X                    status = created = 0;
X                    break;
X                `7D
X            `7D
X        `7D
X    `7D
X    if (status != 0)
X        return (-1);
X    if(verbose && created)
X        printf("                              %s\n",want);
X    return(0);
X`7D
X
X /* Function to open and get data from the blocked input file */
XFILE *opentar()
X`7B
XFILE *fp;
X    fp = fopen(tarfile, "rb");
X    return(fp);
X`7D
X
X/* Get the next file header from the input file buffer. We will always
X* move to the next 512 byte boundary.
X*/
Xint hdr_read(buffer)
Xchar *buffer;
X`7B
Xint stat;
X    stat = fread(buffer,1,RECSIZE,tarfp);    /* read the header */
X    return(stat);                       /* catch them next read ? */
X`7D
X
X
X/* This is supposed to skip over data to get to the desired position */
X/* Position is the number of bytes to skip. We should never have to use
X* this during data transfers; just during listings. */
Xint tarskip(bytes)
Xint bytes;
X`7B
Xint i=0;
X    while(bytes > 0)
X        `7B
X        if((i=fread(buffer,1,RECSIZE,tarfp)) == 0)
X            `7B
X            printf("tar: EOF hit while skipping.\n");
X            return(-1);
X            `7D
X        bytes -= i;
X        `7D
X    return(0);
X`7D
X
X/* Decode the fields of the header */
X
Xint decode_header()
X`7B
Xint idate, *bintim, chksum, value;
Xchar ll, *ptr;
Xbintim = &idate;
X    linktype=0; strcpy(linkname,"");
X    strcpy(pathname,header.title);
X    sscanf(header.time,"%o",bintim);
X    strcpy(creation,ctime(bintim));     /* Work on this! */
X    creation`5B24`5D=0;
X    sscanf(header.count,"%o",&bytecount);
X    sscanf(header.protection,"%o",&mode);
X    sscanf(header.uid,"%o",&uic1);
X    sscanf(header.gid,"%o",&uic2);
X    sscanf(header.chksum,"%o",&chksum);
X
X/* Verify checksum */
X
X    for(value = 0, ptr = &header; ptr < &header.chksum; ptr++)
X             value += *ptr;                /* make the checksum */
X    for(ptr = &header.linkcount; ptr <= &header.dummy`5B255`5D; ptr++)
X             value += *ptr;
X    value += (8 * ' ');`09               /* checksum considered as all space
Vs */
X
X    if (chksum != value)
X    `7B                                       /* abort if incorrect */
X        printf("tar: directory checksum error for %s\n",pathname);
X        exit(1);
X    `7D
X
X
X/* We may have the link written as binary or as character:  */
X
X    linktype = isdigit(header.linkcount)?
X            (header.linkcount - '0'):header.linkcount;
X    if(linktype != 0)
X        sscanf(header.linkname,"%s",linkname);
X    return(0);
X`7D
X
X
X/* vms_cleanup -- removes illegal characters from directory and file names
X * Replaces hyphens and commas with underscores. Returns number of translati
Vons
X * that were made.
X */
X
Xvms_cleanup(string)
Xchar string`5B`5D;
X`7B
X    int i,flag=0;
X    char c;
X
X    for(i=0; c=string`5Bi`5D; ++i)
X    `7B
X        if (strchr(badchars, c) != NULL)
X        `7B                    /* Replace illegal characters by underscores
V */
X            string`5Bi`5D= '_';
X            flag++;          /* Record if any changes were made */
X        `7D
X        else
X            string`5Bi`5D = toupper(c); /* Map to uppercase */
X    `7D
X    return(flag);
X`7D
X
X/* vms2tar -- handles create function */
X
Xvms2tar(argc,argv)
Xint argc;
Xchar **argv;
X`7B
X    int argi, process, file_type, absolute;
X    char string`5BNAMSIZE`5D, *cp, *dp, *wp;
X
X    if (argc < 3 `7C`7C (foption && argc < 4)) usage();
X
X    bufferpointer = 0;
X    gid = getgid();
X    uid = getuid();
X    mode = 0644;
X
X/* Open the output file */
X
X    outfd = creat(tarfile,0600,"rfm=fix","mrs=512");
X    if (outfd < 0)
X    `7B
X        printf("tar: error opening output tarfile %s\n", tarfile);
X        exit(SS$_NORMAL);
X    `7D `20
X
X    for (argi = foption ? 3 : 2; argi < argc; ++argi)
X    `7B
X        strcpy(string, argv`5Bargi`5D);
X        absolute = 0;
X        cp = strchr(string, ':');   /* device name in argument ? */
X        if (cp != NULL)            /* yes, force absolute mode */
X            absolute = 1;
X        else
X        `7B
X            cp = strchr(string, '`5B');  /* test argument for absolute... */
X            if (cp != NULL)            /* ...or relative filespec */
X            `7B
X                ++cp;
X                if (*cp != '.' && *cp != '-')
X                    absolute = 1;
X            `7D
X        `7D
X        if(initsearch(string) <= 0)
X            printf("tar: no files matching %s\n",string);
X        else
X          while(search(newfile,NAMSIZE)!=0)
X          `7B
X            strcpy(linkname, newfile);
X            cleanup_dire(newfile);
X            file_type = scan_name(newfile,new_directory,outfile,absolute);
X            strcpy(pathname,new_directory);
X            strcat(pathname,outfile);
X            if (get_attributes(newfile) != 0) exit(SS$_NORMAL);
X            process = 1;
X            if(wait)
X            `7B
X                *temp = '\0';
X                while (*temp != 'y' && *temp != 'n')
X                `7B
X                    printf("%s   (y/n) ? ", linkname);
X                    scanf("%s", temp);
X                    *temp = tolower(*temp);
X                `7D
X                process = (*temp == 'y');
X            `7D
X            if (process)
X            `7B
X                if(file_type == ISDIRE)
X                `7B
X                    bytecount =  0;
X                    mode = 0755;
X                    fill_header(pathname);
X                    write_header(outfd);
X                `7D
X                if(file_type == ISFILE)
X                `7B
X                    mode = 0644;
X                    if(addfile(newfile, pathname) < 0)
X                    `7B
X                        printf("tar: error copying %s\n",linkname);
X                        exit(SS$_NORMAL);
X                    `7D
X                `7D
X                if (bytecount == 0 && file_type == ISFILE)
X`09`09`7B
X                    printf("*** skipped  %s\n", linkname);
X`09`09    printf("*** empty file or unsupported format\n");
X`09`09`7D
X                if (verbose && (bytecount `7C`7C file_type == ISDIRE))
X                `7B
X                     strcpy(creation,ctime(&vmstime)); /* work on this */
X                     creation`5B24`5D=0;
X                     printf("%s %8d %s\n",creation + 4,bytecount,pathname);
X                `7D
X            `7D
X          `7D
X    `7D
X    write_trailer(outfd);
X    close(outfd);
X`7D
X
X/* addfile - copy the vms file to the output file */
X
Xint addfile(vmsname,unixname)
Xchar vmsname`5B`5D,unixname`5B`5D;
X`7B
Xint ind;
X    if(bytecount == 0)          /* we don't output null files  */
X        return(0);
X    if((ind=out_file(vmsname,bytecount,outfd)) < 0)
X        return(ind);
X    bufferpointer = bufferpointer%BLKSIZE;
X    return(1);
X`7D
X
X
X/* out_file - write out the file.
X* move nbytes of data from "fdin" to "fdout";
X* Always pad the output to a full RECSIZE
X* If it a VMS text file, it may be various formats, so we will
X* read the file twice in case of a text file
X* so that we get the correct byte count.
X* We set the bytecount=0 if this is funny file.
X*/
X
Xint out_file(filename,nbytes,fdout)
Xchar filename`5B`5D;
Xint fdout, nbytes;
X`7B
Xint i, n, pos;
Xchar *bufp, *linep;
XFILE *filein;
X
X    if(vmsrfm == FAB$C_FIX `7C`7C vmsrfm == FAB$C_STM `7C`7C
X       vmsrfm == FAB$C_STMLF)
X    `7B
X    `09if((filein = fopen(filename,"rb")) == NULL)
X    `09`7B
X    `09`09printf("tar: error opening input file %s\n",filename);
X        `09return(-1);
X        `7D
X        fill_header(pathname);          /* We have all of the information */
X        write_header(outfd);            /* So write to the output */
X        while(nbytes > 0)
X        `7B
X            n = fread(buffer, 1, nbytes>RECSIZE? RECSIZE:nbytes, filein);
X            if (n == 0)
X            `7B
X                fclose(filein);
X                printf("tar: error reading input file %s\n",filename);
X                return(-1);
X            `7D
X            nbytes -= n;
X            flushout(fdout);
X        `7D
X        fclose(filein);
X        return(0);
X    `7D
X    else
X        if(vmsrat != 0)                 /* must be a text file  */
X        `7B                               /* compute "Unix" file size */
X            if((filein = fopen(filename,"r")) == NULL)
X            `7B
X                printf("tar: error opening input file %s\n",filename);
X                return(-1);
X            `7D
X            nbytes = 0;
X            while(fgets(dbuffer,RECSIZE,filein) !=  NULL)
X                nbytes += strlen(dbuffer);
X`09    if (!feof(filein))
X`09    `7B
X                fclose(filein);
X                printf("tar: error reading input file %s\n",filename);
X                printf("     record too large or incorrect RMS attributes\n"
V);
X                return(-1);
X            `7D
X            rewind(filein);                 /* Back to the beginning  */
X            bytecount = nbytes;             /* Use the real count  */
X            fill_header(pathname);          /* Compute the header */
X            write_header(outfd);            /* Write it  */
X            bufp = buffer;
X
X`09    if (nbytes != 0)`09`09    /* Check for empty file */
X`09    `7B
X                while(fgets(dbuffer,RECSIZE,filein) !=  NULL)
X                `7B                           /* Now copy to the output */
X                    linep = dbuffer;
X                    while (*linep != '\0')  /* read source file line by line
V */
X                    `7B
X                        if (bufp >= &buffer`5BRECSIZE`5D)
X                        `7B
X                            bufp = buffer;
X                            flushout(fdout); /* if buffer full, flush it */
X                        `7D               /* copy in fixed size output buffe
Vr */
X                        *bufp++ = *linep++;
X`09`09    `7D `20
X                `7D
X                flushout(fdout);
X`09    `7D
X            fclose(filein);
X        `7D
X        else              /* Other formats e.g. .OBJ are not done  */
X        `09bytecount = 0;
X        return (0);       `20
X`7D
X
X/* flushout - write a fixed size block in output tarfile */
X
Xflushout(fdout)
Xint fdout;
X`7B
X    if (write(fdout,buffer,RECSIZE) != RECSIZE)
X    `7B
X        printf("tar: error writing tarfile.\n");
X        exit(SS$_NORMAL);
X    `7D
X    bufferpointer += RECSIZE;
X`7D
X
X/* write_header - copy the header to the output file  */
X
Xint write_header(fd)
Xint fd;
X`7B
Xint n;
X    if((n=write(fd,&header,RECSIZE))!=RECSIZE)
X    `7B
X        printf("tar: error writing header in tarfile.\n");
X        exit(SS$_NORMAL);
X    `7D
X    bufferpointer += RECSIZE;
X    return(n);
X`7D
X
X/*  get_attributes - get the file attributes via stat()  */
X
Xint get_attributes(fname)
Xchar fname`5B`5D;
X`7B
X    if(stat(fname,&sblock))
X    `7B
X        printf("tar: can't get file status on %s\n",fname);
X        vmstime = 0;                    /* Prevent garbage printoout */
X        bytecount = 0;                  /* of inaccessible files  */
X        return(-1);
X    `7D
X
X/* now get the file attributes, we don't use them all */
X    bytecount = sblock.st_size;
X    vmsrat = sblock.st_fab_rat;
X    vmsmrs = sblock.st_fab_mrs;
X    vmsrfm = sblock.st_fab_rfm;
X    vmstime = sblock.st_mtime;
X    return (0);
X`7D
X
X
X/* write_trailer - write the two blank blocks on the output file */
X/* pad the output to a full blocksize if needed. */
X
Xwrite_trailer(fdout)
Xint fdout;
X`7B
Xint i;
X    for (i=0; i < NAMSIZE; ++i)
X        header.title`5Bi`5D = '\0';
X    write_header(fdout);
X    write_header(fdout);
X    bufferpointer = bufferpointer%BLKSIZE;
X    while (bufferpointer < BLKSIZE)
X        write_header(fdout);
X    return(1);
X`7D
X
X/* scan_name - decode a file name */
X
X/* Decode a file name into the directory, and the name, and convert
X* to a valid UNIX pathname. Return  a value to indicate if this is
X* a directory name, or another file.
X* We return the extracted directory string in "dire", and the
X* filename (if it exists) in "fname". The full title is in "line"
X* at input.
X*/
X
Xint scan_name(line,dire,fname,absolute)
Xchar line`5B`5D,dire`5B`5D,fname`5B`5D;
Xint absolute;
X`7B
Xchar *cp1,*cp2;
Xint len,len2,i;
Xchar *strindex();
X
X/* The format will be VMS at input, so we have to scan for the
X* VMS device separator ':', and also the VMS directory separators
X* '`5B' and '`5D'.
X* If the name ends with '.dir;1' then it is actually a directory name.
X* The outputs dire and  fname will be a complete file spec, based on the def
Vault
X* directory.
X* It may be a rooted directory, in which case there will be a "`5D`5B" strin
Vg,
X* remove it.
X* Strip out colons from the right, in case there is a node name (should not
V be!)
X* If the filename ends in a trailing '.', suppress it , unless the "d" optio
Vn
X* is set.
X*/
X
X
X    strcpy(temp,strrchr(line,':')+1);           /* Start with the whole name
V */
X
X/* If relative path, get rid of default directory part of the name  */
X
X    if (absolute == 0)
X    `7B
X        strcpy(dire,"./");
X        for(cp1 = temp ,cp2 = curdir; *cp2 && (*cp1 == *cp2);
X            cp1++, cp2++);
X        if(*cp2 == 0)
X            *cp1 = 0;              /* Perfect match, no directory spec  */
X        else
X        `7B
X            switch(*cp1)
X            `7B
X            case '.':
X            case '`5B':               /* Legal beginnings or ends  */
X                break;
X            default:            /* We are above the default, use full name *
V/
X                cp1 = strchr(temp,'`5B');    /* Fixed this from 1.5  */
X                *dire = '\0';
X                break;
X            `7D
X            cp1++;                 /* Get past the starting . or `5B */
X        `7D
X        strcat(dire, cp1);
X    `7D
X    else
X        strcpy(dire, temp + 1);
X    cp1 = strrchr(dire, '`5D');       /* change trailing directory mark */
X    if (cp1 != NULL)
X    `7B
X        *cp1++ = '/';
X        *cp1 = '\0';                /* and terminate string (no file name) *
V/
X    `7D
X    strcpy(temp,strrchr(line,'`5D')+1); /* Now get the file name */
X    if((cp1=strindex(temp,".DIR;1"))!=0)
X    `7B
X        *cp1++ = '/';                          /* Terminate directory name *
V/
X        *cp1 = '\0';
X        strcat(dire,temp);
X        *fname = '\0';
X    `7D
X    else
X    `7B
X        strcpy(fname,temp);
X        *strchr(fname,';') = '\0';;           /* no version numbers */
X        lowercase(fname);                     /* map to lowercase */
X    `7D
X
X    /* Now rewrite the directory name  */
X
X   lowercase(dire);
X
X    for (cp1 = dire + 1; *cp1; ++cp1)         /* Change '.' to '/'  */
X        if(*cp1 == '.')
X            *cp1 = '/';
X    if((len=strlen(fname))==0)
X        return(ISDIRE);
X    else
X        if(fname`5B--len`5D == '.')
X           if (dot == 0)
X                fname`5Blen`5D = 0; /* No trailing dots  */
X        return(ISFILE);
X`7D
X/* initsearch - parse input file name */
X/* To start looking for file names to satisfy the requested input,
X* use the sys$parse routine to create a wild-card name block. When
X* it returns, we can then use the resultant FAB and NAM blocks on
X* successive calls to sys$search() until there are no more files
X* that match.
X*/
X
Xint initsearch(string)
Xchar string`5B`5D;
X`7B
Xint status;
Xchar *strindex();
X
X    if(strindex(string,"::")!=NULL)
X    `7B
X        printf("tar: DECnet file access is not supported.\n");
X        return(-1);
X    `7D
X    fblock = cc$rms_fab;
X    nblock = cc$rms_nam;
X    fblock.fab$l_dna = default_name;
X    fblock.fab$b_dns = strlen(default_name);
X    fblock.fab$l_fna = string;
X    fblock.fab$b_fns = strlen(string);
X    fblock.fab$l_nam = &nblock;
X    nblock.nam$l_esa = searchname;
X    nblock.nam$b_ess = sizeof(searchname);
X#ifdef debug
X    printf("searching on: %s\n",string);
X#endif
X    status = sys$parse(&fblock);
X    if(status != RMS$_NORMAL)
X    `7B
X        if(status == RMS$_DNF)
X            printf("tar: directory not found %s\n",searchname);
X        else
X            printf("tar: error in SYS$PARSE.\n");
X        return (-1);
X    `7D
X    searchname`5Bnblock.nam$b_esl`5D = 0;   /* Terminate the string  */
X
X    /* Now reset for searching, pointing to the parsed name block */
X
X    fblock = cc$rms_fab;
X    fblock.fab$l_nam = &nblock;
X    return(nblock.nam$b_esl); /* return the length of the string  */
X`7D
X
X/* search - get the next file name that matches the namblock */
X/* that was set up by the sys$search() function. */
X
Xint search(buff,maxlen)
Xchar buff`5B`5D;
Xint maxlen;
X`7B
Xint status;
X
X    nblock.nam$l_rsa = buff;
X    nblock.nam$b_rss = maxlen;
X    nblock.nam$b_rsl = 0;       /* For next time around  */
X    while ((status = sys$search(&fblock)) != RMS$_NMF)
X    `7B
X        buff`5Bnblock.nam$b_rsl`5D = 0;
X        if(status == RMS$_NORMAL)
X            return(nblock.nam$b_rsl);
X        else
X        `7B
X            if (status == RMS$_PRV)
X                printf("tar: no privilege to access %s\n",buff);
X            else if (status == RMS$_FNF)
X                printf("tar: file not found %s\n",buff);
X            else
X            `7B
X                printf("tar: error in SYS$SEARCH for %s\n", buff);
X                return (0);
X            `7D
X        `7D
X    `7D
X    return (0);
X`7D
X/* fill_header - fill the fields of the header */
X/* enter with the file name, if the file name is empty, */
X/* then this is a trailer, and we should fill it with zeroes. */
X
Xint fill_header(name)
Xchar name`5B`5D;
X`7B
Xint i,chksum;
Xint zero = 0, hdrsize = RECSIZE;
Xchar *ptr,tem`5B15`5D;
X
X/* Fill the header with zeroes */
X
X    LIB$MOVC5(&zero, &zero, &zero, &hdrsize, &header); `20
X    if(strlen(name)!=0)         /* only fill if there is a file */
X    `7B
X        sprintf(header.title,"%s",name);        /* write file name */
X        sprintf(header.protection,"%6o ",mode); /* all written with */
X        sprintf(header.uid,"%6o ",uid);         /* a trailing space */
X        sprintf(header.gid,"%6o ",gid);
X        sprintf(tem,"%11o ",bytecount);         /* except the count */
X        strncpy(header.count,tem,12);           /* and the time, which */
X        sprintf(tem,"%11o ",vmstime);           /* except the count */
X        strncpy(header.time,tem,12);            /* have no null */
X        strncpy(header.chksum,"        ",8);    /* all blanks for sum*/
X
X/* I know that the next two are already zero, but do them */
X
X        header.linkcount = 0;                   /* always zero */
X        sprintf(header.linkname,"%s","");       /* always blank */
X        for(chksum=0, ptr = &header;ptr < &header.linkcount;ptr++)
X                 chksum += *ptr;                /* make the checksum */
X        sprintf(header.chksum,"%6o",chksum);
X    `7D
X    return(0);
X`7D
X
X/* strindex - search for string2 in string1, return address pointer */
X
Xchar *strindex(string1,string2)
Xchar *string1,*string2;
X`7B
Xchar *c1, *c2, *cp;
X    for(c1 = string1; *c1 !=0; c1++)
X    `7B
X        cp = c1;        /* save the start address */
X        for(c2=string2; *c2 !=0 && *c1 == *c2; c1++,c2++);
X           if(*c2 == 0)
X                return(cp);
X    `7D
X    return(NULL);
X`7D
X
X/* lowercase - function to change a string to lower case */
X
Xint lowercase(string)
Xchar string`5B`5D;
X`7B
Xint i;
X        for(i=0;string`5Bi`5D=tolower(string`5Bi`5D);i++);
X        return (--i);           /* return string length */
X`7D
X
X/* cleanup_dire - routine to get rid of rooted directory problems */
X/* and any others that turn up */
X
Xint cleanup_dire(string)
Xchar string`5B`5D;
X`7B
Xchar *ptr;
X        if((ptr=strindex(string,"`5D`5B")) != NULL)
X        `7B       /* Just collapse around the string */
X          strcpy(ptr,ptr+2);
X          return(1);
X        `7D
X        if((ptr=strindex(string,"`5B000000.")) != NULL)
X        `7B         /* remove "000000." */
X            strcpy(ptr + 1, ptr + 8);
X            return(1);
X        `7D
X        return(0);
X`7D
X
X/* Syntax error exit */
X
Xusage()
X`7B
X    printf("usage: tar x`7Cc`7Ct`5Bvbdz`5D`5Bf tarfile`5D `5Bfile `5Bfile...
V`5D`5D\n");
X    exit(1);
X`7D
$ CALL UNPACK VMSTAR.C;69 1685880388
$ create 'f'
X1 VMSTAR
X
X VMSTAR  is  a  TAR  reader/writer  for  VMS.  It  can  read  archives
X ("tarfiles") created by the Un*x command "tar" (VMSTAR has a  similar
X syntax) and also create such archives so that they can be read  later
X by a Un*x system. Tarfiles can be VMS disk files or directly on tape.
X Default tarfile is  whatever  the  logical  name  "$TAPE"  points  to
X (either device or file name) unless specified by  the  "f"  modifier.
X
X Tapes read/written by VMSTAR must be mounted /FOREIGN/RECORD=512/BLOCK=1024
V0
X
X Usage:    $ VMSTAR `5Boptions`5D `5Bfilespec `5Bfilespec...`5D`5D
X2 Options
X Options are single letters grouped together (no space). There must be
X at  list one of "x" (extract), "t" (type) or "c" (create) to indicate
X what  kind  of  action  VMSTAR  should have. Other single letters are
X modifiers.  The group of options may optionally include a leading "-"
X (dash).
X3 x (extract)
X This option instructs VMSTAR that files are to be extracted from  the
X tar archive and copied as VMS  files.  One  or  more  Un*x-like  file
X specifications including VMS wildcard characters may  be  present  on
X the command line. Only files matching one of  the  patterns  will  be
X actually   extracted.   Default   is   to    extract    all    files.
X
X VMSTAR will attempt to re-create the directory hierarchy  present  in
X the tar archive. If files are named "./foo/bar..." in the tar archive
X (common case) the VMS directory tree  will  be  created  relative  to
X current default.  All  illegal  characters  in  file  names  will  be
X replaced by "_" (underscore).
X3 t (type)
X This option produces a listing of the contents of  the  tar  archive,
X including file name (Un*x style), size (in  bytes)  and  modification
X date.
X3 c (create)
X This  option  directs  VMSTAR to create a tar archive and to copy VMS
X files  as directed by file specification(s) into this archive in such
X a  way  it  can  be  further  extracted  on  an  Un*x  machine.  File
X specifications  (space separated, no commas) can include standard VMS
X wildcards in file and directory name.
X
X If a relative specification  is  given  (no  directory  or  directory
X beginning with "`5B." and no device name), the file name given  is  the
X tar  archive  will  be  relative  too  (not   beginning   with   "/")
X3 v (verbose)
X Adding this modifier to a "x" or "c"  option  will  cause  VMSTAR  to
X display file names and sizes stored when archiving VMS files and  VMS
X directory and file names created when  extracting  from  an  archive.
X3 w (wait)
X VMSTAR asks for a  confirmation  before  each  file  is  archived  or
X extracted when this modifier is specified.
X3 b (binary)
X This modifier is meaningful only when VMSTAR extracts  files  from  a
X tar archive. If it is specified, VMSTAR  will  create  VMS  files  in
X fixed format, record size = 512 bytes and no record  attributes.  Use
X the "b" modifier when you extract  compressed  files,  tar  archives,
X executable VMS images or any kind of files  other  than  ASCII  files
X with line-feed terminated lines.
X
X When  this  modifier  is  *NOT*  present,  VMS  files  are created as
X stream-LF    files    with    implied    (CR)    record   attributes.
X3 z (automatic mode)
X When this modifier is  present  in  a  extract  operation  (it's  not
X meaningful  for  any  other  operation),  VMSTAR  will   attempt   to
X automatically determine if the file present in  the  tar  archive  is
X text or binary, and extract it  accordingly  (see  'b'  option).  The
X choice is based on very  simple  rules  such  as  the  proportion  of
X characters in the range 0-31 except CR, LF, FF  and  TAB  ;  and  the
X proportion of the characters above 127 in  the  first  block  of  the
X file.
X3 d (dots)
X This modifier is only meaningful for the "c" (create) option. When it
X is specified, VMSTAR will keep the trailing dot in file names without
X extension in the archive.
X3 f tarfile
X This  modifier allows to specify the tarfile (either VMS file name of
X VMS  device  name) read or written by VMSTAR. Default is whatever the
X logical    name   $TAPE   points   to,   either   file   or   device.
X2 Filespec
X One or more file specifications may be present on the command line as
X last arguments. They must be separated by spaces, *NOT*  commas  like
X in most VMS commands. They may include VMS  wildcard  characters  "*"
X and "%". Case is never significant.
X
X Upon create, the file  specifications  must  be  valid  VMS  file  or
X directory names. If only a directory name  is  specified,  "*.*;"  is
X automatically appended. The resultant specifications are the names of
X the VMS file names that will be  archived  in  the  tarfile.  Use  of
X device names and absolute paths ("`5BFOO.BAR`5D") is strongly discouraged
X unless  absolute  archives  are  to  be  created  (see  "c"  option).
X
X Upon  extract,  the  file  specifications  must be Un*x file names or
X patterns  for Un*x file names using VMS wildcard characters. Files in
X the  tarfile  having names matching one of the specifications will be
X extracted.  If  no  specification  is given, all files are extracted.
X Matching  is  done using pure wildcarded strings matching algorithms,
X i.e. "/" is a normal character.
X2 Examples
X $ MOUNT/FOREIGN/RECORD=512/BLOCK=10240
X $ VMSTAR TVF MUA0:
X
X Will give a full listing of the tar tape loaded in MUA0:
X
X $ SET DEF `5BFOO_ROOT`5D
X $ TAR XVF MUA0:
X
X Will  extract  files  from the tar tape in `5BFOO_ROOT...`5D provided the
X files in the tar archive do not begin with "/".
X
X $ DEFINE $TAPE MUA0:
X $ TAR XV *SOURCES/*.C
X
X Will  only  extract  C source files in the subdirectory "sources" (or
X "Sources"  or  "SOURCES",  case is not significant) from the tar tape
X mounted in MUA0:
X
X $ TAR XVF EMACS.TAR
X
X Will  extract  files in tar archive file EMACS.TAR which may has been
X transmitted from a Un*x system by network.
X
X $ TAR XVBF EMACS.TAR ./EXECUTABLE/EMACS.EXE
X
X Will  only  extract  the  specified file and create it as a VMS fixed
X format,   record  size  =  512  bytes,  no  record  attributes  file.
X
X $ TAR CWVF MUA0: `5B.GNUCC...`5D
X
X Will archive the contents of the whole  "`5B.GNUCC...`5D"  subtree  in  a
X tape tar archive on MUA0:. VMSTAR will prompt user  before  archiving
X each file.
X
X $ DEFINE $TAPE TARFILE.TAR
X $ TAR CV *.DOC `5B.GNUCC...`5D
X
X Will create a tar archive file TARFILE.TAR and write all files with
X type ".DOC" and all the "`5B.GNUCC...`5D" subtree in it.
X2 Restrictions
X Because of diffrences in the Un*x and VMS filesystems, some files may
X fail to be correctly transferred to/from the  tarfile.  This  can  be
X caused by :
X
X - restrictions in VMS file naming scheme: extra dots  in  file  names
X will  be  mapped  to  underscores,  dummy  directory  names  will  be
X generated if archive contains more than 8 levels  of  subdirectories,
X links are extracted as empty files containing only  a  short  message
X "this file is only a link  to...",  all  file  names  are  mapped  to
X uppercase etc.
X
X - restrictions of the Un*x filesystem: tar will only get  the  latest
X version of a VMS file to enter it into the archive, no trace  of  the
X orginal file device name is kept in the archive.
X
X - VMS strong file typing: VMSTAR can only  safely  tranfer  back  and
X forth VMS "text" files (rfm=vfc or  stream_lf  with  rat=cr)  or  VMS
X fixed size record, 512 bytes/record, rat=none files (e.g. .EXE  image
X files). VMSTAR will skip other file types  (this  includes  .OBJ  and
X library files, they *can't* be archived).
X
X Other restrictions:
X
X RMS file attributes are lost in the archive process, text  files  are
X archived as <record><LF><record><LF>, fixed files are archived as is.
X
X VMSTAR will always restore files relative to your current RMS default
X if names in tarfile do not begin by `60/'. If  file  names  in  tarfile
X begin with a `60/' (bad practice), an attempt will be made  to  restore
X files to the absolute path. There is currently no way to  explicitely
X specify the target VMS directory where  files  should  be  extracted.
X
X No  attempt has been made to handle search list as RMS defaults (e.g.
X SYSTEM account). Be very careful about that.
$ CALL UNPACK VMSTAR.HLP;10 1518046826
$ create 'f'
X$! BUILD.COM - Compiles and link VMSTAR
X$
X$ CC VMSTAR
X$ LINK VMSTAR,SYS$INPUT/OPT
XSYS$SHARE:VAXCRTL.EXE/SHARE
X
$ CALL UNPACK BUILD.COM;1 1547639552
$ v=f$verify(v)
$ EXIT
