[comp.sources.mac] Comb

kevin@kosman.UUCP (Kevin O'Gorman) (06/30/87)

I hope this belongs in this newsgroup: it is a source intended to run
on a UNIX box, but is in service of Macintosh users.

This little program was originally scarfed from usenet as an
unmoderated source.  It has been improved by making it go through lint
a bit better, by making it take more styles of input, by making it more
correct, and by adding a man page.

There is no makefile because it makes okay with just 'make comb'.

The program takes one or more files from mail or usenet postings, trims
headers, commentary and signatures, and attempts to rebuild the
original BinHex output.  I have had good results using it myself.  I
then Red Ryder the stuff onto my Mac, and BinHex usually works just
fine.

...ihnp4 ---\                                 Kevin O'Gorman
...allegra --- philabs!hhb --- kosman!kevin   Anarm Software Systems
...decvax --/                                 17 Wierimus Lane
       Voice: (201) 666-1734                  Hillsdale, NJ 07642

---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	comb.1
#	comb.c
# This archive created: Sun May  3 08:58:51 1987
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'comb.1'" '(1208 characters)'
if test -f 'comb.1'
then
	echo shar: "will not over-write existing file 'comb.1'"
else
sed 's/^X//' << \SHAR_EOF > 'comb.1'
X.TH COMB 1
X.SH NAME
Xcomb \- combine and trim BinHex files
X.SH SYNOPSIS
X.B "comb [-m] [-q] filename [filename]..."
X.SH DESCRIPTION
XA hex file (output of the BinHex program) is rebuilt from inputs that may have
Xmail headers, English text, signatures, and other stuff that needs to be
Xremoved to restore the original file.  The file may have been split into
Xhunks for transmission, in which case there is by default one hunk per file.
XWith the \fB-m\fR flag, the hunks have been combined in a single "mail" file,
Xfrom which headers and other additions must be trimmed.
X.PP
XThe resulting BinHex file is sent to the standard output.  Lines which are
Xremoved are output on standard error unless the \fB-q\fR flag is used.
X.SH DIAGNOSTICS
XExit code 0 is returned on success, 1 for error in the inputs, and 2 for
Xan error on the command line.
XMessages are intended to be self-explanatory.  
X.SH BUGS
XThe code assumes it can determine what is hex code by checking for a few
XEnglish words and any white space.  Lines with neither are taken to begin
Xa hex hunk, and the hunk continues as long as the lines stay the same
Xlength.
X.PP
XThere is no checking of the contents of the line, and the checksums are not
Xexamined.
X
SHAR_EOF
if test 1208 -ne "`wc -c < 'comb.1'`"
then
	echo shar: "error transmitting 'comb.1'" '(should have been 1208 characters)'
fi
fi
echo shar: "extracting 'comb.c'" '(9267 characters)'
if test -f 'comb.c'
then
	echo shar: "will not over-write existing file 'comb.c'"
else
sed 's/^X//' << \SHAR_EOF > 'comb.c'
X/*  comb - prepare binhex files from usenet or mail
X
X    Modified by Kevin O'Gorman to clean it up a bit and to make it work
Xcorrectly on a single input file (just to trim the trash and check for
Xtermination), and on those rare cases where the last line is the same
Xlength as all the others (i.e. the final ':' is the 64th char of a line).
X
X    Also made it a bit cleaner: no gotos, no longer assume (FILE *) is the
Xsame cast as (char *), lint complaints are minimal, tests the number of
Xarguments more closely.
X
X    There is one preprocessor flag, DEBUG.  If this is defined, you get
Xmore verbose output than normal, showing what comb thinks it's doing at
Xvarious points.  With ksh, I can use
X    CFLAGS=-DEBUG make comb
Xor
X    make comb
Xdepending on what I want.
X
X    Original comments follow:
X
X*/
X/*
X    comb - combine split binhex files
X    usage:
X	comb file1 .. fileN > result ; xbin result
X	comb -m file > result ; xbin result
X    compile: cc -o comb comb.c
X
X    binhex files often come across the net split into multiple parts.  I
Xgot sick of re-combining them by hand.  comb is a quick hack that takes 
Xas its arguments a set of files which are the parts
Xof a binhex file.  It splits out the binhex file to standard output.
XIf the parts have been combined into a single file already, with mail
Xheaders and such in between, the "-m" flag can be used.  The text that
Xdoesn't look like binhex goes to standard output, unless the "-q" (for
Xquiet) flag is specified.
X    It's real ugly (even has gotos!), but hey, it works.
X    Author: Greg Dudek
X    Usenet:	{linus, ihnp4, allegra, decvax, floyd}!utcsri!dudek
X*/
X
X#include <stdio.h>
X#define min(a,b)	(a<b?a:b)
X#define index	strchr
X#ifdef DEBUG
X#define EBUG
X#endif
X
X#ifdef EBUG
X#define debug(x)	x
X#else
X#define debug(x)	/**/
X#endif
X
Xint verbose=1;
Xint mailfile = 0;	/* file contains multiple parts */
Xint gotend = 0;		/* found apparent end of binhex data */
Xint eof = 0;		/* found at least 1 eof (only used if mailfile) */
Xextern int substr();    /* defined later */
X
Xmain(argc,argv)
Xchar **argv;
X{
X    int l,i,fnum, curline;
X    char inline[256];
X    char inline2[256];
X    FILE *fd;
X
X    if (argc <= 1) {
X	fprintf(stderr,"Usage: %s [-q] [-m] file1 [..fileN]\n",argv[0]);
X	exit(2);
X	}
X
X    fnum=1;
X    /* get flags */
X    while (argv[fnum][0]=='-' && (argc > 1)) {
X        switch (argv[fnum][1]) {
X        case 'm':
X            mailfile=1;
X            break;
X        case 'q':
X            verbose=0;
X            break;
X        case 'v':
X            verbose=1;
X            break;
X        default:
X            fprintf(stderr,"Unknown option -%c ignored\n",argv[fnum][1]);
X            break;
X            }
X        fnum++;
X	argc--;
X        }
X
X    if (argc <= 1)  {
X	fprintf(stderr,"Cannot find a file in the arguments.\n");
X	exit(3);
X	}
X    if (mailfile && argc != 2) {
X	fprintf(stderr,
X	"Mail option -m only works with one file; others ignored.\n");
X	argc = 2;
X	}
X
X    fd = (FILE *) NULL;   /* kludgey flag saying need to open a file */
X    inline[0] = '\0';     /* kludgey flag saying have not seen any hex */
X
X    /* loop here once per file (or if -m, per hunk ) */
X    for ( ; (mailfile && !eof) || (argc > 1);  ) {
X
X	/* make sure the right file is open */
X        if (fd == (FILE *) NULL || !mailfile) { /* first time, or !-m  */
X            if (fd == (FILE *) NULL) fd = fopen(argv[fnum],"r"); 
X               else                  fd = freopen(argv[fnum++],"r",fd);
X            if (fd==(FILE *)NULL) {
X        	perror(argv[fnum]);
X        	exit(3);
X        	}
X            argc--;
X            fnum++;
X	    }; 
X
X	/* find the beginning of a hunk: the rules depend on whether this is
X	   the first one or not.
X        */
X        if (inline[0] == '\0') { 
X	    /* rules for the first hunk are easiest */
X            for ( ;; ) {
X                if (fgets(inline,80,fd) == NULL) {
X                    fprintf(stderr,"No hunk in the first file at all.\n");
X		    perror(argv[fnum - 1]);
X		    exit(3);
X		    }
X                if (strncmp(inline,"(This file",10)==0) {
X                    printf("%s",inline); /* send the "This file..." line */
X        
X		    /* send the blank line */
X                    if (fgets(inline,80,fd) == NULL) {
X		        perror(argv[fnum - 1]);
X		        exit(3);
X			}
X                    printf("%s",inline);
X        
X		    /* send the first "real" line, assume it's full length */
X                    if (fgets(inline,80,fd) == NULL) {
X		        perror(argv[fnum - 1]);
X			exit(3);
X			}
X                    printf("%s",inline);
X
X                    l = strlen(inline);  /* record what "full length" means */
X                    break;               /* leave the loop with setup done */
X                    }
X                else {
X                    if (verbose) fprintf(stderr,"%s",inline); /* continue */
X                    }
X                }
X            } 
X	else {
X	    /* rules for finding later hunks involve some guesses */
X
X
X            /* only consider first 500 lines of each file for data start */
X	    for (curline=1; curline<500; curline++){
X                if (fgets(inline,90,fd)==NULL) {
X                    debug(printf("eof (argc=%d)\n",argc));
X                    eof = 1;
X                    break;
X                    }
X
X                /* is the line the right length? */
X                if (strlen(inline)!=l) {
X                    if (verbose) fprintf(stderr,"%s",inline);
X                    debug(printf("Bad length %d != %d\n",strlen(inline),l));
X                    continue;
X                    }
X
X	        /* we don't expect binhex to contain these lines, just in case
X		    we fluked out on line length 
X	        */
X                if ((substr(inline,"here"))  ||
X                    (substr(inline,"From")) ||
X                    (substr(inline,"CUT")) ||
X                    (substr(inline,"end")) ||
X                    (substr(inline,"Path")) ||
X                    (substr(inline,"cut")) ) {
X                    if (verbose) fprintf(stderr,"%s",inline);
X                    debug(printf("Has English\n"));
X                    continue;
X                    }
X
X		/* we also don't expect white-space in any line */
X		if ((substr(inline," ")) ||
X		    (substr(inline,"\t")) ) {
X		    if (verbose) fprintf(stderr,"%s",inline);
X		    debug(printf("Has White Space\n"));
X		    continue;
X		    }
X
X                /* get another line, see if lengths match */
X                if (fgets(inline2,80,fd)==NULL) {
X		    fprintf(stderr,"%s",inline);
X                    eof = 1;
X                    break;
X                    }
X	        /* check it for the keywords too */
X                if ((strlen(inline)==strlen(inline2)) &&
X                    ( ! ( (substr(inline2,"here"))  ||
X                     (substr(inline2,"From")) ||
X                     (substr(inline2,"CUT")) ||
X                     (substr(inline2,"end")) ||
X                     (substr(inline2,"Path")) ||
X                     (substr(inline2,"cut")) ||
X		     (substr(inline2," ")) ||
X		     (substr(inline2,"\t")) ))) {
X
X                    /* Okay, we're convinced 	*/
X		    /* spit the 2 lines		*/
X                    printf("%s",inline);
X                    strcpy(inline,inline2);
X		    break;
X		    }
X                else {
X		    fprintf(stderr,"%s",inline);
X		    fprintf(stderr,"%s",inline2);
X                    debug(printf("Second line is bad\n"));
X                    }
X		} /* end of 500-line scan */
X	    if (curline >= 500) {
X	        debug(printf(stderr,"Over 500 lines and no hunk found.\n"));
X	        eof = 1; /* a slight misnomer, but is gets us out */
X	        }
X	    } /* end of looking for a hunk (if/else) */
X        /* at this point, one of the following cases should be true:
X            eof is set -- ran off the end of the current file
X	    inline contains the next valid line of hex data
X        */
X
X        /* Take any more lines of the right length */
X        for ( ; ; ) {
X            if (fgets(inline,80,fd)==NULL) {
X                eof = 1;
X                break;
X                }
X            i = strlen(inline);
X            while (inline[i-1]=='\n') i--;
X            if (inline[i-1]==':') {
X                gotend = 1; /* end of stuff */
X                printf("%s",inline);
X		break;
X                }
X            if (strlen(inline)!=l) {
X		fprintf(stderr,"%s",inline);
X                break;
X                }
X            else printf("%s",inline);
X            } /* done replicating lines; 'inline' contains the short one */
X
X        if (gotend) break;
X
X        if (!mailfile) {
X            /* throw away rest of file */
X            while (verbose && (fgets(inline,80,fd) != NULL)) {
X                fprintf(stderr,"%s",inline);
X                }
X            }
X        } /* end of hunk loop.  exit with gotend, please. */
X
X    while (verbose & (fgets(inline,80,fd) != NULL)) {
X        fprintf(stderr,"%s",inline);
X        }
X
X    if (argc != 1) {
X	fprintf(stderr,"Ended before the last file: %d left.\n",argc-1);
X	exit(1);
X	}
X
X    if (!gotend) {
X	fprintf(stderr,"File didn't seem to end properly\n");
X	exit(1);
X	}
X
X    exit(0);
X    /*NOTREACHED*/
X    }
X
Xint
Xsubstr(s,t)
Xchar *s, *t;
X{
X    extern char *index();
X    while ((s=index(s,*t))!=0) {
X        if (strncmp(s,t,(min(strlen(s),strlen(t))))==0) return(1);
X        s++;
X        }
X    return(0);
X    }
SHAR_EOF
if test 9267 -ne "`wc -c < 'comb.c'`"
then
	echo shar: "error transmitting 'comb.c'" '(should have been 9267 characters)'
fi
fi
exit 0
#	End of shell archive
---