home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
back2roots/padua
/
padua.7z
/
padua
/
uucp
/
pathalias_V10.lzh
/
addlink.c
next >
Wrap
C/C++ Source or Header
|
1992-01-23
|
6KB
|
288 lines
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)addlink.c 9.7 88/06/10";
#endif /* lint */
#include "def.h"
/* exports */
extern link *addlink();
extern void deadlink(), atrace(), freelink();
extern int tracelink(), maptrace();
char *Netchars = "!:@%"; /* sparse, but sufficient */
long Lcount; /* how many edges? */
/* imports */
extern int Tflag, Dflag;
extern link *newlink();
extern node *addnode();
extern void yyerror(), die();
extern int strcmp(), strlen();
/* privates */
STATIC void netbits(), ltrace(), ltrprint();
static link *Trace[NTRACE];
static int Tracecount;
#define EQ(n1, n2) (strcmp((n1)->n_name, (n2)->n_name) == 0)
#define LTRACE if (Tflag) ltrace
link *
addlink(from, to, cost, netchar, netdir)
node *from;
register node *to;
Cost cost;
char netchar, netdir;
{ register link *l, *prev = 0;
LTRACE(from, to, cost, netchar, netdir, "");
/*
* maintain uniqueness for dead links (only).
*/
for (l = from->n_link; l; l = l->l_next) {
if (!DEADLINK(l))
break;
if (to == l->l_to) {
/* what the hell, use cheaper dead cost */
if (cost < l->l_cost) {
l->l_cost = cost;
netbits(l, netchar, netdir);
}
return l;
}
prev = l;
}
/* allocate and link in the new link struct */
l = newlink();
if (cost != INF) /* ignore back links */
Lcount++;
if (prev) {
l->l_next = prev->l_next;
prev->l_next = l;
} else {
l->l_next = from->n_link;
from->n_link = l;
}
l->l_to = to;
/* add penalty */
if ((l->l_cost = cost + from->n_cost) < 0) {
char buf[100];
l->l_flag |= LDEAD;
sprintf(buf, "link to %s ignored with negative cost", to->n_name);
yyerror(buf);
}
if (netchar == 0) {
netchar = DEFNET;
netdir = DEFDIR;
}
netbits(l, netchar, netdir);
if (Dflag && ISADOMAIN(from))
l->l_flag |= LTERMINAL;
return l;
}
void
deadlink(nleft, nright)
node *nleft, *nright;
{ link *l, *lhold = 0, *lprev, *lnext;
/* DEAD host */
if (nright == 0) {
nleft->n_flag |= NDEAD; /* DEAD host */
return;
}
/* DEAD link */
/* grab <nleft, nright> instances at head of nleft adjacency list */
while ((l = nleft->n_link) != 0 && l->l_to == nright) {
nleft->n_link = l->l_next; /* disconnect */
l->l_next = lhold; /* terminate */
lhold = l; /* add to lhold */
}
/* move remaining <nleft, nright> instances */
for (lprev = nleft->n_link; lprev && lprev->l_next; lprev = lprev->l_next) {
if (lprev->l_next->l_to == nright) {
l = lprev->l_next;
lprev->l_next = l->l_next; /* disconnect */
l->l_next = lhold; /* terminate */
lhold = l;
}
}
/* check for emptiness */
if (lhold == 0) {
addlink(nleft, nright, INF / 2, DEFNET, DEFDIR)->l_flag |= LDEAD;
return;
}
/* reinsert deleted edges as DEAD links */
for (l = lhold; l; l = lnext) {
lnext = l->l_next;
addlink(nleft, nright, l->l_cost, NETCHAR(l), NETDIR(l))->l_flag |= LDEAD;
freelink(l);
}
}
STATIC void
netbits(l, netchar, netdir)
register link *l;
char netchar, netdir;
{
l->l_flag &= ~LDIR;
l->l_flag |= netdir;
l->l_netop = netchar;
}
int
tracelink(arg)
char *arg;
{ char *bang;
link *l;
if (Tracecount >= NTRACE)
return -1;
l = newlink();
bang = index(arg, '!');
if (bang) {
*bang = 0;
l->l_to = addnode(bang+1);
} else
l->l_to = 0;
l->l_from = addnode(arg);
Trace[Tracecount++] = l;
return 0;
}
/*
* the obvious choice for testing equality is to compare struct
* addresses, but that misses private nodes, so we use strcmp().
*/
STATIC void
ltrace(from, to, cost, netchar, netdir, message)
node *from, *to;
Cost cost;
char netchar, netdir, *message;
{ link *l;
int i;
for (i = 0; i < Tracecount; i++) {
l = Trace[i];
/* overkill, but you asked for it! */
if (l->l_to == 0) {
if (EQ(from, l->l_from) || EQ(to, l->l_from))
break;
} else if (EQ(from, l->l_from) && EQ(to, l->l_to))
break;
else if (EQ(from, l->l_to) && EQ(to, l->l_from))
break; /* potential dead backlink */
}
if (i < Tracecount)
ltrprint(from, to, cost, netchar, netdir, message);
}
/* print a trace item */
STATIC void
ltrprint(from, to, cost, netchar, netdir, message)
node *from, *to;
Cost cost;
char netchar, netdir, *message;
{ char buf[256], *bptr = buf;
strcpy(bptr, from->n_name);
bptr += strlen(bptr);
*bptr++ = ' ';
if (netdir == LRIGHT) /* @% */
*bptr++ = netchar;
strcpy(bptr, to->n_name);
bptr += strlen(bptr);
if (netdir == LLEFT) /* !: */
*bptr++ = netchar;
sprintf(bptr, "(%ld) %s", cost, message);
yyerror(buf);
}
void
atrace(n1, n2)
node *n1, *n2;
{ link *l;
int i;
char buf[256];
for (i = 0; i < Tracecount; i++) {
l = Trace[i];
if (l->l_to == 0 && ((node *) l->l_from == n1 || (node *) l->l_from == n2)) {
sprintf(buf, "%s = %s", n1->n_name, n2->n_name);
yyerror(buf);
return;
}
}
}
int
maptrace(from, to)
register node *from, *to;
{ register link *l;
register int i;
for (i = 0; i < Tracecount; i++) {
l = Trace[i];
if (l->l_to == 0) {
if (EQ(from, l->l_from) || EQ(to, l->l_from))
return 1;
} else if (EQ(from, l->l_from) && EQ(to, l->l_to))
return 1;
}
return 0;
}
void
deletelink(from, to)
node *from;
node *to;
{ register link *l, *lnext;
l = from->n_link;
/* delete all neighbors of from */
if (to == 0) {
while (l) {
LTRACE(from, l->l_to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED");
lnext = l->l_next;
freelink(l);
l = lnext;
}
from->n_link = 0;
return;
}
/* delete from head of list */
while (l && EQ(to, l->l_to)) {
LTRACE(from, to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED");
lnext = l->l_next;
freelink(l);
l = from->n_link = lnext;
}
/* delete from interior of list */
if (l == 0)
return;
for (lnext = l->l_next; lnext; lnext = l->l_next) {
if (EQ(to, lnext->l_to)) {
LTRACE(from, to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED");
l->l_next = lnext->l_next;
freelink(lnext);
/* continue processing this link */
} else
l = lnext; /* next link */
}
}