1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#include "libbb.h"
31#include "common_bufsiz.h"
32
33struct node {
34 unsigned in_count;
35 unsigned out_count;
36 struct node **out;
37 char name[1];
38};
39
40struct globals {
41 struct node **nodes;
42 unsigned nodes_len;
43};
44#define G (*(struct globals*)bb_common_bufsiz1)
45#define INIT_G() do { \
46 setup_common_bufsiz(); \
47 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
48 G.nodes = NULL; \
49 G.nodes_len = 0; \
50} while (0)
51
52static struct node *
53get_node(const char *name)
54{
55 struct node *n;
56 unsigned a = 0;
57 unsigned b = G.nodes_len;
58
59
60 while (a != b) {
61 unsigned m = (a + b) / 2;
62 int cmp = strcmp(name, G.nodes[m]->name);
63 if (cmp == 0)
64 return G.nodes[m];
65 if (cmp < 0) {
66 b = m;
67 } else {
68 a = m + 1;
69 }
70 }
71
72
73 n = xzalloc(sizeof(*n) + strlen(name));
74
75
76
77 strcpy(n->name, name);
78
79
80 G.nodes = xrealloc(G.nodes, (G.nodes_len + 1) * sizeof(*G.nodes));
81 memmove(&G.nodes[a + 1], &G.nodes[a],
82 (G.nodes_len - a) * sizeof(*G.nodes));
83 G.nodes[a] = n;
84 G.nodes_len++;
85 return n;
86}
87
88static void
89add_edge(struct node *a, struct node *b)
90{
91 a->out = xrealloc_vector(a->out, 6, a->out_count);
92 a->out[a->out_count++] = b;
93 b->in_count++;
94}
95
96int tsort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
97int tsort_main(int argc UNUSED_PARAM, char **argv)
98{
99 char *line;
100 size_t linesz;
101 ssize_t len;
102 struct node *a;
103 int cycles;
104
105 INIT_G();
106
107 if (argv[1]) {
108 if (argv[2])
109 bb_show_usage();
110 if (NOT_LONE_DASH(argv[1])) {
111 close(STDIN_FILENO);
112 xopen(argv[1], O_RDONLY);
113 }
114 }
115
116
117 a = NULL;
118 line = NULL;
119 linesz = 0;
120 while ((len = getline(&line, &linesz, stdin)) != -1) {
121 char *s = line;
122 while (*(s = skip_whitespace(s)) != '\0') {
123 struct node *b;
124 char *word;
125
126 word = s;
127 s = skip_non_whitespace(s);
128 if (*s)
129 *s++ = '\0';
130
131
132 b = get_node(word);
133 if (!a) {
134 a = b;
135 } else {
136 if (a != b)
137 add_edge(a, b);
138 a = NULL;
139 }
140 }
141 }
142
143
144 if (a)
145 bb_simple_error_msg_and_die("odd input");
146 free(line);
147
148
149
150
151
152
153
154 cycles = 0;
155 while (G.nodes_len) {
156 struct node *n;
157 unsigned i;
158
159
160 for (i = 0; i < G.nodes_len; i++) {
161 if (!G.nodes[i]->in_count)
162 break;
163 }
164 if (i == G.nodes_len) {
165
166 cycles++;
167 i = 0;
168#ifndef TINY
169 bb_error_msg("cycle at %s", G.nodes[i]->name);
170#endif
171 }
172
173
174 n = G.nodes[i];
175 G.nodes[i] = G.nodes[--G.nodes_len];
176
177
178 for (i = 0; i < n->out_count; i++)
179 n->out[i]->in_count--;
180 free(n->out);
181
182 puts(n->name);
183 free(n);
184 }
185 free(G.nodes);
186
187 fflush_stdout_and_exit(cycles ? 1 : 0);
188}
189