[unix-pc.sources] Arc v5.21

egray@fthood.UUCP (01/02/89)

Howdy netlanders...

I've gotten a few request lately to post my version of the Arc v5.21
source that contains the squashing algorithm.

This is part 1 (of 6) to the Arc v5.21 distribution package.

This distribution of Arc v5.21 was derived almost entirely from work by
Howard Chu (uunet!umix!hyc).  This code includes the five offical patches
(patch #1, patch #1b, patch #2, patch #2b, and patch #3).

With the use of the preprocessor definition LOCAL, you can include my
local enhancements and changes.  The following changes were made:

	1) By default, Unix file names are changed to meet MSDOS
	file name restrictions when added to an archive.  Also, 
	file names are folded to lowercase when extracted.  This
	feature can be disabled by the use of the -z option.

	2) Duplicate file names no longer cause a fatal error, the
	second file name is mearly skipped.

This version is somewhat specific to the AT&T Unix PC 7300/3b1 (all
the wierd stuff is in scandir.c and tmclock.c).

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Arc521.doc
# This archive created: Sun Jan  1 12:48:03 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Arc521.doc'" '(54142 characters)'
if test -f 'Arc521.doc'
then
	echo shar: "will not over-write existing file 'Arc521.doc'"
else
sed 's/^X//' << \SHAR_EOF > 'Arc521.doc'
X
X
X
X
X
X
X
X
X
X
X
X
X                          ARC
X
X                 File Archive Utility
X                     Version 5.20
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X                 (C)COPYRIGHT 1985,86
X                          by
X          System Enhancement Associates, Inc.
X                  ALL RIGHTS RESERVED
X
X
X
X
X
XThis document describes version 5.20 of the ARC file
Xutility, which was created by System Enhancement
XAssociates, Inc. in October of 1986.
X
X
X       TABLE OF CONTENTS
X
X
X
XSection                                           Page
X
X
XIntroduction  ....................................   1
XUsing ARC  .......................................   3
XARC commands  ....................................   5
X    Adding files  ................................   5
X    Extracting files  ............................   7
X    Deleting files  ..............................   8
X    Listing archive entries  .....................   8
X    Running files  ...............................  10
X    Printing files  ..............................  11
X    Testing an archive  ..........................  11
X    Converting an archive  .......................  12
XARC options  .....................................  13
X    Suppressing compression  .....................  13
X    Backup retention  ............................  14
X    Message suppression  .........................  15
X    Encryption/Decryption  .......................  17
XRAMdisk support  .................................  18
XMARC  ............................................  19
XARCE  ............................................  20
XVersion numbers  .................................  21
XCommon questions and answers  ....................  22
XMaintenance contracts  ...........................  24
XRevision history  ................................  25
X    Changes in version 3  ........................  25
X    Changes in version 4  ........................  25
X    Changes in version 4.1  ......................  26
X    Changes in version 4.3  ......................  26
X    Changes in version 4.4  ......................  27
X    Changes in version 4.5  ......................  27
X    Changes in version 5.0  ......................  28
X    Changes in version 5.1  ......................  29
X    Changes in version 5.2  ......................  30
XProgram history and credits  .....................  31
XBulletin boards  .................................  33
XSite licenses  ...................................  34
X
X
X
X
X
X
X
X
X
X
X
X
X
X         INTRODUCTION
X
X
X
XARC is the copyrighted property of System Enhancement
XAssociates, Inc.  You are granted a limited license to
Xuse ARC, and to copy it and distribute it, provided
Xthat the following conditions are met:
X
X1) No fee may be charged for such copying and
X   distribution.
X
X2) ARC may ONLY be distributed in its original,
X   unmodified state.
X
X3) ARC may *not* be distributed, in whole or in part, as
X   part of any commercial product or service without
X   the express written permission of System
X   Enhancement Associates.
X
X
XContributions for the use of this program will be
Xappreciated, and should be sent to:
X
X          System Enhancement Associates, Inc.
X             21 New Street, Wayne NJ 07470
X
XYou may not use this product in a commercial
Xenvironment or a governmental organization without
Xpaying a license fee of $35.  Site licenses and
Xcommercial distribution licenses are available.  A
Xprogram disk and printed documentation are available
Xfor $50.  See the order form enclosed with this manual
Xfor more details.
X
X
X
XARC is user supported software.  This means that you
Xmay copy it freely and give the copies away to anyone
Xyou wish, at no cost.  They are in turn requested to
Xsend in a contribution if they decide to use it.
X
XThe user supported software concept (often referred to
Xas "shareware") is an attempt to provide software at low
Xcost.  The cost of offering a new product by
Xconventional means is staggering, and hence dissuades
Xmany independent authors and small companies from
Xdeveloping and promoting their ideas.  User supported
Xsoftware is an attempt to develop a new marketing
Xchannel, where products can be introduced at low cost.
X
X
X
X
XARC                                              Page 1
XIf user supported software works, then everyone will
Xbenefit.  The user will benefit by receiving quality
Xproducts at low cost, and by being able to "test
Xdrive" software thoroughly before purchasing it.  The
Xauthor benefits by being able to enter the commercial
Xsoftware arena without first needing large sources of
Xventure capital.
X
XBut it can only work with your support.  We're not
Xjust talking about ARC here, but about all user
Xsupported software.  If you obtain a user supported
Xprogram from a friend or colleague, and are still
Xusing it after a couple of weeks, then it is obviously
Xworth something to you, and a contribution should be
Xsent.
X
X
X
XAnd now, back to ARC:
X
XARC is used to create and maintain file archives.  An
Xarchive is a group of files collected together into
Xone file in such a way that the individual files may
Xbe recovered intact.
X
XARC is different from other archive and library
Xutilities in that it automatically compresses the
Xfiles being archived, so that the resulting archive
Xtakes up a minimum amount of space.
X
XWhen ARC is used to add a file to an archive it
Xanalyzes the file to determine which of three storage
Xmethods will result in the greatest savings.  These
Xthree methods are:
X
X1) No compression; the file is stored as is.
X
X2) Repeated-character compression; repeated sequences
X   of the same byte value are collapsed into a three-
X   byte code sequence.
X
X3) Dynamic Lempel-Zev compression;  the file is stored
X   as a series of variable size bit codes which
X   represent character strings, and which are created
X   "on the fly".
X
XNote that since one of the three methods involves no
Xcompression at all, the resulting archive entry will
Xnever be larger than the original file.
X
X
X
X
X
XARC                                              Page 2
X           USING ARC
X
X
X
XARC is invoked with a command of the following format:
X
X    ARC <x> <arcname> [<template> . . .]
X
XWhere:
X
X    <x> is an ARC command letter (see below), in
X    either upper or lower case.
X
X    <arcname> is the name of the archive to act on,
X    with or without an extension.  If no extension is
X    supplied, then ".ARC" is assumed.  The archive
X    name may include path and drive specifiers.
X
X    <template> is one or more file name templates.
X    The "wildcard" characters "*" and "?" may be used.
X    A file name template may include a path or drive
X    specifier, though it isn't always meaningful.
X
X
XIf ARC is invoked with no arguments (by typing "ARC",
Xand pressing "enter"), then a brief command summary is
Xdisplayed.
X
X
X
XFollowing is a brief summary of the available ARC
Xcommands:
X
X    a   = add files to archive
X    m   = move files to archive
X    u   = update files in archive
X    f   = freshen files in archive
X    d   = delete files from archive
X    x,e = extract files from archive
X    r   = run files from archive
X    p   = copy files from archive to standard output
X    l   = list files in archive
X    v   = verbose listing of files in archive
X    t   = test archive integrity
X    c   = convert entry to new packing method
X
X
X
X
X
X
X
X
X
XARC                                              Page 3
XFollowing is a brief summary of the available ARC
Xoptions, which may alter how a command works:
X
X    b   = retain backup copy of archive
X    s   = suppress compression (store only)
X    w   = suppress warning messages
X    n   = suppress notes and comments
X    o   = overwrite existing files when extracting
X    g   = encode or decode archive entry
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                              Page 4
X         ARC COMMANDS
X
X
X
XThis section describes each of the commands.  ARC will
Xaccept any one command at a time.  If no commands are
Xgiven, then a brief command list is displayed.
X
X
X
XADDING FILES
X
XFiles are added to an archive using the "A" (Add), "M"
X(Move), "U" (Update), or "F" (Freshen) commands.  Add
Xalways adds the file.  Move differs from Add in that
Xthe source file is deleted once it has been added to
Xthe archive.
X
XUpdate differs from Add in that the file is only added
Xif it is not already in the archive, or if it is newer
Xthat the corresponding entry in the archive.
X
XFreshen is similar to Update, except that new files
Xare not added to the archive; only files already in
Xthe archive are updated.
X
X
XFor example, if you wish to add a file named
X"TEST.DAT" to an archive named "MY.ARC", you would use
Xa command of the form:
X
X    ARC a my test.dat
X
XIf you wanted to add all files with a ".C" extension,
Xand all files named "STUFF" to an archive named
X"JUNK.ARC", you could type:
X
X    ARC a junk *.c stuff.*
X
XIf you wanted to move all files in your current
Xdirectory into an archive named "SUM.ARC", you could
Xuse a command of the form:
X
X    ARC m sum *.*
X
XIf you have an archive named "TEXT.ARC", and you
Xwanted to add to it all of your files with an
Xextension of ".TXT" which have been created or changed
Xsince they were last archived, then you would type:
X
X    ARC u text *.txt
X
X
X
XARC                                              Page 5
XIf you have a bunch of files in your current
Xdirectory, with backup copies being stored in an
Xarchive named "SAFE.ARC", then if you wanted to make
Xsure that every file in the archive is the latest
Xversion of that file, you would type:
X
X    ARC f safe
X
X
XA word about Update and Freshen:  These are similar in
Xthat they look at the date and time of last change on
Xthe file, and only add it if the file has been changed
Xsince it was last archived.  They differ in that
XUpdate will add new files, while Freshen will not.
X
XIn other words, Update looks for the files on disk,
Xand adds them if they are new or have changed, while
XFreshen looks in the archive, and tries to update the
Xfiles which are already there.
X
X
XArchive entries are always maintained in alphabetic
Xorder.  Archive entries may not have duplicate names.
XIf you add a file to an archive that already contains
Xa file by that name, then the existing entry in the
Xarchive is replaced.  Also, the archive itself and its
Xbackup will not be added.
X
XYou may also add a file which is in a directory other
Xthan your current directory.  For example, it is
Xperfectly legal to type:
X
X    ARC a junk c:\dustbin\stuff.txt
X
XYou cannot add two files with the same name.  In other
Xwords, if you have a file named "C:\DUSTBIN\STUFF.TXT"
Xand another file named "C:\BUCKET\STUFF.TXT", then
Xtyping:
X
X    arc a junk c:\dustbin\*.* c:\bucket\*.*
X
Xwill not work.
X
X
XARC does not save the path name.  In other words, if
Xyou specify a drive and/or path when adding a file,
Xonly the actual file name is stored in the archive.
X
X
X
X
X
X
X
XARC                                              Page 6
XARC will never add an archive to itself, nor will it
Xadd the temporary copy or a backup copy of the
Xarchive.
X
X
XAn interesting note:  It has been brought to our
Xattention that BASIC programs compress to a smaller
Xsize when they are *not* tokenized.  If you are more
Xconcerned with space than speed, you may wish to
Xconvert your BASIC programs to ASCII form before
Xadding them to an archive.  Your BASIC manual should
Xgive instructions on how to do this.
X
X
X
XEXTRACTING FILES
X
XArchive entries are extracted with the "E" (Extract)
Xand "X" (eXtract) commands.  For example, if you had
Xan archive named "JUNK.ARC", and you wanted all files
Xin it with an extension of ".TXT" or ".DOC" to be
Xrecreated on your disk, you could type:
X
X    ARC x junk *.txt *.doc
X
XIf you wanted to extract all of the files in an
Xarchive named "JUNK.ARC", you could simply type:
X
X    ARC x junk
X
XWhatever method of file compression was used in
Xstoring the files is reversed, and uncompressed copies
Xare created in the current directory.
X
XYou can also specify a path name, in which case the
Xdecompressed copy is placed in the specified
Xdirectory.  For example, if you had an archive named
X"JUNK.ARC", and you wanted all files in it with an
Xextension of ".TXT" to be placed in the directory
X"C:\WASTE\LAND", then you could type:
X
X    ARC x junk c:\waste\land\*.txt
X
XIf you wanted to put the file "TRASH.TXT" on your A:
Xdrive, and the file "LITTER.TXT" on your B: drive, you
Xcould type:
X
X    ARC x junk a:trash.txt b:litter.txt
X
X
X
X
X
X
XARC                                              Page 7
XIf you give more than one path for a file, then only
Xthe first one is used.  For example, if you typed:
X
X    ARC x junk a:trash.txt b:trash.txt
X
Xthen TRASH.TXT will be placed on your A: drive.
X
X
X
XDELETING FILES
X
XArchive entries are deleted with the "D" (Delete)
Xcommand.  For example, if you had an archive named
X"JUNK.ARC", and you wished to delete all entries in it
Xwith a filename extension of ".C", you could type:
X
X    ARC d junk *.c
X
X
X
XLISTING ARCHIVE ENTRIES
X
XYou can obtain a list of the contents of an archive by
Xusing the "L" (List) command or the "V" (Verbose list)
Xcommand.  For example, to see what is in an archive
Xnamed "JUNK.ARC", you could type:
X
X    ARC l junk
X
XIf you are only interested in files with an extension
Xof ".DOC", then you could type:
X
X    ARC l junk *.doc
X
X
XARC prints a short listing of an archive's contents
Xlike this:
X
X    Name          Length    Date
X    ============  ========  =========
X    ALPHA.TXT         6784  16 May 85
X    BRAVO.TXT         2432  16 May 85
X    COCO.TXT           256  16 May 85
X            ====  ========
X    Total      3      9472
X
X
X"Name" is simply the name of the file.
X
X
X
X
X
X
XARC                                              Page 8
X"Length" is the unpacked file length.  In other words,
Xit is the number of bytes of disk space which the file
Xwould take up if it were extracted.
X
X"Date" is the date on which the file had last been
Xmodified, as of the time when it was added to the
Xarchive.
X
X"Total" is pretty obvious, I think.
X
X
XARC prints a verbose listing of an archive's contents
Xlike this:
X
XName          Length    Stowage    SF   Size now  Date       Time    CRC
X============  ========  ========  ====  ========  =========  ======  ====
XALPHA.TXT         6784  Crunched   35%      4413  16 May 85  11:53a  8708
XBRAVO.TXT         2432  Crunched   41%      1438  16 May 85  11:53a  5BD6
XCOCO.TXT           256   Packed     5%       244  16 May 85  11:53a  3AFB
X        ====  ========            ====  ========
XTotal      3      9472             27%      6095
X
X
X"Name", "Length", and "Date" are the same as for a
Xshort listing.
X
X"Stowage" is the compression method used.  The
Xfollowing compression methods are currently known:
X
X       --          No compression.
X
X     Packed        Runs of repeated byte values are
X                   collapsed.
X
X    Crunched       Lempel-Zev compression technique
X                   employed.
X
X    Squeezed       Huffman encoding compression
X                   technique, as employed by an
X                   earlier version of ARC.
X
X"SF" is the stowage factor.  In other words, it is the
Xpercentage of the file length which was saved by
Xcompression.  The total stowage factor is the stowage
Xfactor for the archive as a whole, not counting
Xarchive overhead.
X
X"Size now" is the number of bytes the file is
Xoccupying while in the archive.
X
X
X
X
X
XARC                                              Page 9
X"Time" is the time of last modification, and is
Xassociated with the date of last modification.
X
X"CRC" is the CRC check value which has been stored
Xwith the file.  Another CRC value will be calculated
Xwhen the file is extracted or tested to ensure data
Xintegrity.  There is no especially good reason for
Xdisplaying this value.
X
X
X
XRUNNING FILES
X
XArchive entries may be run without being extracted by
Xuse of the "R" (Run) command.  For example, if you had
Xan archive named "JUNK.ARC" which contained a file
Xnamed "LEMON.COM", which you wished to run, you could
Xtype:
X
X    ARC r junk lemon
X
XYou can run any file from an archive which has an
Xextension of ".COM", ".EXE", ".BAT", or ".BAS".  You
Xdo not have to specify the extension, but all matching
Xfiles are run if you do not.  In other words, if you
Xhad an archive named "JUNK.ARC" which contained the
Xfiles "LEMON.COM", "LEMON.EXE", and "LEMON.BAS", and
Xyou typed:
X
X    ARC r junk lemon
X
XThen all three programs will be run.  You can avoid
Xthis by specifying an extension in this case.
X
XYou can give arguments to the program you are running
Xby appending them to the command line.  For example,
Xif you have an archive named "JUNK.ARC" which contains
Xa program named "LEMON.COM", and you wanted to run it
Xgiving it the argument "JUICE", you would type:
X
X    ARC r junk lemon juice
X
XYou will need a fair amount of memory to run a program
Xfrom an archive.  It probably cannot be done with less
Xthan 256k.
X
X
X
X
X
X
X
X
X
XARC                                             Page 10
XIn practice, the file to be run is extracted, run, and
Xthen deleted.  In other words, the above example is
Xequivalent to:
X
X    ARC x junk lemon.com
X    lemon juice
X    erase lemon.com
X
XIf you have an archive which contains a program that
Xyou will be running often, then you should probably
Xextract the program from the archive and use it
Xnormally.
X
X
X
XPRINTING FILES
X
XArchive entries may be examined with the "P" (Print)
Xcommand.  This works the same as the Extract command,
Xexcept that the files are not created on disk.
XInstead, the contents of the files are written to
Xstandard output.  For example, if you wanted to see
Xthe contents of every ".TXT" file in an archive named
X"JUNK.ARC", but didn't want them saved on disk, you
Xcould type:
X
X    ARC p junk *.txt
X
XIf you wanted them to be printed on your printer
Xinstead of on your screen, you could type:
X
X    ARC p junk *.txt >prn
X
X
X
XTESTING AN ARCHIVE
X
XThe integrity of an archive may be tested by use of
Xthe "T" (Test) command.  This checks to make sure that
Xall of the file headers are properly placed, and that
Xall of the files are in good shape.
X
XThis can be very useful for critical archives, where
Xdata integrity must be assured.  When an archive is
Xtested, all of the entries in the archive are unpacked
X(without saving them anywhere) so that a CRC check
Xvalue may be calculated and compared with the recorded
XCRC value.
X
X
X
X
X
X
XARC                                             Page 11
XFor example, if you just received an archive named
X"JUNK.ARC" over a phone line, and you want to make
Xsure that you received it properly, you could type:
X
X    ARC t junk
X
XIt defeats the purpose of the T command to combine it
Xwith N or W.
X
X
X
XCONVERTING AN ARCHIVE
X
XThe "C" (Convert) command is used to convert an
Xarchive entry to take advantage of newer compression
Xtechniques.  This is occasionally desirable when a new
Xversion of ARC is released.  Please refer to the
Xrevision history section for details on when new
Xcompression methods were implemented.
X
XFor example, if you had an archive named "JUNK.ARC",
Xand you wanted to make sure that all files with an
Xextension of ".DOC" were encoded using the very latest
Xmethods, you could type:
X
X    ARC c junk *.doc
X
XOr if you wanted to convert every file in the archive,
Xyou could type:
X
X    ARC c junk
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 12
X          ARC OPTIONS
X
X
X
XThis section describes the options which are available
Xto modify how ARC works.  Any of these options can be
Xcombined with any of the commands, though the result
Xmay not always be something you'd want to do.
X
X
X
XSUPPRESSING COMPRESSION
X
XThe "S" (Suppress compression) option can be combined
Xwith any command that updates archive entries.  These
Xinclude Add, Move, Update, Freshen, and Convert.  The
Xeffect of the S option is to prevent any compression
Xtechniques from being employed.  This is intended to
Xallow you to add a few files at a time to an archive
Xquickly, and then later convert the archive to
Xcompress everything at once.
X
XFor example, over the course of a day you might give
Xeach of the following commands:
X
X    ARC as junk *.txt
X    ARC as junk *.mac
X    ARC as junk *.doc
X
XAt the end of the day, when you have finished adding
Xthings to the archive, you could have all of the
Xarchive entries compressed at once by typing:
X
X    ARC c junk
X
XYou could also decompress the archive by typing:
X
X    ARC cs junk
X
Xthough I can't imagine why you'd want to.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 13
XBACKUP RETENTION
X
XWhen ARC changes an archive (during an Add, Move,
XUpdate, Freshen, Delete, or Convert) it creates a new
Xarchive with the same name, but with an extension of
X".$$$".  For example, if you add a file to an archive
Xnamed STUFF.ARC, then ARC will create a new archive
Xnamed STUFF.$$$.  ARC will read from your existing
Xarchive and write out the new archive with any changes
Xto the ".$$$" copy.
X
XNormally when ARC is finished it deletes the original
Xand renames the new archive to the original name (ie.
XSTUFF.ARC goes away, and STUFF.$$$ becomes the new
XSTUFF.ARC).  Among other things, this means that if
Xanything goes wrong and ARC is unable to finish, then
Xyour original archive will still be intact.
X
X
XIn some circumstances you may wish to retain the
Xoriginal version of the archive as a backup copy.  You
Xcan do this easily by using the Backup option.  Add
Xthe letter "B" to your command, and ARC will rename
Xyour original archive to have an extension of ".BAK"
Xinstead of deleting it.
X
X
XIn other words, if you wanted to add "WASTE.TXT" to an
Xarchive named "JUNK.ARC", but wanted to keep a backup
Xcopy, then you would type:
X
X    ARC ab junk waste.txt
X
XYour original archive would become "JUNK.BAK", while
X"JUNK.ARC" would contain the new "WASTE.TXT" file.
X
X
XIf you keep a backup of an archive which already has a
Xbackup, then the older backup copy is deleted.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 14
XMESSAGE SUPPRESSION
X
XARC prints three types of messages: warnings,
Xcomments, and errors.
X
XWarnings are messages about suspected error
Xconditions, such as when a file to be extracted
Xalready exists, or when an extracted file fails the
XCRC error check.  Warnings may be suppressed by use of
Xthe "W" (Warn) command.  You should use this command
Xsparingly.  In fact, you should probably not use this
Xcommand at all.
X
XComments (or notes) are informative messages, such as
Xnaming each file as it is added to the archive.
XComments and notes may be suppressed by use of the "N"
X(Note) command.
X
XErrors are actual system problems, such as running out
Xof disk space.  You cannot suppress errors.
X
X
XFor example, suppose you extracted all files with an
Xextension of ".BAS" from an archive named "JUNK.ARC"
XThen, after making some changes which you decide not
Xto keep, you decide that you want to extract them all
Xagain, but you don't want to be asked to confirm every
Xone.  In this case, you could type:
X
X    ARC xw junk *.bas
X
XOr, if you are going to add a hundred files with an
Xextension of ".MSG" to an archive named "TRASH.ARC",
Xand you don't want ARC to list them as it adds them,
Xyou could type:
X
X    ARC an trash *.msg
X
XOr, if you want to extract the entire contents of an
Xarchive named "JUNK.ARC", and you don't want to hear
Xanything, then type:
X
X    ARC xnw junk
X
X
XA special case is provided when extracting files from
Xan archive.  One of the various warnings that can
Xoccur is when a file being extracted already exists on
Xdisk.  Normally, ARC will stop and ask you if you want
Xto overwrite the file.  This can be suppressed with
Xthe "W" command, but that will also suppress any
X
X
X
XARC                                             Page 15
Xwarnings about other things, like failed CRC checks
Xand such.
X
XThe "O" (Overwrite) option suppresses *only* the warning
Xthat the file already exists.  For example, in our
Xearlier case of extracting all the ".BAS" files from
X"JUNK.ARC", a much safer way to do it is to type:
X
X    ARC xo junk *.BAS
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 16
XENCRYPTION/DECRYPTION
X
XArchive entries may be encrypted and decrypted by
Xusing the "G" (Garble) option.  The Garble option
Xtakes the remainder of the command string as the
Xpassword to use, so it must be the *last* option.
X
X
XFor example, if you wanted to add a file named
X"WASTE.TXT" to an archive named "JUNK.ARC", and you
Xwanted to encrypt it using the password "DEBRIS", then
Xyou would type:
X
X    ARC agdebris junk waste.txt
X
XLater on, when you want to extract it again, you would
Xtype:
X
X    ARC xgdebris junk waste.txt
X
XThe password you supply is used to encrypt (or
Xdecrypt) the archive entry by performing an exclusive
XOR between each byte of the packed data and each byte
Xof the password.  The password can be any length, and
Xeach of its bytes is used in rotation.  The password
Xis converted to uppercase before it is used, so it is
X*not* case sensitive.  Since the encryption is performed
Xon the packed data, it has no effect on stowage
Xfactors.
X
XThis is not a particularly sophisticated means of
Xencryption, and it is theoretically possible to crack.
XStill, since it is performed on the packed data, the
Xresult should be quite sufficient for casual use.
X
X
XYou can, if you wish, use different passwords for
Xdifferent files in an archive, but we advise against
Xit.  If you are going to encrypt an archive, we
Xsuggest you use the same password for every file, and
Xgive the password whenever you do anything at all with
Xthe archive.  It is possible to list the entries in an
Xencrypted archive using the "L" and "V" commands
Xwithout giving the password, but nothing else will
Xwork properly.
X
X
XWe advise that you use this option sparingly, if at
Xall.  If you should forget or mistype your password,
Xit is highly unlikely that you will ever recover your
Xdata.
X
X
X
XARC                                             Page 17
X        RAMDISK SUPPORT
X
X
X
XIf you have a RAMdisk, or other high-speed storage,
Xthen you can speed up ARC somewhat by telling it to
Xput its temporary files on the RAMdisk.  You do this
Xby setting the ARCTEMP environment string with the MS-
XDOS SET command.  For example, if drive B: is your
XRAMdisk, then you would type:
X
X    set ARCTEMP=B:
X
XRefer to the MS-DOS manual for more details about the
XSET command.  You need only set the ARCTEMP string
Xonce, and ARC will use it from then on until you
Xchange its value or reboot your system.
X
X
XIf ARC does not find an environment string named
XARCTEMP, then it looks for one named TEMP to use
Xinstead.  Several packages already use the TEMP string
Xfor exactly this purpose.  If you have need of an
Xenvironment string named TEMP for something else, then
Xyou should be sure to define ARCTEMP.
X
X
XThere are a limited number of temporary files created
Xby ARC.  The Convert command uses a file named
X"$ARCTEMP.CVT" to hold each file as it is being
Xconverted.  The Run command also creates a temporary
Xfile, which has the name "$ARCTEMP", and whose
Xextension matches that of the file being run.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 18
X             MARC
X
X
X
XMARC is a separate program which is used to merge
Xarchives created by ARC.  MARC moves files from one
Xarchive to another without unpacking them.
X
X
XMARC is used as follows:
X
X    MARC <target> <source> [<template> . . .]
X
XWhere:
X
X    <target> is the name of the archive to add files
X    to.
X
X    <source> is the name of the archive to read files
X    from.
X
X    <template> is one or more file name templates.
X    The wildcard characters "*" and "?" may be used.
X    If no template is supplied, then all of the files
X    in <source> are added to <target>.
X
XIt is not necessary for the target to exist.  If it
Xdoes not exist, then it is created.  Thus, MARC can be
Xused as an "extractor" as well as a "merger".
X
X
XFor example, if you wanted to create an archive named
X"JUNK.ARC", which is to contain all of the files with
Xan extension of ".TXT" which are currently contained
Xin another archive named "WASTE.ARC", then you could
Xtype:
X
X    MARC junk waste *.txt
X
XIf you wanted to create an archive named "JUNK.ARC",
Xwhich is to contain all of the files currently in the
Xarchives "WASTE.ARC" and "TRASH.ARC", you could type:
X
X    MARC junk waste
X    MARC junk trash
X
X
XIf MARC is invoked with no arguments, then it gives
Xbrief directions in its use.
X
X
X
X
X
XARC                                             Page 19
X             ARCE
X
X
X
XARCE is a program which is used to extract files from
Xan archive.  It will *only* extract files, and it will
X*not* extract encrypted files.  It doesn't do anything
Xthat ARC can't do, but it is highly optimized for the
Xsole purpose of archive extraction, so it is very
Xsmall and very fast.
X
XARCE is used in a fashion very similar to the "ARC E"
Xcommand (hence the name).  The first argument is the
Xname of the archive to extract files from, and may
Xinclude a drive and path specifier.  Up to sixteen
Xadditional arguments can be supplied, which specify
Xthe files to extract.  The wildcard characters "*" and
X"?" are allowed, as with ARC.  If no files are named,
Xthen all files are extracted from the archive.  If the
Xfile being extracted already exists, you are asked
Xwhether or not you want to overwrite it.  You can use
Xthe "/R" option to bypass this.
X
XFor example, if you had an archive named "WASTE.ARC"
Xthat you wanted to extract everything from, then you
Xcould type:
X
X    ARCE waste
X
XOr if you just wanted to extract the files with a
Xfilename extension of ".ASM", you could type:
X
X    ARCE waste *.asm
X
XIf you already have a few files from the archive that
Xyou want replaced, then you could type:
X
X    ARCE waste *.asm /R
X
XIf you run ARCE with no arguments at all, then it will
Xgive you a brief reminder of how to use it.
X
X
XNOTICE:NOTICE: ARCE is the copyrighted property of Vernon D.
X        Buerg and Wayne Chin.  It is included on the
X        ARC program disk as a service to ARC users.
X
X        Vernon D. Buerg
X        456 Lakeshire Drive
X        Daly City, CA  94015
X        RBBS: (415) 994-2944
X
X
X
XARC                                             Page 20
X        VERSION NUMBERS
X
X
X
XThere seems to be some confusion about our version
Xnumbering scheme.  All of our version numbers are
Xgiven as a number with two decimal places.
X
XThe units indicate a major revision, such as adding a
Xnew packing algorithm.
X
XThe first decimal place (tenths) indicates a minor
Xrevision that is not essential, but which may be
Xdesired.
X
XThe second decimal place (hundredths) indicates a
Xtrivial revision that will probably only be desired by
Xspecific individuals or by die-hard "latest version"
Xfanatics.
X
XARC also displays its date and time of last edit.  A
Xchange of the date and time without a corresponding
Xchange in version number indicates a truly trivial
Xchange, such as fixing a spelling error.
X
X
XTo sum up: If the units change, then you should get
Xthe newer version as soon as you can.  If the tenths
Xchange, then you may want to get the newer version,
Xbut there's no hurry.  If anything else changes, then
Xyou probably shouldn't bother.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 21
X COMMON QUESTIONS AND ANSWERS
X
X
X
XHere are some of the more common questions we've
Xreceived about ARC, along with their answers:
X
X
XQ: Why does ARC run out of room if I make an archive
X   bigger than about 180k?
X
XA: Because you are working on a floppy disk.  ARC
X   creates a copy of your archive, incorporating any
X   new files as it goes.  When it is done, it deletes
X   the original and renames the new one.  There are a
X   number of reasons for doing it this way, one being
X   that your original archive is still intact if
X   anything happens while ARC is running.
X
X   You can save some space by using drive specifiers
X   and having the archive and the files to add on
X   separate disks, but you still won't be able to make
X   an archive larger than about 180k.  If you need to
X   make a larger archive, and if you have a fixed
X   disk, then you can create the archive on the fixed
X   disk and then copy it to the floppy.
X
X
XQ: I've seen an ARC.COM and an ARC.EXE.  Which one is
X   the right one?
X
XA: ARC.EXE.  One or more people have been running ARC
X   through a utility that converts an ".EXE" file to a
X   ".COM" file.  But this utility is designed to save
X   space, not speed.  On ARC it saves about 250 bytes,
X   and makes no measurable difference in program
X   speed.  We've decided that the savings are not
X   worth the extra step in development in this case.
X
X
XQ: How can I get the latest version of ARC?
X
XA: ARC updates are distributed through normal
X   shareware channels, and by FidoNet.  We also ship a
X   program update disk on every order of $50 or more.
X   Also, please refer to the next section for
X   information about our maintenance contracts.
X
X
X
X
X
X
X
XARC                                             Page 22
XQ: Can I use ARC to distribute my public domain or
X   shareware program?
X
XA: Yes, of course.
X
X
XQ: Can I use ARC to distribute my commercial software
X   package?
X
XA: Yes, provided that you obtain a commercial
X   distribution license from us.  Please contact us
X   for details.
X
X
XQ: I'm a commercial user.  Why should I pay for
X   shareware that others get for free?
X
XA: Because you cannot credibly plead poverty.
X              ___   Shareware, all shareware, is an attempt to develop
X   a new marketing channel to the benefit of everyone.
X   You can still "test drive" shareware for a short
X   period, but if you decide to use it in your
X   business, then you should pay for it.
X
X
XQ: Why not allow me to select which method of
X   compression I want ARC to use?
X
XA: It would needlessly complicate ARC, both internally
X   and in use.  The exact nature of the compression
X   methods used are complex, and quite different.  The
X   only sure way to tell which will be best in any
X   given case is to analyze the data, as ARC does.
X   The method chosen may not always be what you
X   expect.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 23
X     MAINTENANCE CONTRACTS
X
X
X
XRegistered users of ARC receive 90 days of telephone
Xsupport at no extra charge.  If you wish, you can
Xextend this by pruchasing a maintenance contract.
X
XA maintenance contract costs $50 per year and entitles
Xyou to unlimited telephone support, as well as free
Xupdates to ARC as they come out.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 24
X       REVISION HISTORY
X
X
X
XCHANGES IN VERSION 3
X
XThe function used to calculate the CRC check value in
Xprevious versions has been found to be in error.  It
Xhas been replaced with the proper function.  ARC will
Xstill read archives created with earlier versions of
XARC, but it will report a warning that the CRC value
Xis in error.  All archives created prior to version
X3.0 should be unpacked and repacked with the latest
Xversion of ARC.
X
X
XTransmitting a file with XMODEM protocol rounds the
Xsize up to the next multiple of 128 bytes, adding
Xgarbage to the end of the file.  This used to confuse
XARC, causing it to think that the end of the archive
Xwas invalidly formatted.  This has been corrected in
Xversion 3.01.  Older archives may still be read, but
XARC may report them to be improperly formatted.  All
Xfiles can be extracted, and no data is lost.  In
Xaddition, ARC will automatically correct the problem
Xwhen it is encountered.
X
X
X
XCHANGES IN VERSION 4
X
XARC is adding another data compression technique in
Xthis version.  We have been looking for some technique
Xthat could improve on Huffman squeezing in at least a
Xfew cases.  So far, Lempel-Zev compression seems to be
Xfulfilling our fondest hopes, often achieving
Xcompression rates as much as 20% better than
Xsqueezing, and sometimes even better.  Huffman
Xsqueezing depends on some bytes being more "popular"
Xthan others, taking the file as a whole.  Lempel-Zev
Xcompression is instead looking for strings of bytes
Xwhich are repeated at various points (such as an end
Xof line followed by spaces for indentation).  Lempel-
XZev compression is therefore looking for repetition at
Xa more "macro" level, often achieving impressive
Xpacking rates.
X
XIn the typical case a file is added to an archive once
Xand then extracted many times, so the increased time
Xfor an update should more than pay for itself in
Xincreased disk space and reduced transmission time.
X
X
X
XARC                                             Page 25
XCHANGES IN VERSION 4.1
X
XLempel-Zev coding has been improved somewhat by
Xperforming non-repeat compression on the data before
Xit is coded (as was already done with Huffman
Xsqueezing).  This has the two fold advantage of (a)
Xreducing to some extent the amount of data to be
Xencoded, and (b) increasing the time it takes for the
Xstring table to fill up.  Performance gains are small,
Xbut noticeable.
X
XThe primary changes are in internal organization.  ARC
Xis now much "cleaner" inside.  In addition to the
Xaesthetic benefits to the author, this should make
Xlife easier for the hackers out there.  There is also
Xa slight, but not noticeable, improvement in overall
Xspeed when doing an update.
X
X
X
XCHANGES IN VERSION 4.3
X
XVersion 4.3 adds the much-demanded feature of using
Xpathnames when adding files to an archive.
X
XVersion 4.3 is also using a slightly different
Xapproach when adding a file to an archive.  The end
Xresult is twofold:
X
X1) Slightly more disk space is required on the drive
X   containing the archive.  This should only be
X   noticeable to those creating very large archives on
X   a floppy based system.
X
X2) A 30% reduction in packing time has been achieved
X   in most cases.  This should be noticeable to
X   everyone.
X
XAs always, version 4.3 is still fully upwards
Xcompatible, and is backwards compatible as far as
Xversion 4.1.
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 26
XCHANGES IN VERSION 4.4
X
XThe temporary file introduced in version 4.3
Xoccasionally caused problems for people who had not
Xadded a FILES= statement to their CONFIG.SYS file.
XThis has now been corrected.  Also, support of the
XARCTEMP environment string was added to allow placing
Xof the temporary file on a RAMdisk.
X
XA bug was reported in the Run command, which has been
Xfixed.  From the nature of the bug, and the extreme
Xtime required before the bug was reported, it is
Xdeduced that the Run command is probably the least
Xused feature of ARC.
X
XThe Update command was changed.  It is no longer a
Xstraight synonym for Add.  Instead, Update now only
Xadds a file if it is newer than the version already in
Xthe archive, as shown by the MS-DOS date/time stamp.
X
X
X
XCHANGES IN VERSION 4.5
X
XThe Convert command was not making use of RAMdisk
Xsupport.  Now it is.
X
XThe Freshen command was added.  Our first choice for a
Xname was Refresh, but we already had a Run command.
XAssuming that you have an archive which already
Xcontains everything you want in it (for software
Xdistribution, perhaps), then Freshen would be used to
Xupdate the archive.  It was pointed out to us that ARC
Xalready knows what is in the archive, so it should be
Xable to look on disk for newer versions.  Now it can.
X
XThe Suppress compression option was added by popular
Xdemand.  It allows files to be added quickly to an
Xarchive, since the files are not analyzed or
Xcompressed, but merely stored straight.  The intent is
Xto allow users to build an archive "in pieces", and
Xthen compress all of the entries at once with the
XConvert command.  The conversion is much faster if you
Xtake advantage of RAMdisk support.
X
XA minor bug was detected in our handling of date/time
Xstamps which occasionally resulted in stamping an
Xarchive with the wrong date and time.  This has been
Xcorrected.
X
X
X
X
X
XARC                                             Page 27
XCHANGES IN VERSION 5.0
X
XThe Move command used to delete the files as it went.
XIt now waits until it is finished updating the
Xarchive, and deletes them all at once.  (You *did* know
Xthat Move is just an Add where the file gets deleted,
Xdidn't you?)  This, along with the changes made in
Xversion 4.5, means that it is now much safer to
Xinterrupt ARC while it is working.
X
XThe Print command no longer prints the name of each
Xfile.  Instead, it prints a formfeed after each file.
X
XThe Run command now supports BASICA programs.  Also,
Xthe filename extension is no longer required on the
XRun command.
X
XThe Garble option was added.  It provides a convenient
Xmeans of low level data security for the casual user.
XUse it sparingly, if at all.
X
XARC no longer tests for the presence of $ARCTEMP.CRN
Xbefore creating a new one.  If you interrupt ARC a
Xlot, you'll find this much more convenient.  If you
Xhappen to have a file named $ARCTEMP.CRN which you
Xwant to keep, too bad.
X
XImproved error recovery was added when reading an
Xarchive.  ARC now has a good chance of recovering the
Xdata from a corrupted archive (the corrupted entry is
Xstill lost, of course).
X
XPath support has been added for all commands, though
Xit doesn't do anything on most of them.  For example,
Xthere isn't much we can do with a path in the List
Xcommand.  But many users will be glad to know that a
Xpath can be used when extracting a file, and specifies
Xwhere the file is to be placed.
X
XSupport for the TEMP environment string was added.  If
XARC doesn't find an environment string named ARCTEMP,
Xthen it looks for one named TEMP to use instead.
XSeveral packages already use the TEMP string for
Xexactly this purpose.  With any luck, maybe we can get
Xa standard going.
X
X
X
X
X
X
X
X
X
XARC                                             Page 28
XARC is now using a different variation of Lempel-Zev
Xcoding, courtesy of Kent Williams, who found it on
XUSENET and adapted it to the IBM PC.  The new method
Xdiffers from the old in several respects.  The most
Xsignificant differences are:
X
X1) Where our previous implementation used a fixed code
X   size of twelve bits, the new one starts with a code
X   size of nine bits and increases it as it needs to.
X
X2) The earlier method tended to "choke" on large files
X   when its string table filled up.  The new method
X   has a rather ingenious scheme its authors call
X   "adaptive reset."  When it notices that its string
X   table has filled, and its compression ratio is
X   starting to suffer, it clears the table and starts
X   defining new strings.
X
XOur benchmarks show an improvement in compression on
Xthe order of 10% when crunching is used.
XAdditionally, ARC 5.0 is on the order of 23% faster at
Xadding a file when crunching is used, or 13% faster
Xwhen squeezing is used.  Extracting a file crunched
Xwith the new method is 27% faster than it is with the
Xold method.  Extraction of any other type of file
X(including those crunched with the older method) is no
Xfaster than before.  These figures are based on our
Xown benchmark tests; your results may vary.
X
XThe previous implementation of Lempel-Zev coding is no
Xlonger used to pack files.  The "V" (Verbose listing)
Xcommand distinguishes between the two by referring to
Xthe older method as "crunched" (with a lower-case
X"c"), and the newer method as "Crunched" (with a
Xcapital "C").
X
XARC 5.0 can still read archives created by earlier
Xversions of ARC, but once again it creates archives
Xwhich older versions cannot read.
X
X
X
XCHANGES IN VERSION 5.1
X
XRick Moore discovered that ARC was occasionally adding
Xan archive to itself.  This would only happen when the
Xarchive is in the same directory as the files being
Xadded, and its name comes last.  This bug has been
Xfixed, though it is still possible to fool ARC into
Xadding an archive to itself by getting tricky with
Xpath names.
X
X
X
XARC                                             Page 29
XDana Montgomery found the upper limit on how many
Xfiles can be added to an archive.  There's always been
Xan upper limit, but it depends on memory, and used to
Xbe larger than anyone could possibly want (knock on
Xwood).  However, the added memory requirements in
Xversion 5.0 lowered this limit into the realm of
Xpossibility, somewhere around 300 files.  We change
Xsome things around, and effectively, there is no
Xlonger a limit on how many files you can add at once.
XARC will add the files in batches of as many as it can
Xhandle at one time.
X
XWe've also introduced a new packaging method for ARC
Xand its documentation, since we are in the unique
Xposition of being unable to use ARC for this purpose.
XWe've created a program called ARC51.COM which, when
Xexecuted, attempts to create the ARC program and
Xmanual.  You must be in the same directory as
XARC51.COM when you run it.
X
X
X
XCHANGES IN VERSION 5.2
X
XWe've made some changes to Lempel-Zev coding to
Xfurther improve its compression ability on "poor fit"
Xfiles (mainly .EXE and .COM files).  The result is
Xthat crunching now works better than squeezing on
Xalmost all files, and comes close on most of the rest
X(within 5%, by our benchmarks).  Accordingly, we have
Xdropped Huffman encoding in this version.  Our
Xbenchmarks show a speed improvement of around 14% when
Xadding a file to an archive.
X
XA low-level file copy routine was implemented to speed
Xup bulk data moves.  Deleting or adding a file to a
Xlarge existing archive is now much faster.
X
XThe Run command has been modified to allow passing
Xcommand line arguments to the program being run.
X
XThe temporary file introduced in version 4.3 has been
Xeliminated.  Crunched output generated in the analysis
Xphase is now placed directly in the output archive,
Xand is rewritten if crunching turns out not to be the
Xbest choice.  This can, in rare circumstances, cause
Xan archive to be slightly larger than it should be,
Xbut it also makes ARC considerably faster at adding
Xfiles to an archive.
X
X
X
X
X
XARC                                             Page 30
X  PROGRAM HISTORY AND CREDITS
X
X
X
XIn its short life thus far, ARC has astounded us with
Xits popularity.  We first wrote it in March of 1985
Xbecause we wanted an archive utility that used a
Xdistributive directory approach, since this has
Xcertain advantages over the then popular central
Xdirectory approach.  We added automatic squeezing in
Xversion 2 at the prompting of a friend.  In version
X2.1 we added the code to test for the best compression
Xmethod.  In less than a year we found that our humble
Xlittle program had spread across the country, and
Xseems to have become a new institution.
X
XWe are thankful for the support and appreciation we
Xhave received.  We hope that you find this program of
Xuse.
X
X
XIf we have achieved greatness, it is because we have
Xstood upon the shoulders of giants.  Nothing is
Xcreated as a thing unto itself, and ARC is no
Xexception.  Therefore, we would like to give credit to
Xthe following people, without whose efforts ARC could
Xnot exist:
X
X
XBrian W. Kernighan and P. J. Plauger, whose book
X"Software Tools" provided many of the ideas behind the
Xdistributive directory approach used by ARC.
X
XDick Greenlaw, who wrote the public domain SQ and USQ
Xprograms, in which the Huffman squeezing algorithm was
Xfirst developed.
X
XRobert J. Beilstein, who adapted SQ and USQ to
XComputer Innovations C86 (the language we use), thus
Xproviding us with important parts of our squeezing
Xlogic.
X
XKent Williams, who graciously allowed us to use his
XLZWCOM and LZWUNC programs as a basis for our Lempel-
XZev compression logic, and who continues to make
Xvaluable contributions.
X
XDavid Schwaderer, whose article in the April 1985
Xissue of PC Tech Journal provided us with the logic
Xfor calculating the CRC 16 bit polynomial.
X
X
X
X
XARC                                             Page 31
XTerry A. Welch, whose article "A Technique for High
XPerformance Data Compression", IEEE Computer Vol 17 No
X6 (June 1984) seems to have started all the research
Xon Lempel-Zev coding.
X
XSpencer W. Thomas, Jim McKie, Steve Davies, Ken
XTurkowski, James A.  Woods, and Joe Orost, who are the
Xauthors of the UNIX compress utility.
X
XAlex Jacobs, who in June of 1985 sent us the very
Xfirst shareware contribution we ever received.
X
X
XAnd many, many others whom we could not identify.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 32
X        BULLETIN BOARDS
X
X
X
XARC is distributed mainly through shareware channels.
XAmong other things, this means that ARC is available
Xfrom many bulletin board systems.  In fact, the system
Xoperators (sysops) of many bulletin boards have taken
Xto storing almost all of their downloadable files in
Xarchives to save themselves disk space and to save
Xtheir users time.
X
XThis also makes things more convenient for the
Xbulletin board users, since one archive may contain
Xseveral programs, any related data files, and the
Xdocumentation.  Many shareware authors have taken to
Xdistributing their software in archives to help ensure
Xthat the users receive everything.
X
XObviously, we can't do that with ARC.  As a result,
Xmany of our users have ARC, but don't have the manual.
XMost of our customer support calls come from people
Xwho have never seen the manual, and in many cases
Xdidn't even know that one exists!
X
XTo solve this problem we developed what is in essence
Xa self-unpacking archive.  We distribute this as
X"ARCxxx.COM", where "xxx" is the current version
Xnumber.  For example, ARC version 5.20 would be
Xdistributed as "ARC520.COM".  This program, when run,
Xunpacks itself into a copy of ARC plus its
Xdocumentation.
X
XNow that we've gone to all that work, we'd really
Xappreciate it if you would use this program when you
Xdistribute ARC.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 33
X         SITE LICENSES
X
X
X
XCorporate users may wish to obtain a site license for
Xthe use of ARC.  Please use the order form in this
Xmanual to order a site license.  Site licenses are
Xgranted as of when we receive your payment.  License
Xfees vary depending on the number of computers on
Xwhich ARC will be used, as follows:
X
X     1 to  9 machines  $35 each
X    10 to 24 machines  $25 each
X    25 to 49 machines  $20 each
X    50 to 99 machines  $15 each
X    over  99 machines  $1500 one time fee
X
X
X
XEnclosed is a site license agreement, which should be
Xsigned and sent with your payment when ordering a
Xcommercial site license.
X
X
XA commercial site license does not include additional
Xcopies of the ARC program disk and the ARC manual.
XInstead, you make your own copies of the disk and
Xmanual as you need them.  If you wish, you can order
Xadditional program disks and manuals from us.
X
XAdditional program disks cost $10 each.  Additional
Xmanuals cost $20 each.  If you wish, you can order
Xprogram sets for $40 each.  A "program set" is a
Xprogram disk and manual enclosed in a vinyl binder.
XThere is a $50 minimum on all orders.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XARC                                             Page 34
X             SITE LICENSE APPLICATION
X
X
X
XThe use of ARC in a commercial environment or government organization
Xis granted under the following terms:
X
X1.  Payment of the license fee must be made to System Enhancement
X    Associates, Inc.  The fee is based on the number of computers
X    which will be used to run ARC, as follows:
X
X          1 to  9 machines  $35 each
X         10 to 24 machines  $25 each
X         25 to 49 machines  $20 each
X         50 to 99 machines  $15 each
X         over  99 machines  $1500 one time fee
X
X2.  You may use ARC on the number of computers included in the license
X    fee.  If you have paid the fee for over 99 machines, then you may
X    use ARC on any number of computers within your organization.
X
X3.  You may make copies of the program and documentation, in their
X    original,  unmodified form,  without restriction.  You may
X    distribute these copies without restriction.
X
X4.  If these copies are distributed outside of your organization,  you
X    have no obligation to control the use of those copies which are
X    outside of your organization.
X
X5.  You may make copies of the program documentation, in both its
X    printed form and machine readable form, without restriction.
X
X6.  You may use all future versions of ARC under this license.
X
X7.  You may *not* modify the program or charge a fee for copying or
X    distributing the program or its documentation.
X
X8.  It is your responsibility to make the necessary copies and to
X    deliver them to the computers which they will be used on.  If you
X    wish, you can order additional ARC program disks and manuals.
X
X9.  We are not responsible for *anything* that may happen or not happen
X    if you use ARC.  You're on your own.
X
X
X    I agree to abide by the terms and conditions of this license.
X
X    _____________________________         __________________________
X    Signature                             Date
X
X    _____________________________
X    Name (please print or type)
X
X    _____________________________
X    Title
X
X    _____________________________
X    Company
X
X
X                   ORDER FORM
X
X
X
XCheck which items you wish to purchase:
X
X    [] Noncommercial license for the use of ARC.
X
X    [] Commercial license for the use of ARC on ___ computers (see
X       attached price schedule and terms).
X
X    [] Program disk and documentation (only on orders of $50 or more,
X       not counting maintenance contracts).
X
X    [] ____ additional program disks at $10 per disk.
X
X    [] ____ additional manuals at $20 per manual
X
X    [] ____ additional program sets (disk, manual, and binder) at $40
X       per program set.
X
X    [] One year maintenance agreement at $50 per year.
X
X    [] Payment of $_____ is enclosed (check or money order).
X
X    [] Please charge $_____ to my [] Visa or [] MasterCard:
X
X      Card number:  _______________________________
X
X      Expiration date:  ___________________________
X
X      Signature:  _________________________________
X
X    _______________________________________________
X    Name
X
X    _______________________________________________
X
X
X    _______________________________________________
X    Address
X
X    ______________________   ________  ____________
X    City                     State     Zip
X
X    _______/_______
X    FidoNet address
X
X
XSend this completed form to:
X
X                  System Enhancement Associates, Inc.
X                     21 New Street, Wayne NJ 07470
X
XFor program disk orders outside the U.S., please add an additional $5,
Xand enclose an international money order payable in U.S. currency.
X
XFor commercial site license orders, please enclose a signed copy of
Xthe site license agreement.
X
SHAR_EOF
if test 54142 -ne "`wc -c < 'Arc521.doc'`"
then
	echo shar: "error transmitting 'Arc521.doc'" '(should have been 54142 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (01/02/89)

