|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T q
Length: 16314 (0x3fba) Types: TextFile Names: »qterm.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/qterm/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); }