# 2.11BSD#431 - /usr/src/local/qterm/qterm.c

##### Functions

    addterm           X
    catch             X
    compare           X
    config            X
    decode            X
    done              X
    dprintf           X
    fixctl            X
    getch             X
    main              X
    mktable           X
    myperror          X
    notrecognized     X
    prinfo            X
    proctab           X
    qterm_listen      X
    readtabfile       X
    resetmodes        X
    setmodes          X
    wakeup            X
    xmalloc           X

##### Variables

    _ntty             X
    _otty             X
    _tty              X
    _tty_ch           X
    almwait           X
    always_send       X
    debug             X
    do_systabfile     X
    do_usrtabfile     X
    env               X
    found             X
    longname          X
    modes_set         X
    progname          X
    quiet             X
    recvbuf           X
    sent_chars        X
    termfile          X
    towait            X
    use_alt_str       X
    watch_chars       X

##### Macros

    FFLAG             X
    OLD_NoArg         X
    OLD_SepArg        X
    fFLAG             X

       1: #ifndef lint
       2: static char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $";
       3: #endif
       4:
       5: /*
       6:  * Copyright (c) 1990 Michael A. Cooper.
       7:  * This software may be freely distributed provided it is not sold for
       8:  * profit and the author is credited appropriately.
       9:  */
      10:
      11: /*
      12:  *------------------------------------------------------------------
      13:  *
      14:  * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $
      15:  * $Revision: 5.4 $
      16:  * $Date: 1991/03/21 02:09:40 $
      17:  * $State: Exp $
      18:  * $Author: mcooper $
      19:  * $Locker:  $
      20:  *
      21:  *------------------------------------------------------------------
      22:  *
      23:  * Michael A. Cooper
      24:  * Research and Development Group
      25:  * University Computing Services
      26:  * University of Southern California
      27:  * (mcooper@usc.edu)
      28:  *
      29:  *------------------------------------------------------------------
      30:  *
      31:  * $Log: qterm.c,v $
      32:  * Revision 5.4  1991/03/21  02:09:40  mcooper
      33:  * Fix memory buffer problem with some C
      34:  * compilers.  (tp@vtold.vtol.fi)
      35:  *
      36:  * Revision 5.3  1991/03/16  05:36:30  mcooper
      37:  * Fix casting of (char) NULL problem.
      38:  *
      39:  * Revision 5.2  1991/03/12  00:46:24  mcooper
      40:  * Change CMASK to CHAR_CMASK to avoid conflict
      41:  * under AIX 3.1.
      42:  *
      43:  * Revision 5.1  1991/02/20  02:23:33  mcooper
      44:  * Cleanup #ifdef USG5 as part of port
      45:  * to UTS 2.1 (System V.3).
      46:  *
      47:  * Revision 5.0  1990/12/15  18:30:41  mcooper
      48:  * Version 5.
      49:  *
      50:  * Revision 4.13  90/12/15  18:14:23  mcooper
      51:  * Add copywrite.
      52:  *
      53:  * Revision 4.12  90/11/13  16:00:03  mcooper
      54:  * Convert OptInt's to OptBool's where needed.
      55:  *
      56:  * Revision 4.11  90/11/13  15:38:28  mcooper
      57:  * Make OLD_SepArg include both
      58:  * SepArg and StickyArg.
      59:  *
      60:  * Revision 4.10  90/11/08  15:41:08  mcooper
      61:  * Make sure qt_fullname is not 0 length.
      62:  *
      63:  * Revision 4.9  90/11/08  13:02:06  mcooper
      64:  * Fix bug that closes the tty when an error
      65:  * occurs during command line parsing.
      66:  *
      67:  * Revision 4.8  90/11/06  13:19:40  mcooper
      68:  * Changed command line options to new
      69:  * longer names.
      70:  *
      71:  * Revision 4.7  90/11/05  17:09:30  mcooper
      72:  * Update option help messages and option names
      73:  * to be more mnemonic.
      74:  *
      75:  * Revision 4.6  90/11/05  16:44:35  mcooper
      76:  * - Converted to use new ParseOptions() for
      77:  *   command line parsing.
      78:  * - Major de-linting.
      79:  * - Convert dprintf() to use varargs (if
      80:  *   HAS_VARARGS is defined).
      81:  * - Lots of misc. cleanup.
      82:  *
      83:  * Revision 4.5  89/10/20  22:50:49  mcooper
      84:  * Changed code indention to current local
      85:  * standard of 4.  (This should also mess up
      86:  * everybody trying to do diff's from older versions!)
      87:  *
      88:  * Revision 4.4  89/10/20  14:03:48  mcooper
      89:  * Fixed command line parsing of "-f -q".
      90:  *
      91:  * Revision 4.3  88/06/16  19:43:46  mcooper
      92:  * - Added -T flag to wait until timeout when
      93:  *   listening for response string.  This solves
      94:  *   problem when the first entry in a table
      95:  *   doesn't have a response string with a
      96:  *   common ending character to look for.
      97:  * - Added -I flag for "intense" query mode.
      98:  * - Cleaned up debugging a bit.
      99:  *
     100:  * Revision 4.2  88/06/08  15:30:53  mcooper
     101:  * Cleanup pass including removing
     102:  * extraneous debugging messages.
     103:  *
     104:  * Revision 4.1  88/04/25  13:24:38  mcooper
     105:  * Added -S option to print send and recieve
     106:  * strings as they are sent and recieved as
     107:  * suggested by David W. Sanderson
     108:  * (dws@attunix.att.com).
     109:  *
     110:  * Revision 4.0  88/03/08  19:30:59  mcooper
     111:  * Version 4.
     112:  *
     113:  * Revision 3.7  88/03/08  19:28:32  mcooper
     114:  * Major rewrite.
     115:  *
     116:  * Revision 3.6  88/03/08  15:31:35  mcooper
     117:  * General cleanup time.
     118:  *
     119:  * Revision 3.5  88/03/08  13:59:39  mcooper
     120:  * - Catch signals and fix terminal modes.
     121:  * - Don't allow alarm times of 0.
     122:  * - Support for HP-UX machines and cleaner
     123:  *   listen() code from Zenon Fortuna,
     124:  *   HP-UX Support, Hewlett-Packard Vienna.
     125:  *
     126:  * Revision 3.4  87/10/07  15:16:17  mcooper
     127:  * - Beautify code a bit.
     128:  * - Add -w <N> option to set the wait time.
     129:  *
     130:  * Revision 3.3  87/08/24  19:25:32  mcooper
     131:  * The following based on code from Frank Crawford
     132:  * <frank@teti.qhtours.OZ>:
     133:  * - Use $TERM as output string when the terminal
     134:  *   type is not known instead of "dumb".
     135:  * - Regular Expressions are now supported.  RE are
     136:  *   started with a leading `\'.
     137:  * - Octal values may now be used in send/recieve strings.
     138:  *
     139:  * Revision 3.1  87/08/03  15:21:07  mcooper
     140:  * As pointed out by Scott H. Robinson <shr@cetus.ece.cmu.edu>,
     141:  * the -F switch does work.  Problem was that it never read
     142:  * in the ~/.qterm file.
     143:  *
     144:  * Revision 3.0  87/06/30  19:07:59  mcooper
     145:  * Release of version 3.
     146:  *
     147:  * Revision 2.4  87/04/29  19:28:35  mcooper
     148:  * In readtabfile() we now do special
     149:  * things when opening "file" fails
     150:  * depending on the bequiet flag.
     151:  *
     152:  * Revision 2.3  87/04/29  13:11:37  mcooper
     153:  * - No more "internal" table.  The master
     154:  *   table is read from a file (TABFILE).
     155:  *   This makes ~/.qterm stuff much cleaner.
     156:  * - Error handling for qtermtab files is
     157:  *   much more informative now.
     158:  * - More things I can't remember.
     159:  *
     160:  * Revision 2.2  87/03/05  21:01:28  mcooper
     161:  * Fixed system V compiler problem.
     162:  *
     163:  * Revision 2.1  87/03/01  19:43:22  mcooper
     164:  * Be more intelligent about the size of
     165:  * the default terminal table.
     166:  *
     167:  * Revision 2.0  87/03/01  19:20:00  mcooper
     168:  * General cleanup.
     169:  *
     170:  *------------------------------------------------------------------
     171:  */
     172:
     173:
     174: /*
     175:  * qterm - Query Terminal
     176:  *
     177:  * qterm is used to query a terminal to determine the name of the terminal.
     178:  * This is done by sending a fairly universal string "\33Z" to the terminal,
     179:  * reading in a response, and comparing it against a master table of responses
     180:  * and names.  The "name" printed to standard output should be one found in
     181:  * the termcap(5) database.
     182:  *
     183:  * Putting a line in your ".login" file such as:
     184:  *
     185:  *	setenv TERM `qterm`
     186:  *
     187:  * or the following lines in your ".profile" file:
     188:  *
     189:  *	TERM=`qterm`
     190:  *	export TERM
     191:  *
     192:  * will set your terminal type automagically.
     193:  *
     194:  * If you add a terminal to the master table, please also send me a copy
     195:  * so that I may put it into my version.
     196:  *
     197:  * Michael Cooper
     198:  * Internet: 	mcooper@usc.edu
     199:  * UUCP: 	...!rutgers!usc!mcooper
     200:  * BITNET:	mcooper@gamera
     201:  */
     202:
     203: #include <stdio.h>
     204: #include <ctype.h>
     205: #include <pwd.h>
     206: #include <signal.h>
     207: #include <sys/ioctl.h>
     208: #include <setjmp.h>
     209: #ifdef USG5
     210: # include <termio.h>
     211: #else /*USG5*/
     212: # include <sys/file.h>
     213: # include <sgtty.h>
     214: #endif /*USG5*/
     215: #include "qterm.h"
     216: #include "options.h"
     217: #ifdef HAS_VARARGS
     218: #include <varargs.h>
     219: #endif /*HAS_VARARGS*/
     220:
     221: #ifdef USG5
     222: struct termio _ntty, _otty;
     223: #else
     224: struct sgttyb _tty;
     225: #endif
     226: int _tty_ch = 2;
     227: char recvbuf[SIZE];
     228: char *progname;
     229: char *termfile = NULL;
     230:
     231: int debug = FALSE;      /* Debug mode */
     232: int use_alt_str = FALSE;    /* Alternate string */
     233: int towait = FALSE;     /* Time out wait flag */
     234: int always_send = FALSE;    /* Intense query mode */
     235: int longname = FALSE;       /* Print long terminal name */
     236: int sent_chars = FALSE;     /* Print strings sent from the terminal */
     237: int watch_chars = FALSE;    /* Watch strings as they are sent and recv. */
     238: int quiet = FALSE;      /* Quiet mode */
     239: int do_usrtabfile = FALSE;  /* Use user's own .qtermtab file */
     240: int do_systabfile = TRUE;   /* Use the system's qterm tab file */
     241: int almwait = WAIT;     /* Wait (timeout) interval */
     242:
     243: /*
     244:  * Old options should not be visable in help and usage messages.
     245:  */
     246: #ifdef OPT_COMPAT
     247: #define OLD_NoArg   NoArg|ArgHidden
     248: #define OLD_SepArg  SepArg|StickyArg|ArgHidden
     249: #define fFLAG       "-f"
     250: #define FFLAG       "-F"
     251: #endif
     252:
     253: /*
     254:  * Command line options table.
     255:  */
     256: OptionDescRec opts[] = {
     257: #ifdef OPT_COMPAT
     258:     {"-a",  OLD_NoArg,  OptInt, (caddr_t) &use_alt_str,     "1",
     259:      (char *)NULL,  "Use alternate query string"},
     260:     {"-s",  OLD_NoArg,  OptInt, (caddr_t) &sent_chars,      "1",
     261:      (char *)NULL,  "Display the characters the terminal sent"},
     262:     {"-t", ArgHidden|OLD_NoArg, OptInt, (caddr_t) &sent_chars,      "1",
     263:      (char *)NULL,  "Display the characters the terminal sent"},
     264:     {"-I",  OLD_NoArg,  OptInt, (caddr_t) &always_send,     "1",
     265:      (char *)NULL,  "Always send the terminal query string"},
     266:     {"-T",  OLD_NoArg,  OptInt, (caddr_t) &towait,      "1",
     267:      (char *)NULL,  "Enable time out wait"},
     268:     {"-S",  OLD_NoArg,  OptInt, (caddr_t) &watch_chars,     "1",
     269:      (char *)NULL,  "Print strings as they are sent and received"},
     270:     {"-q",  OLD_NoArg,  OptInt, (caddr_t) &quiet,       "1",
     271:      (char *)NULL,  "Enable quite mode"},
     272:     {"-f",  OLD_SepArg, OptStr, (caddr_t) &termfile,  fFLAG,
     273:      "<tabfile>",  "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
     274:     {"-F",  OLD_SepArg, OptStr, (caddr_t) &termfile,  FFLAG,
     275:      "<tabfile>",   "Try <tabfile>, then ~/.qtermtab"},
     276:     {"-l",  OLD_NoArg,  OptInt, (caddr_t) &longname,        "1",
     277:      (char *)NULL,  "Output only the long (verbose) terminal name"},
     278:     {"-d",  OLD_NoArg,  OptInt, (caddr_t) &debug,       "1",
     279:      (char *)NULL,  "Enable debug mode"},
     280:     {"-w",  OLD_SepArg, OptInt, (caddr_t) &almwait,     __ NULL,
     281:      "<interval>",  "Wait (timeout) period (in seconds)"},
     282: #endif /*OPT_COMPAT*/
     283:     {"+alt",    NoArg,      OptBool, (caddr_t) &use_alt_str,    "1",
     284:      (char *)NULL,  "Use alternate query string"},
     285:     {"-alt",    NoArg,      OptBool, (caddr_t) &use_alt_str,    "0",
     286:      (char *)NULL,  "Don't use alternate query string"},
     287:     {"+always", NoArg,      OptBool, (caddr_t) &always_send,    "1",
     288:      (char *)NULL,  "Always send the terminal query string"},
     289:     {"-always", NoArg,      OptBool, (caddr_t) &always_send,    "0",
     290:      (char *)NULL,  "Don't always send the terminal query string"},
     291:     {"-file",   SepArg,     OptStr, (caddr_t) &termfile,        __ NULL,
     292:      "<tabfile>",   "Use <tabfile> to query terminal"},
     293:     {"+longname",NoArg,     OptBool, (caddr_t) &longname,       "1",
     294:      (char *)NULL,  "Output only the long (verbose) terminal name"},
     295:     {"-longname",NoArg,     OptBool, (caddr_t) &longname,       "0",
     296:      (char *)NULL,  "Don't output the long (verbose) terminal name"},
     297:     {"+quiet",  NoArg,      OptBool, (caddr_t) &quiet,      "1",
     298:      (char *)NULL,  "Enable quiet mode"},
     299:     {"-quiet",  NoArg,      OptBool, (caddr_t) &quiet,      "0",
     300:      (char *)NULL,  "Disable quiet mode"},
     301:     {"+sent",   NoArg,      OptBool, (caddr_t) &sent_chars,     "1",
     302:      (char *)NULL,  "Display the characters the terminal sent"},
     303:     {"-sent",   NoArg,      OptBool, (caddr_t) &sent_chars,     "0",
     304:      (char *)NULL,  "Don't display the characters the terminal sent"},
     305:     {"+timeout",NoArg,      OptBool, (caddr_t) &towait,     "1",
     306:      (char *)NULL,  "Enable time out wait"},
     307:     {"-timeout",NoArg,      OptBool, (caddr_t) &towait,     "0",
     308:      (char *)NULL,  "Disable time out wait"},
     309:     {"+usrtab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "1",
     310:      (char *)NULL,  "Enable using ~/.qtermtab"},
     311:     {"-usrtab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "0",
     312:      (char *)NULL,  "Disable using ~/.qtermtab"},
     313:     {"-wait",   SepArg,     OptInt, (caddr_t) &almwait,     __ NULL,
     314:      "<interval>",  "Wait (timeout) period (in seconds)"},
     315:     {"+watch",  NoArg,      OptBool, (caddr_t) &watch_chars,    "1",
     316:      (char *)NULL,  "Watch the characters sent and recieved"},
     317:     {"-watch",  NoArg,      OptBool, (caddr_t) &watch_chars,    "0",
     318:      (char *)NULL,  "Don't watch the characters sent and recieved"},
     319:     {"+systab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "1",
     320:      (char *)NULL,  "Enable using system qtermtab file"},
     321:     {"-systab", NoArg,      OptBool, (caddr_t) &do_systabfile,  "0",
     322:      (char *)NULL,  "Disable using system qtermtab file"},
     323:     {"-debug", ArgHidden|NoArg, OptInt, (caddr_t) &debug,       "1",
     324:      (char *)NULL,  "Enable debug mode"},
     325: };
     326:
     327: FILE *fopen();
     328: char *decode();
     329: char *getenv();
     330: char *malloc();
     331: char *re_comp();
     332: char *strcat();
     333: char *xmalloc();
     334: int alarm();
     335: int found = FALSE;
     336: int modes_set = FALSE;
     337: jmp_buf env;
     338: struct termtable *compare();
     339: struct passwd *getpwuid();
     340: void catch();
     341: void done();
     342: void dprintf();
     343: void exit();
     344: void myperror();
     345: void mktable();
     346: void notrecognized();
     347: void proctab();
     348: void wakeup();
     349: #ifdef USG5
     350: char *regcmp();
     351: #endif /* USG5 */
     352:
     353: main(argc, argv)
     354:      int argc;
     355:      char **argv;
     356: {
     357:     config(argc, argv);
     358:     setmodes();
     359:     mktable();
     360:     proctab((struct termtable *)NULL);
     361:     resetmodes();
     362:
     363:     if (!found) {
     364:     notrecognized();
     365:     }
     366:
     367:     exit(0);
     368: }
     369:
     370: /*
     371:  * Config() - Perform configuration operations.
     372:  */
     373: config(argc, argv)
     374:      int argc;
     375:      char **argv;
     376: {
     377:     progname = argv[0];
     378:
     379:     /*
     380:      * Parse command line args
     381:      */
     382:     if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) {
     383:     done(1);
     384:     /*NOTREACHED*/
     385:     }
     386:
     387:     /*
     388:      * Check results of command line parsing and perform any
     389:      * needed post processing.
     390:      */
     391:
     392:     if (longname)
     393:     quiet = TRUE;
     394:
     395:     if (almwait == 0) {
     396:     (void) fprintf(stderr,
     397:               "%s: Alarm (wait) time must be greater than 0.\n",
     398:                progname);
     399:     done(1);
     400:     /*NOTREACHED*/
     401:     }
     402:
     403: #ifdef OPT_COMPAT
     404:     /*
     405:      * Kludgy stuff to be backwards compatable for command line options.
     406:      */
     407:     if (termfile) {
     408:     if (strcmp(termfile, fFLAG) == 0) {
     409:         do_usrtabfile = TRUE;
     410:         do_systabfile = TRUE;
     411:         termfile = NULL;
     412:     } else if (strcmp(termfile, FFLAG) == 0) {
     413:         do_usrtabfile = TRUE;
     414:         do_systabfile = FALSE;
     415:         termfile = NULL;
     416:     }
     417:     }
     418: #endif /*OPT_COMPAT*/
     419:
     420:     dprintf("[ %s debug mode enabled ]\n\n", progname);
     421: }
     422:
     423: /*
     424:  * Set signal catches and terminal modes
     425:  */
     426: setmodes()
     427: {
     428:     if (!isatty(0)) {
     429:     (void) fprintf(stderr, "%s: Not a tty.\n", progname);
     430:     done(0);
     431:     /*NOTREACHED*/
     432:     }
     433:
     434:     /*
     435:      * Set output buffers
     436:      */
     437:     setbuf(stdout, (char *)0);
     438:     if (debug)
     439:     setbuf(stderr, (char *)0);
     440:
     441:     /*
     442:      * Cleanup terminal modes & such if we are killed
     443:      */
     444:     (void) signal(SIGINT, catch);
     445:     (void) signal(SIGHUP, catch);
     446:     (void) signal(SIGTERM, catch);
     447:
     448:     /*
     449:      * Set terminal modes
     450:      */
     451: #ifdef USG5
     452:     if (ioctl(_tty_ch, TCGETA, &_otty) < 0)
     453: #else
     454:     if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
     455: #endif /* USG5 */
     456:     {
     457:     myperror("gtty");
     458:     done(1);
     459:     /*NOTREACHED*/
     460:     }
     461: #ifdef USG5
     462:     _ntty = _otty;
     463: #endif /* USG5 */
     464:
     465:     if (crmode() < 0) {
     466:     myperror("crmode");
     467:     done(1);
     468:     /*NOTREACHED*/
     469:     }
     470:
     471:     if (noecho() < 0) {
     472:     myperror("noecho");
     473:     done(1);
     474:     /*NOTREACHED*/
     475:     }
     476:     modes_set = TRUE;
     477: }
     478:
     479: /*
     480:  * Reset terminal modes
     481:  */
     482: resetmodes()
     483: {
     484:     if (modes_set) {
     485:     (void) nocrmode();
     486:     (void) echo();
     487:     }
     488: }
     489:
     490: /*
     491:  * Print info about terminal structure t.
     492:  */
     493: prinfo(t, what)
     494:      struct termtable *t;
     495:      int what;
     496: {
     497:     int len = 0;
     498:     int st = FALSE;
     499:
     500:     if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) {
     501:     if (debug || sent_chars) {
     502:         len = strlen(recvbuf);
     503:         (void) fprintf(stderr, "%s received %d character%s:",
     504:                progname, len, (len == 1) ? "" : "s");
     505:         (void) fprintf(stderr, " %s\n", decode(recvbuf));
     506:     }
     507:
     508:     if (!quiet) {
     509:         (void) fprintf(stderr, "Terminal recognized as %s",
     510:                t->qt_termname);
     511:         if (t->qt_fullname && t->qt_fullname[0])
     512:         (void) fprintf(stderr, " (%s)\n", t->qt_fullname);
     513:         else
     514:         (void) fprintf(stderr, "\n");
     515:     }
     516:
     517:     if (longname) {
     518:         if (t->qt_fullname && t->qt_fullname[0])
     519:         (void) printf("%s\n", t->qt_fullname);
     520:         else
     521:         (void) fprintf(stderr, "%s: No full terminal name for %s.\n",
     522:                    progname, t->qt_termname);
     523:     } else {
     524:         (void) printf("%s\n", t->qt_termname);
     525:     }
     526:
     527:     found = TRUE;
     528:     done(0);
     529:     /*NOTREACHED*/
     530:     } else {
     531:     found = FALSE;
     532:
     533:     if (what) {
     534:         notrecognized();
     535:         done(1);
     536:         /*NOTREACHED*/
     537:     }
     538:     }
     539:
     540:     return(st);
     541: }
     542:
     543: /*
     544:  * compare - actually compare what we received against the table.
     545:  */
     546: struct termtable *compare(str)
     547:      char *str;
     548: {
     549: #ifdef USG5
     550:     register char *reexp;
     551: #endif /* USG5 */
     552:     register struct termtable *t;
     553:     char buf[BUFSIZ];
     554:
     555:     dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing");
     556:     (void) alarm((unsigned)0);
     557:
     558:     if (strlen(str) == 0)
     559:     return(NULL);
     560:
     561:     for (t = termtab; t != NULL; t = t->nxt) {
     562:     dprintf("  with %s ", decode(t->qt_recvstr));
     563:     (void) sprintf(buf, "^%s$", t->qt_recvstr);
     564:
     565: #ifdef USG5
     566:     if ((reexp = regcmp(buf, NULL)) == NULL) {
     567: #else
     568:     if (re_comp((char *)buf) != NULL) {
     569: #endif /* USG5 */
     570:         (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n",
     571:                progname, t->qt_recvstr);
     572:         done(1);
     573:         /*NOTREACHED*/
     574:     }
     575:
     576: #ifdef USG5
     577:     if (regex(reexp, str) != NULL) {
     578: #else
     579:     if (re_exec(str) == 1) {
     580: #endif /* USG5 */
     581:         found = TRUE;
     582:         dprintf("\tOK\n");
     583:         return(t);
     584:     }
     585:
     586:     dprintf("\tNOPE\n");
     587: #ifdef USG5
     588:     (void) free(reexp);
     589: #endif /* USG5 */
     590:     }
     591:     found = FALSE;
     592:
     593:     return(NULL);
     594: }
     595:
     596: /*
     597:  * getch - read in a character at a time.
     598:  */
     599: getch()
     600: {
     601:     char c;
     602:
     603:     (void) read(0, &c, 1);
     604:
     605:     return(c & CHAR_MASK);
     606: }
     607:
     608: /*
     609:  * decode - print str in a readable fashion
     610:  */
     611: char *decode(str)
     612:      char *str;
     613: {
     614:     register int len;
     615:     static char buf[BUFSIZ];
     616:     char tmp[10];
     617:
     618:     if (!str)
     619:       return("(null)");
     620:
     621:     (void) strcpy(buf, "");
     622:     while (*str) {
     623:     if (*str == ESC) {
     624:         (void) strcat(buf, "<esc> ");
     625:     } else if ((*str <= 33) || (*str >= 127)) {
     626:         (void) sprintf(tmp,"\\%#o ", (unsigned) *str);
     627:         (void) strcat(buf, tmp);
     628:     } else {
     629:         (void) sprintf(tmp,"%c ", *str);
     630:         (void) strcat(buf, tmp);
     631:     }
     632:     ++str;
     633:     }
     634:
     635:     len = strlen(buf);
     636:     if (len && buf[len - 1] == ' ') {
     637:     buf[len - 1] = (char) NULL;
     638:     }
     639:
     640:     return(buf);
     641: }
     642:
     643: /*
     644:  * Make a termtab table
     645:  */
     646: void mktable()
     647: {
     648:     char file[BUFSIZ];
     649:     struct passwd *pwd;
     650:     char *home;
     651:
     652:     dprintf("[ initilizing term table... ]\n");
     653:
     654:     if (termfile != NULL) {
     655:     (void) readtabfile(termfile, FALSE);
     656:     }
     657:
     658:     if (do_usrtabfile) {
     659:     /*
     660: 	 * Try to read the user's own table
     661: 	 */
     662:     if ((home = getenv("HOME")) == NULL) {
     663:         if ((pwd = getpwuid(getuid())) == NULL) {
     664:         (void) fprintf(stderr,
     665:                    "%s: Cannot find user info for uid %d.\n",
     666:                    progname, getuid());
     667:         done(1);
     668:         /*NOTREACHED*/
     669:         }
     670:         home = pwd->pw_dir;
     671:     }
     672:
     673:     (void) sprintf(file, "%s/%s", home, USRFILE);
     674:     if (readtabfile(file, TRUE) < 0) {
     675:         (void) sprintf(file, "%s/%s", home, OLDUSRFILE);
     676:         (void) readtabfile(file, TRUE);
     677:     }
     678:     }
     679:
     680:     if (do_systabfile)
     681:     (void) readtabfile(TABFILE, FALSE);
     682:
     683:     dprintf("[ mktable done ]\n");
     684: }
     685:
     686: int readtabfile(file, bequiet)
     687:      char *file;
     688:      int bequiet;
     689: {
     690:     static int line = 0;
     691:     char lbuf[4][BUFSIZ];
     692:     char buf[BUFSIZ];
     693:     FILE *fd;
     694:     char *p, *fixctl();
     695:     char *errmsg = NULL;
     696:     struct termtable *t;
     697:
     698:     if ((fd = fopen(file, "r")) == NULL) {
     699:     if (bequiet) {
     700:         dprintf("[ tab file '%s' can not read ]\n", file);
     701:         return(-1);
     702:     }
     703:     myperror(file);
     704:     done(1);
     705:     /*NOTREACHED*/
     706:     }
     707:
     708:     dprintf("[ Read tab file '%s' ]\n", file);
     709:
     710:     line = 0;
     711:     while (fgets(buf, sizeof(buf), fd)) {
     712:     ++line;
     713:
     714:     if (buf[0] == '#' || buf[0] == '\n')
     715:         continue;
     716:
     717:     lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL;
     718:
     719:     (void) sscanf(buf, "%s%s%s\t%[^\n]",
     720:               lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
     721:
     722:     if (lbuf[0][0] == (char) NULL)
     723:         continue;
     724:
     725:     if (lbuf[1][0] == (char) NULL)
     726:         errmsg = "receive string";
     727:
     728:     if (lbuf[2][0] == (char) NULL)
     729:         errmsg = "terminal name";
     730:
     731:     if (errmsg) {
     732:         (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n",
     733:                progname, line, file, errmsg);
     734:         done(1);
     735:         /*NOTREACHED*/
     736:     }
     737:
     738:     t = (struct termtable *) xmalloc(sizeof(struct termtable));
     739:
     740:     if (use_alt_str)
     741:         p = fixctl(ALTSEND, 0);
     742:     else
     743:         p = fixctl(lbuf[0], 0);
     744:
     745:     t->qt_sendstr = (char *) xmalloc(strlen(p)+1);
     746:     (void) strcpy(t->qt_sendstr, p);
     747:
     748:     p = fixctl(lbuf[1], 1);
     749:     t->qt_recvstr = (char *) xmalloc(strlen(p)+1);
     750:     (void) strcpy(t->qt_recvstr, p);
     751:
     752:     t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1);
     753:     (void) strcpy(t->qt_termname, lbuf[2]);
     754:
     755:     t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1);
     756:     (void) strcpy(t->qt_fullname, lbuf[3]);
     757:
     758:     dprintf("\n  Send String = %s\n", decode(t->qt_sendstr));
     759:     dprintf("Expect String = %s\n", decode(t->qt_recvstr));
     760:     dprintf("     Terminal = '%s'\n", t->qt_termname);
     761:     dprintf("    Full Name = '%s'\n", t->qt_fullname);
     762:
     763:     (void) addterm(t);
     764:     }
     765:
     766:     return(0);
     767: }
     768:
     769: /*
     770:  * Add termtab (n) entry to main termtab.
     771:  */
     772: int addterm(n)
     773:      struct termtable *n;
     774: {
     775:     register struct termtable *t;
     776:
     777:     if (!n)
     778:       return(-1);
     779:
     780:     n->nxt = NULL;
     781:
     782:     if (termtab == NULL) {
     783:     termtab = n;
     784:     } else {
     785:     t = termtab;
     786:     while(t && t->nxt)
     787:       t = t->nxt;
     788:     t->nxt = n;
     789:     }
     790:
     791:     return(0);
     792: }
     793:
     794: /*
     795:  * Listen for a response.
     796:  */
     797: void qterm_listen(q)
     798:      struct termtable *q;
     799: {
     800:     static int i, len;
     801:     register char c;
     802:     char end;
     803:
     804:     (void) alarm((unsigned)0);
     805:     (void) strcpy(recvbuf, "");
     806:     i = 0;
     807:
     808:     len = strlen(q->qt_recvstr);
     809:
     810:     if (len) {
     811:     end = q->qt_recvstr[len - 1];
     812:     } else {
     813:     end = 'c'; /* Fairly standard ANSI default */
     814:     }
     815:
     816:     dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n",
     817:         decode(q->qt_recvstr), len, end);
     818:
     819:     /*
     820:      * If we don't get an initial character, bounce out
     821:      * of here and finish with done(0).
     822:      */
     823:     if (setjmp(env)) {
     824:     if (found) {
     825:         done(0);
     826:         /*NOTREACHED*/
     827:     }
     828:     (void) fflush(stdin);
     829:     proctab(q->nxt);
     830:     } else {
     831:     (void) signal(SIGALRM, wakeup);
     832:     (void) alarm((unsigned)almwait);
     833:     recvbuf[0] = getch();
     834:     (void) alarm((unsigned)0);
     835:     }
     836:
     837:     /*
     838:      * Read in remaining response.  Loop until ending character
     839:      * is received or until alarm goes off.  If towait is set,
     840:      * then let alarm go off.
     841:      */
     842:     for (i = 1, c = -1; (!towait && (c != end)) || towait; ) {
     843:     if (setjmp(env))  {
     844:         recvbuf[i] = (char) NULL;
     845:         return;
     846:     } else {
     847:         (void) signal(SIGALRM, wakeup);
     848:         (void) alarm((unsigned)almwait);
     849:         c = getch();
     850:         (void) alarm((unsigned)0);
     851:     }
     852:     recvbuf[i++] = c;
     853:     }
     854:     recvbuf[i] = (char) NULL;
     855:
     856:     dprintf("listen done.  read %d chars.\n\n", i);
     857: }
     858:
     859: /*
     860:  * Print a message since we didn't recognize this terminal.
     861:  */
     862: void notrecognized()
     863: {
     864:     char *envterm;
     865:
     866:     if ((envterm = getenv("TERM")) == NULL)
     867:     envterm = "dumb";
     868:
     869:     if (!quiet)
     870:     (void) fprintf(stderr,
     871:                "Terminal NOT recognized - defaults to \"%s\".\n",
     872:                envterm);
     873:
     874:     puts(envterm);
     875: }
     876:
     877: /*
     878:  * Process entries in the termtable.
     879:  */
     880: void proctab(t)
     881:      struct termtable *t;
     882: {
     883:     int st = FALSE;
     884:     static int firsttime = TRUE;
     885:     static struct termtable *lastt;
     886:
     887:     dprintf("\n[ Processing entries ] \n");
     888:
     889:     if (firsttime) {
     890:     t = termtab;
     891:     lastt = NULL;
     892:     }
     893:
     894:     while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) {
     895:     /*
     896: 	 * If this is our first time or the sendstr is the same as
     897: 	 * last time, don't send it again.
     898: 	 */
     899:     if (always_send || firsttime || lastt == NULL ||
     900:         strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) {
     901:
     902:         if (firsttime)
     903:         firsttime = FALSE;
     904:
     905:         if (watch_chars)
     906:         (void) printf("Send: %s\n", decode(t->qt_sendstr));
     907:
     908:         (void) fflush(stdin);
     909:         (void) fprintf(stderr, "%s", t->qt_sendstr);
     910:         (void) fflush(stderr);
     911:
     912:         lastt = t;
     913:         (void) qterm_listen(t);
     914:
     915:         if (watch_chars)
     916:         (void) printf("\tRead: %s\n", decode(recvbuf));
     917:     }
     918:
     919:     st = prinfo(compare(recvbuf), FALSE);
     920:
     921:     lastt = t;
     922:     t = t->nxt;
     923:     }
     924:
     925:     if (!found)
     926:     notrecognized();
     927:
     928:     done(0);
     929:     /*NOTREACHED*/
     930: }
     931:
     932: char *fixctl(str, rex)
     933:      char *str;
     934:      int rex;
     935: {
     936:     register int i;
     937:     static char buf[BUFSIZ];
     938:
     939:     for (i = 0; str && *str; ) {
     940:     switch (*str) {
     941:
     942:       case '\\':
     943:         if (isdigit(*++str)) {
     944:         buf[i] = 0;
     945:         while (isdigit(*str))
     946:             buf[i] = (char) (((int)buf[i] * 8) +
     947:                      (int)*str++ - (int) '0');
     948:         i++;
     949:         } else
     950:         buf[i++] = *str++;
     951:         continue;
     952:
     953:       case '^':
     954:         switch (*++str) {
     955:           case '?':
     956:         buf[i++] = '\177';
     957:         break;
     958:           default:
     959:         buf[i++] = *str & 037;
     960:         break;
     961:         }
     962:         break;
     963:
     964:         /* Special R.E. symbols */
     965:       case '[':
     966:       case '*':
     967:       case '.':
     968:       case '$':
     969:       case '{':
     970:       case '(':
     971:         if (rex)
     972:           buf[i++] = '\\';
     973:
     974:       default:
     975:         buf[i++] = *str;
     976:     }
     977:     *++str;
     978:     }
     979:
     980:     buf[i] = (char) NULL;
     981:
     982:     return(buf);
     983: }
     984:
     985: /*
     986:  * xmalloc - Do a malloc with error checking.
     987:  */
     988: char *xmalloc(size)
     989:      int size;
     990: {
     991:     char *p;
     992:
     993:     if ((p = malloc((unsigned) size)) == NULL) {
     994:     myperror("malloc");
     995:     done(1);
     996:     /*NOTREACHED*/
     997:     }
     998:
     999:     return(p);
    1000: }
    1001:
    1002: #ifdef HAS_VARARGS
    1003: void dprintf(va_alist)
    1004:      va_dcl
    1005: {
    1006:     va_list args;
    1007:     char *fmt;
    1008:
    1009:     if (!debug)
    1010:     return;
    1011:
    1012:     va_start(args);
    1013:     fmt = (char *) va_arg(args, char *);
    1014:     (void) vprintf(fmt, args);
    1015:     va_end(args());
    1016:     (void) fflush(stdout);
    1017: }
    1018:
    1019: #else /*HAS_VARARGS*/
    1020:
    1021: void dprintf(fmt, a1, a2, a3, a4, a5, a6)
    1022:      char *fmt;
    1023: {
    1024:     if (!debug)
    1025:     return;
    1026:
    1027:     (void) printf(fmt, a1, a2, a3, a4, a5, a6);
    1028:     (void) fflush(stdout);
    1029: }
    1030: #endif /*HAS_VARARGS*/
    1031:
    1032: /*
    1033:  * Catch kill signals and cleanup.
    1034:  */
    1035: void catch()
    1036: {
    1037:     done(2);
    1038:     /*NOTREACHED*/
    1039: }
    1040:
    1041: void wakeup()
    1042: {
    1043:     dprintf("wakeup called\n");
    1044:     longjmp(env, 1);
    1045: }
    1046:
    1047: void myperror(msg)
    1048:      char *msg;
    1049: {
    1050:     (void) fprintf(stderr, "%s: ", progname);
    1051:     perror(msg);
    1052: }
    1053:
    1054: /*
    1055:  * Reset terminal and exit with status s.
    1056:  */
    1057: void done(s)
    1058:      int s;
    1059: {
    1060:     resetmodes();
    1061:     exit(s);
    1062: }