This is part 2 (of 6) to the Arc v5.21 distribution package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Arc.1
#	Arcinfo
#	Changes.521
#	Makefile
#	Manifest
#	README
#	Read.me
#	Readme.local
#	Readme.too
#	arc.c
#	arc.h
# This archive created: Sun Jan  1 12:48:09 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Arc.1'" '(7232 characters)'
if test -f 'Arc.1'
then
	echo shar: "will not over-write existing file 'Arc.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Arc.1'
X.TH ARC 1L "12 Jun 1988" "Local" "LOCAL COMMANDS"
X.SH NAME
Xarc \- pc archive utility
X.SH SYNOPSIS
X.B arc
Xa|m|u|f|d|x|e|r|p|l|v|t|c [ biswnoq ] [ g\fIpassword\fR ]
X.I archive 
X[ \fIfilename\fR ...]
X.SH DESCRIPTION
X.I Arc
Xis a general archive and file compression utility, used to maintain
Xa compressed archive of files.
XAn
X.I archive
Xis a single file that combines many files, reducing storage space
Xand allowing multiple files to be handled as one.
X.I Arc
Xuses one of several compression methods for each file within the
X.IR archive ,
Xbased on whichever method yields the smallest result.
X.SH INSTRUCTIONS
XExecute
X.I arc
Xwith no arguments for fairly verbose, usable instructions.
X.SH COMMAND SWITCHES
X.TP 3
Xa
Xadd files to archive.  Copies the indicated files to the archive.
X.TP
Xm
Xmove files to archive.  Same as 'a' switch except
Xthat the files are deleted from the directory as
Xthey are moved to the archive.
X.TP
Xu
Xupdate files in archive.  This switch will replace archived
Xfiles when the named file is newer than the archived copy.
XNew files will be added automatically.
X.TP
Xf
Xfreshen files in archive.  Same as 'u' except that
Xnew files will not be added.
X.TP
Xd
Xdelete files in archive.  The named files are removed from the archive.
X.TP
Xx,e
Xextract files from archive.  The named files are extracted
Xfrom the archive and created in the current directory
Xin an uncompressed state.
X.TP
Xr
Xrun one file with arguments from archive.  Any
Xprogram may be executed directly from the archive.
XThe parameters given after the program name are passed to
Xthe program without modification.
X.TP
Xp
Xcopy files from archive to standard output.  Useful
Xwith I/O redirection. A form-feed is appended after each file,
Xto ease use with printers.
X.TP
Xl
Xlist files in archive.  Limited information listing
Xof files contained in an archive.  Displays the
Xfilename, original length, and date last modified.
XIf the 'n' option (see below) is used, only the
Xfilename is displayed.
X.TP
Xv
Xverbose listing of files in archive.  Complete
Xinformation listing of files contained in an archive.
XDisplays the filename, original length, storage method,
Xstorage factor (% savings), compressed size, date, time,
Xand CRC.
X.TP
Xt
Xtest archive integrity.  Computes CRC values for each member of
Xthe archive and compares against the previously saved value.
X.TP
Xc
Xconvert entry to new packing method.  Convert files
Xstored with older methods to newer methods that are
Xmore efficient. Also useful for files previously
Xarchived with the 's' option.
X.SH OPTIONS
X.TP 3
Xb
Xretain backup copy of archive.  Keep the original
Xarchive file and rename to .BAK.
XThis switch may be used with the
Xfollowing commands:  a, m, u, f, d, c.
X.TP
Xi
Xsuppress image mode.  This switch causes files to
Xbe treated as text files, and will translate their
Xend-of-line sequence. (Unix's '\\n' vs. '\\r\\n' used
Xon many other systems.)  The default is to perform
Xno translation when compressing or extracting files.
XThis option makes dealing with text files much nicer,
Xthough the 'tr' command can also be used. ('\\r' in
Xmakefiles and C source code is such a nuisance...)
X.TP
Xs
Xsuppress compression.  This forces new files to be
Xsaved using Method 2 (no compression).  This switch
Xmay be used with the following commands:  a, m, u, f, c.
X.TP
Xw
Xsuppress warning messages.  This switch will keep
Xwarning messages from being displayed which is the default.
XMost warnings concern the deletion or existence of
Xfiles with the same name.
X.TP
Xn
Xsuppress notes and comments.  This switch will keep
Xuseful notes from being displayed which is the default.
XMost notes indicate what stage of compression is
Xbeing run (analyze, compaction, storage).
X.TP
Xo
Xoverwrite existing files when extracting.  This switch
Xwill make existing files silently get overwritten, instead
Xof asking for confirmation, which is the default.
X.TP
Xq
Xforce Squash compression method.  This switch causes
Xthe Squash compression method to be used, instead of
XCrunch, which is the default.
X.TP
Xg
Xencrypt/decrypt archive entry.  This is used to encode
Xfiles so that others may not read them.  BE CAREFUL!
XThis must be the last parameter in the switches because
Xeverything following is part of the password.
X.SH PROGRAMMING NOTES
X.I Arc
XVersion 2 differs from version 1 in that archive entries
Xare automatically compressed when they are added to the archive,
Xmaking a separate compression step unecessary.  The nature of the
Xcompression is indicated by the header version number placed in
Xeach archive entry, as follows:
X.nf
X         1 = Old style, no compression
X         2 = New style, no compression
X         3 = Compression of repeated characters only
X         4 = Compression of repeated characters plus Huffman SQueezing
X         5 = Lempel-Zev packing of repeated strings (old style)
X         6 = Lempel-Zev packing of repeated strings (new style)
X         7 = Lempel-Zev Williams packing with improved hash function
X         8 = Dynamic Lempel-Zev packing with adaptive reset
X         9 = Squashing
X.fi
X
XType 5, Lempel-Zev packing, was added as of version 4.0
X
XType 6 is Lempel-Zev packing where runs of repeated characters
Xhave been collapsed, and was added as of version 4.1
X
XType 7 is a variation of Lempel-Zev using a different hash
Xfunction which yields speed improvements of 20-25%, and was
Xadded as of version 4.6
X
XType 8 is a different implementation of Lempel-Zev, using a
Xvariable code size and an adaptive block reset, and was added
Xas of version 5.0
X
XType 9 is another variation of Lempel-Zev, using a larger
Xhash table. This method was developed by Phil Katz, and is
Xnot supported by the "official" \fBARC\fP programs.
X
X.I Arc
Xwill look for environment variables named \fIARCTEMP\fP or
X\fITMPDIR\fP, which, if present, indicates the pathname
Xwhere temporary files should be created. This is typically
Xthe location of a RAMdisk on a microcomputer, "/tmp/" or
Xleft unset.
X
XSee the included documentation file for more details.
X.SH HISTORY
X\fIArc\fP has been in use in the CP/M and MSDOS world for many years.
XThom Henderson developed the original version, but it is important to note that
X\fIarc\fP is based on the file compression theories developed by Huffman, Welch,
XKnott, Knuth, and many other scientists. This implementation is based on
Xversion 5.21 of the MSDOS program.
X.SH BUGS
X\fIArc\fP behaves just like the PC version of the program; all functions
Xof the "usage" display are working.
XFull compatibility with PC ARC files is maintained, the price for which is
Xthat \fIarc\fP doesn't like long filenames, and can only archive files with
Xnames of up to 12 characters.
XIt will *sometimes* do The Right Thing with them, but I suggest
Xyou put long-winded filenames in a "shar" before
X.IR arc ing
Xthem.
X
XThere shouldn't be any problems, (hah!) but if you find any, please
Xsend them to me at:
X
X	hyc@umix.cc.umich.edu
X	{rutgers, uunet}!umix!hyc
X
X.SH AUTHORS
XOriginal MSDOS program by Thom Henderson
X.br
XCOPYRIGHT(C) 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X
XOriginal Lempel-Zev code derived from compress 4.0.
XModified to support Squashing by Dan Lanciani (ddl@harvard.edu)
XPorted from MSDOS by Howard Chu (umix!hyc),
Xwith help from John Gilmore (hoptoad!gnu), James Turner (daisy!turner)
Xand others.
SHAR_EOF
if test 7232 -ne "`wc -c < 'Arc.1'`"
then
	echo shar: "error transmitting 'Arc.1'" '(should have been 7232 characters)'
fi
fi
echo shar: "extracting 'Arcinfo'" '(5577 characters)'
if test -f 'Arcinfo'
then
	echo shar: "will not over-write existing file 'Arcinfo'"
else
sed 's/^X//' << \SHAR_EOF > 'Arcinfo'
X
XARC-FILE.INF, created by Keith Petersen, W8SDZ, 21-Sep-86, extracted
Xfrom UNARC.INF by Robert A. Freed.
X
XFrom:     Robert A. Freed
XSubject:  Technical Information for ARC files
XDate:     June 24, 1986
X
XNote: In the following discussion, UNARC refers to my CP/M-80 program
Xfor extracting files from MSDOS ARCs.  The definitions of the ARC file
Xformat are based on MSDOS ARC512.EXE.
X
XARCHIVE FILE FORMAT
X-------------------
X
XComponent files are stored sequentially within an archive.  Each entry
Xis preceded by a 29-byte header, which contains the directory
Xinformation.  There is no wasted space between entries.  (This is in
Xcontrast to the centralized directory used by Novosielski libraries.
XAlthough random access to subfiles within an archive can be noticeably
Xslower than with libraries, archives do have the advantage of not
Xrequiring pre-allocation of directory space.)
X
XArchive entries are normally maintained in sorted name order.  The
Xformat of the 29-byte archive header is as follows:
X
XByte 1:  1A Hex.
X         This marks the start of an archive header.  If this byte is not found 
X         when expected, UNARC will scan forward in the file (up to 64K bytes) 
X         in an attempt to find it (followed by a valid compression version).  
X         If a valid header is found in this manner, a warning message is 
X         issued and archive file processing continues.  Otherwise, the file is 
X         assumed to be an invalid archive and processing is aborted.  (This is 
X         compatible with MS-DOS ARC version 5.12).  Note that a special 
X         exception is made at the beginning of an archive file, to accomodate 
X         "self-unpacking" archives (see below).
X
XByte 2:  Compression version, as follows:
X
X         0 = end of file marker (remaining bytes not present)
X         1 = unpacked (obsolete)
X         2 = unpacked
X         3 = packed
X         4 = squeezed (after packing)
X         5 = crunched (obsolete)
X         6 = crunched (after packing) (obsolete)
X         7 = crunched (after packing, using faster hash algorithm) (obsolete)
X         8 = crunched (after packing, using dynamic LZW variations)
X
XBytes 3-15:  ASCII file name, nul-terminated.
X
X(All of the following numeric values are stored low-byte first.)
X
XBytes 16-19:  Compressed file size in bytes.
X
XBytes 20-21:  File date, in 16-bit MS-DOS format:
X              Bits 15:9 = year - 1980
X              Bits  8:5 = month of year
X              Bits  4:0 = day of month
X              (All zero means no date.)
X
XBytes 22-23:  File time, in 16-bit MS-DOS format:
X              Bits 15:11 = hour (24-hour clock)
X              Bits 10:5  = minute
X              Bits  4:0  = second/2 (not displayed by UNARC)
X
XBytes 24-25:  Cyclic redundancy check (CRC) value (see below).
X
XBytes 26-29:  Original (uncompressed) file length in bytes.
X              (This field is not present for version 1 entries, byte 2 = 1.  
X              I.e., in this case the header is only 25 bytes long.  Because 
X              version 1 files are uncompressed, the value normally found in 
X              this field may be obtained from bytes 16-19.)
X
X
XSELF-UNPACKING ARCHIVES
X-----------------------
X
XA "self-unpacking" archive is one which can be renamed to a .COM file
Xand executed as a program.  An example of such a file is the MS-DOS
Xprogram ARC512.COM, which is a standard archive file preceded by a
Xthree-byte jump instruction.  The first entry in this file is a simple
X"bootstrap" program in uncompressed form, which loads the subfile
XARC.EXE (also uncompressed) into memory and passes control to it.  In
Xanticipation of a similar scheme for future distribution of UNARC, the
Xprogram permits up to three bytes to precede the first header in an
Xarchive file (with no error message).
X
X
XCRC COMPUTATION
X---------------
X
XArchive files use a 16-bit cyclic redundancy check (CRC) for error
Xcontrol.  The particular CRC polynomial used is x^16 + x^15 + x^2 + 1,
Xwhich is commonly known as "CRC-16" and is used in many data
Xtransmission protocols (e.g. DEC DDCMP and IBM BSC), as well as by
Xmost floppy disk controllers.  Note that this differs from the CCITT
Xpolynomial (x^16 + x^12 + x^5 + 1), which is used by the XMODEM-CRC
Xprotocol and the public domain CHEK program (although these do not
Xadhere strictly to the CCITT standard).  The MS-DOS ARC program does
Xperform a mathematically sound and accurate CRC calculation.  (We
Xmention this because it contrasts with some unfortunately popular
Xpublic domain programs we have witnessed, which from time immemorial
Xhave based their calculation on an obscure magazine article which
Xcontained a typographical error!)
X
XAdditional note (while we are on the subject of CRC's): The validity
Xof using a 16-bit CRC for checking an entire file is somewhat
Xquestionable.  Many people quote the statistics related to these
Xfunctions (e.g. "all two-bit errors, all single burst errors of 16 or
Xfewer bits, 99.997% of all single 17-bit burst errors, etc."), without
Xrealizing that these claims are valid only if the total number of bits
Xchecked is less than 32767 (which is why they are used in small-packet
Xdata transmission protocols).  I.e., for file sizes in excess of about
X4K bytes, a 16-bit CRC is not really as good as what is often claimed.
XThis is not to say that it is bad, but there are more reliable methods
Xavailable (e.g. the 32-bit AUTODIN-II polynomial).  (End of lecture!)
X
X                           Bob Freed
X                           62 Miller Road
X                           Newton Centre, MA  02159
X                           Telephone (617) 332-3533
X
X
SHAR_EOF
if test 5577 -ne "`wc -c < 'Arcinfo'`"
then
	echo shar: "error transmitting 'Arcinfo'" '(should have been 5577 characters)'
fi
fi
echo shar: "extracting 'Changes.521'" '(1892 characters)'
if test -f 'Changes.521'
then
	echo shar: "will not over-write existing file 'Changes.521'"
else
sed 's/^X//' << \SHAR_EOF > 'Changes.521'
X                        CHANGES IN VERSION 5.21
X
X
XThe following changes have been made in ARC version 5.21, but have not
Xyet been included in the manual:
X
Xo   When adding files to an archive, ARC now shows the stowage facter
X    achieved on each file.
X
Xo   A bug was found that would keep an archive entry from being
X    encrypted if it was stored without compression.  This has now been
X    fixed.
X
Xo   If changes are made to a corrupted archive, the corrupted entries
X    are discarded.  This makes it possible to lose data accidentally.
X    ARC will now only make changes to a corrupted archive if the W
X    (suppress Warnings) option has been given.
X
Xo   The N (suppress Notes) option now suppresses the "Creating
X    archive" note when a new archive is being created.
X
Xo   The N (suppress Notes) option formerly did nothing useful when
X    used with the L (List files) command.  It now causes a terse
X    listing of filenames only, suitable for use with pipes and
X    redirection.
X
Xo   The list of filenames given to ARC may now include indirect
X    references.  If a filename begins with an "at sign" ("@"), it is
X    taken to be the name of a file which contains a list of file
X    names.  The list of file names may include further indirection.
X    If no extension is given, ".CMD" is assumed.  For example, the
X    command:
X
X         arc a waste junk.txt @trash
X
X    would cause ARC to add JUNK.TXT plus all files listed in the file
X    TRASH.CMD to an archive named WASTE.ARC.  If no file is specified,
X    then the list is read from standard input.  For example, the
X    command:
X
X         arc ln waste | arc a trash @
X
X    would cause ARC to add files to TRASH.ARC based on the names of
X    the files stored in WASTE.ARC.  It is probably a good idea to give
X    the O (Overwrite) option if you are extracting files this way.
X
X    Version 5.21 of MARC also allows for indirection.
SHAR_EOF
if test 1892 -ne "`wc -c < 'Changes.521'`"
then
	echo shar: "error transmitting 'Changes.521'" '(should have been 1892 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(4440 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X#       Makefile for Arc v5.21
X#
X# Originals from Dan Lanciani, James Turner, and others...
X#
X# Modified to support squashing, also added targets for the time routine
X# library.  -- Howard Chu, hyc@umix.cc.umich.edu, 4-11-88
X#
X# Modified again by John Gilmore & Howard Chu, July 1988.
X#
X# I put SRCDIR on a real disk on the ST, but copy the makefile to a
X# RAMdisk and compile from there. Makes things go a bit quicker...
X# This has to be done in the shell, to get the trailing backslash
X# specified correctly. e.g., setenv SRCDIR='d:\src\arc\'
XSRCDIR = 
X
XHEADER = $(SRCDIR)arc.h $(SRCDIR)arcs.h
X
X# Add a ".TTP" suffix to the executable files on an ST.
X#PROG = .ttp
XPROG =
X
X# SYSTEM defines your operating system:
X# MSDOS for IBM PCs or other MSDOS machines
X# GEMDOS for Atari ST (Predefined by MWC, so you don't need to define it.)
X# BSD for Berkeley Unix
X# SYSV for AT&T System V Unix
X# (MTS for Michigan Terminal System, which requires a different makefile)
X# (MTS also requires one of USEGFINFO or USECATSCAN for directory search)
XSYSTEM = -DSYSV=1
X
X# For MWC 3.0 on the Atari ST, use:
X#CFLAGS = -VCOMPAC -VPEEP
XCFLAGS = -O $(SYSTEM) -Dabort=xabort -Dgetch=xgetch -DLOCAL
XLDFLAGS = -s
XSHAREDLIB = /lib/crt0s.o /lib/shlib.ifile
X
X# GNU's gcc is very nice, if you've got it. Otherwise just cc.
XCC = cc
X
X# tmclock is only needed on Unix systems...
XTMCLOCK = tmclock.o
X
X# Files needed for System V 
XSYSVOBJ =	getwd.o rename.o scandir.o utimes.o
X#SYSVOBJ =
X
XOBJS = arc.o arcadd.o arccode.o arccvt.o arcdata.o arcdel.o arcdos.o \
Xarcext.o arcio.o arclst.o arclzw.o arcmatch.o arcpack.o arcrun.o \
Xarcsq.o arcsqs.o arcsvc.o arctst.o arcunp.o arcusq.o arcmisc.o $(SYSVOBJ)
X
XMOBJ = marc.o arcdata.o arcdos.o arcio.o arcmatch.o arcmisc.o $(SYSVOBJ)
X
Xall:	arc$(PROG) $(PROG)marc
X
Xarc$(PROG):	$(OBJS) $(TMCLOCK) 
X#	$(CC) $(LDFLAGS) -o arc$(PROG) $(OBJS) $(TMCLOCK)
X	$(LD) $(LDFLAGS) -o arc$(PROG) $(OBJS) $(TMCLOCK) $(SHAREDLIB)
X
Xmarc$(PROG):	$(MOBJ) $(TMCLOCK)
X#	$(CC) $(LDFLAGS) -o marc$(PROG) $(MOBJ) $(TMCLOCK)
X	$(LD) $(LDFLAGS) -o marc$(PROG) $(MOBJ) $(TMCLOCK) $(SHAREDLIB)
X
Xclean:
X	-rm *.o arc$(PROG) marc$(PROG)
X
Xshar:
X	shar -a Arc521.doc > arc_sh.1
X	shar -a Arc.1 Arcinfo Changes.521 Makefile Manifest README \
X	Read.me Readme.local Readme.too arc.c arc.h > arc_sh.2
X	shar -a arcadd.c arccode.c arccvt.c arcdata.c arcdel.c arcdos.c \
X	arcext.c arcio.c arclst.c > arc_sh.3
X	shar -a arclzw.c arcmatch.c arcmisc.c arcpack.c arcrun.c arcs.h \
X	> arc_sh.4
X	shar -a arcsq.c arcsqs.c arcsvc.c arctst.c arcunp.c arcusq.c \
X	getwd.c > arc_sh.5
X	shar -a marc.c memset.c rename.c scandir.3 scandir.c tmclock.c \
X	utimes.c > arc_sh.6
X
Xarc.o:	$(SRCDIR)arc.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arc.c
Xmarc.o:	$(SRCDIR)marc.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)marc.c
Xarcadd.o:	$(SRCDIR)arcadd.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcadd.c
Xarccode.o:	$(SRCDIR)arccode.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arccode.c
Xarccvt.o:	$(SRCDIR)arccvt.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arccvt.c
Xarcdata.o:	$(SRCDIR)arcdata.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcdata.c
Xarcdel.o:	$(SRCDIR)arcdel.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcdel.c
Xarcdir.o:	$(SRCDIR)arcdir.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcdir.c
Xarcdos.o:	$(SRCDIR)arcdos.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcdos.c
Xarcext.o:	$(SRCDIR)arcext.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcext.c
Xarcio.o:	$(SRCDIR)arcio.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcio.c
Xarclst.o:	$(SRCDIR)arclst.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arclst.c
Xarclzw.o:	$(SRCDIR)arclzw.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arclzw.c
Xarcmatch.o:	$(SRCDIR)arcmatch.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcmatch.c
Xarcmisc.o:	$(SRCDIR)arcmisc.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcmisc.c
Xarcpack.o:	$(SRCDIR)arcpack.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcpack.c
Xarcrun.o:	$(SRCDIR)arcrun.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcrun.c
Xarcsq.o:	$(SRCDIR)arcsq.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcsq.c
Xarcsqs.o:	$(SRCDIR)arcsqs.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcsqs.c
Xarcsvc.o:	$(SRCDIR)arcsvc.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcsvc.c
Xarctst.o:	$(SRCDIR)arctst.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arctst.c
Xarcunp.o:	$(SRCDIR)arcunp.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcunp.c
Xarcusq.o:	$(SRCDIR)arcusq.c	$(HEADER)
X	$(CC) $(CFLAGS) -c $(SRCDIR)arcusq.c
X
Xtmclock.o:	$(SRCDIR)tmclock.c
X	$(CC) $(CFLAGS) -c $(SRCDIR)tmclock.c
SHAR_EOF
if test 4440 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 4440 characters)'
fi
fi
echo shar: "extracting 'Manifest'" '(2413 characters)'
if test -f 'Manifest'
then
	echo shar: "will not over-write existing file 'Manifest'"
