#!/bin/sh
# This is ar2.shar, a shell archive (produced by GNU sharutils 4.6.3).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh12698
# Made on 2010-12-06 12:33 EST by <informix@galadriel-ii>.
# Source directory was `/home/art/SharedDocuments/iiug/ar2'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   5071 -rw-rw-rw- README.ar2
#  55779 -rw-rw-rw- ar2.c
#    394 -rw-rw-rw- ar2.mk
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
  echo 'Note: not verifying md5sums.  Consider installing GNU coreutils.'
echo=echo
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
     then shar_n= shar_c='
'
     else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
   test ! -f ${st1} && test -f ${f}; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
   test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
   test ! -f ${st3} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'

else
  shar_touch=:
  echo
  ${echo} 'WARNING: not restoring timestamps.  Consider getting and'
  ${echo} 'installing GNU `touch'\'', distributed in GNU coreutils...'
  echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir}
then : ; else ${echo} 'lock directory '${lock_dir}' exists'
  exit 1
fi
if mkdir ${lock_dir}
then ${echo} 'x - created lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to create lock directory `'${lock_dir}\''.'
  exit 1
fi
# ============= README.ar2 ==============
if test -f 'README.ar2' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING README.ar2 (file already exists)'
else
${echo} 'x - extracting README.ar2 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README.ar2' &&
README for utility: ar2
X
Author: Art S. Kagel, 1990
Version: Features version 1.4, Source revision 1.30
File(s): ar2.c, ar2.mk
X
Description:
X
Ar2 was written as a portable ar archiver at a time when GNU ar and GNU tar
were not available or not commonly available so that I could transport
collections of files from UNIX to DOS and back.  Later features were added to
allow me to transport between systems with incompatible versions of ar.  The
main incompatibilities arise from the different handling of long filenames
in BSD and System V derived versions.  BSD systems (notably Ultrix, OSF-1, and
AIX) extended the entry header format to be variable lenght to accomodate
longer names.  System V.4+ systems added a long names table at the beginning of
the file which contains an offset to the actual file entry which has a zero
length name in its actual header.  GNU ar is System V.4 compatible.
X
Ar2 can both read and write both BSD (-d) and System V (-g) formats although
it cannot append long filename files to an existing System V archive.  In
addition it supports a third long filename scheme of my own, implemented with
the '-i' flag, which is marginally portable to both the other systems.  An
archive created with '-i' can be extracted successfully with ANY ar utility
but the filenames will be truncated (with whatever name clashes that causes)
and a single bogus file named '!' will be left around.  On reading an archive
the header version is automatically detected.
X
Ar2 does not currently support the initial symbol table entry needed to
support object libraries (ar's primary use) and is intended for source file
transport ONLY.  (Although with the appropriate header option the resulting
library will not be incompatible with OS utilities used to add the symbol
table, ie "ar -s" or ranlib.)  Anyone who feels the need to add this
capability is welcome to do so and feedback the updates to me.
X
X
Important:
X
Note, when compiling, if you do not have getopt on your system simply define
the macro 'nooptarg' to enable another commandline parser built into the source.
X
Usage:
X
Since it was originally intended for extraction of archives created elsewhere
extraction is the default operation so that a line like:
X
ar2 arcfile.ar
X
will extract the contents of the archive named arcfile.ar.  My archive naming
convention is to use .ar or .ar2 (for -i archives) to distinguish source
archives from object libraries (lib*.a).
X
The following is the usage report printed by "ar -?" or just "ar":
> ar2
X
Copyright 1990 through 2011 inclusive
Art S. Kagel
222 Dunhams Corner Rd.
East Brunswick, N.J. 08816
X
X        Written by Art S. Kagel, August 1990.  Portable Version 1.6
X        RCS $Revision: 1.37 $
X        This program is placed in the public domain for private use only.
X        All commercial rights are retained.
X
Usage:          ./ar2 [-[qmrxtacle]] [-[dgi]] arcname [file1 [file 2 [...]]]
X
X    With no flags ./ar2 extracts files from a UNIX portable archive.
X
X        UNIX "ar" compatible flags (keys), as follows:
X        -q      Quick append.  Add file to end.
X                (This function will include duplicate copies of files.)
X        -m      Move file to archive and remove.
X                (This function will include duplicate copies of files.)
X        -r      Replace file.  Replace file in archive with another version.
X                (Current version replaces all occurances if the file is
X                multiply contained in the archive.)
X        -x      Extract files.
X        -t      List out contents of archive.
X
X        Additional (non-compatible) flags available:
X        -a      Append file.  Synonym for -q.
X        -e      Extract files.  Synonym for -x.
X        -l      List out files.  Synonym for -t.
X        -c      Create archive.  CREATE a NEW archive or OVERWRITE an existing
X                one!  (q, m, a, & r will also CREATE an archive if none exists.)
X
X        Compatibility options:
X        -d      Write archive with BSD compatible headers.  BSD ar handles
X                filenames longer than 14 characters by making the file
X                header variable length.
X        -g      Write archive with System V ar compatible Centralized
X                Extended Name table.  Permits names longer than 14 characters.
X                Long names cannot be appended to an existing archive in
X                this format.
X        -i      Write archive with Distributed Extended Name table.
X                Permits names longer than 14 characters.  This format extended
X                name table may be appended to.
X        -A      Write archive in AIX extended name small header format.  Does
X                not support files larger than 2GB.
X        -B      Write archive in AIX extended name large header format.
X
BSD, System V, and ar2 Extended format archives are recognized transparently
for listing and extraction.  The -d, -g, and -i options are provided to create
and update such archives.  Only one of these options may be provided.  If none
of -d, -g, -i is provided System V.4 compatibility is assumed.
X
X
SHAR_EOF
  (set 20 10 12 06 12 29 54 'README.ar2'; eval "$shar_touch") &&
  chmod 0666 'README.ar2'
if test $? -ne 0
then ${echo} 'restore of README.ar2 failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'README.ar2: MD5 check failed'
       ) << SHAR_EOF
