[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.45

1.45    ! nicm        1: /*     $OpenBSD: tset.c,v 1.44 2022/12/04 23:50:49 cheloha Exp $       */
1.22      niklas      2:
1.7       millert     3: /****************************************************************************
1.45    ! nicm        4:  * Copyright 2020,2021 Thomas E. Dickey                                     *
        !             5:  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
1.7       millert     6:  *                                                                          *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a  *
                      8:  * copy of this software and associated documentation files (the            *
                      9:  * "Software"), to deal in the Software without restriction, including      *
                     10:  * without limitation the rights to use, copy, modify, merge, publish,      *
                     11:  * distribute, distribute with modifications, sublicense, and/or sell       *
                     12:  * copies of the Software, and to permit persons to whom the Software is    *
                     13:  * furnished to do so, subject to the following conditions:                 *
                     14:  *                                                                          *
                     15:  * The above copyright notice and this permission notice shall be included  *
                     16:  * in all copies or substantial portions of the Software.                   *
                     17:  *                                                                          *
                     18:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
                     19:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
                     20:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
                     21:  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
                     22:  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
                     23:  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
                     24:  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
                     25:  *                                                                          *
                     26:  * Except as contained in this notice, the name(s) of the above copyright   *
                     27:  * holders shall not be used in advertising or otherwise to promote the     *
                     28:  * sale, use or other dealings in this Software without prior written       *
                     29:  * authorization.                                                           *
                     30:  ****************************************************************************/
                     31:
                     32: /****************************************************************************
                     33:  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
                     34:  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
1.35      nicm       35:  *     and: Thomas E. Dickey                        1996-on                 *
1.7       millert    36:  ****************************************************************************/
1.1       deraadt    37:
1.7       millert    38: /*
1.45    ! nicm       39:  * Notes:
        !            40:  * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
        !            41:  * lines from that version, and made changes/additions for 150 lines.  There
        !            42:  * was no reformatting, so with/without ignoring whitespace, the amount of
        !            43:  * change is the same.
        !            44:  *
        !            45:  * Comparing with current (2009) source, excluding this comment:
        !            46:  * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
        !            47:  *    changed/added.
        !            48:  * a) Ignoring whitespace, the current version still uses 516 lines from the
        !            49:  *    4.4BSD Lite sources, with 402 lines changed/added.
        !            50:  *
        !            51:  * Raymond's original comment on this follows...
        !            52:  */
        !            53:
        !            54: /*
1.7       millert    55:  * tset.c - terminal initialization utility
                     56:  *
                     57:  * This code was mostly swiped from 4.4BSD tset, with some obsolescent
                     58:  * cruft removed and substantial portions rewritten.  A Regents of the
                     59:  * University of California copyright applies to some portions of the
                     60:  * code, and is reproduced below:
                     61:  */
1.1       deraadt    62: /*-
                     63:  * Copyright (c) 1980, 1991, 1993
                     64:  *     The Regents of the University of California.  All rights reserved.
                     65:  *
                     66:  * Redistribution and use in source and binary forms, with or without
                     67:  * modification, are permitted provided that the following conditions
                     68:  * are met:
                     69:  * 1. Redistributions of source code must retain the above copyright
                     70:  *    notice, this list of conditions and the following disclaimer.
                     71:  * 2. Redistributions in binary form must reproduce the above copyright
                     72:  *    notice, this list of conditions and the following disclaimer in the
                     73:  *    documentation and/or other materials provided with the distribution.
1.26      millert    74:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    75:  *    may be used to endorse or promote products derived from this software
                     76:  *    without specific prior written permission.
                     77:  *
                     78:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     79:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     80:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     81:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     82:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     83:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     84:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     85:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     86:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     87:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     88:  * SUCH DAMAGE.
                     89:  */
                     90:
1.45    ! nicm       91: #include <reset_cmd.h>
1.7       millert    92: #include <termcap.h>
1.45    ! nicm       93: #include <transform.h>
        !            94: #include <tty_settings.h>
1.7       millert    95:
1.45    ! nicm       96: #if HAVE_GETTTYNAM
1.7       millert    97: #include <ttyent.h>
                     98: #endif
                     99: #ifdef NeXT
                    100: char *ttyname(int fd);
                    101: #endif
                    102:
                    103:
                    104:
1.45    ! nicm      105: #ifndef environ
1.7       millert   106: extern char **environ;
1.45    ! nicm      107: #endif
1.7       millert   108:
1.45    ! nicm      109: const char *_nc_progname = "tset";
1.7       millert   110:
1.45    ! nicm      111: #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
1.35      nicm      112:
1.45    ! nicm      113: static GCC_NORETURN void exit_error(void);
1.7       millert   114:
                    115: static int
1.16      millert   116: CaselessCmp(const char *a, const char *b)
                    117: {                              /* strcasecmp isn't portable */
                    118:     while (*a && *b) {
                    119:        int cmp = LOWERCASE(*a) - LOWERCASE(*b);
                    120:        if (cmp != 0)
                    121:            break;
                    122:        a++, b++;
                    123:     }
                    124:     return LOWERCASE(*a) - LOWERCASE(*b);
1.7       millert   125: }
                    126:
1.45    ! nicm      127: static GCC_NORETURN void
1.35      nicm      128: exit_error(void)
                    129: {
1.45    ! nicm      130:     restore_tty_settings();
1.35      nicm      131:     (void) fprintf(stderr, "\n");
                    132:     fflush(stderr);
                    133:     ExitProgram(EXIT_FAILURE);
                    134:     /* NOTREACHED */
                    135: }
                    136:
1.45    ! nicm      137: static GCC_NORETURN void
        !           138: err(const char *fmt, ...)
1.7       millert   139: {
1.16      millert   140:     va_list ap;
                    141:     va_start(ap, fmt);
1.35      nicm      142:     (void) fprintf(stderr, "%s: ", _nc_progname);
1.16      millert   143:     (void) vfprintf(stderr, fmt, ap);
                    144:     va_end(ap);
1.35      nicm      145:     exit_error();
1.16      millert   146:     /* NOTREACHED */
1.7       millert   147: }
                    148:
1.45    ! nicm      149: static GCC_NORETURN void
1.7       millert   150: failed(const char *msg)
                    151: {
1.45    ! nicm      152:     char temp[BUFSIZ];
        !           153:     size_t len = strlen(_nc_progname) + 2;
        !           154:
        !           155:     if ((int) len < (int) sizeof(temp) - 12) {
        !           156:        _nc_STRCPY(temp, _nc_progname, sizeof(temp));
        !           157:        _nc_STRCAT(temp, ": ", sizeof(temp));
        !           158:     } else {
        !           159:        _nc_STRCPY(temp, "tset: ", sizeof(temp));
        !           160:     }
        !           161:     _nc_STRNCAT(temp, msg, sizeof(temp), sizeof(temp) - strlen(temp) - 2);
        !           162:     perror(temp);
1.35      nicm      163:     exit_error();
1.16      millert   164:     /* NOTREACHED */
1.7       millert   165: }
                    166:
                    167: /* Prompt the user for a terminal type. */
                    168: static const char *
                    169: askuser(const char *dflt)
                    170: {
1.16      millert   171:     static char answer[256];
1.7       millert   172:
1.16      millert   173:     /* We can get recalled; if so, don't continue uselessly. */
1.35      nicm      174:     clearerr(stdin);
1.16      millert   175:     if (feof(stdin) || ferror(stdin)) {
                    176:        (void) fprintf(stderr, "\n");
1.35      nicm      177:        exit_error();
                    178:        /* NOTREACHED */
1.16      millert   179:     }
1.45    ! nicm      180:
1.16      millert   181:     for (;;) {
1.45    ! nicm      182:        char *p;
        !           183:
1.16      millert   184:        if (dflt)
                    185:            (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
                    186:        else
                    187:            (void) fprintf(stderr, "Terminal type? ");
                    188:        (void) fflush(stderr);
                    189:
1.45    ! nicm      190:        if (fgets(answer, sizeof(answer), stdin) == 0) {
1.16      millert   191:            if (dflt == 0) {
1.35      nicm      192:                exit_error();
                    193:                /* NOTREACHED */
1.16      millert   194:            }
                    195:            return (dflt);
1.7       millert   196:        }
                    197:
1.45    ! nicm      198:        if ((p = strchr(answer, '\n')) != 0)
        !           199:            *p = '\0';
1.16      millert   200:        if (answer[0])
                    201:            return (answer);
                    202:        if (dflt != 0)
                    203:            return (dflt);
                    204:     }
1.7       millert   205: }
                    206:
                    207: /**************************************************************************
                    208:  *
                    209:  * Mapping logic begins here
                    210:  *
                    211:  **************************************************************************/
                    212:
                    213: /* Baud rate conditionals for mapping. */
                    214: #define        GT              0x01
                    215: #define        EQ              0x02
                    216: #define        LT              0x04
                    217: #define        NOT             0x08
                    218: #define        GE              (GT | EQ)
                    219: #define        LE              (LT | EQ)
                    220:
                    221: typedef struct map {
1.16      millert   222:     struct map *next;          /* Linked list of maps. */
                    223:     const char *porttype;      /* Port type, or "" for any. */
                    224:     const char *type;          /* Terminal type to select. */
                    225:     int conditional;           /* Baud rate conditionals bitmask. */
1.20      millert   226:     int speed;                 /* Baud rate to compare against. */
1.7       millert   227: } MAP;
                    228:
                    229: static MAP *cur, *maplist;
                    230:
1.45    ! nicm      231: #define DATA(name,value) { { name }, value }
        !           232:
1.7       millert   233: typedef struct speeds {
1.45    ! nicm      234:     const char string[8];
1.16      millert   235:     int speed;
1.7       millert   236: } SPEEDS;
                    237:
1.45    ! nicm      238: #if defined(EXP_WIN32_DRIVER)
1.16      millert   239: static const SPEEDS speeds[] =
                    240: {
1.45    ! nicm      241:     {"0", 0}
        !           242: };
        !           243: #else
        !           244: static const SPEEDS speeds[] =
        !           245: {
        !           246:     DATA("0", B0),
        !           247:     DATA("50", B50),
        !           248:     DATA("75", B75),
        !           249:     DATA("110", B110),
        !           250:     DATA("134", B134),
        !           251:     DATA("134.5", B134),
        !           252:     DATA("150", B150),
        !           253:     DATA("200", B200),
        !           254:     DATA("300", B300),
        !           255:     DATA("600", B600),
        !           256:     DATA("1200", B1200),
        !           257:     DATA("1800", B1800),
        !           258:     DATA("2400", B2400),
        !           259:     DATA("4800", B4800),
        !           260:     DATA("9600", B9600),
1.19      millert   261:     /* sgttyb may define up to this point */
                    262: #ifdef B19200
1.45    ! nicm      263:     DATA("19200", B19200),
1.19      millert   264: #endif
                    265: #ifdef B38400
1.45    ! nicm      266:     DATA("38400", B38400),
1.19      millert   267: #endif
                    268: #ifdef B19200
1.45    ! nicm      269:     DATA("19200", B19200),
1.19      millert   270: #endif
                    271: #ifdef B38400
1.45    ! nicm      272:     DATA("38400", B38400),
1.19      millert   273: #endif
1.7       millert   274: #ifdef B19200
1.45    ! nicm      275:     DATA("19200", B19200),
1.7       millert   276: #else
                    277: #ifdef EXTA
1.45    ! nicm      278:     DATA("19200", EXTA),
1.7       millert   279: #endif
                    280: #endif
                    281: #ifdef B38400
1.45    ! nicm      282:     DATA("38400", B38400),
1.7       millert   283: #else
                    284: #ifdef EXTB
1.45    ! nicm      285:     DATA("38400", EXTB),
1.7       millert   286: #endif
                    287: #endif
                    288: #ifdef B57600
1.45    ! nicm      289:     DATA("57600", B57600),
        !           290: #endif
        !           291: #ifdef B76800
        !           292:     DATA("76800", B57600),
1.7       millert   293: #endif
                    294: #ifdef B115200
1.45    ! nicm      295:     DATA("115200", B115200),
        !           296: #endif
        !           297: #ifdef B153600
        !           298:     DATA("153600", B153600),
1.7       millert   299: #endif
                    300: #ifdef B230400
1.45    ! nicm      301:     DATA("230400", B230400),
        !           302: #endif
        !           303: #ifdef B307200
        !           304:     DATA("307200", B307200),
1.7       millert   305: #endif
                    306: #ifdef B460800
1.45    ! nicm      307:     DATA("460800", B460800),
        !           308: #endif
        !           309: #ifdef B500000
        !           310:     DATA("500000", B500000),
        !           311: #endif
        !           312: #ifdef B576000
        !           313:     DATA("576000", B576000),
        !           314: #endif
        !           315: #ifdef B921600
        !           316:     DATA("921600", B921600),
        !           317: #endif
        !           318: #ifdef B1000000
        !           319:     DATA("1000000", B1000000),
        !           320: #endif
        !           321: #ifdef B1152000
        !           322:     DATA("1152000", B1152000),
        !           323: #endif
        !           324: #ifdef B1500000
        !           325:     DATA("1500000", B1500000),
        !           326: #endif
        !           327: #ifdef B2000000
        !           328:     DATA("2000000", B2000000),
        !           329: #endif
        !           330: #ifdef B2500000
        !           331:     DATA("2500000", B2500000),
        !           332: #endif
        !           333: #ifdef B3000000
        !           334:     DATA("3000000", B3000000),
        !           335: #endif
        !           336: #ifdef B3500000
        !           337:     DATA("3500000", B3500000),
        !           338: #endif
        !           339: #ifdef B4000000
        !           340:     DATA("4000000", B4000000),
1.7       millert   341: #endif
                    342: };
1.45    ! nicm      343: #undef DATA
        !           344: #endif
1.7       millert   345:
                    346: static int
                    347: tbaudrate(char *rate)
                    348: {
1.45    ! nicm      349:     const SPEEDS *sp = 0;
        !           350:     size_t n;
1.7       millert   351:
1.16      millert   352:     /* The baudrate number can be preceded by a 'B', which is ignored. */
                    353:     if (*rate == 'B')
                    354:        ++rate;
                    355:
1.45    ! nicm      356:     for (n = 0; n < SIZEOF(speeds); ++n) {
        !           357:        if (n > 0 && (speeds[n].speed <= speeds[n - 1].speed)) {
        !           358:            /* if the speeds are not increasing, likely a numeric overflow */
        !           359:            break;
        !           360:        }
        !           361:        if (!CaselessCmp(rate, speeds[n].string)) {
        !           362:            sp = speeds + n;
1.16      millert   363:            break;
                    364:        }
                    365:     }
1.45    ! nicm      366:     if (sp == 0)
1.16      millert   367:        err("unknown baud rate %s", rate);
                    368:     return (sp->speed);
1.7       millert   369: }
                    370:
                    371: /*
                    372:  * Syntax for -m:
                    373:  * [port-type][test baudrate]:terminal-type
                    374:  * The baud rate tests are: >, <, @, =, !
                    375:  */
                    376: static void
                    377: add_mapping(const char *port, char *arg)
                    378: {
1.16      millert   379:     MAP *mapp;
                    380:     char *copy, *p;
                    381:     const char *termp;
                    382:     char *base = 0;
                    383:
                    384:     copy = strdup(arg);
1.45    ! nicm      385:     mapp = typeMalloc(MAP, 1);
1.16      millert   386:     if (copy == 0 || mapp == 0)
                    387:        failed("malloc");
1.45    ! nicm      388:
        !           389:     assert(copy != 0);
        !           390:     assert(mapp != 0);
        !           391:
1.16      millert   392:     mapp->next = 0;
                    393:     if (maplist == 0)
                    394:        cur = maplist = mapp;
                    395:     else {
                    396:        cur->next = mapp;
                    397:        cur = mapp;
                    398:     }
                    399:
                    400:     mapp->porttype = arg;
                    401:     mapp->conditional = 0;
                    402:
                    403:     arg = strpbrk(arg, "><@=!:");
                    404:
                    405:     if (arg == 0) {            /* [?]term */
                    406:        mapp->type = mapp->porttype;
                    407:        mapp->porttype = 0;
                    408:        goto done;
                    409:     }
                    410:
                    411:     if (arg == mapp->porttype) /* [><@=! baud]:term */
                    412:        termp = mapp->porttype = 0;
                    413:     else
                    414:        termp = base = arg;
                    415:
1.17      millert   416:     for (;; ++arg) {           /* Optional conditionals. */
1.16      millert   417:        switch (*arg) {
                    418:        case '<':
                    419:            if (mapp->conditional & GT)
                    420:                goto badmopt;
                    421:            mapp->conditional |= LT;
                    422:            break;
                    423:        case '>':
                    424:            if (mapp->conditional & LT)
1.7       millert   425:                goto badmopt;
1.16      millert   426:            mapp->conditional |= GT;
                    427:            break;
                    428:        case '@':
                    429:        case '=':               /* Not documented. */
                    430:            mapp->conditional |= EQ;
                    431:            break;
                    432:        case '!':
                    433:            mapp->conditional |= NOT;
                    434:            break;
                    435:        default:
                    436:            goto next;
                    437:        }
1.17      millert   438:     }
1.16      millert   439:
1.17      millert   440:   next:
                    441:     if (*arg == ':') {
1.16      millert   442:        if (mapp->conditional)
                    443:            goto badmopt;
                    444:        ++arg;
                    445:     } else {                   /* Optional baudrate. */
                    446:        arg = strchr(p = arg, ':');
                    447:        if (arg == 0)
                    448:            goto badmopt;
                    449:        *arg++ = '\0';
                    450:        mapp->speed = tbaudrate(p);
                    451:     }
                    452:
                    453:     mapp->type = arg;
                    454:
                    455:     /* Terminate porttype, if specified. */
                    456:     if (termp != 0)
                    457:        *base = '\0';
                    458:
                    459:     /* If a NOT conditional, reverse the test. */
                    460:     if (mapp->conditional & NOT)
                    461:        mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
                    462:
                    463:     /* If user specified a port with an option flag, set it. */
1.35      nicm      464:   done:
                    465:     if (port) {
                    466:        if (mapp->porttype) {
                    467:          badmopt:
                    468:            err("illegal -m option format: %s", copy);
                    469:        }
1.16      millert   470:        mapp->porttype = port;
                    471:     }
1.34      nicm      472:     free(copy);
1.7       millert   473: #ifdef MAPDEBUG
1.16      millert   474:     (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
                    475:     (void) printf("type: %s\n", mapp->type);
                    476:     (void) printf("conditional: ");
                    477:     p = "";
                    478:     if (mapp->conditional & GT) {
                    479:        (void) printf("GT");
                    480:        p = "/";
                    481:     }
                    482:     if (mapp->conditional & EQ) {
                    483:        (void) printf("%sEQ", p);
                    484:        p = "/";
                    485:     }
                    486:     if (mapp->conditional & LT)
                    487:        (void) printf("%sLT", p);
                    488:     (void) printf("\nspeed: %d\n", mapp->speed);
1.7       millert   489: #endif
                    490: }
                    491:
                    492: /*
                    493:  * Return the type of terminal to use for a port of type 'type', as specified
                    494:  * by the first applicable mapping in 'map'.  If no mappings apply, return
                    495:  * 'type'.
                    496:  */
                    497: static const char *
                    498: mapped(const char *type)
                    499: {
1.16      millert   500:     MAP *mapp;
                    501:     int match;
1.7       millert   502:
1.16      millert   503:     for (mapp = maplist; mapp; mapp = mapp->next)
                    504:        if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
                    505:            switch (mapp->conditional) {
                    506:            case 0:             /* No test specified. */
                    507:                match = TRUE;
                    508:                break;
                    509:            case EQ:
1.45    ! nicm      510:                match = ((int) ospeed == mapp->speed);
1.16      millert   511:                break;
                    512:            case GE:
1.45    ! nicm      513:                match = ((int) ospeed >= mapp->speed);
1.16      millert   514:                break;
                    515:            case GT:
1.45    ! nicm      516:                match = ((int) ospeed > mapp->speed);
1.16      millert   517:                break;
                    518:            case LE:
1.45    ! nicm      519:                match = ((int) ospeed <= mapp->speed);
1.16      millert   520:                break;
                    521:            case LT:
1.45    ! nicm      522:                match = ((int) ospeed < mapp->speed);
1.16      millert   523:                break;
                    524:            default:
                    525:                match = FALSE;
                    526:            }
                    527:            if (match)
                    528:                return (mapp->type);
                    529:        }
                    530:     /* No match found; return given type. */
                    531:     return (type);
1.7       millert   532: }
                    533:
                    534: /**************************************************************************
                    535:  *
                    536:  * Entry fetching
                    537:  *
                    538:  **************************************************************************/
                    539:
                    540: /*
                    541:  * Figure out what kind of terminal we're dealing with, and then read in
                    542:  * its termcap entry.
                    543:  */
                    544: static const char *
1.45    ! nicm      545: get_termcap_entry(int fd, char *userarg)
1.7       millert   546: {
1.23      millert   547:     int errret;
1.16      millert   548:     char *p;
                    549:     const char *ttype;
1.45    ! nicm      550: #if HAVE_PATH_TTYS
1.7       millert   551: #if HAVE_GETTTYNAM
1.16      millert   552:     struct ttyent *t;
1.7       millert   553: #else
1.16      millert   554:     FILE *fp;
1.7       millert   555: #endif
1.16      millert   556:     char *ttypath;
1.45    ! nicm      557: #endif /* HAVE_PATH_TTYS */
        !           558:
        !           559:     (void) fd;
1.7       millert   560:
1.16      millert   561:     if (userarg) {
                    562:        ttype = userarg;
                    563:        goto found;
                    564:     }
                    565:
                    566:     /* Try the environment. */
                    567:     if ((ttype = getenv("TERM")) != 0)
                    568:        goto map;
                    569:
1.45    ! nicm      570: #if HAVE_PATH_TTYS
        !           571:     if ((ttypath = ttyname(fd)) != 0) {
1.20      millert   572:        p = _nc_basename(ttypath);
1.16      millert   573: #if HAVE_GETTTYNAM
                    574:        /*
                    575:         * We have the 4.3BSD library call getttynam(3); that means
                    576:         * there's an /etc/ttys to look up device-to-type mappings in.
                    577:         * Try ttyname(3); check for dialup or other mapping.
                    578:         */
                    579:        if ((t = getttynam(p))) {
                    580:            ttype = t->ty_type;
                    581:            goto map;
1.7       millert   582:        }
1.16      millert   583: #else
                    584:        if ((fp = fopen("/etc/ttytype", "r")) != 0
                    585:            || (fp = fopen("/etc/ttys", "r")) != 0) {
                    586:            char buffer[BUFSIZ];
                    587:            char *s, *t, *d;
                    588:
1.45    ! nicm      589:            while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
1.16      millert   590:                for (s = buffer, t = d = 0; *s; s++) {
1.35      nicm      591:                    if (isspace(UChar(*s)))
1.16      millert   592:                        *s = '\0';
                    593:                    else if (t == 0)
                    594:                        t = s;
                    595:                    else if (d == 0 && s != buffer && s[-1] == '\0')
                    596:                        d = s;
1.7       millert   597:                }
1.16      millert   598:                if (t != 0 && d != 0 && !strcmp(d, p)) {
                    599:                    ttype = strdup(t);
                    600:                    fclose(fp);
                    601:                    goto map;
1.7       millert   602:                }
1.16      millert   603:            }
                    604:            fclose(fp);
                    605:        }
1.7       millert   606: #endif /* HAVE_GETTTYNAM */
1.16      millert   607:     }
1.45    ! nicm      608: #endif /* HAVE_PATH_TTYS */
1.7       millert   609:
1.16      millert   610:     /* If still undefined, use "unknown". */
                    611:     ttype = "unknown";
1.7       millert   612:
1.16      millert   613:   map:ttype = mapped(ttype);
1.7       millert   614:
1.16      millert   615:     /*
                    616:      * If not a path, remove TERMCAP from the environment so we get a
                    617:      * real entry from /etc/termcap.  This prevents us from being fooled
                    618:      * by out of date stuff in the environment.
                    619:      */
1.45    ! nicm      620:   found:
        !           621:     if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
1.16      millert   622:        /* 'unsetenv("TERMCAP")' is not portable.
                    623:         * The 'environ' array is better.
1.7       millert   624:         */
1.16      millert   625:        int n;
                    626:        for (n = 0; environ[n] != 0; n++) {
1.45    ! nicm      627:            if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
1.16      millert   628:                while ((environ[n] = environ[n + 1]) != 0) {
                    629:                    n++;
1.7       millert   630:                }
1.16      millert   631:                break;
                    632:            }
1.7       millert   633:        }
1.16      millert   634:     }
1.7       millert   635:
1.16      millert   636:     /*
                    637:      * ttype now contains a pointer to the type of the terminal.
                    638:      * If the first character is '?', ask the user.
                    639:      */
                    640:     if (ttype[0] == '?') {
                    641:        if (ttype[1] != '\0')
                    642:            ttype = askuser(ttype + 1);
                    643:        else
                    644:            ttype = askuser(0);
                    645:     }
                    646:     /* Find the terminfo entry.  If it doesn't exist, ask the user. */
