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

Annotation of src/usr.bin/tset/tset.c, Revision 1.43

1.43    ! tb          1: /*     $OpenBSD: tset.c,v 1.42 2021/06/22 18:32:24 tb Exp $    */
1.22      niklas      2:
1.7       millert     3: /****************************************************************************
1.35      nicm        4:  * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
1.7       millert     5:  *                                                                          *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a  *
                      7:  * copy of this software and associated documentation files (the            *
                      8:  * "Software"), to deal in the Software without restriction, including      *
                      9:  * without limitation the rights to use, copy, modify, merge, publish,      *
                     10:  * distribute, distribute with modifications, sublicense, and/or sell       *
                     11:  * copies of the Software, and to permit persons to whom the Software is    *
                     12:  * furnished to do so, subject to the following conditions:                 *
                     13:  *                                                                          *
                     14:  * The above copyright notice and this permission notice shall be included  *
                     15:  * in all copies or substantial portions of the Software.                   *
                     16:  *                                                                          *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
                     19:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
                     20:  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
                     21:  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
                     22:  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
                     23:  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
                     24:  *                                                                          *
                     25:  * Except as contained in this notice, the name(s) of the above copyright   *
                     26:  * holders shall not be used in advertising or otherwise to promote the     *
                     27:  * sale, use or other dealings in this Software without prior written       *
                     28:  * authorization.                                                           *
                     29:  ****************************************************************************/
                     30:
                     31: /****************************************************************************
                     32:  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
                     33:  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
1.35      nicm       34:  *     and: Thomas E. Dickey                        1996-on                 *
1.7       millert    35:  ****************************************************************************/
1.1       deraadt    36:
1.7       millert    37: /*
                     38:  * tset.c - terminal initialization utility
                     39:  *
                     40:  * This code was mostly swiped from 4.4BSD tset, with some obsolescent
                     41:  * cruft removed and substantial portions rewritten.  A Regents of the
                     42:  * University of California copyright applies to some portions of the
                     43:  * code, and is reproduced below:
                     44:  */
1.1       deraadt    45: /*-
                     46:  * Copyright (c) 1980, 1991, 1993
                     47:  *     The Regents of the University of California.  All rights reserved.
                     48:  *
                     49:  * Redistribution and use in source and binary forms, with or without
                     50:  * modification, are permitted provided that the following conditions
                     51:  * are met:
                     52:  * 1. Redistributions of source code must retain the above copyright
                     53:  *    notice, this list of conditions and the following disclaimer.
                     54:  * 2. Redistributions in binary form must reproduce the above copyright
                     55:  *    notice, this list of conditions and the following disclaimer in the
                     56:  *    documentation and/or other materials provided with the distribution.
1.26      millert    57:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    58:  *    may be used to endorse or promote products derived from this software
                     59:  *    without specific prior written permission.
                     60:  *
                     61:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     62:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     63:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     64:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     65:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     66:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     67:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     68:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     69:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     70:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     71:  * SUCH DAMAGE.
                     72:  */
                     73:
1.35      nicm       74: #define USE_LIBTINFO
1.7       millert    75: #define __INTERNAL_CAPS_VISIBLE        /* we need to see has_hardware_tabs */
                     76: #include <progs.priv.h>
                     77:
1.1       deraadt    78: #include <errno.h>
                     79: #include <stdio.h>
1.7       millert    80: #include <termcap.h>
                     81: #include <fcntl.h>
                     82:
                     83: #if HAVE_GETTTYNAM && HAVE_TTYENT_H
                     84: #include <ttyent.h>
                     85: #endif
                     86: #ifdef NeXT
                     87: char *ttyname(int fd);
                     88: #endif
                     89:
1.35      nicm       90: #if HAVE_SIZECHANGE
                     91: # if !defined(sun) || !TERMIOS
                     92: #  if HAVE_SYS_IOCTL_H
                     93: #   include <sys/ioctl.h>
                     94: #  endif
                     95: # endif
1.7       millert    96: #endif
                     97:
                     98: #if NEED_PTEM_H
                     99: /* they neglected to define struct winsize in termios.h -- it's only
                    100:    in termio.h */
1.35      nicm      101: #include <sys/stream.h>
                    102: #include <sys/ptem.h>
1.7       millert   103: #endif
                    104:
                    105: #include <dump_entry.h>
1.20      millert   106: #include <transform.h>
1.7       millert   107:
                    108: extern char **environ;
                    109:
                    110: #undef CTRL
                    111: #define CTRL(x)        ((x) & 0x1f)
                    112:
1.42      tb        113: const char *_nc_progname;
1.7       millert   114:
1.35      nicm      115: static TTY mode, oldmode, original;
                    116:
                    117: static bool opt_c;             /* set control-chars */
                    118: static bool opt_w;             /* set window-size */
1.7       millert   119:
1.35      nicm      120: static bool can_restore = FALSE;
1.20      millert   121: static bool isreset = FALSE;   /* invoked as reset */
1.16      millert   122: static int terasechar = -1;    /* new erase character */
                    123: static int intrchar = -1;      /* new interrupt character */
                    124: static int tkillchar = -1;     /* new kill character */
                    125: static int tlines, tcolumns;   /* window size */
1.7       millert   126:
1.35      nicm      127: #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
1.7       millert   128:
                    129: static int
1.16      millert   130: CaselessCmp(const char *a, const char *b)
                    131: {                              /* strcasecmp isn't portable */
                    132:     while (*a && *b) {
                    133:        int cmp = LOWERCASE(*a) - LOWERCASE(*b);
                    134:        if (cmp != 0)
                    135:            break;
                    136:        a++, b++;
                    137:     }
                    138:     return LOWERCASE(*a) - LOWERCASE(*b);
1.7       millert   139: }
                    140:
                    141: static void
1.35      nicm      142: exit_error(void)
                    143: {
                    144:     if (can_restore)
1.41      deraadt   145:        tcsetattr(STDERR_FILENO, TCSADRAIN, &original);
1.35      nicm      146:     (void) fprintf(stderr, "\n");
                    147:     fflush(stderr);
                    148:     ExitProgram(EXIT_FAILURE);
                    149:     /* NOTREACHED */
                    150: }
                    151:
                    152: static void
