150276Speter/****************************************************************************
2184989Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter * tset.c - terminal initialization utility
3750276Speter *
3850276Speter * This code was mostly swiped from 4.4BSD tset, with some obsolescent
3950276Speter * cruft removed and substantial portions rewritten.  A Regents of the
4050276Speter * University of California copyright applies to some portions of the
4150276Speter * code, and is reproduced below:
4250276Speter */
4350276Speter/*-
4450276Speter * Copyright (c) 1980, 1991, 1993
4550276Speter *	The Regents of the University of California.  All rights reserved.
4650276Speter *
4750276Speter * Redistribution and use in source and binary forms, with or without
4850276Speter * modification, are permitted provided that the following conditions
4950276Speter * are met:
5050276Speter * 1. Redistributions of source code must retain the above copyright
5150276Speter *    notice, this list of conditions and the following disclaimer.
5250276Speter * 2. Redistributions in binary form must reproduce the above copyright
5350276Speter *    notice, this list of conditions and the following disclaimer in the
5450276Speter *    documentation and/or other materials provided with the distribution.
5550276Speter * 3. All advertising materials mentioning features or use of this software
5650276Speter *    must display the following acknowledgement:
5750276Speter *	This product includes software developed by the University of
5850276Speter *	California, Berkeley and its contributors.
5950276Speter * 4. Neither the name of the University nor the names of its contributors
6050276Speter *    may be used to endorse or promote products derived from this software
6150276Speter *    without specific prior written permission.
6250276Speter *
6350276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6450276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6550276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6650276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6750276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6850276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6950276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7050276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7150276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7250276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7350276Speter * SUCH DAMAGE.
7450276Speter */
7550276Speter
76174993Srafan#define USE_LIBTINFO
7750276Speter#define __INTERNAL_CAPS_VISIBLE	/* we need to see has_hardware_tabs */
7850276Speter#include <progs.priv.h>
7950276Speter
8050276Speter#include <errno.h>
8150276Speter#include <stdio.h>
8250276Speter#include <termcap.h>
8350276Speter#include <fcntl.h>
8450276Speter
8550276Speter#if HAVE_GETTTYNAM && HAVE_TTYENT_H
8650276Speter#include <ttyent.h>
8750276Speter#endif
8850276Speter#ifdef NeXT
8950276Speterchar *ttyname(int fd);
9050276Speter#endif
9150276Speter
92184989Srafan#if HAVE_SIZECHANGE
93184989Srafan# if !defined(sun) || !TERMIOS
94184989Srafan#  if HAVE_SYS_IOCTL_H
95184989Srafan#   include <sys/ioctl.h>
96184989Srafan#  endif
97184989Srafan# endif
9850276Speter#endif
9950276Speter
10050276Speter#if NEED_PTEM_H
10150276Speter/* they neglected to define struct winsize in termios.h -- it's only
10250276Speter   in termio.h	*/
10397049Speter#include <sys/stream.h>
10497049Speter#include <sys/ptem.h>
10550276Speter#endif
10650276Speter
10750276Speter#include <dump_entry.h>
10866963Speter#include <transform.h>
10950276Speter
110184989SrafanMODULE_ID("$Id: tset.c,v 1.76 2008/10/11 19:26:19 tom Exp $")
11150276Speter
112184989Srafan/*
113184989Srafan * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
114184989Srafan * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
115184989Srafan */
116184989Srafan#ifdef TIOCGSIZE
117184989Srafan# define IOCTL_GET_WINSIZE TIOCGSIZE
118184989Srafan# define IOCTL_SET_WINSIZE TIOCSSIZE
119184989Srafan# define STRUCT_WINSIZE struct ttysize
120184989Srafan# define WINSIZE_ROWS(n) n.ts_lines
121184989Srafan# define WINSIZE_COLS(n) n.ts_cols
122184989Srafan#else
123184989Srafan# ifdef TIOCGWINSZ
124184989Srafan#  define IOCTL_GET_WINSIZE TIOCGWINSZ
125184989Srafan#  define IOCTL_SET_WINSIZE TIOCSWINSZ
126184989Srafan#  define STRUCT_WINSIZE struct winsize
127184989Srafan#  define WINSIZE_ROWS(n) n.ws_row
128184989Srafan#  define WINSIZE_COLS(n) n.ws_col
129184989Srafan# endif
130184989Srafan#endif
131184989Srafan
13250276Speterextern char **environ;
13350276Speter
13450276Speter#undef CTRL
13550276Speter#define CTRL(x)	((x) & 0x1f)
13650276Speter
13750276Speterconst char *_nc_progname = "tset";
13850276Speter
13997049Speterstatic TTY mode, oldmode, original;
14050276Speter
141166124Srafanstatic bool opt_c;		/* set control-chars */
142166124Srafanstatic bool opt_w;		/* set window-size */
143166124Srafan
14497049Speterstatic bool can_restore = FALSE;
14566963Speterstatic bool isreset = FALSE;	/* invoked as reset */
14662449Speterstatic int terasechar = -1;	/* new erase character */
14762449Speterstatic int intrchar = -1;	/* new interrupt character */
14862449Speterstatic int tkillchar = -1;	/* new kill character */
14962449Speterstatic int tlines, tcolumns;	/* window size */
15050276Speter
15197049Speter#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
15250276Speter
15350276Speterstatic int
15462449SpeterCaselessCmp(const char *a, const char *b)
15562449Speter{				/* strcasecmp isn't portable */
15662449Speter    while (*a && *b) {
15762449Speter	int cmp = LOWERCASE(*a) - LOWERCASE(*b);
15862449Speter	if (cmp != 0)
15962449Speter	    break;
16062449Speter	a++, b++;
16162449Speter    }
16262449Speter    return LOWERCASE(*a) - LOWERCASE(*b);
16350276Speter}
16450276Speter
16550276Speterstatic void
16697049Speterexit_error(void)
16797049Speter{
16897049Speter    if (can_restore)
16997049Speter	SET_TTY(STDERR_FILENO, &original);
17097049Speter    (void) fprintf(stderr, "\n");
17197049Speter    fflush(stderr);
172166124Srafan    ExitProgram(EXIT_FAILURE);
17397049Speter    /* NOTREACHED */
17497049Speter}
17597049Speter
17697049Speterstatic void
17762449Spetererr(const char *fmt,...)
17850276Speter{
17962449Speter    va_list ap;
18062449Speter    va_start(ap, fmt);
181166124Srafan    (void) fprintf(stderr, "%s: ", _nc_progname);
18262449Speter    (void) vfprintf(stderr, fmt, ap);
18362449Speter    va_end(ap);
18497049Speter    exit_error();
18562449Speter    /* NOTREACHED */
18650276Speter}
18750276Speter
18850276Speterstatic void
18950276Speterfailed(const char *msg)
19050276Speter{
19162449Speter    char temp[BUFSIZ];
192166124Srafan    unsigned len = strlen(_nc_progname) + 2;
193166124Srafan
194184989Srafan    if ((int) len < (int) sizeof(temp) - 12) {
195166124Srafan	strcpy(temp, _nc_progname);
196166124Srafan	strcat(temp, ": ");
197166124Srafan    } else {
198166124Srafan	strcpy(temp, "tset: ");
199166124Srafan    }
200166124Srafan    perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
20197049Speter    exit_error();
20262449Speter    /* NOTREACHED */
20350276Speter}
20450276Speter
20550276Speterstatic void
20650276Spetercat(char *file)
20750276Speter{
20897049Speter    FILE *fp;
20997049Speter    size_t nr;
21062449Speter    char buf[BUFSIZ];
21150276Speter
21297049Speter    if ((fp = fopen(file, "r")) == 0)
21362449Speter	failed(file);
21450276Speter
21597049Speter    while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
21697049Speter	if (fwrite(buf, sizeof(char), nr, stderr) != nr)
21797049Speter	      failed("write to stderr");
21897049Speter    fclose(fp);
21950276Speter}
22050276Speter
22150276Speterstatic int
22250276Speteroutc(int c)
22350276Speter{
22462449Speter    return putc(c, stderr);
22550276Speter}
22650276Speter
22750276Speter/* Prompt the user for a terminal type. */
22850276Speterstatic const char *
22950276Speteraskuser(const char *dflt)
23050276Speter{
23162449Speter    static char answer[256];
23262449Speter    char *p;
23350276Speter
23462449Speter    /* We can get recalled; if so, don't continue uselessly. */
235166124Srafan    clearerr(stdin);
23662449Speter    if (feof(stdin) || ferror(stdin)) {
23762449Speter	(void) fprintf(stderr, "\n");
23897049Speter	exit_error();
23997049Speter	/* NOTREACHED */
24062449Speter    }
24162449Speter    for (;;) {
24262449Speter	if (dflt)
24362449Speter	    (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
24462449Speter	else
24562449Speter	    (void) fprintf(stderr, "Terminal type? ");
24662449Speter	(void) fflush(stderr);
24762449Speter
24862449Speter	if (fgets(answer, sizeof(answer), stdin) == 0) {
24962449Speter	    if (dflt == 0) {
25097049Speter		exit_error();
25197049Speter		/* NOTREACHED */
25262449Speter	    }
25362449Speter	    return (dflt);
25450276Speter	}
25550276Speter
25662449Speter	if ((p = strchr(answer, '\n')) != 0)
25762449Speter	    *p = '\0';
25862449Speter	if (answer[0])
25962449Speter	    return (answer);
26062449Speter	if (dflt != 0)
26162449Speter	    return (dflt);
26262449Speter    }
26350276Speter}
26450276Speter
26550276Speter/**************************************************************************
26650276Speter *
26750276Speter * Mapping logic begins here
26850276Speter *
26950276Speter **************************************************************************/
27050276Speter
27150276Speter/* Baud rate conditionals for mapping. */
27250276Speter#define	GT		0x01
27350276Speter#define	EQ		0x02
27450276Speter#define	LT		0x04
27550276Speter#define	NOT		0x08
27650276Speter#define	GE		(GT | EQ)
27750276Speter#define	LE		(LT | EQ)
27850276Speter
27950276Spetertypedef struct map {
28062449Speter    struct map *next;		/* Linked list of maps. */
28162449Speter    const char *porttype;	/* Port type, or "" for any. */
28262449Speter    const char *type;		/* Terminal type to select. */
28362449Speter    int conditional;		/* Baud rate conditionals bitmask. */
28466963Speter    int speed;			/* Baud rate to compare against. */
28550276Speter} MAP;
28650276Speter
28750276Speterstatic MAP *cur, *maplist;
28850276Speter
28950276Spetertypedef struct speeds {
29062449Speter    const char *string;
29162449Speter    int speed;
29250276Speter} SPEEDS;
29350276Speter
29462449Speterstatic const SPEEDS speeds[] =
29562449Speter{
29662449Speter    {"0", B0},
29762449Speter    {"50", B50},
29862449Speter    {"75", B75},
29962449Speter    {"110", B110},
30062449Speter    {"134", B134},
30162449Speter    {"134.5", B134},
30262449Speter    {"150", B150},
30362449Speter    {"200", B200},
30462449Speter    {"300", B300},
30562449Speter    {"600", B600},
30662449Speter    {"1200", B1200},
30762449Speter    {"1800", B1800},
30862449Speter    {"2400", B2400},
30962449Speter    {"4800", B4800},
31062449Speter    {"9600", B9600},
31166963Speter    /* sgttyb may define up to this point */
31266963Speter#ifdef B19200
31362449Speter    {"19200", B19200},
31466963Speter#endif
31566963Speter#ifdef B38400
31662449Speter    {"38400", B38400},
31766963Speter#endif
31866963Speter#ifdef B19200
31962449Speter    {"19200", B19200},
32066963Speter#endif
32166963Speter#ifdef B38400
32262449Speter    {"38400", B38400},
32366963Speter#endif
32450276Speter#ifdef B19200
32562449Speter    {"19200", B19200},
32650276Speter#else
32750276Speter#ifdef EXTA
32862449Speter    {"19200", EXTA},
32950276Speter#endif
33050276Speter#endif
33150276Speter#ifdef B38400
33262449Speter    {"38400", B38400},
33350276Speter#else
33450276Speter#ifdef EXTB
33562449Speter    {"38400", EXTB},
33650276Speter#endif
33750276Speter#endif
33850276Speter#ifdef B57600
33962449Speter    {"57600", B57600},
34050276Speter#endif
34150276Speter#ifdef B115200
34262449Speter    {"115200", B115200},
34350276Speter#endif
34450276Speter#ifdef B230400
34562449Speter    {"230400", B230400},
34650276Speter#endif
34750276Speter#ifdef B460800
34862449Speter    {"460800", B460800},
34950276Speter#endif
35062449Speter    {(char *) 0, 0}
35150276Speter};
35250276Speter
35350276Speterstatic int
35450276Spetertbaudrate(char *rate)
35550276Speter{
35662449Speter    const SPEEDS *sp;
35762449Speter    int found = FALSE;
35850276Speter
35962449Speter    /* The baudrate number can be preceded by a 'B', which is ignored. */
36062449Speter    if (*rate == 'B')
36162449Speter	++rate;
36250276Speter
36362449Speter    for (sp = speeds; sp->string; ++sp) {
36462449Speter	if (!CaselessCmp(rate, sp->string)) {
36562449Speter	    found = TRUE;
36662449Speter	    break;
36750276Speter	}
36862449Speter    }
36962449Speter    if (!found)
37062449Speter	err("unknown baud rate %s", rate);
37162449Speter    return (sp->speed);
37250276Speter}
37350276Speter
37450276Speter/*
37550276Speter * Syntax for -m:
37650276Speter * [port-type][test baudrate]:terminal-type
37750276Speter * The baud rate tests are: >, <, @, =, !
37850276Speter */
37950276Speterstatic void
38050276Speteradd_mapping(const char *port, char *arg)
38150276Speter{
38262449Speter    MAP *mapp;
38362449Speter    char *copy, *p;
38462449Speter    const char *termp;
38562449Speter    char *base = 0;
38650276Speter
38762449Speter    copy = strdup(arg);
388166124Srafan    mapp = (MAP *) malloc(sizeof(MAP));
38962449Speter    if (copy == 0 || mapp == 0)
39062449Speter	failed("malloc");
39162449Speter    mapp->next = 0;
39262449Speter    if (maplist == 0)
39362449Speter	cur = maplist = mapp;
39462449Speter    else {
39562449Speter	cur->next = mapp;
39662449Speter	cur = mapp;
39762449Speter    }
39850276Speter
39962449Speter    mapp->porttype = arg;
40062449Speter    mapp->conditional = 0;
40150276Speter
40262449Speter    arg = strpbrk(arg, "><@=!:");
40350276Speter
40462449Speter    if (arg == 0) {		/* [?]term */
40562449Speter	mapp->type = mapp->porttype;
40662449Speter	mapp->porttype = 0;
40762449Speter	goto done;
40862449Speter    }
40950276Speter
41062449Speter    if (arg == mapp->porttype)	/* [><@=! baud]:term */
41162449Speter	termp = mapp->porttype = 0;
41262449Speter    else
41362449Speter	termp = base = arg;
41450276Speter
41562449Speter    for (;; ++arg) {		/* Optional conditionals. */
41662449Speter	switch (*arg) {
41762449Speter	case '<':
41862449Speter	    if (mapp->conditional & GT)
41962449Speter		goto badmopt;
42062449Speter	    mapp->conditional |= LT;
42162449Speter	    break;
42262449Speter	case '>':
42362449Speter	    if (mapp->conditional & LT)
42462449Speter		goto badmopt;
42562449Speter	    mapp->conditional |= GT;
42662449Speter	    break;
42762449Speter	case '@':
42862449Speter	case '=':		/* Not documented. */
42962449Speter	    mapp->conditional |= EQ;
43062449Speter	    break;
43162449Speter	case '!':
43262449Speter	    mapp->conditional |= NOT;
43362449Speter	    break;
43462449Speter	default:
43562449Speter	    goto next;
43650276Speter	}
43762449Speter    }
43850276Speter
43962449Speter  next:
44062449Speter    if (*arg == ':') {
44162449Speter	if (mapp->conditional)
44262449Speter	    goto badmopt;
44362449Speter	++arg;
44462449Speter    } else {			/* Optional baudrate. */
44562449Speter	arg = strchr(p = arg, ':');
44662449Speter	if (arg == 0)
44762449Speter	    goto badmopt;
44862449Speter	*arg++ = '\0';
44962449Speter	mapp->speed = tbaudrate(p);
45062449Speter    }
45150276Speter
45262449Speter    if (arg == (char *) 0)	/* Non-optional type. */
45362449Speter	goto badmopt;
45450276Speter
45562449Speter    mapp->type = arg;
45650276Speter
45762449Speter    /* Terminate porttype, if specified. */
45862449Speter    if (termp != 0)
45962449Speter	*base = '\0';
46050276Speter
46162449Speter    /* If a NOT conditional, reverse the test. */
46262449Speter    if (mapp->conditional & NOT)
46362449Speter	mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
46450276Speter
46562449Speter    /* If user specified a port with an option flag, set it. */
466184989Srafan  done:
467184989Srafan    if (port) {
468184989Srafan	if (mapp->porttype) {
469184989Srafan	  badmopt:
470184989Srafan	    err("illegal -m option format: %s", copy);
471184989Srafan	}
47262449Speter	mapp->porttype = port;
47362449Speter    }
474184989Srafan    free(copy);
47550276Speter#ifdef MAPDEBUG
47662449Speter    (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
47762449Speter    (void) printf("type: %s\n", mapp->type);
47862449Speter    (void) printf("conditional: ");
47962449Speter    p = "";
48062449Speter    if (mapp->conditional & GT) {
48162449Speter	(void) printf("GT");
48262449Speter	p = "/";
48362449Speter    }
48462449Speter    if (mapp->conditional & EQ) {
48562449Speter	(void) printf("%sEQ", p);
48662449Speter	p = "/";
48762449Speter    }
48862449Speter    if (mapp->conditional & LT)
48962449Speter	(void) printf("%sLT", p);
49062449Speter    (void) printf("\nspeed: %d\n", mapp->speed);
49150276Speter#endif
49250276Speter}
49350276Speter
49450276Speter/*
49550276Speter * Return the type of terminal to use for a port of type 'type', as specified
49650276Speter * by the first applicable mapping in 'map'.  If no mappings apply, return
49750276Speter * 'type'.
49850276Speter */
49950276Speterstatic const char *
50050276Spetermapped(const char *type)
50150276Speter{
50262449Speter    MAP *mapp;
50362449Speter    int match;
50450276Speter
50562449Speter    for (mapp = maplist; mapp; mapp = mapp->next)
50662449Speter	if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
50762449Speter	    switch (mapp->conditional) {
50862449Speter	    case 0:		/* No test specified. */
50962449Speter		match = TRUE;
51062449Speter		break;
51162449Speter	    case EQ:
51262449Speter		match = (ospeed == mapp->speed);
51362449Speter		break;
51462449Speter	    case GE:
51562449Speter		match = (ospeed >= mapp->speed);
51662449Speter		break;
51762449Speter	    case GT:
51862449Speter		match = (ospeed > mapp->speed);
51962449Speter		break;
52062449Speter	    case LE:
52162449Speter		match = (ospeed <= mapp->speed);
52262449Speter		break;
52362449Speter	    case LT:
52462449Speter		match = (ospeed < mapp->speed);
52562449Speter		break;
52662449Speter	    default:
52762449Speter		match = FALSE;
52862449Speter	    }
52962449Speter	    if (match)
53062449Speter		return (mapp->type);
53162449Speter	}
53262449Speter    /* No match found; return given type. */
53362449Speter    return (type);
53450276Speter}
53550276Speter
53650276Speter/**************************************************************************
53750276Speter *
53850276Speter * Entry fetching
53950276Speter *
54050276Speter **************************************************************************/
54150276Speter
54250276Speter/*
54350276Speter * Figure out what kind of terminal we're dealing with, and then read in
54450276Speter * its termcap entry.
54550276Speter */
54650276Speterstatic const char *
54750276Speterget_termcap_entry(char *userarg)
54850276Speter{
54976726Speter    int errret;
55062449Speter    char *p;
55162449Speter    const char *ttype;
55250276Speter#if HAVE_GETTTYNAM
55362449Speter    struct ttyent *t;
55450276Speter#else
55562449Speter    FILE *fp;
55650276Speter#endif
55762449Speter    char *ttypath;
55850276Speter
55962449Speter    if (userarg) {
56062449Speter	ttype = userarg;
56162449Speter	goto found;
56262449Speter    }
56350276Speter
56462449Speter    /* Try the environment. */
56562449Speter    if ((ttype = getenv("TERM")) != 0)
56662449Speter	goto map;
56750276Speter
56862449Speter    if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
56966963Speter	p = _nc_basename(ttypath);
57050276Speter#if HAVE_GETTTYNAM
57162449Speter	/*
57262449Speter	 * We have the 4.3BSD library call getttynam(3); that means
57362449Speter	 * there's an /etc/ttys to look up device-to-type mappings in.
57462449Speter	 * Try ttyname(3); check for dialup or other mapping.
57562449Speter	 */
57662449Speter	if ((t = getttynam(p))) {
57762449Speter	    ttype = t->ty_type;
57862449Speter	    goto map;
57962449Speter	}
58050276Speter#else
58162449Speter	if ((fp = fopen("/etc/ttytype", "r")) != 0
58262449Speter	    || (fp = fopen("/etc/ttys", "r")) != 0) {
58362449Speter	    char buffer[BUFSIZ];
58462449Speter	    char *s, *t, *d;
58550276Speter
58662449Speter	    while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
58762449Speter		for (s = buffer, t = d = 0; *s; s++) {
58897049Speter		    if (isspace(UChar(*s)))
58962449Speter			*s = '\0';
59062449Speter		    else if (t == 0)
59162449Speter			t = s;
59262449Speter		    else if (d == 0 && s != buffer && s[-1] == '\0')
59362449Speter			d = s;
59450276Speter		}
59562449Speter		if (t != 0 && d != 0 && !strcmp(d, p)) {
59662449Speter		    ttype = strdup(t);
59762449Speter		    fclose(fp);
59862449Speter		    goto map;
59962449Speter		}
60062449Speter	    }
60162449Speter	    fclose(fp);
60262449Speter	}
60350276Speter#endif /* HAVE_GETTTYNAM */
60462449Speter    }
60550276Speter
60662449Speter    /* If still undefined, use "unknown". */
60762449Speter    ttype = "unknown";
60850276Speter
60962449Speter  map:ttype = mapped(ttype);
61050276Speter
61162449Speter    /*
61262449Speter     * If not a path, remove TERMCAP from the environment so we get a
61362449Speter     * real entry from /etc/termcap.  This prevents us from being fooled
61462449Speter     * by out of date stuff in the environment.
61562449Speter     */
616166124Srafan  found:if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
61762449Speter	/* 'unsetenv("TERMCAP")' is not portable.
61862449Speter	 * The 'environ' array is better.
61950276Speter	 */
62062449Speter	int n;
62162449Speter	for (n = 0; environ[n] != 0; n++) {
62262449Speter	    if (!strncmp("TERMCAP=", environ[n], 8)) {
62362449Speter		while ((environ[n] = environ[n + 1]) != 0) {
62462449Speter		    n++;
62550276Speter		}
62662449Speter		break;
62762449Speter	    }
62850276Speter	}
62962449Speter    }
63050276Speter
63162449Speter    /*
63262449Speter     * ttype now contains a pointer to the type of the terminal.
63362449Speter     * If the first character is '?', ask the user.
63462449Speter     */
63562449Speter    if (ttype[0] == '?') {
63662449Speter	if (ttype[1] != '\0')
63762449Speter	    ttype = askuser(ttype + 1);
63862449Speter	else
63962449Speter	    ttype = askuser(0);
64062449Speter    }
64162449Speter    /* Find the terminfo entry.  If it doesn't exist, ask the user. */
64276726Speter    while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
64376726Speter	   != OK) {
64462449Speter	if (errret == 0) {
645166124Srafan	    (void) fprintf(stderr, "%s: unknown terminal type %s\n",
646166124Srafan			   _nc_progname, ttype);
64762449Speter	    ttype = 0;
64862449Speter	} else {
64962449Speter	    (void) fprintf(stderr,
650166124Srafan			   "%s: can't initialize terminal type %s (error %d)\n",
651166124Srafan			   _nc_progname, ttype, errret);
65262449Speter	    ttype = 0;
65350276Speter	}
65462449Speter	ttype = askuser(ttype);
65562449Speter    }
65650276Speter#if BROKEN_LINKER
65762449Speter    tgetflag("am");		/* force lib_termcap.o to be linked for 'ospeed' */
65850276Speter#endif
65962449Speter    return (ttype);
66050276Speter}
66150276Speter
66250276Speter/**************************************************************************
66350276Speter *
66450276Speter * Mode-setting logic
66550276Speter *
66650276Speter **************************************************************************/
66750276Speter
66850276Speter/* some BSD systems have these built in, some systems are missing
669166124Srafan * one or more definitions. The safest solution is to override unless the
670166124Srafan * commonly-altered ones are defined.
67150276Speter */
672166124Srafan#if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
67350276Speter#undef CEOF
67450276Speter#undef CERASE
67550276Speter#undef CINTR
67650276Speter#undef CKILL
67750276Speter#undef CLNEXT
67850276Speter#undef CRPRNT
67950276Speter#undef CQUIT
68050276Speter#undef CSTART
68150276Speter#undef CSTOP
68250276Speter#undef CSUSP
683166124Srafan#endif
68450276Speter
68550276Speter/* control-character defaults */
686166124Srafan#ifndef CEOF
68750276Speter#define CEOF	CTRL('D')
688166124Srafan#endif
689166124Srafan#ifndef CERASE
69050276Speter#define CERASE	CTRL('H')
691166124Srafan#endif
692166124Srafan#ifndef CINTR
69350276Speter#define CINTR	127		/* ^? */
694166124Srafan#endif
695166124Srafan#ifndef CKILL
69650276Speter#define CKILL	CTRL('U')
697166124Srafan#endif
698166124Srafan#ifndef CLNEXT
69950276Speter#define CLNEXT  CTRL('v')
700166124Srafan#endif
701166124Srafan#ifndef CRPRNT
70250276Speter#define CRPRNT  CTRL('r')
703166124Srafan#endif
704166124Srafan#ifndef CQUIT
70550276Speter#define CQUIT	CTRL('\\')
706166124Srafan#endif
707166124Srafan#ifndef CSTART
70850276Speter#define CSTART	CTRL('Q')
709166124Srafan#endif
710166124Srafan#ifndef CSTOP
71150276Speter#define CSTOP	CTRL('S')
712166124Srafan#endif
713166124Srafan#ifndef CSUSP
71450276Speter#define CSUSP	CTRL('Z')
715166124Srafan#endif
71650276Speter
717166124Srafan#if defined(_POSIX_VDISABLE)
718166124Srafan#define DISABLED(val)   (((_POSIX_VDISABLE != -1) \
719166124Srafan		       && ((val) == _POSIX_VDISABLE)) \
720166124Srafan		      || ((val) <= 0))
721166124Srafan#else
722166124Srafan#define DISABLED(val)   ((int)(val) <= 0)
723166124Srafan#endif
72450276Speter
725166124Srafan#define CHK(val, dft)   (DISABLED(val) ? dft : val)
726166124Srafan
72762449Speterstatic bool set_tabs(void);
72850276Speter
72950276Speter/*
73050276Speter * Reset the terminal mode bits to a sensible state.  Very useful after
73150276Speter * a child program dies in raw mode.
73250276Speter */
73350276Speterstatic void
73450276Speterreset_mode(void)
73550276Speter{
73650276Speter#ifdef TERMIOS
73762449Speter    tcgetattr(STDERR_FILENO, &mode);
73850276Speter#else
73962449Speter    stty(STDERR_FILENO, &mode);
74050276Speter#endif
74150276Speter
74250276Speter#ifdef TERMIOS
74350276Speter#if defined(VDISCARD) && defined(CDISCARD)
74462449Speter    mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
74550276Speter#endif
74662449Speter    mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
74762449Speter    mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
74850276Speter#if defined(VFLUSH) && defined(CFLUSH)
74962449Speter    mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
75050276Speter#endif
75162449Speter    mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
75262449Speter    mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
75350276Speter#if defined(VLNEXT) && defined(CLNEXT)
75462449Speter    mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
75550276Speter#endif
75662449Speter    mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
75750276Speter#if defined(VREPRINT) && defined(CRPRNT)
75862449Speter    mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
75950276Speter#endif
76050276Speter#if defined(VSTART) && defined(CSTART)
76162449Speter    mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
76250276Speter#endif
76350276Speter#if defined(VSTOP) && defined(CSTOP)
76462449Speter    mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
76550276Speter#endif
76650276Speter#if defined(VSUSP) && defined(CSUSP)
76762449Speter    mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
76850276Speter#endif
76950276Speter#if defined(VWERASE) && defined(CWERASE)
77062449Speter    mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
77150276Speter#endif
77250276Speter
77362449Speter    mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
77450276Speter#ifdef IUCLC
77566963Speter		      | IUCLC
77650276Speter#endif
77750276Speter#ifdef IXANY
77866963Speter		      | IXANY
77950276Speter#endif
78066963Speter		      | IXOFF);
78150276Speter
78262449Speter    mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
78350276Speter#ifdef IMAXBEL
78466963Speter		     | IMAXBEL
78550276Speter#endif
78662449Speter	);
78750276Speter
78862449Speter    mode.c_oflag &= ~(0
78950276Speter#ifdef OLCUC
79066963Speter		      | OLCUC
79150276Speter#endif
79250276Speter#ifdef OCRNL
79366963Speter		      | OCRNL
79450276Speter#endif
79550276Speter#ifdef ONOCR
79666963Speter		      | ONOCR
79750276Speter#endif
79850276Speter#ifdef ONLRET
79966963Speter		      | ONLRET
80050276Speter#endif
80150276Speter#ifdef OFILL
80266963Speter		      | OFILL
80350276Speter#endif
80450276Speter#ifdef OFDEL
80566963Speter		      | OFDEL
80650276Speter#endif
80750276Speter#ifdef NLDLY
808174993Srafan		      | NLDLY
80950276Speter#endif
810184989Srafan#ifdef CRDLY
811174993Srafan		      | CRDLY
812174993Srafan#endif
813184989Srafan#ifdef TABDLY
814174993Srafan		      | TABDLY
815174993Srafan#endif
816184989Srafan#ifdef BSDLY
817174993Srafan		      | BSDLY
818174993Srafan#endif
819184989Srafan#ifdef VTDLY
820174993Srafan		      | VTDLY
821174993Srafan#endif
822174993Srafan#ifdef FFDLY
823174993Srafan		      | FFDLY
824174993Srafan#endif
82562449Speter	);
82650276Speter
82762449Speter    mode.c_oflag |= (OPOST
82850276Speter#ifdef ONLCR
82966963Speter		     | ONLCR
83050276Speter#endif
83162449Speter	);
83250276Speter
83362449Speter    mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
83462449Speter    mode.c_cflag |= (CS8 | CREAD);
83562449Speter    mode.c_lflag &= ~(ECHONL | NOFLSH
83650276Speter#ifdef TOSTOP
83766963Speter		      | TOSTOP
83850276Speter#endif
83950276Speter#ifdef ECHOPTR
84066963Speter		      | ECHOPRT
84150276Speter#endif
84250276Speter#ifdef XCASE
84366963Speter		      | XCASE
84450276Speter#endif
84562449Speter	);
84650276Speter
84762449Speter    mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
84850276Speter#ifdef ECHOCTL
84966963Speter		     | ECHOCTL
85050276Speter#endif
85150276Speter#ifdef ECHOKE
85266963Speter		     | ECHOKE
85350276Speter#endif
85462449Speter	);
85550276Speter#endif
85650276Speter
85797049Speter    SET_TTY(STDERR_FILENO, &mode);
85850276Speter}
85950276Speter
86050276Speter/*
86150276Speter * Returns a "good" value for the erase character.  This is loosely based on
86250276Speter * the BSD4.4 logic.
86350276Speter */
86466963Speter#ifdef TERMIOS
86550276Speterstatic int
86650276Speterdefault_erase(void)
86750276Speter{
86862449Speter    int result;
86950276Speter
87062449Speter    if (over_strike
87162449Speter	&& key_backspace != 0
87262449Speter	&& strlen(key_backspace) == 1)
87362449Speter	result = key_backspace[0];
87462449Speter    else
87562449Speter	result = CERASE;
87650276Speter
87762449Speter    return result;
87850276Speter}
87966963Speter#endif
88050276Speter
88150276Speter/*
88250276Speter * Update the values of the erase, interrupt, and kill characters in 'mode'.
88350276Speter *
88450276Speter * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
88550276Speter * characters if they're unset, or if we specify them as options.  This differs
88650276Speter * from BSD 4.4 tset, which always sets erase.
88750276Speter */
88850276Speterstatic void
88950276Speterset_control_chars(void)
89050276Speter{
89150276Speter#ifdef TERMIOS
892166124Srafan    if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0)
893184989Srafan	mode.c_cc[VERASE] = (terasechar >= 0) ? terasechar : default_erase();
89450276Speter
895166124Srafan    if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0)
896184989Srafan	mode.c_cc[VINTR] = (intrchar >= 0) ? intrchar : CINTR;
89750276Speter
898166124Srafan    if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0)
899184989Srafan	mode.c_cc[VKILL] = (tkillchar >= 0) ? tkillchar : CKILL;
90050276Speter#endif
90150276Speter}
90250276Speter
90350276Speter/*
90450276Speter * Set up various conversions in 'mode', including parity, tabs, returns,
90550276Speter * echo, and case, according to the termcap entry.  If the program we're
90650276Speter * running was named with a leading upper-case character, map external
90750276Speter * uppercase to internal lowercase.
90850276Speter */
90950276Speterstatic void
91050276Speterset_conversions(void)
91150276Speter{
91250276Speter#ifdef __OBSOLETE__
91362449Speter    /*
91462449Speter     * Conversion logic for some *really* ancient terminal glitches,
91562449Speter     * not supported in terminfo.  Left here for succeeding generations
91662449Speter     * to marvel at.
91762449Speter     */
91862449Speter    if (tgetflag("UC")) {
91950276Speter#ifdef IUCLC
92062449Speter	mode.c_iflag |= IUCLC;
92162449Speter	mode.c_oflag |= OLCUC;
92250276Speter#endif
92362449Speter    } else if (tgetflag("LC")) {
92450276Speter#ifdef IUCLC
92562449Speter	mode.c_iflag &= ~IUCLC;
92662449Speter	mode.c_oflag &= ~OLCUC;
92750276Speter#endif
92862449Speter    }
92962449Speter    mode.c_iflag &= ~(PARMRK | INPCK);
93062449Speter    mode.c_lflag |= ICANON;
93162449Speter    if (tgetflag("EP")) {
93262449Speter	mode.c_cflag |= PARENB;
93362449Speter	mode.c_cflag &= ~PARODD;
93462449Speter    }
93562449Speter    if (tgetflag("OP")) {
93662449Speter	mode.c_cflag |= PARENB;
93762449Speter	mode.c_cflag |= PARODD;
93862449Speter    }
93950276Speter#endif /* __OBSOLETE__ */
94050276Speter
94150276Speter#ifdef TERMIOS
94250276Speter#ifdef ONLCR
94362449Speter    mode.c_oflag |= ONLCR;
94450276Speter#endif
94562449Speter    mode.c_iflag |= ICRNL;
94662449Speter    mode.c_lflag |= ECHO;
94750276Speter#ifdef OXTABS
94862449Speter    mode.c_oflag |= OXTABS;
94950276Speter#endif /* OXTABS */
95050276Speter
95162449Speter    /* test used to be tgetflag("NL") */
95262449Speter    if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
95362449Speter	/* Newline, not linefeed. */
95450276Speter#ifdef ONLCR
95562449Speter	mode.c_oflag &= ~ONLCR;
95650276Speter#endif
95762449Speter	mode.c_iflag &= ~ICRNL;
95862449Speter    }
95950276Speter#ifdef __OBSOLETE__
96062449Speter    if (tgetflag("HD"))		/* Half duplex. */
96162449Speter	mode.c_lflag &= ~ECHO;
96250276Speter#endif /* __OBSOLETE__ */
96350276Speter#ifdef OXTABS
96462449Speter    /* test used to be tgetflag("pt") */
96562449Speter    if (has_hardware_tabs)	/* Print tabs. */
96662449Speter	mode.c_oflag &= ~OXTABS;
96750276Speter#endif /* OXTABS */
96862449Speter    mode.c_lflag |= (ECHOE | ECHOK);
96950276Speter#endif
97050276Speter}
97150276Speter
97250276Speter/* Output startup string. */
97350276Speterstatic void
97450276Speterset_init(void)
97550276Speter{
97662449Speter    char *p;
97762449Speter    bool settle;
97850276Speter
97950276Speter#ifdef __OBSOLETE__
98062449Speter    if (pad_char != (char *) 0)	/* Get/set pad character. */
98162449Speter	PC = pad_char[0];
98250276Speter#endif /* OBSOLETE */
98350276Speter
98450276Speter#ifdef TAB3
98562449Speter    if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
98662449Speter	oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
98797049Speter	SET_TTY(STDERR_FILENO, &oldmode);
98862449Speter    }
98950276Speter#endif
99062449Speter    settle = set_tabs();
99150276Speter
99262449Speter    if (isreset) {
99362449Speter	if ((p = reset_1string) != 0) {
99462449Speter	    tputs(p, 0, outc);
99562449Speter	    settle = TRUE;
99650276Speter	}
99762449Speter	if ((p = reset_2string) != 0) {
99862449Speter	    tputs(p, 0, outc);
99962449Speter	    settle = TRUE;
100062449Speter	}
100162449Speter	/* What about rf, rs3, as per terminfo man page? */
100262449Speter	/* also might be nice to send rmacs, rmul, rmm */
100362449Speter	if ((p = reset_file) != 0
100462449Speter	    || (p = init_file) != 0) {
100562449Speter	    cat(p);
100662449Speter	    settle = TRUE;
100762449Speter	}
100862449Speter    }
100950276Speter
101062449Speter    if (settle) {
101162449Speter	(void) putc('\r', stderr);
101262449Speter	(void) fflush(stderr);
101362449Speter	(void) napms(1000);	/* Settle the terminal. */
101462449Speter    }
101550276Speter}
101650276Speter
101750276Speter/*
101850276Speter * Set the hardware tabs on the terminal, using the ct (clear all tabs),
101950276Speter * st (set one tab) and ch (horizontal cursor addressing) capabilities.
102050276Speter * This is done before if and is, so they can patch in case we blow this.
102150276Speter * Return TRUE if we set any tab stops, FALSE if not.
102250276Speter */
102350276Speterstatic bool
1024166124Srafanset_tabs(void)
102550276Speter{
102662449Speter    if (set_tab && clear_all_tabs) {
102762449Speter	int c;
102850276Speter
102962449Speter	(void) putc('\r', stderr);	/* Force to left margin. */
103062449Speter	tputs(clear_all_tabs, 0, outc);
103150276Speter
103262449Speter	for (c = 8; c < tcolumns; c += 8) {
103362449Speter	    /* Get to the right column.  In BSD tset, this
103462449Speter	     * used to try a bunch of half-clever things
103562449Speter	     * with cup and hpa, for an average saving of
103662449Speter	     * somewhat less than two character times per
1037166124Srafan	     * tab stop, less than .01 sec at 2400cps. We
103862449Speter	     * lost all this cruft because it seemed to be
103962449Speter	     * introducing some odd bugs.
1040166124Srafan	     * -----------12345678----------- */
104162449Speter	    (void) fputs("        ", stderr);
104262449Speter	    tputs(set_tab, 0, outc);
104350276Speter	}
104462449Speter	putc('\r', stderr);
104562449Speter	return (TRUE);
104662449Speter    }
104762449Speter    return (FALSE);
104850276Speter}
104950276Speter
105050276Speter/**************************************************************************
105150276Speter *
105250276Speter * Main sequence
105350276Speter *
105450276Speter **************************************************************************/
105550276Speter
105650276Speter/*
105750276Speter * Tell the user if a control key has been changed from the default value.
105850276Speter */
105966963Speter#ifdef TERMIOS
106050276Speterstatic void
106150276Speterreport(const char *name, int which, unsigned def)
106250276Speter{
106362449Speter    unsigned older, newer;
106462449Speter    char *p;
106550276Speter
106662449Speter    newer = mode.c_cc[which];
106762449Speter    older = oldmode.c_cc[which];
106850276Speter
106962449Speter    if (older == newer && older == def)
107062449Speter	return;
107150276Speter
107262449Speter    (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
107350276Speter
1074166124Srafan    if (DISABLED(newer))
1075166124Srafan	(void) fprintf(stderr, "undef.\n");
107662449Speter    /*
107762449Speter     * Check 'delete' before 'backspace', since the key_backspace value
107862449Speter     * is ambiguous.
107962449Speter     */
1080166124Srafan    else if (newer == 0177)
108162449Speter	(void) fprintf(stderr, "delete.\n");
108262449Speter    else if ((p = key_backspace) != 0
108366963Speter	     && newer == (unsigned char) p[0]
108466963Speter	     && p[1] == '\0')
108562449Speter	(void) fprintf(stderr, "backspace.\n");
108662449Speter    else if (newer < 040) {
108762449Speter	newer ^= 0100;
1088166124Srafan	(void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
108962449Speter    } else
1090166124Srafan	(void) fprintf(stderr, "%c.\n", UChar(newer));
109166963Speter}
109250276Speter#endif
109350276Speter
109450276Speter/*
109550276Speter * Convert the obsolete argument forms into something that getopt can handle.
109650276Speter * This means that -e, -i and -k get default arguments supplied for them.
109750276Speter */
109850276Speterstatic void
109950276Speterobsolete(char **argv)
110050276Speter{
110162449Speter    for (; *argv; ++argv) {
110262449Speter	char *parm = argv[0];
110350276Speter
110462449Speter	if (parm[0] == '-' && parm[1] == '\0') {
110562449Speter	    argv[0] = strdup("-q");
110662449Speter	    continue;
110762449Speter	}
110850276Speter
110962449Speter	if ((parm[0] != '-')
111062449Speter	    || (argv[1] && argv[1][0] != '-')
111162449Speter	    || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
111262449Speter	    || (parm[2] != '\0'))
111362449Speter	    continue;
111462449Speter	switch (argv[0][1]) {
111562449Speter	case 'e':
111662449Speter	    argv[0] = strdup("-e^H");
111762449Speter	    break;
111862449Speter	case 'i':
111962449Speter	    argv[0] = strdup("-i^C");
112062449Speter	    break;
112162449Speter	case 'k':
112262449Speter	    argv[0] = strdup("-k^U");
112362449Speter	    break;
112450276Speter	}
112562449Speter    }
112650276Speter}
112750276Speter
112850276Speterstatic void
1129166124Srafanusage(void)
113050276Speter{
1131166124Srafan    static const char *tbl[] =
1132166124Srafan    {
1133166124Srafan	""
1134166124Srafan	,"Options:"
1135166124Srafan	,"  -c          set control characters"
1136166124Srafan	,"  -e ch       erase character"
1137166124Srafan	,"  -I          no initialization strings"
1138166124Srafan	,"  -i ch       interrupt character"
1139166124Srafan	,"  -k ch       kill character"
1140166124Srafan	,"  -m mapping  map identifier to type"
1141166124Srafan	,"  -Q          do not output control key settings"
1142166124Srafan	,"  -r          display term on stderr"
1143166124Srafan	,"  -s          output TERM set command"
1144166124Srafan	,"  -V          print curses-version"
1145166124Srafan	,"  -w          set window-size"
1146166124Srafan    };
1147166124Srafan    unsigned n;
1148166124Srafan    (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
1149166124Srafan    for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n)
1150166124Srafan	fprintf(stderr, "%s\n", tbl[n]);
115197049Speter    exit_error();
115297049Speter    /* NOTREACHED */
115350276Speter}
115450276Speter
115562449Speterstatic char
115662449Speterarg_to_char(void)
115750276Speter{
1158184989Srafan    return (char) ((optarg[0] == '^' && optarg[1] != '\0')
1159184989Srafan		   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
1160184989Srafan		   : optarg[0]);
116150276Speter}
116250276Speter
116350276Speterint
116450276Spetermain(int argc, char **argv)
116550276Speter{
116662449Speter    int ch, noinit, noset, quiet, Sflag, sflag, showterm;
116762449Speter    const char *p;
116862449Speter    const char *ttype;
116950276Speter
117062449Speter    obsolete(argv);
117162449Speter    noinit = noset = quiet = Sflag = sflag = showterm = 0;
1172174993Srafan    while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
117362449Speter	switch (ch) {
1174166124Srafan	case 'c':		/* set control-chars */
1175166124Srafan	    opt_c = TRUE;
117662449Speter	    break;
117762449Speter	case 'a':		/* OBSOLETE: map identifier to type */
117862449Speter	    add_mapping("arpanet", optarg);
117962449Speter	    break;
118062449Speter	case 'd':		/* OBSOLETE: map identifier to type */
118162449Speter	    add_mapping("dialup", optarg);
118262449Speter	    break;
118362449Speter	case 'e':		/* erase character */
118462449Speter	    terasechar = arg_to_char();
118562449Speter	    break;
118662449Speter	case 'I':		/* no initialization strings */
118762449Speter	    noinit = 1;
118862449Speter	    break;
118962449Speter	case 'i':		/* interrupt character */
119062449Speter	    intrchar = arg_to_char();
119162449Speter	    break;
119262449Speter	case 'k':		/* kill character */
119362449Speter	    tkillchar = arg_to_char();
119462449Speter	    break;
119562449Speter	case 'm':		/* map identifier to type */
119662449Speter	    add_mapping(0, optarg);
119762449Speter	    break;
119862449Speter	case 'n':		/* OBSOLETE: set new tty driver */
119962449Speter	    break;
120062449Speter	case 'p':		/* OBSOLETE: map identifier to type */
120162449Speter	    add_mapping("plugboard", optarg);
120262449Speter	    break;
120362449Speter	case 'Q':		/* don't output control key settings */
120462449Speter	    quiet = 1;
120562449Speter	    break;
1206166124Srafan	case 'q':		/* display term only */
1207166124Srafan	    noset = 1;
120862449Speter	    break;
120962449Speter	case 'r':		/* display term on stderr */
121062449Speter	    showterm = 1;
121162449Speter	    break;
1212166124Srafan	case 'S':		/* OBSOLETE: output TERM & TERMCAP */
1213166124Srafan	    Sflag = 1;
1214166124Srafan	    break;
121562449Speter	case 's':		/* output TERM set command */
121662449Speter	    sflag = 1;
121762449Speter	    break;
1218166124Srafan	case 'V':		/* print curses-version */
121966963Speter	    puts(curses_version());
1220166124Srafan	    ExitProgram(EXIT_SUCCESS);
1221166124Srafan	case 'w':		/* set window-size */
1222166124Srafan	    opt_w = TRUE;
1223166124Srafan	    break;
122462449Speter	case '?':
122562449Speter	default:
1226166124Srafan	    usage();
122750276Speter	}
122862449Speter    }
1229166124Srafan
1230166124Srafan    _nc_progname = _nc_rootname(*argv);
123162449Speter    argc -= optind;
123262449Speter    argv += optind;
123350276Speter
123462449Speter    if (argc > 1)
1235166124Srafan	usage();
123650276Speter
1237166124Srafan    if (!opt_c && !opt_w)
1238166124Srafan	opt_c = opt_w = TRUE;
1239166124Srafan
1240166124Srafan    if (GET_TTY(STDERR_FILENO, &mode) < 0)
1241166124Srafan	failed("standard error");
1242166124Srafan    can_restore = TRUE;
1243166124Srafan    original = oldmode = mode;
1244166124Srafan#ifdef TERMIOS
1245184989Srafan    ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
1246166124Srafan#else
1247184989Srafan    ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
1248166124Srafan#endif
1249166124Srafan
1250166124Srafan    if (!strcmp(_nc_progname, PROG_RESET)) {
1251166124Srafan	isreset = TRUE;
1252166124Srafan	reset_mode();
1253166124Srafan    }
1254166124Srafan
125562449Speter    ttype = get_termcap_entry(*argv);
125650276Speter
125762449Speter    if (!noset) {
125862449Speter	tcolumns = columns;
125962449Speter	tlines = lines;
126050276Speter
1261184989Srafan#if HAVE_SIZECHANGE
1262166124Srafan	if (opt_w) {
1263184989Srafan	    STRUCT_WINSIZE win;
1264184989Srafan	    /* Set window size if not set already */
1265184989Srafan	    (void) ioctl(STDERR_FILENO, IOCTL_GET_WINSIZE, &win);
1266184989Srafan	    if (WINSIZE_ROWS(win) == 0 &&
1267184989Srafan		WINSIZE_COLS(win) == 0 &&
1268166124Srafan		tlines > 0 && tcolumns > 0) {
1269184989Srafan		WINSIZE_ROWS(win) = tlines;
1270184989Srafan		WINSIZE_COLS(win) = tcolumns;
1271184989Srafan		(void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win);
1272166124Srafan	    }
127362449Speter	}
127450276Speter#endif
1275166124Srafan	if (opt_c) {
1276166124Srafan	    set_control_chars();
1277166124Srafan	    set_conversions();
127850276Speter
1279166124Srafan	    if (!noinit)
1280166124Srafan		set_init();
128150276Speter
1282166124Srafan	    /* Set the modes if they've changed. */
1283166124Srafan	    if (memcmp(&mode, &oldmode, sizeof(mode))) {
1284166124Srafan		SET_TTY(STDERR_FILENO, &mode);
1285166124Srafan	    }
128650276Speter	}
128762449Speter    }
128850276Speter
128962449Speter    /* Get the terminal name from the entry. */
129062449Speter    ttype = _nc_first_name(cur_term->type.term_names);
129150276Speter
129262449Speter    if (noset)
129362449Speter	(void) printf("%s\n", ttype);
129462449Speter    else {
129562449Speter	if (showterm)
129662449Speter	    (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
129762449Speter	/*
129862449Speter	 * If erase, kill and interrupt characters could have been
129962449Speter	 * modified and not -Q, display the changes.
130062449Speter	 */
130166963Speter#ifdef TERMIOS
130262449Speter	if (!quiet) {
130362449Speter	    report("Erase", VERASE, CERASE);
1304166124Srafan	    report("Kill", VKILL, CKILL);
1305166124Srafan	    report("Interrupt", VINTR, CINTR);
130650276Speter	}
130766963Speter#endif
130862449Speter    }
130950276Speter
131062449Speter    if (Sflag)
131162449Speter	err("The -S option is not supported under terminfo.");
131250276Speter
131362449Speter    if (sflag) {
1314166124Srafan	int len;
1315166124Srafan	char *var;
1316166124Srafan	char *leaf;
131762449Speter	/*
131862449Speter	 * Figure out what shell we're using.  A hack, we look for an
131962449Speter	 * environmental variable SHELL ending in "csh".
132062449Speter	 */
1321166124Srafan	if ((var = getenv("SHELL")) != 0
1322184989Srafan	    && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
1323166124Srafan	    && !strcmp(leaf + len - 3, "csh"))
132462449Speter	    p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
132562449Speter	else
132662449Speter	    p = "TERM=%s;\n";
132762449Speter	(void) printf(p, ttype);
132862449Speter    }
132950276Speter
1330166124Srafan    ExitProgram(EXIT_SUCCESS);
133150276Speter}
1332