[mod.sources] v08i095: Query terminal for its type

sources-request@mirror.UUCP (03/04/87)

Submitted by: Michael A. Cooper <usc-oberon!mcooper>
Mod.sources: Volume 8, Issue 95
Archive-name: qterm

#!/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:
#	README Makefile table.c qterm.c qterm.1
# Wrapped by Michael A. Cooper (USC Computing Services, Los Angeles)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(936 characters)'
if test -f 'README'
then
	echo shar: over-writing existing file "'README'"
fi
cat << \SHAR_EOF > 'README'

		 Q T E R M  -  Q U E R Y   T E R M I N A L

         		     Revision 1.23
			     January, 1987

	Qterm is a program that queries terminals to find out what kind
of terminal is responding.  It is useful to automagically define your
terminal type.  It prints the name of the terminal (compatible, hopefully,
with a termcap/terminfo name) such as "vt100" to standard output.
See the manual for details.

	Qterm was written under 4.2BSD and will probably run without 
modification on other Berkeley Unix systems.  It has been tested under
4.2BSD, 4.3BSD, Sun 3.0 and Sun 3.2.  It should work under System V.2,
but I have not personally tested it on such a system.  (For System V.2,
compile with USG5 defined).


				Mike


Michael A. Cooper, University Computing Services, U of Southern California
  UUCP: {sdcrdcf, uscvax}!usc-oberon!mcooper  BITNET: mcooper@uscvaxq
  ARPA: mcooper@usc-oberon.USC.EDU            PHONE: (213) 743-3462
SHAR_EOF
echo shar: extracting "'Makefile'" '(449 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
#
# $Header: Makefile,v 1.1 86/12/22 10:45:46 mcooper Exp $
#
# Makefile for QTERM
#
BIN=/usr/usc/bin
MAN=/usr/usc/man/man1

OBJS = qterm.o table.o

#
# Use "-DUSG5" for $(CFLAGS) below, if your system is Unix System V.
#
CFLAGS = -O

qterm: $(OBJS)
	cc $(CFLAGS) $(OBJS) -o qterm

shar:
	shar README Makefile table.c qterm.c qterm.1 > qterm.shar

clean:
	rm -f *.o core log 

install: qterm qterm.1
	install qterm $(BIN)
	install -c qterm.1 $(MAN)
SHAR_EOF
echo shar: extracting "'table.c'" '(2400 characters)'
if test -f 'table.c'
then
	echo shar: over-writing existing file "'table.c'"
fi
cat << \SHAR_EOF > 'table.c'
#ifndef lint
static char *RCSid = "$Header: table.c,v 1.3 86/11/13 15:40:26 mcooper Locked $";
#endif

/*
 *------------------------------------------------------------------
 *
 * $Source: /big/mcooper/src/qterm/RCS/table.c,v $
 * $Revision: 1.3 $
 * $Date: 86/11/13 15:40:26 $
 * $State: Exp $
 * $Author: mcooper $
 * $Locker: mcooper $
 *
 *------------------------------------------------------------------
 *
 * Michael A. Cooper
 * University Computing Services, 
 * University of Southern California
 * (mcooper@usc-oberon.arpa)
 *
 *------------------------------------------------------------------
 * $Log:	table.c,v $
 * Revision 1.3  86/11/13  15:40:26  mcooper
 * z29 -> h29.  "h29" is recognized
 * more.
 * 
 * Revision 1.2  86/07/01  23:13:04  mcooper
 * Added vt220 and f220 entries.
 * 
 * Revision 1.1  86/07/01  22:58:12  mcooper
 * Initial revision
 * 
 *------------------------------------------------------------------
 */

#include <stdio.h>

/*
 * The Master Table
 */
