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