summaryrefslogtreecommitdiffstats
path: root/usr.sbin/portsnap/make_index/make_index.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/portsnap/make_index/make_index.c')
-rw-r--r--usr.sbin/portsnap/make_index/make_index.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/usr.sbin/portsnap/make_index/make_index.c b/usr.sbin/portsnap/make_index/make_index.c
new file mode 100644
index 0000000..6139fad
--- /dev/null
+++ b/usr.sbin/portsnap/make_index/make_index.c
@@ -0,0 +1,491 @@
+/*-
+ * Copyright 2005 Colin Percival
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct port;
+
+typedef union {
+ char * name;
+ struct port * p;
+} DEP;
+
+typedef struct port {
+ char * pkgname;
+ char * portdir;
+ char * prefix;
+ char * comment;
+ char * pkgdescr;
+ char * maintainer;
+ char * categories;
+ size_t n_edep;
+ DEP * edep;
+ size_t n_pdep;
+ DEP * pdep;
+ size_t n_fdep;
+ DEP * fdep;
+ size_t n_bdep;
+ DEP * bdep;
+ size_t n_rdep;
+ DEP * rdep;
+ char * www;
+ int recursed;
+} PORT;
+
+static void usage(void);
+static char * strdup2(const char *str);
+static DEP * makelist(char * str, size_t * n);
+static PORT * portify(char * line);
+static int portcompare(char * a, char * b);
+static void heapifyports(PORT **pp, size_t size, size_t pos);
+static PORT * findport(PORT ** pp, size_t st, size_t en, char * name);
+static void translateport(PORT ** pp, size_t pplen, PORT * p);
+static DEP * recurse_one(DEP * d, size_t * nd);
+static void recurse(PORT * p);
+static void heapifypkgs(DEP * d, size_t size, size_t pos);
+static void sortpkgs(DEP * d, size_t nd);
+static void printport(PORT * p);
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: make_index file\n");
+ exit(1);
+ /* NOTREACHED */
+}
+
+static char *
+strdup2(const char *str)
+{
+ char * r;
+
+ r = strdup(str);
+ if (r == NULL)
+ err(1, "strdup");
+ return r;
+}
+
+/* Take a space-separated list and return an array of (char *) */
+static DEP *
+makelist(char * str, size_t * n)
+{
+ DEP * d;
+ size_t i;
+
+ /* No depends at all? */
+ if (str[0] == 0) {
+ *n = 0;
+ return NULL;
+ }
+
+ /* Count the number of fields */
+ *n = 1;
+ for (i = 0; str[i] != 0; i++)
+ if (str[i] == ' ')
+ (*n)++;
+
+ /* Allocate and fill an array */
+ d = malloc(*n * sizeof(DEP));
+ for (i = 0; i < *n; i++) {
+ d[i].name = strdup2(strsep(&str, " "));
+
+ /* Strip trailing slashes */
+ if (d[i].name[strlen(d[i].name) - 1] == '/')
+ d[i].name[strlen(d[i].name) - 1] = 0;
+ }
+
+ return d;
+}
+
+/* Take a port's describe line and split it into fields */
+static PORT *
+portify(char * line)
+{
+ PORT * p;
+ size_t i, n;
+
+ /* Verify that line has the right number of fields */
+ for (n = i = 0; line[i] != 0; i++)
+ if (line[i] == '|')
+ n++;
+ if (n != 12)
+ errx(1, "Port describe line is corrupt:\n%s\n", line);
+
+ p = malloc(sizeof(PORT));
+ if (p == NULL)
+ err(1, "malloc(PORT)");
+
+ p->pkgname = strdup2(strsep(&line, "|"));
+ p->portdir = strdup2(strsep(&line, "|"));
+ p->prefix = strdup2(strsep(&line, "|"));
+ p->comment = strdup2(strsep(&line, "|"));
+ p->pkgdescr = strdup2(strsep(&line, "|"));
+ p->maintainer = strdup2(strsep(&line, "|"));
+ p->categories = strdup2(strsep(&line, "|"));
+ p->edep = makelist(strsep(&line, "|"), &p->n_edep);
+ p->pdep = makelist(strsep(&line, "|"), &p->n_pdep);
+ p->fdep = makelist(strsep(&line, "|"), &p->n_fdep);
+ p->bdep = makelist(strsep(&line, "|"), &p->n_bdep);
+ p->rdep = makelist(strsep(&line, "|"), &p->n_rdep);
+ p->www = strdup2(strsep(&line, "|"));
+
+ p->recursed = 0;
+
+ /*
+ * line will now be equal to NULL -- we counted the field
+ * separators at the top of the function.
+ */
+
+ return p;
+}
+
+/* Returns -1, 0, or 1 based on a comparison of the portdir strings */
+static int
+portcompare(char * a, char * b)
+{
+ size_t i;
+
+ /* Find first non-matching position */
+ for (i = 0; ; i++) {
+ if (a[i] != b[i])
+ break;
+ if (a[i] == 0) /* End of strings */
+ return 0;
+ }
+
+ /* One string is a prefix of the other */
+ if (a[i] == 0)
+ return -1;
+ if (b[i] == 0)
+ return 1;
+
+ /* One string has a category which is a prefix of the other */
+ if (a[i] == '/')
+ return -1;
+ if (b[i] == '/')
+ return 1;
+
+ /* The two strings are simply different */
+ if (a[i] < b[i])
+ return -1;
+ else
+ return 1;
+}
+
+/* Heapify (PORT *) number pos in a pseudo-heap pp[0]..pp[size - 1] */
+static void
+heapifyports(PORT **pp, size_t size, size_t pos)
+{
+ size_t i = pos;
+ PORT * tmp;
+
+top:
+ /* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
+ if ((2 * pos + 1 < size) &&
+ (portcompare(pp[i]->portdir, pp[2 * pos + 1]->portdir) < 0))
+ i = 2 * pos + 1;
+ if ((2 * pos + 2 < size) &&
+ (portcompare(pp[i]->portdir, pp[2 * pos + 2]->portdir) < 0))
+ i = 2 * pos + 2;
+
+ /* If necessary, swap elements and iterate down the tree. */
+ if (i != pos) {
+ tmp = pp[pos];
+ pp[pos] = pp[i];
+ pp[i] = tmp;
+ pos = i;
+ goto top;
+ }
+}
+
+/* Translate a port directory name into a (PORT *), and free the name */
+static PORT *
+findport(PORT ** pp, size_t st, size_t en, char * name)
+{
+ size_t mid;
+ int r;
+
+ if (st == en)
+ errx(1, "Unresolved dependency: %s", name);
+
+ mid = (st + en) / 2;
+ r = portcompare(pp[mid]->portdir, name);
+
+ if (r == 0) {
+ free(name);
+ return pp[mid];
+ } else if (r < 0)
+ return findport(pp, mid + 1, en, name);
+ else
+ return findport(pp, st, mid, name);
+}
+
+/* Translate all depends from names into PORT *s */
+static void
+translateport(PORT ** pp, size_t pplen, PORT * p)
+{
+ size_t i;
+
+ for (i = 0; i < p->n_edep; i++)
+ p->edep[i].p = findport(pp, 0, pplen, p->edep[i].name);
+ for (i = 0; i < p->n_pdep; i++)
+ p->pdep[i].p = findport(pp, 0, pplen, p->pdep[i].name);
+ for (i = 0; i < p->n_fdep; i++)
+ p->fdep[i].p = findport(pp, 0, pplen, p->fdep[i].name);
+ for (i = 0; i < p->n_bdep; i++)
+ p->bdep[i].p = findport(pp, 0, pplen, p->bdep[i].name);
+ for (i = 0; i < p->n_rdep; i++)
+ p->rdep[i].p = findport(pp, 0, pplen, p->rdep[i].name);
+}
+
+/* Recurse on one specific depends list */
+static DEP *
+recurse_one(DEP * d, size_t * nd)
+{
+ size_t i, j, k, n, N;
+
+ N = n = *nd;
+ for (i = 0; i < n; i++) {
+ recurse(d[i].p);
+ for (j = 0; j < d[i].p->n_rdep; j++) {
+ for (k = 0; k < N; k++) {
+ if (d[i].p->rdep[j].p == d[k].p)
+ break;
+ }
+ if (k == N) {
+ N++;
+ if (N >= *nd) {
+ *nd += *nd;
+ d = realloc(d, *nd * sizeof(DEP));
+ if (d == NULL)
+ err(1, "realloc(d)");
+ }
+ d[k].p = d[i].p->rdep[j].p;
+ }
+ }
+ }
+ *nd = N;
+
+ return d;
+}
+
+/* Recurse on the depends lists */
+static void
+recurse(PORT * p)
+{
+ if (p->recursed != 0)
+ return;
+ p->recursed = 1;
+
+ p->edep = recurse_one(p->edep, &p->n_edep);
+ p->pdep = recurse_one(p->pdep, &p->n_pdep);
+ p->fdep = recurse_one(p->fdep, &p->n_fdep);
+ p->bdep = recurse_one(p->bdep, &p->n_bdep);
+ p->rdep = recurse_one(p->rdep, &p->n_rdep);
+}
+
+/* Heapify an element in a package list */
+static void
+heapifypkgs(DEP * d, size_t size, size_t pos)
+{
+ size_t i = pos;
+ PORT * tmp;
+
+top:
+ /* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
+ if ((2 * pos + 1 < size) &&
+ (strcmp(d[i].p->pkgname, d[2 * pos + 1].p->pkgname) < 0))
+ i = 2 * pos + 1;
+ if ((2 * pos + 2 < size) &&
+ (strcmp(d[i].p->pkgname, d[2 * pos + 2].p->pkgname) < 0))
+ i = 2 * pos + 2;
+
+ /* If necessary, swap elements and iterate down the tree. */
+ if (i != pos) {
+ tmp = d[pos].p;
+ d[pos].p = d[i].p;
+ d[i].p = tmp;
+ pos = i;
+ goto top;
+ }
+}
+
+/* Sort a list of dependent packages in alphabetical order */
+static void
+sortpkgs(DEP * d, size_t nd)
+{
+ size_t i;
+ PORT * tmp;
+
+ if (nd == 0)
+ return;
+
+ for (i = nd; i > 0; i--)
+ heapifypkgs(d, nd, i - 1); /* Build a heap */
+ for (i = nd - 1; i > 0; i--) {
+ tmp = d[0].p; /* Extract elements */
+ d[0].p = d[i].p;
+ d[i].p = tmp;
+ heapifypkgs(d, i, 0); /* And re-heapify */
+ }
+}
+
+/* Output an index line for the given port. */
+static void
+printport(PORT * p)
+{
+ size_t i;
+
+ sortpkgs(p->edep, p->n_edep);
+ sortpkgs(p->pdep, p->n_pdep);
+ sortpkgs(p->fdep, p->n_fdep);
+ sortpkgs(p->bdep, p->n_bdep);
+ sortpkgs(p->rdep, p->n_rdep);
+
+ printf("%s|%s|%s|%s|%s|%s|%s|",
+ p->pkgname, p->portdir, p->prefix, p->comment, p->pkgdescr,
+ p->maintainer, p->categories);
+ for (i = 0; i < p->n_bdep; i++)
+ printf("%s%s", i ? " " : "", p->bdep[i].p->pkgname);
+ printf("|");
+ for (i = 0; i < p->n_rdep; i++)
+ printf("%s%s", i ? " " : "", p->rdep[i].p->pkgname);
+ printf("|");
+ printf("%s|", p->www);
+ for (i = 0; i < p->n_edep; i++)
+ printf("%s%s", i ? " " : "", p->edep[i].p->pkgname);
+ printf("|");
+ for (i = 0; i < p->n_pdep; i++)
+ printf("%s%s", i ? " " : "", p->pdep[i].p->pkgname);
+ printf("|");
+ for (i = 0; i < p->n_fdep; i++)
+ printf("%s%s", i ? " " : "", p->fdep[i].p->pkgname);
+ printf("\n");
+}
+
+/*
+ * Algorithm:
+ * 1. Suck in all the data, splitting into fields.
+ * 2. Sort the ports according to port directory.
+ * 3. Using a binary search, translate each dependency from a
+ * port directory name into a pointer to a port.
+ * 4. Recursively follow dependencies, expanding the lists of
+ * pointers as needed (using realloc).
+ * 5. Iterate through the ports, printing them out (remembering
+ * to list the dependent ports in alphabetical order).
+ */
+
+int
+main(int argc, char *argv[])
+{
+ FILE * f;
+ char * line;
+ size_t linelen;
+ PORT ** pp; /* Array of pointers to PORTs */
+ PORT * tmp;
+ size_t pplen; /* Allocated size of array */
+ size_t i;
+
+ if (argc != 2)
+ usage();
+ if ((f = fopen(argv[1], "r")) == NULL)
+ err(1, "fopen(%s)", argv[1]);
+
+ pplen = 1024;
+ if ((pp = malloc(pplen * sizeof(PORT *))) == NULL)
+ err(1, "malloc(pp)");
+
+ /*
+ * 1. Suck in all the data, splitting into fields.
+ */
+ for(i = 0; (line = fgetln(f, &linelen)) != NULL; i++) {
+ if (line[linelen - 1] != '\n')
+ errx(1, "Unterminated line encountered");
+ line[linelen - 1] = 0;
+
+ /* Enlarge array if needed */
+ if (i >= pplen) {
+ pplen *= 2;
+ if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
+ err(1, "realloc(pp)");
+ }
+
+ pp[i] = portify(line);
+ }
+ /* Reallocate to the correct size */
+ pplen = i;
+ if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
+ err(1, "realloc(pp)");
+
+ /* Make sure we actually reached the EOF */
+ if (!feof(f))
+ err(1, "fgetln(%s)", argv[1]);
+ /* Close the describes file */
+ if (fclose(f) != 0)
+ err(1, "fclose(%s)", argv[1]);
+
+ /*
+ * 2. Sort the ports according to port directory.
+ */
+ for (i = pplen; i > 0; i--)
+ heapifyports(pp, pplen, i - 1); /* Build a heap */
+ for (i = pplen - 1; i > 0; i--) {
+ tmp = pp[0]; /* Extract elements */
+ pp[0] = pp[i];
+ pp[i] = tmp;
+ heapifyports(pp, i, 0); /* And re-heapify */
+ }
+
+ /*
+ * 3. Using a binary search, translate each dependency from a
+ * port directory name into a pointer to a port.
+ */
+ for (i = 0; i < pplen; i++)
+ translateport(pp, pplen, pp[i]);
+
+ /*
+ * 4. Recursively follow dependencies, expanding the lists of
+ * pointers as needed (using realloc).
+ */
+ for (i = 0; i < pplen; i++)
+ recurse(pp[i]);
+
+ /*
+ * 5. Iterate through the ports, printing them out (remembering
+ * to list the dependent ports in alphabetical order).
+ */
+ for (i = 0; i < pplen; i++)
+ printport(pp[i]);
+
+ return 0;
+}
OpenPOWER on IntegriCloud