#### Defined functions

addterm defined in line 772; used 1 times

- in line 763

catch defined in line 1035; used 4 times

- in line 340, 444-446(3)

compare defined in line 546; used 2 times

- in line 338, 919

config defined in line 373; used 1 times

- in line 357

decode defined in line 611; used 9 times

- in line 328, 505, 555, 562, 758-759(2), 817, 906, 916

done defined in line 1057; used 17 times

- in line 341, 383, 399, 430, 458, 467, 473, 528, 535, 572, 667, 704, 734, 825, 928, 995, 1037

dprintf defined in line 1021; used 18 times

- in line 342, 420, 555, 562, 582-586(2), 652, 683, 700, 708, 758-761(4), 816, 856, 887, 1043

fixctl defined in line 932; used 4 times

- in line 694, 741-748(3)

getch defined in line 599; used 2 times

- in line 833, 849

main defined in line 353; never used
mktable defined in line 646; used 2 times

- in line 345, 359

myperror defined in line 1047; used 6 times

- in line 344, 457, 466, 472, 703, 994

notrecognized defined in line 862; used 4 times

- in line 346, 364, 534, 926

prinfo defined in line 493; used 1 times

- in line 919

proctab defined in line 880; used 3 times

- in line 347, 360, 829

qterm_listen defined in line 797; used 1 times

