home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume10 / qterm / qterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-07-29  |  12.9 KB  |  634 lines

  1. #ifndef lint
  2. static char *RCSid = "$Header: qterm.c,v 3.0 87/06/30 19:07:59 mcooper Release $";
  3. #endif
  4.  
  5. /*
  6.  *------------------------------------------------------------------
  7.  *
  8.  * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
  9.  * $Revision: 3.0 $
  10.  * $Date: 87/06/30 19:07:59 $
  11.  * $State: Release $
  12.  * $Author: mcooper $
  13.  * $Locker:  $
  14.  *
  15.  *------------------------------------------------------------------
  16.  *
  17.  * Michael A. Cooper
  18.  * Research and Development Group
  19.  * University Computing Services 
  20.  * University of Southern California
  21.  * (mcooper@oberon.USC.EDU)
  22.  *
  23.  *------------------------------------------------------------------
  24.  *
  25.  * $Log:    qterm.c,v $
  26.  * Revision 3.0  87/06/30  19:07:59  mcooper
  27.  * Release of version 3.
  28.  * 
  29.  * Revision 2.4  87/04/29  19:28:35  mcooper
  30.  * In readtabfile() we now do special
  31.  * things when opening "file" fails
  32.  * depending on the bequiet flag.
  33.  * 
  34.  * Revision 2.3  87/04/29  13:11:37  mcooper
  35.  * - No more "internal" table.  The master
  36.  *   table is read from a file (TABFILE).
  37.  *   This makes ~/.qterm stuff much cleaner.
  38.  * - Error handling for qtermtab files is
  39.  *   much more informative now.
  40.  * - More things I can't remember.
  41.  * 
  42.  * Revision 2.2  87/03/05  21:01:28  mcooper
  43.  * Fixed system V compiler problem.
  44.  * 
  45.  * Revision 2.1  87/03/01  19:43:22  mcooper
  46.  * Be more intelligent about the size of 
  47.  * the default terminal table.
  48.  * 
  49.  * Revision 2.0  87/03/01  19:20:00  mcooper
  50.  * General cleanup.
  51.  * 
  52.  *------------------------------------------------------------------
  53.  */
  54.  
  55.  
  56. /*
  57.  * qterm - Query Terminal
  58.  *
  59.  * qterm is used to query a terminal to determine the name of the terminal.
  60.  * This is done by sending a fairly universal string "\33Z" to the terminal,
  61.  * reading in a response, and comparing it against a master table of responses
  62.  * and names.  The "name" printed to standard output should be one found in
  63.  * the termcap(5) database.
  64.  *
  65.  * Putting a line in your ".login" file such as:
  66.  *
  67.  *    setenv TERM `qterm`
  68.  *
  69.  * or the following lines in your ".profile" file:
  70.  *
  71.  *    TERM=`qterm`
  72.  *    export TERM
  73.  *
  74.  * will set your terminal type automagically.
  75.  * 
  76.  * If you add a terminal to the master table, please also send me a copy
  77.  * so that I may put it into my version.
  78.  *
  79.  * Michael Cooper
  80.  * ARPA:     mcooper@oberon.USC.EDU
  81.  * UUCP:     {sdcrdcf, cit-vax}!oberon!mcooper
  82.  * BITNET:    mcooper@uscvaxq
  83.  */
  84.  
  85. #include <stdio.h>
  86. #include <pwd.h>
  87. #include <signal.h>
  88. #include <sys/ioctl.h>
  89. #include <setjmp.h>
  90. #ifdef USG5
  91. # include <termio.h>
  92. #else
  93. # include <sys/file.h>
  94. # include <sgtty.h>
  95. #endif
  96.  
  97. #include "qterm.h"
  98.  
  99. int tabtotal = 0;
  100. int has_set = 0;
  101.  
  102. struct qt *compare();
  103. struct qt termtab[MAXTERMS];
  104.  
  105. #ifdef USG5
  106. struct termio _ntty, _otty;
  107. #else
  108. struct sgttyb _tty;
  109. #endif
  110. int _tty_ch = 2;
  111.  
  112.  
  113. static char recvbuf[SIZE];
  114. static char *progname;
  115.  
  116. int debug = FALSE;          /* debug mode */
  117. int aflag = FALSE;          /* alternate string */
  118. int sflag = FALSE;          /* print strings */
  119. int qflag = FALSE;          /* quiet mode */
  120. int fflag = FALSE;          /* use user's own .qterm file */
  121. int Fflag = FALSE;          /* same as above, but don't add our own table */
  122.  
  123. int found = FALSE;
  124. int index = 0;
  125. int finish(), wakeup(), done();
  126.  
  127. char *decode();
  128.  
  129. jmp_buf env;
  130.  
  131. main(argc, argv)
  132. char *argv[];
  133. {
  134.   register int x;
  135.  
  136.   progname = argv[0];
  137.  
  138.   for (x = 1; x < argc; x++) {
  139.     if (argv[x][0] != '-')
  140.       break;
  141.     switch (argv[x][1]) {
  142.       case 'a':
  143.         aflag = TRUE;
  144.         break;
  145.       case 't':
  146.       case 's':
  147.         sflag = TRUE;
  148.         break;
  149.       case 'q':
  150.         qflag = TRUE;
  151.         break;
  152.       case 'f':
  153.         fflag = TRUE;
  154.         break;
  155.       case 'F':
  156.         Fflag = TRUE;
  157.         break;
  158.       case 'd':
  159.         debug = TRUE;
  160.         break;
  161.       default:
  162.         usage();
  163.         exit(1);
  164.     }
  165.   }
  166.  
  167.   setbuf(stdout, 0);
  168.   if(debug)
  169.     setbuf(stderr, 0);
  170.  
  171.   dprintf("[ %s debug mode enabled ]\n\n", progname);
  172.  
  173.   if(!isatty(0))
  174.     fprintf(stderr,"Not a tty.\n");
  175.  
  176. #ifdef USG5
  177.   if(ioctl(_tty_ch, TCGETA, &_otty) < 0)
  178. #else
  179.   if(ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
  180. #endif
  181.   {
  182.     perror("gtty");
  183.     exit(1);
  184.   }
  185. #ifdef USG5
  186.   _ntty = _otty;
  187. #endif
  188.   if(crmode() < 0) {
  189.     perror("crmode");
  190.     exit(1);
  191.   }
  192.   if(noecho() < 0) {
  193.     perror("noecho");
  194.     exit(1);
  195.   }
  196.  
  197.   mktable();
  198.  
  199.   index = 0;
  200.   dprintf("main: we'll do a dotab()\n");
  201.   dotab();
  202.   dprintf("main: dotab done\n");
  203.  
  204.   putc('\r', stderr);
  205.   (void) nocrmode();
  206.   (void) echo();
  207.  
  208.   if(!found) {
  209.     dprintf("end of main\n");
  210.     notrecognized();
  211.   }
  212. }
  213.  
  214. usage()
  215. {
  216.   fprintf(stderr, "usage: %s [ -a ] [ -s ] [ -q ] [ -f ] [ -F ]\n", 
  217.       progname);
  218. }
  219.  
  220. done(s)
  221. int s;
  222. {
  223.   putc('\r', stderr);
  224.   (void) nocrmode();
  225.   (void) echo();
  226.   exit(s);
  227. }
  228.  
  229. /*
  230.  * finish - clean things up.
  231.  */
  232. finish()
  233. {
  234.   dprintf("finish called\n");
  235.  
  236.   putc('\r', stderr);
  237.   (void) nocrmode();
  238.   (void) echo();
  239.  
  240.   if(recvbuf[0] != NULL)
  241.     (void) prinfo(compare(recvbuf, 0, tabtotal), 1);
  242.     
  243.   dprintf("finish done\n");
  244.   if(!found)
  245.     notrecognized();
  246.  
  247.   exit(0);
  248. }
  249.  
  250. prinfo(t, what)
  251. struct qt *t;
  252. int what;
  253. {
  254.   int len = 0;
  255.   int st = FALSE;
  256.  
  257.   dprintf("prinfo startup\n");
  258.  
  259.   if((t != NULL) && (t->qt_termname[0] != NULL) && (recvbuf[0] != NULL)) {
  260.     if(debug || sflag) {
  261.       len = strlen(recvbuf);
  262.       fprintf(stderr, "%s receives %d character%s:", 
  263.         progname, len, (len == 1) ? "" : "s");
  264.       fprintf(stderr, " %s\n", decode(recvbuf));
  265.     }
  266.     if(!qflag)
  267.       if(t->qt_fullname[0] != NULL)
  268.         fprintf(stderr, "Terminal recognized as %s (%s)\n", 
  269.           t->qt_termname, t->qt_fullname);
  270.       else
  271.         fprintf(stderr, "Terminal recognized as %s\n", 
  272.           t->qt_termname);
  273.     printf("%s\n", t->qt_termname);
  274.     found = TRUE;
  275.     done(0);
  276.     /*NOTREACHED*/
  277.   } else {
  278.     found = FALSE;
  279.     if(what) {
  280.       dprintf("prinfo(): doing notrecognized()\n");
  281.       notrecognized();
  282.       done(1);
  283.       /*NOTREACHED*/
  284.     }
  285.   }
  286.  
  287.   dprintf("prinfo done\n");
  288.  
  289.   return(st);
  290. }
  291.  
  292. /*
  293.  * compare - actually compare what we received against the table.
  294.  */
  295. struct qt *
  296. compare(str, start, stop)
  297. char *str;
  298. int start;
  299. int stop;
  300. {
  301.   register int i = 0;
  302.  
  303.   dprintf("compare(%s, %d, %d) startup.\n", decode(str), start, stop);
  304.   alarm(0);
  305.  
  306.   i = start;
  307.   while(i <= stop) {
  308.     dprintf("compare(): tr = '%s'\n", decode(termtab[i].qt_recvstr));
  309.     if(strncmp(str, termtab[i].qt_recvstr, 
  310.       strlen(termtab[i].qt_recvstr)) == 0) {
  311.       found = TRUE;
  312.       return(&termtab[i]);
  313.     }
  314.     ++i;
  315.   }
  316.   found = FALSE;
  317.  
  318.   return(NULL);
  319. }
  320.  
  321. /*
  322.  * getch - read in a character at a time.
  323.  */
  324. getch()
  325. {
  326.   char c;
  327.  
  328.   (void) read(0, &c, 1);
  329.   return(c & CMASK);
  330. }
  331.  
  332. /*
  333.  * decode - print str in a readable fashion
  334.  */
  335. char *
  336. decode(str)
  337. char *str;
  338. {
  339.   char buf[BUFSIZ];
  340.   char tmp[10];
  341.  
  342.   strcpy(buf, "");
  343.   while(*str) {
  344.     if (*str == ESC) {
  345.       strcat(buf, "<esc> ");
  346.     } else if((*str <= 33) || (*str >= 127)) {
  347.       sprintf(tmp,"\\%o ", *str);
  348.       strcat(buf, tmp);
  349.     } else {
  350.       sprintf(tmp,"%c ", *str);
  351.       strcat(buf, tmp);
  352.     }
  353.     *++str;
  354.   }
  355.   return(buf);
  356. }
  357.  
  358. mktable()
  359. {
  360.   char file[BUFSIZ];
  361.   struct passwd *pwd;
  362.   char *home;
  363.  
  364.   dprintf("[ initilizing term table... ]\n");
  365.  
  366.   if(fflag) {
  367.     /*
  368.      * Try and read the user's own table
  369.      */
  370.     if((home = (char *) getenv("HOME")) == NULL) {
  371.       if((pwd = (struct passwd *) getpwuid(getuid())) == NULL) {
  372.     fprintf(stderr, "Who the hell are you????\n");
  373.     exit(1);
  374.       }
  375.       home = pwd->pw_dir;
  376.     }
  377.     dprintf("home = '%s'\n", home);
  378.     sprintf(file, "%s/%s", home, STRFILE);
  379.     dprintf("strfile = '%s'\n", file);
  380.  
  381.     (void) readtabfile(file, TRUE);
  382.   }
  383.  
  384.   if(!Fflag)
  385.     (void) readtabfile(TABFILE, FALSE);
  386.  
  387.   dprintf("termtab total  = %d\n", tabtotal);
  388.   dprintf("[ mktable done ]\n");
  389. }
  390.  
  391. readtabfile(file, bequiet)
  392. char *file;
  393. int bequiet;
  394. {
  395.   static int i = 0, line;
  396.   char lbuf[4][BUFSIZ];
  397.   char buf[BUFSIZ];
  398.   FILE *fd, *fopen();
  399.   char *msg, *fixctl();
  400.   int iserr = 0;
  401.  
  402.   if((fd = fopen(file, "r")) == NULL) {
  403.     if(bequiet)
  404.       return(-1);
  405.     perror(file);
  406.     done(1);
  407.   }
  408.  
  409.   line = 0;
  410.   while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
  411.     ++line;
  412.     
  413.     if(buf[0] == '#' || buf[0] == '\n')
  414.       continue;
  415.     
  416.     lbuf[0][0] = NULL;
  417.     lbuf[1][0] = NULL;
  418.     lbuf[2][0] = NULL;
  419.     lbuf[3][0] = NULL;
  420.     
  421.     (void) sscanf(buf, "%s%s%s\t%[^\n]", 
  422.           lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
  423.     if(lbuf[0][0] == NULL)
  424.       continue;
  425.     if(lbuf[1][0] == NULL) {
  426.       iserr = TRUE;
  427.       msg = "receive string";
  428.     }
  429.     if(lbuf[2][0] == NULL) {
  430.       iserr = TRUE;
  431.       msg = "terminal name";
  432.     }
  433.     if(iserr) {
  434.       fprintf(stderr, "Line %d of %s: Error parsing %s.\n", 
  435.           line, file, msg);
  436.       done(1);
  437.       /* NOTREACHED */
  438.     }
  439.     if(aflag)
  440.       (void) strcpy(termtab[i].qt_sendstr, fixctl(ALTSEND));
  441.     else
  442.       (void) strcpy(termtab[i].qt_sendstr, fixctl(lbuf[0]));
  443.     (void) strcpy(termtab[i].qt_recvstr, fixctl(lbuf[1]));
  444.     (void) strcpy(termtab[i].qt_termname, lbuf[2]);
  445.     (void) strcpy(termtab[i].qt_fullname, lbuf[3]);
  446.     
  447.     dprintf("entry %d:\n", i);
  448.     dprintf("qt_sendstr = %s\n", decode(termtab[i].qt_sendstr));
  449.     dprintf("qt_recvstr = %s\n", decode(termtab[i].qt_recvstr));
  450.     dprintf("qt_termname = '%s'\n", termtab[i].qt_termname);
  451.     dprintf("qt_fullname = '%s'\n", termtab[i].qt_fullname);
  452.     
  453.     ++i;
  454.   }
  455.  
  456.   tabtotal = i;
  457.  
  458.   return(0);
  459. }
  460.  
  461. listen(q)
  462. struct qt *q;
  463. {
  464.   register int i;
  465.   register char c;
  466.   char end, begin;
  467.  
  468.   dprintf("listen startup\n");
  469.   alarm(0);
  470.  
  471.   dprintf("listen: listening for '%s'\n", decode(q->qt_recvstr));
  472.  
  473.   if (q->qt_recvstr[0] == NULL) {
  474.     begin = ESC;
  475.     end = 'c';
  476.   } else {
  477.     begin = q->qt_recvstr[0];
  478.     end = q->qt_recvstr[strlen(q->qt_recvstr)-1];
  479.   }
  480.  
  481.   dprintf("listen: read initial character...\n");
  482.   if(setjmp(env)) {
  483.     dprintf("listen: setjmp TRUE\n");
  484.     if(found)
  485.       done();
  486.     ++index;
  487.     (void) fflush(stdin);
  488.     dprintf("listen: dotab()\n");
  489.     dotab();
  490.   } else {
  491.     dprintf("listen: setjmp FALSE...set alarm\n");
  492.     signal(SIGALRM, wakeup);
  493.     alarm(WAIT);
  494.     dprintf("listen: read char\n");
  495.     recvbuf[0] = getch();
  496.     alarm(0);
  497.     dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  498.  
  499.   }
  500.   i = 0;
  501.   if(recvbuf[0] == begin) {
  502.     dprintf("listen begin\n");
  503.     while(c != end) {
  504.       if(setjmp(env))  {
  505.         dprintf("listen: setjmp (2) return\n");
  506.         return;
  507.       } else {
  508.         signal(SIGALRM, wakeup);
  509.         alarm(WAIT);
  510.         dprintf("listen: read (2) char\n");
  511.         c = getch();
  512.         alarm(0);
  513.         dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  514.       }
  515.       recvbuf[++i] = c;
  516.     }
  517.     if(debug)
  518.       fprintf(stderr,"\n[ Received terminator. ]\n");
  519.   } else {
  520.     dprintf("listen: Not Recognized.  exiting...\n");
  521.     notrecognized();
  522.     putc('\r',stderr);
  523.     (void) nocrmode();
  524.     (void) echo();
  525.     exit(1);
  526.   }
  527.   dprintf("listen done\n");
  528. }
  529.  
  530. notrecognized()
  531. {
  532.   if(!qflag)
  533.     fprintf(stderr, 
  534.       "Terminal NOT recognized - defaults to \"dumb\".\n");
  535.   puts("dumb");
  536. }
  537.  
  538. wakeup()
  539. {
  540.   dprintf("wakeup called\n");
  541.   longjmp(env, 1);
  542.   dprintf("wakeUP: done\n");
  543. }
  544.  
  545. dotab()
  546. {
  547.   int wakeup();
  548.   int st = FALSE;
  549.   static int firsttime = TRUE;
  550.  
  551.   dprintf("dotab startup\n");
  552.   dprintf("index = %d\n", index);
  553.  
  554.   if(index > tabtotal) {
  555.     /*
  556.      * if we haven't reset things yet, do so.
  557.      * now try the internal tables if the user's
  558.      * tables failed.
  559.      */
  560.     if(!has_set)  {
  561.       index = 0;
  562.       has_set = 1;
  563.       dprintf("dotab(): has_set now true.\n");
  564.       dotab();
  565.     }
  566.     dprintf("dotab(): index > tabtotal\n");
  567.     finish();
  568.   }
  569.   if(!found || fflag) {
  570.     while(!found && termtab[index].qt_sendstr[0] != NULL && !st) {
  571.       dprintf("dotab: termtab PASS %d\n", index);
  572.       dprintf("dotab: sending str %s\n", 
  573.         decode(termtab[index].qt_sendstr));
  574.       (void) fflush(stdin);
  575.  
  576.       if(firsttime || strncmp(termtab[index].qt_sendstr, 
  577.         termtab[index-1].qt_sendstr,
  578.         strlen(termtab[index].qt_sendstr))) {
  579.  
  580.         firsttime = FALSE;
  581.         dprintf("dotab(): sendstr's didn't match.\n");
  582.         dprintf("dotab: str1 %s\n", decode(termtab[index].qt_sendstr));
  583.         dprintf("dotab: str2 %s\n", decode(termtab[index-1].qt_sendstr));
  584.  
  585.         fprintf(stderr, termtab[index].qt_sendstr);
  586.         (void) fflush(stdout);
  587.         (void) fflush(stderr);
  588.  
  589.         (void) listen(&termtab[index]);
  590.       } else {
  591.         dprintf("dotab(): sendstr's DID match.  No str sent.\n");
  592.         dprintf("dotab: str1 %s\n", decode(termtab[index].qt_sendstr));
  593.         dprintf("dotab: str2 %s\n", decode(termtab[index-1].qt_sendstr));
  594.       }
  595.  
  596.       firsttime = FALSE;
  597.       dprintf("dotab(): recbuf = '%s'\n", decode(recvbuf));
  598.       dprintf("dotab(): qt_rec = '%s'\n", decode(termtab[index].qt_recvstr));
  599.  
  600.       st = prinfo(compare(recvbuf, 0, tabtotal), FALSE);
  601.  
  602.       dprintf("st = %d\n", st);
  603.  
  604.       ++index;
  605.     }
  606.   }
  607.  
  608.   if(!found) {
  609.     dprintf("dotab: failed.\n");
  610.     notrecognized();
  611.   }
  612.  
  613.   done();
  614. }
  615.  
  616. char *
  617. fixctl(str)
  618. char *str;
  619. {
  620.   register int i;
  621.   char buf[BUFSIZ];
  622.  
  623.   i = 0;
  624.   while(*str) {
  625.     if(*str == '^')
  626.       buf[i++] = *++str & 037;
  627.     else
  628.       buf[i++] = *str;
  629.     *++str;
  630.   }
  631.   buf[i] = NULL;
  632.   return(buf);
  633. }
  634.