1.16      millert   153: err(const char *fmt,...)
1.7       millert   154: {
1.16      millert   155:     va_list ap;
                    156:     va_start(ap, fmt);
1.35      nicm      157:     (void) fprintf(stderr, "%s: ", _nc_progname);
1.16      millert   158:     (void) vfprintf(stderr, fmt, ap);
                    159:     va_end(ap);
1.35      nicm      160:     exit_error();
1.16      millert   161:     /* NOTREACHED */
1.7       millert   162: }
                    163:
                    164: static void
                    165: failed(const char *msg)
                    166: {
1.35      nicm      167:     fprintf(stderr, "%s: ", _nc_progname);
1.16      millert   168:     perror(msg);
1.35      nicm      169:     exit_error();
1.16      millert   170:     /* NOTREACHED */
1.7       millert   171: }
                    172:
                    173: static void
                    174: cat(char *file)
                    175: {
1.35      nicm      176:     FILE *fp;
                    177:     size_t nr;
1.16      millert   178:     char buf[BUFSIZ];
1.7       millert   179:
1.35      nicm      180:     if ((fp = fopen(file, "r")) == 0)
1.16      millert   181:        failed(file);
1.7       millert   182:
1.35      nicm      183:     while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
                    184:        if (fwrite(buf, sizeof(char), nr, stderr) != nr)
                    185:              failed("write to stderr");
                    186:     fclose(fp);
1.7       millert   187: }
                    188:
                    189: static int
                    190: outc(int c)
                    191: {
1.16      millert   192:     return putc(c, stderr);
1.7       millert   193: }
                    194:
                    195: /* Prompt the user for a terminal type. */
                    196: static const char *
                    197: askuser(const char *dflt)
                    198: {
1.16      millert   199:     static char answer[256];
1.7       millert   200:
1.16      millert   201:     /* We can get recalled; if so, don't continue uselessly. */
1.35      nicm      202:     clearerr(stdin);
1.16      millert   203:     if (feof(stdin) || ferror(stdin)) {
                    204:        (void) fprintf(stderr, "\n");
1.35      nicm      205:        exit_error();
                    206:        /* NOTREACHED */
1.16      millert   207:     }
                    208:     for (;;) {
                    209:        if (dflt)
                    210:            (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
                    211:        else
                    212:            (void) fprintf(stderr, "Terminal type? ");
                    213:        (void) fflush(stderr);
                    214:
1.28      cloder    215:        if (fgets(answer, sizeof(answer), stdin) == NULL) {
1.16      millert   216:            if (dflt == 0) {
1.35      nicm      217:                exit_error();
                    218:                /* NOTREACHED */
1.16      millert   219:            }
                    220:            return (dflt);
1.7       millert   221:        }
                    222:
1.30      gilles    223:        answer[strcspn(answer, "\n")] = '\0';
1.16      millert   224:        if (answer[0])
                    225:            return (answer);
                    226:        if (dflt != 0)
                    227:            return (dflt);
                    228:     }
1.7       millert   229: }
                    230:
                    231: /**************************************************************************
                    232:  *
                    233:  * Mapping logic begins here
                    234:  *
                    235:  **************************************************************************/
                    236:
                    237: /* Baud rate conditionals for mapping. */
                    238: #define        GT              0x01
                    239: #define        EQ              0x02
                    240: #define        LT              0x04
                    241: #define        NOT             0x08
                    242: #define        GE              (GT | EQ)
                    243: #define        LE              (LT | EQ)
                    244:
                    245: typedef struct map {
1.16      millert   246:     struct map *next;          /* Linked list of maps. */
                    247:     const char *porttype;      /* Port type, or "" for any. */
                    248:     const char *type;          /* Terminal type to select. */
                    249:     int conditional;           /* Baud rate conditionals bitmask. */
1.20      millert   250:     int speed;                 /* Baud rate to compare against. */
1.7       millert   251: } MAP;
                    252:
                    253: static MAP *cur, *maplist;
                    254:
                    255: typedef struct speeds {
1.16      millert   256:     const char *string;
                    257:     int speed;
1.7       millert   258: } SPEEDS;
                    259:
1.16      millert   260: static const SPEEDS speeds[] =
                    261: {
                    262:     {"0", B0},
                    263:     {"50", B50},
                    264:     {"75", B75},
                    265:     {"110", B110},
                    266:     {"134", B134},
                    267:     {"134.5", B134},
                    268:     {"150", B150},
                    269:     {"200", B200},
                    270:     {"300", B300},
                    271:     {"600", B600},
                    272:     {"1200", B1200},
                    273:     {"1800", B1800},
                    274:     {"2400", B2400},
                    275:     {"4800", B4800},
                    276:     {"9600", B9600},
1.19      millert   277:     /* sgttyb may define up to this point */
                    278: #ifdef B19200
1.16      millert   279:     {"19200", B19200},
1.19      millert   280: #endif
                    281: #ifdef B38400
1.16      millert   282:     {"38400", B38400},
1.19      millert   283: #endif
                    284: #ifdef B19200
1.16      millert   285:     {"19200", B19200},
1.19      millert   286: #endif
                    287: #ifdef B38400
1.16      millert   288:     {"38400", B38400},
1.19      millert   289: #endif
1.7       millert   290: #ifdef B19200
1.16      millert   291:     {"19200", B19200},
1.7       millert   292: #else
                    293: #ifdef EXTA
1.16      millert   294:     {"19200", EXTA},
1.7       millert   295: #endif
                    296: #endif
                    297: #ifdef B38400
1.16      millert   298:     {"38400", B38400},
1.7       millert   299: #else
                    300: #ifdef EXTB
1.16      millert   301:     {"38400", EXTB},
1.7       millert   302: #endif
                    303: #endif
                    304: #ifdef B57600
1.16      millert   305:     {"57600", B57600},
1.7       millert   306: #endif
                    307: #ifdef B115200
1.16      millert   308:     {"115200", B115200},
1.7       millert   309: #endif
                    310: #ifdef B230400
1.16      millert   311:     {"230400", B230400},
1.7       millert   312: #endif
                    313: #ifdef B460800
1.16      millert   314:     {"460800", B460800},
1.7       millert   315: #endif
1.16      millert   316:     {(char *) 0, 0}
1.7       millert   317: };
                    318:
                    319: static int
                    320: tbaudrate(char *rate)
                    321: {
1.16      millert   322:     const SPEEDS *sp;
                    323:     int found = FALSE;
1.7       millert   324:
1.16      millert   325:     /* The baudrate number can be preceded by a 'B', which is ignored. */
                    326:     if (*rate == 'B')
                    327:        ++rate;
                    328:
                    329:     for (sp = speeds; sp->string; ++sp) {
                    330:        if (!CaselessCmp(rate, sp->string)) {
                    331:            found = TRUE;
                    332:            break;
                    333:        }
                    334:     }
                    335:     if (!found)
                    336:        err("unknown baud rate %s", rate);
                    337:     return (sp->speed);
1.7       millert   338: }
                    339:
                    340: /*
                    341:  * Syntax for -m:
                    342:  * [port-type][test baudrate]:terminal-type
                    343:  * The baud rate tests are: >, <, @, =, !
                    344:  */
                    345: static void
                    346: add_mapping(const char *port, char *arg)
                    347: {
1.16      millert   348:     MAP *mapp;
                    349:     char *copy, *p;
                    350:     const char *termp;
                    351:     char *base = 0;
                    352:
                    353:     copy = strdup(arg);
1.37      deraadt   354:     mapp = malloc(sizeof(MAP));
1.16      millert   355:     if (copy == 0 || mapp == 0)
                    356:        failed("malloc");
                    357:     mapp->next = 0;
                    358:     if (maplist == 0)
                    359:        cur = maplist = mapp;
                    360:     else {
                    361:        cur->next = mapp;
                    362:        cur = mapp;
                    363:     }
                    364:
                    365:     mapp->porttype = arg;
                    366:     mapp->conditional = 0;
                    367:
                    368:     arg = strpbrk(arg, "><@=!:");
                    369:
                    370:     if (arg == 0) {            /* [?]term */
                    371:        mapp->type = mapp->porttype;
                    372:        mapp->porttype = 0;
                    373:        goto done;
                    374:     }
                    375:
                    376:     if (arg == mapp->porttype) /* [><@=! baud]:term */
                    377:        termp = mapp->porttype = 0;
                    378:     else
                    379:        termp = base = arg;
                    380:
1.17      millert   381:     for (;; ++arg) {           /* Optional conditionals. */
1.16      millert   382:        switch (*arg) {
                    383:        case '<':
                    384:            if (mapp->conditional & GT)
                    385:                goto badmopt;
                    386:            mapp->conditional |= LT;
                    387:            break;
                    388:        case '>':
                    389:            if (mapp->conditional & LT)
1.7       millert   390:                goto badmopt;
1.16      millert   391:            mapp->conditional |= GT;
                    392:            break;
                    393:        case '@':
                    394:        case '=':               /* Not documented. */
                    395:            mapp->conditional |= EQ;
                    396:            break;
                    397:        case '!':
                    398:            mapp->conditional |= NOT;
                    399:            break;
                    400:        default:
                    401:            goto next;
                    402:        }
1.17      millert   403:     }
1.16      millert   404:
1.17      millert   405:   next:
                    406:     if (*arg == ':') {
1.16      millert   407:        if (mapp->conditional)
                    408:            goto badmopt;
                    409:        ++arg;
                    410:     } else {                   /* Optional baudrate. */
                    411:        arg = strchr(p = arg, ':');
                    412:        if (arg == 0)
                    413:            goto badmopt;
                    414:        *arg++ = '\0';
                    415:        mapp->speed = tbaudrate(p);
                    416:     }
                    417:
                    418:     if (arg == (char *) 0)     /* Non-optional type. */
                    419:        goto badmopt;
                    420:
                    421:     mapp->type = arg;
                    422:
                    423:     /* Terminate porttype, if specified. */
                    424:     if (termp != 0)
                    425:        *base = '\0';
                    426:
                    427:     /* If a NOT conditional, reverse the test. */
                    428:     if (mapp->conditional & NOT)
                    429:        mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
                    430:
                    431:     /* If user specified a port with an option flag, set it. */
1.35      nicm      432:   done:
                    433:     if (port) {
                    434:        if (mapp->porttype) {
                    435:          badmopt:
                    436:            err("illegal -m option format: %s", copy);
                    437:        }
1.16      millert   438:        mapp->porttype = port;
                    439:     }
1.34      nicm      440:     free(copy);
1.7       millert   441: #ifdef MAPDEBUG
1.16      millert   442:     (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
                    443:     (void) printf("type: %s\n", mapp->type);
                    444:     (void) printf("conditional: ");
                    445:     p = "";
                    446:     if (mapp->conditional & GT) {
                    447:        (void) printf("GT");
                    448:        p = "/";
                    449:     }
                    450:     if (mapp->conditional & EQ) {
                    451:        (void) printf("%sEQ", p);
                    452:        p = "/";
                    453:     }
                    454:     if (mapp->conditional & LT)
                    455:        (void) printf("%sLT", p);
                    456:     (void) printf("\nspeed: %d\n", mapp->speed);
1.7       millert   457: #endif
                    458: }
                    459:
                    460: /*
                    461:  * Return the type of terminal to use for a port of type 'type', as specified
                    462:  * by the first applicable mapping in 'map'.  If no mappings apply, return
                    463:  * 'type'.
                    464:  */
                    465: static const char *
                    466: mapped(const char *type)
                    467: {
1.16      millert   468:     MAP *mapp;
                    469:     int match;
1.7       millert   470:
1.16      millert   471:     for (mapp = maplist; mapp; mapp = mapp->next)
                    472:        if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
                    473:            switch (mapp->conditional) {
                    474:            case 0:             /* No test specified. */
                    475:                match = TRUE;
                    476:                break;
                    477:            case EQ:
                    478:                match = (ospeed == mapp->speed);
                    479:                break;
                    480:            case GE:
                    481:                match = (ospeed >= mapp->speed);
                    482:                break;
                    483:            case GT:
                    484:                match = (ospeed > mapp->speed);
                    485:                break;
                    486:            case LE:
                    487:                match = (ospeed <= mapp->speed);
                    488:                break;
                    489:            case LT:
                    490:                match = (ospeed < mapp->speed);
                    491:                break;
                    492:            default:
                    493:                match = FALSE;
                    494:            }
                    495:            if (match)
                    496:                return (mapp->type);
                    497:        }
                    498:     /* No match found; return given type. */
                    499:     return (type);
1.7       millert   500: }
                    501:
                    502: /**************************************************************************
                    503:  *
                    504:  * Entry fetching
                    505:  *
                    506:  **************************************************************************/
                    507:
                    508: /*
                    509:  * Figure out what kind of terminal we're dealing with, and then read in
                    510:  * its termcap entry.
                    511:  */
                    512: static const char *
                    513: get_termcap_entry(char *userarg)
                    514: {
1.23      millert   515:     int errret;
1.16      millert   516:     char *p;
                    517:     const char *ttype;
1.7       millert   518: #if HAVE_GETTTYNAM
1.16      millert   519:     struct ttyent *t;
1.7       millert   520: #else
1.16      millert   521:     FILE *fp;
1.7       millert   522: #endif
1.16      millert   523:     char *ttypath;
1.7       millert   524:
1.16      millert   525:     if (userarg) {
                    526:        ttype = userarg;
                    527:        goto found;
                    528:     }
                    529:
                    530:     /* Try the environment. */
                    531:     if ((ttype = getenv("TERM")) != 0)
                    532:        goto map;
                    533:
                    534:     if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
1.20      millert   535:        p = _nc_basename(ttypath);
1.16      millert   536: #if HAVE_GETTTYNAM
                    537:        /*
                    538:         * We have the 4.3BSD library call getttynam(3); that means
                    539:         * there's an /etc/ttys to look up device-to-type mappings in.
                    540:         * Try ttyname(3); check for dialup or other mapping.
                    541:         */
                    542:        if ((t = getttynam(p))) {
                    543:            ttype = t->ty_type;
                    544:            goto map;
1.7       millert   545:        }
1.16      millert   546: #else
                    547:        if ((fp = fopen("/etc/ttytype", "r")) != 0
                    548:            || (fp = fopen("/etc/ttys", "r")) != 0) {
                    549:            char buffer[BUFSIZ];
                    550:            char *s, *t, *d;
                    551:
1.29      ray       552:            while (fgets(buffer, sizeof(buffer), fp) != NULL) {
1.16      millert   553:                for (s = buffer, t = d = 0; *s; s++) {
1.35      nicm      554:                    if (isspace(UChar(*s)))
1.16      millert   555:                        *s = '\0';
                    556:                    else if (t == 0)
                    557:                        t = s;
                    558:                    else if (d == 0 && s != buffer && s[-1] == '\0')
                    559:                        d = s;
1.7       millert   560:                }
1.16      millert   561:                if (t != 0 && d != 0 && !strcmp(d, p)) {
                    562:                    ttype = strdup(t);
                    563:                    fclose(fp);
                    564:                    goto map;
1.7       millert   565:                }
1.16      millert   566:            }
                    567:            fclose(fp);
                    568:        }
1.7       millert   569: #endif /* HAVE_GETTTYNAM */
1.16      millert   570:     }
1.7       millert   571:
1.16      millert   572:     /* If still undefined, use "unknown". */
                    573:     ttype = "unknown";
1.7       millert   574:
1.16      millert   575:   map:ttype = mapped(ttype);
1.7       millert   576:
1.16      millert   577:     /*
                    578:      * If not a path, remove TERMCAP from the environment so we get a
                    579:      * real entry from /etc/termcap.  This prevents us from being fooled
                    580:      * by out of date stuff in the environment.
                    581:      */
1.35      nicm      582:   found:if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
1.16      millert   583:        /* 'unsetenv("TERMCAP")' is not portable.
                    584:         * The 'environ' array is better.
1.7       millert   585:         */
1.16      millert   586:        int n;
                    587:        for (n = 0; environ[n] != 0; n++) {
                    588:            if (!strncmp("TERMCAP=", environ[n], 8)) {
                    589:                while ((environ[n] = environ[n + 1]) != 0) {
                    590:                    n++;
1.7       millert   591:                }
1.16      millert   592:                break;
                    593:            }
1.7       millert   594:        }
1.16      millert   595:     }
1.7       millert   596:
1.16      millert   597:     /*
                    598:      * ttype now contains a pointer to the type of the terminal.
                    599:      * If the first character is '?', ask the user.
                    600:      */
                    601:     if (ttype[0] == '?') {
                    602:        if (ttype[1] != '\0')
                    603:            ttype = askuser(ttype + 1);
                    604:        else
                    605:            ttype = askuser(0);
                    606:     }
                    607:     /* Find the terminfo entry.  If it doesn't exist, ask the user. */
