[comp.os.os9] OS-9 Discussions, V3 #5

os9@cbdkc1.UUCP (05/25/87)

OS-9 Discussions         Monday, May 25th 1987         Volume 3 : Issue 5

Today's Topics:
                         OS/9 68K "arc" - 1 of 3

--------------------------------------------------------------------------

Date: Sun, 24 May 87 18:43:06 EDT
From: mnetor!lsuc!jimomura
Subject: OS/9 68K "arc" - 1 of 3

87/05/24
 
     This is Dieter Stoll's port of ARC from the MS-DOS version to
OS-9 68K.  It is posted to Usenet with the permission of Systems
Enhancements Associates.  If you wish to port ARC to another system
or wish to re-distribute ARC, you should contact them for approval.
I have found them to be quite reasonable.
 
Cheers! -- Jim O.

[Moderator's note:  I have repackaged the code into 3 shar files to
 keep it within the limits of smaller Usenet machines.  I have not yet
 tested the code on my machine.  - JDD ]


# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# README makefile arc.h arcs.h arcadd.c arccode.c arccvt.c arcdel.c arcdir.c arcdos.c arcext.c arcio.c

echo x - README
cat > "README" << '//E*O*F README//'
87/05/24
 
     This is Dieter Stoll's port of ARC from the MS-DOS version to
OS-9 68K.  It is posted to Usenet with the permission of Systems
Enhancements Associates.  If you wish to port ARC to another system
or wish to re-distribute ARC, you should contact them for approval.
I have found them to be quite reasonable.
 
Cheers! -- Jim O.
//E*O*F README//

echo x - makefile
cat > "makefile" << '//E*O*F makefile//'
*
CFLAGS = -ixt=/r0
HEADERS = arc.h arcs.h
RDIR = rels
*
arc: arcmain.r arcadd.r arccode.r arccvt.r arcdel.r arcdir.r arcdos.r \
     arcext.r arcio.r arclst.r arclzw.r arcmatch.r arcpack.r arcsq.r \
     arcsvc.r arctst.r arcunp.r arcusq.r system.r
  chd $(RDIR); cc -f=arc -t=/r0 arcmain.r arcadd.r arccode.r arccvt.r arcdel.r \
  arcdir.r arcdos.r arcext.r arcio.r arclst.r arclzw.r arcmatch.r \
  arcpack.r arcsq.r arcsvc.r arctst.r arcunp.r arcusq.r system.r
*
arcmain.r: arcmain.c $(HEADERS)
arcadd.r: arcadd.c $(HEADERS)
arccode.r: arccode.c $(HEADERS)
arccvt.r: arccvt.c $(HEADERS)
arcdel.r: arcdel.c $(HEADERS)
arcdir.r: arcdir.c $(HEADERS)
arcdos.r: arcdos.c $(HEADERS)
arcext.r: arcext.c $(HEADERS)
arcio.r: arcio.c $(HEADERS)
arclst.r: arclst.c $(HEADERS)
arclzw.r: arclzw.c $(HEADERS)
arcmatch.r: arcmatch.c $(HEADERS)
arcpack.r: arcpack.c $(HEADERS)
arcsq.r: arcsq.c $(HEADERS)  
arcsvc.r: arcsvc.c $(HEADERS)
arctst.r: arctst.c $(HEADERS)
arcunp.r: arcunp.c $(HEADERS)
arcusq.r: arcusq.c $(HEADERS)
system.r: system.c
//E*O*F makefile//

echo x - arc.h
cat > "arc.h" << '//E*O*F arc.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"
#ifndef fputc
#define fputc(a,b) putc(a,b)
#endif
#define ARCMARK 26				/* special archive marker					*/
#define ARCVER 8				/* archive header version code				*/
#define STRLEN 100				/* system standard string length			*/
#define FNLEN 20				/* file name length							*/
#define MAXARG 25				/* maximum number of arguments 				*/

#define READBIN "r"
#define WRITEBIN "w"
#define RWBIN "w+"

#ifdef OSK
EXTERN int ZivLempel;
#endif
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;        /* 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 */

/*
 *   entry points for the memory functions
 */
extern int rename();          /* change the name of a file                  */
extern char *setmem();        /* set a block of memory to a given value     */

//E*O*F arc.h//

