blob: d093df8af9f2aba5353d8d75f63881548ccc9256 [file] [log] [blame]
Mattias Andréeb44d4d82016-02-17 01:17:33 +01001/* See LICENSE file for copyright and license details. */
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <ctype.h>
6
7#include "util.h"
8
sin9a2b8d32016-02-24 15:56:39 +00009enum { WHITE = 0, GREY, BLACK };
Mattias Andréeb44d4d82016-02-17 01:17:33 +010010
11struct vertex;
12
sin1e81e212016-02-17 08:27:41 +000013struct edge {
Mattias Andréeb44d4d82016-02-17 01:17:33 +010014 struct vertex *to;
15 struct edge *next;
16};
17
sin1e81e212016-02-17 08:27:41 +000018struct vertex {
Mattias Andréeb44d4d82016-02-17 01:17:33 +010019 char *name;
20 struct vertex *next;
21 struct edge edges;
22 size_t in_edges;
23 int colour;
24};
25
26static struct vertex graph;
27
28static void
29find_vertex(const char *name, struct vertex **it, struct vertex **prev)
30{
31 for (*prev = &graph; (*it = (*prev)->next); *prev = *it) {
32 int cmp = strcmp(name, (*it)->name);
33 if (cmp > 0)
34 continue;
35 if (cmp < 0)
36 *it = 0;
37 return;
38 }
39}
40
41static void
sin9a2b8d32016-02-24 15:56:39 +000042find_edge(struct vertex *from, const char *to, struct edge **it, struct edge **prev)
Mattias Andréeb44d4d82016-02-17 01:17:33 +010043{
44 for (*prev = &(from->edges); (*it = (*prev)->next); *prev = *it) {
45 int cmp = strcmp(to, (*it)->to->name);
46 if (cmp > 0)
47 continue;
48 if (cmp < 0)
49 *it = 0;
50 return;
51 }
52}
53
54static struct vertex *
55add_vertex(char *name)
56{
57 struct vertex *vertex;
58 struct vertex *prev;
59
60 find_vertex(name, &vertex, &prev);
61 if (vertex)
62 return vertex;
63
FRIGN102baab2016-02-24 16:26:29 +010064 vertex = encalloc(2, 1, sizeof(*vertex));
Mattias Andréeb44d4d82016-02-17 01:17:33 +010065 vertex->name = name;
66 vertex->next = prev->next;
67 prev->next = vertex;
68
69 return vertex;
70}
71
72static struct edge *
sin9a2b8d32016-02-24 15:56:39 +000073add_edge(struct vertex *from, struct vertex* to)
Mattias Andréeb44d4d82016-02-17 01:17:33 +010074{
75 struct edge *edge;
76 struct edge *prev;
77
78 find_edge(from, to->name, &edge, &prev);
79 if (edge)
80 return edge;
81
FRIGN102baab2016-02-24 16:26:29 +010082 edge = encalloc(2, 1, sizeof(*edge));
Mattias Andréeb44d4d82016-02-17 01:17:33 +010083 edge->to = to;
84 edge->next = prev->next;
85 prev->next = edge;
86 to->in_edges += 1;
87
88 return edge;
89}
90
91static void
92load_graph(FILE *fp)
93{
94#define SKIP(VAR, START, FUNC) for (VAR = START; FUNC(*VAR) && *VAR; VAR++)
95#define TOKEN_END(P) do { if (*P) *P++ = 0; else P = 0; } while (0)
96
97 char *line = 0;
98 size_t size = 0;
99 ssize_t len;
100 char *p;
101 char *name;
102 struct vertex *from = 0;
103
104 while ((len = getline(&line, &size, fp)) != -1) {
sin9a2b8d32016-02-24 15:56:39 +0000105 if (line[len - 1] == '\n')
106 line[--len] = 0;
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100107 for (p = line; p;) {
108 SKIP(name, p, isspace);
109 if (!*name)
110 break;
111 SKIP(p, name, !isspace);
112 TOKEN_END(p);
113 if (!from) {
FRIGN102baab2016-02-24 16:26:29 +0100114 from = add_vertex(enstrdup(2, name));
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100115 } else if (strcmp(from->name, name)) {
FRIGN102baab2016-02-24 16:26:29 +0100116 add_edge(from, add_vertex(enstrdup(2, name)));
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100117 from = 0;
118 } else {
119 from = 0;
120 }
121 }
122 }
123
124 free(line);
125
126 if (from)
FRIGN102baab2016-02-24 16:26:29 +0100127 enprintf(2, "odd number of tokens in input\n");
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100128}
129
130static int
131sort_graph_visit(struct vertex *u)
132{
133 struct edge *e = &(u->edges);
134 struct vertex *v;
135 int r = 0;
136 u->colour = GREY;
137 printf("%s\n", u->name);
138 while ((e = e->next)) {
139 v = e->to;
140 if (v->colour == WHITE) {
141 v->in_edges -= 1;
142 if (v->in_edges == 0)
143 r |= sort_graph_visit(v);
144 } else if (v->colour == GREY) {
145 r = 1;
146 fprintf(stderr, "%s: loop detected between %s and %s\n",
147 argv0, u->name, v->name);
148 }
149 }
150 u->colour = BLACK;
151 return r;
152}
153
154static int
155sort_graph(void)
156{
157 struct vertex *u, *prev;
158 int r = 0;
159 size_t in_edges;
160 for (in_edges = 0; graph.next; in_edges++) {
161 for (prev = &graph; (u = prev->next); prev = u) {
162 if (u->colour != WHITE)
163 goto unlist;
164 if (u->in_edges > in_edges)
165 continue;
166 r |= sort_graph_visit(u);
167 unlist:
168 prev->next = u->next;
169 u = prev;
170 }
171 }
172 return r;
173}
174
175static void
176usage(void)
177{
FRIGN102baab2016-02-24 16:26:29 +0100178 enprintf(2, "usage: %s [file]\n", argv0);
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100179}
180
181int
182main(int argc, char *argv[])
183{
184 FILE *fp = stdin;
185 const char *fn = "<stdin>";
186 int ret = 0;
187
188 ARGBEGIN {
189 default:
190 usage();
191 } ARGEND;
192
193 if (argc > 1)
194 usage();
195 if (argc && strcmp(*argv, "-"))
196 if (!(fp = fopen(fn = *argv, "r")))
FRIGN102baab2016-02-24 16:26:29 +0100197 enprintf(2, "fopen %s:", *argv);
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100198
199 memset(&graph, 0, sizeof(graph));
200 load_graph(fp);
FRIGN102baab2016-02-24 16:26:29 +0100201 enfshut(2, fp, fn);
Mattias Andréeb44d4d82016-02-17 01:17:33 +0100202
203 ret = sort_graph();
204
205 if (fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>"))
206 ret = 2;
207
208 return ret;
209}
OSZAR »