[net.sources] shell archiver written in c

perlman@wivax.UUCP (Gary Perlman) (12/05/84)

Here is my shar.  It is somewhat faster than the shell script version:
       14.0 real         1.1 user         5.6 sys  (shell version)
        3.0 real         0.2 user         0.5 sys  (C version)
but another advantage is that it provides better diagnostics (I think).
I know there have been other versions posted, but I saw a recent request.
Gary Perlman/Wang Institute/Tyng Road/Tyngsboro, MA/01879/(617) 649-9731

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	shar.1 #	shar.c 
echo shar: extracting shar.1
cat - << \SHAR_EOF > shar.1
.TH SHAR 1net "December 5, 1984"
.SH NAME
shar \- create storage archive for extraction by /bin/sh
.SH SYNOPSIS
.B shar
[-v] files
.SH DESCRIPTION
.I 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 prints feedback about
what shar is doing.
.SH AUTHOR
Gary Perlman
(based on a shell version by James Gosling)
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 main difference is that my version
does not affect any files because it prints to the standard
output.  Mine also has a -v (verbose) option.
*/


#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);
	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 ("#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----");
	printf ("# %s:	Shell Archiver\n", SHAR);
	puts ("#	Run the following text with /bin/sh to create:");
	for (i = 1; i < argc; i++)
		printf ("#	%s ", argv[i]);
	putchar ('\n');
	return (0);
	}

