[alt.sources] tcm - merge/check termcap files

ccsam@castor.ucdavis.edu (Sam McCall) (08/08/89)

#! /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:
#	Makefile
#	tcm.8
#	mkdep
#	newvers.sh
#	README
#	RELEASE
#	tcm.c
#	tcm.h
# This archive created: Mon Aug  7 10:58:23 1989
# By:	Sam McCall ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(844 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	X#
	X# makefile for tcm
	X#
	XCC=/bin/cc
	XCFLAGS=-O
	X
	XSRCS	= tcm.c
	XINCS	= tcm.h
	XOBJS	= tcm.o version.o
	XLIBS	=
	XETC	= Makefile tcm.8 mkdep newvers.sh README RELEASE
	XALL	= $(ETC) $(SRCS) $(INCS)
	XTARGETS	= tcm
	XPACKAGE	= tcm
	X
	Xall:	$(TARGETS)
	X
	Xtcm:	$(OBJS)
	X	$(CC) -o tcm $(OBJS) $(LIBS)
	X
	X.c.o:
	X	$(CC) $(CFLAGS) -c $<
	X
	Xversion.c:	always
	X	/bin/sh newvers.sh
	X
	Xdepend:
	X	/bin/sh mkdep $(SRCS)
	X
	Xclean:
	X	rm -f $(TARGETS) $(OBJS) version.c VERSION core a.out \
	X		$(PACKAGE).tar $(PACKAGE).shar
	X
	Xlint:	
	X	lint $(SRCS)
	X
	Xtar:	
	X	tar cvf $(PACKAGE).tar $(ALL)
	X
	Xshar:
	X	shar -a $(ALL) > $(PACKAGE).shar
	X
	Xalways:
	X
	X# DO NOT DELETE THIS LINE -- mkdep uses it.
	X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
	X
	Xtcm.o: tcm.c /usr/include/stdio.h /usr/include/ctype.h /usr/include/sys/types.h
	Xtcm.o: /usr/include/sys/stat.h tcm.h
	X
	X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
SHAR_EOF
if test 844 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 844 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tcm.8'" '(4738 characters)'
if test -f 'tcm.8'
then
	echo shar: will not over-write existing file "'tcm.8'"
