page%rishathra@Sun.COM (Bob Page) (05/03/89)
Submitted-by: ecarroll@vax1.tcd.ie (Eddy Carroll) Posting-number: Volume 89, Issue 116 Archive-name: unix/unshar.1 This is yet another unshar utility. In brief: It's small, fast, handles all cat & sed format's I've seen (including multi-char sed strips), sub-directories, "./" type filenames and more. [uuencode executable included. ..bob] # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # makefile # tiny.a # unshar.c # unshar.doc # unshar.n # unshar.uu # This is archive 1 of a 1-part kit. # This archive created: Wed May 3 00:57:54 1989 echo "extracting makefile" sed 's/^X//' << \SHAR_EOF > makefile X# X# Aztec Make makefile, for Lattice C V4.0 :-) X# X# Unshar by Eddy Carroll, April 1989 X# X XZOOEXE = unshar unshar.doc XZOOSRC = unshar.c tiny.a tiny.o unshar.n makefile XOBJS = tiny.o unshar.o X# X# X# X.c.o: X lc -s -v $*.c X.a.o: X sys:lattice/c/asm -isys:include/ -u $*.a X.n.doc: X nro >$*.doc -ms:an $*.n X# X# X# Xall: unshar unshar.doc X Xunshar: $(OBJS) X blink from $(OBJS) to unshar sc sd nd map ram:map lib lib:lc.lib X Xtiny.o: tiny.a Xunshar.o: unshar.c Xunshar.doc: unshar.n X Xzoo: unshar.zoo Xzoosrc: unsharsrc.zoo X Xunshar.zoo: $(ZOOEXE) X -delete unshar.zoo X zoo a unshar.zoo $(ZOOEXE) X Xunsharsrc.zoo: $(ZOOSRC) X -delete unsharsrc.zoo X zoo a unsharsrc.zoo $(ZOOSRC) X Xclean: X -delete "#?.bak" SHAR_EOF echo "extracting tiny.a" sed 's/^X//' << \SHAR_EOF > tiny.a X*:ts=8 X**************************************************************************** X* * X* TINY.A (C) Copyright Eddy Carroll 1989 * X* ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * X* * X* This is a rewrite of the startup code provided with Lattice C V4.0. * X* It is a "bare bones" version, which is substantially smaller, and also * X* allows programs to be linked without needing to access lc.lib (unless * X* of course they are using functions in lc.lib). Only CLI programs are * X* supported, and no default i/o channels or other lattice-specific stuff * X* are initialised. exit() doesn't automatically clean up any more, so * X* don't use things like malloc() and fopen() unless you call free() and * X* fclose() yourself. This replacement is designed for programs that go * X* directly to AmigaDOS and Exec, rather than through the Unix-like Lattice * X* functions. * X* * X* All in all, this version shaves around 1500 bytes off the size of a C * X* program. No guarantees are supplied as regards its suitability for any * X* particular use, other than it works for me. * X* * X* Using it is very simple: Simply modify the command line for BLINK from * X* BLINK FROM LIB:C.O+.... to BLINK FROM TINY.O+... and leave everything * X* else the same. * X* * X* Note that when assembling this, make sure to specify the -u switch on * X* the Lattice assembler's command line. This adds a '_' to all symbols * X* defined. If you are using a different assembler, you need to add a '_' * X* manually yourself. * X* * X**************************************************************************** X X INCLUDE "exec/types.i" X INCLUDE "exec/alerts.i" X INCLUDE "exec/nodes.i" X INCLUDE "exec/lists.i" X INCLUDE "exec/ports.i" X INCLUDE "exec/libraries.i" X INCLUDE "exec/tasks.i" X INCLUDE "libraries/dos.i" X INCLUDE "libraries/dosextens.i" X INCLUDE "workbench/startup.i" X INCLUDE "exec/funcdef.i" X INCLUDE "exec/exec_lib.i" X INCLUDE "libraries/dos_lib.i" X XMAXARGS EQU 32 ; Maximum number of command line arguments from CLI XAbsExecBase EQU 4 ; Welcome to the only fixed point in the universe X X* A useful macro to let us call library routines Xcallsys macro X CALLLIB _LVO\1 X endm X X xdef XCEXIT * exit(code) is standard way to exit C. X xdef exit * X X xref LinkerDB * linker defined base value X xref _BSSBAS * linker defined base of BSS X xref _BSSLEN * linker defined length of BSS X X* library references X X csect text,0,0,1,2 * xref's after this are 16-bit reloc X X xref main * Name of C program to start with. X Xstart: X movem.l d1-d6/a0-a6,-(a7) XREGSIZE EQU (6+7)*4 X lea REGSIZE(a7),A5 * Determine old stack pointer X move.l a0,a2 * Save command pointer X move.l d0,d2 * and command length X lea LinkerDB,a4 * Load base register X X move.l AbsExecBase.W,a6 X move.l a6,SysBase(A4) X move.l a7,_StackPtr(A4) * Save stack ptr X X suba.l a1,a1 X callsys FindTask * Find out our task ID X move.l d0,a3 X X*======================================================================= X*====== CLI Startup Code =============================================== X*======================================================================= X* X* Entry: D2 = command length X* A2 = Command pointer XfromCLI: X move.l a5,D0 * get top of stack X sub.l 4(a5),D0 * compute bottom X add.l #128,D0 * allow for parms overflow X move.l D0,_base(A4) * save for stack checking X*----------------------------------------------------------------------- X* Open the DOS library: X XopenDOS X lea DOSName(A4),A1 X moveq.l #0,D0 X callsys OpenLibrary X move.l D0,DOSBase(A4) X bne getcom XnoDOS: X moveq.l #100,d0 X bra exit2 X X*------ find command name: Xgetcom: X move.l pr_CLI(a3),a0 X add.l a0,a0 * bcpl pointer conversion X add.l a0,a0 X move.l cli_CommandName(a0),a1 X add.l a1,a1 * bcpl pointer conversion X add.l a1,a1 X X*------ collect parameters: X move.l d2,d0 * get command line length X moveq.l #0,d1 X move.b (a1)+,d1 X move.l a1,_ProgramName(A4) X add.l d1,d0 * add length of command name X addq.l #1,d0 * allow for space after command X X clr.w -(A7) * set null terminator for command line X addq.l #1,D0 * force to even number of bytes X andi.w #$fffe,D0 * (round up) X sub.l D0,A7 * make room on stack for command line X subq.l #2,D0 X clr.w 0(A7,D0) X X*------ copy command line onto stack X move.l d2,d0 * get command line length X subq.l #1,d0 X add.l d1,d2 X Xcopy_line: X move.b 0(A2,D0.W),0(A7,D2.W) * copy command line to stack X subq.l #1,d2 X dbf d0,copy_line X move.b #' ',0(a7,d2.w) * add space between command and parms X subq.l #1,d2 X Xcopy_cmd: X move.b 0(a1,d2.w),0(a7,d2.w) * copy command name to stack X dbf d2,copy_cmd X move.l a7,a1 * Get pointer to new command line X X sub.l #(MAXARGS*4),a7 * Reserve space for argv[] X move.l a7,a2 * Initialise base into array X move.l a2,a3 * Save base of argv X moveq #0,d2 * Initialise argc X X* X* From here on down, A1 is pointer into command line X* Xbuild_argv: X bsr.s getnext * Read next character from line X bcs.s doquote * If quote, handle X beq.s build_argv * If white space, skip over it X X lea -1(a1),a0 * Get address of this parameter X bsr.s bumpargv * Store it to argv[] array Xbuild_2: X bsr.s getnext * Get next character X bne.s build_2 * If not white space, keep looking X clr.b -1(a1) * Zero-terminate current argument X bra.s build_argv * And go back to get next argument X Xdoquote: X move.l a1,a0 * Get pointer to this argument X bsr.s bumpargv * Output it to argv[] Xquote_2: X bsr.s getnext * Get next character X bcc.s quote_2 * If not quote, keep looking X clr.b -1(a1) * Zero-terminate current argument Xquote_3: X bsr.s getnext * Get next character X bne.s quote_3 * Skip until space reached X beq.s build_argv * Go back and read next argument X Xbumpargv: X move.l a0,(a2)+ * Output ptr to current argument X addq #1,d2 * Increment argc X cmpi #MAXARGS,d2 * Used up all our arguments yet? X bls.s qrts * If not, then return X moveq #110,d0 * Else set return code X bra.s exit2 * And exit X X* X* Reads next character from command line. If zero, never returns, but X* drops into call to main. Else, returns, with C=1 if character is quote, X* Z=1 if character is white space. X* Xgetnext: X move.b (a1)+,d0 * Get character from command line X beq.s get_2 * Exit if end of line X cmp.b #34,d0 * Check if quote X beq.s isquote * X cmp.b #32,d0 * Check if space X beq.s isspace * X cmp.b #9,d0 * Or tab X beq.s isspace * X cmp.b #10,d0 * Or end of line Xisspace: X andi #$1E,ccr * Clear carry flag, retaining Z Xqrts rts X Xisquote: X ori #1,ccr * Set carry flag X andi #$FB,ccr * Clear zero flag X rts * And return X Xget_2: X move.l a3,-(a7) * Push argv onto stack X move.l d2,-(a7) * Push argc onto stack X X lea _BSSBAS,a3 * get base of BSS X moveq #0,d1 X move.l #_BSSLEN,d0 * get length of BSS in longwords X bra.s clr_lp * and clear for length given Xclr_bss move.l d1,(a3)+ Xclr_lp dbf d0,clr_bss X Xdomain: X jsr main(PC) * Call main(argc,argv) X moveq.l #0,d0 * Set successful status X bra.s exit2 X Xexit: X_exit: XXCEXIT: X move.l 4(SP),d0 * Extract return code Xexit2: X move.l d0,-(a7) X move.l AbsExecBase.W,a6 X move.l DOSBase(A4),a1 X callsys CloseLibrary * Close Dos library X X*------ this rts sends us back to DOS: XexitToDOS: X MOVE.L (A7)+,D0 X movea.l _StackPtr(a4),SP * Restore stack ptr X movem.l (a7)+,d1-d6/a0-a6 X rts X X*----------------------------------------------------------------------- X* Global definitions X* X csect __MERGED,1,,2,2 X* X xdef NULL,SysBase,LoadAddress,DOSBase X xdef _oserr,_OSERR,_ONBREAK X xdef _ProgramName,_StackPtr,_base X* XNULL dc.l 0 X_base dc.l 0 X_oserr equ * X_OSERR dc.l 0 X_ONBREAK dc.l 0 XSysBase dc.l 0 XLoadAddress dc.l 0 X_StackPtr dc.l 0 XDOSBase dc.l 0 X_ProgramName dc.l 0 XDOSName dc.b 'dos.library',0 X X END SHAR_EOF echo "extracting unshar.c" sed 's/^X//' << \SHAR_EOF > unshar.c X/* X * Unshar (C) Copyright Eddy Carroll 1988 X * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ X * Usage: Unshar {-o} <filename> ... X * X * Extracts files from a SHAR'd archive. X * X * This utility has a few advantages over the version of SH on Fish Disk 92. X * For a start, it doesn't crash if it gets a slightly unusual format! It X * also has a (limited) capability for extracting files from shar archives X * which use 'SED' rather than 'CAT' (typically, this is done so that X * each line in the file may be prefixed with an 'X' or similar, so that X * indentation is preserved). Unshar will spot 'SED' lines, and treat them X * the same as 'CAT' (allowing for different parameters of course) with X * the exception that any leading characters matching the string specified X * in the SED command are discarded. X * X * Unshar checks files being extracted to see if they are to be stored X * within a sub-directory. If they are, and the sub-directory does not X * already exist, it is created. X * X * One other small addition is that any filenames which are prefixed with X * the characters "./" have these characters removed. Some shar files X * use this prefix to ensure that the files are stored in the current X * directory. X * X * Files are extracted into the current directory. As each file is extracted, X * an appropriate message is printed on the screen. If the file already X * exists, the user is warned and given the chance to avoid overwriting it X * "Overwrite file (Yes/No/All)? ". The default is Yes. If All is selected, X * then this prompt is supressed for the rest of the current file. It may X * be disabled for all the files by specifying the -o switch on the X * command line. X * X * DISTRIBUTION X * I retain copyright rights to this source code, though it may be _freely_ X * distributed. The executable file created from this source code is in X * the Public Domain and may be distributed without any restrictions. X * X */ X X/* Assumes Lattice V4.0 - should work with Aztec using 32 bit ints */ X X#include <exec/types.h> X#include <libraries/dos.h> X#include <proto/dos.h> X X#define YES 1 X#define NO 0 X#define CR '\015' X#define EOL '\012' X#define SINGLEQUOTE '\'' X#define DOUBLEQUOTE '\042' X Xchar HelpMsg[] = "\ XUnshar by Eddy Carroll 1988 Public Domain, extracts files from shar archives.\ X\n\ XUsage: unshar {-overwrite} <filename> ...\n"; X Xchar DiskMsg[] = "Unshar aborted - Disk write error (disk full?)\n"; Xchar ErrorMsg[] = "Unshar: Invalid CAT or SED command at line "; X Xint linenum; Xint CtrlC = NO; X X X/* X * Note - if you are using any 'C'-type memory allocators, or any C library X * functions which might conceivably allocate memory for you, delete the X * following line. If you are sticking to pure AmigaDOS calls, leave it X * in, and save yourself 1K. X * X */ X Xvoid MemCleanup(){} X X/* X * -------------------------------------------------------------------------- X * The following block may be removed `as-is' and used in other programs. X * It provides basic buffered i/o on two files, an input file and an output X * file. It also provides output to the current standard output via X * print. Buffering is done using buffers of size MAXBUF. X * X * The following routines are provided: X * X * getc() returns an integer corresponding to the next character read from X * infile, or EOF if the end of file has been reached. X * X * putc(c) outputs a character to outfile. putc(EOF) flushes the current X * output buffer to outfile, and should be called just before closing the X * file. X * X * getline() returns a pointer to a string containing the next line X * read in from infile. getline() also checks for CTRL-C via chkabort() X * X * putline(s) outputs a string to outfile, returning non-zero if an X * error occurred during the write. X * X * flushin() resets getc() and getline() for input from a new file X * X * input() returns a pointer to a string containing a line from stdin. X * X * print(s) prints a message on standard output. X * X * print3(s1,s2,s3) outputs three strings on standard output. X * X * numtostr(n) returns a pointer to the ascii representation of n. X * X * Special Notes X * ~~~~~~~~~~~~~ X * You should ensure that you use the filenames 'infile' and 'outfile' X * when you are opening the input and output files in main(). Also, X * do not #define EOF or MAXBUF elsewhere in your program. X * X */ X X#define EOF -1 X#define MAXBUF 4096 X XLONG infile, outfile, Open(), Input(), Output(), Read(); XLONG maxin = MAXBUF, maxout = MAXBUF, inbuf = MAXBUF, outbuf = 0; Xunsigned char inbuffer[MAXBUF], outbuffer[MAXBUF]; Xint diskerror = NO; X X/* X * int getc() X * Returns next character from infile, or EOF if end of file. X * X */ X Xint getc() X{ X if (!maxin) X return (EOF); X X if (inbuf >= maxin) { X maxin = Read(infile, inbuffer, MAXBUF); X inbuf = 0; X if (!maxin) X return (EOF); X } X return (inbuffer[inbuf++]); X} X X/* X * Prepares getc() for input from a new file X * X */ X X#define flushin() maxin = MAXBUF, inbuf = MAXBUF; X X/* X * putc(c) X * Outputs character C to disk. If C is an EOF, then the output is flushed. X * If error detected on Write, then all future writes are ignored until X * an EOF is output, and diskerror is set to YES. X * X */ X Xvoid putc(c) Xint c; X{ X if (c == EOF) X maxout = outbuf; X else X outbuffer[outbuf++] = c; X X if (outbuf >= maxout) { X if (!diskerror && Write(outfile, outbuffer, maxout) == -1) { X if (c == EOF) X diskerror = NO; X else X diskerror = YES; X } X outbuf = 0; X maxout = MAXBUF; X } X} X X/* X * print(s) X * Outputs a message to std output X * X */ X Xvoid print(s) Xchar *s; X{ X Write(Output(),s,strlen(s)); X} X X/* X * Outputs three strings to std output. X * Useful for sequences like print3("string", variable, "string"); X * X */ X Xvoid print3(s1,s2,s3) Xchar *s1,*s2,*s3; X{ X print(s1); X print(s2); X print(s3); X} X X/* X * Reads in a line from current infile into string, and returns a pointer X * to that string. Returns NULL if EOF encountered. X * X */ X Xchar *getline() X{ X register int ch, i = 0; X static char line[90]; X X ch = getc(); X if (ch == EOF) X return (NULL); X X while (i < 80 && ch != EOF && ch != EOL) { X line[i++] = ch; X ch = getc(); X } X X line[i] = '\0'; X linenum++; X chkabort(); X return (line); X} X X X/* X * Outputs a string to the current output file (terminating it with LF). X * Returns 0 for success, non-zero for disk error X * X */ X Xint putline(s) Xchar *s; X{ X while (*s) X putc(*s++); X putc(EOL); X return (diskerror); X} X X X/* X * Reads a line from keyboard and returns pointer to it X * X */ X Xchar *input() X{ X static char s[80]; X X s[Read(Input(),s,75)] = '\0'; X return(s); X} X X/* X * Converts integer to string and returns pointer to it. X * X */ Xchar *numtostr(n) Xint n; X{ X static char s[20]; X int i = 19; X X s[19] = '\0'; X if (n) X while (n) X s[--i] = '0' + (n % 10), n /= 10; X else X s[--i] = '0'; X return(&s[i]); X} X X/* X * -----------------------* End of Buffered IO routines *-------------------- X */ X X X/* X * index(s,c,skip) X * X * Like standard Unix index(), but skips over quotes if skip == true. X * Also skips over chars prefixed by a \. X * Returns pointer to first occurance of char c inside string s, or NULL. X * X */ X Xchar *index(s,c,skip) Xchar *s,c; Xint skip; X{ X register char *p = s; X register int noquotes = YES, literal = NO; X X while (*p) { X if (literal) { X literal = NO; X p++; X } else { X if (skip && ((*p == SINGLEQUOTE) || (*p == DOUBLEQUOTE))) X noquotes = !noquotes; X if (noquotes && (*p == c)) X return(p); X literal = (*p == '\\'); X p++; X } X } X return (NULL); X} X X X/* X * getname(s1,s2,mode) X * X * Extracts a string from start of string s1 and stores it in s2. Leading X * spaces are discarded, and quotes, if present, are used to indicate the X * start and end of the filename. If mode is MODE_FILE, then if the name X * starts with either './' or '/', this prefix is stripped. This doesn't X * happen if the mode is MODE_TEXT. A pointer to the first character after X * the string in s1 is returned. In addition, any characters prefixed with X * are passed through without checking. X * X */ X X#define MODE_FILE 1 X#define MODE_TEXT 2 X Xchar *getname(s1,s2,mode) Xchar *s1,*s2; X{ X char endchar = ' '; X X while (*s1 == ' ') X s1++; X X if (*s1 == SINGLEQUOTE || *s1 == DOUBLEQUOTE) X endchar = *s1++; X X if (mode == MODE_FILE) { X if (s1[0] == '.' && s1[1] == '/') X s1 += 2; X while (*s1 == '/') X s1++; X } X X while (*s1 && *s1 != endchar) { X if (*s1 == '\\' && *(s1+1)) X s1++; X *s2++ = *s1++; X } X *s2 = '\0'; X X if (*s1 == endchar) X return(++s1); X else X return(s1); X} X X X/* X * checkfordir(filename) X * X * Checks filename to see if it is inside a subdirectory. If it is, then X * checks if subdirectory exists, and creates it if it doesn't. X * X */ X Xvoid checkfordir(filename) Xchar *filename; X{ X char dir[80], *p; X int i, x; X long dirlock, Lock(), CreateDir(); X X p = filename; X X while (p = index(p, '/', 1)) { X X /* Dir exists, so copy dir part of filename into dir name area */ X X x = p - filename; X for (i = 0; i < x; i++) X dir[i] = filename[i]; X dir[i] = '\0'; X X /* Now, see if directory exists, if not then create */ X if ((dirlock = Lock(dir,ACCESS_READ)) == NULL) { X dirlock = CreateDir(dir); X if (dirlock) { X print3("Creating directory ", dir, "\n"); X } X } X if (dirlock) X UnLock(dirlock); X X p++; X } X} X X X/* X * Extracts all stored files from a shar file. Returns 0 for success, X * non-zero if disk error occurred. The echofilename parameter, if non-zero, X * causes the name of each shar file to be output before unsharing. X * If overwrite is non-zero, then existing files are overwritten without X * any warning. X * X */ X Xint unshar(sharfile, echofilename, overwrite) Xchar *sharfile; Xint echofilename, overwrite; X{ X register char *s, *p; X char endmarker[100], filename[100],sedstring[100]; X int endlen, stripfirst, startfile, found = NO, err = NO, skip, sedlen; X long filelock, Lock(); X X if ((infile = Open(sharfile, MODE_OLDFILE)) == NULL) { X print3("Can't open file ", sharfile, " for input\n"); X return(0); X } X X linenum = 0; X if (echofilename) X print3("\033[7m Shar file: ", sharfile, " \033[0m\n"); X X while (!err && !CtrlC && (s = getline()) != NULL) { X startfile = NO; X if (strncmp(s,"cat ",4) == 0) { X startfile = YES; X stripfirst = NO; X } X if (strncmp(s,"sed ",4) == 0) { X startfile = YES; X stripfirst = YES; X sedlen = 0; X if ((p = index(s,'^',0)) != NULL) { X while (*(++p) && *p != '/') X sedstring[sedlen++] = *p; X } X } X X if (startfile) { X if (found == NO) { X found = YES; X } X if ((p = index(s,'>',1)) == NULL) { X print3(ErrorMsg, numtostr(linenum), "\n"); X } else { X getname(++p,filename,MODE_FILE); X p = s; X while ((p = index(p,'<',1)) && (p[1] != '<')) X ; X if (p) X getname(p+2,endmarker,MODE_TEXT); X X endlen = strlen(endmarker); X X if (strlen(filename) && endlen) { X X checkfordir(filename); X X /* Found a valid line so perform extract */ X X /* Check if file exists */ X X skip = NO; X if (!overwrite) { X filelock = Lock(filename, ACCESS_READ); X if (filelock) { X UnLock(filelock); X print3("Overwrite file ", filename, X " (Yes, [No], All)? "); X X switch (tolower(*input())) { X X case 'a': X overwrite = YES; X break; X case 'y': X skip = NO; X break; X default: X skip = YES; X break; X } X } X } X X if ((outfile = Open(filename,MODE_NEWFILE)) == NULL) X print3("Couldn't open file ",filename," for output\n"); X else { X if (!skip) X print3("Unsharing file ", filename, "\n"); X s = getline(); X err = NO; X while (s && strncmp(s,endmarker,endlen) && !CtrlC) { X if (stripfirst && !strncmp(sedstring,s,sedlen)) X s += sedlen; X if (!skip && (err = putline(s))) X break; X s = getline(); X } X putc(EOF); X if (err) X print(DiskMsg); X Close(outfile); X } X } else X print(ErrorMsg, numtostr(linenum), "\n"); X } X } X } X if (!err && !CtrlC) X if (found) X print("Unshar done\n"); X else X print("No files to unshar\n"); X Close(infile); X flushin(); X return(err); X} X X/* X * New handler for Ctrl-C. Simply sets global variable to true and exits. X * X */ X Xint brk() X{ X CtrlC = YES; X return (0); X} X X/* X * Start of mainline X * X */ X Xint main(argc,argv) Xint argc; Xchar *argv[]; X{ X X int i, ok, overwrite = NO; X X if ((argc == 1) || (*argv[1] == '?')) { X print(HelpMsg); X return (10); X } X if (onbreak(brk)) X exit(10); X X for (i = 1, ok = YES; ok && i < argc && !CtrlC; i++) { X if (*argv[i] == '-' && (argv[i][1] == 'o' || argv[i][1] == 'O')) X overwrite = YES; X else X ok = !unshar(argv[i], argc > 2, overwrite); X } X X if (CtrlC) X print("^C\n"); X} SHAR_EOF echo "extracting unshar.doc" sed 's/^X//' << \SHAR_EOF > unshar.doc X X UNSHAR(1) AMIGA Programmer's Manual UNSHAR(1) X X X X NAME X unshar - extracts files from shar archives X X SYNOPSIS X unshar {-overwrite} file1 file2 ... X X DESCRIPTION X Unshar is a utility which extracts files from the ubiquitous X Unix shar archives. "But I have umpteen zillion unshar X utilities already", I hear you shout. Well, maybe so, but X this one has the following advantages: X X - Small and fast X - Handles many cat and sed formats X - Allows extraction of subdirectories X - Understands ./file type filenames X - Exits cleanly with CTRL-C X X The total code size is only slightly over 4K, for those with X packed C directories. It treats quotes and imbedded escape X sequences intelligently and handles all the cat and sed X formats I've ever seen, including sed commands which strip X off more than one letter. There are probably a few obscure X shar's out there it won't handle, but I've yet to find X them. X X Invoke unshar with as many filenames as you like. The -o X flag controls how unshar handles the extraction of files X which already exist. It can appear anywhere on the command X line, and only affects those files which appear after it. X Normally, if extracting a file would overwrite an existing X file, unshar will ask you how it should handle this. X Entering 'Y' will overwrite the existing file, 'N' will skip X past this file without extracting it, and 'A' will overwrite X this file, and also any other existing files from the X current shar file without prompting you again. If you don't X like prompts, specifying -o on the command line makes unshar X overwrite all existing files. X X OPERATION X Unshar scans through each archive specified on the command X line, looking for lines beginning with 'cat' or 'sed'. All X other lines are ignored. In particular, 'echo' lines are X not echoed. This way, you don't get a load of messages X which are in any case fairly meaningless, because the X operations they are describing are unsupported by most X unshars. X X When a shar archive contains a file for which a full X pathname is given (as in source/file.c for example) unshar X will create whatever directories are necessary. It also X strips off leading /'s and ./'s, to make filenames X understandable by AmigaDOS. X X AUTHOR X Eddy Carroll X Internet: ecarrollcs.tcd.ie X X X Copyright Eddy Carroll 1989 -1- SHAR_EOF echo "extracting unshar.n" sed 's/^X//' << \SHAR_EOF > unshar.n X.TH BACKDROP 1 "AMIGA Programmer's Manual" "Copyright Eddy Carroll 1989" X.SH NAME Xunshar - extracts files from shar archives X.SH SYNOPSIS Xunshar {-overwrite} file1 file2 ... X.SH DESCRIPTION XUnshar is a utility which extracts files from the ubiquitous Unix shar Xarchives. "But I have umpteen zillion unshar utilities already", XI hear you shout. Well, maybe so, but this one has the following advantages: X X.in +5 X- Small and fast X.br X- Handles many cat and sed formats X.br X- Allows extraction of subdirectories X.br X- Understands ./file type filenames X.br X- Exits cleanly with CTRL-C X.in -5 X XThe total code size is only slightly over 4K, for those with packed C Xdirectories. It treats quotes and imbedded escape sequences intelligently Xand handles all the cat and sed formats I've ever seen, including sed Xcommands which strip off more than one letter. There are probably a few Xobscure shar's out there it won't handle, but I've yet to find them. X XInvoke unshar with as many filenames as you like. The -o flag controls Xhow unshar handles the extraction of files which already exist. It can Xappear anywhere on the command line, and only affects those files which Xappear after it. Normally, if extracting a file would overwrite an Xexisting file, unshar will ask you how it should handle this. Entering X'Y' will overwrite the existing file, 'N' will skip past this file without Xextracting it, and 'A' will overwrite this file, and also any other existing Xfiles from the current shar file without prompting you again. If you don't Xlike prompts, specifying -o on the command line makes unshar overwrite all Xexisting files. X.SH OPERATION XUnshar scans through each archive specified on the command line, looking Xfor lines beginning with 'cat' or 'sed'. All other lines are ignored. In Xparticular, 'echo' lines are not echoed. This way, you don't get a load Xof messages which are in any case fairly meaningless, because the operations Xthey are describing are unsupported by most unshars. X XWhen a shar archive contains a file for which a full pathname is given X(as in source/file.c for example) unshar will create whatever directories Xare necessary. It also strips off leading /'s and ./'s, to make filenames Xunderstandable by AmigaDOS. X.SH AUTHOR XEddy Carroll X.br XInternet: ecarroll@cs.tcd.ie SHAR_EOF echo "extracting unshar.uu" sed 's/^X//' << \SHAR_EOF > unshar.uu X Xbegin 644 unshar XM```#\P`````````"``````````$```-2```)*````^D```-22.=^_DOO`#0D] XM2"0`2?D`````+'@`!"E.`!`I3P`8D\E.KO[:)D`@#9"M``0&@````(`I0``$D XM0^P`)'``3J[]V"E``!QF```(<&1@``#H(&L`K-'(T<@B:``0T\G3R2`"<@`2$ XM&2E)`"#0@5*`0F=2@`)`__Z?P%6`0G<(`"`"4X#4@1^R```@`%."4<C_]A^\V XM`"`@`%."'[$@`"``4<K_^")/G_P```"`)$\F2G0`831E$F?Z0>G__V$<82AF; XM_$(I__]@ZB!)80YA&F3\0BG__V$29OQGV"3(4D(,0@`@8R)P;F!0$!EG)@P`B XM`")G%@P``"!G"@P```EG!`P```H"/``>3G4`/``!`CP`^TYU+PLO`D?Y```"7 XME'(`(#P```B#8`(FP5'(__Q.N@AB<`!@!"`O``0O`"QX``0B;``<3J[^8B`?_ XM+FP`&$S??WY.=0``3G5(YS`"2JP!"F8$</]@1B(L`1*RK`$*;2PB+`*80>P"[ XMH"0()CP``!``+&P`'$ZN_]8I0`$*<``I0`$22JP!"F8$</]@$$'L`J#1[`$2, XM4JP!$G``$!!,WT`,3G5.50``2.<P`B(M``@,@?____]F"B`L`18I0`$.8!!![ XM[!*@(DC3[`$64JP!%A*!(BP!#B0L`1:T@6U$2JP!&F8R(BP"G$'L$J`D""8LB XM`0XL;``<3J[_T%*`9A@,K?____\`"&8(<``I0`$:8`9P`2E``1I"K`$6*7P`" XM`!```0Y,WT`,3EU.=4Y5__A(YS`"+&P`'$ZN_\0O0``,+RT`"$ZZ"9Q83R]`4 XM`!`B+P`,)"T`""8O`!`L;``<3J[_T$S?0`Q.74YU3E4``"\M``AAN%A/+RT`R XM#&&P6$\O+0`08:A83TY=3G5.5?_X2.<#`'P`80#^MBX`#(?_____9@1P`&!"D XM#(8```!0;"0,A_____]G'`R'````"F<40>PBH-'&4H8@!Q"`80#^@"X`8-1!S XM["*@T<9"$%*L`I1.N@F"0>PBH"`(3-\`P$Y=3G5.50``(&T`"$H09Q00$$B`C XM2,!2K0`(+P!A`/Z<6$]@Y$AX``IA`/Z06$\@+`$:3EU.=4Y5__Q(YS`"+&P`P XM'$ZN_\HO0``,(B\`#$'L(OHD"'9++&P`'$ZN_]9!["+Z(DC3P$(1(`A,WT`,L XM3EU.=4Y5__AP$RM`__Q"+"-=2JT`"&<\2JT`"&=(4ZW__$'L(TK1[?_\("T`* XM"'(*+T@``$ZZ!XX&@0```#`@;P``$($@+0`(<@I.N@=X*T``"&#$4ZW__$'L& XM(THB2-/M__P2O``P0>PC2M'M__P@"$Y=3G5.5?_T2.<C("1M``A^`7P`2A)G8 XM3DJ&9P9\`%**8/)*K0`09QH2$@P!`"=G!@P!`")F#$J'5\!$`$B`2,`N`$J'> XM9PX2$A0M``^T`68$(`I@%`P2`%Q7P$0`2(!(P"P`4HI@KG``3-\$Q$Y=3G5.` XM5?_^2.<@`!M\`"#__R!M``@,$``@9@92K0`(8/`@;0`($A`,`0`G9P8,`0`BQ XM9@A2K0`(&T'__PRM`````0`09B8@;0`(#!``+F8,#"@`+P`!9@14K0`((&T`: XM"`P0`"]F!E*M``A@\"!M``A*$&<N$A`4+?__M`%G)`P!`%QF"DHH``%G!%*MQ XM``@@;0`((FT`#!*04JT`"%*M``Q@RB!M``Q"$"!M``@2$+(M__]F#%*M``@@N XM;0`((`A@!"`(3G%,WP`$3EU.=4Y5_Z!(YR`"*VT`"/^L2'@``4AX`"\O+?^L: XM80#^L$_O``PK0/^L2H!G``"0D*T`"$*M_Z@K0/^D(BW_J+*M_Z1L$"!M``@;] XML!@`&+!2K?^H8.8@+?^H0C4(L$'M_[`B"'3^+&P`'$ZN_ZPK0/^@2JW_H&8LE XM0>W_L"((+&P`'$ZN_X@K0/^@2JW_H&<42&P!,DAM_[!(;`$>80#\SD_O``Q*V XMK?^@9PPB+?^@+&P`'$ZN_Z92K?^L8`#_5DS?0`1.74YU3E7^K$CG(")P`"M`7 XM_K@K0/Z\(BT`""0\```#[2QL`!Q.KO_B*4`"F$JL`IAF&DAL`48O+0`(2&P!Z XM-&$`_&I/[P`,<`!@``-J0JP"E$JM``QG%$AL`60O+0`(2&P!4F$`_$9/[P`,U XM2JW^N&8``OY*K`$&9@`"]F$`_$XD0+3\``!G``+H0JW^P$AX``1(;`%L+PI.7 XMN@1.3^\`#$J`9@IP`2M`_L!"K?[$2'@`!$AL`7(O"DZZ!"Y/[P`,2H!F3'`!P XM<@`O`4AX`%XO"BM`_L0K0/[`*T'^L&$`_3)/[P`,*T#_^$J`9R12K?_X(&W_\ XM^$H09Q@2$`P!`"]G$$/M_LS3[?ZP4JW^L!*!8-Q*K?[`9P#_5DJM_KQF!G`!) XM*T#^O$AX``%(>``^+PIA`/S@3^\`#"M`__A*@&8@+RP"E&$`_%Q83TAL`7@O# XM`$AL`-EA`/M83^\`#&``_Q!2K?_X(&W_^$AX``%(;?\P+PAA`/T*3^\`#"M*W XM__A(>``!2'@`/"\M__AA`/R&3^\`#"M`__A*@&<*($`,*``\``%FVDJM__AGW XM&"!M__A4B$AX``)(;?^4+PAA`/S"3^\`#$AM_Y1.N@1>6$](;?\P*T#^R$ZZ8 XM!%!83TJ`9P`!=$JM_LAG``%L2&W_,&$`_5A83T*M_K1*K0`09G)![?\P(@ATN XM_BQL`!Q.KO^L*T#^K$JM_JQG6"(M_JPL;``<3J[_IDAL`8I(;?\P2&P!>F$`/ XM^GY/[P`,80#[+B!`$A!(@4C!+P%.N@,$6$\,@````'EG$`R`````868.<`$K_ XM0``08`Q"K?ZT8`9P`2M`_K1![?\P(@@D/````^XL;``<3J[_XBE``IQ*K`*<5 XM9AA(;`&R2&W_,$AL`9YA`/H43^\`#&``_<Q*K?ZT9A1(;`'02&W_,$AL`<!A@ XM`/GV3^\`#&$`^@XD0$*M_KBT_```9UHO+?[(2&W_E"\*3KH"$$_O``Q*@&=$8 XM2JP!!F8^2JW^Q&<:+RW^L"\*2&W^S$ZZ`>Y/[P`,2H!F!-7M_K!*K?ZT9A`O0 XM"F$`^B!83RM`_KA*@&8(80#YK"1`8*!(>/__80#XO%A/2JW^N&<*2&P`J6$`% XM^3)83R(L`IPL;``<3J[_W&``_1XO+`*480#Z2EA/2&P!TB\`2&P`V6$`^0A/U XM[P`,8`#\_DJM_KAF(DJL`09F'$JM_KQG#$AL`=1A`/CF6$]@"DAL`>)A`/C:0 XM6$\B+`*8+&P`'$ZN_]P@/```$``I0`$**4`!$B`M_KA,WT0$3EU.=7`!*4`!U XM!G``3G5.5?_T2.<X`$*M__0,K0````$`"&<0(FT`#"!I``00$`P``#]F$$AL. XM`#!A`/AZ6$]P"F```+!(>O^^3KH"B%A/2H!G"DAX``I.NO=:6$]P`2M`__@KO XM0/_\2JW_^&=V(BT`""0M__RT@6QJ2JP!!F9D(`+E@")M``P@<0@`%A`,`P`M8 XM9AA2B!`0#```;V<&#```3V8(<`$K0/_T8#(@`N6`#($````"7L%$`4B!2,$O% XM+?_T+P$O,0@`80#[A$_O``Q*@%?!1`%(@4C!*T'_^%*M__Q@A$JL`09G"DAL^ XM`?9A`/?&6$],WP`<3EU.=4CG,#(L>0```I`@;P`8(F\`'"1O`"`F;P`D("\`( XM*"(O`"PD+P`P)B\`-$ZN_J1,WTP,3G5.5?_\2JT`$&<P(&T`"$H09R@B;0`,J XM2A%G('``$!!2K0`(<@`2$5*M``R0@2M`__Q*@&8F4ZT`$&#*2JT`$&<8(&T`S XM"$H09P1P`6`.(&T`#$H09P1P_V`"<`!.74YU```@+P`$#```06T*#```6FX$H XM!@``($YU``!*@&H``!Y$@$J!:@``#$2!80``($2!3G5A```81(!$@4YU2H%J( XM```,1(%A```&1(!.=2\"2$$T`68``")(0$A!2$(T`&<```:$P3`"2$`T`(3!J XM,`)(0C(")!].=2\#=A`,00"`9```!N&944,,00@`9```!NF964,,02``9```A XM!N6954-*06L```;CF5-#-`#FJ$A"0D+FJDA#@,$V`#`"-`-(0<3!D()D```(! XM4T/0@63^<@`R`TA#Y[A(0,-`)A\D'TYU(&\`!$H89OQ3B)'O``0@"$YU``!.? XM5?_X2.<!('X`1>PC8+ZL`?QL'DJ29Q0(*@`"``-G`F`*+RH`!$ZZ`/Q83U*'! XM4(I@W"\M``PO+0`(3KKT^%!/3-\$@$Y=3G5P`6`.(&T`#$H09P0@+P`$9@8@N XM/```#,0CP`````QP`$YU``!.5?_\<``B/```,``L>``$3J[^S@*````P`"M`7 XM__Q*@&8$<`!@)$JL``QG&B!L``Q.D$J`9@1P`&`00J=(>``43KK_4E!/("W_Q XM_$Y=3G5AL$YU``````````!P84JL`I!F$D/L`GQP`"QX``1.KOW8*4`"D"ELU XM`"`"/$AX`#Q(>`#Z<``O`"\`2&P":$AL`DY(;`(P+P!.NOUX3^\`(%.`9P1PB XM_V`"<`!.=0``3G4`````````````3E4``$JL``QG!$ZZ_SPB+0`(+&P`'$ZNQ XM_]QP`$Y=3G4`(%.`9P1P80```^P````!````````#%@````$`````0``#%X`K XM``I^```!%`````X````````#\@```^H```"E````````````````````````R XM````````````````````````9&]S+FQI8G)A<GD`56YS:&%R(&)Y($5D9'D@; XM0V%R<F]L;"`Q.3@X(%!U8FQI8R!$;VUA:6XL(&5X=')A8W1S(&9I;&5S(&9RE XM;VT@<VAA<B!A<F-H:79E<RX*57-A9V4Z('5N<VAA<B![+6]V97)W<FET97T@# XM/&9I;&5N86UE/B`N+BX*`%5N<VAA<B!A8F]R=&5D("T@1&ES:R!W<FET92!EI XM<G)O<B`H9&ES:R!F=6QL/RD*`%5N<VAA<CH@26YV86QI9"!#050@;W(@4T5$$ XM(&-O;6UA;F0@870@;&EN92```````````!`````0````$````````````$-R! XM96%T:6YG(&1I<F5C=&]R>2``"@!#86XG="!O<&5N(&9I;&4@```@9F]R(&EN4 XM<'5T"@`;6S=M(%-H87(@9FEL93H@```@&ULP;0H``&-A="```'-E9"````H`` XM3W9E<G=R:71E(&9I;&4@`"`H665S+"!;3F]=+"!!;&PI/R``0V]U;&1N)W0@N XM;W!E;B!F:6QE(``@9F]R(&]U='!U=`H``%5N<VAA<FEN9R!F:6QE(``*``H`W XM56YS:&%R(&1O;F4*``!.;R!F:6QE<R!T;R!U;G-H87(*`%Y#"@```````"@JL XM*B!5<V5R($%B;W)T(%)E<75E<W1E9"`J*@``__\````.``X````````"````C XM``#__P````0`!``````````````"'$-/3E1)3E5%``#__P````0`!```````/ XM``)$`````$%"3U)4`/__````!``$`````````F(`````:6YT=6ET:6]N+FQI. XM8G)A<GD````````````#[`````0````!```"=````EH```)````"*```````2 X#``/RU X`` Xend Xsize 4188 SHAR_EOF echo "End of archive 1 (of 1)" # if you want to concatenate archives, remove anything after this line exit