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