1.23      millert   608:     while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
                    609:           != OK) {
1.16      millert   610:        if (errret == 0) {
1.35      nicm      611:            (void) fprintf(stderr, "%s: unknown terminal type %s\n",
                    612:                           _nc_progname, ttype);
1.16      millert   613:            ttype = 0;
                    614:        } else {
                    615:            (void) fprintf(stderr,
1.35      nicm      616:                           "%s: can't initialize terminal type %s (error %d)\n",
                    617:                           _nc_progname, ttype, errret);
1.16      millert   618:            ttype = 0;
1.7       millert   619:        }
1.16      millert   620:        ttype = askuser(ttype);
                    621:     }
1.7       millert   622: #if BROKEN_LINKER
1.16      millert   623:     tgetflag("am");            /* force lib_termcap.o to be linked for 'ospeed' */
1.7       millert   624: #endif
1.16      millert   625:     return (ttype);
1.7       millert   626: }
                    627:
                    628: /**************************************************************************
                    629:  *
                    630:  * Mode-setting logic
                    631:  *
                    632:  **************************************************************************/
                    633:
                    634: /* some BSD systems have these built in, some systems are missing
1.35      nicm      635:  * one or more definitions. The safest solution is to override unless the
                    636:  * commonly-altered ones are defined.
1.7       millert   637:  */
1.35      nicm      638: #if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
1.7       millert   639: #undef CEOF
                    640: #undef CERASE
                    641: #undef CINTR
                    642: #undef CKILL
                    643: #undef CLNEXT
                    644: #undef CRPRNT
                    645: #undef CQUIT
                    646: #undef CSTART
                    647: #undef CSTOP
                    648: #undef CSUSP
