ARC for System V R2 (1 of 3)

aeusemrs at csun.UUCP aeusemrs at csun.UUCP
Tue Feb 3 12:10:36 AEST 1987


Please read the README file below.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	arc.c
#	arc.h
#	arcadd.c
#	arccode.c
#	arccvt.c
#	arcdel.c
#	arcdir.c
#	arcdos.c
#	arcext.c
#	arcio.c
#	arclst.c
#	arcm.h
# This archive created: Mon Feb  2 18:01:48 1987
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
ARC  -  For Unix System V

This version is based upon a version that was posted to net.sources for
BSD.  This program DOES NOT suffer from core dumps!  After looking at
the code for BSD I understand why there were core dumps in the first
place.  The BSD version is based upon IBM PC ARC 5.12.  I tried to
maintain backwards compatability with the original PC ARC, but, the
BSD version I got, only made a half-hearted attempt at it, commenting
out entire sections, and deleting sections of the MSDOS version.  After
looking at the BSD version, I decided in favor of NOT attemping to
remain backwards compatable with it.  Maybe some can clean up the code
and make it work under both systems, and send diffs, or the program back
to me (Mike Stump) at:

uucp: {sdcrdcf, ihnp4, hplabs, ttidca, psivax, csustan}!csun!aeusemrs
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#    Makefile for ARC
CFLAGS = -g
#  CFLAGS = -O

OBJS = arc.o arcadd.o arccode.o arccvt.o arcdel.o arcdir.o \
arcdos.o arcext.o arcio.o arclst.o arclzw.o arcmatch.o arcpack.o \
arcsq.o arcsvc.o arctst.o arcunp.o arcusq.o arcmisc.o


SRCS = arc.c arcadd.c arccode.c arccvt.c arcdel.c arcdir.c \
arcdos.c arcext.c arcio.c arclst.c arclzw.c arcmatch.c arcpack.c \
arcs.c arcsq.c arcsvc.c arctst.c arcunp.c arcusq.c arcmisc.c

arc:            ${OBJS}
	cc  ${CFLAGS} -o arc ${OBJS}
${OBJS}:        arc.h
arc.h:          arcm.h arcs.h
	touch arc.h
SHAR_EOF
fi # end of overwriting check
if test -f 'arc.c'
then
	echo shar: will not over-write existing file "'arc.c'"
else
cat << \SHAR_EOF > 'arc.c'
/*  ARC - Archive utility

System V Version 1.0 based upon:
    Version 5.12, created on 02/05/86 at 22:22:01

Port to System V, by Mike Stump
Please send all bug fixes, comments, etc...  to:
uucp: {sdcrdcf, ihnp4, hplabs, ttidca, psivax, csustan}!csun!aeusemrs

Machines known to work on:
    3B5 System V, Version 2 Release 2.0

(C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This program is a general archive utility, and is used to maintain
         an archive of files.  An "archive" is a single file that combines
         many files, reducing storage space and allowing multiple files to
         be handled as one.

    Instructions:
         Run this program with no arguments for complete instructions.

    Programming notes:
         ARC Version 2 differs from version 1 in that archive entries
         are automatically compressed when they are added to the archive,
         making a separate compression step unecessary.  The nature of the
         compression is indicated by the header version number placed in
         each archive entry, as follows:

         1 = Old style, no compression
         2 = New style, no compression
         3 = Compression of repeated characters only
         4 = Compression of repeated characters plus Huffman SQueezing
         5 = Lempel-Zev packing of repeated strings (old style)
         6 = Lempel-Zev packing of repeated strings (new style)
         7 = Lempel-Zev Williams packing with improved has function
         8 = Dynamic Lempel-Zev packing with adaptive reset

         Type 5, Lempel-Zev packing, was added as of version 4.0

         Type 6 is Lempel-Zev packing where runs of repeated characters
         have been collapsed, and was added as of version 4.1

         Type 7 is a variation of Lempel-Zev using a different hash
         function which yields speed improvements of 20-25%, and was
         added as of version 4.6

         Type 8 is a different implementation of Lempel-Zev, using a
         variable code size and an adaptive block reset, and was added
         as of version 5.0

         Verion 4.3 introduced a temporary file for holding the result
         of the first crunch pass, thus speeding up crunching.

         Version 4.4 introduced the ARCTEMP environment string, so that
         the temporary crunch file may be placed on a ramdisk.  Also
         added was the distinction bewteen Adding a file in all cases,
         and Updating a file only if the disk file is newer than the
         corresponding archive entry.

         The compression method to use is determined when the file is
         added, based on whichever method yields the smallest result.

*/
#include "arc.h"