echo x - arcs.h
cat > "arcs.h" << '//E*O*F arcs.h//'
/*  ARC - Archive utility - Archive file header format

    Version 2.12, created on 12/17/85 at 14:40:26

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

    By:  Thom Henderson

    Description:
         This file defines the format of an archive file header, excluding
         the archive marker and the header version number.

         Each entry in an archive begins with a one byte archive marker,
         which is set to 26.  The marker is followed by a one byte
         header type code, from zero to 7.

         If the header type code is zero, then it is an end marker, and
         no more data should be read from the archive.

         If the header type code is in the range 2 to 7, then it is
         followed by a standard archive header, which is defined below.

         If the header type code is one, then it is followed by an older
         format archive header.  The older format header does not contain
         the true length.  A header should be read for a length of
         sizeof(struct heads)-sizeof(long).  Then set length equal to size
         and change the header version to 2.

    Programming note:
         The crc value given in the header is based on the unpacked data.

    Language:
         Computer Innovations Optimizing C86
*/

struct heads                           /* archive entry header format */
{   char name[13];                 /* file name */
    long size;                         /* size of file, in bytes */
    unsigned short date;                 /* creation date */
    unsigned short time;                 /* creation time */
    short crc;                           /* cyclic redundancy check */
    long length;                       /* true file length */
}   ;
//E*O*F arcs.h//

echo x - arcadd.c
cat > "arcadd.c" << '//E*O*F arcadd.c//'
/*  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
*
*	changed abort(...) to exit (_errmsg, (1,...))
*/
#include <stdio.h>
#define EXTERN extern
#include "arc.h"

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

#ifdef DEBUG
	puts ("addarc");
	printf ("num: %d arg[0]: %s  move:%d update:%d fresh:%d\n",
	num, arg[0], move, update, fresh);
#endif
    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 */
         for(d=dir(arg[n],0); *d; d=dir(NULL,0))
         {    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(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;
              }
         }
         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 */

#ifdef DEBUG
	puts ("addbunch");
	printf ("nfiles:%d path[0]:%s name[0]:%s move:%d update:%d fresh:%d\n",
	nfiles, path[0], name[0], move, update, fresh);
#endif
    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 */
         || !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 */
    || !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]))
              exit (_errmsg(1,
				"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 */
    {    
#ifdef DEBUG
		printf("readhdr found something to copy\n");
#endif
		writehdr(&hdr,new);
         filecopy(arc,new,hdr.size);
    }
    hdrver = 0;                        /* archive EOF type */
#ifdef DEBUG
	printf ("writing zero header\n");
#endif
    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 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 */
	int i;
#ifdef OSK
	int tempsize;
#endif
	
#ifdef DEBUG
	puts ("addfile");
	printf ("path:%s name:%s update:%d fresh:%d\n",path,name,update,fresh);
#endif
    if(!(f=fopen(path,READBIN)))
    {    if(warn)
         {    printf("Cannot read file: %s\n",path);
              nerrs++;
         }
         return;
    }
/*
 *	for non-MSDOSes, check here if the name is the correct size!!
 */
	if (strlen(name) > 12)
		exit (_errmsg (1,"File %s: name too long\n",name));
		
    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 */
#ifdef DEBUG
	puts ("addfile before writehdr");
#endif
    writehdr(&nhdr,new);               /* write out header skeleton */
#ifdef DEBUG
	puts ("addfile before pack");
#endif
    pack(f,new,&nhdr);                 /* pack file into archive */
#ifdef DEBUG
	puts ("addfile before fseek");
#endif
    fseek(new,starts,0);               /* move back to header skeleton */
#ifdef OSK
/*
 *	get time stamp again because it may have been destroyed in pack()!
 */
    getstamp(f,&nhdr.date,&nhdr.time);
#endif
#ifdef OSK
/*
 *	save hdr.size because nhdr will be garbled by writehdr() call!
 */
	tempsize = nhdr.size;
#endif
    writehdr(&nhdr,new);               /* write out real header */
#ifdef OSK
	fseek (new, tempsize, 1);
#else
    fseek(new,nhdr.size,1);            /* skip over data to next header */
#endif
    fclose(f);                         /* all done with the file */
#ifdef DEBUG
	puts ("addfile returning");
#endif
}

unsigned int coreleft()
{
	return (unsigned int)freemem();
}
//E*O*F arcadd.c//

echo x - arccode.c
cat > "arccode.c" << '//E*O*F arccode.c//'
/*  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>
#define EXTERN extern
#include "arc.h"

static char *p;                        /* password pointer */

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 */
}
//E*O*F arccode.c//

