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

  1. /*
  2. **  MAKEKIT
  3. **  Split up source files into reasonably-sized shar lists.
  4. */
  5. #include "shar.h"
  6. #ifdef    RCSID
  7. static char RCS[] =
  8.     "$Header: makekit.c,v 2.0 88/05/27 13:27:31 rsalz Exp $";
  9. #endif    /* RCSID */
  10.  
  11.  
  12. /*
  13. **  Our block of information about the files we're doing.
  14. */
  15. typedef struct _block {
  16.     char    *Name;            /* Filename            */
  17.     char    *Text;            /* What it is            */
  18.     int         Where;            /* Where it is            */
  19.     int         Type;            /* Directory or file?        */
  20.     long     Bsize;            /* Size in bytes        */
  21. } BLOCK;
  22.  
  23.  
  24. /*
  25. **  Our block of information about the archives we're making.
  26. */
  27. typedef struct _archive {
  28.     int         Count;            /* Number of files        */
  29.     long     Asize;            /* Bytes used by archive    */
  30. } ARCHIVE;
  31.  
  32.  
  33. /*
  34. **  Format strings; these are strict K&R so you shouldn't have to change them.
  35. */
  36. #define FORMAT1        " %-25s %2d\t%s\n"
  37. #define FORMAT2        "%s%2.2d"
  38. #ifdef    FMT02d
  39. #undef FORMAT2
  40. #define FORMAT2        "%s%02.2d"    /* I spoke too soon...        */
  41. #endif    /* FMT02d */
  42.  
  43.  
  44. /*
  45. **  Global variables.
  46. */
  47. char    *InName;            /* File with list to pack    */
  48. char    *OutName;            /* Where our output goes    */
  49. char    *SharName = "Part";        /* Prefix for name of each shar    */
  50. char    *Trailer;            /* Text for shar to pack in    */
  51. char    *TEMP;                /* Temporary manifest file    */
  52. #ifdef    MSDOS
  53. char    *FLST;                /* File with list for shar    */
  54. #endif    MSDOS
  55. int     ArkCount = 20;            /* Max number of archives    */
  56. int     ExcludeIt;            /* Leave out the output file?    */
  57. int     Header;            /* Lines of prolog in input    */
  58. int     Preserve;            /* Preserve order for Manifest?    */
  59. int     Working = TRUE;        /* Call shar when done?        */
  60. long     Size = 55000;            /* Largest legal archive size    */
  61.  
  62.  
  63. /*
  64. **  Sorting predicate to put README or MANIFEST first, then directories,
  65. **  then larger files, then smaller files, which is how we want to pack
  66. **  stuff in archives.
  67. */
  68. static int
  69. SizeP(t1, t2)
  70.     BLOCK    *t1;
  71.     BLOCK    *t2;
  72. {
  73.     long     i;
  74.  
  75.     if (t1->Type == F_DIR)
  76.     return(t2->Type == F_DIR ? 0 : -1);
  77.     if (t2->Type == F_DIR)
  78.     return(1);
  79.     if (EQn(t1->Name, "README", 6) || (OutName && EQ(t1->Name, OutName)))
  80.     return(-1);
  81.     if (EQn(t2->Name, "README", 6) || (OutName && EQ(t2->Name, OutName)))
  82.     return(1);
  83.     return((i = t1->Bsize - t2->Bsize) == 0L ? 0 : (i < 0L ? -1 : 1));
  84. }
  85.  
  86.  
  87. /*
  88. **  Sorting predicate to get things in alphabetical order, which is how
  89. **  we write the Manifest file.
  90. */
  91. static int
  92. NameP(t1, t2)
  93.     BLOCK    *t1;
  94.     BLOCK    *t2;
  95. {
  96.     int         i;
  97.  
  98.     return((i = *t1->Name - *t2->Name) ? i : strcmp(t1->Name, t2->Name));
  99. }
  100.  
  101.  
  102. /*
  103. **  Skip whitespace.
  104. */
  105. static char *
  106. Skip(p)
  107.     REGISTER char    *p;
  108. {
  109.     while (*p && WHITE(*p))
  110.     p++;
  111.     return(p);
  112. }
  113.  
  114.  
  115. /*
  116. **  Signal handler.  Clean up and die.
  117. */
  118. static sigret_t
  119. Catch(s)
  120.     int         s;
  121. {
  122.     int         e;
  123.  
  124.     e = errno;
  125.     if (TEMP)
  126.     (void)unlink(TEMP);
  127. #ifdef    MSDOS
  128.     if (FLST)
  129.     (void)unlink(FLST);
  130. #endif    /* MSDOS */
  131.     Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
  132.     exit(1);
  133. }
  134.  
  135.  
  136. main(ac, av)
  137.     REGISTER int     ac;
  138.     char        *av[];
  139. {
  140.     REGISTER FILE    *F;
  141.     REGISTER FILE    *In;
  142.     REGISTER BLOCK    *t;
  143.     REGISTER ARCHIVE    *k;
  144.     REGISTER char    *p;
  145.     REGISTER int     i;
  146.     REGISTER int     lines;
  147.     REGISTER int     Value;
  148.     BLOCK        *Table;
  149.     BLOCK        *TabEnd;
  150.     ARCHIVE        *Ark;
  151.     ARCHIVE        *ArkEnd;
  152.     char         buff[BUFSIZ];
  153.     long         lsize;
  154.     int             LastOne;
  155.     int             Start;
  156.     int             Notkits;
  157.     char         EndArkNum[20];
  158.     char         CurArkNum[20];
  159.  
  160.     /* Collect input. */
  161.     Value = FALSE;
  162.     Notkits = FALSE;
  163.     while ((i = getopt(ac, av, "1eh:i:k:n:mo:p:s:t:x")) != EOF)
  164.     switch (i) {
  165.     default:
  166.         Fprintf(stderr,
  167. "usage: makekit -e -s# [-m | -iMANIFEST -oMANIFEST -h2] -nName -tText files..."
  168.             );
  169.         exit(1);
  170.     case '1':
  171.         Notkits = TRUE;
  172.         break;
  173.     case 'e':
  174.         ExcludeIt = TRUE;
  175.         break;
  176.     case 'h':
  177.         Header = atoi(optarg);
  178.         break;
  179.     case 'i':
  180.         InName = optarg;
  181.         break;
  182.     case 'k':
  183.         ArkCount = atoi(optarg);
  184.         break;
  185.     case 'm':
  186.         InName = OutName = "MANIFEST";
  187.         Header = 2;
  188.         break;
  189.     case 'n':
  190.         SharName = optarg;
  191.         break;
  192.     case 'o':
  193.         OutName = optarg;
  194.         break;
  195.     case 'p':
  196.         Preserve = TRUE;
  197.         break;
  198.     case 's':
  199.         Size = atoi(optarg);
  200.         if (IDX(optarg, 'k') || IDX(optarg, 'K'))
  201.         Size *= 1024;
  202.         break;
  203.     case 't':
  204.         Trailer = optarg;
  205.         break;
  206.     case 'x':
  207.         Working = FALSE;
  208.         break;
  209.     }
  210.     ac -= optind;
  211.     av += optind;
  212.  
  213.     /* Write the file list to a temp file. */
  214.     TEMP = mktemp("/tmp/maniXXXXXX");
  215.     F = fopen(TEMP, "w");
  216.     SetSigs(TRUE, Catch);
  217.     if (av[0])
  218.     /* Got the arguments on the command line. */
  219.     while (*av)
  220.         Fprintf(F, "%s\n", *av++);
  221.     else {
  222.     /* Got the name of the file from the command line. */
  223.     if (InName == NULL)
  224.         In = stdin;
  225.     else if ((In = fopen(InName, "r")) == NULL) {
  226.         Fprintf(stderr, "Can't read %s as manifest, %s.\n",
  227.             InName, Ermsg(errno));
  228.         exit(1);
  229.     }
  230.     /* Skip any possible prolog, then output rest of file. */
  231.     while (--Header >= 0 && fgets(buff, sizeof buff, In))
  232.         ;
  233.     if (feof(In)) {
  234.         Fprintf(stderr, "Nothing but header lines in list!?\n");
  235.         exit(1);
  236.     }
  237.     while (fgets(buff, sizeof buff, In))
  238.         fputs(buff, F);
  239.     if (In != stdin)
  240.         (void)fclose(In);
  241.     }
  242.     (void)fclose(F);
  243.  
  244.     /* Count number of files, allow for NULL and our output file. */
  245.     F = fopen(TEMP, "r");
  246.     for (lines = 2; fgets(buff, sizeof buff, F); lines++)
  247.     ;
  248.     rewind(F);
  249.  
  250.     /* Read lines and parse lines, see if we found our OutFile. */
  251.     Table = NEW(BLOCK, lines);
  252.     for (t = Table, Value = FALSE, lines = 0; fgets(buff, sizeof buff, F); ) {
  253.     /* Read line, skip first word, check for blank line. */
  254.     if (p = IDX(buff, '\n'))
  255.         *p = '\0';
  256.     else
  257.         Fprintf(stderr, "Warning, line truncated:\n%s\n", buff);
  258.     p = Skip(buff);
  259.     if (*p == '\0')
  260.         continue;
  261.  
  262.     /* Copy the line, snip off the first word. */
  263.     for (p = t->Name = COPY(p); *p && !WHITE(*p); p++)
  264.         ;
  265.     if (*p)
  266.         *p++ = '\0';
  267.  
  268.     /* Skip <spaces><digits><spaces>; remainder is the file description. */
  269.     for (p = Skip(p); *p && isdigit(*p); )
  270.         p++;
  271.     t->Text = Skip(p);
  272.  
  273.     /* Get file type. */
  274.     if (!GetStat(t->Name)) {
  275.         Fprintf(stderr, "Can't stat %s (%s), skipping.\n",
  276.             t->Name, Ermsg(errno));
  277.         continue;
  278.     }
  279.     t->Type = Ftype(t->Name);
  280.  
  281.     /* Guesstimate its size when archived:  prolog, plus one char/line. */
  282.     t->Bsize = strlen(t->Name) * 3 + 200;
  283.     if (t->Type == F_FILE) {
  284.         lsize = Fsize(t->Name);
  285.         t->Bsize += lsize + lsize / 60;
  286.     }
  287.     if (t->Bsize > Size) {
  288.         Fprintf(stderr, "At %ld bytes, %s is too big for any archive!\n",
  289.             t->Bsize, t->Name);
  290.         exit(1);
  291.     }
  292.  
  293.     /* Is our ouput file there? */
  294.     if (!Value && OutName && EQ(OutName, t->Name))
  295.         Value = TRUE;
  296.  
  297.     /* All done -- advance to next entry. */
  298.     t++;
  299.     }
  300.     (void)fclose(F);
  301.     (void)unlink(TEMP);
  302.     SetSigs(S_RESET, (sigret_t (*)())NULL);
  303.  
  304.     /* Add our output file? */
  305.     if (!ExcludeIt && !Value && OutName) {
  306.     t->Name = OutName;
  307.     t->Text = "This shipping list";
  308.     t->Type = F_FILE;
  309.     t->Bsize = lines * 60;
  310.     t++;
  311.     }
  312.  
  313.     /* Sort by size, get archive space. */
  314.     lines = t - Table;
  315.     TabEnd = &Table[lines];
  316.     if (!Preserve)
  317.     qsort((char *)Table, lines, sizeof Table[0], SizeP);
  318.     Ark = NEW(ARCHIVE, ArkCount);
  319.     ArkEnd = &Ark[ArkCount];
  320.  
  321.     /* Loop through the pieces, and put everyone into an archive. */
  322.     for (t = Table; t < TabEnd; t++) {
  323.     for (k = Ark; k < ArkEnd; k++)
  324.         if (t->Bsize + k->Asize < Size) {
  325.         k->Asize += t->Bsize;
  326.         t->Where = k - Ark;
  327.         k->Count++;
  328.         break;
  329.         }
  330.     if (k == ArkEnd) {
  331.         Fprintf(stderr, "'%s' doesn't fit -- need more then %d archives.\n",
  332.             t->Name, ArkCount);
  333.         exit(1);
  334.     }
  335.     /* Since our share doesn't build sub-directories... */
  336.     if (t->Type == F_DIR && k != Ark)
  337.         Fprintf(stderr, "Warning:  directory '%s' is in archive %d\n",
  338.             t->Name, k - Ark + 1);
  339.     }
  340.  
  341.     /* Open the output file. */
  342.     if (OutName == NULL)
  343.     F = stdout;
  344.     else {
  345.     if (GetStat(OutName)) {
  346.         /* Handle /foo/bar/VeryLongFileName.BAK for non-BSD sites. */
  347.         (void)sprintf(buff, "%s.BAK", OutName);
  348.         p = (p = RDX(buff, '/')) ? p + 1 : buff;
  349.         if (strlen(p) > 14)
  350.         /* ... well, sort of handle it. */
  351.         (void)strcpy(&p[10], ".BAK");
  352.         Fprintf(stderr, "Renaming %s to %s\n", OutName, buff);
  353.         (void)unlink(buff);
  354.         (void)link(OutName, buff);
  355.         (void)unlink(OutName);
  356.     }
  357.     if ((F = fopen(OutName, "w")) == NULL) {
  358.         Fprintf(stderr, "Can't open '%s' for output, %s.\n",
  359.             OutName, Ermsg(errno));
  360.         exit(1);
  361.     }
  362.     }
  363.  
  364.     /* Sort the shipping list, then write it. */
  365.     if (!Preserve)
  366.     qsort((char *)Table, lines, sizeof Table[0], NameP);
  367.     Fprintf(F, "   File Name\t\tArchive #\tDescription\n");
  368.     Fprintf(F, "-----------------------------------------------------------\n");
  369.     for (t = Table; t < TabEnd; t++)
  370.     Fprintf(F, FORMAT1, t->Name, t->Where + 1, t->Text);
  371.  
  372.     /* Close output.  Are we done? */
  373.     if (F != stdout)
  374.     (void)fclose(F);
  375.     if (!Working)
  376.     exit(0);
  377.  
  378.     /* Find last archive number. */
  379.     for (i = 0, t = Table; t < TabEnd; t++)
  380.     if (i < t->Where)
  381.         i = t->Where;
  382.     LastOne = i + 1;
  383.  
  384.     /* Find archive with most files in it. */
  385.     for (i = 0, k = Ark; k < ArkEnd; k++)
  386.     if (i < k->Count)
  387.         i = k->Count;
  388.  
  389.     /* Build the fixed part of the argument vector. */
  390.     av = NEW(char*, i + 10);
  391.     av[0] = "shar";
  392.     i = 1;
  393.     if (Trailer) {
  394.     av[i++] = "-t";
  395.     av[i++] = Trailer;
  396.     }
  397.     if (Notkits == FALSE) {
  398.     (void)sprintf(EndArkNum, "%d", LastOne);
  399.     av[i++] = "-e";
  400.     av[i++] = EndArkNum;
  401.     av[i++] = "-n";
  402.     av[i++] = CurArkNum;
  403.     }
  404. #ifdef    MSDOS
  405.     av[i++] = "-i";
  406.     av[i++] = FLST = mktemp("/tmp/manlXXXXXX");
  407. #endif    /* MSDOS */
  408.  
  409.     av[i++] = "-o";
  410.     av[i++] = buff;
  411.  
  412.     /* Call shar to package up each archive. */
  413.     for (Start = i, i = 0; i < LastOne; i++) {
  414.     (void)sprintf(CurArkNum, "%d", i + 1);
  415.     (void)sprintf(buff, FORMAT2, SharName, i + 1);
  416. #ifndef    MSDOS
  417.     for (lines = Start, t = Table; t < TabEnd; t++)
  418.         if (t->Where == i)
  419.         av[lines++] = t->Name;
  420.     av[lines] = NULL;
  421. #else
  422.     if ((F = fopen(FLST, "w")) == NULL) {
  423.         Fprintf(stderr, "Can't open list file '%s' for output, %s.\n",
  424.             FLST, Ermsg(errno));
  425.         exit(1);
  426.     }
  427.     for (t = Table; t < TabEnd; t++)
  428.         if (t->Where == i)
  429.         Fprintf(F, "%s\n", t->Name);
  430.     (void)fclose(F);
  431. #endif /* MSDOS */
  432.     Fprintf(stderr, "Packing kit %d...\n", i + 1);
  433.     if (lines = Execute(av))
  434.         Fprintf(stderr, "Warning:  shar returned status %d.\n", lines);
  435.     }
  436.  
  437. #ifdef    MSDOS
  438.     (void)unlink(FLST);
  439. #endif    /* MSDOS */
  440.     /* That's all she wrote. */
  441.     exit(0);
  442. }
  443.