[comp.binaries.ibm.pc] ARC for BSD 4.2 - Part 1 of 3

boneill@hawk.ulowell.edu (SoftXc Coordinator) (03/26/88)

Here is the SEA ARC Utility for BSD 4.2 systems. It may need some work for
use on non-BSD 4.2 systems (I know it will not work on Dynix 2.1.1).

============================================================================
Brian O'Neill					University of Lowell
boneill@hawk.ulowell.edu - boneill@hawk.UUCP ...!ulowell!hawk!boneill
MS-DOS Software Exchange Coordinator - E-mail for details

--------------Cut Here---------------
: This is a shar archive.  Extract with sh, not csh.
echo x - BugsEtc
cat > BugsEtc << '!Funky!Stuff!'

To whom it may concern:

Dear Whom,

	This bundle contains the ARC utility, so prolific in the PC world
that it has found its place among the various unix utilities.  (Usually
works the other way, doesn't it? :-)

	I gathered the source (as modified by Turner) and patched it to
run on our machine (BSD4.2 on VAX 11/780).  My mods include. . .

     => changing all declarations (implicit or explicit) of "int" to
	be "INT" (a 16-bit integer which was already defined in the header).
	This act alone restored much sanity to the program.

     => changing "dir" function to handle wildcards without giving all
	those ugly core dumps.  ("dir" is designed to generate a complete
	list of filenames on first call, and then pass them back one-by-one
	on subsequent calls.  It was losing the pointer to the structure.)

     => miscellaneous hacks to make it more useful on a multi-user unix
	machine.  ("uniquification" of the temporary filenames using
	process ID; use file-modified date instead of file-accessed date
	for comparisons; etc..)

HERE'S WHAT IT DOES:

	It behaves just like the PC version of the program; all functions
	of the "usage" display are working.  Full compatibility with PC ARC
	files is maintained.

	However, PC-compatibility has its price (Doesn't it always? :-)
	..see below.

HERE'S WHAT IT DOESN'T DO:

	ARC doesn't like long filenames.  (MSDOS filenames are limited
	to 12 characters, e.g. "TESTFILE.ARC", so BSD ARC must also.)
	It will *sometimes* do The Right Thing with them, but I suggest
	you put long-winded filenames in a "shar" before ARCing them.

	It doesn't do smart things about multi-user access to files.
	If you write to a file while ARC is playing with it, the result
	is usually a munged .arc file.  This will happen, for example,
	if you run two ARCs simultaneously from the same directory -- they
	will stumble over each other's temporary files.  (This particular
	situation can be avoided by setting an environment variable,
	ARCTEMP -- the location of temporary files, to some safe place.
	On our machine, I use "setenv ARCTEMP /tmp/")

PACKING LIST:

