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

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