1.35      nicm      649: #endif
1.7       millert   650:
                    651: /* control-character defaults */
1.35      nicm      652: #ifndef CEOF
1.7       millert   653: #define CEOF   CTRL('D')
1.35      nicm      654: #endif
                    655: #ifndef CERASE
1.7       millert   656: #define CERASE CTRL('H')
1.35      nicm      657: #endif
                    658: #ifndef CINTR
1.7       millert   659: #define CINTR  127             /* ^? */
1.35      nicm      660: #endif
                    661: #ifndef CKILL
1.7       millert   662: #define CKILL  CTRL('U')
1.35      nicm      663: #endif
                    664: #ifndef CLNEXT
1.7       millert   665: #define CLNEXT  CTRL('v')
1.35      nicm      666: #endif
                    667: #ifndef CRPRNT
1.7       millert   668: #define CRPRNT  CTRL('r')
1.35      nicm      669: #endif
                    670: #ifndef CQUIT
1.7       millert   671: #define CQUIT  CTRL('\\')
1.35      nicm      672: #endif
                    673: #ifndef CSTART
1.7       millert   674: #define CSTART CTRL('Q')
1.35      nicm      675: #endif
                    676: #ifndef CSTOP
1.7       millert   677: #define CSTOP  CTRL('S')
1.35      nicm      678: #endif
                    679: #ifndef CSUSP
