[comp.sys.m6809] Wecker's Shar.c ported to OSK

jimomura@lsuc.UUCP (04/22/87)

     I finally got around to porting Wecker's 'shar/unshar' utility
to OS-9.  I haven't looked closely at Bob Larson's Unshar, so I
don't know if there's a substantial difference between them.  I
would suggest keeping both for now (unless you check the code and
feel it's redundant).  If there's any difference, it may be that
Bob's unshar will unpack something this one can't.  Anyway, it's
nice to have this one to make Shar files for a change.

Cheers! -- Jim O.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	shar.doc
#	shar.c
# By:	Jim Omura ()
cat << \SHAR_EOF > shar.doc
	This is an early version of Wecker's Shar.c with "first stage"
porting to OS-9 68K completed.  Use the Unix instructions for now.
The code should be redone in some areas for cleaner logic, but
has been tested and will create a 'shar' file.

	Many thanks to Gary Kendall without whom I would have abandonned
the effort.

Cheers! -- Jim Omura

	The following are all the instructions I received:

Creating a shar file:

        AMIGA:  shar >foo.shar -a makefile *.h *.c

        VMS:    create a batch job that executes:
                $ shar -a makefile *.h *.c
                edit the batch .LOG file (which is your shar file)

        U**X:   shar -a makefile *.h *.c >foo.shar

                (P.S. the -a switch means do all options)

Extracting from a shar file:

        AMIGA:  shar -u foo.shar

        VMS:    shar -u foo.shar

        U**X:   shar -u foo.shar        or    sh foo.shar


Installation:

        AMIGA:  cc -DAMIGA shar.c
                ln -o shar shar.o -lc

        VMS:    cc/DEFINE=VMS shar.c
                link shar,sys$library:vaxcrtl/lib
                shar :== $dev:[dir]shar

        U**X:   cc -O -DULTRIX -o shar shar.c -lc


Just typing "shar" will yield a usage line. (Doc: thanks for the code to
base this off of).


SHAR_EOF
cat << \SHAR_EOF > shar.c
/* Shar puts readable text files together in a package
   from which they are easy to extract.

    v 860712 D. Wecker for ULTRIX and the AMIGA
        - stripped down.. does patterns but no directories
        - added a -u (unshar) switch
	OS-9 port version 87/04/21 by Jim Omura, BIX jimomura
 */
 
#define OS9				/* For OS-9 Systems--Jim O. */

#include <stdio.h>

#ifdef  AMIGA
#include <exec/types.h>
extern char *getenv(),*scdir(),*malloc(),*index();
#endif

#ifdef OS9

#include <ctype.h>
#include <time.h>
#include <modes.h>

#define		void	int
#define		fputc	putc

	extern char *getenv(),*scdir(),*malloc(),*index();
	struct	sgtbuf *timebuf;

#endif 

#ifdef  ULTRIX
#include <sys/types.h>
extern char *getenv(),*scdir(),*malloc(),*index();
#endif

#ifdef  VMS
#include <types.h>
extern char *getenv(),*scdir(),*malloc();
#endif


#define BADCH   ((int)'?')
#define EMSG    ""

#define tell(s) {fputs(*nargv,stderr);fputs((s),stderr); \
                fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}

#define rescanopts()    (optind = 1)

int     optind = 1,             /* index into parent argv vector */
        optopt;                 /* character checked for validity */
long    fsize;                  /* length of file */
char    *optarg;                /* argument associated with option */
char    *sav[100];              /* saved file names */
int     savind;                 /* save index */

/* OPTIONS */
int     Verbose = 0;           /* provide append/extract feedback */
int     Basename = 0;          /* extract into basenames */
int     Count = 0;             /* count characters to check transfer */
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 */
int     UnShar = 0;            /* do we unshar an input file? */

#define SED "sed 's/^%s//'"    /* used to remove prefix from lines */
#define USAGE "[-u archive] [[-a] [-p prefix] [-d delim] [-bcv] files > archive]"
#define OPTSTRING "u:ap:d:bcv"

#ifdef  VMS
char *index(s,c)
char    *s;
char    c;
{
    while (*s != 0 && *s != c) s++;
    if (*s == 0 && *s != c) s = 0;
    return(s);    
}
#endif

