[comp.sources.misc] v09i064: umdb - UUCP Map Database - part 02/02

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (12/13/89)

Posting-number: Volume 9, Issue 64
Submitted-by: wht%n4hgf@gatech.edu (Warren Tucker)
Archive-name: umdb/part02

---- Cut Here and unpack ----
#!/bin/sh
# this is umdb.02 (part 2 of umdb)
# do not concatenate these parts, unpack them in order with /bin/sh
# file btree.c continued
#
touch 2>&1 | fgrep '[-amc]' > /tmp/s3_touch$$
if [ -s /tmp/s3_touch$$ ]
then
    TOUCH=can
else
    TOUCH=cannot
fi
rm -f /tmp/s3_touch$$
CurArch=2
if test ! -r s3_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s3_seq_.tmp || exit 1
echo "x - Continuing file btree.c"
sed 's/^X//' << 'SHAR_EOF' >> btree.c
X	bt->lstak.sptr = 0;
X	bt->rstak.ele[0] = 0;
X	bt->lstak.ele[0] = 0;
X
X	/* begin at list head */
X	s_nod = bt->sblk.root;
X
X	if(_rnode(s_nod,node,bt))
X		return(BT_ERR);
X	while(1)
X	{
X		/* search to right */
X		if(node->n.rptr != 0)
X		{
X			_pushr(bt,s_nod);
X			s_nod = node->n.rptr;
X			if(_rnode(s_nod,node,bt))
X				return(BT_ERR);
X		}
X		else 
X		{
X			if(node->n.deleted == BT_DELETED)
X			{
X				/* skip all deleted nodes */
X				while(node->n.deleted == BT_DELETED)
X				{
X					if(_btnext(&s_nod,node,bt) == BT_EOF)
X					{
X						if(_btprevious(&s_nod,node,bt) <0)
X							return(BT_ERR);
X						*node_num = s_nod;
X						return(0);
X					}
X				}
X				*node_num = s_nod;
X				return(0);
X			}
X			else 
X			{
X				/* at end of a branch */
X				*node_num = s_nod;
X				return(0);
X			}
X		}
X	}
X}
X
X
X/* go to the head of the file */
Xbthead(node_num,key,recno,bt)
Xshort *node_num;
Xchar **key;
Xlong *recno;
Xstruct btree *bt;
X{
X	static struct btnode_m node;
X	register int retn = _bthead(node_num,&node,bt);
X	*key = node.key;
X	*recno = node.n.recno;
X	return(retn);
X}
X
X/* go to the head of the file */
X_bthead(node_num,node,bt)
Xstruct btree *bt;
Xshort *node_num;
Xregister struct btnode_m *node;
X{
X	short s_nod;
X
X	bt->rstak.sptr = 0;
X	bt->lstak.sptr = 0;
X	bt->rstak.ele[0] = 0;
X	bt->lstak.ele[0] = 0;
X
X	/* begin at list head */
X	s_nod = bt->sblk.root;
X
X	if(_rnode(s_nod,node,bt))
X		return(BT_ERR);
X	while(1)
X	{
X		/* search to left */
X		if(node->n.lptr != 0)
X		{
X			_pushl(bt,s_nod);
X			s_nod = node->n.lptr;
X			if(_rnode(s_nod,node,bt))
X				return(BT_ERR);
X		}
X		else 
X		{
X			if(node->n.deleted == BT_DELETED)
X			{
X				/* skip all deleted nodes */
X				while(node->n.deleted == BT_DELETED)
X				{
X					if(_btprevious(&s_nod,node,bt) == BT_EOF)
X					{
X						if(_btnext(&s_nod,node,bt) <0)
X							return(BT_ERR);
X						*node_num = s_nod;
X						return(0);
X					}
X				}
X				*node_num = s_nod;
X				return(0);
X			}
X			else 
X			{
X				/* at end of a branch */
X				*node_num = s_nod;
X				return(0);
X			}
X		}
X	}
X}
X
X
X
X/* find a key */
Xbtfind(key,node_num,reckey,recno,bt)
Xchar *key;
Xshort *node_num;
Xchar **reckey;
Xlong *recno;
Xstruct btree *bt;
X{
X	register int direction;
X	short s_nod;
X	static struct btnode_m node;
X
X	bt->rstak.sptr = 0;
X	bt->lstak.sptr = 0;
X	bt->rstak.ele[0] = 0;
X	bt->lstak.ele[0] = 0;
X
X	bt->slev = 0;		/* tree level at start of search */
X
X	/* begin at list head */
X	s_nod = bt->sblk.root;
X
X	if(_rnode(s_nod,&node,bt))
X		return(BT_ERR);
X	while((direction = strcmp(key,node.key)) != 0 ||
X	    node.n.deleted == BT_DELETED)
X	{
X
X		if(direction > 0)
X		{
X			/* search to right */
X			if(node.n.rptr != 0)
X			{
X				_pushr(bt,s_nod);
X				s_nod = node.n.rptr;
X				if(_rnode(s_nod,&node,bt))
X					return(BT_ERR);
X			}
X			else if(node.n.deleted == BT_DELETED)
X			{
X				/* skip all deleted nodes */
X				while(node.n.deleted == BT_DELETED)
X				{
X					if(_btnext(&s_nod,&node,bt) == BT_EOF)
X					{
X						if(_btprevious(&s_nod,&node,bt) <0)
X							return(BT_ERR);
X						*recno = node.n.recno;
X						*reckey = node.key;
X						*node_num = s_nod;
X						return(BT_NREC);
X					}
X				}
X				*recno = node.n.recno;
X				*reckey = node.key;
X				*node_num = s_nod;
X				return(BT_NREC);
X			}
X			else 
X			{
X				/* at end of a branch */
X				*recno = node.n.recno;
X				*reckey = node.key;
X				*node_num = s_nod;
X				return(BT_NREC);
X			}
X		}
X		else 
X		{
X			/* search to left */
X			if(node.n.lptr != 0)
X			{
X				_pushl(bt,s_nod);
X				s_nod = node.n.lptr;
X				if(_rnode(s_nod,&node,bt))
X					return(BT_ERR);
X			}
X			else if(node.n.deleted == BT_DELETED)
X			{
X				while(node.n.deleted == BT_DELETED)
X				{
X					if(_btnext(&s_nod,&node,bt) == BT_EOF)
X					{
X						if(_btprevious(&s_nod,&node,bt) < 0)
X							return(BT_ERR);
X						*recno = node.n.recno;
X						*reckey = node.key;
X						*node_num = s_nod;
X						return(BT_NREC);
X					}
X				}
X				*recno = node.n.recno;
X				*reckey = node.key;
X				*node_num = s_nod;
X				return(BT_NREC);
X			}
X			else 
X			{
X				*recno = node.n.recno;
X				*reckey = node.key;
X				*node_num = s_nod;
X				return(BT_NREC);
X			}
X		}
X	}
X	*recno = node.n.recno;
X	*reckey = node.key;
X	*node_num = s_nod;
X	return(0);
X}
X
X/* find the previous node */
Xbtprevious(node_num,key,recno,bt)
Xshort *node_num;
Xchar **key;
Xlong *recno;
Xstruct btree *bt;
X{
X	static struct btnode_m node;
X	register int retn;
X	if(_rnode(*node_num,&node,bt))
X		return(BT_ERR);
X	retn = _btprevious(node_num,&node,bt);
X	*key = node.key;
X	*recno = node.n.recno;
X	return(retn);
X}
X
X/* get the previous node */
X_btprevious(node_num,node,bt)
Xshort *node_num;
Xregister struct btnode_m *node;
Xstruct btree *bt;
X{
X	short _popr();
X	short _popl();
X	short s_nod;
X
X	s_nod = *node_num;
X
X	/* if we are called without a node, wind to the end of file */
X	if(*node_num == 0)
X		return(_bttail(node_num,node,bt));
X
X	do 
X	{
X		if(node->n.lptr == 0)
X		{
X			/* can't move left */
X			if(bt->rstak.sptr == 0)
X			{
X				/* none in stack */
X				if(_rnode(*node_num,node,bt))
X					return(BT_ERR);
X				return(BT_EOF);
X				/* don't reset node_num */
X			}
X			else 
X			{
X				/* can't go left & stack full (pop stack) */
X				s_nod = _popr(bt);
X				if(_rnode(s_nod,node,bt))
X					return(BT_ERR);
X			}
X		}
X		else 
X		{
X			/* left then to bottom right - is previous */
X			_pushl(bt,s_nod);
X			s_nod = node->n.lptr;
X			if(_rnode(s_nod,node,bt))
X				return(BT_ERR);
X			while(node->n.rptr != 0)
X			{
X				/* bottom right */
X				_pushr(bt,s_nod);
X				/* of this sub-tree */
X				s_nod = node->n.rptr;
X				if(_rnode(s_nod,node,bt))
X					return(BT_ERR);
X			}
X		}
X	} while(node->n.deleted == BT_DELETED);
X
X	*node_num = s_nod;
X	return(0);
X}
X
X/* print the btree error message */
Xvoid
Xbtperror(str)
Xchar *str;
X{
X	extern	int errno;
X
X	/* is it ours ?? */
X	if(bterrno)
X	{
X		ff(se,"(btree) %s: %s\n",str,bterrs[bterrno]);
X		bterrno = 0;
X	}
X	if(errno)
X	{
X		fputs("(filesys) ",se);
X		perror(str);
X		errno = 0;
X	}
X}
X
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of btree.c */
SHAR_EOF
echo "File btree.c is complete"
chmod 0644 btree.c || echo "restore of btree.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210180489 btree.c
fi
echo "x - extracting diagnose.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > diagnose.c &&
X/*+-------------------------------------------------------------------------
X	diagnose.c - diagnose problems with btree handler
X	hacked by ...!gatech!kd4nc!n4hgf!wht
X
XCopyright (C) 1988, Marcus J.  Ranum, William Welch Medical Library
X$Author: mjr $ $Log: btree.c,v $ Revision 1.1 88/06/01 21:35:07 mjr
XInitial revision The original code was placed in the public domain.
XThis is not, since I wish to retain some control over it.  No
Xrestrictions are placed on modification, or use of this code, as long as
Xthe copyrights are not removed.  There are some areas that really could
Xuse improving (like handling free nodes better) and I hope that if
Xsomeone makes improvements they will keep me up to date on them (e-mail
Xplease, I am not on usenet).
XMarcus J. Ranum, William Welch Medical Library, 1988
Xmjr@jhuigf.BITNET || uunet!mimsy!aplcen!osiris!welchvax!mjr
X--------------------------------------------------------------------------*/
X/* nobody ever writes nice test programs. in fact, this one is pretty gross */
X/* basically, this allows exercising all the various functions of the btree */
X/* library */
X
X#if defined(pyr) || defined(sun) || defined(BSD4)
X#include <sys/file.h>
X#endif
X
X#if defined(M_SYS5) || defined(SYS5)
X#include <sys/fcntl.h>
X#endif
X
X#include <stdio.h>
X#include "btree.h"
X
Xextern	char *strncpy();
Xextern	char *strcpy();
X
Xmain(ac,av)
Xint ac;
Xchar *av[];
X{
X	BTREE	*h1;
X	struct btnode_m nn;	
X	char instr[BUFSIZ];
X	short node_nbr;
X	char *keystr;
X	long recpos;
X
X	printf("sizeof(struct btsuper) = %d(10) %02x\n",
X		sizeof(struct btsuper),sizeof(struct btsuper));
X	printf("sizeof(struct btnode_m) = %d(10) %02x\n",
X		sizeof(struct btnode_m),sizeof(struct btnode_m));
X	printf("offset of node_num: %02x, len=%02x\n",
X		(int)((char *)&nn.node_num - (char *)&nn),sizeof(nn.node_num));
X	printf("offset of n: %02x, len=%02x\n",
X		(int)((char *)&nn.n - (char *)&nn),sizeof(nn.n));
X	printf("offset of key: %02x, len=%02x\n",
X		(int)(nn.key - (char *)&nn),sizeof(nn.key));
X
X	if(ac < 2) {
X		(void)fprintf(stderr,"usage: %s <file>\n",av[0]);
X		exit(1);
X	}
X
X	if((h1 = btopen(av[1],O_CREAT|O_RDWR,0600,0)) ==NULL) {
X		btperror(av[1]);
X		exit(1);
X	}
X
X	while(1) {
X		(void)printf("Find  Next  Tail  Head  Prev  Insrt  Del  Quit:");
X		if(gets(instr) == NULL)
X			exit(btclose(h1));
X
X		switch(*instr) {
X
X		case 'f':
X		case 'F':
X			(void)printf("\nKey to Find: ");
X			(void)gets(instr);
X			switch(btfind(instr,&node_nbr,&keystr,&recpos,h1)) {
X			case BT_NREC:
X				(void)printf("not found: closest = %s (%ld)\n",keystr,recpos);
X				break;
X			case -1:
X				btperror("find");
X				break;
X			case 0:
X				(void)printf("current=%s (%ld)\n",keystr,recpos);
X				break;
X			default:
X				printf("unknown error code\n");
X				break;
X			}
X			break;
X
X		case 'h':
X		case 'H':
X			switch(bthead(&node_nbr,&keystr,&recpos,h1)) {
X			case -1:
X				btperror("bthead() returns -1");
X				continue;
X				break;
X			default:
X				(void)printf("current=%s (%ld)\n",keystr,recpos);
X			}
X			break;
X
X		case 't':
X		case 'T':
X			switch(bttail(&node_nbr,&keystr,&recpos,h1)) {
X			case -1:
X				btperror("bttail() returns -1");
X				continue;
X				break;
X			default:
X				(void)printf("current=%s (%ld)\n",keystr,recpos);
X			}
X			break;
X
X		case 'd':
X		case 'D':
X			if(btdelete(node_nbr,h1) < 0) {
X				btperror("delete failed");
X			} else {
X				(void)printf("...deleted\n");
X			}
X			break;
X
X		case 'n':
X		case 'N':
X			switch(btnext(&node_nbr,&keystr,&recpos,h1)) {
X			case -1:
X				btperror("btnext() returns -1");
X				continue;
X				break;
X
X			case 0:
X				(void)printf("current=%s (%ld)\n",keystr,recpos);
X				break;
X
X			case BT_EOF:
X				(void)printf("EOF: current=%s (%ld)\n",keystr,recpos);
X				break;
X			}
X			break;
X
X		case 'p':
X		case 'P':
X			switch(btprevious(&node_nbr,&keystr,&recpos,h1)) {
X			case -1:
X				btperror("btprevious() returns -1");
X				continue;
X				break;
X			case 0:
X				(void)printf("current=%s (%ld)\n",keystr,recpos);
X				break;
X			case BT_EOF:
X				(void)printf("SOF: current=%s (%ld)\n",keystr,recpos);
X			}
X			break;
X
X		case 'i':
X		case 'I':
X			(void)printf("Enter a key: ");
X			(void)gets(instr);
X
X			/* h1->sblk.free is used here as arbitrary record # */
X			/* typical use would be to set this to the recno */
X			/* for whatever it is that is being indexed into */
X			if(btinsert(instr,(long)h1->sblk.free,h1) < 0)
X				btperror("insert failed");
X			else
X				(void)printf("...inserted\n");
X			break;
X
X		case 'q':
X		case 'Q':
X			exit(btclose(h1));
X
X		default:
X			(void)printf("huh?\n");
X		}
X	}
X}
X
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of diagnose.c */
SHAR_EOF
chmod 0644 diagnose.c || echo "restore of diagnose.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210180489 diagnose.c
fi
echo "x - extracting umdbdup.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > umdbdup.c &&
X/*+-------------------------------------------------------------------------
X	umdbdup.c
X	...!gatech!kd4nc!n4hgf!wht
X--------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:12-10-1989-02:28-wht-creation */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include "btree.h"
X#include "umdb.h"
X
Xchar *umdb = "/usr/lib/uucp/umdb";
Xchar umdb_name[128];
XFILE *fp_umdb;
XBTREE *bt_name;
X
X/*+-------------------------------------------------------------------------
X	print_dup_umdb_rec(sitename,umdb_pos)
X--------------------------------------------------------------------------*/
Xvoid
Xprint_dup_umdb_rec(sitename,umdb_pos)
Xchar *sitename;
Xlong umdb_pos;
X{
Xint ndbarg;
Xchar *dbfld[DBFLD_COUNT+1];
Xchar dbrec[512];
X
X	if(fseek(fp_umdb,umdb_pos,0))
X	{
X		(void)fprintf(stderr,"seek on ");
X		perror(umdb);
X		exit(1);
X	}
X	if(!fgets(dbrec,sizeof(dbrec),fp_umdb))
X	{
X		(void)fprintf(stderr,"read of ");
X		perror(umdb);
X		exit(1);
X	}
X	build_dbfld_array(dbrec,dbfld,DBFLD_COUNT+1,&ndbarg);
X	printf("%s (%s) in %s\n",sitename,
X		dbfld[DBFLD_SNAME],dbfld[DBFLD_MNAME]);
X
X}	/* end of print_dup_umdb_rec */
X
X/*+-------------------------------------------------------------------------
X	main(argc,argv,envp)
X--------------------------------------------------------------------------*/
Xmain(argc,argv,envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
Xint next_error;
Xchar last_sitename[SYSNAME_MAXLEN + 2];
Xchar *sitename;
Xlong last_umdb_pos;
Xlong umdb_pos;
Xunsigned short node_num;
X
X/* get optional db name */
X	if(!strncmp(argv[1],"-n"))
X	{
X		if(strlen(argv[1]) > 2)
X			umdb = argv[1] + 2;
X		else if(argc < 3)
X		{
X			fputs("-n requires map db name\n",stderr);
X			exit(1);
X		}
X		else
X			umdb = argv[2];
X	}
X
X/* open database main file */
X	if(!(fp_umdb = fopen(umdb,"r")))
X	{
X		perror(umdb);
X		fputs("usage: umdbdup [-n dbname]\n",stderr);
X		exit(1);
X	}
X
X/* build index filename */
X	strcpy(umdb_name,umdb);
X	strcat(umdb_name,".in");
X
X/* open index file */
X	if(!(bt_name = btopen(umdb_name,O_RDONLY,0644,0)))
X	{
X		btperror(umdb_name);
X		exit(1);
X	}
X
X/* read each record, scanning for duplicate names */
X	if(bthead(&node_num,&sitename,&umdb_pos,bt_name))
X	{
X		btperror("bthead");
X		exit(1);
X	}
X	strcpy(last_sitename,sitename);
X	last_umdb_pos = umdb_pos;
X
X	next_error = 0;
X	while(!next_error)
X	{
X		switch(next_error = btnext(&node_num,&sitename,&umdb_pos,bt_name))
X		{
X			case 0:
X				if(!strcmp(sitename,last_sitename))
X				{
X					if(last_umdb_pos >= 0)
X					{
X						print_dup_umdb_rec(sitename,last_umdb_pos);
X						last_umdb_pos = -1L;
X					}
X					print_dup_umdb_rec(sitename,umdb_pos);
X				}
X				else
X				{
X					strcpy(last_sitename,sitename);
X					last_umdb_pos = umdb_pos;
X				}
X				break;
X
X			case BT_EOF:
X				break;
X
X			case BT_ERR:
X				btperror("btnext");
X				exit(1);
X		}
X	}
X
X	exit(0);
X}	/* end of main */
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of umdbdup.c */
SHAR_EOF
chmod 0644 umdbdup.c || echo "restore of umdbdup.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210190389 umdbdup.c
fi
echo "x - extracting umdbpath.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > umdbpath.c &&
X/*+-------------------------------------------------------------------------
X	umdbpath.c - use "smail -A" to print buf and umdb to print other data
X    ...gatech!kd4nc!n4hgf!wht
X--------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:11-13-1989-14:52-wht-creation */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include "btree.h"
X#include "umdb.h"
X
X#if defined(M_SYS5) || defined(SYS5)
X#define index strchr
X#define rindex strrchr
X#endif
X
XFILE *popen();
Xchar *index();
Xchar *basename();
Xchar *index();
Xchar *rindex();
X
Xchar *umdb = "/usr/lib/uucp/umdb";
Xchar umdb_name[128];
XFILE *fp_umdb;
XBTREE *bt_name;
X
X/*+-------------------------------------------------------------------------
X	print_site_info(umdb_pos)
X--------------------------------------------------------------------------*/
Xvoid
Xprint_site_info(umdb_pos)
Xlong umdb_pos;
X{
Xregister itmp;
Xint ndbarg;
Xchar *dbfld[DBFLD_COUNT+1];
Xchar dbrec[512];
Xchar *normalized_loc_to_str();
X
X	if(fseek(fp_umdb,umdb_pos,0))
X	{
X		(void)fprintf(stderr,"seek on ");
X		perror(umdb);
X		exit(1);
X	}
X	if(!fgets(dbrec,sizeof(dbrec),fp_umdb))
X	{
X		(void)fprintf(stderr,"read of ");
X		perror(umdb);
X		exit(1);
X	}
X	build_dbfld_array(dbrec,dbfld,DBFLD_COUNT+1,&ndbarg);
X	(void)fputs(dbfld[DBFLD_SNAME],stdout);
X	itmp = 25 - strlen(dbfld[DBFLD_SNAME]);
X	while(itmp--)
X		(void)fputc(' ',stdout);
X	(void)printf(" %s (%s)\n",
X		normalized_loc_to_str(dbfld[DBFLD_NLOC]),
X		basename(dbfld[DBFLD_MNAME]));
X
X}	/* end of print_site_info */
X
X/*+-------------------------------------------------------------------------
X	find_best_match(given_sys,&dbpos,bt)
X	find_best_match(sys[isys],&umdb_pos,bt_name))
X--------------------------------------------------------------------------*/
Xfind_best_match(given_sys,dbpos,bt)
Xchar *given_sys;
Xlong *dbpos;
XBTREE *bt;
X{
Xregister itmp;
Xregister  char *cptr;
Xshort node_num;
Xchar *site;
Xchar site2[SYSNAME_MAXLEN];
Xlong dbpos2;
X
X	switch(btfind(given_sys,&node_num,&site,&*dbpos,bt))
X	{
X		case BT_NREC:
X			break;
X		case BT_ERR:
X			btperror("find_best_match");
X			exit(1);
X		case 0:
X			return(0);
X	}
X
X	(void)strcpy(site2,site);
X	dbpos2 = *dbpos;
X	if(btnext(&node_num,&site,&*dbpos,bt))
X	{
X		(void)printf("%s not found:",given_sys);
X		(void)printf(" %s is the closest\n");
X		return(BT_NREC);
X	}
X	itmp = strlen(given_sys);
X	if(!strncmp(given_sys,site,itmp) &&
X		(itmp < strlen(site)) && (site[itmp] == '.'))
X	{
X		(void)printf("%s not found:",given_sys);
X		(void)printf(" %s seems to match\n",site);
X		return(0);
X	}
X	else if(!strncmp(given_sys,site2,itmp) &&
X		(itmp < strlen(site2)) && (site2[itmp] == '.'))
X	{
X		(void)printf("%s not found:",given_sys);
X		(void)printf(" %s seems to match\n",site2);
X		*dbpos = dbpos2;
X		return(0);
X	}
X	else if(cptr = rindex(given_sys,'.'))
X	{
X		strncpy(site2,given_sys,cptr - given_sys);
X		site2[cptr - given_sys] = 0;
X		return(find_best_match(site2,dbpos,bt));
X	}
X
X	(void)printf("%s not found:",given_sys);
X	(void)printf (" %s and %s are closest\n",site2,site);
X	return(BT_NREC);
X
X}	/* end of find_best_match */
X
X/*+-------------------------------------------------------------------------
X	main(argc,argv,envp)
X--------------------------------------------------------------------------*/
Xmain(argc,argv,envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
Xregister itmp;
Xregister char *cptr;
Xint iargv = 1;
Xint isys,nsys;
Xunsigned short node_num;
Xlong umdb_pos;
Xchar buf[512];
Xchar path[512];
Xchar *smail_argv[4];
Xchar *sys[MAX_SYSTEMS_PER_PATH+1];
Xchar *site;
XFILE *fp;
X
X/* get optional db name */
X	if(!strncmp(argv[1],"-n"))
X	{
X		if(strlen(argv[1]) > 2)
X		{
X			umdb = argv[1] + 2;
X			iargv = 2;
X		}
X		else if(argc < 3)
X		{
X			(void)fputs("-n requires map db name\n",stderr);
X			exit(1);
X		}
X		else
X		{
X			umdb = argv[2];
X			iargv = 3;
X		}
X	}
X
X/* get buf from smail */
X	(void)strcpy(buf,"smail -A ");
X	(void)strcat(buf,argv[iargv]);
X	if(!index(argv[iargv],'!') && !index(argv[iargv],'!'))
X		(void)strcat(buf,"!username");
X
X	if(!(fp = popen(buf,"r")))
X	{
X		perror("uudbpath: popen to 'smail -A'");
X		exit(1);
X	}
X	if(!fgets(buf,sizeof(buf),fp))
X	{
X		perror("uudbpath: fgets from 'smail -A' pipe");
X		exit(1);
X	}
X	pclose(fp);
X	if(cptr = rindex(buf,'!'))
X		*cptr = 0;
X	(void)printf("path: %s\n",buf);
X
X/* open database main file */
X	if(!(fp_umdb = fopen(umdb,"r")))
X	{
X		perror(umdb);
X		(void)fputs("usage: umdbdup [-n dbname]\n",stderr);
X		exit(1);
X	}
X
X/* build index filename */
X	(void)strcpy(umdb_name,umdb);
X	(void)strcat(umdb_name,".in");
X
X/* open index file */
X	if(!(bt_name = btopen(umdb_name,O_RDONLY,0644,0)))
X	{
X		btperror(umdb_name);
X		exit(1);
X	}
X
X	build_arg_array(buf,sys,MAX_SYSTEMS_PER_PATH+1,&nsys,"!\r\n");
X	for(isys = 0; isys < nsys; isys++)
X	{
X		switch(find_best_match(sys[isys],&umdb_pos,bt_name))
X		{
X			case BT_NREC:
X				break;
X			case BT_ERR:
X				btperror("find");
X				break;
X			case 0:
X				print_site_info(umdb_pos);
X				break;
X		}
X	}
X	exit(0);
X}	/* end of main */
X
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of uupath.c */
SHAR_EOF
chmod 0644 umdbpath.c || echo "restore of umdbpath.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210182289 umdbpath.c
fi
echo "x - extracting umdbuild.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > umdbuild.c &&
X/*+-------------------------------------------------------------------------
X	umdbuild.c
X	...!gatech!emory!tridom!wht
X
XGripes (problems handled):
X1.  Some #N lines contain duplicate system names
X2.  Multiple #N lines have the same .domain name
X3.  A very few entries use '#Name' rather than '#N'
X4.  Several sites place longitude before latitude
X--------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:12-09-1989-16:49-wht-creation */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include "btree.h"
X#include "umdb.h"
X
Xextern char *normalize_location();
X
Xchar *umdb = "/usr/lib/uucp/umdb";
XFILE *fp_umdb;
Xchar umdb_name[128];
XBTREE *bt_name;
X
X#ifdef BUILD_LOC_INDEX
Xchar umdb_loc[128];
XBTREE *bt_loc;
X#endif
X
X/*+-------------------------------------------------------------------------
X	mapfile_to_mapdb(mapname)
X--------------------------------------------------------------------------*/
Xvoid
Xmapfile_to_mapdb(mapname)
Xchar *mapname;
X{
Xregister isite,isite2;
Xint nsite;
Xint found_loc;
Xoff_t mappos;
Xoff_t dbpos;
Xchar mapbuf[512];	/* long map entries? - no stinking problem */
Xchar mapbuf2[512];	/* long map entries? - no stinking problem */
Xchar *site[MAX_SITENAMES_PER_LINE];
Xchar *location;
XFILE *fpmap = fopen(mapname,"r");
Xlong start;
Xlong time();
Xint name_count = 0;
X
X	if(!fpmap)
X	{
X		perror(mapname);
X		return;
X	}
X
X	fprintf(stderr,"%s ... ",mapname);
X	time(&start);
X	start--;	/* show at least 1 second */
X
X	while(1)
X	{
X		/* read map file until #N entry found or EOF */
X		do {
X			mapbuf[0] = 0;
X			mappos = ftell(fpmap);
X		} while(fgets(mapbuf,sizeof(mapbuf),fpmap) &&
X			strncmp(mapbuf,"#N",2));
X
X		/* if EOF, done */
X		if(!mapbuf[0])
X			break;
X
X		/* must be #N entry - build array of site names*/
X		build_sitename_array(mapbuf,site,MAX_SITENAMES_PER_LINE,&nsite);
X
X		/* find #L entry */
X		do {
X			mapbuf2[0] = 0;
X		} while(fgets(mapbuf2,sizeof(mapbuf2),fpmap) &&
X			(found_loc = strlen(mapbuf2) > 1) /* entry ends with blank line */
X			&& strncmp(mapbuf2,"#L",2));
X
X		/* '#Location_of_my_system' will NOT work here; '#L' will :-> */
X		if(found_loc)
X			location = normalize_location(mapbuf2 + 2);
X		else
X			location = " 0.0000,  0.00000,?";
X
X		/* write map db items and name indices, one for each name */
X		dbpos = ftell(fp_umdb);
X		/* site[0] == '#N', '#Name', '#N:-<', etc */
X		for(isite = 1; isite < nsite; isite++)
X		{
X			if(strlen(site[isite]) > SYSNAME_MAXLEN)
X			{
X				fprintf(stderr,
X					"\n  too long a name: %s in  %s\n",site[isite],mapname);
X				continue;
X			}
X/* it was tempting to use this
X			if(*site[isite] == '.')
X				continue;
X*/
X			for(isite2= 0; isite2 < isite; isite2++)
X			{
X				if(!strcmp(site[isite],site[isite2]))
X					goto THIS_NAME_DONE;	/* skip dups on _same_ line */
X			}
X			name_count++;
X			fprintf(fp_umdb,"%s:%s:%s:%ld:\n",
X				location,site[isite],mapname,mappos);
X			if(btinsert(site[isite],dbpos,bt_name))
X			{
X				(void)fputs("\n  ",stderr);
X				btperror(umdb_name);
X				exit(1);
X			}
XTHIS_NAME_DONE: ;
X		}
X
X#ifdef BUILD_LOC_INDEX
X		/* write location index, one for each site */
X		if(btinsert(location,dbpos,bt_loc))
X		{
X			btperror(umdb_loc);
X			exit(1);
X		}
X#endif
X
XSITE_DONE: ;
X	}
X
X	(void)fclose(fpmap);
X	fprintf(stderr,"%d names, %ld seconds\n",
X		name_count,time((long *)0) - start);
X
X}	/* end of mapfile_to_mapdb */
X
X/*+-------------------------------------------------------------------------
X	main(argc,argv,envp)
X--------------------------------------------------------------------------*/
Xmain(argc,argv,envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
Xint iargv = 1;	/* first file argument */
X
X/* usage */
X	if(argc < 2)
X	{
X		(void)fputs(
X			"usage: umdbuild [-n dbname] mapfile [mapfile ...]\n",stderr);
X		exit(1);
X	}
X
X/* get optional db name */
X	if(!strncmp(argv[1],"-n"))
X	{
X		if(strlen(argv[1]) > 2)
X		{
X			umdb = argv[1] + 2;
X			iargv = 2;
X		}
X		else if(argc < 3)
X		{
X			(void)fputs("-n requires map db name\n",stderr);
X			exit(1);
X		}
X		else
X		{
X			umdb = argv[2];
X			iargv = 3;
X		}
X	}
X
X/* check argv exhaustion */
X	if(iargv >= argc)
X	{
X		(void)fputs("no map file names!\n",stderr);
X		exit(1);
X	}
X
X/* build index filenames */
X	(void)strcpy(umdb_name,umdb);
X	(void)strcat(umdb_name,".in");
X
X#ifdef BUILD_LOC_INDEX
X	(void)strcpy(umdb_loc,umdb);
X	(void)strcat(umdb_loc,".il");
X#endif
X
X/* remove old files */
X	(void)unlink(umdb);
X	(void)unlink(umdb_name);
X#ifdef BUILD_LOC_INDEX
X	(void)unlink(umdb_loc);
X#endif
X
X/* open map database */
X	if(!(fp_umdb = fopen(umdb,"w")))
X	{
X		perror(umdb);
X		exit(1);
X	}
X
X/* open index files */
X	if(!(bt_name = btopen(umdb_name,O_CREAT|O_RDWR,0644,SYSNAME_MAXLEN + 2)))
X	{
X		btperror(umdb_name);
X		exit(1);
X	}
X#ifdef BUILD_LOC_INDEX
X	if(!(bt_loc = btopen(umdb_loc,O_CREAT|O_RDWR,0644,LOC_LEN)))
X	{
X		btperror(umdb_loc);
X		exit(1);
X	}
X#endif
X
X/* make available to others */
X	(void)chmod(umdb,0644);
X	(void)chmod(umdb_name,0644);
X#ifdef BUILD_LOC_INDEX
X	(void)chmod(umdb_loc,0644);
X#endif
X
X/* read [du].* files, copying building header db file and indices to same */
X	while(iargv < argc)
X		mapfile_to_mapdb(argv[iargv++]);
X
X/* clean up */
X	fprintf(stderr,"flushing ... ");
X	(void)fclose(fp_umdb);
X	if(btclose(bt_name))
X		btperror(umdb_name);
X#ifdef BUILD_LOC_INDEX
X	if(btclose(bt_loc))
X		btperror(umdb_loc);
X#endif
X
X	fprintf(stderr,"done\n");
X	exit(0);
X
X}	/* end of main */
X
X
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of umdbuild.c */
SHAR_EOF
chmod 0644 umdbuild.c || echo "restore of umdbuild.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210203389 umdbuild.c
fi
echo "x - extracting umdbutil.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > umdbutil.c &&
X/*+-------------------------------------------------------------------------
X	umdbutil.c
X	...!gatech!emory!tridom!wht
X
Xutilities for map data items
X
XNOTE: we cover the those who dont read right and put longitude before
Xlatitude
X--------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:12-09-1989-19:19-wht-creation */
X
X#include <ctype.h>
X#include "umdb.h"
X
X#if defined(M_SYS5) || defined(SYS5)
X#define index strchr
X#define rindex strrchr
X#endif
X
Xchar *index();
Xchar *rindex();
X
X/*+-------------------------------------------------------------------------
X	basename(fullname) - strip directory name from filename
X
Xreturns address of static string
X--------------------------------------------------------------------------*/
Xchar *
Xbasename(fullname)
Xchar *fullname;
X{
Xregister char *start;
Xstatic char outstr[256];
Xchar *strrchr();
X
X	start = rindex(fullname,'/'); /* find last slash */
X	if(!start)
X		return(fullname);
X	start++;
X	strcpy(outstr,start);
X	return(outstr);
X}	/* end of basename */
X
X/*+-----------------------------------------------------------------------
X	arg_token(parsestr,termchars)
X
XGet next token from string parsestr ((char *)0 on 2nd, 3rd, etc.
Xcalls), where tokens are nonempty strings separated by runs of chars
Xfrom termchars.  Writes nulls into parsestr to end tokens.
Xtermchars need not remain constant from call to call.
X
XTreats multiple occurrences of a termchar as one delimiter (does not
Xallow null fields).
X------------------------------------------------------------------------*/
Xstatic char *arg_token_static = (char *)0;
Xchar *arg_token(parsestr,termchars)
Xchar *parsestr;
Xchar *termchars;
X{
Xregister first = 1;
Xregister char *termptr;
Xregister char *parseptr;
Xchar *token;
X
X	if(parsestr == (char *)0 && arg_token_static == (char *)0)
X		return((char *)0);
X
X	if(parsestr)
X		parseptr = parsestr;
X	else
X       parseptr = arg_token_static;
X
X	while(*parseptr)
X	{
X		if(!strchr(termchars,*parseptr))
X			break;
X		parseptr++;
X	}
X
X	if(!*parseptr)
X	{
X		arg_token_static = (char *)0;
X		return((char *)0);
X	}
X
X	token = parseptr;
X	if(*token == '\'')
X	{
X		token++;
X		parseptr++;
X		while(*parseptr)
X		{
X			if(*parseptr == '\'')
X			{
X				arg_token_static = parseptr + 1;
X				*parseptr = 0;
X				return(token);
X			}
X			parseptr++;
X		}
X		arg_token_static = (char *)0;
X		return(token);
X	}
X	while(*parseptr)
X	{
X		if(strchr(termchars,*parseptr))
X		{
X			*parseptr = 0;
X			arg_token_static = parseptr + 1;
X			while(*arg_token_static)
X			{
X				if(!strchr(termchars,*arg_token_static))
X					break;
X				arg_token_static++;
X			}
X			return(token);
X		}
X		parseptr++;
X	}
X	arg_token_static = (char *)0;
X	return(token);
X}	/* end of arg_token */
X
X/*+-------------------------------------------------------------------------
X	build_arg_array(argstr,arg,arg_max_quan,&narg,termchars)
X--------------------------------------------------------------------------*/
Xvoid
Xbuild_arg_array(argstr,arg,arg_max_quan,narg_rtn,termchars)
Xchar *argstr;
Xchar **arg;
Xint arg_max_quan;
Xint *narg_rtn;
Xchar *termchars;
X{
Xregister ilocarg;
Xregister narg;
X
X	for(ilocarg = 0; ilocarg < arg_max_quan; ilocarg++)
X		arg[ilocarg] = (char *)0;
X	arg[0] = arg_token(argstr,termchars);
X
X	for(narg = 1; narg < arg_max_quan; ++narg)
X	{
X		if((arg[narg] = arg_token((char *)0,termchars)) == (char *)0) 
X			break;
X	}
X
X	*narg_rtn = narg;
X
X}	/* end of build_arg_array */
X
X/*+-------------------------------------------------------------------------
X	build_dbfld_array(dbrec,dbfld,dbfld_max,ndbfld_rtn)
X--------------------------------------------------------------------------*/
Xvoid
Xbuild_dbfld_array(dbrec,dbfld,dbfld_max,ndbfld_rtn)
Xchar *dbrec;
Xchar **dbfld;
Xint dbfld_max;
Xint *ndbfld_rtn;
X{
X	build_arg_array(dbrec,dbfld,dbfld_max,ndbfld_rtn,":\r\n");
X}	/* end of build_sitename_array */
X
X/*+-------------------------------------------------------------------------
X	build_sitename_array(sitenmstr,site,site_max,nsite_rtn)
X--------------------------------------------------------------------------*/
Xvoid
Xbuild_sitename_array(sitenmstr,site,site_max,nsite_rtn)
Xchar *sitenmstr;
Xchar **site;
Xint site_max;
Xint *nsite_rtn;
X{
X	build_arg_array(sitenmstr,site,site_max,nsite_rtn,", \t\r\n");
X}	/* end of build_sitename_array */
X
X/*+-------------------------------------------------------------------------
X	array_to_angle(array,arraylen,&angle)
Xlatitude 0 at equator, longitude as degrees west
Xreturns ANGLE_? define from umdb.h
X--------------------------------------------------------------------------*/
Xint
Xarray_to_angle(array,arraylen,angle)
Xchar **array;
Xint arraylen;
Xdouble *angle;
X{
Xint iarray;
Xdouble atof();
X
X	*angle = 0.0;
X	for(iarray = 0; iarray < arraylen; iarray++)
X	{
X		if(!isdigit(*array[iarray]))
X		{
X			switch(tolower(*array[iarray]))
X			{
X				case 'n':
X					return(ANGLE_LATITUDE);
X				case 's':
X					*angle *= -1.0;
X					return(ANGLE_LATITUDE);
X				case 'w':
X					return(ANGLE_LONGITUDE);
X				case 'e':
X					*angle = 360.0 - *angle;
X					return(ANGLE_LONGITUDE);
X			}
X			return(ANGLE_BAD);	/* bad direction */
X		}
X		switch(iarray)
X		{
X			case 0: *angle = atof(array[iarray]); break;
X			case 1: *angle += atof(array[iarray]) / 60.0; break;
X			case 2: *angle += atof(array[iarray]) / 3600.0; break;
X			default: return(ANGLE_BAD);
X		}
X	}
X
X	/* NSEW char HAS to be present because SLOBS put long. before lat. */
X	return(ANGLE_BAD);
X			
X}	/* end of array_to_angle */
X
X/*+-------------------------------------------------------------------------
X	build_normalized_locfld(locfld,latitude,longitude,city)
X
Xcity == 0, exact long,lat; == 1, CITY; == -1, bad format was detected
X--------------------------------------------------------------------------*/
Xvoid
Xbuild_normalized_locfld(locfld,latitude,longitude,city)
Xchar *locfld;	/* must be at least LOC_LEN chars in length */
Xdouble latitude;
Xdouble longitude;
Xint city;
X{
X	(void)sprintf(locfld,"%8.4f,%8.4f,%c",latitude,longitude,
X		(city) ?  ((city < 0) ? '?' : 'C') : 'X');
X
X}	/* end of build_normalized_locfld */
X
X/*+-------------------------------------------------------------------------
X	normalize_location(locstr)
X--------------------------------------------------------------------------*/
Xchar *
Xnormalize_location(locstr)
Xchar *locstr;
X{
Xregister ilocarg;
X#define LOCARGS 25	/* plenty - avoid overflow today! */
Xchar *locargs[LOCARGS];
Xint nlocargs;
Xint city = 0;
Xint got_latitude = 0;
Xint got_longitude = 0;
Xdouble angle;
Xdouble longitude = 0.0;
Xdouble latitude = 0.0;
Xstatic char locfld[LOC_LEN];
X
X	build_arg_array(locstr,locargs,LOCARGS,&nlocargs," \r\n\t");
X	switch(array_to_angle(locargs,nlocargs,&angle))
X	{
X		case ANGLE_LATITUDE:
X			latitude = angle;
X			got_latitude = 1;
X			break;
X		case ANGLE_LONGITUDE:
X			longitude = angle;
X			got_longitude = 1;
X			break;
X		case ANGLE_BAD:
X			city = -1;
X			break;
X	}
X
X	for(ilocarg =  0; ilocarg < nlocargs; ilocarg++)
X	{
X		if(*locargs[ilocarg] == '/')
X		{
X			switch(array_to_angle(locargs + ilocarg + 1,
X									nlocargs - ilocarg - 1,&angle))
X			{
X				case ANGLE_LATITUDE:
X					latitude = angle;
X					if(got_latitude)
X						city = -1;
X					got_latitude = 1;
X					break;
X				case ANGLE_LONGITUDE:
X					longitude = angle;
X					if(got_longitude)
X						city = -1;
X					got_longitude = 1;
X					break;
X				case ANGLE_BAD:
X					city = -1;
X					break;
X			}
X		}
X		else if((!strcmp(locargs[ilocarg],"CITY") ||
X				!strcmp(locargs[ilocarg],"city")) && !city)
X			city = 1;
X	}
X
X	if(!got_latitude || !got_longitude)
X		city = -1;
X
X	build_normalized_locfld(locfld,latitude,longitude,city);
X	return(locfld);
X
X}	/* end of normalize_location */
X
X/*+-------------------------------------------------------------------------
X	normalized_loc_to_str(nloc)
X--------------------------------------------------------------------------*/
Xchar *
Xnormalized_loc_to_str(nloc)
Xchar *nloc;
X{
Xfloat latitude,longitude;
Xchar city = '?';
Xchar lat_NS = 'N';
Xchar long_EW = 'W';
Xstatic char presentable[64];
X
X	sscanf(nloc,"%f,%f,%c",&latitude,&longitude,&city);
X	if(latitude < 0.0)
X	{
X		latitude *= -1;
X		lat_NS = 'S';
X	}
X	if(longitude > 180.0)
X	{
X		longitude = 360.0 - longitude;
X		long_EW = 'E';
X	}
X
X	sprintf(presentable,"%7.4f %c %8.4f %c %s",
X		latitude,lat_NS,
X		longitude,long_EW,
X		((city == 'X') ? "    " : ((city == 'C') ? "city" : "??  ")));
X
X	return(presentable);
X
X}	/* end of normalized_loc_to_str */
X
X/* vi: set tabstop=4 shiftwidth=4: */
X/* end of umdbutil.c */
SHAR_EOF
chmod 0644 umdbutil.c || echo "restore of umdbutil.c fails"
if [ $TOUCH = can ]
then
    touch -m 1210195289 umdbutil.c
fi
rm -f s3_seq_.tmp
echo "You have unpacked the last part"
exit 0