home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
packer
/
shar
/
shar.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-03
|
13KB
|
592 lines
/*------------------------------------------------------------------------------
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';
}