shar (file)
char	*file;
	{
	char	line[BUFSIZ];
	FILE	*ioptr;
	if (ioptr = fopen (file, "r"))
		{
		if (Verbose)
			{
			fprintf (stderr, "%s: appending %s\n", SHAR, file);
			printf ("echo %s: extracting %s\n", SHAR, file);
			}
		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_EOF
a - shar.c

thompson@dalcs.UUCP (Michael A. Thompson) (12/10/84)

	 I have made several modifications to this program, and thought
    they might be useful to others, so I am posting this modified
    version of Gary Perlman's program. I am posting the whole program
    rather than the diffs, because the diffs would be almost as large.
    My changes incorperate a couple ideas that I have seen used for
    "Shar" type files posted to the net in the past, namely the line
    prefix character removal, and the exit at the end to avoid problems
    with signatures at the end of the article.

-----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
echo shar: extracting shar.1
sed 's/^X//' << 'SHAR_EOF' > shar.1
X.TH SHAR 1net "December 5, 1984"
X.SH NAME
Xshar \- create storage archive for extraction by /bin/sh
X.SH SYNOPSIS
X.B shar
X[-v] [-s] [-d'delimeter'] [-c] files
X.SH DESCRIPTION
X.I shar
Xprints its input files with special lines around them
Xto be used by the shell (/bin/sh) to extract them later.
XThe output can be filtered through the shell to
Xrecreate copies of the original files.
XThe -v (verbose) option prints feedback about
Xwhat shar is doing.
XThe -s (sum) option prints the sums of the orignal and extracted files.
XThe -d (delimeter) option changes the end of file marker to delimeter.
XThe -c (cut here) option cause the "-----Cut Here..." line to be placed
Xat the beginning of the shar archive.
X.SH AUTHOR
XGary Perlman
X(based on a shell version by James Gosling)
XMichael Thompson -- added -s -d and -c options.
SHAR_EOF
echo 'Orignal Sum -> 22089     1'
echo -n 'Current Sum -> '
sum shar.1
echo shar: extracting shar.c
sed 's/^X//' << 'SHAR_EOF' > shar.c
X#ifndef lint
X#ifdef RCSIDENT
Xstatic char *rcsid[] = {
X    "$Header: shar.c,v 1.3 84/12/09 19:38:53 thompson Exp $",
X    "$Locker:  $"
X};
X#endif RCSIDENT
X#endif lint
X#include <stdio.h>
X
X/*
XShar puts readable text files together in a package
Xfrom which they are easy to extract.  The original version
Xwas a shell script posted to the net, shown below:
X	#Date: Mon Oct 18 11:08:34 1982
X	#From: decvax!microsof!uw-beave!jim (James Gosling at CMU)
X	AR=$1
X	shift
X	for i do
X		echo a - $i
X		echo "echo x - $i" >>$AR
X		echo "cat >$i <<'!Funky!Stuff!'" >>$AR
X		cat $i >>$AR
X		echo "!Funky!Stuff!" >>$AR
X	done
XI rewrote this version in C to provide better diagnostics
Xand to run faster.  The main difference is that my version
Xdoes not affect any files because it prints to the standard
Xoutput.  Mine also has a -v (verbose) option.
X*/
X/*
X *	I have made several mods to this program:
X *
X *	1) the -----Cut Here-----... now preceds the script.
X *	2) the cat has been changed to a sed which removes a prefix
X *	character from the beginning of each line of the extracted
X *	file, this prefix character is added to each line of the archived
X *	files and is not the same as the first character of the
X *	file delimeter.
X *	3) added several options:
X *		-c	- add the -----Cut Here-----... line.
X *		-d'del' - change the file delimeter to del.
X *		-s	- cause the resulting script to print the sum of
X *			  the orignal file and the sum of the extracted
X *			  file.
X *
X *				Michael A. Thompson
X *				Dalhousie University
X *				Halifax, N.S., Canada.
X */
X
X#define	DELIM           "SHAR_EOF"/* put after each file */
X#define PREFIX1	        'X'	/* goes infront of each line */
X#define PREFIX2		'Y'	/* goes infront of each line if Delim
X				   starts with PREFIX1 */
X#define PREFIX		(Delim[0] == PREFIX1 ? PREFIX2 : PREFIX1)
X#define	SHAR            "shar"	/* the name of this program */
X#define	READ_PERMISSION 4	/* access permission */
X#define SUM	        "sum"
X
Xint     Verbose = 0;		/* option to provide append/extract
X				   feedback */
Xint     Sum = 0;		/* option to provide sum checking */
Xchar   *Delim = DELIM;		/* option to provide alternate delimeter 
X				*/
Xint     Cut = 0;		/* option to provide cut mark */
X
XFILE * popen ();
X
Xmain (argc, argv) char **argv;
X{
X    int     status = 0;
X
X    while (argv[1][0] == '-') {
X	switch (argv[1][1]) {
X	    case 'v': 
X		Verbose = 1;
X		break;
X	    case 's': 
X		Sum = 1;
X		break;
X	    case 'd': 
X		if (argv[1][2])
X		    Delim = &argv[1][2];
X		break;
X	    case 'c': 
X		Cut = 1;
X		break;
X	    default: 
X		fprintf (stderr, "%s: invalid argument\n", SHAR);
X		fprintf (stderr, "USAGE: %s [-v] [-s] [-d'delimeter'] [-c] files > archive\n", SHAR);
X		break;
X	}
X	argc--;
X	argv++;
X    }
X    if (argc == 1) {
X	fprintf (stderr, "%s: No input files\n", SHAR);
X	fprintf (stderr, "USAGE: %s [-v] [-s] [-d'delimeter'] [-c] files > archive\n", SHAR);
X	exit (1);
X    }
X    if (header (argc, argv))
X	exit (2);
X    while (--argc)
X	status += shar (*++argv);
X    puts ("exit");
X    exit (status);
X}
X
Xheader (argc, argv)
Xchar  **argv;
X{
X    int     i;
X    int     problems = 0;
X    for (i = 1; i < argc; i++)
X	if (access (argv[i], READ_PERMISSION)) {
X	    fprintf (stderr, "%s: Can't read %s\n", SHAR, argv[i]);
X	    problems++;
X	}
X    if (problems)
X	return (problems);
X    if (Cut)
X	puts ("-----Cut Here-----Cut Here-----Cut Here-----Cut Here-----");
X    puts ("#!/bin/sh");
X    printf ("# %s:	Shell Archiver\n", SHAR);
X    puts ("#	Run the following text with /bin/sh to create:");
X    for (i = 1; i < argc; i++)
X	printf ("#	%s\n", argv[i]);
X    return (0);
X}
X
Xshar (file)
Xchar   *file;
X{
X    char    line[BUFSIZ];
X    FILE * ioptr;
X    if (ioptr = fopen (file, "r")) {
X	if (Verbose) {
X	    fprintf (stderr, "%s: appending %s\n", SHAR, file);
X	    printf ("echo %s: extracting %s\n", SHAR, file);
X	}
X	printf ("sed 's/^%c//' << '%s' > %s\n", PREFIX, Delim, file);
X	while (fgets (line, BUFSIZ, ioptr)) {
X	    putc (PREFIX, stdout);
X	    fputs (line, stdout);
X	}
X	(void) fclose (ioptr);
X	puts (Delim);
X	if (Sum) {
X	    FILE * pfp;
X	    char    command[BUFSIZ];
X
X	    sprintf (command, "%s %s", SUM, file);
X	    if ((pfp = popen (command, "r"))) {
X		char    sum[BUFSIZ];
X
X		fgets (sum, BUFSIZ, pfp);
X		sum[strlen (sum) - 1] = '\0';
X		printf ("echo 'Orignal Sum -> %s'\n", sum);
X		puts ("echo -n 'Current Sum -> '");
X		puts (command);
X		pclose (pfp);
X	    }
X	}
X	return (0);
X    }
X    else {
X	fprintf (stderr, "%s: Can't open %s\n", SHAR, file);
X	return (1);
X    }
X}
SHAR_EOF
echo 'Orignal Sum -> 20927     5'
echo -n 'Current Sum -> '
sum shar.c
exit
-- 

Signed:                   Michael A. Thompson
             (ask me no questions, I'll tell you no lies)
Net address:      ...{utcsrgv,dartvax}!dalcs!thompson
Where in the world:      Dalhousie University
                         Halifax, Nova Scotia

salmi@dicome.UUCP (salmi) (03/13/86)

there have been quite a few requests for the shar script in net.sources.wanted.
here is a version written in c that came off the net last year.

enjoy.....

	-john

------------------------------cut here-----------------------------------------
/*
** cshar.c
*/

#ifndef lint
#ifdef RCSIDENT
static char *rcsid[] = {
    "$Header: shar.c,v 1.3 84/12/09 19:38:53 thompson Exp $",
    "$Locker:  $"
};
#endif RCSIDENT
#endif lint
#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 main difference is that my version
does not affect any files because it prints to the standard
output.  Mine also has a -v (verbose) option.
*/
/*
 *	I have made several mods to this program:
 *
 *	1) the -----Cut Here-----... now preceds the script.
 *	2) the cat has been changed to a sed which removes a prefix
 *	character from the beginning of each line of the extracted
 *	file, this prefix character is added to each line of the archived
 *	files and is not the same as the first character of the
 *	file delimeter.
 *	3) added several options:
 *		-c	- add the -----Cut Here-----... line.
 *		-d'del' - change the file delimeter to del.
 *		-s	- cause the resulting script to print the sum of
 *			  the orignal file and the sum of the extracted
 *			  file.
 *
 *				Michael A. Thompson
 *				Dalhousie University
 *				Halifax, N.S., Canada.
 */

#define	DELIM           "SHAR_EOF"/* put after each file */
#define PREFIX1	        'X'	/* goes infront of each line */
#define PREFIX2		'Y'	/* goes infront of each line if Delim
				   starts with PREFIX1 */
#define PREFIX		(Delim[0] == PREFIX1 ? PREFIX2 : PREFIX1)
#define	SHAR            "shar"	/* the name of this program */
#define	READ_PERMISSION 4	/* access permission */
#define SUM	        "sum"

int     Verbose = 0;		/* option to provide append/extract
				   feedback */
int     Sum = 0;		/* option to provide sum checking */
char   *Delim = DELIM;		/* option to provide alternate delimeter 
				*/
int     Cut = 0;		/* option to provide cut mark */

FILE * popen ();

main (argc, argv) char **argv;
{
    int     status = 0;

    while (argv[1][0] == '-') {
	switch (argv[1][1]) {
	    case 'v': 
		Verbose = 1;
		break;
	    case 's': 
		Sum = 1;
		break;
	    case 'd': 
		if (argv[1][2])
		    Delim = &argv[1][2];
		break;
	    case 'c': 
		Cut = 1;
		break;
	    default: 
		fprintf (stderr, "%s: invalid argument\n", SHAR);
		fprintf (stderr, "USAGE: %s [-v] [-s] [-d'delimeter'] [-c] files > archive\n", SHAR);
		break;
	}
	argc--;
	argv++;
    }
    if (argc == 1) {
	fprintf (stderr, "%s: No input files\n", SHAR);
	fprintf (stderr, "USAGE: %s [-v] [-s] [-d'delimeter'] [-c] files > archive\n", SHAR);
	exit (1);
    }
    if (header (argc, argv))
	exit (2);
    while (--argc)
	status += shar (*++argv);
    puts ("exit");
    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);
    if (Cut)
	puts ("-----Cut Here-----Cut Here-----Cut Here-----Cut Here-----");
    puts ("#!/bin/sh");
    printf ("# %s:	Shell Archiver\n", SHAR);
    puts ("#	Run the following text with /bin/sh to create:");
    for (i = 1; i < argc; i++)
	printf ("#	%s\n", argv[i]);
    return (0);
}

shar (file)
char   *file;
{
    char    line[BUFSIZ];
    FILE * ioptr;
    if (ioptr = fopen (file, "r")) {
	if (Verbose) {
	    fprintf (stderr, "%s: appending %s\n", SHAR, file);
	    printf ("echo x - extracting %s\n", SHAR, file);
	}
	printf ("sed 's/^%c//' << '%s' > %s\n", PREFIX, Delim, file);
	while (fgets (line, BUFSIZ, ioptr)) {
	    putc (PREFIX, stdout);
	    fputs (line, stdout);
	}
	(void) fclose (ioptr);
	puts (Delim);
	if (Sum) {
	    FILE * pfp;
	    char    command[BUFSIZ];

	    sprintf (command, "%s %s", SUM, file);
	    if ((pfp = popen (command, "r"))) {
		char    sum[BUFSIZ];

		fgets (sum, BUFSIZ, pfp);
		sum[strlen (sum) - 1] = '\0';
		printf ("echo 'Orignal Sum -> %s'\n", sum);
		puts ("echo -n 'Current Sum -> '");
		puts (command);
		pclose (pfp);
	    }
	}
	return (0);
    }
    else {
	fprintf (stderr, "%s: Can't open %s\n", SHAR, file);
	return (1);
    }
}