2.11BSD/src/local/qterm/qterm.c
#ifndef lint
static char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $";
#endif
/*
* Copyright (c) 1990 Michael A. Cooper.
* This software may be freely distributed provided it is not sold for
* profit and the author is credited appropriately.
*/
/*
*------------------------------------------------------------------
*
* $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $
* $Revision: 5.4 $
* $Date: 1991/03/21 02:09:40 $
* $State: Exp $
* $Author: mcooper $
* $Locker: $
*
*------------------------------------------------------------------
*
* Michael A. Cooper
* Research and Development Group
* University Computing Services
* University of Southern California
* (mcooper@usc.edu)
*
*------------------------------------------------------------------
*
* $Log: qterm.c,v $
* Revision 5.4 1991/03/21 02:09:40 mcooper
* Fix memory buffer problem with some C
* compilers. (tp@vtold.vtol.fi)
*
* Revision 5.3 1991/03/16 05:36:30 mcooper
* Fix casting of (char) NULL problem.
*
* Revision 5.2 1991/03/12 00:46:24 mcooper
* Change CMASK to CHAR_CMASK to avoid conflict
* under AIX 3.1.
*
* Revision 5.1 1991/02/20 02:23:33 mcooper
* Cleanup #ifdef USG5 as part of port
* to UTS 2.1 (System V.3).
*
* Revision 5.0 1990/12/15 18:30:41 mcooper
* Version 5.
*
* Revision 4.13 90/12/15 18:14:23 mcooper
* Add copywrite.
*
* Revision 4.12 90/11/13 16:00:03 mcooper
* Convert OptInt's to OptBool's where needed.
*
* Revision 4.11 90/11/13 15:38:28 mcooper
* Make OLD_SepArg include both
* SepArg and StickyArg.
*
* Revision 4.10 90/11/08 15:41:08 mcooper
* Make sure qt_fullname is not 0 length.
*
* Revision 4.9 90/11/08 13:02:06 mcooper
* Fix bug that closes the tty when an error
* occurs during command line parsing.
*
* Revision 4.8 90/11/06 13:19:40 mcooper
* Changed command line options to new
* longer names.
*
* Revision 4.7 90/11/05 17:09:30 mcooper
* Update option help messages and option names
* to be more mnemonic.
*
* Revision 4.6 90/11/05 16:44:35 mcooper
* - Converted to use new ParseOptions() for
* command line parsing.
* - Major de-linting.
* - Convert dprintf() to use varargs (if
* HAS_VARARGS is defined).
* - Lots of misc. cleanup.
*
* Revision 4.5 89/10/20 22:50:49 mcooper
* Changed code indention to current local
* standard of 4. (This should also mess up
* everybody trying to do diff's from older versions!)
*
* Revision 4.4 89/10/20 14:03:48 mcooper
* Fixed command line parsing of "-f -q".
*
* Revision 4.3 88/06/16 19:43:46 mcooper
* - Added -T flag to wait until timeout when
* listening for response string. This solves
* problem when the first entry in a table
* doesn't have a response string with a
* common ending character to look for.
* - Added -I flag for "intense" query mode.
* - Cleaned up debugging a bit.
*
* Revision 4.2 88/06/08 15:30:53 mcooper
* Cleanup pass including removing
* extraneous debugging messages.
*
* Revision 4.1 88/04/25 13:24:38 mcooper
* Added -S option to print send and recieve
* strings as they are sent and recieved as
* suggested by David W. Sanderson
* (dws@attunix.att.com).
*
* Revision 4.0 88/03/08 19:30:59 mcooper
* Version 4.
*
* Revision 3.7 88/03/08 19:28:32 mcooper
* Major rewrite.
*
* Revision 3.6 88/03/08 15:31:35 mcooper
* General cleanup time.
*
* Revision 3.5 88/03/08 13:59:39 mcooper
* - Catch signals and fix terminal modes.
* - Don't allow alarm times of 0.
* - Support for HP-UX machines and cleaner
* listen() code from Zenon Fortuna,
* HP-UX Support, Hewlett-Packard Vienna.
*
* Revision 3.4 87/10/07 15:16:17 mcooper
* - Beautify code a bit.
* - Add -w <N> option to set the wait time.
*
* Revision 3.3 87/08/24 19:25:32 mcooper
* The following based on code from Frank Crawford
* <frank@teti.qhtours.OZ>:
* - Use $TERM as output string when the terminal
* type is not known instead of "dumb".
* - Regular Expressions are now supported. RE are
* started with a leading `\'.
* - Octal values may now be used in send/recieve strings.
*
* Revision 3.1 87/08/03 15:21:07 mcooper
* As pointed out by Scott H. Robinson <shr@cetus.ece.cmu.edu>,
* the -F switch does work. Problem was that it never read
* in the ~/.qterm file.
*
* 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
* Internet: mcooper@usc.edu
* UUCP: ...!rutgers!usc!mcooper
* BITNET: mcooper@gamera
*/
#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <setjmp.h>
#ifdef USG5
# include <termio.h>
#else /*USG5*/
# include <sys/file.h>
# include <sgtty.h>
#endif /*USG5*/
#include "qterm.h"
#include "options.h"
#ifdef HAS_VARARGS
#include <varargs.h>
#endif /*HAS_VARARGS*/
#ifdef USG5
struct termio _ntty, _otty;
#else
struct sgttyb _tty;
#endif
int _tty_ch = 2;
char recvbuf[SIZE];
char *progname;
char *termfile = NULL;
int debug = FALSE; /* Debug mode */
int use_alt_str = FALSE; /* Alternate string */
int towait = FALSE; /* Time out wait flag */
int always_send = FALSE; /* Intense query mode */
int longname = FALSE; /* Print long terminal name */
int sent_chars = FALSE; /* Print strings sent from the terminal */
int watch_chars = FALSE; /* Watch strings as they are sent and recv. */
int quiet = FALSE; /* Quiet mode */
int do_usrtabfile = FALSE; /* Use user's own .qtermtab file */
int do_systabfile = TRUE; /* Use the system's qterm tab file */
int almwait = WAIT; /* Wait (timeout) interval */
/*
* Old options should not be visable in help and usage messages.
*/
#ifdef OPT_COMPAT
#define OLD_NoArg NoArg|ArgHidden
#define OLD_SepArg SepArg|StickyArg|ArgHidden
#define fFLAG "-f"
#define FFLAG "-F"
#endif
/*
* Command line options table.
*/
OptionDescRec opts[] = {
#ifdef OPT_COMPAT
{"-a", OLD_NoArg, OptInt, (caddr_t) &use_alt_str, "1",
(char *)NULL, "Use alternate query string"},
{"-s", OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1",
(char *)NULL, "Display the characters the terminal sent"},
{"-t", ArgHidden|OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1",
(char *)NULL, "Display the characters the terminal sent"},
{"-I", OLD_NoArg, OptInt, (caddr_t) &always_send, "1",
(char *)NULL, "Always send the terminal query string"},
{"-T", OLD_NoArg, OptInt, (caddr_t) &towait, "1",
(char *)NULL, "Enable time out wait"},
{"-S", OLD_NoArg, OptInt, (caddr_t) &watch_chars, "1",
(char *)NULL, "Print strings as they are sent and received"},
{"-q", OLD_NoArg, OptInt, (caddr_t) &quiet, "1",
(char *)NULL, "Enable quite mode"},
{"-f", OLD_SepArg, OptStr, (caddr_t) &termfile, fFLAG,
"<tabfile>", "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
{"-F", OLD_SepArg, OptStr, (caddr_t) &termfile, FFLAG,
"<tabfile>", "Try <tabfile>, then ~/.qtermtab"},
{"-l", OLD_NoArg, OptInt, (caddr_t) &longname, "1",
(char *)NULL, "Output only the long (verbose) terminal name"},
{"-d", OLD_NoArg, OptInt, (caddr_t) &debug, "1",
(char *)NULL, "Enable debug mode"},
{"-w", OLD_SepArg, OptInt, (caddr_t) &almwait, __ NULL,
"<interval>", "Wait (timeout) period (in seconds)"},
#endif /*OPT_COMPAT*/
{"+alt", NoArg, OptBool, (caddr_t) &use_alt_str, "1",
(char *)NULL, "Use alternate query string"},
{"-alt", NoArg, OptBool, (caddr_t) &use_alt_str, "0",
(char *)NULL, "Don't use alternate query string"},
{"+always", NoArg, OptBool, (caddr_t) &always_send, "1",
(char *)NULL, "Always send the terminal query string"},
{"-always", NoArg, OptBool, (caddr_t) &always_send, "0",
(char *)NULL, "Don't always send the terminal query string"},
{"-file", SepArg, OptStr, (caddr_t) &termfile, __ NULL,
"<tabfile>", "Use <tabfile> to query terminal"},
{"+longname",NoArg, OptBool, (caddr_t) &longname, "1",
(char *)NULL, "Output only the long (verbose) terminal name"},
{"-longname",NoArg, OptBool, (caddr_t) &longname, "0",
(char *)NULL, "Don't output the long (verbose) terminal name"},
{"+quiet", NoArg, OptBool, (caddr_t) &quiet, "1",
(char *)NULL, "Enable quiet mode"},
{"-quiet", NoArg, OptBool, (caddr_t) &quiet, "0",
(char *)NULL, "Disable quiet mode"},
{"+sent", NoArg, OptBool, (caddr_t) &sent_chars, "1",
(char *)NULL, "Display the characters the terminal sent"},
{"-sent", NoArg, OptBool, (caddr_t) &sent_chars, "0",
(char *)NULL, "Don't display the characters the terminal sent"},
{"+timeout",NoArg, OptBool, (caddr_t) &towait, "1",
(char *)NULL, "Enable time out wait"},
{"-timeout",NoArg, OptBool, (caddr_t) &towait, "0",
(char *)NULL, "Disable time out wait"},
{"+usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1",
(char *)NULL, "Enable using ~/.qtermtab"},
{"-usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "0",
(char *)NULL, "Disable using ~/.qtermtab"},
{"-wait", SepArg, OptInt, (caddr_t) &almwait, __ NULL,
"<interval>", "Wait (timeout) period (in seconds)"},
{"+watch", NoArg, OptBool, (caddr_t) &watch_chars, "1",
(char *)NULL, "Watch the characters sent and recieved"},
{"-watch", NoArg, OptBool, (caddr_t) &watch_chars, "0",
(char *)NULL, "Don't watch the characters sent and recieved"},
{"+systab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1",
(char *)NULL, "Enable using system qtermtab file"},
{"-systab", NoArg, OptBool, (caddr_t) &do_systabfile, "0",
(char *)NULL, "Disable using system qtermtab file"},
{"-debug", ArgHidden|NoArg, OptInt, (caddr_t) &debug, "1",
(char *)NULL, "Enable debug mode"},
};
FILE *fopen();
char *decode();
char *getenv();
char *malloc();
char *re_comp();
char *strcat();
char *xmalloc();
int alarm();
int found = FALSE;
int modes_set = FALSE;
jmp_buf env;
struct termtable *compare();
struct passwd *getpwuid();
void catch();
void done();
void dprintf();
void exit();
void myperror();
void mktable();
void notrecognized();
void proctab();
void wakeup();
#ifdef USG5
char *regcmp();
#endif /* USG5 */
main(argc, argv)
int argc;
char **argv;
{
config(argc, argv);
setmodes();
mktable();
proctab((struct termtable *)NULL);
resetmodes();
if (!found) {
notrecognized();
}
exit(0);
}
/*
* Config() - Perform configuration operations.
*/
config(argc, argv)
int argc;
char **argv;
{
progname = argv[0];
/*
* Parse command line args
*/
if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) {
done(1);
/*NOTREACHED*/
}
/*
* Check results of command line parsing and perform any
* needed post processing.
*/
if (longname)
quiet = TRUE;
if (almwait == 0) {
(void) fprintf(stderr,
"%s: Alarm (wait) time must be greater than 0.\n",
progname);
done(1);
/*NOTREACHED*/
}
#ifdef OPT_COMPAT
/*
* Kludgy stuff to be backwards compatable for command line options.
*/
if (termfile) {
if (strcmp(termfile, fFLAG) == 0) {
do_usrtabfile = TRUE;
do_systabfile = TRUE;
termfile = NULL;
} else if (strcmp(termfile, FFLAG) == 0) {
do_usrtabfile = TRUE;
do_systabfile = FALSE;
termfile = NULL;
}
}
#endif /*OPT_COMPAT*/
dprintf("[ %s debug mode enabled ]\n\n", progname);
}
/*
* Set signal catches and terminal modes
*/
setmodes()
{
if (!isatty(0)) {
(void) fprintf(stderr, "%s: Not a tty.\n", progname);
done(0);
/*NOTREACHED*/
}
/*
* Set output buffers
*/
setbuf(stdout, (char *)0);
if (debug)
setbuf(stderr, (char *)0);
/*
* Cleanup terminal modes & such if we are killed
*/
(void) signal(SIGINT, catch);
(void) signal(SIGHUP, catch);
(void) signal(SIGTERM, catch);
/*
* Set terminal modes
*/
#ifdef USG5
if (ioctl(_tty_ch, TCGETA, &_otty) < 0)
#else
if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
#endif /* USG5 */
{
myperror("gtty");
done(1);
/*NOTREACHED*/
}
#ifdef USG5
_ntty = _otty;
#endif /* USG5 */
if (crmode() < 0) {
myperror("crmode");
done(1);
/*NOTREACHED*/
}
if (noecho() < 0) {
myperror("noecho");
done(1);
/*NOTREACHED*/
}
modes_set = TRUE;
}
/*
* Reset terminal modes
*/
resetmodes()
{
if (modes_set) {
(void) nocrmode();
(void) echo();
}
}
/*
* Print info about terminal structure t.
*/
prinfo(t, what)
struct termtable *t;
int what;
{
int len = 0;
int st = FALSE;
if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) {
if (debug || sent_chars) {
len = strlen(recvbuf);
(void) fprintf(stderr, "%s received %d character%s:",
progname, len, (len == 1) ? "" : "s");
(void) fprintf(stderr, " %s\n", decode(recvbuf));
}
if (!quiet) {
(void) fprintf(stderr, "Terminal recognized as %s",
t->qt_termname);
if (t->qt_fullname && t->qt_fullname[0])
(void) fprintf(stderr, " (%s)\n", t->qt_fullname);
else
(void) fprintf(stderr, "\n");
}
if (longname) {
if (t->qt_fullname && t->qt_fullname[0])
(void) printf("%s\n", t->qt_fullname);
else
(void) fprintf(stderr, "%s: No full terminal name for %s.\n",
progname, t->qt_termname);
} else {
(void) printf("%s\n", t->qt_termname);
}
found = TRUE;
done(0);
/*NOTREACHED*/
} else {
found = FALSE;
if (what) {
notrecognized();
done(1);
/*NOTREACHED*/
}
}
return(st);
}
/*
* compare - actually compare what we received against the table.
*/
struct termtable *compare(str)
char *str;
{
#ifdef USG5
register char *reexp;
#endif /* USG5 */
register struct termtable *t;
char buf[BUFSIZ];
dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing");
(void) alarm((unsigned)0);
if (strlen(str) == 0)
return(NULL);
for (t = termtab; t != NULL; t = t->nxt) {
dprintf(" with %s ", decode(t->qt_recvstr));
(void) sprintf(buf, "^%s$", t->qt_recvstr);
#ifdef USG5
if ((reexp = regcmp(buf, NULL)) == NULL) {
#else
if (re_comp((char *)buf) != NULL) {
#endif /* USG5 */
(void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n",
progname, t->qt_recvstr);
done(1);
/*NOTREACHED*/
}
#ifdef USG5
if (regex(reexp, str) != NULL) {
#else
if (re_exec(str) == 1) {
#endif /* USG5 */
found = TRUE;
dprintf("\tOK\n");
return(t);
}
dprintf("\tNOPE\n");
#ifdef USG5
(void) free(reexp);
#endif /* USG5 */
}
found = FALSE;
return(NULL);
}
/*
* getch - read in a character at a time.
*/
getch()
{
char c;
(void) read(0, &c, 1);
return(c & CHAR_MASK);
}
/*
* decode - print str in a readable fashion
*/
char *decode(str)
char *str;
{
register int len;
static char buf[BUFSIZ];
char tmp[10];
if (!str)
return("(null)");
(void) strcpy(buf, "");
while (*str) {
if (*str == ESC) {
(void) strcat(buf, "<esc> ");
} else if ((*str <= 33) || (*str >= 127)) {
(void) sprintf(tmp,"\\%#o ", (unsigned) *str);
(void) strcat(buf, tmp);
} else {
(void) sprintf(tmp,"%c ", *str);
(void) strcat(buf, tmp);
}
++str;
}
len = strlen(buf);
if (len && buf[len - 1] == ' ') {
buf[len - 1] = (char) NULL;
}
return(buf);
}
/*
* Make a termtab table
*/
void mktable()
{
char file[BUFSIZ];
struct passwd *pwd;
char *home;
dprintf("[ initilizing term table... ]\n");
if (termfile != NULL) {
(void) readtabfile(termfile, FALSE);
}
if (do_usrtabfile) {
/*
* Try to read the user's own table
*/
if ((home = getenv("HOME")) == NULL) {
if ((pwd = getpwuid(getuid())) == NULL) {
(void) fprintf(stderr,
"%s: Cannot find user info for uid %d.\n",
progname, getuid());
done(1);
/*NOTREACHED*/
}
home = pwd->pw_dir;
}
(void) sprintf(file, "%s/%s", home, USRFILE);
if (readtabfile(file, TRUE) < 0) {
(void) sprintf(file, "%s/%s", home, OLDUSRFILE);
(void) readtabfile(file, TRUE);
}
}
if (do_systabfile)
(void) readtabfile(TABFILE, FALSE);
dprintf("[ mktable done ]\n");
}
int readtabfile(file, bequiet)
char *file;
int bequiet;
{
static int line = 0;
char lbuf[4][BUFSIZ];
char buf[BUFSIZ];
FILE *fd;
char *p, *fixctl();
char *errmsg = NULL;
struct termtable *t;
if ((fd = fopen(file, "r")) == NULL) {
if (bequiet) {
dprintf("[ tab file '%s' can not read ]\n", file);
return(-1);
}
myperror(file);
done(1);
/*NOTREACHED*/
}
dprintf("[ Read tab file '%s' ]\n", file);
line = 0;
while (fgets(buf, sizeof(buf), fd)) {
++line;
if (buf[0] == '#' || buf[0] == '\n')
continue;
lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL;
(void) sscanf(buf, "%s%s%s\t%[^\n]",
lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
if (lbuf[0][0] == (char) NULL)
continue;
if (lbuf[1][0] == (char) NULL)
errmsg = "receive string";
if (lbuf[2][0] == (char) NULL)
errmsg = "terminal name";
if (errmsg) {
(void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n",
progname, line, file, errmsg);
done(1);
/*NOTREACHED*/
}
t = (struct termtable *) xmalloc(sizeof(struct termtable));
if (use_alt_str)
p = fixctl(ALTSEND, 0);
else
p = fixctl(lbuf[0], 0);
t->qt_sendstr = (char *) xmalloc(strlen(p)+1);
(void) strcpy(t->qt_sendstr, p);
p = fixctl(lbuf[1], 1);
t->qt_recvstr = (char *) xmalloc(strlen(p)+1);
(void) strcpy(t->qt_recvstr, p);
t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1);
(void) strcpy(t->qt_termname, lbuf[2]);
t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1);
(void) strcpy(t->qt_fullname, lbuf[3]);
dprintf("\n Send String = %s\n", decode(t->qt_sendstr));
dprintf("Expect String = %s\n", decode(t->qt_recvstr));
dprintf(" Terminal = '%s'\n", t->qt_termname);
dprintf(" Full Name = '%s'\n", t->qt_fullname);
(void) addterm(t);
}
return(0);
}
/*
* Add termtab (n) entry to main termtab.
*/
int addterm(n)
struct termtable *n;
{
register struct termtable *t;
if (!n)
return(-1);
n->nxt = NULL;
if (termtab == NULL) {
termtab = n;
} else {
t = termtab;
while(t && t->nxt)
t = t->nxt;
t->nxt = n;
}
return(0);
}
/*
* Listen for a response.
*/
void qterm_listen(q)
struct termtable *q;
{
static int i, len;
register char c;
char end;
(void) alarm((unsigned)0);
(void) strcpy(recvbuf, "");
i = 0;
len = strlen(q->qt_recvstr);
if (len) {
end = q->qt_recvstr[len - 1];
} else {
end = 'c'; /* Fairly standard ANSI default */
}
dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n",
decode(q->qt_recvstr), len, end);
/*
* If we don't get an initial character, bounce out
* of here and finish with done(0).
*/
if (setjmp(env)) {
if (found) {
done(0);
/*NOTREACHED*/
}
(void) fflush(stdin);
proctab(q->nxt);
} else {
(void) signal(SIGALRM, wakeup);
(void) alarm((unsigned)almwait);
recvbuf[0] = getch();
(void) alarm((unsigned)0);
}
/*
* Read in remaining response. Loop until ending character
* is received or until alarm goes off. If towait is set,
* then let alarm go off.
*/
for (i = 1, c = -1; (!towait && (c != end)) || towait; ) {
if (setjmp(env)) {
recvbuf[i] = (char) NULL;
return;
} else {
(void) signal(SIGALRM, wakeup);
(void) alarm((unsigned)almwait);
c = getch();
(void) alarm((unsigned)0);
}
recvbuf[i++] = c;
}
recvbuf[i] = (char) NULL;
dprintf("listen done. read %d chars.\n\n", i);
}
/*
* Print a message since we didn't recognize this terminal.
*/
void notrecognized()
{
char *envterm;
if ((envterm = getenv("TERM")) == NULL)
envterm = "dumb";
if (!quiet)
(void) fprintf(stderr,
"Terminal NOT recognized - defaults to \"%s\".\n",
envterm);
puts(envterm);
}
/*
* Process entries in the termtable.
*/
void proctab(t)
struct termtable *t;
{
int st = FALSE;
static int firsttime = TRUE;
static struct termtable *lastt;
dprintf("\n[ Processing entries ] \n");
if (firsttime) {
t = termtab;
lastt = NULL;
}
while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) {
/*
* If this is our first time or the sendstr is the same as
* last time, don't send it again.
*/
if (always_send || firsttime || lastt == NULL ||
strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) {
if (firsttime)
firsttime = FALSE;
if (watch_chars)
(void) printf("Send: %s\n", decode(t->qt_sendstr));
(void) fflush(stdin);
(void) fprintf(stderr, "%s", t->qt_sendstr);
(void) fflush(stderr);
lastt = t;
(void) qterm_listen(t);
if (watch_chars)
(void) printf("\tRead: %s\n", decode(recvbuf));
}
st = prinfo(compare(recvbuf), FALSE);
lastt = t;
t = t->nxt;
}
if (!found)
notrecognized();
done(0);
/*NOTREACHED*/
}
char *fixctl(str, rex)
char *str;
int rex;
{
register int i;
static char buf[BUFSIZ];
for (i = 0; str && *str; ) {
switch (*str) {
case '\\':
if (isdigit(*++str)) {
buf[i] = 0;
while (isdigit(*str))
buf[i] = (char) (((int)buf[i] * 8) +
(int)*str++ - (int) '0');
i++;
} else
buf[i++] = *str++;
continue;
case '^':
switch (*++str) {
case '?':
buf[i++] = '\177';
break;
default:
buf[i++] = *str & 037;
break;
}
break;
/* Special R.E. symbols */
case '[':
case '*':
case '.':
case '$':
case '{':
case '(':
if (rex)
buf[i++] = '\\';
default:
buf[i++] = *str;
}
*++str;
}
buf[i] = (char) NULL;
return(buf);
}
/*
* xmalloc - Do a malloc with error checking.
*/
char *xmalloc(size)
int size;
{
char *p;
if ((p = malloc((unsigned) size)) == NULL) {
myperror("malloc");
done(1);
/*NOTREACHED*/
}
return(p);
}
#ifdef HAS_VARARGS
void dprintf(va_alist)
va_dcl
{
va_list args;
char *fmt;
if (!debug)
return;
va_start(args);
fmt = (char *) va_arg(args, char *);
(void) vprintf(fmt, args);
va_end(args());
(void) fflush(stdout);
}
#else /*HAS_VARARGS*/
void dprintf(fmt, a1, a2, a3, a4, a5, a6)
char *fmt;
{
if (!debug)
return;
(void) printf(fmt, a1, a2, a3, a4, a5, a6);
(void) fflush(stdout);
}
#endif /*HAS_VARARGS*/
/*
* Catch kill signals and cleanup.
*/
void catch()
{
done(2);
/*NOTREACHED*/
}
void wakeup()
{
dprintf("wakeup called\n");
longjmp(env, 1);
}
void myperror(msg)
char *msg;
{
(void) fprintf(stderr, "%s: ", progname);
perror(msg);
}
/*
* Reset terminal and exit with status s.
*/
void done(s)
int s;
{
resetmodes();
exit(s);
}