Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 1 | /* 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 | |
sin | 9a2b8d3 | 2016-02-24 15:56:39 +0000 | [diff] [blame] | 9 | enum { WHITE = 0, GREY, BLACK }; |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 10 | |
| 11 | struct vertex; |
| 12 | |
sin | 1e81e21 | 2016-02-17 08:27:41 +0000 | [diff] [blame] | 13 | struct edge { |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 14 | struct vertex *to; |
| 15 | struct edge *next; |
| 16 | }; |
| 17 | |
sin | 1e81e21 | 2016-02-17 08:27:41 +0000 | [diff] [blame] | 18 | struct vertex { |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 19 | char *name; |
| 20 | struct vertex *next; |
| 21 | struct edge edges; |
| 22 | size_t in_edges; |
| 23 | int colour; |
| 24 | }; |
| 25 | |
| 26 | static struct vertex graph; |
| 27 | |
| 28 | static void |
| 29 | find_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 | |
| 41 | static void |
sin | 9a2b8d3 | 2016-02-24 15:56:39 +0000 | [diff] [blame] | 42 | find_edge(struct vertex *from, const char *to, struct edge **it, struct edge **prev) |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 43 | { |
| 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 | |
| 54 | static struct vertex * |
| 55 | add_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 | |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 64 | vertex = encalloc(2, 1, sizeof(*vertex)); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 65 | vertex->name = name; |
| 66 | vertex->next = prev->next; |
| 67 | prev->next = vertex; |
| 68 | |
| 69 | return vertex; |
| 70 | } |
| 71 | |
| 72 | static struct edge * |
sin | 9a2b8d3 | 2016-02-24 15:56:39 +0000 | [diff] [blame] | 73 | add_edge(struct vertex *from, struct vertex* to) |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 74 | { |
| 75 | struct edge *edge; |
| 76 | struct edge *prev; |
| 77 | |
| 78 | find_edge(from, to->name, &edge, &prev); |
| 79 | if (edge) |
| 80 | return edge; |
| 81 | |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 82 | edge = encalloc(2, 1, sizeof(*edge)); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 83 | edge->to = to; |
| 84 | edge->next = prev->next; |
| 85 | prev->next = edge; |
| 86 | to->in_edges += 1; |
| 87 | |
| 88 | return edge; |
| 89 | } |
| 90 | |
| 91 | static void |
| 92 | load_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) { |
sin | 9a2b8d3 | 2016-02-24 15:56:39 +0000 | [diff] [blame] | 105 | if (line[len - 1] == '\n') |
| 106 | line[--len] = 0; |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 107 | 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) { |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 114 | from = add_vertex(enstrdup(2, name)); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 115 | } else if (strcmp(from->name, name)) { |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 116 | add_edge(from, add_vertex(enstrdup(2, name))); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 117 | from = 0; |
| 118 | } else { |
| 119 | from = 0; |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | free(line); |
| 125 | |
| 126 | if (from) |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 127 | enprintf(2, "odd number of tokens in input\n"); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | static int |
| 131 | sort_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 | |
| 154 | static int |
| 155 | sort_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 | |
| 175 | static void |
| 176 | usage(void) |
| 177 | { |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 178 | enprintf(2, "usage: %s [file]\n", argv0); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | int |
| 182 | main(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"))) |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 197 | enprintf(2, "fopen %s:", *argv); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 198 | |
| 199 | memset(&graph, 0, sizeof(graph)); |
| 200 | load_graph(fp); |
FRIGN | 102baab | 2016-02-24 16:26:29 +0100 | [diff] [blame] | 201 | enfshut(2, fp, fn); |
Mattias Andrée | b44d4d8 | 2016-02-17 01:17:33 +0100 | [diff] [blame] | 202 | |
| 203 | ret = sort_graph(); |
| 204 | |
| 205 | if (fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>")) |
| 206 | ret = 2; |
| 207 | |
| 208 | return ret; |
| 209 | } |