char *terms[] = {
/*  Terminal Sends:			Terminal Name: 	Real Name: 		*/
/*	---------------			-------------- 	---------- 		*/
	"\33[?1;0c",			"vt100",		"Base vt100",
	"\33[?1;1c",			"vt100",		"vt100 with STP",
	"\33[?1;2c",			"vt100",		"ANSI/VT100 Clone",
	"\33[?1;3c",			"vt100",		"vt100 with AVO and STP",
	"\33[?1;4c",			"vt100",		"vt100 with GPO",
	"\33[?1;5c",			"vt100",		"vt100 with GPO and STP",
	"\33[?1;6c",			"vt100",		"vt100 with GPO and AVO",
	"\33[?1;7c",			"vt100",		"vt100 with GPO, STP, and AVO",
	"\33[?6c",				"vt100",		"Generic vt100",
	"\33[?8c",				"vt100",		"TeleVideo 970",
	"\33[0n",				"vt100",		"AT&T Unix PC 7300",
	"\33[?l;0c",			"vt100",		"AT&T Unix PC 7300",
	"\33[?12c",				"vt100",		"Concept from Pro 350/UNIX",
	"\33[?;c",				"vt100",		"Concept From Pro 350/UNIX",
	"\33[=1;1c",			"avt-4p-s",		"Concept with 4 pages memory",
	"\33[=1;2c",			"avt-8p-s",		"Concept with 8 pages memory",
	"\33iBO",				"h29",			"Zenith z29 in zenith mode",
	"\33/K",				"h29",			"Zenith z29 in zenith mode",
	"\33/Z",				"vt52",			"Generic vt52",
	"\33[?12;7;0;102c",		"vt125",		"DEC Pro 350 in vt125 mode",
	"\33[?10c",				"la120",		"DEC Writer III",
	"\33[?1;11c",			"cit101e",		"CIE CIT-101 Enhanced w/Graphics",
/*	"\33[?1;11c",			"xt100+",		"Northern Tech LANPARSCOPE",	*/
	"\33[?62;1;2;6;7;8;9c",	"vt220",		"DEC VT220",
	"\33[62;1;2;6;8c",		"f220",			"Freedom 220 DEC clone",
	NULL
};
SHAR_EOF
echo shar: extracting "'qterm.c'" '(16314 characters)'
if test -f 'qterm.c'
then
	echo shar: over-writing existing file "'qterm.c'"
fi
cat << \SHAR_EOF > 'qterm.c'
#ifndef lint
static char *RCSid = "$Header: qterm.c,v 1.23 87/01/09 13:55:44 mcooper Locked $";
#endif

