[BACK]Return to tset.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tset

Diff for /src/usr.bin/tset/tset.c between version 1.6 and 1.7

version 1.6, 1998/10/16 18:51:21 version 1.7, 1998/11/16 03:08:41
Line 1 
Line 1 
 /*      $OpenBSD$       */  /****************************************************************************
 /*      $NetBSD: tset.c,v 1.4 1994/12/07 05:08:15 jtc Exp $     */   * Copyright (c) 1998 Free Software Foundation, Inc.                        *
    *                                                                          *
    * Permission is hereby granted, free of charge, to any person obtaining a  *
    * copy of this software and associated documentation files (the            *
    * "Software"), to deal in the Software without restriction, including      *
    * without limitation the rights to use, copy, modify, merge, publish,      *
    * distribute, distribute with modifications, sublicense, and/or sell       *
    * copies of the Software, and to permit persons to whom the Software is    *
    * furnished to do so, subject to the following conditions:                 *
    *                                                                          *
    * The above copyright notice and this permission notice shall be included  *
    * in all copies or substantial portions of the Software.                   *
    *                                                                          *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
    * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
    * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
    * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
    * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
    * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
    * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
    *                                                                          *
    * Except as contained in this notice, the name(s) of the above copyright   *
    * holders shall not be used in advertising or otherwise to promote the     *
    * sale, use or other dealings in this Software without prior written       *
    * authorization.                                                           *
    ****************************************************************************/
   
   /****************************************************************************
    *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
    *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
    ****************************************************************************/
   
   
   /*
    * tset.c - terminal initialization utility
    *
    * This code was mostly swiped from 4.4BSD tset, with some obsolescent
    * cruft removed and substantial portions rewritten.  A Regents of the
    * University of California copyright applies to some portions of the
    * code, and is reproduced below:
    */
 /*-  /*-
  * Copyright (c) 1980, 1991, 1993   * Copyright (c) 1980, 1991, 1993
  *      The Regents of the University of California.  All rights reserved.   *      The Regents of the University of California.  All rights reserved.
Line 34 
Line 73 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 #ifndef lint  #define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */
 static char copyright[] =  #include <progs.priv.h>
 "@(#) Copyright (c) 1980, 1991, 1993\n\  
         The Regents of the University of California.  All rights reserved.\n";  
 #endif /* not lint */  
   
 #ifndef lint  
 #if 0  
 static char sccsid[] = "@(#)tset.c      8.1 (Berkeley) 6/9/93";  
 #endif  
 static char rcsid[] = "$OpenBSD$";  
 #endif /* not lint */  
   
 #include <sys/types.h>  
 #include <sys/ioctl.h>  
 #include <termios.h>  
 #include <errno.h>  #include <errno.h>
 #include <unistd.h>  
 #include <stdlib.h>  
 #include <stdio.h>  #include <stdio.h>
 #include <ctype.h>  #include <termcap.h>
 #include <string.h>  #include <fcntl.h>
 #include <err.h>  
 #include "extern.h"  
   
 void    obsolete __P((char *[]));  #if HAVE_GETTTYNAM && HAVE_TTYENT_H
 void    report __P((char *, int, u_int));  #include <ttyent.h>
 void    usage __P((void));  #endif
   #ifdef NeXT
   char *ttyname(int fd);
   #endif
   
 struct termios mode, oldmode;  /* this is just to stifle a missing-prototype warning */
   #ifdef linux
   # include <sys/ioctl.h>
   #endif
   
 int     erasechar;              /* new erase character */  #if NEED_PTEM_H
 int     intrchar;               /* new interrupt character */  /* they neglected to define struct winsize in termios.h -- it's only
 int     isreset;                /* invoked as reset */     in termio.h  */
 int     killchar;               /* new kill character */  #include        <sys/stream.h>
 int     lines, columns;         /* window size */  #include        <sys/ptem.h>
   #endif
   
   #include <curses.h>     /* for bool typedef */
   #include <dump_entry.h>
   
   MODULE_ID("$Id$")
   
   extern char **environ;
   
   #undef CTRL
   #define CTRL(x) ((x) & 0x1f)
   
   const char *_nc_progname = "tset";
   
   static TTY mode, oldmode;
   
   static int      terasechar = -1;        /* new erase character */
   static int      intrchar = -1;          /* new interrupt character */
   static int      isreset;                /* invoked as reset */
   static int      tkillchar = -1;         /* new kill character */
   static int      tlines, tcolumns;               /* window size */
   
   #define LOWERCASE(c) ((isalpha(c) && isupper(c)) ? tolower(c) : (c))
   
   static int
   CaselessCmp(const char *a, const char *b) /* strcasecmp isn't portable */
   {
           while (*a && *b) {
                   int cmp = LOWERCASE(*a) - LOWERCASE(*b);
                   if (cmp != 0)
                           break;
                   a++, b++;
           }
           return LOWERCASE(*a) - LOWERCASE(*b);
   }
   
   #if !HAVE_STRDUP
   static char *strdup (char *s)
   {
     char *p;
   
     p = malloc(strlen(s)+1);
     if (p)
       strcpy(p,s);
     return(p);
   }
   #endif /* not HAVE_STRDUP */
   
   static void
   err(const char *fmt, ...)
   {
           va_list ap;
           va_start(ap, fmt);
           (void)fprintf(stderr, "tset: ");
           (void)vfprintf(stderr, fmt, ap);
           va_end(ap);
           (void)fprintf(stderr, "\n");
           exit(EXIT_FAILURE);
           /* NOTREACHED */
   }
   
   static void
   failed(const char *msg)
   {
           char    temp[BUFSIZ];
           perror(strcat(strcpy(temp, "tset: "), msg));
           exit(EXIT_FAILURE);
           /* NOTREACHED */
   }
   
   static void
   cat(char *file)
   {
           register int fd, nr, nw;
           char buf[BUFSIZ];
   
           if ((fd = open(file, O_RDONLY, 0)) < 0)
                   failed(file);
   
           while ((nr = read(fd, buf, sizeof(buf))) > 0)
                   if ((nw = write(STDERR_FILENO, buf, (size_t)nr)) == -1)
                           failed("write to stderr");
           if (nr != 0)
                   failed(file);
           (void)close(fd);
   }
   
   static int
   outc(int c)
   {
           return putc(c, stderr);
   }
   
   /* Prompt the user for a terminal type. */
   static const char *
   askuser(const char *dflt)
   {
           static char answer[256];
           char *p;
   
           /* We can get recalled; if so, don't continue uselessly. */
           if (feof(stdin) || ferror(stdin)) {
                   (void)fprintf(stderr, "\n");
                   exit(EXIT_FAILURE);
           }
           for (;;) {
                   if (dflt)
                           (void)fprintf(stderr, "Terminal type? [%s] ", dflt);
                   else
                           (void)fprintf(stderr, "Terminal type? ");
                   (void)fflush(stderr);
   
                   if (fgets(answer, sizeof(answer), stdin) == 0) {
                           if (dflt == 0) {
                                   (void)fprintf(stderr, "\n");
                                   exit(EXIT_FAILURE);
                           }
                           return (dflt);
                   }
   
                   if ((p = strchr(answer, '\n')) != 0)
                           *p = '\0';
                   if (answer[0])
                           return (answer);
                   if (dflt != 0)
                           return (dflt);
           }
   }
   
   /**************************************************************************
    *
    * Mapping logic begins here
    *
    **************************************************************************/
   
   /* Baud rate conditionals for mapping. */
   #define GT              0x01
   #define EQ              0x02
   #define LT              0x04
   #define NOT             0x08
   #define GE              (GT | EQ)
   #define LE              (LT | EQ)
   
   typedef struct map {
           struct map *next;       /* Linked list of maps. */
           const char *porttype;   /* Port type, or "" for any. */
           const char *type;       /* Terminal type to select. */
           int conditional;        /* Baud rate conditionals bitmask. */
           speed_t speed;          /* Baud rate to compare against. */
   } MAP;
   
   static MAP *cur, *maplist;
   
   typedef struct speeds {
           const char *string;
           int     speed;
   } SPEEDS;
   
   static const SPEEDS speeds[] = {
           { "0",          B0 },
           { "50",         B50 },
           { "75",         B75 },
           { "110",        B110 },
           { "134",        B134 },
           { "134.5",      B134 },
           { "150",        B150 },
           { "200",        B200 },
           { "300",        B300 },
           { "600",        B600 },
           { "1200",       B1200 },
           { "1800",       B1800 },
           { "2400",       B2400 },
           { "4800",       B4800 },
           { "9600",       B9600 },
           { "19200",      B19200 },
           { "38400",      B38400 },
           { "19200",      B19200 },
           { "38400",      B38400 },
   #ifdef B19200
           { "19200",      B19200 },
   #else
   #ifdef EXTA
           { "19200",      EXTA },
   #endif
   #endif
   #ifdef B38400
           { "38400",      B38400 },
   #else
   #ifdef EXTB
           { "38400",      EXTB },
   #endif
   #endif
   #ifdef B57600
           { "57600",      B57600 },
   #endif
   #ifdef B115200
           { "115200",     B115200 },
   #endif
   #ifdef B230400
           { "230400",     B230400 },
   #endif
   #ifdef B460800
           { "460800",     B460800 },
   #endif
           { (char *)0,    0 }
   };
   
   static int
   tbaudrate(char *rate)
   {
           const SPEEDS *sp;
           int found = FALSE;
   
           /* The baudrate number can be preceded by a 'B', which is ignored. */
           if (*rate == 'B')
                   ++rate;
   
           for (sp = speeds; sp->string; ++sp) {
                   if (!CaselessCmp(rate, sp->string)) {
                           found = TRUE;
                           break;
                   }
           }
           if (!found)
                   err("unknown baud rate %s", rate);
           return (sp->speed);
   }
   
   /*
    * Syntax for -m:
    * [port-type][test baudrate]:terminal-type
    * The baud rate tests are: >, <, @, =, !
    */
   static void
   add_mapping(const char *port, char *arg)
   {
           MAP *mapp;
           char *copy, *p;
           const char *termp;
           char *base = 0;
   
           copy = strdup(arg);
           mapp = malloc((u_int)sizeof(MAP));
           if (copy == 0 || mapp == 0)
                   failed("malloc");
           mapp->next = 0;
           if (maplist == 0)
                   cur = maplist = mapp;
           else {
                   cur->next = mapp;
                   cur =  mapp;
           }
   
           mapp->porttype = arg;
           mapp->conditional = 0;
   
           arg = strpbrk(arg, "><@=!:");
   
           if (arg == 0) {                 /* [?]term */
                   mapp->type = mapp->porttype;
                   mapp->porttype = 0;
                   goto done;
           }
   
           if (arg == mapp->porttype)              /* [><@=! baud]:term */
                   termp = mapp->porttype = 0;
           else
                   termp = base = arg;
   
           for (;; ++arg)                          /* Optional conditionals. */
                   switch(*arg) {
                   case '<':
                           if (mapp->conditional & GT)
                                   goto badmopt;
                           mapp->conditional |= LT;
                           break;
                   case '>':
                           if (mapp->conditional & LT)
                                   goto badmopt;
                           mapp->conditional |= GT;
                           break;
                   case '@':
                   case '=':                       /* Not documented. */
                           mapp->conditional |= EQ;
                           break;
                   case '!':
                           mapp->conditional |= NOT;
                           break;
                   default:
                           goto next;
                   }
   
   next:   if (*arg == ':') {
                   if (mapp->conditional)
                           goto badmopt;
                   ++arg;
           } else {                                /* Optional baudrate. */
                   arg = strchr(p = arg, ':');
                   if (arg == 0)
                           goto badmopt;
                   *arg++ = '\0';
                   mapp->speed = tbaudrate(p);
           }
   
           if (arg == (char *)0)           /* Non-optional type. */
                   goto badmopt;
   
           mapp->type = arg;
   
           /* Terminate porttype, if specified. */
           if (termp != 0)
                   *base = '\0';
   
           /* If a NOT conditional, reverse the test. */
           if (mapp->conditional & NOT)
                   mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
   
           /* If user specified a port with an option flag, set it. */
   done:   if (port) {
                   if (mapp->porttype)
   badmopt:                err("illegal -m option format: %s", copy);
                   mapp->porttype = port;
           }
   
   #ifdef MAPDEBUG
           (void)printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
           (void)printf("type: %s\n", mapp->type);
           (void)printf("conditional: ");
           p = "";
           if (mapp->conditional & GT) {
                   (void)printf("GT");
                   p = "/";
           }
           if (mapp->conditional & EQ) {
                   (void)printf("%sEQ", p);
                   p = "/";
           }
           if (mapp->conditional & LT)
                   (void)printf("%sLT", p);
           (void)printf("\nspeed: %d\n", mapp->speed);
   #endif
   }
   
   /*
    * Return the type of terminal to use for a port of type 'type', as specified
    * by the first applicable mapping in 'map'.  If no mappings apply, return
    * 'type'.
    */
   static const char *
   mapped(const char *type)
   {
           MAP *mapp;
           int match;
   
           for (mapp = maplist; mapp; mapp = mapp->next)
                   if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
                           switch (mapp->conditional) {
                           case 0:                 /* No test specified. */
                                   match = TRUE;
                                   break;
                           case EQ:
                                   match = (ospeed == mapp->speed);
                                   break;
                           case GE:
                                   match = (ospeed >= mapp->speed);
                                   break;
                           case GT:
                                   match = (ospeed > mapp->speed);
                                   break;
                           case LE:
                                   match = (ospeed <= mapp->speed);
                                   break;
                           case LT:
                                   match = (ospeed < mapp->speed);
                                   break;
                           default:
                                   match = FALSE;
                           }
                           if (match)
                                   return (mapp->type);
                   }
           /* No match found; return given type. */
           return (type);
   }
   
   /**************************************************************************
    *
    * Entry fetching
    *
    **************************************************************************/
   
   /*
    * Figure out what kind of terminal we're dealing with, and then read in
    * its termcap entry.
    */
   static const char *
   get_termcap_entry(char *userarg)
   {
           int rval, errret;
           char *p;
           const char *ttype;
   #if HAVE_GETTTYNAM
           struct ttyent *t;
   #else
           FILE *fp;
   #endif
           char *ttypath;
   
           if (userarg) {
                   ttype = userarg;
                   goto found;
           }
   
           /* Try the environment. */
           if ((ttype = getenv("TERM")) != 0)
                   goto map;
   
           if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
                   if ((p = strrchr(ttypath, '/')) != 0)
                           ++p;
                   else
                           p = ttypath;
   #if HAVE_GETTTYNAM
                   /*
                    * We have the 4.3BSD library call getttynam(3); that means
                    * there's an /etc/ttys to look up device-to-type mappings in.
                    * Try ttyname(3); check for dialup or other mapping.
                    */
                   if ((t = getttynam(p))) {
                           ttype = t->ty_type;
                           goto map;
                   }
   #else
                   if ((fp = fopen("/etc/ttytype", "r")) != 0
                    || (fp = fopen("/etc/ttys", "r")) != 0) {
                           char buffer[BUFSIZ];
                           char *s, *t, *d;
   
                           while (fgets(buffer, sizeof(buffer)-1, fp) != 0) {
                                   for (s = buffer, t = d = 0; *s; s++) {
                                           if (isspace(*s))
                                                   *s = '\0';
                                           else if (t == 0)
                                                   t = s;
                                           else if (d == 0 && s != buffer && s[-1] == '\0')
                                                   d = s;
                                   }
                                   if (t != 0 && d != 0 && !strcmp(d,p)) {
                                           ttype = strdup(t);
                                           fclose(fp);
                                           goto map;
                                   }
                           }
                           fclose(fp);
                   }
   #endif /* HAVE_GETTTYNAM */
           }
   
           /* If still undefined, use "unknown". */
           ttype = "unknown";
   
   map:    ttype = mapped(ttype);
   
           /*
            * If not a path, remove TERMCAP from the environment so we get a
            * real entry from /etc/termcap.  This prevents us from being fooled
            * by out of date stuff in the environment.
            */
   found:  if ((p = getenv("TERMCAP")) != 0 && *p != '/') {
                   /* 'unsetenv("TERMCAP")' is not portable.
                    * The 'environ' array is better.
                    */
                   int n;
                   for (n = 0; environ[n] != 0; n++) {
                           if (!strncmp("TERMCAP=", environ[n], 8)) {
                                   while ((environ[n] = environ[n+1]) != 0) {
                                           n++;
                                   }
                                   break;
                           }
                   }
           }
   
           /*
            * ttype now contains a pointer to the type of the terminal.
            * If the first character is '?', ask the user.
            */
           if (ttype[0] == '?') {
                   if (ttype[1] != '\0')
                           ttype = askuser(ttype + 1);
                   else
                           ttype = askuser(0);
           }
           /* Find the terminfo entry.  If it doesn't exist, ask the user. */
           while ((rval = setupterm(ttype, STDOUT_FILENO, &errret)) != OK) {
                   if (errret == 0) {
                           (void)fprintf(stderr, "tset: unknown terminal type %s\n",
                               ttype);
                           ttype = 0;
                   }
                   else {
                           (void)fprintf(stderr, "tset: can't initialize terminal\
                               type %s (error %d)\n", ttype, errret);
                           ttype = 0;
                   }
                   ttype = askuser(ttype);
           }
   #if BROKEN_LINKER
           tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
   #endif
           return (ttype);
   }
   
   /**************************************************************************
    *
    * Mode-setting logic
    *
    **************************************************************************/
   
   /* some BSD systems have these built in, some systems are missing
    * one or more definitions. The safest solution is to override.
    */
   #undef CEOF
   #undef CERASE
   #undef CINTR
   #undef CKILL
   #undef CLNEXT
   #undef CRPRNT
   #undef CQUIT
   #undef CSTART
   #undef CSTOP
   #undef CSUSP
   
   /* control-character defaults */
   #define CEOF    CTRL('D')
   #define CERASE  CTRL('H')
   #define CINTR   127             /* ^? */
   #define CKILL   CTRL('U')
   #define CLNEXT  CTRL('v')
   #define CRPRNT  CTRL('r')
   #define CQUIT   CTRL('\\')
   #define CSTART  CTRL('Q')
   #define CSTOP   CTRL('S')
   #define CSUSP   CTRL('Z')
   
   #define CHK(val, dft)   ((int)val <= 0 ? dft : val)
   
   static bool     set_tabs (void);
   
   /*
    * Reset the terminal mode bits to a sensible state.  Very useful after
    * a child program dies in raw mode.
    */
   static void
   reset_mode(void)
   {
   #ifdef TERMIOS
           tcgetattr(STDERR_FILENO, &mode);
   #else
           stty(STDERR_FILENO,&mode);
   #endif
   
   #ifdef TERMIOS
   #if defined(VDISCARD) && defined(CDISCARD)
           mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
   #endif
           mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
           mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
   #if defined(VFLUSH) && defined(CFLUSH)
           mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
   #endif
           mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
           mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
   #if defined(VLNEXT) && defined(CLNEXT)
           mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
   #endif
           mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
   #if defined(VREPRINT) && defined(CRPRNT)
           mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
   #endif
   #if defined(VSTART) && defined(CSTART)
           mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
   #endif
   #if defined(VSTOP) && defined(CSTOP)
           mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
   #endif
   #if defined(VSUSP) && defined(CSUSP)
           mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
   #endif
   #if defined(VWERASE) && defined(CWERASE)
           mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
   #endif
   
           mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
   #ifdef IUCLC
                             | IUCLC
   #endif
   #ifdef IXANY
                             | IXANY
   #endif
                             | IXOFF);
   
           mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
   #ifdef IMAXBEL
                            | IMAXBEL
   #endif
                            );
   
           mode.c_oflag &= ~(0
   #ifdef OLCUC
                             | OLCUC
   #endif
   #ifdef OCRNL
                             | OCRNL
   #endif
   #ifdef ONOCR
                             | ONOCR
   #endif
   #ifdef ONLRET
                             | ONLRET
   #endif
   #ifdef OFILL
                             | OFILL
   #endif
   #ifdef OFDEL
                             | OFDEL
   #endif
   #ifdef NLDLY
                             | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
   #endif
                             );
   
           mode.c_oflag |= (OPOST
   #ifdef ONLCR
                            | ONLCR
   #endif
                            );
   
           mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
           mode.c_cflag |= (CS8 | CREAD);
           mode.c_lflag &= ~(ECHONL | NOFLSH
   #ifdef TOSTOP
                             | TOSTOP
   #endif
   #ifdef ECHOPTR
                             | ECHOPRT
   #endif
   #ifdef XCASE
                             | XCASE
   #endif
                             );
   
           mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
   #ifdef ECHOCTL
                            | ECHOCTL
   #endif
   #ifdef ECHOKE
                            | ECHOKE
   #endif
                            );
   #endif
   
   #ifdef TERMIOS
           tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
   #else
           stty(STDERR_FILENO, &mode);
   #endif
   }
   
   /*
    * Returns a "good" value for the erase character.  This is loosely based on
    * the BSD4.4 logic.
    */
   static int
   default_erase(void)
   {
           int result;
   
           if (over_strike
            && key_backspace != 0
            && strlen(key_backspace) == 1)
                   result = key_backspace[0];
           else
                   result = CERASE;
   
           return result;
   }
   
   /*
    * Update the values of the erase, interrupt, and kill characters in 'mode'.
    *
    * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
    * characters if they're unset, or if we specify them as options.  This differs
    * from BSD 4.4 tset, which always sets erase.
    */
   static void
   set_control_chars(void)
   {
   #ifdef TERMIOS
           if (mode.c_cc[VERASE] == 0 || terasechar >= 0)
                   mode.c_cc[VERASE] = terasechar >= 0 ? terasechar : default_erase();
   
           if (mode.c_cc[VINTR] == 0 || intrchar >= 0)
                    mode.c_cc[VINTR] = intrchar >= 0 ? intrchar : CINTR;
   
           if (mode.c_cc[VKILL] == 0 || tkillchar >= 0)
                   mode.c_cc[VKILL] = tkillchar >= 0 ? tkillchar : CKILL;
   #endif
   }
   
   /*
    * Set up various conversions in 'mode', including parity, tabs, returns,
    * echo, and case, according to the termcap entry.  If the program we're
    * running was named with a leading upper-case character, map external
    * uppercase to internal lowercase.
    */
   static void
   set_conversions(void)
   {
   #ifdef __OBSOLETE__
           /*
            * Conversion logic for some *really* ancient terminal glitches,
            * not supported in terminfo.  Left here for succeeding generations
            * to marvel at.
            */
           if (tgetflag("UC")) {
   #ifdef IUCLC
                   mode.c_iflag |= IUCLC;
                   mode.c_oflag |= OLCUC;
   #endif
           } else if (tgetflag("LC")) {
   #ifdef IUCLC
                   mode.c_iflag &= ~IUCLC;
                   mode.c_oflag &= ~OLCUC;
   #endif
           }
           mode.c_iflag &= ~(PARMRK | INPCK);
           mode.c_lflag |= ICANON;
           if (tgetflag("EP")) {
                   mode.c_cflag |= PARENB;
                   mode.c_cflag &= ~PARODD;
           }
           if (tgetflag("OP")) {
                   mode.c_cflag |= PARENB;
                   mode.c_cflag |= PARODD;
           }
   #endif /* __OBSOLETE__ */
   
   #ifdef TERMIOS
   #ifdef ONLCR
           mode.c_oflag |= ONLCR;
   #endif
           mode.c_iflag |= ICRNL;
           mode.c_lflag |= ECHO;
   #ifdef OXTABS
           mode.c_oflag |= OXTABS;
   #endif /* OXTABS */
   
           /* test used to be tgetflag("NL") */
           if (newline != (char *)0 && newline[0] == '\n' && !newline[1]) {
                   /* Newline, not linefeed. */
   #ifdef ONLCR
                   mode.c_oflag &= ~ONLCR;
   #endif
                   mode.c_iflag &= ~ICRNL;
           }
   #ifdef __OBSOLETE__
           if (tgetflag("HD"))                     /* Half duplex. */
                   mode.c_lflag &= ~ECHO;
   #endif /* __OBSOLETE__ */
   #ifdef OXTABS
           /* test used to be tgetflag("pt") */
           if (has_hardware_tabs)                  /* Print tabs. */
                   mode.c_oflag &= ~OXTABS;
   #endif /* OXTABS */
           mode.c_lflag |= (ECHOE | ECHOK);
   #endif
   }
   
   /* Output startup string. */
   static void
   set_init(void)
   {
           char    *p;
           bool settle;
   
   #ifdef __OBSOLETE__
           if (pad_char != (char *)0)              /* Get/set pad character. */
                   PC = pad_char[0];
   #endif /* OBSOLETE */
   
   #ifdef TAB3
           if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
                   oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
                   tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
           }
   #endif
           settle = set_tabs();
   
           if (isreset) {
                   if ((p = reset_1string) != 0) {
                           tputs(p, 0, outc);
                           settle = TRUE;
                   }
                   if ((p = reset_2string) != 0) {
                           tputs(p, 0, outc);
                           settle = TRUE;
                   }
                   /* What about rf, rs3, as per terminfo man page? */
                   /* also might be nice to send rmacs, rmul, rmm */
                   if ((p = reset_file) != 0
                    || (p = init_file) != 0) {
                           cat(p);
                           settle = TRUE;
                   }
           }
   
           if (settle) {
                   (void)putc('\r', stderr);
                   (void)fflush(stderr);
                   (void)napms(1000);      /* Settle the terminal. */
           }
   }
   
   /*
    * Set the hardware tabs on the terminal, using the ct (clear all tabs),
    * st (set one tab) and ch (horizontal cursor addressing) capabilities.
    * This is done before if and is, so they can patch in case we blow this.
    * Return TRUE if we set any tab stops, FALSE if not.
    */
   static bool
   set_tabs()
   {
           if (set_tab && clear_all_tabs) {
                   int c;
   
                   (void)putc('\r', stderr);       /* Force to left margin. */
                   tputs(clear_all_tabs, 0, outc);
   
                   for (c = 8; c < tcolumns; c += 8) {
                           /* Get to the right column.  In BSD tset, this
                            * used to try a bunch of half-clever things
                            * with cup and hpa, for an average saving of
                            * somewhat less than two character times per
                            * tab stop, less that .01 sec at 2400cps. We
                            * lost all this cruft because it seemed to be
                            * introducing some odd bugs.
                            * ----------12345678----------- */
                           (void)fputs("        ", stderr);
                           tputs(set_tab, 0, outc);
                   }
                   putc('\r', stderr);
                   return (TRUE);
           }
           return (FALSE);
   }
   
   /**************************************************************************
    *
    * Main sequence
    *
    **************************************************************************/
   
   /*
    * Tell the user if a control key has been changed from the default value.
    */
   static void
   report(const char *name, int which, u_int def)
   {
   #ifdef TERMIOS
           u_int older, newer;
           char *p;
   
           newer = mode.c_cc[which];
           older = oldmode.c_cc[which];
   
           if (older == newer && older == def)
                   return;
   
           (void)fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
   
           /*
            * Check 'delete' before 'backspace', since the key_backspace value
            * is ambiguous.
            */
           if (newer == 0177)
                   (void)fprintf(stderr, "delete.\n");
           else if ((p = key_backspace) != 0
            && newer == (u_int)p[0]
            && p[1] == '\0')
                   (void)fprintf(stderr, "backspace.\n");
           else if (newer < 040) {
                   newer ^= 0100;
                   (void)fprintf(stderr, "control-%c (^%c).\n", newer, newer);
           } else
                   (void)fprintf(stderr, "%c.\n", newer);
   #endif
   }
   
   /*
    * Convert the obsolete argument forms into something that getopt can handle.
    * This means that -e, -i and -k get default arguments supplied for them.
    */
   static void
   obsolete(char **argv)
   {
           for (; *argv; ++argv) {
                   char *parm = argv[0];
   
                   if (parm[0] == '-' && parm[1] == '\0')
                   {
                       argv[0] = strdup("-q");
                       continue;
                   }
   
                   if ((parm[0] != '-')
                    || (argv[1] && argv[1][0] != '-')
                    || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
                    || (parm[2] != '\0'))
                           continue;
                   switch(argv[0][1]) {
                   case 'e':
                           argv[0] = strdup("-e^H");
                           break;
                   case 'i':
                           argv[0] = strdup("-i^C");
                           break;
                   case 'k':
                           argv[0] = strdup("-k^U");
                           break;
                   }
           }
   }
   
   static void
   usage(const char* pname)
   {
           (void)fprintf(stderr,
   "usage: %s [-IQrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n", pname);
           exit(EXIT_FAILURE);
   }
   
   static char arg_to_char(void)
   {
           return (optarg[0] == '^' && optarg[1] != '\0')
                   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
                   : optarg[0];
   }
   
 int  int
 main(argc, argv)  main(int argc, char **argv)
         int argc;  
         char *argv[];  
 {  {
 #ifdef TIOCGWINSZ  #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
         struct winsize win;          struct winsize win;
 #endif  #endif
         int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper;          int ch, noinit, noset, quiet, Sflag, sflag, showterm;
         char savech, *p, *t, *tcapbuf, *ttype;          const char *p, *t;
           const char *ttype;
   #ifdef __OpenBSD__
           char tcapbuf[1024];
           int tcgetent(char *, const char *);
           void wrtermcap (char *);
   #endif
   
   #ifdef TERMIOS
         if (tcgetattr(STDERR_FILENO, &mode) < 0)          if (tcgetattr(STDERR_FILENO, &mode) < 0)
                 err(1, "standard error");                  failed("standard error");
   
         oldmode = mode;          oldmode = mode;
         ospeed = cfgetospeed(&mode);          ospeed = cfgetospeed(&mode);
   #else
           if (gtty(STDERR_FILENO, &mode) < 0)
                   failed("standard error");
   
         if (p = strrchr(*argv, '/'))          oldmode = mode;
           ospeed = mode.sg_ospeed;
   #endif
   
           if ((p = strrchr(*argv, '/')) != 0)
                 ++p;                  ++p;
         else          else
                 p = *argv;                  p = *argv;
         usingupper = isupper(*p);          if (!CaselessCmp(p, "reset")) {
         if (!strcasecmp(p, "reset")) {  
                 isreset = 1;                  isreset = 1;
                 reset_mode();                  reset_mode();
         }          }
   
         obsolete(argv);          obsolete(argv);
         noinit = noset = quiet = Sflag = sflag = showterm = 0;          noinit = noset = quiet = Sflag = sflag = showterm = 0;
         while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != -1) {          while ((ch = getopt(argc, argv, "a:d:e:Ii:k:m:np:qQSrs")) != EOF) {
                 switch (ch) {                  switch (ch) {
                 case '-':               /* display term only */                  case 'q':               /* display term only */
                         noset = 1;                          noset = 1;
                         break;                          break;
                 case 'a':               /* OBSOLETE: map identifier to type */                  case 'a':               /* OBSOLETE: map identifier to type */
Line 112 
Line 1099 
                         add_mapping("dialup", optarg);                          add_mapping("dialup", optarg);
                         break;                          break;
                 case 'e':               /* erase character */                  case 'e':               /* erase character */
                         erasechar = optarg[0] == '^' && optarg[1] != '\0' ?                          terasechar = arg_to_char();
                             optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :  
                             optarg[0];  
                         break;                          break;
                 case 'I':               /* no initialization strings */                  case 'I':               /* no initialization strings */
                         noinit = 1;                          noinit = 1;
                         break;                          break;
                 case 'i':               /* interrupt character */                  case 'i':               /* interrupt character */
                         intrchar = optarg[0] == '^' && optarg[1] != '\0' ?                          intrchar = arg_to_char();
                             optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :  
                             optarg[0];  
                         break;                          break;
                 case 'k':               /* kill character */                  case 'k':               /* kill character */
                         killchar = optarg[0] == '^' && optarg[1] != '\0' ?                          tkillchar = arg_to_char();
                             optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :  
                             optarg[0];  
                         break;                          break;
                 case 'm':               /* map identifier to type */                  case 'm':               /* map identifier to type */
                         add_mapping(NULL, optarg);                          add_mapping(0, optarg);
                         break;                          break;
                 case 'n':               /* OBSOLETE: set new tty driver */                  case 'n':               /* OBSOLETE: set new tty driver */
                         break;                          break;
Line 138 
Line 1119 
                         add_mapping("plugboard", optarg);                          add_mapping("plugboard", optarg);
                         break;                          break;
                 case 'Q':               /* don't output control key settings */                  case 'Q':               /* don't output control key settings */
                         quiet = 1;  
                         break;                          break;
                 case 'S':               /* output TERM/TERMCAP strings */                          quiet = 1;
                   case 'S':               /* OBSOLETE: output TERM & TERMCAP */
                         Sflag = 1;                          Sflag = 1;
                         break;                          break;
                 case 'r':               /* display term on stderr */                  case 'r':               /* display term on stderr */
                         showterm = 1;                          showterm = 1;
                         break;                          break;
                 case 's':               /* output TERM/TERMCAP strings */                  case 's':               /* output TERM set command */
                         sflag = 1;                          sflag = 1;
                         break;                          break;
                 case '?':                  case '?':
                 default:                  default:
                         usage();                          usage(*argv);
                 }                  }
         }          }
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
   
         if (argc > 1)          if (argc > 1)
                 usage();                  usage(*argv);
   
         ttype = get_termcap_entry(*argv, &tcapbuf);          ttype = get_termcap_entry(*argv);
   #ifdef __OpenBSD__
           if (tcgetent(tcapbuf, ttype) < 0)
                   tcapbuf[0] = '\0';
   #endif
   
         if (!noset) {          if (!noset) {
                 columns = tgetnum("co");                  tcolumns = columns;
                 lines = tgetnum("li");                  tlines = lines;
   
 #ifdef TIOCGWINSZ  #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
                 /* Set window size */                  /* Set window size */
                 (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);                  (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
                 if (win.ws_row == 0 && win.ws_col == 0 &&                  if (win.ws_row == 0 && win.ws_col == 0 &&
                     lines > 0 && columns > 0) {                      tlines > 0 && tcolumns > 0) {
                         win.ws_row = lines;                          win.ws_row = tlines;
                         win.ws_col = columns;                          win.ws_col = tcolumns;
                         (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);                          (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
                 }                  }
 #endif  #endif
                 set_control_chars();                  set_control_chars();
                 set_conversions(usingupper);                  set_conversions();
   
                 if (!noinit)                  if (!noinit)
                         set_init();                          set_init();
   
                 /* Set the modes if they've changed. */                  /* Set the modes if they've changed. */
                 if (memcmp(&mode, &oldmode, sizeof(mode)))                  if (memcmp(&mode, &oldmode, sizeof(mode)))
   #ifdef TERMIOS
                         tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);                          tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
   #else
                           stty(STDERR_FILENO, &mode);
   #endif
         }          }
   
         /* Get the terminal name from the entry. */          /* Get the terminal name from the entry. */
         p = tcapbuf;          ttype = _nc_first_name(cur_term->type.term_names);
         if (p != NULL && *p != ':') {  
                 t = p;  
                 if (p = strpbrk(p, "|:")) {  
                         savech = *p;  
                         *p = '\0';  
                         if ((ttype = strdup(t)) == NULL)  
                                 err(1, "strdup");  
                         *p = savech;  
                 }  
         }  
   
         if (noset)          if (noset)
                 (void)printf("%s\n", ttype);                  (void)printf("%s\n", ttype);
Line 211 
Line 1190 
                  */                   */
                 if (!quiet) {                  if (!quiet) {
                         report("Erase", VERASE, CERASE);                          report("Erase", VERASE, CERASE);
                         report("Kill", VKILL, CKILL);                          report("Kill", VKILL, CINTR);
                         report("Interrupt", VINTR, CINTR);                          report("Interrupt", VINTR, CKILL);
                 }                  }
         }          }
   
   #ifdef __OpenBSD__
         if (Sflag) {          if (Sflag) {
                 (void)printf("%s ", ttype);                  if (tcapbuf[0]) {
                 if (tcapbuf)                          (void) printf("%s ", ttype);
                         wrtermcap(tcapbuf);                          wrtermcap(tcapbuf);
                   } else
                           err("No termcap entry for %s, only terminfo.", ttype);
         }          }
   #else
           if (Sflag)
                   err("The -S option is not supported under terminfo.");
   #endif /* __OpenBSD__ */
   
   #ifdef __OpenBSD__
         if (sflag) {          if (sflag) {
                 /*                  /*
                  * Figure out what shell we're using.  A hack, we look for an                   * Figure out what shell we're using.  A hack, we look for an
                  * environmental variable SHELL ending in "csh".                   * environmental variable SHELL ending in "csh".
                  */                   */
                 if ((p = getenv("SHELL")) &&                  if ((p = getenv("SHELL")) != 0
                     !strcmp(p + strlen(p) - 3, "csh")) {                   && !strcmp(p + strlen(p) - 3, "csh")) {
                         if (tcapbuf)                          if (tcapbuf[0])
                                 p = "set noglob histchars="";\nsetenv TERM %s;\nsetenv TERMCAP ";                                  p = "set noglob histchars="";\nsetenv TERM %s;\nsetenv TERMCAP ";
                         else                          else
                                 p = "set noglob histchars="";\nsetenv TERM %s;\n";                                  p = "set noglob histchars="";\nsetenv TERM %s;\n";
                         t = "unset noglob histchars;\n";                                  t = "unset noglob histchars;\n";
                 } else {                  } else {
                         if (tcapbuf) {                          if (tcapbuf) {
                                 p = "TERM=%s;\nTERMCAP=";                                  p = "TERM=%s;\nTERMCAP=";
                                 t = "export TERMCAP TERM;\n";                                  t = "export TERMCAP TERM;\n";
                         } else {                          } else {
                                 p = "TERM=%s;\n";                                  if (tcapbuf) {
                                 t = "export TERMCAP;\n";                                          p = "TERM=%s;\nTERMCAP=";
                                           t = "export TERMCAP TERM;\n";
                                   } else {
                                           p = "TERM=%s;\n";
                                           t = "export TERMCAP;\n";
                                   }
                         }                          }
                 }                  }
                 (void)printf(p, ttype);                  (void) printf(p, ttype);
                 if (tcapbuf) {                  if (tcapbuf[0]) {
                         putchar('\'');                          putchar('\'');
                         wrtermcap(tcapbuf);                          wrtermcap(tcapbuf);
                         fputs("';\n", stdout);                          fputs("';\n", stdout);
                 }                  }
                 (void)printf(t);  
         }          }
   #else
         exit(0);          if (sflag) {
 }                  /*
                    * Figure out what shell we're using.  A hack, we look for an
 /*                   * environmental variable SHELL ending in "csh".
  * Tell the user if a control key has been changed from the default value.                   */
  */                  if ((p = getenv("SHELL")) != 0
 void                   && !strcmp(p + strlen(p) - 3, "csh"))
 report(name, which, def)                          p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
         char *name;                  else
         int which;                          p = "TERM=%s;\n";
         u_int def;                  (void) printf(p, ttype);
 {  
         u_int old, new;  
         char *bp, buf[1024];  
   
         new = mode.c_cc[which];  
         old = oldmode.c_cc[which];  
   
         if (old == new && old == def)  
                 return;  
   
         (void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");  
   
         bp = buf;  
         if (tgetstr("kb", &bp) && new == buf[0] && buf[1] == '\0')  
                 (void)fprintf(stderr, "backspace.\n");  
         else if (new == 0177)  
                 (void)fprintf(stderr, "delete.\n");  
         else if (new < 040) {  
                 new ^= 0100;  
                 (void)fprintf(stderr, "control-%c (^%c).\n", new, new);  
         } else  
                 (void)fprintf(stderr, "%c.\n", new);  
 }  
   
 /*  
  * Convert the obsolete argument form into something that getopt can handle.  
  * This means that -e, -i and -k get default arguments supplied for them.  
  */  
 void  
 obsolete(argv)  
         char *argv[];  
 {  
         for (; *argv; ++argv) {  
                 if (argv[0][0] != '-' || argv[1] && argv[1][0] != '-' ||  
                     argv[0][1] != 'e' && argv[0][1] != 'i' &&  
                     argv[0][1] != 'k' || argv[0][2] != '\0')  
                         continue;  
                 switch(argv[0][1]) {  
                 case 'e':  
                         argv[0] = "-e^H";  
                         break;  
                 case 'i':  
                         argv[0] = "-i^C";  
                         break;  
                 case 'k':  
                         argv[0] = "-k^U";  
                         break;  
                 }  
         }          }
 }  #endif /* __OpenBSD__ */
   
 void          return EXIT_SUCCESS;
 usage()  
 {  
         (void)fprintf(stderr,  
 "usage: tset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n");  
         exit(1);  
 }  }
   
   /* tset.c ends here */

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7