357 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			357 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* topo - topological sort		Author: Kent Williams */
 | |
| 
 | |
| /*
 | |
| ** topo - perform a topological sort of the output of lorder.
 | |
| **
 | |
| ** Usage : topo [infile] [outfile]
 | |
| **
 | |
| ** Author: Kent Williams (williams@umaxc.weeg.uiowa.edu)
 | |
| */
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| typedef struct __v {
 | |
|     struct __v *next;   /* link list node                   */
 | |
|     int indegree,       /* number of edges into this vertex */
 | |
|         visited,        /* depth-first search visited flag  */
 | |
|         on_the_path,    /* used to find cycles              */
 | |
|         has_a_cycle;    /* true if a cycle at this vertex   */
 | |
|     struct __e *out;    /* outgoing edges from this vertex  */
 | |
|     char key[1];        /* name of this vertex              */
 | |
| } vertex;
 | |
| 
 | |
| typedef struct __e {
 | |
|     struct __e *next;   /* link list node                   */
 | |
|     vertex *v;          /* vertex to which this edge goes   */
 | |
| } edge;
 | |
| 
 | |
| _PROTOTYPE(int main, (int argc, char **argv));
 | |
| _PROTOTYPE(void *xmalloc, (size_t siz));
 | |
| _PROTOTYPE(edge *new_edge, (vertex *v));
 | |
| _PROTOTYPE(char *copyupto, (char *name, char *buf, int stop));
 | |
| _PROTOTYPE(int child_of, (vertex *parent, vertex *child));
 | |
| _PROTOTYPE(vertex *add_v, (char *s));
 | |
| _PROTOTYPE(void readin, (void));
 | |
| _PROTOTYPE(void pushname, (char *s));
 | |
| _PROTOTYPE(char *popname, (void));
 | |
| _PROTOTYPE(void topo, (void));
 | |
| _PROTOTYPE(void print_cycle, (vertex *parent, vertex *child));
 | |
| _PROTOTYPE(void dfs, (vertex *v));
 | |
| _PROTOTYPE(void check_cycles, (void));
 | |
| 
 | |
| /*
 | |
| ** xmalloc -- standard do or die malloc front end.
 | |
| */
 | |
| void *
 | |
| xmalloc(siz)
 | |
| size_t siz;
 | |