echo x - arccvt.c
cat > "arccvt.c" << '//E*O*F arccvt.c//'

/*  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
*
*	changed abort(..) to exit(_errmsg(1,...))
*/
#include <stdio.h>
#define EXTERN extern
#include "arc.h"

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

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

    if(arctemp)                   /* use temp area if specified */
#ifdef OSK
         sprintf(tempname,"%s/$ARCTEMP.CVT",arctemp);
#else
         sprintf(tempname,"%s$ARCTEMP.CVT",arctemp);
#endif
    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 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,RWBIN)))
         exit (_errmsg(1,"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++;
    }
}
//E*O*F arccvt.c//

echo x - arcdel.c
cat > "arcdel.c" << '//E*O*F arcdel.c//'
/*  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:
         Colputer Innovations Optimizing C86
*
*	changed abort(..) to exit(_errmsg(1,...))
*/
#include <stdio.h>
#define EXTERN extern
#include "arc.h"

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 */
         exit (_errmsg(1,"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++;
              }
         }
    }
}
//E*O*F arcdel.c//

echo x - arcdir.c
cat > "arcdir.c" << '//E*O*F arcdir.c//'
/*  ARC - Archive utility - ARCDIR

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

    By:  Thom Henderson

    Description:
         This file contains the dir() routine used when adding files to an
         archive.  It is an adaptation of the CI-C86 library function
         filedir().  It differes in that it returns the file names one by
         one, instead of all at once.

*/
#include <stdio.h>
#include <dir.h>
#define EXTERN extern
/*
 *	the following main() is only here for testing purposes.
 */
#ifdef TRYMAIN
main()
{
	char *search;
	char *dir(), *found;
	char placeholder[80];
	for (;;)
{	
	search = placeholder;
	printf ("search string: ");
	scanf ("%s",search);
	while (found = dir (search, 0))
	{
/*
 *	make it a 'search for next'
 */
		search = (char*)0;
		printf ("%s\n",found);
	}
}
}
#endif

char *dir(filename,mode)               /* get files, one by one */
char *filename;                        /* template, or NULL */
int mode;                              /* search mode bits; irrelevant
										for OS-9				 */
{		    
/*
 *	OS-9/68k version
 */
	static DIR *dirptr;
	static struct direct *nextfile;
	static char matchfile[80];		/* local nonvolatile search string		*/
	char is_it_dir[80];				/* local string to check whether a file
										is a directory						*/
	static char dirname[80];		/* directory part of path name			*/
	extern char *rindex();			/* need this to scan for '/'			*/
	char tempname[80];				/* trial file name						*/
	int temppath;					/* temporary path number				*/
	static int wildcards;			/* flag: file name contains wild cards	*/
	static int foundone;			/* true if matching file found			*/
/*
 *	if a file name has been given..
 */
	if (filename)							     
	{										     
		foundone = 0;
/*
 *	check if there are wildcards
 */
		wildcards = ((rindex(filename,'?') || rindex(filename,'*')) ? 1:0); 
/*
 *	check if there is a directory path
 */
		if (rindex(filename,'/'))
		{
/*
 *	yes: strip off directory path
 */
			int slash_index;
			slash_index = (int)(rindex(filename,'/') - filename);
			strncpy (dirname, filename, slash_index);
			dirname[slash_index] = '\0';
			strcpy (tempname, rindex(filename,'/')+1);
			strcpy (filename, tempname);
		}
		else
/*
 *	no: use current directory
 */
		{
			strcpy (dirname, ".");
		}
/*
 *	and open directory
 */
		dirptr = opendir(dirname);		     
/*
 *	copy search template to nonvolatile string
 */
		strcpy (matchfile, filename);		     
	}										     

/*
 *	scan the directory
 */
	while ((nextfile = readdir (dirptr)) != (struct direct *)0)
	{   									     
#ifdef DEBUG
		printf ("name: %s search name: %s ",nextfile->d_name,matchfile);
		if (!filename) printf ("NULL search pattern\n");
		else printf ("\n");
#endif		
/*
 *	check if it is a directory name, if so, forget it
 */
 			sprintf (is_it_dir,"%s/%s",dirname, nextfile->d_name);
/*
 *	build file name, including path name; trying to open a directory file
 *	will return -1...
 */
			temppath = open (is_it_dir,1);
			if (temppath == -1)
			{
#ifdef DEBUG
				printf ("%s: cannot open\n",is_it_dir);
#endif
				continue;
			}
 			close (temppath);
/*
 *	now use the _cmpnam() function to perform wild card matching
 */
		if (!_cmpnam (nextfile->d_name, matchfile, strlen(matchfile)))
		{   
			foundone = 1;
/*
 *	if file name did not contain wild cards, close directory before
 *	leaving
 */
			if (!wildcards)
				closedir (dirptr);
			return nextfile->d_name;
		}   
/*
 *	this file not matching, but found one before, and it is no wild
 *	card search: finish
 */
		else if (foundone && (!wildcards))
		{
			closedir (dirptr);
			return (char *)0;
		}
		else
		{
#ifdef DEBUG
			puts ("NO MATCH");
			foundone = 0;
#endif
		}
	}       
/*
 *	all done, but none found: return NULL pointer
 */
 	closedir (dirptr);
	return (char *)0;
}
//E*O*F arcdir.c//