else
sed 's/^	X//' << \SHAR_EOF > 'tcm.8'
	X.\"
	X.\" -sam Mon May 29 16:44:58 PDT 1989
	X.\"
	X.\" @(#)tcm.8 1.0 alpha 89/05/27
	X.TH TCM 8 "29 May 1989"
	X.SH NAME
	Xtcm \- merge termcap files
	X.SH SYNOPSIS
	X.B tcm
	X[
	X.B \-ns
	X]
	X[
	X.I output-file
	X]
	X.I filename
	X\&.\|.\|.
	X.SH VERSION
	XVersion 1.0, alpha release
	X.SH DESCRIPTION
	X.LP
	X.B tcm
	Xmakes an attempt at rationally combining termcap files, while also
	Xdoing some consistency checking and preserving the relative ordering
	Xof the entries in the files.
	XFor each 
	X.I filename
	Xgiven, 
	X.B tcm
	Xreads the termcap entries from that file, doing many consistency
	Xchecks, noting the termcap's body and whether it is unique, and
	Xalso noting the names for the termcap and whether they are unique.
	XOne should note that, because the files are processed in left to
	Xright order, the termcaps in the files listed first have a higher
	Xpriority than the termcaps listed in the files listed last, even
	Xthoug an attempt is made to preserve their relative ordering.
	X.PP
	XWhen a termcap is read that is unique, and all of its names are
	Xunique, these are all stored away for later use.
	X.PP
	XWhen a termcap is read that is unique, and some of its names are
	Xnot unique, the user is prompted to change, delete, or ignore this
	Xname, unless the "smart" mode option is used.
	X.PP
	XWhen a termcap is read that is not unique, and if it has names that
	Xare not known, these names are added to the names of the termcap
	Xthat has already been saved, and this termcap is discarded.
	X.PP
	XAfter all termcap entries from all of the named files are read, the
	Xinternal database is traversed in order, the termcaps that have been
	Xchanged are modified, and are output to
	X.I output-file.
	X.PP
	XWhen 
	X.B tcm
	Xchanges a termcap entry, it will prepend a comment to the body of the
	Xtermcap of the form:
	X.PP
	X.nf
	X#
	X# @@tcm@@: termcap was known as "foo|bar|baz"
	X#
	X.fi
	X.PP
	XThis indicates that the termcap, when read, was known by these names,
	Xbut has since changed.
	X.SH OPTIONS
	X.TP 15
	X.BI -n
	XDo not generate any output; used when checking consistency.
	X.TP
	X.BI -s
	X"Smart" mode.  When a termcap name has already been seen
	Xin conjunction with another termcap, don't ask to change
	Xor delete it, simply ignore it.  This is perhaps the perferred
	Xmode of operation, since there are many name collisions in
	Xcurrent termcap files, unfortunately.
	X.SH EXAMPLES
	X.B tcm
	Xcan be used in many ways.  For these examples, assume that the file
	X.I foo
	Xcontains some new termcap entries you wish to add to your system
	Xtermcap file,
	X.I /etc/termcap.
	X.PP
	XFirst, 
	X.I tcm
	Xcan be used to check the consistency of /etc/termcap by simply
	Xissuing the command
	X.PP
	X.B tcm -ns /etc/termcap
	X.PP
	XThis will tell you if there are any entries that 
	X.B tcm
	Xdoes not understand, such as improperly continued lines or
	Xbadly formatted comments.
	X.PP
	XTo make /etc/termcap consistent, name-wise, and to be prompted
	Xfor the changes necessary, use the command
	X.PP
	X.B tcm termcap.fixed /etc/termcap
	X.PP
	XTo merge a termcap file 'foo' with /etc/termcap, for example,
	Xand to use 'smart' mode, use the command
	X.PP
	X.B tcm -s termcap.merge foo /etc/termcap
	X.SH DIAGNOSTICS
	X.TP 15
	X.BI "usage: %s [ -sn ] [ output-file ] file [file...]"
	XArguments were used incorrectly.  
	X.I output-file
	Xis not specified if using the
	X.I -n
	Xoption.
	X.BI "%s exists."
	X.I output-file
	Xexists, and 
	X.B tcm
	Xrefuses to overwrite it.
	X.TP
	X.BI "No output created."
	XEither the
	X.I -n
	Xoption was specified or an error occurred that caused tcm
	Xto turn off output, since the database output would be wrong
	Xanyways.
	X.TP
	X.BI "Unrecognized termcap (file %s near line %d): %s"
	X.B tcm
	Xdid not like the format of the termcap near the specified line
	Xin the named file.  Typically, this is either due to an improperly
	Xcontinued line just above the displayed area, or to trailing comments
	Xin the named file.  
	X.TP
	X.BI "EOF encountered."
	XThe EOF character was typed when 
	X.B tcm
	Xwas expecting input.  
	X.B tcm
	Xexits upon such an error.
	X.TP
	X.BI "malloc failure in %s(%d,%d)"
	XUnless there's an internal error causing 
	X.B tcm
	Xto absorb all available memory, it's likely that more
	Xis needed to do the task at hand.
	X.TP
	X.BI "%s(%s,%d) failure."
	XAn error of this form indicates a serious internal error.
	X.SH BUGS
	XIt is important to note that
	X.B tcm
	Xdoes not do semantic checking of the termcap entries; it merely
	Xlooks for really glaring problems, such as badly continued lines
	Xor badly formatted comments.  It is forgiving of comments inside
	Xof termcaps, and it shouldn't be \- only comments before or after
	Xtermcap entries are valid.
	X.PP
	XAlso, 
	X.B tcm
	Xis not bright enough to realize that trailing comments in /etc/termcap
	Xare okay.
	X.SH "SEE ALSO"
	Xtermcap(5)
	X.SH AUTHOR
	X.nf
	XSam McCall
	XUniversity of California, Davis
	X
	XBug reports or comments should be sent to samccall@ucdavis.edu
	Xor ucbvax!ucdavis!samccall.
	X.fi
SHAR_EOF
if test 4738 -ne "`wc -c < 'tcm.8'`"
then
	echo shar: error transmitting "'tcm.8'" '(should have been 4738 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mkdep'" '(1247 characters)'
if test -f 'mkdep'
then
	echo shar: will not over-write existing file "'mkdep'"
