[comp.binaries.ibm.pc.d] Source code for shar for pc's

draper@bu-tyng.bu.edu (Dave (dday) Draper) (05/19/88)

I have received several requests for the source code for the shar
program for pc's. Here it is. Please do not FLAME me for posting them here.
It is not a binary program so that is why I did not post them to the
binaries group. I will be posting the binary version to the binary
group for those of you who do not have a C compiler. This code is setup
to be compiled under Microsoft C version 4.0

Good luck.

Dave (dday) Draper
devcax!elrond!bu-tyng!draper

------------(snip)-------------(snip)--------------------------------------


/* 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
    v 860715 DBW
    - fixed bug with leading white space in unshar command recognition
    - fixed bug in getting sh paramaters with quotes
 */


#include <stdio.h>
#include <string.h>

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

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

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

#ifdef MSDOS
#define ONE_DOT_PER_FNAME   1
#define DEFINE_INDEX  1
#include <sys/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  DEFINE_INDEX
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 = 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);
    (void) time(& clock);
    printf("# This archive created: %s", ctime(&clock));
    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);
        }
        puts(Delim);
        (void) 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);
    if (access(ptr,4)) {
        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,strt;
    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)) {
    for (strt = 0; line[strt] == ' ' || line[strt] == '\t'; strt++) ;
    if (strncmp(&line[strt],"sed ",4) == 0) {
        Prefix = 0;
        if (!(ptr = index(&line[strt],'/'))) goto getfil;
        if (*++ptr == '^') ++ptr;
        while (*ptr++ != '/') Prefix++;
        goto getfil;
        }
    else if (strncmp(&line[strt],"cat ",4) == 0) {
        Prefix = 0;;
getfil:

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

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

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

        }


#if VMS
        strcat(FilNam,"]");
#endif
        getshpar(line,">",ScrStr);
        strcat(FilNam,ScrStr);
#if ONE_DOT_PER_FNAME
        /*
         * only one '.' in the filename.
         * replace all but the first with 'x'
         */
        if( ptr = strchr(FilNam,'.') )
            for( ptr = strchr(1+ptr,'.'); ptr; ptr = strchr(1+ptr,'.') )
                *ptr = 'x';
#endif
        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[strt],"mkdir ",6) == 0) {
        sprintf(stderr,"Need to make directory:\t%s\n",&line[strt+6]);
        }
    else if (strncmp(&line[strt],"chdir ",6) == 0) {
        if (line[strt+6] == '.' && line[strt+7] == '.') DirNum--;
        else strcpy(Dirs[++DirNum],&line[strt+6]);
        if (DirNum < -1) DirNum = -1;
        }
    else if (strncmp(&line[strt],"cd ",3) == 0) {
        if (line[strt+3] == '.' && line[strt+4] == '.') DirNum--;
        else strcpy(Dirs[++DirNum],&line[strt+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 == '"') {
        if (*scr1 == '\'' || *scr1 == '"') {
            scr2 = scr1++;
            break;
            }
        scr1++;
        }
        if (*scr2 != 0) {
        while (*scr1 != *scr2 && *scr1 != 0) *par++ = *scr1++;
        *par = 0;
        return;
        }
        while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
            *scr1 != '\n' && *scr1 != '\r') {
        if (*scr1 != '\\') *par++ = *scr1++;
        else            scr1++;
        }
        *par = 0;
        return;
        }
    line++;
    }
    *par = 0;
    }

----------------(snip)-----------------------(snip)---------------------------

Disclaimer: I did not write this code. I make no guarentees whatsoever
about the usefulness of it or its operation.


==============================================================================
*  Dave Draper                           UUCP: decvax!elrond!bu-tyng!draper  *
*  Wang Institute of Boston University                                       *
*                                                                            *
*  I saw a Dead Head sticker on a Cadillac,                                  *
*     Don't look back, you can never look back.    - Don Henley -            *
*============================================================================*

dhesi@bsu-cs.UUCP (Rahul Dhesi) (05/26/88)

In article <1555@bu-tyng.bu.edu> draper@bu-tyng.UUCP (dday) writes:
>Please do not FLAME me for posting them here.
>It is not a binary program so that is why I did not post them to the
>binaries group.

