|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 9987 (0x2703) Types: TextFile Names: »makekit.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/shar/makekit.c«
/* ** MAKEKIT ** Split up source files into reasonably-sized shar lists. ** ** Options: ** -e Leave our output file out ** -h # Number of header lines in input file ** -i name Input file name ** -k # Maximum number of archives desired ** -m Same as "-i Manifest -o Manifest -s2" ** -n name Name for resultant archives ** -o name Output file name ** -p Preserve original input order ** -s #[k] Maximum size of each archvie ** -t text Set final instructions after all are unpacked ** -x Don't actually do the shar'ing */ #include "shar.h" RCS("$Header: makekit.c,v 1.15 87/03/13 12:56:41 rs Exp $") /* ** Our block of information about the files we're doing. */ typedef struct { char *Name; /* Filename */ char *Text; /* What it is */ int Where; /* Where it is */ int Type; /* Directory or file? */ long Size; /* Size in bytes */ } BLOCK; /* ** Our block of information about the archives we're making. */ typedef struct { int Count; /* Number of files */ long Size; /* Bytes used by archive */ } ARCHIVE; /* ** We re-use parts of one buffer to hold three different strings in our ** argument vector to exec(). */ #define SEG0 0 /* Ending archive number */ #define SEG1 10 /* Current archive number */ #define SEG2 20 /* Output name (rest of buff) */ /* ** Format strings; these are strict K&R so you shouldn't have to change them. */ #define FORMAT1 " %-25s%2d\t%s\n" #define FORMAT2 "%s%2.2d" /* ** Global variables. */ char *InName; /* File with list to pack */ char *OutName; /* Where our output goes */ char *SharName = "Part"; /* Prefix for name of each shar */ char *Trailer; /* Text for shar to pack in */ char TEMP[] = "/tmp/arkXXXXXX"; /* Temporary manifest file */ int ArchCount = 20; /* Max number of archives */ int ExcludeIt; /* Leave out the output file? */ int Header; /* Lines of prolog in input */ int Preserve; /* Preserve order for Manifest? */ int Working = TRUE; /* Call shar when done? */ long Size = 55000; /* Largest legal archive size */ /* ** Sorting predicate to put README first, then directories, then large ** files, then smaller files, which is how we want to assign things to ** the archives. */ static int SizeP(t1, t2) BLOCK *t1; BLOCK *t2; { long i; if (EQ(t1->Name, "README") || EQ(t1->Name, "readme")) return(-1); if (EQ(t2->Name, "README") || EQ(t1->Name, "readme")) return(1); if (t1->Type != t2->Type) return(t1->Type == F_DIR ? 1 : -1); return((i = t1->Size - t2->Size) == 0L ? 0 : (i < 0L ? -1 : 1)); } /* ** Sorting predicate to get things in alphabetical order, which is how ** we write the Manifest file. */ static int NameP(t1, t2) BLOCK *t1; BLOCK *t2; { int i; return((i = *t1->Name - *t2->Name) ? i : strcmp(t1->Name, t2->Name)); } /* ** Skip whitespace. */ static char * Skip(p) register char *p; { while (*p && WHITE(*p)) p++; return(p); } /* ** Signal handler. Clean up and die. */ static Catch(s) int s; { int e; e = errno; (void)unlink(TEMP); fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e)); exit(1); } main(ac, av) register int ac; char *av[]; { register FILE *F; register FILE *In; register BLOCK *t; register ARCHIVE *k; register char *p; register int i; register int lines; register int Value; BLOCK *Table; BLOCK *TabEnd; ARCHIVE *Ark; ARCHIVE *ArkEnd; char buff[BUFSIZ]; int LastOne; int Start; /* Collect input. */ Value = FALSE; while ((i = getopt(ac, av, "eh:i:k:n:mop:s:t:x")) != EOF) switch (i) { default: exit(1); case 'e': ExcludeIt = TRUE; break; case 'h': Header = atoi(optarg); break; case 'i': InName = optarg; break; case 'k': ArchCount = atoi(optarg); break; case 'm': InName = OutName = "MANIFEST"; Header = 2; break; case 'n': SharName = optarg; break; case 'o': OutName = optarg; break; case 'p': Preserve = TRUE; break; case 's': Size = atoi(optarg); if (IDX(optarg, 'k') || IDX(optarg, 'K')) Size *= 1024; break; case 't': Trailer = optarg; break; case 'x': Working = FALSE; break; } ac -= optind; av += optind; /* Write the file list to a temp file. */ F = fopen(mktemp(TEMP), "w"); SetSigs(TRUE, Catch); if (av[0]) /* Got the arguments on the command line. */ while (*av) fprintf(F, "%s\n", *av++); else { /* Got the name of the file from the command line. */ if (InName == NULL) In = stdin; else if ((In = fopen(InName, "r")) == NULL) { fprintf(stderr, "Can't read %s as manifest, %s.\n", InName, Ermsg(errno)); exit(1); } /* Skip any possible prolog, then output rest of file. */ while (--Header >= 0 && fgets(buff, sizeof buff, In)) ; if (feof(In)) { fprintf(stderr, "Nothing but header lines in list!?\n"); exit(1); } while (fgets(buff, sizeof buff, In)) fputs(buff, F); if (In != stdin) (void)fclose(In); } (void)fclose(F); /* Count number of files, allow for NULL and our output file. */ F = fopen(TEMP, "r"); for (lines = 2; fgets(buff, sizeof buff, F); lines++) ; rewind(F); /* Read lines and parse lines, see if we found our OutFile. */ Table = NEW(BLOCK, lines); for (t = Table, Value = FALSE, lines = 0; fgets(buff, sizeof buff, F); ) { /* Read line, skip first word, check for blank line. */ if (p = IDX(buff, '\n')) *p = '\0'; else fprintf(stderr, "Warning, line truncated:\n%s\n", buff); p = Skip(buff); if (*p == '\0') continue; /* Copy the line, snip off the first word. */ for (p = t->Name = COPY(p); *p && !WHITE(*p); p++) ; if (*p) *p++ = '\0'; /* Skip <spaces><digits><spaces>; remainder is the file description. */ for (p = Skip(p); *p && isdigit(*p); ) p++; t->Text = Skip(p); /* Get file type. */ if (!GetStat(t->Name)) { fprintf(stderr, "Can't stat %s (%s), skipping.\n", t->Name, Ermsg(errno)); continue; } t->Type = Ftype(t->Name); /* Guesstimate it's size when archived. */ t->Size = strlen(t->Name) * 3 + 200; if (t->Type == F_FILE) { i = Fsize(t->Name); t->Size += i + i / 60; } if (t->Size > Size) { fprintf(stderr, "At %ld bytes, %s is too big for any archive!\n", t->Size, t->Name); exit(1); } /* Is our ouput file there? */ if (!Value && OutName && EQ(OutName, t->Name)) Value = TRUE; /* All done -- advance to next entry. */ t++; } (void)fclose(F); (void)unlink(TEMP); SetSigs(S_RESET, (int (*)())NULL); /* Add our output file? */ if (!ExcludeIt && !Value && OutName) { t->Name = OutName; t->Text = "This shipping list"; t->Type = F_FILE; t->Size = lines * 60; t++; } /* Sort by size, get archive space. */ lines = t - Table; TabEnd = &Table[lines]; if (!Preserve) qsort((char *)Table, lines, sizeof Table[0], SizeP); Ark = NEW(ARCHIVE, ArchCount); ArkEnd = &Ark[ArchCount]; /* Loop through the pieces, and put everyone into an archive. */ for (t = Table; t < TabEnd; t++) { for (k = Ark; k < ArkEnd; k++) if (t->Size + k->Size < Size) { k->Size += t->Size; t->Where = k - Ark; k->Count++; break; } if (k == ArkEnd) { fprintf(stderr, "'%s' doesn't fit -- need more then %d archives.\n", t->Name, ArchCount); exit(1); } /* Since our share doesn't build sub-directories... */ if (t->Type == F_DIR && k != Ark) fprintf(stderr, "Warning: directory '%s' is in archive %d\n", t->Name, k - Ark + 1); } /* Open the output file. */ if (OutName == NULL) F = stdout; else { if (GetStat(OutName)) { /* Handle /foo/bar/VeryLongFileName.BAK for non-BSD sites. */ (void)sprintf(buff, "%s.BAK", OutName); p = (p = RDX(buff, '/')) ? p + 1 : buff; if (strlen(p) > 14) /* ... well, sort of handle it. */ (void)strcpy(&p[10], ".BAK"); fprintf(stderr, "Renaming %s to %s\n", OutName, buff); (void)unlink(buff); (void)link(OutName, buff); (void)unlink(OutName); } if ((F = fopen(OutName, "w")) == NULL) { fprintf(stderr, "Can't open '%s' for output, %s.\n", OutName, Ermsg(errno)); exit(1); } } /* Sort the shipping list, then write it. */ if (!Preserve) qsort((char *)Table, lines, sizeof Table[0], NameP); fprintf(F, " File Name\t\tArchive #\tDescription\n"); fprintf(F, "-----------------------------------------------------------\n"); for (t = Table; t < TabEnd; t++) fprintf(F, FORMAT1, t->Name, t->Where + 1, t->Text); /* Close output. Are we done? */ if (F != stdout) (void)fclose(F); if (!Working) exit(0); /* Find last archive number. */ for (i = 0, t = Table; t < TabEnd; t++) if (i < t->Where) i = t->Where; LastOne = i + 1; /* Find archive with most files in it. */ for (i = 0, k = Ark; k < ArkEnd; k++) if (i < k->Count) i = k->Count; /* Build the fixed part of the argument vector. */ av = NEW(char*, i + 10); av[0] = "shar"; i = 1; if (Trailer) { av[i++] = "-t"; av[i++] = Trailer; } (void)sprintf(&buff[SEG0], "%d", LastOne); av[i++] = "-e"; av[i++] = &buff[SEG0]; av[i++] = "-n"; av[i++] = &buff[SEG1]; av[i++] = "-o"; av[i++] = &buff[SEG2]; /* Call shar to package up each archive. */ for (Start = i, i = 0; i < LastOne; i++) { (void)sprintf(&buff[SEG1], "%d", i + 1); (void)sprintf(&buff[SEG2], FORMAT2, SharName, i + 1); for (lines = Start, t = Table; t < TabEnd; t++) if (t->Where == i) av[lines++] = t->Name; av[lines] = NULL; fprintf(stderr, "Packing kit %d...\n", i + 1); if (lines = Execute(av)) fprintf(stderr, "Warning: shar returned status %d.\n", lines); } /* That's all she wrote. */ exit(0); }