else
sed 's/^X//' << \SHAR_EOF > 'Manifest'
XContents of this distribution....
X   5577 Apr 11 19:15 Arcinfo	   Description of .ARC file format
X  54144 Jun 13 05:26 Arc521.doc	   Full program documentation, no CRs.
X   1892 May 14  1987 Changes.521   Differences between 5.20 and 5.21
X   1323 Apr 11 19:10 Make.tws	   Makefile for the time routine library
X   1731 Jun 13 03:58 Makefile	   Makefile for ARC
X   2413 Jun 13 05:29 Manifest	   This file
X   2269 Jun 18 03:39 Read.me	   Spiel
X   2190 Jun 13 04:23 Readme.too	   More spiel
X  18327 Jun 13 04:09 Sysvarcstuf   Useful for Sys V users.
X   7232 Jun 12 19:31 arc.1	   A man page, *roff source
X  11116 Jun 13 04:27 arc.c	   Main routine, option parser...
X   3318 Jun  1 19:59 arc.h	   System dependencies, externs
X   9286 Jun 13 00:31 arcadd.c	   Top level routine for adding to archive
X   1204 Jun  1 15:16 arccode.c	   Code for file encryption/decryption
X   3396 Jun  1 19:18 arccvt.c	   Convert to new packing method
X   2070 Jun 13 04:26 arcdata.c	   Declarations of externs from arc.h
X   2055 Apr 19 01:39 arcdel.c	   Delete files from archive
X   4970 Jun 13 00:41 arcdos.c	   OS specific file management routines
X   4897 Jun  1 20:18 arcext.c	   Top level routine for extraction
X   7384 Jun  2 16:27 arcio.c	   OS specific low-level I/O routines
X   4418 Jun  1 18:06 arclst.c	   List contents of archive
X  22109 Jun  1 20:01 arclzw.c	   Low-level Lempel-Zev compression
X   3026 Jun  1 19:41 arcmatch.c	   Pattern matching routines
X   8319 Jun 13 04:07 arcmisc.c	   OS specific miscellaneous functions
X   7376 Jun  2 16:27 arcpack.c	   Mid-level compression code
X   3838 Jun  1 19:57 arcrun.c	   Run files from archive
X   1645 Apr 17 18:53 arcs.h	   Declaration of .ARC header format
X  14613 Jun  2 16:27 arcsq.c	   Low-level Huffman Squeeze code
X  11587 Jun  1 20:02 arcsqs.c	   Low-level Squash code
X   4680 Jun 13 00:43 arcsvc.c	   .ARC file utilities
X   1284 Apr 19 01:40 arctst.c	   Test archive integrity
X   5325 Jun  7 03:16 arcunp.c	   Mid-level extraction code
X   2484 Jun  2 16:28 arcusq.c	   Low-level Huffman unSqueezer
X   9035 Apr 11 19:10 dtime.c	   sources for the time routine library...
X   7327 Apr 11 19:11 dtimep.lex
X    356 Apr 11 19:12 lexedit.sed
X   3765 Apr 11 19:12 lexstring.c
X   2241 Apr 11 19:13 libtws.3	   man page for the time routine library
X   9053 Jun  6 01:04 marc.c	   source for the marc program
X   2993 Jun  2 00:38 tws.h	   header file for the time routine library
SHAR_EOF
if test 2413 -ne "`wc -c < 'Manifest'`"
then
	echo shar: "error transmitting 'Manifest'" '(should have been 2413 characters)'
fi
fi
echo shar: "extracting 'README'" '(539 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThe enclosed files should be sufficient for bringing up ARC on a Sys V R3
Xsystem. As Jon mentions, Doug Gwyn's directory routines are needed for
XSys V R2. The enclosed copy of scandir is new, as far as I can tell, and
XI've removed the (unneeded) ftw.? files. Also added a rename() routine,
Xcourtesy of Janet Walz. (And an addition from Rich Salz.)
X
X[see comp.sources.unix, volume 9, for gwyn-dir-lib...]
X
XThanks again to Jon Zeeff, Janet Walz, and Rich Salz for their help.
X  -- Howard Chu
X	hyc@umix.cc.umich.edu
X	{uunet,rutgers}!umix!hyc
SHAR_EOF
if test 539 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 539 characters)'
fi
fi
echo shar: "extracting 'Read.me'" '(2269 characters)'
if test -f 'Read.me'
then
	echo shar: "will not over-write existing file 'Read.me'"
