home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / cshar / part02 / unshar.c < prev   
Encoding:
C/C++ Source or Header  |  1988-05-26  |  8.2 KB  |  368 lines

  1. /*
  2. **  UNSHAR
  3. **  Unpack shell archives that might have gone through mail, notes, news, etc.
  4. **  This is Michael Mauldin's code which I have usurped and heavily modified.
  5. */
  6. #include "shar.h"
  7. #ifdef    RCSID
  8. static char RCS[] =
  9.     "$Header: unshar.c,v 2.0 88/05/27 13:28:13 rsalz Exp $";
  10. #endif    /* RCSID */
  11.  
  12.  
  13. /*
  14. **  Print error message and die.
  15. */
  16. static void
  17. Quit(text)
  18.     char    *text;
  19. {
  20.     int         e;
  21.  
  22.     e = errno;
  23.     Fprintf(stderr, "unshar:  %s", text);
  24.     if (e)
  25.     Fprintf(stderr, ", %s", Ermsg(e));
  26.     Fprintf(stderr, ".\n");
  27.     exit(1);
  28. }
  29.  
  30.  
  31. /*
  32. **  Does this look like a mail header line?
  33. */
  34. static int
  35. IsHeader(p)
  36.     REGISTER char    *p;
  37. {
  38.     REGISTER int     i;
  39.  
  40.     if (*p == '\0' || *p == '\n')
  41.     return(FALSE);
  42.     if (WHITE(*p))
  43.     return(TRUE);
  44.     for (i = 0; *p == '-' || *p == '_' || *p == '.' || isalnum(*p); i++)
  45.     p++;
  46.     return(i && *p == ':');
  47. }
  48.  
  49.  
  50. /*
  51. **  Is this a /bin/sh comment line?  We check that because some shars
  52. **  output comments before the CUT line.
  53. */
  54. static int
  55. IsSHcomment(p)
  56.     REGISTER char    *p;
  57. {
  58.     while (isalpha(*p) || WHITE(*p) || *p == '\n' || *p == ',' || *p == '.')
  59.     p++;
  60.     return(*p == '\0');
  61. }
  62.  
  63.  
  64. /*
  65. **  Return TRUE if p has wd1 and wd2 as words (i.e., no preceeding or
  66. **  following letters).  Clever code, Michael.
  67. */
  68. static int
  69. Has(p, wd1, wd2)
  70.     REGISTER char    *p;
  71.     REGISTER char    *wd1;
  72.     REGISTER char    *wd2;
  73. {
  74.     REGISTER char    *wd;
  75.     REGISTER int     first;
  76.  
  77.     wd = wd1;
  78.     first = TRUE;
  79. again: 
  80.     while (*p) {
  81.     if (!isalpha(*p)) {
  82.         p++;
  83.         continue;
  84.     }
  85.     while (*p++ == *wd++) {
  86.         if (*wd == '\0') {
  87.         if (!isalpha(*p)) {
  88.             if (!first)
  89.             return(TRUE);
  90.             first = FALSE;
  91.             wd = wd2;
  92.             goto again;
  93.         }
  94.         break;
  95.         }
  96.     }
  97.     while (isalpha(*p))
  98.         p++;
  99.     wd = first ? wd1 : wd2;
  100.     }
  101.     return(FALSE);
  102. }
  103.  
  104.  
  105. /*
  106. **  Here's where the work gets done.  Skip headers and try to intuit
  107. **  if the file is, e.g., C code, etc.
  108. */
  109. static int
  110. Found(Name, buff, Forced, Stream, Header)
  111.     REGISTER char    *Name;
  112.     REGISTER char    *buff;
  113.     REGISTER int     Forced;
  114.     REGISTER FILE    *Stream;
  115.     REGISTER FILE    *Header;
  116. {
  117.     REGISTER char    *p;
  118.     REGISTER int     InHeader;
  119.     char         lower[BUFSIZ];
  120.  
  121.     if (Header)
  122.     InHeader = TRUE;
  123.  
  124.     while (TRUE) {
  125.     /* Read next line, fail if no more */
  126.     if (fgets(buff, BUFSIZ, Stream) == NULL) {
  127.         Fprintf(stderr, "unshar:  No shell commands in %s.\n", Name);
  128.         return(FALSE);
  129.     }
  130.  
  131.     /* See if it looks like another language. */
  132.     if (!Forced) {
  133.         if (PREFIX(buff, "#include") || PREFIX(buff, "# include")
  134.          || PREFIX(buff, "#define") || PREFIX(buff, "# define")
  135.          || PREFIX(buff, "#ifdef") || PREFIX(buff, "# ifdef")
  136.          || PREFIX(buff, "#ifndef") || PREFIX(buff, "# ifndef")
  137.          || (PREFIX(buff, "/*")
  138.           && !PREFIX(buff, NOTES1) && !PREFIX(buff, NOTES2)))
  139.         p = "C code";
  140.         else if (PREFIX(buff, "(*"))        /* For vi :-) */
  141.         p = "PASCAL code";
  142.         else if (buff[0] == '.' && isalpha(buff[1]) && isalpha(buff[2])
  143.           && !isalpha(buff[3]))
  144.         p = "TROFF source";
  145.         else
  146.         p = NULL;
  147.         if (p) {
  148.         Fprintf(stderr,
  149.             "unshar:  %s is apparently %s, not a shell archive.\n",
  150.             Name, p);
  151.         return(FALSE);
  152.         }
  153.     }
  154.  
  155.     /* Does this line start with a shell command or comment? */
  156.     if ((buff[0] == '#' && !IsSHcomment(buff + 1))
  157.      || buff[0] == ':' || PREFIX(buff, "echo ")
  158.      || PREFIX(buff, "sed ") || PREFIX(buff, "cat ")) {
  159.         return(TRUE);
  160.     }
  161.  
  162.     /* Does this line say "Cut here"? */
  163.     for (p = strcpy(lower, buff); *p; p++)
  164.         if (isascii(*p) && islower(*p))
  165.         *p = toupper(*p);
  166.     if (PREFIX(buff, "-----") || Has(lower, "cut", "here")
  167.      || Has(lower, "cut", "cut") || Has(lower, "tear", "here")) {
  168.         /* Get next non-blank line. */
  169.         do {
  170.         if (fgets(buff, BUFSIZ, Stream) == NULL) {
  171.             Fprintf(stderr, "unshar:  cut line is last line of %s\n",
  172.                 Name);
  173.             return(FALSE);
  174.         }
  175.         } while (*buff == '\n');
  176.  
  177.         /* If it starts with a comment or lower-case letter we win. */
  178.         if (*buff == '#' || *buff == ':' || islower(*buff))
  179.         return(TRUE);
  180.  
  181.         /* The cut message lied. */
  182.         Fprintf(stderr, "unshar: %s is not a shell archive,\n", Name);
  183.         Fprintf(stderr, "        the 'cut' line was followed by: %s", buff);
  184.         return(FALSE);
  185.     }
  186.  
  187.     if (Header) {
  188.         (void)fputs(buff, Header);
  189.         if (InHeader && !IsHeader(buff))
  190.         InHeader = FALSE;
  191.     }
  192.     }
  193. }
  194.  
  195.  
  196. /*
  197. **  Create file for the header, find true start of the archive,
  198. **  and send it off to the shell.
  199. */
  200. static void
  201. Unshar(Name, HdrFile, Stream, Saveit, Forced)
  202.     char        *Name;
  203.     char        *HdrFile;
  204.     REGISTER FILE     *Stream;
  205.     int             Saveit;
  206.     int             Forced;
  207. {
  208.     REGISTER FILE    *Header;
  209. #ifndef    USE_MY_SHELL
  210.     REGISTER FILE    *Pipe;
  211. #endif    /* USE_MY_SHELL */
  212.     char        *p;
  213.     char         buff[BUFSIZ];
  214.  
  215.     if (Saveit) {
  216.     /* Create a name for the saved header. */
  217.     if (HdrFile)
  218.         (void)strcpy(buff, HdrFile);
  219.     else if (Name) {
  220.         p = RDX(Name, '/');
  221.         (void)strncpy(buff, p ? p + 1 : Name, 14);
  222.         buff[10] = 0;
  223.         (void)strcat(buff, ".hdr");
  224.     }
  225.     else
  226.         (void)strcpy(buff, "UNSHAR.HDR");
  227.  
  228.     /* Tell user, and open the file. */
  229.     Fprintf(stderr, "unshar:  Sending header to %s.\n", buff);
  230.     if ((Header = fopen(buff, "a")) == NULL)
  231.         Quit("Can't open file for header");
  232.     }
  233.     else
  234.     Header = NULL;
  235.  
  236.     /* If name is NULL, we're being piped into... */
  237.     p = Name ? Name : "the standard input";
  238.     Printf("unshar:  Doing %s:\n", p);
  239.  
  240.     if (Found(p, buff, Forced, Stream, Header)) {
  241. #ifdef    USE_MY_SHELL
  242.     BinSh(Name, Stream, buff);
  243. #else
  244.     if ((Pipe = popen("/bin/sh", "w")) == NULL)
  245.         Quit("Can't open pipe to /bin/sh process");
  246.  
  247.     (void)fputs(buff, Pipe);
  248.     while (fgets(buff, sizeof buff, Stream))
  249.         (void)fputs(buff, Pipe);
  250.  
  251.     (void)pclose(Pipe);
  252. #endif    /* USE_MY_SHELL */
  253.     }
  254.  
  255.     /* Close the headers. */
  256.     if (Saveit)
  257.     (void)fclose(Header);
  258. }
  259.  
  260.  
  261. main(ac, av)
  262.     REGISTER int     ac;
  263.     REGISTER char    *av[];
  264. {
  265.     REGISTER FILE    *Stream;
  266.     REGISTER int     i;
  267.     char        *p;
  268.     char        *HdrFile;
  269.     char         cwd[BUFSIZ];
  270.     char         dir[BUFSIZ];
  271.     char         buff[BUFSIZ];
  272.     int             Saveit;
  273.     int             Forced;
  274.  
  275.     /* Parse JCL. */
  276.     p = getenv("UNSHARDIR");
  277.     Saveit = DEF_SAVEIT;
  278.     HdrFile = NULL;
  279.     for (Forced = 0; (i = getopt(ac, av, "c:d:fh:ns")) != EOF; )
  280.     switch (i) {
  281.     default:
  282.         Quit("Usage: unshar [-fs] [-c dir] [-h hdrfile] [input files]");
  283.         /* NOTREACHED */
  284.     case 'c': 
  285.     case 'd': 
  286.         p = optarg;
  287.         break;
  288.     case 'f':
  289.         Forced++;
  290.         break;
  291.     case 'h':
  292.         HdrFile = optarg;
  293.         /* FALLTHROUGH */
  294.     case 's': 
  295.         Saveit = TRUE;
  296.         break;
  297.     case 'n':
  298.         Saveit = FALSE;
  299.         break;
  300.     }
  301.     av += optind;
  302.  
  303.     /* Going somewhere? */
  304.     if (p) {
  305.     if (*p == '?') {
  306.         /* Ask for name; go to THE_TTY if we're being piped into. */
  307.         Stream = isatty(fileno(stdin)) ? stdin : fopen(THE_TTY, "r");
  308.         if (Stream == NULL)
  309.         Quit("Can't open tty to ask for directory");
  310.         Printf("unshar:  what directory?  ");
  311.         (void)fflush(stdout);
  312.         if (fgets(buff, sizeof buff, Stream) == NULL
  313.          || buff[0] == '\n'
  314.          || (p = IDX(buff, '\n')) == NULL)
  315.         Quit("Okay, cancelled");
  316.         *p = '\0';
  317.         p = buff;
  318.         if (Stream != stdin)
  319.         (void)fclose(Stream);
  320.     }
  321.  
  322.     /* If name is ~/blah, he means $HOME/blah. */
  323.     if (*p == '~') {
  324.         if (getenv("HOME") == NULL)
  325.         Quit("You have no $HOME?");
  326.         (void)sprintf(dir, "%s/%s", getenv("HOME"), p + 1);
  327.         p = dir;
  328.     }
  329.  
  330.     /* If we're gonna move, first remember where we were. */
  331.     if (Cwd(cwd, sizeof cwd) == NULL) {
  332.         Fprintf(stderr, "unshar warning:  Can't get current directory.\n");
  333.         cwd[0] = '\0';
  334.     }
  335.  
  336.     /* Got directory; try to go there.  Only make last component. */
  337.     if (chdir(p) < 0 && mkdir(p, 0777) < 0 && chdir(p) < 0)
  338.         Quit("Cannot chdir nor mkdir desired directory");
  339.     }
  340.     else
  341.     cwd[0] = '\0';
  342.  
  343.     /* No buffering. */
  344.     (void)setbuf(stdout, (char *)NULL);
  345.     (void)setbuf(stderr, (char *)NULL);
  346.  
  347.     if (*av)
  348.     /* Process filenames from command line. */
  349.     for (; *av; av++) {
  350.         if (cwd[0] && av[0][0] != '/') {
  351.         (void)sprintf(buff, "%s/%s", cwd, *av);
  352.         *av = buff;
  353.         }
  354.         if ((Stream = fopen(*av, "r")) == NULL)
  355.         Fprintf(stderr, "unshar:  Can't open file '%s'.\n", *av);
  356.         else {
  357.         Unshar(*av, HdrFile, Stream, Saveit, Forced);
  358.         (void)fclose(Stream);
  359.         }
  360.     }
  361.     else
  362.     /* Do standard input. */
  363.     Unshar((char *)NULL, HdrFile, stdin, Saveit, Forced);
  364.  
  365.     /* That's all she wrote. */
  366.     exit(0);
  367. }
  368.