1.7       millert   680: #define CSUSP  CTRL('Z')
1.35      nicm      681: #endif
1.7       millert   682:
1.35      nicm      683: #if defined(_POSIX_VDISABLE)
                    684: #define DISABLED(val)   (((_POSIX_VDISABLE != -1) \
                    685:                       && ((val) == _POSIX_VDISABLE)) \
                    686:                      || ((val) <= 0))
                    687: #else
                    688: #define DISABLED(val)   ((int)(val) <= 0)
                    689: #endif
                    690:
                    691: #define CHK(val, dft)   (DISABLED(val) ? dft : val)
1.7       millert   692:
1.16      millert   693: static bool set_tabs(void);
1.7       millert   694:
                    695: /*
                    696:  * Reset the terminal mode bits to a sensible state.  Very useful after
                    697:  * a child program dies in raw mode.
                    698:  */
                    699: static void
                    700: reset_mode(void)
                    701: {
                    702: #ifdef TERMIOS
1.16      millert   703:     tcgetattr(STDERR_FILENO, &mode);
1.7       millert   704: #else
1.16      millert   705:     stty(STDERR_FILENO, &mode);
1.7       millert   706: #endif
                    707:
                    708: #ifdef TERMIOS
                    709: #if defined(VDISCARD) && defined(CDISCARD)
1.16      millert   710:     mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
1.7       millert   711: #endif
1.16      millert   712:     mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
                    713:     mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
1.7       millert   714: #if defined(VFLUSH) && defined(CFLUSH)
1.16      millert   715:     mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
1.7       millert   716: #endif
1.16      millert   717:     mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
                    718:     mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
1.7       millert   719: #if defined(VLNEXT) && defined(CLNEXT)
1.16      millert   720:     mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
1.7       millert   721: #endif
1.16      millert   722:     mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
1.7       millert   723: #if defined(VREPRINT) && defined(CRPRNT)
1.16      millert   724:     mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
1.7       millert   725: #endif
                    726: #if defined(VSTART) && defined(CSTART)
1.16      millert   727:     mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
1.7       millert   728: #endif
                    729: #if defined(VSTOP) && defined(CSTOP)
1.16      millert   730:     mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
1.7       millert   731: #endif
                    732: #if defined(VSUSP) && defined(CSUSP)
1.16      millert   733:     mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
1.7       millert   734: #endif
                    735: #if defined(VWERASE) && defined(CWERASE)
1.16      millert   736:     mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
1.7       millert   737: #endif
                    738:
1.16      millert   739:     mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
1.7       millert   740: #ifdef IUCLC
1.20      millert   741:                      | IUCLC
1.7       millert   742: #endif
                    743: #ifdef IXANY
1.20      millert   744:                      | IXANY
1.7       millert   745: #endif
1.20      millert   746:                      | IXOFF);
1.7       millert   747:
1.16      millert   748:     mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
1.7       millert   749: #ifdef IMAXBEL
1.20      millert   750:                     | IMAXBEL
1.7       millert   751: #endif
1.16      millert   752:        );
1.7       millert   753:
1.16      millert   754:     mode.c_oflag &= ~(0
1.7       millert   755: #ifdef OLCUC
1.20      millert   756:                      | OLCUC
1.7       millert   757: #endif
                    758: #ifdef OCRNL
1.20      millert   759:                      | OCRNL
1.7       millert   760: #endif
                    761: #ifdef ONOCR
1.20      millert   762:                      | ONOCR
1.7       millert   763: #endif
                    764: #ifdef ONLRET
1.20      millert   765:                      | ONLRET
1.7       millert   766: #endif
                    767: #ifdef OFILL
1.20      millert   768:                      | OFILL
1.7       millert   769: #endif
                    770: #ifdef OFDEL
1.20      millert   771:                      | OFDEL
1.7       millert   772: #endif
                    773: #ifdef NLDLY
1.35      nicm      774:                      | NLDLY
                    775: #endif
                    776: #ifdef CRDLY
                    777:                      | CRDLY
                    778: #endif
                    779: #ifdef TABDLY
                    780:                      | TABDLY
                    781: #endif
                    782: #ifdef BSDLY
                    783:                      | BSDLY
                    784: #endif
                    785: #ifdef VTDLY
                    786:                      | VTDLY
                    787: #endif
                    788: #ifdef FFDLY
                    789:                      | FFDLY
1.7       millert   790: #endif
1.16      millert   791:        );
1.7       millert   792:
1.16      millert   793:     mode.c_oflag |= (OPOST
1.7       millert   794: #ifdef ONLCR
1.20      millert   795:                     | ONLCR
1.7       millert   796: #endif
1.16      millert   797:        );
1.7       millert   798:
1.16      millert   799:     mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
                    800:     mode.c_cflag |= (CS8 | CREAD);
                    801:     mode.c_lflag &= ~(ECHONL | NOFLSH
1.7       millert   802: #ifdef TOSTOP
1.20      millert   803:                      | TOSTOP
1.7       millert   804: #endif
                    805: #ifdef ECHOPTR
1.20      millert   806:                      | ECHOPRT
1.7       millert   807: #endif
                    808: #ifdef XCASE
1.20      millert   809:                      | XCASE
1.7       millert   810: #endif
1.16      millert   811:        );
1.7       millert   812:
1.16      millert   813:     mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
1.7       millert   814: #ifdef ECHOCTL
1.20      millert   815:                     | ECHOCTL
1.7       millert   816: #endif
                    817: #ifdef ECHOKE
1.20      millert   818:                     | ECHOKE
1.7       millert   819: #endif
1.16      millert   820:        );
1.7       millert   821: #endif
                    822:
1.41      deraadt   823:     tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1.7       millert   824: }
                    825:
                    826: /*
                    827:  * Returns a "good" value for the erase character.  This is loosely based on
                    828:  * the BSD4.4 logic.
                    829:  */