else
sed 's/^X//' << \SHAR_EOF > 'Read.me'
XHello again,
X	herein you should be pleased to find the complete sources for the
Xlatest and greatest version of ARC, based on the sources for version 5.21
Xof the MSDOS ARC program. The patches to the previous release, 5.12, with
Xsquashing algorithm, have also been applied here. The code is known to
Xwork on a Sun 3 running SunOS 3.4, Apollo DN3000 running SR9.7 DOMAIN/IX,
XVax 750 running 4.3BSD, and IBM 3090 running MTS. It is also now working
Xon Atari STs, as well as Apollo DN3000 running SR10 DOMAIN/OS (Beta).
X
X	Also included is a detailed description of the format of a .ARC
Xfile directory entry, in the file named Arcinfo. Could be useful if you're
Xtrying to port ARC to any more esoteric systems...
X
X	Jon Zeeff has sent along some code he used to get this working on
XSys V style machines. Looks like scandir is all that's really missing. I
Xhaven't tried any of it out for myself yet, but the code is in the file
X"Sysvarcstuf" should you need it.
X
X	One final necessary inclusion: sources for libtws.a, which was
Xposted a long time ago to mod.sources as part of a package he called
X"phoon" - a program that calculated and displayed the PHase of the mOON.
XThe only thing I use the time routines for here is to convert an expanded
Xdate/time back into a Unix style time value, for keeping file modification
Xtimes straight.
X
X	Thanks to Leo Wilson (leo@cs.buffalo.edu) for sending his copy of
Xa man page for ARC. I've updated it for this version, and included it here
Xas well.
X
X	The default value of the (I)mage mode flag has changed. ARC will
Xnow treat files as binary files, unless the 'i' flag is given. Handling of
XCarriage Returns has been improved a bit. ARC is now a little smarter about
Xtemporary files as well.
X
XTo compile all this stuff... Edit Make.tws (shouldn't need to change anything
Xhere, really.) Edit arc.h. After that, just type make and wait a while...
X(Oh yeah - there's a few makefile macros that need redefining for Atari ST...)
XOk... Well, I've had this for a while, and it works for me, but if somehow
XI've goofed, let me know.
X	
X  /
X /_ , ,_.                      Howard Chu
X/ /(_/(__                University of Michigan
X    /           Computing Center          College of LS&A
X   '              Unix Project          Information Systems
SHAR_EOF
if test 2269 -ne "`wc -c < 'Read.me'`"
then
	echo shar: "error transmitting 'Read.me'" '(should have been 2269 characters)'
fi
fi
echo shar: "extracting 'Readme.local'" '(777 characters)'
if test -f 'Readme.local'
then
	echo shar: "will not over-write existing file 'Readme.local'"
else
sed 's/^X//' << \SHAR_EOF > 'Readme.local'
X
XThis distribution of Arc v5.21 was derived almost entirely from work by
XHoward Chu (uunet!umix!hyc).
X
XWith the use of the preprocessor definition LOCAL, you can include my
Xlocal enhancements and changes.  The following changes were made:
X
X	1) By default, Unix file names are changed to meet MSDOS
X	file name restrictions when added to an archive.  Also, 
X	file names are folded to lowercase when extracted.  This
X	feature can be disabled by the use of the -z option.
X
X	2) Duplicate file names no longer cause a fatal error, the
X	second file name is mearly skipped.
X
XEmmet P. Gray				US Army, HQ III Corps & Fort Hood
X...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
X					Directorate of Engineering & Housing
X					Environmental Management Office
X					Fort Hood, TX 76544-5057
SHAR_EOF
if test 777 -ne "`wc -c < 'Readme.local'`"
then
	echo shar: "error transmitting 'Readme.local'" '(should have been 777 characters)'
fi
fi
echo shar: "extracting 'Readme.too'" '(4064 characters)'
if test -f 'Readme.too'
then
	echo shar: "will not over-write existing file 'Readme.too'"
else
sed 's/^X//' << \SHAR_EOF > 'Readme.too'
XNotes for ARC 5.21                                        June 6, 1988
X 
XThis program is based on the MSDOS ARC program, version 5.21, plus
Xa few enhancements... 
X 
X o ARC also performs Huffman Squeezing on data. The Huffman Squeeze
X   algorithm was removed from MSDOS ARC after version 5.12. It turns
X   out to be more efficient than Lempel-Ziv style compression when
X   compressing graphic images. Squeeze analysis is always done now,
X   and the best of packing, squeezing, or crunching is used.
X 
X o Compresses and extracts Squashed files. "Squashing" was created
X   by Phil Katz in his PKxxx series of ARC utility programs for
X   MSDOS. Dan Lanciani wrote the original modifications to ARC's
X   Crunch code to handle Squashing. I've made minor changes since
X   then, mostly to reduce the amount of memory required. The 'q'
X   option flag must be specified to Squash files. The Squashing
X   algorithm will be used instead of the usual Crunch algorithm,
X   and will be compared against packing and squeezing, as before.
X 
XSystem specific notes:
X 
X   On MTS, an additional option flag, 'i' for "image mode," was
Xused. ARC assumes files are text, by default, and will translate
XMTS files from EBCDIC to ASCII before storing in an archive, and
Xtranslates from ASCII to EBCDIC upon extraction. Specifying the
X'i' flag will inhibit this translation. This would most commonly
Xbe used when shipping binary images such as TeX DVI files, other
X.ARC files stored within an archive, etc... The 'r' (run) command
Xis omitted. It just doesn't seem very useful. Also, ARC cannot
Xrestore MTS files with their original time stamps. (Maybe in a
Xfuture release...)
X 
X   On Unix(tm) systems, the 'i' flag is also present. Unix ARC
Xassumes a binary file, by default. Here the only translation
Xinvolved is in end-of-line processing. When storing text files, ARC will
Xchange '\n' to '\r\n', and does the opposite when extracting files.
XCarriage returns in any other location are preserved when extracting.
XThis translation only occurs if the 'i' flag is given.
X
X   On the Atari ST, the 'h' (for "hold screen") option is present,
Xwhich simply delays exiting the program. This is typically used when
Xexecuting ARC from the desktop, to allow reading all of ARC's output
Xbefore the screen is cleared and the desktop is redrawn. The program
Xwill prompt and wait for a keypress before exiting. Note that since
Xthere are no "options" for the MARC program, the "hold screen" option
Xis always active for MARC.
X 
X   On both Unix and Atari systems, ARC & MARC will search for an
Xenvironment variable named "ARCTEMP" or "TMPDIR." If present, any
Xtemporary files will be created in the specified directory. This is
Xprobably insignificant for Unix users, but can be handy on the Atari,
Xin combination with a RAMdisk. Highly recommended for floppy users.
X(Unfortunately, you can only take advantage of this when running some
Xform of command shell that allows setting environment variables. Thus,
Xyou won't see any speed gains when running from the desktop.)
X 
X 
XThat about covers things. The enclosed documentation is taken directly
Xfrom the MSDOS distribution of ARC. Unless specified differently here,
Xthe programs behave indentically. Note that ARC521.DOC is identical to
XARC520.DOC - the differences between the two versions are described in
Xthe file CHANGES.521.
X 
XOh yeah - this program may be distributed freely so long as you don't
Xmodify it in any way. You may not charge for distributing it. (Don't
Xfeel bad, I can't charge for it either. }-) It'd be nice if you kept
Xthis and the other enclosed doc files with it when distributing, but
XI'm not going to make a fuss about it. Most people are so familiar
Xwith the program by now that it wouldn't matter much anyway. You
Xshould keep this README file around, so bug reports & such will find
Xtheir way back to me. (Bugs? What bugs? Nah, there aren't any bugs...)
X 
X         /                 Howard Chu
X   ___  /_ , ,_.     University of Michigan
X       / /(_/(__     hyc@umix.cc.umich.edu
X           /                umix!hyc
X          '     
SHAR_EOF
if test 4064 -ne "`wc -c < 'Readme.too'`"
then
	echo shar: "error transmitting 'Readme.too'" '(should have been 4064 characters)'
fi
fi
echo shar: "extracting 'arc.c'" '(12303 characters)'
if test -f 'arc.c'
then
	echo shar: "will not over-write existing file 'arc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arc.c'
X/*
X * $Header: arc.c,v 1.13 88/11/01 02:22:23 hyc Exp $
X */
X
X/*  ARC - Archive utility
X  
X    Version 5.21, created on 04/22/87 at 15:05:21
X  
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X  
X    By:	 Thom Henderson
X  
X    Description:
X	 This program is a general archive utility, and is used to maintain
X	 an archive of files.  An "archive" is a single file that combines
X	 many files, reducing storage space and allowing multiple files to
X	 be handled as one.
X  
X    Instructions:
X	 Run this program with no arguments for complete instructions.
X  
X    Programming notes:
X	 ARC Version 2 differs from version 1 in that archive entries
X	 are automatically compressed when they are added to the archive,
X	 making a separate compression step unecessary.	 The nature of the
X	 compression is indicated by the header version number placed in
X	 each archive entry, as follows:
X  
X	 1 = Old style, no compression
X	 2 = New style, no compression
X	 3 = Compression of repeated characters only
X	 4 = Compression of repeated characters plus Huffman SQueezing
X	 5 = Lempel-Zev packing of repeated strings (old style)
X	 6 = Lempel-Zev packing of repeated strings (new style)
X	 7 = Lempel-Zev Williams packing with improved hash function
X	 8 = Dynamic Lempel-Zev packing with adaptive reset
X	 9 = Dynamic Lempel-Zev packing, larger hash table
X  
X	 Type 5, Lempel-Zev packing, was added as of version 4.0
X  
X	 Type 6 is Lempel-Zev packing where runs of repeated characters
X	 have been collapsed, and was added as of version 4.1
X  
X	 Type 7 is a variation of Lempel-Zev using a different hash
X	 function which yields speed improvements of 20-25%, and was
X	 added as of version 4.6
X  
X	 Type 8 is a different implementation of Lempel-Zev, using a
X	 variable code size and an adaptive block reset, and was added
X	 as of version 5.0
X  
X	 Type 9 is a slight modification of type 8, first used by Phil
X	 Katz in his PKARC utilites. The primary difference is the use
X	 of a hash table twice as large as for type 8, and that this
X	 algorithm called Squashing, doesn't perform run-length encoding
X	 on the input data.
X  
X	 Verion 4.3 introduced a temporary file for holding the result
X	 of the first crunch pass, thus speeding up crunching.
X  
X	 Version 4.4 introduced the ARCTEMP environment string, so that
X	 the temporary crunch file may be placed on a ramdisk.	Also
X	 added was the distinction bewteen Adding a file in all cases,
X	 and Updating a file only if the disk file is newer than the
X	 corresponding archive entry.
X  
X	 The compression method to use is determined when the file is
X	 added, based on whichever method yields the smallest result.
X  
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X
X#if	UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
X#ifdef LOCAL
Xint unix_names = 0;
X#endif /* LOCAL */
X
Xint		strlen();
Xvoid		addarc(), delarc(), extarc(), lstarc(), tstarc(), cvtarc(), runarc();
Xvoid		abort();
Xstatic	void	expandlst();
X#if	MTS
Xvoid		etoa();
X#endif
X#if	GEMDOS
Xlong		_stksize = 65536L;
X#endif
Xchar		*strcpy(), *strcat();
Xchar		*makefnam();	/* filename fixup routine */
X
Xstatic char   **lst;		/* files list */
Xstatic int	lnum;		/* length of files list */
X
Xmain(num, arg)			/* system entry point */
X	int		num;	/* number of arguments */
X	char	       *arg[];	/* pointers to arguments */
X{
X	char		opt = 0;/* selected action */
X	char	       *a;	/* option pointer */
X	void		upper();/* case conversion routine */
X	char	       *index();/* string index utility */
X	char	       *envfind();	/* environment searcher */
X	int		n;	/* index */
X	char	       *arctemp2, *calloc(), *mktemp();
X#if	GEMDOS
X	void		exitpause();
X	int		append;
X#endif
X#if	MTS
X	fortran void	guinfo();
X	char		gotinf[4];
X#endif
X#if	UNIX
X	struct	stat	sbuf;
X#endif
X
X	if (num < 3) {
X		printf("ARC - Archive utility, Version 5.21, created on 04/22/87 at 15:05:21\n");
X/*		printf("(C) COPYRIGHT 1985,86,87 by System Enhancement Associates;");
X		printf(" ALL RIGHTS RESERVED\n\n");
X		printf("Please refer all inquiries to:\n\n");
X		printf("       System Enhancement Associates\n");
X		printf("       21 New Street, Wayne NJ 07470\n\n");
X		printf("You may copy and distribute this program freely,");
X		printf(" provided that:\n");
X		printf("    1)	 No fee is charged for such copying and");
X		printf(" distribution, and\n");
X		printf("    2)	 It is distributed ONLY in its original,");
X		printf(" unmodified state.\n\n");
X		printf("If you like this program, and find it of use, then your");
X		printf(" contribution will\n");
X		printf("be appreciated.	 You may not use this product in a");
X		printf(" commercial environment\n");
X		printf("or a governmental organization without paying a license");
X		printf(" fee of $35.  Site\n");
X		printf("licenses and commercial distribution licenses are");
X		printf(" available.  A program\n");
X		printf("disk and printed documentation are available for $50.\n");
X		printf("\nIf you fail to abide by the terms of this license, ");
X		printf(" then your conscience\n");
X		printf("will haunt you for the rest of your life.\n\n"); */
X#if	MSDOS
X		printf("Usage: ARC {amufdxerplvtc}[bswnoq][g<password>]");
X#endif
X#if	GEMDOS
X		printf("Usage: ARC {amufdxerplvtc}[bhswnoq][g<password>]");
X#endif
X#if	UNIX
X#ifdef LOCAL
X		printf("Usage: arc {amufdxerplvtc}[biswnoqz][g<password>]");
X#else /* LOCAL */
X		printf("Usage: arc {amufdxerplvtc}[biswnoq][g<password>]");
X#endif /* LOCAL */
X#endif
X#if	MTS
X		printf("Parameters: {amufdxeplvtc}[biswnoq][g<password>]");
X#endif
X		printf(" <archive> [<filename> . . .]\n");
X		printf("Where:	 a   = add files to archive\n");
X		printf("	 m   = move files to archive\n");
X		printf("	 u   = update files in archive\n");
X		printf("	 f   = freshen files in archive\n");
X		printf("	 d   = delete files from archive\n");
X		printf("	 x,e = extract files from archive\n");
X#if	!MTS
X		printf("	 r   = run files from archive\n");
X#endif
X		printf("	 p   = copy files from archive to");
X		printf(" standard output\n");
X		printf("	 l   = list files in archive\n");
X		printf("	 v   = verbose listing of files in archive\n");
X		printf("	 t   = test archive integrity\n");
X		printf("	 c   = convert entry to new packing method\n");
X		printf("	 b   = retain backup copy of archive\n");
X#if	GEMDOS
X		printf("	 h   = hold screen after finishing\n");
X#endif
X#if	MTS
X		printf("	 i   = suppress ASCII/EBCDIC translation\n");
X#endif
X#if	UNIX
X		printf("	 i   = suppress image mode (translate EOL)\n");
X#endif
X		printf("	 s   = suppress compression (store only)\n");
X		printf("	 w   = suppress warning messages\n");
X		printf("	 n   = suppress notes and comments\n");
X		printf("	 o   = overwrite existing files when");
X		printf(" extracting\n");
X		printf("	 q   = squash instead of crunching\n");
X		printf("	 g   = Encrypt/decrypt archive entry\n");
X#ifdef LOCAL
X		printf("	 z   = use Unix file names (as much as possible)\n");
X#endif /* LOCAL */
X		printf("\nAdapted from MSDOS by Howard Chu\n");
X		/*
X		 * printf("\nPlease refer to the program documentation for");
X		 * printf(" complete instructions.\n"); 
X		 */
X#if	GEMDOS
X		exitpause();
X#endif
X		return 1;
X	}
X	/* see where temp files go */
X#if	!MTS
X	arctemp = calloc(1, STRLEN);
X	if (!(arctemp2 = envfind("ARCTEMP")))
X		arctemp2 = envfind("TMPDIR");
X	if (arctemp2) {
X		strcpy(arctemp, arctemp2);
X		n = strlen(arctemp);
X		if (arctemp[n - 1] != CUTOFF)
X			arctemp[n] = CUTOFF;
X	}
X#if	UNIX
X	else	strcpy(arctemp, "/tmp/");
X#endif
X#if	!MSDOS
X	{
X		static char tempname[] = "AXXXXXX";
X		strcat(arctemp, mktemp(tempname));
X	}
X#else
X	strcat(arctemp, "$ARCTEMP");
X	arctemp2 = NULL;
X#endif
X#else
X	guinfo("SHFSEP	", gotinf);
X	sepchr[0] = gotinf[0];
X	guinfo("SCRFCHAR", gotinf);
X	tmpchr[0] = gotinf[0];
X	arctemp = "-$$$";
X	arctemp[0] = tmpchr[0];
X#endif
X
X#if	!UNIX
X	/* avoid any case problems with arguments */
X
X	for (n = 1; n < num; n++)	/* for each argument */
X		upper(arg[n]);	/* convert it to uppercase */
X#else
X	/* avoid case problems with command options */
X	upper(arg[1]);		/* convert to uppercase */
X#endif
X
X	/* create archive names, supplying defaults */
X#if	UNIX
X	if (!stat(arg[2],&sbuf)) {
X		if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
X			makefnam(arg[2],".arc",arcname);
X		else
X			strcpy(arcname,arg[2]);
X	} else
X		makefnam(arg[2],".arc",arcname);
X#else
X	makefnam(arg[2], ".ARC", arcname);
X#endif
X	/* makefnam(".$$$",arcname,newname); */
X	sprintf(newname, "%s.arc", arctemp);
X	makefnam(".BAK", arcname, bakname);
X
X	/* now scan the command and see what we are to do */
X
X	for (a = arg[1]; *a; a++) {	/* scan the option flags */
X#if	!MTS
X		if (index("AMUFDXEPLVTCR", *a)) {	/* if a known command */
X#else
X		if (index("AMUFDXEPLVTC", *a)) {
X#endif
X			if (opt)/* do we have one yet? */
X				abort("Cannot mix %c and %c", opt, *a);
X			opt = *a;	/* else remember it */
X		} else if (*a == 'B')	/* retain backup copy */
X			keepbak = 1;
X
X		else if (*a == 'W')	/* suppress warnings */
X			warn = 0;
X#if	!DOS
X		else if (*a == 'I')	/* image mode, no ASCII/EBCDIC x-late */
X			image = !image;
X#endif
X#if	GEMDOS
X		else if (*a == 'H')	/* pause before exit */
X			hold = 1;
X#endif
X
X		else if (*a == 'N')	/* suppress notes and comments */
X			note = 0;
X
X		else if (*a == 'O')	/* overwrite file on extract */
X			overlay = 1;
X
X		else if (*a == 'G') {	/* garble */
X			password = a + 1;
X			while (*a)
X				a++;
X			a--;
X#if	MTS
X			etoa(password, strlen(password));
X#endif
X		} else if (*a == 'S')	/* storage kludge */
X			nocomp = 1;
X
X		else if (*a == 'K')	/* special kludge */
X			kludge = 1;
X
X		else if (*a == 'Q')	/* use squashing */
X			dosquash = 1;
X#ifdef LOCAL
X		else if (*a == 'Z')	/* use Unix file names */
X			unix_names = 1;
X#endif /* LOCAL */
X
X		else if (*a == '-' || *a == '/')	/* UNIX and PC-DOS
X							 * option markers */
X			;
X
X		else
X			abort("%c is an unknown command", *a);
X	}
X
X	if (!opt)
X		abort("I have nothing to do!");
X
X	/* get the files list set up */
X
X	lnum = num - 3;		/* initial length of list */
X	lst = (char **) calloc((lnum==0) ? 1:lnum,
X				 sizeof(char *));	/* initial list */
X	for (n = 3; n < num; n++)
X		lst[n - 3] = arg[n];
X
X	for (n = 0; n < lnum;) {/* expand indirect references */
X		if (*lst[n] == '@')
X			expandlst(n);
X#if	GEMDOS
X				/* redirect stdout from the desktop...*/
X		else if (*lst[n] == '>') {
X			arctemp2 = (++lst[n]);
X			lst[n] = lst[lnum-1];	/* delete this entry */
X			lnum--;
X			if (arctemp2[0] == '>') {
X				append = 1;
X				arctemp2++;
X			}
X			else	append = 0;
X		}
X#endif
X		else
X			n++;
X	}
X#if	GEMDOS
X	if (arctemp2)
X		freopen(arctemp2,append ? "a" : "w",stdout);
X#endif
X
X	/* act on whatever action command was given */
X
X	switch (opt) {		/* action depends on command */
X	case 'A':		/* Add */
X	case 'M':		/* Move */
X	case 'U':		/* Update */
X	case 'F':		/* Freshen */
X		addarc(lnum, lst, (opt == 'M'), (opt == 'U'), (opt == 'F'));
X		break;
X
X	case 'D':		/* Delete */
X		delarc(lnum, lst);
X		break;
X
X	case 'E':		/* Extract */
X	case 'X':		/* eXtract */
X	case 'P':		/* Print */
X		extarc(lnum, lst, (opt == 'P'));
X		break;
X
X	case 'V':		/* Verbose list */
X		bose = 1;
X	case 'L':		/* List */
X		lstarc(lnum, lst);
X		break;
X
X	case 'T':		/* Test */
X		tstarc();
X		break;
X
X	case 'C':		/* Convert */
X		cvtarc(lnum, lst);
X		break;
X#if	!MTS
X	case 'R':		/* Run */
X		runarc(lnum, lst);
X		break;
X#endif
X	default:
X		abort("I don't know how to do %c yet!", opt);
X	}
X#if	GEMDOS
X	if (hold)
X		exitpause();
X#endif
X	return nerrs;
X}
Xstatic	void
Xexpandlst(n)			/* expand an indirect reference */
X	int		n;	/* number of entry to expand */
X{
X	FILE	       *lf, *fopen();	/* list file, opener */
X	char	       *malloc(), *realloc();	/* memory managers */
X	char		buf[100];	/* input buffer */
X	int		x;	/* index */
X	char	       *p = lst[n] + 1; /* filename pointer */
X
X	if (*p) {		/* use name if one was given */
X		makefnam(p, ".CMD", buf);
X		if (!(lf = fopen(buf, "r")))
X			abort("Cannot read list of files in %s", buf);
X	} else
X		lf = stdin;	/* else use standard input */
X
X	for (x = n + 1; x < lnum; x++)	/* drop reference from the list */
X		lst[x - 1] = lst[x];
X	lnum--;
X
X	while (fscanf(lf, "%99s", buf) > 0) {	/* read in the list */
X		if (!(lst =(char **)realloc(lst, (lnum + 1) * sizeof(char *))))
X			abort("too many file references");
X
X		lst[lnum] = malloc(strlen(buf) + 1);
X		strcpy(lst[lnum], buf); /* save the name */
X		lnum++;
X	}
X
X	if (lf != stdin)	/* avoid closing standard input */
X		fclose(lf);
X}
SHAR_EOF
if test 12303 -ne "`wc -c < 'arc.c'`"
then
	echo shar: "error transmitting 'arc.c'" '(should have been 12303 characters)'
fi
fi
echo shar: "extracting 'arc.h'" '(2930 characters)'
if test -f 'arc.h'
then
	echo shar: "will not over-write existing file 'arc.h'"
else
sed 's/^X//' << \SHAR_EOF > 'arc.h'
X/*
X * $Header: arc.h,v 1.10 88/08/01 14:28:29 hyc Exp $
X */
X
X#undef	DOS	/* Just in case... */
X#undef	UNIX
X
X/*
X * Assumptions:
X * char = 8 bits
X * short = 16 bits
X * long = 32 bits
X * int >= 16 bits
X */
X
X#if	MSDOS || GEMDOS
X#define	DOS	1
X#define	CUTOFF	'\\'
X#define	OPEN_R	"rb"
X#define	OPEN_W	"wb"
X#endif
X
X#if	!MSDOS
X#define	envfind	getenv
X#define	setmem(a, b, c)	memset(a, c, b)
X#endif
X
X#if	BSD || SYSV
X#define	UNIX	1
X#define	CUTOFF	'/'
X#define	OPEN_R	"r"
X#define	OPEN_W	"w"
X#include <ctype.h>
X#endif
X
X#if	MTS
X#define	CUTOFF	sepchr[0]
X#endif
X
X#if	MTS || SYSV
X#define	rindex	strrchr
X#define	index	strchr
X#endif
X
X/*  ARC - Archive utility - ARC Header
X  
X    Version 2.17, created on 04/22/87 at 13:09:43
X  
X(C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X  
X    By:	 Thom Henderson
X  
X    Description: 
X	 This is the header file for the ARC archive utility.  It defines
X	 global parameters and the references to the external data.
X  
X  
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X
X#define ARCMARK 26		/* special archive marker        */
X#define ARCVER 9		/* archive header version code   */
X#define STRLEN 100		/* system standard string length */
X#define FNLEN 13		/* file name length              */
X#define MAXARG 400		/* maximum number of arguments   */
X
X#ifndef DONT_DEFINE		/* Defined by arcdata.c */
X#include "arcs.h"
X
Xextern int      keepbak;	/* true if saving the old archive */
X#if	!DOS
Xextern int      image;		/* true to suppress CRLF/LF x-late */
X#endif
X#if	MTS
Xextern char     sepchr[2];	/* Shared file separator, default = ':' */
Xextern char     tmpchr[2];	/* Temporary file prefix, default = '-' */
X#endif
X#if	GEMDOS
Xextern int      hold;		/* hold screen before exiting */
X#endif
Xextern int      warn;		/* true to print warnings */
Xextern int      note;		/* true to print comments */
Xextern int      bose;		/* true to be verbose */
Xextern int      nocomp;		/* true to suppress compression */
Xextern int      overlay;	/* true to overlay on extract */
Xextern int      kludge;		/* kludge flag */
Xextern char    *arctemp;	/* arc temp file prefix */
Xextern char    *password;	/* encryption password pointer */
Xextern int      nerrs;		/* number of errors encountered */
Xextern int      changing;	/* true if archive being modified */
X
Xextern char     hdrver;		/* header version */
X
Xextern FILE    *arc;		/* the old archive */
Xextern FILE    *new;		/* the new archive */
Xextern char     arcname[STRLEN];/* storage for archive name */
Xextern char     bakname[STRLEN];/* storage for backup copy name */
Xextern char     newname[STRLEN];/* storage for new archive name */
Xextern unsigned short arcdate;	/* archive date stamp */
Xextern unsigned short arctime;	/* archive time stamp */
Xextern unsigned short olddate;	/* old archive date stamp */
Xextern unsigned short oldtime;	/* old archive time stamp */
Xextern int      dosquash;	/* squash instead of crunch */
X#endif				/* DONT_DEFINE */
SHAR_EOF
if test 2930 -ne "`wc -c < 'arc.h'`"
then
	echo shar: "error transmitting 'arc.h'" '(should have been 2930 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (01/02/89)

This is part 3 (of 6) to the Arc v5.21 distribution package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	arcadd.c
#	arccode.c
#	arccvt.c
#	arcdata.c
#	arcdel.c
#	arcdos.c
#	arcext.c
#	arcio.c
#	arclst.c
# This archive created: Sun Jan  1 12:48:17 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arcadd.c'" '(12955 characters)'
if test -f 'arcadd.c'
then
	echo shar: "will not over-write existing file 'arcadd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcadd.c'
X/*
X * $Header: arcadd.c,v 1.10 88/11/16 17:43:25 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCADD
X * 
X * Version 3.40, created on 06/18/86 at 13:10:18
X * 
X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to add files to an archive.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X#if	MTS
X#include <mts.h>
X#endif
X
Xstatic	int	addfile();
Xchar	*strcpy();
Xint	strcmp(), strlen(), free(), readhdr(), unlink();
X#if	UNIX
Xint	izadir();
X#endif
Xvoid	writehdr(), filecopy(), getstamp();
Xvoid	pack(), closearc(), openarc(), abort();
X
Xvoid
Xaddarc(num, arg, move, update, fresh)		/* add files to archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
Xint             move;		/* true if moving file */
Xint             update;		/* true if updating */
Xint             fresh;		/* true if freshening */
X{
X	char           *d, *dir();	/* directory junk */
X	char            buf[STRLEN];	/* pathname buffer */
X	char          **path;	/* pointer to pointers to paths */
X	char          **name;	/* pointer to pointers to names */
X	int             nfiles = 0;	/* number of files in lists */
X	int             notemp;	/* true until a template works */
X	int             nowork = 1;	/* true until files are added */
X	char           *i, *rindex();	/* string indexing junk */
X	char           *malloc(), *realloc();	/* memory allocators */
X	int             n;	/* index */
X#ifdef LOCAL
X	extern int unix_names;
X#endif /* LOCAL */
X#if	MSDOS
X	unsigned int	coreleft();	/* remaining memory reporter */
X#endif
X	int		addbunch();
X
X	if (num < 1) {		/* if no files named */
X		num = 1;	/* then fake one */
X#if	DOS
X		arg[0] = "*.*";	/* add everything */
X#endif
X#if	UNIX
X		arg[0] = "*";
X#endif
X#if	MTS
X		arg[0] = "?";
X#endif
X	}
X	path = (char **) malloc(sizeof(char **));
X	name = (char **) malloc(sizeof(char **));
X
X
X	for (n = 0; n < num; n++) {	/* for each template supplied */
X		strcpy(buf, arg[n]);	/* get ready to fix path */
X#if	!MTS
X		if (!(i = rindex(buf, '\\')))
X			if (!(i = rindex(buf, '/')))
X				if (!(i = rindex(buf, ':')))
X					i = buf - 1;
X#else
X		if (!(i = rindex(buf, sepchr[0])))
X			if (buf[0] != tmpchr[0])
X				i = buf - 1;
X			else
X				i = buf;
X#endif
X		i++;		/* pointer to where name goes */
X
X		notemp = 1;	/* reset files flag */
X		for (d = dir(arg[n]); d; d = dir(NULL)) {
X			notemp = 0;	/* template is giving results */
X			nfiles++;	/* add each matching file */
X			path = (char **) realloc(path, nfiles * sizeof(char **));
X			name = (char **) realloc(name, nfiles * sizeof(char **));
X			strcpy(i, d);	/* put name in path */
X			path[nfiles - 1] = malloc(strlen(buf) + 1);
X			strcpy(path[nfiles - 1], buf);
X			name[nfiles - 1] = d;	/* save name */
X#if LOCAL
X						/* make it a MSDOS file name */
X			if (!unix_names) {
X				if (legalize(path[nfiles-1], name[nfiles-1])) {
X					nfiles--;
X					continue;
X				}
X			}
X#endif /* LOCAL */
X#if	MSDOS
X			if (coreleft() < 5120) {
X				nfiles = addbunch(nfiles, path, name, move, update, fresh);
X				nowork = nowork && !nfiles;
X				while (nfiles) {
X					free(path[--nfiles]);
X					free(name[nfiles]);
X				}
X				free(path);
X				free(name);
X				path = name = NULL;
X			}
X#endif
X		}
X		if (notemp && warn)
X			printf("No files match: %s\n", arg[n]);
X	}
X
X	if (nfiles) {
X		nfiles = addbunch(nfiles, path, name, move, update, fresh);
X		nowork = nowork && !nfiles;
X		while (nfiles) {
X			free(path[--nfiles]);
X			free(name[nfiles]);
X		}
X		free(path);
X		free(name);
X	}
X	if (nowork && warn)
X		printf("No files were added.\n");
X}
X
Xint
Xaddbunch(nfiles, path, name, move, update, fresh)	/* add a bunch of files */
X	int             nfiles;	/* number of files to add */
X	char          **path;	/* pointers to pathnames */
X	char          **name;	/* pointers to filenames */
X	int             move;	/* true if moving file */
X	int             update;	/* true if updating */
X	int             fresh;	/* true if freshening */
X{
X	int             m, n;	/* indices */
X	char           *d;	/* swap pointer */
X	struct heads    hdr;	/* file header data storage */
X
X	for (n = 0; n < nfiles - 1; n++) {	/* sort the list of names */
X		for (m = n + 1; m < nfiles; m++) {
X			if (strcmp(name[n], name[m]) > 0) {
X				d = path[n];
X				path[n] = path[m];
X				path[m] = d;
X				d = name[n];
X				name[n] = name[m];
X				name[m] = d;
X			}
X		}
X	}
X
X	for (n = 0; n < nfiles - 1;) {	/* consolidate the list of names */
X		if (!strcmp(path[n], path[n + 1])	/* if duplicate names */
X		    ||!strcmp(path[n], arcname)	/* or this archive */
X#if	UNIX
X		    ||izadir(path[n])	/* or a directory */
X#endif
X		    ||!strcmp(path[n], newname)	/* or the new version */
X		    ||!strcmp(path[n], bakname)) {	/* or its backup */
X			free(path[n]);	/* then forget the file */
X			free(name[n]);
X			for (m = n; m < nfiles - 1; m++) {
X				path[m] = path[m + 1];
X				name[m] = name[m + 1];
X			}
X			nfiles--;
X		} else
X			n++;	/* else test the next one */
X	}
X
X	if (!strcmp(path[n], arcname)	/* special check for last file */
X	    ||!strcmp(path[n], newname)	/* courtesy of Rick Moore */
X#if	UNIX
X	    ||izadir(path[n])
X#endif
X	    || !strcmp(path[n], bakname)) {
X		free(path[n]);
X		free(name[n]);
X		nfiles--;
X	}
X	if (!nfiles)		/* make sure we got some */
X		return 0;
X
X	for (n = 0; n < nfiles - 1; n++) {	/* watch out for duplicate
X						 * names */
X#ifdef LOCAL
X		if (!strcmp(name[n], name[n + 1])) {
X			printf("Duplicate filenames: %s %s\n", path[n], path[n+1]);
X			printf("Skipping filename: %s\n", path[n+1]);
X			free(path[n+1]);
X			free(name[n+1]);
X			for (m = n+1; m < nfiles-1 ; m++) {
X				path[m] = path[m+1];
X				name[m] = name[m+1];
X			}
X			nfiles--;
X		}
X#else /* LOCAL */
X		if (!strcmp(name[n], name[n + 1]))
X			abort("Duplicate filenames:\n  %s\n  %s", path[n], path[n + 1]);
X#endif /* LOCAL */
X	}
X	openarc(1);		/* open archive for changes */
X
X	for (n = 0; n < nfiles;) { /* add each file in the list */
X		if (addfile(path[n], name[n], update, fresh) < 0) {
X			free(path[n]);		/* remove this name if */
X			free(name[n]);		/* it wasn't added */
X			for (m = n; m < nfiles-1 ; m++) {
X				path[m] = path[m+1];
X				name[m] = name[m+1];
X			}
X			nfiles--;
X		} else n++;
X	}
X
X	/* now we must copy over all files that follow our additions */
X
X	while (readhdr(&hdr, arc)) {	/* while more entries to copy */
X		writehdr(&hdr, new);
X		filecopy(arc, new, hdr.size);
X	}
X	hdrver = 0;		/* archive EOF type */
X	writehdr(&hdr, new);	/* write out our end marker */
X	closearc(1);		/* close archive after changes */
X
X	if (move) {		/* if this was a move */
X		for (n = 0; n < nfiles; n++) {	/* then delete each file
X						 * added */
X			if (unlink(path[n]) && warn) {
X				printf("Cannot unsave %s\n", path[n]);
X				nerrs++;
X			}
X		}
X	}
X	return nfiles;		/* say how many were added */
X}
X
Xstatic          int
Xaddfile(path, name, update, fresh)	/* add named file to archive */
X	char           *path;	/* path name of file to add */
X	char           *name;	/* name of file to add */
X	int             update;	/* true if updating */
X	int             fresh;	/* true if freshening */
X{
X	struct heads    nhdr;	/* data regarding the new file */
X	struct heads    ohdr;	/* data regarding an old file */
X	FILE           *f, *fopen();	/* file to add, opener */
X	long            starts, ftell();	/* file locations */
X	int             upd = 0;/* true if replacing an entry */
X#ifdef LOCAL
X	void upper();
X#endif /* LOCAL */
X
X#if	!MTS
X	if (!(f = fopen(path, OPEN_R)))
X#else
X	if (image)
X		f = fopen(path, "rb");
X	else
X		f = fopen(path, "r");
X	if (!f)
X#endif
X	{
X		if (warn) {
X			printf("Cannot read file: %s\n", path);
X			nerrs++;
X		}
X		return(-1);
X	}
X#if	!DOS
X	if (strlen(name) >= FNLEN) {
X		if (warn) {
X			char	buf[STRLEN];
X			printf("WARNING: File %s name too long!\n", name);
X			name[FNLEN-1]='\0';
X			while(1) {
X				printf("  Truncate to %s (y/n)? ", name);
X				fflush(stdout);
X				fgets(buf, STRLEN, stdin);
X				*buf = toupper(*buf);
X				if (*buf == 'Y' || *buf == 'N')
X					break;
X			}
X			if (*buf == 'N') {
X				printf("Skipping...\n");
X				fclose(f);
X				return(-1);
X			}
X		}
X		else {
X			if (note)
X				printf("Skipping file: %s - name too long.\n",
X					name);
X			fclose(f);
X			return(-1);
X		}
X	}
X#endif
X#ifdef LOCAL
X	upper(name);
X#endif /* LCOAL */
X	strcpy(nhdr.name, name);/* save name */
X	nhdr.size = 0;		/* clear out size storage */
X	nhdr.crc = 0;		/* clear out CRC check storage */
X#if	!MTS
X	getstamp(f, &nhdr.date, &nhdr.time);
X#else
X	{
X	char *buffer, *malloc();
X	int	inlen;
X	struct	GDDSECT	*region;
X
X	region=gdinfo(f->_fd._fdub);
X	inlen=region->GDINLEN;
X	buffer=malloc(inlen);	/* maximum line length */
X	setbuf(f,buffer);        
X	f->_bufsiz=inlen;        
X	f->_mods|=_NOIC;	/* Don't do "$continue with" */
X	f->_mods&=~_IC;		/* turn it off, if set... */
X	}
X	getstamp(path, &nhdr.date, &nhdr.time);
X#endif
X
X	/* position archive to spot for new file */
X
X	if (arc) {		/* if adding to existing archive */
X		starts = ftell(arc);	/* where are we? */
X		while (readhdr(&ohdr, arc)) {	/* while more files to check */
X			if (!strcmp(ohdr.name, nhdr.name)) {
X				upd = 1;	/* replace existing entry */
X				if (update || fresh) {	/* if updating or
X							 * freshening */
X					if (nhdr.date < ohdr.date
X					    || (nhdr.date == ohdr.date && nhdr.time <= ohdr.time)) {
X						fseek(arc, starts, 0);
X						fclose(f);
X						return(0);/* skip if !newer */
X					}
X				}
X			}
X			if (strcmp(ohdr.name, nhdr.name) >= 0)
X				break;	/* found our spot */
X
X			writehdr(&ohdr, new);	/* entry preceeds update;
X						 * keep it */
X			filecopy(arc, new, ohdr.size);
X			starts = ftell(arc);	/* now where are we? */
X		}
X
X		if (upd) {	/* if an update */
X			if (note) {
X				printf("Updating file: %-12s  ", name);
X				fflush(stdout);
X			}
X			fseek(arc, ohdr.size, 1);
X		} else if (fresh) {	/* else if freshening */
X			fseek(arc, starts, 0);	/* then do not add files */
X			fclose(f);
X			return(0);
X		} else {	/* else adding a new file */
X			if (note) {
X				printf("Adding file:   %-12s  ", name);
X				fflush(stdout);
X			}
X			fseek(arc, starts, 0);	/* reset for next time */
X		}
X	} else {		/* no existing archive */
X		if (fresh) {	/* cannot freshen nothing */
X			fclose(f);
X			return(0);
X		} else if (note) {	/* else adding a file */
X			printf("Adding file:   %-12s  ", name);
X			fflush(stdout);
X		}
X	}
X
X	starts = ftell(new);	/* note where header goes */
X	hdrver = ARCVER;		/* anything but end marker */
X	writehdr(&nhdr, new);	/* write out header skeleton */
X	pack(f, new, &nhdr);	/* pack file into archive */
X	fseek(new, starts, 0);	/* move back to header skeleton */
X	writehdr(&nhdr, new);	/* write out real header */
X	fseek(new, nhdr.size, 1);	/* skip over data to next header */
X	fclose(f);		/* all done with the file */
X	return(0);
X}
X
X#ifdef LOCAL
X/*
X * Convert a Unix filename to a legal MSDOS name.  Returns a 1 if the file
X * can't be found (or is not a regular file).  Will truncate file and
X * extension names, will substitute the letter 'X' for any illegal character
X * in the name.
X */
X
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xint
Xlegalize(path, name)
Xchar *path, *name;
X{
X	static char *dev[8] = {"CON", "AUX", "COM1", "LPT1", "PRN", "LPT2",
X	"LPT3", "NUL"};
X	char *s, *temp, *ext, *strcpy(), *strpbrk(), buf[256];
X	int i, dot, modified, verbose;
X	struct stat stbuf;
X
X/*	verbose = warn; */
X	verbose = 0;
X
X	if (stat(path, &stbuf) < 0) {
X		fprintf(stderr, "Can't find \"%s\"\n", path);
X		return(1);
X	}
X	if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X		if (verbose)
X			fprintf(stderr, "\"%s\" Is not a regular file\n", path);
X		return(1);
X	}
X
X	strcpy(buf, name);
X	temp = buf;
X
X	ext = "";
X	dot = 0;
X	for (s = temp; *s; ++s) {
X		if (*s == '.' && !dot) {
X			dot = 1;
X			*s = '\0';
X			ext = s + 1;
X		}
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X	if (*temp == '\0') {
X		temp = "X";
X		if (verbose)
X			printf("\"%s\" Null name component, using \"%s.%s\"\n", name, temp, ext);
X	}
X	for (i=0; i<8; i++) {
X		if (!strcmp(temp, dev[i])) {
X			*temp = 'X';
X			if (verbose)
X				printf("\"%s\" Is a device name, using \"%s.%s\"\n", name, temp, ext);
X		}
X	}
X	if (strlen(temp) > 8) {
X		*(temp+8) = '\0';
X		if (verbose)
X			printf("\"%s\" Name too long, using, \"%s.%s\"\n", name, temp, ext);
X	}
X	if (strlen(ext) > 3) {
X		*(ext+3) = '\0';
X		if (verbose)
X			printf("\"%s\" Extension too long, using \"%s.%s\"\n", name, temp, ext);
X	}
X	modified = 0;
X	while (s = strpbrk(temp, "^+=/[]:',?*\\<>|\". ")) {
X		modified++;
X		*s = 'X';
X	}
X	while (s = strpbrk(ext, "^+=/[]:',?*\\<>|\". ")) {
X		modified++;
X		*s = 'X';
X	}
X	if (modified && verbose)
X		printf("\"%s\" Contains illegal character(s), using \"%s.%s\"\n", name, temp, ext);
X
X	if (*ext != '\0') 
X		sprintf(name, "%s.%s", temp, ext);
X	else
X		strcpy(name, temp);
X	return(0);
X}
X
X#ifdef BSD
X
Xchar *
Xstrpbrk(p1, p2)
Xchar *p1, *p2;
X{
X	char *p2start = p2;
X
X	while (*p1) {
X		while (*p2) {
X			if (*p2 == *p1)
X				return p1;
X			p2++;
X		}
X		p2 = p2start;
X		p1++;
X	}
X	return NULL;
X}
X
X#endif /* BSD */
X#endif /* LOCAL */
SHAR_EOF
if test 12955 -ne "`wc -c < 'arcadd.c'`"
then
	echo shar: "error transmitting 'arcadd.c'" '(should have been 12955 characters)'
fi
fi
echo shar: "extracting 'arccode.c'" '(1192 characters)'
if test -f 'arccode.c'
then
	echo shar: "will not over-write existing file 'arccode.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arccode.c'
X/*
X * $Header: arccode.c,v 1.1 88/06/01 15:15:58 hyc Locked $
X */
X
X/*
X * ARC - Archive utility - ARCCODE
X * 
X * Version 1.02, created on 01/20/86 at 13:33:35
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to encrypt and decrypt data
X * in an archive.  The encryption method is nothing fancy, being just a
X * routine XOR, but it is used on the packed data, and uses a variable length
X * key.  The end result is something that is in theory crackable, but I'd
X * hate to try it.  It should be more than sufficient for casual use.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xstatic char    *p;		/* password pointer */
X
Xvoid
Xsetcode()
X{				/* get set for encoding/decoding */
X	p = password;		/* reset password pointer */
X}
X
Xint
Xcode(c)				/* encode some character */
Xint            c;	/* character to encode */
X{
X	if (p) {		/* if password is in use */
X		if (!*p)	/* if we reached the end */
X			p = password;	/* then wrap back to the start */
X		return c ^ *p++;/* very simple here */
X	} else
X		return c;	/* else no encryption */
X}
SHAR_EOF
if test 1192 -ne "`wc -c < 'arccode.c'`"
then
	echo shar: "error transmitting 'arccode.c'" '(should have been 1192 characters)'
fi
fi
echo shar: "extracting 'arccvt.c'" '(3396 characters)'
if test -f 'arccvt.c'
then
	echo shar: "will not over-write existing file 'arccvt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arccvt.c'
X/*
X * $Header: arccvt.c,v 1.5 88/06/01 19:17:40 hyc Locked $
X */
X
X/*
X * ARC - Archive utility - ARCCVT
X * 
X * Version 1.16, created on 02/03/86 at 22:53:02
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to convert archives to use
X * newer file storage methods.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	openarc(), rempath(), closearc(), abort(), pack(), writehdr(), filecopy();
Xint	match(), readhdr(), unpack(), unlink();
X
Xstatic char     tempname[STRLEN];	/* temp file name */
X
Xvoid
Xcvtarc(num, arg)		/* convert archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X{
X	struct heads    hdr;	/* file header */
X	int             cvt;	/* true to convert current file */
X	int             did[MAXARG];/* true when argument was used */
X	int             n;	/* index */
X	char           *makefnam();	/* filename fixer */
X	FILE           *fopen();/* file opener */
X	void            cvtfile();
X
X	if (arctemp)		/* use temp area if specified */
X		sprintf(tempname, "%s.CVT", arctemp);
X	else
X		makefnam("$ARCTEMP.CVT", arcname, tempname);
X#if	!DOS
X	image = 1;
X#endif
X
X	openarc(1);		/* open archive for changes */
X
X	for (n = 0; n < num; n++)	/* for each argument */
X		did[n] = 0;	/* reset usage flag */
X	rempath(num, arg);	/* strip off paths */
X
X	if (num) {		/* if files were named */
X		while (readhdr(&hdr, arc)) {	/* while more files to check */
X			cvt = 0;/* reset convert flag */
X			for (n = 0; n < num; n++) {	/* for each template
X							 * given */
X				if (match(hdr.name, arg[n])) {
X					cvt = 1;	/* turn on convert flag */
X					did[n] = 1;	/* turn on usage flag */
X					break;	/* stop looking */
X				}
X			}
X
X			if (cvt)/* if converting this one */
X				cvtfile(&hdr);	/* then do it */
X			else {	/* else just copy it */
X				writehdr(&hdr, new);
X				filecopy(arc, new, hdr.size);
X			}
X		}
X	} else
X		while (readhdr(&hdr, arc))	/* else convert all files */
X			cvtfile(&hdr);
X
X	hdrver = 0;		/* archive EOF type */
X	writehdr(&hdr, new);	/* write out our end marker */
X	closearc(1);		/* close archive after changes */
X
X	if (note) {
X		for (n = 0; n < num; n++) {	/* report unused args */
X			if (!did[n]) {
X				printf("File not found: %s\n", arg[n]);
X				nerrs++;
X			}
X		}
X	}
X}
X
Xvoid
Xcvtfile(hdr)			/* convert a file */
X	struct heads   *hdr;	/* pointer to header data */
X{
X	long            starts, ftell();	/* where the file goes */
X	FILE           *tmp, *fopen();	/* temporary file */
X
X	if (!(tmp = fopen(tempname, "w+b")))
X		abort("Unable to create temporary file %s", tempname);
X
X	if (note) {
X		printf("Converting file: %-12s   reading, ", hdr->name);
X		fflush(stdout);
X	}
X	unpack(arc, tmp, hdr);	/* unpack the entry */
X	fseek(tmp, 0L, 0);	/* reset temp for reading */
X
X	starts = ftell(new);	/* note where header goes */
X	hdrver = ARCVER;		/* anything but end marker */
X	writehdr(hdr, new);	/* write out header skeleton */
X	pack(tmp, new, hdr);	/* pack file into archive */
X	fseek(new, starts, 0);	/* move back to header skeleton */
X	writehdr(hdr, new);	/* write out real header */
X	fseek(new, hdr->size, 1);	/* skip over data to next header */
X	fclose(tmp);		/* all done with the file */
X	if (unlink(tempname) && warn) {
X		printf("Cannot unsave %s\n", tempname);
X		nerrs++;
X	}
X}
SHAR_EOF
if test 3396 -ne "`wc -c < 'arccvt.c'`"
then
	echo shar: "error transmitting 'arccvt.c'" '(should have been 3396 characters)'
fi
fi
echo shar: "extracting 'arcdata.c'" '(2067 characters)'
if test -f 'arcdata.c'
then
	echo shar: "will not over-write existing file 'arcdata.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcdata.c'
X/*
X * $Header: arcdata.c,v 1.7 88/07/31 18:47:22 hyc Exp $
X */
X
X/*  ARC - Archive utility - ARCDATA
X
X    Version 2.17, created on 04/22/87 at 13:09:43
X
X(C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:	 Thom Henderson
X
X    Description: 
X	 This file defines the external data storage used by the ARC
X	 archive utility.
X
X
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X
X#define DONT_DEFINE
X#include "arc.h"
X
Xint             keepbak = 0;	/* true if saving the old archive */
X#if	UNIX
Xint		image = 1;	/* true to suppress CRLF/LF x-late */
X#endif
X#if	MTS
Xint             image = 0;	/* true to suppress EBCDIC/ASCII x-late */
Xchar            sepchr[2] = ":";/* Shared file separator */
Xchar            tmpchr[2] = "-";/* Temporary file prefix */
X#endif
X#if	GEMDOS
Xint		hold = 0;	/* true to pause before exit */
X#endif
Xint             warn = 1;	/* true to print warnings */
Xint             note = 1;	/* true to print comments */
Xint             bose = 0;	/* true to be verbose */
Xint             nocomp = 0;	/* true to suppress compression */
Xint             overlay = 0;	/* true to overlay on extract */
Xint             kludge = 0;	/* kludge flag */
Xchar           *arctemp = NULL;	/* arc temp file prefix */
Xchar           *password = NULL;/* encryption password pointer */
Xint             nerrs = 0;	/* number of errors encountered */
Xint		changing = 0;	/* true if archive being modified */
X
Xchar            hdrver;		/* header version */
X
XFILE           *arc;		/* the old archive */
XFILE           *new;		/* the new archive */
Xchar            arcname[STRLEN];	/* storage for archive name */
Xchar            bakname[STRLEN];	/* storage for backup copy name */
Xchar            newname[STRLEN];	/* storage for new archive name */
Xunsigned short  arcdate = 0;	/* archive date stamp */
Xunsigned short  arctime = 0;	/* archive time stamp */
Xunsigned short  olddate = 0;	/* old archive date stamp */
Xunsigned short  oldtime = 0;	/* old archive time stamp */
Xint		dosquash = 0;	/* true to squash instead of crunch */
SHAR_EOF
if test 2067 -ne "`wc -c < 'arcdata.c'`"
then
	echo shar: "error transmitting 'arcdata.c'" '(should have been 2067 characters)'
fi
fi
echo shar: "extracting 'arcdel.c'" '(2055 characters)'
if test -f 'arcdel.c'
then
	echo shar: "will not over-write existing file 'arcdel.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcdel.c'
X/*
X * $Header: arcdel.c,v 1.3 88/04/19 01:39:32 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCDEL
X * 
X * Version 2.09, created on 02/03/86 at 22:53:27
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to delete entries in an
X * archive.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	abort(), rempath(), openarc(), closearc(), writehdr(), filecopy();
Xint	match(), readhdr();
X
Xvoid
Xdelarc(num, arg)		/* remove files from archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X{
X	struct heads    hdr;	/* header data */
X	int             del;	/* true to delete a file */
X	int             did[MAXARG];/* true when argument used */
X	int             n;	/* index */
X
X	if (!num)		/* she must specify which */
X		abort("You must tell me which files to delete!");
X
X	for (n = 0; n < num; n++)	/* for each argument */
X		did[n] = 0;	/* reset usage flag */
X	rempath(num, arg);	/* strip off paths */
X
X	openarc(1);		/* open archive for changes */
X
X	while (readhdr(&hdr, arc)) {	/* while more entries in archive */
X		del = 0;	/* reset delete flag */
X		for (n = 0; n < num; n++) {	/* for each template given */
X			if (match(hdr.name, arg[n])) {
X				del = 1;	/* turn on delete flag */
X				did[n] = 1;	/* turn on usage flag */
X				break;	/* stop looking */
X			}
X		}
X
X		if (del) {	/* skip over unwanted files */
X			fseek(arc, hdr.size, 1);
X			if (note)
X				printf("Deleting file: %s\n", hdr.name);
X		} else {	/* else copy over file data */
X			writehdr(&hdr, new);	/* write out header and file */
X			filecopy(arc, new, hdr.size);
X		}
X	}
X
X	hdrver = 0;		/* special end of archive type */
X	writehdr(&hdr, new);	/* write out archive end marker */
X	closearc(1);		/* close archive after changes */
X
X	if (note) {
X		for (n = 0; n < num; n++) {	/* report unused arguments */
X			if (!did[n]) {
X				printf("File not found: %s\n", arg[n]);
X				nerrs++;
X			}
X		}
X	}
X}
SHAR_EOF
if test 2055 -ne "`wc -c < 'arcdel.c'`"
then
	echo shar: "error transmitting 'arcdel.c'" '(should have been 2055 characters)'
fi
fi
echo shar: "extracting 'arcdos.c'" '(4684 characters)'
if test -f 'arcdos.c'
then
	echo shar: "will not over-write existing file 'arcdos.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcdos.c'
X/*
X * $Header: arcdos.c,v 1.8 88/08/01 15:07:15 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCDOS
X * 
X * Version 1.44, created on 07/25/86 at 14:17:38
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains certain DOS level routines that assist in
X * doing fancy things with an archive, primarily reading and setting the date
X * and time last modified.
X * 
X * These are, by nature, system dependant functions.  But they are also, by
X * nature, very expendable.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
X#if	MSDOS
X#include "fileio2.h"		/* needed for filehand */
X#endif
X
X#if	UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X
Xstruct timeval {	/* man page said <sys/types.h>, but it */
X	long tv_sec;	/* really seems to be in <sys/time.h>, */
X	long tv_usec;	/* but why bother... */
X};
X#endif
X
X#if	GEMDOS
X#include <osbind.h>
X#endif
X
Xchar	*strcpy(), *strcat(), *malloc();
X
Xvoid
Xgetstamp(f, date, time)		/* get a file's date/time stamp */
X#if	!MTS
X	FILE           *f;	/* file to get stamp from */
X#else
X	char           *f;	/* filename "" "" */
X#endif
X	unsigned short   *date, *time;	/* storage for the stamp */
X{
X#if	MSDOS
X	struct {
X		int             ax, bx, cx, dx, si, di, ds, es;
X	}               reg;
X
X	reg.ax = 0x5700;	/* get date/time */
X	reg.bx = filehand(f);	/* file handle */
X	if (sysint21(&reg, &reg) & 1)	/* DOS call */
X		printf("Get timestamp fail (%d)\n", reg.ax);
X
X	*date = reg.dx;		/* save date/time */
X	*time = reg.cx;
X#endif
X#if	GEMDOS
X	int	fd, ret[2];
X
X	fd = fileno(f);
X	Fdatime(ret, fd, 0);
X	*date = ret[1];
X	*time = ret[0];
X#endif
X#if	UNIX
X	struct stat	buf;
X	struct tm	*localtime(), *t;
X
X	fstat(fileno(f), &buf);
X	t=localtime(&(buf.st_mtime));
X	*date = (unsigned short) (((t->tm_year - 80) << 9) +
X				((t->tm_mon + 1) << 5) + t->tm_mday);
X	*time = (unsigned short) ((t->tm_hour << 11) +
X				(t->tm_min << 5) + t->tm_sec / 2);
X#endif
X#if	MTS
X	fortran         timein(),
X#if	USEGFINFO
X	                gfinfo();
X#else
X	                fileinfo();
X#endif
X	int             stclk[2];
X	char            name[24];
X	struct bigtime {
X		int             greg;
X		int             year;
X		int             mon;
X		int             day;
X		int             hour;
X		int             min;
X		int             sec;
X		int             usec;
X		int             week;
X		int             toff;
X		int             tzn1;
X		int             tzn2;
X	}               tvec;
X#if	USEGFINFO
X	static int      gfflag = 0x0009, gfdummy[2] = {
X						       0, 0
X	};
X	int             gfcinfo[18];
X#else
X	static int      cattype = 2;
X#endif
X
X	strcpy(name, f);
X	strcat(name, " ");
X#if	USEGFINFO
X	gfcinfo[0] = 18;
X	gfinfo(name, name, &gfflag, gfcinfo, gfdummy, gfdummy);
X	timein("*IBM MICROSECONDS*", &gfcinfo[16], &tvec);
X#else
X	fileinfo(name, &cattype, "CILCCT  ", stclk);
X	timein("*IBM MICROSECONDS*", stclk, &tvec);
X#endif
X
X	*date = (unsigned short) (((tvec.year - 1980) << 9) + ((tvec.mon) << 5) + tvec.day);
X	*time = (unsigned short) ((tvec.hour << 11) + (tvec.min << 5) + tvec.sec / 2);
X#endif
X}
X
Xvoid
Xsetstamp(f, date, time)		/* set a file's date/time stamp */
X	char           *f;	/* filename to stamp */
X	unsigned short    date, time;	/* desired date, time */
X{
X#if	MSDOS
X	FILE	*ff;
X	struct {
X		int             ax, bx, cx, dx, si, di, ds, es;
X	}               reg;
X
X	ff = fopen(f, "w+");	/* How else can I get a handle? */
X
X	reg.ax = 0x5701;	/* set date/time */
X	reg.bx = filehand(f);	/* file handle */
X	reg.cx = time;		/* desired time */
X	reg.dx = date;		/* desired date */
X	if (sysint21(&reg, &reg) & 1)	/* DOS call */
X		printf("Set timestamp fail (%d)\n", reg.ax);
X	fclose(ff);
X#endif
X#if	GEMDOS
X	int	fd, set[2];
X
X	fd = Fopen(f, 0);
X	set[0] = time;
X	set[1] = date;
X	Fdatime(set, fd, 1);
X	Fclose(fd);
X#endif
X#if	UNIX
X	struct tm	tm;
X	struct timeval  tvp[2];
X	int	utimes();
X	long tmclock();
X	tm.tm_sec = (time & 31) * 2;
X	tm.tm_min = (time >> 5) & 63;
X	tm.tm_hour = (time >> 11);
X	tm.tm_mday = date & 31;
X	tm.tm_mon = ((date >> 5) & 15) - 1;
X	tm.tm_year = (date >> 9) + 80;
X	tvp[0].tv_sec = tmclock(&tm);
X	tvp[1].tv_sec = tvp[0].tv_sec;
X	tvp[0].tv_usec = tvp[1].tv_usec = 0;
X	utimes(f, tvp);
X#endif
X}
X
X#if	MSDOS
Xint
Xfilehand(stream)		/* find handle on a file */
X	struct bufstr  *stream;	/* file to grab onto */
X{
X	return stream->bufhand;	/* return DOS 2.0 file handle */
X}
X#endif
X
X#if	UNIX
Xint
Xizadir(filename)		/* Is filename a directory? */
X	char           *filename;
X{
X	struct stat     buf;
X
X	if (stat(filename, &buf) != 0)
X		return (0);	/* Ignore if stat fails since */
X	else
X		return (buf.st_mode & S_IFDIR);	/* bad files trapped later */
X}
X#endif
SHAR_EOF
if test 4684 -ne "`wc -c < 'arcdos.c'`"
then
	echo shar: "error transmitting 'arcdos.c'" '(should have been 4684 characters)'
fi
fi
echo shar: "extracting 'arcext.c'" '(5041 characters)'
if test -f 'arcext.c'
then
	echo shar: "will not over-write existing file 'arcext.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcext.c'
X/*
X * $Header: arcext.c,v 1.5 88/06/01 19:26:31 hyc Locked $
X */
X
X/*
X * ARC - Archive utility - ARCEXT
X * 
X * Version 2.19, created on 10/24/86 at 14:53:32
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to extract files from an
X * archive.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X#if	!MSDOS
X#include <ctype.h>
X#endif
X
Xvoid	openarc(), closearc(), setstamp();
Xint	free(), match(), readhdr(), unpack();
Xchar	*strcpy(), *strcat();
X
Xvoid
Xextarc(num, arg, prt)		/* extract files from archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X	int             prt;		/* true if printing */
X{
X	struct heads    hdr;	/* file header */
X	int             save;	/* true to save current file */
X	int             did[MAXARG];/* true when argument was used */
X	char           *i, *rindex();	/* string index */
X	char          **name, *malloc();	/* name pointer list,
X						 * allocator */
X	int             n;	/* index */
X	void            extfile();
X
X	name = (char **) malloc(num * sizeof(char *));	/* get storage for name
X							 * pointers */
X
X	for (n = 0; n < num; n++) {	/* for each argument */
X		did[n] = 0;	/* reset usage flag */
X#if	!MTS
X		if (!(i = rindex(arg[n], '\\')))	/* find start of name */
X			if (!(i = rindex(arg[n], '/')))
X				if (!(i = rindex(arg[n], ':')))
X					i = arg[n] - 1;
X#else
X		if (!(i = rindex(arg[n], sepchr[0])))
X			if (arg[n][0] != tmpchr[0])
X				i = arg[n] - 1;
X			else
X				i = arg[n];
X#endif
X		name[n] = i + 1;
X	}
X
X
X	openarc(0);		/* open archive for reading */
X
X	if (num) {		/* if files were named */
X		while (readhdr(&hdr, arc)) {	/* while more files to check */
X			save = 0;	/* reset save flag */
X			for (n = 0; n < num; n++) {	/* for each template
X							 * given */
X				if (match(hdr.name, name[n])) {
X					save = 1;	/* turn on save flag */
X					did[n] = 1;	/* turn on usage flag */
X					break;	/* stop looking */
X				}
X			}
X
X			if (save)	/* extract if desired, else skip */
X				extfile(&hdr, arg[n], prt);
X			else
X				fseek(arc, hdr.size, 1);
X		}
X	} else
X		while (readhdr(&hdr, arc))	/* else extract all files */
X			extfile(&hdr, "", prt);
X
X	closearc(0);		/* close archive after reading */
X
X	if (note) {
X		for (n = 0; n < num; n++) {	/* report unused args */
X			if (!did[n]) {
X				printf("File not found: %s\n", arg[n]);
X				nerrs++;
X			}
X		}
X	}
X	free(name);
X}
X
Xvoid
Xextfile(hdr, path, prt)		/* extract a file */
X	struct heads   *hdr;	/* pointer to header data */
X	char           *path;	/* pointer to path name */
X	int             prt;	/* true if printing */
X{
X	FILE           *f, *fopen();	/* extracted file, opener */
X	char            buf[STRLEN];	/* input buffer */
X	char            fix[STRLEN];	/* fixed name buffer */
X	char           *i, *rindex();	/* string index */
X#ifdef LOCAL
X	extern int unix_names;
X	void lower();
X#endif /* LOCAL */
X
X	if (prt) {		/* printing is much easier */
X		unpack(arc, stdout, hdr);	/* unpack file from archive */
X		printf("\f");	/* eject the form */
X		return;		/* see? I told you! */
X	}
X	strcpy(fix, path);	/* note path name template */
X#if	!MTS
X	if (*path) {
X	if (!(i = rindex(fix, '\\')))	/* find start of name */
X		if (!(i = rindex(fix, '/')))
X			if (!(i = rindex(fix, ':')))
X				i = fix - 1;
X	} else i = fix -1;
X#else
X	if (!(i = rindex(fix, sepchr[0])))
X		if (fix[0] != tmpchr[0])
X			i = fix - 1;
X		else
X			i = fix;
X#endif
X#ifdef LOCAL
X	if (!unix_names)
X		lower(hdr->name);
X#endif /* LOCAL */
X	strcpy(i + 1, hdr->name);	/* replace template with name */
X
X	if (note)
X		printf("Extracting file: %s\n", fix);
X
X	if (warn && !overlay) {
X		if (f = fopen(fix, "r")) {	/* see if it exists */
X				fclose(f);
X				printf("WARNING: File %s already exists!", fix);
X				fflush(stdout);
X				while (1) {
X					printf("  Overwrite it (y/n)? ");
X					fflush(stdout);
X					fgets(buf, STRLEN, stdin);
X					*buf = toupper(*buf);
X					if (*buf == 'Y' || *buf == 'N')
X						break;
X				}
X				if (*buf == 'N') {
X					printf("%s not extracted.\n", fix);
X					fseek(arc, hdr->size, 1);
X					return;
X				}
X		}
X	}
X#if	!MTS
X	if (!(f = fopen(fix, OPEN_W)))
X#else
X	{
X		fortran         create();
X		void		memset();
X		char            c_name[256];
X		struct crsize {
X			short           maxsize, cursize;
X		}               c_size;
X		char            c_vol[6];
X		int             c_type;
X		strcpy(c_name, fix);
X		strcat(c_name, " ");
X		c_size.maxsize = 0;
X		c_size.cursize = hdr->length / 4096 + 1;
X		memset(c_vol, 0, sizeof(c_vol));
X		c_type = 0x100;
X		create(c_name, &c_size, c_vol, &c_type);
X	}
X	if (image) {
X		f = fopen(fix, "wb");
X	} else
X		f = fopen(fix, "w");
X	if (!f)
X#endif
X	{
X		if (warn) {
X			printf("Cannot create %s\n", fix);
X			nerrs++;
X		}
X		fseek(arc, hdr->size, 1);
X		return;
X	}
X	/* now unpack the file */
X
X	unpack(arc, f, hdr);	/* unpack file from archive */
X	fclose(f);		/* all done writing to file */
X#if	!MTS
X	setstamp(fix, hdr->date, hdr->time);	/* use filename for stamp */
X#endif
X}
SHAR_EOF
if test 5041 -ne "`wc -c < 'arcext.c'`"
then
	echo shar: "error transmitting 'arcext.c'" '(should have been 5041 characters)'
fi
fi
echo shar: "extracting 'arcio.c'" '(7491 characters)'
if test -f 'arcio.c'
then
	echo shar: "will not over-write existing file 'arcio.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcio.c'
X/*
X * $Header: arcio.c,v 1.9 88/07/31 18:49:19 hyc Exp $
X */
X
X/*  ARC - Archive utility - ARCIO
X
X    Version 2.50, created on 04/22/87 at 13:25:20
X
X(C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:	 Thom Henderson
X
X    Description:
X	 This file contains the file I/O routines used to manipulate
X	 an archive.
X
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X#if	MTS
X#include <ctype.h>
X#endif
X
Xvoid	abort();
Xint	strlen(), free();
X
Xint
Xreadhdr(hdr, f)			/* read a header from an archive */
X	struct heads   *hdr;	/* storage for header */
X	FILE           *f;	/* archive to read header from */
X{
X#if	!MSDOS
X	unsigned char   dummy[28];
X	int             i;
X#endif
X	char            name[FNLEN];	/* filename buffer */
X	int             try = 0;/* retry counter */
X	static int      first = 1;	/* true only on first read */
X
X	if (!f)			/* if archive didn't open */
X		return 0;	/* then pretend it's the end */
X	if (feof(f))		/* if no more data */
X		return 0;	/* then signal end of archive */
X
X	if (fgetc(f) != ARCMARK) {	/* check archive validity */
X		if (warn) {
X			printf("An entry in %s has a bad header.", arcname);
X			nerrs++;
X		}
X		while (!feof(f)) {
X			try++;
X			if (fgetc(f) == ARCMARK) {
X				ungetc(hdrver = fgetc(f), f);
X				if (!(hdrver & 0x80) && hdrver <= ARCVER)
X					break;
X			}
X		}
X
X		if (feof(f) && first)
X			abort("%s is not an archive", arcname);
X
X		if (changing && warn)
X			abort("%s is corrupted -- changes disallowed", arcname);
X
X		if (warn)
X			printf("  %d bytes skipped.\n", try);
X
X		if (feof(f))
X			return 0;
X	}
X	hdrver = fgetc(f);	/* get header version */
X	if (hdrver & 0x80)	/* sign bit? negative? */
X		abort("Invalid header in archive %s", arcname);
X	if (hdrver == 0)
X		return 0;	/* note our end of archive marker */
X	if (hdrver > ARCVER) {
X		fread(name, sizeof(char), FNLEN, f);
X#if	MTS
X		atoe(name, strlen(name));
X#endif
X		printf("I don't know how to handle file %s in archive %s\n",
X		       name, arcname);
X		printf("I think you need a newer version of ARC.\n");
X		exit(1);
X	}
X	/* amount to read depends on header type */
X
X	if (hdrver == 1) {	/* old style is shorter */
X		fread(hdr, sizeof(struct heads) - sizeof(long int), 1, f);
X		hdrver = 2;	/* convert header to new format */
X		hdr->length = hdr->size;	/* size is same when not
X						 * packed */
X	} else
X#if	MSDOS
X		fread(hdr, sizeof(struct heads), 1, f);
X#else
X		fread(dummy, 27, 1, f);
X
X	for (i = 0; i < FNLEN; hdr->name[i] = dummy[i], i++);
X#if	MTS
X	(void) atoe(hdr->name, strlen(hdr->name));
X#endif
X	for (i = 0, hdr->size=0; i<4; hdr->size<<=8, hdr->size += dummy[16-i], i++);
X	hdr->date = (short) ((dummy[18] << 8) + dummy[17]);
X	hdr->time = (short) ((dummy[20] << 8) + dummy[19]);
X	hdr->crc = (short) ((dummy[22] << 8) + dummy[21]);
X	for (i = 0, hdr->length=0; i<4; hdr->length<<=8, hdr->length += dummy[26-i], i++);
X#endif
X
X	if (hdr->date > olddate
X	    || (hdr->date == olddate && hdr->time > oldtime)) {
X		olddate = hdr->date;
X		oldtime = hdr->time;
X	}
X	first = 0;
X	return 1;		/* we read something */
X}
X
Xvoid
Xput_int(number, f)		/* write a 2 byte integer */
X	short           number;
X	FILE           *f;
X{
X	fputc((char) (number & 255), f);
X	fputc((char) (number >> 8), f);
X}
X
Xvoid
Xput_long(number, f)		/* write a 4 byte integer */
X	long            number;
X	FILE           *f;
X{
X	put_int((short) (number & 0xFFFF), f);
X	put_int((short) (number >> 16), f);
X}
X
Xvoid
Xwritehdr(hdr, f)		/* write a header to an archive */
X	struct heads   *hdr;	/* header to write */
X	FILE           *f;	/* archive to write to */
X{
X	fputc(ARCMARK, f);		/* write out the mark of ARC */
X	fputc(hdrver, f);	/* write out the header version */
X	if (!hdrver)		/* if that's the end */
X		return;		/* then write no more */
X#if	MSDOS
X	fwrite(hdr, sizeof(struct heads), 1, f);
X#else
X	/* byte/word ordering hassles... */
X#if	MTS
X	etoa(hdr->name, strlen(hdr->name));
X#endif
X	fwrite(hdr->name, 1, FNLEN, f);
X	put_long(hdr->size, f);
X	put_int(hdr->date, f);
X	put_int(hdr->time, f);
X	put_int(hdr->crc, f);
X	put_long(hdr->length, f);
X#endif
X
X	/* note the newest file for updating the archive timestamp */
X
X	if (hdr->date > arcdate
X	    || (hdr->date == arcdate && hdr->time > arctime)) {
X		arcdate = hdr->date;
X		arctime = hdr->time;
X	}
X}
X
Xvoid
Xputc_tst(c, t)			/* put a character, with tests */
X	char            c;	/* character to output */
X	FILE           *t;	/* file to write to */
X{
X	c &= 0xff;
X	if (t) {
X#if	UNIX
X		fputc(c, t);
X		if (ferror(t))
X			abort("Write failed");
X#else
X		if (fputc(c, t) == EOF)
X			abort("Write fail (disk full?)");
X#endif
X	}
X}
X
X/*
X * NOTE:  The filecopy() function is used to move large numbers of bytes from
X * one file to another.  This particular version has been modified to improve
X * performance in Computer Innovations C86 version 2.3 in the small memory
X * model.  It may not work as expected with other compilers or libraries, or
X * indeed with different versions of the CI-C86 compiler and library, or with
X * the same version in a different memory model.
X * 
X * The following is a functional equivalent to the filecopy() routine that
X * should work properly on any system using any compiler, albeit at the cost
X * of reduced performance:
X * 
X * filecopy(f,t,size) 
X *      FILE *f, *t; long size; 
X * { 
X *      while(size--)
X *              putc_tst(fgetc(f),t); 
X * }
X */
X#if	MSDOS
X#include <fileio2.h>
X
Xfilecopy(f, t, size)		/* bulk file copier */
X	FILE           *f, *t;	/* files from and to */
X	long            size;	/* bytes to copy */
X{
X	char           *buf;	/* buffer pointer */
X	char           *alloc();/* buffer allocator */
X	unsigned int    bufl;	/* buffer length */
X	unsigned int    coreleft();	/* space available reporter */
X	unsigned int    cpy;	/* bytes being copied */
X	long            floc, tloc, fseek();	/* file pointers, setter */
X	struct regval   reg;	/* registers for DOS calls */
X
X	if ((bufl = coreleft()) < 1000)	/* see how much space we have */
X		abort("Out of memory");
X	bufl -= 1000;		/* fudge factor for overhead */
X	if (bufl > 60000)
X		bufl = 60000;	/* avoid choking alloc() */
X	if (bufl > size)
X		bufl = size;	/* avoid wasting space */
X	buf = alloc(bufl);	/* allocate our buffer */
X
X	floc = fseek(f, 0L, 1);	/* reset I/O system */
X	tloc = fseek(t, 0L, 1);
X
X	segread(&reg.si);	/* set segment registers for DOS */
X
X	while (size > 0) {	/* while more to copy */
X		reg.ax = 0x3F00;/* read from handle */
X		reg.bx = filehand(f);
X		reg.cx = bufl < size ? bufl : size;	/* amount to read */
X		reg.dx = buf;
X		if (sysint21(&reg, &reg) & 1)
X			abort("Read fail");
X
X		cpy = reg.ax;	/* amount actually read */
X		reg.ax = 0x4000;/* write to handle */
X		reg.bx = filehand(t);
X		reg.cx = cpy;
X		reg.dx = buf;
X		sysint21(&reg, &reg);
X
X		if (reg.ax != cpy)
X			abort("Write fail (disk full?)");
X
X		size -= (long) cpy;
X	}
X
X	free(buf);		/* all done with buffer */
X}
X#else
X
Xvoid
Xfilecopy(f, t, size)		/* bulk file copier */
X	FILE           *f, *t;	/* files from and to */
X	long            size;	/* bytes to copy */
X{
X	char           *buf;	/* buffer pointer */
X	char           *malloc();	/* buffer allocator */
X	unsigned int    bufl;	/* buffer length */
X	unsigned int    cpy;	/* bytes being copied */
X
X	bufl = 32760;
X	if (bufl > size)
X		bufl = size;	/* don't waste space */
X
X	buf = malloc(bufl);
X
X	while (size > 0) {
X		cpy = fread(buf, sizeof(char),
X			bufl < size ? bufl : (unsigned short) size, f);
X		if (fwrite(buf, sizeof(char), cpy, t) != cpy)
X			abort("Write fail (no space?)");
X		size -= cpy;
X	}
X
X	free(buf);
X}
X#endif
SHAR_EOF
if test 7491 -ne "`wc -c < 'arcio.c'`"
then
	echo shar: "error transmitting 'arcio.c'" '(should have been 7491 characters)'
fi
fi
echo shar: "extracting 'arclst.c'" '(4418 characters)'
if test -f 'arclst.c'
then
	echo shar: "will not over-write existing file 'arclst.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arclst.c'
X/*
X * $Header: arclst.c,v 1.5 88/06/01 18:05:57 hyc Locked $
X */
X
X/*  ARC - Archive utility - ARCLST
X  
X    Version 2.39, created on 04/22/87 at 13:48:29
X  
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X  
X    By:	 Thom Henderson
X  
X    Description:
X	 This file contains the routines used to list the contents
X	 of an archive.
X  
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X
Xvoid            rempath(), openarc(), closearc();
Xint             readhdr(), match();
X
Xvoid
Xlstarc(num, arg)		/* list files in archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X{
X	struct heads    hdr;	/* header data */
X	int             list;	/* true to list a file */
X	int             did[MAXARG];	/* true when argument was used */
X	long            tnum, tlen, tsize;	/* totals */
X	int             n;	/* index */
X	void            lstfile();
X
X	tnum = tlen = tsize = 0;/* reset totals */
X
X	for (n = 0; n < num; n++)	/* for each argument */
X		did[n] = 0;	/* reset usage flag */
X	rempath(num, arg);	/* strip off paths */
X
X	if (note && !kludge) {
X		printf("Name          Length  ");
X		if (bose)
X			printf("  Stowage    SF   Size now");
X		printf("  Date     ");
X		if (bose)
X			printf("  Time    CRC");
X		printf("\n");
X
X		printf("============  ========");
X		if (bose)
X			printf("  ========  ====  ========");
X		printf("  =========");
X		if (bose)
X			printf("  ======  ====");
X		printf("\n");
X	}
X	openarc(0);		/* open archive for reading */
X
X	if (num) {		/* if files were named */
X		while (readhdr(&hdr, arc)) {	/* process all archive files */
X			list = 0;	/* reset list flag */
X			for (n = 0; n < num; n++) {	/* for each template
X							 * given */
X				if (match(hdr.name, arg[n])) {
X					list = 1;	/* turn on list flag */
X					did[n] = 1;	/* turn on usage flag */
X					break;	/* stop looking */
X				}
X			}
X
X			if (list) {	/* if this file is wanted */
X				if (!kludge)
X					lstfile(&hdr);	/* then tell about it */
X				tnum++;	/* update totals */
X				tlen += hdr.length;
X				tsize += hdr.size;
X			}
X			fseek(arc, hdr.size, 1);	/* move to next header */
X		}
X	} else
X		while (readhdr(&hdr, arc)) {	/* else report on all files */
X			if (!kludge)
X				lstfile(&hdr);
X			tnum++;	/* update totals */
X			tlen += hdr.length;
X			tsize += hdr.size;
X			fseek(arc, hdr.size, 1);	/* skip to next header */
X		}
X
X	closearc(0);		/* close archive after reading */
X
X	if (note && !kludge) {
X		printf("        ====  ========");
X		if (bose)
X			printf("            ====  ========");
X		printf("\n");
X	}
X	if (note) {
X		printf("Total %6ld  %8ld", tnum, tlen);
X		if (bose) {
X			if (tlen)
X				printf("            %3ld%%", 100L - (100L * tsize) / tlen);
X			else
X				printf("            ---");
X			printf("  %8ld", tsize);
X		}
X		printf("\n");
X
X		for (n = 0; n < num; n++) {	/* report unused args */
X			if (!did[n]) {
X				printf("File not found: %s\n", arg[n]);
X				nerrs++;
X			}
X		}
X	}
X}
X
Xvoid
Xlstfile(hdr)			/* tell about a file */
X	struct heads   *hdr;	/* pointer to header data */
X{
X	int             yr, mo, dy;	/* parts of a date */
X	int             hh, mm;	/* parts of a time */
X
X	static char    *mon[] =	/* month abbreviations */
X	{
X	 "Jan", "Feb", "Mar", "Apr",
X	 "May", "Jun", "Jul", "Aug",
X	 "Sep", "Oct", "Nov", "Dec"
X	};
X
X	if (!note) {		/* no notes means short listing */
X		printf("%s\n", hdr->name);
X		return;
X	}
X
X	yr = (hdr->date >> 9) & 0x7f;	/* dissect the date */
X	mo = (hdr->date >> 5) & 0x0f;
X	dy = hdr->date & 0x1f;
X
X	hh = (hdr->time >> 11) & 0x1f;	/* dissect the time */
X	mm = (hdr->time >> 5) & 0x3f;
X/*	ss = (hdr->time & 0x1f) * 2;	seconds, not used. */
X
X	printf("%-12s  %8ld  ", hdr->name, hdr->length);
X
X	if (bose) {
X		switch (hdrver) {
X		case 1:
X		case 2:
X			printf("   --   ");
X			break;
X		case 3:
X			printf(" Packed ");
X			break;
X		case 4:
X			printf("Squeezed");
X			break;
X		case 5:
X		case 6:
X		case 7:
X			printf("crunched");
X			break;
X		case 8:
X			printf("Crunched");
X			break;
X		case 9:
X			printf("Squashed");
X			break;
X		default:
X			printf("Unknown!");
X		}
X
X		if (hdr->length)
X			printf("  %3ld%%", 100L - (100L * hdr->size) / hdr->length);
X		else
X			printf("  ---");
X		printf("  %8ld  ", hdr->size);
X	}
X	printf("%2d %3s %02d", dy, mon[mo - 1], (yr + 80) % 100);
X
X	if (bose)
X		printf("  %2d:%02d%c  %04x",
X		       (hh > 12 ? hh - 12 : hh), mm, (hh > 11 ? 'p' : 'a'),
X		       hdr->crc & 0xffff);
X
X	printf("\n");
X}
SHAR_EOF
if test 4418 -ne "`wc -c < 'arclst.c'`"
then
	echo shar: "error transmitting 'arclst.c'" '(should have been 4418 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (01/03/89)

This is part 4 (of 6) to the Arc v5.21 distribution package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	arclzw.c
#	arcmatch.c
#	arcmisc.c
#	arcpack.c
#	arcrun.c
#	arcs.h
# This archive created: Sun Jan  1 12:48:23 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arclzw.c'" '(22114 characters)'
if test -f 'arclzw.c'
then
	echo shar: "will not over-write existing file 'arclzw.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arclzw.c'
X/*
X * $Header: arclzw.c,v 1.6 88/07/31 18:49:49 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCLZW
X * 
X * Version 2.03, created on 10/24/86 at 11:46:22
X * 
X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to implement Lempel-Zev
X * data compression, which calls for building a coding table on the fly.
X * This form of compression is especially good for encoding files which
X * contain repeated strings, and can often give dramatic improvements over
X * traditional Huffman SQueezing.
X * 
X * Language: Computer Innovations Optimizing C86
X * 
X * Programming notes: In this section I am drawing heavily on the COMPRESS
X * program from UNIX.  The basic method is taken from "A Technique for High
X * Performance Data Compression", Terry A. Welch, IEEE Computer Vol 17, No 6
X * (June 1984), pp 8-19.  Also see "Knuth's Fundamental Algorithms", Donald
X * Knuth, Vol 3, Section 6.4.
X * 
X * As best as I can tell, this method works by tracing down a hash table of code
X * strings where each entry has the property:
X * 
X * if <string> <char> is in the table then <string> is in the table.
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	putc_pak(), abort(), putc_ncr();
Xint	getc_unp();
X#if	MSDOS
Xchar	*setmem();
X#else
Xchar	*memset();
X#endif
X
Xstatic void	putcode();
X/* definitions for older style crunching */
X
X#define FALSE    0
X#define TRUE     !FALSE
X#define TABSIZE  4096
X#define NO_PRED  0xFFFF
X#define EMPTY    0xFFFF
X#define NOT_FND  0xFFFF
X
Xstatic unsigned short inbuf;	/* partial input code storage */
Xstatic int      sp;		/* current stack pointer */
X
Xstruct entry {		/* string table entry format */
X	char            used;	/* true when this entry is in use */
X	unsigned char   follower;	/* char following string */
X	unsigned short  next;	/* ptr to next in collision list */
X	unsigned short  predecessor;	/* code for preceeding string */
X};            /* string_tab[TABSIZE];	   the code string table */
X
X
X/* definitions for the new dynamic Lempel-Zev crunching */
X
X#define BITS   12		/* maximum bits per code */
X#define HSIZE  5003		/* 80% occupancy */
X#define INIT_BITS 9		/* initial number of bits/code */
X
Xstatic int      n_bits;		/* number of bits/code */
Xstatic int      maxcode;	/* maximum code, given n_bits */
X#define MAXCODE(n)      ((1<<(n)) - 1)	/* maximum code calculation */
Xstatic int      maxcodemax = 1 << BITS;	/* largest possible code (+1) */
X
Xstatic char     buf[BITS];	/* input/output buffer */
X
Xstatic unsigned char lmask[9] =	/* left side masks */
X{
X 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00
X};
Xstatic unsigned char rmask[9] =	/* right side masks */
X{
X 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
X};
X
Xstatic int      offset;		/* byte offset for code output */
Xstatic long     in_count;	/* length of input */
Xstatic long     bytes_out;	/* length of compressed output */
Xstatic long     bytes_ref;	/* output quality reference */
Xstatic long     bytes_last;	/* output size at last checkpoint */
Xstatic unsigned short ent;
X
X/*
X * To save much memory (which we badly need at this point), we overlay the
X * table used by the previous version of Lempel-Zev with those used by the
X * new version.  Since no two of these routines will be used together, we can
X * safely do this.
X */
X
Xextern long     htab[HSIZE];		/* hash code table   (crunch) */
Xextern unsigned short codetab[HSIZE];	/* string code table (crunch) */
Xstatic struct	entry *string_tab=(struct entry *)htab;	/* old crunch string table */
X
Xstatic unsigned short *prefix=codetab;	/* prefix code table (uncrunch) */
Xstatic unsigned char *suffix=(unsigned char *)htab;	/* suffix table (uncrunch) */
X
Xstatic int      free_ent;	/* first unused entry */
Xstatic int      firstcmp;	/* true at start of compression */
Xextern unsigned char stack[HSIZE];	/* local push/pop stack */
X
X/*
X * block compression parameters -- after all codes are used up, and
X * compression rate changes, start over.
X */
X
Xstatic int      clear_flg;
X#define CHECK_GAP 2048		/* ratio check interval */
Xstatic long     checkpoint;
Xvoid            upd_tab();
X
X/*
X * the next two codes should not be changed lightly, as they must not lie
X * within the contiguous general code space.
X */
X#define FIRST   257		/* first free entry */
X#define CLEAR   256		/* table clear output code */
X
X/*
X * The cl_block() routine is called at each checkpoint to determine if
X * compression would likely improve by resetting the code table.  The method
X * chosen to determine this is based on empirical observation that, in
X * general, every 2k of input data should compress at least as well as the
X * first 2k of input.
X */
X
Xstatic          void
Xcl_block(t)			/* table clear for block compress */
X	FILE           *t;	/* our output file */
X{
X	checkpoint = in_count + CHECK_GAP;
X
X	if (bytes_ref) {
X		if (bytes_out - bytes_last > bytes_ref) {
X			setmem(htab, HSIZE * sizeof(long), 0xff);
X			free_ent = FIRST;
X			clear_flg = 1;
X			putcode(CLEAR, t);
X			bytes_ref = 0;
X		}
X	} else
X		bytes_ref = bytes_out - bytes_last;
X
X	bytes_last = bytes_out;	/* remember where we were */
X}
X
X/*****************************************************************
X *
X * Output a given code.
X * Inputs:
X *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
X *              that n_bits =< (LONG)wordsize - 1.
X * Outputs:
X *      Outputs code to the file.
X * Assumptions:
X *      Chars are 8 bits long.
X * Algorithm:
X *      Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly).  When the buffer fills up empty it and start over.
X */
X
Xstatic          void
Xputcode(code, t)		/* output a code */
X	int             code;	/* code to output */
X	FILE           *t;	/* where to put it */
X{
X	int             r_off = offset;	/* right offset */
X	int             bits = n_bits;	/* bits to go */
X	char           *bp = buf;	/* buffer pointer */
X	int             n;	/* index */
X
X	register int	ztmp;
X
X	if (code >= 0) {	/* if a real code *//* Get to the first byte. */
X		bp += (r_off >> 3);
X		r_off &= 7;
X
X		/*
X		 * Since code is always >= 8 bits, only need to mask the
X		 * first hunk on the left. 
X		 */
X		ztmp = (code << r_off) & lmask[r_off];
X		*bp = (*bp & rmask[r_off]) | ztmp;
X		bp++;
X		bits -= (8 - r_off);
X		code >>= (8 - r_off);
X
X		/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X		if (bits >= 8) {
X			*bp++ = code;
X			code >>= 8;
X			bits -= 8;
X		}
X		/* Last bits. */
X		if (bits)
X			*bp = code;
X		offset += n_bits;
X
X		if (offset == (n_bits << 3)) {
X			bp = buf;
X			bits = n_bits;
X			bytes_out += bits;
X			do
X				putc_pak(*bp++, t);
X			while (--bits);
X			offset = 0;
X		}
X		/*
X		 * If the next entry is going to be too big for the code
X		 * size, then increase it, if possible. 
X		 */
X		if (free_ent > maxcode || clear_flg > 0) {
X			/*
X			 * Write the whole buffer, because the input side
X			 * won't discover the size increase until after
X			 * it has read it. 
X			 */
X			if (offset > 0) {
X				bp = buf;	/* reset pointer for writing */
X				bytes_out += n = n_bits;
X				while (n--)
X					putc_pak(*bp++, t);
X			}
X			offset = 0;
X
X			if (clear_flg) {	/* reset if clearing */
X				maxcode = MAXCODE(n_bits = INIT_BITS);
X				clear_flg = 0;
X			} else {/* else use more bits */
X				n_bits++;
X				if (n_bits == BITS)
X					maxcode = maxcodemax;
X				else
X					maxcode = MAXCODE(n_bits);
X			}
X		}
X	} else {		/* dump the buffer on EOF */
X		bytes_out += n = (offset + 7) / 8;
X
X		if (offset > 0)
X			while (n--)
X				putc_pak(*bp++, t);
X		offset = 0;
X	}
X}
X
X/*****************************************************************
X *
X * Read one code from the standard input.  If EOF, return -1.
X * Inputs:
X *      cmpin
X * Outputs:
X *      code or -1 is returned.
X */
X
Xstatic          int
Xgetcode(f)			/* get a code */
X	FILE           *f;	/* file to get from */
X{
X	int             code;
X	static int      loffset = 0, size = 0;
X	int             r_off, bits;
X	unsigned char  *bp = (unsigned char *) buf;
X
X	if (clear_flg > 0 || loffset >= size || free_ent > maxcode) {
X		/*
X		 * If the next entry will be too big for the current code
X		 * size, then we must increase the size. This implies
X		 * reading a new buffer full, too. 
X		 */
X		if (free_ent > maxcode) {
X			n_bits++;
X			if (n_bits == BITS)
X				maxcode = maxcodemax;	/* won't get any bigger
X							 * now */
X			else
X				maxcode = MAXCODE(n_bits);
X		}
X		if (clear_flg > 0) {
X			maxcode = MAXCODE(n_bits = INIT_BITS);
X			clear_flg = 0;
X		}
X		for (size = 0; size < n_bits; size++) {
X			if ((code = getc_unp(f)) == EOF)
X				break;
X			else
X				buf[size] = (char) code;
X		}
X		if (size <= 0)
X			return -1;	/* end of file */
X
X		loffset = 0;
X		/* Round size down to integral number of codes */
X		size = (size << 3) - (n_bits - 1);
X	}
X	r_off = loffset;
X	bits = n_bits;
X
X	/*
X	 * Get to the first byte. 
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X
X	/* Get first part (low order bits) */
X	code = (*bp++ >> r_off);
X	bits -= 8 - r_off;
X	r_off = 8 - r_off;	/* now, offset into code word */
X
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if (bits >= 8) {
X		code |= *bp++ << r_off;
X		r_off += 8;
X		bits -= 8;
X	}
X	/* high order bits. */
X	code |= (*bp & rmask[bits]) << r_off;
X	loffset += n_bits;
X
X	return code & MAXCODE(BITS);
X}
X
X/*
X * compress a file
X * 
X * Algorithm:  use open addressing double hashing (no chaining) on the prefix
X * code / next character combination.  We do a variant of Knuth's algorithm D
X * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
X * Here, the modular division first probe is gives way to a faster
X * exclusive-or manipulation.  Also do block compression with an adaptive
X * reset, where the code table is cleared when the compression ratio
X * decreases, but after the table fills.  The variable-length output codes
X * are re-sized at this point, and a special CLEAR code is generated for the
X * decompressor.
X */
X
Xvoid
Xinit_cm(t)			/* initialize for compression */
X	FILE           *t;	/* where compressed file goes */
X{
X	offset = 0;
X	bytes_out = bytes_last = 1;
X	bytes_ref = 0;
X	clear_flg = 0;
X	in_count = 1;
X	checkpoint = CHECK_GAP;
X	maxcode = MAXCODE(n_bits = INIT_BITS);
X	free_ent = FIRST;
X	setmem(htab, HSIZE * sizeof(long), 0xff);
X	n_bits = INIT_BITS;	/* set starting code size */
X
X	putc_pak(BITS, t);	/* note our max code length */
X
X	firstcmp = 1;		/* next byte will be first */
X}
X
Xvoid
Xputc_cm(c, t)			/* compress a character */
X	unsigned char   c;	/* character to compress */
X	FILE           *t;	/* where to put it */
X{
X	static long     fcode;
X	static int      hshift;
X	int             i;
X	int             disp;
X
X	if (firstcmp) {		/* special case for first byte */
X		ent = c;	/* remember first byte */
X
X		hshift = 0;
X		for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L)
X			hshift++;
X		hshift = 8 - hshift;	/* set hash code range bound */
X
X		firstcmp = 0;	/* no longer first */
X		return;
X	}
X	in_count++;
X
X	fcode = (long) (((long) c << BITS) + ent);
X	i = (c << hshift) ^ ent;/* xor hashing */
X
X	if (htab[i] == fcode) {
X		ent = codetab[i];
X		return;
X	} else if (htab[i] < 0)	/* empty slot */
X		goto nomatch;
X	disp = HSIZE - i;	/* secondary hash (after G.Knott) */
X	if (i == 0)
X		disp = 1;
X
Xprobe:
X	if ((i -= disp) < 0)
X		i += HSIZE;
X
X	if (htab[i] == fcode) {
X		ent = codetab[i];
X		return;
X	}
X	if (htab[i] > 0)
X		goto probe;
X
Xnomatch:
X	putcode(ent, t);
X	ent = c;
X	if (free_ent < maxcodemax) {
X		codetab[i] = free_ent++;	/* code -> hashtable */
X		htab[i] = fcode;
X	}
X	if (in_count >= checkpoint)
X		cl_block(t);	/* check for adaptive reset */
X}
X
Xlong
Xpred_cm(t)			/* finish compressing a file */
X	FILE           *t;	/* where to put it */
X{
X	putcode(ent, t);	/* put out the final code */
X	putcode(-1, t);		/* tell output we are done */
X
X	return bytes_out;	/* say how big it got */
X}
X
X/*
X * Decompress a file.  This routine adapts to the codes in the file building
X * the string table on-the-fly; requiring no table to be stored in the
X * compressed file.  The tables used herein are shared with those of the
X * compress() routine.  See the definitions above.
X */
X
Xvoid
Xdecomp(f, t)			/* decompress a file */
X	FILE           *f;	/* file to read codes from */
X	FILE           *t;	/* file to write text to */
X{
X	unsigned char  *stackp;
X	int             finchar;
X	int             code, oldcode, incode;
X
X	if ((code = getc_unp(f)) != BITS)
X		abort("File packed with %d bits, I can only handle %d", code, BITS);
X
X	n_bits = INIT_BITS;	/* set starting code size */
X	clear_flg = 0;
X
X	/*
X	 * As above, initialize the first 256 entries in the table. 
X	 */
X	maxcode = MAXCODE(n_bits = INIT_BITS);
X	setmem(prefix, 256 * sizeof(short), 0);	/* reset decode string table */
X	for (code = 255; code >= 0; code--)
X		suffix[code] = (unsigned char) code;
X
X	free_ent = FIRST;
X
X	finchar = oldcode = getcode(f);
X	if (oldcode == -1)	/* EOF already? */
X		return;		/* Get out of here */
X	putc_ncr((unsigned char) finchar, t);	/* first code must be 8 bits=char */
X	stackp = stack;
X
X	while ((code = getcode(f)) > -1) {
X		if (code == CLEAR) {	/* reset string table */
X			setmem(prefix, 256 * sizeof(short), 0);
X			clear_flg = 1;
X			free_ent = FIRST - 1;
X			if ((code = getcode(f)) == -1)	/* O, untimely death! */
X				break;
X		}
X		incode = code;
X		/*
X		 * Special case for KwKwK string. 
X		 */
X		if (code >= free_ent) {
X			if (code > free_ent) {
X				if (warn) {
X					printf("Corrupted compressed file.\n");
X					printf("Invalid code %d when max is %d.\n",
X						code, free_ent);
X				}
X				nerrs++;
X				return;
X			}
X			*stackp++ = finchar;
X			code = oldcode;
X		}
X		/*
X		 * Generate output characters in reverse order 
X		 */
X		while (code >= 256) {
X			*stackp++ = suffix[code];
X			code = prefix[code];
X		}
X		*stackp++ = finchar = suffix[code];
X
X		/*
X		 * And put them out in forward order 
X		 */
X		do
X			putc_ncr(*--stackp, t);
X		while (stackp > stack);
X
X		/*
X		 * Generate the new entry. 
X		 */
X		if ((code = free_ent) < maxcodemax) {
X			prefix[code] = (unsigned short) oldcode;
X			suffix[code] = finchar;
X			free_ent = code + 1;
X		}
X		/*
X		 * Remember previous code. 
X		 */
X		oldcode = incode;
X	}
X}
X
X
X/*************************************************************************
X * Please note how much trouble it can be to maintain upwards            *
X * compatibility.  All that follows is for the sole purpose of unpacking *
X * files which were packed using an older method.                        *
X *************************************************************************/
X
X
X/*
X * The h() pointer points to the routine to use for calculating a hash value.
X * It is set in the init routines to point to either of oldh() or newh().
X * 
X * oldh() calculates a hash value by taking the middle twelve bits of the square
X * of the key.
X * 
X * newh() works somewhat differently, and was tried because it makes ARC about
X * 23% faster.  This approach was abandoned because dynamic Lempel-Zev
X * (above) works as well, and packs smaller also.  However, inadvertent
X * release of a developmental copy forces us to leave this in.
X */
X
Xstatic unsigned short(*h) ();	/* pointer to hash function */
X
Xstatic unsigned short
Xoldh(pred, foll)		/* old hash function */
X	unsigned short  pred;	/* code for preceeding string */
X	unsigned char   foll;	/* value of following char */
X{
X	long            local;	/* local hash value */
X
X	local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
X	local *= local;		/* square it */
X	return (local >> 6) & 0x0FFF;	/* return the middle 12 bits */
X}
X
Xstatic unsigned short
Xnewh(pred, foll)		/* new hash function */
X	unsigned short  pred;	/* code for preceeding string */
X	unsigned char   foll;	/* value of following char */
X{
X	return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
X}
X
X/*
X * The eolist() function is used to trace down a list of entries with
X * duplicate keys until the last duplicate is found.
X */
X
Xstatic unsigned short
Xeolist(index)			/* find last duplicate */
X	unsigned short  index;
X{
X	int             temp;
X
X	while (temp = string_tab[index].next)	/* while more duplicates */
X		index = temp;
X
X	return index;
X}
X
X/*
X * The hash() routine is used to find a spot in the hash table for a new
X * entry.  It performs a "hash and linear probe" lookup, using h() to
X * calculate the starting hash value and eolist() to perform the linear
X * probe.  This routine DOES NOT detect a table full condition.  That MUST be
X * checked for elsewhere.
X */
X
Xstatic unsigned short
Xhash(pred, foll)		/* find spot in the string table */
X	unsigned short  pred;	/* code for preceeding string */
X	unsigned char   foll;	/* char following string */
X{
X	unsigned short  local, tempnext;	/* scratch storage */
X	struct entry   *ep;	/* allows faster table handling */
X
X	local = (*h) (pred, foll);	/* get initial hash value */
X
X	if (!string_tab[local].used)	/* if that spot is free */
X		return local;	/* then that's all we need */
X
X	else {			/* else a collision has occured */
X		local = eolist(local);	/* move to last duplicate */
X
X		/*
X		 * We must find an empty spot. We start looking 101 places
X		 * down the table from the last duplicate. 
X		 */
X
X		tempnext = (local + 101) & 0x0FFF;
X		ep = &string_tab[tempnext];	/* initialize pointer */
X
X		while (ep->used) {	/* while empty spot not found */
X			if (++tempnext == TABSIZE) {	/* if we are at the end */
X				tempnext = 0;	/* wrap to beginning of table */
X				ep = string_tab;
X			} else
X				++ep;	/* point to next element in table */
X		}
X
X		/*
X		 * local still has the pointer to the last duplicate, while
X		 * tempnext has the pointer to the spot we found.  We use
X		 * this to maintain the chain of pointers to duplicates. 
X		 */
X
X		string_tab[local].next = tempnext;
X
X		return tempnext;
X	}
X}
X
X/*
X * The init_tab() routine is used to initialize our hash table. You realize,
X * of course, that "initialize" is a complete misnomer.
X */
X
Xstatic          void
Xinit_tab()
X{				/* set ground state in hash table */
X	unsigned int    i;	/* table index */
X
X	setmem((char *) string_tab, sizeof(string_tab), 0);
X
X	for (i = 0; i < 256; i++)	/* list all single byte strings */
X		upd_tab(NO_PRED, i);
X
X	inbuf = EMPTY;		/* nothing is in our buffer */
X}
X
X/*
X * The upd_tab routine is used to add a new entry to the string table. As
X * previously stated, no checks are made to ensure that the table has any
X * room.  This must be done elsewhere.
X */
X
Xvoid
Xupd_tab(pred, foll)		/* add an entry to the table */
X	unsigned short  pred;	/* code for preceeding string */
X	unsigned short  foll;	/* character which follows string */
X{
X	struct entry   *ep;	/* pointer to current entry */
X
X	/* calculate offset just once */
X
X	ep = &string_tab[hash(pred, foll)];
X
X	ep->used = TRUE;	/* this spot is now in use */
X	ep->next = 0;		/* no duplicates after this yet */
X	ep->predecessor = pred;	/* note code of preceeding string */
X	ep->follower = foll;	/* note char after string */
X}
X
X/*
X * This algorithm encoded a file into twelve bit strings (three nybbles). The
X * gocode() routine is used to read these strings a byte (or two) at a time.
X */
X
Xstatic          int
Xgocode(fd)			/* read in a twelve bit code */
X	FILE           *fd;	/* file to get code from */
X{
X	unsigned short  localbuf, returnval;
X	int             temp;
X
X	if (inbuf == EMPTY) {	/* if on a code boundary */
X		if ((temp = getc_unp(fd)) == EOF)	/* get start of next
X							 * code */
X			return EOF;	/* pass back end of file status */
X		localbuf = temp & 0xFF;	/* mask down to true byte value */
X		if ((temp = getc_unp(fd)) == EOF)
X			/* get end of code, * start of next */
X			return EOF;	/* this should never happen */
X		inbuf = temp & 0xFF;	/* mask down to true byte value */
X
X		returnval = ((localbuf << 4) & 0xFF0) + ((inbuf >> 4) & 0x00F);
X		inbuf &= 0x000F;/* leave partial code pending */
X	} else {		/* buffer contains first nybble */
X		if ((temp = getc_unp(fd)) == EOF)
X			return EOF;
X		localbuf = temp & 0xFF;
X
X		returnval = localbuf + ((inbuf << 8) & 0xF00);
X		inbuf = EMPTY;	/* note no hanging nybbles */
X	}
X	return returnval;	/* pass back assembled code */
X}
X
Xstatic          void
Xpush(c)				/* push char onto stack */
X	int             c;	/* character to push */
X{
X	stack[sp] = ((char) c);	/* coerce integer into a char */
X
X	if (++sp >= TABSIZE)
X		abort("Stack overflow\n");
X}
X
Xstatic          int
Xpop()
X{				/* pop character from stack */
X	if (sp > 0)
X		return ((int) stack[--sp]);	/* leave ptr at next empty
X						 * slot */
X
X	else
X		return EMPTY;
X}
X
X/***** LEMPEL-ZEV DECOMPRESSION *****/
X
Xstatic int      code_count;	/* needed to detect table full */
Xstatic int      firstc;		/* true only on first character */
X
Xvoid
Xinit_ucr(inew)			/* get set for uncrunching */
X	int             inew;	/* true to use new hash function */
X{
X	if (inew)		/* set proper hash function */
X		h = newh;
X	else
X		h = oldh;
X
X	sp = 0;			/* clear out the stack */
X	init_tab();		/* set up atomic code definitions */
X	code_count = TABSIZE - 256;	/* note space left in table */
X	firstc = 1;		/* true only on first code */
X}
X
Xint
Xgetc_ucr(f)			/* get next uncrunched byte */
X	FILE           *f;	/* file containing crunched data */
X{
X	int             code, newcode;
X	static int      oldcode, finchar;
X	struct entry   *ep;	/* allows faster table handling */
X
X	if (firstc) {		/* first code is always known */
X		firstc = FALSE;	/* but next will not be first */
X		oldcode = gocode(f);
X		return finchar = string_tab[oldcode].follower;
X	}
X	if (!sp) {		/* if stack is empty */
X		if ((code = newcode = gocode(f)) == EOF)
X			return EOF;
X
X		ep = &string_tab[code];	/* initialize pointer */
X
X		if (!ep->used) {/* if code isn't known */
X			code = oldcode;
X			ep = &string_tab[code];	/* re-initialize pointer */
X			push(finchar);
X		}
X		while (ep->predecessor != NO_PRED) {
X			push(ep->follower);	/* decode string backwards */
X			code = ep->predecessor;
X			ep = &string_tab[code];
X		}
X
X		push(finchar = ep->follower);	/* save first character also */
X
X		/*
X		 * The above loop will terminate, one way or another, with
X		 * string_tab[code].follower equal to the first character in
X		 * the string. 
X		 */
X
X		if (code_count) {	/* if room left in string table */
X			upd_tab(oldcode, finchar);
X			--code_count;
X		}
X		oldcode = newcode;
X	}
X	return pop();		/* return saved character */
X}
SHAR_EOF
if test 22114 -ne "`wc -c < 'arclzw.c'`"
then
	echo shar: "error transmitting 'arclzw.c'" '(should have been 22114 characters)'
fi
fi
echo shar: "extracting 'arcmatch.c'" '(3257 characters)'
if test -f 'arcmatch.c'
then
	echo shar: "will not over-write existing file 'arcmatch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcmatch.c'
X/*
X * $Header: arcmatch.c,v 1.6 88/07/31 18:50:18 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCMATCH
X * 
X * Version 2.17, created on 12/17/85 at 20:32:18
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains service routines needed to maintain an
X * archive.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xint	strcmp(), strlen();
Xvoid	abort();
Xchar	*strcpy();
X
Xint
Xmatch(n, t)			/* test name against template */
X	char           *n;	/* name to test */
X	char           *t;	/* template to test against */
X{
X#ifdef LOCAL
X	extern int unix_names;
X#endif /* LOCAL */
X#if	MTS
X	fortran         patbuild(), patmatch(), patfree();
X	static int      patlen = (-1);
X	static int      patwork = 0;
X	static int      patswch = 0;
X	char            patccid[4];
X	static char     patchar[2] = "?";
X	static char     oldtemp[16] = 0;
X	int             namlen, RETCODE;
X
X	if (strcmp(t, oldtemp)) {
X		if (patwork)
X			patfree(&patwork);
X		strcpy(oldtemp, t);
X		patlen = strlen(oldtemp);
X		patbuild(oldtemp, &patlen, &patwork, &patswch, patccid, patchar, _retcode RETCODE);
X		if (RETCODE > 8) {
X			printf("MTS: patbuild returned %d\n", RETCODE);
X			abort("bad wildcard in filename");
X		}
X	}
X	namlen = strlen(n);
X	patmatch(n, &namlen, &patwork, _retcode RETCODE);
X	switch (RETCODE) {
X	case 0:
X		return (1);
X	case 4:
X		return (0);
X	default:
X		abort("wildcard pattern match failed");
X	}
X}
X
X#else
X#if	!UNIX
X	upper(n);
X	upper(t);		/* avoid case problems */
X#endif	/* UNIX */
X#if	GEMDOS
X	char *strstr(), *i;	/* allow "*.*" to mean '*' */
X	if (i=strstr(t,"*.*")) {
X		i++;
X		*i='\0';
X	}
X	return(pnmatch(n, t, 0));
X#else
X	/* first match name part */
X
X#ifdef LOCAL
X	if (!unix_names) {
X		upper(n);
X		upper(t);
X	}
X#endif /* LOCAL */
X
X	while ((*n && *n != '.') || (*t && *t != '.')) {
X		if (*n != *t && *t != '?') {	/* match fail? */
X			if (*t != '*')	/* wildcard fail? */
X				return 0;	/* then no match */
X			else {	/* else jump over wildcard */
X				while (*n && *n != '.')
X					n++;
X				while (*t && *t != '.')
X					t++;
X				break;	/* name part matches wildcard */
X			}
X		} else {	/* match good for this char */
X			n++;	/* advance to next char */
X			t++;
X		}
X	}
X
X	if (*n && *n == '.')
X		n++;		/* skip extension delimiters */
X	if (*t && *t == '.')
X		t++;
X
X	/* now match name part */
X
X	while (*n || *t) {
X		if (*n != *t && *t != '?') {	/* match fail? */
X			if (*t != '*')	/* wildcard fail? */
X				return 0;	/* then no match */
X			else
X				return 1;	/* else good enough */
X		} else {	/* match good for this char */
X			n++;	/* advance to next char */
X			t++;
X		}
X	}
X
X	return 1;		/* match worked */
X#endif	/* GEMDOS */
X}
X#endif
X
Xvoid
Xrempath(nargs, arg)		/* remove paths from filenames */
X	int             nargs;	/* number of names */
X	char           *arg[];	/* pointers to names */
X{
X	char           *i, *rindex();	/* string index, reverse indexer */
X	int             n;	/* index */
X
X	for (n = 0; n < nargs; n++) {	/* for each supplied name */
X		if (!(i = rindex(arg[n], '\\')))	/* search for end of
X							 * path */
X			if (!(i = rindex(arg[n], '/')))
X				i = rindex(arg[n], ':');
X		if (i)		/* if path was found */
X			arg[n] = i + 1;	/* then skip it */
X	}
X}
SHAR_EOF
if test 3257 -ne "`wc -c < 'arcmatch.c'`"
then
	echo shar: "error transmitting 'arcmatch.c'" '(should have been 3257 characters)'
fi
fi
echo shar: "extracting 'arcmisc.c'" '(8946 characters)'
if test -f 'arcmisc.c'
then
	echo shar: "will not over-write existing file 'arcmisc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcmisc.c'
X/*
X * Miscellaneous routines to get ARC running on non-MSDOS systems...
X * $Header: arcmisc.c,v 1.8 88/07/31 18:50:56 hyc Exp $ 
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "arc.h"
X
X#if	MSDOS
X#include <dir.h>
X#include <stat.h>
X#endif
X
X#if	GEMDOS
X#include <osbind.h>
X#include <stat.h>
Xchar           *index(), *rindex();
X
Xvoid 
Xexitpause()
X{
X	while (Cconis())
X		Cnecin();
X	fprintf(stderr, "Press any key to continue: ");
X	fflush(stderr);
X	Cnecin();
X	fprintf(stderr, "\n");
X}
X
Xint
Xchdir(dirname)
X	char           *dirname;
X{
X	char           *i;
X	int             drv;
X
X	i = dirname;
X	if ((i = index(dirname, ':')) != NULL) {
X		drv = i[-1];
X		i++;		/* Move past device spec */
X		if (drv > '\'')
X			drv -= 'a';
X		else
X			drv -= 'A';
X		if (drv >= 0 && drv < 16)
X			Dsetdrv(drv);
X	}
X	if (*i != '\0')
X		return (Dsetpath(i));
X}
X#endif
X
X#if	UNIX
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/stat.h>
X	int	rename(), unlink();
X#endif
X
X#if	0
X#include <dirent.h>
X#define DIRECT dirent
X#else
X#define DIRECT direct
X#endif
X
X#if	BSD
Xchar	*
Xmemset(s, c, n)		/* oops. Thought it was standard BSD, but my Sun */
X	char	*s;	/* fooled me again. -- hyc */
X	int	c, n;
X{
X	register int i;
X	for(i=0;i<n;i++)
X		s[i]=c;
X	return(s);
X}
X#endif
X
Xchar           *strcpy(), *strcat(), *malloc();
Xint             strlen(), strcmp(), match();
X
Xint
Xmove(oldnam, newnam)
X	char           *oldnam, *newnam;
X{
X	FILE           *fopen(), *old, *mnew;
X#if	!MTS
X	struct stat     oldstat;
X#endif
X	char           *strcpy();
X	void		filecopy();
X#if	GEMDOS
X	if (Frename(0, oldnam, newnam))
X#else
X	if (rename(oldnam, newnam))
X#endif
X#if	!MTS
X	{
X		if (stat(oldnam, &oldstat))	/* different partition? */
X			return (-1);
X		old = fopen(oldnam, OPEN_R);
X		if (old == NULL)
X			return (-1);
X		mnew = fopen(newnam, OPEN_W);
X		if (mnew == NULL)
X			return (-1);
X		filecopy(old, mnew, oldstat.st_size);
X		return(unlink(oldnam));
X	}
X	return 0;
X#else
X	return(-1);
X#endif
X}
X
Xstatic void
X_makefn(source, dest)
X	char           *source;
X	char           *dest;
X{
X	int             j;
X#if	MSDOS
X	char	       *setmem();
X#else
X	char	       *memset();
X#endif
X
X	setmem(dest, 17, 0);	/* clear result field */
X	for (j = 0; *source && *source != '.'; ++source)
X		if (j < 8)
X			dest[j++] = *source;
X	for (j = 9; *source; ++source)
X		if (j < 13)
X			dest[j++] = *source;
X}
X/*
X * make a file name using a template 
X */
X
Xchar           *
Xmakefnam(rawfn, template, result)
X	char           *rawfn;	/* the original file name */
X	char           *template;	/* the template data */
X	char           *result;	/* where to place the result */
X{
X	char            et[17], er[17], rawbuf[STRLEN], *i, *rindex();
X
X	*rawbuf = 0;
X	strcpy(rawbuf, rawfn);
X#if	MTS
X	i = rawbuf;
X	if (rawbuf[0] == tmpchr[0]) {
X		i++;
X		strcpy(rawfn, i);
X	} else
X#endif
X	if ((i = rindex(rawbuf, CUTOFF))) {
X		i++;
X		strcpy(rawfn, i);
X	}
X#if	DOS
X	else if ((i = rindex(rawbuf, ':'))) {
X		i++;
X		strcpy(rawfn, i);
X	}
X#endif
X	if (i)
X		*i = 0;
X	else
X		*rawbuf = 0;
X
X	_makefn(template, et);
X	_makefn(rawfn, er);
X	*result = 0;		/* assure no data */
X	strcat(result, rawbuf);
X	strcat(result, er[0] ? er : et);
X	strcat(result, er[9] ? er + 9 : et + 9);
X	return ((char *) &result[0]);
X}
X
X#if	MSDOS || SYSV
X
Xint
Xalphasort(dirptr1, dirptr2)
X	struct DIRECT **dirptr1, **dirptr2;
X{
X	return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
X}
X
X#endif
X
X#ifdef LOCAL
Xvoid
Xlower(string)
X	char           *string;
X{
X	char           *p;
X
X	for (p = string; *p; p++)
X		if (isupper(*p))
X			*p = tolower(*p);
X}
X#endif /* LOCAL */
X
Xvoid
Xupper(string)
X	char           *string;
X{
X	char           *p;
X
X	for (p = string; *p; p++)
X		if (islower(*p))
X			*p = toupper(*p);
X}
X/* VARARGS1 */
Xvoid
Xabort(s, arg1, arg2, arg3)
X	char           *s;
X{
X	fprintf(stderr, "ARC: ");
X	fprintf(stderr, s, arg1, arg2, arg3);
X	fprintf(stderr, "\n");
X#if	UNIX
X	perror("UNIX");
X#endif
X#if	GEMDOS
X	exitpause();
X#endif
X	exit(1);
X}
X
X#if	!MTS
X
Xchar           *
Xgcdir(dirname)
X	char           *dirname;
X
X{
X	char           *getwd();
X#if	GEMDOS
X	int             drv;
X	char           *buf;
X#endif
X	if (dirname == NULL || strlen(dirname) == 0)
X		dirname = (char *) malloc(1024);
X
X#if	!GEMDOS
X	getwd(dirname);
X#else
X	buf = dirname;
X	*buf++ = (drv = Dgetdrv()) + 'A';
X	*buf++ = ':';
X	Dgetpath(buf, 0);
X#endif
X	return (dirname);
X}
X
X#if	UNIX
Xchar           *pattern;	/* global so that fmatch can use it */
X#endif
X
Xchar           *
Xdir(filename)		/* get files, one by one */
X	char           *filename;	/* template, or NULL */
X{
X#if	GEMDOS
X	static int      Nnum = 0;
X	static DMABUFFER dbuf, *saved;
X	char           *name;
X
X	if (Nnum == 0) {	/* first call */
X		saved = (DMABUFFER *) Fgetdta();
X		Fsetdta(&dbuf);
X		if (Fsfirst(filename, 0) == 0) {
X			name = malloc(FNLEN);
X			strcpy(name, dbuf.d_fname);
X			Nnum++;
X			return (name);
X		} else {
X			Fsetdta(saved);
X			return (NULL);
X		}
X	} else {
X		if (Fsnext() == 0) {
X			name = malloc(FNLEN);
X			strcpy(name, dbuf.d_fname);
X			return (name);
X		} else {
X			Nnum = 0;
X			Fsetdta(saved);
X			return (NULL);
X		}
X	}
X}
X#else
X	static struct DIRECT **namelist;
X	static char   **NameList;
X	static char	namecopy[STRLEN], *dirname;
X#if	UNIX
X	int             alphasort();
X	int             scandir();
X#endif				/* UNIX */
X	int             fmatch(), free();
X	static int      Nnum = 0, ii;
X	char		*rindex();
X
X
X	if (Nnum == 0) {	/* first call */
X		strcpy(namecopy,filename);
X		if(pattern=rindex(namecopy,CUTOFF)) {
X			*pattern = 0;
X			pattern++;
X			dirname = namecopy;
X		} else {
X			pattern = filename;
X			dirname = ".";
X		}
X		Nnum = scandir(dirname, &namelist, fmatch, alphasort);
X		NameList = (char **) malloc(Nnum * sizeof(char *));
X		for (ii = 0; ii < Nnum; ii++) {
X			(NameList)[ii] = malloc(strlen(namelist[ii]->d_name) + 1);
X			strcpy((NameList)[ii], namelist[ii]->d_name);
X		}
X		ii = 0;
X	}
X	if (ii >= Nnum) {	/* all out of files */
X		if (Nnum) {	/* there were some files found */
X			for (ii = 0; ii < Nnum; ii++)
X				free(namelist[ii]);
X			free(namelist);
X		}
X		Nnum = 0;
X		return (NULL);
X	} else {
X		return ((NameList)[ii++]);
X	}
X}
X
X/*
X * Filename match - here, * matches everything 
X */
X
Xint
Xfmatch(direntry)
X	struct DIRECT  *direntry;
X{
X	char           *string;
X
X	string = direntry->d_name;
X
X	if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
X		return (1);
X#if	UNIX
X	return(!strcmp(pattern, string));
X#else
X	return (match(string, pattern));
X#endif
X}
X#endif				/* GEMDOS */
X#else
X/* dir code for MTS under Bell Labs C... */
X
Xchar           *
Xdir(filepattern)
X	char           *filepattern;	/* template or NULL */
X{
X	char           *malloc(), *index();
X#if	USECATSCAN
X	fortran void    catscan(), fileinfo();
X
X	struct catname {
X		short           len;
X		char            name[257];
X	}               pattern;
X
X	struct catval {
X		int             maxlen;
X		int             actlen;
X		char            name[257];
X	}               catreturn;
X
X	char           *i;
X	int             j, RETCODE;
X
X	static int      catptr = 0;
X	static int      catflag = 0x200;
X	static int      cattype = 1;
X	static int      patflag = 0;
X
X	catreturn.maxlen = 256;
X
X	if (patflag) {
X		patflag = 0;
X		catptr = 0;
X		return (NULL);
X	}
X	if (filepattern) {
X		strcpy(pattern.name, filepattern);
X		pattern.len = strlen(filepattern);
X		if (!index(filepattern, '?'))
X			patflag = 1;
X	}
X	if (patflag) {
X		fileinfo(&pattern, &cattype, "CINAME  ", &catreturn, _retcode RETCODE);
X		catptr = RETCODE ? 0 : 1;
X	} else
X		catscan(&pattern, &catflag, &cattype, &catreturn, &catptr);
X
X	if (!catptr)
X		return (NULL);
X	else {
X		char           *k;
X
X		k = index(catreturn.name, ' ');
X		if (k)
X			*k = 0;
X		else {
X			j = catreturn.actlen;
X			catreturn.name[j] = 0;
X		}
X		k = catreturn.name;
X		if (catreturn.name[0] == tmpchr[0])
X			k++;
X		else if ((k = index(catreturn.name, sepchr[0])))
X			k++;
X		else
X			k = catreturn.name;
X		j = strlen(k);
X		i = malloc(++j);
X		strcpy(i, k);
X		return (i);
X	}
X#else
X	fortran void    gfinfo();
X	static char     gfname[24];
X	static char     pattern[20];
X	static int      gfdummy[2] = {
X				      0, 0
X	},              gfflags;
X	int             i, RETCODE;
X	char           *j, *k;
X
X	if (filepattern) {
X		strcpy(pattern, filepattern);
X		strcat(pattern, " ");
X		for (i = 20; i < 24; i++)
X			gfname[i] = '\0';
X		if (index(pattern, '?'))
X			gfflags = 0x0C;
X		else
X			gfflags = 0x09;
X	} else if (gfflags == 0x09)
X		return (NULL);
X
X	gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE);
X	if (RETCODE)
X		return (NULL);
X	else {
X		k = index(gfname, ' ');
X		*k = '\0';
X		k = gfname;
X		if (gfname[0] == tmpchr[0])
X			k++;
X		else if ((k = index(gfname, sepchr[0])))
X			k++;
X		else
X			k = gfname;
X		i = strlen(k);
X		j = malloc(++i);
X		strcpy(j, k);
X		return (j);
X	}
X#endif
X}
X
Xint
Xunlink(path)
X	char           *path;	/* name of file to delete */
X{
X	fortran void    destroy();
X	int             RETCODE;
X
X	char            name[258];
X
X	strcpy(name, path);
X	strcat(name, " ");
X	destroy(name, _retcode RETCODE);
X	if (RETCODE)
X		return (-1);
X	else
X		return (0);
X}
X#endif
SHAR_EOF
if test 8946 -ne "`wc -c < 'arcmisc.c'`"
then
	echo shar: "error transmitting 'arcmisc.c'" '(should have been 8946 characters)'