/*
 *------------------------------------------------------------------
 *
 * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
 * $Revision: 1.23 $
 * $Date: 87/01/09 13:55:44 $
 * $State: Exp $
 * $Author: mcooper $
 * $Locker: mcooper $
 *
 *------------------------------------------------------------------
 *
 * Michael A. Cooper
 * University Computing Services, 
 * University of Southern California
 * (mcooper@usc-oberon.arpa)
 *
 *------------------------------------------------------------------
 * $Log:	qterm.c,v $
 * Revision 1.23  87/01/09  13:55:44  mcooper
 * Fixed bug with -s option that caused "ers:" 
 * to be printed instead of the string
 * received from the terminal.
 * 
 * Revision 1.22  86/12/11  15:57:16  mcooper
 * Should now work under System V thanks to Brian L. Matthews
 * (cxsea!blm).
 * 
 * Revision 1.21  86/10/13  12:52:54  mcooper
 * Fixed bug that caused problems with
 * send strings not being sent from .qterm
 * files.
 * 
 * Revision 1.20  86/08/25  15:45:58  mcooper
 * BUG FIX: When the -f flag was specified and the user's
 *          tables did not produce the terminal's entry,
 *          the internal terminal tables where not tried
 *          as documented.
 * 
 * Revision 1.19  86/08/12  15:31:22  mcooper
 * Fixed bug that caused terminals to wedge due
 * to qterm failing to match receive strings
 * from the .qterm file.
 * 
 * Revision 1.18  86/08/11  13:49:42  mcooper
 * Fixed bug that caused qterm to wedge.  Problem
 * due to alarms not being set correctly.
 * 
 * Revision 1.17  86/08/08  14:40:09  mcooper
 * - Only send/listen for strings if the previously sent string
 *   is not the same as the current string.
 * - Fixed -s option.
 * 
 * Revision 1.16  86/08/08  13:16:05  mcooper
 * Major re-write: Added ~/.qterm file that contains
 * the users own copy of terminal tables.
 * 
 * Revision 1.15  86/07/21  12:35:54  mcooper
 * Now works under System V (Define USG5).
 * 
 * Revision 1.14  86/07/01  22:57:45  mcooper
 * Moved terminal table to seperate
 * file (table.c).
 * 
 * Revision 1.13  86/06/30  11:17:53  mcooper
 * More terminals to main table...
 * 
 * Revision 1.12  86/06/19  13:57:51  mcooper
 * Added responses for concept from a Pro running
 * 2.9bsd.
 * 
 * Revision 1.11  86/06/18  15:58:45  mcooper
 * Cleanup for release.
 * 
 * Revision 1.10  86/06/17  23:06:55  mcooper
 * Added Unix PC responses.
 * 
 * Revision 1.9  86/06/16  14:19:09  mcooper
 * Added vt100 responses from vt100 manual.
 * 
 * Revision 1.8  86/06/16  13:23:40  mcooper
 * Print additional information about
 * what the actual terminal is.
 * 
 * Revision 1.7  86/06/12  10:59:27  mcooper
 * *** empty log message ***
 * 
 * Revision 1.6  86/06/11  19:48:35  mcooper
 * Added alternate string and table entries for concepts.
 * 
 * Revision 1.5  86/05/19  12:30:32  mcooper
 * General clean up.
 * 
 * Revision 1.4  86/05/18  17:56:11  mcooper
 * Added another vt100.  This one is for when you rlogin
 * from a Pro 2.9bsd host on a HDS Concept.
 * 
 * Revision 1.3  86/05/08  09:24:13  mcooper
 * Added another vt100 description.
 * 
 * Revision 1.2  86/05/06  18:23:35  mcooper
 * More cleanup - de-linted (almost).
 * 
 * Revision 1.1  86/05/06  14:56:57  mcooper
 * Initial revision
 * 
 *------------------------------------------------------------------
 */

/*
 * [Edit with tabstop=4]
 *
 * qterm - Query Terminal
 *
 * qterm is used to query a terminal to determine the name of the terminal.
 * This is done by sending a fairly universal string "\33Z" to the terminal,
 * reading in a response, and comparing it against a master table of responses
 * and names.  The "name" printed to standard output should be one found in
 * the termcap(5) database.
 *
 * Putting a line in your ".login" file such as:
 *
 *	setenv TERM `qterm`
 *
 * or the following lines in your ".profile" file:
 *
 *	TERM=`qterm`
 *	export TERM
 *
 * will set your terminal type automagically.
 * 
 * If you add a terminal to the master table, please also send me a copy
 * so that I may put it into my version.
 *
 * Michael Cooper
 * ARPA: 	mcooper@usc-oberon.ARPA
 * UUCP: 	mcooper@usc-oberon.UUCP
 * BITNET:	mcooper@uscvaxq
 */

#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <setjmp.h>
#ifdef USG5
# include <termio.h>
#else
# include <sys/file.h>
# include <sgtty.h>
#endif

#define SEND		"\033Z"		/* send this to query terminal */
#define ALTSEND		"\033[c"	/* alternate string */

#define STRFILE		".qterm"	/* file containing terminal strings */

#define dprintf		if(debug)printf
#define MAXTERMS	100

#define TRUE		1
#define FALSE		0

#define T_STR		0
#define T_NAME		1
#define T_LNAME		2