total 155
-rw-r--r--  1 wilhite  hack         3757 Jan 13 15:21 BugsEtc
-rw-r--r--  1 wilhite  hack         1333 Dec 29 17:48 Makefile
-rw-r--r--  1 wilhite  hack        10207 Jan  8 10:48 arc.c
-rw-r--r--  1 wilhite  hack         2325 Jan  8 11:07 arc.h
-rw-r--r--  1 wilhite  hack        11371 Jan  8 08:56 arcadd.c
-rw-r--r--  1 wilhite  hack         1882 Dec 29 14:10 arccode.c
-rw-r--r--  1 wilhite  hack         4637 Jan  7 21:00 arccvt.c
-rw-r--r--  1 wilhite  hack         3072 Dec 29 14:11 arcdel.c
-rw-r--r--  1 wilhite  hack         8701 Jan  7 17:40 arcdir.c
-rw-r--r--  1 wilhite  hack         3664 Jan  8 08:51 arcdos.c
-rw-r--r--  1 wilhite  hack         6092 Dec 29 14:32 arcext.c
-rw-r--r--  1 wilhite  hack         5563 Jan  7 15:43 arcio.c
-rw-r--r--  1 wilhite  hack         5712 Dec 29 14:34 arclst.c
-rw-r--r--  1 wilhite  hack        27442 Dec 29 14:38 arclzw.c
-rw-r--r--  1 wilhite  hack          695 Dec 20 02:03 arcm.h
-rw-r--r--  1 wilhite  hack         3250 Dec 29 14:47 arcmatch.c
-rw-r--r--  1 wilhite  hack         1518 Dec 29 14:48 arcmisc.c
-rw-r--r--  1 wilhite  hack         9991 Jan  7 18:43 arcpack.c
-rw-r--r--  1 wilhite  hack         4920 Jan  7 18:46 arcrun.c
-rw-r--r--  1 wilhite  hack         1968 Dec 29 17:47 arcs.h
-rw-r--r--  1 wilhite  hack        16995 Dec 29 14:58 arcsq.c
-rw-r--r--  1 wilhite  hack         5272 Dec 29 15:00 arcsvc.c
-rw-r--r--  1 wilhite  hack         1945 Jan  7 15:41 arctst.c
-rw-r--r--  1 wilhite  hack         6532 Dec 29 15:02 arcunp.c
-rw-r--r--  1 wilhite  hack         3360 Dec 29 15:03 arcusq.c
-rw-r--r--  1 wilhite  hack          850 Jan  7 21:58 arcvax.c

Hope it worx!
!Funky!Stuff!
echo x - Makefile
cat > Makefile << '!Funky!Stuff!'
#
#	Makefile for Hack-attack 1.3
#	VAX 11/780 BSD4.2 "ARC" utility
#
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 arcrun.o \
arcsq.o arcsvc.o arctst.o arcunp.o arcusq.o arcvax.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 arcrun.c \
arcs.c arcsq.c arcsvc.c arctst.c arcunp.c arcusq.c arcvax.c arcmisc.c

arc:		${OBJS}
	cc  -O -o arc ${OBJS}
arc.o:		arc.h
	cc -O -c arc.c
arcadd.o:	arc.h
	cc -O -c arcadd.c
arccode.o:	arc.h
	cc -O -c arccode.c
arccvt.o:	arc.h
	cc -O -c arccvt.c
arcdel.o:	arc.h
	cc -O -c arcdel.c
arcdir.o:	arc.h
	cc -O -c arcdir.c
arcdos.o:	arc.h
	cc -O -c arcdos.c
arcext.o:	arc.h
	cc -O -c arcext.c
arcio.o:	arc.h
	cc -O -c arcio.c
arclst.o:	arc.h
	cc -O -c arclst.c
arclzw.o:	arc.h
	cc -O -c arclzw.c
arcmatch.o:	arc.h
	cc -O -c arcmatch.c
arcmisc.o:	arc.h
	cc -O -c arcmisc.c
arcpack.o:	arc.h
	cc -O -c arcpack.c
arcrun.o:	arc.h
	cc -O -c arcrun.c
arcs.o:		arcm.h
	cc -O -c arcs.c
arcsq.o:	arc.h
	cc -O -c arcsq.c
arcsvc.o:	arc.h
	cc -O -c arcsvc.c
arctst.o:	arc.h
	cc -O -c arctst.c
arcunp.o:	arc.h
	cc -O -c arcunp.c
arcusq.o:	arc.h
	cc -O -c arcusq.c
arcvax.o:	arc.h
	cc -O -c arcvax.c
arc.h:		arcm.h arcs.h
	touch arc.h
!Funky!Stuff!
echo x - arc.c
cat > arc.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arc.c,v 1.2 86/07/15 07:52:04 turner Exp $";