else
sed 's/^	X//' << \SHAR_EOF > 'mkdep'
	X#! /bin/sh
	X#
	X#	@(#)mkdep.sh	1.7	(Berkeley)	10/13/87
	X#
	X
	XPATH=/bin:/usr/bin:/usr/ucb
	Xexport PATH
	X
	Xif [ $# = 0 ] ; then
	X	echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
	X	exit 1
	Xfi
	X
	XMAKE=Makefile			# default makefile name is "Makefile"
	Xcase $1 in
	X	# -f allows you to select a makefile name
	X	-f)
	X		MAKE=$2
	X		shift; shift ;;
	X
	X	# the -p flag produces "program: program.c" style dependencies
	X	# so .o's don't get produced
	X	-p)
	X		SED='-e s;\.o;;'
	X		shift ;;
	Xesac
	X
	Xif [ ! -w $MAKE ]; then
	X	echo "mkdep: no writeable file \"$MAKE\""
	X	exit 1
	Xfi
	X
	XTMP=/tmp/mkdep$$
	X
	Xtrap 'rm -f $TMP ; exit 1' 1 2 3 13 15
	X
	Xcp $MAKE ${MAKE}.bak
	X
	Xsed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
	X
	Xcat << _EOF_ >> $TMP
	X# DO NOT DELETE THIS LINE -- mkdep uses it.
	X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
	X
	X_EOF_
	X
	Xcc -M $* | /bin/sed -e "s; \./; ;g" $SED | \
	X	awk ' { \
	X		if ($1 != prev) { \
	X			if (rec != "") \
	X				print rec; rec = $0; prev = $1; \
	X		} \
	X		else { \
	X			if (length(rec $2) > 78) { \
	X				print rec; rec = $0; \
	X			} else \
	X				rec = rec " " $2 \
	X		} \
	X	} \
	X	END { \
	X		print rec \
	X	} ' >> $TMP
	X
	Xcat << _EOF_ >> $TMP
	X
	X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
	X_EOF_
	X
	X# copy to preserve permissions
	Xcp $TMP $MAKE
	Xrm -f ${MAKE}.bak $TMP
	Xexit 0
SHAR_EOF
if test 1247 -ne "`wc -c < 'mkdep'`"
then
	echo shar: error transmitting "'mkdep'" '(should have been 1247 characters)'
fi
chmod +x 'mkdep'
fi # end of overwriting check
echo shar: extracting "'newvers.sh'" '(392 characters)'
if test -f 'newvers.sh'
then
	echo shar: will not over-write existing file "'newvers.sh'"
else
sed 's/^	X//' << \SHAR_EOF > 'newvers.sh'
	X#!/bin/sh
	X#
	Xif [ ! -r VERSION ]
	Xthen
	X	/bin/echo 0 > VERSION
	Xfi
	Xtouch VERSION
	Xr=`cat RELEASE` v=`cat VERSION` u=${USER-root} d=`pwd` h=`hostname` t=`date`
	X(/bin/echo '#ifndef lint' ;
	X /bin/echo "char version[] = \"${r} #${v}: ${t} ${u}@${h}:${d}\";" ;
	X /bin/echo "char copyright[] = \"(C)1989 by Sam McCall\";" ;
	X /bin/echo '#endif'
	X  ) > version.c
	Xsleep 1
	X/bin/echo `expr ${v} + 1` > VERSION
SHAR_EOF
if test 392 -ne "`wc -c < 'newvers.sh'`"
then
	echo shar: error transmitting "'newvers.sh'" '(should have been 392 characters)'
fi
chmod +x 'newvers.sh'
fi # end of overwriting check
echo shar: extracting "'README'" '(347 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XFiles in this directory:
	X
	X	Makefile
	X	README
	X	RELEASE
	X	mkdep
	X	newvers.sh
	X	tcm.8
	X	tcm.c
	X	tcm.h
	X
	XPermission is hereby granted to distribute and copy this code
	Xas desired as long as this message remains with the code.
	X
	XMail comments, suggestions, or bug reports to 
	X
	X	ucbvax!ucdavis!samccall
	Xor	samccall@ucdavis.edu
	X
	X-sam Mon May 29 16:31:22 PDT 1989
SHAR_EOF
if test 347 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 347 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'RELEASE'" '(22 characters)'
if test -f 'RELEASE'
then
	echo shar: will not over-write existing file "'RELEASE'"
else
sed 's/^	X//' << \SHAR_EOF > 'RELEASE'
	Xtcm release 1.0 alpha
