BSD 3 development
[unix-history] / usr / src / cmd / tsort.c
CommitLineData
9c79dca0
BJ
1/* topological sort
2 * input is sequence of pairs of items (blank-free strings)
3 * nonidentical pair is a directed edge in graph
4 * identical pair merely indicates presence of node
5 * output is ordered list of items consistent with
6 * the partial ordering specified by the graph
7*/
8#include "stdio.h"
9
10/* the nodelist always has an empty element at the end to
11 * make it easy to grow in natural order
12 * states of the "live" field:*/
13#define DEAD 0 /* already printed*/
14#define LIVE 1 /* not yet printed*/
15#define VISITED 2 /*used only in findloop()*/
16
17struct nodelist {
18 struct nodelist *nextnode;
19 struct predlist *inedges;
20 char *name;
21 int live;
22} firstnode = {NULL, NULL, NULL, DEAD};
23
24/* a predecessor list tells all the immediate
25 * predecessors of a given node
26*/
27struct predlist {
28 struct predlist *nextpred;
29 struct nodelist *pred;
30};
31
32struct nodelist *index();
33struct nodelist *findloop();
34struct nodelist *mark();
35char *malloc();
36char *empty = "";
37
38/* the first for loop reads in the graph,
39 * the second prints out the ordering
40*/
41main(argc,argv)
42char **argv;
43{
44 register struct predlist *t;
45 FILE *input = stdin;
46 register struct nodelist *i, *j;
47 int x;
48 char precedes[50], follows[50];
49 if(argc>1) {
50 input = fopen(argv[1],"r");
51 if(input==NULL)
52 error("cannot open ", argv[1]);
53 }
54 for(;;) {
55 x = fscanf(input,"%s%s",precedes, follows);
56 if(x==EOF)
57 break;
58 if(x!=2)
59 error("odd data",empty);
60 i = index(precedes);
61 j = index(follows);
62 if(i==j||present(i,j))
63 continue;
64 t = (struct predlist *)malloc(sizeof(struct predlist));
65 t->nextpred = j->inedges;
66 t->pred = i;
67 j->inedges = t;
68 }
69 for(;;) {
70 x = 0; /*anything LIVE on this sweep?*/
71 for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode) {
72 if(i->live==LIVE) {
73 x = 1;
74 if(!anypred(i))
75 break;
76 }
77 }
78 if(x==0)
79 break;
80 if(i->nextnode==NULL)
81 i = findloop();
82 printf("%s\n",i->name);
83 i->live = DEAD;
84 }
85}
86
87/* is i present on j's predecessor list?
88*/
89present(i,j)
90struct nodelist *i, *j;
91{
92 register struct predlist *t;
93 for(t=j->inedges; t!=NULL; t=t->nextpred)
94 if(t->pred==i)
95 return(1);
96 return(0);
97}
98
99/* is there any live predecessor for i?
100*/
101anypred(i)
102struct nodelist *i;
103{
104 register struct predlist *t;
105 for(t=i->inedges; t!=NULL; t=t->nextpred)
106 if(t->pred->live==LIVE)
107 return(1);
108 return(0);
109}
110
111/* turn a string into a node pointer
112*/
113struct nodelist *
114index(s)
115register char *s;
116{
117 register struct nodelist *i;
118 register char *t;
119 for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
120 if(cmp(s,i->name))
121 return(i);
122 for(t=s; *t; t++) ;
123 t = malloc((unsigned)(t+1-s));
124 i->nextnode = (struct nodelist *)malloc(sizeof(struct nodelist));
125 if(i->nextnode==NULL||t==NULL)
126 error("too many items",empty);
127 i->name = t;
128 i->live = LIVE;
129 i->nextnode->nextnode = NULL;
130 i->nextnode->inedges = NULL;
131 i->nextnode->live = DEAD;
132 while(*t++ = *s++);
133 return(i);
134}
135
136cmp(s,t)
137register char *s, *t;
138{
139 while(*s==*t) {
140 if(*s==0)
141 return(1);
142 s++;
143 t++;
144 }
145 return(0);
146}
147
148error(s,t)
149char *s, *t;
150{
151 note(s,t);
152 exit(1);
153}
154
155note(s,t)
156char *s,*t;
157{
158 fprintf(stderr,"tsort: %s%s\n",s,t);
159}
160
161/* given that there is a cycle, find some
162 * node in it
163*/
164struct nodelist *
165findloop()
166{
167 register struct nodelist *i, *j;
168 for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
169 if(i->live==LIVE)
170 break;
171 note("cycle in data",empty);
172 i = mark(i);
173 if(i==NULL)
174 error("program error",empty);
175 for(j= &firstnode; j->nextnode!=NULL; j=j->nextnode)
176 if(j->live==VISITED)
177 j->live = LIVE;
178 return(i);
179}
180
181/* depth-first search of LIVE predecessors
182 * to find some element of a cycle;
183 * VISITED is a temporary state recording the
184 * visits of the search
185*/
186struct nodelist *
187mark(i)
188register struct nodelist *i;
189{
190 register struct nodelist *j;
191 register struct predlist *t;
192 if(i->live==DEAD)
193 return(NULL);
194 if(i->live==VISITED)
195 return(i);
196 i->live = VISITED;
197 for(t=i->inedges; t!=NULL; t=t->nextpred) {
198 j = mark(t->pred);
199 if(j!=NULL) {
200 note(i->name,empty);
201 return(j);
202 }
203 }
204 return(NULL);
205}