From decwrl!elroy.jpl.nasa.gov!usc!cs.utexas.edu!uunet!allbery Sun Apr 15 18:37:20 PDT 1990
Article 1490 of comp.sources.misc:
Path: decwrl!elroy.jpl.nasa.gov!usc!cs.utexas.edu!uunet!allbery
From: grwalter@watfun.waterloo.edu (Fred Walter)
Newsgroups: comp.sources.misc
Subject: v12i010: newsbreak 1.09
Message-ID: <84768@uunet.UU.NET>
Date: 16 Apr 90 00:38:20 GMT
Sender: allbery@uunet.UU.NET
Organization: University of Waterloo
Lines: 503
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 12, Issue 10
Submitted-by: grwalter@watfun.waterloo.edu (Fred Walter)
Archive-name: newsbreak1.9/part01

Some shar's don't create the necessary sub-directories. New for newsbreak 1.09
are the checks for sed and cat commands that create files, and attempts to
ensure that the directories exist or are created.

#! /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@watfun on Sun Apr 15 02:25:51 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'\" \(12595 characters\)
sed "s/^X//" >'newsbreak.c' <<'END_OF_FILE'
X#define VERSION "newsbreak 1.09 by G. R. Walter"
X
X/*
X * newsbreak.c
X *
X * by G. R. Walter (Fred) December 30, 1988
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 * 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.
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@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@etl.go.jp (Michel Pasquier)
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)
X
Xmain()
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
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    /*
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 (is_a_sharfile(dp[i]->d_name)) {
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            path[200];
X    char           *p;
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	path[0] = '\0';
X	for (p = dir; *p != NULL; p++)
X	    if (*p == '/') {
X		*p = NULL;
X		if (strncmp(p + 1, "part", 4) == 0)
X		    break;
X		if (access(dir, F_OK) < 0)
X		    if (mkdir(dir, 0777) < 0)
X			goto ABORT_ATTEMPT;
X		strcpy(path, archivename);
X		*p = '/';
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		if (path[0] != '\0')
X		    (void) unlink(path);
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 (AN_ARCHIVE(buf))
X	    break;
X    }
X
X    sprintf(path, "%s/.unshar.temp.file", dir);
X    fout = fopen(path, "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    (void) unlink(path);
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     * If the file ends in ".uue" or ".zuu" or ".uu" just uudecode it. Handle
X     * ".zuu#", ".zu#" and ".uu#" where # is a number. 
X     */
X    p = name + strlen(name) - 4;
X    if (strcmp(p, ".uue") && strcmp(p, ".zuu") && 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")) {
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")) {
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	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 * is_a_sharfile - return -1 if a sharfile, 0 otherwise.
X *               - as well, set the global variable ArchiveName
X */
X
Xint
Xis_a_sharfile(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) {	/* not a shar file !? */
X	    break;
X	} else if (strncmp(buf, "Archive-name:", 13) == 0) {
X	    sscanf(buf, "Archive-name: %s", ArchiveName);
X	} else if (AN_ARCHIVE(buf)) {
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 12595 -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
grwalter@watmath.uwaterloo.ca                  (Canadian domain)
grwalter@watmath.waterloo.edu                  (US Internet, including CSNET)
grwalter@watmath.waterloo.cdn                  (CDNnet and some European nets)
watmath!grwalter                               (UUCP)