- in line 913

readtabfile defined in line 686; used 4 times

- in line 655, 674-681(3)

resetmodes defined in line 482; used 2 times

- in line 361, 1060

setmodes defined in line 426; used 1 times

- in line 358

wakeup defined in line 1041; used 3 times

- in line 348, 831, 847

xmalloc defined in line 988; used 6 times

- in line 333, 738, 745-755(4)

#### Defined variables

RCSid defined in line 2; never used
_ntty defined in line 222; used 1 times

- in line 462

_otty defined in line 222; used 2 times

- in line 452, 462

_tty defined in line 224; used 1 times

- in line 454

_tty_ch defined in line 226; used 2 times

- in line 452-454(2)

almwait defined in line 241; used 5 times

- in line 280, 313, 395, 832, 848

always_send defined in line 234; used 4 times

- in line 264, 287-289(2), 899

debug defined in line 231; used 6 times

- in line 278, 323, 438, 501, 1009, 1024

do_systabfile defined in line 240; used 4 times

- in line 321, 410-414(2), 680

do_usrtabfile defined in line 239; used 7 times

- in line 309-311(2), 319, 409-413(2), 658, 894

env defined in line 337; used 3 times

- in line 823, 843, 1044

found defined in line 335; used 8 times

- in line 363, 527-531(2), 581, 591, 824, 894, 925

