340 lines
7.3 KiB
C
340 lines
7.3 KiB
C
/* unshar - extract files from a shell archive Author: Warren Toomey */
|
|
|
|
|
|
/* Unshar - extract files from shell archive
|
|
*
|
|
* Written by Warren Toomey [wkt@csadfa.oz.au@munnari.oz@uunet.uu.net] You may
|
|
* freely copy or give away this source as long as this notice remains
|
|
* intact.
|
|
*
|
|
* Definitions used by unshar
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
/* Methods of unsharing */
|
|
#define UNKNOWN 0
|
|
#define BRUTAL 1
|
|
|
|
/* Whitespace indicators */
|
|
#define WHITE 0
|
|
#define NOWHITE 1
|
|
|
|
/* Leading character indicators */
|
|
#define NOX 0
|
|
#define YESX 1
|
|
|
|
/* Emulation types available */
|
|
|
|
#define NUMTOKS 4 /* Must change NUMTOKS to equal the */
|
|
/* Define UNKNOWN 0 *//* number of emulation types */
|
|
#define SED 1
|
|
#define GRES 2
|
|
#define CAT 3
|
|
|
|
/* The list of emulation types. */
|
|
static char *token[NUMTOKS]=
|
|
{
|
|
"",
|
|
"sed",
|
|
"gres",
|
|
"cat"
|
|
};
|
|
|
|
|
|
/* Misc. constants */
|
|
#define BUFSIZE 512 /* Size of line buffer */
|
|
|
|
/* Global variables */
|
|
int table; /* Generate a table, or extract */
|
|
int verbose; /* Unshar verbosely - debugging */
|
|
int numext; /* Number of files to extract */
|
|
int binfile; /* Binary file - err indicator */
|
|
char *exfile[100]; /* Files to extract */
|
|
|
|
|
|
#define getline(x,y) fgetline(stdin,x,y)
|
|
|
|
int fgetline(zin, how, buf) /* Get a line from a file */
|
|
FILE *zin;
|
|
int how; /* Ignore leading whitespace if */
|
|
char *buf; /* how == NOWHITE */
|
|
{
|
|
int ch = 0;
|
|
|
|
*buf = 0; /* Null the buffer */
|
|
if (how == NOWHITE) { /* If skip any whitespace */
|
|
while (((ch = fgetc(zin)) == ' ') || (ch == '\t'));
|
|
if (ch == EOF) return(EOF); /* Returning EOF or 0 */
|
|
if (ch == '\n') return (0);
|
|
*buf++ = ch; /* Put char in buffer */
|
|
}
|
|
while ((ch = fgetc(zin)) != '\n') { /* Now get the line */
|
|
if (ch == EOF) {
|
|
*buf = 0;
|
|
return(EOF);
|
|
}
|
|
if (ch > 127) {
|
|
binfile = 1;
|
|
return(0);
|
|
}
|
|
*buf++ = ch;
|
|
}
|
|
|
|
*buf = 0; /* Finally null-terminate the buffer */
|
|
return(0); /* and return */
|
|
}
|
|
|
|
|
|
|
|
char *getstring(buf) /* Get the next string from the buffer */
|
|
char *buf; /* ignoring any quotes */
|
|
{
|
|
char out[BUFSIZE];
|
|
char *temp = out;
|
|
char inquotes = 0, ok = 1;
|
|
while ((*buf == ' ') || (*buf == '\t'))
|
|
buf++; /* Skip whitespace */
|
|
|
|
if (verbose) printf("In getstring...\n");
|
|
*temp = 0;
|
|
while (ok) { /* Parse line */
|
|
switch (*buf) {
|
|
case '\"':
|
|
case '\'':
|
|
buf++;
|
|
inquotes = !inquotes; /* Toggle inquotes */
|
|
break;
|
|
case 0:
|
|
case '\n': /* Stop on <, >, NULL */
|
|
case '>': /* \n, and sometimes */
|
|
case '<': ok = 0; break; /* space & tab */
|
|
case '\t':
|
|
case ' ':
|
|
if (!inquotes) ok = 0;
|
|
case '\\':
|
|
if (!inquotes) {/* Ignore backquotes */
|
|
buf++;
|
|
break;
|
|
}
|
|
default:
|
|
*temp++ = *buf++; /* Copy chars :-) */
|
|
}
|
|
}
|
|
*temp = 0;
|
|
if (verbose) printf("Returning *%s*\n", out);
|
|
return(out);
|
|
}
|
|
|
|
|
|
int firstword(buf) /* Return token value of first word */
|
|
char *buf; /* in the buffer. Assume no leading */
|
|
{ /* whitespace in the buffer */
|
|
int i;
|
|
|
|
for (i = 1; i < NUMTOKS; i++)
|
|
if (strncmp(buf, token[i], strlen(token[i])) == 0) return(i);
|
|
|
|
return(UNKNOWN);
|
|
}
|
|
|
|
|
|
int mustget(s1) /* Return 1 if s1 is in the list of */
|
|
char *s1; /* files to extract. Return 0 if not */
|
|
{
|
|
int i;
|
|
|
|
if (numext == 0) return(0);
|
|
for (i = 0; i < numext; i++)
|
|
if (!strcmp(s1, exfile[i])) return(1);
|
|
return(0);
|
|
}
|
|
|
|
|
|
void extract(how, file, end, lead) /* Extract file, up until end word */
|
|
int how; /* If how==YESX, then ignore lead */
|
|
char *file; /* character on every line */
|
|
char *end;
|
|
int lead;
|
|
{
|
|
FILE *zout;
|
|
char line[BUFSIZE];
|
|
char *temp;
|
|
int ch;
|
|
|
|
zout = fopen(file, "w"); /* Open output file */
|
|
if (zout == NULL) {
|
|
perror("unshar1");
|
|
return;
|
|
}
|
|
while (1) {
|
|
binfile = 0;
|
|
ch = getline(WHITE, line); /* Get a line of file */
|
|
temp = line;
|
|
if (binfile || (ch == EOF)) {
|
|
fprintf(zout, "%s\n", line);
|
|
fclose(zout);
|
|
return;
|
|
}
|
|
if ((how == YESX) && (*temp == lead)) temp++; /* Skip any lead */
|
|
|
|
if (strcmp(temp, end) == 0) { /* If end word */
|
|
fclose(zout); /* close the file */
|
|
return;
|
|
}
|
|
fprintf(zout, "%s\n", temp);
|
|
}
|
|
}
|
|
|
|
|
|
void getnames(buf, file, word) /* Get the file & end word */
|
|
char *buf, *file, *word; /* from the buffer */
|
|
{
|
|
char *temp;
|
|
|
|
temp = buf;
|
|
if (verbose) printf("Getnames: buf is %s\n", buf);
|
|
|
|
while (*temp != 0) { /* Scan along buffer */
|
|
switch (*temp) { /* Get file or end word */
|
|
case '>':
|
|
strcpy(file, getstring(++temp)); /* Get the file name */
|
|
break;
|
|
case '<':
|
|
if (*(++temp) == '<') ++temp; /* Skip 2nd < */
|
|
strcpy(word, getstring(temp)); /* Get next word */
|
|
break;
|
|
default:
|
|
temp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void disembowel()
|
|
{ /* Unshar brutally! */
|
|
char buf[BUFSIZE]; /* Line buffer */
|
|
char file[BUFSIZE]; /* File name */
|
|
char word[BUFSIZE]; /* Word buffer */
|
|
int ch, x;
|
|
|
|
if (verbose) printf("Entering disembowel\n");
|
|
x = 'X'; /* Leading X character */
|
|
while (1) {
|
|
binfile = 0;
|
|
ch = getline(NOWHITE, buf); /* Get a line from file */
|
|
if (ch == EOF) return;
|
|
if (binfile) continue;
|
|
|
|
switch (firstword(buf)) { /* Extract, depending on first word */
|
|
case CAT:
|
|
if (verbose) printf("About to do getnames\n");
|
|
getnames(buf, file, word);
|
|
if (table == 0) {
|
|
if ((numext == 0) || (mustget(file))) {
|
|
printf("unshar: Extracting %s\n", file);
|
|
if (verbose)
|
|
printf(" stopping at %s\n", word);
|
|
extract(NOX, file, word, x);
|
|
}
|
|
} else
|
|
printf(" %s\n", file);
|
|
break;
|
|
case GRES:
|
|
case SED:
|
|
if (verbose) printf("About to do getnames\n");
|
|
getnames(buf, file, word);
|
|
if (table == 0) {
|
|
if ((numext == 0) || (mustget(file))) {
|
|
printf("unshar: Extracting %s\n", file);
|
|
if (verbose)
|
|
printf(" stopping at %s\n", word);
|
|
extract(YESX, file, word, x);
|
|
}
|
|
} else
|
|
printf(" %s\n", file);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "Usage: unshar [-t] [-b] [-v] [-xfile] [file(s)]\n");
|
|
exit(0);
|
|
}
|
|
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
extern int optind;
|
|
extern char *optarg;
|
|
int i, c, first;
|
|
|
|
FILE *zin; /* Dummy file descriptor */
|
|
int method; /* Method of unsharing */
|
|
|
|
method = BRUTAL; /* Only BRUTAL currently available */
|
|
table = 0; /* Don't generate a table */
|
|
verbose = 0; /* Nor be very verbose */
|
|
numext = 0; /* Initially no files to extract */
|
|
|
|
|
|
while ((c = getopt(argc, argv, "x:tbv")) != EOF) switch (c) {
|
|
case 't':
|
|
table = 1; /* Get the various options */
|
|
break;
|
|
case 'b': method = BRUTAL; break;
|
|
case 'v': verbose = 1; break;
|
|
case 'x':
|
|
exfile[numext] = (char *) malloc(strlen(optarg) + 1);
|
|
strcpy(exfile[numext++], optarg);
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
if (argc == 1)
|
|
first = argc; /* Find first file argument */
|
|
else
|
|
for (first = 1; first < argc; first++)
|
|
if (argv[first][0] != '-') break;
|
|
|
|
if (first == argc) { /* If no file argument *//* use stdin only */
|
|
switch (method) {
|
|
case BRUTAL:
|
|
disembowel(); /* Unshar brutally! */
|
|
break;
|
|
default:
|
|
fprintf(stderr, "unshar: Unknown method of unsharing\n");
|
|
exit(1);
|
|
}
|
|
} else
|
|
for (i = first; i < argc; i++) { /* open stdio with every
|
|
* file */
|
|
if (table) printf("%s:\n", argv[i]);
|
|
fclose(stdin);
|
|
if ((zin = fopen(argv[i], "r")) == NULL) {
|
|
perror("unshar2");
|
|
exit(1);
|
|
}
|
|
switch (method) {
|
|
case BRUTAL:
|
|
disembowel(); /* Unshar brutally! */
|
|
break;
|
|
default:
|
|
fprintf(stderr, "unshar: Unknown method of unsharing\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
exit(0);
|
|
}
|