doc@s.cc.purdue.edu.UUCP (06/05/87)
Here is a small unshar'ing program that I worked up real quick. It does not support directories or atob/btoa shell archives, but that may come later depending on demand. It does work on all the different shell archive types I came across and works on both Unix and the Amiga. Have fun and please send any bugfixes/enhancements to me! Craig Norborg comp.sources.amiga moderator # 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: # unshar.c # This archive created: Fri Jun 5 02:05:34 1987 # By: Craig Norborg (Purdue University Computing Center) cat << \SHAR_EOF > unshar.c /* * unshar -- undo a shell archive file * (C) Copyright June 4 1987 by Craig Norborg * Permission given to use this code in any form as long as it is * not sold or marketed in any form without the written permission * of its author. Removal of this copyright notice is expressly * forbidden as well as any alteration of it. */ /* * Here is a small unshar program written to be as portable as possible. * It was written under Aztec C on an Amiga and tested on a VAX 11/780, * pdp11/70 and a Sequent Balance 21000. Any bug reports or enhancements * should be reported to the author. Some further enhancements may * include the correct handling of sub-directories and the handling of * btoa/atob type shars. If you find a type of shar that this code * does not work on, please send it to me, doc@j.cc.purdue.edu. */ #include <stdio.h> #include <ctype.h> #define BUFSIZE 512 /* Max length of an input line */ #define STRLEN 25 /* Max length of a file name or delimiter */ #define CAT "cat" /* The name of the 'cat' program */ #define SED "sed" /* The name of the 'sed' program */ #define WCOUNT "if test" /* Leader for 'wc' testing */ /* * This is a small routine that given a 'cat' or 'sed' string, will pull out * the end of file string and the file name */ void getendfile(line, end, file) char *line, /* The 'sed' or 'cat' string */ *end, /* Place to store the end of file marker */ *file; /* Place for the filename */ { char *tmp, *rindex(); register int i = 0; /* * This section of code finds the end of file string. It assumes * that the eof string is the string of characters immediately * following the last '<' and that it has either a '\' preceding it * or is surrounded by single quotes. */ tmp = (char *) rindex(line, '<'); /* Find the last '<' on the * line */ while (isspace(*++tmp)) ; /* Do nothing */ if ('\'' == *tmp) { /* Is it a quoted string? */ while ('\'' != *++tmp) end[i++] = *tmp; tmp++; } else if ('\\' == *tmp) { /* Is it a backslashed string? */ while (!isspace(*++tmp)) end[i++] = *tmp; } else { /* Uh-oh! */ (void) printf("Can't find eof string\n"); exit(2); } end[i] = '\0'; /* Null off the end of the string */ /* * This section of code finds the name of the file. It assumes that * the name of the file is the string immediately following the last * '>' in the line */ i = 0; tmp = (char *) rindex(line, '>'); while (isspace(*++tmp)) ; /* Do Nothing */ while (!isspace(*tmp)) { file[i++] = *tmp; tmp++; } file[i] = '\0'; /* Null off the end of the string */ #ifdef DEBUG (void) printf("EOF = %s, FILE = %s\n", end, file); #endif DEBUG } int main(argc, argv) int argc; char **argv; { FILE *fp, *dfp, *fopen(); /* input file pointer and dest file * pointer */ char buf[BUFSIZE], /* line buffer */ prefix[STRLEN], /* SED leader if any */ endstring[STRLEN], /* EOF marker */ filename[STRLEN]; /* file name */ int infile = 0, /* var to tell if we're in the middle of a * file or not */ wc = 0; /* variable to keep a word count */ if (1 == argc) { /* check usage */ (void) printf("usage: unshar <file>"); } if (NULL == (fp = fopen(argv[1], "r"))) { (void) printf("Error opening input file\n"); exit(1); } while (NULL != fgets(buf, BUFSIZE, fp)) { /* while there are lines * to get */ #ifdef DEBUG puts(buf); #endif DEBUG if (0 == infile) { /* if we are not in the middle of a * file */ if ('#' == buf[0]) /* comment? */ continue; /* Is this a CAT type shar? */ if (0 == strncmp(buf, CAT, strlen(CAT))) { prefix[0] = '\0'; getendfile(buf, endstring, filename); if (NULL == (dfp = fopen(filename, "w"))) { (void) printf("Error opening output file %s\n", filename); exit(1); } (void) printf("Extracting %s ... ", filename); (void) fflush(stdout); infile = 1; wc = 0; continue; } /* Is it a SED type shar? */ if (0 == strncmp(buf, SED, strlen(SED))) { register int i = 0, j = 0; while ('^' != buf[i++]) ; while ('/' != buf[i]) { prefix[j++] = buf[i++]; } prefix[j] = '\0'; getendfile(&buf[i], endstring, filename); if (NULL == (dfp = fopen(filename, "w"))) { (void) printf("Error opening output file %s\n", filename); exit(1); } (void) printf("Extracting %s ... ", filename); (void) fflush(stdout); infile = 1; wc = 0; continue; } /* Did we want to do a word count on that last file? */ if (0 == strncmp(buf, WCOUNT, strlen(WCOUNT))) { register int i = 0; while(!isdigit(buf[i])) i++; if (wc != atoi(&buf[i])) (void) printf("Error unsharing %s (wc should have been %d, but was %d)\n", filename, atoi(&buf[i]), wc); continue; } } else { /* We are in the middle of a file */ /* Are we at the end of this one? */ if (0 == strncmp(buf, endstring, strlen(endstring))) { (void) printf("Done\n"); (void) fclose(dfp); infile = 0; continue; } /* No, then does it have a prefix? */ if ('\0' == prefix[0]) { fputs(buf, dfp); wc = wc + strlen(buf); } else { /* * If it does have a prefix, is there one on * this line? */ if (0 != strncmp(buf, prefix, strlen(prefix))) { fputs(buf, dfp); } else { fputs(&buf[strlen(prefix)], dfp); wc = wc + strlen(buf) - strlen(prefix); } } } } (void) printf("All Done!\n"); (void) fclose(fp); } SHAR_EOF # End of shell archive exit 0
doc@s.cc.purdue.edu (Craig Norborg) (06/24/87)
Here is a repost of my unshar program.. It works a bit better and now handles checking to see if files exist before writing over them (if it is in the shar file to do so). It compiles under AZTEC C when given the -DAMIGA flag using 16 bit ints. Binaries will follow in comp.binaries.amiga. /* * unshar -- undo a shell archive file * (C) Copyright June 4 1987 by Craig Norborg * Permission given to use this code in any form as long as it is * not sold or marketed in any form without the written permission * of its author. Removal of this copyright notice is expressly * forbidden as well as any alteration of it. */ /* * Here is a small unshar program written to be as portable as possible. * It was written under Aztec C on an Amiga and tested on a VAX 11/780, * pdp11/70 and a Sequent Balance 21000. Any bug reports or enhancements * should be reported to the author. Some further enhancements may * include the correct handling of sub-directories and the handling of * btoa/atob type shars. If you find a type of shar that this code * does not work on, please send it to me, doc@j.cc.purdue.edu. */ #include <stdio.h> #include <ctype.h> #ifdef unix #include <sys/file.h> #endif unix #ifdef AMIGA #define F_OK 0 #endif AMIGA #define BUFSIZE 512 /* Max length of an input line */ #define STRLEN 25 /* Max length of a file name or delimiter */ #define CAT "cat" /* The name of the 'cat' program */ #define SED "sed" /* The name of the 'sed' program */ #define TEST "if test" /* Leader for test types */ /* * This is a small routine that given the beginning of a quoted, backslashed * or just plain string, will return it in a given buffer. */ void copystring(source, dest) char *source, *dest; { register int i = 0; char c; if ('\'' == *source || '\"' == *source) {/* Is it a quoted string? */ c = *source; while (c != *++source) dest[i++] = *source; source++; } else if ('\' == *source) { /* Is it a backslashed string? */ while (!isspace(*++source)) dest[i++] = *source; } else { /* Just a string */ while (!isspace(*source)) { dest[i++] = *source; source++; } } dest[i] = '\0'; } void wordcount(buf, filename, wc) char *buf, *filename; int wc; { if (wc != atoi(buf)) { (void) printf("Error unsharing %s (wc should have been %d, but was %d)\n", filename, atoi(buf), wc); } } int checkfile(string) char *string; { char filename[BUFSIZE]; while (0 != isspace(*string)) string++; copystring(string, filename); if (0 == access(filename, F_OK)) return 1; return 0; } /* * This is a small routine that given a 'cat' or 'sed' string, will pull out * the end of file string and the file name */ void getendfile(line, end, file) char *line, /* The 'sed' or 'cat' string */ *end, /* Place to store the end of file marker */ *file; /* Place for the filename */ { char *tmp, *rindex(); /* * This section of code finds the end of file string. It assumes * that the eof string is the string of characters immediately * following the last '<' and that it has either a '\' preceding it * or is surrounded by single quotes. */ tmp = (char *) rindex(line, '<'); /* Find the last '<' on the * line */ while (isspace(*++tmp)) ; /* Do nothing */ copystring(tmp, end); /* * This section of code finds the name of the file. It assumes that * the name of the file is the string immediately following the last * '>' in the line */ tmp = (char *) rindex(line, '>'); while (isspace(*++tmp)) ; /* Do Nothing */ copystring(tmp, file); #ifdef DEBUG (void) printf("EOF = %s, FILE = %s\n", end, file); #endif DEBUG } int main(argc, argv) int argc; char **argv; { FILE *fp, *dfp, *fopen(); /* input file pointer and dest file * pointer */ char buf[BUFSIZE], /* line buffer */ prefix[STRLEN], /* SED leader if any */ endstring[STRLEN], /* EOF marker */ filename[STRLEN]; /* file name */ int infile = 0, /* var to tell if we're in the middle of a * file or not */ wc = 0, /* variable to keep a word count */ fileexists = 0; /* does the file exist? */ if (1 == argc) { /* check usage */ (void) printf("usage: unshar <file>"); } if (NULL == (fp = fopen(argv[1], "r"))) { (void) printf("Error opening input file\n"); exit(1); } while (NULL != fgets(buf, BUFSIZE, fp)) { /* while there are lines * to get */ #ifdef DEBUG puts(buf); #endif DEBUG if (0 == infile) { /* if we are not in the middle of a * file */ if ('#' == buf[0]) /* comment? */ continue; /* Is this a CAT type shar? */ if (0 == strncmp(buf, CAT, strlen(CAT))) { prefix[0] = '\0'; getendfile(buf, endstring, filename); if (fileexists != 0) { fprintf(stderr, "File exists (%s), skipping\n", filename); fileexists = 0; continue; } if (NULL == (dfp = fopen(filename, "w"))) { (void) printf("Error opening output file %s\n", filename); exit(1); } (void) printf("Extracting %s ... ", filename); (void) fflush(stdout); infile = 1; wc = 0; continue; } /* Is it a SED type shar? */ if (0 == strncmp(buf, SED, strlen(SED))) { register int i = 0, j = 0; while ('^' != buf[i++]) ; while ('/' != buf[i]) { prefix[j++] = buf[i++]; } prefix[j] = '\0'; getendfile(&buf[i], endstring, filename); if (fileexists != 0) { fprintf(stderr, "File exists (%s), skipping\n", filename); fileexists = 0; continue; } if (NULL == (dfp = fopen(filename, "w"))) { (void) printf("Error opening output file %s\n", filename); exit(1); } (void) printf("Extracting %s ... ", filename); (void) fflush(stdout); infile = 1; wc = 0; continue; } /* Do we want to do a test of sorts on a file? */ if (0 == strncmp(buf, TEST, strlen(TEST))) { register int i = 0; while(!isdigit(buf[i]) && '-' != buf[i] && NULL != buf[i]) i++; if (0 != isdigit(buf[i])) { wordcount(&buf[i], filename, wc); } if ('f' == buf[++i]) { fileexists = checkfile(&buf[++i]); } continue; } } else { /* We are in the middle of a file */ /* Are we at the end of this one? */ if (0 == strncmp(buf, endstring, strlen(endstring))) { (void) printf("Done\n"); (void) fclose(dfp); infile = 0; continue; } /* No, then does it have a prefix? */ if ('\0' == prefix[0]) { fputs(buf, dfp); wc = wc + strlen(buf); } else { /* * If it does have a prefix, is there one on * this line? */ if (0 != strncmp(buf, prefix, strlen(prefix))) { fputs(buf, dfp); } else { fputs(&buf[strlen(prefix)], dfp); wc = wc + strlen(buf) - strlen(prefix); } } } } (void) printf("All Done!\n"); (void) fclose(fp); }