Annotation of src/usr.bin/tsort/tsort.c, Revision 1.35
1.35 ! espie 1: /* $OpenBSD: tsort.c,v 1.34 2015/12/31 18:00:41 millert Exp $ */
1.15 espie 2: /* ex:ts=8 sw=4:
1.1 deraadt 3: *
1.19 espie 4: * Copyright (c) 1999-2004 Marc Espie <espie@openbsd.org>
1.1 deraadt 5: *
1.19 espie 6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 deraadt 17: */
18:
1.5 espie 19: #include <assert.h>
1.1 deraadt 20: #include <ctype.h>
21: #include <err.h>
1.5 espie 22: #include <limits.h>
23: #include <stddef.h>
1.1 deraadt 24: #include <stdio.h>
1.20 espie 25: #include <stdint.h>
1.1 deraadt 26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
1.20 espie 29: #include <ohash.h>
1.1 deraadt 30:
1.15 espie 31: /* The complexity of topological sorting is O(e), where e is the
1.5 espie 32: * size of input. While reading input, vertices have to be identified,
33: * thus add the complexity of e keys retrieval among v keys using
1.15 espie 34: * an appropriate data structure. This program uses open double hashing
35: * for that purpose. See Knuth for the expected complexity of double
1.5 espie 36: * hashing (Brent variation should probably be used if v << e, as a user
37: * option).
38: *
39: * The algorithm used for longest cycle reporting is accurate, but somewhat
40: * expensive. It may need to build all free paths of the graph (a free
41: * path is a path that never goes twice through the same node), whose
1.15 espie 42: * number can be as high as O(2^e). Usually, the number of free paths is
1.5 espie 43: * much smaller though. This program's author does not believe that a
44: * significantly better worst-case complexity algorithm exists.
45: *
46: * In case of a hints file, the set of minimal nodes is maintained as a
47: * heap. The resulting complexity is O(e+v log v) for the worst case.
48: * The average should actually be near O(e).
49: *
1.8 espie 50: * If the hints file is incomplete, there is some extra complexity incurred
51: * by make_transparent, which does propagate order values to unmarked
52: * nodes. In the worst case, make_transparent is O(e u),
53: * where u is the number of originally unmarked nodes.
54: * In practice, it is much faster.
55: *
1.5 espie 56: * The simple topological sort algorithm detects cycles. This program
1.15 espie 57: * goes further, breaking cycles through the use of simple heuristics.
58: * Each cycle break checks the whole set of nodes, hence if c cycles break
1.5 espie 59: * are needed, this is an extra cost of O(c v).
1.1 deraadt 60: *
1.5 espie 61: * Possible heuristics are as follows:
62: * - break cycle at node with lowest number of predecessors (default case),
63: * - break longest cycle at node with lowest number of predecessors,
64: * - break cycle at next node from the hints file.
1.1 deraadt 65: *
1.5 espie 66: * Except for the hints file case, which sets an explicit constraint on
1.15 espie 67: * which cycle to break, those heuristics locally result in the smallest
1.5 espie 68: * number of broken edges.
1.1 deraadt 69: *
1.5 espie 70: * Those are admittedly greedy strategies, as is the selection of the next
71: * node from the hints file amongst equivalent candidates that is used for
72: * `stable' topological sorting.
1.1 deraadt 73: */
1.5 espie 74:
75: #ifdef __GNUC__
76: #define UNUSED __attribute__((unused))
77: #else
78: #define UNUSED
79: #endif
80:
81: struct node;
82:
83: /* The set of arcs from a given node is stored as a linked list. */
84: struct link {
85: struct link *next;
86: struct node *node;
87: };
88:
1.7 espie 89: #define NO_ORDER UINT_MAX
90:
1.5 espie 91: struct node {
1.15 espie 92: unsigned int refs; /* Number of arcs left, coming into this node.
93: * Note that nodes with a null count can't
1.5 espie 94: * be part of cycles. */
95: struct link *arcs; /* List of forward arcs. */
96:
97: unsigned int order; /* Order of nodes according to a hint file. */
98:
99: /* Cycle detection algorithms build a free path of nodes. */
100: struct node *from; /* Previous node in the current path. */
101:
102: unsigned int mark; /* Mark processed nodes in cycle discovery. */
103: struct link *traverse; /* Next link to traverse when backtracking. */
104: char k[1]; /* Name of this node. */
1.1 deraadt 105: };
106:
1.5 espie 107: #define HASH_START 9
108:
109: struct array {
110: unsigned int entries;
111: struct node **t;
112: };
113:
1.12 millert 114: static void nodes_init(struct ohash *);
115: static struct node *node_lookup(struct ohash *, const char *, const char *);
116: static void usage(void);
117: static struct node *new_node(const char *, const char *);
1.5 espie 118:
1.15 espie 119: static unsigned int read_pairs(FILE *, struct ohash *, int,
1.13 millert 120: const char *, unsigned int, int);
1.12 millert 121: static void split_nodes(struct ohash *, struct array *, struct array *);
122: static void make_transparent(struct ohash *);
123: static void insert_arc(struct node *, struct node *);
1.5 espie 124:
125: #ifdef DEBUG
1.12 millert 126: static void dump_node(struct node *);
127: static void dump_array(struct array *);
128: static void dump_hash(struct ohash *);
1.5 espie 129: #endif
1.15 espie 130: static unsigned int read_hints(FILE *, struct ohash *, int,
1.13 millert 131: const char *, unsigned int);
1.12 millert 132: static struct node *find_smallest_node(struct array *);
133: static struct node *find_good_cycle_break(struct array *);
134: static void print_cycle(struct array *);
135: static struct node *find_cycle_from(struct node *, struct array *);
136: static struct node *find_predecessor(struct array *, struct node *);
137: static unsigned int traverse_node(struct node *, unsigned int, struct array *);
138: static struct node *find_longest_cycle(struct array *, struct array *);
1.29 espie 139: static struct node *find_normal_cycle(struct array *, struct array *);
1.12 millert 140:
141: static void heap_down(struct array *, unsigned int);
142: static void heapify(struct array *, int);
143: static struct node *dequeue(struct array *);
144: static void enqueue(struct array *, struct node *);
1.5 espie 145:
1.1 deraadt 146:
1.5 espie 147:
1.23 espie 148: static void *hash_calloc(size_t, size_t, void *);
149: static void hash_free(void *, void *);
1.12 millert 150: static void* entry_alloc(size_t, void *);
1.24 deraadt 151: static void *ereallocarray(void *, size_t, size_t);
1.12 millert 152: static void *emem(void *);
1.5 espie 153: #define DEBUG_TRAVERSE 0
1.15 espie 154: static struct ohash_info node_info = {
1.23 espie 155: offsetof(struct node, k), NULL, hash_calloc, hash_free, entry_alloc };
1.29 espie 156: static void parse_args(int, char *[], struct ohash *);
157: static int tsort(struct ohash *);
158:
159: static int quiet_flag, long_flag,
160: warn_flag, hints_flag, verbose_flag;
1.5 espie 161:
162:
1.12 millert 163: int main(int, char *[]);
1.5 espie 164:
165: /***
1.15 espie 166: *** Memory handling.
1.5 espie 167: ***/
168:
169: static void *
1.14 espie 170: emem(void *p)
1.5 espie 171: {
172: if (p)
173: return p;
174: else
1.34 millert 175: errx(1, "Memory exhausted");
1.5 espie 176: }
177:
178: static void *
1.23 espie 179: hash_calloc(size_t n, size_t s, void *u UNUSED)
1.5 espie 180: {
1.23 espie 181: return emem(calloc(n, s));
1.5 espie 182: }
183:
184: static void
1.23 espie 185: hash_free(void *p, void *u UNUSED)
1.5 espie 186: {
187: free(p);
188: }
189:
190: static void *
1.14 espie 191: entry_alloc(size_t s, void *u UNUSED)
1.5 espie 192: {
1.24 deraadt 193: return ereallocarray(NULL, 1, s);
1.5 espie 194: }
195:
196: static void *
1.24 deraadt 197: ereallocarray(void *p, size_t n, size_t s)
1.1 deraadt 198: {
1.24 deraadt 199: return emem(reallocarray(p, n, s));
1.5 espie 200: }
1.1 deraadt 201:
1.5 espie 202:
1.15 espie 203: /***
1.5 espie 204: *** Hash table.
205: ***/
206:
207: /* Inserting and finding nodes in the hash structure.
208: * We handle interval strings for efficiency wrt fgetln. */
209: static struct node *
1.14 espie 210: new_node(const char *start, const char *end)
1.5 espie 211: {
212: struct node *n;
1.1 deraadt 213:
1.5 espie 214: n = ohash_create_entry(&node_info, start, &end);
215: n->from = NULL;
216: n->arcs = NULL;
217: n->refs = 0;
218: n->mark = 0;
1.7 espie 219: n->order = NO_ORDER;
1.5 espie 220: n->traverse = NULL;
221: return n;
222: }
1.1 deraadt 223:
224:
1.15 espie 225: static void
1.14 espie 226: nodes_init(struct ohash *h)
1.5 espie 227: {
228: ohash_init(h, HASH_START, &node_info);
1.1 deraadt 229: }
230:
1.5 espie 231: static struct node *
1.14 espie 232: node_lookup(struct ohash *h, const char *start, const char *end)
1.1 deraadt 233: {
1.5 espie 234: unsigned int i;
235: struct node * n;
1.1 deraadt 236:
1.5 espie 237: i = ohash_qlookupi(h, start, &end);
1.1 deraadt 238:
1.5 espie 239: n = ohash_find(h, i);
240: if (n == NULL)
241: n = ohash_insert(h, i, new_node(start, end));
242: return n;
243: }
1.25 jasper 244:
1.5 espie 245: #ifdef DEBUG
246: static void
1.14 espie 247: dump_node(struct node *n)
1.5 espie 248: {
249: struct link *l;
250:
251: if (n->refs == 0)
1.1 deraadt 252: return;
1.8 espie 253: printf("%s (%u/%u): ", n->k, n->order, n->refs);
1.5 espie 254: for (l = n->arcs; l != NULL; l = l->next)
255: if (n->refs != 0)
1.8 espie 256: printf("%s(%u/%u) ", l->node->k, l->node->order, l->node->refs);
1.5 espie 257: putchar('\n');
258: }
1.1 deraadt 259:
1.5 espie 260: static void
1.14 espie 261: dump_array(struct array *a)
1.5 espie 262: {
263: unsigned int i;
1.1 deraadt 264:
1.5 espie 265: for (i = 0; i < a->entries; i++)
266: dump_node(a->t[i]);
267: }
1.25 jasper 268:
1.15 espie 269: static void
1.14 espie 270: dump_hash(struct ohash *h)
1.5 espie 271: {
272: unsigned int i;
273: struct node *n;
274:
275: for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i))
276: dump_node(n);
277: }
278: #endif
1.25 jasper 279:
1.5 espie 280: /***
281: *** Reading data.
282: ***/
283:
1.15 espie 284: static void
1.14 espie 285: insert_arc(struct node *a, struct node *b)
1.5 espie 286: {
287: struct link *l;
288:
289: /* Check that this arc is not already present. */
290: for (l = a->arcs; l != NULL; l = l->next) {
291: if (l->node == b)
1.1 deraadt 292: return;
1.5 espie 293: }
294: b->refs++;
1.24 deraadt 295: l = ereallocarray(NULL, 1, sizeof(struct link));
1.5 espie 296: l->node = b;
297: l->next = a->arcs;
298: a->arcs = l;
299: }
1.1 deraadt 300:
1.7 espie 301: static unsigned int
1.15 espie 302: read_pairs(FILE *f, struct ohash *h, int reverse, const char *name,
1.14 espie 303: unsigned int order, int hint)
1.5 espie 304: {
305: int toggle;
306: struct node *a;
307: size_t size;
308: char *str;
309:
310: toggle = 1;
311: a = NULL;
1.25 jasper 312:
1.5 espie 313: while ((str = fgetln(f, &size)) != NULL) {
314: char *sentinel;
315:
316: sentinel = str + size;
317: for (;;) {
318: char *e;
319:
1.22 deraadt 320: while (str < sentinel &&
321: isspace((unsigned char)*str))
1.5 espie 322: str++;
323: if (str == sentinel)
324: break;
1.22 deraadt 325: for (e = str;
326: e < sentinel && !isspace((unsigned char)*e); e++)
1.5 espie 327: continue;
328: if (toggle) {
329: a = node_lookup(h, str, e);
1.8 espie 330: if (a->order == NO_ORDER && hint)
1.7 espie 331: a->order = order++;
1.5 espie 332: } else {
333: struct node *b;
334:
335: b = node_lookup(h, str, e);
336: assert(a != NULL);
337: if (b != a) {
1.15 espie 338: if (reverse)
1.5 espie 339: insert_arc(b, a);
1.15 espie 340: else
1.5 espie 341: insert_arc(a, b);
342: }
343: }
344: toggle = !toggle;
345: str = e;
346: }
347: }
348: if (toggle == 0)
1.34 millert 349: errx(1, "odd number of node names in %s", name);
1.5 espie 350: if (!feof(f))
1.34 millert 351: err(1, "error reading %s", name);
1.7 espie 352: return order;
1.5 espie 353: }
1.1 deraadt 354:
1.7 espie 355: static unsigned int
1.15 espie 356: read_hints(FILE *f, struct ohash *h, int quiet, const char *name,
1.14 espie 357: unsigned int order)
1.5 espie 358: {
359: char *str;
360: size_t size;
361:
362: while ((str = fgetln(f, &size)) != NULL) {
363: char *sentinel;
364:
365: sentinel = str + size;
366: for (;;) {
367: char *e;
368: struct node *a;
369:
1.22 deraadt 370: while (str < sentinel && isspace((unsigned char)*str))
1.5 espie 371: str++;
372: if (str == sentinel)
373: break;
1.22 deraadt 374: for (e = str;
375: e < sentinel && !isspace((unsigned char)*e); e++)
1.5 espie 376: continue;
377: a = node_lookup(h, str, e);
1.7 espie 378: if (a->order != NO_ORDER) {
1.6 espie 379: if (!quiet)
380: warnx(
1.5 espie 381: "duplicate node %s in hints file %s",
382: a->k, name);
1.7 espie 383: } else
384: a->order = order++;
1.5 espie 385: str = e;
386: }
387: }
1.33 espie 388: if (!feof(f))
1.34 millert 389: err(1, "error reading %s", name);
1.7 espie 390: return order;
1.5 espie 391: }
392:
393:
394: /***
1.15 espie 395: *** Standard heap handling routines.
1.5 espie 396: ***/
397:
1.15 espie 398: static void
1.14 espie 399: heap_down(struct array *h, unsigned int i)
1.5 espie 400: {
401: unsigned int j;
402: struct node *swap;
403:
404: for (; (j=2*i+1) < h->entries; i = j) {
405: if (j+1 < h->entries && h->t[j+1]->order < h->t[j]->order)
406: j++;
407: if (h->t[i]->order <= h->t[j]->order)
408: break;
409: swap = h->t[i];
410: h->t[i] = h->t[j];
411: h->t[j] = swap;
1.1 deraadt 412: }
1.5 espie 413: }
414:
1.15 espie 415: static void
1.14 espie 416: heapify(struct array *h, int verbose)
1.5 espie 417: {
418: unsigned int i;
1.1 deraadt 419:
1.6 espie 420: for (i = h->entries; i != 0;) {
1.8 espie 421: if (h->t[--i]->order == NO_ORDER && verbose)
1.6 espie 422: warnx("node %s absent from hints file", h->t[i]->k);
423: heap_down(h, i);
424: }
1.5 espie 425: }
426:
427: #define DEQUEUE(h) ( hints_flag ? dequeue(h) : (h)->t[--(h)->entries] )
1.1 deraadt 428:
1.5 espie 429: static struct node *
1.14 espie 430: dequeue(struct array *h)
1.5 espie 431: {
432: struct node *n;
433:
434: if (h->entries == 0)
435: n = NULL;
436: else {
437: n = h->t[0];
438: if (--h->entries != 0) {
439: h->t[0] = h->t[h->entries];
440: heap_down(h, 0);
441: }
442: }
443: return n;
1.1 deraadt 444: }
1.25 jasper 445:
1.5 espie 446: #define ENQUEUE(h, n) do { \
447: if (hints_flag) \
448: enqueue((h), (n)); \
449: else \
450: (h)->t[(h)->entries++] = (n); \
451: } while(0);
452:
1.15 espie 453: static void
1.14 espie 454: enqueue(struct array *h, struct node *n)
1.5 espie 455: {
456: unsigned int i, j;
457: struct node *swap;
1.1 deraadt 458:
1.5 espie 459: h->t[h->entries++] = n;
460: for (i = h->entries-1; i > 0; i = j) {
461: j = (i-1)/2;
462: if (h->t[j]->order < h->t[i]->order)
463: break;
464: swap = h->t[j];
465: h->t[j] = h->t[i];
466: h->t[i] = swap;
467: }
468: }
1.1 deraadt 469:
1.8 espie 470: /* Nodes without order should not hinder direct dependencies.
1.15 espie 471: * Iterate until no nodes are left.
1.8 espie 472: */
473: static void
1.14 espie 474: make_transparent(struct ohash *hash)
1.8 espie 475: {
476: struct node *n;
477: unsigned int i;
478: struct link *l;
479: int adjusted;
480: int bad;
481: unsigned int min;
482:
483: /* first try to solve complete nodes */
484: do {
485: adjusted = 0;
486: bad = 0;
1.15 espie 487: for (n = ohash_first(hash, &i); n != NULL;
1.8 espie 488: n = ohash_next(hash, &i)) {
489: if (n->order == NO_ORDER) {
490: min = NO_ORDER;
491:
492: for (l = n->arcs; l != NULL; l = l->next) {
493: /* unsolved node -> delay resolution */
494: if (l->node->order == NO_ORDER) {
495: bad = 1;
496: break;
497: } else if (l->node->order < min)
498: min = l->node->order;
499: }
500: if (min < NO_ORDER && l == NULL) {
501: n->order = min;
502: adjusted = 1;
503: }
504: }
505: }
506:
507: } while (adjusted);
508:
509: /* then, if incomplete nodes are left, do them */
510: if (bad) do {
511: adjusted = 0;
1.15 espie 512: for (n = ohash_first(hash, &i); n != NULL;
1.8 espie 513: n = ohash_next(hash, &i))
514: if (n->order == NO_ORDER)
515: for (l = n->arcs; l != NULL; l = l->next)
516: if (l->node->order < n->order) {
517: n->order = l->node->order;
518: adjusted = 1;
519: }
520: } while (adjusted);
521: }
522:
1.5 espie 523:
524: /***
525: *** Search through hash array for nodes.
526: ***/
527:
528: /* Split nodes into unrefed nodes/live nodes. */
529: static void
1.14 espie 530: split_nodes(struct ohash *hash, struct array *heap, struct array *remaining)
1.1 deraadt 531: {
532:
1.5 espie 533: struct node *n;
534: unsigned int i;
535:
1.24 deraadt 536: heap->t = ereallocarray(NULL, ohash_entries(hash),
537: sizeof(struct node *));
538: remaining->t = ereallocarray(NULL, ohash_entries(hash),
539: sizeof(struct node *));
1.5 espie 540: heap->entries = 0;
541: remaining->entries = 0;
542:
543: for (n = ohash_first(hash, &i); n != NULL; n = ohash_next(hash, &i)) {
1.15 espie 544: if (n->refs == 0)
1.5 espie 545: heap->t[heap->entries++] = n;
546: else
1.9 espie 547: remaining->t[remaining->entries++] = n;
1.5 espie 548: }
1.1 deraadt 549: }
550:
1.5 espie 551: /* Good point to break a cycle: live node with as few refs as possible. */
552: static struct node *
1.14 espie 553: find_good_cycle_break(struct array *h)
1.5 espie 554: {
555: unsigned int i;
1.15 espie 556: unsigned int best;
557: struct node *u;
1.5 espie 558:
559: best = UINT_MAX;
560: u = NULL;
561:
562: assert(h->entries != 0);
563: for (i = 0; i < h->entries; i++) {
564: struct node *n = h->t[i];
1.25 jasper 565: /* No need to look further. */
1.5 espie 566: if (n->refs == 1)
567: return n;
568: if (n->refs != 0 && n->refs < best) {
569: best = n->refs;
570: u = n;
571: }
572: }
573: assert(u != NULL);
574: return u;
575: }
1.25 jasper 576:
1.5 espie 577: /* Retrieve the node with the smallest order. */
1.15 espie 578: static struct node *
1.14 espie 579: find_smallest_node(struct array *h)
1.5 espie 580: {
581: unsigned int i;
582: unsigned int best;
583: struct node *u;
584:
585: best = UINT_MAX;
586: u = NULL;
587:
588: assert(h->entries != 0);
589: for (i = 0; i < h->entries; i++) {
590: struct node *n = h->t[i];
591: if (n->refs != 0 && n->order < best) {
592: best = n->order;
593: u = n;
594: }
595: }
596: assert(u != NULL);
597: return u;
598: }
599:
600:
601: /***
602: *** Graph algorithms.
603: ***/
604:
1.15 espie 605: /* Explore the nodes reachable from i to find a cycle, store it in c.
1.10 espie 606: * This may fail. */
1.15 espie 607: static struct node *
1.14 espie 608: find_cycle_from(struct node *i, struct array *c)
1.5 espie 609: {
610: struct node *n;
611:
612: n = i;
613: /* XXX Previous cycle findings may have left this pointer non-null. */
614: i->from = NULL;
615:
616: for (;;) {
617: /* Note that all marks are reversed before this code exits. */
618: n->mark = 1;
1.15 espie 619: if (n->traverse)
1.5 espie 620: n->traverse = n->traverse->next;
621: else
622: n->traverse = n->arcs;
623: /* Skip over dead nodes. */
624: while (n->traverse && n->traverse->node->refs == 0)
625: n->traverse = n->traverse->next;
626: if (n->traverse) {
627: struct node *go = n->traverse->node;
628:
629: if (go->mark) {
1.10 espie 630: c->entries = 0;
631: for (; n != NULL && n != go; n = n->from) {
632: c->t[c->entries++] = n;
633: n->mark = 0;
1.1 deraadt 634: }
1.10 espie 635: for (; n != NULL; n = n->from)
636: n->mark = 0;
637: c->t[c->entries++] = go;
638: return go;
1.5 espie 639: } else {
640: go->from = n;
641: n = go;
1.1 deraadt 642: }
1.5 espie 643: } else {
644: n->mark = 0;
645: n = n->from;
1.15 espie 646: if (n == NULL)
1.10 espie 647: return NULL;
1.5 espie 648: }
649: }
650: }
1.1 deraadt 651:
1.5 espie 652: /* Find a live predecessor of node n. This is a slow routine, as it needs
653: * to go through the whole array, but it is not needed often.
654: */
655: static struct node *
1.14 espie 656: find_predecessor(struct array *a, struct node *n)
1.5 espie 657: {
658: unsigned int i;
659:
660: for (i = 0; i < a->entries; i++) {
661: struct node *m;
1.1 deraadt 662:
1.5 espie 663: m = a->t[i];
664: if (m->refs != 0) {
665: struct link *l;
666:
667: for (l = m->arcs; l != NULL; l = l->next)
668: if (l->node == n)
669: return m;
1.1 deraadt 670: }
1.5 espie 671: }
672: assert(1 == 0);
673: return NULL;
674: }
675:
676: /* Traverse all strongly connected components reachable from node n.
677: Start numbering them at o. Return the maximum order reached.
678: Update the largest cycle found so far.
679: */
1.15 espie 680: static unsigned int
1.14 espie 681: traverse_node(struct node *n, unsigned int o, struct array *c)
1.5 espie 682: {
683: unsigned int min, max;
684:
685: n->from = NULL;
686: min = o;
687: max = ++o;
688:
689: for (;;) {
690: n->mark = o;
691: if (DEBUG_TRAVERSE)
1.11 espie 692: printf("%s(%u) ", n->k, n->mark);
1.5 espie 693: /* Find next arc to explore. */
1.15 espie 694: if (n->traverse)
1.5 espie 695: n->traverse = n->traverse->next;
696: else
697: n->traverse = n->arcs;
698: /* Skip over dead nodes. */
699: while (n->traverse && n->traverse->node->refs == 0)
700: n->traverse = n->traverse->next;
701: /* If arc left. */
702: if (n->traverse) {
703: struct node *go;
704:
705: go = n->traverse->node;
1.15 espie 706: /* Optimisation: if go->mark < min, we already
1.5 espie 707: * visited this strongly-connected component in
708: * a previous pass. Hence, this can yield no new
709: * cycle. */
710:
711: /* Not part of the current path: go for it. */
712: if (go->mark == 0 || go->mark == min) {
713: go->from = n;
714: n = go;
715: o++;
716: if (o > max)
717: max = o;
718: /* Part of the current path: check cycle length. */
719: } else if (go->mark > min) {
720: if (DEBUG_TRAVERSE)
721: printf("%d\n", o - go->mark + 1);
722: if (o - go->mark + 1 > c->entries) {
723: struct node *t;
724: unsigned int i;
725:
726: c->entries = o - go->mark + 1;
727: i = 0;
728: c->t[i++] = go;
729: for (t = n; t != go; t = t->from)
730: c->t[i++] = t;
1.1 deraadt 731: }
1.5 espie 732: }
1.1 deraadt 733:
1.5 espie 734: /* No arc left: backtrack. */
735: } else {
736: n->mark = min;
737: n = n->from;
738: if (!n)
739: return max;
1.25 jasper 740: o--;
1.5 espie 741: }
1.1 deraadt 742: }
743: }
744:
1.5 espie 745: static void
1.14 espie 746: print_cycle(struct array *c)
1.5 espie 747: {
748: unsigned int i;
749:
750: /* Printing in reverse order, since cycle discoveries finds reverse
751: * edges. */
752: for (i = c->entries; i != 0;) {
753: i--;
754: warnx("%s", c->t[i]->k);
755: }
1.1 deraadt 756: }
757:
1.5 espie 758: static struct node *
1.14 espie 759: find_longest_cycle(struct array *h, struct array *c)
1.5 espie 760: {
761: unsigned int i;
762: unsigned int o;
763: unsigned int best;
764: struct node *n;
765: static int notfirst = 0;
766:
767: assert(h->entries != 0);
768:
769: /* No cycle found yet. */
770: c->entries = 0;
771:
772: /* Reset the set of marks, except the first time around. */
773: if (notfirst) {
1.15 espie 774: for (i = 0; i < h->entries; i++)
1.5 espie 775: h->t[i]->mark = 0;
776: } else
777: notfirst = 1;
778:
779: o = 0;
780:
781: /* Traverse the array. Each unmarked, live node heralds a
782: * new set of strongly connected components. */
783: for (i = 0; i < h->entries; i++) {
784: n = h->t[i];
785: if (n->refs != 0 && n->mark == 0) {
786: /* Each call to traverse_node uses a separate
787: * interval of numbers to mark nodes. */
788: o++;
789: o = traverse_node(n, o, c);
790: }
791: }
1.25 jasper 792:
1.5 espie 793: assert(c->entries != 0);
794: n = c->t[0];
795: best = n->refs;
796: for (i = 0; i < c->entries; i++) {
797: if (c->t[i]->refs < best) {
798: n = c->t[i];
799: best = n->refs;
800: }
801: }
802: return n;
803: }
1.1 deraadt 804:
1.29 espie 805: static struct node *
806: find_normal_cycle(struct array *h, struct array *c)
807: {
808: struct node *b, *n;
809:
810: if (hints_flag)
811: n = find_smallest_node(h);
812: else
813: n = find_good_cycle_break(h);
814: while ((b = find_cycle_from(n, c)) == NULL)
815: n = find_predecessor(h, n);
816: return b;
817: }
818:
1.5 espie 819:
820: #define plural(n) ((n) > 1 ? "s" : "")
1.1 deraadt 821:
1.29 espie 822: static void
823: parse_args(int argc, char *argv[], struct ohash *pairs)
1.5 espie 824: {
1.29 espie 825: int c;
1.7 espie 826: unsigned int order;
1.29 espie 827: int reverse_flag;
1.32 espie 828: const char **files;
1.31 espie 829: int i, j;
1.7 espie 830:
1.31 espie 831: i = 0;
1.5 espie 832:
1.15 espie 833: reverse_flag = quiet_flag = long_flag =
1.5 espie 834: warn_flag = hints_flag = verbose_flag = 0;
1.31 espie 835: /* argc is good enough, as we start at argv[1] */
836: files = ereallocarray(NULL, argc, sizeof (char *));
1.29 espie 837: while ((c = getopt(argc, argv, "h:flqrvw")) != -1) {
838: switch(c) {
1.31 espie 839: case 'h':
840: files[i++] = optarg;
1.29 espie 841: hints_flag = 1;
842: break;
843: /*FALLTHRU*/
844: case 'f':
845: hints_flag = 2;
846: break;
847: case 'l':
848: long_flag = 1;
849: break;
850: case 'q':
851: quiet_flag = 1;
852: break;
853: case 'r':
854: reverse_flag = 1;
855: break;
856: case 'v':
857: verbose_flag = 1;
858: break;
859: case 'w':
860: warn_flag = 1;
861: break;
862: default:
863: usage();
864: }
865: }
1.1 deraadt 866:
1.29 espie 867: argc -= optind;
868: argv += optind;
1.1 deraadt 869:
1.5 espie 870: switch(argc) {
1.31 espie 871: case 1:
872: files[i++] = argv[0];
873: break;
874: case 0:
875: break;
876: default:
877: usage();
878: }
879:
880: files[i] = NULL;
881:
1.35 ! espie 882: /* if (pledge("stdio rpath", files) == -1) */
! 883: if (pledge("stdio rpath", NULL) == -1)
1.32 espie 884: err(1, "pledge");
885:
1.31 espie 886: nodes_init(pairs);
887: order = 0;
888:
889: for (j = 0; j != i-argc; j++) {
890: FILE *f;
891:
892: f = fopen(files[j], "r");
893: if (f == NULL)
1.34 millert 894: err(1, "Can't open hint file %s", files[i]);
1.31 espie 895: order = read_hints(f, pairs, quiet_flag, files[i], order);
896: fclose(f);
897: }
898: free(files);
899:
900: if (argc == 1) {
1.5 espie 901: FILE *f;
902:
903: f = fopen(argv[0], "r");
904: if (f == NULL)
1.34 millert 905: err(1, "Can't open file %s", argv[0]);
1.29 espie 906: order = read_pairs(f, pairs, reverse_flag, argv[0], order,
1.8 espie 907: hints_flag == 2);
1.5 espie 908: fclose(f);
1.31 espie 909: } else {
1.29 espie 910: order = read_pairs(stdin, pairs, reverse_flag, "stdin",
1.8 espie 911: order, hints_flag == 2);
1.5 espie 912: }
1.32 espie 913:
914: if (pledge("stdio", NULL) == -1)
915: err(1, "pledge");
1.29 espie 916: }
1.1 deraadt 917:
1.29 espie 918: static int
919: tsort(struct ohash *pairs)
920: {
1.5 espie 921: struct array aux; /* Unrefed nodes/cycle reporting. */
922: struct array remaining;
923: unsigned int broken_arcs, broken_cycles;
924: unsigned int left;
925:
926: broken_arcs = 0;
927: broken_cycles = 0;
928:
1.8 espie 929: if (hints_flag)
1.29 espie 930: make_transparent(pairs);
931: split_nodes(pairs, &aux, &remaining);
932: ohash_delete(pairs);
1.5 espie 933:
934: if (hints_flag)
1.6 espie 935: heapify(&aux, verbose_flag);
1.5 espie 936:
937: left = remaining.entries + aux.entries;
938: while (left != 0) {
939:
940: /* Standard topological sort. */
941: while (aux.entries) {
942: struct link *l;
943: struct node *n;
944:
945: n = DEQUEUE(&aux);
946: printf("%s\n", n->k);
947: left--;
948: /* We can't free nodes, as we don't know which
949: * entry we can remove in the hash table. We
1.15 espie 950: * rely on refs == 0 to recognize live nodes.
1.5 espie 951: * Decrease ref count of live nodes, enter new
952: * candidates into the unrefed list. */
1.15 espie 953: for (l = n->arcs; l != NULL; l = l->next)
954: if (l->node->refs != 0 &&
1.5 espie 955: --l->node->refs == 0) {
956: ENQUEUE(&aux, l->node);
957: }
958: }
959: /* There are still cycles to break. */
960: if (left != 0) {
961: struct node *n;
962:
963: broken_cycles++;
964: /* XXX Simple cycle detection and long cycle
965: * detection are mutually exclusive. */
966:
1.29 espie 967: if (long_flag)
1.5 espie 968: n = find_longest_cycle(&remaining, &aux);
1.29 espie 969: else
970: n = find_normal_cycle(&remaining, &aux);
1.5 espie 971:
972: if (!quiet_flag) {
973: warnx("cycle in data");
974: print_cycle(&aux);
975: }
976:
977: if (verbose_flag)
978: warnx("%u edge%s broken", n->refs,
979: plural(n->refs));
980: broken_arcs += n->refs;
981: n->refs = 0;
982: /* Reinitialization, cycle reporting uses aux. */
983: aux.t[0] = n;
984: aux.entries = 1;
985: }
986: }
987: if (verbose_flag && broken_cycles != 0)
988: warnx("%u cycle%s broken, for a total of %u edge%s",
989: broken_cycles, plural(broken_cycles),
990: broken_arcs, plural(broken_arcs));
1.15 espie 991: if (warn_flag)
1.29 espie 992: return (broken_cycles < 256 ? broken_cycles : 255);
1.5 espie 993: else
1.34 millert 994: return (0);
1.29 espie 995: }
996:
997: int
998: main(int argc, char *argv[])
999: {
1000: struct ohash pairs;
1.30 deraadt 1001:
1002: if (pledge("stdio rpath", NULL) == -1)
1003: err(1, "pledge");
1.29 espie 1004:
1005: parse_args(argc, argv, &pairs);
1006: return tsort(&pairs);
1.1 deraadt 1007: }
1008:
1.5 espie 1009:
1010: extern char *__progname;
1011:
1012: static void
1.16 deraadt 1013: usage(void)
1.1 deraadt 1014: {
1.18 espie 1015: fprintf(stderr, "Usage: %s [-flqrvw] [-h file] [file]\n", __progname);
1.34 millert 1016: exit(1);
1.1 deraadt 1017: }