V10/cmd/tsort/subs.c
#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);
}