int header(ppchFiles)
char *ppchFiles[];
{
    extern char *ctime();
    register int i;
    auto long clock;
    register int  problems = 0;
    register char **ppchList;
    register char *pchOrg = "";  /* getenv("ORGANIZATION"); */
    register char *pchName = "Jim Omura"; /* getenv("NAME"); */

    puts("#\tThis is a shell archive.");
    puts("#\tRemove everything above and including the cut line.");
    puts("#\tThen run the rest of the file through sh.");
    puts("#----cut here-----cut here-----cut here-----cut here----#");
    puts("#!/bin/sh");
    puts("# shar:    Shell Archiver");
    puts("#\tRun the following text with /bin/sh to create:");
    for (ppchList = ppchFiles; *ppchList; ++ppchList)
        printf("#\t%s\n", *ppchList);
#ifdef OS9
	getime(timebuf);	/* Finish this later--Jim O. */
#else
    (void) time(& clock);
    printf("# This archive created: %s", ctime(&clock));
#endif
    if (pchName)
        printf("# By:\t%s (%s)\n", pchName, 
        pchOrg ? pchOrg : "Dave Wecker Midnight Hacks");
    return(0);
}

int archive(input, output)
char *input, *output;
{
    auto char line[BUFSIZ];
    register FILE *ioptr;

    if (ioptr = fopen(input, "r")) {
        printf("%s << \\%s > %s\n", Filter, Delim, output);
        while(fgets(line, BUFSIZ, ioptr)) {
            if (Prefix) fputs(Prefix, stdout);
            fputs(line, stdout);
            if (Count) fsize += strlen(line);
        }
 
        fputs(Delim, stdout);
        fputc('\n', stdout);
        fclose(ioptr);
        return(0);
    } 
    else {
        fprintf(stderr, "shar: Can't open '%s'\n", input);
        return(1);
    }
}


void shar(file)
char *file;
{
    register char *basefile = file;
    if (!strcmp(file, "."))
        return;
    fsize = 0;
    if (Basename) {
        while(*basefile)
            basefile++;        /* go to end of name */
        while(basefile > file && *(basefile-1) != '/')
            basefile--;
    }
    if (Verbose) printf("echo shar: extracting %s\n", basefile);
    if (archive(file, basefile)) exit(66);
    if (Count) {
        printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile);
        printf("then\necho shar: error transmitting %s ",basefile);
        printf("'(should have been %ld characters)'\nfi\n",fsize);
    }
}

int main(argc, argv)
int argc;
char **argv;    
{
    auto char *ppchFiles[256];
    register int  C;
    register char **ppchList = ppchFiles;
    register int errflg = 0;

    while(EOF != (C = getopt(argc, argv, OPTSTRING))) {
        switch(C) {
        case 'v': 
            Verbose++; 
            break;
        case 'c': 
            Count++; 
            break;
        case 'b': 
            Basename++; 
            break;
        case 'd': 
            Delim = optarg; 
            break;
        case 'a': /* all the options */
            optarg = "XX";
            Verbose++;
            Count++;
            Basename++;
            /* fall through to set prefix */
        case 'p': 
            (void) sprintf(Filter, SED, Prefix = optarg); 
            break;
        case 'u':
            UnShar++;
            dounshar(optarg);
            break;
        default: 
            errflg++;
        }
    }

    if (UnShar) exit(0);

    C = getarg(argc, argv);
    if (errflg || EOF == C) {
        if (EOF == C)
            fprintf(stderr, "shar: No input files\n");
        fprintf(stderr, "usage: shar %s\n", USAGE);
        exit(1);
    }

    savind = 0;
    do {
        if (getpat(optarg)) exit(2);
    } 
    while (EOF != (C = getarg(argc, argv)));

    sav[savind] = 0;
    header(sav);
    for (ppchList = sav; *ppchList; ++ppchList) shar(*ppchList);
    puts("#\tEnd of shell archive");
    puts("exit 0");
    exit(0);
}