| {
 | |
|     void *rval = (void *)malloc(siz);
 | |
|     if(rval == NULL) {
 | |
|         fputs("Out of memory.\n",stderr);
 | |
|         exit(1);
 | |
|     }
 | |
|     return rval;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** edge allocater.
 | |
| */
 | |
| edge *
 | |
| new_edge(v)
 | |
| vertex *v;
 | |
| {
 | |
|     edge *rval;
 | |
|     rval = (edge *)xmalloc(sizeof(edge));
 | |
|     rval->v = v; return rval;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** copyupto - copy until you see the stop character.
 | |
| */
 | |
| char *
 | |
| copyupto(name,buf,stop)
 | |
| char *name,*buf,stop;
 | |
| {
 | |
|     while(*buf != '\0' && *buf != stop)
 | |
|         *name++ = *buf++;
 | |
|     *name = '\0';
 | |
|     while(*buf != '\0' && isspace(*buf))
 | |
|         buf++;
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** find out if the vertex child is a child of the vertex parent.
 | |
| */
 | |
| int
 | |
| child_of(parent,child)
 | |
| vertex *parent,*child;
 | |
| {
 | |
|     edge *e;
 | |
|     for(e = parent->out; e != NULL && e->v != child; e = e->next)
 | |
|         ;
 | |
|     return e == NULL ? 0 : 1;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** the vertex set.
 | |
| **
 | |
| ** add_v adds a vertex to the set if it's not already there.
 | |
| */
 | |
| vertex *vset = NULL;
 | |
| 
 | |
| vertex *
 | |
| add_v(s)
 | |
| char *s;
 | |
| {
 | |
|     vertex *v,*last;
 | |
|     /*
 | |
|     ** go looking for this key in the vertex set.
 | |
|     */
 | |
|     for(last = v = vset; v != NULL && strcmp(v->key,s) != 0;
 | |
|         last = v, v = v->next)
 | |
|         ;
 | |
|     if(v != NULL) {
 | |
|         /*
 | |
|         ** use the move-to-front heuristic to keep this from being
 | |
|         ** an O(N^2) algorithm.
 | |
|         */
 | |
|         if(last != vset) {
 | |
|             last->next = v->next;
 | |
|             v->next = vset;
 | |
|             vset = v;
 | |
|         }
 | |
|         return v;
 | |
|     }
 | |
| 
 | |
|     v = (vertex *)xmalloc(sizeof(vertex) + strlen(s));
 | |
| 
 | |
|     v->out = NULL;
 | |
|     strcpy(v->key,s);
 | |
|     v->indegree =
 | |
|     v->on_the_path =
 | |
|     v->has_a_cycle =
 | |
|     v->visited = 0;
 | |
|     v->next = vset;
 | |
|     vset = v;
 | |
|     return v;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** readin -- read in the dependency pairs.
 | |
| */
 | |
| void
 | |
| readin()
 | |
| {
 | |
|     static char buf[128];
 | |
|     static char name[64];
 | |
|     char *bp;
 | |
|     vertex *child,*parent;
 | |
|     edge *e;
 | |
|     while(fgets(buf,sizeof(buf),stdin) != NULL) {
 | |
| 	bp = buf + strlen(buf);
 | |
| 	if (bp > buf && bp[-1] == '\n') *--bp = 0;
 | |
|         bp = copyupto(name,buf,' ');
 | |
|         child = add_v(name);
 | |
|         parent = add_v(bp);
 | |
|         if(child != parent && !child_of(parent,child)) {
 | |
|             e = new_edge(child);
 | |
|             e->next = parent->out;
 | |
|             parent->out = e;
 | |
|             child->indegree++;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** the topological sort produces names of modules in reverse of
 | |
| ** the order we want them in, so use a stack to hold the names
 | |
| ** until we get them all, then pop them off to print them.
 | |
| */
 | |
| struct name { struct name *next; char *s; }
 | |
| *namelist = NULL;
 | |
| 
 | |
| void
 | |
| pushname(s)
 | |
| char *s;
 | |
| {
 | |
|     struct name *x = (struct name *)xmalloc(sizeof(struct name));
 | |
|     x->s = s;
 | |
|     x->next = namelist;
 | |
|     namelist = x;
 | |
| }
 | |
| 
 | |
| char *
 | |
| popname() {
 | |
|     char *rval;
 | |
|     struct name *tmp;
 | |
|     if(namelist == NULL)
 | |
|         return NULL;
 | |
|     tmp = namelist;
 | |
|     rval = namelist->s;
 | |
|     namelist = namelist->next;
 | |
|     free(tmp);
 | |
|     return rval;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** topo - do a topological sort of the dependency graph.
 | |
| */
 | |
| void topo() {
 | |
|     vertex *x = vset,*n;
 | |
|     edge *e;
 | |
|     vertex *outq = NULL,*tmp;
 | |
| #define insq(x) ((x->next = outq),(outq = x))
 | |
| #define deq() ((tmp = outq),(outq = outq->next),tmp)
 | |
| 
 | |
|     /*
 | |
|     ** find all vertices that don't depend on any other vertices
 | |
|     ** Since it breaks the "next" links to insert x into the queue,
 | |
|     ** x->next is saved before insq, to resume the list traversal.
 | |
|     */
 | |
|     while (x != NULL) {
 | |
| 	n = x->next;
 | |
|         if(x->indegree == 0) {
 | |
|             insq(x);
 | |
|             pushname(x->key);       
 | |
|         }
 | |
| 	x = n;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** for each vertex V with indegree of zero,
 | |
|     **     for each edge E from vertex V
 | |
|     **        subtract one from the indegree of the vertex V'
 | |
|     **        pointed to by E.  If V' now has an indegree of zero,
 | |
|     **        add it to the set of vertices with indegree zero, and
 | |
|     **        push its name on the output stack.
 | |
|     */
 | |
|     while(outq != NULL) {
 | |
|         x = deq();
 | |
|         e = x->out;
 | |
|         while(e != NULL) {
 | |
|             if(--(e->v->indegree) == 0) {
 | |
|                 insq(e->v);
 | |
|                 pushname(e->v->key);
 | |
|             }
 | |
|             e = e->next;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|     ** print the vertex names in opposite of the order they were
 | |
|     ** encountered.
 | |
|     */
 | |
|     while(namelist != NULL)
 | |
|         puts(popname());
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** print_cycle --
 | |
| ** A cycle has been detected between parent and child.
 | |
| ** Start with the child, and look at each of its edges for
 | |
| ** the parent.
 | |
| **
 | |
| ** We know a vertex is on the path from the child to the parent
 | |
| ** because the depth-first search sets on_the_path true for each
 | |
| ** vertex it visits.
 | |
| */
 | |
| void
 | |
| print_cycle(parent,child)
 | |
| vertex *parent, *child;
 | |
| {
 | |
|     char *s;
 | |
|     vertex *x;
 | |
|     edge *e;
 | |
|     for(x = child; x != parent; ) {
 | |
|         pushname(x->key);
 | |
|         for(e = x->out; e != NULL; e = e->next) {
 | |
|             /*
 | |
|             ** stop looking for the path at the first node found
 | |
|             ** that's on the path.  Watch out for cycles already
 | |
|             ** detected, because if you follow an edge into a cycle,
 | |
|             ** you're stuck in an infinite loop!
 | |
|             */
 | |
|             if(e->v->on_the_path && !e->v->has_a_cycle) {
 | |
|                 x = e->v;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /*
 | |
|     ** print the name of the parent, and then names of each of the
 | |
|     ** vertices on the path from the child to the parent.
 | |
|     */
 | |
|     fprintf(stderr,"%s\n",x->key);
 | |
|     while((s = popname()) != NULL)
 | |
|         fprintf(stderr,"%s\n",s);
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** depth first search for cycles in the dependency graph.
 | |
| ** See "Introduction to Algorithms" by Udi Manber Addison-Wesley 1989
 | |
| */
 | |
| void
 | |
| dfs(v)
 | |
| vertex *v;
 | |
| {
 | |
|     edge *e;
 | |
| 
 | |
|     if(v->visited)      /* If you've been here before, don't go again! */
 | |
|         return;
 | |
|     v->visited++;
 | |
|     v->on_the_path++;   /* this node is on the path from the root. */
 | |
| 
 | |
|     /*
 | |
|     ** depth-first search all outgoing edges.
 | |
|     */
 | |
|     for(e = v->out; e != NULL; e = e->next) {
 | |
|         if(!e->v->visited)
 | |
|             dfs(e->v);
 | |
|         if(e->v->on_the_path) {
 | |
|             fprintf(stderr,"cycle found between %s and %s\n",
 | |
|                 v->key,e->v->key);
 | |
|             print_cycle(v,e->v);
 | |
|             v->has_a_cycle++;
 | |
|         }
 | |
|     }
 | |
|     v->on_the_path = 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** check cycles starts the recursive depth-first search from
 | |
| ** each vertex in vset.
 | |
| */
 | |
| void
 | |
| check_cycles()
 | |
| {
 | |
|     vertex *v;
 | |
|     for(v = vset; v != NULL; v = v->next)
 | |
|         dfs(v);
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** main program.
 | |
| */
 | |
| int main(argc,argv)
 | |
| int argc;
 | |
| char **argv;
 | |
| {
 | |
|     if(argc > 1 && freopen(argv[1],"r",stdin) == NULL) {
 | |
|         perror(argv[1]);
 | |
|         exit(0);
 | |
|     }
 | |
|     if(argc > 2 && freopen(argv[2],"w",stdout) == NULL) {
 | |
|         perror(argv[2]);
 | |
|         exit(0);
 | |
|     }
 | |
|     readin();
 | |
|     check_cycles();
 | |
|     topo();
 | |
|     return(0);
 | |
| }
 | 
