[comp.sys.atari.st] shar/unshar.c

RDROYA01@ULKYVX.BITNET.UUCP (01/29/87)

 
#       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:
#       readme.shr
#       shar.c
#       shar.lnk
# This archive created: 29-January-1987 15:12:56 EST
# By:   Robert_Royar (University_of_Louisville)
cat << \SHAR_EOF > README.SHR
 
The next two files make up a shar/unshare program for the ST and vax VMS.  I
have tested both versions and they work the same on each system.  I've had
this source for quite a while and have been using it on VMS, but hadn't
bothered to port it to the ST until recently.  The first file is the shar
archive for source and the link68 linkfile.  The second file is the uuencoded
binary shar.prg.  I haven't prefixed the lines so that you can easily
extract the files without the progrm itself.  The original was posted to
net.sources last year.  This one has had some bugs removed and most of the
amiga/cpm stuff deleted (it made it difficult to decipher the code).  But I
left the VMS conditionals in place to make it easy to get versions running
on the two machines.  Hope you can find a use for this.  I sure have.
 
SHAR_EOF
if test 817 -ne "`wc -c README.SHR`"
then
echo shar: error transmitting README.SHR '(should have been 817 characters)'
fi
cat << \SHAR_EOF > SHAR.C
/*
 *  Shar puts readable text files together in a package
 *
 *  from which they are easy to extract.
 *
 *      v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
 *      - enhanced usage message
 *
 *      v 860712 D. Wecker for ULTRIX and the AMIGA
 *      - stripped down.. does patterns but no directories
 *      - added a -u (unshar) switch
 *
 *      v 870128 R. Royar for ST
 *      - removed #ifdefs that left stray }s in file
 *      - reformatted text for consistant style
 *      - modified main to abort when no files are given
 *      - fixed call to fputc in tell macro, which omitted the stream
 *        causing address errors on the ST.
 *      - fixed STUPID coding in getopt that tried to write to
 *        address 0++.
 *      - known bug:
 *              still no directory support.  Extracting
 *              files with directory names will get
 *              only the directory name on an open call.
 */
#define ST
 
#include <stdio.h>
 
#ifdef  ST
#include <osbind.h>
long _STKSIZ = 16 * 1024;       /* for new gemstart.s */
char *Defenv = "ENOENV";        /* if no cc.ini file */
extern char *getenv(),*malloc(),*index(),*fopen();
void shar();
#endif
 
#ifdef  ULTRIX
#include <sys/types.h>
extern char *getenv(),*scdir(),*malloc(),*index();
#endif
 
#ifdef  VMS
#include <stdio.h>
#include <types.h>
extern char *getenv(),*scdir(),*malloc();
#endif
 
 
#define BADCH   ((int)'?')
#define EMSG    ""
#define tell(s) {fputs(*nargv,stderr);fputs((s),stderr);fputc('\n',stderr);}
#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? */
 
char Usage1[] =
"\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n\
\n\
usage: shar [-u archive] [[-a] [-p prefix]\
 [-d delim] [-bcv] files > archive]\n\
\n\
        where:  -a  all the options (v,c,b,-pXX)\n";
 
char Usage2[] =
"               -b  extract absolute paths into current directory\n\
                -c  check filesizes on extraction\n\
                -d  use this EOF delimiter instead of SHAR_EOF\n";
 
char Usage3[] =
"               -p  use this as prefix to each line in archived files\n\
                -u  unshar <archive>\n\
                -v  verbose on extraction, incl. echoing filesizes\n";
 
 
#define SED "sed 's/^%s//'"     /* used to remove prefix from lines */
#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
 
void main(argc, argv)
int argc;
char **argv;
{
        char *ppchFiles[256];
        register int  C;
        char **ppchList = ppchFiles;
        register int errflg;
        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':
                        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, "%s%s%s", Usage1, Usage2, Usage3);
                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);
}
 
