xref: /freebsd/contrib/ncurses/progs/tset.c (revision 06bfebdedb0d353f1771adb65731f64461d9bd01)
10e3d5408SPeter Wemm /****************************************************************************
2*06bfebdeSXin LI  * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
324a1a9510SRong-En Fan  *     and: Thomas E. Dickey                        1996-on                 *
330e3d5408SPeter Wemm  ****************************************************************************/
340e3d5408SPeter Wemm 
350e3d5408SPeter Wemm /*
36*06bfebdeSXin LI  * Notes:
37*06bfebdeSXin LI  * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
38*06bfebdeSXin LI  * lines from that version, and made changes/additions for 150 lines.  There
39*06bfebdeSXin LI  * was no reformatting, so with/without ignoring whitespace, the amount of
40*06bfebdeSXin LI  * change is the same.
41*06bfebdeSXin LI  *
42*06bfebdeSXin LI  * Comparing with current (2009) source, excluding this comment:
43*06bfebdeSXin LI  * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
44*06bfebdeSXin LI  *    changed/added.
45*06bfebdeSXin LI  * a) Ignoring whitespace, the current version still uses 516 lines from the
46*06bfebdeSXin LI  *    4.4BSD Lite sources, with 402 lines changed/added.
47*06bfebdeSXin LI  *
48*06bfebdeSXin LI  * Raymond's original comment on this follows...
49*06bfebdeSXin LI  */
50*06bfebdeSXin LI 
51*06bfebdeSXin LI /*
520e3d5408SPeter Wemm  * tset.c - terminal initialization utility
530e3d5408SPeter Wemm  *
540e3d5408SPeter Wemm  * This code was mostly swiped from 4.4BSD tset, with some obsolescent
550e3d5408SPeter Wemm  * cruft removed and substantial portions rewritten.  A Regents of the
560e3d5408SPeter Wemm  * University of California copyright applies to some portions of the
570e3d5408SPeter Wemm  * code, and is reproduced below:
580e3d5408SPeter Wemm  */
590e3d5408SPeter Wemm /*-
600e3d5408SPeter Wemm  * Copyright (c) 1980, 1991, 1993
610e3d5408SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
620e3d5408SPeter Wemm  *
630e3d5408SPeter Wemm  * Redistribution and use in source and binary forms, with or without
640e3d5408SPeter Wemm  * modification, are permitted provided that the following conditions
650e3d5408SPeter Wemm  * are met:
660e3d5408SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
670e3d5408SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
680e3d5408SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
690e3d5408SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
700e3d5408SPeter Wemm  *    documentation and/or other materials provided with the distribution.
71*06bfebdeSXin LI  * 3. Neither the name of the University nor the names of its contributors
720e3d5408SPeter Wemm  *    may be used to endorse or promote products derived from this software
730e3d5408SPeter Wemm  *    without specific prior written permission.
740e3d5408SPeter Wemm  *
750e3d5408SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
760e3d5408SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
770e3d5408SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
780e3d5408SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
790e3d5408SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
800e3d5408SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
810e3d5408SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
820e3d5408SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
830e3d5408SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
840e3d5408SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
850e3d5408SPeter Wemm  * SUCH DAMAGE.
860e3d5408SPeter Wemm  */
870e3d5408SPeter Wemm 
885ca44d1cSRong-En Fan #define USE_LIBTINFO
890e3d5408SPeter Wemm #define __INTERNAL_CAPS_VISIBLE	/* we need to see has_hardware_tabs */
900e3d5408SPeter Wemm #include <progs.priv.h>
910e3d5408SPeter Wemm 
920e3d5408SPeter Wemm #include <errno.h>
930e3d5408SPeter Wemm #include <stdio.h>
940e3d5408SPeter Wemm #include <termcap.h>
950e3d5408SPeter Wemm #include <fcntl.h>
960e3d5408SPeter Wemm 
970e3d5408SPeter Wemm #if HAVE_GETTTYNAM && HAVE_TTYENT_H
980e3d5408SPeter Wemm #include <ttyent.h>
990e3d5408SPeter Wemm #endif
1000e3d5408SPeter Wemm #ifdef NeXT
1010e3d5408SPeter Wemm char *ttyname(int fd);
1020e3d5408SPeter Wemm #endif
1030e3d5408SPeter Wemm 
1045d08fb1fSRong-En Fan #if HAVE_SIZECHANGE
1055d08fb1fSRong-En Fan # if !defined(sun) || !TERMIOS
1065d08fb1fSRong-En Fan #  if HAVE_SYS_IOCTL_H
1070e3d5408SPeter Wemm #   include <sys/ioctl.h>
1080e3d5408SPeter Wemm #  endif
1095d08fb1fSRong-En Fan # endif
1105d08fb1fSRong-En Fan #endif
1110e3d5408SPeter Wemm 
1120e3d5408SPeter Wemm #if NEED_PTEM_H
1130e3d5408SPeter Wemm /* they neglected to define struct winsize in termios.h -- it's only
1140e3d5408SPeter Wemm    in termio.h	*/
1150e3d5408SPeter Wemm #include <sys/stream.h>
1160e3d5408SPeter Wemm #include <sys/ptem.h>
1170e3d5408SPeter Wemm #endif
1180e3d5408SPeter Wemm 
1190e3d5408SPeter Wemm #include <dump_entry.h>
12018259542SPeter Wemm #include <transform.h>
1210e3d5408SPeter Wemm 
122*06bfebdeSXin LI MODULE_ID("$Id: tset.c,v 1.82 2010/05/01 21:42:46 tom Exp $")
1235d08fb1fSRong-En Fan 
1245d08fb1fSRong-En Fan /*
1255d08fb1fSRong-En Fan  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
1265d08fb1fSRong-En Fan  * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
1275d08fb1fSRong-En Fan  */
1285d08fb1fSRong-En Fan #ifdef TIOCGSIZE
1295d08fb1fSRong-En Fan # define IOCTL_GET_WINSIZE TIOCGSIZE
1305d08fb1fSRong-En Fan # define IOCTL_SET_WINSIZE TIOCSSIZE
1315d08fb1fSRong-En Fan # define STRUCT_WINSIZE struct ttysize
1325d08fb1fSRong-En Fan # define WINSIZE_ROWS(n) n.ts_lines
1335d08fb1fSRong-En Fan # define WINSIZE_COLS(n) n.ts_cols
1345d08fb1fSRong-En Fan #else
1355d08fb1fSRong-En Fan # ifdef TIOCGWINSZ
1365d08fb1fSRong-En Fan #  define IOCTL_GET_WINSIZE TIOCGWINSZ
1375d08fb1fSRong-En Fan #  define IOCTL_SET_WINSIZE TIOCSWINSZ
1385d08fb1fSRong-En Fan #  define STRUCT_WINSIZE struct winsize
1395d08fb1fSRong-En Fan #  define WINSIZE_ROWS(n) n.ws_row
1405d08fb1fSRong-En Fan #  define WINSIZE_COLS(n) n.ws_col
1415d08fb1fSRong-En Fan # endif
1425d08fb1fSRong-En Fan #endif
1430e3d5408SPeter Wemm 
144*06bfebdeSXin LI #ifndef environ
1450e3d5408SPeter Wemm extern char **environ;
146*06bfebdeSXin LI #endif
1470e3d5408SPeter Wemm 
1480e3d5408SPeter Wemm #undef CTRL
1490e3d5408SPeter Wemm #define CTRL(x)	((x) & 0x1f)
1500e3d5408SPeter Wemm 
1510e3d5408SPeter Wemm const char *_nc_progname = "tset";
1520e3d5408SPeter Wemm 
15339f2269fSPeter Wemm static TTY mode, oldmode, original;
1540e3d5408SPeter Wemm 
1554a1a9510SRong-En Fan static bool opt_c;		/* set control-chars */
1564a1a9510SRong-En Fan static bool opt_w;		/* set window-size */
1574a1a9510SRong-En Fan 
15839f2269fSPeter Wemm static bool can_restore = FALSE;
15918259542SPeter Wemm static bool isreset = FALSE;	/* invoked as reset */
1600e3d5408SPeter Wemm static int terasechar = -1;	/* new erase character */
1610e3d5408SPeter Wemm static int intrchar = -1;	/* new interrupt character */
1620e3d5408SPeter Wemm static int tkillchar = -1;	/* new kill character */
1630e3d5408SPeter Wemm static int tlines, tcolumns;	/* window size */
1640e3d5408SPeter Wemm 
16539f2269fSPeter Wemm #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
1660e3d5408SPeter Wemm 
1670e3d5408SPeter Wemm static int
16815589c42SPeter Wemm CaselessCmp(const char *a, const char *b)
16915589c42SPeter Wemm {				/* strcasecmp isn't portable */
1700e3d5408SPeter Wemm     while (*a && *b) {
1710e3d5408SPeter Wemm 	int cmp = LOWERCASE(*a) - LOWERCASE(*b);
1720e3d5408SPeter Wemm 	if (cmp != 0)
1730e3d5408SPeter Wemm 	    break;
1740e3d5408SPeter Wemm 	a++, b++;
1750e3d5408SPeter Wemm     }
1760e3d5408SPeter Wemm     return LOWERCASE(*a) - LOWERCASE(*b);
1770e3d5408SPeter Wemm }
1780e3d5408SPeter Wemm 
1790e3d5408SPeter Wemm static void
18039f2269fSPeter Wemm exit_error(void)
18139f2269fSPeter Wemm {
18239f2269fSPeter Wemm     if (can_restore)
18339f2269fSPeter Wemm 	SET_TTY(STDERR_FILENO, &original);
18439f2269fSPeter Wemm     (void) fprintf(stderr, "\n");
18539f2269fSPeter Wemm     fflush(stderr);
1864a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
18739f2269fSPeter Wemm     /* NOTREACHED */
18839f2269fSPeter Wemm }
18939f2269fSPeter Wemm 
19039f2269fSPeter Wemm static void
1910e3d5408SPeter Wemm err(const char *fmt,...)
1920e3d5408SPeter Wemm {
1930e3d5408SPeter Wemm     va_list ap;
1940e3d5408SPeter Wemm     va_start(ap, fmt);
1954a1a9510SRong-En Fan     (void) fprintf(stderr, "%s: ", _nc_progname);
1960e3d5408SPeter Wemm     (void) vfprintf(stderr, fmt, ap);
1970e3d5408SPeter Wemm     va_end(ap);
19839f2269fSPeter Wemm     exit_error();
1990e3d5408SPeter Wemm     /* NOTREACHED */
2000e3d5408SPeter Wemm }
2010e3d5408SPeter Wemm 
2020e3d5408SPeter Wemm static void
2030e3d5408SPeter Wemm failed(const char *msg)
2040e3d5408SPeter Wemm {
2050e3d5408SPeter Wemm     char temp[BUFSIZ];
2064a1a9510SRong-En Fan     unsigned len = strlen(_nc_progname) + 2;
2074a1a9510SRong-En Fan 
2085d08fb1fSRong-En Fan     if ((int) len < (int) sizeof(temp) - 12) {
2094a1a9510SRong-En Fan 	strcpy(temp, _nc_progname);
2104a1a9510SRong-En Fan 	strcat(temp, ": ");
2114a1a9510SRong-En Fan     } else {
2124a1a9510SRong-En Fan 	strcpy(temp, "tset: ");
2134a1a9510SRong-En Fan     }
2144a1a9510SRong-En Fan     perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
21539f2269fSPeter Wemm     exit_error();
2160e3d5408SPeter Wemm     /* NOTREACHED */
2170e3d5408SPeter Wemm }
2180e3d5408SPeter Wemm 
2190e3d5408SPeter Wemm static void
2200e3d5408SPeter Wemm cat(char *file)
2210e3d5408SPeter Wemm {
22239f2269fSPeter Wemm     FILE *fp;
22339f2269fSPeter Wemm     size_t nr;
2240e3d5408SPeter Wemm     char buf[BUFSIZ];
2250e3d5408SPeter Wemm 
22639f2269fSPeter Wemm     if ((fp = fopen(file, "r")) == 0)
2270e3d5408SPeter Wemm 	failed(file);
2280e3d5408SPeter Wemm 
22939f2269fSPeter Wemm     while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
23039f2269fSPeter Wemm 	if (fwrite(buf, sizeof(char), nr, stderr) != nr)
2310e3d5408SPeter Wemm 	      failed("write to stderr");
23239f2269fSPeter Wemm     fclose(fp);
2330e3d5408SPeter Wemm }
2340e3d5408SPeter Wemm 
2350e3d5408SPeter Wemm static int
2360e3d5408SPeter Wemm outc(int c)
2370e3d5408SPeter Wemm {
2380e3d5408SPeter Wemm     return putc(c, stderr);
2390e3d5408SPeter Wemm }
2400e3d5408SPeter Wemm 
2410e3d5408SPeter Wemm /* Prompt the user for a terminal type. */
2420e3d5408SPeter Wemm static const char *
2430e3d5408SPeter Wemm askuser(const char *dflt)
2440e3d5408SPeter Wemm {
2450e3d5408SPeter Wemm     static char answer[256];
2460e3d5408SPeter Wemm     char *p;
2470e3d5408SPeter Wemm 
2480e3d5408SPeter Wemm     /* We can get recalled; if so, don't continue uselessly. */
2494a1a9510SRong-En Fan     clearerr(stdin);
2500e3d5408SPeter Wemm     if (feof(stdin) || ferror(stdin)) {
2510e3d5408SPeter Wemm 	(void) fprintf(stderr, "\n");
25239f2269fSPeter Wemm 	exit_error();
25339f2269fSPeter Wemm 	/* NOTREACHED */
2540e3d5408SPeter Wemm     }
2550e3d5408SPeter Wemm     for (;;) {
2560e3d5408SPeter Wemm 	if (dflt)
2570e3d5408SPeter Wemm 	    (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
2580e3d5408SPeter Wemm 	else
2590e3d5408SPeter Wemm 	    (void) fprintf(stderr, "Terminal type? ");
2600e3d5408SPeter Wemm 	(void) fflush(stderr);
2610e3d5408SPeter Wemm 
2620e3d5408SPeter Wemm 	if (fgets(answer, sizeof(answer), stdin) == 0) {
2630e3d5408SPeter Wemm 	    if (dflt == 0) {
26439f2269fSPeter Wemm 		exit_error();
26539f2269fSPeter Wemm 		/* NOTREACHED */
2660e3d5408SPeter Wemm 	    }
2670e3d5408SPeter Wemm 	    return (dflt);
2680e3d5408SPeter Wemm 	}
2690e3d5408SPeter Wemm 
2700e3d5408SPeter Wemm 	if ((p = strchr(answer, '\n')) != 0)
2710e3d5408SPeter Wemm 	    *p = '\0';
2720e3d5408SPeter Wemm 	if (answer[0])
2730e3d5408SPeter Wemm 	    return (answer);
2740e3d5408SPeter Wemm 	if (dflt != 0)
2750e3d5408SPeter Wemm 	    return (dflt);
2760e3d5408SPeter Wemm     }
2770e3d5408SPeter Wemm }
2780e3d5408SPeter Wemm 
2790e3d5408SPeter Wemm /**************************************************************************
2800e3d5408SPeter Wemm  *
2810e3d5408SPeter Wemm  * Mapping logic begins here
2820e3d5408SPeter Wemm  *
2830e3d5408SPeter Wemm  **************************************************************************/
2840e3d5408SPeter Wemm 
2850e3d5408SPeter Wemm /* Baud rate conditionals for mapping. */
2860e3d5408SPeter Wemm #define	GT		0x01
2870e3d5408SPeter Wemm #define	EQ		0x02
2880e3d5408SPeter Wemm #define	LT		0x04
2890e3d5408SPeter Wemm #define	NOT		0x08
2900e3d5408SPeter Wemm #define	GE		(GT | EQ)
2910e3d5408SPeter Wemm #define	LE		(LT | EQ)
2920e3d5408SPeter Wemm 
2930e3d5408SPeter Wemm typedef struct map {
2940e3d5408SPeter Wemm     struct map *next;		/* Linked list of maps. */
2950e3d5408SPeter Wemm     const char *porttype;	/* Port type, or "" for any. */
2960e3d5408SPeter Wemm     const char *type;		/* Terminal type to select. */
2970e3d5408SPeter Wemm     int conditional;		/* Baud rate conditionals bitmask. */
29818259542SPeter Wemm     int speed;			/* Baud rate to compare against. */
2990e3d5408SPeter Wemm } MAP;
3000e3d5408SPeter Wemm 
3010e3d5408SPeter Wemm static MAP *cur, *maplist;
3020e3d5408SPeter Wemm 
3030e3d5408SPeter Wemm typedef struct speeds {
3040e3d5408SPeter Wemm     const char *string;
3050e3d5408SPeter Wemm     int speed;
3060e3d5408SPeter Wemm } SPEEDS;
3070e3d5408SPeter Wemm 
30815589c42SPeter Wemm static const SPEEDS speeds[] =
30915589c42SPeter Wemm {
3100e3d5408SPeter Wemm     {"0", B0},
3110e3d5408SPeter Wemm     {"50", B50},
3120e3d5408SPeter Wemm     {"75", B75},
3130e3d5408SPeter Wemm     {"110", B110},
3140e3d5408SPeter Wemm     {"134", B134},
3150e3d5408SPeter Wemm     {"134.5", B134},
3160e3d5408SPeter Wemm     {"150", B150},
3170e3d5408SPeter Wemm     {"200", B200},
3180e3d5408SPeter Wemm     {"300", B300},
3190e3d5408SPeter Wemm     {"600", B600},
3200e3d5408SPeter Wemm     {"1200", B1200},
3210e3d5408SPeter Wemm     {"1800", B1800},
3220e3d5408SPeter Wemm     {"2400", B2400},
3230e3d5408SPeter Wemm     {"4800", B4800},
3240e3d5408SPeter Wemm     {"9600", B9600},
32518259542SPeter Wemm     /* sgttyb may define up to this point */
32618259542SPeter Wemm #ifdef B19200
3270e3d5408SPeter Wemm     {"19200", B19200},
32818259542SPeter Wemm #endif
32918259542SPeter Wemm #ifdef B38400
3300e3d5408SPeter Wemm     {"38400", B38400},
33118259542SPeter Wemm #endif
33218259542SPeter Wemm #ifdef B19200
3330e3d5408SPeter Wemm     {"19200", B19200},
33418259542SPeter Wemm #endif
33518259542SPeter Wemm #ifdef B38400
3360e3d5408SPeter Wemm     {"38400", B38400},
33718259542SPeter Wemm #endif
3380e3d5408SPeter Wemm #ifdef B19200
3390e3d5408SPeter Wemm     {"19200", B19200},
3400e3d5408SPeter Wemm #else
3410e3d5408SPeter Wemm #ifdef EXTA
3420e3d5408SPeter Wemm     {"19200", EXTA},
3430e3d5408SPeter Wemm #endif
3440e3d5408SPeter Wemm #endif
3450e3d5408SPeter Wemm #ifdef B38400
3460e3d5408SPeter Wemm     {"38400", B38400},
3470e3d5408SPeter Wemm #else
3480e3d5408SPeter Wemm #ifdef EXTB
3490e3d5408SPeter Wemm     {"38400", EXTB},
3500e3d5408SPeter Wemm #endif
3510e3d5408SPeter Wemm #endif
3520e3d5408SPeter Wemm #ifdef B57600
3530e3d5408SPeter Wemm     {"57600", B57600},
3540e3d5408SPeter Wemm #endif
3550e3d5408SPeter Wemm #ifdef B115200
3560e3d5408SPeter Wemm     {"115200", B115200},
3570e3d5408SPeter Wemm #endif
3580e3d5408SPeter Wemm #ifdef B230400
3590e3d5408SPeter Wemm     {"230400", B230400},
3600e3d5408SPeter Wemm #endif
3610e3d5408SPeter Wemm #ifdef B460800
3620e3d5408SPeter Wemm     {"460800", B460800},
3630e3d5408SPeter Wemm #endif
3640e3d5408SPeter Wemm     {(char *) 0, 0}
3650e3d5408SPeter Wemm };
3660e3d5408SPeter Wemm 
3670e3d5408SPeter Wemm static int
3680e3d5408SPeter Wemm tbaudrate(char *rate)
3690e3d5408SPeter Wemm {
3700e3d5408SPeter Wemm     const SPEEDS *sp;
3710e3d5408SPeter Wemm     int found = FALSE;
3720e3d5408SPeter Wemm 
3730e3d5408SPeter Wemm     /* The baudrate number can be preceded by a 'B', which is ignored. */
3740e3d5408SPeter Wemm     if (*rate == 'B')
3750e3d5408SPeter Wemm 	++rate;
3760e3d5408SPeter Wemm 
3770e3d5408SPeter Wemm     for (sp = speeds; sp->string; ++sp) {
3780e3d5408SPeter Wemm 	if (!CaselessCmp(rate, sp->string)) {
3790e3d5408SPeter Wemm 	    found = TRUE;
3800e3d5408SPeter Wemm 	    break;
3810e3d5408SPeter Wemm 	}
3820e3d5408SPeter Wemm     }
3830e3d5408SPeter Wemm     if (!found)
3840e3d5408SPeter Wemm 	err("unknown baud rate %s", rate);
3850e3d5408SPeter Wemm     return (sp->speed);
3860e3d5408SPeter Wemm }
3870e3d5408SPeter Wemm 
3880e3d5408SPeter Wemm /*
3890e3d5408SPeter Wemm  * Syntax for -m:
3900e3d5408SPeter Wemm  * [port-type][test baudrate]:terminal-type
3910e3d5408SPeter Wemm  * The baud rate tests are: >, <, @, =, !
3920e3d5408SPeter Wemm  */
3930e3d5408SPeter Wemm static void
3940e3d5408SPeter Wemm add_mapping(const char *port, char *arg)
3950e3d5408SPeter Wemm {
3960e3d5408SPeter Wemm     MAP *mapp;
3970e3d5408SPeter Wemm     char *copy, *p;
3980e3d5408SPeter Wemm     const char *termp;
3990e3d5408SPeter Wemm     char *base = 0;
4000e3d5408SPeter Wemm 
4010e3d5408SPeter Wemm     copy = strdup(arg);
402*06bfebdeSXin LI     mapp = typeMalloc(MAP, 1);
4030e3d5408SPeter Wemm     if (copy == 0 || mapp == 0)
4040e3d5408SPeter Wemm 	failed("malloc");
405*06bfebdeSXin LI 
406*06bfebdeSXin LI     assert(copy != 0);
407*06bfebdeSXin LI     assert(mapp != 0);
408*06bfebdeSXin LI 
4090e3d5408SPeter Wemm     mapp->next = 0;
4100e3d5408SPeter Wemm     if (maplist == 0)
4110e3d5408SPeter Wemm 	cur = maplist = mapp;
4120e3d5408SPeter Wemm     else {
4130e3d5408SPeter Wemm 	cur->next = mapp;
4140e3d5408SPeter Wemm 	cur = mapp;
4150e3d5408SPeter Wemm     }
4160e3d5408SPeter Wemm 
4170e3d5408SPeter Wemm     mapp->porttype = arg;
4180e3d5408SPeter Wemm     mapp->conditional = 0;
4190e3d5408SPeter Wemm 
4200e3d5408SPeter Wemm     arg = strpbrk(arg, "><@=!:");
4210e3d5408SPeter Wemm 
4220e3d5408SPeter Wemm     if (arg == 0) {		/* [?]term */
4230e3d5408SPeter Wemm 	mapp->type = mapp->porttype;
4240e3d5408SPeter Wemm 	mapp->porttype = 0;
4250e3d5408SPeter Wemm 	goto done;
4260e3d5408SPeter Wemm     }
4270e3d5408SPeter Wemm 
4280e3d5408SPeter Wemm     if (arg == mapp->porttype)	/* [><@=! baud]:term */
4290e3d5408SPeter Wemm 	termp = mapp->porttype = 0;
4300e3d5408SPeter Wemm     else
4310e3d5408SPeter Wemm 	termp = base = arg;
4320e3d5408SPeter Wemm 
43315589c42SPeter Wemm     for (;; ++arg) {		/* Optional conditionals. */
4340e3d5408SPeter Wemm 	switch (*arg) {
4350e3d5408SPeter Wemm 	case '<':
4360e3d5408SPeter Wemm 	    if (mapp->conditional & GT)
4370e3d5408SPeter Wemm 		goto badmopt;
4380e3d5408SPeter Wemm 	    mapp->conditional |= LT;
4390e3d5408SPeter Wemm 	    break;
4400e3d5408SPeter Wemm 	case '>':
4410e3d5408SPeter Wemm 	    if (mapp->conditional & LT)
4420e3d5408SPeter Wemm 		goto badmopt;
4430e3d5408SPeter Wemm 	    mapp->conditional |= GT;
4440e3d5408SPeter Wemm 	    break;
4450e3d5408SPeter Wemm 	case '@':
4460e3d5408SPeter Wemm 	case '=':		/* Not documented. */
4470e3d5408SPeter Wemm 	    mapp->conditional |= EQ;
4480e3d5408SPeter Wemm 	    break;
4490e3d5408SPeter Wemm 	case '!':
4500e3d5408SPeter Wemm 	    mapp->conditional |= NOT;
4510e3d5408SPeter Wemm 	    break;
4520e3d5408SPeter Wemm 	default:
4530e3d5408SPeter Wemm 	    goto next;
4540e3d5408SPeter Wemm 	}
45515589c42SPeter Wemm     }
4560e3d5408SPeter Wemm 
45715589c42SPeter Wemm   next:
45815589c42SPeter Wemm     if (*arg == ':') {
4590e3d5408SPeter Wemm 	if (mapp->conditional)
4600e3d5408SPeter Wemm 	    goto badmopt;
4610e3d5408SPeter Wemm 	++arg;
4620e3d5408SPeter Wemm     } else {			/* Optional baudrate. */
4630e3d5408SPeter Wemm 	arg = strchr(p = arg, ':');
4640e3d5408SPeter Wemm 	if (arg == 0)
4650e3d5408SPeter Wemm 	    goto badmopt;
4660e3d5408SPeter Wemm 	*arg++ = '\0';
4670e3d5408SPeter Wemm 	mapp->speed = tbaudrate(p);
4680e3d5408SPeter Wemm     }
4690e3d5408SPeter Wemm 
4700e3d5408SPeter Wemm     if (arg == (char *) 0)	/* Non-optional type. */
4710e3d5408SPeter Wemm 	goto badmopt;
4720e3d5408SPeter Wemm 
4730e3d5408SPeter Wemm     mapp->type = arg;
4740e3d5408SPeter Wemm 
4750e3d5408SPeter Wemm     /* Terminate porttype, if specified. */
4760e3d5408SPeter Wemm     if (termp != 0)
4770e3d5408SPeter Wemm 	*base = '\0';
4780e3d5408SPeter Wemm 
4790e3d5408SPeter Wemm     /* If a NOT conditional, reverse the test. */
4800e3d5408SPeter Wemm     if (mapp->conditional & NOT)
4810e3d5408SPeter Wemm 	mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
4820e3d5408SPeter Wemm 
4830e3d5408SPeter Wemm     /* If user specified a port with an option flag, set it. */
4845d08fb1fSRong-En Fan   done:
4855d08fb1fSRong-En Fan     if (port) {
4865d08fb1fSRong-En Fan 	if (mapp->porttype) {
4875d08fb1fSRong-En Fan 	  badmopt:
4885d08fb1fSRong-En Fan 	    err("illegal -m option format: %s", copy);
4895d08fb1fSRong-En Fan 	}
4900e3d5408SPeter Wemm 	mapp->porttype = port;
4910e3d5408SPeter Wemm     }
4925d08fb1fSRong-En Fan     free(copy);
4930e3d5408SPeter Wemm #ifdef MAPDEBUG
4940e3d5408SPeter Wemm     (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
4950e3d5408SPeter Wemm     (void) printf("type: %s\n", mapp->type);
4960e3d5408SPeter Wemm     (void) printf("conditional: ");
4970e3d5408SPeter Wemm     p = "";
4980e3d5408SPeter Wemm     if (mapp->conditional & GT) {
4990e3d5408SPeter Wemm 	(void) printf("GT");
5000e3d5408SPeter Wemm 	p = "/";
5010e3d5408SPeter Wemm     }
5020e3d5408SPeter Wemm     if (mapp->conditional & EQ) {
5030e3d5408SPeter Wemm 	(void) printf("%sEQ", p);
5040e3d5408SPeter Wemm 	p = "/";
5050e3d5408SPeter Wemm     }
5060e3d5408SPeter Wemm     if (mapp->conditional & LT)
5070e3d5408SPeter Wemm 	(void) printf("%sLT", p);
5080e3d5408SPeter Wemm     (void) printf("\nspeed: %d\n", mapp->speed);
5090e3d5408SPeter Wemm #endif
5100e3d5408SPeter Wemm }
5110e3d5408SPeter Wemm 
5120e3d5408SPeter Wemm /*
5130e3d5408SPeter Wemm  * Return the type of terminal to use for a port of type 'type', as specified
5140e3d5408SPeter Wemm  * by the first applicable mapping in 'map'.  If no mappings apply, return
5150e3d5408SPeter Wemm  * 'type'.
5160e3d5408SPeter Wemm  */
5170e3d5408SPeter Wemm static const char *
5180e3d5408SPeter Wemm mapped(const char *type)
5190e3d5408SPeter Wemm {
5200e3d5408SPeter Wemm     MAP *mapp;
5210e3d5408SPeter Wemm     int match;
5220e3d5408SPeter Wemm 
5230e3d5408SPeter Wemm     for (mapp = maplist; mapp; mapp = mapp->next)
5240e3d5408SPeter Wemm 	if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
5250e3d5408SPeter Wemm 	    switch (mapp->conditional) {
5260e3d5408SPeter Wemm 	    case 0:		/* No test specified. */
5270e3d5408SPeter Wemm 		match = TRUE;
5280e3d5408SPeter Wemm 		break;
5290e3d5408SPeter Wemm 	    case EQ:
5300e3d5408SPeter Wemm 		match = (ospeed == mapp->speed);
5310e3d5408SPeter Wemm 		break;
5320e3d5408SPeter Wemm 	    case GE:
5330e3d5408SPeter Wemm 		match = (ospeed >= mapp->speed);
5340e3d5408SPeter Wemm 		break;
5350e3d5408SPeter Wemm 	    case GT:
5360e3d5408SPeter Wemm 		match = (ospeed > mapp->speed);
5370e3d5408SPeter Wemm 		break;
5380e3d5408SPeter Wemm 	    case LE:
5390e3d5408SPeter Wemm 		match = (ospeed <= mapp->speed);
5400e3d5408SPeter Wemm 		break;
5410e3d5408SPeter Wemm 	    case LT:
5420e3d5408SPeter Wemm 		match = (ospeed < mapp->speed);
5430e3d5408SPeter Wemm 		break;
5440e3d5408SPeter Wemm 	    default:
5450e3d5408SPeter Wemm 		match = FALSE;
5460e3d5408SPeter Wemm 	    }
5470e3d5408SPeter Wemm 	    if (match)
5480e3d5408SPeter Wemm 		return (mapp->type);
5490e3d5408SPeter Wemm 	}
5500e3d5408SPeter Wemm     /* No match found; return given type. */
5510e3d5408SPeter Wemm     return (type);
5520e3d5408SPeter Wemm }
5530e3d5408SPeter Wemm 
5540e3d5408SPeter Wemm /**************************************************************************
5550e3d5408SPeter Wemm  *
5560e3d5408SPeter Wemm  * Entry fetching
5570e3d5408SPeter Wemm  *
5580e3d5408SPeter Wemm  **************************************************************************/
5590e3d5408SPeter Wemm 
5600e3d5408SPeter Wemm /*
5610e3d5408SPeter Wemm  * Figure out what kind of terminal we're dealing with, and then read in
5620e3d5408SPeter Wemm  * its termcap entry.
5630e3d5408SPeter Wemm  */
5640e3d5408SPeter Wemm static const char *
5650e3d5408SPeter Wemm get_termcap_entry(char *userarg)
5660e3d5408SPeter Wemm {
5677a69bbfbSPeter Wemm     int errret;
5680e3d5408SPeter Wemm     char *p;
5690e3d5408SPeter Wemm     const char *ttype;
5700e3d5408SPeter Wemm #if HAVE_GETTTYNAM
5710e3d5408SPeter Wemm     struct ttyent *t;
5720e3d5408SPeter Wemm #else
5730e3d5408SPeter Wemm     FILE *fp;
5740e3d5408SPeter Wemm #endif
5750e3d5408SPeter Wemm     char *ttypath;
5760e3d5408SPeter Wemm 
5770e3d5408SPeter Wemm     if (userarg) {
5780e3d5408SPeter Wemm 	ttype = userarg;
5790e3d5408SPeter Wemm 	goto found;
5800e3d5408SPeter Wemm     }
5810e3d5408SPeter Wemm 
5820e3d5408SPeter Wemm     /* Try the environment. */
5830e3d5408SPeter Wemm     if ((ttype = getenv("TERM")) != 0)
5840e3d5408SPeter Wemm 	goto map;
5850e3d5408SPeter Wemm 
5860e3d5408SPeter Wemm     if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
58718259542SPeter Wemm 	p = _nc_basename(ttypath);
5880e3d5408SPeter Wemm #if HAVE_GETTTYNAM
5890e3d5408SPeter Wemm 	/*
5900e3d5408SPeter Wemm 	 * We have the 4.3BSD library call getttynam(3); that means
5910e3d5408SPeter Wemm 	 * there's an /etc/ttys to look up device-to-type mappings in.
5920e3d5408SPeter Wemm 	 * Try ttyname(3); check for dialup or other mapping.
5930e3d5408SPeter Wemm 	 */
5940e3d5408SPeter Wemm 	if ((t = getttynam(p))) {
5950e3d5408SPeter Wemm 	    ttype = t->ty_type;
5960e3d5408SPeter Wemm 	    goto map;
5970e3d5408SPeter Wemm 	}
5980e3d5408SPeter Wemm #else
5990e3d5408SPeter Wemm 	if ((fp = fopen("/etc/ttytype", "r")) != 0
6000e3d5408SPeter Wemm 	    || (fp = fopen("/etc/ttys", "r")) != 0) {
6010e3d5408SPeter Wemm 	    char buffer[BUFSIZ];
6020e3d5408SPeter Wemm 	    char *s, *t, *d;
6030e3d5408SPeter Wemm 
6040e3d5408SPeter Wemm 	    while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
6050e3d5408SPeter Wemm 		for (s = buffer, t = d = 0; *s; s++) {
60639f2269fSPeter Wemm 		    if (isspace(UChar(*s)))
6070e3d5408SPeter Wemm 			*s = '\0';
6080e3d5408SPeter Wemm 		    else if (t == 0)
6090e3d5408SPeter Wemm 			t = s;
6100e3d5408SPeter Wemm 		    else if (d == 0 && s != buffer && s[-1] == '\0')
6110e3d5408SPeter Wemm 			d = s;
6120e3d5408SPeter Wemm 		}
6130e3d5408SPeter Wemm 		if (t != 0 && d != 0 && !strcmp(d, p)) {
6140e3d5408SPeter Wemm 		    ttype = strdup(t);
6150e3d5408SPeter Wemm 		    fclose(fp);
6160e3d5408SPeter Wemm 		    goto map;
6170e3d5408SPeter Wemm 		}
6180e3d5408SPeter Wemm 	    }
6190e3d5408SPeter Wemm 	    fclose(fp);
6200e3d5408SPeter Wemm 	}
6210e3d5408SPeter Wemm #endif /* HAVE_GETTTYNAM */
6220e3d5408SPeter Wemm     }
6230e3d5408SPeter Wemm 
6240e3d5408SPeter Wemm     /* If still undefined, use "unknown". */
6250e3d5408SPeter Wemm     ttype = "unknown";
6260e3d5408SPeter Wemm 
6270e3d5408SPeter Wemm   map:ttype = mapped(ttype);
6280e3d5408SPeter Wemm 
6290e3d5408SPeter Wemm     /*
6300e3d5408SPeter Wemm      * If not a path, remove TERMCAP from the environment so we get a
6310e3d5408SPeter Wemm      * real entry from /etc/termcap.  This prevents us from being fooled
6320e3d5408SPeter Wemm      * by out of date stuff in the environment.
6330e3d5408SPeter Wemm      */
6344a1a9510SRong-En Fan   found:if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
6350e3d5408SPeter Wemm 	/* 'unsetenv("TERMCAP")' is not portable.
6360e3d5408SPeter Wemm 	 * The 'environ' array is better.
6370e3d5408SPeter Wemm 	 */
6380e3d5408SPeter Wemm 	int n;
6390e3d5408SPeter Wemm 	for (n = 0; environ[n] != 0; n++) {
6400e3d5408SPeter Wemm 	    if (!strncmp("TERMCAP=", environ[n], 8)) {
6410e3d5408SPeter Wemm 		while ((environ[n] = environ[n + 1]) != 0) {
6420e3d5408SPeter Wemm 		    n++;
6430e3d5408SPeter Wemm 		}
6440e3d5408SPeter Wemm 		break;
6450e3d5408SPeter Wemm 	    }
6460e3d5408SPeter Wemm 	}
6470e3d5408SPeter Wemm     }
6480e3d5408SPeter Wemm 
6490e3d5408SPeter Wemm     /*
6500e3d5408SPeter Wemm      * ttype now contains a pointer to the type of the terminal.
6510e3d5408SPeter Wemm      * If the first character is '?', ask the user.
6520e3d5408SPeter Wemm      */
6530e3d5408SPeter Wemm     if (ttype[0] == '?') {
6540e3d5408SPeter Wemm 	if (ttype[1] != '\0')
6550e3d5408SPeter Wemm 	    ttype = askuser(ttype + 1);
6560e3d5408SPeter Wemm 	else
6570e3d5408SPeter Wemm 	    ttype = askuser(0);
6580e3d5408SPeter Wemm     }
6590e3d5408SPeter Wemm     /* Find the terminfo entry.  If it doesn't exist, ask the user. */
6607a69bbfbSPeter Wemm     while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
6617a69bbfbSPeter Wemm 	   != OK) {
6620e3d5408SPeter Wemm 	if (errret == 0) {
6634a1a9510SRong-En Fan 	    (void) fprintf(stderr, "%s: unknown terminal type %s\n",
6644a1a9510SRong-En Fan 			   _nc_progname, ttype);
6650e3d5408SPeter Wemm 	    ttype = 0;
66615589c42SPeter Wemm 	} else {
66715589c42SPeter Wemm 	    (void) fprintf(stderr,
6684a1a9510SRong-En Fan 			   "%s: can't initialize terminal type %s (error %d)\n",
6694a1a9510SRong-En Fan 			   _nc_progname, ttype, errret);
6700e3d5408SPeter Wemm 	    ttype = 0;
6710e3d5408SPeter Wemm 	}
6720e3d5408SPeter Wemm 	ttype = askuser(ttype);
6730e3d5408SPeter Wemm     }
6740e3d5408SPeter Wemm #if BROKEN_LINKER
6750e3d5408SPeter Wemm     tgetflag("am");		/* force lib_termcap.o to be linked for 'ospeed' */
6760e3d5408SPeter Wemm #endif
6770e3d5408SPeter Wemm     return (ttype);
6780e3d5408SPeter Wemm }
6790e3d5408SPeter Wemm 
6800e3d5408SPeter Wemm /**************************************************************************
6810e3d5408SPeter Wemm  *
6820e3d5408SPeter Wemm  * Mode-setting logic
6830e3d5408SPeter Wemm  *
6840e3d5408SPeter Wemm  **************************************************************************/
6850e3d5408SPeter Wemm 
6860e3d5408SPeter Wemm /* some BSD systems have these built in, some systems are missing
6874a1a9510SRong-En Fan  * one or more definitions. The safest solution is to override unless the
6884a1a9510SRong-En Fan  * commonly-altered ones are defined.
6890e3d5408SPeter Wemm  */
6904a1a9510SRong-En Fan #if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
6910e3d5408SPeter Wemm #undef CEOF
6920e3d5408SPeter Wemm #undef CERASE
6930e3d5408SPeter Wemm #undef CINTR
6940e3d5408SPeter Wemm #undef CKILL
6950e3d5408SPeter Wemm #undef CLNEXT
6960e3d5408SPeter Wemm #undef CRPRNT
6970e3d5408SPeter Wemm #undef CQUIT
6980e3d5408SPeter Wemm #undef CSTART
6990e3d5408SPeter Wemm #undef CSTOP
7000e3d5408SPeter Wemm #undef CSUSP
7014a1a9510SRong-En Fan #endif
7020e3d5408SPeter Wemm 
7030e3d5408SPeter Wemm /* control-character defaults */
7044a1a9510SRong-En Fan #ifndef CEOF
7050e3d5408SPeter Wemm #define CEOF	CTRL('D')
7064a1a9510SRong-En Fan #endif
7074a1a9510SRong-En Fan #ifndef CERASE
7080e3d5408SPeter Wemm #define CERASE	CTRL('H')
7094a1a9510SRong-En Fan #endif
7104a1a9510SRong-En Fan #ifndef CINTR
7110e3d5408SPeter Wemm #define CINTR	127		/* ^? */
7124a1a9510SRong-En Fan #endif
7134a1a9510SRong-En Fan #ifndef CKILL
7140e3d5408SPeter Wemm #define CKILL	CTRL('U')
7154a1a9510SRong-En Fan #endif
7164a1a9510SRong-En Fan #ifndef CLNEXT
7170e3d5408SPeter Wemm #define CLNEXT  CTRL('v')
7184a1a9510SRong-En Fan #endif
7194a1a9510SRong-En Fan #ifndef CRPRNT
7200e3d5408SPeter Wemm #define CRPRNT  CTRL('r')
7214a1a9510SRong-En Fan #endif
7224a1a9510SRong-En Fan #ifndef CQUIT
7230e3d5408SPeter Wemm #define CQUIT	CTRL('\\')
7244a1a9510SRong-En Fan #endif
7254a1a9510SRong-En Fan #ifndef CSTART
7260e3d5408SPeter Wemm #define CSTART	CTRL('Q')
7274a1a9510SRong-En Fan #endif
7284a1a9510SRong-En Fan #ifndef CSTOP
7290e3d5408SPeter Wemm #define CSTOP	CTRL('S')
7304a1a9510SRong-En Fan #endif
7314a1a9510SRong-En Fan #ifndef CSUSP
7320e3d5408SPeter Wemm #define CSUSP	CTRL('Z')
7334a1a9510SRong-En Fan #endif
7340e3d5408SPeter Wemm 
7354a1a9510SRong-En Fan #if defined(_POSIX_VDISABLE)
7364a1a9510SRong-En Fan #define DISABLED(val)   (((_POSIX_VDISABLE != -1) \
7374a1a9510SRong-En Fan 		       && ((val) == _POSIX_VDISABLE)) \
7384a1a9510SRong-En Fan 		      || ((val) <= 0))
7394a1a9510SRong-En Fan #else
7404a1a9510SRong-En Fan #define DISABLED(val)   ((int)(val) <= 0)
7414a1a9510SRong-En Fan #endif
7424a1a9510SRong-En Fan 
7434a1a9510SRong-En Fan #define CHK(val, dft)   (DISABLED(val) ? dft : val)
7440e3d5408SPeter Wemm 
7450e3d5408SPeter Wemm static bool set_tabs(void);
7460e3d5408SPeter Wemm 
7470e3d5408SPeter Wemm /*
7480e3d5408SPeter Wemm  * Reset the terminal mode bits to a sensible state.  Very useful after
7490e3d5408SPeter Wemm  * a child program dies in raw mode.
7500e3d5408SPeter Wemm  */
7510e3d5408SPeter Wemm static void
7520e3d5408SPeter Wemm reset_mode(void)
7530e3d5408SPeter Wemm {
7540e3d5408SPeter Wemm #ifdef TERMIOS
7550e3d5408SPeter Wemm     tcgetattr(STDERR_FILENO, &mode);
7560e3d5408SPeter Wemm #else
7570e3d5408SPeter Wemm     stty(STDERR_FILENO, &mode);
7580e3d5408SPeter Wemm #endif
7590e3d5408SPeter Wemm 
7600e3d5408SPeter Wemm #ifdef TERMIOS
7610e3d5408SPeter Wemm #if defined(VDISCARD) && defined(CDISCARD)
7620e3d5408SPeter Wemm     mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
7630e3d5408SPeter Wemm #endif
7640e3d5408SPeter Wemm     mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
7650e3d5408SPeter Wemm     mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
7660e3d5408SPeter Wemm #if defined(VFLUSH) && defined(CFLUSH)
7670e3d5408SPeter Wemm     mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
7680e3d5408SPeter Wemm #endif
7690e3d5408SPeter Wemm     mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
7700e3d5408SPeter Wemm     mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
7710e3d5408SPeter Wemm #if defined(VLNEXT) && defined(CLNEXT)
7720e3d5408SPeter Wemm     mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
7730e3d5408SPeter Wemm #endif
7740e3d5408SPeter Wemm     mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
7750e3d5408SPeter Wemm #if defined(VREPRINT) && defined(CRPRNT)
7760e3d5408SPeter Wemm     mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
7770e3d5408SPeter Wemm #endif
7780e3d5408SPeter Wemm #if defined(VSTART) && defined(CSTART)
7790e3d5408SPeter Wemm     mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
7800e3d5408SPeter Wemm #endif
7810e3d5408SPeter Wemm #if defined(VSTOP) && defined(CSTOP)
7820e3d5408SPeter Wemm     mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
7830e3d5408SPeter Wemm #endif
7840e3d5408SPeter Wemm #if defined(VSUSP) && defined(CSUSP)
7850e3d5408SPeter Wemm     mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
7860e3d5408SPeter Wemm #endif
7870e3d5408SPeter Wemm #if defined(VWERASE) && defined(CWERASE)
7880e3d5408SPeter Wemm     mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
7890e3d5408SPeter Wemm #endif
7900e3d5408SPeter Wemm 
7910e3d5408SPeter Wemm     mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
7920e3d5408SPeter Wemm #ifdef IUCLC
7930e3d5408SPeter Wemm 		      | IUCLC
7940e3d5408SPeter Wemm #endif
7950e3d5408SPeter Wemm #ifdef IXANY
7960e3d5408SPeter Wemm 		      | IXANY
7970e3d5408SPeter Wemm #endif
7980e3d5408SPeter Wemm 		      | IXOFF);
7990e3d5408SPeter Wemm 
8000e3d5408SPeter Wemm     mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
8010e3d5408SPeter Wemm #ifdef IMAXBEL
8020e3d5408SPeter Wemm 		     | IMAXBEL
8030e3d5408SPeter Wemm #endif
8040e3d5408SPeter Wemm 	);
8050e3d5408SPeter Wemm 
8060e3d5408SPeter Wemm     mode.c_oflag &= ~(0
8070e3d5408SPeter Wemm #ifdef OLCUC
8080e3d5408SPeter Wemm 		      | OLCUC
8090e3d5408SPeter Wemm #endif
8100e3d5408SPeter Wemm #ifdef OCRNL
8110e3d5408SPeter Wemm 		      | OCRNL
8120e3d5408SPeter Wemm #endif
8130e3d5408SPeter Wemm #ifdef ONOCR
8140e3d5408SPeter Wemm 		      | ONOCR
8150e3d5408SPeter Wemm #endif
8160e3d5408SPeter Wemm #ifdef ONLRET
8170e3d5408SPeter Wemm 		      | ONLRET
8180e3d5408SPeter Wemm #endif
8190e3d5408SPeter Wemm #ifdef OFILL
8200e3d5408SPeter Wemm 		      | OFILL
8210e3d5408SPeter Wemm #endif
8220e3d5408SPeter Wemm #ifdef OFDEL
8230e3d5408SPeter Wemm 		      | OFDEL
8240e3d5408SPeter Wemm #endif
8250e3d5408SPeter Wemm #ifdef NLDLY
8265ca44d1cSRong-En Fan 		      | NLDLY
8275ca44d1cSRong-En Fan #endif
8285ca44d1cSRong-En Fan #ifdef CRDLY
8295ca44d1cSRong-En Fan 		      | CRDLY
8305ca44d1cSRong-En Fan #endif
8315ca44d1cSRong-En Fan #ifdef TABDLY
8325ca44d1cSRong-En Fan 		      | TABDLY
8335ca44d1cSRong-En Fan #endif
8345ca44d1cSRong-En Fan #ifdef BSDLY
8355ca44d1cSRong-En Fan 		      | BSDLY
8365ca44d1cSRong-En Fan #endif
8375ca44d1cSRong-En Fan #ifdef VTDLY
8385ca44d1cSRong-En Fan 		      | VTDLY
8395ca44d1cSRong-En Fan #endif
8405ca44d1cSRong-En Fan #ifdef FFDLY
8415ca44d1cSRong-En Fan 		      | FFDLY
8420e3d5408SPeter Wemm #endif
8430e3d5408SPeter Wemm 	);
8440e3d5408SPeter Wemm 
8450e3d5408SPeter Wemm     mode.c_oflag |= (OPOST
8460e3d5408SPeter Wemm #ifdef ONLCR
8470e3d5408SPeter Wemm 		     | ONLCR
8480e3d5408SPeter Wemm #endif
8490e3d5408SPeter Wemm 	);
8500e3d5408SPeter Wemm 
8510e3d5408SPeter Wemm     mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
8520e3d5408SPeter Wemm     mode.c_cflag |= (CS8 | CREAD);
8530e3d5408SPeter Wemm     mode.c_lflag &= ~(ECHONL | NOFLSH
8540e3d5408SPeter Wemm #ifdef TOSTOP
8550e3d5408SPeter Wemm 		      | TOSTOP
8560e3d5408SPeter Wemm #endif
8570e3d5408SPeter Wemm #ifdef ECHOPTR
8580e3d5408SPeter Wemm 		      | ECHOPRT
8590e3d5408SPeter Wemm #endif
8600e3d5408SPeter Wemm #ifdef XCASE
8610e3d5408SPeter Wemm 		      | XCASE
8620e3d5408SPeter Wemm #endif
8630e3d5408SPeter Wemm 	);
8640e3d5408SPeter Wemm 
8650e3d5408SPeter Wemm     mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
8660e3d5408SPeter Wemm #ifdef ECHOCTL
8670e3d5408SPeter Wemm 		     | ECHOCTL
8680e3d5408SPeter Wemm #endif
8690e3d5408SPeter Wemm #ifdef ECHOKE
8700e3d5408SPeter Wemm 		     | ECHOKE
8710e3d5408SPeter Wemm #endif
8720e3d5408SPeter Wemm 	);
8730e3d5408SPeter Wemm #endif
8740e3d5408SPeter Wemm 
87539f2269fSPeter Wemm     SET_TTY(STDERR_FILENO, &mode);
8760e3d5408SPeter Wemm }
8770e3d5408SPeter Wemm 
8780e3d5408SPeter Wemm /*
8790e3d5408SPeter Wemm  * Returns a "good" value for the erase character.  This is loosely based on
8800e3d5408SPeter Wemm  * the BSD4.4 logic.
8810e3d5408SPeter Wemm  */
88218259542SPeter Wemm #ifdef TERMIOS
8830e3d5408SPeter Wemm static int
8840e3d5408SPeter Wemm default_erase(void)
8850e3d5408SPeter Wemm {
8860e3d5408SPeter Wemm     int result;
8870e3d5408SPeter Wemm 
8880e3d5408SPeter Wemm     if (over_strike
8890e3d5408SPeter Wemm 	&& key_backspace != 0
8900e3d5408SPeter Wemm 	&& strlen(key_backspace) == 1)
8910e3d5408SPeter Wemm 	result = key_backspace[0];
8920e3d5408SPeter Wemm     else
8930e3d5408SPeter Wemm 	result = CERASE;
8940e3d5408SPeter Wemm 
8950e3d5408SPeter Wemm     return result;
8960e3d5408SPeter Wemm }
89718259542SPeter Wemm #endif
8980e3d5408SPeter Wemm 
8990e3d5408SPeter Wemm /*
9000e3d5408SPeter Wemm  * Update the values of the erase, interrupt, and kill characters in 'mode'.
9010e3d5408SPeter Wemm  *
9020e3d5408SPeter Wemm  * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
9030e3d5408SPeter Wemm  * characters if they're unset, or if we specify them as options.  This differs
9040e3d5408SPeter Wemm  * from BSD 4.4 tset, which always sets erase.
9050e3d5408SPeter Wemm  */
9060e3d5408SPeter Wemm static void
9070e3d5408SPeter Wemm set_control_chars(void)
9080e3d5408SPeter Wemm {
9090e3d5408SPeter Wemm #ifdef TERMIOS
9104a1a9510SRong-En Fan     if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0)
9115d08fb1fSRong-En Fan 	mode.c_cc[VERASE] = (terasechar >= 0) ? terasechar : default_erase();
9120e3d5408SPeter Wemm 
9134a1a9510SRong-En Fan     if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0)
9145d08fb1fSRong-En Fan 	mode.c_cc[VINTR] = (intrchar >= 0) ? intrchar : CINTR;
9150e3d5408SPeter Wemm 
9164a1a9510SRong-En Fan     if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0)
9175d08fb1fSRong-En Fan 	mode.c_cc[VKILL] = (tkillchar >= 0) ? tkillchar : CKILL;
9180e3d5408SPeter Wemm #endif
9190e3d5408SPeter Wemm }
9200e3d5408SPeter Wemm 
9210e3d5408SPeter Wemm /*
9220e3d5408SPeter Wemm  * Set up various conversions in 'mode', including parity, tabs, returns,
9230e3d5408SPeter Wemm  * echo, and case, according to the termcap entry.  If the program we're
9240e3d5408SPeter Wemm  * running was named with a leading upper-case character, map external
9250e3d5408SPeter Wemm  * uppercase to internal lowercase.
9260e3d5408SPeter Wemm  */
9270e3d5408SPeter Wemm static void
9280e3d5408SPeter Wemm set_conversions(void)
9290e3d5408SPeter Wemm {
9300e3d5408SPeter Wemm #ifdef __OBSOLETE__
9310e3d5408SPeter Wemm     /*
9320e3d5408SPeter Wemm      * Conversion logic for some *really* ancient terminal glitches,
9330e3d5408SPeter Wemm      * not supported in terminfo.  Left here for succeeding generations
9340e3d5408SPeter Wemm      * to marvel at.
9350e3d5408SPeter Wemm      */
9360e3d5408SPeter Wemm     if (tgetflag("UC")) {
9370e3d5408SPeter Wemm #ifdef IUCLC
9380e3d5408SPeter Wemm 	mode.c_iflag |= IUCLC;
9390e3d5408SPeter Wemm 	mode.c_oflag |= OLCUC;
9400e3d5408SPeter Wemm #endif
9410e3d5408SPeter Wemm     } else if (tgetflag("LC")) {
9420e3d5408SPeter Wemm #ifdef IUCLC
9430e3d5408SPeter Wemm 	mode.c_iflag &= ~IUCLC;
9440e3d5408SPeter Wemm 	mode.c_oflag &= ~OLCUC;
9450e3d5408SPeter Wemm #endif
9460e3d5408SPeter Wemm     }
9470e3d5408SPeter Wemm     mode.c_iflag &= ~(PARMRK | INPCK);
9480e3d5408SPeter Wemm     mode.c_lflag |= ICANON;
9490e3d5408SPeter Wemm     if (tgetflag("EP")) {
9500e3d5408SPeter Wemm 	mode.c_cflag |= PARENB;
9510e3d5408SPeter Wemm 	mode.c_cflag &= ~PARODD;
9520e3d5408SPeter Wemm     }
9530e3d5408SPeter Wemm     if (tgetflag("OP")) {
9540e3d5408SPeter Wemm 	mode.c_cflag |= PARENB;
9550e3d5408SPeter Wemm 	mode.c_cflag |= PARODD;
9560e3d5408SPeter Wemm     }
9570e3d5408SPeter Wemm #endif /* __OBSOLETE__ */
9580e3d5408SPeter Wemm 
9590e3d5408SPeter Wemm #ifdef TERMIOS
9600e3d5408SPeter Wemm #ifdef ONLCR
9610e3d5408SPeter Wemm     mode.c_oflag |= ONLCR;
9620e3d5408SPeter Wemm #endif
9630e3d5408SPeter Wemm     mode.c_iflag |= ICRNL;
9640e3d5408SPeter Wemm     mode.c_lflag |= ECHO;
9650e3d5408SPeter Wemm #ifdef OXTABS
9660e3d5408SPeter Wemm     mode.c_oflag |= OXTABS;
9670e3d5408SPeter Wemm #endif /* OXTABS */
9680e3d5408SPeter Wemm 
9690e3d5408SPeter Wemm     /* test used to be tgetflag("NL") */
9700e3d5408SPeter Wemm     if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
9710e3d5408SPeter Wemm 	/* Newline, not linefeed. */
9720e3d5408SPeter Wemm #ifdef ONLCR
9730e3d5408SPeter Wemm 	mode.c_oflag &= ~ONLCR;
9740e3d5408SPeter Wemm #endif
9750e3d5408SPeter Wemm 	mode.c_iflag &= ~ICRNL;
9760e3d5408SPeter Wemm     }
9770e3d5408SPeter Wemm #ifdef __OBSOLETE__
9780e3d5408SPeter Wemm     if (tgetflag("HD"))		/* Half duplex. */
9790e3d5408SPeter Wemm 	mode.c_lflag &= ~ECHO;
9800e3d5408SPeter Wemm #endif /* __OBSOLETE__ */
9810e3d5408SPeter Wemm #ifdef OXTABS
9820e3d5408SPeter Wemm     /* test used to be tgetflag("pt") */
9830e3d5408SPeter Wemm     if (has_hardware_tabs)	/* Print tabs. */
9840e3d5408SPeter Wemm 	mode.c_oflag &= ~OXTABS;
9850e3d5408SPeter Wemm #endif /* OXTABS */
9860e3d5408SPeter Wemm     mode.c_lflag |= (ECHOE | ECHOK);
9870e3d5408SPeter Wemm #endif
9880e3d5408SPeter Wemm }
9890e3d5408SPeter Wemm 
9900e3d5408SPeter Wemm /* Output startup string. */
9910e3d5408SPeter Wemm static void
9920e3d5408SPeter Wemm set_init(void)
9930e3d5408SPeter Wemm {
9940e3d5408SPeter Wemm     char *p;
9950e3d5408SPeter Wemm     bool settle;
9960e3d5408SPeter Wemm 
9970e3d5408SPeter Wemm #ifdef __OBSOLETE__
9980e3d5408SPeter Wemm     if (pad_char != (char *) 0)	/* Get/set pad character. */
9990e3d5408SPeter Wemm 	PC = pad_char[0];
10000e3d5408SPeter Wemm #endif /* OBSOLETE */
10010e3d5408SPeter Wemm 
10020e3d5408SPeter Wemm #ifdef TAB3
10030e3d5408SPeter Wemm     if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
10040e3d5408SPeter Wemm 	oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
100539f2269fSPeter Wemm 	SET_TTY(STDERR_FILENO, &oldmode);
10060e3d5408SPeter Wemm     }
10070e3d5408SPeter Wemm #endif
10080e3d5408SPeter Wemm     settle = set_tabs();
10090e3d5408SPeter Wemm 
10100e3d5408SPeter Wemm     if (isreset) {
10110e3d5408SPeter Wemm 	if ((p = reset_1string) != 0) {
10120e3d5408SPeter Wemm 	    tputs(p, 0, outc);
10130e3d5408SPeter Wemm 	    settle = TRUE;
10140e3d5408SPeter Wemm 	}
10150e3d5408SPeter Wemm 	if ((p = reset_2string) != 0) {
10160e3d5408SPeter Wemm 	    tputs(p, 0, outc);
10170e3d5408SPeter Wemm 	    settle = TRUE;
10180e3d5408SPeter Wemm 	}
10190e3d5408SPeter Wemm 	/* What about rf, rs3, as per terminfo man page? */
10200e3d5408SPeter Wemm 	/* also might be nice to send rmacs, rmul, rmm */
10210e3d5408SPeter Wemm 	if ((p = reset_file) != 0
10220e3d5408SPeter Wemm 	    || (p = init_file) != 0) {
10230e3d5408SPeter Wemm 	    cat(p);
10240e3d5408SPeter Wemm 	    settle = TRUE;
10250e3d5408SPeter Wemm 	}
10260e3d5408SPeter Wemm     }
10270e3d5408SPeter Wemm 
10280e3d5408SPeter Wemm     if (settle) {
10290e3d5408SPeter Wemm 	(void) putc('\r', stderr);
10300e3d5408SPeter Wemm 	(void) fflush(stderr);
10310e3d5408SPeter Wemm 	(void) napms(1000);	/* Settle the terminal. */
10320e3d5408SPeter Wemm     }
10330e3d5408SPeter Wemm }
10340e3d5408SPeter Wemm 
10350e3d5408SPeter Wemm /*
10360e3d5408SPeter Wemm  * Set the hardware tabs on the terminal, using the ct (clear all tabs),
10370e3d5408SPeter Wemm  * st (set one tab) and ch (horizontal cursor addressing) capabilities.
10380e3d5408SPeter Wemm  * This is done before if and is, so they can patch in case we blow this.
10390e3d5408SPeter Wemm  * Return TRUE if we set any tab stops, FALSE if not.
10400e3d5408SPeter Wemm  */
10410e3d5408SPeter Wemm static bool
10424a1a9510SRong-En Fan set_tabs(void)
10430e3d5408SPeter Wemm {
10440e3d5408SPeter Wemm     if (set_tab && clear_all_tabs) {
10450e3d5408SPeter Wemm 	int c;
10460e3d5408SPeter Wemm 
10470e3d5408SPeter Wemm 	(void) putc('\r', stderr);	/* Force to left margin. */
10480e3d5408SPeter Wemm 	tputs(clear_all_tabs, 0, outc);
10490e3d5408SPeter Wemm 
10500e3d5408SPeter Wemm 	for (c = 8; c < tcolumns; c += 8) {
10510e3d5408SPeter Wemm 	    /* Get to the right column.  In BSD tset, this
10520e3d5408SPeter Wemm 	     * used to try a bunch of half-clever things
10530e3d5408SPeter Wemm 	     * with cup and hpa, for an average saving of
10540e3d5408SPeter Wemm 	     * somewhat less than two character times per
10554a1a9510SRong-En Fan 	     * tab stop, less than .01 sec at 2400cps. We
10560e3d5408SPeter Wemm 	     * lost all this cruft because it seemed to be
10570e3d5408SPeter Wemm 	     * introducing some odd bugs.
10584a1a9510SRong-En Fan 	     * -----------12345678----------- */
10590e3d5408SPeter Wemm 	    (void) fputs("        ", stderr);
10600e3d5408SPeter Wemm 	    tputs(set_tab, 0, outc);
10610e3d5408SPeter Wemm 	}
10620e3d5408SPeter Wemm 	putc('\r', stderr);
10630e3d5408SPeter Wemm 	return (TRUE);
10640e3d5408SPeter Wemm     }
10650e3d5408SPeter Wemm     return (FALSE);
10660e3d5408SPeter Wemm }
10670e3d5408SPeter Wemm 
10680e3d5408SPeter Wemm /**************************************************************************
10690e3d5408SPeter Wemm  *
10700e3d5408SPeter Wemm  * Main sequence
10710e3d5408SPeter Wemm  *
10720e3d5408SPeter Wemm  **************************************************************************/
10730e3d5408SPeter Wemm 
10740e3d5408SPeter Wemm /*
10750e3d5408SPeter Wemm  * Tell the user if a control key has been changed from the default value.
10760e3d5408SPeter Wemm  */
107718259542SPeter Wemm #ifdef TERMIOS
10780e3d5408SPeter Wemm static void
10790e3d5408SPeter Wemm report(const char *name, int which, unsigned def)
10800e3d5408SPeter Wemm {
10810e3d5408SPeter Wemm     unsigned older, newer;
10820e3d5408SPeter Wemm     char *p;
10830e3d5408SPeter Wemm 
10840e3d5408SPeter Wemm     newer = mode.c_cc[which];
10850e3d5408SPeter Wemm     older = oldmode.c_cc[which];
10860e3d5408SPeter Wemm 
10870e3d5408SPeter Wemm     if (older == newer && older == def)
10880e3d5408SPeter Wemm 	return;
10890e3d5408SPeter Wemm 
10900e3d5408SPeter Wemm     (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
10910e3d5408SPeter Wemm 
10924a1a9510SRong-En Fan     if (DISABLED(newer))
10934a1a9510SRong-En Fan 	(void) fprintf(stderr, "undef.\n");
10940e3d5408SPeter Wemm     /*
10950e3d5408SPeter Wemm      * Check 'delete' before 'backspace', since the key_backspace value
10960e3d5408SPeter Wemm      * is ambiguous.
10970e3d5408SPeter Wemm      */
10984a1a9510SRong-En Fan     else if (newer == 0177)
10990e3d5408SPeter Wemm 	(void) fprintf(stderr, "delete.\n");
11000e3d5408SPeter Wemm     else if ((p = key_backspace) != 0
11010e3d5408SPeter Wemm 	     && newer == (unsigned char) p[0]
11020e3d5408SPeter Wemm 	     && p[1] == '\0')
11030e3d5408SPeter Wemm 	(void) fprintf(stderr, "backspace.\n");
11040e3d5408SPeter Wemm     else if (newer < 040) {
11050e3d5408SPeter Wemm 	newer ^= 0100;
11064a1a9510SRong-En Fan 	(void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
11070e3d5408SPeter Wemm     } else
11084a1a9510SRong-En Fan 	(void) fprintf(stderr, "%c.\n", UChar(newer));
11090e3d5408SPeter Wemm }
111018259542SPeter Wemm #endif
11110e3d5408SPeter Wemm 
11120e3d5408SPeter Wemm /*
11130e3d5408SPeter Wemm  * Convert the obsolete argument forms into something that getopt can handle.
11140e3d5408SPeter Wemm  * This means that -e, -i and -k get default arguments supplied for them.
11150e3d5408SPeter Wemm  */
11160e3d5408SPeter Wemm static void
11170e3d5408SPeter Wemm obsolete(char **argv)
11180e3d5408SPeter Wemm {
11190e3d5408SPeter Wemm     for (; *argv; ++argv) {
11200e3d5408SPeter Wemm 	char *parm = argv[0];
11210e3d5408SPeter Wemm 
112215589c42SPeter Wemm 	if (parm[0] == '-' && parm[1] == '\0') {
11230e3d5408SPeter Wemm 	    argv[0] = strdup("-q");
11240e3d5408SPeter Wemm 	    continue;
11250e3d5408SPeter Wemm 	}
11260e3d5408SPeter Wemm 
11270e3d5408SPeter Wemm 	if ((parm[0] != '-')
11280e3d5408SPeter Wemm 	    || (argv[1] && argv[1][0] != '-')
11290e3d5408SPeter Wemm 	    || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
11300e3d5408SPeter Wemm 	    || (parm[2] != '\0'))
11310e3d5408SPeter Wemm 	    continue;
11320e3d5408SPeter Wemm 	switch (argv[0][1]) {
11330e3d5408SPeter Wemm 	case 'e':
11340e3d5408SPeter Wemm 	    argv[0] = strdup("-e^H");
11350e3d5408SPeter Wemm 	    break;
11360e3d5408SPeter Wemm 	case 'i':
11370e3d5408SPeter Wemm 	    argv[0] = strdup("-i^C");
11380e3d5408SPeter Wemm 	    break;
11390e3d5408SPeter Wemm 	case 'k':
11400e3d5408SPeter Wemm 	    argv[0] = strdup("-k^U");
11410e3d5408SPeter Wemm 	    break;
11420e3d5408SPeter Wemm 	}
11430e3d5408SPeter Wemm     }
11440e3d5408SPeter Wemm }
11450e3d5408SPeter Wemm 
11460e3d5408SPeter Wemm static void
11474a1a9510SRong-En Fan usage(void)
11480e3d5408SPeter Wemm {
11494a1a9510SRong-En Fan     static const char *tbl[] =
11504a1a9510SRong-En Fan     {
11514a1a9510SRong-En Fan 	""
11524a1a9510SRong-En Fan 	,"Options:"
11534a1a9510SRong-En Fan 	,"  -c          set control characters"
11544a1a9510SRong-En Fan 	,"  -e ch       erase character"
11554a1a9510SRong-En Fan 	,"  -I          no initialization strings"
11564a1a9510SRong-En Fan 	,"  -i ch       interrupt character"
11574a1a9510SRong-En Fan 	,"  -k ch       kill character"
11584a1a9510SRong-En Fan 	,"  -m mapping  map identifier to type"
11594a1a9510SRong-En Fan 	,"  -Q          do not output control key settings"
11604a1a9510SRong-En Fan 	,"  -r          display term on stderr"
11614a1a9510SRong-En Fan 	,"  -s          output TERM set command"
11624a1a9510SRong-En Fan 	,"  -V          print curses-version"
11634a1a9510SRong-En Fan 	,"  -w          set window-size"
11644a1a9510SRong-En Fan     };
11654a1a9510SRong-En Fan     unsigned n;
11664a1a9510SRong-En Fan     (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
11674a1a9510SRong-En Fan     for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n)
11684a1a9510SRong-En Fan 	fprintf(stderr, "%s\n", tbl[n]);
116939f2269fSPeter Wemm     exit_error();
117039f2269fSPeter Wemm     /* NOTREACHED */
11710e3d5408SPeter Wemm }
11720e3d5408SPeter Wemm 
117315589c42SPeter Wemm static char
117415589c42SPeter Wemm arg_to_char(void)
11750e3d5408SPeter Wemm {
11765d08fb1fSRong-En Fan     return (char) ((optarg[0] == '^' && optarg[1] != '\0')
11770e3d5408SPeter Wemm 		   ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
11785d08fb1fSRong-En Fan 		   : optarg[0]);
11790e3d5408SPeter Wemm }
11800e3d5408SPeter Wemm 
11810e3d5408SPeter Wemm int
11820e3d5408SPeter Wemm main(int argc, char **argv)
11830e3d5408SPeter Wemm {
11840e3d5408SPeter Wemm     int ch, noinit, noset, quiet, Sflag, sflag, showterm;
11850e3d5408SPeter Wemm     const char *p;
11860e3d5408SPeter Wemm     const char *ttype;
11870e3d5408SPeter Wemm 
11880e3d5408SPeter Wemm     obsolete(argv);
11890e3d5408SPeter Wemm     noinit = noset = quiet = Sflag = sflag = showterm = 0;
11905ca44d1cSRong-En Fan     while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
11910e3d5408SPeter Wemm 	switch (ch) {
11924a1a9510SRong-En Fan 	case 'c':		/* set control-chars */
11934a1a9510SRong-En Fan 	    opt_c = TRUE;
11940e3d5408SPeter Wemm 	    break;
11950e3d5408SPeter Wemm 	case 'a':		/* OBSOLETE: map identifier to type */
11960e3d5408SPeter Wemm 	    add_mapping("arpanet", optarg);
11970e3d5408SPeter Wemm 	    break;
11980e3d5408SPeter Wemm 	case 'd':		/* OBSOLETE: map identifier to type */
11990e3d5408SPeter Wemm 	    add_mapping("dialup", optarg);
12000e3d5408SPeter Wemm 	    break;
12010e3d5408SPeter Wemm 	case 'e':		/* erase character */
12020e3d5408SPeter Wemm 	    terasechar = arg_to_char();
12030e3d5408SPeter Wemm 	    break;
12040e3d5408SPeter Wemm 	case 'I':		/* no initialization strings */
12050e3d5408SPeter Wemm 	    noinit = 1;
12060e3d5408SPeter Wemm 	    break;
12070e3d5408SPeter Wemm 	case 'i':		/* interrupt character */
12080e3d5408SPeter Wemm 	    intrchar = arg_to_char();
12090e3d5408SPeter Wemm 	    break;
12100e3d5408SPeter Wemm 	case 'k':		/* kill character */
12110e3d5408SPeter Wemm 	    tkillchar = arg_to_char();
12120e3d5408SPeter Wemm 	    break;
12130e3d5408SPeter Wemm 	case 'm':		/* map identifier to type */
12140e3d5408SPeter Wemm 	    add_mapping(0, optarg);
12150e3d5408SPeter Wemm 	    break;
12160e3d5408SPeter Wemm 	case 'n':		/* OBSOLETE: set new tty driver */
12170e3d5408SPeter Wemm 	    break;
12180e3d5408SPeter Wemm 	case 'p':		/* OBSOLETE: map identifier to type */
12190e3d5408SPeter Wemm 	    add_mapping("plugboard", optarg);
12200e3d5408SPeter Wemm 	    break;
12210e3d5408SPeter Wemm 	case 'Q':		/* don't output control key settings */
12220e3d5408SPeter Wemm 	    quiet = 1;
12230e3d5408SPeter Wemm 	    break;
12244a1a9510SRong-En Fan 	case 'q':		/* display term only */
12254a1a9510SRong-En Fan 	    noset = 1;
12260e3d5408SPeter Wemm 	    break;
12270e3d5408SPeter Wemm 	case 'r':		/* display term on stderr */
12280e3d5408SPeter Wemm 	    showterm = 1;
12290e3d5408SPeter Wemm 	    break;
12304a1a9510SRong-En Fan 	case 'S':		/* OBSOLETE: output TERM & TERMCAP */
12314a1a9510SRong-En Fan 	    Sflag = 1;
12324a1a9510SRong-En Fan 	    break;
12330e3d5408SPeter Wemm 	case 's':		/* output TERM set command */
12340e3d5408SPeter Wemm 	    sflag = 1;
12350e3d5408SPeter Wemm 	    break;
12364a1a9510SRong-En Fan 	case 'V':		/* print curses-version */
123718259542SPeter Wemm 	    puts(curses_version());
12384a1a9510SRong-En Fan 	    ExitProgram(EXIT_SUCCESS);
12394a1a9510SRong-En Fan 	case 'w':		/* set window-size */
12404a1a9510SRong-En Fan 	    opt_w = TRUE;
12414a1a9510SRong-En Fan 	    break;
12420e3d5408SPeter Wemm 	case '?':
12430e3d5408SPeter Wemm 	default:
12444a1a9510SRong-En Fan 	    usage();
12450e3d5408SPeter Wemm 	}
12460e3d5408SPeter Wemm     }
12474a1a9510SRong-En Fan 
12484a1a9510SRong-En Fan     _nc_progname = _nc_rootname(*argv);
12490e3d5408SPeter Wemm     argc -= optind;
12500e3d5408SPeter Wemm     argv += optind;
12510e3d5408SPeter Wemm 
12520e3d5408SPeter Wemm     if (argc > 1)
12534a1a9510SRong-En Fan 	usage();
12544a1a9510SRong-En Fan 
12554a1a9510SRong-En Fan     if (!opt_c && !opt_w)
12564a1a9510SRong-En Fan 	opt_c = opt_w = TRUE;
12574a1a9510SRong-En Fan 
12584a1a9510SRong-En Fan     if (GET_TTY(STDERR_FILENO, &mode) < 0)
12594a1a9510SRong-En Fan 	failed("standard error");
12604a1a9510SRong-En Fan     can_restore = TRUE;
12614a1a9510SRong-En Fan     original = oldmode = mode;
12624a1a9510SRong-En Fan #ifdef TERMIOS
12635d08fb1fSRong-En Fan     ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
12644a1a9510SRong-En Fan #else
12655d08fb1fSRong-En Fan     ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
12664a1a9510SRong-En Fan #endif
12674a1a9510SRong-En Fan 
1268*06bfebdeSXin LI     if (same_program(_nc_progname, PROG_RESET)) {
12694a1a9510SRong-En Fan 	isreset = TRUE;
12704a1a9510SRong-En Fan 	reset_mode();
12714a1a9510SRong-En Fan     }
12720e3d5408SPeter Wemm 
1273*06bfebdeSXin LI     (void) get_termcap_entry(*argv);
12740e3d5408SPeter Wemm 
12750e3d5408SPeter Wemm     if (!noset) {
12760e3d5408SPeter Wemm 	tcolumns = columns;
12770e3d5408SPeter Wemm 	tlines = lines;
12780e3d5408SPeter Wemm 
12795d08fb1fSRong-En Fan #if HAVE_SIZECHANGE
12804a1a9510SRong-En Fan 	if (opt_w) {
12815d08fb1fSRong-En Fan 	    STRUCT_WINSIZE win;
12825d08fb1fSRong-En Fan 	    /* Set window size if not set already */
12835d08fb1fSRong-En Fan 	    (void) ioctl(STDERR_FILENO, IOCTL_GET_WINSIZE, &win);
12845d08fb1fSRong-En Fan 	    if (WINSIZE_ROWS(win) == 0 &&
12855d08fb1fSRong-En Fan 		WINSIZE_COLS(win) == 0 &&
12860e3d5408SPeter Wemm 		tlines > 0 && tcolumns > 0) {
12875d08fb1fSRong-En Fan 		WINSIZE_ROWS(win) = tlines;
12885d08fb1fSRong-En Fan 		WINSIZE_COLS(win) = tcolumns;
12895d08fb1fSRong-En Fan 		(void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win);
12900e3d5408SPeter Wemm 	    }
12914a1a9510SRong-En Fan 	}
12920e3d5408SPeter Wemm #endif
12934a1a9510SRong-En Fan 	if (opt_c) {
12940e3d5408SPeter Wemm 	    set_control_chars();
12950e3d5408SPeter Wemm 	    set_conversions();
12960e3d5408SPeter Wemm 
12970e3d5408SPeter Wemm 	    if (!noinit)
12980e3d5408SPeter Wemm 		set_init();
12990e3d5408SPeter Wemm 
13000e3d5408SPeter Wemm 	    /* Set the modes if they've changed. */
130115589c42SPeter Wemm 	    if (memcmp(&mode, &oldmode, sizeof(mode))) {
130239f2269fSPeter Wemm 		SET_TTY(STDERR_FILENO, &mode);
13030e3d5408SPeter Wemm 	    }
130415589c42SPeter Wemm 	}
13054a1a9510SRong-En Fan     }
13060e3d5408SPeter Wemm 
13070e3d5408SPeter Wemm     /* Get the terminal name from the entry. */
13080e3d5408SPeter Wemm     ttype = _nc_first_name(cur_term->type.term_names);
13090e3d5408SPeter Wemm 
13100e3d5408SPeter Wemm     if (noset)
13110e3d5408SPeter Wemm 	(void) printf("%s\n", ttype);
13120e3d5408SPeter Wemm     else {
13130e3d5408SPeter Wemm 	if (showterm)
13140e3d5408SPeter Wemm 	    (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
13150e3d5408SPeter Wemm 	/*
13160e3d5408SPeter Wemm 	 * If erase, kill and interrupt characters could have been
13170e3d5408SPeter Wemm 	 * modified and not -Q, display the changes.
13180e3d5408SPeter Wemm 	 */
131918259542SPeter Wemm #ifdef TERMIOS
13200e3d5408SPeter Wemm 	if (!quiet) {
13210e3d5408SPeter Wemm 	    report("Erase", VERASE, CERASE);
13224a1a9510SRong-En Fan 	    report("Kill", VKILL, CKILL);
13234a1a9510SRong-En Fan 	    report("Interrupt", VINTR, CINTR);
13240e3d5408SPeter Wemm 	}
132518259542SPeter Wemm #endif
13260e3d5408SPeter Wemm     }
13270e3d5408SPeter Wemm 
13280e3d5408SPeter Wemm     if (Sflag)
13290e3d5408SPeter Wemm 	err("The -S option is not supported under terminfo.");
13300e3d5408SPeter Wemm 
13310e3d5408SPeter Wemm     if (sflag) {
13324a1a9510SRong-En Fan 	int len;
13334a1a9510SRong-En Fan 	char *var;
13344a1a9510SRong-En Fan 	char *leaf;
13350e3d5408SPeter Wemm 	/*
13360e3d5408SPeter Wemm 	 * Figure out what shell we're using.  A hack, we look for an
13370e3d5408SPeter Wemm 	 * environmental variable SHELL ending in "csh".
13380e3d5408SPeter Wemm 	 */
13394a1a9510SRong-En Fan 	if ((var = getenv("SHELL")) != 0
13405d08fb1fSRong-En Fan 	    && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
13414a1a9510SRong-En Fan 	    && !strcmp(leaf + len - 3, "csh"))
13420e3d5408SPeter Wemm 	    p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
13430e3d5408SPeter Wemm 	else
13440e3d5408SPeter Wemm 	    p = "TERM=%s;\n";
13450e3d5408SPeter Wemm 	(void) printf(p, ttype);
13460e3d5408SPeter Wemm     }
13470e3d5408SPeter Wemm 
13484a1a9510SRong-En Fan     ExitProgram(EXIT_SUCCESS);
13490e3d5408SPeter Wemm }
1350