1148871Scperciva/*-
2148871Scperciva * Copyright 2005 Colin Percival
3148871Scperciva * All rights reserved
4148871Scperciva *
5148871Scperciva * Redistribution and use in source and binary forms, with or without
6148871Scperciva * modification, are permitted providing that the following conditions
7148871Scperciva * are met:
8148871Scperciva * 1. Redistributions of source code must retain the above copyright
9148871Scperciva *    notice, this list of conditions and the following disclaimer.
10148871Scperciva * 2. Redistributions in binary form must reproduce the above copyright
11148871Scperciva *    notice, this list of conditions and the following disclaimer in the
12148871Scperciva *    documentation and/or other materials provided with the distribution.
13148871Scperciva *
14148871Scperciva * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15148871Scperciva * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16148871Scperciva * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148871Scperciva * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18148871Scperciva * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148871Scperciva * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148871Scperciva * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148871Scperciva * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22148871Scperciva * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23148871Scperciva * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24148871Scperciva * POSSIBILITY OF SUCH DAMAGE.
25148871Scperciva */
26148871Scperciva
27148871Scperciva#include <sys/cdefs.h>
28148871Scperciva__FBSDID("$FreeBSD$");
29148871Scperciva
30148871Scperciva#include <err.h>
31148871Scperciva#include <stdio.h>
32148871Scperciva#include <stdlib.h>
33148871Scperciva#include <string.h>
34148871Scperciva
35148871Scpercivastruct port;
36148871Scperciva
37148871Scpercivatypedef union {
38148871Scperciva	char * name;
39148871Scperciva	struct port * p;
40148871Scperciva} DEP;
41148871Scperciva
42148871Scpercivatypedef struct port {
43148871Scperciva	char * pkgname;
44148871Scperciva	char * portdir;
45148871Scperciva	char * prefix;
46148871Scperciva	char * comment;
47148871Scperciva	char * pkgdescr;
48148871Scperciva	char * maintainer;
49148871Scperciva	char * categories;
50148871Scperciva	size_t n_edep;
51148871Scperciva	DEP * edep;
52148871Scperciva	size_t n_pdep;
53148871Scperciva	DEP * pdep;
54148871Scperciva	size_t n_fdep;
55148871Scperciva	DEP * fdep;
56148871Scperciva	size_t n_bdep;
57148871Scperciva	DEP * bdep;
58148871Scperciva	size_t n_rdep;
59148871Scperciva	DEP * rdep;
60148871Scperciva	char * www;
61148871Scperciva	int recursed;
62148871Scperciva} PORT;
63148871Scperciva
64148871Scpercivastatic void usage(void);
65148871Scpercivastatic char * strdup2(const char *str);
66148871Scpercivastatic DEP * makelist(char * str, size_t * n);
67148871Scpercivastatic PORT * portify(char * line);
68148871Scpercivastatic int portcompare(char * a, char * b);
69148871Scpercivastatic void heapifyports(PORT **pp, size_t size, size_t pos);
70152997Scpercivastatic PORT * findport(PORT ** pp, size_t st, size_t en, char * name, char * from);
71148871Scpercivastatic void translateport(PORT ** pp, size_t pplen, PORT * p);
72148871Scpercivastatic DEP * recurse_one(DEP * d, size_t * nd);
73148871Scpercivastatic void recurse(PORT * p);
74148871Scpercivastatic void heapifypkgs(DEP * d, size_t size, size_t pos);
75148871Scpercivastatic void sortpkgs(DEP * d, size_t nd);
76148871Scpercivastatic void printport(PORT * p);
77148871Scperciva
78148871Scpercivastatic void
79148871Scpercivausage(void)
80148871Scperciva{
81148871Scperciva
82148871Scperciva	fprintf(stderr, "usage: make_index file\n");
83148871Scperciva	exit(1);
84148871Scperciva	/* NOTREACHED */
85148871Scperciva}
86148871Scperciva
87148871Scpercivastatic char *
88148871Scpercivastrdup2(const char *str)
89148871Scperciva{
90148871Scperciva	char * r;
91148871Scperciva
92148871Scperciva	r = strdup(str);
93148871Scperciva	if (r == NULL)
94148871Scperciva		err(1, "strdup");
95148871Scperciva	return r;
96148871Scperciva}
97148871Scperciva
98148871Scperciva/* Take a space-separated list and return an array of (char *) */
99148871Scpercivastatic DEP *
100148871Scpercivamakelist(char * str, size_t * n)
101148871Scperciva{
102148871Scperciva	DEP * d;
103148871Scperciva	size_t i;
104148871Scperciva
105148871Scperciva	/* No depends at all? */
106148871Scperciva	if (str[0] == 0) {
107148871Scperciva		*n = 0;
108148871Scperciva		return NULL;
109148871Scperciva	}
110148871Scperciva
111148871Scperciva	/* Count the number of fields */
112148871Scperciva	*n = 1;
113148871Scperciva	for (i = 0; str[i] != 0; i++)
114148871Scperciva		if (str[i] == ' ')
115148871Scperciva			(*n)++;
116148871Scperciva
117148871Scperciva	/* Allocate and fill an array */
118148871Scperciva	d = malloc(*n * sizeof(DEP));
119148885Scperciva	if (d == NULL)
120148885Scperciva		err(1, "malloc(DEP)");
121148871Scperciva	for (i = 0; i < *n; i++) {
122148871Scperciva		d[i].name = strdup2(strsep(&str, " "));
123148871Scperciva
124148871Scperciva		/* Strip trailing slashes */
125148871Scperciva		if (d[i].name[strlen(d[i].name) - 1] == '/')
126148871Scperciva			d[i].name[strlen(d[i].name) - 1] = 0;
127148871Scperciva	}
128148871Scperciva
129148871Scperciva	return d;
130148871Scperciva}
131148871Scperciva
132148871Scperciva/* Take a port's describe line and split it into fields */
133148871Scpercivastatic PORT *
134148871Scpercivaportify(char * line)
135148871Scperciva{
136148871Scperciva	PORT * p;
137148871Scperciva	size_t i, n;
138148871Scperciva
139148871Scperciva	/* Verify that line has the right number of fields */
140148871Scperciva	for (n = i = 0; line[i] != 0; i++)
141148871Scperciva		if (line[i] == '|')
142148871Scperciva			n++;
143148871Scperciva	if (n != 12)
144148871Scperciva		errx(1, "Port describe line is corrupt:\n%s\n", line);
145148871Scperciva
146148871Scperciva	p = malloc(sizeof(PORT));
147148871Scperciva	if (p == NULL)
148148871Scperciva		err(1, "malloc(PORT)");
149148871Scperciva
150148871Scperciva	p->pkgname = strdup2(strsep(&line, "|"));
151148871Scperciva	p->portdir = strdup2(strsep(&line, "|"));
152148871Scperciva	p->prefix = strdup2(strsep(&line, "|"));
153148871Scperciva	p->comment = strdup2(strsep(&line, "|"));
154148871Scperciva	p->pkgdescr = strdup2(strsep(&line, "|"));
155148871Scperciva	p->maintainer = strdup2(strsep(&line, "|"));
156148871Scperciva	p->categories = strdup2(strsep(&line, "|"));
157148871Scperciva	p->edep = makelist(strsep(&line, "|"), &p->n_edep);
158148871Scperciva	p->pdep = makelist(strsep(&line, "|"), &p->n_pdep);
159148871Scperciva	p->fdep = makelist(strsep(&line, "|"), &p->n_fdep);
160148871Scperciva	p->bdep = makelist(strsep(&line, "|"), &p->n_bdep);
161148871Scperciva	p->rdep = makelist(strsep(&line, "|"), &p->n_rdep);
162148871Scperciva	p->www = strdup2(strsep(&line, "|"));
163148871Scperciva
164148871Scperciva	p->recursed = 0;
165148871Scperciva
166148871Scperciva	/*
167148871Scperciva	 * line will now be equal to NULL -- we counted the field
168148871Scperciva	 * separators at the top of the function.
169148871Scperciva	 */
170148871Scperciva
171148871Scperciva	return p;
172148871Scperciva}
173148871Scperciva
174148871Scperciva/* Returns -1, 0, or 1 based on a comparison of the portdir strings */
175148871Scpercivastatic int
176148871Scpercivaportcompare(char * a, char * b)
177148871Scperciva{
178148871Scperciva	size_t i;
179148871Scperciva
180148871Scperciva	/* Find first non-matching position */
181148871Scperciva	for (i = 0; ; i++) {
182148871Scperciva		if (a[i] != b[i])
183148871Scperciva			break;
184148871Scperciva		if (a[i] == 0)			/* End of strings */
185148871Scperciva			return 0;
186148871Scperciva	}
187148871Scperciva
188148871Scperciva	/* One string is a prefix of the other */
189148871Scperciva	if (a[i] == 0)
190148871Scperciva		return -1;
191148871Scperciva	if (b[i] == 0)
192148871Scperciva		return 1;
193148871Scperciva
194148871Scperciva	/* One string has a category which is a prefix of the other */
195148871Scperciva	if (a[i] == '/')
196148871Scperciva		return -1;
197148871Scperciva	if (b[i] == '/')
198148871Scperciva		return 1;
199148871Scperciva
200148871Scperciva	/* The two strings are simply different */
201148871Scperciva	if (a[i] < b[i])
202148871Scperciva		return -1;
203148871Scperciva	else
204148871Scperciva		return 1;
205148871Scperciva}
206148871Scperciva
207148871Scperciva/* Heapify (PORT *) number pos in a pseudo-heap pp[0]..pp[size - 1] */
208148871Scpercivastatic void
209148871Scpercivaheapifyports(PORT **pp, size_t size, size_t pos)
210148871Scperciva{
211148871Scperciva	size_t i = pos;
212148871Scperciva	PORT * tmp;
213148871Scperciva
214148871Scpercivatop:
215148871Scperciva	/* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
216148871Scperciva	if ((2 * pos + 1 < size) &&
217148871Scperciva	    (portcompare(pp[i]->portdir, pp[2 * pos + 1]->portdir) < 0))
218148871Scperciva		i = 2 * pos + 1;
219148871Scperciva	if ((2 * pos + 2 < size) &&
220148871Scperciva	    (portcompare(pp[i]->portdir, pp[2 * pos + 2]->portdir) < 0))
221148871Scperciva		i = 2 * pos + 2;
222148871Scperciva
223148871Scperciva	/* If necessary, swap elements and iterate down the tree. */
224148871Scperciva	if (i != pos) {
225148871Scperciva		tmp = pp[pos];
226148871Scperciva		pp[pos] = pp[i];
227148871Scperciva		pp[i] = tmp;
228148871Scperciva		pos = i;
229148871Scperciva		goto top;
230148871Scperciva	}
231148871Scperciva}
232148871Scperciva
233148871Scperciva/* Translate a port directory name into a (PORT *), and free the name */
234148871Scpercivastatic PORT *
235152997Scpercivafindport(PORT ** pp, size_t st, size_t en, char * name, char * from)
236148871Scperciva{
237148871Scperciva	size_t mid;
238148871Scperciva	int r;
239148871Scperciva
240148871Scperciva	if (st == en)
241152997Scperciva		errx(1, "%s: no entry for %s", from, name);
242148871Scperciva
243148871Scperciva	mid = (st + en) / 2;
244148871Scperciva	r = portcompare(pp[mid]->portdir, name);
245148871Scperciva
246148871Scperciva	if (r == 0) {
247148871Scperciva		free(name);
248148871Scperciva		return pp[mid];
249148871Scperciva	} else if (r < 0)
250152997Scperciva		return findport(pp, mid + 1, en, name, from);
251148871Scperciva	else
252152997Scperciva		return findport(pp, st, mid, name, from);
253148871Scperciva}
254148871Scperciva
255148871Scperciva/* Translate all depends from names into PORT *s */
256148871Scpercivastatic void
257148871Scpercivatranslateport(PORT ** pp, size_t pplen, PORT * p)
258148871Scperciva{
259148871Scperciva	size_t i;
260148871Scperciva
261148871Scperciva	for (i = 0; i < p->n_edep; i++)
262152997Scperciva		p->edep[i].p = findport(pp, 0, pplen, p->edep[i].name, p->portdir);
263148871Scperciva	for (i = 0; i < p->n_pdep; i++)
264152997Scperciva		p->pdep[i].p = findport(pp, 0, pplen, p->pdep[i].name, p->portdir);
265148871Scperciva	for (i = 0; i < p->n_fdep; i++)
266152997Scperciva		p->fdep[i].p = findport(pp, 0, pplen, p->fdep[i].name, p->portdir);
267148871Scperciva	for (i = 0; i < p->n_bdep; i++)
268152997Scperciva		p->bdep[i].p = findport(pp, 0, pplen, p->bdep[i].name, p->portdir);
269148871Scperciva	for (i = 0; i < p->n_rdep; i++)
270152997Scperciva		p->rdep[i].p = findport(pp, 0, pplen, p->rdep[i].name, p->portdir);
271148871Scperciva}
272148871Scperciva
273148871Scperciva/* Recurse on one specific depends list */
274148871Scpercivastatic DEP *
275148871Scpercivarecurse_one(DEP * d, size_t * nd)
276148871Scperciva{
277148871Scperciva	size_t i, j, k, n, N;
278148871Scperciva
279148871Scperciva	N = n = *nd;
280148871Scperciva	for (i = 0; i < n; i++) {
281148871Scperciva		recurse(d[i].p);
282148871Scperciva		for (j = 0; j < d[i].p->n_rdep; j++) {
283148871Scperciva			for (k = 0; k < N; k++) {
284148871Scperciva				if (d[i].p->rdep[j].p == d[k].p)
285148871Scperciva					break;
286148871Scperciva			}
287148871Scperciva			if (k == N) {
288148871Scperciva				N++;
289148871Scperciva				if (N >= *nd) {
290148871Scperciva					*nd += *nd;
291148871Scperciva					d = realloc(d, *nd * sizeof(DEP));
292148871Scperciva					if (d == NULL)
293148871Scperciva						err(1, "realloc(d)");
294148871Scperciva				}
295148871Scperciva				d[k].p = d[i].p->rdep[j].p;
296148871Scperciva			}
297148871Scperciva		}
298148871Scperciva	}
299148871Scperciva	*nd = N;
300148871Scperciva
301148871Scperciva	return d;
302148871Scperciva}
303148871Scperciva
304148871Scperciva/* Recurse on the depends lists */
305148871Scpercivastatic void
306148871Scpercivarecurse(PORT * p)
307148871Scperciva{
308150254Scperciva	switch (p->recursed) {
309150254Scperciva	case 0:
310150254Scperciva		/* First time we've seen this port */
311150254Scperciva		p->recursed = 1;
312150254Scperciva		break;
313150254Scperciva	case 1:
314150254Scperciva		/* We're in the middle of recursing this port */
315150254Scperciva		errx(1, "Circular dependency loop found: %s"
316150254Scperciva		    " depends upon itself.\n", p->pkgname);
317150254Scperciva	case 2:
318150254Scperciva		/* This port has already been recursed */
319148871Scperciva		return;
320150254Scperciva	}
321148871Scperciva
322148871Scperciva	p->edep = recurse_one(p->edep, &p->n_edep);
323148871Scperciva	p->pdep = recurse_one(p->pdep, &p->n_pdep);
324148871Scperciva	p->fdep = recurse_one(p->fdep, &p->n_fdep);
325148871Scperciva	p->bdep = recurse_one(p->bdep, &p->n_bdep);
326148871Scperciva	p->rdep = recurse_one(p->rdep, &p->n_rdep);
327150254Scperciva
328150254Scperciva	/* Finished recursing on this port */
329150254Scperciva	p->recursed = 2;
330148871Scperciva}
331148871Scperciva
332148871Scperciva/* Heapify an element in a package list */
333148871Scpercivastatic void
334148871Scpercivaheapifypkgs(DEP * d, size_t size, size_t pos)
335148871Scperciva{
336148871Scperciva	size_t i = pos;
337148871Scperciva	PORT * tmp;
338148871Scperciva
339148871Scpercivatop:
340148871Scperciva	/* Find the largest value out of {pos, 2*pos+1, 2*pos+2} */
341148871Scperciva	if ((2 * pos + 1 < size) &&
342148871Scperciva	    (strcmp(d[i].p->pkgname, d[2 * pos + 1].p->pkgname) < 0))
343148871Scperciva		i = 2 * pos + 1;
344148871Scperciva	if ((2 * pos + 2 < size) &&
345148871Scperciva	    (strcmp(d[i].p->pkgname, d[2 * pos + 2].p->pkgname) < 0))
346148871Scperciva		i = 2 * pos + 2;
347148871Scperciva
348148871Scperciva	/* If necessary, swap elements and iterate down the tree. */
349148871Scperciva	if (i != pos) {
350148871Scperciva		tmp = d[pos].p;
351148871Scperciva		d[pos].p = d[i].p;
352148871Scperciva		d[i].p = tmp;
353148871Scperciva		pos = i;
354148871Scperciva		goto top;
355148871Scperciva	}
356148871Scperciva}
357148871Scperciva
358148871Scperciva/* Sort a list of dependent packages in alphabetical order */
359148871Scpercivastatic void
360148871Scpercivasortpkgs(DEP * d, size_t nd)
361148871Scperciva{
362148871Scperciva	size_t i;
363148871Scperciva	PORT * tmp;
364148871Scperciva
365148871Scperciva	if (nd == 0)
366148871Scperciva		return;
367148871Scperciva
368148871Scperciva	for (i = nd; i > 0; i--)
369148871Scperciva		heapifypkgs(d, nd, i - 1);	/* Build a heap */
370148871Scperciva	for (i = nd - 1; i > 0; i--) {
371148871Scperciva		tmp = d[0].p;			/* Extract elements */
372148871Scperciva		d[0].p = d[i].p;
373148871Scperciva		d[i].p = tmp;
374148871Scperciva		heapifypkgs(d, i, 0);		/* And re-heapify */
375148871Scperciva	}
376148871Scperciva}
377148871Scperciva
378148871Scperciva/* Output an index line for the given port. */
379148871Scpercivastatic void
380148871Scpercivaprintport(PORT * p)
381148871Scperciva{
382148871Scperciva	size_t i;
383148871Scperciva
384148871Scperciva	sortpkgs(p->edep, p->n_edep);
385148871Scperciva	sortpkgs(p->pdep, p->n_pdep);
386148871Scperciva	sortpkgs(p->fdep, p->n_fdep);
387148871Scperciva	sortpkgs(p->bdep, p->n_bdep);
388148871Scperciva	sortpkgs(p->rdep, p->n_rdep);
389148871Scperciva
390148871Scperciva	printf("%s|%s|%s|%s|%s|%s|%s|",
391148871Scperciva	    p->pkgname, p->portdir, p->prefix, p->comment, p->pkgdescr,
392148871Scperciva	    p->maintainer, p->categories);
393148871Scperciva	for (i = 0; i < p->n_bdep; i++)
394148871Scperciva		printf("%s%s", i ? " " : "", p->bdep[i].p->pkgname);
395148871Scperciva	printf("|");
396148871Scperciva	for (i = 0; i < p->n_rdep; i++)
397148871Scperciva		printf("%s%s", i ? " " : "", p->rdep[i].p->pkgname);
398148871Scperciva	printf("|");
399148871Scperciva	printf("%s|", p->www);
400148871Scperciva	for (i = 0; i < p->n_edep; i++)
401148871Scperciva		printf("%s%s", i ? " " : "", p->edep[i].p->pkgname);
402148871Scperciva	printf("|");
403148871Scperciva	for (i = 0; i < p->n_pdep; i++)
404148871Scperciva		printf("%s%s", i ? " " : "", p->pdep[i].p->pkgname);
405148871Scperciva	printf("|");
406148871Scperciva	for (i = 0; i < p->n_fdep; i++)
407148871Scperciva		printf("%s%s", i ? " " : "", p->fdep[i].p->pkgname);
408148871Scperciva	printf("\n");
409148871Scperciva}
410148871Scperciva
411148871Scperciva/*
412148871Scperciva * Algorithm:
413148871Scperciva * 1. Suck in all the data, splitting into fields.
414152625Scperciva * 1a. If there are no ports, there is no INDEX.
415148871Scperciva * 2. Sort the ports according to port directory.
416148871Scperciva * 3. Using a binary search, translate each dependency from a
417148871Scperciva * port directory name into a pointer to a port.
418148871Scperciva * 4. Recursively follow dependencies, expanding the lists of
419148871Scperciva * pointers as needed (using realloc).
420148871Scperciva * 5. Iterate through the ports, printing them out (remembering
421148871Scperciva * to list the dependent ports in alphabetical order).
422148871Scperciva */
423148871Scperciva
424148871Scpercivaint
425148871Scpercivamain(int argc, char *argv[])
426148871Scperciva{
427148871Scperciva	FILE * f;
428148871Scperciva	char * line;
429148871Scperciva	size_t linelen;
430148871Scperciva	PORT ** pp;	/* Array of pointers to PORTs */
431148871Scperciva	PORT * tmp;
432148871Scperciva	size_t pplen;	/* Allocated size of array */
433148871Scperciva	size_t i;
434148871Scperciva
435148871Scperciva	if (argc != 2)
436148871Scperciva		usage();
437148871Scperciva	if ((f = fopen(argv[1], "r")) == NULL)
438148871Scperciva		err(1, "fopen(%s)", argv[1]);
439148871Scperciva
440148871Scperciva	pplen = 1024;
441148871Scperciva	if ((pp = malloc(pplen * sizeof(PORT *))) == NULL)
442148871Scperciva		err(1, "malloc(pp)");
443148871Scperciva
444148871Scperciva	/*
445148871Scperciva	 * 1. Suck in all the data, splitting into fields.
446148871Scperciva	 */
447148871Scperciva	for(i = 0; (line = fgetln(f, &linelen)) != NULL; i++) {
448148871Scperciva		if (line[linelen - 1] != '\n')
449148871Scperciva			errx(1, "Unterminated line encountered");
450148871Scperciva		line[linelen - 1] = 0;
451148871Scperciva
452148871Scperciva		/* Enlarge array if needed */
453148871Scperciva		if (i >= pplen) {
454148871Scperciva			pplen *= 2;
455148871Scperciva			if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
456148871Scperciva				err(1, "realloc(pp)");
457148871Scperciva		}
458148871Scperciva
459148871Scperciva		pp[i] = portify(line);
460148871Scperciva	}
461148871Scperciva	/* Reallocate to the correct size */
462148871Scperciva	pplen = i;
463148871Scperciva	if ((pp = realloc(pp, pplen * sizeof(PORT *))) == NULL)
464148871Scperciva		err(1, "realloc(pp)");
465148871Scperciva
466148871Scperciva	/* Make sure we actually reached the EOF */
467148871Scperciva	if (!feof(f))
468148871Scperciva		err(1, "fgetln(%s)", argv[1]);
469148871Scperciva	/* Close the describes file */
470148871Scperciva	if (fclose(f) != 0)
471148871Scperciva		err(1, "fclose(%s)", argv[1]);
472148871Scperciva
473148871Scperciva	/*
474152625Scperciva	 * 1a. If there are no ports, there is no INDEX.
475152625Scperciva	 */
476152625Scperciva	if (pplen == 0)
477152625Scperciva		return 0;
478152625Scperciva
479152625Scperciva	/*
480148871Scperciva	 * 2. Sort the ports according to port directory.
481148871Scperciva	 */
482148871Scperciva	for (i = pplen; i > 0; i--)
483148871Scperciva		heapifyports(pp, pplen, i - 1);	/* Build a heap */
484148871Scperciva	for (i = pplen - 1; i > 0; i--) {
485148871Scperciva		tmp = pp[0];			/* Extract elements */
486148871Scperciva		pp[0] = pp[i];
487148871Scperciva		pp[i] = tmp;
488148871Scperciva		heapifyports(pp, i, 0);		/* And re-heapify */
489148871Scperciva	}
490148871Scperciva
491148871Scperciva	/*
492148871Scperciva	 * 3. Using a binary search, translate each dependency from a
493148871Scperciva	 * port directory name into a pointer to a port.
494148871Scperciva	 */
495148871Scperciva	for (i = 0; i < pplen; i++)
496148871Scperciva		translateport(pp, pplen, pp[i]);
497148871Scperciva
498148871Scperciva	/*
499148871Scperciva	 * 4. Recursively follow dependencies, expanding the lists of
500148871Scperciva	 * pointers as needed (using realloc).
501148871Scperciva	 */
502148871Scperciva	for (i = 0; i < pplen; i++)
503148871Scperciva		recurse(pp[i]);
504148871Scperciva
505148871Scperciva	/*
506148871Scperciva	 * 5. Iterate through the ports, printing them out (remembering
507148871Scperciva	 * to list the dependent ports in alphabetical order).
508148871Scperciva	 */
509148871Scperciva	for (i = 0; i < pplen; i++)
510148871Scperciva		printport(pp[i]);
511148871Scperciva
512148871Scperciva	return 0;
513148871Scperciva}
514