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