150276Speter/****************************************************************************
2262685Sdelphij * Copyright (c) 1998-2012,2013 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/*
36262629Sdelphij * Notes:
37262629Sdelphij * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
38262629Sdelphij * lines from that version, and made changes/additions for 150 lines.  There
39262629Sdelphij * was no reformatting, so with/without ignoring whitespace, the amount of
40262629Sdelphij * change is the same.
41262629Sdelphij *
42262629Sdelphij * Comparing with current (2009) source, excluding this comment:
43262629Sdelphij * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
44262629Sdelphij *    changed/added.
45262629Sdelphij * a) Ignoring whitespace, the current version still uses 516 lines from the
46262629Sdelphij *    4.4BSD Lite sources, with 402 lines changed/added.
47262629Sdelphij *
48262629Sdelphij * Raymond's original comment on this follows...
49262629Sdelphij */
50262629Sdelphij
51262629Sdelphij/*
5250276Speter * tset.c - terminal initialization utility
5350276Speter *
5450276Speter * This code was mostly swiped from 4.4BSD tset, with some obsolescent
5550276Speter * cruft removed and substantial portions rewritten.  A Regents of the
5650276Speter * University of California copyright applies to some portions of the
5750276Speter * code, and is reproduced below:
5850276Speter */
5950276Speter/*-
6050276Speter * Copyright (c) 1980, 1991, 1993
6150276Speter *	The Regents of the University of California.  All rights reserved.
6250276Speter *
6350276Speter * Redistribution and use in source and binary forms, with or without
6450276Speter * modification, are permitted provided that the following conditions
6550276Speter * are met:
6650276Speter * 1. Redistributions of source code must retain the above copyright
6750276Speter *    notice, this list of conditions and the following disclaimer.
6850276Speter * 2. Redistributions in binary form must reproduce the above copyright
6950276Speter *    notice, this list of conditions and the following disclaimer in the
7050276Speter *    documentation and/or other materials provided with the distribution.
71262629Sdelphij * 3. Neither the name of the University nor the names of its contributors
7250276Speter *    may be used to endorse or promote products derived from this software
7350276Speter *    without specific prior written permission.
7450276Speter *
7550276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
7650276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7750276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7850276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
7950276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8050276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8150276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8250276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8350276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8450276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8550276Speter * SUCH DAMAGE.
8650276Speter */
8750276Speter
88174993Srafan#define USE_LIBTINFO
8950276Speter#define __INTERNAL_CAPS_VISIBLE	/* we need to see has_hardware_tabs */
9050276Speter#include <progs.priv.h>
9150276Speter
9250276Speter#include <errno.h>
9350276Speter#include <stdio.h>
9450276Speter#include <termcap.h>
9550276Speter#include <fcntl.h>
9650276Speter
9750276Speter#if HAVE_GETTTYNAM && HAVE_TTYENT_H
9850276Speter#include <ttyent.h>
9950276Speter#endif
10050276Speter#ifdef NeXT
10150276Speterchar *ttyname(int fd);
10250276Speter#endif
10350276Speter
104184989Srafan#if HAVE_SIZECHANGE
105184989Srafan# if !defined(sun) || !TERMIOS
106184989Srafan#  if HAVE_SYS_IOCTL_H
107184989Srafan#   include <sys/ioctl.h>
108184989Srafan#  endif
109184989Srafan# endif
11050276Speter#endif
11150276Speter
11250276Speter#if NEED_PTEM_H
11350276Speter/* they neglected to define struct winsize in termios.h -- it's only
11450276Speter   in termio.h	*/
11597049Speter#include <sys/stream.h>
11697049Speter#include <sys/ptem.h>
11750276Speter#endif
11850276Speter
11950276Speter#include <dump_entry.h>
12066963Speter#include <transform.h>
12150276Speter
122262685SdelphijMODULE_ID("$Id: tset.c,v 1.93 2013/12/15 01:05:56 tom Exp $")
12350276Speter
124184989Srafan/*
125184989Srafan * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
126184989Srafan * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
127184989Srafan */
128184989Srafan#ifdef TIOCGSIZE
129184989Srafan# define IOCTL_GET_WINSIZE TIOCGSIZE
130184989Srafan# define IOCTL_SET_WINSIZE TIOCSSIZE
131184989Srafan# define STRUCT_WINSIZE struct ttysize
132184989Srafan# define WINSIZE_ROWS(n) n.ts_lines
133184989Srafan# define WINSIZE_COLS(n) n.ts_cols
134184989Srafan#else
135184989Srafan# ifdef TIOCGWINSZ
136184989Srafan#  define IOCTL_GET_WINSIZE TIOCGWINSZ
137184989Srafan#  define IOCTL_SET_WINSIZE TIOCSWINSZ
138184989Srafan#  define STRUCT_WINSIZE struct winsize
139184989Srafan#  define WINSIZE_ROWS(n) n.ws_row
140184989Srafan#  define WINSIZE_COLS(n) n.ws_col
141184989Srafan# endif
142184989Srafan#endif
143184989Srafan
144262629Sdelphij#ifndef environ
14550276Speterextern char **environ;
146262629Sdelphij#endif
14750276Speter
14850276Speter#undef CTRL
14950276Speter#define CTRL(x)	((x) & 0x1f)
15050276Speter
151262685Sdelphijstatic void failed(const char *) GCC_NORETURN;
152262685Sdelphijstatic void exit_error(void) GCC_NORETURN;
153262685Sdelphijstatic void err(const char *,...) GCC_NORETURN;
154262685Sdelphij
15550276Speterconst char *_nc_progname = "tset";
15650276Speter
15797049Speterstatic TTY mode, oldmode, original;
15850276Speter
159166124Srafanstatic bool opt_c;		/* set control-chars */
160166124Srafanstatic bool opt_w;		/* set window-size */
161166124Srafan
16297049Speterstatic bool can_restore = FALSE;
16366963Speterstatic bool isreset = FALSE;	/* invoked as reset */
16462449Speterstatic int terasechar = -1;	/* new erase character */
16562449Speterstatic int intrchar = -1;	/* new interrupt character */
16662449Speterstatic int tkillchar = -1;	/* new kill character */
167262685Sdelphij
168262685Sdelphij#if HAVE_SIZECHANGE
16962449Speterstatic int tlines, tcolumns;	/* window size */
170262685Sdelphij#endif
17150276Speter
17297049Speter#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
17350276Speter
17450276Speterstatic int
17562449SpeterCaselessCmp(const char *a, const char *b)
17662449Speter{				/* strcasecmp isn't portable */
17762449Speter    while (*a && *b) {
17862449Speter	int cmp = LOWERCASE(*a) - LOWERCASE(*b);
17962449Speter	if (cmp != 0)
18062449Speter	    break;
18162449Speter	a++, b++;
18262449Speter    }
18362449Speter    return LOWERCASE(*a) - LOWERCASE(*b);
18450276Speter}
18550276Speter
18650276Speterstatic void
18797049Speterexit_error(void)
18897049Speter{
18997049Speter    if (can_restore)
19097049Speter	SET_TTY(STDERR_FILENO, &original);
19197049Speter    (void) fprintf(stderr, "\n");
19297049Speter    fflush(stderr);
193166124Srafan    ExitProgram(EXIT_FAILURE);
19497049Speter    /* NOTREACHED */
19597049Speter}
19697049Speter
19797049Speterstatic void
19862449Spetererr(const char *fmt,...)
19950276Speter{
20062449Speter    va_list ap;
20162449Speter    va_start(ap, fmt);
202166124Srafan    (void) fprintf(stderr, "%s: ", _nc_progname);
20362449Speter    (void) vfprintf(stderr, fmt, ap);
20462449Speter    va_end(ap);
20597049Speter    exit_error();
20662449Speter    /* NOTREACHED */
20750276Speter}
20850276Speter
20950276Speterstatic void
21050276Speterfailed(const char *msg)
21150276Speter{
21262449Speter    char temp[BUFSIZ];
213262685Sdelphij    size_t len = strlen(_nc_progname) + 2;
214166124Srafan
215184989Srafan    if ((int) len < (int) sizeof(temp) - 12) {
216262685Sdelphij	_nc_STRCPY(temp, _nc_progname, sizeof(temp));
217262685Sdelphij	_nc_STRCAT(temp, ": ", sizeof(temp));
218166124Srafan    } else {
219262685Sdelphij	_nc_STRCPY(temp, "tset: ", sizeof(temp));
220166124Srafan    }
221166124Srafan    perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
22297049Speter    exit_error();
22362449Speter    /* NOTREACHED */
22450276Speter}
22550276Speter
22650276Speterstatic void
22750276Spetercat(char *file)
22850276Speter{
22997049Speter    FILE *fp;
23097049Speter    size_t nr;
23162449Speter    char buf[BUFSIZ];
23250276Speter
23397049Speter    if ((fp = fopen(file, "r")) == 0)
23462449Speter	failed(file);
23550276Speter
23697049Speter    while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
23797049Speter	if (fwrite(buf, sizeof(char), nr, stderr) != nr)
23897049Speter	      failed("write to stderr");
23997049Speter    fclose(fp);
24050276Speter}
24150276Speter
24250276Speterstatic int
24350276Speteroutc(int c)
24450276Speter{
24562449Speter    return putc(c, stderr);
24650276Speter}
24750276Speter
24850276Speter/* Prompt the user for a terminal type. */
24950276Speterstatic const char *
25050276Speteraskuser(const char *dflt)
25150276Speter{
25262449Speter    static char answer[256];
25362449Speter    char *p;
25450276Speter
25562449Speter    /* We can get recalled; if so, don't continue uselessly. */
256166124Srafan    clearerr(stdin);
25762449Speter    if (feof(stdin) || ferror(stdin)) {
25862449Speter	(void) fprintf(stderr, "\n");
25997049Speter	exit_error();
26097049Speter	/* NOTREACHED */
26162449Speter    }
26262449Speter    for (;;) {
26362449Speter	if (dflt)
26462449Speter	    (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
26562449Speter	else
26662449Speter	    (void) fprintf(stderr, "Terminal type? ");
26762449Speter	(void) fflush(stderr);
26862449Speter
26962449Speter	if (fgets(answer, sizeof(answer), stdin) == 0) {
27062449Speter	    if (dflt == 0) {
27197049Speter		exit_error();
27297049Speter		/* NOTREACHED */
27362449Speter	    }
27462449Speter	    return (dflt);
27550276Speter	}
27650276Speter
27762449Speter	if ((p = strchr(answer, '\n')) != 0)
27862449Speter	    *p = '\0';
27962449Speter	if (answer[0])
28062449Speter	    return (answer);
28162449Speter	if (dflt != 0)
28262449Speter	    return (dflt);
28362449Speter    }
28450276Speter}
28550276Speter
28650276Speter/**************************************************************************
28750276Speter *
28850276Speter * Mapping logic begins here
28950276Speter *
29050276Speter **************************************************************************/
29150276Speter
29250276Speter/* Baud rate conditionals for mapping. */
29350276Speter#define	GT		0x01
29450276Speter#define	EQ		0x02
29550276Speter#define	LT		0x04
29650276Speter#define	NOT		0x08
29750276Speter#define	GE		(GT | EQ)
29850276Speter#define	LE		(LT | EQ)
29950276Speter
30050276Spetertypedef struct map {
30162449Speter    struct map *next;		/* Linked list of maps. */
30262449Speter    const char *porttype;	/* Port type, or "" for any. */
30362449Speter    const char *type;		/* Terminal type to select. */
30462449Speter    int conditional;		/* Baud rate conditionals bitmask. */
30566963Speter    int speed;			/* Baud rate to compare against. */
30650276Speter} MAP;
30750276Speter
30850276Speterstatic MAP *cur, *maplist;
30950276Speter
31050276Spetertypedef struct speeds {
31162449Speter    const char *string;
31262449Speter    int speed;
31350276Speter} SPEEDS;
31450276Speter
31562449Speterstatic const SPEEDS speeds[] =
31662449Speter{
31762449Speter    {"0", B0},
31862449Speter    {"50", B50},
31962449Speter    {"75", B75},
32062449Speter    {"110", B110},
32162449Speter    {"134", B134},
32262449Speter    {"134.5", B134},
32362449Speter    {"150", B150},
32462449Speter    {"200", B200},
32562449Speter    {"300", B300},
32662449Speter    {"600", B600},
32762449Speter    {"1200", B1200},
32862449Speter    {"1800", B1800},
32962449Speter    {"2400", B2400},
33062449Speter    {"4800", B4800},
33162449Speter    {"9600", B9600},
33266963Speter    /* sgttyb may define up to this point */
33366963Speter#ifdef B19200
33462449Speter    {"19200", B19200},
33566963Speter#endif
33666963Speter#ifdef B38400
33762449Speter    {"38400", B38400},
33866963Speter#endif
33966963Speter#ifdef B19200
34062449Speter    {"19200", B19200},
34166963Speter#endif
34266963Speter#ifdef B38400
34362449Speter    {"38400", B38400},
34466963Speter#endif
34550276Speter#ifdef B19200
34662449Speter    {"19200", B19200},
34750276Speter#else
34850276Speter#ifdef EXTA
34962449Speter    {"19200", EXTA},
35050276Speter#endif
35150276Speter#endif
35250276Speter#ifdef B38400
35362449Speter    {"38400", B38400},
35450276Speter#else
35550276Speter#ifdef EXTB
35662449Speter    {"38400", EXTB},
35750276Speter#endif
35850276Speter#endif
35950276Speter#ifdef B57600
36062449Speter    {"57600", B57600},
36150276Speter#endif
36250276Speter#ifdef B115200
36362449Speter    {"115200", B115200},
36450276Speter#endif
36550276Speter#ifdef B230400
36662449Speter    {"230400", B230400},
36750276Speter#endif
36850276Speter#ifdef B460800
36962449Speter    {"460800", B460800},
37050276Speter#endif
37162449Speter    {(char *) 0, 0}
37250276Speter};
37350276Speter
37450276Speterstatic int
37550276Spetertbaudrate(char *rate)
37650276Speter{
37762449Speter    const SPEEDS *sp;
37862449Speter    int found = FALSE;
37950276Speter
38062449Speter    /* The baudrate number can be preceded by a 'B', which is ignored. */
38162449Speter    if (*rate == 'B')
38262449Speter	++rate;
38350276Speter
38462449Speter    for (sp = speeds; sp->string; ++sp) {
38562449Speter	if (!CaselessCmp(rate, sp->string)) {
38662449Speter	    found = TRUE;
38762449Speter	    break;
38850276Speter	}
38962449Speter    }
39062449Speter    if (!found)
39162449Speter	err("unknown baud rate %s", rate);
39262449Speter    return (sp->speed);
39350276Speter}
39450276Speter
39550276Speter/*
39650276Speter * Syntax for -m:
39750276Speter * [port-type][test baudrate]:terminal-type
39850276Speter * The baud rate tests are: >, <, @, =, !
39950276Speter */
40050276Speterstatic void
40150276Speteradd_mapping(const char *port, char *arg)
40250276Speter{
40362449Speter    MAP *mapp;
40462449Speter    char *copy, *p;
40562449Speter    const char *termp;
40662449Speter    char *base = 0;
40750276Speter
40862449Speter    copy = strdup(arg);
409262629Sdelphij    mapp = typeMalloc(MAP, 1);
41062449Speter    if (copy == 0 || mapp == 0)
41162449Speter	failed("malloc");
412262629Sdelphij
413262629Sdelphij    assert(copy != 0);
414262629Sdelphij    assert(mapp != 0);
415262629Sdelphij
41662449Speter    mapp->next = 0;
41762449Speter    if (maplist == 0)
41862449Speter	cur = maplist = mapp;
41962449Speter    else {
42062449Speter	cur->next = mapp;
42162449Speter	cur = mapp;
42262449Speter    }
42350276Speter
42462449Speter    mapp->porttype = arg;
42562449Speter    mapp->conditional = 0;
42650276Speter
42762449Speter    arg = strpbrk(arg, "><@=!:");
42850276Speter
42962449Speter    if (arg == 0) {		/* [?]term */
43062449Speter	mapp->type = mapp->porttype;
43162449Speter	mapp->porttype = 0;
43262449Speter	goto done;
43362449Speter    }
43450276Speter
43562449Speter    if (arg == mapp->porttype)	/* [><@=! baud]:term */
43662449Speter	termp = mapp->porttype = 0;
43762449Speter    else
43862449Speter	termp = base = arg;
43950276Speter
44062449Speter    for (;; ++arg) {		/* Optional conditionals. */
44162449Speter	switch (*arg) {
44262449Speter	case '<':
44362449Speter	    if (mapp->conditional & GT)
44462449Speter		goto badmopt;
44562449Speter	    mapp->conditional |= LT;
44662449Speter	    break;
44762449Speter	case '>':
44862449Speter	    if (mapp->conditional & LT)
44962449Speter		goto badmopt;
45062449Speter	    mapp->conditional |= GT;
45162449Speter	    break;
45262449Speter	case '@':
45362449Speter	case '=':		/* Not documented. */
45462449Speter	    mapp->conditional |= EQ;
45562449Speter	    break;
45662449Speter	case '!':
45762449Speter	    mapp->conditional |= NOT;
45862449Speter	    break;
45962449Speter	default:
46062449Speter	    goto next;
46150276Speter	}
46262449Speter    }
46350276Speter
46462449Speter  next:
46562449Speter    if (*arg == ':') {
46662449Speter	if (mapp->conditional)
46762449Speter	    goto badmopt;
46862449Speter	++arg;
46962449Speter    } else {			/* Optional baudrate. */
47062449Speter	arg = strchr(p = arg, ':');
47162449Speter	if (arg == 0)
47262449Speter	    goto badmopt;
47362449Speter	*arg++ = '\0';
47462449Speter	mapp->speed = tbaudrate(p);
47562449Speter    }
47650276Speter
47762449Speter    mapp->type = arg;
47850276Speter
47962449Speter    /* Terminate porttype, if specified. */
48062449Speter    if (termp != 0)
48162449Speter	*base = '\0';
48250276Speter
48362449Speter    /* If a NOT conditional, reverse the test. */
48462449Speter    if (mapp->conditional & NOT)
48562449Speter	mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
48650276Speter
48762449Speter    /* If user specified a port with an option flag, set it. */
488184989Srafan  done:
489184989Srafan    if (port) {
490184989Srafan	if (mapp->porttype) {
491184989Srafan	  badmopt:
492184989Srafan	    err("illegal -m option format: %s", copy);
493184989Srafan	}
49462449Speter	mapp->porttype = port;
49562449Speter    }
496184989Srafan    free(copy);
49750276Speter#ifdef MAPDEBUG
49862449Speter    (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
49962449Speter    (void) printf("type: %s\n", mapp->type);
50062449Speter    (void) printf("conditional: ");
50162449Speter    p = "";
50262449Speter    if (mapp->conditional & GT) {
50362449Speter	(void) printf("GT");
50462449Speter	p = "/";
50562449Speter    }
50662449Speter    if (mapp->conditional & EQ) {
50762449Speter	(void) printf("%sEQ", p);
50862449Speter	p = "/";
50962449Speter    }
51062449Speter    if (mapp->conditional & LT)
51162449Speter	(void) printf("%sLT", p);
51262449Speter    (void) printf("\nspeed: %d\n", mapp->speed);
51350276Speter#endif
51450276Speter}
51550276Speter
51650276Speter/*
51750276Speter * Return the type of terminal to use for a port of type 'type', as specified
51850276Speter * by the first applicable mapping in 'map'.  If no mappings apply, return
51950276Speter * 'type'.
52050276Speter */
52150276Speterstatic const char *
52250276Spetermapped(const char *type)
52350276Speter{
52462449Speter    MAP *mapp;
52562449Speter    int match;
52650276Speter
52762449Speter    for (mapp = maplist; mapp; mapp = mapp->next)
52862449Speter	if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
52962449Speter	    switch (mapp->conditional) {
53062449Speter	    case 0:		/* No test specified. */
53162449Speter		match = TRUE;
53262449Speter		break;
53362449Speter	    case EQ:
534262685Sdelphij		match = ((int) ospeed == mapp->speed);
53562449Speter		break;
53662449Speter	    case GE:
537262685Sdelphij		match = ((int) ospeed >= mapp->speed);
53862449Speter		break;
53962449Speter	    case GT:
540262685Sdelphij		match = ((int) ospeed > mapp->speed);
54162449Speter		break;
54262449Speter	    case LE:
543262685Sdelphij		match = ((int) ospeed <= mapp->speed);
54462449Speter		break;
54562449Speter	    case LT:
546262685Sdelphij		match = ((int) ospeed < mapp->speed);
54762449Speter		break;
54862449Speter	    default:
54962449Speter		match = FALSE;
55062449Speter	    }
55162449Speter	    if (match)
55262449Speter		return (mapp->type);
55362449Speter	}
55462449Speter    /* No match found; return given type. */
55562449Speter    return (type);
55650276Speter}
55750276Speter
55850276Speter/**************************************************************************
55950276Speter *
56050276Speter * Entry fetching
56150276Speter *
56250276Speter **************************************************************************/
56350276Speter
56450276Speter/*
56550276Speter * Figure out what kind of terminal we're dealing with, and then read in
56650276Speter * its termcap entry.
56750276Speter */
56850276Speterstatic const char *
56950276Speterget_termcap_entry(char *userarg)
57050276Speter{
57176726Speter    int errret;
57262449Speter    char *p;
57362449Speter    const char *ttype;
57450276Speter#if HAVE_GETTTYNAM
57562449Speter    struct ttyent *t;
57650276Speter#else
57762449Speter    FILE *fp;
57850276Speter#endif
57962449Speter    char *ttypath;
58050276Speter
58162449Speter    if (userarg) {
58262449Speter	ttype = userarg;
58362449Speter	goto found;
58462449Speter    }
58550276Speter
58662449Speter    /* Try the environment. */
58762449Speter    if ((ttype = getenv("TERM")) != 0)
58862449Speter	goto map;
58950276Speter
59062449Speter    if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
59166963Speter	p = _nc_basename(ttypath);
59250276Speter#if HAVE_GETTTYNAM
59362449Speter	/*
59462449Speter	 * We have the 4.3BSD library call getttynam(3); that means
59562449Speter	 * there's an /etc/ttys to look up device-to-type mappings in.
59662449Speter	 * Try ttyname(3); check for dialup or other mapping.
59762449Speter	 */
59862449Speter	if ((t = getttynam(p))) {
59962449Speter	    ttype = t->ty_type;
60062449Speter	    goto map;
60162449Speter	}
60250276Speter#else
60362449Speter	if ((fp = fopen("/etc/ttytype", "r")) != 0
60462449Speter	    || (fp = fopen("/etc/ttys", "r")) != 0) {
60562449Speter	    char buffer[BUFSIZ];
60662449Speter	    char *s, *t, *d;
60750276Speter
60862449Speter	    while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
60962449Speter		for (s = buffer, t = d = 0; *s; s++) {
61097049Speter		    if (isspace(UChar(*s)))
61162449Speter			*s = '\0';
61262449Speter		    else if (t == 0)
61362449Speter			t = s;
61462449Speter		    else if (d == 0 && s != buffer && s[-1] == '\0')
61562449Speter			d = s;
61650276Speter		}
61762449Speter		if (t != 0 && d != 0 && !strcmp(d, p)) {
61862449Speter		    ttype = strdup(t);
61962449Speter		    fclose(fp);
62062449Speter		    goto map;
62162449Speter		}
62262449Speter	    }
62362449Speter	    fclose(fp);
62462449Speter	}
62550276Speter#endif /* HAVE_GETTTYNAM */
62662449Speter    }
62750276Speter
62862449Speter    /* If still undefined, use "unknown". */
62962449Speter    ttype = "unknown";
63050276Speter
63162449Speter  map:ttype = mapped(ttype);
63250276Speter
63362449Speter    /*
63462449Speter     * If not a path, remove TERMCAP from the environment so we get a
63562449Speter     * real entry from /etc/termcap.  This prevents us from being fooled
63662449Speter     * by out of date stuff in the environment.
63762449Speter     */
638262685Sdelphij  found:
639262685Sdelphij    if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
64062449Speter	/* 'unsetenv("TERMCAP")' is not portable.
64162449Speter	 * The 'environ' array is better.
64250276Speter	 */
64362449Speter	int n;
64462449Speter	for (n = 0; environ[n] != 0; n++) {
645262685Sdelphij	    if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
64662449Speter		while ((environ[n] = environ[n + 1]) != 0) {
64762449Speter		    n++;
64850276Speter		}
64962449Speter		break;
65062449Speter	    }
65150276Speter	}
65262449Speter    }
65350276Speter
65462449Speter    /*
65562449Speter     * ttype now contains a pointer to the type of the terminal.
65662449Speter     * If the first character is '?', ask the user.
65762449Speter     */
65862449Speter    if (ttype[0] == '?') {
65962449Speter	if (ttype[1] != '\0')
66062449Speter	    ttype = askuser(ttype + 1);
66162449Speter	else
66262449Speter	    ttype = askuser(0);
66362449Speter    }
66462449Speter    /* Find the terminfo entry.  If it doesn't exist, ask the user. */
66576726Speter    while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
66676726Speter	   != OK) {
66762449Speter	if (errret == 0) {
668166124Srafan	    (void) fprintf(stderr, "%s: unknown terminal type %s\n",
669166124Srafan			   _nc_progname, ttype);
67062449Speter	    ttype = 0;
67162449Speter	} else {
67262449Speter	    (void) fprintf(stderr,
673166124Srafan			   "%s: can't initialize terminal type %s (error %d)\n",
674166124Srafan			   _nc_progname, ttype, errret);
67562449Speter	    ttype = 0;
67650276Speter	}
67762449Speter	ttype = askuser(ttype);
67862449Speter    }
67950276Speter#if BROKEN_LINKER
68062449Speter    tgetflag("am");		/* force lib_termcap.o to be linked for 'ospeed' */
68150276Speter#endif
68262449Speter    return (ttype);
68350276Speter}
68450276Speter
68550276Speter/**************************************************************************
68650276Speter *
68750276Speter * Mode-setting logic
68850276Speter *
68950276Speter **************************************************************************/
69050276Speter
69150276Speter/* some BSD systems have these built in, some systems are missing
692166124Srafan * one or more definitions. The safest solution is to override unless the
693166124Srafan * commonly-altered ones are defined.
69450276Speter */
695166124Srafan#if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
69650276Speter#undef CEOF
69750276Speter#undef CERASE
69850276Speter#undef CINTR
69950276Speter#undef CKILL
70050276Speter#undef CLNEXT
70150276Speter#undef CRPRNT
70250276Speter#undef CQUIT
70350276Speter#undef CSTART
70450276Speter#undef CSTOP
70550276Speter#undef CSUSP
706166124Srafan#endif
70750276Speter
70850276Speter/* control-character defaults */
709166124Srafan#ifndef CEOF
71050276Speter#define CEOF	CTRL('D')
711166124Srafan#endif
712166124Srafan#ifndef CERASE
71350276Speter#define CERASE	CTRL('H')
714166124Srafan#endif
715166124Srafan#ifndef CINTR
71650276Speter#define CINTR	127		/* ^? */
717166124Srafan#endif
718166124Srafan#ifndef CKILL
71950276Speter#define CKILL	CTRL('U')
720166124Srafan#endif
721166124Srafan#ifndef CLNEXT
72250276Speter#define CLNEXT  CTRL('v')
723166124Srafan#endif
724166124Srafan#ifndef CRPRNT
72550276Speter#define CRPRNT  CTRL('r')
726166124Srafan#endif
727166124Srafan#ifndef CQUIT
72850276Speter#define CQUIT	CTRL('\\')
729166124Srafan#endif
730166124Srafan#ifndef CSTART
73150276Speter#define CSTART	CTRL('Q')
732166124Srafan#endif
733166124Srafan#ifndef CSTOP
73450276Speter#define CSTOP	CTRL('S')
735166124Srafan#endif
736166124Srafan#ifndef CSUSP
73750276Speter#define CSUSP	CTRL('Z')
738166124Srafan#endif
73950276Speter
740166124Srafan#if defined(_POSIX_VDISABLE)
741166124Srafan#define DISABLED(val)   (((_POSIX_VDISABLE != -1) \
742166124Srafan		       && ((val) == _POSIX_VDISABLE)) \
743166124Srafan		      || ((val) <= 0))
744166124Srafan#else
745166124Srafan#define DISABLED(val)   ((int)(val) <= 0)
746166124Srafan#endif
74750276Speter
748166124Srafan#define CHK(val, dft)   (DISABLED(val) ? dft : val)
749166124Srafan
75062449Speterstatic bool set_tabs(void);
75150276Speter
75250276Speter/*
75350276Speter * Reset the terminal mode bits to a sensible state.  Very useful after
75450276Speter * a child program dies in raw mode.
75550276Speter */
75650276Speterstatic void
75750276Speterreset_mode(void)
75850276Speter{
75950276Speter#ifdef TERMIOS
76062449Speter    tcgetattr(STDERR_FILENO, &mode);
76150276Speter#else
76262449Speter    stty(STDERR_FILENO, &mode);
76350276Speter#endif
76450276Speter
76550276Speter#ifdef TERMIOS
76650276Speter#if defined(VDISCARD) && defined(CDISCARD)
76762449Speter    mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
76850276Speter#endif
76962449Speter    mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
77062449Speter    mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
77150276Speter#if defined(VFLUSH) && defined(CFLUSH)
77262449Speter    mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
77350276Speter#endif
77462449Speter    mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
77562449Speter    mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
77650276Speter#if defined(VLNEXT) && defined(CLNEXT)
77762449Speter    mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
77850276Speter#endif
77962449Speter    mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
78050276Speter#if defined(VREPRINT) && defined(CRPRNT)
78162449Speter    mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
78250276Speter#endif
78350276Speter#if defined(VSTART) && defined(CSTART)
78462449Speter    mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
78550276Speter#endif
78650276Speter#if defined(VSTOP) && defined(CSTOP)
78762449Speter    mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
78850276Speter#endif
78950276Speter#if defined(VSUSP) && defined(CSUSP)
79062449Speter    mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
79150276Speter#endif
79250276Speter#if defined(VWERASE) && defined(CWERASE)
79362449Speter    mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
79450276Speter#endif
79550276Speter
796262685Sdelphij    mode.c_iflag &= ~((unsigned) (IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
79750276Speter#ifdef IUCLC
798262685Sdelphij				  | IUCLC
79950276Speter#endif
80050276Speter#ifdef IXANY
801262685Sdelphij				  | IXANY
80250276Speter#endif
803262685Sdelphij				  | IXOFF));
80450276Speter
80562449Speter    mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
80650276Speter#ifdef IMAXBEL
80766963Speter		     | IMAXBEL
80850276Speter#endif
80962449Speter	);
81050276Speter
811262685Sdelphij    mode.c_oflag &= ~((unsigned) (0
81250276Speter#ifdef OLCUC
813262685Sdelphij				  | OLCUC
81450276Speter#endif
81550276Speter#ifdef OCRNL
816262685Sdelphij				  | OCRNL
81750276Speter#endif
81850276Speter#ifdef ONOCR
819262685Sdelphij				  | ONOCR
82050276Speter#endif
82150276Speter#ifdef ONLRET
822262685Sdelphij				  | ONLRET
82350276Speter#endif
82450276Speter#ifdef OFILL
825262685Sdelphij				  | OFILL
82650276Speter#endif
82750276Speter#ifdef OFDEL
828262685Sdelphij				  | OFDEL
82950276Speter#endif
83050276Speter#ifdef NLDLY
831262685Sdelphij				  | NLDLY
83250276Speter#endif
833184989Srafan#ifdef CRDLY
834262685Sdelphij				  | CRDLY
835174993Srafan#endif
836184989Srafan#ifdef TABDLY
837262685Sdelphij				  | TABDLY
838174993Srafan#endif
839184989Srafan#ifdef BSDLY
840262685Sdelphij				  | BSDLY
841174993Srafan#endif
842184989Srafan#ifdef VTDLY
843262685Sdelphij				  | VTDLY
844174993Srafan#endif
845174993Srafan#ifdef FFDLY
846262685Sdelphij				  | FFDLY
847174993Srafan#endif
848262685Sdelphij		      ));
84950276Speter
85062449Speter    mode.c_oflag |= (OPOST
85150276Speter#ifdef ONLCR
85266963Speter		     | ONLCR
85350276Speter#endif
85462449Speter	);
85550276Speter
856262685Sdelphij    mode.c_cflag &= ~((unsigned) (CSIZE | CSTOPB | PARENB | PARODD | CLOCAL));
85762449Speter    mode.c_cflag |= (CS8 | CREAD);
858262685Sdelphij    mode.c_lflag &= ~((unsigned) (ECHONL | NOFLSH
85950276Speter#ifdef TOSTOP
860262685Sdelphij				  | TOSTOP
86150276Speter#endif
86250276Speter#ifdef ECHOPTR
863262685Sdelphij				  | ECHOPRT
86450276Speter#endif
86550276Speter#ifdef XCASE
866262685Sdelphij				  | XCASE
86750276Speter#endif
868262685Sdelphij		      ));
86950276Speter
87062449Speter    mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
87150276Speter#ifdef ECHOCTL
87266963Speter		     | ECHOCTL
87350276Speter#endif
87450276Speter#ifdef ECHOKE
87566963Speter		     | ECHOKE
87650276Speter#endif
87762449Speter	);
87850276Speter#endif
87950276Speter
88097049Speter    SET_TTY(STDERR_FILENO, &mode);
88150276Speter}
88250276Speter
88350276Speter/*
88450276Speter * Returns a "good" value for the erase character.  This is loosely based on
88550276Speter * the BSD4.4 logic.
88650276Speter */
88766963Speter#ifdef TERMIOS
88850276Speterstatic int
88950276Speterdefault_erase(void)
89050276Speter{
89162449Speter    int result;
89250276Speter
89362449Speter    if (over_strike
89462449Speter	&& key_backspace != 0
89562449Speter	&& strlen(key_backspace) == 1)
89662449Speter	result = key_backspace[0];
89762449Speter    else
89862449Speter	result = CERASE;
89950276Speter
90062449Speter    return result;
90150276Speter}
90266963Speter#endif
90350276Speter
90450276Speter/*
90550276Speter * Update the values of the erase, interrupt, and kill characters in 'mode'.
90650276Speter *
90750276Speter * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
90850276Speter * characters if they're unset, or if we specify them as options.  This differs
90950276Speter * from BSD 4.4 tset, which always sets erase.
91050276Speter */
91150276Speterstatic void
91250276Speterset_control_chars(void)
91350276Speter{
91450276Speter#ifdef TERMIOS
915262685Sdelphij    if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0) {
916262685Sdelphij	mode.c_cc[VERASE] = UChar((terasechar >= 0)
917262685Sdelphij				  ? terasechar
918262685Sdelphij				  : default_erase());
919262685Sdelphij    }
92050276Speter
921262685Sdelphij    if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0) {
922262685Sdelphij	mode.c_cc[VINTR] = UChar((intrchar >= 0)
923262685Sdelphij				 ? intrchar
924262685Sdelphij				 : CINTR);
925262685Sdelphij    }
92650276Speter
927262685Sdelphij    if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0) {
928262685Sdelphij	mode.c_cc[VKILL] = UChar((tkillchar >= 0)
929262685Sdelphij				 ? tkillchar
930262685Sdelphij				 : CKILL);
931262685Sdelphij    }
93250276Speter#endif
93350276Speter}
93450276Speter
93550276Speter/*
93650276Speter * Set up various conversions in 'mode', including parity, tabs, returns,
93750276Speter * echo, and case, according to the termcap entry.  If the program we're
93850276Speter * running was named with a leading upper-case character, map external
93950276Speter * uppercase to internal lowercase.
94050276Speter */
94150276Speterstatic void
94250276Speterset_conversions(void)
94350276Speter{
94450276Speter#ifdef __OBSOLETE__
94562449Speter    /*
94662449Speter     * Conversion logic for some *really* ancient terminal glitches,
94762449Speter     * not supported in terminfo.  Left here for succeeding generations
94862449Speter     * to marvel at.
94962449Speter     */
95062449Speter    if (tgetflag("UC")) {
95150276Speter#ifdef IUCLC
95262449Speter	mode.c_iflag |= IUCLC;
95362449Speter	mode.c_oflag |= OLCUC;
95450276Speter#endif
95562449Speter    } else if (tgetflag("LC")) {
95650276Speter#ifdef IUCLC
95762449Speter	mode.c_iflag &= ~IUCLC;
95862449Speter	mode.c_oflag &= ~OLCUC;
95950276Speter#endif
96062449Speter    }
96162449Speter    mode.c_iflag &= ~(PARMRK | INPCK);
96262449Speter    mode.c_lflag |= ICANON;
96362449Speter    if (tgetflag("EP")) {
96462449Speter	mode.c_cflag |= PARENB;
96562449Speter	mode.c_cflag &= ~PARODD;
96662449Speter    }
96762449Speter    if (tgetflag("OP")) {
96862449Speter	mode.c_cflag |= PARENB;
96962449Speter	mode.c_cflag |= PARODD;
97062449Speter    }
97150276Speter#endif /* __OBSOLETE__ */
97250276Speter
97350276Speter#ifdef TERMIOS
97450276Speter#ifdef ONLCR
97562449Speter    mode.c_oflag |= ONLCR;
97650276Speter#endif
97762449Speter    mode.c_iflag |= ICRNL;
97862449Speter    mode.c_lflag |= ECHO;
97950276Speter#ifdef OXTABS
98062449Speter    mode.c_oflag |= OXTABS;
98150276Speter#endif /* OXTABS */
98250276Speter
98362449Speter    /* test used to be tgetflag("NL") */
98462449Speter    if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
98562449Speter	/* Newline, not linefeed. */
98650276Speter#ifdef ONLCR
987262685Sdelphij	mode.c_oflag &= ~((unsigned) ONLCR);
98850276Speter#endif
989262685Sdelphij	mode.c_iflag &= ~((unsigned) ICRNL);
99062449Speter    }
99150276Speter#ifdef __OBSOLETE__
99262449Speter    if (tgetflag("HD"))		/* Half duplex. */
99362449Speter	mode.c_lflag &= ~ECHO;
99450276Speter#endif /* __OBSOLETE__ */
99550276Speter#ifdef OXTABS
99662449Speter    /* test used to be tgetflag("pt") */
99762449Speter    if (has_hardware_tabs)	/* Print tabs. */
99862449Speter	mode.c_oflag &= ~OXTABS;
99950276Speter#endif /* OXTABS */
100062449Speter    mode.c_lflag |= (ECHOE | ECHOK);
100150276Speter#endif
100250276Speter}
100350276Speter
100450276Speter/* Output startup string. */
100550276Speterstatic void
100650276Speterset_init(void)
100750276Speter{
100862449Speter    char *p;
100962449Speter    bool settle;
101050276Speter
101150276Speter#ifdef __OBSOLETE__
101262449Speter    if (pad_char != (char *) 0)	/* Get/set pad character. */
101362449Speter	PC = pad_char[0];
101450276Speter#endif /* OBSOLETE */
101550276Speter
101650276Speter#ifdef TAB3
101762449Speter    if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
101862449Speter	oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
101997049Speter	SET_TTY(STDERR_FILENO, &oldmode);
102062449Speter    }
102150276Speter#endif
102262449Speter    settle = set_tabs();
102350276Speter
102462449Speter    if (isreset) {
102562449Speter	if ((p = reset_1string) != 0) {
102662449Speter	    tputs(p, 0, outc);
102762449Speter	    settle = TRUE;
102850276Speter	}
102962449Speter	if ((p = reset_2string) != 0) {
103062449Speter	    tputs(p, 0, outc);
103162449Speter	    settle = TRUE;
103262449Speter	}
103362449Speter	/* What about rf, rs3, as per terminfo man page? */
103462449Speter	/* also might be nice to send rmacs, rmul, rmm */
103562449Speter	if ((p = reset_file) != 0
103662449Speter	    || (p = init_file) != 0) {
103762449Speter	    cat(p);
103862449Speter	    settle = TRUE;
103962449Speter	}
104062449Speter    }
104150276Speter
104262449Speter    if (settle) {
104362449Speter	(void) putc('\r', stderr);
104462449Speter	(void) fflush(stderr);
104562449Speter	(void) napms(1000);	/* Settle the terminal. */
104662449Speter    }
104750276Speter}
104850276Speter
104950276Speter/*
105050276Speter * Set the hardware tabs on the terminal, using the ct (clear all tabs),
105150276Speter * st (set one tab) and ch (horizontal cursor addressing) capabilities.
105250276Speter * This is done before if and is, so they can patch in case we blow this.
105350276Speter * Return TRUE if we set any tab stops, FALSE if not.
105450276Speter */
105550276Speterstatic bool
1056166124Srafanset_tabs(void)
105750276Speter{
105862449Speter    if (set_tab && clear_all_tabs) {
105962449Speter	int c;
1060262685Sdelphij	int lim =
1061262685Sdelphij#if HAVE_SIZECHANGE
1062262685Sdelphij	tcolumns
1063262685Sdelphij#else
1064262685Sdelphij	columns
1065262685Sdelphij#endif
1066262685Sdelphij	 ;
106750276Speter
106862449Speter	(void) putc('\r', stderr);	/* Force to left margin. */
106962449Speter	tputs(clear_all_tabs, 0, outc);
107050276Speter
1071262685Sdelphij	for (c = 8; c < lim; c += 8) {
107262449Speter	    /* Get to the right column.  In BSD tset, this
107362449Speter	     * used to try a bunch of half-clever things
107462449Speter	     * with cup and hpa, for an average saving of
107562449Speter	     * somewhat less than two character times per
1076166124Srafan	     * tab stop, less than .01 sec at 2400cps. We
107762449Speter	     * lost all this cruft because it seemed to be
107862449Speter	     * introducing some odd bugs.
1079166124Srafan	     * -----------12345678----------- */
108062449Speter	    (void) fputs("        ", stderr);
108162449Speter	    tputs(set_tab, 0, outc);
108250276Speter	}
108362449Speter	putc('\r', stderr);
108462449Speter	return (TRUE);
108562449Speter    }
108662449Speter    return (FALSE);
108750276Speter}
108850276Speter
108950276Speter/**************************************************************************
109050276Speter *
109150276Speter * Main sequence
109250276Speter *
109350276Speter **************************************************************************/
109450276Speter
109550276Speter/*
109650276Speter * Tell the user if a control key has been changed from the default value.
109750276Speter */
109866963Speter#ifdef TERMIOS
109950276Speterstatic void
110050276Speterreport(const char *name, int which, unsigned def)
110150276Speter{
110262449Speter    unsigned older, newer;
110362449Speter    char *p;
110450276Speter
110562449Speter    newer = mode.c_cc[which];
110662449Speter    older = oldmode.c_cc[which];
110750276Speter
110862449Speter    if (older == newer && older == def)
110962449Speter	return;
111050276Speter
111162449Speter    (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
111250276Speter
1113166124Srafan    if (DISABLED(newer))
1114166124Srafan	(void) fprintf(stderr, "undef.\n");
111562449Speter    /*
111662449Speter     * Check 'delete' before 'backspace', since the key_backspace value
111762449Speter     * is ambiguous.
111862449Speter     */
1119166124Srafan    else if (newer == 0177)
112062449Speter	(void) fprintf(stderr, "delete.\n");
112162449Speter    else if ((p = key_backspace) != 0
112266963Speter	     && newer == (unsigned char) p[0]
112366963Speter	     && p[1] == '\0')
112462449Speter	(void) fprintf(stderr, "backspace.\n");
112562449Speter    else if (newer < 040) {
112662449Speter	newer ^= 0100;
1127166124Srafan	(void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
112862449Speter    } else
1129166124Srafan	(void) fprintf(stderr, "%c.\n", UChar(newer));
113066963Speter}
113150276Speter#endif
113250276Speter
113350276Speter/*
113450276Speter * Convert the obsolete argument forms into something that getopt can handle.
113550276Speter * This means that -e, -i and -k get default arguments supplied for them.
113650276Speter */
113750276Speterstatic void
113850276Speterobsolete(char **argv)
113950276Speter{
114062449Speter    for (; *argv; ++argv) {
114162449Speter	char *parm = argv[0];
114250276Speter
114362449Speter	if (parm[0] == '-' && parm[1] == '\0') {
114462449Speter	    argv[0] = strdup("-q");
114562449Speter	    continue;
114662449Speter	}
114750276Speter
114862449Speter	if ((parm[0] != '-')
114962449Speter	    || (argv[1] && argv[1][0] != '-')
115062449Speter	    || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
115162449Speter	    || (parm[2] != '\0'))
115262449Speter	    continue;
115362449Speter	switch (argv[0][1]) {
115462449Speter	case 'e':
115562449Speter	    argv[0] = strdup("-e^H");
115662449Speter	    break;
115762449Speter	case 'i':
115862449Speter	    argv[0] = strdup("-i^C");
115962449Speter	    break;
116062449Speter	case 'k':
116162449Speter	    argv[0] = strdup("-k^U");
116262449Speter	    break;
116350276Speter	}
116462449Speter    }
116550276Speter}
116650276Speter
116750276Speterstatic void
1168166124Srafanusage(void)
116950276Speter{
1170166124Srafan    static const char *tbl[] =
1171166124Srafan    {
1172166124Srafan	""
1173166124Srafan	,"Options:"
1174166124Srafan	,"  -c          set control characters"
1175166124Srafan	,"  -e ch       erase character"
1176166124Srafan	,"  -I          no initialization strings"
1177166124Srafan	,"  -i ch       interrupt character"
1178166124Srafan	,"  -k ch       kill character"
1179166124Srafan	,"  -m mapping  map identifier to type"
1180166124Srafan	,"  -Q          do not output control key settings"
1181166124Srafan	,"  -r          display term on stderr"
1182166124Srafan	,"  -s          output TERM set command"
1183166124Srafan	,"  -V          print curses-version"
1184166124Srafan	,"  -w          set window-size"
1185166124Srafan    };
1186166124Srafan    unsigned n;
1187166124Srafan    (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
1188166124Srafan    for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n)
1189166124Srafan	fprintf(stderr, "%s\n", tbl[n]);
119097049Speter    exit_error();
119197049Speter    /* NOTREACHED */
119250276Speter}
119350276Speter
119462449Speterstatic char
119562449Speterarg_to_char(void)
119650276Speter{
1197184989Srafan    return (char) ((optarg[0] == '^' && optarg[1] != '\0')
1198184989Srafan		   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
1199184989Srafan		   : optarg[0]);
120050276Speter}
120150276Speter
120250276Speterint
120350276Spetermain(int argc, char **argv)
120450276Speter{
120562449Speter    int ch, noinit, noset, quiet, Sflag, sflag, showterm;
120662449Speter    const char *p;
120762449Speter    const char *ttype;
120850276Speter
120962449Speter    obsolete(argv);
121062449Speter    noinit = noset = quiet = Sflag = sflag = showterm = 0;
1211174993Srafan    while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
121262449Speter	switch (ch) {
1213166124Srafan	case 'c':		/* set control-chars */
1214166124Srafan	    opt_c = TRUE;
121562449Speter	    break;
121662449Speter	case 'a':		/* OBSOLETE: map identifier to type */
121762449Speter	    add_mapping("arpanet", optarg);
121862449Speter	    break;
121962449Speter	case 'd':		/* OBSOLETE: map identifier to type */
122062449Speter	    add_mapping("dialup", optarg);
122162449Speter	    break;
122262449Speter	case 'e':		/* erase character */
122362449Speter	    terasechar = arg_to_char();
122462449Speter	    break;
122562449Speter	case 'I':		/* no initialization strings */
122662449Speter	    noinit = 1;
122762449Speter	    break;
122862449Speter	case 'i':		/* interrupt character */
122962449Speter	    intrchar = arg_to_char();
123062449Speter	    break;
123162449Speter	case 'k':		/* kill character */
123262449Speter	    tkillchar = arg_to_char();
123362449Speter	    break;
123462449Speter	case 'm':		/* map identifier to type */
123562449Speter	    add_mapping(0, optarg);
123662449Speter	    break;
123762449Speter	case 'n':		/* OBSOLETE: set new tty driver */
123862449Speter	    break;
123962449Speter	case 'p':		/* OBSOLETE: map identifier to type */
124062449Speter	    add_mapping("plugboard", optarg);
124162449Speter	    break;
124262449Speter	case 'Q':		/* don't output control key settings */
124362449Speter	    quiet = 1;
124462449Speter	    break;
1245166124Srafan	case 'q':		/* display term only */
1246166124Srafan	    noset = 1;
124762449Speter	    break;
124862449Speter	case 'r':		/* display term on stderr */
124962449Speter	    showterm = 1;
125062449Speter	    break;
1251166124Srafan	case 'S':		/* OBSOLETE: output TERM & TERMCAP */
1252166124Srafan	    Sflag = 1;
1253166124Srafan	    break;
125462449Speter	case 's':		/* output TERM set command */
125562449Speter	    sflag = 1;
125662449Speter	    break;
1257166124Srafan	case 'V':		/* print curses-version */
125866963Speter	    puts(curses_version());
1259166124Srafan	    ExitProgram(EXIT_SUCCESS);
1260166124Srafan	case 'w':		/* set window-size */
1261166124Srafan	    opt_w = TRUE;
1262166124Srafan	    break;
126362449Speter	case '?':
126462449Speter	default:
1265166124Srafan	    usage();
126650276Speter	}
126762449Speter    }
1268166124Srafan
1269166124Srafan    _nc_progname = _nc_rootname(*argv);
127062449Speter    argc -= optind;
127162449Speter    argv += optind;
127250276Speter
127362449Speter    if (argc > 1)
1274166124Srafan	usage();
127550276Speter
1276166124Srafan    if (!opt_c && !opt_w)
1277166124Srafan	opt_c = opt_w = TRUE;
1278166124Srafan
1279166124Srafan    if (GET_TTY(STDERR_FILENO, &mode) < 0)
1280166124Srafan	failed("standard error");
1281166124Srafan    can_restore = TRUE;
1282166124Srafan    original = oldmode = mode;
1283166124Srafan#ifdef TERMIOS
1284184989Srafan    ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
1285166124Srafan#else
1286184989Srafan    ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
1287166124Srafan#endif
1288166124Srafan
1289262629Sdelphij    if (same_program(_nc_progname, PROG_RESET)) {
1290166124Srafan	isreset = TRUE;
1291166124Srafan	reset_mode();
1292166124Srafan    }
1293166124Srafan
1294262629Sdelphij    (void) get_termcap_entry(*argv);
129550276Speter
129662449Speter    if (!noset) {
1297262685Sdelphij#if HAVE_SIZECHANGE
129862449Speter	tcolumns = columns;
129962449Speter	tlines = lines;
130050276Speter
1301166124Srafan	if (opt_w) {
1302184989Srafan	    STRUCT_WINSIZE win;
1303184989Srafan	    /* Set window size if not set already */
1304184989Srafan	    (void) ioctl(STDERR_FILENO, IOCTL_GET_WINSIZE, &win);
1305184989Srafan	    if (WINSIZE_ROWS(win) == 0 &&
1306184989Srafan		WINSIZE_COLS(win) == 0 &&
1307166124Srafan		tlines > 0 && tcolumns > 0) {
1308184989Srafan		WINSIZE_ROWS(win) = tlines;
1309184989Srafan		WINSIZE_COLS(win) = tcolumns;
1310184989Srafan		(void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win);
1311166124Srafan	    }
131262449Speter	}
131350276Speter#endif
1314166124Srafan	if (opt_c) {
1315166124Srafan	    set_control_chars();
1316166124Srafan	    set_conversions();
131750276Speter
1318166124Srafan	    if (!noinit)
1319166124Srafan		set_init();
132050276Speter
1321166124Srafan	    /* Set the modes if they've changed. */
1322166124Srafan	    if (memcmp(&mode, &oldmode, sizeof(mode))) {
1323166124Srafan		SET_TTY(STDERR_FILENO, &mode);
1324166124Srafan	    }
132550276Speter	}
132662449Speter    }
132750276Speter
132862449Speter    /* Get the terminal name from the entry. */
132962449Speter    ttype = _nc_first_name(cur_term->type.term_names);
133050276Speter
133162449Speter    if (noset)
133262449Speter	(void) printf("%s\n", ttype);
133362449Speter    else {
133462449Speter	if (showterm)
133562449Speter	    (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
133662449Speter	/*
133762449Speter	 * If erase, kill and interrupt characters could have been
133862449Speter	 * modified and not -Q, display the changes.
133962449Speter	 */
134066963Speter#ifdef TERMIOS
134162449Speter	if (!quiet) {
134262449Speter	    report("Erase", VERASE, CERASE);
1343166124Srafan	    report("Kill", VKILL, CKILL);
1344166124Srafan	    report("Interrupt", VINTR, CINTR);
134550276Speter	}
134666963Speter#endif
134762449Speter    }
134850276Speter
134962449Speter    if (Sflag)
135062449Speter	err("The -S option is not supported under terminfo.");
135150276Speter
135262449Speter    if (sflag) {
1353166124Srafan	int len;
1354166124Srafan	char *var;
1355166124Srafan	char *leaf;
135662449Speter	/*
135762449Speter	 * Figure out what shell we're using.  A hack, we look for an
135862449Speter	 * environmental variable SHELL ending in "csh".
135962449Speter	 */
1360166124Srafan	if ((var = getenv("SHELL")) != 0
1361184989Srafan	    && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
1362166124Srafan	    && !strcmp(leaf + len - 3, "csh"))
136362449Speter	    p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
136462449Speter	else
136562449Speter	    p = "TERM=%s;\n";
136662449Speter	(void) printf(p, ttype);
136762449Speter    }
136850276Speter
1369166124Srafan    ExitProgram(EXIT_SUCCESS);
137050276Speter}
1371