fi
fi
echo shar: "extracting 'arcpack.c'" '(7438 characters)'
if test -f 'arcpack.c'
then
	echo shar: "will not over-write existing file 'arcpack.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcpack.c'
X/*
X * $Header: arcpack.c,v 1.12 88/11/16 17:18:06 hyc Exp $
X */
X
X/*  ARC - Archive utility - ARCPACK
X
X    Version 3.49, created on 04/21/87 at 11:26:51
X
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:	 Thom Henderson
X
X    Description:
X	 This file contains the routines used to compress a file
X	 when placing it in an archive.
X
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X#if	MTS
X#include <ctype.h>
X#endif
X
Xvoid	setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
Xvoid	filecopy(), abort(), putc_tst(), init_sq(), scan_sq();
Xint	getch(), addcrc();
X
X/* stuff for non-repeat packing */
X
X#define DLE 0x90		/* repeat sequence marker */
X
Xstatic unsigned char state;	/* current packing state */
X
X/* non-repeat packing states */
X
X#define NOHIST  0		/* don't consider previous input */
X#define SENTCHAR 1		/* lastchar set, no lookahead yet */
X#define SENDNEWC 2		/* run over, send new char next */
X#define SENDCNT 3		/* newchar set, send count next */
X
X/* packing results */
X
Xstatic long     stdlen;		/* length for standard packing */
Xstatic short    crcval;		/* CRC check value */
X
Xvoid
Xpack(f, t, hdr)			/* pack file into an archive */
X	FILE           *f, *t;	/* source, destination */
X	struct heads   *hdr;	/* pointer to header data */
X{
X	int             c;	/* one character of stream */
X	long            ncrlen;	/* length after packing */
X	long		huflen;	/* length after squeezing */
X	long            lzwlen;	/* length after crunching */
X	long		pred_sq(), file_sq();	/* stuff for squeezing */
X	long            pred_cm(), sqpred_cm();	/* dynamic crunching cleanup */
X	long            tloc, ftell();	/* start of output */
X	int		getch();
X	int             getc_ncr();
X	void            putc_pak();
X
X	/* first pass - see which method is best */
X
X	tloc = ftell(t);	/* note start of output */
X
X	if (!nocomp) {		/* if storage kludge not active */
X		if (note) {
X			printf(" analyzing, ");
X			fflush(stdout);
X		}
X		state = NOHIST;	/* initialize ncr packing */
X		stdlen = ncrlen = 0;	/* reset size counters */
X		crcval = 0;	/* initialize CRC check value */
X		setcode();	/* initialize encryption */
X		init_sq();	/* initialize for squeeze scan */
X
X		if (dosquash) {
X			sqinit_cm();
X			while ((c = getch(f)) != EOF) {	/* for each byte of file */
X				ncrlen++;	/* one more packed byte */
X				scan_sq(c);	/* see what squeezing can do */
X				sqputc_cm(c, t);	/* see what squashing
X							 * can do */
X			}
X			lzwlen = sqpred_cm(t);
X		} else {
X			init_cm(t);	/* initialize for crunching */
X	
X			while ((c = getc_ncr(f)) != EOF) {	/* for each byte of file */
X				ncrlen++;	/* one more packed byte */
X				scan_sq(c);	/* see what squeezing can do */
X				putc_cm(c, t);	/* see what crunching can do */
X			}
X			lzwlen = pred_cm(t);	/* finish up after crunching */
X		}
X		huflen = pred_sq();	/* finish up after squeezing */
X	} else {		/* else kludge the method */
X		stdlen = 0;	/* make standard look best */
X		ncrlen = huflen = lzwlen = 1;
X	}
X
X	/* standard set-ups common to all methods */
X
X	fseek(f, 0L, 0);	/* rewind input */
X	hdr->crc = crcval;	/* note CRC check value */
X	hdr->length = stdlen;	/* set actual file length */
X	state = NOHIST;		/* reinitialize ncr packing */
X	setcode();		/* reinitialize encryption */
X
X	/* choose and use the shortest method */
X
X	if (kludge && note)
X		printf("\n\tS:%ld  P:%ld  S:%ld  C:%ld,\t ",
X			stdlen, ncrlen, huflen, lzwlen);
X
X	if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
X		if (note) {
X			printf("storing, ");	/* store without compression */
X			fflush(stdout);
X		}
X		hdrver = 2;	/* note packing method */
X		fseek(t, tloc, 0);	/* reset output for new method */
X		stdlen = crcval = 0;	/* recalc these for kludge */
X		while ((c = getch(f)) != EOF)	/* store it straight */
X			putc_pak(c, t);
X		hdr->crc = crcval;
X		hdr->length = hdr->size = stdlen;
X	} else if (ncrlen < lzwlen && ncrlen < huflen) {
X		if (note) {
X			printf("packing, ");	/* pack with repeat */
X			fflush(stdout);		/* suppression */
X		}
X		hdrver = 3;	/* note packing method */
X		hdr->size = ncrlen;	/* set data length */
X		fseek(t, tloc, 0);	/* reset output for new method */
X		while ((c = getc_ncr(f)) != EOF)
X			putc_pak(c, t);
X	} else if (huflen < lzwlen) {
X		if (note) {
X			printf("squeezing, ");
X			fflush(stdout);
X		}
X		hdrver = 4;	/* note packing method */
X		fseek(t, tloc, 0);	/* reset output for new method */
X		hdr->size = file_sq(f, t);	/* note final size */
X	} else {
X		if (note)
X			printf(dosquash ? "squashed, " : "crunched, ");
X		hdrver = dosquash ? 9 : 8;
X		hdr->size = lzwlen;	/* size should not change */
X	}
X
X	/* standard cleanups common to all methods */
X
X	if (note)
X		printf("done. (%ld%%)\n",hdr->length == 0 ?
X				0L : 100L - (100L*hdr->size)/hdr->length);
X}
X
X/*
X * Non-repeat compression - text is passed through normally, except that a
X * run of more than two is encoded as:
X * 
X * <char> <DLE> <count>
X * 
X * Special case: a count of zero indicates that the DLE is really a DLE, not a
X * repeat marker.
X */
X
Xint
Xgetc_ncr(f)			/* get bytes with collapsed runs */
X	FILE           *f;	/* file to get from */
X{
X	static int      lastc;	/* value returned on last call */
X	static int      repcnt;	/* repetition counter */
X	static int      c;	/* latest value seen */
X
X	switch (state) {	/* depends on our state */
X	case NOHIST:		/* no relevant history */
X		state = SENTCHAR;
X		return lastc = getch(f);	/* remember the value next
X						 * time */
X
X	case SENTCHAR:		/* char was sent. look ahead */
X		switch (lastc) {/* action depends on char */
X		case DLE:	/* if we sent a real DLE */
X			state = NOHIST;	/* then start over again */
X			return 0;	/* but note that the DLE was real */
X
X		case EOF:	/* EOF is always a special case */
X			return EOF;
X
X		default:	/* else test for a repeat */
X			for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
X			/* find end of run */
X
X			switch (repcnt) {	/* action depends on run size */
X			case 1:/* not a repeat */
X				return lastc = c;	/* but remember value
X							 * next time */
X
X			case 2:/* a repeat, but too short */
X				state = SENDNEWC;	/* send the second one
X							 * next time */
X				return lastc;
X
X			default:	/* a run - compress it */
X				state = SENDCNT;	/* send repeat count
X							 * next time */
X				return DLE;	/* send repeat marker this
X						 * time */
X			}
X		}
X
X	case SENDNEWC:		/* send second char of short run */
X		state = SENTCHAR;
X		return lastc = c;
X
X	case SENDCNT:		/* sent DLE, now send count */
X		state = SENDNEWC;
X		return repcnt;
X
X	default:
X		abort("Bug - bad ncr state\n");
X	}
X	return 0;
X}
X
Xint
Xgetch(f)			/* special get char for packing */
X	FILE           *f;	/* file to get from */
X{
X	int		c;	/* a char from the file */
X#if	!DOS
X	static int      cr = 0;	/* add \r before \n ? */
X
X	if (cr) {
X		c = '\n';
X#if	MTS
X		c = toascii(c);
X#endif
X		crcval = addcrc(crcval, c);
X		stdlen++;
X		cr = 0;
X		return (c);
X	}
X#endif
X
X	if ((c = fgetc(f)) != EOF) {	/* if not the end of file */
X#if	!DOS
X		if (!image && (c == '\n')) {
X			c = '\r';
X			cr = 1;
X		}
X#endif
X#if	MTS
X		if (!image)
X			c = toascii(c);
X#endif
X		crcval = addcrc(crcval, c);	/* then update CRC check
X						 * value */
X		stdlen++;	/* and bump length counter */
X	}
X	return c;
X}
X
Xvoid
Xputc_pak(c, f)			/* put a packed byte into archive */
X	char            c;	/* byte to put */
X	FILE           *f;	/* archive to put it in */
X{
X	unsigned char		code();
X	putc_tst(code(c), f);	/* put encoded byte, with checks */
X}
SHAR_EOF
if test 7438 -ne "`wc -c < 'arcpack.c'`"
then
	echo shar: "error transmitting 'arcpack.c'" '(should have been 7438 characters)'
