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

  1. /*
  2. **  SHAR
  3. **  Make a shell archive of a list of files.
  4. */
  5. #include "shar.h"
  6. #ifdef    RCSID
  7. static char RCS[] =
  8.     "$Header: shar.c,v 2.0 88/05/27 14:10:47 rsalz Exp $";
  9. #endif    /* RCSID */
  10.  
  11. /*
  12. **  Minimum allocation of file name pointers used in "-i" option processing.
  13. */
  14. #define    MIN_FILES    50
  15.  
  16.  
  17. /*
  18. **  This prolog is output before the archive.
  19. */
  20. static char     *Prolog[] = {
  21.   "! /bin/sh",
  22.   " This is a shell archive.  Remove anything before this line, then unpack",
  23.   " it by saving it into a file and typing \"sh file\".  To overwrite existing",
  24.   " files, type \"sh file -c\".  You can also feed this as standard input via",
  25.   " unshar, or by typing \"sh <file\", e.g..  If this archive is complete, you",
  26.   " will see the following message at the end:",
  27.   NULL
  28. };
  29.  
  30.  
  31. /*
  32. **  Package up one file or directory.
  33. */
  34. static void
  35. shar(file, Basename)
  36.     char        *file;
  37.     int             Basename;
  38. {
  39.     REGISTER char    *s;
  40.     REGISTER char    *Name;
  41.     REGISTER int     Bads;
  42.     REGISTER off_t     Size;
  43.     char         buf[BUFSIZ];
  44.  
  45.     /* Just in case. */
  46.     if (EQ(file, ".") || EQ(file, ".."))
  47.     return;
  48.  
  49.     Size = Fsize(file);
  50.     Name =  Basename && (Name = RDX(file, '/')) ? Name + 1 : file;
  51.  
  52.     /* Making a directory? */
  53.     if (Ftype(file) == F_DIR) {
  54.     Printf("if test ! -d '%s' ; then\n", Name);
  55.     Printf("    echo shar: Creating directory \\\"'%s'\\\"\n", Name);
  56.     Printf("    mkdir '%s'\n", Name);
  57.     Printf("fi\n");
  58.     }
  59.     else {
  60.     if (freopen(file, "r", stdin) == NULL) {
  61.         Fprintf(stderr, "Can't open %s, %s\n", file, Ermsg(errno));
  62.         exit(1);
  63.     }
  64.  
  65.     /* Emit the per-file prolog. */
  66.     Printf("if test -f '%s' -a \"${1}\" != \"-c\" ; then \n", Name);
  67.     Printf("  echo shar: Will not clobber existing file \\\"'%s'\\\"\n",
  68.            Name);
  69.     Printf("else\n");
  70.     Printf("echo shar: Extracting \\\"'%s'\\\" \\(%ld character%s\\)\n",
  71.            Name, (long)Size, Size == 1 ? "" : "s");
  72.     Printf("sed \"s/^X//\" >'%s' <<'END_OF_FILE'\n", Name, Name);
  73.  
  74.     /* Output the file contents. */
  75.     for (Bads = 0; fgets(buf, BUFSIZ, stdin); )
  76.         if (buf[0]) {
  77.         if (buf[0] == 'X' || buf[0] == 'E' || buf[0] == 'F'
  78.          || !isalpha(buf[0]))
  79.             /* Protect non-alpha's, the shar pattern character, the
  80.              * END_OF_FILE message, and mail "From" lines. */
  81.             (void)putchar('X');
  82.         for (s = buf; *s; s++) {
  83.             if (BADCHAR(*s))
  84.             Bads++;
  85.             (void)putchar(*s);
  86.         }
  87.         }
  88.  
  89.     /* Tell about and control characters. */
  90.     Printf("END_OF_FILE\n", Name);
  91.     if (Bads) {
  92.         Printf(
  93.     "echo shar: %d control character%s may be missing from \\\"'%s'\\\"\n",
  94.            Bads, Bads == 1 ? "" : "s", Name);
  95.         Fprintf(stderr, "Found %d control char%s in \"'%s'\"\n",
  96.             Bads, Bads == 1 ? "" : "s", Name);
  97.     }
  98.  
  99.     /* Output size check. */
  100.     Printf("if test %ld -ne `wc -c <'%s'`; then\n", (long)Size, Name);
  101.     Printf("    echo shar: \\\"'%s'\\\" unpacked with wrong size!\n", Name);
  102.     Printf("fi\n");
  103.  
  104.     /* Executable? */
  105.     if (Fexecute(file))
  106.         Printf("chmod +x '%s'\n", Name);
  107.  
  108.     Printf("# end of '%s'\nfi\n", Name);
  109.     }
  110. }
  111.  
  112.  
  113. /*
  114. **  Read list of files from file.
  115. */
  116. static char **
  117. GetFiles(Name)
  118.     char         *Name;
  119. {
  120.     REGISTER FILE     *F;
  121.     REGISTER int      i;
  122.     REGISTER int      count;
  123.     REGISTER char    **files;
  124.     REGISTER char    **temp;
  125.     REGISTER int      j;
  126.     char          buff[BUFSIZ];
  127.     char         *p;
  128.  
  129.     /* Open the file. */
  130.     if (EQ(Name, "-"))
  131.     F = stdin;
  132.     else if ((F = fopen(Name, "r")) == NULL) {
  133.     Fprintf(stderr, "Can't open '%s' for input.\n", Name);
  134.     return(NULL);
  135.     }
  136.  
  137.     /* Get space. */
  138.     count = MIN_FILES;
  139.     files = NEW(char*, count);
  140.  
  141.     /* Read lines. */
  142.     for (i = 0; fgets(buff, sizeof buff, F); ) {
  143.     if (p = IDX(buff, '\n'))
  144.         *p = '\0';
  145.     files[i] = COPY(buff);
  146.     if (++i == count - 2) {
  147.         /* Get more space; some systems don't have realloc()... */
  148.         for (count += MIN_FILES, temp = NEW(char*, count), j = 0; j < i; j++)
  149.         temp[j] = files[j];
  150.         files = temp;
  151.     }
  152.     }
  153.  
  154.     /* Clean up, close up, return. */
  155.     files[i] = NULL;
  156.     (void)fclose(F);
  157.     return(files);
  158. }
  159.  
  160.  
  161.  
  162. main(ac, av)
  163.     int             ac;
  164.     REGISTER char    *av[];
  165. {
  166.     REGISTER char    *Trailer;
  167.     REGISTER char    *p;
  168.     REGISTER char    *q;
  169.     REGISTER int     i;
  170.     REGISTER int     length;
  171.     REGISTER int     Oops;
  172.     REGISTER int     Knum;
  173.     REGISTER int     Kmax;
  174.     REGISTER int     Basename;
  175.     REGISTER int     j;
  176.     time_t         clock;
  177.     char        **Flist;
  178.  
  179.     /* Parse JCL. */
  180.     Basename = 0;
  181.     Knum = 0;
  182.     Kmax = 0;
  183.     Trailer = NULL;
  184.     for (Oops = 0; (i = getopt(ac, av, "be:i:n:o:t:")) != EOF; )
  185.     switch (i) {
  186.     default:
  187.         Oops++;
  188.         break;
  189.     case 'b':
  190.         Basename++;
  191.         break;
  192.     case 'e':
  193.         Kmax = atoi(optarg);
  194.         break;
  195.     case 'i':
  196.         Flist = GetFiles(optarg);
  197.         break;
  198.     case 'n':
  199.         Knum = atoi(optarg);
  200.         break;
  201.     case 'o':
  202.         if (freopen(optarg, "w", stdout) == NULL) {
  203.         Fprintf(stderr, "Can't open %s for output, %s.\n",
  204.             optarg, Ermsg(errno));
  205.         Oops++;
  206.         }
  207.         break;
  208.     case 't':
  209.         Trailer = optarg;
  210.         break;
  211.     }
  212.  
  213.     /* Rest of arguments are files. */
  214.     if  (Flist == NULL) {
  215.     av += optind;
  216.     if (*av == NULL) {
  217.         Fprintf(stderr, "No input files\n");
  218.         Oops++;
  219.     }
  220.     Flist = av;
  221.     }
  222.  
  223.     if (Oops) {
  224.     Fprintf(stderr,
  225.         "USAGE: shar [-b] [-o:] [-i:] [-n:e:t:] file... >SHAR\n");
  226.     exit(1);
  227.     }
  228.  
  229.     /* Everything readable and reasonably-named? */
  230.     for (Oops = 0, i = 0; p = Flist[i]; i++)
  231.     if (freopen(p, "r", stdin) == NULL) {
  232.         Fprintf(stderr, "Can't read %s, %s.\n", p, Ermsg(errno));
  233.         Oops++;
  234.     }
  235.     else
  236.         for (; *p; p++)
  237.         if (!isascii(*p)) {
  238.             Fprintf(stderr, "Bad character '%c' in '%s'.\n",
  239.                 *p, Flist[i]);
  240.             Oops++;
  241.         }
  242.     if (Oops)
  243.     exit(2);
  244.  
  245.     /* Prolog. */
  246.     for (i = 0; p = Prolog[i]; i++)
  247.     Printf("#%s\n", p);
  248.     if (Knum && Kmax)
  249.     Printf("#\t\t\"End of archive %d (of %d).\"\n", Knum, Kmax);
  250.     else
  251.         Printf("#\t\t\"End of shell archive.\"\n");
  252.     Printf("# Contents: ");
  253.     for (length = 12, i = 0; p = Flist[i++]; length += j) {
  254.     if (Basename && (q = RDX(p, '/')))
  255.         p = q + 1;
  256.     j = strlen(p) + 1;
  257.     if (length + j < WIDTH)
  258.         Printf(" %s", p);
  259.     else {
  260.         Printf("\n#   %s", p);
  261.         length = 4;
  262.     }
  263.     }
  264.     Printf("\n");
  265.     clock = time((time_t *)NULL);
  266.     Printf("# Wrapped by %s@%s on %s", User(), Host(), ctime(&clock));
  267.     Printf("PATH=/bin:/usr/bin:/usr/ucb ; export PATH\n");
  268.  
  269.     /* Do it. */
  270.     while (*Flist)
  271.     shar(*Flist++, Basename);
  272.  
  273.     /* Epilog. */
  274.     if (Knum && Kmax) {
  275.     Printf("echo shar: End of archive %d \\(of %d\\).\n", Knum, Kmax);
  276.     Printf("cp /dev/null ark%disdone\n", Knum);
  277.     Printf("MISSING=\"\"\n");
  278.     Printf("for I in");
  279.     for (i = 0; i < Kmax; i++)
  280.         Printf(" %d", i + 1);
  281.     Printf(" ; do\n");
  282.     Printf("    if test ! -f ark${I}isdone ; then\n");
  283.     Printf("\tMISSING=\"${MISSING} ${I}\"\n");
  284.     Printf("    fi\n");
  285.     Printf("done\n");
  286.     Printf("if test \"${MISSING}\" = \"\" ; then\n");
  287.     if (Kmax == 1)
  288.         Printf("    echo You have the archive.\n");
  289.     else if (Kmax == 2)
  290.         Printf("    echo You have unpacked both archives.\n");
  291.     else
  292.         Printf("    echo You have unpacked all %d archives.\n", Kmax);
  293.     if (Trailer && *Trailer)
  294.         Printf("    echo \"%s\"\n", Trailer);
  295.     Printf("    rm -f ark[1-9]isdone%s\n",
  296.            Kmax >= 9 ? " ark[1-9][0-9]isdone" : "");
  297.     Printf("else\n");
  298.     Printf("    echo You still need to unpack the following archives:\n");
  299.     Printf("    echo \"        \" ${MISSING}\n");
  300.     Printf("fi\n");
  301.     Printf("##  End of shell archive.\n");
  302.     }
  303.     else {
  304.         Printf("echo shar: End of shell archive.\n");
  305.     if (Trailer && *Trailer)
  306.         Printf("echo \"%s\"\n", Trailer);
  307.     }
  308.  
  309.     Printf("exit 0\n");
  310.  
  311.     exit(0);
  312. }
  313.