2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright 2005 Colin Percival
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted providing that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
66 static void usage(void);
67 static char * strdup2(const char *str);
68 static DEP * makelist(char * str, size_t * n);
69 static PORT * portify(char * line);
70 static int portcompare(char * a, char * b);
71 static void heapifyports(PORT **pp, size_t size, size_t pos);
72 static PORT * findport(PORT ** pp, size_t st, size_t en, char * name, char * from);
73 static void translateport(PORT ** pp, size_t pplen, PORT * p);
74 static DEP * recurse_one(DEP * d, size_t * nd);
75 static void recurse(PORT * p);
76 static void heapifypkgs(DEP * d, size_t size, size_t pos);
77 static void sortpkgs(DEP * d, size_t nd);
78 static void printport(PORT * p);
84 fprintf(stderr, "usage: make_index file\n");
90 strdup2(const char *str)
100 /* Take a space-separated list and return an array of (char *) */
102 makelist(char * str, size_t * n)
107 /* No depends at all? */
113 /* Count the number of fields */
115 for (i = 0; str[i] != 0; i++)
119 /* Allocate and fill an array */
120 d = malloc(*n * sizeof(DEP));
122 err(1, "malloc(DEP)");
123 for (i = 0; i < *n; i++) {
124 d[i].name = strdup2(strsep(&str, " "));
126 /* Strip trailing slashes */
127 if (d[i].name[strlen(d[i].name) - 1] == '/')
128 d[i].name[strlen(d[i].name) - 1] = 0;
134 /* Take a port's describe line and split it into fields */
141 /* Verify that line has the right number of fields */
142 for (n = i = 0; line[i] != 0; i++)
146 errx(1, "Port describe line is corrupt:\n%s\n", line);
148 p = malloc(sizeof(PORT));
150 err(1, "malloc(PORT)");
152 p->pkgname = strdup2(strsep(&line, "|"));
153 p->portdir = strdup2(strsep(&line, "|"));
154 p->prefix = strdup2(strsep(&line, "|"));
155 p->comment = strdup2(strsep(&line, "|"));
156 p->pkgdescr = strdup2(strsep(&line, "|"));
157 p->maintainer = strdup2(strsep(&line, "|"));
158 p->categories = strdup2(strsep(&line, "|"));
159 p->edep = makelist(strsep(&line, "|"), &p->n_edep);
160 p->pdep = makelist(strsep(&line, "|"), &p->n_pdep);
161 p->fdep = makelist(strsep(&line, "|"), &p->n_fdep);
162 p->bdep = makelist(strsep(&line, "|"), &p->n_bdep);
163 p->rdep = makelist(strsep(&line, "|"), &p->n_rdep);
164 p->www = strdup2(strsep(&line, "|"));
169 * line will now be equal to NULL -- we counted the field
170 * separators at the top of the function.
176 /* Returns -1, 0, or 1 based on a comparison of the portdir strings */
178 portcompare(char * a, char * b)
182 /* Find first non-matching position */
186 if (a[i] == 0) /* End of strings */
190 /* One string is a prefix of the other */
196 /* One string has a category which is a prefix of the other */
202 /* The two strings are simply different */
209 /* Heapify (PORT *) number pos in a pseudo-heap pp[0]..pp[size - 1] */
211 heapifyports(PORT **pp, size_t size, size_t pos)
217 /* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
218 if ((2 * pos + 1 < size) &&
219 (portcompare(pp[i]->portdir, pp[2 * pos + 1]->portdir) < 0))
221 if ((2 * pos + 2 < size) &&
222 (portcompare(pp[i]->portdir, pp[2 * pos + 2]->portdir) < 0))
225 /* If necessary, swap elements and iterate down the tree. */
235 /* Translate a port directory name into a (PORT *), and free the name */
237 findport(PORT ** pp, size_t st, size_t en, char * name, char * from)
243 errx(1, "%s: no entry for %s", from, name);
246 r = portcompare(pp[mid]->portdir, name);
252 return findport(pp, mid + 1, en, name, from);
254 return findport(pp, st, mid, name, from);
257 /* Translate all depends from names into PORT *s */
259 translateport(PORT ** pp, size_t pplen, PORT * p)
263 for (i = 0; i < p->n_edep; i++)
264 p->edep[i].p = findport(pp, 0, pplen, p->edep[i].name, p->portdir);
265 for (i = 0; i < p->n_pdep; i++)
266 p->pdep[i].p = findport(pp, 0, pplen, p->pdep[i].name, p->portdir);
267 for (i = 0; i < p->n_fdep; i++)
268 p->fdep[i].p = findport(pp, 0, pplen, p->fdep[i].name, p->portdir);
269 for (i = 0; i < p->n_bdep; i++)
270 p->bdep[i].p = findport(pp, 0, pplen, p->bdep[i].name, p->portdir);
271 for (i = 0; i < p->n_rdep; i++)
272 p->rdep[i].p = findport(pp, 0, pplen, p->rdep[i].name, p->portdir);
275 /* Recurse on one specific depends list */
277 recurse_one(DEP * d, size_t * nd)
279 size_t i, j, k, n, N;
282 for (i = 0; i < n; i++) {
284 for (j = 0; j < d[i].p->n_rdep; j++) {
285 for (k = 0; k < N; k++) {
286 if (d[i].p->rdep[j].p == d[k].p)
293 d = realloc(d, *nd * sizeof(DEP));
295 err(1, "realloc(d)");
297 d[k].p = d[i].p->rdep[j].p;
306 /* Recurse on the depends lists */
310 switch (p->recursed) {
312 /* First time we've seen this port */
316 /* We're in the middle of recursing this port */
317 errx(1, "Circular dependency loop found: %s"
318 " depends upon itself.\n", p->pkgname);
320 /* This port has already been recursed */
324 p->edep = recurse_one(p->edep, &p->n_edep);
325 p->pdep = recurse_one(p->pdep, &p->n_pdep);
326 p->fdep = recurse_one(p->fdep, &p->n_fdep);
327 p->bdep = recurse_one(p->bdep, &p->n_bdep);
328 p->rdep = recurse_one(p->rdep, &p->n_rdep);
330 /* Finished recursing on this port */
334 /* Heapify an element in a package list */
336 heapifypkgs(DEP * d, size_t size, size_t pos)
342 /* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
343 if ((2 * pos + 1 < size) &&
344 (strcmp(d[i].p->pkgname, d[2 * pos + 1].p->pkgname) < 0))
346 if ((2 * pos + 2 < size) &&
347 (strcmp(d[i].p->pkgname, d[2 * pos + 2].p->pkgname) < 0))
350 /* If necessary, swap elements and iterate down the tree. */
360 /* Sort a list of dependent packages in alphabetical order */
362 sortpkgs(DEP * d, size_t nd)
370 for (i = nd; i > 0; i--)
371 heapifypkgs(d, nd, i - 1); /* Build a heap */
372 for (i = nd - 1; i > 0; i--) {
373 tmp = d[0].p; /* Extract elements */
376 heapifypkgs(d, i, 0); /* And re-heapify */
380 /* Output an index line for the given port. */
386 sortpkgs(p->edep, p->n_edep);
387 sortpkgs(p->pdep, p->n_pdep);
388 sortpkgs(p->fdep, p->n_fdep);
389 sortpkgs(p->bdep, p->n_bdep);
390 sortpkgs(p->rdep, p->n_rdep);
392 printf("%s|%s|%s|%s|%s|%s|%s|",
393 p->pkgname, p->portdir, p->prefix, p->comment, p->pkgdescr,
394 p->maintainer, p->categories);
395 for (i = 0; i < p->n_bdep; i++)
396 printf("%s%s", i ? " " : "", p->bdep[i].p->pkgname);
398 for (i = 0; i < p->n_rdep; i++)
399 printf("%s%s", i ? " " : "", p->rdep[i].p->pkgname);
401 printf("%s|", p->www);
402 for (i = 0; i < p->n_edep; i++)
403 printf("%s%s", i ? " " : "", p->edep[i].p->pkgname);
405 for (i = 0; i < p->n_pdep; i++)
406 printf("%s%s", i ? " " : "", p->pdep[i].p->pkgname);
408 for (i = 0; i < p->n_fdep; i++)
409 printf("%s%s", i ? " " : "", p->fdep[i].p->pkgname);
415 * 1. Suck in all the data, splitting into fields.
416 * 1a. If there are no ports, there is no INDEX.
417 * 2. Sort the ports according to port directory.
418 * 3. Using a binary search, translate each dependency from a
419 * port directory name into a pointer to a port.
420 * 4. Recursively follow dependencies, expanding the lists of
421 * pointers as needed (using realloc).
422 * 5. Iterate through the ports, printing them out (remembering
423 * to list the dependent ports in alphabetical order).
427 main(int argc, char *argv[])
432 PORT ** pp; /* Array of pointers to PORTs */
434 size_t pplen; /* Allocated size of array */
439 if ((f = fopen(argv[1], "r")) == NULL)
440 err(1, "fopen(%s)", argv[1]);
443 if ((pp = malloc(pplen * sizeof(PORT *))) == NULL)
444 err(1, "malloc(pp)");
447 * 1. Suck in all the data, splitting into fields.
449 for(i = 0; (line = fgetln(f, &linelen)) != NULL; i++) {
450 if (line[linelen - 1] != '\n')
451 errx(1, "Unterminated line encountered");
452 line[linelen - 1] = 0;
454 /* Enlarge array if needed */
457 if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
458 err(1, "realloc(pp)");
461 pp[i] = portify(line);
463 /* Reallocate to the correct size */
465 if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
466 err(1, "realloc(pp)");
468 /* Make sure we actually reached the EOF */
470 err(1, "fgetln(%s)", argv[1]);
471 /* Close the describes file */
473 err(1, "fclose(%s)", argv[1]);
476 * 1a. If there are no ports, there is no INDEX.
482 * 2. Sort the ports according to port directory.
484 for (i = pplen; i > 0; i--)
485 heapifyports(pp, pplen, i - 1); /* Build a heap */
486 for (i = pplen - 1; i > 0; i--) {
487 tmp = pp[0]; /* Extract elements */
490 heapifyports(pp, i, 0); /* And re-heapify */
494 * 3. Using a binary search, translate each dependency from a
495 * port directory name into a pointer to a port.
497 for (i = 0; i < pplen; i++)
498 translateport(pp, pplen, pp[i]);
501 * 4. Recursively follow dependencies, expanding the lists of
502 * pointers as needed (using realloc).
504 for (i = 0; i < pplen; i++)
508 * 5. Iterate through the ports, printing them out (remembering
509 * to list the dependent ports in alphabetical order).
511 for (i = 0; i < pplen; i++)