int header(ppchFiles)
char *ppchFiles[];
{
        register int i;
#ifdef  ST
        char clock[40];
#else
        extern char *ctime();
        auto long clock;
#endif
        register char **ppchList;
        char *pchOrg;
        char *pchName;
        register int  problems;
        problems = 0;
#ifdef  ST              /* see cc.ini for this */
        pchOrg = getenv("organization");
        pchName = getenv("name");
#else
        pchOrg = getenv("ORGANIZATION");
        pchName = getenv("NAME");
#endif
        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);
        time(&clock);
#ifdef  ST
        printf("# This archive created: %s",clock);
#else
        printf("# This archive created: %s", ctime(&clock));
#endif
        if (pchName)
                printf("# By:\t%s (%s)\n", pchName,pchOrg);
        return(0);
}
#ifdef  ST
 
/* create an ASCII time string and copy it into timeline.  Caller
 * should make sure timeline has ~35 characters space.
 */
time(timeline)
char timeline[];
{
        register int mytime;
        register int date;
        register int hours, minutes, seconds;
        int day, month, year;
        static char *months[] = {"January","February","March","April",
                                "May","June","July","August","September",
                                "October","November","December"};
        char *tzone;
        tzone = getenv("timezone");
        mytime  = Tgettime();
        date = Tgetdate();
        seconds = (mytime&31)*2;
        minutes = (mytime>>5)&63;
        hours   = (mytime>>11)&31;
        day = (date&31);
        month = (date>>5)-113;
        year = ((date>>9)&31)+1980;
        sprintf(timeline,"%02d-%s-%d %d:%02d:%02d %s\n",
        day,months[month],year,hours,minutes,seconds,tzone);
        return(TRUE);
}
#endif
 
int
archive(input, output)
char *input, *output;
{
        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);
                fclose(ioptr);
                return(0);
                }
        else
                {
                fprintf(stderr, "shar: Can't open '%s'\n", input);
                return(1);
                }
}
 
void shar(file)
char *file;
{
        register char *basefile;
        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);
                }
}
 
getpat(pattern)
char *pattern;
{
        register char *ptr;
        int temp;
 
        ptr = pattern;
        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)                /* %$^& what if oli = NULL!!! */
                {
                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;
        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;
}
 
#ifdef  ST
/* since nothing ever initializes the environment table on the ST
 * I'll just use my home brew cc.ini environment file.
 */
char *getenv(var)
register char *var;
{
        FILE *fp;
        register char *ptr;
        static char line[81];
        register char *safestore;
 
        if ((fp=fopen("cc.ini","r")) == NULL)
                return(Defenv);
        while (fgets(line,80,fp))
                {
                if ((ptr=index(line,' '))!=(char *)NULL)
                        *ptr = '\0';
                if ((ptr=index(line,'\n'))!=(char *)NULL)
                        *ptr = '\0';
                if ((ptr=index(line,'\t'))!=(char *)NULL)
                        *ptr = '\0';
                if ((ptr=index(line,'='))!=(char *)NULL)
                        *ptr = '\0';
                else
                        continue;
                ++ptr;
                if (strcmp(line,var)==NULL)
                        {
                        safestore = malloc(strlen(ptr)+1);
                        strcpy(safestore,ptr);
                        return(safestore);
                        }
                else if (feof(fp))
                        break;
                }
        return(Defenv);
}
#endif
SHAR_EOF
if test 11755 -ne "`wc -c SHAR.C`"
then
echo shar: error transmitting SHAR.C '(should have been 11755 characters)'
fi
cat << \SHAR_EOF > SHAR.LNK
[tem[m:]]m:unshare.68k=gemsnew,m:unshare,gemlib[in[_nofloats],in[_nottyin],
in[_nofilesz],in[_nobinary]]
SHAR_EOF
if test 105 -ne "`wc -c SHAR.LNK`"
then
echo shar: error transmitting SHAR.LNK '(should have been 105 characters)'
fi
#       End of shell archive
exit 0