1 /****************************************************************************
2 * Copyright (c) 1998-2015,2016 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 * and: Thomas E. Dickey 1996-on *
33 ****************************************************************************/
37 * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
38 * lines from that version, and made changes/additions for 150 lines. There
39 * was no reformatting, so with/without ignoring whitespace, the amount of
42 * Comparing with current (2009) source, excluding this comment:
43 * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
45 * a) Ignoring whitespace, the current version still uses 516 lines from the
46 * 4.4BSD Lite sources, with 402 lines changed/added.
48 * Raymond's original comment on this follows...
52 * tset.c - terminal initialization utility
54 * This code was mostly swiped from 4.4BSD tset, with some obsolescent
55 * cruft removed and substantial portions rewritten. A Regents of the
56 * University of California copyright applies to some portions of the
57 * code, and is reproduced below:
60 * Copyright (c) 1980, 1991, 1993
61 * The Regents of the University of California. All rights reserved.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
66 * 1. Redistributions of source code must retain the above copyright
67 * notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in the
70 * documentation and/or other materials provided with the distribution.
71 * 3. Neither the name of the University nor the names of its contributors
72 * may be used to endorse or promote products derived from this software
73 * without specific prior written permission.
75 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
76 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
79 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 #define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */
90 #include <progs.priv.h>
97 #if HAVE_GETTTYNAM && HAVE_TTYENT_H
101 char *ttyname(int fd);
105 # if !defined(sun) || !TERMIOS
106 # if HAVE_SYS_IOCTL_H
107 # include <sys/ioctl.h>
113 /* they neglected to define struct winsize in termios.h -- it's only
115 #include <sys/stream.h>
116 #include <sys/ptem.h>
119 #include <dump_entry.h>
120 #include <transform.h>
122 MODULE_ID("$Id: tset.c,v 1.100 2016/07/30 21:32:26 tom Exp $")
125 * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
126 * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
129 # define IOCTL_GET_WINSIZE TIOCGSIZE
130 # define IOCTL_SET_WINSIZE TIOCSSIZE
131 # define STRUCT_WINSIZE struct ttysize
132 # define WINSIZE_ROWS(n) n.ts_lines
133 # define WINSIZE_COLS(n) n.ts_cols
136 # define IOCTL_GET_WINSIZE TIOCGWINSZ
137 # define IOCTL_SET_WINSIZE TIOCSWINSZ
138 # define STRUCT_WINSIZE struct winsize
139 # define WINSIZE_ROWS(n) n.ws_row
140 # define WINSIZE_COLS(n) n.ws_col
145 extern char **environ;
149 #define CTRL(x) ((x) & 0x1f)
151 static void failed(const char *) GCC_NORETURN;
152 static void exit_error(void) GCC_NORETURN;
153 static void err(const char *,...) GCC_NORETURN;
155 const char *_nc_progname = "tset";
158 static TTY mode, oldmode, original;
160 static bool opt_c; /* set control-chars */
161 static bool opt_w; /* set window-size */
163 static bool can_restore = FALSE;
164 static bool isreset = FALSE; /* invoked as reset */
165 static int terasechar = -1; /* new erase character */
166 static int intrchar = -1; /* new interrupt character */
167 static int tkillchar = -1; /* new kill character */
170 static int tlines, tcolumns; /* window size */
173 #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
176 CaselessCmp(const char *a, const char *b)
177 { /* strcasecmp isn't portable */
179 int cmp = LOWERCASE(*a) - LOWERCASE(*b);
184 return LOWERCASE(*a) - LOWERCASE(*b);
191 SET_TTY(my_fd, &original);
192 (void) fprintf(stderr, "\n");
194 ExitProgram(EXIT_FAILURE);
199 err(const char *fmt,...)
203 (void) fprintf(stderr, "%s: ", _nc_progname);
204 (void) vfprintf(stderr, fmt, ap);
211 failed(const char *msg)
214 size_t len = strlen(_nc_progname) + 2;
216 if ((int) len < (int) sizeof(temp) - 12) {
217 _nc_STRCPY(temp, _nc_progname, sizeof(temp));
218 _nc_STRCAT(temp, ": ", sizeof(temp));
220 _nc_STRCPY(temp, "tset: ", sizeof(temp));
222 perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
232 if (GET_TTY(my_fd, &mode) < 0) {
245 if ((fp = fopen(file, "r")) == 0)
248 while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
249 if (fwrite(buf, sizeof(char), nr, stderr) != nr)
250 failed("write to stderr");
257 return putc(c, stderr);
260 /* Prompt the user for a terminal type. */
262 askuser(const char *dflt)
264 static char answer[256];
267 /* We can get recalled; if so, don't continue uselessly. */
269 if (feof(stdin) || ferror(stdin)) {
270 (void) fprintf(stderr, "\n");
276 (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
278 (void) fprintf(stderr, "Terminal type? ");
279 (void) fflush(stderr);
281 if (fgets(answer, sizeof(answer), stdin) == 0) {
289 if ((p = strchr(answer, '\n')) != 0)
298 /**************************************************************************
300 * Mapping logic begins here
302 **************************************************************************/
304 /* Baud rate conditionals for mapping. */
313 struct map *next; /* Linked list of maps. */
314 const char *porttype; /* Port type, or "" for any. */
315 const char *type; /* Terminal type to select. */
316 int conditional; /* Baud rate conditionals bitmask. */
317 int speed; /* Baud rate to compare against. */
320 static MAP *cur, *maplist;
322 #define DATA(name,value) { { name }, value }
324 typedef struct speeds {
325 const char string[7];
329 static const SPEEDS speeds[] =
346 /* sgttyb may define up to this point */
348 DATA("19200", B19200),
351 DATA("38400", B38400),
354 DATA("19200", B19200),
357 DATA("38400", B38400),
360 DATA("19200", B19200),
367 DATA("38400", B38400),
374 DATA("57600", B57600),
377 DATA("115200", B115200),
380 DATA("230400", B230400),
383 DATA("460800", B460800),
389 tbaudrate(char *rate)
391 const SPEEDS *sp = 0;
394 /* The baudrate number can be preceded by a 'B', which is ignored. */
398 for (n = 0; n < SIZEOF(speeds); ++n) {
399 if (!CaselessCmp(rate, speeds[n].string)) {
405 err("unknown baud rate %s", rate);
411 * [port-type][test baudrate]:terminal-type
412 * The baud rate tests are: >, <, @, =, !
415 add_mapping(const char *port, char *arg)
423 mapp = typeMalloc(MAP, 1);
424 if (copy == 0 || mapp == 0)
432 cur = maplist = mapp;
438 mapp->porttype = arg;
439 mapp->conditional = 0;
441 arg = strpbrk(arg, "><@=!:");
443 if (arg == 0) { /* [?]term */
444 mapp->type = mapp->porttype;
449 if (arg == mapp->porttype) /* [><@=! baud]:term */
450 termp = mapp->porttype = 0;
454 for (;; ++arg) { /* Optional conditionals. */
457 if (mapp->conditional & GT)
459 mapp->conditional |= LT;
462 if (mapp->conditional & LT)
464 mapp->conditional |= GT;
467 case '=': /* Not documented. */
468 mapp->conditional |= EQ;
471 mapp->conditional |= NOT;
480 if (mapp->conditional)
483 } else { /* Optional baudrate. */
484 arg = strchr(p = arg, ':');
488 mapp->speed = tbaudrate(p);
493 /* Terminate porttype, if specified. */
497 /* If a NOT conditional, reverse the test. */
498 if (mapp->conditional & NOT)
499 mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
501 /* If user specified a port with an option flag, set it. */
504 if (mapp->porttype) {
506 err("illegal -m option format: %s", copy);
508 mapp->porttype = port;
512 (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
513 (void) printf("type: %s\n", mapp->type);
514 (void) printf("conditional: ");
516 if (mapp->conditional & GT) {
520 if (mapp->conditional & EQ) {
521 (void) printf("%sEQ", p);
524 if (mapp->conditional & LT)
525 (void) printf("%sLT", p);
526 (void) printf("\nspeed: %d\n", mapp->speed);
531 * Return the type of terminal to use for a port of type 'type', as specified
532 * by the first applicable mapping in 'map'. If no mappings apply, return
536 mapped(const char *type)
541 for (mapp = maplist; mapp; mapp = mapp->next)
542 if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
543 switch (mapp->conditional) {
544 case 0: /* No test specified. */
548 match = ((int) ospeed == mapp->speed);
551 match = ((int) ospeed >= mapp->speed);
554 match = ((int) ospeed > mapp->speed);
557 match = ((int) ospeed <= mapp->speed);
560 match = ((int) ospeed < mapp->speed);
568 /* No match found; return given type. */
572 /**************************************************************************
576 **************************************************************************/
579 * Figure out what kind of terminal we're dealing with, and then read in
583 get_termcap_entry(char *userarg)
600 /* Try the environment. */
601 if ((ttype = getenv("TERM")) != 0)
604 if ((ttypath = ttyname(my_fd)) != 0) {
605 p = _nc_basename(ttypath);
608 * We have the 4.3BSD library call getttynam(3); that means
609 * there's an /etc/ttys to look up device-to-type mappings in.
610 * Try ttyname(3); check for dialup or other mapping.
612 if ((t = getttynam(p))) {
617 if ((fp = fopen("/etc/ttytype", "r")) != 0
618 || (fp = fopen("/etc/ttys", "r")) != 0) {
622 while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
623 for (s = buffer, t = d = 0; *s; s++) {
624 if (isspace(UChar(*s)))
628 else if (d == 0 && s != buffer && s[-1] == '\0')
631 if (t != 0 && d != 0 && !strcmp(d, p)) {
639 #endif /* HAVE_GETTTYNAM */
642 /* If still undefined, use "unknown". */
645 map:ttype = mapped(ttype);
648 * If not a path, remove TERMCAP from the environment so we get a
649 * real entry from /etc/termcap. This prevents us from being fooled
650 * by out of date stuff in the environment.
653 if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
654 /* 'unsetenv("TERMCAP")' is not portable.
655 * The 'environ' array is better.
658 for (n = 0; environ[n] != 0; n++) {
659 if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
660 while ((environ[n] = environ[n + 1]) != 0) {
669 * ttype now contains a pointer to the type of the terminal.
670 * If the first character is '?', ask the user.
672 if (ttype[0] == '?') {
673 if (ttype[1] != '\0')
674 ttype = askuser(ttype + 1);
678 /* Find the terminfo entry. If it doesn't exist, ask the user. */
679 while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
682 (void) fprintf(stderr, "%s: unknown terminal type %s\n",
683 _nc_progname, ttype);
686 (void) fprintf(stderr,
687 "%s: can't initialize terminal type %s (error %d)\n",
688 _nc_progname, ttype, errret);
691 ttype = askuser(ttype);
694 tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
699 /**************************************************************************
703 **************************************************************************/
705 /* some BSD systems have these built in, some systems are missing
706 * one or more definitions. The safest solution is to override unless the
707 * commonly-altered ones are defined.
709 #if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
722 /* control-character defaults */
724 #define CEOF CTRL('D')
727 #define CERASE CTRL('H')
730 #define CINTR 127 /* ^? */
733 #define CKILL CTRL('U')
736 #define CLNEXT CTRL('v')
739 #define CRPRNT CTRL('r')
742 #define CQUIT CTRL('\\')
745 #define CSTART CTRL('Q')
748 #define CSTOP CTRL('S')
751 #define CSUSP CTRL('Z')
754 #if defined(_POSIX_VDISABLE)
755 #define DISABLED(val) (((_POSIX_VDISABLE != -1) \
756 && ((val) == _POSIX_VDISABLE)) \
759 #define DISABLED(val) ((int)(val) <= 0)
762 #define CHK(val, dft) (unsigned char) (DISABLED(val) ? dft : val)
764 static bool set_tabs(void);
767 * Reset the terminal mode bits to a sensible state. Very useful after
768 * a child program dies in raw mode.
774 tcgetattr(my_fd, &mode);
780 #if defined(VDISCARD) && defined(CDISCARD)
781 mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
783 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
784 mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
785 #if defined(VFLUSH) && defined(CFLUSH)
786 mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
788 mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
789 mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
790 #if defined(VLNEXT) && defined(CLNEXT)
791 mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
793 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
794 #if defined(VREPRINT) && defined(CRPRNT)
795 mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
797 #if defined(VSTART) && defined(CSTART)
798 mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
800 #if defined(VSTOP) && defined(CSTOP)
801 mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
803 #if defined(VSUSP) && defined(CSUSP)
804 mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
806 #if defined(VWERASE) && defined(CWERASE)
807 mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
810 mode.c_iflag &= ~((unsigned) (IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
819 mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
825 mode.c_oflag &= ~((unsigned) (0
864 mode.c_oflag |= (OPOST
870 mode.c_cflag &= ~((unsigned) (CSIZE | CSTOPB | PARENB | PARODD | CLOCAL));
871 mode.c_cflag |= (CS8 | CREAD);
872 mode.c_lflag &= ~((unsigned) (ECHONL | NOFLSH
884 mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
894 SET_TTY(my_fd, &mode);
898 * Returns a "good" value for the erase character. This is loosely based on
908 && key_backspace != 0
909 && strlen(key_backspace) == 1)
910 result = key_backspace[0];
919 * Update the values of the erase, interrupt, and kill characters in 'mode'.
921 * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
922 * characters if they're unset, or if we specify them as options. This differs
923 * from BSD 4.4 tset, which always sets erase.
926 set_control_chars(void)
929 if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0) {
930 mode.c_cc[VERASE] = UChar((terasechar >= 0)
935 if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0) {
936 mode.c_cc[VINTR] = UChar((intrchar >= 0)
941 if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0) {
942 mode.c_cc[VKILL] = UChar((tkillchar >= 0)
950 * Set up various conversions in 'mode', including parity, tabs, returns,
951 * echo, and case, according to the termcap entry. If the program we're
952 * running was named with a leading upper-case character, map external
953 * uppercase to internal lowercase.
956 set_conversions(void)
960 * Conversion logic for some *really* ancient terminal glitches,
961 * not supported in terminfo. Left here for succeeding generations
964 if (tgetflag("UC")) {
966 mode.c_iflag |= IUCLC;
967 mode.c_oflag |= OLCUC;
969 } else if (tgetflag("LC")) {
971 mode.c_iflag &= ~IUCLC;
972 mode.c_oflag &= ~OLCUC;
975 mode.c_iflag &= ~(PARMRK | INPCK);
976 mode.c_lflag |= ICANON;
977 if (tgetflag("EP")) {
978 mode.c_cflag |= PARENB;
979 mode.c_cflag &= ~PARODD;
981 if (tgetflag("OP")) {
982 mode.c_cflag |= PARENB;
983 mode.c_cflag |= PARODD;
985 #endif /* __OBSOLETE__ */
989 mode.c_oflag |= ONLCR;
991 mode.c_iflag |= ICRNL;
992 mode.c_lflag |= ECHO;
994 mode.c_oflag |= OXTABS;
997 /* test used to be tgetflag("NL") */
998 if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
999 /* Newline, not linefeed. */
1001 mode.c_oflag &= ~((unsigned) ONLCR);
1003 mode.c_iflag &= ~((unsigned) ICRNL);
1006 if (tgetflag("HD")) /* Half duplex. */
1007 mode.c_lflag &= ~ECHO;
1008 #endif /* __OBSOLETE__ */
1010 /* test used to be tgetflag("pt") */
1011 if (has_hardware_tabs) /* Print tabs. */
1012 mode.c_oflag &= ~OXTABS;
1014 mode.c_lflag |= (ECHOE | ECHOK);
1018 /* Output startup string. */
1026 if (pad_char != (char *) 0) /* Get/set pad character. */
1028 #endif /* OBSOLETE */
1031 if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
1032 oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
1033 SET_TTY(my_fd, &oldmode);
1036 settle = set_tabs();
1039 if ((p = reset_1string) != 0) {
1043 if ((p = reset_2string) != 0) {
1047 /* What about rf, rs3, as per terminfo man page? */
1048 /* also might be nice to send rmacs, rmul, rmm */
1049 if ((p = reset_file) != 0
1050 || (p = init_file) != 0) {
1057 (void) putc('\r', stderr);
1058 (void) fflush(stderr);
1059 (void) napms(1000); /* Settle the terminal. */
1064 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
1065 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
1066 * This is done before if and is, so they can patch in case we blow this.
1067 * Return TRUE if we set any tab stops, FALSE if not.
1072 if (set_tab && clear_all_tabs) {
1082 (void) putc('\r', stderr); /* Force to left margin. */
1083 tputs(clear_all_tabs, 0, outc);
1085 for (c = 8; c < lim; c += 8) {
1086 /* Get to the right column. In BSD tset, this
1087 * used to try a bunch of half-clever things
1088 * with cup and hpa, for an average saving of
1089 * somewhat less than two character times per
1090 * tab stop, less than .01 sec at 2400cps. We
1091 * lost all this cruft because it seemed to be
1092 * introducing some odd bugs.
1093 * -----------12345678----------- */
1094 (void) fputs(" ", stderr);
1095 tputs(set_tab, 0, outc);
1103 /**************************************************************************
1107 **************************************************************************/
1110 * Tell the user if a control key has been changed from the default value.
1114 report(const char *name, int which, unsigned def)
1116 unsigned older, newer;
1119 newer = mode.c_cc[which];
1120 older = oldmode.c_cc[which];
1122 if (older == newer && older == def)
1125 (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
1127 if (DISABLED(newer))
1128 (void) fprintf(stderr, "undef.\n");
1130 * Check 'delete' before 'backspace', since the key_backspace value
1133 else if (newer == 0177)
1134 (void) fprintf(stderr, "delete.\n");
1135 else if ((p = key_backspace) != 0
1136 && newer == (unsigned char) p[0]
1138 (void) fprintf(stderr, "backspace.\n");
1139 else if (newer < 040) {
1141 (void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
1143 (void) fprintf(stderr, "%c.\n", UChar(newer));
1148 * Convert the obsolete argument forms into something that getopt can handle.
1149 * This means that -e, -i and -k get default arguments supplied for them.
1152 obsolete(char **argv)
1154 for (; *argv; ++argv) {
1155 char *parm = argv[0];
1157 if (parm[0] == '-' && parm[1] == '\0') {
1158 argv[0] = strdup("-q");
1162 if ((parm[0] != '-')
1163 || (argv[1] && argv[1][0] != '-')
1164 || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
1165 || (parm[2] != '\0'))
1167 switch (argv[0][1]) {
1169 argv[0] = strdup("-e^H");
1172 argv[0] = strdup("-i^C");
1175 argv[0] = strdup("-k^U");
1184 #define DATA(s) s "\n"
1185 static const char msg[] =
1189 DATA(" -c set control characters")
1190 DATA(" -e ch erase character")
1191 DATA(" -I no initialization strings")
1192 DATA(" -i ch interrupt character")
1193 DATA(" -k ch kill character")
1194 DATA(" -m mapping map identifier to type")
1195 DATA(" -Q do not output control key settings")
1196 DATA(" -r display term on stderr")
1197 DATA(" -s output TERM set command")
1198 DATA(" -V print curses-version")
1199 DATA(" -w set window-size")
1202 (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
1211 return (char) ((optarg[0] == '^' && optarg[1] != '\0')
1212 ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
1217 main(int argc, char **argv)
1219 int ch, noinit, noset, quiet, Sflag, sflag, showterm;
1223 my_fd = STDERR_FILENO;
1225 noinit = noset = quiet = Sflag = sflag = showterm = 0;
1226 while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQSrsVw")) != -1) {
1228 case 'c': /* set control-chars */
1231 case 'a': /* OBSOLETE: map identifier to type */
1232 add_mapping("arpanet", optarg);
1234 case 'd': /* OBSOLETE: map identifier to type */
1235 add_mapping("dialup", optarg);
1237 case 'e': /* erase character */
1238 terasechar = arg_to_char();
1240 case 'I': /* no initialization strings */
1243 case 'i': /* interrupt character */
1244 intrchar = arg_to_char();
1246 case 'k': /* kill character */
1247 tkillchar = arg_to_char();
1249 case 'm': /* map identifier to type */
1250 add_mapping(0, optarg);
1252 case 'p': /* OBSOLETE: map identifier to type */
1253 add_mapping("plugboard", optarg);
1255 case 'Q': /* don't output control key settings */
1258 case 'q': /* display term only */
1261 case 'r': /* display term on stderr */
1264 case 'S': /* OBSOLETE: output TERM & TERMCAP */
1267 case 's': /* output TERM set command */
1270 case 'V': /* print curses-version */
1271 puts(curses_version());
1272 ExitProgram(EXIT_SUCCESS);
1273 case 'w': /* set window-size */
1282 _nc_progname = _nc_rootname(*argv);
1289 if (!opt_c && !opt_w)
1290 opt_c = opt_w = TRUE;
1293 * stderr is less likely to be redirected than stdout; try that first.
1295 if (!get_mode(STDERR_FILENO) &&
1296 !get_mode(STDOUT_FILENO) &&
1297 !get_mode(STDIN_FILENO) &&
1298 !get_mode(open("/dev/tty", O_RDWR))) {
1299 failed("terminal attributes");
1302 original = oldmode = mode;
1304 ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
1306 ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
1309 if (same_program(_nc_progname, PROG_RESET)) {
1314 ttype = get_termcap_entry(*argv);
1323 /* Set window size if not set already */
1324 (void) ioctl(my_fd, IOCTL_GET_WINSIZE, &win);
1325 if (WINSIZE_ROWS(win) == 0 &&
1326 WINSIZE_COLS(win) == 0 &&
1327 tlines > 0 && tcolumns > 0) {
1328 WINSIZE_ROWS(win) = (unsigned short) tlines;
1329 WINSIZE_COLS(win) = (unsigned short) tcolumns;
1330 (void) ioctl(my_fd, IOCTL_SET_WINSIZE, &win);
1335 set_control_chars();
1341 /* Set the modes if they've changed. */
1342 if (memcmp(&mode, &oldmode, sizeof(mode))) {
1343 SET_TTY(my_fd, &mode);
1349 (void) printf("%s\n", ttype);
1352 (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
1354 * If erase, kill and interrupt characters could have been
1355 * modified and not -Q, display the changes.
1359 report("Erase", VERASE, CERASE);
1360 report("Kill", VKILL, CKILL);
1361 report("Interrupt", VINTR, CINTR);
1367 err("The -S option is not supported under terminfo.");
1374 * Figure out what shell we're using. A hack, we look for an
1375 * environmental variable SHELL ending in "csh".
1377 if ((var = getenv("SHELL")) != 0
1378 && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
1379 && !strcmp(leaf + len - 3, "csh"))
1380 p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
1383 (void) printf(p, ttype);
1386 ExitProgram(EXIT_SUCCESS);