fi
fi
echo shar: "extracting 'arcrun.c'" '(3859 characters)'
if test -f 'arcrun.c'
then
	echo shar: "will not over-write existing file 'arcrun.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcrun.c'
X/*
X * $Header: arcrun.c,v 1.4 88/07/31 18:52:50 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCRUN
X * 
X * Version 1.20, created on 03/24/86 at 19:34:31
X * 
X * (C) COPYRIGHT 1985,85 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to "run" a file which is
X * stored in an archive.  At present, all we really do is (a) extract a
X * temporary file, (b) give its name as a system command, and then (c) delete
X * the file.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	rempath(), openarc(), closearc(), abort();
Xint	readhdr(), match(), unpack();
Xstatic	void	runfile();
Xchar	*strcat();
X
Xvoid
Xrunarc(num, arg)		/* run file from archive */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X{
X	struct heads    hdr;	/* file header */
X	char           *makefnam();	/* filename fixer */
X	char            buf[STRLEN];	/* filename buffer */
X	FILE           *fopen();/* file opener */
X	char	       *dummy[2];
X
X	dummy[0]="dummy";
X	dummy[1]=NULL;
X	rempath(num, arg);	/* strip off paths */
X
X	openarc(0);		/* open archive for reading */
X
X	if (num) {		/* if files were named */
X		while (readhdr(&hdr, arc)) {	/* while more files to check */
X			if (match(hdr.name, makefnam(arg[0], ".*", buf)))
X				runfile(&hdr, num, arg);
X			else
X				fseek(arc, hdr.size, 1);
X		}
X	} else
X		while (readhdr(&hdr, arc))	/* else run all files */
X			runfile(&hdr, 1, dummy);
X
X	closearc(0);		/* close archive after changes */
X}
X
Xstatic  void
Xrunfile(hdr, num, arg)		/* run a file */
X	struct heads   *hdr;	/* pointer to header data */
X	int             num;	/* number of arguments */
X	char           *arg[];	/* pointers to arguments */
X{
X	FILE           *tmp, *fopen();	/* temporary file */
X	char           *dir, *gcdir();	/* directory stuff */
X	char            buf[STRLEN], *makefnam();	/* temp file name, fixer */
X#if	DOS
X	char		nbuf[64], *i, *rindex();
X#endif
X#if	!GEMDOS
X	int             n;	/* index */
X	char            sys[STRLEN];	/* invocation command buffer */
X#endif
X
X	/* makefnam("$ARCTEMP",hdr->name,buf); */
X#if	UNIX
X	sprintf(buf, "%s.RUN", arctemp);
X	strcpy(sys, buf);
X#else
X	strcpy(nbuf, arctemp);
X	makefnam(nbuf,hdr->name,buf);
X	i = rindex(buf,'.');
X#endif
X#if	MSDOS
X	if (!strcmp(i, ".BAS")) {
X		strcpy(sys, "BASICA ");
X		strcat(sys, buf);
X	}
X	else if (!strcmp(i, ".BAT")
X		 || !strcmp(i, ".COM")
X		 || !strcmp(i, ".EXE"))
X		strcpy(sys, buf);
X
X	else {
X		if (warn) {
X			printf("File %s is not a .BAS, .BAT, .COM, or .EXE\n",
X			       hdr->name);
X			nerrs++;
X		}
X		fseek(arc, hdr->size, 1);	/* skip this file */
X		return;
X	}
X#endif
X#if	GEMDOS
X      if (strcmp(i, ".PRG")
X              && strcmp(i, ".TTP")
X              && strcmp(i, ".TOS"))
X      {
X              if (warn) {
X                      printf("File %s is not a .PRG, .TOS, or .TTP\n",
X                              hdr->name);
X                      nerrs++;
X              }
X              fseek(arc, hdr->size, 1);       /* skip this file */
X              return;
X      }
X#endif
X
X	if (warn)
X		if (tmp = fopen(buf, "r"))
X			abort("Temporary file %s already exists", buf);
X	if (!(tmp = fopen(buf, OPEN_W)))
X		abort("Unable to create temporary file %s", buf);
X
X	if (note)
X		printf("Invoking file: %s\n", hdr->name);
X
X	dir = gcdir("");	/* see where we are */
X	unpack(arc, tmp, hdr);	/* unpack the entry */
X	fclose(tmp);		/* release the file */
X	chmod(buf, "700");	/* make it executable */
X#if	GEMDOS
X	execve(buf, arg, NULL);
X#else
X	for (n = 1; n < num; n++) {	/* add command line arguments */
X		strcat(sys, " ");
X		strcat(sys, arg[n]);
X	}
X	system(buf);		/* try to invoke it */
X#endif
X	chdir(dir);
X	free(dir);		/* return to whence we started */
X	if (unlink(buf) && warn) {
X		printf("Cannot unsave temporary file %s\n", buf);
X		nerrs++;
X	}
X}
SHAR_EOF
if test 3859 -ne "`wc -c < 'arcrun.c'`"
then
	echo shar: "error transmitting 'arcrun.c'" '(should have been 3859 characters)'
fi
fi
echo shar: "extracting 'arcs.h'" '(1645 characters)'
if test -f 'arcs.h'
then
	echo shar: "will not over-write existing file 'arcs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'arcs.h'
X/*
X * $Header: arcs.h,v 1.2 88/04/17 18:53:19 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - Archive file header format
X * 
X * Version 2.12, created on 12/17/85 at 14:40:26
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file defines the format of an archive file header,
X * excluding the archive marker and the header version number.
X * 
X * Each entry in an archive begins with a one byte archive marker, which is set
X * to 26.  The marker is followed by a one byte header type code, from zero
X * to 7.
X * 
X * If the header type code is zero, then it is an end marker, and no more data
X * should be read from the archive.
X * 
X * If the header type code is in the range 2 to 7, then it is followed by a
X * standard archive header, which is defined below.
X * 
X * If the header type code is one, then it is followed by an older format
X * archive header.  The older format header does not contain the true length.
X * A header should be read for a length of sizeof(struct heads)-sizeof(long).
X * Then set length equal to size and change the header version to 2.
X * 
X * Programming note: The crc value given in the header is based on the unpacked
X * data.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X
Xstruct heads {			/* archive entry header format */
X    char    name[FNLEN];		/* file name */
X            long size;		/* size of file, in bytes */
X    unsigned    short date;	/* creation date */
X    unsigned    short time;	/* creation time */
X                short crc;	/* cyclic redundancy check */
X                long length;	/* true file length */
X};
SHAR_EOF
if test 1645 -ne "`wc -c < 'arcs.h'`"
then
	echo shar: "error transmitting 'arcs.h'" '(should have been 1645 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (01/03/89)

This is part 6 (of 6) to the Arc v5.21 distribution package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	marc.c
#	memset.c
#	rename.c
#	scandir.3
#	scandir.c
#	tmclock.c
#	utimes.c
# This archive created: Sun Jan  1 12:48:37 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'marc.c'" '(9440 characters)'
if test -f 'marc.c'
then
	echo shar: "will not over-write existing file 'marc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'marc.c'
