holloway@drivax.UUCP (03/25/87)
"path" is a quick utility to find paths from the local site to a remote
one. It uses pathalias to generate its database, which is incorporated into
the program in a highly compressed form.
Two utility programs massage the pathalias database before "path" gets hold
of it.
"pathfix" creates paths to certain domain gateways and leaf nodes in order
to facilitate the creation of the database, and
"walkdb" creates the ".c" files which make up the database. Ignore any
warnings from these two programs... they'll stop and tell you if there's
a serious problem.
"path" generates paths to sites, but it can also shorten those long
paths that "Rnmail" gets when you reply to netnews. The following
context diff illustrates this:
*** Rnmail.old Thu Mar 12 12:06:07 1987
--- Rnmail Thu Mar 12 14:58:56 1987
***************
*** 49,54
cat=/bin/cat
grep=/usr/ucb/grep
rm=/bin/rm
tmpart=/tmp/rnmail$$
dotdir=${DOTDIR-${HOME-$LOGDIR}}
--- 49,56 -----
cat=/bin/cat
grep=/usr/ucb/grep
rm=/bin/rm
+ mv=/bin/mv
+ lpath=/usr/local/bin/path
tmpart=/tmp/rnmail$$
dotdir=${DOTDIR-${HOME-$LOGDIR}}
***************
*** 59,64
*) case $1 in
-h)
headerfile="$2"
case $# in
3) oldart=$3 ;;
esac
--- 61,71 -----
*) case $1 in
-h)
headerfile="$2"
+ # cat $headerfile
+ $lpath -h <$headerfile >$tmpart
+ # cat $tmpart
+ $mv $tmpart $headerfile
+ # cat $headerfile
case $# in
3) oldart=$3 ;;
esac
#------------------------cut here-------------------------------------
#! /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:
# README
# Makefile
# path.1
# path.c
# pathfix.c
# walkdb.c
# walkdb.h
# This archive created: Wed Mar 25 12:42:27 1987
# By: Bruce Holloway (Digitalis Research, Inc.)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(1443 characters)'
if test -f 'README'
then
echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
"path" is a quick utility to find paths from the local site to a remote
one. It uses pathalias to generate its database, which is incorporated into
the program in a highly compressed form.
Two utility programs massage the pathalias database before "path" gets hold
of it.
"pathfix" creates paths to certain domain gateways and leaf nodes in order
to facilitate the creation of the database, and
"walkdb" creates the ".c" files which make up the database. Ignore any
warnings from these two programs... they'll stop and tell you if there's
a serious problem.
"path" generates paths to sites, but it can also shorten those long
paths that "Rnmail" gets when you reply to netnews. The following
context diff illustrates this:
*** Rnmail.old Thu Mar 12 12:06:07 1987
--- Rnmail Thu Mar 12 14:58:56 1987
***************
*** 49,54
cat=/bin/cat
grep=/usr/ucb/grep
rm=/bin/rm
tmpart=/tmp/rnmail$$
dotdir=${DOTDIR-${HOME-$LOGDIR}}
--- 49,56 -----
cat=/bin/cat
grep=/usr/ucb/grep
rm=/bin/rm
+ mv=/bin/mv
+ lpath=/usr/local/bin/path
tmpart=/tmp/rnmail$$
dotdir=${DOTDIR-${HOME-$LOGDIR}}
***************
*** 59,64
*) case $1 in
-h)
headerfile="$2"
case $# in
3) oldart=$3 ;;
esac
--- 61,71 -----
*) case $1 in
-h)
headerfile="$2"
+ # cat $headerfile
+ $lpath -h <$headerfile >$tmpart
+ # cat $tmpart
+ $mv $tmpart $headerfile
+ # cat $headerfile
case $# in
3) oldart=$3 ;;
esac
SHAR_EOF
fi
echo shar: "extracting 'Makefile'" '(763 characters)'
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Makefile for PATH - requires PATHALIAS and the Usenet MAP.
#
# Should work on any Unix system, but I've only tried it on BSD4.2.
#
# v1.0 03/25/87 Bruce Holloway (drivax!holloway)
pathalias = /usr/local/bin/pathalias
getopt = /usr/local/bin/getopt.o
# MAP describes the location of the Usenet MAP files.
MAP = *.map /scratch/map/u.* /scratch/map/d.*
all: pathfix walkdb path
path: pathmap.a path.o
cc -o path -O path.o pathmap.a $(getopt)
pathmap.a: $(MAP)
$(pathalias) $(MAP) >path.out
pathfix <path.out >path.fix
walkdb <path.fix
cc -c *.map.c
rm pathmap.a
ar r pathmap.a master.map.o br*.map.o
ranlib pathmap.a
rm *.map.*
pathfix: pathfix.o
cc -o pathfix -O pathfix.o
walkdb: walkdb.o
cc -o walkdb -O walkdb.o
path.o walkdb.o: walkdb.h
SHAR_EOF
fi
echo shar: "extracting 'path.1'" '(1555 characters)'
if test -f 'path.1'
then
echo shar: "will not over-write existing file 'path.1'"
else
cat << \SHAR_EOF > 'path.1'
.TH PATH 1 "25 March 1987"
.UC 4
.SH NAME
path \- find the best path to a UUCP site
.SH SYNOPSIS
.B path
site [site...]
.PP
.B path
-s pattern
.PP
.B path
-h <mail-header
.PP
.B path
-r path [path...]
.SH DESCRIPTION
This is a handy program to have when you're trying to find a path to a
machine, when all you have is its name. Also nice for finding cheap paths
to a
.I very
remote machine, like
.I ihnp4.
.PP
.I path
understands domains, and will generate paths to the correct domain gateway
if no more direct path was found.
.I path
also understands the special case of the
.I .UUCP
domain, and will try to route the path directly to the destination site
before it tries for the gateway.
.TP 5
.B \-s
This searches for paths to all sites matching the regular expression
.I pattern.
.TP 5
.B \-r
Takes the full path to a user at another site, and finds a shorter or
cheaper path to it. If the destination site is unknown,
.I path
tries to find a path to the previous site on the list, and so on, until
it reaches the beginning of the list. If it still hasn't found a correct
path, it will assume the one given is correct and return that.
.TP 5
.B \-h
Takes a standard mail or news header from standard input, and replaces
each path in a
.B To:
line with a shorter one, as in the
.I \-r
option.
This allows
.I Rnmail
(with a little modification) to automatically find shorter and
more reliable sites through
which to return mail than the ones given by default.
.TP 5
.I site
Any valid UUCP site name.
.SH AUTHOR
Bruce Holloway (holloway@drivax.UUCP)
SHAR_EOF
fi
echo shar: "extracting 'path.c'" '(5175 characters)'
if test -f 'path.c'
then
echo shar: "will not over-write existing file 'path.c'"
else
cat << \SHAR_EOF > 'path.c'
#include <stdio.h>
#include "walkdb.h"
#undef DEBUG
extern WALK *dbase[];
extern int strcmp();
extern char *rindex();
extern char *index();
int strccmp();
WALK *lastsite = 0;
char prgname[128];
char site[128];
int numsites = 2;
char xpath[512];
int fullpath = 0;
int main(acnt,avar)
int acnt;
char *avar[];
{
char *s;
int argc, i;
extern int optind;
extern char *optarg;
if(s = rindex(avar[0],'/')) ++s;
else s = avar[0];
strcpy(prgname,s);
if(acnt < 2){
fprintf(stderr,"%s: usage: %s <site> {<site>...}\n",prgname,prgname);
exit(3);
}
while((i=getopt(acnt,avar,"s:rh")) != EOF){
switch(i){
case 's': /* Search for map */
ssearch(optarg);
break;
case 'r':
fullpath = 1;
break;
case 'h':
header();
return(0);
}
}
numsites = acnt - optind;
for(; optind < acnt; ++optind){
if(fullpath) upath(1,avar[optind]);
else{
strcpy(site,avar[optind]);
findsite(1,xpath);
}
}
}
header(){
char iline[256];
extern char *gets();
fullpath = 1;
numsites = 1;
while(gets(iline)){
if(!strncmp(iline,"To: ",4)){
upath(0,&iline[4]);
strcpy(&iline[4],xpath);
}
printf("%s\n",iline);
}
}
upath(prnt,fpath)
int prnt;
char *fpath;
{
char uname[256];
char itsite[256];
int numbang, i;
char *s;
for(s=fpath, i=0; *s; ++s) i += (*s == '!');
if(i < 2){
strcpy(xpath,fpath);
if(prnt) printf("%s\n",fpath);
return;
}
for(numbang=1;; ++numbang){
strcpy(itsite,fpath);
for(s = &itsite[strlen(itsite)], i=0; s != itsite &&
i < numbang ; --s)
if(*s == '!') ++i;
if(i != numbang){
fprintf(stderr,"%s: couldn't find a known site.\n",prgname);
break;
}
++s;
strcpy(uname,s+1);
*s = 0;
s = rindex(itsite,'!');
if(!s) s = itsite; else ++s;
strcpy(site,s);
if(findsite(0,xpath)){
strcat(xpath,"!");
strcat(xpath,uname);
if(prnt) printf("%s\n",xpath);
break;
}
}
}
findsite(prnt,pname)
int prnt;
char *pname;
{
#ifdef DEBUG
fprintf(stderr,"findsite(0x%02x,pname) - site = %s\n",prnt,site);
#endif
if(!(prnt & 0x80) && index(site,'.')) return(dodomain(prnt,pname));
else{
*pname = 0;
if(!search(site[0],site,strcmp,pname) &&
!search(chlower(site[0]),site,strccmp,pname) &&
!search(chupper(site[0]),site,strccmp,pname)){
if(!(prnt & 0x40) && !fullpath)
fprintf(stderr,"%s: Can't find a path to %s\n",prgname,site);
return(0);
}
else{
if(prnt & 0x1){
printf("%s\n",pname);
}
return(1);
}
}
}
dodomain(prnt,pname)
int prnt;
char *pname;
{
char *s;
char tsite[256];
char tpath[256];
#ifdef DEBUG
fprintf(stderr,"dodomain(0x%02x,pname)\n",prnt);
#endif
lastsite = 0;
s = index(site,'.');
strcpy(tsite,site);
strcpy(site,s);
if(!strccmp(site,".uucp")){
strcpy(site,tsite);
*s = 0;
if(findsite(0xC0|prnt,pname)) return(1);
strcpy(site,".uucp");
}
if(findsite(0xC0,tpath)){
if(lastsite) strcpy(index(tsite,'.'),lastsite->wname);
if((numsites > 1) && (s = index(tpath,':'))){
strcpy(pname,s);
strcpy(tpath,tsite);
strcat(tpath,pname);
}
sprintf(pname,"%s!%s",tpath,tsite);
if(prnt & 1) printf("%s\n",pname);
return(1);
}
else{
strcpy(site,tsite);
return(findsite(prnt|0x80,pname));
}
}
int chlower(ch)
int ch;
{
return((ch >= 'A' && ch <= 'Z') ? ch-'A'+'a' : ch);
}
int chupper(ch)
int ch;
{
return((ch >= 'a' && ch <= 'z') ? ch-'a'+'A' : ch);
}
int strccmp(s1,s2)
char *s1, *s2;
{
while(*s1 && *s2 && chlower(*s1) == chlower(*s2)) ++s1, ++s2;
return(chlower(*s1) - chlower(*s2));
}
ssearch(s)
char *s;
{
register WALK *wr;
register int j, i;
int numfound = 0;
char *e;
extern char *re_comp();
extern int re_exec();
e = re_comp(s);
if(e){
fprintf(stderr,"%s: %s\n",prgname,e);
return;
}
for(i=0; i<128; ++i){
if(!(wr = dbase[i])) continue;
for(j=0; wr; ++j, ++wr){
if(!(*(wr->wname))) break;
if(re_exec(wr->wname) == 1){
strcpy(site,wr->wname);
++numfound;
findsite(1,xpath);
}
}
}
if(!numfound)
fprintf(stderr,"%s: Couldn't find any sites matching \"%s\".\n",
prgname,s);
}
int search(i,s,fn,pname)
int i;
char *s, *pname;
int (*fn)();
{
register WALK *wr;
register int j;
#ifdef DEBUG
fprintf(stderr,"search(0x%02x,\"%s\",fn,pname)\n",i,s);
#endif
if(!(wr = dbase[i])) return(0);
for(j=0; wr; ++j, ++wr){
if(!(*(wr->wname))) break;
if(!((*fn)(wr->wname,s))){
follow(i,j,pname);
return(1);
}
}
return(0);
}
follow(oi,oj,pname)
int oi, oj;
char *pname;
{
int i, j;
WALK *w;
w = dbase[oi & 0x7F];
w += oj;
i = w->wflag;
j = w->windex;
#ifdef DEBUG
fprintf(stderr,"%s: follow(0x%02x,0x%02x);\n",prgname,oi,oj);
fprintf(stderr,"\twname=\"%s\", wflag=0x%02x, windex=0x%02x.\n",
w->wname,i,j);
#endif
if((i & 0x7F) == oi && j == oj){
if(numsites > 1) sprintf(pname+strlen(pname),"%s: ",site);
strcat(pname,w->wname);
return(1);
}
follow(i & 0x7F,j,pname);
if(!(i & 0x80))
sprintf(pname+strlen(pname),"!%s",w->wname);
lastsite = w;
return(0);
}
SHAR_EOF
fi
echo shar: "extracting 'pathfix.c'" '(1569 characters)'
if test -f 'pathfix.c'
then
echo shar: "will not over-write existing file 'pathfix.c'"
else
cat << \SHAR_EOF > 'pathfix.c'
#include <stdio.h>
extern char *gets();
extern char *malloc();
extern char *index(), *rindex();
char iline[256];
#define PATH struct _zap
PATH{
PATH *next;
char *site;
char *path;
};
#define newpath() (PATH *)malloc(sizeof(PATH))
PATH *paths = 0;
main(){
while(gets(iline)){
addpath();
}
fixpaths();
writepaths();
}
addpath(){
char *s;
char *s1;
char *s2, *s3;
PATH *p;
s = index(iline,'\t');
if(!s){
fprintf(stderr,"No tab in path - \"%s\".\n",iline);
return;
}
*s = 0;
s1 = s+1;
s = rindex(s1,'!');
if(!s){
fprintf(stderr,"No bang in path - \"%s\t%s\".\n",iline,s1);
s = s1;
}
*s = 0;
p = newpath();
if(!p) outofmem();
s2 = malloc(strlen(iline)+1);
if(!s2) outofmem();
s3 = malloc(strlen(s1)+1);
if(!s3) outofmem();
p->next = paths;
paths = p;
strcpy(s2,iline);
strcpy(s3,s1);
p->site = s2;
p->path = s3;
}
outofmem(){
fprintf(stderr,"Out of memory.\n");
exit(1);
}
fixpaths(){
register PATH *p1, *p2;
register char *s;
for(p1=paths; p1; p1=p1->next){
s = rindex(p1->path,'!');
if(!s) continue;
++s;
if(!strcmp(s,p1->site)) continue;
for(p2=paths; p2; p2=p2->next){
if(!strcmp(s,p2->site)) goto cmain;
}
sprintf(iline,"%s\t%s!%%s",s,p1->path);
fprintf(stderr,"Adding line: \"%s\".\n",iline);
addpath();
cmain: ;
}
}
writepaths(){
register PATH *p;
for(p=paths; p; p=p->next){
if(*(p->path))
printf("%s\t%s!%%s\n",p->site,p->path);
else
printf("%s\t%%s\n",p->site);
}
}
SHAR_EOF
fi
echo shar: "extracting 'walkdb.c'" '(3754 characters)'
if test -f 'walkdb.c'
then
echo shar: "will not over-write existing file 'walkdb.c'"
else
cat << \SHAR_EOF > 'walkdb.c'
#include <stdio.h>
extern char *gets();
extern char *malloc();
extern char *index();
extern char *rindex();
char *zalloc();
#define node struct _node
node {
node *nnext;
char *myname;
char *rname;
char *lname;
};
char msg_string[] = "string";
char msg_node[] = "node";
node *leaf[128];
char iline[1024];
#define newstr(s) zalloc(msg_string,strlen(s)+1)
#define newnode() (node *)zalloc(msg_node,sizeof(node))
main(){
int i;
for(i=0; i<128;) leaf[i++] = (node *)0;
while(gets(iline)) addnode();
writenode();
}
addnode(){
int i;
node *n;
char *s, *s1, *s2;
char *dstnode, *leafnode, *rootnode;
static char zap[] = "!!";
static char zip[] = "!!";
dstnode = leafnode = rootnode = 0;
s = index(iline,'\t');
if(!s){
fprintf(stderr,"warning: no tab in \"%s\".\n",iline);
return;
}
dstnode = iline;
*s = 0; s1 = s+1;
s = rindex(s1,'!');
if(!s){
fprintf(stderr,"warning: better be host name \"%s\".\n",iline);
return;
}
*s = 0;
s2 = rindex(s1,'!');
if(!s2){
leafnode = s1;
fprintf(stderr,"warning: better be direct link \"%s\".\n",iline);
s2 = &zip[1];
strcpy(zip,zap);
}
else leafnode = s2+1;
*s2 = 0;
s2 = rindex(s1,'!');
if(!s2) s2 = s1;
else ++s2;
rootnode = s2;
if(strcmp(dstnode,leafnode)) rootnode = 0;
else leafnode = 0;
#if 0
if(rootnode)
fprintf(stderr,"parent of %s is %s\n",dstnode,rootnode);
else
fprintf(stderr,"alias of %s is %s\n",dstnode,leafnode);
#endif
n = newnode();
n->myname = newstr(dstnode);
strcpy(n->myname,dstnode);
if(rootnode){
n->rname = newstr(rootnode);
strcpy(n->rname,rootnode);
}
else n->rname = 0;
if(leafnode){
n->lname = newstr(leafnode);
strcpy(n->lname,leafnode);
}
else n->lname = 0;
i = *dstnode;
n->nnext = leaf[i];
leaf[i] = n;
}
char *zalloc(reason,size)
char *reason;
unsigned size;
{
char *s;
s = malloc(size);
if(!s){
fprintf(stderr,"Couldn't allocate %d bytes for a %s.\n",size,reason);
exit(1);
}
return(s);
}
writenode(){
int i, j;
register node *n;
FILE *ochan;
char zap[50];
fprintf(stderr,"writing nodes now.\n");
for(i=0; i<128; ++i)
if(n=leaf[i]){
sprintf(zap,"br%d.map.c",i);
ochan = fopen(zap,"w");
if(!ochan){
fprintf(stderr,"Couldn't open %s for writing.\n",zap);
exit(2);
}
fprintf(ochan,"#include \"walkdb.h\"\n\n");
for(j=0; n; ++j, n=n->nnext);
++j;
fprintf(ochan,"WALK br%d[%d] = {\n",i,j);
for(n=leaf[i]; n; n=n->nnext){
fprintf(ochan," { \"%s\", 0x", n->myname);
if(n->rname){
fprintf(ochan,"%02x, ",*(n->rname));
j = lookfor(n->rname);
}
else{
fprintf(ochan,"%02x, ",*(n->lname) + 0x80);
j = lookfor(n->lname);
}
fprintf(ochan,"%d },\n",j);
}
fprintf(ochan," { \"\", 0, 0 }\n};\n\n");
fclose(ochan);
}
ochan = fopen("master.map.c","w");
if(!ochan){
fprintf(stderr,"Couldn't open master.map.c for writing.\n");
exit(3);
}
fprintf(ochan,"#include \"walkdb.h\"\n\n");
for(i=0; i<128; ++i)
if(leaf[i])
fprintf(ochan,"extern WALK br%d[];\n",i);
fprintf(ochan,"\n\nWALK *dbase[129] = {\n");
for(i=0; i<128; ++i){
if(leaf[i]) fprintf(ochan," br%d,\n",i);
else fprintf(ochan," 0,\n");
}
fprintf(ochan," 0\n};\n");
fclose(ochan);
}
lookfor(s)
char *s;
{
register int i, j;
register node *n;
char *e;
i = *s;
n = leaf[i];
if(!n){ e = "bad initial character"; goto error; }
for(j=0; n; ++j, n=n->nnext){
if(!strcmp(s,n->myname))
return(j);
}
e = "node not in leaf";
error:
fprintf(stderr,"lookfor(%s) - %s.\n",s,e);
return(-1);
}
SHAR_EOF
fi
echo shar: "extracting 'walkdb.h'" '(85 characters)'
if test -f 'walkdb.h'
then
echo shar: "will not over-write existing file 'walkdb.h'"
else
cat << \SHAR_EOF > 'walkdb.h'
#define WALK struct _walk
WALK {
char *wname;
int wflag;
int windex;
};
SHAR_EOF
fi
exit 0
# End of shell archive
--
Bruce Holloway - Relapsed Newsaholic
{seismo,hplabs,sun,ihnp4}!amdahl!drivax!holloway
Put the power of RANDOM NUMBERS to work FOR YOU!