int tabmark = 0;
int tabtotal = 0;
int has_set = 0;


#define BUF			666

struct qt {
	char	qt_sendstr[BUFSIZ]; 		/* String to send to terminal */
	char	qt_recvstr[BUFSIZ];			/* String expected in response */
	char	qt_termname[BUFSIZ];		/* Terminal name */
	char	qt_fullname[BUFSIZ];		/* Full terminal name & description */
};
struct qt *compare();
static struct qt termtab[MAXTERMS];


#ifdef USG5
struct termio _ntty, _otty;
#else
struct sgttyb _tty;
#endif
int _tty_ch = 2;

#ifdef USG5
# define crmode()		(_ntty.c_lflag &= ~ICANON,\
						 _ntty.c_cc[VMIN] = 1, _ntty.c_cc[VTIME] = 0,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define nocrmode()		(_ntty.c_lflag |= ICANON,\
						 _ntty.c_cc[VMIN] = _otty.c_cc[VMIN],\
						 _ntty.c_cc[VTIME] = _otty.c_cc[VTIME],\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define echo()			(_ntty.c_lflag |= ECHO,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define noecho()		(_ntty.c_lflag &= ~ECHO,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
#else
# define crmode() 		(_tty.sg_flags |= CBREAK,\
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define nocrmode() 	(_tty.sg_flags &= ~CBREAK,\
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define echo() 		(_tty.sg_flags |= ECHO,   \
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define noecho() 		(_tty.sg_flags &= ~ECHO,  \
							ioctl(_tty_ch, TIOCSETP, &_tty))
#endif

#define SIZE 		512
#define CMASK 		0377
#define ESC			'\033'

static char recvbuf[SIZE];
static char *progname;
int debug;					/* debug mode 			*/
int aflag;					/* alternate string 	*/
int sflag;					/* print strings		*/
int qflag;					/* quiet mode 			*/
int fflag;					/* use strings file 	*/

int found = FALSE;
int index = 0;
int finish(), wakeup(), done();

char *decode();

jmp_buf env;

main(argc, argv)
char *argv[];
{
	register int x;

	progname = argv[0];

	for (x = 1; x < argc; x++) {
		if (argv[x][0] != '-')
			break;
		switch (argv[x][1]) {
			case 'a':
				aflag = TRUE;
				break;
			case 't':
			case 's':
				sflag = TRUE;
				break;
			case 'q':
				qflag = TRUE;
				break;
			case 'f':
				fflag = TRUE;
				break;
			case 'd':
				debug = TRUE;
				break;
			default:
				usage();
				exit(1);
		}
	}

	setbuf(stdout, 0);
	if(debug)
		setbuf(stderr, 0);

	dprintf("[ %s debug mode enabled ]\n\n", progname);

	if(!isatty(0))
		fprintf(stderr,"Not a tty.\n");

#ifdef USG5
	if(ioctl(_tty_ch, TCGETA, &_otty) < 0)
#else
	if(ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
#endif
	{
		perror("gtty");
		exit(1);
	}
#ifdef USG5
	_ntty = _otty;
#endif
	if(crmode() < 0) {
		perror("crmode");
		exit(1);
	}
	if(noecho() < 0) {
		perror("noecho");
		exit(1);
	}

	dprintf("[ initilizing term table... ]\n");
	mktable();
	dprintf("[ table done ]\n");

	if(!fflag) {
		dointernal();
	} else
		dprintf("!fflag.  not doing dointernal().\n");

	index = tabmark;
	dprintf("main: we'll do a dotab()\n");
	dotab();
	dprintf("main: dotab done\n");

	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	if(!found) {
		dprintf("end of main\n");
		notrecognized();
	}
}

done()
{
	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	exit(0);
}

/*
 * finish - clean things up.
 */
finish()
{
	dprintf("finish called\n");
	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	if(recvbuf[0] != NULL)
		(void) prinfo(compare(recvbuf, 0, tabtotal), 1);
		
	dprintf("finish done\n");
	if(!found)
		notrecognized();
	exit(0);
}

prinfo(t, what)
struct qt *t;
int what;
{
	int len = 0;
	int st = FALSE;

	dprintf("prinfo startup\n");
	if((t->qt_termname[0] != NULL) && (recvbuf[0] != NULL)) {
		if(debug || sflag) {
			len = strlen(recvbuf);
			fprintf(stderr, "%s receives %d character%s:", 
				progname, len, (len == 1) ? "" : "s");
			fprintf(stderr, " %s\n", decode(recvbuf));
		}
		if(!qflag)
			if(t->qt_fullname[0] != NULL)
				fprintf(stderr, "Terminal recognized as %s (%s)\n", 
					t->qt_termname, t->qt_fullname);
			else
				fprintf(stderr, "Terminal recognized as %s\n", 
					t->qt_termname);
		printf("%s\n", t->qt_termname);
		found = TRUE;
		done();
		/*NOTREACHED*/
	} else {
		found = FALSE;
		if(what) {
			dprintf("prinfo(): doing notrecognized()\n");
			notrecognized();
			done();
			/*NOTREACHED*/
		}
	}
	dprintf("prinfo done\n");
	return(st);
}

/*
 * compare - actually compare what we received against the table.
 */
struct qt *
compare(str, start, stop)
char *str;
int start;
int stop;
{
	register int i = 0;
	int len;

	dprintf("compare(%s, %d, %d) startup.\n", decode(str), start, stop);
	alarm(0);

	i = start;
	while(i <= stop) {
		dprintf("compare(): tr = '%s'\n", decode(termtab[i].qt_recvstr));
		if(strncmp(str, termtab[i].qt_recvstr, 
		  strlen(termtab[i].qt_recvstr)) == 0) {
			found = TRUE;
			return(&termtab[i]);
		}
		++i;
	}
	found = FALSE;
}

/*
 * getch - read in a character at a time.
 */
getch()
{
	char c;

	(void) read(0, &c, 1);
	return(c & CMASK);
}

/*
 * decode - print str in a readable fashion
 */
char *
decode(str)
char *str;
{
	char buf[BUFSIZ];
	char tmp[10];

	strcpy(buf, "");
	while(*str) {
		if (*str == ESC) {
			strcat(buf, "<esc> ");
		} else if((*str <= 33) || (*str >= 127)) {
			sprintf(tmp,"\\%o ", *str);
			strcat(buf, tmp);
		} else {
			sprintf(tmp,"%c ", *str);
			strcat(buf, tmp);
		}
		*++str;
	}
	return(buf);
}

usage()
{
	fprintf(stderr, "usage: %s [ -asq ]\n", progname);
}

mktable()
{
	register int i, z;
	FILE *fd, *fopen();
	char file[BUFSIZ];
	char buf[BUFSIZ];
	char lbuf[4][BUFSIZ];
	char *home, *msg, *fixctl();
	int iserr = 0;
	extern char *terms[];
	struct passwd *pwd;

	i = z = 0;
	/*
	 * Copy internal table
	 */
	while(terms[z] != NULL && i < MAXTERMS) {
		(void) strcpy(termtab[i].qt_sendstr, (aflag) ? ALTSEND : SEND);
		(void) strcpy(termtab[i].qt_recvstr, terms[z + T_STR]);
		(void) strcpy(termtab[i].qt_termname, terms[z + T_NAME]);
		(void) strcpy(termtab[i].qt_fullname, terms[z + T_LNAME]);

		z += 3;
		++i;
	}
	tabmark = i;

	/*
	 * Try and read the user's own table
	 */
	if((home = (char *) getenv("HOME")) == NULL) {
		if((pwd = (struct passwd *) getpwuid(getuid())) == NULL) {
			fprintf(stderr, "Who the hell are you????\n");
			exit(1);
		}
		home = pwd->pw_dir;
	}
	dprintf("home = '%s'\n", home);
	sprintf(file, "%s/%s", home, STRFILE);
	dprintf("strfile = '%s'\n", file);
	if(fflag && (fd = fopen(file, "r")) != NULL) {
		while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
			if(buf[0] == '#' || buf[0] == '\n')
				continue;

			lbuf[0][0] = NULL;
			lbuf[1][0] = NULL;
			lbuf[2][0] = NULL;
			lbuf[3][0] = NULL;
	
			(void) sscanf(buf, "%s%s%s\t%[^\n]", 
				lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
			if(lbuf[0][0] == NULL)
				continue;
			if(lbuf[1][0] == NULL) {
				iserr = TRUE;
				msg = "receive string";
			}
			if(lbuf[2][0] == NULL) {
				iserr = TRUE;
				msg = "terminal name";
			}
			if(iserr) {
				fprintf(stderr, "%s: Error parsing %s.\n", file, msg);
				exit(1);
			}
			(void) strcpy(termtab[i].qt_sendstr, fixctl(lbuf[0]));
			(void) strcpy(termtab[i].qt_recvstr, fixctl(lbuf[1]));
			(void) strcpy(termtab[i].qt_termname, lbuf[2]);
			(void) strcpy(termtab[i].qt_fullname, lbuf[3]);

			dprintf("entry %d:\n", i);
			dprintf("qt_sendstr = %s\n", decode(termtab[i].qt_sendstr));
			dprintf("qt_recvstr = %s\n", decode(termtab[i].qt_recvstr));
			dprintf("qt_termname = '%s'\n", termtab[i].qt_termname);
			dprintf("qt_fullname = '%s'\n", termtab[i].qt_fullname);

			++i;
		}
	}
	tabtotal = i;
	dprintf("termtab total  = %d\n", tabtotal);
	dprintf("termtab mark  = %d\n", tabmark);
}

listen(q)
struct qt *q;
{
	register int i;
	register char c;
	char end, begin;

	dprintf("listen startup\n");
	alarm(0);

	dprintf("listen: listening for '%s'\n", decode(q->qt_recvstr));

	if (q->qt_recvstr[0] == NULL) {
		begin = ESC;
		end = 'c';
	} else {
		begin = q->qt_recvstr[0];
		end = q->qt_recvstr[strlen(q->qt_recvstr)-1];
	}

	dprintf("listen: read initial character...\n");
	if(setjmp(env)) {
		dprintf("listen: setjmp TRUE\n");
		if(found)
			done();
		++index;
		(void) fflush(stdin);
		dprintf("listen: dotab()\n");
		dotab();
	} else {
		dprintf("listen: setjmp FALSE...set alarm\n");
		signal(SIGALRM, wakeup);
		alarm(3);
		dprintf("listen: read char\n");
		recvbuf[0] = getch();
		alarm(0);
		dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);

	}
	i = 0;
	if(recvbuf[0] == begin) {
		dprintf("listen begin\n");
		while(c != end) {
			if(setjmp(env))  {
				dprintf("listen: setjmp (2) return\n");
				return;
			} else {
				signal(SIGALRM, wakeup);
				alarm(2);
				dprintf("listen: read (2) char\n");
				c = getch();
				alarm(0);
				dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
			}
			recvbuf[++i] = c;
		}
		if(debug)
			fprintf(stderr,"\n[ Received terminator. ]\n");
	} else {
		dprintf("listen: Not Recognized.  exiting...\n");
		notrecognized();
		putc('\r',stderr);
		(void) nocrmode();
		(void) echo();
		exit(1);
	}
	dprintf("listen done\n");
}

notrecognized()
{
	if(!qflag)
		fprintf(stderr, 
		  "Terminal NOT recognized - defaults to \"dumb\".\n");
	puts("dumb");
}

wakeup()
{
	dprintf("wakeup called\n");
	longjmp(env, 1);
	dprintf("wakeUP: done\n");
}

dotab()
{
	int wakeup();
	int st = FALSE;
	static int firsttime = TRUE;

	dprintf("dotab startup\n");
	dprintf("index = %d\n", index);
	if(index > tabtotal) {
		/*
		 * if we haven't reset things yet, do so.
		 * now try the internal tables if the user's
		 * tables failed.
		 */
		if(!has_set)  {
			tabtotal = tabmark;
			index = 0;
			has_set = 1;
			dprintf("dotab(): has_set now true.\n");
			dotab();
		}
		dprintf("dotab(): index > tabtotal\n");
		finish();
	}
	if(!found || fflag) {
		while(!found && termtab[index].qt_sendstr[0] != NULL && !st) {
			dprintf("dotab: termtab PASS %d\n", index);
			dprintf("dotab: sending str %s\n", 
				decode(termtab[index].qt_sendstr));
			(void) fflush(stdin);
			if(firsttime || strncmp(termtab[index].qt_sendstr, 
			  termtab[index-1].qt_sendstr,
			  strlen(termtab[index].qt_sendstr))) {
				firsttime = FALSE;
				dprintf("dotab(): sendstr's didn't match.\n");
				dprintf("dotab: str1 %s\n", 
					decode(termtab[index].qt_sendstr));
				dprintf("dotab: str2 %s\n", 
					decode(termtab[index-1].qt_sendstr));
				fprintf(stderr, termtab[index].qt_sendstr);
				(void) fflush(stdout);
				(void) fflush(stderr);
				(void) listen(&termtab[index]);
			} else {
				dprintf("dotab(): sendstr's DID match.  No str sent.\n");
				dprintf("dotab: str1 %s\n", 
					decode(termtab[index].qt_sendstr));
				dprintf("dotab: str2 %s\n", 
					decode(termtab[index-1].qt_sendstr));
			}

			firsttime = FALSE;
			dprintf("dotab(): recbuf = '%s'\n", decode(recvbuf));
			dprintf("dotab(): qt_rec = '%s'\n", 
				decode(termtab[index].qt_recvstr));
			st = prinfo(compare(recvbuf, tabmark, tabtotal), !fflag);
			dprintf("st = %d\n", st);
			++index;
		}
		dprintf("dotab(): mark 1\n");
	}
	dprintf("i'm here (2)\n");
	if(!found) {
		dprintf("end of dotab\n");
		dointernal();
		if(!found) {
			dprintf("dotab: dointernal failed.\n");
			notrecognized();
		}
	}
	done();
}

dointernal()
{
	struct qt q;

	dprintf("DOINTERNAL startup.\n");

	(void) fflush(stdin);
	fprintf(stderr, (aflag) ? ALTSEND : SEND);
	(void) fflush(stdout);
	(void) fflush(stderr);

	q.qt_recvstr[0] = NULL;

	(void) listen(&q);

	(void) prinfo(compare(recvbuf, 0, tabmark), 1);
	if(found)
		done();

	dprintf("dointernal end.\n");
}

char *
fixctl(str)
char *str;
{
	register int i;
	char buf[BUFSIZ];

	i = 0;
	while(*str) {
		if(*str == '^')
			buf[i++] = *++str & 037;
		else
			buf[i++] = *str;
		*++str;
	}
	buf[i] = NULL;
	return(buf);
}
SHAR_EOF
echo shar: extracting "'qterm.1'" '(3334 characters)'
if test -f 'qterm.1'
then
	echo shar: over-writing existing file "'qterm.1'"
fi
cat << \SHAR_EOF > 'qterm.1'
.\"
.\" $Header: qterm.1,v 1.1 86/12/22 10:45:25 mcooper Exp $
.\"
.TH QTERM 1 8/8/86
.ds ]W USC Computing Services
.SH NAME
qterm \- Query Terminal
.SH SYNOPSIS
qterm 
[
.B \-a
]
[
.B \-f
]
[
.B \-s
]
[
.B \-q
]
.SH DESCRIPTION
.I Qterm
is used to query a terminal to determine its name.
This is done by sending the fairly universal 
string ``<ESCAPE>Z'' to the terminal,
reading in a response, and comparing it against a master table of possible
responses.
The ``name'' printed to standard output should be one found in
the
.I termcap(5) 
database.
.PP
For 
.I csh(1) 
users,
putting a line in your 
.I .login 
file such as:
.sp 1
.in +.5i
setenv TERM `qterm`
.in -.5i
.sp 1
should automagically set your terminal type.
For 
.I sh(1)
users, putting these lines in your 
.I .profile 
file should set your terminal type:
.sp 1
.in +.5i
TERM=`qterm`
.br
export TERM
.in -.5i
.sp 1
.SH OPTIONS
.IP \-a
Use the alternate string ``<ESCAPE>[c'' when asking the terminal to
identify itself.  This string is recognized by most ANSI compatible
terminals.
.IP \-f
If the file
.B $HOME/.qterm
is present, it's contents are scanned to produce information for
querying terminals.  In this way, a user may setup different values
for certain terminals.
After the contents of this file have been scanned, 
.I qterm
proceeds to query the terminal with the information provided
in the file
.B $HOME/.qterm.
If an un-intelligable response is received (or non at all), 
.I qterm
will proceed to use its own internal information to determine the terminal
type.
.IP \-s
Display the response received from
the terminal in a ``nice'' fashion.
.IP \-q
Be ``quiet'' and only print the terminal name to standard
output.
.SH ".QTERM FILE"
.PP
The format of the file
$HOME/.qterm
consists of four fields each seperated by white space (tabs and/or spaces).
The first field is the string that should be used to query the terminal.
The second field is the string to expect in response to the query.
The third field is the terminal name (compatible with 
.I termcap(5))
to print to standard output.
The fourth field is optional and may contain a description of the exact
manufacturer and model name of the terminal to be used in a message
printed to standard error.
.PP
Blank lines or lines starting with the character ``#''
are ignored and may be used as comment lines.
A character preceeded by a ``^'' is taken to mean the 
.I control
character.  (i.e. ``^['' is interpretted as an <ESCAPE>).
.PP
Below is a sample file:
.sp 2
.nf
	#
	# QTerm File
	#
	^[Z\0\0\0\0\0^[[?1;1c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with STP
	^[Z\0\0\0\0\0^[[?1;2c\0\0\0\0\0vt100\0\0\0\0\0ANSI/VT100 Clone
	^[Z\0\0\0\0\0^[[?1;3c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with AVO and STP
	^[Z\0\0\0\0\0^[[?1;4c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with GPO
	^[Z\0\0\0\0\0^[iBO\0\0\0\0\0\0\0\0z29\0\0\0\0\0\0\0Zenith in Zenith Mode
.fi
.sp
.SH AUTHOR
Michael A. Cooper, 
.br
USC Computing Services, Los Angeles.
.SH FILES
/etc/termcap	\- termcap(5) database
.SH SEE ALSO
csh(1), sh(1), termcap(5)
.SH DIAGNOSTICS
.IP "\fITerminal not recognized - defaults to dumb.\fP"
.I QTerm
did not receive a response from the terminal, or the response
did not match any that 
.I qterm 
has stored internally.  Use the \-s option to check to see which
is the case.
.SH BUGS
Many terminals do not send a response at all.
SHAR_EOF
#	End of shell archive
exit 0
-- 
Michael A. Cooper, University Computing Services, U of Southern California
  UUCP: {sdcrdcf, uscvax}!usc-oberon!mcooper  BITNET: mcooper@uscvaxq
  ARPA: mcooper@usc-oberon.USC.EDU            PHONE: (213) 743-3462