v15i019: Tools to create and unpack shell archives, Part02/03
Rich Salz
rsalz at uunet.uu.net
Sat May 28 04:20:22 AEST 1988
Submitted-by: Rich Salz <rsalz at uunet.uu.net>
Posting-number: Volume 15, Issue 19
Archive-name: cshar/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 3)."
# Contents: dir.amiga findsrc.c makekit.c shar.c unshar.c
# Wrapped by rsalz at fig.bbn.com on Fri May 27 14:15:08 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'dir.amiga' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dir.amiga'\"
else
echo shar: Extracting \"'dir.amiga'\" \(6596 characters\)
sed "s/^X//" >'dir.amiga' <<'END_OF_FILE'
X
X[ I have not tried this at all. --r$ ]
X
Return-Path: mwm at violet.Berkeley.EDU
Received: from violet.berkeley.edu (violet.berkeley.edu.ARPA) by PINEAPPLE.BBN.COM (4.12/4.7) id AA28194; Tue, 14 Jul 87 00:52:17 edt
Received: from localhost.ARPA
X by violet.berkeley.edu (5.54 (CFC 4.22.3)/1.16.15)
X id AA16462; Mon, 13 Jul 87 21:54:26 PDT
Message-Id: <8707140454.AA16462 at violet.berkeley.edu>
To: Richard Salz <rsalz at pineapple.bbn.com>
Subject: Re: Amiga version of the dir library...
Ultrix: Just say No!
In-Reply-To: Your message of Wed, 08 Jul 87 21:19:51 -0400
Date: Mon, 13 Jul 87 21:54:25 PDT
XFrom: Mike (My watch has windows) Meyer <mwm at violet.Berkeley.EDU>
X
Here's what I did. This is built to reflect the 4BSD manual pages, not
the SysV/dpANS manual pages.
X
I now know how to get the telldir/seekdir pair to work correctly with
multiple tell()s, but don't have much motivation to do so. If someone
out there does it, or is interested in doing it, I'd be interested in
the results or willing to help.
X
XFinal note: as with many micros, there's more than one C compiler.
This was written for the Lattice compiler, and uses features known
not to exist in other Amiga compilers. Fixing it should be trivial.
X
Oh, yeah - sorry for the delay in getting these two you.
X
X <mike
X
X#! /bin/sh
X# This is a shell archive, meaning:
X# 1. Remove everything above the #! /bin/sh line.
X# 2. Save the resulting text in a file.
X# 3. Execute the file with /bin/sh (not csh) to create:
X# dir.h
X# ndir.c
X# By: Mike (My watch has windows) Meyer (Missionaria Phonibalonica)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'dir.h'" '(1708 characters)'
if test -f 'dir.h'
then
X echo shar: "will not over-write existing file 'dir.h'"
else
sed 's/^X//' << \SHAR_EOF > 'dir.h'
XX#ifndef DIR_H
XX#define DIR_H
XX
XX#ifndef EXEC_TYPES_H
XX#include "exec/types.h"
XX#endif
XX
XX#ifndef LIBRARIES_DOS_H
XX#include "libraries/dos.h"
XX#endif
XX
XX#ifndef LIBRARIES_DOSEXTENS_H
XX#include "libraries/dosextens.h"
XX#endif
XX/*
XX * MAXNAMELEN is the maximum length a file name can be. The direct structure
XX * is lifted form 4BSD, and has not been changed so that code which uses
XX * it will be compatable with 4BSD code. d_ino and d_reclen are unused,
XX * and will probably be set to some non-zero value.
XX */
XX#define MAXNAMLEN 31 /* AmigaDOS file max length */
XX
XXstruct direct {
XX ULONG d_ino ; /* unused - there for compatability */
XX USHORT d_reclen ; /* ditto */
XX USHORT d_namlen ; /* length of string in d_name */
XX char d_name[MAXNAMLEN + 1] ; /* name must be no longer than this */
XX};
XX/*
XX * The DIRSIZ macro gives the minimum record length which will hold
XX * the directory entry. This requires the amount of space in struct direct
XX * without the d_name field, plus enough space for the name with a terminating
XX * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
XX */
XX
XX#undef DIRSIZ
XX#define DIRSIZ(dp) \
XX ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp) -> d_namlen+1 + 3) &~ 3))
XX/*
XX * The DIR structure holds the things that AmigaDOS needs to know about
XX * a file to keep track of where it is and what it's doing.
XX */
XX
XXtypedef struct {
XX struct FileInfoBlock d_info , /* Default info block */
XX d_seek ; /* Info block for seeks */
XX struct FileLock *d_lock ; /* Lock on directory */
XX } DIR ;
XX
XXextern DIR *opendir(char *) ;
XXextern struct direct *readdir(DIR *) ;
XXextern long telldir(DIR *) ;
XXextern void seekdir(DIR *, long) ;
XXextern void rewinddir(DIR *) ;
XXextern void closedir(DIR *) ;
XX#endif DIR_H
SHAR_EOF
if test 1708 -ne "`wc -c < 'dir.h'`"
then
X echo shar: "error transmitting 'dir.h'" '(should have been 1708 characters)'
fi
fi
echo shar: "extracting 'ndir.c'" '(2486 characters)'
if test -f 'ndir.c'
then
X echo shar: "will not over-write existing file 'ndir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ndir.c'
XX/*
XX * ndir - routines to simulate the 4BSD new directory code for AmigaDOS.
XX */
XX#include <dir.h>
XX
XXDIR *
XXopendir(dirname) char *dirname; {
XX register DIR *my_dir, *AllocMem(int, int) ;
XX struct FileLock *Lock(char *, int), *CurrentDir(struct FileLock *) ;
XX
XX if ((my_dir = AllocMem(sizeof(DIR), 0)) == NULL) return NULL ;
XX
XX
XX if (((my_dir -> d_lock = Lock(dirname, ACCESS_READ)) == NULL)
XX /* If we can't examine it */
XX || !Examine(my_dir -> d_lock, &(my_dir -> d_info))
XX /* Or it's not a directory */
XX || (my_dir -> d_info . fib_DirEntryType < 0)) {
XX FreeMem(my_dir, sizeof(DIR)) ;
XX return NULL ;
XX }
XX return my_dir ;
XX }
XX
XXstruct direct *
XXreaddir(my_dir) DIR *my_dir; {
XX static struct direct result ;
XX
XX if (!ExNext(my_dir -> d_lock, &(my_dir -> d_info))) return NULL ;
XX
XX result . d_reclen = result . d_ino = 1 ; /* Not NULL! */
XX (void) strcpy(result . d_name, my_dir -> d_info . fib_FileName) ;
XX result . d_namlen = strlen(result . d_name) ;
XX return &result ;
XX }
XX
XXvoid
XXclosedir(my_dir) DIR *my_dir; {
XX
XX UnLock(my_dir -> d_lock) ;
XX FreeMem(my_dir, sizeof(DIR)) ;
XX }
XX/*
XX * telldir and seekdir don't work quite right. The problem is that you have
XX * to save more than a long's worth of stuff to indicate position, and it's
XX * socially unacceptable to alloc stuff that you don't free later under
XX * AmigaDOS. So we fake it - you get one level of seek, and dat's all.
XX * As of now, these things are untested.
XX */
XX#define DIR_SEEK_RETURN ((long) 1) /* Not 0! */
XXlong
XXtelldir(my_dir) DIR *my_dir; {
XX
XX my_dir -> d_seek = my_dir -> d_info ;
XX return (long) DIR_SEEK_RETURN ;
XX }
XX
XXvoid
XXseekdir(my_dir, where) DIR *my_dir; long where; {
XX
XX if (where == DIR_SEEK_RETURN)
XX my_dir -> d_info = my_dir -> d_seek ;
XX else /* Makes the next readdir fail */
XX setmem((char *) my_dir, sizeof(DIR), 0) ;
XX }
XX
XXvoid
XXrewinddir(my_dir) DIR *my_dir; {
XX
XX if (!Examine(my_dir -> d_lock, &(my_dir -> d_info)))
XX setmem((char *) my_dir, sizeof(DIR), 0) ;
XX }
XX#ifdef TEST
XX/*
XX * Simple code to list the files in the argument directory,
XX * lifted straight from the man page.
XX */
XX#include <stdio.h>
XXvoid
XXmain(argc, argv) int argc; char **argv; {
XX register DIR *dirp ;
XX register struct direct *dp ;
XX register char *name ;
XX
XX if (argc < 2) name = "" ;
XX else name = argv[1] ;
XX
XX if ((dirp = opendir(name)) == NULL) {
XX fprintf(stderr, "Bogus! Can't opendir %s\n", name) ;
XX exit(1) ;
XX }
XX
XX for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
XX printf("%s ", dp -> d_name) ;
XX closedir(dirp);
XX putchar('\n') ;
XX }
XX#endif TEST
XX
SHAR_EOF
if test 2486 -ne "`wc -c < 'ndir.c'`"
then
X echo shar: "error transmitting 'ndir.c'" '(should have been 2486 characters)'
fi
fi
exit 0
X# End of shell archive
END_OF_FILE
if test 6596 -ne `wc -c <'dir.amiga'`; then
echo shar: \"'dir.amiga'\" unpacked with wrong size!
fi
# end of 'dir.amiga'
fi
if test -f 'findsrc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'findsrc.c'\"
else
echo shar: Extracting \"'findsrc.c'\" \(7195 characters\)
sed "s/^X//" >'findsrc.c' <<'END_OF_FILE'
X/*
X** FINDSRC
X** Walk directories, trying to find source files.
X*/
X#include "shar.h"
X#ifdef RCSID
static char RCS[] =
X "$Header: findsrc.c,v 2.0 88/05/27 13:26:05 rsalz Exp $";
X#endif /* RCSID */
X
X
X/*
X** Global variables.
X*/
int DoDOTFILES; /* Do .newsrc and friends? */
int DoRCS; /* Do RCS and SCCS files? */
int Default; /* Default answer from user */
int Verbose; /* List rejected files, too? */
char *Dname; /* Filename of directory list */
char *Fname; /* Filename of file list */
XFILE *Dfile; /* List of directories found */
XFILE *Ffile; /* List of files found */
XFILE *DEVTTY; /* The tty, if in filter mode */
X
X
X/*
X** Signal handler. Clean up and die.
X*/
static sigret_t
Catch(s)
X int s;
X{
X int e;
X
X e = errno;
X if (Dname)
X (void)unlink(Dname);
X if (Fname)
X (void)unlink(Fname);
X Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
X exit(1);
X}
X
X
X/*
X** Given a filename, apply heuristics to see if we want it.
X*/
static int
Wanted(Name)
X REGISTER char *Name;
X{
X REGISTER FILE *F;
X REGISTER char *s;
X REGISTER char *p;
X REGISTER char *d;
X char buff[BUFSIZ];
X
X /* Get down to brass tacks. */
X s = (p = RDX(Name, '/')) ? p + 1 : Name;
X
X /* Only do directories other than . and .. and regular files. */
X if ((Ftype(Name) != F_DIR && Ftype(Name) != F_FILE)
X || EQ(s, ".") || EQ(s, ".."))
X return(FALSE);
X
X /* Common cruft we never want. */
X if (EQ(s, "foo") || EQ(s, "core") || EQ(s, "tags") || EQ(s, "lint"))
X return(FALSE);
X
X /* Disregard stuff with bogus suffixes. */
X d = RDX(s, '.');
X if ((p = d)
X && (EQ(++p, "out") || EQ(p, "orig") || EQ(p, "rej") || EQ(p, "BAK")
X || EQ(p, "CKP") || EQ(p, "old") || EQ(p, "o") || EQ(p, "EXE")
X || EQ(p, "OBJ")))
X return(FALSE);
X
X /* Want .cshrc, .newsrc, etc.? */
X if (*s == '.' && isalpha(s[1]))
X return(DoDOTFILES);
X
X /* RCS or SCCS file or directory? */
X if (EQ(s, "RCS")
X || ((p = RDX(s, ',')) && *++p == 'v' && *++p == '\0')
X || EQ(s, "SCCS") || (s[0] == 's' && s[1] == '.'))
X return(DoRCS);
X
X /* Mlisp, m4 (yes to .m? but no to .mo)? */
X /* really, no to .mo but yes to names matching the regexp ".m?" */
X if ((p = d) && *++p == 'm' && p[2] == '\0')
X return(*++p != 'o');
X
X /* Gnu Emacs elisp (yes to .el*, but no to .elc)? */
X if ((p = d) && *++p == 'e' && *++p == 'l')
X return(*++p != 'c' || *++p);
X
X /* C source (*.[ch])? */
X if ((p = d) && (*++p == 'c' || *p == 'h') && *++p == '\0')
X
X /* Manpage (*.[1234567890] or *.man)? */
X if ((p = d) && isdigit(*p))
X return(TRUE);
X if ((p = d) && *++p == 'm' && *++p == 'a' && *++p == 'n')
X return(TRUE);
X
X /* Make control file? */
X if ((*s == 'M' || *s == 'm') && EQ(s + 1, "akefile"))
X return(TRUE);
X
X /* Convert to lowercase, and see if it's a README or MANIFEST. */
X for (p = strcpy(buff, s); *p; p++)
X if (isascii(*p) && isupper(*p))
X *p = tolower(*p);
X if (EQ(buff, "readme") || EQ(buff, "read_me") || EQ(buff, "read-me")
X || EQ(buff, "manifest"))
X return(TRUE);
X
X /* Larry Wall-style template file (*.SH)? */
X if ((p = d) && *++p == 'S' && *++p == 'H')
X return(TRUE);
X
X /* If we have a default, give it back. */
X if (Default)
X return(Default == 'y');
X
X#ifdef CAN_POPEN
X /* See what file(1) has to say; if it says executable, punt. */
X (void)sprintf(buff, "exec file '%s'", Name);
X if (F = popen(buff, "r")) {
X (void)fgets(buff, sizeof buff, F);
X (void)pclose(F);
X for (p = buff; p = IDX(p, 'e'); p++)
X if (PREFIX(p, "executable"))
X return(FALSE);
X (void)fputs(buff, stderr);
X }
X#endif /* CAN_POPEN */
X
X /* Add it? */
X while (TRUE) {
X if (DEVTTY == NULL)
X DEVTTY = fopen(THE_TTY, "r");
X Fprintf(stderr, "Add this one (y or n)[y]? ");
X (void)fflush(stderr);
X if (fgets(buff, sizeof buff, DEVTTY) == NULL
X || buff[0] == '\n' || buff[0] == 'y' || buff[0] == 'Y')
X break;
X if (buff[0] == 'n' || buff[0] == 'N')
X return(FALSE);
X if (buff[0] == '!' )
X (void)system(&buff[1]);
X Fprintf(stderr, "--------------------\n%s: ", Name);
X clearerr(DEVTTY);
X }
X return(TRUE);
X}
X
X
X/*
X** Quick and dirty recursive routine to walk down directory tree.
X** Could be made more general, but why bother?
X*/
static void
Process(p, level)
X REGISTER char *p;
X REGISTER int level;
X{
X REGISTER char *q;
X DIR *Dp;
X DIRENTRY *E;
X char buff[BUFSIZ];
X
X#ifdef MSDOS
X strlwr(p);
X#endif /* MSDOS */
X
X if (!GetStat(p))
X Fprintf(stderr, "Can't walk down %s, %s.\n", Ermsg(errno));
X else {
X /* Skip leading ./ which find(1), e.g., likes to put out. */
X if (p[0] == '.' && p[1] == '/')
X p += 2;
X
X if (Wanted(p))
X Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "%s\n", p);
X else if (Verbose)
X Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "PUNTED %s\n", p);
X
X if (Ftype(p) == F_DIR)
X if (++level == MAX_LEVELS)
X Fprintf(stderr, "Won't walk down %s -- more than %d levels.\n",
X p, level);
X else if (Dp = opendir(p)) {
X q = buff + strlen(strcpy(buff, p));
X for (*q++ = '/'; E = readdir(Dp); )
X if (!EQ(E->d_name, ".") && !EQ(E->d_name, "..")) {
X (void)strcpy(q, E->d_name);
X Process(buff, level);
X }
X (void)closedir(Dp);
X }
X else
X Fprintf(stderr, "Can't open directory %s, %s.\n",
X p, Ermsg(errno));
X }
X}
X
X
main(ac, av)
X REGISTER int ac;
X REGISTER char *av[];
X{
X REGISTER char *p;
X REGISTER int i;
X REGISTER int Oops;
X char buff[BUFSIZ];
X
X /* Parse JCL. */
X for (Oops = 0; (i = getopt(ac, av, ".d:o:RSv")) != EOF; )
X switch (i) {
X default:
X Oops++;
X break;
X case '.':
X DoDOTFILES++;
X break;
X case 'd':
X switch (optarg[0]) {
X default:
X Oops++;
X break;
X case 'y':
X case 'Y':
X Default = 'y';
X break;
X case 'n':
X case 'N':
X Default = 'n';
X break;
X }
X break;
X case 'o':
X if (freopen(optarg, "w", stdout) == NULL) {
X Fprintf(stderr, "Can't open %s for output, %s.\n",
X optarg, Ermsg(errno));
X exit(1);
X }
X case 'R':
X case 'S':
X DoRCS++;
X break;
X case 'v':
X Verbose++;
X break;
X }
X if (Oops) {
X Fprintf(stderr, "Usage: findsrc [-d{yn}] [-.] [-{RS}] [-v] files...\n");
X exit(1);
X }
X av += optind;
X
X /* Set signal catcher, open temp files. */
X SetSigs(TRUE, Catch);
X Dname = mktemp("/tmp/findDXXXXXX");
X Fname = mktemp("/tmp/findFXXXXXX");
X Dfile = fopen(Dname, "w");
X Ffile = fopen(Fname, "w");
X
X /* Read list of files, determine their status. */
X if (*av)
X for (DEVTTY = stdin; *av; av++)
X Process(*av, 0);
X else
X while (fgets(buff, sizeof buff, stdin)) {
X if (p = IDX(buff, '\n'))
X *p = '\0';
X else
X Fprintf(stderr, "Warning, line too long:\n\t%s\n", buff);
X Process(buff, 0);
X }
X
X /* First print directories. */
X if (freopen(Dname, "r", Dfile)) {
X while (fgets(buff, sizeof buff, Dfile))
X (void)fputs(buff, stdout);
X (void)fclose(Dfile);
X }
X
X /* Now print regular files. */
X if (freopen(Fname, "r", Ffile)) {
X while (fgets(buff, sizeof buff, Ffile))
X (void)fputs(buff, stdout);
X (void)fclose(Ffile);
X }
X
X /* That's all she wrote. */
X (void)unlink(Dname);
X (void)unlink(Fname);
X exit(0);
X}
END_OF_FILE
if test 7195 -ne `wc -c <'findsrc.c'`; then
echo shar: \"'findsrc.c'\" unpacked with wrong size!
fi
# end of 'findsrc.c'
fi
if test -f 'makekit.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'makekit.c'\"
else
echo shar: Extracting \"'makekit.c'\" \(10488 characters\)
sed "s/^X//" >'makekit.c' <<'END_OF_FILE'
X/*
X** MAKEKIT
X** Split up source files into reasonably-sized shar lists.
X*/
X#include "shar.h"
X#ifdef RCSID
static char RCS[] =
X "$Header: makekit.c,v 2.0 88/05/27 13:27:31 rsalz Exp $";
X#endif /* RCSID */
X
X
X/*
X** Our block of information about the files we're doing.
X*/
typedef struct _block {
X char *Name; /* Filename */
X char *Text; /* What it is */
X int Where; /* Where it is */
X int Type; /* Directory or file? */
X long Bsize; /* Size in bytes */
X} BLOCK;
X
X
X/*
X** Our block of information about the archives we're making.
X*/
typedef struct _archive {
X int Count; /* Number of files */
X long Asize; /* Bytes used by archive */
X} ARCHIVE;
X
X
X/*
X** Format strings; these are strict K&R so you shouldn't have to change them.
X*/
X#define FORMAT1 " %-25s %2d\t%s\n"
X#define FORMAT2 "%s%2.2d"
X#ifdef FMT02d
X#undef FORMAT2
X#define FORMAT2 "%s%02.2d" /* I spoke too soon... */
X#endif /* FMT02d */
X
X
X/*
X** Global variables.
X*/
char *InName; /* File with list to pack */
char *OutName; /* Where our output goes */
char *SharName = "Part"; /* Prefix for name of each shar */
char *Trailer; /* Text for shar to pack in */
char *TEMP; /* Temporary manifest file */
X#ifdef MSDOS
char *FLST; /* File with list for shar */
X#endif MSDOS
int ArkCount = 20; /* Max number of archives */
int ExcludeIt; /* Leave out the output file? */
int Header; /* Lines of prolog in input */
int Preserve; /* Preserve order for Manifest? */
int Working = TRUE; /* Call shar when done? */
long Size = 55000; /* Largest legal archive size */
X
X
X/*
X** Sorting predicate to put README or MANIFEST first, then directories,
X** then larger files, then smaller files, which is how we want to pack
X** stuff in archives.
X*/
static int
SizeP(t1, t2)
X BLOCK *t1;
X BLOCK *t2;
X{
X long i;
X
X if (t1->Type == F_DIR)
X return(t2->Type == F_DIR ? 0 : -1);
X if (t2->Type == F_DIR)
X return(1);
X if (EQn(t1->Name, "README", 6) || (OutName && EQ(t1->Name, OutName)))
X return(-1);
X if (EQn(t2->Name, "README", 6) || (OutName && EQ(t2->Name, OutName)))
X return(1);
X return((i = t1->Bsize - t2->Bsize) == 0L ? 0 : (i < 0L ? -1 : 1));
X}
X
X
X/*
X** Sorting predicate to get things in alphabetical order, which is how
X** we write the Manifest file.
X*/
static int
NameP(t1, t2)
X BLOCK *t1;
X BLOCK *t2;
X{
X int i;
X
X return((i = *t1->Name - *t2->Name) ? i : strcmp(t1->Name, t2->Name));
X}
X
X
X/*
X** Skip whitespace.
X*/
static char *
Skip(p)
X REGISTER char *p;
X{
X while (*p && WHITE(*p))
X p++;
X return(p);
X}
X
X
X/*
X** Signal handler. Clean up and die.
X*/
static sigret_t
Catch(s)
X int s;
X{
X int e;
X
X e = errno;
X if (TEMP)
X (void)unlink(TEMP);
X#ifdef MSDOS
X if (FLST)
X (void)unlink(FLST);
X#endif /* MSDOS */
X Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
X exit(1);
X}
X
X
main(ac, av)
X REGISTER int ac;
X char *av[];
X{
X REGISTER FILE *F;
X REGISTER FILE *In;
X REGISTER BLOCK *t;
X REGISTER ARCHIVE *k;
X REGISTER char *p;
X REGISTER int i;
X REGISTER int lines;
X REGISTER int Value;
X BLOCK *Table;
X BLOCK *TabEnd;
X ARCHIVE *Ark;
X ARCHIVE *ArkEnd;
X char buff[BUFSIZ];
X long lsize;
X int LastOne;
X int Start;
X int Notkits;
X char EndArkNum[20];
X char CurArkNum[20];
X
X /* Collect input. */
X Value = FALSE;
X Notkits = FALSE;
X while ((i = getopt(ac, av, "1eh:i:k:n:mo:p:s:t:x")) != EOF)
X switch (i) {
X default:
X Fprintf(stderr,
X"usage: makekit -e -s# [-m | -iMANIFEST -oMANIFEST -h2] -nName -tText files..."
X );
X exit(1);
X case '1':
X Notkits = TRUE;
X break;
X case 'e':
X ExcludeIt = TRUE;
X break;
X case 'h':
X Header = atoi(optarg);
X break;
X case 'i':
X InName = optarg;
X break;
X case 'k':
X ArkCount = atoi(optarg);
X break;
X case 'm':
X InName = OutName = "MANIFEST";
X Header = 2;
X break;
X case 'n':
X SharName = optarg;
X break;
X case 'o':
X OutName = optarg;
X break;
X case 'p':
X Preserve = TRUE;
X break;
X case 's':
X Size = atoi(optarg);
X if (IDX(optarg, 'k') || IDX(optarg, 'K'))
X Size *= 1024;
X break;
X case 't':
X Trailer = optarg;
X break;
X case 'x':
X Working = FALSE;
X break;
X }
X ac -= optind;
X av += optind;
X
X /* Write the file list to a temp file. */
X TEMP = mktemp("/tmp/maniXXXXXX");
X F = fopen(TEMP, "w");
X SetSigs(TRUE, Catch);
X if (av[0])
X /* Got the arguments on the command line. */
X while (*av)
X Fprintf(F, "%s\n", *av++);
X else {
X /* Got the name of the file from the command line. */
X if (InName == NULL)
X In = stdin;
X else if ((In = fopen(InName, "r")) == NULL) {
X Fprintf(stderr, "Can't read %s as manifest, %s.\n",
X InName, Ermsg(errno));
X exit(1);
X }
X /* Skip any possible prolog, then output rest of file. */
X while (--Header >= 0 && fgets(buff, sizeof buff, In))
X ;
X if (feof(In)) {
X Fprintf(stderr, "Nothing but header lines in list!?\n");
X exit(1);
X }
X while (fgets(buff, sizeof buff, In))
X fputs(buff, F);
X if (In != stdin)
X (void)fclose(In);
X }
X (void)fclose(F);
X
X /* Count number of files, allow for NULL and our output file. */
X F = fopen(TEMP, "r");
X for (lines = 2; fgets(buff, sizeof buff, F); lines++)
X ;
X rewind(F);
X
X /* Read lines and parse lines, see if we found our OutFile. */
X Table = NEW(BLOCK, lines);
X for (t = Table, Value = FALSE, lines = 0; fgets(buff, sizeof buff, F); ) {
X /* Read line, skip first word, check for blank line. */
X if (p = IDX(buff, '\n'))
X *p = '\0';
X else
X Fprintf(stderr, "Warning, line truncated:\n%s\n", buff);
X p = Skip(buff);
X if (*p == '\0')
X continue;
X
X /* Copy the line, snip off the first word. */
X for (p = t->Name = COPY(p); *p && !WHITE(*p); p++)
X ;
X if (*p)
X *p++ = '\0';
X
X /* Skip <spaces><digits><spaces>; remainder is the file description. */
X for (p = Skip(p); *p && isdigit(*p); )
X p++;
X t->Text = Skip(p);
X
X /* Get file type. */
X if (!GetStat(t->Name)) {
X Fprintf(stderr, "Can't stat %s (%s), skipping.\n",
X t->Name, Ermsg(errno));
X continue;
X }
X t->Type = Ftype(t->Name);
X
X /* Guesstimate its size when archived: prolog, plus one char/line. */
X t->Bsize = strlen(t->Name) * 3 + 200;
X if (t->Type == F_FILE) {
X lsize = Fsize(t->Name);
X t->Bsize += lsize + lsize / 60;
X }
X if (t->Bsize > Size) {
X Fprintf(stderr, "At %ld bytes, %s is too big for any archive!\n",
X t->Bsize, t->Name);
X exit(1);
X }
X
X /* Is our ouput file there? */
X if (!Value && OutName && EQ(OutName, t->Name))
X Value = TRUE;
X
X /* All done -- advance to next entry. */
X t++;
X }
X (void)fclose(F);
X (void)unlink(TEMP);
X SetSigs(S_RESET, (sigret_t (*)())NULL);
X
X /* Add our output file? */
X if (!ExcludeIt && !Value && OutName) {
X t->Name = OutName;
X t->Text = "This shipping list";
X t->Type = F_FILE;
X t->Bsize = lines * 60;
X t++;
X }
X
X /* Sort by size, get archive space. */
X lines = t - Table;
X TabEnd = &Table[lines];
X if (!Preserve)
X qsort((char *)Table, lines, sizeof Table[0], SizeP);
X Ark = NEW(ARCHIVE, ArkCount);
X ArkEnd = &Ark[ArkCount];
X
X /* Loop through the pieces, and put everyone into an archive. */
X for (t = Table; t < TabEnd; t++) {
X for (k = Ark; k < ArkEnd; k++)
X if (t->Bsize + k->Asize < Size) {
X k->Asize += t->Bsize;
X t->Where = k - Ark;
X k->Count++;
X break;
X }
X if (k == ArkEnd) {
X Fprintf(stderr, "'%s' doesn't fit -- need more then %d archives.\n",
X t->Name, ArkCount);
X exit(1);
X }
X /* Since our share doesn't build sub-directories... */
X if (t->Type == F_DIR && k != Ark)
X Fprintf(stderr, "Warning: directory '%s' is in archive %d\n",
X t->Name, k - Ark + 1);
X }
X
X /* Open the output file. */
X if (OutName == NULL)
X F = stdout;
X else {
X if (GetStat(OutName)) {
X /* Handle /foo/bar/VeryLongFileName.BAK for non-BSD sites. */
X (void)sprintf(buff, "%s.BAK", OutName);
X p = (p = RDX(buff, '/')) ? p + 1 : buff;
X if (strlen(p) > 14)
X /* ... well, sort of handle it. */
X (void)strcpy(&p[10], ".BAK");
X Fprintf(stderr, "Renaming %s to %s\n", OutName, buff);
X (void)unlink(buff);
X (void)link(OutName, buff);
X (void)unlink(OutName);
X }
X if ((F = fopen(OutName, "w")) == NULL) {
X Fprintf(stderr, "Can't open '%s' for output, %s.\n",
X OutName, Ermsg(errno));
X exit(1);
X }
X }
X
X /* Sort the shipping list, then write it. */
X if (!Preserve)
X qsort((char *)Table, lines, sizeof Table[0], NameP);
X Fprintf(F, " File Name\t\tArchive #\tDescription\n");
X Fprintf(F, "-----------------------------------------------------------\n");
X for (t = Table; t < TabEnd; t++)
X Fprintf(F, FORMAT1, t->Name, t->Where + 1, t->Text);
X
X /* Close output. Are we done? */
X if (F != stdout)
X (void)fclose(F);
X if (!Working)
X exit(0);
X
X /* Find last archive number. */
X for (i = 0, t = Table; t < TabEnd; t++)
X if (i < t->Where)
X i = t->Where;
X LastOne = i + 1;
X
X /* Find archive with most files in it. */
X for (i = 0, k = Ark; k < ArkEnd; k++)
X if (i < k->Count)
X i = k->Count;
X
X /* Build the fixed part of the argument vector. */
X av = NEW(char*, i + 10);
X av[0] = "shar";
X i = 1;
X if (Trailer) {
X av[i++] = "-t";
X av[i++] = Trailer;
X }
X if (Notkits == FALSE) {
X (void)sprintf(EndArkNum, "%d", LastOne);
X av[i++] = "-e";
X av[i++] = EndArkNum;
X av[i++] = "-n";
X av[i++] = CurArkNum;
X }
X#ifdef MSDOS
X av[i++] = "-i";
X av[i++] = FLST = mktemp("/tmp/manlXXXXXX");
X#endif /* MSDOS */
X
X av[i++] = "-o";
X av[i++] = buff;
X
X /* Call shar to package up each archive. */
X for (Start = i, i = 0; i < LastOne; i++) {
X (void)sprintf(CurArkNum, "%d", i + 1);
X (void)sprintf(buff, FORMAT2, SharName, i + 1);
X#ifndef MSDOS
X for (lines = Start, t = Table; t < TabEnd; t++)
X if (t->Where == i)
X av[lines++] = t->Name;
X av[lines] = NULL;
X#else
X if ((F = fopen(FLST, "w")) == NULL) {
X Fprintf(stderr, "Can't open list file '%s' for output, %s.\n",
X FLST, Ermsg(errno));
X exit(1);
X }
X for (t = Table; t < TabEnd; t++)
X if (t->Where == i)
X Fprintf(F, "%s\n", t->Name);
X (void)fclose(F);
X#endif /* MSDOS */
X Fprintf(stderr, "Packing kit %d...\n", i + 1);
X if (lines = Execute(av))
X Fprintf(stderr, "Warning: shar returned status %d.\n", lines);
X }
X
X#ifdef MSDOS
X (void)unlink(FLST);
X#endif /* MSDOS */
X /* That's all she wrote. */
X exit(0);
X}
END_OF_FILE
if test 10488 -ne `wc -c <'makekit.c'`; then
echo shar: \"'makekit.c'\" unpacked with wrong size!
fi
# end of 'makekit.c'
fi
if test -f 'shar.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'shar.c'\"
else
echo shar: Extracting \"'shar.c'\" \(7551 characters\)
sed "s/^X//" >'shar.c' <<'END_OF_FILE'
X/*
X** SHAR
X** Make a shell archive of a list of files.
X*/
X#include "shar.h"
X#ifdef RCSID
static char RCS[] =
X "$Header: shar.c,v 2.0 88/05/27 14:10:47 rsalz Exp $";
X#endif /* RCSID */
X
X/*
X** Minimum allocation of file name pointers used in "-i" option processing.
X*/
X#define MIN_FILES 50
X
X
X/*
X** This prolog is output before the archive.
X*/
static char *Prolog[] = {
X "! /bin/sh",
X " This is a shell archive. Remove anything before this line, then unpack",
X " it by saving it into a file and typing \"sh file\". To overwrite existing",
X " files, type \"sh file -c\". You can also feed this as standard input via",
X " unshar, or by typing \"sh <file\", e.g.. If this archive is complete, you",
X " will see the following message at the end:",
X NULL
X};
X
X
X/*
X** Package up one file or directory.
X*/
static void
shar(file, Basename)
X char *file;
X int Basename;
X{
X REGISTER char *s;
X REGISTER char *Name;
X REGISTER int Bads;
X REGISTER off_t Size;
X char buf[BUFSIZ];
X
X /* Just in case. */
X if (EQ(file, ".") || EQ(file, ".."))
X return;
X
X Size = Fsize(file);
X Name = Basename && (Name = RDX(file, '/')) ? Name + 1 : file;
X
X /* Making a directory? */
X if (Ftype(file) == F_DIR) {
X Printf("if test ! -d '%s' ; then\n", Name);
X Printf(" echo shar: Creating directory \\\"'%s'\\\"\n", Name);
X Printf(" mkdir '%s'\n", Name);
X Printf("fi\n");
X }
X else {
X if (freopen(file, "r", stdin) == NULL) {
X Fprintf(stderr, "Can't open %s, %s\n", file, Ermsg(errno));
X exit(1);
X }
X
X /* Emit the per-file prolog. */
X Printf("if test -f '%s' -a \"${1}\" != \"-c\" ; then \n", Name);
X Printf(" echo shar: Will not clobber existing file \\\"'%s'\\\"\n",
X Name);
X Printf("else\n");
X Printf("echo shar: Extracting \\\"'%s'\\\" \\(%ld character%s\\)\n",
X Name, (long)Size, Size == 1 ? "" : "s");
X Printf("sed \"s/^X//\" >'%s' <<'END_OF_FILE'\n", Name, Name);
X
X /* Output the file contents. */
X for (Bads = 0; fgets(buf, BUFSIZ, stdin); )
X if (buf[0]) {
X if (buf[0] == 'X' || buf[0] == 'E' || buf[0] == 'F'
X || !isalpha(buf[0]))
X /* Protect non-alpha's, the shar pattern character, the
X * END_OF_FILE message, and mail "From" lines. */
X (void)putchar('X');
X for (s = buf; *s; s++) {
X if (BADCHAR(*s))
X Bads++;
X (void)putchar(*s);
X }
X }
X
X /* Tell about and control characters. */
X Printf("END_OF_FILE\n", Name);
X if (Bads) {
X Printf(
X "echo shar: %d control character%s may be missing from \\\"'%s'\\\"\n",
X Bads, Bads == 1 ? "" : "s", Name);
X Fprintf(stderr, "Found %d control char%s in \"'%s'\"\n",
X Bads, Bads == 1 ? "" : "s", Name);
X }
X
X /* Output size check. */
X Printf("if test %ld -ne `wc -c <'%s'`; then\n", (long)Size, Name);
X Printf(" echo shar: \\\"'%s'\\\" unpacked with wrong size!\n", Name);
X Printf("fi\n");
X
X /* Executable? */
X if (Fexecute(file))
X Printf("chmod +x '%s'\n", Name);
X
X Printf("# end of '%s'\nfi\n", Name);
X }
X}
X
X
X/*
X** Read list of files from file.
X*/
static char **
GetFiles(Name)
X char *Name;
X{
X REGISTER FILE *F;
X REGISTER int i;
X REGISTER int count;
X REGISTER char **files;
X REGISTER char **temp;
X REGISTER int j;
X char buff[BUFSIZ];
X char *p;
X
X /* Open the file. */
X if (EQ(Name, "-"))
X F = stdin;
X else if ((F = fopen(Name, "r")) == NULL) {
X Fprintf(stderr, "Can't open '%s' for input.\n", Name);
X return(NULL);
X }
X
X /* Get space. */
X count = MIN_FILES;
X files = NEW(char*, count);
X
X /* Read lines. */
X for (i = 0; fgets(buff, sizeof buff, F); ) {
X if (p = IDX(buff, '\n'))
X *p = '\0';
X files[i] = COPY(buff);
X if (++i == count - 2) {
X /* Get more space; some systems don't have realloc()... */
X for (count += MIN_FILES, temp = NEW(char*, count), j = 0; j < i; j++)
X temp[j] = files[j];
X files = temp;
X }
X }
X
X /* Clean up, close up, return. */
X files[i] = NULL;
X (void)fclose(F);
X return(files);
X}
X
X
X
main(ac, av)
X int ac;
X REGISTER char *av[];
X{
X REGISTER char *Trailer;
X REGISTER char *p;
X REGISTER char *q;
X REGISTER int i;
X REGISTER int length;
X REGISTER int Oops;
X REGISTER int Knum;
X REGISTER int Kmax;
X REGISTER int Basename;
X REGISTER int j;
X time_t clock;
X char **Flist;
X
X /* Parse JCL. */
X Basename = 0;
X Knum = 0;
X Kmax = 0;
X Trailer = NULL;
X for (Oops = 0; (i = getopt(ac, av, "be:i:n:o:t:")) != EOF; )
X switch (i) {
X default:
X Oops++;
X break;
X case 'b':
X Basename++;
X break;
X case 'e':
X Kmax = atoi(optarg);
X break;
X case 'i':
X Flist = GetFiles(optarg);
X break;
X case 'n':
X Knum = atoi(optarg);
X break;
X case 'o':
X if (freopen(optarg, "w", stdout) == NULL) {
X Fprintf(stderr, "Can't open %s for output, %s.\n",
X optarg, Ermsg(errno));
X Oops++;
X }
X break;
X case 't':
X Trailer = optarg;
X break;
X }
X
X /* Rest of arguments are files. */
X if (Flist == NULL) {
X av += optind;
X if (*av == NULL) {
X Fprintf(stderr, "No input files\n");
X Oops++;
X }
X Flist = av;
X }
X
X if (Oops) {
X Fprintf(stderr,
X "USAGE: shar [-b] [-o:] [-i:] [-n:e:t:] file... >SHAR\n");
X exit(1);
X }
X
X /* Everything readable and reasonably-named? */
X for (Oops = 0, i = 0; p = Flist[i]; i++)
X if (freopen(p, "r", stdin) == NULL) {
X Fprintf(stderr, "Can't read %s, %s.\n", p, Ermsg(errno));
X Oops++;
X }
X else
X for (; *p; p++)
X if (!isascii(*p)) {
X Fprintf(stderr, "Bad character '%c' in '%s'.\n",
X *p, Flist[i]);
X Oops++;
X }
X if (Oops)
X exit(2);
X
X /* Prolog. */
X for (i = 0; p = Prolog[i]; i++)
X Printf("#%s\n", p);
X if (Knum && Kmax)
X Printf("#\t\t\"End of archive %d (of %d).\"\n", Knum, Kmax);
X else
X Printf("#\t\t\"End of shell archive.\"\n");
X Printf("# Contents: ");
X for (length = 12, i = 0; p = Flist[i++]; length += j) {
X if (Basename && (q = RDX(p, '/')))
X p = q + 1;
X j = strlen(p) + 1;
X if (length + j < WIDTH)
X Printf(" %s", p);
X else {
X Printf("\n# %s", p);
X length = 4;
X }
X }
X Printf("\n");
X clock = time((time_t *)NULL);
X Printf("# Wrapped by %s@%s on %s", User(), Host(), ctime(&clock));
X Printf("PATH=/bin:/usr/bin:/usr/ucb ; export PATH\n");
X
X /* Do it. */
X while (*Flist)
X shar(*Flist++, Basename);
X
X /* Epilog. */
X if (Knum && Kmax) {
X Printf("echo shar: End of archive %d \\(of %d\\).\n", Knum, Kmax);
X Printf("cp /dev/null ark%disdone\n", Knum);
X Printf("MISSING=\"\"\n");
X Printf("for I in");
X for (i = 0; i < Kmax; i++)
X Printf(" %d", i + 1);
X Printf(" ; do\n");
X Printf(" if test ! -f ark${I}isdone ; then\n");
X Printf("\tMISSING=\"${MISSING} ${I}\"\n");
X Printf(" fi\n");
X Printf("done\n");
X Printf("if test \"${MISSING}\" = \"\" ; then\n");
X if (Kmax == 1)
X Printf(" echo You have the archive.\n");
X else if (Kmax == 2)
X Printf(" echo You have unpacked both archives.\n");
X else
X Printf(" echo You have unpacked all %d archives.\n", Kmax);
X if (Trailer && *Trailer)
X Printf(" echo \"%s\"\n", Trailer);
X Printf(" rm -f ark[1-9]isdone%s\n",
X Kmax >= 9 ? " ark[1-9][0-9]isdone" : "");
X Printf("else\n");
X Printf(" echo You still need to unpack the following archives:\n");
X Printf(" echo \" \" ${MISSING}\n");
X Printf("fi\n");
X Printf("## End of shell archive.\n");
X }
X else {
X Printf("echo shar: End of shell archive.\n");
X if (Trailer && *Trailer)
X Printf("echo \"%s\"\n", Trailer);
X }
X
X Printf("exit 0\n");
X
X exit(0);
X}
END_OF_FILE
if test 7551 -ne `wc -c <'shar.c'`; then
echo shar: \"'shar.c'\" unpacked with wrong size!
fi
# end of 'shar.c'
fi
if test -f 'unshar.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'unshar.c'\"
else
echo shar: Extracting \"'unshar.c'\" \(8368 characters\)
sed "s/^X//" >'unshar.c' <<'END_OF_FILE'
X/*
X** UNSHAR
X** Unpack shell archives that might have gone through mail, notes, news, etc.
X** This is Michael Mauldin's code which I have usurped and heavily modified.
X*/
X#include "shar.h"
X#ifdef RCSID
static char RCS[] =
X "$Header: unshar.c,v 2.0 88/05/27 13:28:13 rsalz Exp $";
X#endif /* RCSID */
X
X
X/*
X** Print error message and die.
X*/
static void
Quit(text)
X char *text;
X{
X int e;
X
X e = errno;
X Fprintf(stderr, "unshar: %s", text);
X if (e)
X Fprintf(stderr, ", %s", Ermsg(e));
X Fprintf(stderr, ".\n");
X exit(1);
X}
X
X
X/*
X** Does this look like a mail header line?
X*/
static int
IsHeader(p)
X REGISTER char *p;
X{
X REGISTER int i;
X
X if (*p == '\0' || *p == '\n')
X return(FALSE);
X if (WHITE(*p))
X return(TRUE);
X for (i = 0; *p == '-' || *p == '_' || *p == '.' || isalnum(*p); i++)
X p++;
X return(i && *p == ':');
X}
X
X
X/*
X** Is this a /bin/sh comment line? We check that because some shars
X** output comments before the CUT line.
X*/
static int
IsSHcomment(p)
X REGISTER char *p;
X{
X while (isalpha(*p) || WHITE(*p) || *p == '\n' || *p == ',' || *p == '.')
X p++;
X return(*p == '\0');
X}
X
X
X/*
X** Return TRUE if p has wd1 and wd2 as words (i.e., no preceeding or
X** following letters). Clever code, Michael.
X*/
static int
Has(p, wd1, wd2)
X REGISTER char *p;
X REGISTER char *wd1;
X REGISTER char *wd2;
X{
X REGISTER char *wd;
X REGISTER int first;
X
X wd = wd1;
X first = TRUE;
again:
X while (*p) {
X if (!isalpha(*p)) {
X p++;
X continue;
X }
X while (*p++ == *wd++) {
X if (*wd == '\0') {
X if (!isalpha(*p)) {
X if (!first)
X return(TRUE);
X first = FALSE;
X wd = wd2;
X goto again;
X }
X break;
X }
X }
X while (isalpha(*p))
X p++;
X wd = first ? wd1 : wd2;
X }
X return(FALSE);
X}
X
X
X/*
X** Here's where the work gets done. Skip headers and try to intuit
X** if the file is, e.g., C code, etc.
X*/
static int
XFound(Name, buff, Forced, Stream, Header)
X REGISTER char *Name;
X REGISTER char *buff;
X REGISTER int Forced;
X REGISTER FILE *Stream;
X REGISTER FILE *Header;
X{
X REGISTER char *p;
X REGISTER int InHeader;
X char lower[BUFSIZ];
X
X if (Header)
X InHeader = TRUE;
X
X while (TRUE) {
X /* Read next line, fail if no more */
X if (fgets(buff, BUFSIZ, Stream) == NULL) {
X Fprintf(stderr, "unshar: No shell commands in %s.\n", Name);
X return(FALSE);
X }
X
X /* See if it looks like another language. */
X if (!Forced) {
X if (PREFIX(buff, "#include") || PREFIX(buff, "# include")
X || PREFIX(buff, "#define") || PREFIX(buff, "# define")
X || PREFIX(buff, "#ifdef") || PREFIX(buff, "# ifdef")
X || PREFIX(buff, "#ifndef") || PREFIX(buff, "# ifndef")
X || (PREFIX(buff, "/*")
X && !PREFIX(buff, NOTES1) && !PREFIX(buff, NOTES2)))
X p = "C code";
X else if (PREFIX(buff, "(*")) /* For vi :-) */
X p = "PASCAL code";
X else if (buff[0] == '.' && isalpha(buff[1]) && isalpha(buff[2])
X && !isalpha(buff[3]))
X p = "TROFF source";
X else
X p = NULL;
X if (p) {
X Fprintf(stderr,
X "unshar: %s is apparently %s, not a shell archive.\n",
X Name, p);
X return(FALSE);
X }
X }
X
X /* Does this line start with a shell command or comment? */
X if ((buff[0] == '#' && !IsSHcomment(buff + 1))
X || buff[0] == ':' || PREFIX(buff, "echo ")
X || PREFIX(buff, "sed ") || PREFIX(buff, "cat ")) {
X return(TRUE);
X }
X
X /* Does this line say "Cut here"? */
X for (p = strcpy(lower, buff); *p; p++)
X if (isascii(*p) && islower(*p))
X *p = toupper(*p);
X if (PREFIX(buff, "-----") || Has(lower, "cut", "here")
X || Has(lower, "cut", "cut") || Has(lower, "tear", "here")) {
X /* Get next non-blank line. */
X do {
X if (fgets(buff, BUFSIZ, Stream) == NULL) {
X Fprintf(stderr, "unshar: cut line is last line of %s\n",
X Name);
X return(FALSE);
X }
X } while (*buff == '\n');
X
X /* If it starts with a comment or lower-case letter we win. */
X if (*buff == '#' || *buff == ':' || islower(*buff))
X return(TRUE);
X
X /* The cut message lied. */
X Fprintf(stderr, "unshar: %s is not a shell archive,\n", Name);
X Fprintf(stderr, " the 'cut' line was followed by: %s", buff);
X return(FALSE);
X }
X
X if (Header) {
X (void)fputs(buff, Header);
X if (InHeader && !IsHeader(buff))
X InHeader = FALSE;
X }
X }
X}
X
X
X/*
X** Create file for the header, find true start of the archive,
X** and send it off to the shell.
X*/
static void
Unshar(Name, HdrFile, Stream, Saveit, Forced)
X char *Name;
X char *HdrFile;
X REGISTER FILE *Stream;
X int Saveit;
X int Forced;
X{
X REGISTER FILE *Header;
X#ifndef USE_MY_SHELL
X REGISTER FILE *Pipe;
X#endif /* USE_MY_SHELL */
X char *p;
X char buff[BUFSIZ];
X
X if (Saveit) {
X /* Create a name for the saved header. */
X if (HdrFile)
X (void)strcpy(buff, HdrFile);
X else if (Name) {
X p = RDX(Name, '/');
X (void)strncpy(buff, p ? p + 1 : Name, 14);
X buff[10] = 0;
X (void)strcat(buff, ".hdr");
X }
X else
X (void)strcpy(buff, "UNSHAR.HDR");
X
X /* Tell user, and open the file. */
X Fprintf(stderr, "unshar: Sending header to %s.\n", buff);
X if ((Header = fopen(buff, "a")) == NULL)
X Quit("Can't open file for header");
X }
X else
X Header = NULL;
X
X /* If name is NULL, we're being piped into... */
X p = Name ? Name : "the standard input";
X Printf("unshar: Doing %s:\n", p);
X
X if (Found(p, buff, Forced, Stream, Header)) {
X#ifdef USE_MY_SHELL
X BinSh(Name, Stream, buff);
X#else
X if ((Pipe = popen("/bin/sh", "w")) == NULL)
X Quit("Can't open pipe to /bin/sh process");
X
X (void)fputs(buff, Pipe);
X while (fgets(buff, sizeof buff, Stream))
X (void)fputs(buff, Pipe);
X
X (void)pclose(Pipe);
X#endif /* USE_MY_SHELL */
X }
X
X /* Close the headers. */
X if (Saveit)
X (void)fclose(Header);
X}
X
X
main(ac, av)
X REGISTER int ac;
X REGISTER char *av[];
X{
X REGISTER FILE *Stream;
X REGISTER int i;
X char *p;
X char *HdrFile;
X char cwd[BUFSIZ];
X char dir[BUFSIZ];
X char buff[BUFSIZ];
X int Saveit;
X int Forced;
X
X /* Parse JCL. */
X p = getenv("UNSHARDIR");
X Saveit = DEF_SAVEIT;
X HdrFile = NULL;
X for (Forced = 0; (i = getopt(ac, av, "c:d:fh:ns")) != EOF; )
X switch (i) {
X default:
X Quit("Usage: unshar [-fs] [-c dir] [-h hdrfile] [input files]");
X /* NOTREACHED */
X case 'c':
X case 'd':
X p = optarg;
X break;
X case 'f':
X Forced++;
X break;
X case 'h':
X HdrFile = optarg;
X /* FALLTHROUGH */
X case 's':
X Saveit = TRUE;
X break;
X case 'n':
X Saveit = FALSE;
X break;
X }
X av += optind;
X
X /* Going somewhere? */
X if (p) {
X if (*p == '?') {
X /* Ask for name; go to THE_TTY if we're being piped into. */
X Stream = isatty(fileno(stdin)) ? stdin : fopen(THE_TTY, "r");
X if (Stream == NULL)
X Quit("Can't open tty to ask for directory");
X Printf("unshar: what directory? ");
X (void)fflush(stdout);
X if (fgets(buff, sizeof buff, Stream) == NULL
X || buff[0] == '\n'
X || (p = IDX(buff, '\n')) == NULL)
X Quit("Okay, cancelled");
X *p = '\0';
X p = buff;
X if (Stream != stdin)
X (void)fclose(Stream);
X }
X
X /* If name is ~/blah, he means $HOME/blah. */
X if (*p == '~') {
X if (getenv("HOME") == NULL)
X Quit("You have no $HOME?");
X (void)sprintf(dir, "%s/%s", getenv("HOME"), p + 1);
X p = dir;
X }
X
X /* If we're gonna move, first remember where we were. */
X if (Cwd(cwd, sizeof cwd) == NULL) {
X Fprintf(stderr, "unshar warning: Can't get current directory.\n");
X cwd[0] = '\0';
X }
X
X /* Got directory; try to go there. Only make last component. */
X if (chdir(p) < 0 && mkdir(p, 0777) < 0 && chdir(p) < 0)
X Quit("Cannot chdir nor mkdir desired directory");
X }
X else
X cwd[0] = '\0';
X
X /* No buffering. */
X (void)setbuf(stdout, (char *)NULL);
X (void)setbuf(stderr, (char *)NULL);
X
X if (*av)
X /* Process filenames from command line. */
X for (; *av; av++) {
X if (cwd[0] && av[0][0] != '/') {
X (void)sprintf(buff, "%s/%s", cwd, *av);
X *av = buff;
X }
X if ((Stream = fopen(*av, "r")) == NULL)
X Fprintf(stderr, "unshar: Can't open file '%s'.\n", *av);
X else {
X Unshar(*av, HdrFile, Stream, Saveit, Forced);
X (void)fclose(Stream);
X }
X }
X else
X /* Do standard input. */
X Unshar((char *)NULL, HdrFile, stdin, Saveit, Forced);
X
X /* That's all she wrote. */
X exit(0);
X}
END_OF_FILE
if test 8368 -ne `wc -c <'unshar.c'`; then
echo shar: \"'unshar.c'\" unpacked with wrong size!
fi
# end of 'unshar.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
echo "See the README"
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list