1 /* $NetBSD: tset.c,v 1.17 2009/04/14 05:45:23 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)tset.c 8.1 (Berkeley) 6/9/93"; 41 #endif 42 __RCSID("$NetBSD: tset.c,v 1.17 2009/04/14 05:45:23 lukem Exp $"); 43 #endif /* not lint */ 44 45 #include <sys/types.h> 46 #include <sys/ioctl.h> 47 #include <ctype.h> 48 #include <err.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <termcap.h> 54 #include <termios.h> 55 #include <unistd.h> 56 #include "extern.h" 57 58 int main __P((int, char *[])); 59 void obsolete __P((char *[])); 60 void report __P((const char *, int, u_int)); 61 void usage __P((void)); 62 63 struct termios mode, oldmode; 64 65 int isreset; /* invoked as reset */ 66 int lines, columns; /* window size */ 67 68 int 69 main(argc, argv) 70 int argc; 71 char *argv[]; 72 { 73 #ifdef TIOCGWINSZ 74 struct winsize win; 75 #endif 76 int ch, extended, noinit, noset, quiet, Sflag, sflag, showterm; 77 int erasechar = 0, intrchar = 0, killchar = 0; 78 int usingupper; 79 char savech, *p, *tcapbuf; 80 const char *k1, *k2, *k3; 81 const char *ttype; 82 83 if (tcgetattr(STDERR_FILENO, &mode) < 0) 84 err(1, "standard error"); 85 86 oldmode = mode; 87 ospeed = cfgetospeed(&mode); 88 89 if ((p = strrchr(*argv, '/')) != NULL) 90 ++p; 91 else 92 p = *argv; 93 usingupper = isupper((unsigned char)*p); 94 if (!strcasecmp(p, "reset")) { 95 isreset = 1; 96 reset_mode(); 97 } 98 99 obsolete(argv); 100 noinit = noset = quiet = Sflag = sflag = showterm = extended = 0; 101 while ((ch = getopt(argc, argv, "-a:d:e:EIi:k:m:np:QSrs")) != -1) { 102 switch (ch) { 103 case '-': /* display term only */ 104 noset = 1; 105 break; 106 case 'a': /* OBSOLETE: map identifier to type */ 107 add_mapping("arpanet", optarg); 108 break; 109 case 'd': /* OBSOLETE: map identifier to type */ 110 add_mapping("dialup", optarg); 111 break; 112 case 'e': /* erase character */ 113 erasechar = optarg[0] == '^' && optarg[1] != '\0' ? 114 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 115 optarg[0]; 116 break; 117 case 'E': 118 extended = 1; 119 break; 120 case 'I': /* no initialization strings */ 121 noinit = 1; 122 break; 123 case 'i': /* interrupt character */ 124 intrchar = optarg[0] == '^' && optarg[1] != '\0' ? 125 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 126 optarg[0]; 127 break; 128 case 'k': /* kill character */ 129 killchar = optarg[0] == '^' && optarg[1] != '\0' ? 130 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 131 optarg[0]; 132 break; 133 case 'm': /* map identifier to type */ 134 add_mapping(NULL, optarg); 135 break; 136 case 'n': /* OBSOLETE: set new tty driver */ 137 break; 138 case 'p': /* OBSOLETE: map identifier to type */ 139 add_mapping("plugboard", optarg); 140 break; 141 case 'Q': /* don't output control key settings */ 142 quiet = 1; 143 break; 144 case 'S': /* output TERM/TERMCAP strings */ 145 Sflag = 1; 146 break; 147 case 'r': /* display term on stderr */ 148 showterm = 1; 149 break; 150 case 's': /* output TERM/TERMCAP strings */ 151 sflag = 1; 152 break; 153 case '?': 154 default: 155 usage(); 156 } 157 } 158 argc -= optind; 159 argv += optind; 160 161 if (argc > 1) 162 usage(); 163 164 ttype = get_termcap_entry(*argv, &tcapbuf, extended); 165 166 if (!noset) { 167 columns = tgetnum("co"); 168 lines = tgetnum("li"); 169 170 #ifdef TIOCGWINSZ 171 /* Set window size */ 172 (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win); 173 if (win.ws_row > 0 && win.ws_col > 0) { 174 lines = win.ws_row; 175 columns = win.ws_col; 176 } else if (win.ws_row == 0 && win.ws_col == 0 && 177 lines > 0 && columns > 0) { 178 win.ws_row = lines; 179 win.ws_col = columns; 180 (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win); 181 } 182 #endif 183 set_control_chars(erasechar, intrchar, killchar); 184 set_conversions(usingupper); 185 186 if (!noinit) 187 set_init(); 188 189 /* Set the modes if they've changed. */ 190 if (memcmp(&mode, &oldmode, sizeof(mode))) 191 tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); 192 } 193 194 /* Get the terminal name from the entry. */ 195 p = tcapbuf; 196 if (p != NULL && *p != ':') { 197 k1 = p; 198 if ((p = strpbrk(p, "|:")) != NULL) { 199 savech = *p; 200 *p = '\0'; 201 if ((ttype = strdup(k1)) == NULL) 202 err(1, "strdup"); 203 *p = savech; 204 } 205 } 206 207 if (noset) 208 (void)printf("%s\n", ttype); 209 else { 210 if (showterm) 211 (void)fprintf(stderr, "Terminal type is %s.\n", ttype); 212 /* 213 * If erase, kill and interrupt characters could have been 214 * modified and not -Q, display the changes. 215 */ 216 if (!quiet) { 217 report("Erase", VERASE, CERASE); 218 report("Kill", VKILL, CKILL); 219 report("Interrupt", VINTR, CINTR); 220 } 221 } 222 223 if (Sflag) { 224 (void)printf("%s ", ttype); 225 wrtermcap(tcapbuf); 226 } 227 228 if (sflag) { 229 /* 230 * Figure out what shell we're using. A hack, we look for an 231 * environmental variable SHELL ending in "csh". 232 */ 233 if ((p = getenv("SHELL")) && 234 !strcmp(p + strlen(p) - 3, "csh")) { 235 k1 = "set noglob;\nsetenv TERM "; 236 k2 = ";\nsetenv TERMCAP '"; 237 k3 = "';\nunset noglob;\n"; 238 } else { 239 k1 = "TERM="; 240 k2 = ";\nTERMCAP='"; 241 k3 = "';\nexport TERMCAP TERM;\n"; 242 } 243 (void)printf("%s%s%s", k1, ttype, k2); 244 wrtermcap(tcapbuf); 245 (void)printf("%s", k3); 246 } 247 248 exit(0); 249 } 250 251 /* 252 * Tell the user if a control key has been changed from the default value. 253 */ 254 void 255 report(name, which, def) 256 const char *name; 257 int which; 258 u_int def; 259 { 260 u_int old, new; 261 char *bp, buf[1024]; 262 263 new = mode.c_cc[which]; 264 old = oldmode.c_cc[which]; 265 266 if (old == new && old == def) 267 return; 268 269 (void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to"); 270 271 bp = buf; 272 if (tgetstr("kb", &bp) && new == (unsigned int)buf[0] && buf[1] == '\0') 273 (void)fprintf(stderr, "backspace.\n"); 274 else if (new == 0177) 275 (void)fprintf(stderr, "delete.\n"); 276 else if (new < 040) { 277 new ^= 0100; 278 (void)fprintf(stderr, "control-%c (^%c).\n", new, new); 279 } else if (new == _POSIX_VDISABLE) 280 (void)fprintf(stderr, "<undef>.\n"); 281 else 282 (void)fprintf(stderr, "%c.\n", new); 283 } 284 285 /* 286 * Convert the obsolete argument form into something that getopt can handle. 287 * This means that -e, -i and -k get default arguments supplied for them. 288 */ 289 void 290 obsolete(argv) 291 char *argv[]; 292 { 293 static char earg[5] = { '-', 'e', '^', 'H', '\0' }; 294 static char iarg[5] = { '-', 'i', '^', 'C', '\0' }; 295 static char karg[5] = { '-', 'k', '^', 'U', '\0' }; 296 297 for (; *argv; ++argv) { 298 if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') || 299 (argv[0][1] != 'e' && argv[0][1] != 'i' && 300 argv[0][1] != 'k') || argv[0][2] != '\0') 301 continue; 302 switch(argv[0][1]) { 303 case 'e': 304 argv[0] = earg; 305 break; 306 case 'i': 307 argv[0] = iarg; 308 break; 309 case 'k': 310 argv[0] = karg; 311 break; 312 } 313 } 314 } 315 316 void 317 usage() 318 { 319 (void)fprintf(stderr, 320 "usage: %s [-EIQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n", 321 getprogname()); 322 exit(1); 323 } 324