1
0
Files
irix-657m-src/eoe/cmd/tsort/tsort.c
2022-09-29 17:59:04 +03:00

255 lines
5.2 KiB
C

/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)tsort:tsort.c 1.8"
/* topological sort
* 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
*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
/* the nodelist always has an empty element at the end to
* make it easy to grow in natural order
* states of the "live" field:*/
#define DEAD 0 /* already printed*/
#define LIVE 1 /* not yet printed*/
#define VISITED 2 /*used only in findloop()*/
static
struct nodelist {
struct nodelist *nextnode;
struct predlist *inedges;
char *name;
int 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;
};
static struct nodelist *index();
static struct nodelist *findloop();
static struct nodelist *mark();
static char *zmalloc();
static present(), anypred();
static void errmsg(), warn();
/* the first for loop reads in the graph,
* the second prints out the ordering
*/
main(argc,argv)
char **argv;
{
register struct predlist *t;
FILE *input = stdin;
register struct nodelist *i, *j;
int x;
char precedes[100], follows[100];
switch( argc ) {
case 1:
break;
case 2:
if( !strcmp( argv[1], "-" ) )
break;
if( (input = fopen( argv[1], "r" )) == NULL )
errmsg("cannot open for reading: ", argv[1]);
break;
case 3:
if( strcmp( argv[1], "--" ) )
errmsg( "usage: tsort [ file ]", "");
if( !strcmp( argv[2], "-" ) )
break;
if( (input = fopen( argv[2], "r" )) == NULL )
errmsg("cannot open for reading: ", argv[1]);
break;
default:
errmsg( "usage: tsort [ file ]", "");
}
for(;;) {
x = fscanf(input,"%99s%99s",precedes, follows);
if(x==EOF)
break;
if(x!=2)
errmsg ("odd data", "");
i = index(precedes);
j = index(follows);
if(i==j||present(i,j))
continue;
t = (struct predlist *)zmalloc(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();
(void)puts(i->name);
i->live = DEAD;
}
return 0; /* Ensure zero return on normal termination */
}
/* is i present on j's predecessor list?
*/
static
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?
*/
static
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
*/
static
struct nodelist *
index(s)
register char *s;
{
register struct nodelist *i;
register char *t;
for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
if(!strcmp(s,i->name))
return(i);
for(t=s; *t; t++) ;
t = zmalloc( (unsigned)(t+1-s));
i->nextnode = (struct nodelist *)zmalloc( sizeof(struct nodelist));
i->name = t;
i->live = LIVE;
i->nextnode->nextnode = NULL;
i->nextnode->inedges = NULL;
i->nextnode->live = DEAD;
while(*t++ = *s++);
return(i);
}
/* given that there is a cycle, find some
* node in it
*/
static
struct nodelist *
findloop()
{
register struct nodelist *i, *j;
for(i= &firstnode; i->nextnode!=NULL; i=i->nextnode)
if(i->live==LIVE)
break;
warn("warning: cycle in data", "");
i = mark(i);
if(i==NULL)
errmsg("program error", "");
for(j= &firstnode; j->nextnode!=NULL; j=j->nextnode)
if(j->live==VISITED)
j->live = LIVE;
return(i);
}
/* depth-first search of LIVE predecessors
* to find some element of a cycle;
* VISITED is a temporary state recording the
* visits of the search
*/
static
struct nodelist *
mark(i)
register struct nodelist *i;
{
register struct nodelist *j;
register struct predlist *t;
if(i->live==DEAD)
return(NULL);
if(i->live==VISITED)
return(i);
i->live = VISITED;
for(t=i->inedges; t!=NULL; t=t->nextpred) {
j = mark(t->pred);
if(j!=NULL) {
warn("\t", i->name);
return(j);
}
}
return(NULL);
}
/* print concatenated error message and exit
*/
static void errmsg(s,t)
char *s, *t;
{
warn(s,t);
exit(255);
}
/* print a 'warning' to the user on standard error
*/
static void warn(s,t)
char *s,*t;
{
(void)fprintf(stderr,"tsort: %s%s\n",s,t);
(void)fflush(stderr);
}
/* internal malloc routine that checks for errors
*/
static char *
zmalloc(n)
unsigned int n;
{
char *p;
char tmp[60];
if( (p = (char *)malloc(n)) == NULL ) {
(void)sprintf(tmp, "error, malloc cannot allocate block of %d bytes", n);
errmsg(tmp, "");
}
return p;
}