echo x - arcdos.c
cat > "arcdos.c" << '//E*O*F arcdos.c//'

/*  ARC - Archive utility - ARCDOS

    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 <stdio.h>
#define EXTERN extern
#include "arc.h"
#ifdef OSK
#include <direct.h>
#endif

getstamp(f,date,time)                  /* get a file's date/time stamp */
FILE *f;                               /* file to get stamp from */
unsigned short *date, *time;             /* storage for the stamp */
{
#ifdef OSK
/*
 *	this is the OS-9/68k version
 */
	int path;
	struct fildes filbuf;
	char filedate[5];
/*
 *	need to get the path number belonging to the file descriptor
 */
	path = fileno (f);
/*
 *	get file descriptor
 */
	_gs_gfd (path, &filbuf, sizeof (struct fildes));
/*
 *	copy date to local array
 */
	strncpy (filedate, filbuf.fd_date,5);
/*
 *	dissect date and build MSDOS compatible date entry
 *
 *	below is the layout of the date and time words
 *
 *	Byte 3   Byte 2:   empty (CI86 int is 16 bits)
 *
 *  	Byte 1            Byte 0
 *
 *    year         month       day
 *  |-----------| |-------| |-------|
 *  7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0
 *  |_______| |___________| |_______|
 *	hours(24)  minutes       seconds/2 
 *
 *	The 'year' storage format is funny: when decoding the year, the formula
 *	is (yr+80) % 100
 *
 */
#ifdef DEBUG
	puts ("getstamp");
	printf ("file date: %d %d %d %d %d\n",filedate[0],filedate[1],filedate[2],filedate[3],filedate[4]);	
#endif
	*date = (unsigned short)((filedate[0]+20) & 0x7f);
	*date <<= 9;
	*date &= (unsigned short)0xfe00;
	*date += (unsigned short)((filedate[1] & 0x0f)<< 5);
	*date += (unsigned short)(filedate[2] & 0x1f);
	
	*time = (unsigned short)(filedate[3] & 0x1f);
	*time <<= 11;
	*time += (unsigned short)((filedate[4] & 0x3f) << 5);
#ifdef DEBUG
	printf ("getstamp: date = %04.4x time = %04.4x\n",*date&0xffff,*time&0xffff);
#endif
#else
	fprintf (stderr, "getstamp routine not implemented\n");
	*date = *time = 0;
#endif
}