getpat(pattern)
char *pattern;
{
    register char *ptr;

#ifdef AMIGA
    while (ptr = scdir(pattern)) {
#else
    ptr = pattern;
    {
#endif
        sav[savind] = malloc(strlen(ptr)+1);
        strcpy(sav[savind++],ptr);
#ifdef	OS9
		if (access(ptr,S_IOREAD) || access(ptr,S_IREAD))
		{
/* The logic here is mucked up.  Change it later.--Jim O. */
		}
		else {
#else
        if (access(ptr,4)) {
#endif
            printf("No read access for file: %s\n",ptr);
            return(-1);
        }
    }
    return(0);
}

/*
 * get option letter from argument vector
 */
 
int	getopt(nargc, nargv, ostr)
int nargc;
char **nargv, *ostr;

{
    register char    *oli;        /* option letter list index */
    static char    *place = EMSG;    /* option letter processing */

    if(!*place) {            /* update scanning pointer */
        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
        if (*place == '-') {    /* found "--" */
            ++optind;
            return EOF;
        }
    }                /* option letter okay? */
    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
        if(!*place) ++optind;
        tell(": illegal option -- ");
    }
    if (*++oli != ':') {        /* don't need argument */
        optarg = NULL;
        if (!*place)
            ++optind;
    } 
    else {                /* need an argument */
        if (*place) {            /* no white space */
            optarg = place;
        } 
        else if (nargc <= ++optind) {    /* no arg */
            place = EMSG;
            tell(": option requires an argument -- ");
        } 
        else {
            optarg = nargv[optind];    /* white space */
        }
        place = EMSG;
        ++optind;
    }
    return optopt;            /* dump back option letter */
}

int
getarg(nargc, nargv)
int nargc;
char **nargv;
{
    if (nargc <= optind) {
        optarg = (char *) 0;
        return EOF;
    } 
    else {
        optarg = nargv[optind++];
        return 0;
    }
}

dounshar(ArcNam)
char *ArcNam;
{
    register int i,j;
    register FILE *inptr,*outptr;
    auto char line[BUFSIZ];
    int DirNum = -1;
    int Prefix = 0;
    char Dirs[5][40],FilNam[128],Delim[40],ScrStr[128];
    char *ptr;

    if (!(inptr = fopen(ArcNam,"r"))) {
        fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam);
        return;
    }
    while (fgets(line,BUFSIZ,inptr)) {
        if (strncmp(line,"sed ",4) == 0) {
            Prefix = 0;
            if (!(ptr = index(line,'/'))) goto getfil;
            if (*++ptr == '^') ++ptr;
            while (*ptr++ != '/') Prefix++;
            goto getfil;
        }
        else if (strncmp(line,"cat ",4) == 0) {
            Prefix = 0;
            ;
getfil:

#ifdef    VMS
            strcpy(FilNam,"[");
#else
            FilNam[0] = 0;
#endif

            for (i = 0; i <= DirNum; i++) {

#ifdef    VMS
                strcat(FilNam,".");
                strcat(FilNam,Dirs[i]);
#else
                strcat(FilNam,Dirs[i]);
                strcat(FilNam,"/");
#endif

            }


#ifdef    VMS
            strcat(FilNam,"]");
#endif

            getshpar(line, ">", ScrStr);
            strcat(FilNam,ScrStr);
            getshpar(line,"<<",Delim);
            fprintf(stderr,"Creating %s ...",FilNam);
            outptr = fopen(FilNam,"w");
            while (fgets(line,BUFSIZ,inptr)) {
                if (strncmp(line,Delim,strlen(Delim)) == 0) break;
                if (outptr) fputs(&line[Prefix],outptr);
            }
            if (outptr) {
                fclose(outptr);
                fprintf(stderr,"...done\n");
            }
            else fprintf(stderr,"...error in creating file\n");
        }
        else if (strncmp(line,"mkdir ",6) == 0) {
            sprintf(stderr,"Need to make directory: %s\n",&line[6]);
        }
        else if (strncmp(line,"chdir ",6) == 0) {
            if (line[6] == '.' && line[7] == '.') DirNum--;
            else strcpy(Dirs[++DirNum],&line[6]);
            if (DirNum < -1) DirNum = -1;
        }
        else if (strncmp(line,"cd ",3) == 0) {
            if (line[3] == '.' && line[4] == '.') DirNum--;
            else strcpy(Dirs[++DirNum],&line[3]);
            if (DirNum < -1) DirNum = -1;
        }
    }
    fclose(inptr);
}

getshpar(line,sea,par)
char *line,*sea,*par;
{
    register int i,j,k;
    register char *scr1,*scr2;

    while (*line) {
        scr1 = line;
        scr2 = sea;
        while (*scr1 && *scr2 && *scr1 == *scr2) { 
            scr1++; 
            scr2++; 
        }
        if (*scr2 == 0) {
            if (*scr1 == 0) { 
                *par = 0; 
                return; 
            }
            while ( *scr1 == ' ' || *scr1 == '\t' ||
                *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"') scr1++;
            while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
                *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' &&
                *scr1 != '\n' && *scr1 != '\r') *par++ = *scr1++;
            *par = 0;
            return;
        }
        line++;
    }
    *par = 0;
}

/* End of Shar.c */
SHAR_EOF
#	End of shell archive
exit 0
-- 
Jim Omura, 2A King George's Drive, Toronto, (416) 652-3880
ihnp4!utzoo!lsuc!jimomura
Byte Information eXchange: jimomura