home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / tset.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  15KB  |  677 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. # include    <sgtty.h>
  3. # include    <stdio.h>
  4.  
  5. /*
  6. **  TSET -- set terminal modes
  7. **
  8. **    This program does sophisticated terminal initialization.
  9. **    I recommend that you include it in your .start_up or .login
  10. **    file to initialize whatever terminal you are on.
  11. **
  12. **    There are several features:
  13. **
  14. **    A special file or sequence (as controlled by the ttycap file)
  15. **    is sent to the terminal.
  16. **
  17. **    Mode bits are set on a per-terminal_type basis (much better
  18. **    than UNIX itself).  This allows special delays, automatic
  19. **    tabs, etc.
  20. **
  21. **    Erase and Kill characters can be set to whatever you want.
  22. **    Default is to change erase to control-H on a terminal which
  23. **    can overstrike, and leave it alone on anything else.  Kill
  24. **    is always left alone unless specifically requested.
  25. **
  26. **    Terminals which are dialups or plugboard types can be aliased
  27. **    to whatever type you may have in your home or office.  Thus,
  28. **    if you know that when you dial up you will always be on a
  29. **    TI 733, you can specify that fact to tset.
  30. **
  31. **    The htmp file, used by ex, etc., can be updated.
  32. **
  33. **    The current terminal type can be queried.
  34. **
  35. **    Usage:
  36. **        tset [-] [-r] [-EC] [-eC] [-d type] [-p type]
  37. **            [-b type] [-h] [-u] [type]
  38. **
  39. **        In systems with environments, use:
  40. **            setenv TERM `tset - ...`
  41. **
  42. **    Positional Parameters:
  43. **        type -- the terminal type to force.  If this is
  44. **            specified, initialization is for this
  45. **            terminal type.
  46. **
  47. **    Flags:
  48. **        - -- report terminal type.  Whatever type is
  49. **            decided on is reported.
  50. **        -r -- report to user, on diagnostic output instead
  51. **            of standard output.
  52. **        -EC -- set the erase character to C on all terminals
  53. **            except those which cannot backspace (e.g.,
  54. **            a TTY 33).  C defaults to control-H.
  55. **        -eC -- set the erase character to C on all terminals.
  56. **            C defaults to control-H.  If neither -E or -e
  57. **            are specified, the erase character is set to
  58. **            control-H if the terminal can both backspace
  59. **            and not overstrike (e.g., a CRT).  If the erase
  60. **            character is NULL (zero byte), it will be reset
  61. **            to '#' if nothing else is specified.
  62. **        -kC -- set the kill character to C on all terminals.
  63. **            Default for C is control-X.  If not specified,
  64. **            the kill character is untouched; however, if
  65. **            not specified and the kill character is NULL
  66. **            (zero byte), the kill character is set to '@'.
  67. **        -d type -- set the dialup type to be type.  If the
  68. **            terminal type seems to be dialup, make it
  69. **            'type' instead.  There need not be a space
  70. **            between 'd' and 'type'.
  71. **        -p type -- ditto for a plugboard.
  72. **        -b type -- ditto for a bussiplexer.
  73. **        -h -- don't read htmp file.  Normally the terminal type
  74. **            is determined by reading the htmp file (unless
  75. **            -d or -p are specified).  This forces a read
  76. **            of the ttytype file -- useful when htmp is
  77. **            somehow wrong.  On a version seven system, this
  78. **            flag means don't look at the TERM entry in
  79. **            the environment.
  80. **        -u -- don't update htmp.  It seemed like this should
  81. **            be put in.  Note that htmp is never actually
  82. **            written if there are no changes, so don't bother
  83. **            bother using this for efficiency reasons alone.
  84. **            On version seven systems this flag is ignored.
  85. **
  86. **    Files:
  87. **        /etc/ttytype
  88. **            contains a terminal id -> terminal type
  89. **            mapping; used when -h, -d, or -p is used.
  90. **        /etc/termcap
  91. **            a terminal_type -> terminal_capabilities
  92. **            mapping.
  93. **
  94. **    Return Codes:
  95. **        -1 -- couldn't open ttycap.
  96. **        1 -- bad terminal type, or standard output not tty.
  97. **        0 -- ok.
  98. **
  99. **    Defined Constants:
  100. **        DIALUP -- the type code for a dialup port
  101. **        PLUGBOARD -- the code for a plugboard port.
  102. **        BUSSIPLEXER -- the code for a bussiplexer port.
  103. **        BACKSPACE -- control-H, the default for -e.
  104. **        CONTROLX -- control-X, the default for -k.
  105. **        OLDERASE -- the system default erase character.
  106. **        OLDKILL -- the system default kill character.
  107. **        FILEDES -- the file descriptor to do the operation
  108. **            on, nominally 1 or 2.
  109. **        STDOUT -- the standard output file descriptor.
  110. **        UIDMASK -- the bit pattern to mask with the getuid()
  111. **            call to get just the user id.
  112. **
  113. **    Requires:
  114. **        Routines to handle htmp, ttytype, and ttycap.
  115. **
  116. **    Compilation Flags:
  117. **        PLUGBOARD -- if defined, accept the -p flag.
  118. **        BUSSIPLEXER -- if defined, accept the -b flag.
  119. **        FULLLOGIN -- if defined, login sets the ttytype from
  120. **            /etc/ttytype file.
  121. **        VERSION7 -- if set, use environments, not htmp.
  122. **            Also, use 'ioctl' not 'stty' -- to get type-
  123. **            ahead.
  124. **        GTTYN -- if set, uses generalized tty names.
  125. **
  126. **    Compilation Instructions:
  127. **        cc -n -O tset.c -lX
  128. **        mv a.out tset
  129. **        chown bin tset
  130. **        chmod 4755 tset
  131. **
  132. **        where 'bin' should be whoever owns the 'htmp' file.
  133. **        If 'htmp' is 666, then tset need not be setuid.
  134. **
  135. **    Author:
  136. **        Eric Allman
  137. **        Electronics Research Labs
  138. **        U.C. Berkeley
  139. **
  140. **    History:
  141. **        3/79 -- Use ioctl in version7.
  142. **        12/78 -- modified for eventual migration to VAX/UNIX,
  143. **            so the '-' option is changed to output only
  144. **            the terminal type to STDOUT instead of
  145. **            FILEDES.  FULLLOGIN flag added.  BUSSIPLEXER
  146. **            and -r added.
  147. **        9/78 -- '-' and '-p' options added (now fully
  148. **            compatible with ttytype!), and spaces are
  149. **            permitted between the -d and the type.
  150. **        8/78 -- The sense of -h and -u were reversed, and the
  151. **            -f flag is dropped -- same effect is available
  152. **            by just stating the terminal type.
  153. **        10/77 -- This version, in much it's previous state,
  154. **            written by Eric Allman.
  155. */
  156.  
  157. # define    BACKSPACE    ('H' & 037)
  158. # define    CONTROLX    ('X' & 037)
  159. # define    OLDERASE    '#'
  160. # define    OLDKILL        '@'
  161.  
  162. # define    FILEDES        2
  163. # define    STDOUT        1
  164.  
  165. # define    DIALUP        "du"
  166. # define    PLUGBOARD    "pb"
  167. # define    BUSSIPLEXER    "bx"
  168. /* # define    FULLLOGIN    FULLLOGIN    login does everything */
  169. # define    VERSION7    VERSION7    /* version seven flag */
  170. # define    GTTYN        GTTYN        /* general tty names */
  171.  
  172. # ifdef VERSION7
  173. # define    UIDMASK        0177777
  174. # else
  175. # define    UIDMASK        0377
  176. # endif
  177.  
  178. # ifdef GTTYN
  179. typedef char    *ttyid_t;
  180. # else
  181. typedef char    ttyid_t;
  182. # endif
  183.  
  184. # define    NOTTY        0
  185.  
  186.  
  187.  
  188.  
  189.  
  190. char    Erase_char;        /* new erase character */
  191. char    Kill_char;        /* new kill character */
  192. char    Specialerase;        /* set => Erase_char only on terminals with backspace */
  193.  
  194. ttyid_t    Ttyid = NOTTY;        /* terminal identifier */
  195. char    *Ttytype;        /* type of terminal */
  196. char    *Dialtype;        /* override type if dialup terminal */
  197. char    *Plugtype;        /* override type if plugboard port */
  198. char    *Bxtype;        /* override type if bussiplexer port */
  199. int    Dash_u;            /* don't-update-htmp flag */
  200. int    Dash_h;            /* don't-read-htmp flag */
  201. int    Report;            /* report current type */
  202. int    Ureport;        /* report to user */
  203.  
  204. char    Usage[] = "usage: tset [-] [-r] [-eC] [-kC] [-d T] [-p T] [-b T] [-h] [-u] [type]\n";
  205.  
  206. char    Capbuf[256];        /* line from /etc/ttycap for this Ttytype */
  207.  
  208. struct delay
  209. {
  210.     int    d_delay;
  211.     int    d_bits;
  212. };
  213.  
  214. # include    "tset.del.h"
  215.  
  216.  
  217.  
  218. main(argc, argv)
  219. int    argc;
  220. char    *argv[];
  221. {
  222.     struct sgttyb    mode;
  223.     struct sgttyb    oldmode;
  224.     char        buf[256];
  225.     auto char    *bufp;
  226.     register char    *p;
  227.     char        *command;
  228.     register int    i;
  229.     register int    error;
  230.     int        mdvect[2];
  231.     extern char    *stypeof();
  232. # ifndef VERSION7
  233.     extern char    *hsgettype();
  234. # else
  235.     extern char    *getenv();
  236. # endif
  237. # ifdef GTTYN
  238.     extern char    *ttyname();
  239. # endif
  240.  
  241.     /* scan argument list and collect flags */
  242.     error = 0;
  243.     command = argv[0];
  244.     argc--;
  245.     while (--argc >= 0)
  246.     {
  247.         p = *++argv;
  248.         if (p[0] == '-')
  249.         {
  250.             switch (p[1])
  251.             {
  252.  
  253.               case 0:    /* report current terminal type */
  254.                 Report++;
  255.                 continue;
  256.  
  257.               case 'r':    /* report to user */
  258.                 Ureport++;
  259.                 continue;
  260.  
  261.               case 'E':    /* special erase: operate on all but TTY33 */
  262.                 Specialerase++;
  263.                 /* exlicit fall-through to -e case */
  264.  
  265.               case 'e':    /* erase character */
  266.                 if (p[2] == 0)
  267.                     Erase_char = BACKSPACE;
  268.                 else
  269.                     Erase_char = p[2];
  270.                 continue;
  271.  
  272.               case 'k':    /* kill character */
  273.                 if (p[2] == 0)
  274.                     Kill_char = CONTROLX;
  275.                 else
  276.                     Kill_char = p[2];
  277.                 continue;
  278.  
  279.               case 'd':    /* dialup type */
  280.                 if (p[2] != 0)
  281.                     Dialtype = &p[2];
  282.                 else if (--argc < 0 || argv[1][0] == '-')
  283.                     error++;
  284.                 else
  285.                     Dialtype = *++argv;
  286.                 continue;
  287.  
  288. # ifdef PLUGBOARD
  289.               case 'p':    /* plugboard type */
  290.                 if (p[2] != 0)
  291.                     Plugtype = &p[2];
  292.                 else if (--argc < 0 || argv[1][0] == '-')
  293.                     error++;
  294.                 else
  295.                     Plugtype = *++argv;
  296.                 continue;
  297. # endif
  298.  
  299. # ifdef BUSSIPLEXER
  300.               case 'b':    /* bussiplexer type */
  301.                 if (p[2] != 0)
  302.                     Bxtype = &p[2];
  303.                 else if (--argc < 0 || argv[1][0] == '-')
  304.                     error++;
  305.                 else
  306.                     Bxtype = *++argv;
  307. # endif
  308.  
  309.               case 'h':    /* don't get type from htmp */
  310.                 Dash_h++;
  311.                 continue;
  312.  
  313. # ifndef VERSION7
  314.               case 'u':    /* don't update htmp */
  315.                 Dash_u++;
  316.                 continue;
  317. # endif
  318.  
  319.               default:
  320.                 prs("Bad flag ");
  321.                 prs(p);
  322.                 prs("\n");
  323.                 error++;
  324.  
  325.             }
  326.         }
  327.         else
  328.         {
  329.             /* terminal type */
  330.             Ttytype = p;
  331.         }
  332.     }
  333.  
  334.     if (error)
  335.     {
  336.         prs(Usage);
  337.         exit(1);
  338.     }
  339.  
  340. # ifndef FULLLOGIN
  341.     /* if dialup is specified, check ttytype not htmp */
  342.     if (Dialtype != 0 || Plugtype != 0 || Bxtype != 0)
  343.         Dash_h++;
  344. # endif
  345.  
  346.     /* determine terminal id if needed */
  347.     if (Ttyid == NOTTY && (Ttytype == 0 || !Dash_h || !Dash_u))
  348. # ifndef VERSION7
  349.         Ttyid = ttyn(FILEDES);
  350. # else
  351.         Ttyid = ttyname(FILEDES);
  352. # endif
  353.  
  354. # ifndef VERSION7
  355.     /* get htmp if ever used */
  356.     if (!Dash_u || (Ttytype == 0 && !Dash_h))
  357.     {
  358.         /* get htmp entry */
  359.         hget(Ttyid);
  360.     
  361.         /* if not for this user, look at ttytype file */
  362.         if (hgettype() == 0 || hgetuid() != (getuid() & UIDMASK))
  363.             Dash_h++;
  364.     }
  365. # endif
  366.  
  367.     /* find terminal type (if not already known) */
  368.     if (Ttytype == 0)
  369.     {
  370.         /* get type from /etc/ttytype or /etc/htmp */
  371.         if (!Dash_h)
  372.         {
  373. # ifndef VERSION7
  374.             Ttytype = hsgettype();
  375. # else
  376.             Ttytype = getenv("TERM");
  377. # endif
  378.         }
  379.         if (Ttytype == 0)
  380.         {
  381.             Ttytype = stypeof(Ttyid);
  382.         }
  383.  
  384.         /* check for dialup or plugboard override */
  385.         if (Dialtype != 0 && bequal(Ttytype, DIALUP, 2))
  386.             Ttytype = Dialtype;
  387. # ifdef PLUGBOARD
  388.         else if (Plugtype != 0 && bequal(Ttytype, PLUGBOARD, 2))
  389.             Ttytype = Plugtype;
  390. # endif
  391. # ifdef BUSSIPLEXER
  392.         else if (Bxtype != 0 && bequal(Ttytype, BUSSIPLEXER, 2))
  393.             Ttytype = Bxtype;
  394. # endif
  395.     }
  396.  
  397.     /* Ttytype now contains a pointer to the type of the terminal */
  398.  
  399.     if (gtty(FILEDES, &mode) < 0)
  400.     {
  401.         prs("Not a terminal\n");
  402.         exit(1);
  403.     }
  404.     bmove(&mode, &oldmode, sizeof mode);
  405.  
  406.     /* get terminal capabilities */
  407.     switch (tgetent(Capbuf, Ttytype))
  408.     {
  409.  
  410.       case -1:
  411.         prs("Cannot open ttycap file\n");
  412.         exit(-1);
  413.  
  414.       case 0:
  415.         prs("Type ");
  416.         prs(Ttytype);
  417.         prs(" unknown\n");
  418.         exit(1);
  419.     }
  420.  
  421.     /* report type if appropriate */
  422.     if (Report || Ureport)
  423.     {
  424.         /* find first alias (if any) */
  425.         for (p = Capbuf; *p != 0 && *p != '|' && *p != ':'; p++)
  426.             continue;
  427.         if (*p == 0 || *p == ':')
  428.             p = Capbuf;
  429.         else
  430.             p++;
  431.         bufp = p;
  432.         while (*p != '|' && *p != ':' && *p != 0)
  433.             p++;
  434.         i = *p;
  435.         if (Report)
  436.         {
  437.             *p = '\n';
  438.             write(STDOUT, bufp, p + 1 - bufp);
  439.         }
  440.         if (Ureport)
  441.         {
  442.             *p = '\0';
  443.             prs("Terminal type is ");
  444.             prs(bufp);
  445.             prs("\n");
  446.         }
  447.         *p = i;
  448.     }
  449.  
  450.     /* determine erase and kill characters */
  451.     if (Specialerase && !tgetflag("bs"))
  452.         Erase_char = 0;
  453.     if (Erase_char == 0)
  454.     {
  455.         if (mode.sg_erase == 0)
  456.             mode.sg_erase = OLDERASE;
  457.         if (tgetflag("bs") && !tgetflag("os"))
  458.             mode.sg_erase = BACKSPACE;
  459.     }
  460.     else
  461.         mode.sg_erase = Erase_char;
  462.  
  463.     if (mode.sg_kill == 0)
  464.         mode.sg_kill = OLDKILL;
  465.     if (Kill_char != 0)
  466.         mode.sg_kill = Kill_char;
  467.  
  468.     /* set modes */
  469.     setdelay("dC", CRdelay, CRbits, &mode.sg_flags);
  470.     setdelay("dN", NLdelay, NLbits, &mode.sg_flags);
  471.     setdelay("dB", BSdelay, BSbits, &mode.sg_flags);
  472.     setdelay("dF", FFdelay, FFbits, &mode.sg_flags);
  473.     setdelay("dT", TBdelay, TBbits, &mode.sg_flags);
  474.     if (tgetflag("UC") || command[0] == 'T')
  475.         mode.sg_flags |= LCASE;
  476.     else if (tgetflag("LC"))
  477.         mode.sg_flags &= ~LCASE;
  478.     mode.sg_flags &= ~(EVENP | ODDP | RAW);
  479.     if (tgetflag("EP"))
  480.         mode.sg_flags |= EVENP;
  481.     if (tgetflag("OP"))
  482.         mode.sg_flags |= ODDP;
  483.     if ((mode.sg_flags & (EVENP | ODDP)) == 0)
  484.         mode.sg_flags |= EVENP | ODDP;
  485.     mode.sg_flags |= CRMOD | ECHO | XTABS;
  486.     if (tgetflag("NL"))    /* new line, not line feed */
  487.         mode.sg_flags &= ~CRMOD;
  488.     if (tgetflag("HD"))    /* half duplex */
  489.         mode.sg_flags &= ~ECHO;
  490.     if (tgetflag("pt"))    /* print tabs */
  491.         mode.sg_flags &= ~XTABS;
  492. # ifdef VERSION7
  493.     if (!bequal(&mode, &oldmode, sizeof mode))
  494.         ioctl(FILEDES, TIOCSETN, &mode);
  495. # else
  496.     if (!bequal(&mode, &oldmode, sizeof mode))
  497.         stty(FILEDES, &mode);
  498. # endif
  499.  
  500.     /* output startup string */
  501.     bufp = buf;
  502.     if (tgetstr("is", &bufp) != 0)
  503.         prs(buf);
  504.     bufp = buf;
  505.     if (tgetstr("if", &bufp) != 0)
  506.         cat(buf);
  507.  
  508.     /* tell about changing erase and kill characters */
  509.     reportek("Erase", mode.sg_erase, oldmode.sg_erase, OLDERASE);
  510.     reportek("Kill", mode.sg_kill, oldmode.sg_kill, OLDKILL);
  511.  
  512. # ifndef VERSION7
  513.     /* update htmp */
  514.     if (!Dash_u)
  515.     {
  516.         if (Ttyid == 0)
  517.             Ttyid = ttyn(FILEDES);
  518.         if (Ttyid == 'x')
  519.             prs("Cannot update htmp\n");
  520.         else
  521.         {
  522.             /* update htmp file only if changed */
  523.             if (!bequal(Capbuf, hsgettype(), 2))
  524.             {
  525.                 hsettype(Capbuf[0] | (Capbuf[1] << 8));
  526.                 hput(Ttyid);
  527.             }
  528.         }
  529.     }
  530. # endif
  531.  
  532.     exit(0);
  533. }
  534.  
  535.  
  536. reportek(name, new, old, def)
  537. char    *name;
  538. char    old;
  539. char    new;
  540. char    def;
  541. {
  542.     register char    o;
  543.     register char    n;
  544.     register char    *p;
  545.  
  546.     o = old;
  547.     n = new;
  548.  
  549.     if (o == n && n == def)
  550.         return;
  551.     prs(name);
  552.     if (o == n)
  553.         prs(" is ");
  554.     else
  555.         prs(" set to ");
  556.     if (n < 040)
  557.     {
  558.         prs("control-");
  559.         n = (n & 037) | 0100;
  560.     }
  561.     p = "x\n";
  562.     p[0] = n;
  563.     prs(p);
  564. }
  565.  
  566.  
  567.  
  568.  
  569. setdelay(cap, dtab, bits, flags)
  570. char        *cap;
  571. struct delay    dtab[];
  572. int        bits;
  573. int        *flags;
  574. {
  575.     register int    i;
  576.     register struct delay    *p;
  577.  
  578.     /* see if this capability exists at all */
  579.     i = tgetnum(cap);
  580.     if (i < 0)
  581.         i = 0;
  582.  
  583.     /* clear out the bits, replace with new ones */
  584.     *flags &= ~bits;
  585.  
  586.     /* scan dtab for first entry with adequate delay */
  587.     for (p = dtab; p->d_delay >= 0; p++)
  588.     {
  589.         if (p->d_delay >= i)
  590.         {
  591.             p++;
  592.             break;
  593.         }
  594.     }
  595.  
  596.     /* use last entry if none will do */
  597.     *flags |= (--p)->d_bits;
  598. }
  599.  
  600.  
  601. prs(s)
  602. char    *s;
  603. {
  604.     register char    *p;
  605.     register char    *q;
  606.     register int    i;
  607.  
  608.     p = q = s;
  609.     i = 0;
  610.     while (*q++ != 0)
  611.         i++;
  612.  
  613.     if (i > 0)
  614.         write(FILEDES, p, i);
  615. }
  616.  
  617.  
  618. cat(file)
  619. char    *file;
  620. {
  621.     register int    fd;
  622.     register int    i;
  623.     char        buf[512];
  624.  
  625.     fd = open(file, 0);
  626.     if (fd < 0)
  627.     {
  628.         prs("Cannot open ");
  629.         prs(file);
  630.         prs("\n");
  631.         exit(-1);
  632.     }
  633.  
  634.     while ((i = read(fd, buf, 512)) > 0)
  635.         write(FILEDES, buf, i);
  636.  
  637.     close(fd);
  638. }
  639.  
  640.  
  641.  
  642. bmove(from, to, length)
  643. char    *from;
  644. char    *to;
  645. int    length;
  646. {
  647.     register char    *p, *q;
  648.     register int    i;
  649.  
  650.     i = length;
  651.     p = from;
  652.     q = to;
  653.  
  654.     while (i-- > 0)
  655.         *q++ = *p++;
  656. }
  657.  
  658.  
  659.  
  660. bequal(a, b, len)
  661. char    *a;
  662. char    *b;
  663. int    len;
  664. {
  665.     register char    *p, *q;
  666.     register int    i;
  667.  
  668.     i = len;
  669.     p = a;
  670.     q = b;
  671.  
  672.     while (i-- > 0)
  673.         if (*p++ != *q++)
  674.             return (0);
  675.     return (1);
  676. }
  677.