setstamp(f,date,time)                  /* set a file's date/time stamp */
FILE *f;                               /* file to set stamp on */
unsigned short date, time;               /* desired date, time */
{
/*
 *	inverse of the above
 */
#ifdef OSK
/*
 *	this is the OS-9/68k version
 */
	int path;
	struct fildes filbuf;
	char filedate[5];
	int yr, mo, dy, hh, mm, ss;
/*
 *	need to get the path number belonging to the file descriptor
 */
	path = fileno (f);
/*
 *	get file descriptor
 */
	_gs_gfd (path, &filbuf, sizeof (struct fildes));
/*
 *	dissect date from MSDOS format and insert into OS-9 file descriptor
 *
 *	below is the layout of the date and time words
 *
 *	Byte 3   Byte 2:   empty (CI86 int is 16 bits)
 *
 *  	Byte 1            Byte 0
 *
 *    year         month       day
 *  |-----------| |-------| |-------|
 *  7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0
 *  |_______| |___________| |_______|
 *	hours(24)  minutes       seconds/2 
 *
 */
    yr = (((date >> 9) & 0x7f)+80)%100;      /* dissect the date */
    mo = (date >> 5) & 0x0f;
    dy = date & 0x1f;

    hh = (time >> 11) & 0x1f;     /* dissect the time */
    mm = (time >> 5) & 0x3f;
    ss = (time & 0x1f) * 2;
	filedate[0] = yr;
	filedate[1] = mo;
	filedate[2] = dy;
	filedate[3] = hh;
	filedate[4] = mm;
/*
 *	no seconds in OS-9!
 */
	strncpy (filbuf.fd_date, filedate, 5);
	_ss_pfd (path, &filbuf);
#else
	fprintf (stderr, "setstamp routine not implemented\n");
#endif
}
//E*O*F arcdos.c//

echo x - arcext.c
cat > "arcext.c" << '//E*O*F arcext.c//'

/******* arcext.mac
$define(arc,$ifdef(xarc,off,on))#      macro switch for ARC only code
$define(xarc,$ifdef(xarc,on,off))#     macro switch for XARC only code
$emit($arc)#
*/
/*  ARC - Archive utility - ARCEXT

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

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

    Language:
         Computer Innovations Optimizing C86
*/
#include <stdio.h>
#define EXTERN extern
#include "arc.h"

#define ARC


#ifdef ARC
extarc(num,arg,prt)                    /* extract files from archive */
int num;                               /* number of arguments */
char *arg[];                           /* pointers to arguments */
int prt;                               /* true if printing */
#else
extarc()                               /* extract files from archive */
#endif
{
    struct heads hdr;                  /* file header */

#ifdef ARC
    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 */

#ifdef DEBUG
	printf ("extarc (%d,%s,%d)\n",num,arg[0],prt);
#endif

    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 */
              if(!(i=rindex(arg[n],'/')))
                   if(!(i=rindex(arg[n],':')))
                        i = arg[n]-1;
         name[n] = i+1;
    }

#endif

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

#ifdef ARC
    if(num)                            /* if files were named */
    {    
#ifdef DEBUG
		printf ("before readhdr: n: %d num: %d\n",n,num);
#endif
		while(readhdr(&hdr,arc))      /* while more files to check */
         {    save = 0;                /* reset save flag */
#ifdef DEBUG
		printf ("n: %d num: %d\n",n,num);
#endif
              for(n=0; n<num; n++)     /* for each template given */
              {    
#	ifdef DEBUG
	printf ("header name: %s  matchname: %s\n",
		hdr.name, name[n]);
#	endif
					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);

#else

    while(readhdr(&hdr,arc))           /* extract all files */
         extfile(&hdr);
#endif

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

#ifdef ARC

    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);
#endif
}