1.45    ! nicm      647:     while (setupterm((NCURSES_CONST char *) ttype, fd, &errret)
1.23      millert   648:           != OK) {
1.16      millert   649:        if (errret == 0) {
1.35      nicm      650:            (void) fprintf(stderr, "%s: unknown terminal type %s\n",
                    651:                           _nc_progname, ttype);
1.16      millert   652:            ttype = 0;
                    653:        } else {
                    654:            (void) fprintf(stderr,
1.35      nicm      655:                           "%s: can't initialize terminal type %s (error %d)\n",
                    656:                           _nc_progname, ttype, errret);
1.16      millert   657:            ttype = 0;
1.7       millert   658:        }
1.16      millert   659:        ttype = askuser(ttype);
                    660:     }
1.7       millert   661: #if BROKEN_LINKER
1.16      millert   662:     tgetflag("am");            /* force lib_termcap.o to be linked for 'ospeed' */
1.7       millert   663: #endif
1.16      millert   664:     return (ttype);
1.7       millert   665: }
                    666:
                    667: /**************************************************************************
                    668:  *
                    669:  * Main sequence
                    670:  *
                    671:  **************************************************************************/
                    672:
                    673: /*
                    674:  * Convert the obsolete argument forms into something that getopt can handle.
                    675:  * This means that -e, -i and -k get default arguments supplied for them.
                    676:  */
                    677: static void
                    678: obsolete(char **argv)
                    679: {
1.16      millert   680:     for (; *argv; ++argv) {
                    681:        char *parm = argv[0];
1.7       millert   682:
1.16      millert   683:        if (parm[0] == '-' && parm[1] == '\0') {
                    684:            argv[0] = strdup("-q");
                    685:            continue;
                    686:        }
                    687:
                    688:        if ((parm[0] != '-')
                    689:            || (argv[1] && argv[1][0] != '-')
                    690:            || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
                    691:            || (parm[2] != '\0'))
                    692:            continue;
                    693:        switch (argv[0][1]) {
                    694:        case 'e':
                    695:            argv[0] = strdup("-e^H");
                    696:            break;
                    697:        case 'i':
                    698:            argv[0] = strdup("-i^C");
                    699:            break;
                    700:        case 'k':
                    701:            argv[0] = strdup("-k^U");
                    702:            break;
1.7       millert   703:        }
1.16      millert   704:     }
1.7       millert   705: }
                    706:
                    707: static void