SHAR_EOF
if test 22 -ne "`wc -c < 'RELEASE'`"
then
	echo shar: error transmitting "'RELEASE'" '(should have been 22 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tcm.c'" '(10920 characters)'
if test -f 'tcm.c'
then
	echo shar: will not over-write existing file "'tcm.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'tcm.c'
	X/*
	X * -sam Mon May 29 16:34:49 PDT 1989
	X */
	X#include <stdio.h>
	X#include <ctype.h>
	X#include <sys/types.h>
	X#include <sys/stat.h>
	X#include "tcm.h"
	X
	X#define USAGE	"usage: %s [ -sn ] [ output-file ] file [file...]\n",pname
	X
	Xchar	*malloc();
	Xchar	*strcpy();
	Xchar	*strncpy();
	Xchar	*strcat();
	Xchar	*strncat();
	Xchar	*strsave();
	X
	Xchar	*getinput();
	Xchar	*getlinput();
	Xchar	*gettcap();
	Xchar	*gettcapbyname();
	Xchar	*findtbody();
	Xchar	*dofixnames();
	Xchar	*findtnames();
	Xchar	*gettcapname();
	Xstruct	stat	sbuf;
	Xstruct	nameent	*getnameent();
	Xstruct	terment	*gettcapent();
	X
	Xint	lno;
	Xint	order;
	Xint	nosave = 0;
	Xint	smartmode = 0;
	Xchar	*pname;
	X
	X#define ISTCSTART(c)	(isascii(c)&&isalnum(c))
	X
	Xmain(ac,av)
	Xint	ac;
	Xchar	**av;
	X{
	X	int	i;
	X	int	aj;
	X	FILE	*fpin,*fpdribble;
	X
	X	pname = av[0];
	X	while(av[1][0]=='-'){
	X		aj=1;
	X		while(av[1][aj]){
	X			switch(av[1][aj]){
	X				case 's':	smartmode++;
	X						aj++;
	X						continue;
	X				case 'n':	nosave++;
	X						aj++;
	X						continue;
	X				default:	(void)fprintf(stderr,USAGE);
	X						exit(1);
	X			}
	X		}
	X		ac--;
	X		av++;
	X	}
	X	if((nosave&&ac<2)||(!nosave&&ac<3)){
	X		(void)fprintf(stderr,USAGE);
	X		exit(1);
	X	}
	X	if(!nosave){
	X		if(stat(av[1],&sbuf)<0){
	X			if((fpdribble=fopen(av[1],"w"))==NULL){
	X				perror(av[1]);
	X				exit(1);
	X			}
	X		} else {
	X			(void)fprintf(stderr,"%s exists.\n",av[1]);
	X			exit(1);
	X		}
	X		ac--;av++;
	X	}
	X	lno=0;
	X	order=0;
	X	for(i=1;i<ac;i++){
	X		if((fpin=fopen(av[i],"r"))==NULL){
	X			perror(av[i]);
	X			exit(1);
	X		}
	X		while(getnewent(fpin,av[i],&lno,&order));
	X		(void)fclose(fpin);
	X		lno=0;
	X		order=0;
	X	}
	X	if(!nosave){
	X		dumpdb(fpdribble);
	X	} else {
	X		(void)printf("No output created.\n");
	X	}
	X}
	X
	Xgetnewent(fp,fname,lno,order)
	XFILE	*fp;
	Xchar	*fname;
	Xint	*lno;
	Xint	*order;
	X{
	X	char	name[BUFSIZ];
	X	char	buf[BUFSIZ];
	X	char	nbuf[BUFSIZ];
	X	char	tbuf[10*BUFSIZ];
	X	char	*p,*q,*response;
	X	int	tcunique;
	X	int	looping;
	X
	X	tbuf[0]='\0';
	X	buf[0]='\0';
	X	while(fgets(buf,sizeof(buf),fp)!=NULL){
	X		(*lno)++;
	X		/*
	X		 * if the last character in the line, not counting
	X		 * the newline, is an '\', then we have to continue.
	X		 */
	X		if(buf[strlen(buf)-2]=='\\'){
	X			(void)strcat(tbuf,buf);
	X			continue;
	X		}
	X		/*
	X		 * append comment lines right away
	X		 */
	X		if(buf[0]=='#'){
	X			(void)strcat(tbuf,buf);
	X			continue;
	X		}
	X		if(buf[0]=='\n')
	X			continue;
	X		/*
	X		 * just a normal line
	X		 */
	X		(void)strcat(tbuf,buf);
	X		break;
	X	}
	X	if(buf[0]=='\0'||buf[0]=='\n')
	X		return(0);
	X	(*order)++;
	X	/*
	X	 * now point to the names of the termcap
	X	 */
	X	if((p=findtnames(tbuf))==NULL){
	X		(void)fprintf(stderr,
	X			"Unrecognized termcap (file %s near line %d):\n%s",
	X			fname,*lno,tbuf);
	X		(void)fprintf(stderr,"Ignoring.\n");
	X		return(0);
	X	}
	X	(void)strcpy(nbuf,p);
	X	tcunique=1;
	X	if(gettcapent(tbuf)){
	X		tcunique=0;
	X	}
	X	if(tcunique){
	X		if(!putintcaphash(tbuf)){
	X			(void)fprintf(stderr,"putintcaphash(%d) failure.\n",
	X				tbuf);
	X			exit(1);
	X		}
	X		if(!addorderent(*order,gettcapent(tbuf))){
	X			(void)fprintf(stderr,"addorderent(%d,%d) failure.\n",
	X				*order,tbuf);
	X			exit(1);
	X		}
	X		p=nbuf;
	X		while(*p){
	X			for(q=p;*q&&*q!='|';q++);
	X			(void)strncpy(name,p,(q-p));
	X			name[(q-p)]='\0';
	X			if(getnameent(name)){
	X				looping=1;
	X				while(looping){
	X					if(!smartmode){
	X						(void)printf(
	X						"Name \"%s\" already in use.\n",
	X							name);
	X						(void)printf(
	X						"Current termcap ...\n%s\n",
	X							tbuf);
	X						(void)printf(
	X						"Used in termcap ...\n%s\n",
	X							dofixnames(
	X								gettcapent(
	X								gettcapbyname(
	X								name))));
	X					} else {
	X						goto nameign;
	X					}
	Xz1:					response=getlinput(
	X						"(change/delete/ignore)? ");
	X					if(*response=='\0') goto z1;
	X					if(*response=='d'){
	X						setfixnames(tbuf);
	X						(void)printf("\n\n");
	X						goto namedrop;
	X					}
	X					if(*response=='i'){
	X						(void)printf("\n\n");
	X						goto nameign;
	X					}
	X					if(*response=='c'){
	Xz2:						(void)strcpy(name,
	X							getinput("New name: "));
	X						if(*name=='\0') goto z2;
	X						if(!getnameent(name)){
	X							looping=0;
	X						} else {
	X							(void)printf(
	X			    "That name (%s) is also already in use.\n",name);
	X						}
	X					}
	X				}
	X				(void)printf("\n\n");
	X				setfixnames(tbuf);
	X			}
	X			if(!putinnamehash(name,tbuf)){
	X				(void)fprintf(stderr,
	X					"putinnamehash(%s) failure.\n",
	X					name);
	X				exit(1);
	X			}
	Xnameign:		if(!addname(gettcapent(tbuf),name)){
	X				(void)fprintf(stderr,
	X					"addname(%s) failure.\n",
	X					name);
	X				exit(1);
	X			}
	Xnamedrop:		if(*q=='|')
	X				p=q+1;
	X			else
	X				p=q;
	X		}
	X	} else {
	X		/*
	X		 * now run through the list of names, taking those
	X		 * that aren't already known, and add them to this
	X		 * termcap.
	X		 */
	X		p=nbuf;
	X		while(*p){
	X			for(q=p;*q&&*q!='|';q++);
	X			(void)strncpy(name,p,(q-p));
	X			name[(q-p)]='\0';
	X			if(!getnameent(name)){
	X				if(!putinnamehash(name,tbuf)){
	X					(void)fprintf(stderr,
	X						"putinnamehash(%s) failure.\n",
	X						name);
	X					exit(1);
	X				}
	X				if(!addname(gettcapent(tbuf),name)){
	X					(void)fprintf(stderr,
	X						"addname(%s) failure.\n",
	X						name);
	X					exit(1);
	X				}
	X				setfixnames(tbuf);
	X			}
	X			if(*q=='|')
	X				p=q+1;
	X			else
	X				p=q;
	X		}
	X	}
	X	return(1);
	X}
	X
	Xdumpdb(fp)
	XFILE	*fp;
	X{
	X	int	i;
	X	struct orderent	*p;
	X
	X	for(i=0;i<ORDERTABSIZE;i++){
	X		p=ordertab[i];
	X		while(p){
	X			fputs(dofixnames(p->tptr),fp);
	X			p=p->next;
	X		}
	X	}
	X}
	X
	X/*
	X * hash function 
	X *
	X * copied directly from 2nd edition dragon book
	X * "Compilers - Principles, Techniques, and Tools"
	X * Aho, Sethi, and Ullman
	X */
	Xhash(name,tabsize)
	Xchar	*name;
	Xint	tabsize;
	X{
	X	char	*p;
	X	unsigned h=0,g;
	X
	X	if(!name)return(0);
	X	for(p=name;*p;p++){
	X		h=(h<<4)+(*p);
	X		if(g=h&0xf0000000){
	X			h=h^(g>>24);
	X			h=h^g;
	X		}
	X	}
	X	return(h%tabsize);
	X}
	X
	Xaddorderent(order,tptr)
	Xint	order;
	Xstruct	terment	*tptr;
	X{
	X	struct	orderent	*qp;
	X	struct	orderent	*sp;
	X
	X	if(order>ORDERTABSIZE||order<0) return(0);
	X	if((qp=(struct orderent *)malloc(sizeof(struct orderent)))==NULL){
	X		(void)fprintf(stderr,"malloc failure in addorderent(%d,%d)\n",
	X			order,tptr);
	X		exit(1);
	X	}
	X	sp=ordertab[order];
	X	if(sp){
	X		while(sp&&sp->next)sp=sp->next;
	X		sp->next=qp;
	X	} else {
	X		ordertab[order]=qp;
	X	}
	X	qp->tptr=tptr;
	X	return(1);
	X}
	X
	Xstruct	nameent	*
	Xgetnameent(name)
	Xchar	*name;
	X{
	X	int	hval;
	X	struct	nameent	*tp;
	X
	X	hval = NAMEHASH(name);
	X	tp = nametab[hval];
	X	while(tp){
	X		if(!strcmp(tp->name,name))
	X			return(tp);
	X		tp=tp->next;
	X	}
	X	return((struct nameent *)NULL);
	X}
	X
	X/*
	X * assumes name not already in name hash table
	X */
	Xputinnamehash(name,tcap)
	Xchar	*name;
	Xchar	*tcap;
	X{
	X	int	hval;
	X	struct	terment	*tp;
	X	struct	nameent	*np;
	X	struct	nameent	*qp;
	X
	X	if(!name||!tcap) return(0);
	X	if((tp=gettcapent(tcap))==NULL) return(0);
	X	hval = NAMEHASH(name);
	X	np = nametab[hval];
	X	if((qp = (struct nameent *)malloc(sizeof(struct nameent)))==NULL){
	X		(void)fprintf(stderr,
	X			"malloc failure in putinnamehash(%d,%d).\n",
	X			name,tcap);
	X		exit(1);
	X	}
	X	if(np){
	X		qp->next = np;
	X	} else {
	X		qp->next = (struct nameent *)NULL;
	X	}
	X	nametab[hval] = qp;
	X	qp->name=strsave(name);
	X	qp->tptr = tp;
	X	return(1);
	X}
	X
	Xaddname(tcap,name)
	Xstruct	terment	*tcap;
	Xchar	*name;
	X{
	X	int	i;
	X	char	**p;
	X
	X	if(!tcap) return(0);
	X	p=tcap->names;
	X	i=tcap->nnames++;
	X	if(i>=NTCNAMES){
	X		--tcap->nnames;
	X		return(0);
	X	}
	X	p[i]=strsave(name);
	X	return(1);
	X}
	X
	Xchar *
	Xgettcap(tent)
	Xstruct	terment	*tent;
	X{
	X	return(tent?tent->tcap:NULL);
	X}
	X
	Xchar *
	Xgettcapname(tent,i)
	Xstruct terment	*tent;
	Xint	i;
	X{
	X	return(tent?tent->names[i]:(char *)NULL);
	X}
	X
	Xgettcapnnames(tent)
	Xstruct terment	*tent;
	X{
	X	return(tent?tent->nnames:0);
	X}
	X
	Xchar	*
	Xgettcapbyname(name)
	Xchar	*name;
	X{
	X	struct	nameent	*np;
	X
	X	if(!name) return(NULL);
	X	if((np=getnameent(name))==NULL) return(NULL);
	X	return(np->tptr->tcap);
	X}
	X
	Xstruct	terment	*
	Xgettcapent(tcap)
	Xchar	*tcap;
	X{
	X	struct	terment	*tp;
	X	char	*b;
	X
	X	if((b=findtbody(tcap))==NULL) return((struct terment *)NULL);
	X	tp = tcaptab[TCAPHASH(b)];
	X	while(tp){
	X		if(!strcmp(b,tp->tbody)){
	X			return(tp);
	X		}
	X		tp=tp->next;
	X	}
	X	return((struct terment *)NULL);
	X}
	X
	X/*
	X * assumes that this tcap not already in database.
	X */
	Xputintcaphash(tcap)
	Xchar	*tcap;
	X{
	X	int	hval;
	X	char	*b;
	X	struct	terment	*qp;
	X
	X	if((b=findtbody(tcap))==NULL){
	X		return(0);
	X	}
	X	hval = TCAPHASH(b);
	X	if((qp = (struct terment *)malloc(sizeof(struct terment)))==NULL){
	X		(void)fprintf(stderr,"malloc failure in putintcaphash(%d).\n",
	X			tcap);
	X		exit(1);
	X	}
	X	if(tcaptab[hval])
	X		qp->next = tcaptab[hval];
	X	else
	X		qp->next = (struct terment *)NULL;
	X	tcaptab[hval] = qp;
	X	tcaptab[hval]->tcap=strsave(tcap);
	X	tcaptab[hval]->tbody=findtbody(tcaptab[hval]->tcap);
	X	tcaptab[hval]->fixnames=0;
	X	tcaptab[hval]->nnames=0;
	X	return(1);
	X}
	X
	Xchar *
	Xstrsave(str)
	Xchar	*str;
	X{
	X	char	*sptr;
	X
	X	if(!str){
	X		(void)fprintf(stderr,"strsave(%d) failure.\n",str);
	X		exit(1);
	X	}
	X	if((sptr=malloc((unsigned)strlen(str)+1))==NULL){
	X		(void)fprintf(stderr,"malloc failure in strsave(%s)\n",str);
	X		exit(1);
	X	}
	X	(void)strcpy(sptr,str);
	X	return(sptr);
	X}
	X
	Xchar	*
	Xgetlinput(prompt)
	Xchar	*prompt;
	X{
	X	static char	rbuf[BUFSIZ];
	X	char	*p;
	X
	X	(void)printf(prompt);
	X	(void)fflush(stdout);
	X	(void)fflush(stdin);
	X	if(fgets(rbuf,BUFSIZ,stdin)==NULL){
	X		(void)fprintf(stderr,"EOF encountered.\n");
	X		exit(1);
	X	}
	X	p=rbuf;
	X	while(*p){
	X		if(isalpha(*p))
	X			if(isupper(*p))
	X				*p=tolower(*p);
	X		p++;
	X	}
	X	p=rbuf;
	X	while(*p&&*p!='\n')p++;
	X	if(*p=='\n')*p='\0';
	X	return(rbuf);
	X}
	X
	Xchar	*
	Xgetinput(prompt)
	Xchar	*prompt;
	X{
	X	static char	rbuf[BUFSIZ];
	X	char	*p;
	X
	X	(void)printf(prompt);
	X	(void)fflush(stdout);
	X	(void)fflush(stdin);
	X	if(fgets(rbuf,BUFSIZ,stdin)==NULL){
	X		(void)fprintf(stderr,"EOF encountered.\n");
	X		exit(1);
	X	}
	X	p=rbuf;
	X	while(*p&&*p!='\n')p++;
	X	if(*p=='\n')*p='\0';
	X	return(rbuf);
	X}
	X
	Xsetfixnames(tcap)
	Xchar	*tcap;
	X{
	X	struct	terment	*tptr;
	X
	X	if((tptr=gettcapent(tcap))==NULL){
	X		(void)fprintf(stderr,"setfixnames(%d) failure.\n",tcap);
	X		exit(1);
	X	}
	X	tptr->fixnames = 1;
	X}
	X
	Xneedfixnames(tptr)
	Xstruct terment *tptr;
	X{
	X	return(tptr?tptr->fixnames:NULL);
	X}
	X
	Xchar	*
	Xdofixnames(tptr)
	Xstruct	terment	*tptr;
	X{
	X	char	*p;
	X	char	*q,*s;
	X	static	char	rbuf[10*BUFSIZ];
	X	int	i;
	X	int	j;
	X
	X	if(!needfixnames(tptr)) return(gettcap(tptr));
	X	p = gettcap(tptr);
	X	q = p;
	X	while(*q&&*q=='#'){
	X		q++;
	X		while(*q&&*q!='\n')q++;
	X		if(*q=='\n')q++;
	X	}
	X	s = q;
	X	while(*s&&*s!=':')s++;
	X	if(p!=q)(void)strncpy(rbuf,p,(q-p));
	X	rbuf[(q-p)]='\0';
	X	(void)strcat(rbuf,"#\n# @@tcm@@ termcap was known as \"");
	X	(void)strncat(rbuf,q,(s-q));
	X	(void)strcat(rbuf,"\"\n#\n");
	X	i = gettcapnnames(tptr);
	X	j = 0;
	X	while(j<i){
	X		(void)strcat(rbuf,gettcapname(tptr,j));
	X		if(++j<i)(void)strcat(rbuf,"|");
	X	}
	X	(void)strcat(rbuf,s);
	X	return(rbuf);
	X}
	X
	Xchar *
	Xfindtbody(tcap)
	Xchar	*tcap;
	X{
	X	char	*p;
	X
	X	p=tcap;
	X	if(!p)return(NULL);
	X	while(*p&&*p=='#'){
	X		p++;
	X		while(*p&&*p!='\n')p++;
	X		if(*p=='\n')p++;
	X	}
	X	if(!ISTCSTART(*p)){
	X		return(NULL);
	X	}
	X	while(*p&&*p!=':')p++;
	X	return(!*p?NULL:p);
	X}
	X
	Xchar *
	Xfindtnames(tcap)
	Xchar	*tcap;
	X{
	X	char	*p,*q;
	X	static	char	rbuf[BUFSIZ];
	X
	X	p=tcap;
	X	if(!p)return(NULL);
	X	while(*p&&*p=='#'){
	X		p++;
	X		while(*p&&*p!='\n')p++;
	X		if(*p=='\n')p++;
	X	}
	X	if(!ISTCSTART(*p)){
	X		return(NULL);
	X	}
	X	q=p;
	X	while(*q&&*q!=':')q++;
	X	(void)strncpy(rbuf,p,(q-p));
	X	rbuf[(q-p)]='\0';
	X	return(rbuf);
	X}