#ifdef ARC
static 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 */
#else
static extfile(hdr)                    /* extract a file */
struct heads *hdr;
#endif
/****
$define(use,$ife($arc,on,fix,hdr->name))#
*****/
{
    FILE *f, *fopen();                 /* extracted file, opener */
    char buf[STRLEN];                 /* input buffer */
#ifdef ARC
    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 */
         if(!(i=rindex(fix,'/')))
              if(!(i=rindex(fix,':')))
                   i = fix-1;
    strcpy(i+1,hdr->name);             /* replace template with name */

#endif

    if(note)
#ifdef ARC
         printf("Extracting file: %s\n",fix);
#else
         printf("Extracting file: %s\n",hdr->name);
#endif

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

    if(!(f=fopen(
#ifdef ARC
			fix,
#else
			hdr->name,
#endif
					WRITEBIN)))
    {    if(warn)
         {    printf("Cannot create %s\n",
#ifdef ARC
										fix);
#else
										hdr->name);
#endif
              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 */
}
//E*O*F arcext.c//

echo x - arcio.c
cat > "arcio.c" << '//E*O*F arcio.c//'
/*  ARC - Archive utility - ARCIO

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

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

    Language:
         Computer Innovations Optimizing C86
*
*	changed abort(..) to exit(_errmsg(1,...))
*/
#include <stdio.h>
#define EXTERN extern
#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 */
{
    char name[FNLEN];                 /* filename buffer */
    int try = 0;                       /* retry counter */
    static int first = 1;              /* true only on first read */

#ifdef DEBUG
	puts ("readhdr");
#endif

    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.",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)
              exit (_errmsg(1,"%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 */
#ifdef DEBUG
	printf ("header version %d\n",hdrver);
#endif

    if(hdrver<0)
         exit (_errmsg(1,"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 int),1,f);
         hdrver = 2;                   /* convert header to new format */
         hdr->length = hdr->size;      /* size is same when not packed */
    }
#ifndef OSK
    else fread(hdr,sizeof(struct heads),1,f);
#else
/*
 *	see comments below why we can read one less than sizeof(struct heads)
 */
	else fread (hdr, sizeof(struct heads)-1, 1, f);
#endif
#ifdef DEBUG
	printf ("header read\n");
#endif
#ifdef OSK
/*
 *	one heck of a hack for the 68000! Since the 68k always word-aligns,
 *	the struct heads is actually one byte longer than in the file! (The
 *	file name is 13 chars, expanded to 14 chars by 68k C). Thus, bytes
 *	13..end must be moved down one. Further, long and short ints must be
 *	byte-swapped.
 */
	{
		char *ptr;
		int i;
		ptr = (char *)hdr;
		for (i=sizeof(struct heads)-2; i>=13; i--)
			*(ptr+i+1) = *(ptr+i);
		hdr->length = longswap(hdr->length);
		hdr->size   = longswap(hdr->size);
		hdr->date   = (unsigned short)wordswap(hdr->date);
		hdr->time   = (unsigned short)wordswap(hdr->time);
		hdr->crc    = (short)(wordswap(hdr->crc) & 0xffff);
	}
#endif
    first = 0; return 1;               /* we read something */
}

writehdr(hdr,f)                        /* write a header to an archive */
struct heads *hdr;                     /* header to write */
FILE *f;                               /* archive to write to */
{
#ifdef OSK
	struct heads temphdr;
#endif

#ifdef DEBUG
	puts ("writehdr");
#endif
    fputc(ARCMARK,f);                 /* write out the mark of ARC */
    fputc(hdrver,f);                  /* write out the header version */

    if(!hdrver)                        /* if that's the end */
	{
#ifdef DEBUG
		puts ("writehdr: hdrver=0: returning");
        return;                       /* then write no more */
#endif
	}
#ifdef OSK
	{
		char *ptr;
		int i;
/*
 *	copy hdr to temphdr
 */		
		_strass (&temphdr, hdr, sizeof (struct heads));
		
		temphdr.length = longswap(temphdr.length);
		temphdr.size   = longswap(temphdr.size);
		temphdr.date   = (unsigned short)wordswap(temphdr.date);
		temphdr.time   = (unsigned short)wordswap(temphdr.time);
		temphdr.crc    = (short)(wordswap(temphdr.crc) & 0xffff);
		ptr = (char *)&temphdr;

		for (i=13; i<sizeof(struct heads)-1; i++)
		{
			*(ptr+i) = *(ptr+i+1);
		}
	}
    fwrite(&temphdr,sizeof(struct heads)-1,1,f);
#else
    fwrite(hdr,sizeof(struct heads),1,f);
#endif
    /* 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;
    }
#ifdef DEBUG
	puts ("writehdr returning");
#endif
}

filecopy(f,t,size)                     /* bulk file copier */
FILE *f, *t;                           /* from, to */
long size;                             /* number of bytes */
{
    int len;                           /* length of a given copy */
#ifdef DEBUG
	printf("filecopy: size = %ld\n",size);
#endif
    while(size--)                      /* while more bytes to move */
         putc_tst(fgetc(f),t);
}     
	  
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)
		{
/*
 *	next line added for OS-9
 */
#ifdef OSK
              if (c != 0xff)
#endif
				exit (_errmsg(1,"Write fail (disk full?)"));
		}
}
//E*O*F arcio.c//

exit 0
-------------------------------------
The views expressed in OS-9 Discussions are those of the individual authors
only.  Copies of digests are available by mail request.
------
Moderator:  John Daleske   cbosgd!cbdkc1!daleske    daleske@cbdkc1.ATT.COM
Submissions should go to:  cbosgd!os9               os9@cbosgd.ATT.COM
Comments to the moderator  cbosgd!os9-request       os9-request@cbosgd.ATT.COM

*********************
End of OS-9 Discussions
*********************