V10/cmd/tsort/subs.c

Compare this file to the similar file:
Show the results in this format:

#include <stdio.h>
#include "ts.h"

#define HSIZE 307
#define ALSIZE 2040

static struct obj **objhash, *cobj = 0, *lastobj;
static struct ref **refhash;
static struct group **grouphash, *group0;
struct ref *undefrefs = 0, *defedrefs = 0;
struct group *cgroup = 0; /* current group */
struct obj *obj0 = 0; /* special null object */

unsigned lasthash = 0, ngroup = 0, nrefc = 0;
int nextseq;

char *malloc(), *strcpy();
extern char *progname;
extern int cyclep, verbose, verify;

init(){
	int i;

	objhash = (struct obj **) malloc(HSIZE*sizeof(struct obj *));
	refhash = (struct ref **) malloc(HSIZE*sizeof(struct ref *));
	grouphash = (struct group **) malloc(HSIZE*sizeof(struct group *));
	if (!objhash || !refhash || !grouphash)
		scream("initial mallocs fail\n","");
	for (i = 0; i < HSIZE; i++)
		{ objhash[i] = 0; refhash[i] = 0; grouphash[i] = 0;}
	cgroup = 0;
	newgroup("");
	group0 = cgroup;
	newobj("",1);
	obj0 = cobj;
	}

unsigned
hash(s)
unsigned char *s;
{
	unsigned x = 0;
	unsigned char c;

	while(c = *s++) x = (x<<1) + c;
	return x % HSIZE;
	}

char *
newstruct(n)
unsigned n;
{
	static char *next = 0, *last = 0;
	char *s;

	if (next + n > last) {
		next = malloc(ALSIZE);
		if (!next) scream("malloc fails in newstruct\n","");
		last = next + ALSIZE;
		}
	s = next;
	next += n;
	return s;
	}

char *
newstring(s)
char *s;
{
	static char *next = 0, *last = 0;
	char *s1;
	unsigned n, strlen();

	n = strlen(s) + 1;
	if (next + n > last) {
		next = malloc(ALSIZE);
		if (!next) scream("malloc fails in newstring\n","");
		last = next + ALSIZE;
		}
	s1 = next;
	next += n;
	strcpy(s1,s);
	return s1;
	}

newgroup(s)
char *s;
{
	struct group *g, *gnext = 0, *gprev;

	cobj = 0;
	gprev = (struct group *) &grouphash[hash(s)];
	g = gprev->next;
	for(;; gprev = g, g = g->next) {
		if (!g) {
			g = (struct group *)
				newstruct(sizeof(struct group));
			g->name = newstring(s);
			g->next = 0;
			g->gseq = ngroup++;
			gprev->next = g;
			break;
			}
		if (!strcmp(s,g->name)) break;
		}
	cgroup = g;
	}

struct ref *
lookup(s,add)
char *s;
int add;
{
	struct ref *h, *hprev;

	hprev = (struct ref *) &refhash[lasthash = hash(s)];
	h = hprev->next;
	while(h) {
		if (!strcmp(h->name,s)) return h;
		hprev = h;
		h = h->next;
		}
	if (add) {
		h = (struct ref *) newstruct(sizeof(struct ref));
		hprev->next = h;
		h->next = 0;
		h->name = cobj && !strcmp(cobj->name,s) ? cobj->name : newstring(s);
		h->robj = 0;
		}
	return h;
	}

newobj(s,dup)
char *s;
int dup;
{
	struct obj *h, *hnext = 0, *hprev, *o;
	struct ref *r1;

	hprev = (struct obj *) &objhash[hash(s)];
	h = hprev->next;
	while(h) {
		if (!strcmp(h->name,s) && h->ogroup == cgroup) {
			if (dup || h == obj0) { cobj = h; return; }
			if (verbose) {
				fprintf(stderr, "duplicate %s", s);
				if (*cgroup->name) fprintf(stderr, " in %s", cgroup->name);
				fputs(" ignored\n", stderr);
				}
			cobj = 0;
			return;
			}
		hprev = h;
		h = h->next;
		}
	cobj = o = (struct obj *) newstruct(sizeof(struct obj));
	hprev->next = o;
	o->next = hnext;
	r1 = lookup(s,0);
	o->name = r1 ? r1->name : newstring(s);
	o->ogroup = cgroup;
	o->seq = o->iptr = o->jct = 0;
	}

defobjref(s,dup)
char *s;
int dup;
{
	rdefobjref(lookup(s,1), s, dup);
	}

rdefobjref(r,s,dup)
struct ref *r;
char *s;
int dup;
{
	struct obj *o;

	if (o = r->robj) {
		newobj(s,dup);
		if (!dup || o->ogroup != cgroup) dupmsg(0,r,s);
		}
	else {
		r->robj = cobj = o = (struct obj *) newstruct(sizeof(struct obj));
		o->next = objhash[lasthash];
		objhash[lasthash] = o;
		o->name = r->name;
		o->ogroup = cgroup;
		o->seq = o->iptr = o->jct = 0;
		}
	}

dupmsg(oprt,r,s)
int oprt;
struct ref *r;
char *s;
{
	struct obj *o = r->robj;
	char *in;

	if (verbose && o != obj0) {
		fprintf(stderr, "def of %s", s);
		if (oprt && strcmp(s,cobj->name)) {
			fprintf(stderr, " in %s", cobj->name);
			in = "of";
			}
		else in = "in";
		if (*cgroup->name) fprintf(stderr, " %s lib %s", in, cgroup->name);
		else in = "of";
		fprintf(stderr, " ignored; first defined in %s", o->name);
		if (*(s = o->ogroup->name)) fprintf(stderr, " of lib %s", s);
		putc('\n', stderr);
		}
	}


