static char *SccsId = "@(#)hierar.c 1.1 (TU-Delft) 08/21/85";
/**********************************************************

Name/Version      : getldm/1.1

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : L.K. Regenbogen 
Creation date     : 01-Jan-1985
Modified by       : S. de Graaf
Modification date : 21-Aug-1985


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1985 , All rights reserved
**********************************************************/
#include "stdio.h"

/*  topological sort (modified tsort.c)
**  input is sequence of pairs of items (blank-free strings)
**  nonidentical pair is a directed edge in graph
**  identical pair merely indicates presence of node
**  output is ordered list of items consistent with
**  the partial ordering specified by the graph
**
**  the nodelist always has an empty element at the end to
**  make it easy to grow in natural order
*/
struct nodelist {
    struct nodelist *nextnode;
    struct predlist *inedges;
    char   *name;
            enum {
	        DEAD, LIVE, ONCE, TWICE
    }               live;
} firstnode = {
    NULL, NULL, NULL, DEAD
};

/*  a predecessor list tells all the immediate
**  predecessors of a given node
*/
struct predlist {
    struct predlist *nextpred;
    struct nodelist *pred;
};

struct nodelist *indx ();
struct nodelist *findloop ();
char   *argv0;
char   *malloc ();
char   *empty = "";

/*  the first for loop reads in the graph,
**  the second prints out the ordering
*/
hierar (input, output)
FILE  *input, *output;
{
    register struct predlist   *t;
    register struct nodelist   *i, *j;
    int     x;
    char    precedes[50],
            follows[50];

    for (;;) {
	x = fscanf (input, "%s%s", precedes, follows);
	if (x == EOF)
	    break;
	if (x != 2)
	    error ("odd data", empty);
	i = indx (precedes);
	j = indx (follows);
	if (i == j || present (i, j))
	    continue;
	t = (struct predlist   *) malloc (sizeof (struct predlist));
	t -> nextpred = j -> inedges;
	t -> pred = i;
	j -> inedges = t;
    }
    for (;;) {
	x = 0;			/* anything LIVE on this sweep? */
	for (i = &firstnode; i -> nextnode != NULL; i = i -> nextnode) {
	    if (i -> live == LIVE) {
		x = 1;
		if (!anypred (i))
		    break;
	    }
	}
	if (x == 0)
	    break;
	if (i -> nextnode == NULL)
	    i = findloop ();
	fprintf (output, "%s\n", i -> name);
	i -> live = DEAD;
    }
}

/*  is i present on j's predecessor list?
*/
present (i, j)
struct nodelist *i, *j;
{
    register struct predlist   *t;
    for (t = j -> inedges; t != NULL; t = t -> nextpred)
	if (t -> pred == i)
	    return (1);
    return (0);
}

/*  is there any live predecessor for i?
*/
anypred (i)
struct nodelist *i;
{
    register struct predlist   *t;
    for (t = i -> inedges; t != NULL; t = t -> nextpred)
	if (t -> pred -> live == LIVE)
	    return (1);
    return (0);
}

/*  turn a string into a node pointer
*/
struct nodelist *
indx (s)
register char  *s;
{
    register struct nodelist   *i;
    register char  *t;
    for (i = &firstnode; i -> nextnode != NULL; i = i -> nextnode)
	if (cmp (s, i -> name))
	    return (i);
    for (t = s; *t; t++);
    t = malloc ((unsigned) (t + 1 - s));
    i -> nextnode = (struct nodelist   *) malloc (sizeof (struct nodelist));
    if (i -> nextnode == NULL || t == NULL)
	error ("too many items", empty);
    i -> name = t;
    i -> live = LIVE;
    i -> nextnode -> nextnode = NULL;
    i -> nextnode -> inedges = NULL;
    i -> nextnode -> live = DEAD;
    while (*t++ = *s++);
    return (i);
}

cmp (s, t)
register char  *s, *t;
{
    while (*s == *t) {
	if (*s == 0)
	    return (1);
	s++;
	t++;
    }
    return (0);
}

error (s, t)
char   *s, *t;
{
    note (s, t);
    die (1);
}

note (s, t)
char   *s, *t;
{
    fprintf (stderr, "%s: hierar(): %s%s\n", argv0, s, t);
}

/*  given that there is a cycle, find some node in it
*/
struct nodelist *
findloop ()
{
    register struct nodelist   *i, *j;
    register struct predlist   *p;

    for (i = &firstnode; i -> nextnode != NULL; i = i -> nextnode)
	if (i -> live == LIVE)
	    break;

    note ("cycle in reverse order", empty);
    while (i -> live == LIVE) {
	i -> live = ONCE;
	for (p = i -> inedges;; p = p -> nextpred) {
	    if (p == NULL)
		error ("error", "1");
	    i = p -> pred;
	    if (i -> live != DEAD)
		break;
	}
    }
    while (i -> live == ONCE) {
	i -> live = TWICE;
	note (i -> name, empty);
	for (p = i -> inedges;; p = p -> nextpred) {
	    if (p == NULL)
		error ("error", "2");
	    i = p -> pred;
	    if (i -> live != DEAD)
		break;
	}
    }
    for (j = &firstnode; j -> nextnode != NULL; j = j -> nextnode)
	if (j -> live != DEAD)
	    j -> live = LIVE;
    return (i);
}