/*
 * $Log:	arc.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:04  turner
 * first working version for the vax
 * 
 * Revision 1.1  86/06/26  14:59:15  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =5.12), created on $tag(
TED_DATE DB =02/05/86) at $tag(
TED_TIME DB =22:22:01))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#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, $version\n");
         printf("(C) COPYRIGHT 1985,86 by System Enhancement Associates;");
         printf(" ALL RIGHTS RESERVED\n\n");
         printf("Please refer all inquiries to:\n\n");
         printf("       System Enhancement Associates\n");
         printf("       21 New Street, Wayne NJ 07470\n\n");
         printf("You may copy and distribute this program freely,");
         printf(" provided that:\n");
         printf("    1)   No fee is charged for such copying and");
         printf(" distribution, and\n");
         printf("    2)   It is distributed ONLY in its original,");
         printf(" unmodified state.\n\n");
         printf("If you like this program, and find it of use, then your");
         printf(" contribution will\n");
         printf("be appreciated.  You may not use this product in a");
         printf(" commercial environment\n");
         printf("or a governmental organization without paying a license");
         printf(" fee of $35.  Site\n");
         printf("licenses and commercial distribution licenses are");
         printf(" available.  A program\n");
         printf("disk and printed documentation are available for $50.\n");
         printf("\nIf you fail to abide by the terms of this license, ");
         printf(" then your conscience\n");
         printf("will haunt you for the rest of your life.\n\n");            */
         printf("Usage: ARC {amufdxerplvtc}[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("         r   = run 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");
/*       printf("\nPlease refer to the program documentation for");          */
/*       printf(" complete instructions.\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());

#if MSDOS 
    /* avoid any case problems with arguments */

    for(n=1; n<num; n++)               /* for each argument */
         upper(arg[n]);                /* convert it to uppercase */
#endif
#if BSD | ST
    /* avoid any case problems with command options */

         upper(arg[1]);                /* convert it to uppercase */
#endif

    /* create archive names, supplying defaults */

#if MSDOS
    makefnam(arg[2],".ARC",arcname);
#endif
#if BSD | ST
    makefnam(arg[2],".arc",arcname);
#endif
/*  makefnam(".$$$$",arcname,newname); */
    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("AMUFDXEPLVTCR",*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=='K')              /* special kludge */
              kludge = 1;

         else if(*a=='-' || *a=='/')   /* UNIX and PC-DOS option markers */
              ;

         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;

    case 'R':                          /* Run */
         runarc(num-3,&arg[3]);
         break;

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

    return nerrs;
}
!Funky!Stuff!
echo x - arc.h
cat > arc.h << '!Funky!Stuff!'
/*
 * $Header: arc.h,v 1.2 86/07/15 07:52:34 turner Exp $
 */

/*
 * $Log:	arc.h,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:34  turner
 * 
 * 
 * Revision 1.1  86/06/26  15:01:23  turner
 * initial version
 * 
 * 
 */

#define	ST	0	/* Atari 520ST or 1040 		 */
#define BSD	1	/* BSD4.2 on a vax		 */
#define MSDOS	0	/* MSDOS on an IBM PC or Wannabe */

#if ST
#define EXTERN
#define INT short
#endif

#if BSD
#include <ctype.h>	/* for isupper etc.                  */
#define EXTERN
#define INT short
#define envfind getenv
#endif

#if MSDOS
#define EXTERN extern
#define INT int
#endif

/*
 * added macro def's in C format 6/26/86 jmt 
 */
#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.


    Language:
         Computer Innovations Optimizing C86
 */

#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 INT kludge;              /* kludge flag */
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 */
!Funky!Stuff!
echo x - arcadd.c
cat > arcadd.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arcadd.c,v 1.2 86/07/15 07:52:37 turner Exp $";