main(num,arg)                          /* system entry point */
int num;                               /* number of arguments */
char **arg;                            /* pointers to arguments */
{
    char opt = 0;                      /* selected action */
    char *a;                           /* option pointer */
    char *makefnam();                  /* filename fixup routine */
    char *upper();                     /* case conversion routine */
    char *index();                     /* string index utility */
    char *envfind();                   /* environment searcher */
    INT n;                             /* argument index */
    char *arctemp2;
    long getpid();

    warn = 1;
    note = 1;
    if(num<3)
    {    printf("arc - Archive Utility, 5.12\n");
         printf("Usage: arc {amufdxeplvtc}[bswn][g<password>]");
         printf(" <archive> [<filename> . . .]\n");
         printf("Where:   a   = add files to archive\n");
         printf("         m   = move files to archive\n");
         printf("         u   = update files in archive\n");
         printf("         f   = freshen files in archive\n");
         printf("         d   = delete files from archive\n");
         printf("         x,e = extract files from archive\n");
         printf("         p   = copy files from archive to");
         printf(" standard output\n");
         printf("         l   = list files in archive\n");
         printf("         v   = verbose listing of files in archive\n");
         printf("         t   = test archive integrity\n");
         printf("         c   = convert entry to new packing method\n");
         printf("         b   = retain backup copy of archive\n");
         printf("         s   = suppress compression (store only)\n");
         printf("         w   = suppress warning messages\n");
         printf("         n   = suppress notes and comments\n");
         printf("         g   = Encrypt/decrypt archive entry\n\n");
         return 1;
    }

    /* see where temp files go */
    /* use process id to "enhance uniquity" of temp filenames */
    /* (avoids multi-user or background foolishness) */

    if(!(arctemp2 = envfind("ARCTEMP")))
         arctemp2 = envfind("TEMP");
    if (arctemp2) sprintf(arctemp,"%s.Arc%ld",arctemp2,getpid());
    else sprintf(arctemp,".Arc%ld",getpid());

    /* avoid any case problems with command options */
         upper(arg[1]);                /* convert it to uppercase */

    /* create archive names, supplying defaults */

    makefnam(arg[2],".arc",arcname);
    sprintf(newname,"%s.arc",arctemp);
    makefnam(".bak",arcname,bakname);

    /* now scan the command and see what we are to do */

    for(a=arg[1]; *a; a++)             /* scan the option flags */
    {    if(index("AMUFDXEPLVTC",*a)) /* if a known command */
         {    if(opt)                  /* do we have one yet? */
                   abort("Cannot mix %c and %c",opt,*a);
              opt = *a;                /* else remember it */
         }

         else if(*a=='B')              /* retain backup copy */
              keepbak = 1;

         else if(*a=='W')              /* suppress warnings */
              warn = 0;

         else if(*a=='N')              /* suppress notes and comments */
              note = 0;

         else if(*a=='G')              /* garble */
         {    password = a+1;
              while(*a)
                   a++;
              a--;
         }

         else if(*a=='S')              /* storage kludge */
              nocomp = 1;

         else if (*a=='-')   /* UNIX option marker */
              ;

         else abort("%c is an unknown command",*a);
    }

    if(!opt)
         abort("I have nothing to do!");

    /* act on whatever action command was given */

    switch(opt)                        /* action depends on command */
    {
    case 'A':                          /* Add */
    case 'M':                          /* Move */
    case 'U':                          /* Update */
    case 'F':                          /* Freshen */
         addarc(num-3,&arg[3],(opt=='M'),(opt=='U'),(opt=='F'));
         break;

    case 'D':                          /* Delete */
         delarc(num-3,&arg[3]);
         break;

    case 'E':                          /* Extract */
    case 'X':                          /* eXtract */
    case 'P':                          /* Print */
         extarc(num-3,&arg[3],(opt=='P'));
         break;

    case 'V':                          /* Verbose list */
         bose = 1;
    case 'L':                          /* List */
         lstarc(num-3,&arg[3]);
         break;

    case 'T':                          /* Test */
         tstarc();
         break;

    case 'C':                          /* Convert */
         cvtarc(num-3,&arg[3]);
         break;

    default:
         abort("I don't know how to do %c yet!",opt);
    }

    return nerrs;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arc.h'
then
	echo shar: will not over-write existing file "'arc.h'"
else
cat << \SHAR_EOF > 'arc.h'
/*
System V Version 1.0.
*/
#include <stdio.h>

#include <ctype.h>	/* for isupper etc.                  */
#define EXTERN
#define INT short
#define envfind getenv
#define index strchr
#define rindex strrchr

#include "arcm.h"

/*  ARC - Archive utility - ARC Header

    Version 2.14, created on 02/03/86 at 22:48:29

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description: 
         This is the header file for the ARC archive utility.  It defines
         global parameters and the references to the external data.

 */

#include "arcs.h"

EXTERN INT keepbak;             /* true if saving the old archive */
EXTERN INT warn;                /* true to print warnings */
EXTERN INT note;                /* true to print comments */
EXTERN INT bose;                /* true to be verbose */
EXTERN INT nocomp;              /* true to suppress compression */
EXTERN char arctemp[STRLEN];    /* arc temp file prefix */
EXTERN char *password;          /* encryption password pointer */
EXTERN INT nerrs;               /* number of errors encountered */

EXTERN char hdrver;             /* header version */

EXTERN FILE *arc;               /* the old archive */
EXTERN FILE *new;               /* the new archive */

EXTERN char arcname[STRLEN];    /* storage for archive name */
EXTERN char bakname[STRLEN];    /* storage for backup copy name */
EXTERN char newname[STRLEN];    /* storage for new archive name */
EXTERN unsigned INT arcdate;    /* archive date stamp */
EXTERN unsigned INT arctime;    /* archive time stamp */
SHAR_EOF
fi # end of overwriting check
if test -f 'arcadd.c'
then
	echo shar: will not over-write existing file "'arcadd.c'"
else
cat << \SHAR_EOF > 'arcadd.c'
/*  ARC - Archive utility - ARCADD

System V Version 1.0 based upon:
    Version 3.39, created on 02/05/86 at 22:21:53

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to add files to an archive.
*/
#include "arc.h"

INT addarc(num,arg,move,update,fresh)  /* add files to archive */
INT num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
INT move;                              /* true if moving file */
INT update;                            /* true if updating */
INT fresh;                             /* true if freshening */
{
    char *buf;                         /* pathname buffer */
    char *i, *rindex();                /* string indexing junk */
    INT n;                             /* indices */
    struct heads hdr;                  /* file header data storage */
    INT addfile();

    openarc(1); /* open archive for changes */

    for (n=0; n<num; ++n) {
        if (i=rindex(buf=arg[n], '/')) buf=i+1;
        addfile(arg[n],buf,update,fresh);
    }

    /* now we must copy over all files that follow our additions */

    while (readhdr(&hdr,arc))           /* while more entries to copy */
    {    writehdr(&hdr,new);
         filecopy(arc,new,hdr.size);
    }
    hdrver = 0;                        /* archive EOF type */
    writehdr(&hdr,new);                /* write out our end marker */
    closearc(1);                       /* close archive after changes */

    if (move) for (n=0; n<num; ++n)    /* if this was a move */
        if (unlink(arg[n]) && warn) {
            printf("Cannot unsave %s\n",arg[n]);
            ++nerrs;
         }
}

static INT addfile(path,name,update,fresh) /* add named file to archive */
char *path;                                /* path name of file to add */
char *name;                                /* name of file to add */
INT update;                                /* true if updating */
INT fresh;                                 /* true if freshening */
{
    struct heads nhdr;                 /* data regarding the new file */
    struct heads ohdr;                 /* data regarding an old file */
    FILE *f, *fopen();                 /* file to add, opener */
    long starts, ftell();              /* file locations */
    INT c;                             /* one char of file */
    INT upd = 0;                       /* true if replacing an entry */

    if (!(f=fopen(path,"r"))) {
        if (warn)
         {    printf("Cannot read file: %s\n",path);
              nerrs++;
         }
    }

    strcpy(nhdr.name,name);            /* save name */
    nhdr.size = 0;                     /* clear out size storage */
    nhdr.crc = 0;                      /* clear out CRC check storage */
    getstamp(f,&nhdr.date,&nhdr.time);

    /* position archive to spot for new file */

    if (arc)                           /* if adding to existing archive */
    {    starts = ftell(arc);          /* where are we? */
         while (readhdr(&ohdr,arc))    /* while more files to check */
         {    if (!strcmp(ohdr.name,nhdr.name))
              {    upd = 1;            /* replace existing entry */
                   if (update || fresh) /* if updating or freshening */
                   {    if (nhdr.date<ohdr.date
                        || (nhdr.date==ohdr.date && nhdr.time<=ohdr.time))
                        {    fseek(arc,starts,0);
                             fclose(f);
                             return;   /* skip if not newer */
                        }
                   }
              }

              if (strcmp(ohdr.name,nhdr.name)>=0)
                   break;              /* found our spot */

              writehdr(&ohdr,new);     /* entry preceeds update; keep it */
              filecopy(arc,new,ohdr.size);
              starts = ftell(arc);     /* now where are we? */
         }

         if (upd)                      /* if an update */
         {    if (note)
                 { printf("Updating file: %-12s  ",name); fflush(stdout);}
              fseek(arc,ohdr.size,1);
         }
         else if (fresh)               /* else if freshening */
         {    fseek(arc,starts,0);     /* then do not add files */
              fclose(f);
              return;
         }
         else                          /* else adding a new file */
         {    if (note)
                 { printf("Adding file:   %-12s  ",name); fflush(stdout);}
              fseek(arc,starts,0);     /* reset for next time */
         }
    }

    else                               /* no existing archive */
    {    if (fresh)                    /* cannot freshen nothing */
         {    fclose(f);
              return;
         }
         else if (note)                 /* else adding a file */
            { printf("Adding file:   %-12s  ",name); fflush(stdout);}
    }

    starts = ftell(new);               /* note where header goes */
    hdrver = ARCVER;                   /* anything but end marker */
    writehdr(&nhdr,new);               /* write out header skeleton */
    pack(f,new,&nhdr);                 /* pack file into archive */
    fseek(new,starts,0);               /* move back to header skeleton */
    writehdr(&nhdr,new);               /* write out real header */
    fseek(new,nhdr.size,1);            /* skip over data to next header */
    fclose(f);                         /* all done with the file */
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arccode.c'
then
	echo shar: will not over-write existing file "'arccode.c'"
else
cat << \SHAR_EOF > 'arccode.c'
/*  ARC - Archive utility - ARCCODE

System V Version 1.0 based upon:
    Version 1.02, created on 01/20/86 at 13:33:35

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to encrypt and decrypt
         data in an archive.  The encryption method is nothing fancy,
         being just a routine XOR, but it is used on the packed data,
         and uses a variable length key.  The end result is something
         that is in theory crackable, but I'd hate to try it.  It should
         be more than sufficient for casual use.
*/
#include "arc.h"

static char *p;                        /* password pointer */

INT setcode()                          /* get set for encoding/decoding */
{
    p = password;                      /* reset password pointer */
}

INT code(c)                            /* encode some character */
INT c;                                 /* character to encode */
{
    if(p)                              /* if password is in use */
    {    if(!*p)                       /* if we reached the end */
              p = password;            /* then wrap back to the start */
         return c^*p++;                /* very simple here */
    }
    else return c;                     /* else no encryption */
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arccvt.c'
then
	echo shar: will not over-write existing file "'arccvt.c'"
else
cat << \SHAR_EOF > 'arccvt.c'
/*  ARC - Archive utility - ARCCVT

System V Version 1.0 based upon:
    Version 1.16, created on 02/03/86 at 22:53:02

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to convert archives to use
         newer file storage methods.
*/
#include "arc.h"

static char tempname[STRLEN];          /* temp file name */

INT cvtarc(num,arg)                    /* convert archive */
INT num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
{
    struct heads hdr;                  /* file header */
    INT cvt;                           /* true to convert current file */
    INT did[MAXARG];                   /* true when argument was used */
    INT n;                             /* index */
    char *makefnam();                  /* filename fixer */
    FILE *fopen();                     /* file opener */
    INT cvtfile();

    if(arctemp)                   /* use temp area if specified */
         sprintf(tempname,"%s.cvt",arctemp);
    else makefnam("$ARCTEMP.cvt",arcname,tempname);

    openarc(1);                        /* open archive for changes */

    for(n=0; n<num; n++)               /* for each argument */
         did[n] = 0;                   /* reset usage flag */
    rempath(num,arg);                  /* strip off paths */

    if(num)                            /* if files were named */
    {    while(readhdr(&hdr,arc))      /* while more files to check */
         {    cvt = 0;                 /* reset convert flag */
              for(n=0; n<num; n++)     /* for each template given */
              {    if(match(hdr.name,arg[n]))
                   {    cvt = 1;       /* turn on convert flag */
                        did[n] = 1;    /* turn on usage flag */
                        break;         /* stop looking */
                   }
              }

              if(cvt)                  /* if converting this one */
                   cvtfile(&hdr);      /* then do it */
              else                     /* else just copy it */
              {    writehdr(&hdr,new);
                   filecopy(arc,new,hdr.size);
              }
         }
    }

    else while(readhdr(&hdr,arc))      /* else convert all files */
         cvtfile(&hdr);

    hdrver = 0;                        /* archive EOF type */
    writehdr(&hdr,new);                /* write out our end marker */
    closearc(1);                       /* close archive after changes */

    if(note)
    {    for(n=0; n<num; n++)          /* report unused args */
         {    if(!did[n])
              {    printf("File not found: %s\n",arg[n]);
                   nerrs++;
              }
         }
    }
}

static INT cvtfile(hdr)                /* convert a file */
struct heads *hdr;                     /* pointer to header data */
{
    long starts, ftell();              /* where the file goes */
    FILE *tmp, *fopen();               /* temporary file */

    if(!(tmp=fopen(tempname,"w+")))
         abort("Unable to create temporary file %s",tempname);

    if(note)
     { printf("Converting file: %-12s   reading, ",hdr->name); fflush(stdout);}

    unpack(arc,tmp,hdr);               /* unpack the entry */
    fseek(tmp,0L,0);                   /* reset temp for reading */
    starts = ftell(new);               /* note where header goes */
    hdrver = ARCVER;                   /* anything but end marker */
    writehdr(hdr,new);                 /* write out header skeleton */
    pack(tmp,new,hdr);                 /* pack file into archive */
    fseek(new,starts,0);               /* move back to header skeleton */
    writehdr(hdr,new);                 /* write out real header */
    fseek(new,hdr->size,1);            /* skip over data to next header */
    fclose(tmp);                       /* all done with the file */
    if(unlink(tempname) && warn)
    {    printf("Cannot unsave %s\n",tempname);
         nerrs++;
    }
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcdel.c'
then
	echo shar: will not over-write existing file "'arcdel.c'"
else
cat << \SHAR_EOF > 'arcdel.c'
/*  ARC - Archive utility - ARCDEL

System V Version 1.0 based upon:
    Version 2.09, created on 02/03/86 at 22:53:27

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to delete entries
         in an archive.
*/
#include "arc.h"

INT delarc(num,arg)                    /* remove files from archive */
INT num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
{
    struct heads hdr;                  /* header data */
    INT del;                           /* true to delete a file */
    INT did[MAXARG];                   /* true when argument used */
    INT n;                             /* index */

    if(!num)                           /* she must specify which */
         abort("You must tell me which files to delete!");

    for(n=0; n<num; n++)               /* for each argument */
         did[n] = 0;                   /* reset usage flag */
    rempath(num,arg);                  /* strip off paths */

    openarc(1);                        /* open archive for changes */

    while(readhdr(&hdr,arc))           /* while more entries in archive */
    {    del = 0;                      /* reset delete flag */
         for(n=0; n<num; n++)          /* for each template given */
         {    if(match(hdr.name,arg[n]))
              {    del = 1;            /* turn on delete flag */
                   did[n] = 1;         /* turn on usage flag */
                   break;              /* stop looking */
              }
         }

         if(del)                       /* skip over unwanted files */
         {    fseek(arc,hdr.size,1);
              if(note)
                   printf("Deleting file: %s\n",hdr.name);
         }
         else                          /* else copy over file data */
         {    writehdr(&hdr,new);      /* write out header and file */
              filecopy(arc,new,hdr.size);
         }
    }

    hdrver = 0;                        /* special end of archive type */
    writehdr(&hdr,new);                /* write out archive end marker */
    closearc(1);                       /* close archive after changes */

    if(note)
    {    for(n=0; n<num; n++)          /* report unused arguments */
         {    if(!did[n])
              {    printf("File not found: %s\n",arg[n]);
                   nerrs++;
              }
         }
    }
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcdir.c'
then
	echo shar: will not over-write existing file "'arcdir.c'"
else
cat << \SHAR_EOF > 'arcdir.c'
/*  ARC - Archive utility - ARCDIR

System V Version 1.0 based upon:
    Version ?.??, created on ??/??/?? at ??:??:??

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contians ...
*/
#include "arc.h"

#include <sys/types.h>
#include <sys/dir.h>

char *pattern;			      /* global so that fmatch can use them */
INT filemode;

char *dir(filename,mode,NameList)      /* get files, one by one */
char *filename;                        /* template, or NULL */
INT mode;                              /* search mode bits */
char *(*NameList[]);
{
    return NULL;
}


#define ASTERISK '*'		/* The '*' metacharacter */
#define QUESTION '?'		/* The '?' metacharacter */
#define LEFT_BRACKET '['	/* The '[' metacharacter */
#define RIGHT_BRACKET ']'	/* The ']' metacharacter */

#define IS_OCTAL(ch) (ch >= '0' && ch <= '7')

typedef INT BOOLEAN;
#define VOID short
#define TRUE 1
#define FALSE 0
#define EOS '\000'

static BOOLEAN do_list ();
static char nextch ();
static VOID list_parse ();


/*
 *  FUNCTION
 *
 *	match   test string for wildcard match
 *
 *  SYNOPSIS
 *
 *	BOOLEAN match (string, pattern)
 *	register char *string;
 *	register char *pattern;
 *
 *  DESCRIPTION
 *
 *	Test string for match using pattern.  The pattern may
 *	contain the normal shell metacharacters for pattern
 *	matching.  The '*' character matches any string,
 *	including the null string.  The '?' character matches
 *	any single character.  A list of characters enclosed
 *	in '[' and ']' matches any character in the list.
 *	If the first character following the beginning '['
 *	is a '!' then any character not in the list is matched.
 *
 */


/*
 *  PSEUDO CODE
 *
 *	Begin match
 *	    Switch on type of pattern character
 *		Case ASTERISK:
 *		    Attempt to match asterisk
 *		    Break
 *		Case QUESTION MARK:
 *		    Attempt to match question mark
 *		    Break
 *		Case EOS:
 *		    Match is result of EOS on string test
 *		    Break
 *		Case default:
 *		    If explicit match then
 *			Match is result of submatch
 *		    Else
 *			Match is FALSE
 *		    End if
 *		    Break
 *	    End switch
 *	    Return result of match test
 *	End match
 *
 */

static BOOLEAN match (string, pattern)
register char *string;
register char *pattern;
{
    register BOOLEAN ismatch;

    ismatch = FALSE;
    switch (*pattern) {
	case ASTERISK:
	    pattern++;
	    do {
		ismatch = match (string, pattern);
	    } while (!ismatch && *string++ != EOS);
	    break;
	case QUESTION:
	    if (*string != EOS) {
		ismatch = match (++string, ++pattern);
	    }
	    break;
	case EOS:
	    if (*string == EOS) {
		ismatch = TRUE;
	    }
	    break;
	case LEFT_BRACKET:
	    if (*string != EOS) {
		ismatch = do_list (string, pattern);
	    }
	    break;
	default:
	    if (tolower(*string) == tolower(*pattern))
	    {
	    	string++;
	    	pattern++;
		ismatch = match (string, pattern);
	    } else {
		ismatch = FALSE;
	    }
	    break;
    }
    return (ismatch);
}


/*
 *  FUNCTION
 *
 *	do_list    process a list and following substring
 *
 *  SYNOPSIS
 *
 *	static BOOLEAN do_list (string, pattern)
 *	register char *string;
 *	register char *pattern;
 *
 *  DESCRIPTION
 *
 *	Called when a list is found in the pattern.  Returns
 *	TRUE if the current character matches the list and
 *	the remaining substring matches the remaining pattern.
 *
 *	Returns FALSE if either the current character fails to
 *	match the list or the list matches but the remaining
 *	substring and subpattern's don't.
 *
 *  RESTRICTIONS
 *
 *	The mechanism used to match characters in an inclusive
 *	pair (I.E. [a-d]) may not be portable to machines
 *	in which the native character set is not ASCII.
 *
 *	The rules implemented here are:
 *
 *		(1)	The backslash character may be
 *			used to quote any special character.
 *			I.E.  "\]" and "\-" anywhere in list,
 *			or "\!" at start of list.
 *
 *		(2)	The sequence \nnn becomes the character
 *			given by nnn (in octal).
 *
 *		(3)	Any non-escaped ']' marks the end of list.
 *
 *		(4)	A list beginning with the special character
 *			'!' matches any character NOT in list.
 *			The '!' character is only special if it
 *			is the first character in the list.
 *
 */


/*
 *  PSEUDO CODE
 *
 *	Begin do_list
 *	    Default result is no match
 *	    Skip over the opening left bracket
 *	    If the next pattern character is a '!' then
 *		List match gives FALSE
 *		Skip over the '!' character
 *	    Else
 *		List match gives TRUE
 *	    End if
 *	    While not at closing bracket or EOS
 *		Get lower and upper bounds
 *		If character in bounds then
 *		    Result is same as sense flag.
 *		    Skip over rest of list
 *		End if
 *	    End while
 *	    If match found then
 *		If not at end of pattern then
 *		    Call match with rest of pattern
 *		End if
 *	    End if
 *	    Return match result
 *	End do_list
 *
 */

static BOOLEAN do_list (string, pattern)
register char *string;
char *pattern;
{
    register BOOLEAN ismatch;
    register BOOLEAN if_found;
    register BOOLEAN if_not_found;
    auto char lower;
    auto char upper;

    pattern++;
    if (*pattern == '!') {
	if_found = FALSE;
	if_not_found = TRUE;
	pattern++;
    } else {
	if_found = TRUE;
	if_not_found = FALSE;
    }
    ismatch = if_not_found;
    while (*pattern != ']' && *pattern != EOS) {
	list_parse (&pattern, &lower, &upper);
	if (*string >= lower && *string <= upper) {
	    ismatch = if_found;
	    while (*pattern != ']' && *pattern != EOS) {pattern++;}
	}
    }
    if (*pattern++ != ']') {
	fprintf (stderr, "warning - character class error\n");
    } else {
	if (ismatch) {
	    ismatch = match (++string, pattern);
	}
    }
    return (ismatch);
}


/*
 *  FUNCTION
 *
 *	list_parse    parse part of list into lower and upper bounds
 *
 *  SYNOPSIS
 *
 *	static VOID list_parse (patp, lowp, highp)
 *	char **patp;
 *	char *lowp;
 *	char *highp;
 *
 *  DESCRIPTION
 *
 *	Given pointer to a pattern pointer (patp), pointer to
 *	a place to store lower bound (lowp), and pointer to a
 *	place to store upper bound (highp), parses part of
 *	the list, updating the pattern pointer in the process.
 *
 *	For list characters which are not part of a range,
 *	the lower and upper bounds are set to that character.
 *
 */

static VOID list_parse (patp, lowp, highp)
char **patp;
char *lowp;
char *highp;
{
    *lowp = nextch (patp);
    if (**patp == '-') {
	(*patp)++;
	*highp = nextch (patp);
    } else {
	*highp = *lowp;
    }
}


/*
 *  FUNCTION
 *
 *	nextch    determine next character in a pattern
 *
 *  SYNOPSIS
 *
 *	static char nextch (patp)
 *	char **patp;
 *
 *  DESCRIPTION
 *
 *	Given pointer to a pointer to a pattern, uses the pattern
 *	pointer to determine the next character in the pattern,
 *	subject to translation of backslash-char and backslash-octal
 *	sequences.
 *
 *	The character pointer is updated to point at the next pattern
 *	character to be processed.
 *
 */

static char nextch (patp)
char **patp;
{
    register char ch;
    register char chsum;
    register INT count;

    ch = *(*patp)++;
    if (ch == '\\') {
	ch = *(*patp)++;
	if (IS_OCTAL (ch)) {
	    chsum = 0;
	    for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
		chsum *= 8;
		chsum += ch - '0';
		ch = *(*patp)++;
	    }
	    (*patp)--;
	    ch = chsum;
	}
    }
    return (ch);
}

/*
 *	Filename match - here, *.* matches everything
 */

BOOLEAN fmatch (direntry)
struct direct *direntry;
{
    char *ptr,*string;

    string = direntry->d_name;

    if(!strcmp(pattern, "") || !strcmp(pattern, "*.*"))
    	return(1);
    return(match(string, pattern));
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcdos.c'
then
	echo shar: will not over-write existing file "'arcdos.c'"
else
cat << \SHAR_EOF > 'arcdos.c'
/*  ARC - Archive utility - ARCDOS

System V Version 1.0 based upon:
    Version 1.43, created on 11/09/85 at 22:24:44

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains certain DOS level routines that assist
         in doing fancy things with an archive, primarily reading and
         setting the date and time last modified.

         These are, by nature, system dependant functions.  But they are
         also, by nature, very expendable.
*/
#include "arc.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>

INT getstamp(f,date,time)              /* get a file's date/time stamp */
FILE *f;                               /* file to get stamp from */
unsigned INT *date, *time;             /* storage for the stamp */
{
    struct stat buf;
    struct tm *tmbuf;

    fstat(fileno(f),&buf);
    tmbuf=localtime(&buf.st_mtime);
    
    *date = ((tmbuf->tm_year-80)<<9) + ((tmbuf->tm_mon+1)<<5) + tmbuf->tm_mday;
    *time = (tmbuf->tm_hour<<11) + (tmbuf->tm_min<<5) + (tmbuf->tm_sec>>1);;
}

INT setstamp(f,date,time)              /* set a file's date/time stamp */
FILE *f;                               /* file to set stamp on */
unsigned INT date, time;               /* desired date, time */
{
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcext.c'
then
	echo shar: will not over-write existing file "'arcext.c'"
else
cat << \SHAR_EOF > 'arcext.c'
/*  ARC - Archive utility - ARCEXT

System V Version 1.0 based upon:
    Version 2.18, created on 02/03/86 at 22:55:19

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to extract files from
         an archive.
*/
#include "arc.h"
INT extarc(num,arg,prt)                /* extract files from archive */
INT num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
INT prt;                               /* true if printing */
{
    struct heads hdr;                  /* file header */
    INT save;                          /* true to save current file */
    INT did[MAXARG];                   /* true when argument was used */
    char *i, *rindex();                /* string index */
    char **name, *malloc();            /* name pointer list, allocator */
    INT n;                             /* index */
    INT extfile();

    name = (char **)malloc(num*sizeof(char *));  /* get storage for name pointers */

    for(n=0; n<num; n++)               /* for each argument */
    {    did[n] = 0;                   /* reset usage flag */
         if(!(i=rindex(arg[n],'/')))  /* find start of name */
              i = arg[n]-1;
         name[n] = i+1;
    }

    openarc(0);                        /* open archive for reading */

    if(num)                            /* if files were named */
    {    while(readhdr(&hdr,arc))      /* while more files to check */
         {    save = 0;                /* reset save flag */
              for(n=0; n<num; n++)     /* for each template given */
              {    if(match(hdr.name,name[n]))
                   {    save = 1;      /* turn on save flag */
                        did[n] = 1;    /* turn on usage flag */
                        break;         /* stop looking */
                   }
              }

              if(save)                 /* extract if desired, else skip */
                   extfile(&hdr,arg[n],prt);
              else fseek(arc,hdr.size,1);
         }
    }

    else while(readhdr(&hdr,arc))      /* else extract all files */
         extfile(&hdr,"",prt);

    closearc(0);                       /* close archive after reading */

    if(note)
    {    for(n=0; n<num; n++)          /* report unused args */
         {    if(!did[n])
              {    printf("File not found: %s\n",arg[n]);
                   nerrs++;
              }
         }
    }

    free(name);
}

static INT extfile(hdr,path,prt)       /* extract a file */
struct heads *hdr;                     /* pointer to header data */
char *path;                            /* pointer to path name */
INT prt;                               /* true if printing */

{
    FILE *f, *fopen();                 /* extracted file, opener */
    char buf[STRLEN];                  /* input buffer */
    char fix[STRLEN];                  /* fixed name buffer */
    char *i, *rindex();                /* string index */

    if(prt)                            /* printing is much easier */
    {    unpack(arc,stdout,hdr);       /* unpack file from archive */
         printf("\f");                 /* eject the form */
         return;                       /* see? I told you! */
    }

    strcpy(fix,path);                  /* note path name template */
    if(!(i=rindex(fix,'/')))           /* find start of name */
        i = fix-1;
    strcpy(i+1,hdr->name);             /* replace template with name */

    if(note)
         printf("Extracting file: %s\n",fix);

    if(warn)
    {    if(f=fopen(fix,"r"))        /* see if it exists */
         {    fclose(f);
              printf("WARNING: File %s already exists!",fix);
              while(1)
              {    printf("  Overwrite it (y/n)? ");
                   fgets(buf,STRLEN,stdin);
                   *buf = toupper(*buf);
                   if(*buf=='Y' || *buf=='N')
                        break;
              }
              if(*buf=='N')
              {    printf("%s not extracted.\n",fix);
                   fseek(arc,hdr->size,1);
                   return;
              }
         }
    }

    if(!(f=fopen(fix,"w")))
    {    if(warn)
         {    printf("Cannot create %s\n",fix);
              nerrs++;
         }
         fseek(arc,hdr->size,1);
         return;
    }

    /* now unpack the file */

    unpack(arc,f,hdr);                 /* unpack file from archive */
    setstamp(f,hdr->date,hdr->time);   /* set the proper date/time stamp */
    fclose(f);                         /* all done writing to file */
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcio.c'
then
	echo shar: will not over-write existing file "'arcio.c'"
else
cat << \SHAR_EOF > 'arcio.c'
/*  ARC - Archive utility - ARCIO

System V Version 1.0 based upon:
    Version 2.30, created on 02/03/86 at 22:56:00

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the file I/O routines used to manipulate
         an archive.
*/
#include "arc.h"

INT readhdr(hdr,f)                     /* read a header from an archive */
struct heads *hdr;                     /* storage for header */
FILE *f;                               /* archive to read header from */
{
    unsigned char dummy[28];
	INT i,j,k;
    char name[FNLEN];                  /* filename buffer */
    INT try = 0;                       /* retry counter */
    static INT first = 1;              /* true only on first read */

    if(!f)                             /* if archive didn't open */
         return 0;                     /* then pretend it's the end */
    if(feof(f))                        /* if no more data */
         return 0;                     /* then signal end of archive */

    if(fgetc(f)!=ARCMARK)              /* check archive validity */
    {    if(warn)
         {    printf("An entry in %s has a bad header.\n",arcname);
              nerrs++;
         }

         while(!feof(f))
         {    try++;
              if(fgetc(f)==ARCMARK)
              {    ungetc(hdrver=fgetc(f),f);
                   if(hdrver>=0 && hdrver<=ARCVER)
                        break;
              }
         }

         if(feof(f) && first)
              abort("%s is not an archive",arcname);

         if(warn)
              printf("  %d bytes skipped.\n",try);

         if(feof(f))
              return 0;
    }

    hdrver = fgetc(f);                 /* get header version */
    if(hdrver<0)
         abort("Invalid header in archive %s",arcname);
    if(hdrver==0)
         return 0;                     /* note our end of archive marker */
    if(hdrver>ARCVER)
    {    fread(name,sizeof(char),FNLEN,f);
         printf("I don't know how to handle file %s in archive %s\n",
              name,arcname);
         printf("I think you need a newer version of ARC.\n");
         exit(1);
    }

    /* amount to read depends on header type */

    if(hdrver==1)                      /* old style is shorter */
    {    fread(hdr,sizeof(struct heads)-sizeof(long),1,f);
         hdrver = 2;                   /* convert header to new format */
         hdr->length = hdr->size;      /* size is same when not packed */
    }
    else {
	fread(dummy,27,1,f);

	for(i=0;i<13;hdr->name[i]=dummy[i],i++);
	hdr->size = (long)((dummy[16]<<24) + (dummy[15]<<16) + (dummy[14]<<8)
	    + dummy[13]);
	hdr->date = (short)((dummy[18]<<8) + dummy[17]);
	hdr->time = (short)((dummy[20]<<8) + dummy[19]);
	hdr->crc  = (short)((dummy[22]<<8) + dummy[21]);
	hdr->length = (long)((dummy[26]<<24) + (dummy[25]<<16)
	    + (dummy[24]<<8) + dummy[23]);
    }

    first = 0; return 1;               /* we read something */
}

INT writehdr(hdr,f)                    /* write a header to an archive */
struct heads *hdr;                     /* header to write */
FILE *f;                               /* archive to write to */
{
    unsigned char dummy[27];

    fputc(ARCMARK,f);                  /* write out the mark of ARC */
    fputc(hdrver,f);                   /* write out the header version */
    if(!hdrver)                        /* if that's the end */
         return;                       /* then write no more */

    fwrite(hdr->name,1,13,f);
    fputc(hdr->size&255,f);         fputc((hdr->size>>8)&255,f);
    fputc((hdr->size>>16)&255,f);   fputc((hdr->size>>24)&255,f);
    fputc(hdr->date&255,f);         fputc((hdr->date>>8)&255,f);
    fputc(hdr->time&255,f);         fputc((hdr->time>>8)&255,f);
    fputc(hdr->crc&255,f);          fputc((hdr->crc>>8)&255,f);
    fputc(hdr->length&255,f);       fputc((hdr->length>>8)&255,f);
    fputc((hdr->length>>16)&255,f); fputc((hdr->length>>24)&255,f);

    /* note the newest file for updating the archive timestamp */

    if(hdr->date>arcdate
    ||(hdr->date==arcdate && hdr->time>arctime))
    {    arcdate = hdr->date;
         arctime = hdr->time;
    }
}

INT filecopy(f,t,size)                 /* bulk file copier */
FILE *f, *t;                           /* from, to */
long size;                             /* number of bytes */
{
    INT len;                           /* length of a given copy */
    INT putc_tst();

    while(size--)                      /* while more bytes to move */
         putc_tst(fgetc(f),t);
}

INT putc_tst(c,t)                      /* put a character, with tests */
char c;                                /* character to output */
FILE *t;                               /* file to write to */
{
    if(t)
         if(fputc(c,t)==EOF)
              abort("Write fail (disk full?)");
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arclst.c'
then
	echo shar: will not over-write existing file "'arclst.c'"
else
cat << \SHAR_EOF > 'arclst.c'
/*  ARC - Archive utility - ARCLST

System V Version 1.0 based upon:
    Version 2.34, created on 02/03/86 at 22:56:57

(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED

    By:  Thom Henderson

    Description:
         This file contains the routines used to list the contents
         of an archive.
*/
#include "arc.h"

INT lstarc(num,arg)                    /* list files in archive */
INT num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
{
    struct heads hdr;                  /* header data */
    INT list;                          /* true to list a file */
    INT did[MAXARG];                   /* true when argument was used */
    long tnum, tlen, tsize;            /* totals */
    INT n;                             /* index */
    INT lstfile();

    tnum = tlen = tsize = 0;           /* reset totals */

    for(n=0; n<num; n++)               /* for each argument */
         did[n] = 0;                   /* reset usage flag */
    rempath(num,arg);                  /* strip off paths */

    printf("Name          Length  ");
    if(bose)
        printf("  Stowage    SF   Size now");
    printf("  Date     ");
    if(bose)
        printf("  Time    CRC");
    printf("\n");

    printf("============  ========");
    if(bose)
        printf("  ========  ====  ========");
    printf("  =========");
    if(bose)
         printf("  ======  ====");
    printf("\n");

    openarc(0);                        /* open archive for reading */

    if(num)                            /* if files were named */
    {    while(readhdr(&hdr,arc))      /* process all archive files */
         {    list = 0;                /* reset list flag */
              for(n=0; n<num; n++)     /* for each template given */
              {    if(match(hdr.name,arg[n]))
                   {    list = 1;      /* turn on list flag */
                        did[n] = 1;    /* turn on usage flag */
                        break;         /* stop looking */
                   }
              }

              if(list)                 /* if this file is wanted */
              {    lstfile(&hdr);      /* then tell about it */
                   tnum++;             /* update totals */
                   tlen += hdr.length;
                   tsize += hdr.size;
              }

              fseek(arc,hdr.size,1);   /* move to next header */
         }
    }

    else while(readhdr(&hdr,arc))      /* else report on all files */
    {    lstfile(&hdr);
         tnum++;                       /* update totals */
         tlen += hdr.length;
         tsize += hdr.size;
         fseek(arc,hdr.size,1);        /* skip to next header */
    }

    closearc(0);                       /* close archive after reading */

    printf("        ====  ========");
    if (bose)
        printf("            ====  ========");
    printf("\n");
    printf("Total %6ld  %8ld  ",tnum,tlen);
    if (bose)
        printf("          %3ld%%  %8ld  ",100L - (100L*tsize)/tlen,tsize);
    printf("\n");

    if(note)
    {    for(n=0; n<num; n++)          /* report unused args */
         {    if(!did[n])
              {    printf("File not found: %s\n",arg[n]);
                   nerrs++;
              }
         }
    }
}

static INT lstfile(hdr)                /* tell about a file */
struct heads *hdr;                     /* pointer to header data */
{
    INT yr, mo, dy;                    /* parts of a date */
    INT hh, mm, ss;                    /* parts of a time */

    static char *mon[] =               /* month abbreviations */
    {    "Jan",    "Feb",    "Mar",    "Apr",
         "May",    "Jun",    "Jul",    "Aug",
         "Sep",    "Oct",    "Nov",    "Dec"
    };

    yr = (hdr->date >> 9) & 0x7f;      /* dissect the date */
    mo = (hdr->date >> 5) & 0x0f;
    dy = hdr->date & 0x1f;

    hh = (hdr->time >> 11) & 0x1f;     /* dissect the time */
    mm = (hdr->time >> 5) & 0x3f;
    ss = (hdr->time & 0x1f) * 2;

    printf("%-12s  %8ld  ",hdr->name,hdr->length);

    if(bose)
    {    switch(hdrver)
         {
         case 1:
         case 2:
              printf("   --   ");
              break;
         case 3:
              printf(" Packed ");
              break;
         case 4:
              printf("Squeezed");
              break;
         case 5:
         case 6:
         case 7:
              printf("crunched");
              break;
         case 8:
              printf("Crunched");
              break;
         default:
              printf("Unknown!");
         }

         printf("  %3d%%",100L - (100L*hdr->size)/hdr->length);
         printf("  %8ld  ",hdr->size);
    }

    printf("%2d %3s %02d", dy, mon[mo-1], (yr+80)%100);

    if(bose)
         printf("  %2d:%02d%c  %04x",
              (hh>12?hh-12:hh), mm, (hh>12?'p':'a'),
              (unsigned INT)hdr->crc);

    printf("\n");
}
SHAR_EOF
fi # end of overwriting check
if test -f 'arcm.h'
then
	echo shar: will not over-write existing file "'arcm.h'"
else
cat << \SHAR_EOF > 'arcm.h'
/*  ARC archive utility - standard MACRO insert file.

System V Version 1.0.
*/

#define ARCMARK 26 /*                   special archive marker        */
#define ARCVER 8   /*                   archive header version code   */
#define STRLEN 100 /*                   system standard string length */
#define FNLEN 13   /*                   file name length              */
#define MAXARG 25  /*                   maximum number of arguments   */
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
Mike Stump, Cal State Univ, Northridge Comp Sci Department
uucp: {sdcrdcf, ihnp4, hplabs, ttidca, psivax, csustan}!csun!aeusemrs



More information about the Comp.sources.unix mailing list