home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
-
- The UNIX program 'shar' (from "shell archive") puts readable text files
- together in a package from which they are easy to extract by feeding the
- package to 'sh'.
-
- Like its predecessors, this OS/2 implementation of shar builds shell
- archives but is also capable of decomposing them in the absence of the
- Bourne shell. It is thus a useful tool for dealing with shell archives
- created on UNIX systems.
-
- v 920202 J. Saxton
- - Recently I've seen some shell archives which are like no others I've
- encountered previously. These are characterised by having the shar
- prefix only on those lines which begin with a space or tab. Whereas
- the number of such files has been so small as to be easy to deal with
- manually, however the recent distribution of dmake version 3.8 in
- this format has prompted an effort to accomodate it.
-
- v 920128 J. Saxton
- - During decomposition, allowed for concatenation to an existing file.
-
- e.g. the shar file might contain a line such as
- sed 's/^X//' << 'SHAR_EOF' > 'readme'
- followed later by
- sed 's/^X//' << 'SHAR_EOF' >> 'readme'
-
- v 911225 J. Saxton
- - Corrected a problem in mkdir when directory name was NOT quoted.
- - Tidied up reporting of directory operations.
-
- v 911205 J. Saxton
- - This version strictly for OS/2 HPFS. No longer is any attempt made
- to rectify file names for FAT or CP/M file systems. Code for VMS
- has been deleted. Code for ULTRIX and the Amiga has been retained
- without verification.
- - Detect directories and don't try to add them to archives.
- (Maybe next version will allow recursion into directories?)
- - Added dequote() function to normalize directory names.
- - Generated a Makefile and a definitions file.
- - made -pX the default pattern instead of -pXX.
- - fixed 'unshar' operation to ignore leading blanks.
- - tidied up source so it now compiles with MSC 6.0A at -W3 without
- complaint.
-
- v 910525 J. Saxton for OS/2 2.0 and HPFS
-
- v 891212 J. Saxton for MSDOS and OS/2
- - index() function changed to strchr() to comply with more modern C
- compilers.
- - eliminated several warning messages generated by the Microsoft C
- compiler (version 5.1)
- - compiled as a non-PM application for OS/2 and bound as a family mode
- program for MSDOS. Does wildcard expansion on input file names.
-
- cl /Ox /Fb shar.c c:\os2\lib\setargv.obj
-
- 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
-
- ------------------------------------------------------------------------------*/
-
- #ifdef MSDOS
- #define OS2
- #endif
-
- #ifdef OS2
- #include <string.h>
- #include <ctype.h>
- #include <malloc.h>
- #include <stdlib.h>
- #include <direct.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
-
- #include <stdio.h>
- #include <io.h>
- #include <time.h>
- #include <errno.h>
-
- #ifdef AMIGA
- #include <exec/types.h>
- extern char *getenv(), *scdir(), *malloc(), *strchr();
- #endif
-
- #ifdef ULTRIX
- #include <sys/types.h>
- #include <sys/stat.h>
- extern char *getenv(), *scdir(), *malloc(), *strchr();
- #endif
-
- int
- getopt(int, char **, char *),
- getpat(char *),
- getarg(int, char **);
- void
- dounshar(char *),
- getshpar(char *, char *, char *),
- dequote(char *);
-
- #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? */
- int Concat = 0; /* unshar to end of existing 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,-pX)\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";
-
- struct stat
- FileInfo;
-
- #define SED "sed 's/^%s//'"
-
- #define OPTSTRING "u:ap:d:bcv"
-
- int header(char **ppchFiles)
- {
- auto long clock;
- char **ppchList;
- char *pchOrg;
- char *pchName;
- register int problems = 0;
-
- pchOrg = getenv("ORGANIZATION");
- 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 != NULL)
- printf("# By:\t%s (%s)\n", pchName,
- pchOrg == NULL ? "Dave Wecker Midnight Hacks" : pchOrg);
- return (0);
- }
-
- int archive(char *input, char *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 != NULL)
- 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(char *file)
- {
- char *basefile;
-
- if (!strcmp(file, "."))
- return;
- fsize = 0;
- if (stat(file, &FileInfo))
- {
- fprintf(stderr,"Unable to do a stat() on '%s'\n", file);
- return;
- }
- if (FileInfo.st_mode & S_IFMT != S_IFREG)
- {
- basefile = "strange file";
- if (FileInfo.st_mode & S_IFCHR)
- basefile = "character special file";
- if (FileInfo.st_mode & S_IFDIR)
- basefile = "directory";
- fprintf(stderr,"Cannot archive %s '%s'\n", basefile, file);
- return;
- }
-
- basefile = file;
- 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);
- }
- }
-
- void main(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 = "X";
- 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, "%s%s%s", Usage1, Usage2, Usage3);
- exit(1);
- }
-
- savind = 0;
- do
- {
- if (getpat(optarg))
- exit(2);
- }
- while (EOF != (C = getarg(argc, argv)));
-
- sav[savind] = NULL;
- header(sav);
- for (ppchList = sav; *ppchList; ++ppchList)
- {
- shar(*ppchList);
- }
- puts("#\tEnd of shell archive");
- puts("exit 0");
- exit(0);
- }
-
- int getpat(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(int nargc, char **nargv, char *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 = strchr(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(int nargc, char **nargv)
- {
- if (nargc <= optind)
- {
- optarg = (char *) 0;
- return EOF;
- }
- else
- {
- optarg = nargv[optind++];
- return 0;
- }
- }
-
- void dounshar(char *ArcNam)
- {
- int
- Prefix = 0,
- i;
- FILE
- *inptr, *outptr;
- char
- *ptr,
- *nlf,
- line[BUFSIZ],
- FilNam[256],
- Delim[40],
- PrefixPat[10];
-
- if (!(inptr = fopen(ArcNam, "r")))
- {
- fprintf(stderr, "shar: Can't open archive '%s'\n", ArcNam);
- return;
- }
- while (fgets(line, BUFSIZ, inptr))
- {
- ptr = line + strspn(line, " \t");
- if (strncmp(ptr, "sed ", 4) == 0)
- {
- memset(PrefixPat, 0, sizeof PrefixPat);
- Prefix = 0;
- if (!(ptr = strchr(ptr, '/')))
- goto getfil;
- if (*++ptr == '^')
- ++ptr;
- while (*ptr != '/')
- {
- if (Prefix < sizeof PrefixPat - 2)
- PrefixPat[Prefix] = *ptr;
- ++Prefix;
- ++ptr;
- }
- ++ptr;
- goto getfil;
- }
- else
- if (strncmp(ptr, "cat ", 4) == 0)
- {
- Prefix = 0;
- getfil:
- getshpar(ptr, ">", FilNam);
- getshpar(ptr, "<<", Delim);
- if (Concat)
- {
- fprintf(stderr, "Appending to %s ...", FilNam);
- outptr = fopen(FilNam, "a");
- }
- else
- {
- fprintf(stderr, "Creating %s ...", FilNam);
- outptr = fopen(FilNam, "w");
- }
- while (fgets(line, BUFSIZ, inptr))
- {
- if (strncmp(line, Delim, strlen(Delim)) == 0)
- break;
- if (outptr != NULL)
- if (Prefix && strncmp(line, PrefixPat, Prefix) == 0)
- fputs(&line[Prefix], outptr);
- else
- fputs(line, outptr);
- }
- if (outptr)
- {
- fclose(outptr);
- fprintf(stderr, "...done\n");
- }
- else
- fprintf(stderr, "...error in creating file\n");
- }
- else
- if (strncmp(ptr, "mkdir ", 6) == 0)
- {
- for (nlf=ptr+6; *nlf; ++nlf)
- if (*nlf == '\n')
- *nlf = '\0';
- fprintf(stderr, "Creating directory %s ...", ptr+6);
- dequote(ptr+6);
- i = mkdir(ptr+6);
- if (i) /* then it failed */
- fprintf(stderr, "failed, errno=%u\n", errno);
- else
- fprintf(stderr, "done\n");
- }
- else
- if (strncmp(ptr, "chdir ", 6) == 0)
- {
- dequote(ptr+6);
- chdir(ptr+6);
- }
- else
- if (strncmp(line, "cd ", 3) == 0)
- {
- dequote(ptr+3);
- chdir(ptr+3);
- }
- }
- fclose(inptr);
- }
-
- void getshpar(char *line, char *sea, char *par)
- {
- register char *scr1, *scr2;
-
- while (*line)
- {
- scr1 = line;
- scr2 = sea;
- while (*scr1 && *scr2 && *scr1 == *scr2)
- {
- scr1++;
- scr2++;
- }
- if (*scr2 == 0)
- {
-
- // If search target is '>' then watch out for '>>'
-
- if (strcmp(sea,">") == 0)
- if (*scr1 == '>')
- {
- Concat = 1;
- ++scr1;
- }
- else
- Concat = 0;
-
- if (*scr1 == 0)
- {
- *par = 0;
- return;
- }
- while (*scr1 == ' ' || *scr1 == '\t' ||
- *scr1 == '/' ||
- *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"')
- scr1++;
- while (*scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
- // *scr1 != '/' &&
- *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' &&
- *scr1 != '\n' && *scr1 != '\r')
- *par++ = *scr1++;
- *par = 0;
- return;
- }
- line++;
- }
- *par = 0;
- }
-
- void dequote(char *p)
- {
- char
- *d = p,
- q;
-
- while (isspace(*d))
- ++d;
- switch (*d)
- {
- case '\'':
- case '"':
- q = *d++;
- break;
- default:
- q = ' ';
- }
- while (*d && !isspace(*d) && *d != q)
- *p++ = *d++;
- *p = '\0';
- }
-