Likely, most sites expire articles in the .d groups much faster, so
posting any source here will result in a lot of people saying they
didn't get it, could you please repost.  Better would be to send it to
comp.sources.misc.

Better still, we need comp.sources.msdos.  Why doesn't somebody propose
it?  The net population likes sources, so it should have no trouble
getting approved, and it might even encourage more source postings.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!dhesi

nelson@sun.soe.clarkson.edu (Russ Nelson) (05/26/88)

In article <3186@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>Better still, we need comp.sources.msdos.  Why doesn't somebody propose
>it?  The net population likes sources, so it should have no trouble
>getting approved, and it might even encourage more source postings.

The difference between comp.sources.unix and comp.sources.msdos is that
you can *count* on a Unix system to have a C compiler, whereas you can't
count on *any* MS-DOS system to have any sort of compiler.

Of course, given the price of Turbo C, we could standardize on it.  ;-)
-- 
char *reply-to-russ(int network) {
if(network == BITNET) return "NELSON@CLUTX";
else return "nelson@clutx.clarkson.edu"; }

pete@octopus.UUCP (Pete Holzmann) (05/26/88)

In article <3186@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
}In article <1555@bu-tyng.bu.edu> draper@bu-tyng.UUCP (dday) writes:
}>Please do not FLAME me for posting them here. [comp.binaries.ibm.pc.d]

}Better still, we need comp.sources.msdos.  Why doesn't somebody propose
}it?  The net population likes sources, so it should have no trouble
}getting approved, and it might even encourage more source postings.

Until we see some kind of traffic in MSDOS-specific source code, I
don't see any reason to make a whole group just for DOS sources. 
For now, they fit very nicely into comp.sources.misc! Let's use
the net the way it is already set up first.

Pete

-- 
  OOO   __| ___      Peter Holzmann, Octopus Enterprises
 OOOOOOO___/ _______ USPS: 19611 La Mar Court, Cupertino, CA 95014
  OOOOO \___/        UUCP: {hpda,pyramid}!octopus!pete
___| \_____          Phone: 408/996-7746

bobmon@iuvax.cs.indiana.edu (RAMontante) (05/26/88)

dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>
>Better still, we need comp.sources.msdos.  Why doesn't somebody propose
                       ^^^^^^^^^^^^^^^^^^

I would like to propose, instead, that comp.binaries.ibm.pc become
	comp.code.msdos.
The msdos world has less reason to distinguish between source and executable
than the Unix world.  Begging the cost-to-post issue, I would be inclined to
post my super-neato-utility in a package that included binary for those poor
souls without the correct compiler, AND source for those who can make use of it.

If this really is a terrible idea (impossible!:-), then as second choice I will

	propose comp.sources.msdos	(and let OS/2 hang!)

If this means I've agreed to collect votes for either or both of these groups,
someboddy please tell me what it is I have to do.

-Bob Montante

nather@ut-sally.UUCP (Ed Nather) (05/27/88)

In article <239@octopus.UUCP>, pete@octopus.UUCP (Pete Holzmann) writes:
> In article <3186@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
> 
> }Better still, we need comp.sources.msdos.  Why doesn't somebody propose
> }it?  The net population likes sources, so it should have no trouble
> }getting approved, and it might even encourage more source postings.
> 
> Until we see some kind of traffic in MSDOS-specific source code, I
> don't see any reason to make a whole group just for DOS sources. 
> For now, they fit very nicely into comp.sources.misc! Let's use
> the net the way it is already set up first.

Well, there was a flood of traffic in net.sources.pc, back when there was
one, almost exclusively devoted to the IBM variety of PCs.  People with
Amigas or Ataris complained (rightly) that almost all of the traffic was
for IBM PCs.  They got their own source groups as a result, which they
still retained under the Great Net Reorganization.  They have them now.
But, somehow, net.source.ibm.pc never made it through the Great Dying
in spite of (or because of?) its great popularity.

It's sad to see something so viable go extinct, or get forced into the
same group with (shudder) vms.


-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.AS.UTEXAS.EDU