X/*
X * $Header: marc.c,v 1.5 88/08/01 14:19:19 hyc Exp $
X */
X
X/*  MARC - Archive merge utility
X
X    Version 5.21, created on 04/22/87 at 15:05:10
X
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:	 Thom Henderson
X
X    Description:
X	 This program is used to "merge" archives.  That is, to move
X	 files from one archive to another with no data conversion.
X	 Please refer to the ARC source for a description of archives
X	 and archive formats.
X
X    Instructions:
X	 Run this program with no arguments for complete instructions.
X
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X
X#if	UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
XFILE *src;			       /* source archive */
Xchar srcname[STRLEN];		       /* source archive name */
X
Xstatic char **lst;		       /* files list */
Xstatic int lnum;		       /* length of files list */
X
X#ifdef LOCAL
Xint unix_names = 0;
X#endif /* LOCAL */
X
X
Xmain(nargs,arg)			       /* system entry point */
Xint nargs;			       /* number of arguments */
Xchar *arg[];			       /* pointers to arguments */
X{
X    char *makefnam();		       /* filename fixup routine */
X    char *calloc();		       /* memory manager */
X    char *envfind();
X#if	!MTS
X    char *arctemp2, *mktemp();		/* temp file stuff */
X#endif
X#if	GEMDOS
X    void exitpause();
X#endif
X    int n;			       /* index */
X#if	UNIX
X    struct	stat	sbuf;
X#endif
X
X
X    if(nargs<3)
X    {	 printf("MARC - Archive merger, Version 5.21, created on 04/22/87 at 15:05:10\n");
X/*	 printf("(C) COPYRIGHT 1985,86,87 by System Enhancement Associates;");
X	 printf(" ALL RIGHTS RESERVED\n\n");
X	 printf("Please refer all inquiries to:\n\n");
X	 printf("	System Enhancement Associates\n");
X	 printf("	21 New Street, Wayne NJ 07470\n\n");
X	 printf("You may copy and distribute this program freely,");
X	 printf(" provided that:\n");
X	 printf("    1)	  No fee is charged for such copying and");
X	 printf(" distribution, and\n");
X	 printf("    2)	  It is distributed ONLY in its original,");
X	 printf(" unmodified state.\n\n");
X	 printf("If you like this program, and find it of use, then your");
X	 printf(" contribution will\n");
X	 printf("be appreciated.  You may not use this product in a");
X	 printf(" commercial environment\n");
X	 printf("or a governmental organization without paying a license");
X	 printf(" fee of $35.  Site\n");
X	 printf("licenses and commercial distribution licenses are");
X	 printf(" available.  A program\n");
X	 printf("disk and printed documentation are available for $50.\n");
X	 printf("\nIf you fail to abide by the terms of this license, ");
X	 printf(" then your conscience\n");
X	 printf("will haunt you for the rest of your life.\n\n");
X*/
X	 printf("Usage: MARC <tgtarc> <srcarc> [<filename> . . .]\n");
X	 printf("Where: <tgtarc> is the archive to add files to,\n");
X	 printf("	<srcarc> is the archive to get files from, and\n");
X	 printf("	<filename> is zero or more file names to get.\n");
X	 printf("\nAdapted from MSDOS by Howard Chu\n");
X#if	GEMDOS
X	 exitpause();
X#endif
X	 return 1;
X    }
X
X	/* see where temp files go */
X#if	!MTS
X	arctemp = calloc(1, STRLEN);
X	if (!(arctemp2 = envfind("ARCTEMP")))
X		arctemp2 = envfind("TMPDIR");
X	if (arctemp2) {
X		strcpy(arctemp, arctemp2);
X		n = strlen(arctemp);
X		if (arctemp[n - 1] != CUTOFF)
X			arctemp[n] = CUTOFF;
X	}
X#if	UNIX
X	else	strcpy(arctemp, "/tmp/");
X#endif
X#if	!MSDOS
X	{
X		static char tempname[] = "AXXXXXX";
X		strcat(arctemp, mktemp(tempname));
X	}
X#else
X	strcat(arctemp, "$ARCTEMP");
X#endif
X#else
X	guinfo("SHFSEP	", gotinf);
X	sepchr[0] = gotinf[0];
X	guinfo("SCRFCHAR", gotinf);
X	tmpchr[0] = gotinf[0];
X	arctemp = "-$$$";
X	arctemp[0] = tmpchr[0];
X#endif
X
X#if	UNIX
X	if (!stat(arg[1],&sbuf))
X		strcpy(arcname,arg[1]);
X	else
X		makefnam(arg[1],".arc",arcname);
X	if (!stat(arg[2],&sbuf))
X		strcpy(srcname,arg[2]);
X	else
X		makefnam(arg[2],".arc",srcname);
X#else
X    makefnam(arg[1],".ARC",arcname);   /* fix up archive names */
X    makefnam(arg[2],".ARC",srcname);
X/*	makefnam(".$$$",arcname,newname);*/
X	sprintf(newname,"%s.arc",arctemp);
X#endif
X
X    arc = fopen(arcname,OPEN_R);	       /* open the archives */
X    if(!(src=fopen(srcname,OPEN_R)))
X	 abort("Cannot read source archive %s",srcname);
X    if(!(new=fopen(newname,OPEN_W)))
X	 abort("Cannot create new archive %s",newname);
X
X    if(!arc)
X	 printf("Creating new archive %s\n",arcname);
X
X    /* get the files list set up */
X
X    lnum = nargs-3;		       /* initial length of list */
X    if(lnum<1)			       /* phoney for default case */
X    {	 lnum = 1;
X	 lst = (char **) calloc(1,sizeof(char *));
X	 lst[0] = "*.*";
X    }
X    else			       /* else use filenames given */
X    {	 lst = (char **) calloc(lnum,sizeof(char *));
X	 for(n=3; n<nargs; n++)
X	      lst[n-3] = arg[n];
X
X	 for(n=0; n<lnum; )	       /* expand indirect references */
X	 {    if(*lst[n] == '@')
X		   expandlst(n);
X	      else n++;
X	 }
X    }
X
X    merge(lnum,lst);		       /* merge desired files */
X
X    if(arc) fclose(arc);	       /* close the archives */
X    fclose(src);
X    fclose(new);
X
X    if(arc)			       /* make the switch */
X	 if(unlink(arcname))
X	      abort("Unable to delete old copy of %s",arcname);
X    if(move(newname,arcname))
X	 abort("Unable to rename %s to %s",newname,arcname);
X
X    setstamp(arcname,arcdate,arctime);     /* new arc matches newest file */
X
X#if	GEMDOS
X    exitpause();
X#endif
X    return nerrs;
X}
X
Xmerge(nargs,arg)		       /* merge two archives */
Xint nargs;			       /* number of filename templates */
Xchar *arg[];			       /* pointers to names */
X{
X    struct heads srch;		       /* source archive header */
X    struct heads arch;		       /* target archive header */
X    int gotsrc, gotarc;		       /* archive entry versions (0=end) */
X    int copy;			       /* true to copy file from source */
X    int n;			       /* index */
X
X    gotsrc = gethdr(src,&srch);	       /* get first source file */
X    gotarc = gethdr(arc,&arch);	       /* get first target file */
X
X    while(gotsrc || gotarc)	       /* while more to merge */
X    {	 if(strcmp(srch.name,arch.name)>0)
X	 {    copyfile(arc,&arch,gotarc);
X	      gotarc = gethdr(arc,&arch);
X	 }
X
X	 else if(strcmp(srch.name,arch.name)<0)
X	 {    copy = 0;
X	      for(n=0; n<nargs; n++)
X	      {	   if(match(srch.name,arg[n]))
X		   {	copy = 1;
X			break;
X		   }
X	      }
X	      if(copy)		       /* select source or target */
X	      {	   printf("Adding file:	  %s\n",srch.name);
X		   copyfile(src,&srch,gotsrc);
X	      }
X	      else fseek(src,srch.size,1);
X	      gotsrc = gethdr(src,&srch);
X	 }
X
X	 else			       /* duplicate names */
X	 {    copy = 0;
X	      {	   if((srch.date>arch.date)
X		   || (srch.date==arch.date && srch.time>arch.time))
X		   {	for(n=0; n<nargs; n++)
X			{    if(match(srch.name,arg[n]))
X			     {	  copy = 1;
X				  break;
X			     }
X			}
X		   }
X	      }
X	      if(copy)		       /* select source or target */
X	      {	   printf("Updating file: %s\n",srch.name);
X		   copyfile(src,&srch,gotsrc);
X		   gotsrc = gethdr(src,&srch);
X		   if(gotarc)
X		   {	fseek(arc,arch.size,1);
X			gotarc = gethdr(arc,&arch);
X		   }
X	      }
X	      else
X	      {	   copyfile(arc,&arch,gotarc);
X		   gotarc = gethdr(arc,&arch);
X		   if(gotsrc)
X		   {	fseek(src,srch.size,1);
X			gotsrc = gethdr(src,&srch);
X		   }
X	      }
X	 }
X    }
X
X    hdrver = 0;			       /* end of archive marker */
X    writehdr(&arch,new);	       /* mark the end of the archive */
X}
X
Xint gethdr(f,hdr)		       /* special read header for merge */
XFILE *f;			       /* file to read from */
Xstruct heads *hdr;		       /* storage for header */
X{
X    char *i = hdr->name;	       /* string index */
X    int n;			       /* index */
X
X    for(n=0; n<FNLEN; n++)	       /* fill name field */
X	 *i++ = 0176;		       /* impossible high value */
X    *--i = '\0';		       /* properly end the name */
X
X    hdrver = 0;			       /* reset header version */
X    if(readhdr(hdr,f))		       /* use normal reading logic */
X	 return hdrver;		       /* return the version */
X    else return 0;		       /* or fake end of archive */
X}
X
Xcopyfile(f,hdr,ver)		       /* copy a file from an archive */
XFILE *f;			       /* archive to copy from */
Xstruct heads *hdr;		       /* header data for file */
Xint ver;			       /* header version */
X{
X    hdrver = ver;		       /* set header version */
X    writehdr(hdr,new);		       /* write out the header */
X    filecopy(f,new,hdr->size);	       /* copy over the data */
X}
X
Xstatic expandlst(n)		       /* expand an indirect reference */
Xint n;				       /* number of entry to expand */
X{
X    FILE *lf, *fopen();		       /* list file, opener */
X    char *malloc(), *realloc();	       /* memory managers */
X    char buf[100];		       /* input buffer */
X    int x;			       /* index */
X    char *p = lst[n]+1;		       /* filename pointer */
X
X    if(*p)			       /* use name if one was given */
X    {	 makefnam(p,".CMD",buf);
X	 upper(buf);
X	 if(!(lf=fopen(buf,"r")))
X	      abort("Cannot read list of files in %s",buf);
X    }
X    else lf = stdin;		       /* else use standard input */
X
X    for(x=n+1; x<lnum; x++)	       /* drop reference from the list */
X	 lst[x-1] = lst[x];
X    lnum--;
X
X    while(fscanf(lf,"%99s",buf)>0)     /* read in the list */
X    {	 if(!(lst=(char **) realloc(lst,(lnum+1)*sizeof(char *))))
X	      abort("too many file references");
X
X	 lst[lnum] = malloc(strlen(buf)+1);
X	 strcpy(lst[lnum],buf);	       /* save the name */
X	 lnum++;
X    }
X
X    if(lf!=stdin)		       /* avoid closing standard input */
X	 fclose(lf);
X}
SHAR_EOF
if test 9440 -ne "`wc -c < 'marc.c'`"
then
	echo shar: "error transmitting 'marc.c'" '(should have been 9440 characters)'
fi
fi
echo shar: "extracting 'memset.c'" '(144 characters)'
if test -f 'memset.c'
then
	echo shar: "will not over-write existing file 'memset.c'"
else
sed 's/^X//' << \SHAR_EOF > 'memset.c'
X/* missing function
X */
Xchar *
Xmemset(d, n, c)
X	char *d;
X	int n;
X	char c;
X{
X	char *s = d;
X
X	while (n > 0) {
X		--n;
X		*d++ = c;
X	}
X	return(s);
X}
SHAR_EOF
if test 144 -ne "`wc -c < 'memset.c'`"
then
	echo shar: "error transmitting 'memset.c'" '(should have been 144 characters)'
fi
fi
echo shar: "extracting 'rename.c'" '(280 characters)'
if test -f 'rename.c'
then
	echo shar: "will not over-write existing file 'rename.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rename.c'
X/*
X * substitute for BSD/SVR3 rename() system call, from
X * Janet Walz, walz@mimsy.umd.edu & Rich Salz, rsalz@pineapple.bbn.com
X */
X
Xint rename(oldname,newname)
Xchar *oldname,*newname;
X{
X	(void)unlink(newname);
X	if(link(oldname,newname))
X		return(-1);
X	return(unlink(oldname));
X}
SHAR_EOF
if test 280 -ne "`wc -c < 'rename.c'`"
then
	echo shar: "error transmitting 'rename.c'" '(should have been 280 characters)'
fi
fi
echo shar: "extracting 'scandir.3'" '(2353 characters)'
if test -f 'scandir.3'
then
	echo shar: "will not over-write existing file 'scandir.3'"
else
sed 's/^X//' << \SHAR_EOF > 'scandir.3'
X.TH SCANDIR 3
X.\" $Header: scandir.3,v 1.1 87/12/29 21:35:54 rsalz Exp $
X.SH NAME
Xscandir, alphasort \- scan a directory
X.SH SYNOPSIS
X.nf
X.ft B
X#include <sys/types.h>
X#include <sys/dirent.h>
X
Xint
Xscandir(name, list, selector, sorter)
X.in +4n
Xchar *name;
Xstruct dirent ***list;
Xint (*selector)();
Xint (*sorter)();
X.in -4n
X
Xint
Xalphasort(d1, d2)
X.in +4n
Xstruct dirent **d1;
Xstruct dirent **d2;
X.in -4n
X.ft R
X.fi
X.SH DESCRIPTION
X.I Scandir
Xreads the directory
X.I name
Xand builds a NULL\-terminated array of pointers to the entries found
Xin that directory.
XThis array is put into the location pointed to by the
X.I list
Xparameter.
X.PP
XIf the
X.I selector
Xparameter is non\-NULL, it is taken to be a pointer to a function called
Xwith each entry, to determine whether or not it should be included in
Xthe returned list.
XIf the parameter is NULL, all entries are included.
X.PP
XAs an added feature, the entries can be sorted (with
X.IR qsort (3))
Xbefore the list is returned.
XIf the
X.I sorter
Xparameter is non\-NULL, it is passed to qsort to use as the comparison
Xfunction.
XThe
X.I alphasort
Xroutine is provided to sort the array alphabetically.
X.PP
XThe array pointed to by
X.I list
Xand the items it points to are all space obtained through
X.IR malloc (3),
Xand their storage can be reclaimed as shown in the example below.
X.SH "EXAMPLE"
XHere is a small
X.IR ls (1)\-like
Xprogram:
X.ne 50
X.RS
X.nf
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
Xextern int alphasort();
X
Xstatic int
Xfilesonly(e)
X	struct dirent *e;
X{
X	struct stat sb;
X
X	return(stat(e->d_name, &sb) >= 0 && (sb.st_mode & S_IFMT) == S_IFREG);
X}
X
Xmain(ac, av)
X	int ac;
X	char *av[];
X{
X	register int i;
X	register int j;
X	struct dirent **list;
X
X	if (ac != 2) {
X		fprintf(stderr, "usage: %s dirname\n", av[0]);
X		exit(1);
X	}
X	if (chdir(av[1]) < 0) {
X		perror(av[1]);
X		exit(1);
X	}
X	if ((i = scandir(".", &list, filesonly, alphasort)) < 0) {
X		perror("Error reading directory");
X		exit(1);
X	}
X	for (j = 0; j < i; j++)
X		printf("%s\n", list[j]->d_name);
X	for (j = 0; j < i; j++)
X		free((char *)list[j]);
X	free((char *)list);
X	exit(0);
X}
X.fi
X.RE
X.SH "SEE ALSO"
Xdirectory(3), qsort(3)
X.SH DIAGNOSTICS
XReturns the number of entries in the ``list,'' or \-1 if the directory
Xcould not be opened or a memory allocation failed.
X.SH BUGS
XThe routine can be slightly wasteful of space.
SHAR_EOF
if test 2353 -ne "`wc -c < 'scandir.3'`"
then
	echo shar: "error transmitting 'scandir.3'" '(should have been 2353 characters)'
fi
fi
echo shar: "extracting 'scandir.c'" '(2409 characters)'
if test -f 'scandir.c'
then
	echo shar: "will not over-write existing file 'scandir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'scandir.c'
X/*
X**  SCANDIR
X**  Scan a directory, collecting all (selected) items into a an array.
X*/
X
X#ifdef	RCSID
Xstatic char RCS[] = "$Header: scandir.c,v 1.1 87/12/29 21:35:56 rsalz Exp $";
X#endif	/* RCSID */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X
X#ifdef MAXNAMLEN
X
X#include <dirent.h>
X#define	namedir(entry) (entry->d_name)
X#define	MAXNAME 256
X
X#else
X
X#define dirent 	direct
X#define	DIR	FILE
X#define	MAXNAME (DIRSIZ+2)
X#define	opendir(path) fopen (path, "r")
X#define closedir(dirp) fclose (dirp)
Xstruct direct *
Xreaddir (dirp)
XDIR 	*dirp;
X	{
X	static	struct	direct	entry;
X	if (dirp == NULL) return (NULL);
X	for (;;)
X		{
X		if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
X		if (entry.d_ino) return (&entry);
X		}
X	}
X#endif 
X
X/* Initial guess at directory size. */
X#define INITIAL_SIZE	20
X
X/* A convenient shorthand. */
Xtypedef struct dirent	 ENTRY;
X	    
X#define MDIRSIZ(d) (sizeof(struct dirent) + strlen(d->d_name) + 1) 
X
X/* Linked in later. */
Xextern char		*malloc();
Xextern char		*realloc();
Xextern char		*strcpy();
X
X
Xint
Xscandir(Name, List, Selector, Sorter)
X    char		  *Name;
X    ENTRY		***List;
X    int			 (*Selector)();
X    int			 (*Sorter)();
X{
X    register ENTRY	 **names;
X    register ENTRY	  *E;
X    register DIR	  *Dp;
X    register int	   i;
X    register int	   size;
X
X    /* Get initial list space and open directory. */
X    size = INITIAL_SIZE;
X    if ((names = (ENTRY **)malloc(size * sizeof names[0])) == NULL
X     || (Dp = opendir(Name)) == NULL)
X	return(-1);
X
X    /* Read entries in the directory. */
X    for (i = 0; E = readdir(Dp); )
X	if (Selector == NULL || (*Selector)(E)) {
X	    /* User wants them all, or he wants this one. */
X	    if (++i >= size) {
X		size <<= 1;
X		names = (ENTRY **)realloc((char *)names, size * sizeof names[0]);
X		if (names == NULL) {
X		    closedir(Dp);
X		    return(-1);
X		}
X	    }
X
X	    /* Copy the entry. */
X	    if ((names[i - 1] = (ENTRY *)malloc(MDIRSIZ(E))) == NULL) { 
X		closedir(Dp);
X		return(-1);
X	    }
X	    names[i - 1]->d_ino = E->d_ino;
X#ifndef SYSV
X	    names[i - 1]->d_reclen = E->d_reclen;
X	 /*   names[i - 1]->d_namlen = E->d_namlen; */
X#endif /* SYSV */
X	    (void)strcpy(names[i - 1]->d_name, E->d_name);
X	}
X
X    /* Close things off. */
X    names[i] = NULL;
X    *List = names;
X    closedir(Dp);
X
X    /* Sort? */
X    if (i && Sorter)
X	qsort((char *)names, i, sizeof names[0], Sorter);
X
X    return(i);
X}
SHAR_EOF
if test 2409 -ne "`wc -c < 'scandir.c'`"
then
	echo shar: "error transmitting 'scandir.c'" '(should have been 2409 characters)'
fi
fi
echo shar: "extracting 'tmclock.c'" '(2334 characters)'
if test -f 'tmclock.c'
then
	echo shar: "will not over-write existing file 'tmclock.c'"
else
sed 's/^X//' << \SHAR_EOF > 'tmclock.c'
X/*
X * Stolen from Jef Poskanzer's tws time library, which was stolen from
X * Marshall Rose's MH Message Handling system...
X *
X * tmclock() will convert time from a tm struct back to a clock value.
X * tmjuliandate() converts a tm struct to its julian day number.
X * tmsubdayclock() takes hours, minutes, and seconds from a tm struct
X * and returns the number of seconds since midnight of that day. (?)
X *  -- Howard Chu, August 1 1988      hyc@umix.cc.umich.edu, umix!hyc
X */
X
X/* $Header: tmclock.c,v 1.3 88/08/02 14:15:58 hyc Exp $ */
X
X/* Julian day number of the Unix* clock's origin, 01 Jan 1970. */
X#define JD1970 2440587L
X#define	CENTURY	19
X#if	BSD
X#include <sys/time.h>
Xint	daylight;
X#else
X#include <time.h>
X#endif
X
Xlong	tzone;
X
Xlong
Xtmjuliandate( tm )
Xstruct tm *tm;
X    {
X    register int mday, mon, year;
X    register long a, b;
X    double jd;
X
X    if ( (mday = tm -> tm_mday) < 1 || mday > 31 ||
X	    (mon = tm -> tm_mon + 1) < 1 || mon > 12 ||
X	    (year = tm -> tm_year) < 1 || year > 10000 )
X	return ( -1L );
X    if ( year < 100 )
X	year += CENTURY * 100;
X
X    if ( mon == 1 || mon == 2 )
X	{
X	--year;
X	mon += 12;
X	}
X    if ( year < 1583 )
X	return ( -1L );
X    a = year / 100;
X    b = 2 - a + a / 4;
X    b += (long) ( (double) year * 365.25 );
X    b += (long) ( 30.6001 * ( (double) mon + 1.0 ) );
X    jd = mday + b + 1720994.5;
X    return ( (long) jd );
X    }
X
X
Xlong
Xtmsubdayclock( tm )
Xstruct tm *tm;
X    {
X    register int sec, min, hour;
X    register long result;
X#if	BSD
X    {
X       struct timeval tp;
X       struct timezone tzp;
X
X       gettimeofday(&tp, &tzp);
X       daylight=tzp.tz_dsttime;
X       tzone=tzp.tz_minuteswest*(-60);
X    }
X#else
X    tzset();
X    tzone = -timezone;	/* declared as extern in SYSV <time.h> */
X#endif
X    if ( (sec = tm -> tm_sec) < 0 || sec > 59 ||
X	    (min = tm -> tm_min) < 0 || min > 59 ||
X	    (hour = tm -> tm_hour) < 0 || hour > 23 )
X	return ( -1L );
X
X    result = ( hour * 60 + min ) * 60 + sec;
X    result -= tzone;
X    if ( tm->tm_isdst )
X	result -= 60 * 60;
X
X    return ( result );
X    }
X
X
Xlong
Xtmclock( tm )
Xstruct tm *tm;
X    {
X    register long jd, sdc, result;
X
X    if ( ( jd = tmjuliandate( tm ) ) == -1L )
X	return ( -1L );
X    if ( ( sdc = tmsubdayclock( tm ) ) == -1L )
X	return ( -1L );
X
X    result = ( jd - JD1970 ) * 24 * 60 * 60 + sdc;
X
X    return ( result );
X    }
SHAR_EOF
if test 2334 -ne "`wc -c < 'tmclock.c'`"
then
	echo shar: "error transmitting 'tmclock.c'" '(should have been 2334 characters)'
fi
fi
echo shar: "extracting 'utimes.c'" '(399 characters)'
if test -f 'utimes.c'
then
	echo shar: "will not over-write existing file 'utimes.c'"
else
sed 's/^X//' << \SHAR_EOF > 'utimes.c'
X
X/* bsd utimes emulation for Sys V */
X/* by Jon Zeeff */
X
X#include <sys/types.h>
X
Xstruct utimbuf {
X     time_t  actime;
X     time_t  modtime;
X};
X
Xstruct timeval {
X     long    tv_sec;
X     long    tv_usec;
X};
X
Xutimes(path,tvp)
Xchar *path;
Xstruct timeval tvp[2];
X{
X
Xstruct utimbuf times;
X
Xtimes.actime = (time_t) tvp[0].tv_sec;
Xtimes.modtime = (time_t) tvp[1].tv_sec;
X
Xreturn utime(path, &times);
X
X}
SHAR_EOF
if test 399 -ne "`wc -c < 'utimes.c'`"
then
	echo shar: "error transmitting 'utimes.c'" '(should have been 399 characters)'
fi
fi
exit 0
#	End of shell archive

egray@fthood.UUCP (01/03/89)

This is part 5 (of 6) to the Arc v5.21 distribution package.

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
					Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	arcsq.c
#	arcsqs.c
#	arcsvc.c
#	arctst.c
#	arcunp.c
#	arcusq.c
#	getwd.c
# This archive created: Sun Jan  1 12:48:31 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'arcsq.c'" '(14548 characters)'
if test -f 'arcsq.c'
then
	echo shar: "will not over-write existing file 'arcsq.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcsq.c'
X/*
X * $Header: arcsq.c,v 1.3 88/07/31 18:53:32 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCSQ 
X *
X * Version 3.10, created on 01/30/86 at 20:10:46
X *
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED 
X *
X * By:  Thom Henderson 
X *
X * Description: This file contains the routines used to squeeze a file when
X * placing it in an archive. 
X *
X * Language: Computer Innovations Optimizing C86 
X *
X * Programming notes: Most of the routines used for the Huffman squeezing
X * algorithm were lifted from the SQ program by Dick Greenlaw, as adapted to
X * CI-C86 by Robert J. Beilstein. 
X */
X#include <stdio.h>
X#include "arc.h"
X
X/* stuff for Huffman squeezing */
X
X#define TRUE 1
X#define FALSE 0
X#define ERROR (-1)
X#define SPEOF 256		/* special endfile token */
X#define NOCHILD (-1)		/* marks end of path through tree */
X#define NUMVALS 257		/* 256 data values plus SPEOF */
X#define NUMNODES (NUMVALS+NUMVALS-1)	/* number of nodes */
X#define MAXCOUNT (unsigned short) 65535	/* biggest unsigned integer */
X
X/*
X * The following array of structures are the nodes of the binary trees. The
X * first NUMVALS nodes become the leaves of the final tree and represent the
X * values of the data bytes being encoded and the special endfile, SPEOF. The
X * remaining nodes become the internal nodes of the final tree. 
X */
X
Xstruct nd {			/* shared by unsqueezer */
X	unsigned short	weight;	/* number of appearances */
X	short		tdepth;	/* length on longest path in tree */
X	short		lchild, rchild;	/* indices to next level */
X}               node[NUMNODES];	/* use large buffer */
X
Xstatic int      dctreehd;	/* index to head of final tree */
X
X/*
X * This is the encoding table: The bit strings have first bit in low bit.
X * Note that counts were scaled so code fits unsigned integer. 
X */
X
Xstatic int      codelen[NUMVALS];	/* number of bits in code */
Xstatic unsigned short code[NUMVALS];	/* code itself, right adjusted */
Xstatic unsigned short tcode;	/* temporary code value */
Xstatic long     valcount[NUMVALS];	/* actual count of times seen */
X
X/* Variables used by encoding process */
X
Xstatic int      curin;		/* value currently being encoded */
Xstatic int      cbitsrem;	/* # of code string bits left */
Xstatic unsigned short ccode;	/* current code right justified */
X
Xstatic	void	scale(), heap(), adjust(), bld_tree(), init_enc(), put_int();
Xstatic	int	cmptrees(), buildenc(), maxchar();
Xvoid 
Xinit_sq()
X{				/* prepare for scanning pass */
X	int             i;	/* node index */
X
X	/*
X	 * Initialize all nodes to single element binary trees with zero
X	 * weight and depth. 
X	 */
X
X	for (i = 0; i < NUMNODES; ++i) {
X		node[i].weight = 0;
X		node[i].tdepth = 0;
X		node[i].lchild = NOCHILD;
X		node[i].rchild = NOCHILD;
X	}
X
X	for (i = 0; i < NUMVALS; i++)
X		valcount[i] = 0;
X}
X
Xvoid 
Xscan_sq(c)			/* add a byte to the tables */
X	int             c;	/* byte to add */
X{
X	unsigned short *wp;	/* speeds up weight counting */
X
X	/* Build frequency info in tree */
X
X	if (c == EOF)		/* it's traditional */
X		c = SPEOF;	/* dumb, but traditional */
X
X	if (*(wp = &node[c].weight) != MAXCOUNT)
X		++(*wp);	/* bump weight counter */
X
X	valcount[c]++;		/* bump byte counter */
X}
X
Xlong 
Xpred_sq()
X{				/* predict size of squeezed file */
X	int             i;
X	int             btlist[NUMVALS];	/* list of intermediate
X						 * b-trees */
X	int             listlen;/* length of btlist */
X	unsigned short	ceiling;/* limit for scaling */
X	long            size = 0;	/* predicted size */
X	int             numnodes;	/* # of nodes in simplified tree */
X
X	scan_sq(EOF);		/* signal end of input */
X
X	ceiling = MAXCOUNT;
X
X	/* Keep trying to scale and encode */
X
X	do {
X		scale(ceiling);
X		ceiling /= 2;	/* in case we rescale */
X
X		/*
X		 * Build list of single node binary trees having leaves for
X		 * the input values with non-zero counts 
X		 */
X
X		for (i = listlen = 0; i < NUMVALS; ++i) {
X			if (node[i].weight != 0) {
X				node[i].tdepth = 0;
X				btlist[listlen++] = i;
X			}
X		}
X
X		/*
X		 * Arrange list of trees into a heap with the entry indexing
X		 * the node with the least weight at the top. 
X		 */
X
X		heap(btlist, listlen);
X
X		/* Convert the list of trees to a single decoding tree */
X
X		bld_tree(btlist, listlen);
X
X		/* Initialize the encoding table */
X
X		init_enc();
X
X		/*
X		 * Try to build encoding table. Fail if any code is > 16 bits
X		 * long. 
X		 */
X	} while (buildenc(0, dctreehd) == ERROR);
X
X	/* Initialize encoding variables */
X
X	cbitsrem = 0;		/* force initial read */
X	curin = 0;		/* anything but endfile */
X
X	for (i = 0; i < NUMVALS; i++)	/* add bits for each code */
X		size += valcount[i] * codelen[i];
X
X	size = (size + 7) / 8;	/* reduce to number of bytes */
X
X	numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
X
X	size += sizeof(short) + 2 * numnodes * sizeof(short);
X
X	return size;
X}
X
X/*
X * The count of number of occurrances of each input value have already been
X * prevented from exceeding MAXCOUNT. Now we must scale them so that their
X * sum doesn't exceed ceiling and yet no non-zero count can become zero. This
X * scaling prevents errors in the weights of the interior nodes of the
X * Huffman tree and also ensures that the codes will fit in an unsigned
X * integer. Rescaling is used if necessary to limit the code length. 
X */
X
Xstatic	void
Xscale(ceil)
X	unsigned short	ceil;	/* upper limit on total weight */
X{
X	register int    i;
X	int             ovflw, divisor;
X	unsigned short	w, sum;
X	unsigned char   increased;	/* flag */
X
X	do {
X		for (i = sum = ovflw = 0; i < NUMVALS; ++i) {
X			if (node[i].weight > (ceil - sum))
X				++ovflw;
X			sum += node[i].weight;
X		}
X
X		divisor = ovflw + 1;
X
X		/* Ensure no non-zero values are lost */
X
X		increased = FALSE;
X		for (i = 0; i < NUMVALS; ++i) {
X			w = node[i].weight;
X			if (w < divisor && w != 0) {	/* Don't fail to provide
X							 * a code if it's used
X							 * at all */
X
X				node[i].weight = divisor;
X				increased = TRUE;
X			}
X		}
X	} while (increased);
X
X	/* Scaling factor chosen, now scale */
X
X	if (divisor > 1)
X		for (i = 0; i < NUMVALS; ++i)
X			node[i].weight /= divisor;
X}
X
X/*
X * heap() and adjust() maintain a list of binary trees as a heap with the top
X * indexing the binary tree on the list which has the least weight or, in
X * case of equal weights, least depth in its longest path. The depth part is
X * not strictly necessary, but tends to avoid long codes which might provoke
X * rescaling. 
X */
X
Xstatic	void
Xheap(list, length)
X	int             list[], length;
X{
X	register int    i;
X
X	for (i = (length - 2) / 2; i >= 0; --i)
X		adjust(list, i, length - 1);
X}
X
X/* Make a heap from a heap with a new top */
X
Xstatic	void
Xadjust(list, top, bottom)
X	int             list[], top, bottom;
X{
X	register int    k, temp;
X
X	k = 2 * top + 1;	/* left child of top */
X	temp = list[top];	/* remember root node of top tree */
X
X	if (k <= bottom) {
X		if (k < bottom && cmptrees(list[k], list[k + 1]))
X			++k;
X
X		/* k indexes "smaller" child (in heap of trees) of top */
X		/* now make top index "smaller" of old top and smallest child */
X
X		if (cmptrees(temp, list[k])) {
X			list[top] = list[k];
X			list[k] = temp;
X
X			/* Make the changed list a heap */
X
X			adjust(list, k, bottom);	/* recursive */
X		}
X	}
X}
X
X/*
X * Compare two trees, if a > b return true, else return false. Note
X * comparison rules in previous comments. 
X */
X
Xstatic	int 
Xcmptrees(a, b)
X	int             a, b;	/* root nodes of trees */
X{
X	if (node[a].weight > node[b].weight)
X		return TRUE;
X	if (node[a].weight == node[b].weight)
X		if (node[a].tdepth > node[b].tdepth)
X			return TRUE;
X	return FALSE;
X}
X
X/*
X * HUFFMAN ALGORITHM: develops the single element trees into a single binary
X * tree by forming subtrees rooted in interior nodes having weights equal to
X * the sum of weights of all their descendents and having depth counts
X * indicating the depth of their longest paths. 
X *
X * When all trees have been formed into a single tree satisfying the heap
X * property (on weight, with depth as a tie breaker) then the binary code
X * assigned to a leaf (value to be encoded) is then the series of left (0)
X * and right (1) paths leading from the root to the leaf. Note that trees are
X * removed from the heaped list by moving the last element over the top
X * element and reheaping the shorter list. 
X */
X
Xstatic	void
Xbld_tree(list, len)
X	int             list[];
Xint             len;
X{
X	register int    freenode;	/* next free node in tree */
X	register struct nd *frnp;	/* free node pointer */
X	int             lch, rch;	/* temps for left, right children */
X
X	/*
X	 * Initialize index to next available (non-leaf) node. Lower numbered
X	 * nodes correspond to leaves (data values). 
X	 */
X
X	freenode = NUMVALS;
X
X	while (len > 1) {	/* Take from list two btrees with least
X				 * weight and build an interior node pointing
X				 * to them. This forms a new tree. */
X
X		lch = list[0];	/* This one will be left child */
X
X		/* delete top (least) tree from the list of trees */
X
X		list[0] = list[--len];
X		adjust(list, 0, len - 1);
X
X		/* Take new top (least) tree. Reuse list slot later */
X
X		rch = list[0];	/* This one will be right child */
X
X		/*
X		 * Form new tree from the two least trees using a free node
X		 * as root. Put the new tree in the list. 
X		 */
X
X		frnp = &node[freenode];	/* address of next free node */
X		list[0] = freenode++;	/* put at top for now */
X		frnp->lchild = lch;
X		frnp->rchild = rch;
X		frnp->weight = node[lch].weight + node[rch].weight;
X		frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
X
X		/* reheap list  to get least tree at top */
X
X		adjust(list, 0, len - 1);
X	}
X	dctreehd = list[0];	/* head of final tree */
X}
X
Xstatic int 
Xmaxchar(a, b)
X{
X	return a > b ? a : b;
X}
X
Xstatic	void
Xinit_enc()
X{
X	register int    i;
X
X	/* Initialize encoding table */
X
X	for (i = 0; i < NUMVALS; ++i)
X		codelen[i] = 0;
X}
X
X/*
X * Recursive routine to walk the indicated subtree and level and maintain the
X * current path code in bstree. When a leaf is found the entire code string
X * and length are put into the encoding table entry for the leaf's data value
X * . 
X *
X * Returns ERROR if codes are too long. 
X */
X
Xstatic int 
Xbuildenc(level, root)
X	int             level;	/* level of tree being examined, from zero */
X	int             root;	/* root of subtree is also data value if leaf */
X{
X	register int    l, r;
X
X	l = node[root].lchild;
X	r = node[root].rchild;
X
X	if (l == NOCHILD && r == NOCHILD) {	/* Leaf. Previous path
X						 * determines bit string code
X						 * of length level (bits 0 to
X						 * level - 1). Ensures unused
X						 * code bits are zero. */
X
X		codelen[root] = level;
X		code[root] = tcode & (((unsigned short	) ~0) >> (16 - level));
X		return (level > 16) ? ERROR : 0;
X	} else {
X		if (l != NOCHILD) {	/* Clear path bit and continue deeper */
X
X			tcode &= ~(1 << level);
X			if (buildenc(level + 1, l) == ERROR)
X				return ERROR;	/* pass back bad statuses */
X		}
X		if (r != NOCHILD) {	/* Set path bit and continue deeper */
X
X			tcode |= 1 << level;
X			if (buildenc(level + 1, r) == ERROR)
X				return ERROR;	/* pass back bad statuses */
X		}
X	}
X	return NULL;		/* it worked if we reach here */
X}
X
Xstatic	void
Xput_int(n, f)			/* output an integer */
X	short		n;	/* integer to output */
X	FILE           *f;	/* file to put it to */
X{
X	void		putc_pak();
X
X	putc_pak(n & 0xff, f);	/* first the low byte */
X	putc_pak(n >> 8, f);	/* then the high byte */
X}
X
X/* Write out the header of the compressed file */
X
Xstatic long 
Xwrt_head(ob)
X	FILE           *ob;
X{
X	register int    l, r;
X	int             i, k;
X	int             numnodes;	/* # of nodes in simplified tree */
X
X	/*
X	 * Write out a simplified decoding tree. Only the interior nodes are
X	 * written. When a child is a leaf index (representing a data value)
X	 * it is recoded as -(index + 1) to distinguish it from interior
X	 * indexes which are recoded as positive indexes in the new tree. 
X	 *
X	 * Note that this tree will be empty for an empty file. 
X	 */
X
X	numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
X	put_int(numnodes, ob);
X
X	for (k = 0, i = dctreehd; k < numnodes; ++k, --i) {
X		l = node[i].lchild;
X		r = node[i].rchild;
X		l = l < NUMVALS ? -(l + 1) : dctreehd - l;
X		r = r < NUMVALS ? -(r + 1) : dctreehd - r;
X		put_int(l, ob);
X		put_int(r, ob);
X	}
X
X	return sizeof(short) + numnodes * 2 * sizeof(short);
X}
X
X/*
X * Get an encoded byte or EOF. Reads from specified stream AS NEEDED. 
X *
X * There are two unsynchronized bit-byte relationships here. The input stream
X * bytes are converted to bit strings of various lengths via the static
X * variables named c... These bit strings are concatenated without padding to
X * become the stream of encoded result bytes, which this function returns one
X * at a time. The EOF (end of file) is converted to SPEOF for convenience and
X * encoded like any other input value. True EOF is returned after that. 
X */
X
Xstatic int 
Xgethuff(ib)			/* Returns bytes except for EOF */
X	FILE           *ib;
X{
X	int             rbyte;	/* Result byte value */
X	int             need;	/* number of bits */
X	int		getc_ncr();
X
X	rbyte = 0;
X	need = 8;		/* build one byte per call */
X
X	/*
X	 * Loop to build a byte of encoded data. Initialization forces read
X	 * the first time. 
X	 */
X
Xloop:
X	if (cbitsrem >= need) {	/* if current code is big enough */
X		if (need == 0)
X			return rbyte;
X
X		rbyte |= ccode << (8 - need);	/* take what we need */
X		ccode >>= need;	/* and leave the rest */
X		cbitsrem -= need;
X		return rbyte & 0xff;
X	}
X	/* We need more than current code */
X
X	if (cbitsrem > 0) {
X		rbyte |= ccode << (8 - need);	/* take what there is */
X		need -= cbitsrem;
X	}
X	/* No more bits in current code string */
X
X	if (curin == SPEOF) {	/* The end of file token has been encoded. If
X				 * result byte has data return it and do EOF
X				 * next time. */
X
X		cbitsrem = 0;
X		return (need == 8) ? EOF : rbyte + 0;
X	}
X	/* Get an input byte */
X
X	if ((curin = getc_ncr(ib)) == EOF)
X		curin = SPEOF;	/* convenient for encoding */
X
X	ccode = code[curin];	/* get the new byte's code */
X	cbitsrem = codelen[curin];
X
X	goto loop;
X}
X
X/*
X * This routine is used to perform the actual squeeze operation.  It can only
X * be called after the file has been scanned.  It returns the true length of
X * the squeezed entry. 
X */
X
Xlong 
Xfile_sq(f, t)			/* squeeze a file into an archive */
X	FILE           *f;	/* file to squeeze */
X	FILE           *t;	/* archive to receive file */
X{
X	int             c;	/* one byte of squeezed data */
X	long            size;	/* size after squeezing */
X
X	size = wrt_head(t);	/* write out the decode tree */
X
X	while ((c = gethuff(f)) != EOF) {
X		putc_pak(c, t);
X		size++;
X	}
X
X	return size;		/* report true size */
X}
SHAR_EOF
if test 14548 -ne "`wc -c < 'arcsq.c'`"
then
	echo shar: "error transmitting 'arcsq.c'" '(should have been 14548 characters)'
