New pathalias, part 2 of 2
sources-request at panda.UUCP
sources-request at panda.UUCP
Thu Jan 23 10:26:27 AEST 1986
Mod.sources: Volume 3, Issue 93
Submitted by: princeton!down!honey (Peter Honeyman)
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# addlink.c
# addnode.c
# extern.c
# local.c
# main.c
# makedb.c
# mapaux.c
# mapit.c
# mem.c
# printit.c
# parse.y
# This archive created: Wed Jan 22 18:53:16 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'addlink.c'" '(3358 characters)'
if test -f 'addlink.c'
then
echo shar: will not over-write existing file "'addlink.c'"
else
cat << \SHAR_EOF > 'addlink.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)addlink.c 8.1 (down!honey) 86/01/19";
#endif lint
#include "def.h"
static link *Trace[NTRACE];
static int Tracecount;
link *
addlink(from, to, cost, netchar, netdir)
node *from;
register node *to;
Cost cost;
char netchar;
char netdir;
{
register link *l, *prev = 0;
if (Tflag)
ltrace(from, to, cost, netchar, netdir);
/* maintain uniqueness for dead links (only) */
for (l = from->n_link; l && l->l_flag & LDEAD; l = l->l_next) {
if (to == l->l_to) {
/* what the hell, use cheaper 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;
l->l_cost = cost;
if (netchar == 0) {
netchar = DEFNET;
netdir = DEFDIR;
}
netbits(l, netchar, netdir);
return(l);
}
link *
addgateway(from, to, cost, netchar, netdir)
node *from;
node *to;
Cost cost;
char netchar;
char netdir;
{
register link *l;
l = addlink(from, to, cost, netchar, netdir);
l->l_flag |= LGATEWAY;
return(l);
}
deadlink(s)
char *s;
{
char *t, c;
link *l;
t = index(s, '!');
if (t) {
c = *t;
*t = 0;
l = addlink(addnode(s), addnode(t + 1), INF / 2, c, DEFDIR);
l->l_flag |= LDEAD;
} else
addnode(s)->n_flag |= NDEAD;
}
netbits(l, netchar, netdir)
link *l;
char netchar, netdir;
{
char *nptr;
if ((nptr = index(Netchars, netchar)) == 0) {
fprintf(stderr, "%s: unknown network operator: %c\n",
ProgName, netchar);
badmagic(1);
}
l->l_flag &= ~(LNETCHARS|LDIR);
l->l_flag |= (nptr - Netchars) | dirbits(netdir);
}
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 = (link *) addnode(arg);
Trace[Tracecount++] = l;
return(0);
}
STATIC
ltrace(from, to, cost, netchar, netdir)
node *from, *to;
Cost cost;
char netchar;
char netdir;
{
link *l;
int i;
for (i = 0; i < Tracecount; i++) {
l = Trace[i];
/* overkill -- you asked for it! */
if ((l->l_to == 0
&& (from == (node *) l->l_from || to == (node *) l->l_from))
|| (from == (node *) l->l_from && to == l->l_to)
|| (to == (node *) l->l_from && from == l->l_to)) {
ltrprint(from, to, cost, netchar, netdir);
return;
}
}
}
/* print a trace item */
STATIC
ltrprint(from, to, cost, netchar, netdir)
node *from, *to;
Cost cost;
char netchar;
char netdir;
{
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)", cost);
yyerror(buf);
}
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;
}
}
}
SHAR_EOF
if test 3358 -ne "`wc -c < 'addlink.c'`"
then
echo shar: error transmitting "'addlink.c'" '(should have been 3358 characters)'
fi
fi
echo shar: extracting "'addnode.c'" '(6585 characters)'
if test -f 'addnode.c'
then
echo shar: will not over-write existing file "'addnode.c'"
else
cat << \SHAR_EOF > 'addnode.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)addnode.c 8.1 (down!honey) 86/01/19";
#endif
#include "def.h"
extern void lowercase(), rehash();
extern node *isprivate();
extern long hash();
/*
* these numbers are chosen because:
* -> they are prime,
* -> they are monotonic increasing,
* -> each is a tad smaller than a multiple of 1024,
* -> they form a fibonacci sequence (almost).
* the first point yields good hash functions, the second is used for the
* standard re-hashing implementation of open addressing, the third
* optimizes for quirks in some mallocs i have seen, and the fourth simply
* appeals to me.
*/
static int Primes[] = {
#ifndef SQUANDER
1021, 2039, 3067, 5113, 8179,
#endif
13309, 21499, 0
};
static int Tabindex = -1;
static int Collision; /* mark host name collisions in hash() */
node *
addnode(name)
register char *name;
{
register long i;
register node *n;
if (Iflag)
lowercase(name);
/* is it a private host? */
n = isprivate(name);
if (n)
return(n);
i = hash(name, 0);
if (Table[i])
return(Table[i]);
n = newnode();
n->n_name = strsave(name);
Table[i] = n;
n->n_tloc = i; /* essentially a back link to the table */
if (Collision)
n->n_flag |= COLLISION; /* name collision with private host */
return(n);
}
alias(n1, n2)
node *n1, *n2;
{
link *l;
extern link *addlink();
l = addlink(n1, n2, (Cost) 0, DEFNET, DEFDIR);
l->l_flag |= LALIAS;
l = addlink(n2, n1, (Cost) 0, DEFNET, DEFDIR);
l->l_flag |= LALIAS;
if (Tflag)
atrace(n1, n2);
}
/*
* fold a string into a long int. this algorithm ignores all but the last
* eight bytes, which affects < 15% of all host names, many of which have
* common prefixes anyway.
*/
STATIC long
fold(str)
register char *str;
{
register long sum;
sum = *str++;
while (*str) {
sum <<= 4;
sum += *str++;
}
if (sum < 0)
sum = -sum;
return(sum);
}
#define HASH1(n) ((n) % Tabsize);
#define HASH2(n) (Tabsize - 2 - ((n) % (Tabsize-2))) /* princeton!rs */
/*
* with a 0.75 high water mark, probes per access should be 1.84.
* use long constant to force promotion.
*/
#define HIGHWATER 75L
#define isfull(n, size) ((n) > ((size) * HIGHWATER) / 100)
STATIC long
hash(name, unique)
char *name;
{
register long probe, hash2;
register node *n;
if (Tabindex < 0) { /* first time */
Tabindex = 0;
Tabsize = Primes[0];
Table = newtable(Tabsize);
} else if (isfull(Ncount, Tabsize))
rehash(); /* more, more! */
probe = fold(name);
/* don't change the order of the next two lines */
hash2 = HASH2(probe);
probe = HASH1(probe);
/* thank you! */
/*
* probe the hash table.
* if unique is set, we require a fresh slot.
* otherwise, use double hashing to find either
* (1) an empty slot, or
* (2) a non-private copy of this host name
*
* as a side effect, if we notice a collision with a private host
* we mark the other so that it is skipped at output time.
*/
Collision = 0;
while ((n = Table[probe]) != 0) {
if (strcmp(n->n_name, name) == 0) {
if (unique)
n->n_flag |= COLLISION;
else if (n->n_flag & ISPRIVATE)
Collision++;
else
break; /* this is it! */
}
probe -= hash2;
if (probe < 0)
probe += Tabsize;
}
return(probe);
}
STATIC void
rehash()
{
register node **otable, **optr;
register long probe;
long osize;
#ifdef DEBUG
hashanalyze();
#endif
optr = Table + Tabsize - 1; /* ptr to last */
otable = Table;
osize = Tabsize;
Tabsize = Primes[++Tabindex];
if (Tabsize == 0) { /* need more prime numbers */
fprintf(stderr, "%s: > %d hosts\n", ProgName, Primes[Tabindex-1]);
badmagic(1);
}
vprintf(stderr, "rehash into %d\n", Tabsize);
Table = newtable(Tabsize);
do {
if (*optr == 0)
continue; /* empty slot in old table */
probe = hash((*optr)->n_name, (*optr)->n_flag & ISPRIVATE);
if (Table[probe] != 0) {
fprintf(stderr, "%s: rehash error\n", ProgName);
badmagic(1);
}
Table[probe] = *optr;
(*optr)->n_tloc = probe;
} while (optr-- > otable);
freetable(otable, osize);
}
hashanalyze()
{
long probe, hash2;
int count, i, collision[8];
int longest = 0, total = 0, slots = 0;
int nslots = sizeof(collision)/sizeof(collision[0]);
if (!Vflag)
return;
strclear((char *) collision, sizeof(collision));
for (i = 0; i < Tabsize; i++) {
if (Table[i] == 0)
continue;
/* private hosts too hard to account for ... */
if (Table[i]->n_flag & ISPRIVATE)
continue;
count = 1;
probe = fold(Table[i]->n_name);
/* don't change the order of the next two lines */
hash2 = HASH2(probe);
probe = HASH1(probe);
/* thank you! */
while (Table[probe] != 0
&& strcmp(Table[probe]->n_name, Table[i]->n_name) != 0) {
count++;
probe -= hash2;
if (probe < 0)
probe += Tabsize;
}
if (Table[probe] == 0) {
fprintf(stderr, "%s: impossible hash error for %s\n",
ProgName, Table[i]->n_name);
badmagic(1);
}
total += count;
slots++;
if (count > longest)
longest = count;
if (count >= nslots)
count = 0;
collision[count]++;
}
for (i = 1; i < nslots; i++)
if (collision[i])
fprintf(stderr, "%d chains: %d (%ld%%)\n",
i, collision[i], (collision[i] * 100L)/ slots);
if (collision[0])
fprintf(stderr, "> %d chains: %d (%ld%%)\n",
nslots - 1, collision[0],
(collision[0] * 100L)/ slots);
fprintf(stderr, "%2.2f probes per access, longest chain: %d\n",
(double) total / slots, longest);
}
STATIC void
lowercase(s)
register char *s;
{
do {
if (isupper(*s))
*s -= 'A' - 'a'; /* assumes ASCII */
} while (*s++);
}
/*
* this might have to be recoded for performance if privates catch on
*/
STATIC node *
isprivate(name)
register char *name;
{
register node *n;
for (n = Private; n != 0; n = n->n_private)
if (strcmp(name, n->n_name) == 0)
return(n);
return(0);
}
fixprivate()
{
register node *n, *next;
register long i;
for (n = Private; n != 0; n = next) {
n->n_flag |= ISPRIVATE; /* overkill, but safe */
i = hash(n->n_name, 1);
if (Table[i] != 0) {
fprintf(stderr, "%s: impossible private node error on %s\n",
ProgName, n->n_name);
badmagic(1);
}
Table[i] = n;
n->n_tloc = i; /* essentially a back link to the table */
next = n->n_private;
n->n_private = 0; /* clear for later use */
}
Private = 0;
}
node *
addprivate(name)
register char *name;
{
register node *n;
if (Iflag)
lowercase(name);
if ((n = isprivate(name)) != 0)
return(n);
n = newnode();
n->n_name = strsave(name);
n->n_private = Private;
Private = n;
return(n);
}
SHAR_EOF
if test 6585 -ne "`wc -c < 'addnode.c'`"
then
echo shar: error transmitting "'addnode.c'" '(should have been 6585 characters)'
fi
fi
echo shar: extracting "'extern.c'" '(650 characters)'
if test -f 'extern.c'
then
echo shar: will not over-write existing file "'extern.c'"
else
cat << \SHAR_EOF > 'extern.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)extern.c 8.1 (down!honey) 86/01/19";
#endif lint
#include "def.h"
node *Home;
char *Cfile;
char **Ifiles;
char *ProgName;
int Vflag;
int Cflag;
int Iflag;
int Tflag;
int Lineno = 1;
char *Netchars = "!:@%"; /* sparse, but sufficient */
int Ncount;
int Lcount;
char *Graphout;
char *Linkout;
node **Table; /* hash table + priority queue */
long Tabsize; /* size of Table */
node *Private; /* list of private nodes in this file */
long Hashpart; /* used while mapping -- above is heap */
int Scanstate = NEWLINE; /* scanner (yylex) state */
SHAR_EOF
if test 650 -ne "`wc -c < 'extern.c'`"
then
echo shar: error transmitting "'extern.c'" '(should have been 650 characters)'
fi
fi
echo shar: extracting "'local.c'" '(1426 characters)'
if test -f 'local.c'
then
echo shar: will not over-write existing file "'local.c'"
else
cat << \SHAR_EOF > 'local.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)local.c 8.1 (down!honey) 86/01/19";
#endif lint
#include <stdio.h>
#include "config.h"
#ifdef UNAME
#include <sys/utsname.h>
char *
local()
{
static struct utsname utsname;
uname(&utsname);
return(utsname.nodename);
}
#else !UNAME
char *
local()
{
static char lname[64];
void gethostname();
gethostname(lname, sizeof(lname));
return(lname);
}
#ifndef GETHOSTNAME
static void
gethostname(name, len)
char *name;
{
FILE *whoami, *fopen(), *popen();
char *ptr, *index();
*name = '\0';
/* try /etc/whoami */
if ((whoami = fopen("/etc/whoami", "r")) != 0) {
(void) fgets(name, len, whoami);
(void) fclose(whoami);
if ((ptr = index(name, '\n')) != 0)
*ptr = '\0';
}
if (*name)
return;
/* try /usr/include/whoami.h */
if ((whoami = fopen("/usr/include/whoami.h", "r")) != 0) {
while (!feof(whoami)) {
char buf[100];
if (fgets(buf, 100, whoami) == 0)
break;
if (sscanf(buf, "#define sysname \"%[^\"]\"", name))
break;
}
(void) fclose(whoami);
if (*name)
return;
}
/* ask uucp */
if ((whoami = popen("uuname -l", "r")) != 0) {
(void) fgets(name, len, whoami);
(void) pclose(whoami);
if ((ptr = index(name, '\n')) != 0)
*ptr = '\0';
}
if (*name)
return;
/* aw hell, i give up! is this a real unix? */
return;
}
#endif GETHOSTNAME
#endif UNAME
SHAR_EOF
if test 1426 -ne "`wc -c < 'local.c'`"
then
echo shar: error transmitting "'local.c'" '(should have been 1426 characters)'
fi
fi
echo shar: extracting "'main.c'" '(2362 characters)'
if test -f 'main.c'
then
echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)main.c 8.1 (down!honey) 86/01/19";
#endif
#define MAIN /* for sccsid in header files */
#include "def.h"
#define USAGE "usage: %s [-vci] [-l localname] [-d deadlink] [-t tracelink] [-g file] [-s file]\n"
main(argc, argv)
int argc;
char *argv[];
{
char *locname = 0;
int c, errflg = 0;
ProgName = argv[0];
(void) allocation(); /* initialize data space monitoring */
Cfile = "[deadlinks]"; /* for tracing dead links */
while ((c = getopt(argc, argv, "cd:g:il:s:t:v")) != EOF)
switch(c) {
case 'c': /* print cost info */
Cflag++;
break;
case 'd': /* dead host or link */
deadlink(optarg);
break;
case 'g': /* graph output file */
Graphout = optarg;
break;
case 'i': /* ignore case */
Iflag++;
break;
case 'l': /* local name */
locname = optarg;
break;
case 's': /* show shortest path tree */
Linkout = optarg;
break;
case 't': /* trace this link */
if (tracelink(optarg) < 0) {
fprintf(stderr, "%s: can trace only %d links\n", ProgName, NTRACE);
exit(1);
}
Tflag = 1;
break;
case 'v': /* verbose stderr, mixed blessing */
Vflag++;
break;
default:
errflg++;
}
if (errflg) {
fprintf(stderr, USAGE, ProgName);
exit(1);
}
argv += optind; /* kludge for yywrap() */
if (*argv) {
Ifiles = argv;
freopen("/dev/null", "r", stdin);
}
if (!locname)
locname = local();
if (*locname == 0) {
locname = "lostinspace";
fprintf(stderr, "%s: using \"%s\" for local name\n",
ProgName, locname);
}
Home = addnode(locname); /* add home node */
Home->n_cost = 0; /* doesn't cost to get here */
yyparse(); /* read in link info */
if (Vflag > 1)
hashanalyze();
vprintf(stderr, "%d vertices, %d edges\n", Ncount, Lcount);
vprintf(stderr, "allocation is %ldk after parsing\n", allocation());
Cfile = "[backlinks]"; /* for tracing back links */
Lineno = 0;
mapit(); /* compute shortest path tree */
vprintf(stderr, "allocation is %ldk after mapping\n", allocation());
printit(); /* traverse tree and print paths */
vprintf(stderr, "allocation is %ldk after printing\n", allocation());
exit(0);
}
badmagic(n)
{
if (n) {
fprintf(stderr, "%s: cannot recover!\n", ProgName);
#ifdef DEBUG
abort();
#else
exit(n);
#endif
}
}
SHAR_EOF
if test 2362 -ne "`wc -c < 'main.c'`"
then
echo shar: error transmitting "'main.c'" '(should have been 2362 characters)'
fi
fi
echo shar: extracting "'makedb.c'" '(2348 characters)'
if test -f 'makedb.c'
then
echo shar: will not over-write existing file "'makedb.c'"
else
cat << \SHAR_EOF > 'makedb.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)makedb.c 8.1 (down!honey) 86/01/19";
#endif lint
#include <stdio.h>
#include "config.h"
typedef struct {
char *dptr;
int dsize;
} datum;
char *Ofile = ALIASDB, *ProgName;
#define USAGE "%s [-o dbmname] [-a] [file ...]"
main(argc, argv)
char *argv[];
{ char *ofptr;
int c, append = 0;
extern int optind;
extern char *optarg;
ProgName = argv[0];
while ((c = getopt(argc, argv, "o:av")) != EOF)
switch(c) {
case 'o': /* dbm output file */
Ofile = optarg;
break;
case 'a': /* append mode */
append++;
break;
default:
fprintf(stderr, USAGE, ProgName);
exit(1);
break;
}
if ((ofptr = rindex(Ofile, '/')) != 0)
ofptr++;
else
ofptr = Ofile;
if (strlen(ofptr) > 10) {
ofptr[10] = 0;
fprintf(stderr, "%s: using %s for dbm output\n", ProgName, Ofile);
}
if (append == 0 && dbfile(Ofile) != 0) {
perror_(Ofile);
exit(1);
}
if (dbminit(Ofile) < 0) {
perror_(Ofile);
exit(1);
}
if (optind == argc)
makedb((char *) 0);
else for ( ; optind < argc; optind++)
makedb(argv[optind]);
exit(0);
}
dbfile(dbf)
char *dbf;
{
return (dbcreat(dbf, "dir") != 0 || dbcreat(dbf, "pag") != 0);
}
dbcreat(dbf, suffix)
char *dbf, *suffix;
{ char buf[BUFSIZ];
int fd;
(void) sprintf(buf, "%s.%s", dbf, suffix);
if ((fd = creat(buf, 0666)) < 0)
return(-1);
(void) close(fd);
return(0);
}
makedb(ifile)
char *ifile;
{ char line[BUFSIZ];
datum key, val;
if (ifile && (freopen(ifile, "r", stdin) == NULL)) {
perror_(ifile);
return;
}
/*
* keys and values are 0 terminated. this wastes time and (disk) space,
* but does lend simplicity and backwards compatibility.
*/
key.dptr = line;
while (fgets(line, sizeof(line), stdin) != NULL) {
char *op, *end;
end = line + strlen(line);
end[-1] = 0; /* kill newline, stuff null terminator */
op = index(line, '\t');
if (op != 0) {
*op++ = 0;
key.dsize = op - line; /* 0 terminated */
val.dptr = op;
val.dsize = end - op; /* 0 terminated */
} else {
key.dsize = end - line; /* 0 terminated */
val.dptr = "\0"; /* why must i do this? */
val.dsize = 1;
}
if (store(key, val) < 0)
perror_(Ofile);
}
}
perror_(str)
char *str;
{
fprintf(stderr, "%s: ", ProgName);
perror(str);
}
SHAR_EOF
if test 2348 -ne "`wc -c < 'makedb.c'`"
then
echo shar: error transmitting "'makedb.c'" '(should have been 2348 characters)'
fi
fi
echo shar: extracting "'mapaux.c'" '(5168 characters)'
if test -f 'mapaux.c'
then
echo shar: will not over-write existing file "'mapaux.c'"
else
cat << \SHAR_EOF > 'mapaux.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)mapaux.c 8.1 (down!honey) 86/01/19";
#endif lint
#include "def.h"
void pack();
void
pack()
{
long hole, next;
/* find first "hole " */
for (hole = Tabsize - 1; hole >= 0 && Table[hole] != 0; --hole)
;
/* repeatedly move next filled entry into last hole */
for (next = hole - 1; next >= 0; --next) {
if (Table[next] != 0) {
Table[hole] = Table[next];
Table[hole]->n_tloc = hole;
Table[next] = 0;
while (Table[--hole] != 0) /* find next hole */
;
}
}
Hashpart = hole + 1;
}
FILE *Gstream;
dumpgraph()
{
long i;
node *n;
if ((Gstream = fopen(Graphout, "w")) == NULL) {
fprintf(stderr, "%s: ", ProgName);
perror(Graphout);
}
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);
}
}
dumpnode(from)
node *from;
{
node *to;
link *l;
char netbuf[BUFSIZ], *nptr = netbuf;
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 */
while (to->n_root && to != to->n_root)
to = to->n_root;
*nptr++ = ',';
strcpy(nptr, to->n_name);
nptr += strlen(nptr);
}
}
/* dump nets */
if (nptr != netbuf) {
/* nets -- print host@\tnet,net, ... */
*nptr = 0;
fputs(from->n_name, Gstream);
putc('@', Gstream);
*netbuf = '\t'; /* insert tab by killing initial ',' */
fputs(netbuf, Gstream); /* skip initial ',' */
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).
*/
untangle()
{
long i;
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);
}
}
dfs(n)
node *n;
{
link *l;
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;
}
showlinks()
{
link *l;
node *n;
long i;
FILE *estream;
if ((estream = fopen(Linkout, "w")) == 0)
return;
for (i = Hashpart; i < Tabsize; i++) {
n = Table[i];
if (n == 0) /* impossible, but ... */
continue;
if (l = n->n_link) {
fprintf(estream, "%s\t%s(%d)", n->n_name,
l->l_to->n_name,
l->l_cost ? l->l_cost : DEFCOST);
for (l = l->l_next; l; l = l->l_next)
fprintf(estream, ",\n\t%s(%d)", l->l_to->n_name,
l->l_cost ? l->l_cost : DEFCOST);
fputc('\n', estream);
}
}
(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
tiebreaker(n, newp)
node *n, *newp;
{
register char *opname, *npname, *name;
node *oldp;
int metric;
oldp = n->n_parent;
/*
* given the choice of going through a gatewayed not or not,
* choose the latter, placating the FCC or whatever.
*/
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 = oldp->n_parent;
while (newp->n_flag & NNET)
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;
/* find point of departure */
while (*opname == *npname && *npname == *name) {
if (*name == 0) {
fprintf(stderr, "%s: error in tie breaker\n", ProgName);
badmagic(1);
}
opname++;
npname++;
name++;
}
/* use longest match, if appl. */
if (*opname == *name || *opname == 0)
return(OLDP);
if (*npname == *name || *npname == 0)
return(NEWP);
/* use shorter host name, if appl. */
metric = strlen(opname) - strlen(npname);
if (metric < 0)
return(OLDP);
if (metric > 0)
return(NEWP);
/* use larger lexicographically (no reason) */
metric = strcmp(opname, npname);
if (metric < 0)
return(NEWP);
return(OLDP);
}
height(n)
register node *n;
{
register int i = 0;
while ((n = n->n_parent) != 0)
if ((n->n_flag & NNET) == 0)
i++; /* should count domains too ... */
return(i);
}
SHAR_EOF
if test 5168 -ne "`wc -c < 'mapaux.c'`"
then
echo shar: error transmitting "'mapaux.c'" '(should have been 5168 characters)'
fi
fi
echo shar: extracting "'mapit.c'" '(10469 characters)'
if test -f 'mapit.c'
then
echo shar: will not over-write existing file "'mapit.c'"
else
cat << \SHAR_EOF > 'mapit.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)mapit.c 8.1 (down!honey) 86/01/19";
#endif
#include "def.h"
/* privates */
extern void reheap(), insert(), heapswap();
extern link *min_node(), *rmlink();
extern Cost costof();
static long Nheap;
static long Heaphighwater;
static link **Heap;
/* transform the graph to a shortest-path tree by marking tree edges */
mapit()
{
register node *n, *next;
register link *l;
link *lprev, *lnext;
Cost cost;
/*
* re-use the hash table space for the heap.
*/
Heap = (link **) Table;
pack(); /* remove holes in the Table */
if (Linkout && *Linkout) /* dump cheapest links */
showlinks();
if (Graphout && *Graphout) /* dump the edge list */
dumpgraph();
/* invent and insert a link for Home to get things started */
l = newlink();
l->l_to = Home;
(void) dehash(Home);
insert(l);
/* main mapping loop */
remap:
Heaphighwater = Nheap;
while ((l = min_node()) != 0) {
l->l_flag |= LTREE;
n = l->l_to;
n->n_flag |= MAPPED;
/* add children to heap */
lprev = 0;
for (l = n->n_link; l != 0; l = lnext) {
next = l->l_to; /* neighboring node */
if (next->n_flag & MAPPED) {
lnext = rmlink(l, lprev, n);
continue;
}
cost = costof(n, l);
if (skiplink(l, n, cost)) {
lnext = rmlink(l, lprev, n);
continue;
}
/*
* put this link in the heap, in a place where it may
* percolate up, but not down. if new, or if cost is
* being increased, move to end. otherwise, cost is
* same or less, so leave it where it is. unfortunately,
* freeing a link already in the heap is too costly at
* this point.
*
* TODO: avoid heaping aliases and network members.
*/
if (dehash(next) == 0) /* first time in heap */
insert(l); /* insert at end */
else {
/* replace heaped link by this one */
if (cost > next->n_cost) { /* gateway */
/* move old link to end of heap */
heapswap((long) (next->n_tloc), Nheap);
next->n_tloc = Nheap;
}
Heap[next->n_tloc] = l;
}
next->n_cost = cost;
next->n_parent = n;
reheap(l); /* restore heap property */
/*
* note whether we got here via a gatewayed net.
* domains are presumed to require gateways.
* aliases inherit parent's gateway status.
*/
next->n_flag &= ~GATEWAYIN;
if (l->l_flag & LALIAS)
next->n_flag |= (n->n_flag & GATEWAYIN);
else if (GATEWAYED(n))
next->n_flag |= GATEWAYIN;
lprev = l; /* this link's a keeper */
lnext = l->l_next;
}
}
vprintf(stderr, "heap high water mark was %d\n", Heaphighwater);
/* sanity check on implementation */
if (Nheap != 0) {
fprintf(stderr, "%s: null entry found in heap\n", ProgName);
badmagic(1);
}
if (Hashpart < Tabsize) {
/*
* add back links from unreachable hosts to reachable
* neighbors, then remap. asymptotically, this is
* quadratic. in practice, this is done exactly once.
*/
backlinks();
if (Nheap)
goto remap;
}
if (Hashpart < Tabsize) {
fputs("You can't get there from here:\n", stderr);
for ( ; Hashpart < Tabsize; Hashpart++) {
fprintf(stderr, "\t%s", Table[Hashpart]->n_name);
if (Table[Hashpart]->n_flag & (ISPRIVATE|COLLISION))
fputs(" (private)", stderr);
putc('\n', stderr);
}
}
}
/*
* can this link be ignored? if yes, return 1, o.w. 0.
* a link can be skipped if it is not in the shortest path tree.
*/
STATIC int
skiplink(l, parent, cost)
link *l; /* new link to this node */
node *parent; /* new parent of this node */
Cost cost; /* new cost to this node */
{
node *n; /* this node */
link *lheap; /* existing link to this node */
n = l->l_to;
/* first time we've reached this node? */
if (n->n_tloc >= Hashpart)
return(0);
lheap = Heap[n->n_tloc];
/* examine links to nets that require gateways */
if (GATEWAYED(n)) {
/* if exactly one is a gateway, use it */
if ((lheap->l_flag & LGATEWAY) && !(l->l_flag & LGATEWAY))
return(1); /* old is gateway */
if (!(lheap->l_flag & LGATEWAY) && (l->l_flag & LGATEWAY))
return(0); /* new is gateway */
/* no gateway or both gateways; resolve in standard way ... */
}
/* examine dup link (sanity check) */
if (n->n_parent == parent && ((lheap->l_flag & LDEAD) || (l->l_flag & LDEAD))) {
fprintf(stderr, "%s: dup dead link not eliminated: %s -> %s\n",
ProgName, parent->n_name, n->n_name);
badmagic(1);
}
/* examine cost */
if (cost < n->n_cost)
return(0);
if (cost > n->n_cost)
return(1);
/* all other things being equal, consult the oracle */
return(tiebreaker(n, parent));
}
STATIC Cost
costof(prev, l)
register node *prev;
register link *l;
{
register node *next;
register Cost cost;
next = l->l_to;
if (l->l_flag & LALIAS) {
/* copy left/right bits */
next->n_flag &= ~(HASLEFT|HASRIGHT);
next->n_flag |= (prev->n_flag & (HASLEFT|HASRIGHT));
return(prev->n_cost); /* by definition */
}
cost = prev->n_cost + l->l_cost; /* basic cost */
/*
* heuristics:
* charge for a dead link.
* charge for getting out of a dead host.
* charge for getting into a gatewayed net (except at a gateway).
* discourage mixing of left and right syntax when next is a host.
* charge for leaving a gatewayed net.
*
* life was simpler when pathalias computed true shortest paths.
*/
if (l->l_flag & LDEAD) /* dead link */
cost += INF/2;
if (DEADHOST(prev)) /* dead host */
cost += INF/2;
if (GATEWAYED(next) && !(l->l_flag & LGATEWAY)) /* not gateway */
cost += INF/2;
if (!ISANET(next)) {
/* charge for mixed syntax here */
if ((NETDIR(l) == LLEFT && (prev->n_flag & HASRIGHT))
|| (NETDIR(l) == LRIGHT && (prev->n_flag & HASLEFT)))
cost += DEFCOST;
}
/*
* if reached by a gatewayed net, discourage further links.
* this has some relevance to common carriers and the FCC ...
* the penalty inheres to hosts, not aliases, nets, or domains.
*/
if ((prev->n_flag & GATEWAYIN) && !ISADOMAIN(prev) && !(prev->n_flag & NNET))
cost += INF/2; /* heavyweight, but appropriate */
/* set left/right bits */
next->n_flag &= ~(HASLEFT|HASRIGHT);
if (NETDIR(l) == LLEFT || (prev->n_flag & HASLEFT))
next->n_flag |= HASLEFT;
if (NETDIR(l) == LRIGHT || (prev->n_flag & HASRIGHT))
next->n_flag |= HASRIGHT;
return(cost);
}
STATIC link *
rmlink(l, lprev, n)
link *l, *lprev;
node *n;
{
link *lnext;
lnext = l->l_next;
if (lprev)
lprev->l_next = l->l_next;
else
n->n_link = l->l_next;
free((char *) l);
return(lnext);
}
/*
* binary heap implementation of priority queue.
* TODO: make the heap smaller by giving inserting a placeholder
* for net members when the net is extracted. this requires storing the
* cost of a net in the net node itself -- yuck. is it worth it?
*/
STATIC void
insert(l)
link *l;
{
register node *n;
n = l->l_to;
Heap[n->n_tloc] = 0;
if (Heap[Nheap+1] != 0) {
fprintf(stderr, "%s: heap error in insert\n", ProgName);
badmagic(1);
}
if (Nheap++ == 0) {
Heap[1] = l;
n->n_tloc = 1;
return;
}
if (Vflag && Nheap > Heaphighwater)
Heaphighwater = Nheap; /* diagnostics */
/* insert at the end. caller must reheap(). */
Heap[Nheap] = l;
n->n_tloc = Nheap;
}
/*
* replace existing link in heap by this one, then
* "percolate" up the heap by exchanging with the parent
*/
STATIC void
reheap(l)
link *l;
{
register long loc, parent;
register Cost cost;
register node *n, *np;
n = l->l_to;
cost = n->n_cost;
for (loc = n->n_tloc; loc > 1; loc = parent) {
parent = loc / 2;
/* sanity check on implementation */
if (Heap[parent] == 0) {
fprintf(stderr, "%s: heap error in insert\n", ProgName);
badmagic(1);
}
np = Heap[parent]->l_to;
if (cost > np->n_cost)
return;
/* move nets below hosts for output stability */
if (cost == np->n_cost && ((n->n_flag & NNET) || !(np->n_flag & NNET)))
return;
heapswap(loc, parent);
}
}
/* extract min (== Heap[1]) from heap */
STATIC link *
min_node()
{
link *rval;
register link **regheap;
register long i, child;
if (Nheap == 0)
return(0);
regheap = Heap; /* in register -- heavily used */
rval = regheap[1]; /* return this one */
/* move last entry into root, percolate down */
regheap[1] = regheap[Nheap];
regheap[1]->l_to->n_tloc = 1;
regheap[Nheap] = 0;
if (--Nheap == 0)
return(rval);
i = 1;
for (;;) {
/* swap with smaller child down the tree */
child = i * 2; /* lhs child is 2i, rhs is 2i+1. */
if (child >= Nheap)
return(rval);
/* use rhs child if smaller than lhs child */
if (regheap[child]->l_to->n_cost > regheap[child+1]->l_to->n_cost
|| (regheap[child]->l_to->n_cost == regheap[child+1]->l_to->n_cost
&& !ISANET(regheap[child+1]->l_to)))
child++;
if (regheap[i]->l_to->n_cost < regheap[child]->l_to->n_cost)
return(rval);
/* move nets below hosts for output stability */
if (regheap[i]->l_to->n_cost == regheap[child]->l_to->n_cost
&& (!ISANET(regheap[i]->l_to) || ISANET(regheap[child]->l_to)))
return(rval);
heapswap(i, child);
i = child;
}
/*NOTREACHED*/
}
/* exchange Heap[i] and Heap[j] pointers */
STATIC void
heapswap(i, j)
long i, j;
{
register link *temp, **regheap;
regheap = Heap; /* heavily used -- put in register */
temp = regheap[i];
regheap[i] = regheap[j];
regheap[j] = temp;
regheap[j]->l_to->n_tloc = j;
regheap[i]->l_to->n_tloc = i;
}
/* return 1 if n is already de-hashed (n_tloc < Hashpart), 0 o.w. */
dehash(n)
register node *n;
{
if (n->n_tloc < Hashpart)
return(1);
/* swap with entry in Table[Hashpart] */
Table[Hashpart]->n_tloc = n->n_tloc;
Table[n->n_tloc] = Table[Hashpart];
Table[Hashpart] = n;
n->n_tloc = Hashpart++;
return(0);
}
backlinks()
{
link *l;
node *n, *parent, *nomap;
long i;
for (i = Hashpart; i < Tabsize; i++) {
nomap = Table[i];
parent = 0;
for (l = nomap->n_link; l; l = l->l_next) {
n = l->l_to;
if (!(n->n_flag & MAPPED))
continue;
if (parent == 0) {
parent = n;
continue;
}
if (n->n_cost > parent->n_cost)
continue;
if (n->n_cost == parent->n_cost) {
nomap->n_parent = parent;
if (tiebreaker(nomap, n))
continue;
}
parent = n;
}
if (parent == 0)
continue;
(void) dehash(nomap);
l = addlink(parent, nomap, INF, DEFNET, DEFDIR);
nomap->n_parent = parent;
nomap->n_cost = costof(parent, l);
insert(l);
reheap(l);
}
vprintf(stderr, "%d backlinks\n", Nheap);
}
SHAR_EOF
if test 10469 -ne "`wc -c < 'mapit.c'`"
then
echo shar: error transmitting "'mapit.c'" '(should have been 10469 characters)'
fi
fi
echo shar: extracting "'mem.c'" '(3448 characters)'
if test -f 'mem.c'
then
echo shar: will not over-write existing file "'mem.c'"
else
cat << \SHAR_EOF > 'mem.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)mem.c 8.1 (down!honey) 86/01/19";
#endif
#include "def.h"
/* imported */
extern char *sbrk();
link *
newlink()
{
link *rval;
if ((rval = (link * ) calloc(1, sizeof(link))) == 0)
nomem();
return(rval);
}
node *
newnode()
{
node *rval;
if ((rval = (node * ) calloc(1, sizeof(node))) == 0)
nomem();
Ncount++;
return(rval);
}
char *
strsave(s)
char *s;
{
char *r;
if ((r = malloc((unsigned int) strlen(s) + 1)) == 0)
nomem();
(void) strcpy(r, s);
return(r);
}
#ifndef strclear
void
strclear(dst, len)
register char *dst;
register int len;
{
while (--len >= 0)
*dst++ = 0;
}
#endif /*strclear*/
node **
newtable(size)
long size;
{
node **rval;
if ((rval = (node **) calloc(1, (unsigned int) (size * sizeof(*rval)))) == 0)
nomem();
return(rval);
}
freetable(t, size)
node **t;
long size;
{
#ifdef MYMALLOC
addtoheap((char *) t, (long) (size * sizeof(*t)));
#else
free((char *) t);
#endif
}
nomem()
{
fprintf(stderr, "%s: Out of memory (%ldk allocated)\n",
ProgName, allocation());
badmagic(1);
}
/* data space allocation -- main sets End very early */
allocation()
{
static char *dataspace;
if (dataspace == 0) { /* first time */
dataspace = sbrk(0); /* &end? */
return(0);
}
return((sbrk(0) - dataspace)/1024);
}
#ifdef MYMALLOC
/* use c library malloc/calloc here, and here only */
#undef malloc
#undef calloc
extern char *malloc(), *calloc();
/* allocate in MBUFSIZ chunks. 4k works ok (less 16 for malloc quirks). */
#define MBUFSIZ (4 * 1024 - 16)
/*
* mess with ALIGN at your peril. longword (== 0 mod 4)
* alignment seems to work everywhere.
*/
#define ALIGN 2
typedef struct heap heap;
struct heap {
heap *h_next;
long h_size;
};
static heap *Mheap; /* not to be confused with a priority queue */
addtoheap(p, size)
char *p;
long size;
{
int adjustment;
heap *pheap;
/* p is aligned, but it doesn't hurt to check */
adjustment = align(p);
p += adjustment;
size -= adjustment;
if (size < 1024)
return; /* can't happen */
pheap = (heap *) p; /* pheap is shorthand */
pheap->h_next = Mheap;
pheap->h_size = size;
Mheap = pheap;
}
/*
* buffered malloc()
* returns space initialized to 0. calloc isn't used, since
* strclear can be faster.
*
* free is ignored, except for very large objects,
* which are returned to the heap with addtoheap().
*/
char *
mymalloc(n)
register unsigned int n;
{
static long size; /* how much do we have on hand? */
static char *mstash; /* where is it? (kept aligned) */
register char *rval;
n += align((char *) n); /* keep everything aligned */
if (n >= 1024) { /* from hash table */
rval = malloc(n); /* aligned */
strclear(rval, n);
return(rval);
}
if (n > size) {
/* look in the heap (already aligned) */
if (Mheap) {
mstash = (char *) Mheap;
size = Mheap->h_size;
Mheap = Mheap->h_next;
} else {
mstash = malloc(MBUFSIZ); /* aligned */
if (mstash == 0) {
size = 0;
return(0);
}
size = MBUFSIZ;
}
strclear(mstash, size);
}
rval = mstash;
mstash += n;
size -= n;
return(rval);
}
/* what's the (mis-)alignment of n? return the complement of (n mod 2^ALIGN) */
align(n)
char *n;
{
int abits; /* misalignment bits in n */
abits = (int) n & ~(0xff << ALIGN) & 0xff;
if (abits == 0)
return(0);
return((1 << ALIGN) - abits);
}
#endif /*MYMALLOC*/
SHAR_EOF
if test 3448 -ne "`wc -c < 'mem.c'`"
then
echo shar: error transmitting "'mem.c'" '(should have been 3448 characters)'
fi
fi
echo shar: extracting "'printit.c'" '(3713 characters)'
if test -f 'printit.c'
then
echo shar: will not over-write existing file "'printit.c'"
else
cat << \SHAR_EOF > 'printit.c'
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)printit.c 8.1 (down!honey) 86/01/19";
#endif
#include "def.h"
/* use lots of char bufs -- profiling indicates this costs about 5 kbytes */
/* in practice, even the longest paths are < 100 bytes */
#define PSIZE 512
printit()
{ link *l;
char pbuf[PSIZE];
/* print home */
if (Cflag)
printf("%ld\t", (long) Home->n_cost);
printf("%s\t%%s\n", Home->n_name);
strcpy(pbuf, "%s");
for (l = Home->n_link; l; l = l->l_next) {
if (l->l_flag & LTREE) {
preorder(l, pbuf);
strcpy(pbuf, "%s");
}
}
}
/* preorder traversal of shortest path tree */
preorder(l, ppath)
register link *l;
char *ppath;
{
register node *n;
char npath[PSIZE];
setpath(l, ppath, npath);
n = l->l_to;
if ((n->n_flag & NNET) || ISADOMAIN(n))
printnet(n, npath, n->n_cost);
else
printhost(n, npath, n->n_cost);
for (l = n->n_link; l; l = l->l_next)
if (l->l_flag & LTREE)
preorder(l, npath);
}
setpath(l, ppath, npath)
link *l;
register char *ppath, *npath;
{
register node *next;
char netchar;
extern char *hostpath();
next = l->l_to;
/*
* for magic @-% conversion.
* assume that gateways to domains want no @'s
*/
if (next->n_parent->n_flag & ATSIGN || ISADOMAIN(next))
next->n_flag |= ATSIGN;
/* special handling for aliases , domains, and nets */
if ((l->l_flag & LALIAS) || (next->n_flag & NNET) || ISADOMAIN(next)) {
strcpy(npath, ppath);
return;
}
netchar = NETCHAR(l);
if (netchar == '@')
if (next->n_flag & ATSIGN)
netchar = '%'; /* shazam? shaman? */
else
next->n_flag |= ATSIGN;
/* remainder should be a sprintf -- foo on '%' as an operator */
for ( ; *npath = *ppath; ppath++) {
if (*ppath == '%') {
switch(ppath[1]) {
case 's':
ppath++;
npath = hostpath(npath, l, netchar);
break;
case '%':
*++npath = *++ppath;
npath++;
break;
default:
fprintf(stderr, "%s: %%%c found in setpath\n",
ProgName, ppath[1]);
badmagic(1);
break;
}
} else
npath++;
}
}
char *
hostpath(path, l, netchar)
register char *path;
register link *l;
char netchar;
{
register node *prev;
prev = l->l_to->n_parent;
if (NETDIR(l) == LLEFT) {
/* host!user */
strcpy(path, l->l_to->n_name);
path += strlen(path);
while (ISADOMAIN(prev)) {
strcpy(path, prev->n_name);
path += strlen(path);
prev = prev->n_parent;
}
*path++ = netchar;
if (netchar == '%')
*path++ = '%';
*path++ = '%';
*path++ = 's';
} else {
/* %s at host */
*path++ = '%';
*path++ = 's';
*path++ = netchar;
if (netchar == '%')
*path++ = '%';
strcpy(path, l->l_to->n_name);
path += strlen(path);
while (ISADOMAIN(prev)) {
strcpy(path, prev->n_name);
path += strlen(path);
prev = prev->n_parent;
}
}
return(path);
}
STATIC
printhost(n, path, cost)
node *n;
char *path;
Cost cost;
{
/* for collisions, print the domained name only */
if ((n->n_flag & (ISPRIVATE|COLLISION)) == 0) {
if (Cflag)
printf("%ld\t", (long) cost);
fputs(n->n_name, stdout);
putchar('\t');
puts(path);
} else if (ISADOMAIN(n->n_parent))
printdomain(n, path, cost); /* print fully qualified name */
}
STATIC
printnet(n, path, cost)
node *n;
char *path;
Cost cost;
{
/* print gateways */
if (!ISADOMAIN(n))
return;
/* if it's private, print only if qualifed */
if ((n->n_flag & (ISPRIVATE|COLLISION)) && !ISADOMAIN(n->n_parent))
return;
printdomain(n, path, cost);
}
STATIC
printdomain(n, path, cost)
node *n;
char *path;
Cost cost;
{
if (Cflag)
printf("%ld\t", (long) cost);
do {
fputs(n->n_name, stdout);
n = n->n_parent;
} while (ISADOMAIN(n));
putchar('\t');
puts(path);
}
SHAR_EOF
if test 3713 -ne "`wc -c < 'printit.c'`"
then
echo shar: error transmitting "'printit.c'" '(should have been 3713 characters)'
fi
fi
echo shar: extracting "'parse.y'" '(7502 characters)'
if test -f 'parse.y'
then
echo shar: will not over-write existing file "'parse.y'"
else
cat << \SHAR_EOF > 'parse.y'
%{
/* pathalias -- by steve bellovin, as told to peter honeyman */
#ifndef lint
static char *sccsid = "@(#)parse.y 8.1 (down!honey) 86/01/19";
#endif lint
#include "def.h"
/* I thank Paul Haahr and Greg Noel for helping to clean this up. */
%}
%union {
node *y_node;
Cost y_cost;
char y_net;
char *y_name;
struct {
node *ys_node;
Cost ys_cost;
char ys_net;
char ys_dir;
} y_s;
}
%type <y_s> site
%type <y_node> links aliases plist network nlist host Psite Site
%type <y_cost> cost cexpr
%token <y_name> SITE HOST
%token <y_cost> COST
%token <y_net> NET
%token NL PRIVATE
%left '+' '-'
%left '*' '/'
%%
map : /* empty */
| map NL
| map links NL
| map aliases NL
| map network NL
| map private NL
| error NL
;
links : host site cost {
if (GATEWAYED($2.ys_node))
addgateway($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir);
else
addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir);
}
| links ',' site cost {
if (GATEWAYED($3.ys_node))
addgateway($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir);
else
addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir);
}
| links ',' /* permit this benign error */
;
aliases : host '=' Site {alias($1, $3);}
| aliases ',' Site {alias($1, $3);}
| aliases ',' /* permit this benign error */
;
network : host '=' '{' nlist '}' cost {fixnet($1, $4, $6, DEFNET, DEFDIR);}
| host '=' NET '{' nlist '}' cost {fixnet($1, $5, $7, $3, LRIGHT);}
| host '=' '{' nlist '}' NET cost {fixnet($1, $4, $7, $6, LLEFT);}
;
private : PRIVATE '{' plist '}' ;
host : HOST {$$ = addnode($1);}
| PRIVATE {$$ = addnode("private");}
;
Site : SITE {$$ = addnode($1);} ;
site : Site {
$$.ys_node = $1;
$$.ys_net = DEFNET;
$$.ys_dir = DEFDIR;
}
| NET Site {
$$.ys_node = $2;
$$.ys_net = $1;
$$.ys_dir = LRIGHT;
}
| Site NET {
$$.ys_node = $1;
$$.ys_net = $2;
$$.ys_dir = LLEFT;
}
;
Psite : SITE {$$ = addprivate($1);} ;
plist : Psite {$1->n_flag |= ISPRIVATE;}
| plist ',' Psite {$3->n_flag |= ISPRIVATE;}
| plist ',' /* permit this benign error */
;
nlist : Site
| nlist ',' Site {
if ($3->n_net == 0) {
$3->n_net = $1;
$$ = $3;
}
}
| nlist ',' /* permit this benign error */
;
cost : {$$ = DEFCOST; /* empty -- cost is always optional */}
| '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')'
{$$ = $3;}
;
cexpr : COST
| '(' cexpr ')' {$$ = $2;}
| cexpr '+' cexpr {$$ = $1 + $3;}
| cexpr '-' cexpr {$$ = $1 - $3;}
| cexpr '*' cexpr {$$ = $1 * $3;}
| cexpr '/' cexpr {
if ($3 == 0)
yyerror("zero divisor\n");
else
$$ = $1 / $3;
}
;
%%
yyerror(s)
char *s;
{
/* a concession to bsd error(1) */
if (Cfile)
fprintf(stderr, "\"%s\", ", Cfile);
else
fprintf(stderr, "%s: ", ProgName);
fprintf(stderr, "line %d: %s\n", Lineno, s);
}
/*
* patch in the costs of getting on/off the network.
*
* for each network member on netlist, add links:
* network -> member cost = 0;
* member -> network cost = parameter.
*
* if network and member both require gateways, assume network
* is a gateway to member (but not v.v., to avoid such travesties
* as topaz!seismo.css.gov.edu.rutgers).
*
* note that members can have varying costs to a network, by suitable
* multiple declarations. this is a feechur, albeit a useless one.
*/
fixnet(network, nlist, cost, netchar, netdir)
register node *network;
node *nlist;
Cost cost;
char netchar, netdir;
{
register node *member, *nextnet;
link *l;
network->n_flag |= NNET;
/* now insert the links */
for (member = nlist ; member; member = nextnet) {
/* network -> member, cost is 0 */
if (GATEWAYED(network) && GATEWAYED(member))
(void) addgateway(network, member, (Cost) 0, netchar, netdir);
else
(void) addlink(network, member, (Cost) 0, netchar, netdir);
/* member -> network, cost is parameter */
(void) addlink(member, network, cost, netchar, netdir);
nextnet = member->n_net;
member->n_net = 0; /* clear for later use */
}
}
/* scanner */
#define LBRACE '{'
#define RBRACE '}'
#define LPAREN '('
#define RPAREN ')'
#define QUOTE '"'
Cost isacost();
yylex()
{
register int c;
Cost cost;
char buf[BUFSIZ], errbuf[128];
tailrecursion:
if (feof(stdin) && yywrap())
return(EOF);
if ((c = getchar()) == EOF)
goto tailrecursion;
while (c == ' ' || c == '\t')
c = getchar();
if (c == '\n') {
Lineno++;
c = getchar();
if (c == ' ' || c == '\t')
goto tailrecursion;
ungetc(c, stdin);
Scanstate = NEWLINE;
return(NL);
}
if (c == '#') {
while ((c = getchar()) != '\n')
if (c == EOF)
goto tailrecursion;
ungetc(c, stdin);
goto tailrecursion;
}
ungetc(c, stdin);
switch(Scanstate) {
case COSTING:
if (isdigit(c)) {
cost = 0;
for (c = getchar(); isdigit(c); c = getchar())
cost = (cost * 10) + c - '0';
ungetc(c, stdin);
yylval.y_cost = cost;
return(COST);
}
if (getword(buf) == 0) {
if ((yylval.y_cost = isacost(buf)) == 0) {
sprintf(errbuf, "unknown cost (%s), using default", buf);
yyerror(errbuf);
yylval.y_cost = DEFCOST;
}
return(COST);
}
return(getchar()); /* can't be EOF */
case NEWLINE:
Scanstate = OTHER;
if (getword(buf) != 0)
return(getchar()); /* can't be EOF */
/* `private' (but not `"private"')? */
if (c == 'p' && strcmp(buf, "private") == 0)
return(PRIVATE);
yylval.y_name = buf;
return(HOST);
}
if (getword(buf) == 0) {
yylval.y_name = buf;
return(SITE);
}
c = getchar(); /* can't be EOF */
if (index(Netchars, c)) {
yylval.y_net = c;
return(NET);
}
return(c);
}
/*
* fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted
* string that contains no newline. return -1 on failure or EOF, 0 o.w.
*/
getword(str)
register char *str;
{
register int c;
c = getchar();
if (c == QUOTE) {
for ( ; (*str = getchar()) != '"'; str++) {
if (*str == '\n') {
yyerror("newline in quoted string\n");
ungetc('\n', stdin);
return(-1);
}
}
*str = 0;
return(0);
}
/* host name must start with alphanumeric or `.' */
if (!isalnum(c) && c != '.') {
ungetc(c, stdin);
return(-1);
}
yymore:
do {
*str++ = c;
c = getchar();
} while (isalnum(c) || c == '.' || c == '_');
if (c == '-' && Scanstate != COSTING)
goto yymore;
ungetc(c, stdin);
*str = 0;
return(0);
}
static struct ctable {
char *cname;
Cost cval;
} ctable[] = {
/*
* this list is searched sequentially (with strcmps!).
* it is too long. (they are ordered by frequency of
* appearance in a "typical" dataset.)
*
* adding a 0 cost token breaks isacost(). don't do it.
*/
{"DEMAND", 300},
{"DAILY", 5000},
{"DIRECT", 200},
{"EVENING", 1800},
{"LOCAL", 25},
{"LOW", 5}, /* baud rate penalty */
{"HOURLY", 500},
{"POLLED", 5000},
{"DEDICATED", 95},
{"WEEKLY", 30000},
{"DEAD", INF/2},
{"HIGH", -5}, /* baud rate bonus */
/* the remainder are reviled */
{"ARPA", 100},
{"DIALED", 300},
{"A", 300},
{"B", 500},
{"C", 1800},
{"D", 5000},
{"E", 30000},
{"F", INF/2},
0
};
STATIC Cost
isacost(buf)
register char *buf;
{
register struct ctable *ct;
for (ct = ctable; ct->cname; ct++)
if (strcmp(buf, ct->cname) == 0)
return(ct->cval);
return((Cost) 0);
}
yywrap()
{
char errbuf[100];
fixprivate(); /* munge private host definitions */
if (Ifiles == 0)
return(1);
fclose(stdin);
while (*Ifiles) {
Lineno = 1;
if (fopen((Cfile = *Ifiles++), "r"))
return(0);
sprintf(errbuf, "%s: %s", ProgName, Cfile);
perror(errbuf);
}
return(1);
}
SHAR_EOF
if test 7502 -ne "`wc -c < 'parse.y'`"
then
echo shar: error transmitting "'parse.y'" '(should have been 7502 characters)'
fi
fi
exit 0
# End of shell archive
More information about the Mod.sources
mailing list