fix installation
[vlock.git] / src / tsort.c
blobb2b22c7a54dba8cd1e18f965a4a0e52445095ac1
1 /* tsort.c -- topological sort for vlock, the VT locking program for linux
3 * This program is copyright (C) 2007 Frank Benkstein, and is free
4 * software which is freely distributable under the terms of the
5 * GNU General Public License version 2, included as the file COPYING in this
6 * distribution. It is NOT public domain software, and any
7 * redistribution not permitted by the GNU General Public License is
8 * expressly forbidden without prior written permission from
9 * the author.
13 #include <stdlib.h>
15 #include "list.h"
17 #include "tsort.h"
19 /* Get the zeros of the graph, i.e. nodes with no incoming edges. */
20 static struct list *get_zeros(struct list *nodes, struct list *edges)
22 struct list *zeros = list_copy(nodes);
24 list_for_each(edges, edge_item) {
25 struct edge *e = edge_item->data;
26 list_delete(zeros, e->successor);
29 return zeros;
32 /* Check if the given node is a zero. */
33 static bool is_zero(void *node, struct list *edges)
35 list_for_each(edges, edge_item) {
36 struct edge *e = edge_item->data;
38 if (e->successor == node)
39 return false;
42 return true;
45 /* For the given directed graph, generate a topological sort of the nodes.
47 * Sorts the list and deletes all edges. If there are circles found in the
48 * graph or there are edges that have no corresponding nodes the erroneous
49 * edges are left.
51 * The algorithm is taken from the Wikipedia:
53 * http://en.wikipedia.org/w/index.php?title=Topological_sorting&oldid=153157450#Algorithms
56 void tsort(struct list *nodes, struct list *edges)
58 struct list *sorted_nodes = list_new();
59 /* Retrieve all zeros. */
60 struct list *zeros = get_zeros(nodes, edges);
62 /* While the list of zeros is not empty, take the first zero and remove it
63 * and ... */
64 list_delete_for_each(zeros, zero_item) {
65 void *zero = zero_item->data;
66 /* ... add it to the list of sorted nodes. */
67 list_append(sorted_nodes, zero);
69 /* Then look at each edge ... */
70 list_for_each_manual(edges, edge_item) {
71 struct edge *e = edge_item->data;
73 /* ... that has this zero as its predecessor ... */
74 if (e->predecessor == zero) {
75 /* ... and remove it. */
76 edge_item = list_delete_item(edges, edge_item);
78 /* If the successor has become a zero now ... */
79 if (is_zero(e->successor, edges))
80 /* ... add it to the list of zeros. */
81 list_append(zeros, e->successor);
83 free(e);
84 } else {
85 edge_item = edge_item->next;
90 /* If all edges were deleted the algorithm was successful. */
91 if (list_is_empty(edges)) {
92 /* Switch the given list of nodes for the list of sorted nodes. */
93 struct list_item *first = sorted_nodes->first;
94 struct list_item *last = sorted_nodes->last;
96 sorted_nodes->first = nodes->first;
97 sorted_nodes->last = nodes->last;
99 nodes->first = first;
100 nodes->last = last;
103 list_free(sorted_nodes);