fi
fi
echo shar: "extracting 'arcsqs.c'" '(11513 characters)'
if test -f 'arcsqs.c'
then
	echo shar: "will not over-write existing file 'arcsqs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcsqs.c'
X/*
X * $Header: arcsqs.c,v 1.3 88/07/31 18:54:14 hyc Exp $
X */
X
X/*  ARC - Archive utility - SQUASH
X 
X(C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X 
X This is a quick hack to ARCLZW to make it handle squashed archives.
X Dan Lanciani (ddl@harvard.*) July 87
X 
X*/
X
X/*
X * $Header: arcsqs.c,v 1.3 88/07/31 18:54:14 hyc Exp $
X */
X
X#include <stdio.h>
X#include "arc.h"
X
X#if	MSDOS
Xchar	*setmem();
X#else
Xchar	*memset();
X#endif
Xint	getc_unp();
Xvoid	putc_pak(), putc_unp();
Xstatic void	putcode();
X
X/* definitions for the new dynamic Lempel-Zev crunching */
X
X#define BITS   13		/* maximum bits per code */
X#define HSIZE  10007		/* 80% occupancy */
X#define INIT_BITS 9		/* initial number of bits/code */
Xstatic int      n_bits;		/* number of bits/code */
Xstatic int      maxcode;	/* maximum code, given n_bits */
X#define MAXCODE(n)      ((1<<(n)) - 1)	/* maximum code calculation */
Xstatic int      maxcodemax = 1 << BITS;	/* largest possible code (+1) */
X
Xstatic unsigned char buf[BITS];	/* input/output buffer */
X
Xstatic unsigned char lmask[9] =	/* left side masks */
X{0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
Xstatic unsigned char rmask[9] =	/* right side masks */
X{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
X
Xstatic int      offset;		/* byte offset for code output */
Xstatic long     in_count;	/* length of input */
Xstatic long     bytes_out;	/* length of compressed output */
Xstatic unsigned short ent;
X
Xlong     htab[HSIZE];	/* hash code table   (crunch) */
Xunsigned short codetab[HSIZE];	/* string code table (crunch) */
X
Xstatic unsigned short *prefix = codetab;  /* prefix code table (uncrunch) */
Xstatic unsigned char *suffix=(unsigned char *)htab;  /* suffix table (uncrunch) */
Xstatic int      free_ent;	/* first unused entry */
Xstatic int      firstcmp;	/* true at start of compression */
Xunsigned char stack[HSIZE];	/* local push/pop stack */
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
X
Xstatic int      clear_flg;
Xstatic long     ratio;
X#define CHECK_GAP 10000		/* ratio check interval */
Xstatic long     checkpoint;
X
X/*
X * the next two codes should not be changed lightly, as they must not
X * lie within the contiguous general code space.
X */
X#define FIRST   257		/* first free entry */
X#define CLEAR   256		/* table clear output code */
X
Xstatic void
Xcl_block(t)			/* table clear for block compress */
X	FILE           *t;	/* our output file */
X{
X	long            rat;
X
X	checkpoint = in_count + CHECK_GAP;
X
X	if (in_count > 0x007fffffL) {	/* shift will overflow */
X		rat = bytes_out >> 8;
X		if (rat == 0)	/* Don't divide by zero */
X			rat = 0x7fffffffL;
X		else
X			rat = in_count / rat;
X	} else
X		rat = (in_count << 8) / bytes_out;	/* 8 fractional bits */
X
X	if (rat > ratio)
X		ratio = rat;
X	else {
X		ratio = 0;
X		setmem(htab, HSIZE * sizeof(long), 0xff);
X		free_ent = FIRST;
X		clear_flg = 1;
X		putcode(CLEAR, t);
X	}
X}
X
X/*****************************************************************
X *
X * Output a given code.
X * Inputs:
X *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
X *              that n_bits =< (long)wordsize - 1.
X * Outputs:
X *      Outputs code to the file.
X * Assumptions:
X *      Chars are 8 bits long.
X * Algorithm:
X *      Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly).  When the buffer fills up empty it and start over.
X */
X
Xstatic void
Xputcode(code, t)		/* output a code */
X	int             code;	/* code to output */
X	FILE           *t;	/* where to put it */
X{
X	int             r_off = offset;	/* right offset */
X	int             bits = n_bits;	/* bits to go */
X	unsigned char  *bp = buf;	/* buffer pointer */
X	int             n;	/* index */
X	register int	ztmp;
X
X	if (code >= 0) {	/* if a real code *//* Get to the first byte. */
X		bp += (r_off >> 3);
X		r_off &= 7;
X
X		/*
X		 * Since code is always >= 8 bits, only need to mask the
X		 * first hunk on the left. 
X		 */
X		ztmp = (code << r_off) & lmask[r_off];
X		*bp = (*bp & rmask[r_off]) | ztmp;
X		bp++;
X		bits -= (8 - r_off);
X		code >>= (8 - r_off);
X
X		/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X		if (bits >= 8) {
X			*bp++ = code;
X			code >>= 8;
X			bits -= 8;
X		}
X		/* Last bits. */
X		if (bits)
X			*bp = code;
X
X		offset += n_bits;
X
X		if (offset == (n_bits << 3)) {
X			bp = buf;
X			bits = n_bits;
X			bytes_out += bits;
X			do
X				putc_pak(*bp++, t);
X			while (--bits);
X			offset = 0;
X		}
X		/*
X		 * If the next entry is going to be too big for the code
X		 * size, then increase it, if possible. 
X		 */
X		if (free_ent > maxcode || clear_flg > 0) {	/* Write the whole
X								 * buffer, because the
X								 * input side won't
X								 * discover the size
X								 * increase until after
X								 * it has read it. */
X			if (offset > 0) {
X				bp = buf;	/* reset pointer for writing */
X				bytes_out += n = n_bits;
X				while (n--)
X					putc_pak(*bp++, t);
X			}
X			offset = 0;
X
X			if (clear_flg) {	/* reset if clearing */
X				maxcode = MAXCODE(n_bits = INIT_BITS);
X				clear_flg = 0;
X			} else {/* else use more bits */
X				n_bits++;
X				if (n_bits == BITS)
X					maxcode = maxcodemax;
X				else
X					maxcode = MAXCODE(n_bits);
X			}
X		}
X	} else {		/* dump the buffer on EOF */
X		bytes_out += n = (offset + 7) / 8;
X
X		if (offset > 0)
X			while (n--)
X				putc_pak(*bp++, t);
X		offset = 0;
X	}
X}
X
X/*****************************************************************
X *
X * Read one code from the standard input.  If EOF, return -1.
X * Inputs:
X *      cmpin
X * Outputs:
X *      code or -1 is returned.
X */
X
Xstatic int
Xgetcode(f)			/* get a code */
X	FILE           *f;	/* file to get from */
X{
X	int             code;
X	static int      loffset = 0, size = 0;
X	int             r_off, bits;
X	unsigned char  *bp = buf;
X
X	if (clear_flg > 0 || loffset >= size || free_ent > maxcode) {
X		/* If the next entry will be too big for the current code
X		 * size, then we must increase the size. This implies reading
X		 * a new buffer full, too. */
X		if (free_ent > maxcode) {
X			n_bits++;
X			if (n_bits == BITS)
X				maxcode = maxcodemax;	/* won't get any bigger
X							 * now */
X			else
X				maxcode = MAXCODE(n_bits);
X		}
X		if (clear_flg > 0) {
X			maxcode = MAXCODE(n_bits = INIT_BITS);
X			clear_flg = 0;
X		}
X		for (size = 0; size < n_bits; size++) {
X			if ((code = getc_unp(f)) == EOF)
X				break;
X			else
X				buf[size] = code;
X		}
X		if (size <= 0)
X			return -1;	/* end of file */
X
X		loffset = 0;
X		/* Round size down to integral number of codes */
X		size = (size << 3) - (n_bits - 1);
X	}
X	r_off = loffset;
X	bits = n_bits;
X
X	/*
X	 * Get to the first byte. 
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X
X	/* Get first part (low order bits) */
X	code = (*bp++ >> r_off);
X	bits -= 8 - r_off;
X	r_off = 8 - r_off;	/* now, offset into code word */
X
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if (bits >= 8) {
X		code |= *bp++ << r_off;
X		r_off += 8;
X		bits -= 8;
X	}
X	/* high order bits. */
X	code |= (*bp & rmask[bits]) << r_off;
X	loffset += n_bits;
X
X	return code;
X}
X
X/*
X * compress a file
X *
X * Algorithm:  use open addressing double hashing (no chaining) on the
X * prefix code / next character combination.  We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe.  Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation.  Also do block compression with
X * an adaptive reset, where the code table is cleared when the compression
X * ratio decreases, but after the table fills.  The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor.
X */
X
Xvoid
Xsqinit_cm()			/* initialize for compression */
X{
X	offset = 0;
X	bytes_out = 0;
X	clear_flg = 0;
X	ratio = 0;
X	in_count = 1;
X	checkpoint = CHECK_GAP;
X	maxcode = MAXCODE(n_bits = INIT_BITS);
X	free_ent = FIRST;
X	setmem(htab, HSIZE * sizeof(long), 0xff);
X	n_bits = INIT_BITS;	/* set starting code size */
X
X	firstcmp = 1;		/* next byte will be first */
X}
X
Xvoid
Xsqputc_cm(c, t)			/* compress a character */
X	unsigned char   c;	/* character to compress */
X	FILE           *t;	/* where to put it */
X{
X	static long     fcode;
X	static int      hshift;
X	int             i;
X	int             disp;
X
X	if (firstcmp) {		/* special case for first byte */
X		ent = c;	/* remember first byte */
X
X		hshift = 0;
X		for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L)
X			hshift++;
X		hshift = 8 - hshift;	/* set hash code range bund */
X
X		firstcmp = 0;	/* no longer first */
X		return;
X	}
X	in_count++;
X	fcode = (long) (((long) c << BITS) + ent);
X	i = (c << hshift) ^ ent;/* xor hashing */
X
X	if (htab[i] == fcode) {
X		ent = codetab[i];
X		return;
X	} else if (htab[i] < 0)	/* empty slot */
X		goto nomatch;
X	disp = HSIZE - i;	/* secondary hash (after G.Knott) */
X	if (i == 0)
X		disp = 1;
X
Xprobe:
X	if ((i -= disp) < 0)
X		i += HSIZE;
X
X	if (htab[i] == fcode) {
X		ent = codetab[i];
X		return;
X	}
X	if (htab[i] > 0)
X		goto probe;
X
Xnomatch:
X	putcode(ent, t);
X	ent = c;
X	if (free_ent < maxcodemax) {
X		codetab[i] = free_ent++;	/* code -> hashtable */
X		htab[i] = fcode;
X	} else if ((long) in_count >= checkpoint)
X		cl_block(t);
X}
X
Xlong 
Xsqpred_cm(t)			/* finish compressing a file */
X	FILE           *t;	/* where to put it */
X{
X	putcode(ent, t);	/* put out the final code */
X	putcode(-1, t);		/* tell output we are done */
X
X	return bytes_out;	/* say how big it got */
X}
X
X/*
X * Decompress a file.  This routine adapts to the codes in the file
X * building the string table on-the-fly; requiring no table to be stored
X * in the compressed file.  The tables used herein are shared with those of
X * the compress() routine.  See the definitions above.
X */
X
Xvoid
Xsqdecomp(f, t)			/* decompress a file */
X	FILE           *f;	/* file to read codes from */
X	FILE           *t;	/* file to write text to */
X{
X	unsigned char  *stackp;
X	int             finchar;
X	int             code, oldcode, incode;
X
X	n_bits = INIT_BITS;	/* set starting code size */
X	clear_flg = 0;
X
X	/*
X	 * As above, initialize the first 256 entries in the table. 
X	 */
X	maxcode = MAXCODE(n_bits = INIT_BITS);
X	for (code = 255; code >= 0; code--) {
X		prefix[code] = 0;
X		suffix[code] = (unsigned char) code;
X	}
X	free_ent = FIRST;
X
X	finchar = oldcode = getcode(f);
X	if (oldcode == -1)	/* EOF already? */
X		return;		/* Get out of here */
X	putc_unp((char) finchar, t);	/* first code must be 8 bits=char */
X	stackp = stack;
X
X	while ((code = getcode(f)) > -1) {
X		if (code == CLEAR) {
X			for (code = 255; code >= 0; code--)
X				prefix[code] = 0;
X			clear_flg = 1;
X			free_ent = FIRST - 1;
X			if ((code = getcode(f)) == -1)	/* O, untimely death! */
X				break;
X		}
X		incode = code;
X		/*
X		 * Special case for KwKwK string. 
X		 */
X		if (code >= free_ent) {
X			if (code > free_ent) {
X				if (warn) {
X					printf("Corrupted compressed file.\n");
X					printf("Invalid code %d when max is %d.\n",
X						code, free_ent);
X				}
X				nerrs++;
X				return;
X			}
X			*stackp++ = finchar;
X			code = oldcode;
X		}
X		/*
X		 * Generate output characters in reverse order 
X		 */
X		while (code >= 256) {
X			*stackp++ = suffix[code];
X			code = prefix[code];
X		}
X		*stackp++ = finchar = suffix[code];
X
X		/*
X		 * And put them out in forward order 
X		 */
X		do
X			putc_unp(*--stackp, t);
X		while (stackp > stack);
X
X		/*
X		 * Generate the new entry. 
X		 */
X		if ((code = free_ent) < maxcodemax) {
X			prefix[code] = (unsigned short) oldcode;
X			suffix[code] = finchar;
X			free_ent = code + 1;
X		}
X		/*
X		 * Remember previous code. 
X		 */
X		oldcode = incode;
X	}
X}
SHAR_EOF
if test 11513 -ne "`wc -c < 'arcsqs.c'`"
then
	echo shar: "error transmitting 'arcsqs.c'" '(should have been 11513 characters)'
fi
fi
echo shar: "extracting 'arcsvc.c'" '(4689 characters)'
if test -f 'arcsvc.c'
then
	echo shar: "will not over-write existing file 'arcsvc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcsvc.c'
X/*
X * $Header: arcsvc.c,v 1.9 88/07/31 18:54:55 hyc Exp $
X */
X
X/*  ARC - Archive utility - ARCSVC
X
X    Version 2.23, created on 04/22/87 at 13:10:10
X
X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
X
X    By:	 Thom Henderson
X
X    Description:
X	 This file contains service routines needed to maintain an archive.
X
X    Language:
X	 Computer Innovations Optimizing C86
X*/
X#include <stdio.h>
X#include "arc.h"
X#if	MTS
X#include <mts.h>
X#endif
X
Xvoid	abort(), setstamp();
Xint	unlink();
X
Xvoid
Xopenarc(chg)			/* open archive */
X	int             chg;	/* true to open for changes */
X{
X	FILE           *fopen();/* file opener */
X
X	if (!(arc = fopen(arcname, OPEN_R))) {
X		if (chg) {
X			if (note)
X				printf("Creating new archive: %s\n", arcname);
X		}
X		else
X			abort("Archive not found: %s", arcname);
X	}
X#if	MTS
X		/* allow reading archives of max MTS record length */
X	else {
X		char *buffer, *malloc();
X		int inlen;
X		struct GDDSECT *region;
X
X		region=gdinfo(arc->_fd._fdub);
X		inlen=region->GDINLEN;
X		buffer=malloc(inlen);
X		setbuf(arc, buffer);
X		arc->_bufsiz=inlen;
X	}
X#endif
X	if (chg) {		/* if opening for changes */
X		if (!(new = fopen(newname, OPEN_W)))
X			abort("Cannot create archive copy: %s", newname);
X
X	changing = chg;		/* note if open for changes */
X	}
X}
X
Xvoid
Xclosearc(chg)			/* close an archive */
X	int             chg;	/* true if archive was changed */
X{
X	if (arc) {		/* if we had an initial archive */
X		fclose(arc);
X#if	!MTS
X		if (kludge)	/* kludge to update timestamp */
X			setstamp(arcname, olddate, oldtime);
X#endif
X	}
X	if (chg) {		/* if things have changed */
X		fclose(new);	/* close the new copy */
X		if (arc) {	/* if we had an original archive */
X			if (keepbak) {	/* if a backup is wanted */
X				unlink(bakname);	/* erase any old copies */
X				if (move(arcname, bakname))
X					abort("Cannot rename %s to %s", arcname, bakname);
X				printf("Keeping backup archive: %s\n", bakname);
X			} else if (unlink(arcname))
X				abort("Cannot delete old archive: %s", arcname);
X		}
X		if (move(newname, arcname))
X			abort("Cannot move %s to %s", newname, arcname);
X#if	!MTS
X		setstamp(arcname, arcdate, arctime);
X#endif
X	}
X}
X
X/*
X * CRC computation logic
X * 
X * The logic for this method of calculating the CRC 16 bit polynomial is taken
X * from an article by David Schwaderer in the April 1985 issue of PC Tech
X * Journal.
X */
X
Xstatic short      crctab[] =	/* CRC lookup table */
X{
X 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
X 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
X 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
X 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
X 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
X 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
X 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
X 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
X 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
X 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
X 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
X 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
X 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
X 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
X 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
X 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
X 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
X 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
X 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
X 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
X 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
X 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
X 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
X 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
X 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
X 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
X 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
X 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
X 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
X 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
X 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
X 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
X};
X
Xint
Xaddcrc(crc, c)			/* update a CRC check */
X	int             crc;	/* running CRC value */
X	unsigned char   c;	/* character to add */
X{
X	return ((crc >> 8) & 0x00ff) ^ crctab[(crc ^ c) & 0x00ff];
X}
SHAR_EOF
if test 4689 -ne "`wc -c < 'arcsvc.c'`"
then
	echo shar: "error transmitting 'arcsvc.c'" '(should have been 4689 characters)'
fi
fi
echo shar: "extracting 'arctst.c'" '(1284 characters)'
if test -f 'arctst.c'
then
	echo shar: "will not over-write existing file 'arctst.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arctst.c'
X/*
X * $Header: arctst.c,v 1.4 88/04/19 01:40:28 hyc Exp $
X */
X
X/*
X * ARC - Archive utility - ARCTST
X * 
X * Version 2.12, created on 02/03/86 at 23:00:40
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to test archive integrity.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	openarc();
Xint	readhdr(), unpack();
X
Xvoid
Xtstarc()
X{				/* test integrity of an archive */
X	struct heads    hdr;	/* file header */
X	long            arcsize, ftell();	/* archive size */
X
X	openarc(0);		/* open archive for reading */
X	fseek(arc, 0L, 2);	/* move to end of archive */
X	arcsize = ftell(arc);	/* see how big it is */
X	fseek(arc, 0L, 0);	/* return to top of archive */
X
X	while (readhdr(&hdr, arc)) {
X		if (ftell(arc) + hdr.size > arcsize) {
X			printf("Archive truncated in file %s\n", hdr.name);
X			nerrs++;
X			break;
X		} else {
X			printf("Testing file: %-12s  ", hdr.name);
X			fflush(stdout);
X			if (unpack(arc, NULL, &hdr))
X				nerrs++;
X			else
X				printf("okay\n");
X		}
X	}
X
X	if (nerrs < 1)
X		printf("No errors detected\n");
X	else if (nerrs == 1)
X		printf("One error detected\n");
X	else
X		printf("%d errors detected\n", nerrs);
X}
SHAR_EOF
if test 1284 -ne "`wc -c < 'arctst.c'`"
then
	echo shar: "error transmitting 'arctst.c'" '(should have been 1284 characters)'
fi
fi
echo shar: "extracting 'arcunp.c'" '(5347 characters)'
if test -f 'arcunp.c'
then
	echo shar: "will not over-write existing file 'arcunp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcunp.c'
X/*
X * $Header: arcunp.c,v 1.7 88/06/18 03:12:36 hyc Locked $
X */
X
X/*
X * ARC - Archive utility - ARCUNP
X * 
X * Version 3.17, created on 02/13/86 at 10:20:08
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to expand a file when
X * taking it out of an archive.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X#if	MTS
X#include <ctype.h>
X#endif
X
Xvoid	setcode(), init_usq(), init_ucr(), decomp(), sqdecomp();
Xvoid	abort(), putc_tst();
Xint	getc_usq(), getc_ucr(), addcrc();
X
X/* stuff for repeat unpacking */
X
X#define DLE 0x90		/* repeat byte flag */
X
Xstatic int      state;		/* repeat unpacking state */
X
X/* repeat unpacking states */
X
X#define NOHIST 0		/* no relevant history */
X#define INREP 1			/* sending a repeated value */
X
Xstatic short    crcval;		/* CRC check value */
Xstatic long     size;		/* bytes to read */
X#if	!DOS
Xstatic int	gotcr;		/* got a carriage return? */
X#endif
X
Xint
Xunpack(f, t, hdr)		/* unpack an archive entry */
X	FILE           *f, *t;	/* source, destination */
X	struct heads   *hdr;	/* pointer to file header data */
X{
X	int             c;	/* one char of stream */
X	void            putc_unp();
X	void            putc_ncr();
X	int             getc_unp();
X
X	/* setups common to all methods */
X#if	!DOS
X	gotcr = 0;
X#endif
X	crcval = 0;		/* reset CRC check value */
X	size = hdr->size;	/* set input byte counter */
X	state = NOHIST;		/* initial repeat unpacking state */
X	setcode();		/* set up for decoding */
X
X	/* use whatever method is appropriate */
X
X	switch (hdrver) {	/* choose proper unpack method */
X	case 1:		/* standard packing */
X	case 2:
X		while ((c = getc_unp(f)) != EOF)
X			putc_unp((char) c, t);
X		break;
X
X	case 3:		/* non-repeat packing */
X		while ((c = getc_unp(f)) != EOF)
X			putc_ncr((unsigned char) c, t);
X		break;
X
X	case 4:		/* Huffman squeezing */
X		init_usq(f);
X		while ((c = getc_usq(f)) != EOF)
X			putc_ncr((unsigned char) c, t);
X		break;
X
X	case 5:		/* Lempel-Zev compression */
X		init_ucr(0);
X		while ((c = getc_ucr(f)) != EOF)
X			putc_unp((char) c, t);
X		break;
X
X	case 6:		/* Lempel-Zev plus non-repeat */
X		init_ucr(0);
X		while ((c = getc_ucr(f)) != EOF)
X			putc_ncr((unsigned char) c, t);
X		break;
X
X	case 7:		/* L-Z plus ncr with new hash */
X		init_ucr(1);
X		while ((c = getc_ucr(f)) != EOF)
X			putc_ncr((unsigned char) c, t);
X		break;
X
X	case 8:		/* dynamic Lempel-Zev */
X		decomp(f, t);
X		break;
X
X	case 9:		/* Squashing */
X		sqdecomp(f, t);
X		break;
X
X	default:		/* unknown method */
X		if (warn) {
X			printf("I don't know how to unpack file %s\n", hdr->name);
X			printf("I think you need a newer version of ARC\n");
X			nerrs++;
X		}
X		fseek(f, hdr->size, 1);	/* skip over bad file */
X		return 1;	/* note defective file */
X	}
X
X	/* cleanups common to all methods */
X
X	if (crcval != hdr->crc) {
X		if (warn || kludge) {
X			printf("WARNING: File %s fails CRC check\n", hdr->name);
X			nerrs++;
X		}
X		return 1;	/* note defective file */
X	}
X	return 0;		/* file is okay */
X}
X
X/*
X * This routine is used to put bytes in the output file.  It also performs
X * various housekeeping functions, such as maintaining the CRC check value.
X */
X
Xvoid
Xputc_unp(c, t)			/* output an unpacked byte */
X	char            c;	/* byte to output */
X	FILE           *t;	/* file to output to */
X{
X	crcval = addcrc(crcval, c);	/* update the CRC check value */
X#if	MTS
X	if (!image)
X		atoe(&c, 1);
X#endif
X#if	DOS
X	putc_tst(c, t);
X#else
X	if (image)
X		putc_tst(c, t);
X	else {
X		if (gotcr) {
X			gotcr = 0;
X			if (c != '\n')
X				putc_tst('\r', t);
X		}
X		if (c == '\r')
X			gotcr = 1;
X		else
X			putc_tst(c, t);
X	}
X#endif
X}
X
X/*
X * This routine is used to decode non-repeat compression.  Bytes are passed
X * one at a time in coded format, and are written out uncoded. The data is
X * stored normally, except that runs of more than two characters are
X * represented as:
X * 
X * <char> <DLE> <count>
X * 
X * With a special case that a count of zero indicates a DLE as data, not as a
X * repeat marker.
X */
X
Xvoid
Xputc_ncr(c, t)			/* put NCR coded bytes */
X	unsigned char   c;	/* next byte of stream */
X	FILE           *t;	/* file to receive data */
X{
X	static int      lastc;	/* last character seen */
X
X	switch (state) {	/* action depends on our state */
X	case NOHIST:		/* no previous history */
X		if (c == DLE)	/* if starting a series */
X			state = INREP;	/* then remember it next time */
X		else
X			putc_unp(lastc = c, t);	/* else nothing unusual */
X		return;
X
X	case INREP:		/* in a repeat */
X		if (c)		/* if count is nonzero */
X			while (--c)	/* then repeatedly ... */
X				putc_unp(lastc, t);	/* ... output the byte */
X		else
X			putc_unp(DLE, t);	/* else output DLE as data */
X		state = NOHIST;	/* back to no history */
X		return;
X
X	default:
X		abort("Bad NCR unpacking state (%d)", state);
X	}
X}
X
X/*
X * This routine provides low-level byte input from an archive.  This routine
X * MUST be used, as end-of-file is simulated at the end of the archive entry.
X */
X
Xint
Xgetc_unp(f)			/* get a byte from an archive */
X	FILE           *f;	/* archive file to read */
X{
X	register int    xx;
X	unsigned char		code();
X
X	if (!size)		/* if no data left */
X		return EOF;	/* then pretend end of file */
X
X	size--;			/* deduct from input counter */
X	xx = getc(f);
X	return code(xx);	/* and return next decoded byte */
X}
SHAR_EOF
if test 5347 -ne "`wc -c < 'arcunp.c'`"
then
	echo shar: "error transmitting 'arcunp.c'" '(should have been 5347 characters)'
fi
fi
echo shar: "extracting 'arcusq.c'" '(2486 characters)'
if test -f 'arcusq.c'
then
	echo shar: "will not over-write existing file 'arcusq.c'"
else
sed 's/^X//' << \SHAR_EOF > 'arcusq.c'
X/*
X * $Header: arcusq.c,v 1.2 88/06/02 16:27:44 hyc Locked $
X */
X
X/*
X * ARC - Archive utility - ARCUSQ
X * 
X * Version 3.14, created on 07/25/86 at 13:04:19
X * 
X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
X * 
X * By:  Thom Henderson
X * 
X * Description: This file contains the routines used to expand a file which was
X * packed using Huffman squeezing.
X * 
X * Most of this code is taken from an USQ program by Richard Greenlaw, which was
X * adapted to CI-C86 by Robert J. Beilstein.
X * 
X * Language: Computer Innovations Optimizing C86
X */
X#include <stdio.h>
X#include "arc.h"
X
Xvoid	abort();
Xint	getc_unp();
X
X/* stuff for Huffman unsqueezing */
X
X#define ERROR (-1)
X
X#define SPEOF 256		/* special endfile token */
X#define NUMVALS 257		/* 256 data values plus SPEOF */
X
Xextern	struct nd {		/* decoding tree */
X	int	child[2];	/* left, right */
X}               node[NUMVALS];	/* use large buffer */
X
Xstatic int      bpos;		/* last bit position read */
Xstatic int      curin;		/* last byte value read */
Xstatic int      numnodes;	/* number of nodes in decode tree */
X
Xstatic          short
Xget_int(f)			/* get a 16bit integer */
X	FILE           *f;	/* file to get it from */
X{
X	int	i,j;
X	i = getc_unp(f);
X	j = getc_unp(f) << 8;
X	return (i | j) & 0xFFFF;
X}
X
Xvoid
Xinit_usq(f)			/* initialize Huffman unsqueezing */
X	FILE           *f;	/* file containing squeezed data */
X{
X	int             i;	/* node index */
X
X	bpos = 99;		/* force initial read */
X
X	numnodes = get_int(f);
X
X	if (numnodes < 0 || numnodes >= NUMVALS)
X		abort("File has an invalid decode tree");
X
X	/* initialize for possible empty tree (SPEOF only) */
X
X	node[0].child[0] = -(SPEOF + 1);
X	node[0].child[1] = -(SPEOF + 1);
X
X	for (i = 0; i < numnodes; ++i) {	/* get decoding tree from
X						 * file */
X		node[i].child[0] = get_int(f);
X		node[i].child[1] = get_int(f);
X	}
X}
X
Xint
Xgetc_usq(f)			/* get byte from squeezed file */
X	FILE           *f;	/* file containing squeezed data */
X{
X	short             i;	/* tree index */
X
X	/* follow bit stream in tree to a leaf */
X
X	for (i = 0; i >= 0;) {	/* work down(up?) from root */
X		if (++bpos > 7) {
X			if ((curin = getc_unp(f)) == ERROR)
X				return (ERROR);
X			bpos = 0;
X
X			/* move a level deeper in tree */
X			i = node[i].child[1 & curin];
X		} else
X			i = node[i].child[1 & (curin >>= 1)];
X	}
X
X	/* decode fake node index to original data value */
X
X	i = -(i + 1);
X
X	/* decode special endfile token to normal EOF */
X
X	i = (i == SPEOF) ? EOF : i;
X	return i;
X}
SHAR_EOF
if test 2486 -ne "`wc -c < 'arcusq.c'`"
then
	echo shar: "error transmitting 'arcusq.c'" '(should have been 2486 characters)'
fi
fi
echo shar: "extracting 'getwd.c'" '(786 characters)'
if test -f 'getwd.c'
then
	echo shar: "will not over-write existing file 'getwd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getwd.c'
X/*
X * 4.2bsd getwd simulation for Sys V.3
X */
X
X#include <stdio.h>
X
X#undef SYSV3
X
X#define MAXWD 1024	     /* limited by 4.2 getwd(2) */
X
X#ifdef SYSV3
X
Xchar *getcwd();
X
Xchar *
Xgetwd(path)
Xchar *path;
X{
X    return(getcwd(path,MAXWD));
X}
X
X#else
X
X/*
X * 4.2bsd getwd simulation for Sys V.2
X */
X
X#include <stdio.h>
X
X#define MAXWD 1024	     /* limited by 4.2 getwd(2) */
X
Xchar *
Xgetwd(path)
Xchar *path;
X{
X     char *nlp;
X     FILE *fp;
X     FILE *popen();
X     char *strrchr();
X
X	putenv("IFS= \t\n");
X     fp = popen("PATH=/bin:/usr/bin pwd", "r");
X     if (fp == NULL)
X	     return 0;
X     if (fgets(path, MAXWD, fp) == NULL) {
X	     (void) pclose(fp);
X	     return 0;
X     }
X     if ((nlp = strrchr(path, '\n')) != NULL)
X	     *nlp = '\0';
X     (void) pclose(fp);
X     return path;
X}
X#endif
X
SHAR_EOF
if test 786 -ne "`wc -c < 'getwd.c'`"
then
	echo shar: "error transmitting 'getwd.c'" '(should have been 786 characters)'
fi
fi
exit 0
#	End of shell archive