wkt@csadfa.cs.adfa.oz.au (Warren Toomey) (12/19/89)
This is the WRONG newsgroup to post to, but I saw somebody ask for an Unshar for the PC. I knocked this up a few weeks ago, and although it was intended to run under Unix, it does compile & run under MS-DOS. Modifications may be needed to get it to work with _every_ shell archive! Hope this is what you wanted! Warren Toomey ----ok, you have to use Unix, or manually unshar this shell archive ----- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s Makefile` then echo "writing Makefile" cat > Makefile << '\Rogue\Monster\' O= s unshar: Makefile unshar.$(O) cc -o unshar unshar.$(O) -lgetopt strip unshar chmem =10000 unshar unshar.$(O): Makefile unshar.c unshar.h cc -c -O unshar.c shar: README Makefile unshar.h unshar.c unshar.1 shar README Makefile unshar.h unshar.c unshar.1 > unshar.shar \Rogue\Monster\ else echo "will not over write Makefile" fi if `test ! -s README` then echo "writing README" cat > README << '\Rogue\Monster\' Here is a version of unshar that I have `knocked up' in the past few weeks. It isn't as flash as the standard unshar, but I've made it modular so it can be enhanced easily. However, it has some advantages: - it does not call any other program, especially /bin/sh - it can extract specific files from the shar - can give a table of contents without extracting files - takes several input files, or the standard input - ignores leading `junk' e.g news headers - emulates sed, gres and cat to do the unsharing - avoids the Minix `cat /dev/null > file' problem :-) - it works `as is' under MS-DOS (needs getopt) I've used it to unshar lots of different files; there are bound to be some that it can't extract, but fixing the program should be easy. Warren Toomey - wtoomey@csadfa.oz.au@munnari.oz[@uunet] \Rogue\Monster\ else echo "will not over write README" fi if `test ! -s getopt.c` then echo "writing getopt.c" cat > getopt.c << '\Rogue\Monster\' /* ** @(#)getopt.c 2.2 (smail) 1/26/87 */ /* * Here's something you've all been waiting for: the AT&T public domain * source for getopt(3). It is the code which was given out at the 1985 * UNIFORUM conference in Dallas. I obtained it by electronic mail * directly from AT&T. The people there assure me that it is indeed * in the public domain. * * There is no manual page. That is because the one they gave out at * UNIFORUM was slightly different from the current System V Release 2 * manual page. The difference apparently involved a note about the * famous rules 5 and 6, recommending using white space between an option * and its first argument, and not grouping options that have arguments. * Getopt itself is currently lenient about both of these things White * space is allowed, but not mandatory, and the last option in a group can * have an argument. That particular version of the man page evidently * has no official existence, and my source at AT&T did not send a copy. * The current SVR2 man page reflects the actual behavor of this getopt. * However, I am not about to post a copy of anything licensed by AT&T. */ #ifdef BSD #include <strings.h> #else #include <string.h> #endif /*LINTLIBRARY*/ #define NULL 0 #define EOF (-1) #define ERR(s, c) if(opterr){\ extern int write();\ char errbuf[2];\ errbuf[0] = c; errbuf[1] = '\n';\ (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ (void) write(2, s, (unsigned)strlen(s));\ (void) write(2, errbuf, 2);} extern char *index(); int opterr = 1; int optind = 1; int optopt; char *optarg; int getopt(argc, argv, opts) int argc; char **argv, *opts; { static int sp = 1; register int c; register char *cp; if(sp == 1) if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return(EOF); else if(strcmp(argv[optind], "--") == NULL) { optind++; return(EOF); } optopt = c = argv[optind][sp]; if(c == ':' || (cp=index(opts, c)) == NULL) { ERR(": illegal option -- ", c); if(argv[optind][++sp] == '\0') { optind++; sp = 1; } return('?'); } if(*++cp == ':') { if(argv[optind][sp+1] != '\0') optarg = &argv[optind++][sp+1]; else if(++optind >= argc) { ERR(": option requires an argument -- ", c); sp = 1; return('?'); } else optarg = argv[optind++]; sp = 1; } else { if(argv[optind][++sp] == '\0') { sp = 1; optind++; } optarg = NULL; } return(c); } \Rogue\Monster\ else echo "will not over write getopt.c" fi if `test ! -s index.c` then echo "writing index.c" cat > index.c << '\Rogue\Monster\' char *index(s, c) register char *s, c; { do { if (*s == c) return(s); } while (*s++ != 0); return(0); } \Rogue\Monster\ else echo "will not over write index.c" fi if `test ! -s unshar.1` then echo "writing unshar.1" cat > unshar.1 << '\Rogue\Monster\' .T1 unshar 1L .SH NAME unshar \- extract files from shell archive(s) .SH SYNTAX unshar [\-t] [\-b] [-v] [-xfile] [file(s)] .SH OPTIONS Options are processed by .B getopts(3). .TP 8 .B \-t Do not extract files, just list the files in the archive(s). .TP .B \-b Extract files from the archive(s) brutally, with no regard at all to things such as testing if the file exists, or chmoding the file etc. Currently this is the only method supported, but other methods would be easy to add. .TP .B \-v Be verbose. Used only for debugging purposes. .TP .B \-xfile Extract the named file from the shell archive. If the \-x flag is used, only those files specified will be extracted. .SH DESCRIPTION .I Unshar extracts files from one or more shell archives, and places them in the current directory. It does no forking to achieve this, and is relatively fast. If no file name is given as an agrumemt, .I unshar will use standard input. At the moment .I unshar is very simple-minded, and does its extraction rather brutally. The code has been written to allow more intelligent unarchiving methods to be added. .SH SEE ALSO shar(1), sh(1). \Rogue\Monster\ else echo "will not over write unshar.1" fi if `test ! -s unshar.c` then echo "writing unshar.c" cat > unshar.c << '\Rogue\Monster\' #include <stdio.h> #include "unshar.h" /* * Unshar - extract files from shell archive * * Written by Warren Toomey. Nov, 1989. * You may freely copy or give away this source as * long as this notice remains intact. * */ /* Global variables */ int table; /* Generate a table, or extract */ int verbose; /* Unshar verbosely - debugging */ int numext; /* Number of files to extract */ 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=NULL; *buf=NULL; /* Null the buffer */ if (how==NOWHITE) /* If skip any whitespace */ { while (((ch=fgetc(zin))==' ') || (ch=='\t')); if (ch==EOF) return(EOF); /* Returning EOF or NULL */ if (ch=='\n') return(NULL); *buf++ =ch; /* Put char in buffer */ } while ((ch=fgetc(zin))!='\n') /* Now get the line */ { if (ch==EOF) { *buf=NULL; return(EOF); } *buf++ = ch; } *buf=NULL; /* Finally null-terminate the buffer */ return(NULL); /* and return */ } char *getstring(buf) /* Get the next string from the buffer */ char *buf; /* ignoring any quotes */ { char out[BUFSIZE]; char *temp=out; while ((*buf==' ') || (*buf=='\t')) buf++; /* Skip whitespace */ switch(*buf) /* Now check first char */ { case '\'' : buf++; while (*buf!='\'') *temp++ = *buf++; *temp=NULL; return(out); case '\"' : buf++; while (*buf!='\"') *temp++ = *buf++; *temp=NULL; return(out); case NULL : return(NULL); default : while ((*buf!=' ') && (*buf!='\t')) if (*buf!='\\') *temp++ = *buf++; else buf++; *temp=NULL; 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("unshar"); return; } while(1) { ch=getline(WHITE,line); /* Get a line of file */ temp=line; if (ch==EOF) { fprintf(zout,"%s\n",line); fclose(zout); return; } if (strncmp(line,end,strlen(end))==0) /* If end word */ { fclose(zout); /* close the file */ return; } if ((how==YESX) && (*temp==lead)) temp++; /* Skip any lead */ 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!=NULL) /* 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) { ch=getline(NOWHITE,buf); /* Get a line from file */ if (ch==EOF) return; switch(firstword(buf)) /* Extract, depending on first word */ { case CAT: 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 */ { fclose(stdin); if ((zin=fopen(argv[i],"r"))==NULL) { perror("unshar"); exit(1); } switch(method) { case BRUTAL: disembowel(); /* Unshar brutally! */ break; default: fprintf(stderr,"unshar: Unknown method of unsharing\n"); exit(1); } } exit(0); } \Rogue\Monster\ else echo "will not over write unshar.c" fi if `test ! -s unshar.h` then echo "writing unshar.h" cat > unshar.h << '\Rogue\Monster\' /* * Unshar - extract files from shell archive * * Written by Warren Toomey. Nov, 1989. * You may freely copy or give away this source as * long as this notice remains intact. * * Definitions used by unshar */ /* 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 static char *token[NUMTOKS] = /* The list of emulation types! */ { "", "sed", "gres", "cat" }; /* Misc. constants */ #define BUFSIZE 256 /* Size of line buffer */ \Rogue\Monster\ else echo "will not over write unshar.h" fi echo "Finished archive 1 of 1" exit Warren Toomey VK2XWT, electric guitar licker. Deep in the bowels of ADFA Comp Science. Canberra. ACT. 2600. Email: wkt@csadfa.oz.au `Worth the money but not the risk -CC'
seanp@amix.commodore.com (Sean Petty) (02/16/91)
I'm sure this question is asked quite often, but I'll go ahead and ask it because I need to know. Is there an UNSHAR'ing utility for MS-DOS? I recently saw the jargon file on misc.misc and would like to un-shar it, yet have not been able to find a utility to do so... Could someone please mail, or post one? Thanks in advance... Sean _______ Sean Petty - Somewhere in Pennsylvania There is something fascinating about science. One gets such wholesale returns of conjecture out of such a trifling investment of fact. -- Mark Twain
w8sdz@rigel.acs.oakland.edu (Keith Petersen) (02/17/91)
undrground!seanp@amix.commodore.com (Sean Petty) writes: >Is there an UNSHAR'ing utility for MS-DOS? I recently saw the jargon file >on misc.misc and would like to un-shar it, yet have not been able to find >a utility to do so... WSMR-SIMTEL20.ARMY.MIL [26.2.0.74] NOTE: Type B is Binary; Type A is ASCII Directory PD1:<MSDOS.FILUTL> Filename Type Length Date Description ============================================== SHAREXE.ARC B 159288 880221 Unix-like shar/unshar for DOS TOADSHR1.ARC B 34760 890615 DOS Unix-compatible shar/unshar, w/TP 5.0 src UNSHAR.ARC B 24192 880326 Disassemble a shar file Keith -- Keith Petersen Maintainer of SIMTEL20's MSDOS, MISC & CP/M archives [IP address 26.2.0.74] Internet: w8sdz@WSMR-SIMTEL20.Army.Mil or w8sdz@vela.acs.oakland.edu Uucp: uunet!umich!vela!w8sdz BITNET: w8sdz@OAKLAND