Path: utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!munnari.oz.au!basser!usage!ccadfa!csadfa!wkt From: wkt@csadfa.cs.adfa.oz.au (Warren Toomey) Newsgroups: comp.binaries.ibm.pc.d Subject: unshar(1) for the PC Message-ID: <830@ccadfa.adfa.oz.au> Date: 19 Dec 89 08:44:05 GMT Sender: news@ccadfa.adfa.oz.au Lines: 569 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 #else #include #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 #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' : 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 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'