0c816c88a36138a02adf8775d09af349  README.ar2
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'README.ar2'` -ne 5071 && \
  ${echo} 'restoration warning:  size of README.ar2 is not 5071'
  fi
fi
# ============= ar2.c ==============
if test -f 'ar2.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING ar2.c (file already exists)'
else
${echo} 'x - extracting ar2.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ar2.c' &&
/*
ar2_port.c - portable ar archive utility.
X
RCS Header
----------
$Id: ar2_port.c,v 1.37 2009/07/13 14:25:59 art Exp $
X
RCS Log
-------
$Log: ar2_port.c,v $
Revision 1.37  2009/07/13 14:25:59  art
Fixed typo, misplaced # endif.
X
Revision 1.36  2009/07/13 02:05:46  art
Incorporated updates to make this compatible with Windows 32bit.  May be OK
in Win64 as well, but haven't tested yet.  Thanks to Juan Jose Rodriguez for the patches.
X
Revision 1.35  2006/08/28 22:16:56  kagel
Portability and formatting changes.
X
Revision 1.34  2004/12/22 21:14:18  kagel
CHecking in latest with AIX archive support and remove some library
function name clashes.
X
Revision 1.33  2003/12/04 19:09:01  kagel
Portability fixes.
X
X * Revision 1.32  2002/06/12  13:28:54  13:28:54  kagel
X * Fixed some prototype complaints.
X * 
Revision 1.31  1999/10/12 18:14:50  kagel
Initial insert was actually r1.31.  Log message should be:
Completed '-d' BSD/Ultrix support to be able to write longfilenames to
BSD format files instead of truncating the names.
X
X * Revision 1.30  1999/10/11  15:49:30  kagel
X * Fixed core dump if run without args.
X * Fixed several warnings, now compiles cleanly.
X *
X * Revision 1.29  1993/07/29  19:51:52  kagel
X * Added RCS headers.
X *
X * Revision 1.28  1993/07/28  18:18:38  kagel
X * Fixed #defines protecting DOS specific code.
X *
X * Revision 1.28  1993/07/28  18:18:38  kagel
X * Fixed #defines protecting DOS specific code.
X *
X * Revision 1.27  1993/07/28  18:08:06  kagel
X * cd test
X * Bug.
X *
X * Revision 1.26  1993/07/28  18:02:00  kagel
X * Added support to extract files to the BEST filename possible under DOS.
X * Will tak 1st 8 chars and 3 from any extension.
X *
X * Revision 1.25  1993/07/28  16:54:39  kagel
X * Fixed bug in ar_verify for DG style central string table handling
X *
X * Revision 1.24  1993/07/28  14:42:42  kagel
X * Bug in read_header().
X *
X * Revision 1.23  1993/07/28  14:19:04  kagel
X * Fixed bug in read_header affecting repl_ar()
X *
X * Revision 1.22  1993/07/28  13:01:34  kagel
X * Extracted common code to read and parse archive headers to a function.
X *
X * Revision 1.21  1993/07/22  18:49:16  kagel
X * Added proper messages for bad filenames and nonexistent files.
X *
X * Revision 1.20  1993/07/22  18:36:25  kagel
X * Made -d  -g  -i mutually exclusive.  Added to usage to better explain these
X * options.
X *
X * Revision 1.19  1993/07/22  18:24:57  kagel
X * Just fixing the usage strings.
X *
X * Revision 1.18  1993/07/12  13:30:56  kagel
X * Added compatibility with DEC ar format.  Implemented -d flag for creation/
X * appending/replacing files in archives.  Also implemented listing and
X * extracting of DEC format archives with automatic recognition.  When creating
X * DEC format archives, names are truncated to 14 characters, long names are,
X * however, handled properly when found on listing or extracting.
X *
X * Revision 1.17  1993/07/12  12:18:46  kagel
X * Modified Log Message - ASK -
X * Sorry the bug mentioned in Rev 1.14 was mine not theirs.  I have fixed this.
X * Though I'm not certain what was wrong.
X *
X * Revision 1.16  1993/07/12  12:02:36  kagel
X * Fixed bug in -g option which would write out a null string table.  This
X * confused ar2 and DG/UX-ar.
X *
X * Revision 1.15  1993/07/12  11:52:20  kagel
X * *** empty log message ***
X *
X * Revision 1.14  1993/07/12  11:46:39  kagel
X * Added code to support a DG/UX ar bug which fails to end a 14 character name
X * with the required slash.  The DG/UX ar utility expects this lack when reading
X * archives and truncates terminated names of exactly 14 chars. to zero length.
X *
X * Revision 1.13  1993/07/08  20:29:42  kagel
X * Changed mode string in the string table entries to eliminate spurious error
X * messages from older ar utilities during extraction.  The file named "!"
X * will now contain the full name of the last extended name file extracted.
X * All hail compatibility and portability!
X *
X * Revision 1.12  1993/07/08  20:20:48  kagel
X * Modified the header format for extended file name entries to provide
X * backward compatibility with older ar utilities.  An ar2 format archive may
X * be read and even extracted by standard ar.  Listings will contain files
X * named "!" which represent the string table entries.  Extraction will succeed
X * but, will leave one "!" file around, probably the first.
X *
X * Revision 1.11  1993/07/08  19:45:22  kagel
X * Added list, extract and replace support for DG/UX format extended filename
X * string tables.  This is a central table of long file names.  Such a central
X * table cannot be extended without rewriting the entire archive which is
X * against the philosophy of this program.  Ar2 can, however, create such
X * archives from scratch as well as list, extract and replace their contents.
X *
X * Also added my own version of extended file names.  The '-i' flag (for index)
X * adds a string table like entry before the actual file header for any file
X * with an oversized (>14 chars) name.  This "Distributed" string table can be
X * easily appended to.  This format supports filenames up to 255 characters
X * and supports listing, extraction, creation, replacement and appending
X * operations.  In the next release I will attempt to make this transparent to
X * traditional ar utilities.
X *
X * Revision 1.10  1993/07/07  14:21:37  kagel
X * fix
X *
X * Revision 1.9  1993/07/07  14:15:27  kagel
X * *** empty log message ***
X *
X * Revision 1.8  1993/07/07  14:13:37  kagel
X * *** empty log message ***
X *
X * Revision 1.7  1993/07/07  14:11:55  kagel
X * Reformatted code to fit 80 cols and broke long strings using string pasting.
X *
X * Revision 1.6  1993/07/07  13:48:30  kagel
X * Changed to use optarg.
X *
X * Revision 1.5  1993/07/07  13:43:37  kagel
X * *** empty log message ***
X *
X * Revision 1.4  1993/07/07  13:38:33  kagel
X * Formatting.
X *
X * Revision 1.3  1993/07/07  12:54:12  kagel
X * Implemented ability to read and list an archive with an extended file name
X * string table.  Set up to write and update but not fully implemented.
X *
X * Revision 1.2  1993/07/06  19:44:45  kagel
X * Added RCS Header and Log
X *
03/1993 - ASK Modified to handle D.E.C. Ultrix format headers.  These are
X	missing the slash trailing the filename and may contain oversize
X	filenames in place.  DEC archives handled with an option.
2/10/1993 - ASK Modified to handle long filenames (mostly under BSD) by 
X	truncating to 14 characters with a warning.
*/
#include <sys/types.h>
#include <sys/stat.h>
#if defined(WIN32)
#include <errno.h>
#include <sys/utime.h>
#else
#include <sys/errno.h>
#endif
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <search.h>
#include <stdlib.h>
#include <limits.h>
X
#if defined(__TURBOC__) || defined(WIN32)
#include <io.h>
#else
#include <malloc.h>
#include <utime.h>
#endif
#include <time.h>
X
#if !defined(__STDC__) && !defined(_MSC_VER)
#define void  
#endif
X
#if !defined( __unix__ )
#define nooptarg
#else
#include <unistd.h>
#endif
X
/* Defines */
#define ARMAG   "!<arch>\n"
#define AIXBIGMAG  "<bigaf>\n"
#define AIXSMLMAG  "<aiaff>\n"
#define SARMAG  8
#define ARFMAG  "`\n"
#define MYBUFSIZE 32768
#define AR2_FALSE (0)
#define AR2_TRUE (!AR2_FALSE)
#define OPEN AR2_TRUE
#define CLOSED AR2_FALSE
#ifdef __MSDOS__
#define DIRSEP '\\'
#else
#define DIRSEP '/'
#endif
#if !defined( SEEK_SET )
#define SEEK_SET 0
#endif
#if !defined( SEEK_CUR )
#define SEEK_CUR 1
#endif
#if !defined( SEEK_END )
#define SEEK_END 2
#endif
#if !defined(WIN32) && !defined(O_BINARY)
#define O_BINARY 0    /* Not needed nor normally defined in UNIX */
#endif
X
/* Process States */
#if defined( noenum )
#define INITIAL       0
#define EXIT          1
#define EXTRACT       2
#define CREATE        4
#define APPEND        8
#define BUILD        16
#define FINISHED     32
#define LISTING      64
#define REPLACE     128
X
#define StateList int;
X
/* File format list */
X
#define Naming int
X
#else
enum statelist {
X    INITIAL  = 0,
X    EXIT     = 1,
X    EXTRACT  = 2,
X    CREATE   = 4,
X    APPEND   = 8,
X    BUILD    = 16,
X    FINISHED = 32,
X    LISTING  = 64,
X    REPLACE  = 128
};
X
typedef enum statelist StateList;
X
/* Naming table list */
/* #define TRUNCATE	0 */
/* #define CENTRAL		1 */
/* #define DISTRIBUTE	2 */
/* #define AIXSMALL        3 */
/* #define AIXBIG          4 */
enum naming {
X    TRUNCATE	= 0, /* Old System V.3 Format (defunct). */
X    CENTRAL	= 1, /* System V.4 Format. */
X    DISTRIBUTE	= 2, /* Myextended format. */
X    AIXSMALL    = 3, /* AIX small header format. */
X    AIXBIG      = 4, /* AIX larger header format. */
X    ULTRIX      = 5, /* DEC Ultrix format (defunct) & BSD 4.x. */
X    DEFAULT     = 999
};
X
typedef enum naming Naming;
typedef enum format Format;
#endif
X
/* Process Control Flags */
#define NORMAL  0
#define UNLINK  1
#define NOFLAGS 2
X
/* Structure Definitions */
typedef struct INTERNAL_HDR {
X    char member_name[257];
X    char member_path[1025];
X    time_t modtime;
X    int uid, gid, mode;
X    long long member_size;
} internal_hdr;
X
/* Standard UNIX member header. */
typedef struct AR_HDR {
X    char    ar_name[16];    /* file member name - '/' terminated    */
X    char    ar_date[12];    /* file member date - decimal           */
X    char    ar_uid[6];      /* file member user id - decimal        */
X    char    ar_gid[6];      /* file member group id - decimal       */
X    char    ar_mode[8];     /* file member mode - octal             */
X    char    ar_size[10];    /* file member size - decimal           */
X    char    ar_fmag[2];     /* ARFMAG - string to end header        */
X    char    nullchar;       /* NULL char bucket for fgets to use    */
} ar_hdr;
X
/* AIX Small Format Archive Member Header. */
typedef struct AIX_SMALL_MEMHDR {
X    char ar_size[12];		/* file member size */
X    char ar_nxtmem[12];		/* next member header offset */
X    char ar_prvmem[12];		/* previous member header offset */
X    char ar_date[12];		/* file member date */
X    char ar_uid[12];		/* file member user id */
X    char ar_gid[12];		/* file member group id */
X    char ar_mode[12];		/* file member mode - Octal! */
X    char ar_namelen[4];		/* length of member name (< 255 ) */
X    char ar_name[1];		/* beginning of member name */
} aix_small_memhdr;
X
/* AIX Big Format Archive Member Header. */
typedef struct AIX_BIG_MEMHDR {
X    char ar_size[20];		/* file member size */
X    char ar_nxtmem[20];		/* next member header offset */
X    char ar_prvmem[20];		/* previous member header offset */
X    char ar_date[12];		/* file member date */
X    char ar_uid[12];		/* file member user id */
X    char ar_gid[12];		/* file member group id */
X    char ar_mode[12];		/* file member mode - Octal! */
X    char ar_namelen[4];		/* length of member name (< 255 ) */
X    char ar_name[1];		/* beginning of member name */
} aix_big_memhdr;
X
/* AIX Small Format Archive Header. */
typedef struct AIX_SMALL_ARCHDR {
X    char fl_memoff[12];		/* Offset to trailing member table. */
X    char fl_gstoff[12];		/* Offset to symbol table - zero if none/stripped */
X    char fl_fstmoff[12];	/* Offset to first member */
X    char fl_lstmoff[12];	/* Offset to last member */
X    char fl_freeoff[12];	/* Offset to first deleted member - zero if none */
} aix_small_archdr;
X
/* AIX Big Format Archive Header. */
typedef struct AIX_BIG_ARCHDR {
X    char fl_memoff[20];		/* Offset to trailing member table. */
X    char fl_gstoff[20];		/* Offset to 32bit symbol table - zero if none/stripped */
X    char fl_gst64off[20];	/* Offset to 64bit symbol table - zero if none/stripped */
X    char fl_fstmoff[20];	/* Offset to first member */
X    char fl_lstmoff[20];	/* Offset to last member */
X    char fl_freeoff[20];	/* Offset to first deleted member - zero if none */
} aix_big_archdr;
X
/* Forward Reference Declarations */
void usage( char * );
unsigned otoi();
char *ar2_ltoa();
int renameit();
int read_ar();
int list_ar();
int repl_ar();
FILE *create_arc();
int write_file();
int ar_verify();
void rewrite_strings( FILE *, int, int, char ** );
int read_header( ar_hdr *, char *, FILE *, long * );
X
/* Globals - ARGHH (Much as I dislike them!) */
char RCSID[] = "$Id: ar2_port.c,v 1.37 2009/07/13 14:25:59 art Exp $";
int Flag = NORMAL;
extern int errno;
int Native = AR2_FALSE;
int DECFlag = AR2_FALSE;
int TableSize;
Naming Extended = DEFAULT;
char *NameTable = (char *)NULL;
X
/* N.B. - Copyright notice in copyright[] MUST be displayed to satisfy	*/
/*	requirements of U.S. Copyright law and the specifics of the	*/
/*	public domain release of this product.  In addition the 	*/
/*	release requires that users 1) Make no commercial sale of this	*/
/*	program or any program derived from its source.  2) Forward any	*/
/*	modifications, in the form of complete source listings or file	*/
/*	in human or machine readable format to: AR2 Mods c/o Art S. 	*/
/*	Kagel at 222 Dunham's Corner Road, E. Brunswick, NJ 08816-3414;	*/
/*	for consideration for future releases.  Single user 		*/
/*	installations may refrain from displaying the notice at run	*/
/*	time, however it must remain in an array variable included	*/
/*	in the executable program.					*/
X
char copyright[] =  "\nCopyright 1990 through 2011 inclusive\n"
"Art S. Kagel\n222 Dunhams Corner Rd.\n"
"East Brunswick, N.J. 08816\n";
char attribution[] ="\n\tWritten by Art S. Kagel, August 1990.  "
"Portable Version 1.6\n\tRCS $Revision: 1.37 $\n\t"
"This program is placed in the public domain for private use only."
"\n\tAll commercial rights are retained.\n";
X
X
X
/*
X    Main program function.  Parse args and drive functionality.
*/
int main( argc, argv )
X    int argc;
X    char **argv;
{
X    FILE *out_arc, *in_arc;
X    int  i, fdesc, j, ar_arg, FileStatus, k, GotCommand = AR2_FALSE;
X    StateList state;
X    char activity[20], temp_name[100];
X    int arg_chr;
X    struct stat fstats;
X    
X    state = INITIAL;
X    FileStatus = CLOSED;
X    if (argc == 2) {
X        Flag = NOFLAGS;
X        state = EXTRACT;
X    } else if (argc < 3) {
X        usage( argv[0] );
X        state = FINISHED;
X	exit(1);
X    } else {
X        k = 1;
#if defined( nooptarg )
X        while (argv[k][0] == '-' && k < argc) {
X	    arg_chr = argv[k][1];
#else
X	    while ((arg_chr = getopt( argc, argv, "acdegilmqrtxAB" )) != EOF) {
#endif
X		switch (arg_chr) {
X		case 'a':
X		case 'q':
X		    /* Append to existing archive by default */
X		    state = APPEND;
X		    strcpy( activity, "a -" );
X		    GotCommand = AR2_TRUE;
X		    break;
X		case 'c':
X		    /* Create new archive */
X		    if (state != INITIAL)
X			goto defcas;
X		    state = CREATE;
X		    strcpy( activity, "a -" );
X		    GotCommand = AR2_TRUE;
X		    break;
X		case 'd':
X		    /* Digital ULTRIX compatibility flag.  ULTRIX ar does not */
X		    /* conform to the ar standard in at least one way: file  */
X		    /* names are NOT terminated with a trailing slash!        */
X		    /* Currently no-op!                                       */
X		    if (Extended != DEFAULT && Extended != TRUNCATE) {
X			fprintf( stderr, "Only one of -i -g -d -A -B permitted.\n\n" );
X			usage( argv[0] );
X			return 22;
X		    }
X		    Extended = TRUNCATE;
X		    DECFlag = AR2_TRUE;
X		    break;
X		case 'e':
X		case 'x':
X		    /* Extract from existing archive */
X		    if (state != INITIAL)
X			goto defcas;
X		    state = EXTRACT;
X		    strcpy( activity, "x -" );
X		    GotCommand = AR2_TRUE;
X		    break;
X		case 'i':
X		    /* Write extended name archive with distributed string table.
X		       This differs from the centralized string table implied by
X		       the "-g" option and implemented in System V.  This is my own
X		       implementation of extended filenames.  It places the single
X		       entry string table immediately before the related file's
X		       header.  This has the advantage that the archive can be
X		       appended to without rewriting the file and reconstructing
X		       the string table for each file added.  Reading of archives
X		       so extended is automatic. */
X		    if (Extended != DEFAULT && Extended != DISTRIBUTE) {
X			fprintf( stderr, "Only one of -i -g -d -A -B permitted.\n\n" );
X			usage( argv[0] );
X			return 22;
X		    }
X		    Extended = DISTRIBUTE;
X		    break;
X		case 'l':
X		case 't':
X		    /* List contents of an archive */
X		    if (state != INITIAL)
X			goto defcas;
X		    state = LISTING;
X		    GotCommand = AR2_TRUE;
X		    break;
X		case 'r':
X		    if (state != INITIAL)
X			goto defcas;
X		    state = REPLACE;
X		    Flag = REPLACE;
X		    strcpy( activity, "r -" );
X		    GotCommand = AR2_TRUE;
X		    break;
X		case 'B':
X		    /* Write handle archive in IBM AIX Big file format. */
X		    /* Header points to a double linked list of members and
X		       to a trailing member table, deleted member table and
X		       symbol table any of which can be empty.
X		       */
X		    if (Extended != DEFAULT && Extended != AIXBIG) {
X			fprintf( stderr, "Only one of -i -g -d -A -B permitted.\n\n" );
X			usage( argv[0] );
X			return 22;
X		    }
X		    Extended = AIXBIG;
X		    break;
X		case 'A':
X		    /* Write handle archive in IBM AIX Small file format. */
X		    /* Header points to a double linked list of members and
X		       to a trailing member table, deleted member table and
X		       symbol table any of which can be empty.
X		       */
X		    if (Extended != DEFAULT && Extended != AIXSMALL) {
X			fprintf( stderr, "Only one of -i -g -d -A -B permitted.\n\n" );
X			usage( argv[0] );
X			return 22;
X		    }
X		    Extended = AIXSMALL;
X		    break;
X		case 'm':
X		    /* Move file into archive and unlink */
X		    Flag = UNLINK;
X		    break;
X		case 'g':
X		    /* Write handle archive with extended file name string table */
X		    /* This is used by System V to handle long file names in an  */
X		    /* ar archive.  Format is similar to the symbol table file.  */
X		    /* Reading of extended file name archives is automatic!      */
X		    /* If this flag is left off, all filenames will be truncated */
X		    /* to 14 characters, the System V.3 standard.                */
X		    if (Extended != DEFAULT && Extended != CENTRAL) {
X			fprintf( stderr, "Only one of -i -g -d -A -B permitted.\n\n" );
X			usage( argv[0] );
X			return 22;
X		    }
X		    Extended = CENTRAL;
X		    break;
X		defcas:
X		default:
X		    usage( argv[0] );
X		    state = FINISHED;
X		}
#if defined( nooptarg )
X		k++;
#endif
X	    }
#if !defined( nooptarg )
X	    k = optind;
#endif
X	    if (Extended == DEFAULT)
X		Extended = CENTRAL;   /* Default to System V.4 standard.  Used to be TRUNCATE. */
X
X	    if (k == 1 && state == INITIAL) {
X		state = EXTRACT;
X		Flag = NOFLAGS;
X	    } else if (state == EXTRACT && Flag == UNLINK)
X		Flag = NOFLAGS;
X	    else if (state == INITIAL && Flag == UNLINK)
X		state = APPEND;
X	    else if (state == REPLACE && k >= argc - 1) {
X		fprintf( stderr, "Nothing to REPLACE!\n" );
X		usage( argv[0] );
X		state = FINISHED;
X	    }
X	}
X	/* Open the archive file properly for each mode and verify */
X	if (Flag == NOFLAGS)
X	    ar_arg = 1;
X	else
X	    ar_arg = k;
X	if (Flag == UNLINK)
X	    strcpy( activity, "m -" );
X	if (state == APPEND) {
X            /* Open existing archive for append */
X	    fdesc = open( argv[ar_arg], O_RDWR | O_APPEND | O_BINARY );
X	    if (fdesc == -1 && errno == ENOENT) {
X		errno = 0;
X		fprintf( stderr, "Archive not found, creating!\n" );
X		state = CREATE;
X	    } else {
X		out_arc = fdopen( fdesc, "ab+" );
X		state = BUILD;
X		FileStatus = OPEN;
X	    }
X	}
X	if (state == EXTRACT || state == LISTING) {
X	    fdesc = open( argv[ar_arg], O_RDONLY | O_BINARY );
X	    if (fdesc == -1 && errno == ENOENT) {
X		errno = 0;
X		fprintf( stderr, "Archive not found!  Cannot " );
X		if (state == EXTRACT)
X		    fprintf( stderr, "extract.\n" );
X		else
X		    fprintf( stderr, "list out.\n" );
X		state = EXIT;
X	    } else {
X		out_arc = fdopen( fdesc, "rb" );
X		FileStatus = OPEN;
X	    }
X	}
X    
X	if (state == CREATE) {
X            /* Make File & Initialize Header Block */
X	    out_arc = create_arc( argv[ar_arg] );
X	    if (out_arc == (FILE *)NULL) {
X		state = EXIT;
X		fprintf( stderr, "Cannot create archive file: %s\n", 
X			 argv[ar_arg] );
X	    } else
X		state = BUILD;
X	} else if (state == REPLACE) {
X	    /* Move old archive to temporary name */
X	    temp_name[0] = (char)0;     /* NULL target filename creates a temp */
X	    if (renameit( argv[ar_arg], temp_name ) != 0) {
X		state = EXIT;
X		fprintf( stderr,
X			 "Cannot rename original archive file! Aborting.\n" );
X	    }
X	    if (state != EXIT) {
X		in_arc = fopen( temp_name, "rb" );
X		if (in_arc == (FILE *)NULL) {
X		    state = EXIT;
X		    fprintf( stderr,
X			     "Cannot open original archive file. Aborting.\n" );
X		    unlink( temp_name );
X		} else {
X		    j = ar_verify( in_arc );
X		    switch (j) {
X                    case 0:
X                        break;
X                    case -1:
X                        fprintf( stderr,
X				 "Cannot read archive file.  Aborting.\n" );
X                        renameit( temp_name, argv[ar_arg] );
X                        state = EXIT;
X                        break;
X                    case -2:
X                        fprintf( stderr,
X				 "%s not an \"ar\" UNIX archive file or not expected type. "
X				 " Aborting.\n",
X				 argv[ar_arg] );
X                        renameit( temp_name, argv[ar_arg] );
X                        state = EXIT;
X                        break;
X                    case -3:
X                        fprintf( stderr,
X				 "%s is an object library. "
X				 " Object Libraries are not supported.\n",
X				 argv[ar_arg] );
X                        renameit( temp_name, argv[ar_arg] );
X                        state = EXIT;
X                        break;
X                    default:
X                        fprintf( stderr,
X				 "Unknown error code returned.  Aborting.\n" );
X                        renameit( temp_name, argv[ar_arg] );
X                        state = EXIT;
X                        break;
X		    }
X		}
X	    }
X	    if (state != EXIT) {
X                /* Make New File & Initialize Header Block */
X		out_arc = create_arc( argv[ar_arg] );
X		if (out_arc == (FILE *)NULL) {
X		    state = EXIT;
X		    fprintf( stderr, "Cannot create new archive file: %s\n", 
X			     argv[ar_arg] );
X		    unlink( argv[ar_arg] );
X		    renameit( temp_name, argv[ar_arg] );
X		}
X	    }
X	} else if (state != EXIT && state != FINISHED) {
X	    j = ar_verify( out_arc );
X	    switch (j) {
X            case 0:
X                /* Header verified */
X                break;
X            case -1:
X                fprintf( stderr, "Cannot read archive file.  Aborting.\n" );
X                state = EXIT;
X                break;
X            case -2:
X                fprintf( stderr,
X			 "%s not a \"ar\" UNIX archive file.  Aborting.\n",
X			 argv[ar_arg] );
X                state = EXIT;
X                break;
X            case -3:
X                fprintf( stderr,
X			 "%s is an object library. "
X			 " Object Libraries are not supported.\n",
X			 argv[ar_arg] );
X                state = EXIT;
X                break;
X            default:
X                fprintf( stderr, "Unknown error code returned.  Aborting.\n" );
X                state = EXIT;
X                break;
X	    }
X	}
X    
X	if (state == EXTRACT) {
X	    if (read_ar( argc, argv, ar_arg, out_arc ))
X		state = EXIT;
X	} else if (state == LISTING) {
X	    if (list_ar( argc, argv, ar_arg, out_arc ))
X		state = EXIT;
X	} else if (state == REPLACE) {
X	    if (Extended == CENTRAL) {
X		/* Re-write the string table including the new file names. */
X		rewrite_strings( out_arc, ar_arg, argc, argv );
X	    }
X	    if (repl_ar( argc, argv, ar_arg, out_arc, in_arc ) != 0) {
X		unlink( argv[ar_arg] );
X		renameit( temp_name, argv[ar_arg] );
X		state = EXIT;
X	    } else
X		unlink( temp_name );
X	} else if (state == BUILD) {
X	    if (Extended == CENTRAL) {
X		/* Re-write the string table including the new file names. */
X		rewrite_strings( out_arc, ar_arg, argc, argv );
X	    }
X	    /* For each file, write file and file header */
X	    i = ar_arg;
X	    while (++i < argc) {  /* Actually for each argument */
X		errno = 0;
X	    
X		/* Only insert ordinary files. */
X		if (stat( argv[i], &fstats ) == -1) {
X		    switch (errno) {
X		    case ENOENT:
X		    case ENOTDIR:
X			fprintf( stderr,
X				 "File <%s> not found.  Ignoring!\n",
X				 argv[i] );
X			break;
X		    case ENAMETOOLONG:
X		    case EPERM:
X			fprintf( stderr,
X				 "File name <%s> is invalid.  Ignoring!\n",
X				 argv[i] );
X			break;
#if defined(ELOOP)
X		    case ELOOP:
X			fprintf( stderr,
X				 "Cannot resolve file <%s>, link loop suspected."
X				 "  Ignoring!\n",
X				 argv[i] );
X			break;	
#endif
X	    
X		    }
X		    continue;
X		} else if ((fstats.st_mode & S_IFREG)) {
X		    /* Cannot copy archive into itself! */
X		    if (strcmp(argv[i], argv[ar_arg])) {
X			fprintf( stdout, "%s %s\n", activity, argv[i] );
X			if ((j = write_file(out_arc, (FILE *)NULL, argv[i]))== -1) {
X			    fprintf( stderr,
X				     "\tError writing to archive!  Aborting.\n" );
X			    state = EXIT;
X			    break;
X			} else if (j == -2) {
X			    fprintf( stderr, "\tError reading file!  Aborting.\n" );
X			    state = EXIT;
X			    break;
X			}
X		    }
X		} else {
X		    fprintf( stderr,
X			     "File <%s> is not an ordinary file.  Ignoring!\n",
X			     argv[i] );
X		    continue;
X		}
X		state = FINISHED;
X	    }
X	}
X	if (FileStatus == OPEN) {
X	    fflush( out_arc );
X	    fclose( out_arc );
X	}
X	if (state == EXIT) {
X	    if (Flag == UNLINK)
X		fprintf( stderr,
X			 "\tSuccessfully written files have been "
X			 "moved into the archive.\n\n" );
X	    else if (Flag == REPLACE)
X		fprintf( stderr, "\tOriginal archive has been restored.\n" );
X	    return 10;
X	} else
X	    return 0;
X    }
X    
X
X    void getmagicnumber( magic2 )
X	char *magic2;
X    {
X	switch (Extended) {
X	case AIXBIG:
X	    strcpy( magic2, AIXBIGMAG );
X	    break;
X	case AIXSMALL:
X	    strcpy( magic2, AIXSMLMAG );
X	    break;
X	default:
X	    strcpy( magic2, ARMAG );
X	    break;
X	}
X    }
X
/*
X    Verify that a named file is a valid portable "ar" format archive file.
*/
X    int ar_verify( arch_file )
X	FILE *arch_file;
X    {
X	char magic[SARMAG + 1], magic2[SARMAG + 1];
X	ar_hdr header;
X
X	getmagicnumber( magic2 );
X	/* Seek to begining of file, if appending, file is positioned at end. */
X	rewind( arch_file );
X    
X	/* Check for readability.  Read ar archive magic header. */
X	if (fgets( magic, sizeof magic, arch_file ) == (char *)NULL)
X	    return(-1);
X
X	/* Verify ar magic header. */
X	if (strcmp( magic, magic2 ))
X	    return(-2);
X
X	/* Verify that the first file is not a symbol table */
X	fgets( (char *)&header, sizeof header, arch_file );
X	if (header.ar_name[0] == '/' && header.ar_name[1] == ' ')
X	    return(-3);
X	else if (header.ar_name[0] == '/' && header.ar_name[1] == '/') {
X	    /* Extended filename string table found.
X	       Read the table now and access from memory later. */
X
X	    TableSize = atoi( header.ar_size );
X	
X	    fprintf( stderr,
X		     "Archive contains extended file names. "
X		     " Reading name table.\n\n" );
X	    NameTable = (char *)malloc( TableSize + 2 );
X	    memset( NameTable, 0, TableSize + 2 );
X	    fread( NameTable, TableSize, 1, arch_file );
X	    strtok( NameTable, "/\n" );
X	    TableSize += 2;
X	    /* Replace slashes and NL with NULLs for later. */
X	    while (strtok( (char *)NULL, "/\n" ));
X	    /* Position file after string table pad char if any. */
X	    if (atoi( header.ar_size ) % 2)
X		fseek( arch_file, 1, SEEK_CUR );
X	} else {
X	    /* Reposition file after archive header.  Irrelevant on append. */
X	    fseek( arch_file, SARMAG, SEEK_SET );
X	}
X
X	/* Should probably verify System V -vs- ULTRIX header format here. */
X
X	return(0);
X    }
X    
X
/*
X    Extract files from a portable "ar" format archive file.
*/
X    int read_ar( argc, argv, cur_arg, arch_file )
X	int argc;
X    char **argv;
X    FILE *arch_file;
X    int cur_arg;
X    {
X	FILE    *out_file;
X	ar_hdr  out_hdr;
X	long    byte_count = 0, arch_size, out_size, i;
X	time_t  out_date;
X	unsigned short out_mode;
X	char    filename[257], tempstr[100], *file_list, *InList;
X	int     next_arg, ch, NFiles, Compare, WriteIt;
X	struct stat arch_stat;
X
#if defined(__TURBOC__)
X	struct ftime filetime;
X	struct tm *loctime;
#else
X	struct utimbuf filetime;
#endif
X   
X	if (argc > cur_arg + 1) {   /* Selective extract */
X	    Compare = AR2_TRUE;
X	    i = NFiles = argc - (cur_arg + 1);
X	    next_arg = cur_arg + 1;
X	    file_list = (char *)malloc( (NFiles + 1) * 257 );
X	    /* Build a list of files to extract */
X	    while (i)
X		strcpy( &file_list[257 * (NFiles - i--)], argv[next_arg++] );
X	} else {
X	    Compare = AR2_FALSE;
X	    NFiles = 0;
X	}
X	stat( argv[cur_arg], &arch_stat );
X	arch_size = arch_stat.st_size;
X	byte_count = ftell( arch_file );
X	do {
X	    if (fgets((char *)&out_hdr, sizeof(ar_hdr), arch_file) == (char *)NULL)
X	    {
X		/* No more headers.  We're finished */
X		break;
X	    }
X	    byte_count += strlen( (char *)&out_hdr );
X	    if (read_header( &out_hdr, filename, arch_file, &byte_count ) == -1)
X		break;   /* Finished, no more headers. */
X	    if (Compare)
X		InList = (char *)lfind( filename,
X					file_list,
X					(size_t *)&NFiles,
X					257,
X					(int(*)( const void *, const void *))strcmp );
X	    if (!Compare || (Compare && InList != (char *)NULL)) {
X		WriteIt = AR2_TRUE;
#	if defined (__MSDOS__) || defined(DOSTEST)
X		/* Make the BEST DOS compatible filename we can! */
X		memset( DOSname, 0, 13 );
X		j = 0;
X		for (k=0; k<8; k++)
X		    if (filename[k] && filename[k] != '.')
X			DOSname[j++] = filename[k];
X		    else
X			break;
X		DOSname[j++] = '.';
X		if (filename[k]) {
X		    p = strchr( filename, '.' );
X		    if (p++)
X			strncpy( &DOSname[j], p, 3 );
X		    else
X			strncpy( &DOSname[j], &filename[k], 3 );
X		}
X		out_file = fopen( DOSname, "wb" );
#	else	    
X		out_file = fopen( filename, "wb" );
#	endif
X		if (out_file == (FILE *)NULL) {
X		    fprintf( stderr,
X			     "Cannot open <%s> for writing.  Errno = %d.\n",
X			     filename,
X			     errno );
X		    exit( errno );
X		}
#	if defined (__MSDOS__) || defined (DOSTEST)
X		fprintf( stdout, "x - %s => %s\n", filename, DOSname );
#	else	    
X		fprintf( stdout, "x - %s\n", filename );
#	endif
X	    } else 
X		WriteIt = AR2_FALSE;
X
X	    strncpy( tempstr, out_hdr.ar_size, sizeof out_hdr.ar_size );
X	    tempstr[sizeof out_hdr.ar_size] = '\0';
X	    out_size = atol( tempstr );
X	    if (WriteIt) {
X		strncpy( tempstr, out_hdr.ar_date, sizeof out_hdr.ar_date );
X		tempstr[sizeof out_hdr.ar_date] = '\0';
X		out_date = atol( tempstr );
#if defined(__TURBOC__)
X		loctime = localtime( &out_date );
X		filetime.ft_year        = loctime->tm_year - 80;
X		filetime.ft_month       = loctime->tm_mon;
X		filetime.ft_day         = loctime->tm_mday;
X		filetime.ft_hour        = loctime->tm_hour;
X		filetime.ft_min         = loctime->tm_min;
X		filetime.ft_tsec        = loctime->tm_sec / 2;
#else
X		filetime.actime = filetime.modtime = out_date;
#endif
X    
X		strncpy( tempstr, out_hdr.ar_mode, sizeof out_hdr.ar_mode );
X		tempstr[sizeof out_hdr.ar_mode] = '\0';
X		out_mode = (unsigned short)otoi( tempstr );
X            
X		for (i = 0; i < out_size; i++) {
X		    if ((ch = getc( arch_file )) < 0) {
X			fprintf( stderr,
X				 "Unexpected End of File found.  Error %d.\n",
X				 ch );
X			return(9);
X		    }
X		    if (putc( ch, out_file ) < 0) {
X			fprintf( stderr,
X				 "Error writing output.  Error %d.\n",
X				 ch );
X			return(8);
X		    }
X		    byte_count++;
X		}
X		if (out_size % 2 == 1) {
X		    if ((ch = getc( arch_file )) < 0) {
X			fprintf( stderr,  "Unexpected End of File found.\n" );
X			return(-1);
X		    } else if (ch != '\n') {
X			fprintf( stderr, "File alignment character expected!\n" );
X			return(-1);
X		    }
X		    byte_count++;
X		}
#if defined(__TURBOC__)
X		setftime( fileno( out_file ), &filetime );
X		fclose( out_file );
#else
X		fclose( out_file );
X		utime( filename, &filetime );
#endif
#if !defined(WIN32)
X		chmod( filename, out_mode );
#endif
X	    } else {
X		if (out_size % 2)
X		    out_size++;
X		fseek( arch_file, out_size, SEEK_CUR );
X		byte_count += out_size;
X	    }
X	} while (byte_count < arch_size);
X	return(0);
X    }
X    
X
/*
X    List out files from a portable "ar" format archive file.
*/
X    int list_ar( argc, argv, cur_arg, arch_file )
X	int argc;
X    char **argv;
X    FILE *arch_file;
X    int cur_arg;
X    {
X	ar_hdr  out_hdr;
X	long    byte_count = 0, arch_size, out_size, i, skip_bytes;
X	time_t  out_date;
X	int     j, k;
X	char    *ch;
X	char    filename[257], tempstr[100], p_mode[10],
X	    p_date[100], temp1[7], temp2[7];
X	struct  list { char filename[257], access; } *file_list, *InList, OneItem;
X	int     next_arg, NFiles, Compare, WriteIt;
X	struct  stat arch_stat;
#if defined(__TURBOC__)
X	struct  ftime filetime;
X	struct  tm *loctime;
#else
X	struct  utimbuf filetime;
#endif
X   
X	if (argc > cur_arg + 1) {   /* Selective extract */
X	    Compare = AR2_TRUE;
X	    i = NFiles = argc - (cur_arg + 1);
X	    next_arg = cur_arg + 1;
X	    file_list =
X		(struct list *)malloc( (NFiles + 1) * sizeof (struct list) );
X	    /* Build a list of files to list out */
X	    OneItem.access = 0;
X	    j = 0;
X	    while (i--) {
X		strcpy( OneItem.filename, argv[next_arg++] );
X		lsearch( &OneItem,
X			 (char *)file_list,
X			 (size_t *)&j,
X			 sizeof (struct list),
X			 (int(*)( const void *, const void *))strcmp );
X	    }
X	} else {
X	    Compare = AR2_FALSE;
X	    NFiles = 0;
X	}
X	stat( argv[cur_arg], &arch_stat );
X	arch_size = arch_stat.st_size;
X	byte_count = ftell( arch_file );
X	do {
X	    if (fgets((char *)&out_hdr, sizeof(ar_hdr), arch_file) == (char *)NULL)
X	    {
X		/* No more headers.  We're finished */
X		break;
X	    }
X	    byte_count += strlen( (char *)&out_hdr );
X	    if (read_header( &out_hdr, filename, arch_file, &byte_count ) == -1)
X		break;   /* Finished, no more headers. */
X	    if (Compare) {
X		InList = (struct list *)lfind( filename,
X					       (char *)file_list,
X					       (size_t *)&NFiles,
X					       sizeof (struct list),
X					       (int(*)( const void *, const void *))strcmp );
X		if (InList != (struct list *)NULL)
X		    InList->access++;
X	    }
X	    if (!Compare || (Compare && InList != (struct list *)NULL)) {
X		WriteIt = AR2_TRUE;
X	    } else 
X		WriteIt = AR2_FALSE;
X
X	    strncpy( tempstr, out_hdr.ar_size, sizeof out_hdr.ar_size );
X	    tempstr[sizeof out_hdr.ar_size] = '\0';
X	    out_size = atol( tempstr );
X
X	    skip_bytes = out_size;
X	    if (skip_bytes % 2)
X		skip_bytes++;
X	    fseek( arch_file, skip_bytes, SEEK_CUR );
X	    byte_count += skip_bytes;
X	    if (WriteIt) {
X
X		strncpy( tempstr, out_hdr.ar_date, sizeof out_hdr.ar_date );
X		tempstr[sizeof out_hdr.ar_date] = '\0';
X		out_date = atol( tempstr );
X		filetime.actime = filetime.modtime = out_date;
X
X		p_mode[0] = (char) 0;
X		j = 3;
X		do {
X		    switch (out_hdr.ar_mode[j]) {
X                    case '7':
X                        strcat( p_mode, "rwx" );
X                        break;
X                    case '6':
X                        strcat( p_mode, "rw-" );
X                        break;
X                    case '5':
X                        strcat( p_mode, "r-x" );
X                        break;
X                    case '4':
X                        strcat( p_mode, "r--" );
X                        break;
X                    case '3':
X                        strcat( p_mode, "-wx" );
X                        break;
X                    case '2':
X                        strcat( p_mode, "-w-" );
X                        break;
X                    case '1':
X                        strcat( p_mode, "--x" );
X                        break;
X                    case '0':
X                        strcat( p_mode, "---" );
X                        break;
X		    }
X		} while (++j < 6);
X		strftime( p_date, 100, "%b %d %H:%M %Y", localtime( &out_date ) );
/*
X  cftime( p_date, "%b %e %R %Y", &out_date );
X  */
X		strncpy( temp1, out_hdr.ar_uid, 6 );
X		strncpy( temp2, out_hdr.ar_gid, 6 );
X		temp1[6] = temp2[6] = (char)0;
X		j = atol( temp1 );
X		k = atol( temp2 );
X		ch = strchr( filename, ' ' );
X		if (ch) *ch = (char)0;
X		fprintf( stdout, "%s %04.1d/%-03.0d  %6ld %s %s\n", 
X			 p_mode,
X			 j,
X			 k,
X			 out_size,
X			 p_date,
X			 filename );
X	    }
X	} while (byte_count < arch_size);
X	for ( j=0; j < NFiles; j++ )
X	    if (file_list[j].access == (char)0)
X		fprintf( stdout,
X			 "No listing found for file: %s\n",
X			 file_list[j].filename );
X	return(0);
X    }
X
X    
/*
X  Print Usage information.
*/
X    void usage( filename )
X	char *filename;
X    {
X	fprintf( stdout, "%s\n\n%s", filename, copyright );
X	fprintf( stdout, attribution );
X	fprintf( stdout,
X		 "\nUsage:\t\t%s [-[qmrxtacle]] [-[dgi]] arcname [file1 [file 2 [...]]]\n\n",
X		 filename );
X	fprintf( stdout,
X		 "    With no flags %s extracts files from a UNIX portable archive."
X		 "\n\n", filename );
X	fprintf( stdout, "\tUNIX \"ar\" compatible flags (keys), as follows:\n" );
X	fprintf( stdout,
X		 "\t-q\tQuick append.  Add file to end.\n\t\t(This function will "
X		 "include duplicate copies of files.)\n" );
X	fprintf( stdout,
X		 "\t-m\tMove file to archive and remove.\n\t\t(This function will "
X		 "include duplicate copies of files.)\n" );
X	fprintf( stdout,
X		 "\t-r\tReplace file.  Replace file in archive with another version."
X		 "\n\t\t(Current version replaces all occurances if the file is "
X		 "\n\t\tmultiply contained in the archive.)\n" );
X	fprintf( stdout, "\t-x\tExtract files.\n" );
X	fprintf( stdout, "\t-t\tList out contents of archive.\n" );
X	fprintf( stdout, "\n\tAdditional (non-compatible) flags available:\n" );
X	fprintf( stdout, "\t-a\tAppend file.  Synonym for -q.\n" );
X	fprintf( stdout, "\t-e\tExtract files.  Synonym for -x.\n" );
X	fprintf( stdout, "\t-l\tList out files.  Synonym for -t.\n" );
X	fprintf( stdout,
X		 "\t-c\tCreate archive.  CREATE a NEW archive or OVERWRITE an existing \n"
X		 "\t\tone!  " );
X	fprintf( stdout,
X		 "(q, m, a, & r will also CREATE an archive if none exists.)\n" );
X	fprintf( stdout, "\n\tCompatibility options:\n" );
X	fprintf( stdout,
X		 "\t-d\tWrite archive with BSD compatible headers.  BSD ar handles \n"
X		 "\t\tfilenames longer than 14 characters by making the file\n"
X		 "\t\theader variable length.\n" );
X	fprintf( stdout,
X		 "\t-g\tWrite archive with System V ar compatible Centralized \n"
X		 "\t\tExtended Name table.  Permits names longer than 14 characters.\n"
X		 "\t\tLong names cannot be appended to an existing archive in \n"
X		 "\t\tthis format.\n" );
X	fprintf( stdout,
X		 "\t-i\tWrite archive with Distributed Extended Name table.\n"
X		 "\t\tPermits names longer than 14 characters.  This format extended"
X		 "\n\t\tname table may be appended to.\n" );
X	fprintf( stdout,
X		 "\t-A\tWrite archive in AIX extended name small header format.  Does \n"
X		 "\t\tnot support files larger than 2GB.\n" );
X	fprintf( stdout,
X		 "\t-B\tWrite archive in AIX extended name large header format.\n" );
X	fprintf( stdout,
X		 "\nBSD, System V, and ar2 Extended format archives are recognized transparently\n"
X		 "for listing and extraction.  The -d, -g, and -i options are provided to create\n"
X		 "and update such archives.  Only one of these options may be provided.  If none \n"
X		 "of -d, -g, -i is provided System V.4 compatibility is assumed.\n" );
X	putc( '\n', stdout );
X    }
X    
X
/*
X    Convert from Octal Digit String to unsigned integer.
*/
X    unsigned otoi( octal )
X	char *octal;
X    {
X        int value, len, scale, ch;
X        
X        value = 0;
X        scale = 1;
X        len = strlen( octal );
X        while (len--) {
X	    ch = octal[len-1];
X	    if (isdigit(ch)) {
X		value += (ch - '0') * scale;
X		scale *= 8;
X	    } else if (value > 0)
X		break;
X        }
X        return (value);
X    }
X    
X
/*
X    Report number of Decimal Digits contained in a long integer.
*/
X    int digs_10( value )
X	long value;
X    {
X	int digs;
X    
X	digs = 0;
X	do {
X	    digs++;
X	    value /= 10;
X	} while ( value );
X	return digs;
X    }
X    
X
/*
X    Report number of Octal Digits contained in an unsigned short.
*/
X    int digs_8( value )
X	unsigned short value;
X    {
X	int digs;
X    
X	digs = 0;
X	do {
X	    digs++;
X	    value /= 8;
X	} while ( value );
X	return digs;
X    }
X    
X
/*
X    Convert from unsigned short to octal digit string.
*/
X    char *ar2_itoo ( value, octal, length )
X        unsigned short value;
X    char *octal;
X    int length;
X    {
X        int index, extent;
X        
X        index = extent = digs_8(value);
X        if (value == 0)
X	    octal[--index] = '0';
X        else {
X	    while (value) {
X		octal[--index] =  (char)('0' + (value % 8));
X		value /= 8;
X	    }
X        }
X        length -= extent;
X        while (length > 0)
X	    octal[extent + --length] = ' ';
X        return octal;
X    }
X    
X
/*
X    Convert from long integer to decimal digit string.
*/
X    char *ar2_ltoa( value, string, length )
X	long value;
X    char *string;
X    int length;
X    {
X	int index, extent;
X    
X	index = extent = digs_10(value);
X	if (value == 0) {
X	    string[--index] = '0';
X	} else {
X	    while (value) {
X		string[--index] = '0' + (value % 10);
X		value = value / 10;
X	    }
X	}
X	length -= extent;
X	while (length > 0)
X	    string[extent + --length] = ' ';
X	return string;
X    }
X    
X
/*
X    Create an "ar" format archive file and write magic string.
*/
X    FILE *create_arc( filename )
X	char *filename;
X    {
X	FILE *out_file;
X	char armag[SARMAG + 1];
X    
X	getmagicnumber( armag );
X	out_file = fopen( filename, "wb" );
X	if (out_file == (FILE *)NULL)
X	    fprintf( stderr, "Cannot create archive file!\n" );
X	else
X	    fputs( armag, out_file );
X	return out_file;
X    }
X    
X
/*
X    Add a file to an existing archive.
*/
X    int write_file ( out_file, in_file, in_name )
X	FILE *out_file, *in_file;
X    char in_name[];
X    {
X	ar_hdr header;
X	char *begin;
X	int i, to_read, was_read, were_written, this_read, this_write, IOpened;
X	struct stat fstats;
X	char buffer[MYBUFSIZE], blanks[21], nl[2];
X
X	strcpy( blanks, "                    " );
X	strcpy( nl, "\n" );
X        /* Get file statistics */
X	stat( in_name, &fstats );
X        /* Build file header record. */
X	begin = strrchr( in_name, DIRSEP );
X	if (begin == (char *)NULL)
X	    begin = in_name;
X	else
X	    begin++;
X	/* Make certain to truncate filenames to 14 characters unless extended
X	   string table has been requested. */
X	if (strlen( begin ) > (sizeof header.ar_name - 2)) {
X	    char *nm;
X	    long offs, Found = AR2_FALSE;
X
X	    if (Extended == CENTRAL) {
X		nm = NameTable;
X		while (*nm != (char)0) {
X		    if (strcmp( begin, nm ) == 0) {
X			Found = AR2_TRUE;
X			break;
X		    } else {
X			nm += strlen( nm ) + 2;
X		    }
X		}
X		if (Found) {
X		    offs = (long)nm - (long)NameTable;
X		    sprintf( header.ar_name, "/%0.1ld", offs );
X		} else {
X		    fprintf( stderr,
X			     "Cannot append to a central string table archive.\n" );
X		    exit(33);
X		}
X	    } else if (Extended == DISTRIBUTE) {
X		ar_hdr hdr;
X
X		strcpy( hdr.ar_name, "!/!             " );
X		ar2_ltoa( fstats.st_mtime, hdr.ar_date, 12 );
X		strcpy( hdr.ar_uid, "0     " );
X		strcpy( hdr.ar_gid, "0     " );
X		strcpy( hdr.ar_mode, "600     " );
X		sprintf( hdr.ar_size, "%-10.1d", strlen( begin ) + 2 );
X		getmagicnumber( hdr.ar_fmag );
X		fputs( hdr.ar_name, out_file );
X		fprintf( out_file, "%s/\n", begin );
X		if (strlen( begin ) % 2 == 1)
X		    fputc( '\n', out_file );
X		strncpy( header.ar_name, begin, sizeof header.ar_name - 2 );
X		header.ar_name[sizeof header.ar_name - 2] = (char)0;
X		strcat( header.ar_name, "/" );
X	    } else {
X		strncpy( header.ar_name, begin, sizeof header.ar_name - 2 );
X		header.ar_name[sizeof header.ar_name - 2] = (char)0;
X		if (!DECFlag)
X		    strcat( header.ar_name, "/" );
X		fprintf( stderr,
X			 "Warning: Name of file <%s> too long, truncated to <%s>.\n",
X			 begin,
X			 header.ar_name );
X	    }
X	} else {
X	    strcpy( header.ar_name, begin );
X	    if (!DECFlag)
X		strcat( header.ar_name, "/" );
X	}
X	i = strlen( header.ar_name );
X
X	/* This is tricky.  We're writing the null byte to the beginning of the
X	   next element and then overwriting it with the next field data.
X	   !!! BE CAREFUL WHEN MODIFYING THIS CODE !!!  Do not re-order lines.
X	   strncpy( &(header.ar_name[i]), blanks, (16 - i) );
X	   */
X	memset( &(header.ar_name[i]), ' ', (16 - i) );
X	ar2_ltoa( fstats.st_mtime, header.ar_date, 12 );
X	ar2_ltoa( (long)fstats.st_uid, header.ar_uid, 6 );
X	ar2_ltoa( (long)fstats.st_gid, header.ar_gid, 6 );
X	ar2_itoo( fstats.st_mode, header.ar_mode, 8 );
X	ar2_ltoa( fstats.st_size, header.ar_size, 10 );
X	strcpy( header.ar_fmag, ARFMAG );
X    
X        /* Write file header record. */
X	if (!DECFlag)
X	    fputs( header.ar_name, out_file );
X	else {
X	    if (strlen( begin ) > 16)
X		fprintf( out_file, "%s  ", begin );
X	    else
X		fprintf( out_file, "%-16s", begin );
X	    fputs( header.ar_date, out_file );
X	}
X    
X        /* Open input file */
X	if (in_file == (FILE *)NULL) {
X	    in_file = fopen( in_name, "rb" );
X	    if (in_file == (FILE *)NULL) {
X		fprintf( stderr,
X			 "Cannot open <%s> for reading.  Errno = %d.\n",
X			 in_name,
X			 errno );
X		exit( errno );
X	    }
X	    IOpened = AR2_TRUE;
X	} else
X	    IOpened = AR2_FALSE;
X    
X        /* Copy file into archive */
X	to_read = fstats.st_size;
X	this_read = this_write = was_read = were_written = 0;
X	if (to_read > 0)    /* Don't bother to read zero length files */
X	    do {
X		was_read += this_read = fread( buffer, 1, MYBUFSIZE, in_file );
X		were_written +=
X		    this_write = fwrite( buffer, 1, this_read, out_file );
X		if (this_write <= 0)
X		    break;
X		if (this_read <= 0)
X		    break;
X	    } while (to_read > was_read);
X	if ((to_read % 2) == 1 && this_read >= 0 && this_write >= 0)
X	    this_write = fwrite( nl, 1, 1, out_file );
X	if (IOpened)
X	    fclose( in_file );
X	fflush( out_file );
X	if (Flag == UNLINK && this_read >= 0 && this_write >= 0)
X	    unlink( in_name );
X	if (this_read >= 0 && 
X	    this_write >= 0 && 
X	    to_read == was_read && 
X	    to_read == were_written)
X	    return were_written;
X	else if (this_write < 0 || to_read > were_written)
X	    return -1;
X	else /* (this_read < 0 || to_read > was_read) */
X	    return -2;
X    }
X    
X
/*
X    Replace files from a portable "ar" format archive file with newer(?) ones.
*/
X    int repl_ar( argc, argv, cur_arg, new_arch, arch_file )
X	int argc;
X    char **argv;
X    FILE *arch_file, *new_arch;
X    int cur_arg;
X    {
X	FILE    *in_file;
X	ar_hdr  out_hdr, sav_hdr;
X	long    byte_count = 0, arch_size, out_size, i, write_count = 0, to_read,
X            this_read, block_size;
X	int     j;
X	char    filename[257], *pos, tempstr[100], *block;
X	struct  list { 
X	    char filename[257];
X	    char access; 
X	    char pathname[1025];
X	} *file_list, *InList, OneItem;
X	int     next_arg, NFiles, Compare, ReplaceIt;
X	struct  stat arch_stat, fstats;
X
X	if (argc > cur_arg + 1) {   /* Selective replace */
X	    Compare = AR2_TRUE;
X	    i = NFiles = argc - (cur_arg + 1);
X	    next_arg = cur_arg + 1;
X	    file_list =
X		(struct list *)malloc( (NFiles + 1) * sizeof (struct list) );
X	    /* Build a list of files to replace. */
X	    OneItem.access = 0;
X	    j = 0;
X	    /* New code to allow full paths on command line. */
X	    while (i--) {
X		stat( argv[next_arg], &fstats );
X		/* Only process ordinary files. */
X		if (fstats.st_mode && S_IFREG) {
X		    strcpy( OneItem.pathname, argv[next_arg++] );
X		    if ((pos = strrchr( OneItem.pathname, DIRSEP )) == (char *)NULL)
X			strcpy( OneItem.filename, OneItem.pathname );
X		    else
X			strcpy( OneItem.filename, ++pos );
X		    lsearch( &OneItem,
X			     (char *)file_list,
X			     (size_t *)&j,
X			     sizeof (struct list),
X			     (int(*)( const void *, const void *))strcmp );
X		} else
X		    fprintf( stderr,
X			     "File <%s> is not an ordinary file.  Ignoring!\n",
X			     argv[next_arg++] );
X	    }
X	} else
X	    Compare = AR2_FALSE;
X	NFiles = j;
X	fstat( fileno( arch_file ), &arch_stat );
X	arch_size = arch_stat.st_size;
X	byte_count = ftell( arch_file );
X	do {
X
X	    if (fgets((char *)&out_hdr, sizeof(ar_hdr), arch_file) == (char *)NULL)
X	    {
X		/* No more headers.  We're finished */
X		break;
X	    }
X	    byte_count += strlen( (char *)&out_hdr );
X	    /* Save Header in case it is a Name Extension Header */
X	    sav_hdr = out_hdr;
X	    if (read_header( &out_hdr, filename, arch_file, &byte_count ) == -1)
X		break;   /* Finished, no more headers. */
X	    if (Compare) {
X		InList = (struct list *)lfind( filename,
X					       (char *)file_list,
X					       (size_t *)&NFiles,
X					       sizeof (struct list),
X					       (int(*)( const void *, const void *))strcmp );
X		if (InList != (struct list *)NULL)
X		    InList->access++;
X	    }
X	    if (Compare && InList != (struct list *)NULL) {
X		if ((in_file = fopen( InList->pathname, "rb" )) != (FILE *)NULL) {
X		    ReplaceIt = AR2_TRUE;
X		} else {
X		    fprintf( stdout, "%s not found\n", InList->pathname );
X		    ReplaceIt = AR2_FALSE;
X		}
X	    } else      /* Freshen code would go here */
X		ReplaceIt = AR2_FALSE;
X
X	    strncpy( tempstr, out_hdr.ar_size, sizeof out_hdr.ar_size );
X	    tempstr[sizeof out_hdr.ar_size] = '\0';
X	    out_size = atol( tempstr );
X
X	    if (ReplaceIt) {      /* Replace file with "newer" version, */
X		/* skip over file in the old archive */
X		fprintf( stdout, "r - %s\n", filename );
X		if (out_size % 2)
X		    out_size++;
X		fseek( arch_file, out_size, SEEK_CUR );
X		byte_count += out_size;
X
X		/* Write the new file to the new archive */
X		if ((j = write_file( new_arch, in_file, filename )) == -1) {
X		    fprintf( stderr, "\tError writing to archive!  Aborting.\n" );
X		    return(11);
X		} else if (j == -2) {
X		    fprintf( stderr, "\tError reading file!  Aborting.\n" );
X		    return(12);
X		}
X		write_count += j;
X		fclose( in_file );
X	    } else {    /* Copy file from old archive */
X		/* First re-write Extended name entry if needed. */
X		if (strlen( filename ) > (sizeof out_hdr.ar_name - 2)) {
X		    if (fputs( (char *)&sav_hdr, new_arch ) == EOF) {
X			fprintf( stderr,
X				 "Error copying archive to new archive.\n" );
X			return(10);
X		    }
X		    fprintf( new_arch, "%s/\n", filename );
X		    if (strlen( filename ) % 2 == 1)
X			putc( '\n', new_arch );
X		}
X		/* Now re-write file header */
X		if (fputs( (char *)&out_hdr, new_arch ) == EOF) {
X		    fprintf( stderr, "Error copying archive to new archive.\n" );
X		    return(10);
X		}
X		write_count += (sizeof (ar_hdr) - 1);
X		if (out_size % 2)
X		    out_size++;
X		if (out_size > 0) {
X		    block_size = (out_size > 65535) ? 65535 : out_size;
X		    to_read = out_size;
X		    block = malloc( block_size );
X		    while (to_read) {
X			if ((this_read =
X			     fread(block, 1, block_size, arch_file)) != block_size)
X			{
X			    fprintf( stderr, "Unexpected End of File found.  Error %d.\n", errno );
X			    return(9);
X			}
X			if (fwrite( block, 1, block_size, new_arch) != block_size) {
X			    fprintf( stderr,
X				     "Error writing output.  Error %d.\n",
X				     errno );
X			    return(8);
X			}
X			to_read -= this_read;
X		    }
X		    free( block );
X		}
X		byte_count += out_size;
X		write_count += out_size;
X	    }
X	} while (byte_count < arch_size);
X	for ( j=0; j < NFiles; j++ )
X	    if (file_list[j].access == (char)0)
X		fprintf( stdout,
X			 "File: %s not in archive.\n",
X			 file_list[j].filename );
X	return(0);
X    }
X
/* Portably rename a file - DOS Rename system call,                     */
/*                          UNIX link to new name and unlink the old    */
X
X    int renameit( oldname, newname )
X	char *oldname, *newname;
X    {
#if defined( __MSDOS__ ) || defined(WIN32)
X	/* put rename code for DOS here */
X	strcpy( newname, oldname );
X	if (newname[strlen(newname)-1] != '_')
X	    newname[strlen(newname)-1] = '_';
X	else
X	    newname[strlen(newname)-1] = '!';
X	rename( oldname, newname );
#else
X	char *str_ptr, *str_ptr2;
X
X	if (newname == (char *)NULL) {
X	    newname = (char *)malloc( 1025 );
X	    newname[0] = (char)0;
X	}
X	if (strlen(newname) == 0) {             /* form a temporary filename */
X	    strcpy( newname, oldname );
X	    if ((str_ptr = strrchr( newname, DIRSEP )) == (char *)NULL)
X		str_ptr = newname;              /* get just path to archive file */
X	    else
X		str_ptr++;
X	    ar2_ltoa( getpid(), str_ptr, 10 );      /* append PID to path */
X	    str_ptr2 = strchr( str_ptr, ' ' );  /* find end of PID */
X	    if (str_ptr2 != (char *)NULL)
X		*str_ptr2 = (char)0;
X	}
X	if (link( oldname, newname ) == -1)
X	    return -1;
X	if (unlink( oldname ) == -1)
X	    return -2;
#endif
X	return 0;
X    }
X    void rewrite_strings( FILE *out, int ar_arg, int argc, char **argv )
X	{
X	    int i = ar_arg, Found = AR2_FALSE, oldsize;
X	    ar_hdr hdr;
X	    char *nm;
X    
X	    if (NameTable == (char *)NULL) {
X		NameTable = (char *)malloc( 2 );
X		memset( NameTable, (char)0, 2 );
X		TableSize = 2;
X	    }
X	    while (++i < argc) {
X		if (strlen( argv[i] ) > (sizeof hdr.ar_name - 2)) {
X		    oldsize = TableSize;
X		    Found = AR2_FALSE;
X		    nm = NameTable;
X		    while (*nm != (char)0) {
X			if (strcmp( argv[i], nm ) == 0) {
X			    Found = AR2_TRUE;
X			    break;
X			} else {
X			    nm += strlen( nm ) + 2;
X			}
X		    }
X		    if (!Found) {
X			TableSize += strlen( argv[i] ) + 2;
X			NameTable = (char *)realloc( NameTable, TableSize );
X			strcpy( &NameTable[oldsize - 2], argv[i] );
X			memset( &NameTable[TableSize - 4], (char)0, 4 );
X		    }
X		}
X	    }
X	    if (TableSize > 2) {
X		strcpy( hdr.ar_name, "//              " );
X		ar2_ltoa( time( NULL ), hdr.ar_date, 12 );
X		sprintf( hdr.ar_uid, "%-6.1d", 0 );
X		sprintf( hdr.ar_gid, "%-6.1d", 0 );
X		sprintf( hdr.ar_mode, "%-8.1d", 600 );
X		sprintf( hdr.ar_size, "%-10.1d", TableSize - 2 );
X		strcpy( hdr.ar_fmag, ARFMAG );
X		fputs( (char *)&hdr, out );
X		if (TableSize % 2)
X		    oldsize = TableSize - 1;
X		else
X		    oldsize = TableSize - 2;
X		/* Copy name table and put the "/\n" name terminators back in the
X		    copy before writing it out. */
X		nm = (char *)malloc( TableSize );
X		memcpy( nm, NameTable, TableSize );
X		for (i = 0; i < TableSize - 2; i++) {
X		    if (nm[i] == (char)0) {
X			nm[i++] = '/';
X			nm[i] = '\n';
X		    }
X		}
X		fwrite( nm, oldsize, 1, out );
X	    }
X	    free( nm );
X	}
X    
X    int read_header ( ar_hdr *out_hdr,
X		      char *filename,
X		      FILE *arch_file,
X		      long *byte_count )
X	{
X	    int offs, name_pos;
X	    char *pos;
X
X	    /* Handle distributed string table. */
X	    if (out_hdr->ar_name[1] == '/' && out_hdr->ar_name[2] == '!') {
X		fgets( filename, 257, arch_file );
X		if ((atoi(out_hdr->ar_size ) % 2) == 1)
X		    getc( arch_file );
X		/* Read actual file's header. */
X		if (fgets((char *)out_hdr, sizeof(ar_hdr), arch_file) ==
X		    (char *)NULL)
X		{
X		    /* No more headers.  We're finished */
X		    return -1;
X		}
X		*byte_count += strlen( (char *)out_hdr );
#	if defined( DIAG )
X		if (out_hdr->ar_name[0] != '/' || out_hdr->ar_name[1] != '?') {
X		    fprintf( stderr,
X			     "Distributed Name Table Entry found with no "
X			     "related file! Ignoring." );
X		    strncpy( filename, out_hdr->ar_name, sizeof out_hdr->ar_name );
X		}
#	endif
X	    } else {
X		strncpy( filename, out_hdr->ar_name, sizeof out_hdr->ar_name );
X		filename[ sizeof out_hdr->ar_name ] = (char)0;
X	    }
X	    pos = strrchr( filename, '/' );
X	    if (pos != (char *)NULL)
X		*pos = (char)0;
X	    else {
X		/* Handle DEC style archives with no terminating slash. */
X		/* Assume no spaces in filenames.  Assume long names in place */
X		/* Assuming 2 trailing spaces after filename before date string */
X		/* If not adjust " - 3" in "offs = " below.  */
X		pos = strchr( out_hdr->ar_name, ' ' );
X		*pos = (char)0;
X		strcpy( filename, out_hdr->ar_name );
X		*pos = ' ';    /* Put the space back for repl_ar(). */
X		if (strlen( filename ) > 14 ) {
X		    /* Truncate filename to 14 chars. */
X		    out_hdr->ar_name[14] = out_hdr->ar_name[15] = ' ';
X		    /* Reread rest of header! */
X		    offs = -1 * (sizeof(ar_hdr) - strlen( filename ) - 3);
X		    fseek( arch_file, offs, SEEK_CUR );
X		    fgets( (char *)out_hdr->ar_date,
X			   (sizeof (ar_hdr) - sizeof out_hdr->ar_name),
X			   arch_file );
X		}
X	    }
X	    /* Handling for extended names with Central String Table. */
X	    if (strlen( filename ) == 0 && NameTable != (char *)NULL) {
X		name_pos = atoi( ++pos );
X		strcpy( filename, &NameTable[name_pos] );
X	    }
X	    return 0;
X	}
SHAR_EOF
  (set 20 10 12 06 12 17 57 'ar2.c'; eval "$shar_touch") &&
  chmod 0666 'ar2.c'
if test $? -ne 0
then ${echo} 'restore of ar2.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'ar2.c: MD5 check failed'
       ) << SHAR_EOF
