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