[comp.sources.unix] v10i072: Query terminal for its type

rs@uunet.UU.NET (Rich Salz) (07/31/87)

Submitted-by: Michael A. Cooper <mcooper@oberon.usc.edu>
Posting-number: Volume 10, Issue 72
Archive-name: qterm

[  This program sends a "what are you" escape sequence to a terminal,
   and interprets the reply.  --r$  ]

#!/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
#	qtermtab
#	qterm.c
#	qterm.h
#	qterm.1
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1233 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: 3.0 $
                        $Date: 87/06/30 19:14:35 $

	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
VAX 4.2BSD, VAX 4.3BSD, Sun 3.0 and Sun 3.2.  It is know to work under
System V.2, but I have not personally tested it on such a system.
(For System V.2, compile with USG5 defined).

	If you have ARPA Internet access, the latest and greatest
version of qterm is available from oberon.USC.EDU via anonymous ftp in
the file pub/qterm.shar.  I update this file fairly often, so it's
bound to be newer than a copy from any other source.



Michael A. Cooper, University Computing Services, U of Southern California
  UUCP: {sdcrdcf, cit-vax}!oberon!mcooper     BITNET: mcooper@uscvaxq
  ARPA: mcooper@oberon.USC.EDU                PHONE: (213) 743-2957
SHAR_EOF
echo shar: extracting "'Makefile'" '(949 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
#
# $Header: Makefile,v 3.1 87/07/22 09:36:13 mcooper Exp $
#
# Makefile for QTerm
#

#
# If you change DIR, run "make reconfig".
#
DIR = /usr/public

BIN = $(DIR)/bin
MAN = $(DIR)/man/man1

#
# TABFILE should be set to the location you want the qterm table
# file placed in.
#
TABFILE = $(DIR)/lib/qtermtab

CONFIGFILES = Makefile qterm.1

OBJS = qterm.o
#
# Add "-DUSG5" to $(CFLAGS) below, if your system is Unix System V.
#
CFLAGS = -O -DTABFILE=\"$(TABFILE)\"

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

reconfig:
	-@for i in $(CONFIGFILES); do \
                echo ReConfiguring $$i...;\
		sed "s;/usr/public;$(DIR);g" < $$i > $$i.tmp;\
		mv -f $$i.tmp $$i;\
        done

shar:
	shar README Makefile qtermtab qterm.c qterm.h qterm.1 > qterm.shar

clean:
	rm -f *.o core log *~ \#* qterm qterm.shar o

install: qterm qterm.1 qtermtab
	install qterm $(BIN)
	install -c -m 644 qterm.1 $(MAN)
	install -c -m 644 qtermtab $(TABFILE)
SHAR_EOF
echo shar: extracting "'qtermtab'" '(1556 characters)'
if test -f 'qtermtab'
then
	echo shar: over-writing existing file "'qtermtab'"
