home *** CD-ROM | disk | FTP | other *** search
- char *revision = "3.49";
- char RCS_ID[] = "$Header: /u/rhg/src/shar/unshar.c,v 3.49 90/09/12 15:15:17 rhg Exp $";
- /****************************************************************
- * unshar.c: Unpackage one or more shell archive files
- *
- * Usage: unshar [ -c ] [ -e | -E exit_line ] [ -d directory ] [ file ... ]
- *
- * Description: unshar is a filter which removes the front part
- * of a file and passes the rest to the 'sh' command.
- * It understands phrases like "cut here", and also
- * knows about shell comment characters and the Unix
- * commands "echo", "cat", and "sed".
- *
- * The -c flag is passed through to the shell as a parameter to the script
- *
- * It can unshar shar files concatenated in one file, with the
- * the "-e" command, which separates files by recognizing the
- * "exit 0" string at the beginning of a line
- *
- * (The -E string option allows you to specify this string, thus
- * -e is equivalent to -E "exit 0")
- *
- * The -d flag tells unshar to change directory before unsharing
- *
- * HISTORY
- * 12-Sep-90 Richard H. Gumpertz (rhg@cps.com)
- * use fprintf instead of printf when printing error return from getwd.
- * deleted unused initialization of more_to_read in process.
- * changed ch from char to int in process so the EOF check would work.
- * 4-Aug-90 Richard H. Gumpertz (rhg@cps.com)
- * renamed -c and -C to -e and -E and added -c flag (passed through to sh)
- * 19-Apr-90 Colas Nahaboo (colas@mirsa.inria.fr)
- * added -c and -C flags to read from concatenated archives
- * 1-Feb-85 Guido van Rossum (guido@mcvax) at CWI, Amsterdam
- * Added missing 'quit' routine;
- * added -d flag to change to directory first;
- * added filter mode (read stdin when no arguments);
- * added 'getopt' to get flags (makes it self-contained).
- * 29-Jan-85 Michael Mauldin (mlm) at Carnegie-Mellon University
- * Created.
- ****************************************************************/
- /*+:EDITS:*/
- /*:08-04-1990-15:54-rhg@cps.com-changes listed above (-c/-C => -e/-E, new -c) */
- /*:05-05-1990-01:37-relay.EU.net!rivm!a3-dont assume vax is running BSD */
- /*:04-19-1990-15:20-wht@n4hgf-fix so -d doesnt make argv files unreachable */
- /*:04-19-1990-15:06-wht@n4hgf-colas@mirsa patches had expanded tabs */
- /*:04-10-1990-22:02-wht@n4hgf-stdin failed sometimes-can not seek on pipe */
-
- /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
- This port is distributed under the terms of the
- GNU General Public License as published by the
- Free Software Foundation. */
-
- #include <stdio.h>
- #define EOL '\n'
-
- #ifdef MSDOS
-
- #define VOID void
-
- #include <stdlib.h>
- #include <string.h>
- #include <direct.h>
- #include <errno.h>
- #include <process.h>
- #include <io.h>
-
- #ifdef USE_GNU_GETOPT
- #include <getopt.h>
- #endif
-
- #include <gnulib.h>
- char *program_name;
-
- /* We make this program selfcontained by providing our own pipes.
- This also avoids the neccessity of invoking a subshell (which
- may turn out to be a command.com .... */
-
- #define pipe_file (_pipe_file (0))
- extern char *_pipe_file (int n);
- extern int filter_through_command (char *infile, char *outfile,
- char *command, ...);
-
- extern void main (int argc, char **argv);
- static void process (char *name, FILE * in);
- static int position (char *fn, FILE * fil, long start);
- static int stlmatch (char *big, char *small);
- static int smatch (char *dat, char *pat, char **res);
- static void quit (int status, char *message);
-
- #define USE_GETCWD
- #define getcwd(buf, len) msdos_format_filename (getcwd (buf, len))
-
- #else /* not MSDOS */
-
- #define VOID
-
- char *strchr();
- #if (defined(pyr) || defined(sun) || defined(BSD42) || \
- defined(vax) || defined(sequent)) && !defined(SYS5)
- #define strchr index
- #undef USE_GETCWD
- char *getwd();
- #else
- #define USE_GETCWD
- char *getcwd();
- #endif
-
- #endif /* not MSDOS */
-
- extern char *optarg;
- extern int optind;
-
- int c_flag = 0;
- int continue_reading = 0;
- char *exit_string = "exit 0";
- int exit_string_length;
- char argvdir[1024];
-
- VOID
- main(argc,argv)
- int argc;
- char *argv[];
- {
- int i,ch;
- FILE *in;
- char s1024[1024];
-
- #ifdef MSDOS
- program_name = argv[0];
- #endif
-
- setbuf(stdout,NULL);
- setbuf(stderr,NULL);
-
- #ifdef USE_GETCWD
- if(!getcwd(argvdir,sizeof(argvdir)))
- {
- perror("cannot get current directory name");
- exit(1);
- }
- #else
- argvdir[0] = 0;
- if(!getwd(argvdir))
- {
- if(argvdir[0])
- fprintf(stderr,"%s\n",argvdir);
- else
- fprintf(stderr,"cannot get current directory name\n");
- exit(1);
- }
- #endif
-
-
- /* Process options */
-
- while((ch = getopt(argc,argv,"cd:eE:")) != EOF)
- {
- switch(ch)
- {
- case 'c':
- c_flag = 1;
- break;
- case 'd':
- if(chdir(optarg) == -1)
- {
- fprintf(stderr,"unshar: cannot chdir to '%s'\n",optarg);
- exit(2);
- }
- break;
- case 'E':
- exit_string = optarg;
- case 'e':
- continue_reading = 1;
- exit_string_length = strlen(exit_string);
- break;
- default:
- quit(2,"Usage: unshar [-c] [-e | -E exit_line] [-d directory] [file ...]\n");
- }
- }
-
- if(optind < argc)
- {
- for(i= optind; i < argc; ++i)
- {
- if(argv[i][0] == '/') {
- strcpy(s1024,argv[i]);
- } else {
- strcpy(s1024,argvdir);
- strcat(s1024,"/");
- strcat(s1024,argv[i]);
- }
- if(!(in = fopen(s1024,"r")))
- {
- perror(s1024);
- exit(1);
- }
- process(s1024,in);
- fclose(in);
- }
- }
- else
- {
- sprintf(s1024,"/tmp/unsh.%05d",getpid());
- unlink(s1024);
- if(!(in = fopen(s1024,"w+")))
- {
- fprintf(stderr,"cannot open temp file '%s'\n",s1024);
- exit(1);
- }
- unlink(s1024); /* don't try this with MSDOS, sports fans */
- while(i = fread(s1024,1,sizeof(s1024),stdin))
- fwrite(s1024,i,1,in);
- rewind(in);
- process("standard input",in);
- fclose(in);
- }
-
- exit(0);
- }
-
-
- VOID
- process(name,in)
- char *name;
- FILE *in;
- {
- char buffer[8196];
- int ch;
- FILE *shpr,*popen();
- long current_position = 0;
- char *more_to_read;
-
- while(position(name,in,current_position))
- {
- printf("%s:\n",name);
- #ifdef MSDOS
- if ((shpr = fopen (pipe_file, "w")) == NULL)
- error (1, 0, "pipe error: %s", pipe_file);
- #else
- if(!(shpr = popen((c_flag ? "sh -s -c" : "sh"),"w")))
- quit(1,"unshar: cannot open 'sh' process\n");
- #endif
- if (!continue_reading) {
- while((ch = fgetc(in)) != EOF)
- fputc(ch,shpr);
-
- #ifdef MSDOS
- fclose (shpr);
- if (filter_through_command (pipe_file, NULL, "sh",
- c_flag ? "-s" : NULL,
- "-c", NULL))
- error (1, 0, "sh failed");
- #else
- pclose(shpr);
- #endif
- break;
- } else {
- while (more_to_read = fgets(buffer, 8196, in)) {
- fputs(buffer, shpr);
- if (!strncmp(exit_string, buffer, exit_string_length)) {
- break;
- }
- }
- #ifdef MSDOS
- fclose (shpr);
- if (filter_through_command (pipe_file, NULL, "sh",
- c_flag ? "-s" : NULL,
- "-c", NULL))
- error (1, 0, "sh failed");
- #else
- pclose(shpr);
- #endif
- if (more_to_read)
- current_position = ftell(in);
- else {
- break;
- }
- }
- }
- }
-
- /****************************************************************
- * position: position 'fil' at the start of the shell command
- * portion of a shell archive file.
- ****************************************************************/
-
- position(fn,fil,start)
- char *fn;
- FILE *fil;
- long start; /* scan file from position */
- {
- char buf[BUFSIZ];
- long pos,ftell();
-
- /* Results from star matcher */
- static char res1[BUFSIZ],res2[BUFSIZ],res3[BUFSIZ],res4[BUFSIZ];
- static char *result[] =
- {
- res1,res2,res3,res4 };
-
- fseek(fil, start, 0);
-
- while(1)
- { /* Record position of the start of this line */
- pos = ftell(fil);
-
- /* Read next line, fail if no more and no previous process */
- if(!fgets(buf,BUFSIZ,fil))
- {
- if(!start)
- fprintf(stderr,"unshar: found no shell commands in %s\n",fn);
- return(0);
- }
-
- /* Bail out if we see C preprocessor commands or C comments */
- if(stlmatch(buf,"#include") || stlmatch(buf,"# include") ||
- stlmatch(buf,"#define") || stlmatch(buf,"# define") ||
- stlmatch(buf,"#ifdef") || stlmatch(buf,"# ifdef") ||
- stlmatch(buf,"#ifndef") || stlmatch(buf,"# ifndef") ||
- stlmatch(buf,"/*"))
- {
- fprintf(stderr,
- "unshar: %s looks like raw C code, not a shell archive\n",fn);
- return(0);
- }
-
- /* Does this line start with a shell command or comment */
- if(stlmatch(buf,"#") || stlmatch(buf,":") ||
- stlmatch(buf,"echo ") || stlmatch(buf,"sed ") ||
- stlmatch(buf,"cat ") || stlmatch(buf,"if "))
- {
- fseek(fil,pos,0);
- return(1);
- }
-
- /* Does this line say "Cut here" */
- if(smatch(buf,"*CUT*HERE*",result) ||
- smatch(buf,"*cut*here*",result) ||
- smatch(buf,"*TEAR*HERE*",result) ||
- smatch(buf,"*tear*here*",result) ||
- smatch(buf,"*CUT*CUT*",result) ||
- smatch(buf,"*cut*cut*",result))
- {
- /* Read next line after "cut here", skipping blank lines */
- while(1)
- {
- pos = ftell(fil);
-
- if(!fgets(buf,BUFSIZ,fil))
- {
- fprintf(stderr,
- "unshar: found no shell commands after 'cut' in %s\n",fn);
- return(0);
- }
-
- if(*buf != '\n') break;
- }
-
- /* Win if line starts with a comment character of lower case letter */
- if(*buf == '#' || *buf == ':' || (('a' <= *buf) && ('z' >= *buf)))
- {
- fseek(fil,pos,0);
- return(1);
- }
-
- /* Cut here message lied to us */
- fprintf(stderr,"unshar: %s is probably not a shell archive,\n",fn);
- fprintf(stderr," the 'cut' line was followed by: %s",buf);
- return(0);
- }
- }
- }
-
- /*****************************************************************
- * stlmatch -- match leftmost part of string
- *
- * Usage: i = stlmatch (big,small)
- * int i;
- * char *small, *big;
- *
- * Returns 1 iff initial characters of big match small exactly;
- * else 0.
- *
- * HISTORY
- * 18-May-82 Michael Mauldin (mlm) at Carnegie-Mellon University
- * Ripped out of CMU lib for Rog-O-Matic portability
- * 20-Nov-79 Steven Shafer (sas) at Carnegie-Mellon University
- * Rewritten for VAX from Ken Greer's routine.
- *
- * Originally from klg (Ken Greer) on IUS/SUS UNIX
- *****************************************************************/
-
- int stlmatch(big,small)
- char *small,*big;
- {
- register char *s,*b;
- s = small;
- b = big;
- do
- {
- if(*s == '\0')
- return(1);
- } while(*s++ == *b++);
- return(0);
- }
-
- /*****************************************************************
- * smatch: Given a data string and a pattern containing one or
- * more embedded stars (*) (which match any number of characters)
- * return true if the match succeeds, and set res[i] to the
- * characters matched by the 'i'th *.
- *****************************************************************/
-
- smatch(dat,pat,res)
- register char *dat,*pat,**res;
- {
- register char *star = 0,*starend,*resp;
- int nres = 0;
-
- while(1)
- {
- if(*pat == '*')
- {
- star = ++pat; /* Pattern after * */
- starend = dat; /* Data after * match */
- resp = res[nres++]; /* Result string */
- *resp = '\0'; /* Initially null */
- }
- else if(*dat == *pat) /* Characters match */
- {
- if(*pat == '\0') /* Pattern matches */
- return(1);
- pat++; /* Try next position */
- dat++;
- }
- else
- {
- if(*dat == '\0') /* Pattern fails - no more */
- return(0); /* data */
- if(star == 0) /* Pattern fails - no * to */
- return(0); /* adjust */
- pat = star; /* Restart pattern after * */
- *resp++ = *starend; /* Copy character to result */
- *resp = '\0'; /* null terminate */
- dat = ++starend; /* Rescan after copied char */
- }
- }
- }
-
- /*****************************************************************
- * Addendum: quit subroutine (print a message and exit)
- *****************************************************************/
-
- VOID
- quit(status,message)
- int status;
- char *message;
- {
- fprintf(stderr,message);
- exit(status);
- }
-
- #ifndef USE_GNU_GETOPT
- /*****************************************************************
- * Public Domain getopt routine
- *****************************************************************/
-
- /*
- * get option letter from argument vector
- */
- int opterr = 1; /* useless, never set or used */
- int optind = 1; /* index into parent argv vector */
- int optopt; /* character checked for validity */
- char *optarg; /* argument associated with option */
-
- #define BADCH (int)'?'
- #define EMSG ""
- #define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
- fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
-
- getopt(nargc,nargv,ostr)
- int nargc;
- char **nargv,*ostr;
- {
- static char *place = EMSG; /* option letter processing */
- register char *oli; /* option letter list index */
- char *strchr();
-
- if(!*place)
- { /* update scanning pointer */
- if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
- return(EOF);
- if(*place == '-')
- { /* found "--" */
- ++optind;
- return(EOF);
- }
- } /* option letter okay? */
- if((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt)))
- {
- if(!*place) ++optind;
- tell(": illegal option -- ");
- }
- if(*++oli != ':')
- { /* don't need argument */
- optarg = (char *)0;
- if(!*place) ++optind;
- }
- else
- { /* need an argument */
- if(*place) optarg = place; /* no white space */
- else if(nargc <= ++optind)
- { /* no arg */
- place = EMSG;
- tell(": option requires an argument -- ");
- }
- else optarg = nargv[optind]; /* white space */
- place = EMSG;
- ++optind;
- }
- return(optopt); /* dump back option letter */
- }
- /* vi: set tabstop=4 shiftwidth=4: */
- #endif /* USE_GNU_GETOPT */
-