|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 11108 (0x2b64)
Types: TextFile
Names: »shar.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦579681f02⟧ »EurOpenD3/utils/shar.tar.Z«
└─⟦221e0edf4⟧
└─⟦this⟧ »shar/shar.c«
/*
Shar puts readable text files together in a package
from which they are extracted with /bin/sh and friends.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#ifndef lint
static char sccsid[] = "@(#)shar.c 2.0 (Usenet) 3/11/86";
#endif
typedef int Boole;
#define TRUE ((Boole) 1)
#define FALSE ((Boole) 0)
typedef int Status;
#define SUCCESS 0
#define FAILURE 1
/* GLOBALS */
int Lastchar; /* the last character printed */
int Ctrlcount; /* how many bad control characters are in file */
/* COMMANDS */
#define EXTRACT "#! /bin/sh" /* magic exec string at shar file start */
#define PATH "/bin:/usr/bin:$PATH" /* search path for programs */
#define CAT "cat"; /* /bin/cat */
#define SED "sed 's/^%s//'" /* /bin/sed removes Prefix from lines */
#define MKDIR "mkdir" /* make a new dirctory */
#define CHMOD "chmod" /* change file mode */
#define CHDIR "cd" /* change current directory */
#define TEST "test" /* /bin/test files */
#define WC_C "wc -c <" /* counts chars in file */
#define ECHO "echo shar:" /* echo a message to extractor */
#define DECODE "uudecode" /* used to decode uuencoded files */
\f
/*FUNCTION main: traverse files to make archive to standard output */
main (argc, argv) char **argv;
{
int shar ();
int optind;
if ((optind = initial (argc, argv)) < 0)
exit (FAILURE);
if (header (argc, argv, optind))
exit (FAILURE);
while (optind < argc)
traverse (argv[optind++], shar);
footer ();
exit (SUCCESS);
}
\f
/* OPTIONS */
Boole Verbose = FALSE; /* provide append/extract feedback */
Boole Basename = FALSE; /* extract into basenames */
Boole Count = FALSE; /* count characters to check transfer */
Boole Overcheck = TRUE; /* check overwriting */
Boole Uucode = FALSE; /* uuencode the file */
char *Delim = "SHAR_EOF"; /* put after each file */
char Filter[100] = CAT; /* used to extract archived files */
char *Prefix = NULL; /* line prefix to avoid funny chars */
Boole Modeset = FALSE; /* set exact modes on extraction */
/*FUNCTION: initial: do option parsing and any setup */
int /* returns the index of the first operand file */
initial (argc, argv) char **argv;
{
int errflg = 0;
extern int optind;
extern char *optarg;
int C;
char *optstring = "abcmsuvp:d:";
char *usage = "[-abcmsuv] [-p prefix] [-d delim] files > archive";
while ((C = getopt (argc, argv, optstring)) != EOF)
switch (C)
{
case 'u': Uucode = TRUE; break;
case 'b': Basename = TRUE; break;
case 'c': Count = TRUE; break;
case 'd': Delim = optarg; break;
case 'm': Modeset = TRUE; break;
case 's': /* silent running */
Overcheck = FALSE;
Verbose = FALSE;
Count = FALSE;
Prefix = NULL;
break;
case 'a': /* all the options */
Verbose = TRUE;
Count = TRUE;
Basename = TRUE;
/* fall through to set prefix */
optarg = "X";
/* FALLTHROUGH */
case 'p': (void) sprintf (Filter, SED, Prefix = optarg); break;
case 'v': Verbose = TRUE; break;
default: errflg++;
}
if (errflg || optind == argc)
{
if (optind == argc)
fprintf (stderr, "shar: No input files\n");
fprintf (stderr, "Usage: shar %s\n", usage);
return (-1);
}
return (optind);
}
\f
/*FUNCTION header: print header for archive */
header (argc, argv, optind)
char **argv;
{
int i;
Boole problems = FALSE;
long clock;
char *ctime ();
char *getenv ();
char *NAME = getenv ("NAME");
char *ORG = getenv ("ORGANIZATION");
for (i = optind; i < argc; i++)
if (access (argv[i], 4)) /* check read permission */
{
fprintf (stderr, "shar: Can't read '%s'\n", argv[i]);
problems++;
}
if (problems)
return (FAILURE);
printf ("%s\n", EXTRACT);
printf ("# This is a shell archive, meaning:\n");
printf ("# 1. Remove everything above the %s line.\n", EXTRACT);
printf ("# 2. Save the resulting text in a file.\n");
printf ("# 3. Execute the file with /bin/sh (not csh) to create:\n");
for (i = optind; i < argc; i++)
printf ("#\t%s\n", argv[i]);
(void) time (&clock);
printf ("# This archive created: %s", ctime (&clock));
if (NAME)
printf ("# By:\t%s (%s)\n", NAME, ORG ? ORG : "");
printf ("export PATH; PATH=%s\n", PATH);
return (SUCCESS);
}
/*FUNCTION footer: print end of shell archive */
footer ()
{
printf ("exit 0\n");
printf ("#\tEnd of shell archive\n");
}
\f
/* uuencode options available to send cntrl and non-ascii chars */
/* really, this is getting to be too much like cpio or tar */
/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) (((c) & 077) + ' ')
/*FUNCTION uuarchive: simulate uuencode to send files */
Status
uuarchive (input, protection, output)
char *input;
int protection;
char *output;
{
FILE *in;
if (in = fopen (input, "r"))
{
printf ("%s << \\%s\n", DECODE, Delim);
printf ("begin %o %s\n", protection, output);
uuencode (in, stdout);
printf ("end\n");
fclose (in);
return (SUCCESS);
}
return (FAILURE);
}
uuencode (in, out)
FILE *in, *out;
{
char buf[80];
int i, n;
for (;;)
{
n = fread (buf, 1, 45, in);
putc (ENC(n), out);
for (i = 0; i < n; i += 3)
outdec (&buf[i], out);
putc ('\n', out);
if (n <= 0)
break;
}
}
/* output one group of 3 bytes, pointed at by p, on file ioptr */
outdec (p, ioptr)
char *p;
FILE *ioptr;
{
int c1, c2, c3, c4;
c1 = *p >> 2;
c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
c4 = p[2] & 077;
putc (ENC(c1), ioptr);
putc (ENC(c2), ioptr);
putc (ENC(c3), ioptr);
putc (ENC(c4), ioptr);
}
\f
/*FUNCTION archive: make archive of input file to be extracted to output */
archive (input, output)
char *input, *output;
{
char buf[BUFSIZ];
FILE *ioptr;
if (ioptr = fopen (input, "r"))
{
Ctrlcount = 0; /* no bad control characters so far */
Lastchar = '\n'; /* simulate line start */
printf ("%s << \\%s > '%s'\n", Filter, Delim, output);
if (Prefix)
{
while (fgets (buf, BUFSIZ, ioptr))
{
if (Prefix) outline (Prefix);
outline (buf);
}
}
else copyout (ioptr);
if (Lastchar != '\n') /* incomplete last line */
putchar ('\n'); /* Delim MUST begin new line! */
if (Count == TRUE && Lastchar != '\n')
printf ("%s \"a missing newline was added to '%s'\"\n", ECHO, input);
if (Count == TRUE && Ctrlcount)
printf ("%s \"%d control character%s may be missing from '%s'\"\n",
ECHO, Ctrlcount, Ctrlcount > 1 ? "s" : "", input);
(void) fclose (ioptr);
return (SUCCESS);
}
else
{
fprintf (stderr, "shar: Can't open '%s'\n", input);
return (FAILURE);
}
}
\f
/*FUNCTION copyout: copy ioptr to stdout */
/*
Copyout copies its ioptr almost as fast as possible
except that it has to keep track of the last character
printed. If the last character is not a newline, then
shar has to add one so that the end of file delimiter
is recognized by the shell. This checking costs about
a 10% difference in user time. Otherwise, it is about
as fast as cat. It also might count control characters.
*/
#define badctrl(c) (iscntrl (c) && !isspace (c))
copyout (ioptr)
register FILE *ioptr;
{
register int C;
register int L;
register count;
count = Count;
while ((C = getc (ioptr)) != EOF)
{
if (count == TRUE && badctrl (C))
Ctrlcount++;
L = putchar (C);
}
Lastchar = L;
}
/*FUNCTION outline: output a line, recoring last character */
outline (s)
register char *s;
{
if (*s)
{
while (*s)
{
if (Count == TRUE && badctrl (*s)) Ctrlcount++;
putchar (*s++);
}
Lastchar = *(s-1);
}
}
\f
/*FUNCTION shar: main archiving routine passed to directory traverser */
shar (file, type, pos)
char *file; /* file or directory to be processed */
int type; /* either 'f' for file or 'd' for directory */
int pos; /* 0 going in to a file or dir, 1 going out */
{
struct stat statbuf;
char *basefile = file;
int protection;
if (!strcmp (file, "."))
return;
if (stat (file, &statbuf))
statbuf.st_size = 0;
else
protection = statbuf.st_mode & 07777;
if (Basename == TRUE)
{
while (*basefile) basefile++; /* go to end of name */
while (basefile > file && *(basefile-1) != '/')
basefile--;
}
if (pos == 0) /* before the file starts */
{
beginfile (basefile, type, statbuf.st_size, protection);
if (type == 'f')
{
if (Uucode)
{
if (uuarchive (file, protection, basefile) != SUCCESS)
exit (FAILURE);
}
else
if (archive (file, basefile) != SUCCESS)
exit (FAILURE);
}
}
else /* pos == 1, after the file is archived */
endfile (basefile, type, statbuf.st_size, protection);
}
\f
/*FUNCTION beginfile: do activities before packing up a file */
beginfile (basefile, type, size, protection)
char *basefile; /* name of the target file */
int type; /* either 'd' for directory, or 'f' for file */
int size; /* size of the file */
int protection; /* chmod protection bits */
{
if (type == 'd')
{
printf ("if %s ! -d '%s'\n", TEST, basefile);
printf ("then\n");
if (Verbose == TRUE)
printf (" %s \"creating directory '%s'\"\n", ECHO, basefile);
printf (" %s '%s'\n", MKDIR, basefile);
printf ("fi\n");
if (Verbose == TRUE)
printf ("%s \"entering directory '%s'\"\n", ECHO, basefile);
printf ("%s '%s'\n", CHDIR, basefile);
}
else /* type == 'f' */
{
if (Verbose == TRUE)
printf ("%s \"extracting '%s'\" '(%d character%s)'\n",
ECHO, basefile, size, size > 1 ? "s" : "");
if (Overcheck == TRUE)
{
printf ("if %s -f '%s'\n", TEST, basefile);
printf ("then\n");
printf (" %s \"will not over-write existing file '%s'\"\n",
ECHO, basefile);
printf ("else\n");
}
}
}
\f
/*FUNCTION endfile: do activities after packing up a file */
endfile (basefile, type, size, protection)
char *basefile; /* name of the target file */
int type; /* either 'd' for directory, or 'f' for file */
int size; /* size of the file */
int protection; /* chmod protection bits */
{
if (type == 'd')
{
if (Modeset == TRUE)
printf ("%s %o .\n", CHMOD, protection);
if (Verbose == TRUE)
printf ("%s \"done with directory '%s'\"\n", ECHO, basefile);
printf ("%s ..\n", CHDIR);
}
else /* type == 'f' (plain file) */
{
printf ("%s\n", Delim);
if (Count == TRUE)
{
printf ("if %s %d -ne \"`%s '%s'`\"\n", TEST, size, WC_C, basefile);
printf ("then\n");
printf (" %s \"error transmitting '%s'\" ", ECHO, basefile);
printf ("'(should have been %d character%s)'\n",
size, size == 1 ? "" : "s");
printf ("fi\n");
}
if (Uucode == FALSE) /* might have to chmod by hand */
{
if (Modeset == TRUE) /* set all protection bits (W McKeeman) */
printf ("%s %o '%s'\n",
CHMOD, protection, basefile);
else if (protection & 0111) /* executable -> chmod +x */
printf ("%s +x '%s'\n", CHMOD, basefile);
}
if (Overcheck == TRUE)
printf ("fi\n");
}
}