/*
 * $Log:	arcadd.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:37  turner
 * 
 * 
 * Revision 1.1  86/06/26  14:59:37  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCADD

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =3.39), created on $tag(
TED_DATE DB =02/05/86) at $tag(
TED_TIME DB =22:21:53))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#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 *d, *dir();                   /* directory junk */
    char *NameList;	/* Any pointer.  Used to pass file names around */
    char buf[STRLEN];                 /* pathname buffer */
    char **path = NULL;                /* pointer to pointers to paths */
    char **name = NULL;                /* pointer to pointers to names */
 INT nfiles = 0;                    /* number of files in lists */
 INT notemp;                        /* true until a template works */
 INT nowork = 1;                    /* true until files are added */
    char *i, *rindex();                /* string indexing junk */
    char *malloc(), *realloc();         /* memory allocators */
 INT m, n;                          /* indices */
    unsigned INT coreleft();           /* remaining memory reporter */
    INT addbunch();

    if(num<1)                          /* if no files named */
    {    num = 1;                      /* then fake one */
         arg[0] = "*.*";               /* add everything */
    }

    for(n=0; n<num; n++)               /* for each template supplied */
    {
         strcpy(buf,arg[n]);           /* get ready to fix path */
         if(!(i=rindex(buf,'\\')))
              if(!(i=rindex(buf,'/')))
                   if(!(i=rindex(buf,':')))
                        i = buf-1;
         i++;                          /* pointer to where name goes */

         notemp = 1;                   /* reset files flag */
         NameList = (char *) malloc(sizeof(char *));
         for(d=dir(arg[n],0,NameList); d; d=dir(NULL,0,NameList))
         {    notemp = 0;              /* template is giving results */
              nfiles++;                /* add each matching file */
              path = (char **)realloc(path,nfiles*sizeof(char **));
              name = (char **)realloc(name,nfiles*sizeof(char **));
              strcpy(i,d);             /* put name in path */
              path[nfiles-1] = malloc(strlen(buf)+1);
              strcpy(path[nfiles-1],buf);
              name[nfiles-1] = d;      /* save name */

#if MSDOS
              if(coreleft()<5120)
              {    nfiles = addbunch(nfiles,path,name,move,update,fresh);
                   nowork = nowork && !nfiles;
                   while(nfiles)
                   {    free(path[--nfiles]);
                        free(name[nfiles]);
                   }
                   free(path); free(name);
                   path = name = NULL;
              }
#endif
         }
         if(notemp && warn)
              printf("No files match: %s\n",arg[n]);
    }

    if(nfiles)
    {    nfiles = addbunch(nfiles,path,name,move,update,fresh);
         nowork = nowork && !nfiles;
         while(nfiles)
         {    free(path[--nfiles]);
              free(name[nfiles]);
         }
         free(path); free(name);
    }

    if(nowork && warn)
         printf("No files were added.\n");
}

