shar.c (another edition + a directory traverser)
perlman at wivax.UUCP
perlman at wivax.UUCP
Sun Dec 16 18:36:15 AEST 1984
Here we go again. I've gotten enough sugestions for my shar.c
that I am posting a new version. The minor changes are that
some potential bugs were removed along with unused features.
The major change is that shar now knows how to march through
a directory hierarchy. This posting should supersede the
versions posted recently.
The traversal is done with a function for marching through directories.
I hope people find it useful for other tasks. I am pretty sure about
its behaviour on pre-Berkeley 4.2 UNIX, but not positive about it
on Berkeley 4.2. If there are any bugs in it, please send fixes to me.
Gary Perlman/Wang Institute/Tyngsboro, MA/01879/(617) 649-9731
shar -v shar.1 shar.c makefile traverse.3 traverse.c
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# shar.1
# shar.c
# makefile
# traverse.3
# traverse.c
echo shar: extracting shar.1
cat - << \SHAR_EOF > shar.1
.TH SHAR 1net "December 16, 1984"
.SH NAME
shar \- create storage archive for extraction by /bin/sh
.SH SYNOPSIS
.B shar
[-v] files
.SH DESCRIPTION
shar prints its input files with special lines around them
to be used by the shell (/bin/sh) to extract them later.
The output can be filtered through the shell to
recreate copies of the original files.
The -v (verbose) option causes feedback messages about
what shar is doing to be printed during extraction.
.PP
shar allows directories to be named,
and shar prints the necessary commands to create
new directories and fill them.
.SH AUTHOR
Gary Perlman
(based on a shell version by James Gosling)
.SH BUGS
shar does not know anything about links between files,
about binary files,
or about overwriting existing files.
SHAR_EOF
echo shar: extracting shar.c
cat - << \SHAR_EOF > shar.c
#include <stdio.h>
/*
Shar puts readable text files together in a package
from which they are easy to extract. The original version
was a shell script posted to the net, shown below:
#Date: Mon Oct 18 11:08:34 1982
#From: decvax!microsof!uw-beave!jim (James Gosling at CMU)
AR=$1
shift
for i do
echo a - $i
echo "echo x - $i" >>$AR
echo "cat >$i <<'!Funky!Stuff!'" >>$AR
cat $i >>$AR
echo "!Funky!Stuff!" >>$AR
done
I rewrote this version in C to provide better diagnostics
and to run faster. The major difference is that my version
does not affect any files because it prints to the standard
output. Mine also has a -v (verbose) option.
Gary Perlman/Wang Institute/Tyngsboro, MA/01879/(617) 649-9731
Some enhancements motivated by Michael Thompson.
I did not put in his feature of using sed to strip
a prefix character because: (1) I did not want the
shar scripts to depend on sed because some systems
do not have it. (2) The convention arose so that
people would not have to worry about the end of input
delimiter being part of the line. This is unlikely
and better handled by having a programmable delimiter.
I don't think even that is necessary.
Directory archiving motivated by Derek Zahn @ wisconsin
His version had some problems, so I wrote a general
routine for traversing a directory hierarchy. It
allows marching through a directory on old and new
UNIX systems.
*/
#define DELIM "SHAR_EOF" /* put after each file */
#define SHAR "shar" /* the name of this program */
#define READ_PERMISSION 4 /* access permission */
int Verbose = 0; /* option to provide append/extract feedback */
main (argc, argv) char **argv;
{
int status = 0;
if (!strcmp (argv[1], "-v"))
{
Verbose = 1;
argc--;
argv++;
}
if (argc == 1)
{
fprintf (stderr, "%s: No input files\n", SHAR);
fprintf (stderr, "USAGE: %s [-v] files > archive\n", SHAR);
exit (1);
}
if (header (argc, argv))
exit (2);
while (--argc)
status += shar (*++argv);
footer ();
exit (status);
}
header (argc, argv)
char **argv;
{
int i;
int problems = 0;
for (i = 1; i < argc; i++)
if (access (argv[i], READ_PERMISSION))
{
fprintf (stderr, "%s: Can't read %s\n", SHAR, argv[i]);
problems++;
}
if (problems) return (problems);
puts ("-----cut here-----cut here-----cut here-----cut here-----");
puts ("#!/bin/sh");
printf ("# %s: Shell Archiver\n", SHAR);
puts ("#\tRun the following text with /bin/sh to create:");
for (i = 1; i < argc; i++)
printf ("#\t%s\n", argv[i]);
return (0);
}
footer ()
{
puts ("#That's all folks!");
puts ("exit 0");
}
archive (file)
char *file;
{
char line[BUFSIZ];
FILE *ioptr;
if (ioptr = fopen (file, "r"))
{
printf ("cat - << \\%s > %s\n", DELIM, file);
while (fgets (line, BUFSIZ, ioptr))
fputs (line, stdout);
(void) fclose (ioptr);
puts (DELIM);
return (0);
}
else
{
fprintf (stderr, "%s: Can't open %s\n", SHAR, file);
return (1);
}
}
shar (file)
char *file;
{
int rshar ();
traverse (file, rshar);
}
rshar (file, type, place)
{
if (!strcmp (file, ".")) return;
if (place == 0)
{
if (type == 'd')
{
if (Verbose)
printf ("echo %s: creating directory %s\n", SHAR, file);
printf ("mkdir %s\n", file);
printf ("chdir %s\n", file);
}
else /* type == 'f' */
{
if (Verbose)
printf ("echo %s: extracting %s\n", SHAR, file);
archive (file);
}
}
else /* place == 1 */
{
if (type == 'd')
{
if (Verbose)
printf ("echo %s: done with directory %s\n", SHAR, file);
printf ("chdir ..\n");
}
}
}
SHAR_EOF
echo shar: extracting makefile
cat - << \SHAR_EOF > makefile
# The SYSTEM variable should be set to BSD4_2 to use the new routines
# specific to that release. Otherwise, the value doesn't matter.
SYSTEM=BSD4_1
CFLAGS=-O
shar: shar.o traverse.o
cc -o shar shar.o traverse.o
traverse.o: traverse.c
cc -D$(SYSTEM) -c $(CFLAGS) traverse.c
SHAR_EOF
echo shar: extracting traverse.3
cat - << \SHAR_EOF > traverse.3
.TH TRAVERSE 3WI "December 16, 1984"
.SH NAME
traverse \- recursively traverse a directory
.SH SYNOPSIS
.nf
traverse (path, func)
char *path;
int (*func) ();
func (path, filetype, position)
char *path;
.fi
.SH DESCRIPTION
traverse
applies its argument function func to its argument file pathname path.
If path is a directory,
then traverse applies func to all its entries.
.PP
The argument func should take three parameters:
a file name,
a file type,
and a position.
The call looks like this for directories:
.ce
(*func) (path, 'd', position);
and like this for other files:
.ce
(*func) (path, 'f', position);
The position
is 0 when path is first encountered
and 1 when traverse is done.
This is used to allow processing before and after
a directory is processed.
.SH EXAMPLE
.nf
list (name, type, pos)
char *name;
{
if (type == 'd')
printf ("%s %s\en", pos ? "Leaving" : "Entering", name);
else /* type == 'f' */
printf (" %s\en", name);
}
.fi
.SH AUTHOR
Gary Perlman
.SH BUGS
There are no diagnostics when directories cannot be searched.
SHAR_EOF
echo shar: extracting traverse.c
cat - << \SHAR_EOF > traverse.c
/*LINTLIBRARY*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#ifdef BSD4_2
#define namedir(entry) (entry->d_name)
#define MAXNAME 256
#else
#define DIR FILE
#define MAXNAME (DIRSIZ+2)
#define opendir(path) fopen (path, "r")
#define closedir(dirp) fclose (dirp)
struct direct *
readdir (dirp)
DIR *dirp;
{
static struct direct entry;
if (dirp == NULL) return (NULL);
for (;;)
{
if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
if (entry.d_ino) return (&entry);
}
}
char *strncpy ();
char *
namedir (entry)
struct direct *entry;
{
static char name[MAXNAME];
return (strncpy (name, entry->d_name, DIRSIZ));
}
#endif
#include <sys/stat.h>
#define isdir(path) (stat(path, &buf) ? 0 : (buf.st_mode&S_IFMT)==S_IFDIR)
traverse (path, func)
char *path;
int (*func) ();
{
DIR *dirp;
struct direct *entry;
struct stat buf;
int filetype = isdir (path) ? 'd' : 'f';
(*func) (path, filetype, 0);
if (filetype == 'd')
{
if (chdir (path) == 0)
{
if (dirp = opendir ("."))
{
while (entry = readdir (dirp))
{
char name[MAXNAME];
(void) strcpy (name, namedir (entry));
if (strcmp(name, ".") && strcmp(name, ".."))
traverse (name, func);
}
(void) closedir(dirp);
}
(void) chdir ("..");
}
}
(*func) (path, filetype, 1);
}
SHAR_EOF
#That's all folks!
exit 0
More information about the Comp.sources.unix
mailing list