1.45    ! nicm      708: print_shell_commands(const char *ttype)
        !           709: {
        !           710:     const char *p;
        !           711:     int len;
        !           712:     char *var;
        !           713:     char *leaf;
        !           714:     /*
        !           715:      * Figure out what shell we're using.  A hack, we look for an
        !           716:      * environmental variable SHELL ending in "csh".
        !           717:      */
        !           718:     if ((var = getenv("SHELL")) != 0
        !           719:        && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
        !           720:        && !strcmp(leaf + len - 3, "csh"))
        !           721:        p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
        !           722:     else
        !           723:        p = "TERM=%s;\n";
        !           724:     (void) printf(p, ttype);
        !           725: }
        !           726:
        !           727: static void
1.35      nicm      728: usage(void)
1.7       millert   729: {
1.45    ! nicm      730: #define SKIP(s)                        /* nothing */
        !           731: #define KEEP(s) s "\n"
        !           732:     static const char msg[] =
        !           733:     {
        !           734:        KEEP("")
        !           735:        KEEP("Options:")
        !           736:        SKIP("  -a arpanet  (obsolete)")
        !           737:        KEEP("  -c          set control characters")
        !           738:        SKIP("  -d dialup   (obsolete)")
        !           739:        KEEP("  -e ch       erase character")
        !           740:        KEEP("  -I          no initialization strings")
        !           741:        KEEP("  -i ch       interrupt character")
        !           742:        KEEP("  -k ch       kill character")
        !           743:        KEEP("  -m mapping  map identifier to type")
        !           744:        SKIP("  -p plugboard (obsolete)")
        !           745:        KEEP("  -Q          do not output control key settings")
        !           746:        KEEP("  -q          display term only, do no changes")
        !           747:        KEEP("  -r          display term on stderr")
        !           748:        SKIP("  -S          (obsolete)")
        !           749:        KEEP("  -s          output TERM set command")
        !           750:        KEEP("  -V          print curses-version")
        !           751:        KEEP("  -w          set window-size")
        !           752:        KEEP("")
        !           753:        KEEP("If neither -c/-w are given, both are assumed.")
        !           754:     };
        !           755: #undef KEEP
        !           756: #undef SKIP
        !           757:     (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
        !           758:     fputs(msg, stderr);
        !           759:     ExitProgram(EXIT_FAILURE);
1.35      nicm      760:     /* NOTREACHED */
1.7       millert   761: }
                    762:
1.16      millert   763: static char
                    764: arg_to_char(void)
1.7       millert   765: {
1.35      nicm      766:     return (char) ((optarg[0] == '^' && optarg[1] != '\0')
                    767:                   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
                    768:                   : optarg[0]);
1.7       millert   769: }
1.1       deraadt   770:
                    771: int
1.7       millert   772: main(int argc, char **argv)
1.1       deraadt   773: {
1.16      millert   774:     int ch, noinit, noset, quiet, Sflag, sflag, showterm;
                    775:     const char *ttype;
1.45    ! nicm      776:     int terasechar = -1;       /* new erase character */
        !           777:     int intrchar = -1;         /* new interrupt character */
        !           778:     int tkillchar = -1;                /* new kill character */
        !           779:     int my_fd;
        !           780:     bool opt_c = FALSE;                /* set control-chars */
        !           781:     bool opt_w = FALSE;                /* set window-size */
        !           782:     TTY mode, oldmode;
1.39      deraadt   783:
1.42      tb        784:     _nc_progname = _nc_rootname(*argv);
                    785:
1.39      deraadt   786:     if (pledge("stdio rpath wpath tty", NULL) == -1)
                    787:        err("pledge: %s", strerror(errno));
1.1       deraadt   788:
1.16      millert   789:     obsolete(argv);
                    790:     noinit = noset = quiet = Sflag = sflag = showterm = 0;
1.45    ! nicm      791:     while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQrSsVw")) != -1) {
1.16      millert   792:        switch (ch) {
1.35      nicm      793:        case 'c':               /* set control-chars */
                    794:            opt_c = TRUE;
1.16      millert   795:            break;
                    796:        case 'a':               /* OBSOLETE: map identifier to type */
                    797:            add_mapping("arpanet", optarg);
                    798:            break;
                    799:        case 'd':               /* OBSOLETE: map identifier to type */
                    800:            add_mapping("dialup", optarg);
                    801:            break;
                    802:        case 'e':               /* erase character */
                    803:            terasechar = arg_to_char();
                    804:            break;
                    805:        case 'I':               /* no initialization strings */
                    806:            noinit = 1;
                    807:            break;
                    808:        case 'i':               /* interrupt character */
                    809:            intrchar = arg_to_char();
                    810:            break;
                    811:        case 'k':               /* kill character */
                    812:            tkillchar = arg_to_char();
                    813:            break;
                    814:        case 'm':               /* map identifier to type */
                    815:            add_mapping(0, optarg);
                    816:            break;
                    817:        case 'n':               /* OBSOLETE: set new tty driver */
                    818:            break;
                    819:        case 'p':               /* OBSOLETE: map identifier to type */
                    820:            add_mapping("plugboard", optarg);
                    821:            break;
                    822:        case 'Q':               /* don't output control key settings */
                    823:            quiet = 1;
                    824:            break;
1.35      nicm      825:        case 'q':               /* display term only */
                    826:            noset = 1;
1.16      millert   827:            break;
                    828:        case 'r':               /* display term on stderr */
                    829:            showterm = 1;
                    830:            break;
1.35      nicm      831:        case 'S':               /* OBSOLETE: output TERM & TERMCAP */
                    832:            Sflag = 1;
                    833:            break;
1.16      millert   834:        case 's':               /* output TERM set command */
                    835:            sflag = 1;
                    836:            break;
1.35      nicm      837:        case 'V':               /* print curses-version */
1.20      millert   838:            puts(curses_version());
1.35      nicm      839:            ExitProgram(EXIT_SUCCESS);
                    840:        case 'w':               /* set window-size */
                    841:            opt_w = TRUE;
                    842:            break;
1.45    ! nicm      843:        case '?':
1.16      millert   844:        default:
1.35      nicm      845:            usage();
1.16      millert   846:        }
                    847:     }
1.45    ! nicm      848:
1.16      millert   849:     argc -= optind;
                    850:     argv += optind;
1.1       deraadt   851:
1.16      millert   852:     if (argc > 1)
1.35      nicm      853:        usage();
                    854:
                    855:     if (!opt_c && !opt_w)
                    856:        opt_c = opt_w = TRUE;
                    857:
1.45    ! nicm      858:     my_fd = save_tty_settings(&mode, TRUE);
        !           859:     oldmode = mode;
1.35      nicm      860: #ifdef TERMIOS
                    861:     ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
1.45    ! nicm      862: #elif defined(EXP_WIN32_DRIVER)
        !           863:     ospeed = 0;
1.35      nicm      864: #else
                    865:     ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
                    866: #endif
                    867:
1.45    ! nicm      868:     if (same_program(_nc_progname, PROG_RESET)) {
        !           869:        reset_start(stderr, TRUE, FALSE);
        !           870:        reset_tty_settings(my_fd, &mode, noset);
        !           871:     } else {
        !           872:        reset_start(stderr, FALSE, TRUE);
1.35      nicm      873:     }
1.1       deraadt   874:
1.45    ! nicm      875:     ttype = get_termcap_entry(my_fd, *argv);
1.1       deraadt   876:
1.16      millert   877:     if (!noset) {
1.35      nicm      878: #if HAVE_SIZECHANGE
                    879:        if (opt_w) {
1.45    ! nicm      880:            set_window_size(my_fd, &lines, &columns);
1.16      millert   881:        }
1.1       deraadt   882: #endif
1.35      nicm      883:        if (opt_c) {
1.45    ! nicm      884:            set_control_chars(&mode, terasechar, intrchar, tkillchar);
        !           885:            set_conversions(&mode);
1.35      nicm      886:
1.45    ! nicm      887:            if (!noinit) {
        !           888:                if (send_init_strings(my_fd, &oldmode)) {
        !           889:                    (void) putc('\r', stderr);
        !           890:                    (void) fflush(stderr);
        !           891:                    (void) napms(1000);         /* Settle the terminal. */
        !           892:                }
        !           893:            }
1.35      nicm      894:
1.45    ! nicm      895:            update_tty_settings(&oldmode, &mode);
1.17      millert   896:        }
1.16      millert   897:     }
1.1       deraadt   898:
1.45    ! nicm      899:     if (noset) {
1.16      millert   900:        (void) printf("%s\n", ttype);
1.45    ! nicm      901:     } else {
1.16      millert   902:        if (showterm)
                    903:            (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
                    904:        /*
                    905:         * If erase, kill and interrupt characters could have been
                    906:         * modified and not -Q, display the changes.
                    907:         */
                    908:        if (!quiet) {
1.45    ! nicm      909:            print_tty_chars(&oldmode, &mode);
1.1       deraadt   910:        }
1.16      millert   911:     }
1.1       deraadt   912:
1.16      millert   913:     if (Sflag)
                    914:        err("The -S option is not supported under terminfo.");
1.1       deraadt   915:
1.16      millert   916:     if (sflag) {
1.45    ! nicm      917:        print_shell_commands(ttype);
1.16      millert   918:     }
1.1       deraadt   919:
1.35      nicm      920:     ExitProgram(EXIT_SUCCESS);
1.1       deraadt   921: }