home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / shar-3.49 / unshar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  11.3 KB  |  449 lines

  1. char *revision = "3.49";
  2. char RCS_ID[] = "$Header: /u/rhg/src/shar/unshar.c,v 3.49 90/09/12 15:15:17 rhg Exp $";
  3. /****************************************************************
  4.  * unshar.c: Unpackage one or more shell archive files
  5.  *
  6.  * Usage:     unshar [ -c ] [ -e | -E exit_line ] [ -d directory ] [ file ... ]
  7.  *
  8.  * Description:    unshar is a filter which removes the front part
  9.  *        of  a file and passes the rest to the 'sh' command.
  10.  *        It understands phrases like "cut here", and also
  11.  *        knows about shell comment characters and the Unix
  12.  *        commands "echo", "cat", and "sed".
  13.  *
  14.  *        The -c flag is passed through to the shell as a parameter to the script
  15.  *
  16.  *        It can unshar shar files concatenated in one file, with the
  17.  *        the "-e" command, which separates files by recognizing the
  18.  *        "exit 0" string at the beginning of a line
  19.  *
  20.  *        (The -E string option allows you to specify this string, thus
  21.  *        -e is equivalent to -E "exit 0")
  22.  *
  23.  *        The -d flag tells unshar to change directory before unsharing
  24.  *
  25.  * HISTORY
  26.  * 12-Sep-90  Richard H. Gumpertz (rhg@cps.com)
  27.  *        use fprintf instead of printf when printing error return from getwd.
  28.  *        deleted unused initialization of more_to_read in process.
  29.  *        changed ch from char to int in process so the EOF check would work.
  30.  *  4-Aug-90  Richard H. Gumpertz (rhg@cps.com)
  31.  *        renamed -c and -C to -e and -E and added -c flag (passed through to sh)
  32.  * 19-Apr-90  Colas Nahaboo (colas@mirsa.inria.fr)
  33.  *        added -c and -C flags to read from concatenated archives
  34.  *  1-Feb-85  Guido van Rossum (guido@mcvax) at CWI, Amsterdam
  35.  *        Added missing 'quit' routine;
  36.  *        added -d flag to change to directory first;
  37.  *        added filter mode (read stdin when no arguments);
  38.  *        added 'getopt' to get flags (makes it self-contained).
  39.  * 29-Jan-85  Michael Mauldin (mlm) at Carnegie-Mellon University
  40.  *        Created.
  41.  ****************************************************************/
  42. /*+:EDITS:*/
  43. /*:08-04-1990-15:54-rhg@cps.com-changes listed above (-c/-C => -e/-E, new -c) */
  44. /*:05-05-1990-01:37-relay.EU.net!rivm!a3-dont assume vax is running BSD */
  45. /*:04-19-1990-15:20-wht@n4hgf-fix so -d doesnt make argv files unreachable */
  46. /*:04-19-1990-15:06-wht@n4hgf-colas@mirsa patches had expanded tabs */
  47. /*:04-10-1990-22:02-wht@n4hgf-stdin failed sometimes-can not seek on pipe */
  48.  
  49. #include <stdio.h>
  50. #define EOL '\n'
  51.  
  52. #if (defined(pyr) || defined(sun) || defined(BSD42) || \
  53.  defined(vax) || defined(sequent)) && !defined(SYS5)
  54. #define strchr    index
  55. #undef USE_GETCWD
  56. char *getwd();
  57. #else
  58. #define USE_GETCWD
  59. char *getcwd();
  60. #endif
  61.  
  62. char *strchr();
  63.  
  64. extern char *optarg;
  65. extern int optind;
  66.  
  67. int c_flag = 0;
  68. int continue_reading = 0;
  69. char *exit_string = "exit 0";
  70. int exit_string_length;
  71. char argvdir[1024];
  72.  
  73. main(argc,argv)
  74. int argc;
  75. char *argv[];
  76. {
  77.     int i,ch;
  78.     FILE *in;
  79.     char s1024[1024];
  80.  
  81.     setbuf(stdout,NULL);
  82.     setbuf(stderr,NULL);
  83.  
  84. #ifdef USE_GETCWD
  85.     if(!getcwd(argvdir,sizeof(argvdir)))
  86.     {
  87.         perror("cannot get current directory name");
  88.         exit(1);
  89.     }
  90. #else
  91.     argvdir[0] = 0;
  92.     if(!getwd(argvdir))
  93.     {
  94.         if(argvdir[0])
  95.             fprintf(stderr,"%s\n",argvdir);
  96.         else
  97.             fprintf(stderr,"cannot get current directory name\n");
  98.         exit(1);
  99.     }
  100. #endif
  101.  
  102.  
  103.     /* Process options */
  104.  
  105.     while((ch = getopt(argc,argv,"cd:eE:")) != EOF)
  106.     {
  107.         switch(ch)
  108.         {
  109.         case 'c':
  110.             c_flag = 1;
  111.             break;
  112.         case 'd':
  113.             if(chdir(optarg) == -1)
  114.             {
  115.                 fprintf(stderr,"unshar: cannot chdir to '%s'\n",optarg);
  116.                 exit(2);
  117.             }
  118.             break;
  119.         case 'E':
  120.             exit_string = optarg;
  121.         case 'e':
  122.             continue_reading = 1;
  123.             exit_string_length = strlen(exit_string);
  124.             break;
  125.         default:
  126.             quit(2,"Usage: unshar [-c] [-e | -E exit_line] [-d directory] [file ...]\n");
  127.         }
  128.     }
  129.  
  130.     if(optind < argc)
  131.     {
  132.         for(i= optind; i < argc; ++i)
  133.         {
  134.             if(argv[i][0] == '/') {
  135.                 strcpy(s1024,argv[i]);
  136.             } else {
  137.                 strcpy(s1024,argvdir);
  138.                 strcat(s1024,"/");
  139.                 strcat(s1024,argv[i]);
  140.             }
  141.             if(!(in = fopen(s1024,"r")))
  142.             {
  143.                 perror(s1024);
  144.                 exit(1);
  145.             }
  146.             process(s1024,in);
  147.             fclose(in);
  148.         }
  149.     }
  150.     else
  151.     {
  152.         sprintf(s1024,"/tmp/unsh.%05d",getpid());
  153.         unlink(s1024);
  154.         if(!(in = fopen(s1024,"w+")))
  155.         {
  156.             fprintf(stderr,"cannot open temp file '%s'\n",s1024);
  157.             exit(1);
  158.         }
  159.         unlink(s1024);    /* don't try this with MSDOS, sports fans */
  160.         while(i = fread(s1024,1,sizeof(s1024),stdin))
  161.             fwrite(s1024,i,1,in);
  162.         rewind(in);
  163.         process("standard input",in);
  164.         fclose(in);
  165.     }
  166.  
  167.     exit(0);
  168. }
  169.  
  170.  
  171. process(name,in)
  172. char *name;
  173. FILE *in;
  174. {
  175.     char buffer[8196];
  176.     int ch;
  177.     FILE *shpr,*popen();
  178.     long current_position = 0;
  179.     char *more_to_read;
  180.  
  181.     while(position(name,in,current_position))
  182.     {
  183.         printf("%s:\n",name);
  184.         if(!(shpr = popen((c_flag ? "sh -s -c" : "sh"),"w")))
  185.             quit(1,"unshar: cannot open 'sh' process\n");
  186.  
  187.         if (!continue_reading) {
  188.             while((ch = fgetc(in)) != EOF)
  189.                 fputc(ch,shpr);
  190.             pclose(shpr);
  191.             break;
  192.         } else {
  193.             while (more_to_read = fgets(buffer, 8196, in)) {
  194.                 fputs(buffer, shpr);
  195.                 if (!strncmp(exit_string, buffer, exit_string_length)) {
  196.                     break;
  197.                 }
  198.             }
  199.             pclose(shpr);
  200.             if (more_to_read)
  201.                 current_position = ftell(in);
  202.             else {
  203.                 break;
  204.             }
  205.         }
  206.     }
  207. }
  208.  
  209. /****************************************************************
  210.  * position: position 'fil' at the start of the shell command
  211.  * portion of a shell archive file.
  212.  ****************************************************************/
  213.  
  214. position(fn,fil,start)
  215. char *fn;
  216. FILE *fil;
  217. long start;                   /* scan file from position */
  218. {
  219.     char buf[BUFSIZ];
  220.     long pos,ftell();
  221.  
  222.     /* Results from star matcher */
  223.     static char res1[BUFSIZ],res2[BUFSIZ],res3[BUFSIZ],res4[BUFSIZ];
  224.     static char *result[] = 
  225.     {
  226.         res1,res2,res3,res4         };
  227.  
  228.     fseek(fil, start, 0);
  229.  
  230.     while(1)
  231.     { /* Record position of the start of this line */
  232.         pos = ftell(fil);
  233.  
  234.         /* Read next line, fail if no more and no previous process */
  235.         if(!fgets(buf,BUFSIZ,fil))
  236.         {
  237.             if(!start)
  238.                 fprintf(stderr,"unshar: found no shell commands in %s\n",fn);
  239.             return(0);
  240.         }
  241.  
  242.         /* Bail out if we see C preprocessor commands or C comments */
  243.         if(stlmatch(buf,"#include")    || stlmatch(buf,"# include") ||
  244.             stlmatch(buf,"#define")    || stlmatch(buf,"# define") ||
  245.             stlmatch(buf,"#ifdef")    || stlmatch(buf,"# ifdef") ||
  246.             stlmatch(buf,"#ifndef")    || stlmatch(buf,"# ifndef") ||
  247.             stlmatch(buf,"/*"))
  248.         {
  249.             fprintf(stderr,
  250.                 "unshar: %s looks like raw C code, not a shell archive\n",fn);
  251.             return(0);
  252.         }
  253.  
  254.         /* Does this line start with a shell command or comment */
  255.         if(stlmatch(buf,"#")    || stlmatch(buf,":") ||
  256.             stlmatch(buf,"echo ")    || stlmatch(buf,"sed ") ||
  257.             stlmatch(buf,"cat ") || stlmatch(buf,"if "))
  258.         {
  259.             fseek(fil,pos,0);
  260.             return(1);
  261.         }
  262.  
  263.         /* Does this line say "Cut here" */
  264.         if(smatch(buf,"*CUT*HERE*",result) ||
  265.             smatch(buf,"*cut*here*",result) ||
  266.             smatch(buf,"*TEAR*HERE*",result) ||
  267.             smatch(buf,"*tear*here*",result) ||
  268.             smatch(buf,"*CUT*CUT*",result) ||
  269.             smatch(buf,"*cut*cut*",result))
  270.         {
  271.             /* Read next line after "cut here", skipping blank lines */
  272.             while(1)
  273.             {
  274.                 pos = ftell(fil);
  275.  
  276.                 if(!fgets(buf,BUFSIZ,fil))
  277.                 {
  278.                     fprintf(stderr,
  279.                         "unshar: found no shell commands after 'cut' in %s\n",fn);
  280.                     return(0);
  281.                 }
  282.  
  283.                 if(*buf != '\n') break;
  284.             }
  285.  
  286.             /* Win if line starts with a comment character of lower case letter */
  287.             if(*buf == '#' || *buf == ':' || (('a' <= *buf) && ('z' >= *buf)))
  288.             {
  289.                 fseek(fil,pos,0);
  290.                 return(1);
  291.             }
  292.  
  293.             /* Cut here message lied to us */
  294.             fprintf(stderr,"unshar: %s is probably not a shell archive,\n",fn);
  295.             fprintf(stderr,"        the 'cut' line was followed by: %s",buf);
  296.             return(0);
  297.         }
  298.     }
  299. }
  300.  
  301. /*****************************************************************
  302.  * stlmatch  --  match leftmost part of string
  303.  *
  304.  * Usage:  i = stlmatch (big,small)
  305.  *    int i;
  306.  *    char *small, *big;
  307.  *
  308.  * Returns 1 iff initial characters of big match small exactly;
  309.  * else 0.
  310.  *
  311.  * HISTORY
  312.  * 18-May-82 Michael Mauldin (mlm) at Carnegie-Mellon University
  313.  *      Ripped out of CMU lib for Rog-O-Matic portability
  314.  * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
  315.  *    Rewritten for VAX from Ken Greer's routine.
  316.  *
  317.  *  Originally from klg (Ken Greer) on IUS/SUS UNIX
  318.  *****************************************************************/
  319.  
  320. int stlmatch(big,small)
  321. char *small,*big;
  322. {
  323.     register char *s,*b;
  324.     s = small;
  325.     b = big;
  326.     do
  327.     {
  328.         if(*s == '\0')
  329.             return(1);
  330.     }  while(*s++ == *b++);
  331.     return(0);
  332. }
  333.  
  334. /*****************************************************************
  335.  * smatch: Given a data string and a pattern containing one or
  336.  * more embedded stars (*) (which match any number of characters)
  337.  * return true if the match succeeds, and set res[i] to the
  338.  * characters matched by the 'i'th *.
  339.  *****************************************************************/
  340.  
  341. smatch(dat,pat,res)
  342. register char *dat,*pat,**res;
  343. {
  344.     register char *star = 0,*starend,*resp;
  345.     int nres = 0;
  346.  
  347.     while(1)
  348.     {
  349.         if(*pat == '*')
  350.         {
  351.             star = ++pat;                  /* Pattern after * */
  352.             starend = dat;                  /* Data after * match */
  353.             resp = res[nres++];              /* Result string */
  354.             *resp = '\0';                  /* Initially null */
  355.         }
  356.         else if(*dat == *pat)              /* Characters match */
  357.         {
  358.             if(*pat == '\0')              /* Pattern matches */
  359.                 return(1);
  360.             pat++;                      /* Try next position */
  361.             dat++;
  362.         }
  363.         else
  364.         {
  365.             if(*dat == '\0')              /* Pattern fails - no more */
  366.                 return(0);                  /* data */
  367.             if(star == 0)                  /* Pattern fails - no * to */
  368.                 return(0);                  /* adjust */
  369.             pat = star;                  /* Restart pattern after * */
  370.             *resp++ = *starend;              /* Copy character to result */
  371.             *resp = '\0';                  /* null terminate */
  372.             dat = ++starend;                  /* Rescan after copied char */
  373.         }
  374.     }
  375. }
  376.  
  377. /*****************************************************************
  378.  * Addendum: quit subroutine (print a message and exit)
  379.  *****************************************************************/
  380.  
  381. quit(status,message)
  382. int status;
  383. char *message;
  384. {
  385.     fprintf(stderr,message);
  386.     exit(status);
  387. }
  388.  
  389. /*****************************************************************
  390.  * Public Domain getopt routine
  391.  *****************************************************************/
  392.  
  393. /*
  394.  * get option letter from argument vector
  395.  */
  396. int opterr = 1;        /* useless, never set or used */
  397. int optind = 1;        /* index into parent argv vector */
  398. int optopt;            /* character checked for validity */
  399. char *optarg;        /* argument associated with option */
  400.  
  401. #define BADCH    (int)'?'
  402. #define EMSG    ""
  403. #define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  404.         fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  405.  
  406. getopt(nargc,nargv,ostr)
  407. int nargc;
  408. char **nargv,*ostr;
  409. {
  410.     static char *place = EMSG;    /* option letter processing */
  411.     register char *oli;        /* option letter list index */
  412.     char *strchr();
  413.  
  414.     if(!*place)
  415.     {            /* update scanning pointer */
  416.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
  417.             return(EOF);
  418.         if(*place == '-')
  419.         {    /* found "--" */
  420.             ++optind;
  421.             return(EOF);
  422.         }
  423.     }                /* option letter okay? */
  424.     if((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt)))
  425.     {
  426.         if(!*place) ++optind;
  427.         tell(": illegal option -- ");
  428.     }
  429.     if(*++oli != ':')
  430.     {        /* don't need argument */
  431.         optarg = (char *)0;
  432.         if(!*place) ++optind;
  433.     }
  434.     else 
  435.     {                /* need an argument */
  436.         if(*place) optarg = place;    /* no white space */
  437.         else if(nargc <= ++optind)
  438.         {    /* no arg */
  439.             place = EMSG;
  440.             tell(": option requires an argument -- ");
  441.         }
  442.         else optarg = nargv[optind];    /* white space */
  443.         place = EMSG;
  444.         ++optind;
  445.     }
  446.     return(optopt);            /* dump back option letter */
  447. }
  448. /* vi: set tabstop=4 shiftwidth=4: */
  449.