wkt@csadfa.cs.adfa.oz.au (Warren Toomey) (02/20/90)
Andy has used a new shar program with some the 1.5.3 patches, and all of the lates beta-group patches; unshar(1) cannot handle lines of the form: echo Extracting 'sys_00.uue' sed 's/^X//' > 'sys_00.uue' << '+ END-OF-FILE ''sys_00.uue' I've just changed one of the functions to handle this, and the old shar format. The following is an alpha-test of the new unshar(1). Please test it on as many shar formats as possible! BTW, Andy could you report your indent.pro file which is used for all the files in Minix. I have to repost the whole file as I can't get my `working source' into the Minix style. Thanks! Warren Toomey wkt@csadfa.oz.au@munnari.oz.au[@uunet.uu.net] ---------------------------- unshar here ------------------------------- echo x - unshar.c sed '/^X/s///' > unshar.c << '/' X/* unshar - extract files from a shell archive Author: Warren Toomey */ X X X/* X * Unshar - extract files from shell archive X * X * Written by Warren Toomey [wkt@csadfa.oz.au@munnari.oz@uunet.uu.net] You may X * freely copy or give away this source as long as this notice remains X * intact. X * X * Definitions used by unshar X */ X X X#include <stdio.h> X X/* Methods of unsharing */ X#define UNKNOWN 0 X#define BRUTAL 1 X X/* Whitespace indicators */ X#define WHITE 0 X#define NOWHITE 1 X X/* Leading character indicators */ X#define NOX 0 X#define YESX 1 X X/* Emulation types available */ X X#define NUMTOKS 4 /* Must change NUMTOKS to equal the */ X/* Define UNKNOWN 0 *//* number of emulation types */ X#define SED 1 X#define GRES 2 X#define CAT 3 X Xstatic char *token[NUMTOKS] /= *The list of emulation types ! */ X{"", X "sed", X "gres", X "cat" X}; X X X/* Misc. constants */ X#define BUFSIZE 512 /* Size of line buffer */ X X/* Global variables */ Xint table; /* Generate a table, or extract */ Xint verbose; /* Unshar verbosely - debugging */ Xint numext; /* Number of files to extract */ Xint binfile; /* Binary file - err indicator */ Xchar *exfile[100]; /* Files to extract */ X X X#define getline(x,y) fgetline(stdin,x,y) X Xint Xfgetline(zin, how, buf) /* Get a line from a file */ X FILE *zin; X int how; /* Ignore leading whitespace if */ X char *buf; /* how == NOWHITE */ X{ X int ch = 0; X X *buf = 0; /* Null the buffer */ X if (how == NOWHITE) { /* If skip any whitespace */ X while (((ch = fgetc(zin)) == ' ') || (ch == '\t')); X if (ch == EOF) X return (EOF); /* Returning EOF or 0 */ X if (ch == '\n') X return (0); X *buf++ = ch; /* Put char in buffer */ X } X while ((ch = fgetc(zin)) != '\n') { /* Now get the line */ X if (ch == EOF) { X *buf = 0; X return (EOF); X } X if (ch > 127) { X binfile = 1; X return (0); X } X *buf++ = ch; X } X X *buf = 0; /* Finally null-terminate the buffer */ X return (0); /* and return */ X} X X X Xchar * Xgetstring(buf) /* Get the next string from the buffer */ X char *buf; /* ignoring any quotes */ X{ X char out[BUFSIZE]; X char *temp = out; X char inquotes = 0, ok = 1; X while ((*buf == ' ') || (*buf == '\t')) X buf++; /* Skip whitespace */ X X if (verbose) X printf("In getstring...\n"); X *temp = 0; X while (ok) { /* Parse line */ X#ifdef DEBUG X if (verbose) X printf("*%s*\n", out); X#endif X switch (*buf) { X case '\"': X case '\'': X buf++; X inquotes != inquotes; /* Toggle inquotes */ X break; X case 0: X case '\n': /* Stop on <, >, NULL */ X case '>': /* \n, and sometimes */ X case '<': X ok = 0; X break; /* space & tab */ X case '\t': X case ' ': X if (!inquotes) X ok = 0; X case '\\': X if (!inquotes) { /* Ignore backquotes */ X buf++; X break; X } X default: X *temp++ = *buf++; /* Copy chars :-) */ X } X } X *temp = 0; X if (verbose) X printf("Returning *%s*\n", out); X return (out); X} X X Xint Xfirstword(buf) /* Return token value of first word */ X char *buf; /* in the buffer. Assume no leading */ X{ /* whitespace in the buffer */ X int i; X X for (i = 1; i < NUMTOKS; i++) X if (strncmp(buf, token[i], strlen(token[i])) == 0) X return (i); X X return (UNKNOWN); X} X X Xint Xmustget(s1) /* Return 1 if s1 is in the list of */ X char *s1; /* files to extract. Return 0 if not */ X{ X int i; X X if (numext == 0) X return (0); X for (i = 0; i < numext; i++) X if (!strcmp(s1, exfile[i])) X return (1); X return (0); X} X X Xvoid Xextract(how, file, end, lead) /* Extract file, up until end word */ X int how; /* If how==YESX, then ignore lead */ X char *file; /* character on every line */ X char *end; X int lead; X{ X FILE *zout; X char line[BUFSIZE]; X char *temp; X int ch; X X zout = fopen(file, "w");/* Open output file */ X if (zout == NULL) { X perror("unshar1"); X return; X } X while (1) { X binfile = 0; X ch = getline(WHITE, line); /* Get a line of file */ X temp = line; X if (binfile || (ch == EOF)) { X fprintf(zout, "%s\n", line); X fclose(zout); X return; X } X if ((how == YESX) && (*temp == lead)) X temp++; /* Skip any lead */ X X if (strcmp(temp, end) == 0) { /* If end word */ X fclose(zout); /* close the file */ X return; X } X fprintf(zout, "%s\n", temp); X } X} X X Xvoid Xgetnames(buf, file, word) /* Get the file & end word */ X char *buf, *file, *word; /* from the buffer */ X{ X char *temp; X X temp = buf; X if (verbose) X printf("Getnames: buf is %s\n", buf); X X while (*temp != 0) { /* Scan along buffer */ X switch (*temp) {/* Get file or end word */ X case '>': X strcpy(file, getstring(++temp)); /* Get the file name */ X break; X case '<': X if (*(++temp) == '<') X ++temp; /* Skip 2nd < */ X strcpy(word, getstring(temp)); /* Get next word */ X break; X default: X temp++; X } X } X} X X X Xvoid Xdisembowel() X{ /* Unshar brutally! */ X char buf[BUFSIZE]; /* Line buffer */ X char file[BUFSIZE]; /* File name */ X char word[BUFSIZE]; /* Word buffer */ X int ch, x; X X if (verbose) X printf("Entering disembowel\n"); X x = 'X'; /* Leading X character */ X while (1) { X binfile = 0; X ch = getline(NOWHITE, buf); /* Get a line from file */ X if (ch == EOF) X return; X if (binfile) X continue; X X switch (firstword(buf)) { /* Extract, depending on X * first word */ X case CAT: X if (verbose) X printf("About to do getnames\n"); X getnames(buf, file, word); X if (table == 0) { X if ((numext == 0) || (mustget(file))) { X printf("unshar: Extracting %s\n", file); X if (verbose) X printf(" stopping at %s\n", word); X extract(NOX, file, word, x); X } X } else X printf(" %s\n", file); X break; X case GRES: X case SED: X if (verbose) X printf("About to do getnames\n"); X getnames(buf, file, word); X if (table == 0) { X if ((numext == 0) || (mustget(file))) { X printf("unshar: Extracting %s\n", file); X if (verbose) X printf(" stopping at %s\n", word); X extract(YESX, file, word, x); X } X } else X printf(" %s\n", file); X break; X default: X break; X } X } X} X X X Xusage() X{ X fprintf(stderr, "Usage: unshar [-t] [-b] [-v] [-xfile] [file(s)]\n"); X exit(0); X} X X Xmain(argc, argv) X int argc; X char *argv[]; X{ X extern int optind; X extern char *optarg; X int i, c, first; X X FILE *zin; /* Dummy file descriptor */ X int method; /* Method of unsharing */ X X method = BRUTAL; /* Only BRUTAL currently available */ X table = 0; /* Don't generate a table */ X verbose = 0; /* Nor be very verbose */ X numext = 0; /* Initially no files to extract */ X X X while ((c = getopt(argc, argv, "x:tbv")) != EOF) X switch (c) { X case 't': X table = 1; /* Get the various options */ X break; X case 'b': X method = BRUTAL; X break; X case 'v': X verbose = 1; X break; X case 'x': X exfile[numext] = (char *) malloc(strlen(optarg) + 1); X strcpy(exfile[numext++], optarg); X break; X default: X usage(); X } X X if (argc == 1) X first = argc; /* Find first file argument */ X else X for (first = 1; first < argc; first++) X if (argv[first][0] != '-') X break; X X if (first == argc) { /* If no file argument *//* use stdin only */ X switch (method) { X case BRUTAL: X disembowel(); /* Unshar brutally! */ X break; X default: X fprintf(stderr, "unshar: Unknown method of unsharing\n"); X exit(1); X } X } else X for (i = first; i < argc; i++) { /* open stdio with every X * file */ X if (table) X printf("%s:\n", argv[i]); X fclose(stdin); X if ((zin = fopen(argv[i], "r")) == NULL) { X perror("unshar2"); X exit(1); X } X switch (method) { X case BRUTAL: X disembowel(); /* Unshar brutally! */ X break; X default: X fprintf(stderr, "unshar: Unknown method of unsharing\n"); X exit(1); X } X } X exit(0); X} / Warren Toomey VK2XWT, still 386-less. Deep in the bowels of ADFA Comp Science. `The rain is coming in thru the windows, is that ok?'