INT addbunch(nfiles,path,name,move,update,fresh) /* add a bunch of files */
INT nfiles;                            /* number of files to add */
char **path;                           /* pointers to pathnames */
char **name;                           /* pointers to filenames */
INT move;                              /* true if moving file */
INT update;                            /* true if updating */
INT fresh;                             /* true if freshening */
{
    char buf[STRLEN];                 /* pathname buffer */
 INT m, n;                          /* indices */
    char *d;                           /* swap pointer */
    struct heads hdr;                  /* file header data storage */
    INT addfile();
    INT izadir();		   /* used to weed-out directories */

    for(n=0; n<nfiles-1; n++)          /* sort the list of names */
    {    for(m=n+1; m<nfiles; m++)
         {    if(strcmp(name[n],name[m])>0)
              {    d = path[n];
                   path[n] = path[m];
                   path[m] = d;
                   d = name[n];
                   name[n] = name[m];
                   name[m] = d;
              }
         }
    }

    for(n=0; n<nfiles-1; )             /* consolidate the list of names */
    {    if(!strcmp(path[n],path[n+1]) /* if duplicate names */
         || !strcmp(path[n],arcname)   /* or this archive */
         || izadir(path[n])            /* or directory */
         || !strcmp(path[n],newname)   /* or the new version */
         || !strcmp(path[n],bakname))  /* or its backup */
         {    free(path[n]);           /* then forget the file */
              free(name[n]);
              for(m=n; m<nfiles-1; m++)
              {    path[m] = path[m+1];
                   name[m] = name[m+1];
              }
              nfiles--;
         }
         else n++;                     /* else test the next one */
    }

    if(!strcmp(path[n],arcname)        /* special check for last file */
    || !strcmp(path[n],newname)        /* courtesy of Rick Moore */
    || izadir(path[n])
    || !strcmp(path[n],bakname))
    {    free(path[n]);
         free(name[n]);
         nfiles--;
    }

    if(!nfiles)                        /* make sure we got some */
         return 0;

    for(n=0; n<nfiles-1; n++)          /* watch out for duplicate names */
         if(!strcmp(name[n],name[n+1]))
              abort("Duplicate filenames:\n  %s\n  %s",path[n],path[n+1]);

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

    for(n=0; n<nfiles; n++)            /* add each file in the list */
         addfile(path[n],name[n],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)                           /* if this was a move */
    {    for(n=0; n<nfiles; n++)       /* then delete each file added */
         {    if(unlink(path[n]) && warn)
              {    printf("Cannot unsave %s\n",path[n]);
                   nerrs++;
              }
         }
    }

    return nfiles;                     /* say how many were added */
}

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++;
         }
         return;
    }

    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 */
}
!Funky!Stuff!
echo x - arccode.c
cat > arccode.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arccode.c,v 1.1 86/06/26 14:59:53 turner Exp $";

/*
 * $Log:	arccode.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.1  86/06/26  14:59:53  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCCODE

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =1.02), created on $tag(
TED_DATE DB =01/20/86) at $tag(
TED_TIME DB =13:33:35))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#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 */
}
!Funky!Stuff!
echo x - arccvt.c
cat > arccvt.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arccvt.c,v 1.2 86/07/15 07:52:46 turner Exp $";

/*
 * $Log:	arccvt.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:46  turner
 * 
 * 
 * Revision 1.1  86/06/26  14:59:56  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCCVT

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =1.16), created on $tag(
TED_DATE DB =02/03/86) at $tag(
TED_TIME DB =22:53:02))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#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++;
    }
}
!Funky!Stuff!
echo x - arcdel.c
cat > arcdel.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arcdel.c,v 1.2 86/07/15 07:52:53 turner Exp $";

/*
 * $Log:	arcdel.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:53  turner
 * 
 * 
 * Revision 1.1  86/06/26  15:00:04  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCDEL

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =2.09), created on $tag(
TED_DATE DB =02/03/86) at $tag(
TED_TIME DB =22:53:27))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#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++;
              }
         }
    }
}
!Funky!Stuff!
echo x - arcdir.c
cat > arcdir.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arcdir.c,v 1.2 86/07/15 07:52:56 turner Exp $";

/*
 * $Log:	arcdir.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:52:56  turner
 * 
 * 
 * Revision 1.1  86/06/26  15:00:12  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCDIR
*/
#include <stdio.h>
#include "arc.h"

#if MSDOS
#include <dir.h>
#endif

#if BSD
#include <sys/types.h>
#include <sys/dir.h>
#endif

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[]);
{
        struct direct *(*namelist[]);
#ifdef BSD
	INT alphasort();
	INT scandir();
#endif BSD
        INT fmatch();
	static INT Nnum = 0,ii;
	char *result;

	pattern = filename;
	filemode = mode;		/* set up globals for fmatch */
	if(Nnum == 0) {                  /* first call */
            Nnum = scandir(".", namelist, fmatch, alphasort);
            *NameList = (char **)malloc(Nnum*sizeof(char *));
            for (ii=0; ii<Nnum; ii++) {
                (*NameList)[ii] = (char *)malloc((*namelist)[ii]->d_namlen+1);
                strcpy((*NameList)[ii],(*namelist)[ii]->d_name);
            }
            ii = 0;
	}
	if(ii >= Nnum) { /* all out of files */
		if(Nnum) { /* there were some files found */
		    freedir(namelist);
		    }
		Nnum = 0;
		return(NULL);
	}
	else {
		return((*NameList)[ii++]);
	}
}