SHAR_EOF
if test 10920 -ne "`wc -c < 'tcm.c'`"
then
	echo shar: error transmitting "'tcm.c'" '(should have been 10920 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tcm.h'" '(613 characters)'
if test -f 'tcm.h'
then
	echo shar: will not over-write existing file "'tcm.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'tcm.h'
	X/*
	X * -sam Mon May 29 16:34:33 PDT 1989
	X */
	X#define NAMETABSIZE	4001
	X#define ORDERTABSIZE	1000
	X#define TCAPTABSIZE	4001
	X#define NTCNAMES	32
	X
	Xstruct terment {
	X	char	*tcap;
	X	char	*tbody;
	X	struct	terment	*next;
	X	int	fixnames;
	X	int	nnames;
	X	char	*names[NTCNAMES];
	X};
	X
	Xstruct nameent {
	X	struct	nameent	*next;
	X	struct	terment	*tptr;
	X	char	*name;
	X};
	X
	Xstruct orderent {
	X	struct	orderent	*next;
	X	struct	terment	*tptr;
	X};
	X
	Xstruct	nameent		*nametab[NAMETABSIZE];
	Xstruct	orderent	*ordertab[ORDERTABSIZE];
	Xstruct	terment		*tcaptab[TCAPTABSIZE];
	X
	X#define NAMEHASH(n)	hash(n,NAMETABSIZE)
	X#define TCAPHASH(n)	hash(n,TCAPTABSIZE)
SHAR_EOF
if test 613 -ne "`wc -c < 'tcm.h'`"
then
	echo shar: error transmitting "'tcm.h'" '(should have been 613 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0