1.19      millert   830: #ifdef TERMIOS
1.7       millert   831: static int
                    832: default_erase(void)
                    833: {
1.16      millert   834:     int result;
1.7       millert   835:
1.16      millert   836:     if (over_strike
                    837:        && key_backspace != 0
                    838:        && strlen(key_backspace) == 1)
                    839:        result = key_backspace[0];
                    840:     else
                    841:        result = CERASE;
1.7       millert   842:
1.16      millert   843:     return result;
1.7       millert   844: }
1.19      millert   845: #endif
1.7       millert   846:
                    847: /*
                    848:  * Update the values of the erase, interrupt, and kill characters in 'mode'.
                    849:  *
                    850:  * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
                    851:  * characters if they're unset, or if we specify them as options.  This differs
                    852:  * from BSD 4.4 tset, which always sets erase.
                    853:  */
                    854: static void
                    855: set_control_chars(void)
                    856: {
                    857: #ifdef TERMIOS
1.35      nicm      858:     if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0)
                    859:        mode.c_cc[VERASE] = (terasechar >= 0) ? terasechar : default_erase();
1.7       millert   860:
1.35      nicm      861:     if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0)
                    862:        mode.c_cc[VINTR] = (intrchar >= 0) ? intrchar : CINTR;
1.7       millert   863:
1.35      nicm      864:     if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0)
                    865:        mode.c_cc[VKILL] = (tkillchar >= 0) ? tkillchar : CKILL;
1.7       millert   866: #endif
                    867: }
                    868:
                    869: /*
                    870:  * Set up various conversions in 'mode', including parity, tabs, returns,
                    871:  * echo, and case, according to the termcap entry.  If the program we're
                    872:  * running was named with a leading upper-case character, map external
                    873:  * uppercase to internal lowercase.
                    874:  */
                    875: static void
                    876: set_conversions(void)
                    877: {
                    878: #ifdef __OBSOLETE__
1.16      millert   879:     /*
                    880:      * Conversion logic for some *really* ancient terminal glitches,
                    881:      * not supported in terminfo.  Left here for succeeding generations
                    882:      * to marvel at.
                    883:      */
                    884:     if (tgetflag("UC")) {
1.7       millert   885: #ifdef IUCLC
1.16      millert   886:        mode.c_iflag |= IUCLC;
                    887:        mode.c_oflag |= OLCUC;
1.7       millert   888: #endif
1.16      millert   889:     } else if (tgetflag("LC")) {
1.7       millert   890: #ifdef IUCLC
1.16      millert   891:        mode.c_iflag &= ~IUCLC;
                    892:        mode.c_oflag &= ~OLCUC;
1.7       millert   893: #endif
1.16      millert   894:     }
                    895:     mode.c_iflag &= ~(PARMRK | INPCK);
                    896:     mode.c_lflag |= ICANON;
                    897:     if (tgetflag("EP")) {
                    898:        mode.c_cflag |= PARENB;
                    899:        mode.c_cflag &= ~PARODD;
                    900:     }
                    901:     if (tgetflag("OP")) {
                    902:        mode.c_cflag |= PARENB;
                    903:        mode.c_cflag |= PARODD;
                    904:     }
1.7       millert   905: #endif /* __OBSOLETE__ */
                    906:
                    907: #ifdef TERMIOS
                    908: #ifdef ONLCR
1.16      millert   909:     mode.c_oflag |= ONLCR;
1.7       millert   910: #endif
1.16      millert   911:     mode.c_iflag |= ICRNL;
                    912:     mode.c_lflag |= ECHO;
1.7       millert   913: #ifdef OXTABS
1.16      millert   914:     mode.c_oflag |= OXTABS;
1.7       millert   915: #endif /* OXTABS */
                    916:
1.16      millert   917:     /* test used to be tgetflag("NL") */
                    918:     if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
                    919:        /* Newline, not linefeed. */
1.7       millert   920: #ifdef ONLCR
1.16      millert   921:        mode.c_oflag &= ~ONLCR;
1.7       millert   922: #endif
1.16      millert   923:        mode.c_iflag &= ~ICRNL;
                    924:     }
1.7       millert   925: #ifdef __OBSOLETE__
1.16      millert   926:     if (tgetflag("HD"))                /* Half duplex. */
                    927:        mode.c_lflag &= ~ECHO;
1.7       millert   928: #endif /* __OBSOLETE__ */
                    929: #ifdef OXTABS
1.16      millert   930:     /* test used to be tgetflag("pt") */
1.40      nicm      931:     if (VALID_STRING(set_tab) && VALID_STRING(clear_all_tabs))
1.16      millert   932:        mode.c_oflag &= ~OXTABS;
1.7       millert   933: #endif /* OXTABS */
1.16      millert   934:     mode.c_lflag |= (ECHOE | ECHOK);
1.7       millert   935: #endif
                    936: }
                    937:
                    938: /* Output startup string. */
                    939: static void
                    940: set_init(void)
                    941: {
1.16      millert   942:     char *p;
                    943:     bool settle;
1.7       millert   944:
                    945: #ifdef __OBSOLETE__
1.16      millert   946:     if (pad_char != (char *) 0)        /* Get/set pad character. */
                    947:        PC = pad_char[0];
1.7       millert   948: #endif /* OBSOLETE */
                    949:
                    950: #ifdef TAB3
1.16      millert   951:     if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
                    952:        oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
1.41      deraadt   953:        tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
1.16      millert   954:     }
                    955: #endif
                    956:     settle = set_tabs();
                    957:
                    958:     if (isreset) {
                    959:        if ((p = reset_1string) != 0) {
                    960:            tputs(p, 0, outc);
                    961:            settle = TRUE;
                    962:        }
                    963:        if ((p = reset_2string) != 0) {
                    964:            tputs(p, 0, outc);
                    965:            settle = TRUE;
                    966:        }
                    967:        /* What about rf, rs3, as per terminfo man page? */
                    968:        /* also might be nice to send rmacs, rmul, rmm */
                    969:        if ((p = reset_file) != 0
                    970:            || (p = init_file) != 0) {
                    971:            cat(p);
                    972:            settle = TRUE;
                    973:        }
                    974:     }
                    975:
                    976:     if (settle) {
                    977:        (void) putc('\r', stderr);
                    978:        (void) fflush(stderr);
                    979:        (void) napms(1000);     /* Settle the terminal. */
                    980:     }