fi
cat << \SHAR_EOF > 'qtermtab'
#
# $Header: qtermtab,v 3.0 87/07/01 13:36:30 mcooper Release $
# $Source: /big/src/usc/bin/qterm/RCS/qtermtab,v $
#
# QtermTab - Terminal table for qterm(1).
#
#SendStr ReceiveStr		TermName	FullTermName
#
^[Z	^[iBO         		h29	 	Zenith z29 in zenith mode
^[Z	^[/K          		h29	 	Zenith z29 in zenith mode
^[Z	^[[?1;0c     		vt100    	Base vt100
^[Z	^[[?1;1c     		vt100   	vt100 with STP
^[Z	^[[?1;2c     		vt100   	ANSI/VT100 Clone
^[Z	^[[?1;3c     		vt100    	vt100 with AVO and STP
^[Z	^[[?1;4c     		vt100    	vt100 with GPO
^[Z	^[[?1;5c     		vt100    	vt100 with GPO and STP
^[Z	^[[?1;6c     		vt100    	vt100 with GPO and AVO
^[Z	^[[?1;7c     		vt100    	vt100 with GPO, STP, and AVO
^[Z	^[[?6c        		vt100  	 	Generic vt100
^[Z	^[[?8c        		vt100    	TeleVideo 970
^[Z	^[[0n         		vt100    	AT&T Unix PC 7300
^[Z	^[[?l;0c     		vt100    	AT&T Unix PC 7300
^[Z	^[[?12c       		vt100    	Concept from Pro 350/UNIX
^[Z	^[[?;c        		vt100    	Concept From Pro 350/UNIX
^[Z	^[[=1;1c     		avt-4p-s 	Concept with 4 pages memory
^[Z	^[[=1;2c     		avt-8p-s 	Concept with 8 pages memory
^[Z	^[/Z          		vt52	 	Generic vt52
^[Z	^[[?10c       		la120	 	DEC Writer III
^[Z	^[[?1;11c    		cit101e  	CIE CIT-101 Enhanced w/Graphics
#^[Z	^[[?1;11c    		xt100+   	Northern Tech LANPARSCOPE
^[Z	^[[?12;7;0;102c 	vt125	 	DEC Pro 350 in vt125 mode
^[Z	^[[?62;1;2;6;7;8;9c 	vt220   	DEC VT220
^[Z	^[[?62;1;4;6;7;8;9;15c	vt200-sb	Microvax II VMS
^[Z	^[[62;1;2;6;8c		f220     	Freedom 220 DEC clone
^[Z	^[[?63;1;2;6;7;8c 	tvi9220  	TeleVideo 9220
SHAR_EOF
echo shar: extracting "'qterm.c'" '(13185 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 3.0 87/06/30 19:07:59 mcooper Release $";
#endif

/*
 *------------------------------------------------------------------
 *
 * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
 * $Revision: 3.0 $
 * $Date: 87/06/30 19:07:59 $
 * $State: Release $
 * $Author: mcooper $
 * $Locker:  $
 *
 *------------------------------------------------------------------
 *
 * Michael A. Cooper
 * Research and Development Group
 * University Computing Services 
 * University of Southern California
 * (mcooper@oberon.USC.EDU)
 *
 *------------------------------------------------------------------
 *
 * $Log:	qterm.c,v $
 * Revision 3.0  87/06/30  19:07:59  mcooper
 * Release of version 3.
 * 
 * Revision 2.4  87/04/29  19:28:35  mcooper
 * In readtabfile() we now do special
 * things when opening "file" fails
 * depending on the bequiet flag.
 * 
 * Revision 2.3  87/04/29  13:11:37  mcooper
 * - No more "internal" table.  The master
 *   table is read from a file (TABFILE).
 *   This makes ~/.qterm stuff much cleaner.
 * - Error handling for qtermtab files is
 *   much more informative now.
 * - More things I can't remember.
 * 
 * Revision 2.2  87/03/05  21:01:28  mcooper
 * Fixed system V compiler problem.
 * 
 * Revision 2.1  87/03/01  19:43:22  mcooper
 * Be more intelligent about the size of 
 * the default terminal table.
 * 
 * Revision 2.0  87/03/01  19:20:00  mcooper
 * General cleanup.
 * 
 *------------------------------------------------------------------
 */


/*
 * 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@oberon.USC.EDU
 * UUCP: 	{sdcrdcf, cit-vax}!oberon!mcooper
 * 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

#include "qterm.h"

int tabtotal = 0;
int has_set = 0;

struct qt *compare();
struct qt termtab[MAXTERMS];

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


static char recvbuf[SIZE];
static char *progname;

int debug = FALSE;          /* debug mode */
int aflag = FALSE;          /* alternate string */
int sflag = FALSE;          /* print strings */
int qflag = FALSE;          /* quiet mode */
int fflag = FALSE;          /* use user's own .qterm file */
int Fflag = FALSE;          /* same as above, but don't add our own table */

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 '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);
  }

  mktable();

  index = 0;
  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();
  }
}

usage()
{
  fprintf(stderr, "usage: %s [ -a ] [ -s ] [ -q ] [ -f ] [ -F ]\n", 
	  progname);
}

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

/*
 * 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 != NULL) && (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(0);
    /*NOTREACHED*/
  } else {
    found = FALSE;
    if(what) {
      dprintf("prinfo(): doing notrecognized()\n");
      notrecognized();
      done(1);
      /*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;

  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;

  return(NULL);
}

/*
 * 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);
}

mktable()
{
  char file[BUFSIZ];
  struct passwd *pwd;
  char *home;

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

  if(fflag) {
    /*
     * 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);

    (void) readtabfile(file, TRUE);
  }

  if(!Fflag)
    (void) readtabfile(TABFILE, FALSE);

  dprintf("termtab total  = %d\n", tabtotal);
  dprintf("[ mktable done ]\n");
}

readtabfile(file, bequiet)
char *file;
int bequiet;
{
  static int i = 0, line;
  char lbuf[4][BUFSIZ];
  char buf[BUFSIZ];
  FILE *fd, *fopen();
  char *msg, *fixctl();
  int iserr = 0;

  if((fd = fopen(file, "r")) == NULL) {
    if(bequiet)
      return(-1);
    perror(file);
    done(1);
  }

  line = 0;
  while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
    ++line;
    
    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, "Line %d of %s: Error parsing %s.\n", 
	      line, file, msg);
      done(1);
      /* NOTREACHED */
    }
    if(aflag)
      (void) strcpy(termtab[i].qt_sendstr, fixctl(ALTSEND));
    else
      (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;

  return(0);
}

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(WAIT);
    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(WAIT);
        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)  {
      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, 0, tabtotal), FALSE);

      dprintf("st = %d\n", st);

      ++index;
    }
  }

  if(!found) {
    dprintf("dotab: failed.\n");
    notrecognized();
  }

  done();
}

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.h'" '(2544 characters)'
if test -f 'qterm.h'
then
	echo shar: over-writing existing file "'qterm.h'"
fi
cat << \SHAR_EOF > 'qterm.h'
/*
 * $Header: qterm.h,v 3.0 87/06/30 19:09:04 mcooper Release $
 *------------------------------------------------------------------
 *
 * $Source: /big/src/usc/bin/qterm/RCS/qterm.h,v $
 * $Revision: 3.0 $
 * $Date: 87/06/30 19:09:04 $
 * $State: Release $
 * $Author: mcooper $
 * $Locker:  $
 *
 *------------------------------------------------------------------
 *
 * Michael A. Cooper
 * Research and Development Group
 * University Computing Services 
 * University of Southern California
 * (mcooper@oberon.USC.EDU)
 *
 *------------------------------------------------------------------
 * $Log:	qterm.h,v $
 * Revision 3.0  87/06/30  19:09:04  mcooper
 * Release of version 3.
 * 
 * Revision 2.4  87/06/30  19:02:28  mcooper
 * WAIT changed to 2 for slow systems.
 * 
 *------------------------------------------------------------------
 */



#ifndef TABFILE
# define TABFILE   "/usr/local/lib/qtermtab"
#endif

#define ALTSEND    "\033[c"            /* alternate string */
#define STRFILE    ".qterm"            /* file containing terminal strings */

#define WAIT       2                   /* Number of seconds for alarms */
#define MAXTERMS   50                  /* Maximum # of terminals for qterm */

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

#define TRUE       1
#define FALSE      0

#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 dprintf    if(debug)printf

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 */
};
SHAR_EOF
echo shar: extracting "'qterm.1'" '(3608 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 3.0 87/06/30 19:10:08 mcooper Release $
.\"
.TH QTERM 1 "29 April 1987"
.ds ]W USC-UCS
.SH NAME
qterm \- Query Terminal
.SH SYNOPSIS
qterm 
[
.B \-a
]
[
.B \-f
]
[
.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 a special sequence 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.
If an un-intelligable response is received (or non at all), 
.I qterm
will proceed to use its own information to determine the terminal
type.
.IP \-F
Same as \-f except that the standard 
.I qterm
table is not scanned; only the user's 
.B $HOME/.qterm
file is used.
.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 "QTERMTAB"
The format of the file
$HOME/.qterm
and 
.I qterm's
master file
.I /usr/public/lib/qtermtab,
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
University Computing Services, 
.br
University of Southern California.
.SH FILES
.ta \w'/usr/public/lib/qtermtab\ \ \ 'u
/usr/public/lib/qtermtab	\- Master table
.br
$HOME/.qterm	\- User's table
.br
/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
-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.uu.net