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