1.7       millert   981: }
                    982:
                    983: /*
                    984:  * Set the hardware tabs on the terminal, using the ct (clear all tabs),
                    985:  * st (set one tab) and ch (horizontal cursor addressing) capabilities.
                    986:  * This is done before if and is, so they can patch in case we blow this.
                    987:  * Return TRUE if we set any tab stops, FALSE if not.
                    988:  */
                    989: static bool
1.27      deraadt   990: set_tabs(void)
1.7       millert   991: {
1.16      millert   992:     if (set_tab && clear_all_tabs) {
                    993:        int c;
1.7       millert   994:
1.16      millert   995:        (void) putc('\r', stderr);      /* Force to left margin. */
                    996:        tputs(clear_all_tabs, 0, outc);
1.7       millert   997:
1.16      millert   998:        for (c = 8; c < tcolumns; c += 8) {
                    999:            /* Get to the right column.  In BSD tset, this
                   1000:             * used to try a bunch of half-clever things
                   1001:             * with cup and hpa, for an average saving of
                   1002:             * somewhat less than two character times per
1.35      nicm     1003:             * tab stop, less than .01 sec at 2400cps. We
1.16      millert  1004:             * lost all this cruft because it seemed to be
                   1005:             * introducing some odd bugs.
1.35      nicm     1006:             * -----------12345678----------- */
1.16      millert  1007:            (void) fputs("        ", stderr);
                   1008:            tputs(set_tab, 0, outc);
                   1009:        }
                   1010:        putc('\r', stderr);
                   1011:        return (TRUE);
                   1012:     }
                   1013:     return (FALSE);
1.7       millert  1014: }
                   1015:
                   1016: /**************************************************************************
                   1017:  *
                   1018:  * Main sequence
                   1019:  *
                   1020:  **************************************************************************/
                   1021:
                   1022: /*
                   1023:  * Tell the user if a control key has been changed from the default value.
                   1024:  */
1.19      millert  1025: #ifdef TERMIOS
1.7       millert  1026: static void
1.35      nicm     1027: report(const char *name, int which, unsigned def)
1.7       millert  1028: {
1.35      nicm     1029:     unsigned older, newer;
1.16      millert  1030:     char *p;
1.7       millert  1031:
1.16      millert  1032:     newer = mode.c_cc[which];
                   1033:     older = oldmode.c_cc[which];
1.7       millert  1034:
1.16      millert  1035:     if (older == newer && older == def)
                   1036:        return;
1.7       millert  1037:
1.16      millert  1038:     (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
                   1039:
1.35      nicm     1040:     if (DISABLED(newer))
                   1041:        (void) fprintf(stderr, "undef.\n");
1.16      millert  1042:     /*
                   1043:      * Check 'delete' before 'backspace', since the key_backspace value
                   1044:      * is ambiguous.
                   1045:      */
1.35      nicm     1046:     else if (newer == 0177)
1.16      millert  1047:        (void) fprintf(stderr, "delete.\n");
                   1048:     else if ((p = key_backspace) != 0
1.20      millert  1049:             && newer == (unsigned char) p[0]
                   1050:             && p[1] == '\0')
1.16      millert  1051:        (void) fprintf(stderr, "backspace.\n");
                   1052:     else if (newer < 040) {
                   1053:        newer ^= 0100;
1.35      nicm     1054:        (void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
1.16      millert  1055:     } else
1.35      nicm     1056:        (void) fprintf(stderr, "%c.\n", UChar(newer));
1.19      millert  1057: }
1.7       millert  1058: #endif
                   1059:
                   1060: /*
                   1061:  * Convert the obsolete argument forms into something that getopt can handle.
                   1062:  * This means that -e, -i and -k get default arguments supplied for them.
                   1063:  */
                   1064: static void
                   1065: obsolete(char **argv)
                   1066: {
1.16      millert  1067:     for (; *argv; ++argv) {
                   1068:        char *parm = argv[0];
1.7       millert  1069:
1.16      millert  1070:        if (parm[0] == '-' && parm[1] == '\0') {
                   1071:            argv[0] = strdup("-q");
                   1072:            continue;
                   1073:        }
                   1074:
                   1075:        if ((parm[0] != '-')
                   1076:            || (argv[1] && argv[1][0] != '-')
                   1077:            || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
                   1078:            || (parm[2] != '\0'))
                   1079:            continue;
                   1080:        switch (argv[0][1]) {
                   1081:        case 'e':
                   1082:            argv[0] = strdup("-e^H");
                   1083:            break;
                   1084:        case 'i':
                   1085:            argv[0] = strdup("-i^C");
                   1086:            break;
                   1087:        case 'k':
                   1088:            argv[0] = strdup("-k^U");
                   1089:            break;
1.7       millert  1090:        }
1.16      millert  1091:     }
1.7       millert  1092: }
                   1093:
                   1094: static void
1.35      nicm     1095: usage(void)
1.7       millert  1096: {
1.43    ! tb       1097:     (void) fprintf(stderr, "usage: %s [-cIQqrsVw] [-] "
        !          1098:        "[-e ch] [-i ch] [-k ch] [-m mapping] [terminal]",
1.35      nicm     1099:        _nc_progname);
                   1100:
                   1101:     exit_error();
                   1102:     /* NOTREACHED */
1.7       millert  1103: }
                   1104:
1.16      millert  1105: static char
                   1106: arg_to_char(void)
1.7       millert  1107: {
1.35      nicm     1108:     return (char) ((optarg[0] == '^' && optarg[1] != '\0')
                   1109:                   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
                   1110:                   : optarg[0]);
1.7       millert  1111: }
1.1       deraadt  1112:
                   1113: int
1.7       millert  1114: main(int argc, char **argv)
1.1       deraadt  1115: {
1.16      millert  1116:     int ch, noinit, noset, quiet, Sflag, sflag, showterm;
                   1117:     const char *p;
                   1118:     const char *ttype;
1.39      deraadt  1119:
1.42      tb       1120:     _nc_progname = _nc_rootname(*argv);
                   1121:
1.39      deraadt  1122:     if (pledge("stdio rpath wpath tty", NULL) == -1)
                   1123:        err("pledge: %s", strerror(errno));
1.1       deraadt  1124:
1.16      millert  1125:     obsolete(argv);
                   1126:     noinit = noset = quiet = Sflag = sflag = showterm = 0;
1.35      nicm     1127:     while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
1.16      millert  1128:        switch (ch) {
1.35      nicm     1129:        case 'c':               /* set control-chars */
                   1130:            opt_c = TRUE;
1.16      millert  1131:            break;
                   1132:        case 'a':               /* OBSOLETE: map identifier to type */
                   1133:            add_mapping("arpanet", optarg);
                   1134:            break;
                   1135:        case 'd':               /* OBSOLETE: map identifier to type */
                   1136:            add_mapping("dialup", optarg);
                   1137:            break;
                   1138:        case 'e':               /* erase character */
                   1139:            terasechar = arg_to_char();
                   1140:            break;
                   1141:        case 'I':               /* no initialization strings */
                   1142:            noinit = 1;
                   1143:            break;
                   1144:        case 'i':               /* interrupt character */
                   1145:            intrchar = arg_to_char();
                   1146:            break;
                   1147:        case 'k':               /* kill character */
                   1148:            tkillchar = arg_to_char();
                   1149:            break;
                   1150:        case 'm':               /* map identifier to type */
                   1151:            add_mapping(0, optarg);
                   1152:            break;
                   1153:        case 'n':               /* OBSOLETE: set new tty driver */
                   1154:            break;
                   1155:        case 'p':               /* OBSOLETE: map identifier to type */
                   1156:            add_mapping("plugboard", optarg);
                   1157:            break;
                   1158:        case 'Q':               /* don't output control key settings */
                   1159:            quiet = 1;
                   1160:            break;
1.35      nicm     1161:        case 'q':               /* display term only */
                   1162:            noset = 1;
1.16      millert  1163:            break;
                   1164:        case 'r':               /* display term on stderr */
                   1165:            showterm = 1;
                   1166:            break;
1.35      nicm     1167:        case 'S':               /* OBSOLETE: output TERM & TERMCAP */
                   1168:            Sflag = 1;
                   1169:            break;
1.16      millert  1170:        case 's':               /* output TERM set command */
                   1171:            sflag = 1;
                   1172:            break;
1.35      nicm     1173:        case 'V':               /* print curses-version */
1.20      millert  1174:            puts(curses_version());
1.35      nicm     1175:            ExitProgram(EXIT_SUCCESS);
                   1176:        case 'w':               /* set window-size */
                   1177:            opt_w = TRUE;
                   1178:            break;
1.16      millert  1179:        case '?':
                   1180:        default:
1.35      nicm     1181:            usage();
1.16      millert  1182:        }
                   1183:     }
                   1184:     argc -= optind;
                   1185:     argv += optind;
1.1       deraadt  1186:
1.16      millert  1187:     if (argc > 1)
1.35      nicm     1188:        usage();
                   1189:
                   1190:     if (!opt_c && !opt_w)
                   1191:        opt_c = opt_w = TRUE;
                   1192:
1.41      deraadt  1193:     if (tcgetattr(STDERR_FILENO, &mode) < 0)
1.35      nicm     1194:        failed("standard error");
                   1195:     can_restore = TRUE;
                   1196:     original = oldmode = mode;
                   1197: #ifdef TERMIOS
                   1198:     ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
                   1199: #else
                   1200:     ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
                   1201: #endif
                   1202:
                   1203:     if (!strcmp(_nc_progname, PROG_RESET)) {
                   1204:        isreset = TRUE;
                   1205:        reset_mode();
                   1206:     }
1.1       deraadt  1207:
1.16      millert  1208:     ttype = get_termcap_entry(*argv);
1.1       deraadt  1209:
1.16      millert  1210:     if (!noset) {
                   1211:        tcolumns = columns;
                   1212:        tlines = lines;
1.1       deraadt  1213:
1.35      nicm     1214: #if HAVE_SIZECHANGE
                   1215:        if (opt_w) {
1.38      deraadt  1216:            struct winsize win;
1.35      nicm     1217:            /* Set window size if not set already */
1.41      deraadt  1218:            if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) == 0) {
                   1219:                if (win.ws_row == 0 &&
                   1220:                    win.ws_col == 0 &&
                   1221:                    tlines > 0 && tcolumns > 0) {
                   1222:                    win.ws_row = tlines;
                   1223:                    win.ws_col = tcolumns;
                   1224:                    (void) ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
                   1225:                }
1.35      nicm     1226:            }
1.16      millert  1227:        }
1.1       deraadt  1228: #endif
1.35      nicm     1229:        if (opt_c) {
                   1230:            set_control_chars();
                   1231:            set_conversions();
                   1232:
                   1233:            if (!noinit)
                   1234:                set_init();
                   1235:
                   1236:            /* Set the modes if they've changed. */
                   1237:            if (memcmp(&mode, &oldmode, sizeof(mode))) {
1.41      deraadt  1238:                tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1.35      nicm     1239:            }
1.17      millert  1240:        }
1.16      millert  1241:     }
1.1       deraadt  1242:
1.16      millert  1243:     /* Get the terminal name from the entry. */
                   1244:     ttype = _nc_first_name(cur_term->type.term_names);