newref(s)
char *s;
{ newrefr(lookup(s,1)); }

newrefr(r)
struct ref *r;
{
	struct refc rc;
	struct obj *o1;
	unsigned i;

	if (!cobj) return;
	if (verify && r->robj && cobj != obj0) {
		fputs(cobj->name, stderr);
		if (cgroup != group0) fprintf(stderr, " of %s", cgroup->name);
		fprintf(stderr, " needs %s\n", r->name);
		}
	rc.rcnext = cobj->iptr;
	rc.rcref = r;
	o1 = rc.rcref->robj;
	if (o1 != cobj && o1 != obj0) { /* discard self references */
									/* and refs to null object */
		i = cobj->iptr = ++nrefc;
		refstore(i, &rc);
		}
	}

defref(s)
char *s;
{ defrefr(lookup(s,1), s); }

defrefr(r,s)
struct ref *r;
char *s;
{
	if (!cobj) return;
	if (r->robj) dupmsg(1,r,s);
	else r->robj = cobj;
	}

struct obj *
ts0()
{
	int i;
	struct obj *firstobj, *o, *onext;
	struct ref *r, *rnext;

	/* chain objects together */

	firstobj = 0;
	for (i = 0; i < HSIZE; i++) {
		for(o = objhash[i]; o; o = onext) {
			onext = o->next;
			o->next = firstobj;
			firstobj = o;
			}
		}

	/* chain undefined refs together */

	defedrefs = undefrefs = 0;
	for (i = 0; i < HSIZE; i++) {
		for (r = refhash[i]; r; r = rnext) {
			rnext = r->next;
			if (!r->robj) { r->next = undefrefs; undefrefs = r; }
			else { r->next = defedrefs; defedrefs = r; }
			}
		}

	free((char *) grouphash);
	free((char *) refhash);
	free((char *) objhash);
	return firstobj;
	}

struct obj *
ts(all)
{
	int i, i0, k;
	unsigned j;
	struct obj *firstobj, *o, *o1, *onext, *oprev, **ready, **rs;
	struct refc rc;

	firstobj = ts0();

	/* do depth-first search (to break cycles) */

	nextseq = 1;
	for (o = firstobj; o; o = o->next)
		if (!o->seq && (all || o->ogroup == group0)) dfs(1,o);

	/* discard unreached objects */

	if (!all) {
		oprev = (struct obj *) &firstobj;
		for (o = firstobj; o; o = o->next)
			if (o->seq) { oprev->next = o; oprev = o; }
		oprev->next = 0;
		}

	/* set up for funny breadth-first search */

	ready = (struct obj **) malloc(ngroup * sizeof(struct obj *));
	if (!ready) scream("malloc of ready list fails\n","");
	
	obj0->jct = 0; /* force initial inclusion of obj0 */
	for (i = 0; i < ngroup; i++) ready[i] = 0;
	for (o = firstobj; o; o = onext) {
		onext = o->next;
		if (!o->jct) {
			rs = ready + o->ogroup->gseq;
			o->next = *rs;
			*rs = o;
			}
		}
	firstobj = lastobj = 0;
	i = i0 = 0;
	for(;;) {
		if (!(o = ready[i])) {
			i = i0;
			while(!(o = ready[i]))
				if (++i >= ngroup) {
					if (lastobj) lastobj->next = 0;
					return firstobj;
					}
			i0 = i;
			}
		ready[i] = o->next;
		if (!lastobj) firstobj = o;
		else lastobj->next = o;
		lastobj = o;
		for (j = o->iptr; j; ) {
			reffetch(j, &rc);
			j = rc.rcnext;
			if (j >= nrefc) { j -= nrefc; continue; }
			o1 = rc.rcref->robj;
			if (!o1) continue;
			if (!--o1->jct) {
				k = o1->ogroup->gseq;
				o1->next = ready[k];
				ready[k] = o1;
				if (i0 > k) i0 = k;
				}
			}
		}
	}

dfs(level, o)
int level;
struct obj *o;
{
	struct refc rc;
	struct obj *o1;
	int level0, s;
	static int cycle = 0;
	unsigned i, nextrc;

	o->seq = -level;
	level0 = -(level + 1);
	for (i = o->iptr; i; i = nextrc) {
		reffetch(i, &rc);
		nextrc = rc.rcnext;
		o1 = rc.rcref->robj;
		if (!o1 || o == o1 || o1 == obj0) continue;
		s = o1->seq;
		if (s >= 0) {
			o1->jct++;
			if (s > 0) continue; /* cross link */
			s = dfs(level+1, o1);
			}
		else { /* back link */
			if (cyclep && !cycle) {
				fprintf(stderr, "%s: cycle...\n", progname);
				cycle = 1;
				}
			rc.rcnext += nrefc;
			refstore(i, &rc);
			}
		if (level0 < s) level0 = s;
		}
	o->seq = nextseq;
	level = -level;
	if (level <= level0 && cyclep) {
		fprintf(stderr, "%s\n", o->name);
		if (level == level0) { cycle = 0; putc('\n',stderr); }
		else cycle = 1;
		}
	if (level > level0 || level == -1) { nextseq++; level0 = level; }
	return level0;
	}

scream(s, s1)
char *s, *s1;
{
	fprintf(stderr, "%s: ", progname);
	fprintf(stderr, s, s1);
	exit(1);
	}

undef(s,infile)
char *s;
FILE *infile;
{
	newgroup("");
	newobj("", 1);
	newref(s);
	}