(noinst_HEADERS): Add nanosleep.h.
[coreutils.git] / src / tsort.c
blob3234a4065945c379c2e3a809f9f1d074da802db3
1 /* tsort - topological sort.
2 Copyright (C) 1998, 1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Mark Kettenis <kettenis@phys.uva.nl>. */
20 /* The topological sort is done according to Algorithm T (Topological
21 sort) in Donald E. Knuth, The Art of Computer Programming, Volume
22 1/Fundamental Algorithms, page 262. */
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
28 #include <stdio.h>
29 #include <assert.h>
30 #include <getopt.h>
32 #include "system.h"
33 #include "long-options.h"
34 #include "error.h"
35 #include "readtokens.h"
37 /* The official name of this program (e.g., no `g' prefix). */
38 #define PROGRAM_NAME "tsort"
40 #define AUTHORS "Mark Kettenis"
42 /* Token delimiters when reading from a file. */
43 #define DELIM " \t\n"
45 /* Members of the list of successors. */
46 struct successor
48 struct item *suc;
49 struct successor *next;
52 /* Each string is held in core as the head of a list of successors. */
53 struct item
55 const char *str;
56 struct item *left, *right;
57 int balance;
58 int count;
59 struct item *qlink;
60 struct successor *top;
63 /* The name this program was run with. */
64 char *program_name;
66 /* Nonzero if any of the input files are the standard input. */
67 static int have_read_stdin;
69 /* The head of the sorted list. */
70 static struct item *head = NULL;
72 /* The tail of the list of `zeros', strings that have no predecessors. */
73 static struct item *zeros = NULL;
75 /* The number of strings to sort. */
76 static int n_strings = 0;
78 static struct option const long_options[] =
80 { NULL, 0, NULL, 0}
83 void
84 usage (int status)
86 if (status != 0)
87 fprintf (stderr, _("Try `%s --help' for more information.\n"),
88 program_name);
89 else
91 printf (_("\
92 Usage: %s [OPTION] [FILE]\n\
93 Write totally ordered list consistent with the partial ordering in FILE.\n\
94 With no FILE, or when FILE is -, read standard input.\n\
95 \n\
96 --help display this help and exit\n\
97 --version output version information and exit\n"),
98 program_name);
99 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
102 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
105 /* Create a new item/node for STR. */
106 static struct item *
107 new_item (const char *str)
109 struct item *k = xmalloc (sizeof (struct item));
111 k->str = (str ? xstrdup (str): NULL);
112 k->left = k->right = NULL;
113 k->balance = 0;
115 /* T1. Initialize (COUNT[k] <- 0 and TOP[k] <- ^). */
116 k->count = 0;
117 k->qlink = NULL;
118 k->top = NULL;
120 return k;
123 /* Search binary tree rooted at *ROOT for STR. Allocate a new tree if
124 *ROOT is NULL. Insert a node/item for STR if not found. Return
125 the node/item found/created for STR.
127 This is done according to Algorithm A (Balanced tree search and
128 insertion) in Donald E. Knuth, The Art of Computer Programming,
129 Volume 3/Searching and Sorting, pages 455--457. */
131 static struct item *
132 search_item (struct item *root, const char *str)
134 struct item *p, *q, *r, *s, *t;
135 int a;
137 assert (root);
139 /* Make sure the tree is not empty, since that is what the algorithm
140 below expects. */
141 if (root->right == NULL)
142 return (root->right = new_item (str));
144 /* A1. Initialize. */
145 t = root;
146 s = p = root->right;
148 for (;;)
150 /* A2. Compare. */
151 a = strcmp (str, p->str);
152 if (a == 0)
153 return p;
155 /* A3 & A4. Move left & right. */
156 if (a < 0)
157 q = p->left;
158 else
159 q = p->right;
161 if (q == NULL)
163 /* A5. Insert. */
164 q = new_item (str);
166 /* A3 & A4. (continued). */
167 if (a < 0)
168 p->left = q;
169 else
170 p->right = q;
172 /* A6. Adjust balance factors. */
173 assert (!STREQ (str, s->str));
174 if (strcmp (str, s->str) < 0)
176 r = p = s->left;
177 a = -1;
179 else
181 r = p = s->right;
182 a = 1;
185 while (p != q)
187 assert (!STREQ (str, p->str));
188 if (strcmp (str, p->str) < 0)
190 p->balance = -1;
191 p = p->left;
193 else
195 p->balance = 1;
196 p = p->right;
200 /* A7. Balancing act. */
201 if (s->balance == 0 || s->balance == -a)
203 s->balance += a;
204 return q;
207 if (r->balance == a)
209 /* A8. Single Rotation. */
210 p = r;
211 if (a < 0)
213 s->left = r->right;
214 r->right = s;
216 else
218 s->right = r->left;
219 r->left = s;
221 s->balance = r->balance = 0;
223 else
225 /* A9. Double rotation. */
226 if (a < 0)
228 p = r->right;
229 r->right = p->left;
230 p->left = r;
231 s->left = p->right;
232 p->right = s;
234 else
236 p = r->left;
237 r->left = p->right;
238 p->right = r;
239 s->right = p->left;
240 p->left = s;
243 s->balance = 0;
244 r->balance = 0;
245 if (p->balance == a)
246 s->balance = -a;
247 else if (p->balance == -a)
248 r->balance = a;
249 p->balance = 0;
252 /* A10. Finishing touch. */
253 if (s == t->right)
254 t->right = p;
255 else
256 t->left = p;
258 return q;
261 /* A3 & A4. (continued). */
262 if (q->balance)
264 t = p;
265 s = q;
268 p = q;
271 /* NOTREACHED */
274 /* Record the fact that J precedes K. */
276 static void
277 record_relation (struct item *j, struct item *k)
279 struct successor *p;
281 if (!STREQ (j->str, k->str))
283 k->count++;
284 p = xmalloc (sizeof (struct successor));
285 p->suc = k;
286 p->next = j->top;
287 j->top = p;
291 static void
292 count_items (struct item *k)
294 n_strings++;
297 static void
298 scan_zeros (struct item *k)
300 if (k->count == 0)
302 if (head == NULL)
303 head = k;
304 else
305 zeros->qlink = k;
307 zeros = k;
311 /* If K is part of a loop, print the loop on standard error, and exit. */
313 static void
314 detect_loop (struct item *k)
316 if (k->count > 0 && k->top)
318 while (k && k->count > 0)
320 k->count = 0;
321 fprintf (stderr, "%s: %s\n", program_name, k->str);
322 k = k->top->suc;
325 exit (EXIT_FAILURE);
329 /* Recurse (sub)tree rooted at ROOT, calling ACTION for each node. */
331 static void
332 recurse_tree (struct item *root, void (*action) (struct item *))
334 if (root->left == NULL && root->right == NULL)
335 (*action) (root);
336 else
338 if (root->left != NULL)
339 recurse_tree (root->left, action);
340 (*action) (root);
341 if (root->right != NULL)
342 recurse_tree (root->right, action);
346 /* Walk the tree specified by the head ROOT, calling ACTION for
347 each node. */
349 static void
350 walk_tree (struct item *root, void (*action) (struct item *))
352 if (root->right)
353 recurse_tree (root->right, action);
356 /* Do a topological sort on FILE. */
358 static void
359 tsort (const char *file)
361 struct item *root;
362 struct item *j = NULL;
363 struct item *k = NULL;
364 register FILE *fp;
365 token_buffer tokenbuffer;
367 /* Intialize the head of the tree will hold the strings we're sorting. */
368 root = new_item (NULL);
370 if (STREQ (file, "-"))
372 fp = stdin;
373 have_read_stdin = 1;
375 else
377 fp = fopen (file, "r");
378 if (fp == NULL)
379 error (EXIT_FAILURE, errno, "%s", file);
382 init_tokenbuffer (&tokenbuffer);
384 while (1)
386 long int len;
388 /* T2. Next Relation. */
389 len = readtoken (fp, DELIM, sizeof (DELIM) - 1, &tokenbuffer);
390 if (len < 0)
391 break;
393 assert (len != 0);
395 k = search_item (root, tokenbuffer.buffer);
396 if (j)
398 /* T3. Record the relation. */
399 record_relation (j, k);
400 k = NULL;
403 j = k;
406 /* T1. Initialize (N <- n). */
407 walk_tree (root, count_items);
409 /* T4. Scan for zeros. */
410 walk_tree (root, scan_zeros);
412 while (head)
414 struct successor *p = head->top;
416 /* T5. Output front of queue. */
417 printf ("%s\n", head->str);
418 n_strings--;
420 /* T6. Erase relations. */
421 while (p)
423 p->suc->count--;
424 if (p->suc->count == 0)
426 zeros->qlink = p->suc;
427 zeros = p->suc;
430 p = p->next;
433 /* T7. Remove from queue. */
434 head = head->qlink;
437 /* T8. End of process. */
438 assert (n_strings >= 0);
439 if (n_strings > 0)
441 error (0, 0, _("%s: input contains a loop:"),
442 (have_read_stdin ? "-" : file));
444 /* Print out loop. */
445 walk_tree (root, detect_loop);
447 /* Should not happen. */
448 error (EXIT_FAILURE, 0, _("could not find loop"));
453 main (int argc, char **argv)
455 int opt;
457 program_name = argv[0];
458 setlocale (LC_ALL, "");
459 bindtextdomain (PACKAGE, LOCALEDIR);
460 textdomain (PACKAGE);
462 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
463 AUTHORS, usage);
465 while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1)
466 switch (opt)
468 case 0: /* long option */
469 break;
470 default:
471 usage (EXIT_FAILURE);
474 have_read_stdin = 0;
476 if (optind + 1 < argc)
478 error (0, 0, _("only one argument may be specified"));
479 usage (EXIT_FAILURE);
482 if (optind < argc)
483 tsort (argv[optind]);
484 else
485 tsort ("-");
487 if (fclose (stdout) == EOF)
488 error (EXIT_FAILURE, errno, _("write error"));
490 if (have_read_stdin && fclose (stdin) == EOF)
491 error (EXIT_FAILURE, errno, _("standard input"));
493 exit (EXIT_SUCCESS);