v15i107: newsbreak 1.11 - simplify unpacked sources and binaries
Fred Walter
grwalter at watfun.uwaterloo.ca
Tue Dec 18 12:37:31 AEST 1990
Posting-number: Volume 15, Issue 107
Submitted-by: grwalter at watfun.uwaterloo.ca (Fred Walter)
Archive-name: newsbreak1.11/part01
The following is the lastest revision of newsbreak, a program that :
* Takes a series of files which are shar files (strips any
* garbage at the start of the shar file) that have been posted to
* comp.{sources|binaries}.* and feeds them through sh.
* After they have been fed through sh the original files are
* deleted. Then any uuencoded files are uudecoded, after which
* the uuencoded files are also deleted. Special care is taken
* with files posted to comp.binaries.ibm.pc which use a non-standard
* format.
The way I use it is to copy all the files from the newsgroup directory into
a tmp directory and run newsbreak in there.
IE.
mkdir /tmp/grwalter/pc
cd /tmp/grwalter/pc
cp /usr/spool/news/comp/binaries/ibm/pc/* .
newsbreak >& .news.out &
When newsbreak is done the zoo files/etc are nicely put in subdirectories
(with the name found in the Archive-name entry).
----cut here------
#! /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 shell archive."
# Contents: newsbreak.c
# Wrapped by grwalter at watfun on Sun Dec 9 23:36:38 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'newsbreak.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'newsbreak.c'\"
else
echo shar: Extracting \"'newsbreak.c'\" \(14584 characters\)
sed "s/^X//" >'newsbreak.c' <<'END_OF_FILE'
X#define VERSION "newsbreak 1.11 by G. R. Walter"
X
X/*
X * newsbreak.c
X *
X * by G. R. Walter (Fred) December 30, 1988
X *
X * USAGE:
X * newsbreak [-a]
X * If -a is used then all files will be processed. If -a is omitted then
X * only files with an "Archive-name:" will be processed.
X *
X * DESCRIPTION:
X * Takes a series of files which are shar files (strips any
X * garbage at the start of the shar file) that have been posted to
X * comp.{sources|binaries}.* and feeds them through sh.
X * After they have been fed through sh the original files are
X * deleted. Then any uuencoded files are uudecoded, after which
X * the uuencoded files are also deleted. Special care is taken
X * with files posted to comp.binaries.ibm.pc which use a non-standard
X * format.
X *
X * TO COMPILE:
X * Under BSD 4.3
X * cc newsbreak.c -o newsbreak.c
X * Under System V (only those variants that allow -lbsd, which is
X * required for scandir and alphasort)
X * cc newsbreak.c -DSYSTEM_V -lbsd -o newsbreak.c
X *
X * NOTES:
X * 1) This program assumes that all necessary shar files are in the
X * current directory. It attempts to not delete stuff if it can't
X * handle it (like when not all the parts of a multi-part uuencoded
X * file are available).
X * 2) When there are multiple parts to a uuencoded file, a maximum
X * of 99 parts are currently handled.
X *
X * HISTORY:
X * 1.00 - original version
X * 1.01 - small enhancements/bug fixes
X * 1.02 - now handle .zu's with > 9 parts correctly
X * 1.03 - now check for ":\tshar\:Shell Archiver" when checking if a file
X * is a shar archive
X * - now handles files ending in .uu#
X * 1.04 - now check for ": run sh on this file to unbundle" when checking
X * if a file is a shar archive
X * 1.05 - now check for "# This is a shell archive." when checking
X * if a file is a shar archive
X * - now prints out the version (and author name) when run
X * 1.06 - now check for "Archive-name:" to see what directory the
X * resulting files should be put in. NOTE: any parts after
X * a "part*" section in the path are not mkdir'ed
X * - now handles files ending in .zuu#
X * - now handles files ending in .uu# properly
X * - now doesn't attempt to process files starting in "."
X * - now prints some useful info (so you know what it is doing)
X * - now check for "# After you unpack everything" when checking
X * if a file is a shar archive
X * - make sure I don't try to uudecode directories
X * - recursively descend directories when uudecoding
X * 1.07 - added ifdef's around code needed so this compiles under System V
X * - changes by ames!uts.amdahl.com!dwl10 at mailrus (Dave Lowrey)
X * 1.08 - now check for ": This is a shar archive." when checking
X * if a file is a shar archive
X * - now check for "# This is the first line of a \"shell archive\""
X * when checking if a file is a shar archive
X * - build up a list of files in the current directory before unshar'ing
X * - scan these files to see which ones should be unshar'ed and try
X * to determine the best ordering for unshar'ing (using the secondary
X * header "Archive-name:" if it exists, otherwise using file name)
X * - print what directory is being searched for uuencoded files
X * - print what is being uudecoded
X * 1.09 - added code to force creation of all necessary subdirectories
X * - based on code supplied by michel at etl.go.jp (Michel Pasquier)
X * 1.10 - now check for "# type sh " when checking
X * if a file is a shar archive
X * - now check for "# To recover, type \"sh archive\"" when checking
X * if a file is a shar archive
X * - now handle .puu#
X * - effectively do a caseless strncmp() on "part" in unshar() so that
X * things like "Archive-name: nethack3p9/Part01" are properly handled
X * 1.11 - added special case handling for postings to comp.binaries.ibm.pc
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#ifndef SYSTEM_V
Xchar *getwd();
X#else
X# include <dirent.h>
Xchar *getcwd();
X#endif
X
Xchar *malloc();
Xchar *strcpy();
Xchar *sprintf();
X
Xtypedef struct {
X char *filename;
X char *archivename;
X} Name;
X
Xchar ArchiveName[200];
X
X#define AN_ARCHIVE(BUF) \
X( \
X (!strncmp(BUF, "#!/bin/sh", 9)) \
X|| (!strncmp(BUF, "#! /bin/sh", 10)) \
X|| (!strncmp(BUF, "# This is a shell archive.", 26)) \
X|| (!strncmp(BUF, ": This is a shar archive.", 25)) \
X|| (!strncmp(BUF, ":\tshar:\tShell Archiver", 22)) \
X|| (!strncmp(BUF, ": run sh on this file to unbundle", 33)) \
X|| (!strncmp(BUF, "# After you unpack everything", 29)) \
X|| (!strncmp(BUF, "# This is the first line of a \"shell archive\"", 45)) \
X|| (!strncmp(BUF, "# type sh ", 13)) \
X|| (!strncmp(BUF, "# To recover, type \"sh archive\"", 30)) \
X)
X
X#define COMBINE ".newsbreak.combine"
X
Xmain(argc, argv)
X int argc;
X char **argv;
X{
X#ifndef SYSTEM_V
X struct direct **dp;
X#else
X struct dirent **dp;
X#endif
X struct stat stat_buf;
X int size;
X int i;
X int j;
X Name *array;
X int all_flag = 0;
X
X int Select();
X extern int alphasort();
X int compare();
X void unshar();
X void uudecode();
X
X fprintf(stderr, "%s\n", VERSION);
X
X if (argc > 1)
X if (!strcmp(argv[1], "-a"))
X all_flag = -1;
X
X /*
X * Count the sharfiles in the current directory. If there are any, put
X * the filenames and archive-names (if any) into an array and sort it.
X * Then unshar. (This code assumes that the current directory contents
X * don't change underneath you.)
X */
X size = scandir(".", &dp, Select, alphasort);
X if (size > 0) {
X array = (Name *) malloc((unsigned) (sizeof(Name) * size));
X for (i = 0, j = 0; i < size; i++) {
X if (stat(dp[i]->d_name, &stat_buf)) /* can't stat !?!?!? */
X continue;
X
X if ((stat_buf.st_mode & S_IFDIR)) /* a directory */
X continue;
X
X if (has_an_archive_name(dp[i]->d_name) || all_flag) {
X array[j].filename =
X malloc((unsigned) (strlen(dp[i]->d_name) + 1));
X strcpy(array[j].filename, dp[i]->d_name);
X array[j].archivename =
X malloc((unsigned) (strlen(ArchiveName) + 1));
X strcpy(array[j].archivename, ArchiveName);
X j++;
X }
X }
X size = j;
X if (size > 0) {
X fprintf(stderr, "\nNow performing the unshar pass.\n");
X
X qsort((char *) array, size, (int) sizeof(Name), compare);
X
X /* now unshar everything */
X for (i = 0; i < size; i++)
X unshar(array[i].filename, array[i].archivename);
X }
X fprintf(stderr, "\nNow performing the uudecode pass.\n");
X
X uudecode(".", 0);
X }
X /*
X * In theory I should free all allocated memory, but it will be free'd
X * upon exitting.
X */
X exit(0);
X}
X
X/*
X * create_subpath - recursively create subpath
X */
X
Xvoid
Xcreate_subpath(dir, subpath)
X char *dir;
X char *subpath;
X{
X char *p;
X char *newdir;
X
X for (p = subpath; *p != '\0' && *p != '/'; p++);
X
X if (*p == '/') { /* was a sub-directory and not a filename */
X *p++ = '\0';
X newdir = malloc((unsigned) (strlen(dir) + 1 + strlen(subpath) + 1));
X sprintf(newdir, "%s/%s", dir, subpath);
X /*
X * If it doesn't exist then create it.
X */
X if (access(newdir, F_OK) < 0) {
X if (mkdir(newdir, 0777) < 0) {
X fprintf(stderr, "Couldn't mkdir %s\n", newdir);
X return;
X }
X }
X create_subpath(newdir, p);
X free(newdir);
X }
X}
X
X/*
X * ensure_existance_of_subdirs - ensure existance of necessary sub-directories
X *
X * Search for destination file or path and extract its full name
X * then create necessary sub-directories.
X */
X
X#define NOT_END(P) \
X(*P != ' ' && *P != '\'' && *P != '\"' && *P != '\n' && *P != '&' && *P != '\0')
X
Xvoid
Xensure_existance_of_subdirs(p, dir)
X char *p;
X char *dir;
X{
X char *subdirs;
X
X for (; *p != '>' && *p != '\0'; p++); /* Get to start of path. */
X if (*p == '\0')
X return;
X for (p++; (*p == ' ' || *p == '\'' || *p == '\"') && *p != '\0'; p++);
X if (*p == '\0')
X return;
X
X subdirs = p; /* Get to end of path. */
X for (; NOT_END(p); p++);
X *p = '\0';
X
X create_subpath(dir, subdirs);
X}
X
Xvoid
Xunshar(name, archivename)
X char *name;
X char *archivename;
X{
X FILE *fin;
X FILE *fout;
X char buf[200];
X char dir[200];
X char *part = NULL;
X char *p;
X char tmp[4];
X int i;
X
X fprintf(stderr, "Attempting to unshar %s\n", name);
X fin = fopen(name, "r");
X if (fin == NULL) /* file doesn't exist !? */
X return;
X
X strcpy(dir, "."); /* setup directory to use */
X if (archivename[0] != '\0') {
X strcpy(dir, archivename);
X for (p = dir; *p != NULL; p++) {
X if (*p == '/') {
X *p = NULL;
X for (i = 0; i < 4; i++) {
X if (isascii(p[i + 1]) && isupper(p[i + 1]))
X tmp[i] = tolower(p[i + 1]);
X else
X tmp[i] = p[i + 1];
X if (tmp[i] == '\0')
X break;
X }
X if (!strncmp(tmp, "part", 4)) {
X part = p + 1;
X break;
X }
X if (access(dir, F_OK) < 0)
X if (mkdir(dir, 0777) < 0)
X goto ABORT_ATTEMPT;
X *p = '/';
X }
X }
X if (access(dir, F_OK) < 0) {
X if (mkdir(dir, 0777) < 0) {
X ABORT_ATTEMPT:
X fprintf(stderr, "Couldn't mkdir %s\n", dir);
X fprintf(stderr, "Aborting this attempt\n");
X fclose(fin);
X return;
X }
X }
X }
X fprintf(stderr, "unsharing into directory \"%s\"\n", dir);
X
X for (;;) {
X if (fgets(buf, 200, fin) == NULL) { /* not a shar file !? */
X fclose(fin);
X return;
X }
X if (!strncmp(buf, "Newsgroups: comp.binaries.ibm.pc", 32)) {
X if (part != NULL) {
X fclose(fin);
X sprintf(buf, "mv %s %s/%s%s", name, dir, part, COMBINE);
X (void) system(buf);
X return;
X }
X }
X if (AN_ARCHIVE(buf))
X break;
X }
X
X sprintf(buf, "%s/.unshar.temp.file", dir);
X fout = fopen(buf, "w");
X while (fgets(buf, 200, fin) != NULL) {
X fprintf(fout, "%s", buf);
X /*
X * For each source archived ensure existance of necessary
X * sub-directories.
X */
X if (!strncmp(buf, "sed", 3) || !strncmp(buf, "cat", 3))
X ensure_existance_of_subdirs(buf, dir);
X }
X fclose(fout);
X fclose(fin);
X
X sprintf(buf, "cd %s; sh .unshar.temp.file", dir);
X if (system(buf) == 0) {
X (void) unlink(name);
X } else {
X fprintf(stderr, "exit status non-zero, not deleting %s\n", name);
X }
X
X sprintf(buf, "rm %s/.unshar.temp.file", dir);
X (void) system(buf);
X}
X
Xvoid
Xuudecode(name, level)
X char *name;
X int level;
X{
X#ifndef SYSTEM_V
X struct direct **dp;
X#else
X struct dirent **dp;
X#endif
X FILE *file;
X char buf[200];
X char name_buf[200];
X char path[200];
X char *p;
X struct stat stat_buf;
X char digit;
X int i;
X int size;
X
X int Select();
X extern int alphasort();
X
X if (stat(name, &stat_buf)) /* can't stat !?!?!?! */
X return;
X
X if ((stat_buf.st_mode & S_IFDIR)) {
X /* uudecode everything in this directory */
X#ifndef SYSTEM_V
X if (!getwd(path))
X return;
X#else
X if (!getcwd(path, 200))
X return;
X#endif
X size = scandir(name, &dp, Select, alphasort);
X if (size <= 0)
X return;
X
X if (chdir(name))
X return;
X
X level++;
X if (level == 1)
X fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
X else
X fprintf(stderr, "uudecoding in directory \"%s/%s\"\n", path, name);
X for (i = 0; i < size; i++)
X uudecode(dp[i]->d_name, level);
X (void) chdir(path);
X if (level > 1)
X fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
X return;
X }
X /*
X * First combine any files that end in COMBINE.
X */
X p = name + strlen(name) - strlen(COMBINE);
X if (p >= name) {
X if (!strcmp(p, COMBINE)) {
X sprintf(buf, "cat *%s | sed '/^END/,/^BEGIN/d'| uudecode", COMBINE);
X if (system(buf) == 0) {
X sprintf(buf, "rm *%s", COMBINE);
X (void) system(buf);
X }
X return;
X }
X }
X /*
X * If the file ends in ".uue" or ".zuu" ".puu" or ".uu" just uudecode it.
X * Handle ".zuu#", ".puu#", ".pu#", ".zu#" and ".uu#" where # is a
X * number.
X */
X p = name + strlen(name) - 4;
X if (((strcmp(p, ".uue") && strcmp(p, ".zuu") &&
X strcmp(p, ".puu") && strcmp(p + 1, ".uu")))) {
X p += 3;
X while (isdigit(*p))
X p--;
X
X digit = p[1];
X p[1] = '\0';
X p -= 2;
X if (!strcmp(p, ".uu") || !strcmp(p, ".zu") || !strcmp(p, ".pu")) {
X if (digit == '0') {
X sprintf(buf, "cat %s* | uudecode", name);
X } else {
X sprintf(name_buf, "%s10", name);
X file = fopen(name_buf, "r");
X if (file == NULL) {
X sprintf(buf, "cat %s? | uudecode", name);
X } else {
X fclose(file);
X sprintf(buf, "cat %s? %s?? | uudecode", name, name);
X }
X }
X } else if (strcmp(p - 1, ".zuu") && strcmp(p - 1, ".puu")) {
X return;
X }
X }
X sprintf(buf, "cat %s* | uudecode", name);
X fprintf(stderr, "%s\n", buf);
X if (system(buf) == 0) {
X sprintf(buf, "rm %s*", name);
X (void) system(buf);
X } else {
X fprintf(stderr, "exit status non-zero, not deleting file(s)\n");
X }
X}
X
Xint
Xcompare(element1, element2)
X Name *element1;
X Name *element2;
X{
X int result;
X
X result = strcmp(element1->archivename, element2->archivename);
X if (result == 0)
X result = strcmp(element1->filename, element2->filename);
X
X return (result);
X}
X
X/*
X * has_an_archive_name - return -1 if has an archive name, 0 otherwise.
X * - as well, set the global variable ArchiveName
X */
X
Xint
Xhas_an_archive_name(name)
X char *name;
X{
X FILE *fin;
X char buf[200];
X
X ArchiveName[0] = '\0';
X
X fin = fopen(name, "r");
X if (fin == NULL) /* file doesn't exist !? */
X return (0);
X
X for (;;) {
X if (fgets(buf, 200, fin) == NULL) {
X break;
X } else if (strncmp(buf, "Archive-name:", 13) == 0) {
X sscanf(buf, "Archive-name: %s", ArchiveName);
X fclose(fin);
X return (-1);
X }
X }
X fclose(fin);
X return (0);
X}
X
Xint
XSelect(dp)
X#ifndef SYSTEM_V
X struct direct *dp;
X#else
X struct dirent *dp;
X#endif
X{
X if (dp->d_name[0] != '.')
X return (-1);
X else
X return (0);
X}
END_OF_FILE
if test 14584 -ne `wc -c <'newsbreak.c'`; then
echo shar: \"'newsbreak.c'\" unpacked with wrong size!
fi
# end of 'newsbreak.c'
fi
echo shar: End of shell archive.
exit 0
More information about the Comp.sources.misc
mailing list