1.1       deraadt  1245:
1.16      millert  1246:     if (noset)
                   1247:        (void) printf("%s\n", ttype);
                   1248:     else {
                   1249:        if (showterm)
                   1250:            (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
                   1251:        /*
                   1252:         * If erase, kill and interrupt characters could have been
                   1253:         * modified and not -Q, display the changes.
                   1254:         */
1.19      millert  1255: #ifdef TERMIOS
1.16      millert  1256:        if (!quiet) {
                   1257:            report("Erase", VERASE, CERASE);
1.35      nicm     1258:            report("Kill", VKILL, CKILL);
                   1259:            report("Interrupt", VINTR, CINTR);
1.1       deraadt  1260:        }
1.19      millert  1261: #endif
1.16      millert  1262:     }
1.1       deraadt  1263:
1.16      millert  1264:     if (Sflag)
                   1265:        err("The -S option is not supported under terminfo.");
1.1       deraadt  1266:
1.16      millert  1267:     if (sflag) {
1.35      nicm     1268:        int len;
                   1269:        char *var;
                   1270:        char *leaf;
1.16      millert  1271:        /*
                   1272:         * Figure out what shell we're using.  A hack, we look for an
                   1273:         * environmental variable SHELL ending in "csh".
                   1274:         */
1.35      nicm     1275:        if ((var = getenv("SHELL")) != 0
                   1276:            && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
                   1277:            && !strcmp(leaf + len - 3, "csh"))
1.16      millert  1278:            p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
                   1279:        else
                   1280:            p = "TERM=%s;\n";
                   1281:        (void) printf(p, ttype);
                   1282:     }
1.1       deraadt  1283:
1.35      nicm     1284:     ExitProgram(EXIT_SUCCESS);
1.1       deraadt  1285: }