b84b2a7f48a68496fade54aecc3cdb66  ar2.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'ar2.c'` -ne 55779 && \
  ${echo} 'restoration warning:  size of ar2.c is not 55779'
  fi
fi
# ============= ar2.mk ==============
if test -f 'ar2.mk' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING ar2.mk (file already exists)'
else
${echo} 'x - extracting ar2.mk (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ar2.mk' &&
VPATH=::../bin:RCS
CC=gcc
SHELL=/usr/bin/ksh
CFLAGS= -fforce-addr -fdelayed-branch -fschedule-insns2 \
X	-fexpensive-optimizations -fschedule-insns -frerun-cse-after-loop \
X	-fthread-jumps
X
ar2:	ar2.c
X	@if [ -z "${DFLAG}" ]; \
X	then \
X	    echo $(CC) ${CFLAGS} -oar2 ar2.c;\
X	    $(CC) ${CFLAGS} -oar2 ar2.c;\
X	else \
X	    echo $(CC) $(DFLAG) -oar2 ar2.c;\
X	    $(CC) $(DFLAG) -oar2 ar2.c;\
X	fi
SHAR_EOF
  (set 20 10 12 06 12 33 48 'ar2.mk'; eval "$shar_touch") &&
  chmod 0666 'ar2.mk'
if test $? -ne 0
then ${echo} 'restore of ar2.mk failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'ar2.mk: MD5 check failed'
       ) << SHAR_EOF
4d23fa217f61e607adf306cf888e34e7  ar2.mk
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'ar2.mk'` -ne 394 && \
  ${echo} 'restoration warning:  size of ar2.mk is not 394'
  fi
fi
if rm -fr ${lock_dir}
then ${echo} 'x - removed lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to remove lock directory `'${lock_dir}\''.'
  exit 1
fi
exit 0