longname defined in line 235; used 5 times

- in line 276, 293-295(2), 392, 517

modes_set defined in line 336; used 2 times

- in line 476, 484

progname defined in line 228; used 10 times

- in line 377, 398, 420, 429, 504, 522, 571, 666, 733, 1050

quiet defined in line 238; used 6 times

- in line 270, 297-299(2), 393, 508, 869

recvbuf defined in line 227; used 10 times

- in line 500-505(3), 805, 833, 844, 852-854(2), 916-919(2)

sent_chars defined in line 236; used 5 times

- in line 260-262(2), 301-303(2), 501

termfile defined in line 229; used 10 times

- in line 272-274(2), 291, 407-415(5), 654-655(2)

towait defined in line 233; used 5 times

- in line 266, 305-307(2), 842(2)

use_alt_str defined in line 232; used 4 times

- in line 258, 283-285(2), 740

watch_chars defined in line 237; used 5 times

- in line 268, 315-317(2), 905, 915

#### Defined macros

FFLAG defined in line 250; used 2 times

- in line 274, 412

OLD_NoArg defined in line 247; used 9 times

- in line 258-270(7), 276-278(2)

OLD_SepArg defined in line 248; used 3 times

- in line 272-274(2), 280

fFLAG defined in line 249; used 2 times

- in line 272, 408

Last modified: 1995-11-22 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3882 |