1 /* topo - topological sort Author: Kent Williams */
4 ** topo - perform a topological sort of the output of lorder.
6 ** Usage : topo [infile] [outfile]
8 ** Author: Kent Williams (williams@umaxc.weeg.uiowa.edu)
17 struct __v
*next
; /* link list node */
18 int indegree
, /* number of edges into this vertex */
19 visited
, /* depth-first search visited flag */
20 on_the_path
, /* used to find cycles */
21 has_a_cycle
; /* true if a cycle at this vertex */
22 struct __e
*out
; /* outgoing edges from this vertex */
23 char key
[1]; /* name of this vertex */
27 struct __e
*next
; /* link list node */
28 vertex
*v
; /* vertex to which this edge goes */
31 _PROTOTYPE(int main
, (int argc
, char **argv
));
32 _PROTOTYPE(void *xmalloc
, (size_t siz
));
33 _PROTOTYPE(edge
*new_edge
, (vertex
*v
));
34 _PROTOTYPE(char *copyupto
, (char *name
, char *buf
, int stop
));
35 _PROTOTYPE(int child_of
, (vertex
*parent
, vertex
*child
));
36 _PROTOTYPE(vertex
*add_v
, (char *s
));
37 _PROTOTYPE(void readin
, (void));
38 _PROTOTYPE(void pushname
, (char *s
));
39 _PROTOTYPE(char *popname
, (void));
40 _PROTOTYPE(void topo
, (void));
41 _PROTOTYPE(void print_cycle
, (vertex
*parent
, vertex
*child
));
42 _PROTOTYPE(void dfs
, (vertex
*v
));
43 _PROTOTYPE(void check_cycles
, (void));
46 ** xmalloc -- standard do or die malloc front end.
52 void *rval
= (void *)malloc(siz
);
54 fputs("Out of memory.\n",stderr
);
68 rval
= (edge
*)xmalloc(sizeof(edge
));
69 rval
->v
= v
; return rval
;
73 ** copyupto - copy until you see the stop character.
76 copyupto(name
,buf
,stop
)
79 while(*buf
!= '\0' && *buf
!= stop
)
82 while(*buf
!= '\0' && isspace(*buf
))
88 ** find out if the vertex child is a child of the vertex parent.
91 child_of(parent
,child
)
92 vertex
*parent
,*child
;
95 for(e
= parent
->out
; e
!= NULL
&& e
->v
!= child
; e
= e
->next
)
97 return e
== NULL
? 0 : 1;
103 ** add_v adds a vertex to the set if it's not already there.
113 ** go looking for this key in the vertex set.
115 for(last
= v
= vset
; v
!= NULL
&& strcmp(v
->key
,s
) != 0;
116 last
= v
, v
= v
->next
)
120 ** use the move-to-front heuristic to keep this from being
121 ** an O(N^2) algorithm.
124 last
->next
= v
->next
;
131 v
= (vertex
*)xmalloc(sizeof(vertex
) + strlen(s
));
145 ** readin -- read in the dependency pairs.
150 static char buf
[128];
151 static char name
[64];
153 vertex
*child
,*parent
;
155 while(fgets(buf
,sizeof(buf
),stdin
) != NULL
) {
156 bp
= buf
+ strlen(buf
);
157 if (bp
> buf
&& bp
[-1] == '\n') *--bp
= 0;
158 bp
= copyupto(name
,buf
,' ');
161 if(child
!= parent
&& !child_of(parent
,child
)) {
163 e
->next
= parent
->out
;
171 ** the topological sort produces names of modules in reverse of
172 ** the order we want them in, so use a stack to hold the names
173 ** until we get them all, then pop them off to print them.
175 struct name
{ struct name
*next
; char *s
; }
182 struct name
*x
= (struct name
*)xmalloc(sizeof(struct name
));
196 namelist
= namelist
->next
;
202 ** topo - do a topological sort of the dependency graph.
207 vertex
*outq
= NULL
,*tmp
;
208 #define insq(x) ((x->next = outq),(outq = x))
209 #define deq() ((tmp = outq),(outq = outq->next),tmp)
212 ** find all vertices that don't depend on any other vertices
213 ** Since it breaks the "next" links to insert x into the queue,
214 ** x->next is saved before insq, to resume the list traversal.
218 if(x
->indegree
== 0) {
226 ** for each vertex V with indegree of zero,
227 ** for each edge E from vertex V
228 ** subtract one from the indegree of the vertex V'
229 ** pointed to by E. If V' now has an indegree of zero,
230 ** add it to the set of vertices with indegree zero, and
231 ** push its name on the output stack.
233 while(outq
!= NULL
) {
237 if(--(e
->v
->indegree
) == 0) {
246 ** print the vertex names in opposite of the order they were
249 while(namelist
!= NULL
)
255 ** A cycle has been detected between parent and child.
256 ** Start with the child, and look at each of its edges for
259 ** We know a vertex is on the path from the child to the parent
260 ** because the depth-first search sets on_the_path true for each
264 print_cycle(parent
,child
)
265 vertex
*parent
, *child
;
270 for(x
= child
; x
!= parent
; ) {
272 for(e
= x
->out
; e
!= NULL
; e
= e
->next
) {
274 ** stop looking for the path at the first node found
275 ** that's on the path. Watch out for cycles already
276 ** detected, because if you follow an edge into a cycle,
277 ** you're stuck in an infinite loop!
279 if(e
->v
->on_the_path
&& !e
->v
->has_a_cycle
) {
286 ** print the name of the parent, and then names of each of the
287 ** vertices on the path from the child to the parent.
289 fprintf(stderr
,"%s\n",x
->key
);
290 while((s
= popname()) != NULL
)
291 fprintf(stderr
,"%s\n",s
);
295 ** depth first search for cycles in the dependency graph.
296 ** See "Introduction to Algorithms" by Udi Manber Addison-Wesley 1989
304 if(v
->visited
) /* If you've been here before, don't go again! */
307 v
->on_the_path
++; /* this node is on the path from the root. */
310 ** depth-first search all outgoing edges.
312 for(e
= v
->out
; e
!= NULL
; e
= e
->next
) {
315 if(e
->v
->on_the_path
) {
316 fprintf(stderr
,"cycle found between %s and %s\n",
326 ** check cycles starts the recursive depth-first search from
327 ** each vertex in vset.
333 for(v
= vset
; v
!= NULL
; v
= v
->next
)
344 if(argc
> 1 && freopen(argv
[1],"r",stdin
) == NULL
) {
348 if(argc
> 2 && freopen(argv
[2],"w",stdout
) == NULL
) {