home *** CD-ROM | disk | FTP | other *** search
- /* pathalias -- by steve bellovin, as told to peter honeyman */
- #ifndef lint
- static char *sccsid = "@(#)mapaux.c 9.4 89/03/01";
- #endif /* lint */
-
- #include "def.h"
-
- /* imports */
- extern long Nheap, Hashpart, Tabsize, NumNcopy, Nlink, NumLcopy;
- extern node **Table, *Home;
- extern char *Graphout, *Linkout, *Netchars, **Argv;
- extern int Vflag;
- extern void freelink(), die();
- extern long pack();
- extern link *newlink();
- extern node *newnode();
- extern char *strsave();
- extern int strcmp(), strlen();
-
- /* exports */
- extern long pack();
- extern void resetnodes(), dumpgraph(), showlinks(), terminalnet();
- extern int tiebreaker();
- extern node *ncopy();
-
- /* privates */
- static FILE *Gstream; /* for dumping graph */
- STATIC void dumpnode(), untangle(), dfs();
- STATIC int height();
- STATIC link *lcopy();
-
-
- /*
- * slide everything from Table[low] to Table[high]
- * up toward the high end. make room! make room!
- */
- long
- pack(low, high)
- long low, high;
- { long hole, next;
-
- /* find first "hole " */
- for (hole = high; hole >= low && Table[hole] != 0; --hole)
- ;
-
- /* repeatedly move next filled entry into last hole */
- for (next = hole - 1; next >= low; --next) {
- if (Table[next] != 0) {
- Table[hole] = Table[next];
- Table[hole]->n_tloc = hole;
- Table[next] = 0;
- while (Table[--hole] != 0) /* find next hole */
- ;
- }
- }
- return hole + 1;
- }
-
- void
- resetnodes()
- { register long i;
- register node *n;
-
- for (i = Hashpart; i < Tabsize; i++)
- if ((n = Table[i]) != 0) {
- n->n_cost = (Cost) 0;
- n->n_flag &= ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT|NTERMINAL);
- n->n_copy = n;
- }
-
- Home->n_cost = (Cost) 0;
- Home->n_flag &= ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT|NTERMINAL);
- Home->n_copy = Home;
- }
-
- void
- dumpgraph()
- { register long i;
- register node *n;
-
- if ((Gstream = fopen(Graphout, "w")) == NULL) {
- fprintf(stderr, "%s: ", Argv[0]);
- perror(Graphout);
- return;
- }
-
- untangle(); /* untangle net cycles for proper output */
-
- for (i = Hashpart; i < Tabsize; i++) {
- n = Table[i];
- if (n == 0)
- continue; /* impossible, but ... */
- /* a minor optimization ... */
- if (n->n_link == 0)
- continue;
- /* pathparse doesn't need these */
- if (n->n_flag & NNET)
- continue;
- dumpnode(n);
- }
- }
-
- STATIC void
- dumpnode(from)
- register node *from;
- { register node *to;
- register link *l;
- link *lnet = 0, *ll, *lnext;
-
- for (l = from->n_link ; l; l = l->l_next) {
- to = l->l_to;
- if (from == to)
- continue; /* oops -- it's me! */
-
- if ((to->n_flag & NNET) == 0) {
- /* host -> host -- print host>host */
- if (l->l_cost == INF)
- continue; /* phoney link */
- fputs(from->n_name, Gstream);
- putc('>', Gstream);
- fputs(to->n_name, Gstream);
- putc('\n', Gstream);
- } else {
- /*
- * host -> net -- just cache it for now.
- * first check for dups. (quadratic, but
- * n is small here.)
- */
- while (to->n_root && to != to->n_root)
- to = to->n_root;
- for (ll = lnet; ll; ll = ll->l_next)
- if (strcmp(ll->l_to->n_name, to->n_name) == 0)
- break;
- if (ll)
- continue; /* dup */
- ll = newlink();
- ll->l_next = lnet;
- ll->l_to = to;
- lnet = ll;
- }
- }
-
- /* dump nets */
- if (lnet) {
- /* nets -- print host@\tnet,net, ... */
- fputs(from->n_name, Gstream);
- putc('@', Gstream);
- putc('\t', Gstream);
- for (ll = lnet; ll; ll = lnext) {
- lnext = ll->l_next;
- fputs(ll->l_to->n_name, Gstream);
- if (lnext)
- fputc(',', Gstream);
- freelink(ll);
- }
- putc('\n', Gstream);
- }
- }
-
- /*
- * remove cycles in net definitions.
- *
- * depth-first search
- *
- * for each net, run dfs on its neighbors (nets only). if we return to
- * a visited node, that's a net cycle. mark the cycle with a pointer
- * in the n_root field (which gets us closer to the root of this
- * portion of the dfs tree).
- */
- STATIC void
- untangle()
- { register long i;
- register node *n;
-
- for (i = Hashpart; i < Tabsize; i++) {
- n = Table[i];
- if (n == 0 || (n->n_flag & NNET) == 0 || n->n_root)
- continue;
- dfs(n);
- }
- }
-
- STATIC void
- dfs(n)
- register node *n;
- { register link *l;
- register node *next;
-
- n->n_flag |= INDFS;
- n->n_root = n;
- for (l = n->n_link; l; l = l->l_next) {
- next = l->l_to;
- if ((next->n_flag & NNET) == 0)
- continue;
- if ((next->n_flag & INDFS) == 0) {
- dfs(next);
- if (next->n_root != next)
- n->n_root = next->n_root;
- } else
- n->n_root = next->n_root;
- }
- n->n_flag &= ~INDFS;
- }
-
- void
- showlinks()
- { register link *l;
- register node *n;
- register long i;
- FILE *estream;
-
- if ((estream = fopen(Linkout, "w")) == 0)
- return;
-
- for (i = Hashpart; i < Tabsize; i++) {
- n = Table[i];
- if (n == 0 || n->n_link == 0)
- continue;
- for (l = n->n_link; l; l = l->l_next) {
- fputs(n->n_name, estream);
- putc('\t', estream);
- if (NETDIR(l) == LRIGHT)
- putc(NETCHAR(l), estream);
- fputs(l->l_to->n_name, estream);
- if (NETDIR(l) == LLEFT)
- putc(NETCHAR(l), estream);
- fprintf(estream, "(%d)\n", l->l_cost);
- }
- }
- (void) fclose(estream);
- }
-
- /*
- * n is node in heap, newp is candidate for new parent.
- * choose between newp and n->n_parent for parent.
- * return 0 to use newp, non-zero o.w.
- */
- #define NEWP 0
- #define OLDP 1
- int
- tiebreaker(n, newp)
- node *n;
- register node *newp;
- { register char *opname, *npname, *name;
- register node *oldp;
- int metric;
-
- oldp = n->n_parent;
-
- /* given the choice, avoid gatewayed nets */
- if (GATEWAYED(newp) && !GATEWAYED(oldp))
- return OLDP;
- if (!GATEWAYED(newp) && GATEWAYED(oldp))
- return NEWP;
-
- /* look at real parents, not nets */
- while ((oldp->n_flag & NNET) && oldp->n_parent)
- oldp = oldp->n_parent;
- while ((newp->n_flag & NNET) && newp->n_parent)
- newp = newp->n_parent;
-
- /* use fewer hops, if possible */
- metric = height(oldp) - height(newp);
- if (metric < 0)
- return OLDP;
- if (metric > 0)
- return NEWP;
-
- /*
- * compare names
- */
- opname = oldp->n_name;
- npname = newp->n_name;
- name = n->n_name;
-
- /* use longest common prefix with parent */
- while (*opname == *name && *npname == *name && *name) {
- opname++;
- npname++;
- name++;
- }
- if (*opname == *name)
- return OLDP;
- if (*npname == *name)
- return NEWP;
-
- /* use shorter host name */
- metric = strlen(opname) - strlen(npname);
- if (metric < 0)
- return OLDP;
- if (metric > 0)
- return NEWP;
-
- /* use larger lexicographically */
- metric = strcmp(opname, npname);
- if (metric < 0)
- return NEWP;
- return OLDP;
- }
-
- STATIC int
- height(n)
- register node *n;
- { register int i = 0;
-
- if (n == 0)
- return 0;
- while ((n = n->n_parent) != 0)
- if (ISADOMAIN(n) || !(n->n_flag & NNET))
- i++;
- return i;
- }
-
- /*
- * return a copy of n ( == l->l_to). we rely on n and its copy
- * pointing to the same name string, which is kludgey, but works
- * because the name is non-volatile.
- */
-
- #define REUSABLE(n, l) (((n)->n_flag & NTERMINAL) == 0 \
- && ((n)->n_copy->n_flag & NTERMINAL) \
- && !((n)->n_copy->n_flag & NALIAS) \
- && !((l)->l_flag & LALIAS))
- node *
- ncopy(parent, l)
- register node *parent;
- register link *l;
- { register node *n, *ncp;
-
- #ifdef DEBUG
- if (Vflag > 1)
- vprintf(stderr, "<%s> <- %s\n", l->l_to->n_name, parent->n_name);
- #endif
- n = l->l_to;
- if (REUSABLE(n, l)) {
- Nlink++;
- return n->n_copy; /* re-use */
- }
- NumNcopy++;
- l->l_to = ncp = newnode();
- ncp->n_name = n->n_name; /* nonvolatile */
- ncp->n_tloc = --Hashpart; /* better not be > 20% of total ... */
- if (Hashpart == Nheap)
- die("too many terminal links");
- Table[Hashpart] = ncp;
- ncp->n_copy = n->n_copy; /* circular list */
- n->n_copy = ncp;
- ncp->n_link = lcopy(parent, n);
- ncp->n_flag = (n->n_flag & ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT)) | NTERMINAL;
- return ncp;
- }
-
- /*
- * copy l, but don't include any links to parent.
- *
- * this is a little messier than it should be, because
- * of the funny test for ancestry, and because it wants
- * to be recursive, but the recursion might be very deep
- * (for a long link list), so it's done iteratively.
- */
- STATIC link *
- lcopy(parent, n)
- register node *parent, *n;
- { register link *l, *lcp;
- link *first = 0, *last = 0;
-
- for (l = n->n_link; l != 0; l = l->l_next) {
- /* avoid vestigial descendants */
- if ((l->l_to->n_flag & MAPPED) != 0
- || ALTEREGO(l->l_to, parent))
- continue;
- #ifdef DEBUG
- if (Vflag > 1)
- vprintf(stderr, "\t-> %s\n", l->l_to->n_name);
- #endif
- NumLcopy++;
- lcp = newlink();
- *lcp = *l; /* struct copy */
- lcp->l_flag &= ~LTREE;
- if (ISANET(n))
- lcp->l_flag |= LTERMINAL;
-
- if (first == 0) {
- first = last = lcp;
- } else {
- last->l_next = lcp;
- last = lcp;
- }
- }
- if (last)
- last->l_next = 0;
- return first;
- }
-