home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
shar349.zip
/
src
/
unshar.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-22
|
14KB
|
526 lines
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 */