#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));
}
!Funky!Stuff!
echo x - arcdos.c
cat > arcdos.c << '!Funky!Stuff!'
static char *RCSid = "$Header: arcdos.c,v 1.2 86/07/15 07:53:02 turner Exp $";

/*
 * $Log:	arcdos.c,v $
 * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
 * 	Bludgeoned into submission for VAX 11/780 BSD4.2
 *	(ugly code, but fewer core dumps)
 *
 * Revision 1.2  86/07/15  07:53:02  turner
 * 
 * 
 * Revision 1.1  86/06/26  15:00:15  turner
 * initial version
 * 
 * 
 */

/*  ARC - Archive utility - ARCDOS

$define(tag,$$segment(@1,$$index(@1,=)+1))#
$define(version,Version $tag(
TED_VERSION DB =1.43), created on $tag(
TED_DATE DB =11/09/85) at $tag(
TED_TIME DB =22:24:44))#
$undefine(tag)#
    $version

(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.

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#include "arc.h"
#if MSDOS
#include "fileio2.h"                   /* needed for filehand */
#endif
#if BSD
#include <sys/types.h>
#include <sys/stat.h>
#endif

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 */
{
#if MSDOS
    struct {INT ax,bx,cx,dx,si,di,ds,es;} reg;

    reg.ax = 0x5700;                   /* get date/time */
    reg.bx = filehand(f);              /* file handle */
    if(sysint21(&reg,&reg)&1)          /* DOS call */
         printf("Get timestamp fail (%d)\n",reg.ax);

    *date = reg.dx;                    /* save date/time */
    *time = reg.cx;
#endif
#if BSD
    struct stat *buf;
    int day,hr,min,sec,yr,imon;
    static char mon[4],*mons[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
					"Aug","Sep","Oct","Nov","Dec"};

    buf = (struct stat *)malloc(sizeof(struct stat));
    fstat(f->_file,buf); 
/*
 * assume the UGLY ibm format for date and time
 */
    sscanf(ctime(&(buf->st_mtime)),"%*4s%3s%d%d:%d:%d%d"
	,mon,&day,&hr,&min,&sec,&yr);
    for(imon = 0; imon < 12 && strcmp(mon,mons[imon]); imon++);

    *date = (unsigned INT)(((yr-1980)<<9)+((imon+1)<<5)+day);
    *time = (unsigned INT)((hr<<11)+(min<<5)+sec/2);
#endif
}

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 */
{
#if MSDOS
    struct {INT ax,bx,cx,dx,si,di,ds,es;} reg;

    fflush(f);                         /* force any pending output */

    reg.ax = 0x5701;                   /* set date/time */
    reg.bx = filehand(f);              /* file handle */
    reg.cx = time;                     /* desired time */
    reg.dx = date;                     /* desired date */
    if(sysint21(&reg,&reg)&1)          /* DOS call */
         printf("Set timestamp fail (%d)\n",reg.ax);
#endif
}

static INT filehand(stream)            /* find handle on a file */
struct bufstr *stream;                 /* file to grab onto */
{
#if MSDOS
    return stream->bufhand;            /* return DOS 2.0 file handle */
#endif
}

INT izadir(filename)			/* Is filename a directory? */
char *filename;
{
#if MSDOS
    return 0;
#else
struct stat buf;

    if (stat(filename,&buf)!=0) return 0;   /* Ignore if stat fails since we */
    else return (buf.st_mode & S_IFDIR);    /* trap for bad file elsewhere.  */

#endif
}
!Funky!Stuff!

exit 0

-- 
---------------------
Robert Wilhite
akgua!usceast!wilhite