1 /* $NetBSD: tset.c,v 1.13 2003/08/07 11:16:49 agc 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\n\ 35 The Regents of the University of California. All rights reserved.\n"); 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.13 2003/08/07 11:16:49 agc 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((char *, int, u_int)); 61 void usage __P((void)); 62 63 struct termios mode, oldmode; 64 65 int erasechar; /* new erase character */ 66 int intrchar; /* new interrupt character */ 67 int isreset; /* invoked as reset */ 68 int killchar; /* new kill character */ 69 int lines, columns; /* window size */ 70 71 int 72 main(argc, argv) 73 int argc; 74 char *argv[]; 75 { 76 #ifdef TIOCGWINSZ 77 struct winsize win; 78 #endif 79 int ch, extended, noinit, noset, quiet, Sflag, sflag, showterm; 80 int usingupper; 81 char savech, *p, *q, *t, *tcapbuf; 82 const char *ttype; 83 84 if (tcgetattr(STDERR_FILENO, &mode) < 0) 85 err(1, "standard error"); 86 87 oldmode = mode; 88 ospeed = cfgetospeed(&mode); 89 90 if ((p = strrchr(*argv, '/')) != NULL) 91 ++p; 92 else 93 p = *argv; 94 usingupper = isupper((unsigned char)*p); 95 if (!strcasecmp(p, "reset")) { 96 isreset = 1; 97 reset_mode(); 98 } 99 100 obsolete(argv); 101 noinit = noset = quiet = Sflag = sflag = showterm = extended = 0; 102 while ((ch = getopt(argc, argv, "-a:d:e:EIi:k:m:np:QSrs")) != -1) { 103 switch (ch) { 104 case '-': /* display term only */ 105 noset = 1; 106 break; 107 case 'a': /* OBSOLETE: map identifier to type */ 108 add_mapping("arpanet", optarg); 109 break; 110 case 'd': /* OBSOLETE: map identifier to type */ 111 add_mapping("dialup", optarg); 112 break; 113 case 'e': /* erase character */ 114 erasechar = optarg[0] == '^' && optarg[1] != '\0' ? 115 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 116 optarg[0]; 117 break; 118 case 'E': 119 extended = 1; 120 break; 121 case 'I': /* no initialization strings */ 122 noinit = 1; 123 break; 124 case 'i': /* interrupt character */ 125 intrchar = optarg[0] == '^' && optarg[1] != '\0' ? 126 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 127 optarg[0]; 128 break; 129 case 'k': /* kill character */ 130 killchar = optarg[0] == '^' && optarg[1] != '\0' ? 131 optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : 132 optarg[0]; 133 break; 134 case 'm': /* map identifier to type */ 135 add_mapping(NULL, optarg); 136 break; 137 case 'n': /* OBSOLETE: set new tty driver */ 138 break; 139 case 'p': /* OBSOLETE: map identifier to type */ 140 add_mapping("plugboard", optarg); 141 break; 142 case 'Q': /* don't output control key settings */ 143 quiet = 1; 144 break; 145 case 'S': /* output TERM/TERMCAP strings */ 146 Sflag = 1; 147 break; 148 case 'r': /* display term on stderr */ 149 showterm = 1; 150 break; 151 case 's': /* output TERM/TERMCAP strings */ 152 sflag = 1; 153 break; 154 case '?': 155 default: 156 usage(); 157 } 158 } 159 argc -= optind; 160 argv += optind; 161 162 if (argc > 1) 163 usage(); 164 165 ttype = get_termcap_entry(*argv, &tcapbuf, extended); 166 167 if (!noset) { 168 columns = tgetnum("co"); 169 lines = tgetnum("li"); 170 171 #ifdef TIOCGWINSZ 172 /* Set window size */ 173 (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win); 174 if (win.ws_row > 0 && win.ws_col > 0) { 175 lines = win.ws_row; 176 columns = win.ws_col; 177 } else if (win.ws_row == 0 && win.ws_col == 0 && 178 lines > 0 && columns > 0) { 179 win.ws_row = lines; 180 win.ws_col = columns; 181 (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win); 182 } 183 #endif 184 set_control_chars(); 185 set_conversions(usingupper); 186 187 if (!noinit) 188 set_init(); 189 190 /* Set the modes if they've changed. */ 191 if (memcmp(&mode, &oldmode, sizeof(mode))) 192 tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); 193 } 194 195 /* Get the terminal name from the entry. */ 196 p = tcapbuf; 197 if (p != NULL && *p != ':') { 198 t = p; 199 if ((p = strpbrk(p, "|:")) != NULL) { 200 savech = *p; 201 *p = '\0'; 202 if ((ttype = strdup(t)) == NULL) 203 err(1, "strdup"); 204 *p = savech; 205 } 206 } 207 208 if (noset) 209 (void)printf("%s\n", ttype); 210 else { 211 if (showterm) 212 (void)fprintf(stderr, "Terminal type is %s.\n", ttype); 213 /* 214 * If erase, kill and interrupt characters could have been 215 * modified and not -Q, display the changes. 216 */ 217 if (!quiet) { 218 report("Erase", VERASE, CERASE); 219 report("Kill", VKILL, CKILL); 220 report("Interrupt", VINTR, CINTR); 221 } 222 } 223 224 if (Sflag) { 225 (void)printf("%s ", ttype); 226 wrtermcap(tcapbuf); 227 } 228 229 if (sflag) { 230 /* 231 * Figure out what shell we're using. A hack, we look for an 232 * environmental variable SHELL ending in "csh". 233 */ 234 if ((p = getenv("SHELL")) && 235 !strcmp(p + strlen(p) - 3, "csh")) { 236 p = "set noglob;\nsetenv TERM "; 237 q = ";\nsetenv TERMCAP '"; 238 t = "';\nunset noglob;\n"; 239 } else { 240 p = "TERM="; 241 q = ";\nTERMCAP='"; 242 t = "';\nexport TERMCAP TERM;\n"; 243 } 244 (void)printf("%s%s%s", p, ttype, q); 245 wrtermcap(tcapbuf); 246 (void)printf("%s", t); 247 } 248 249 exit(0); 250 } 251 252 /* 253 * Tell the user if a control key has been changed from the default value. 254 */ 255 void 256 report(name, which, def) 257 char *name; 258 int which; 259 u_int def; 260 { 261 u_int old, new; 262 char *bp, buf[1024]; 263 264 new = mode.c_cc[which]; 265 old = oldmode.c_cc[which]; 266 267 if (old == new && old == def) 268 return; 269 270 (void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to"); 271 272 bp = buf; 273 if (tgetstr("kb", &bp) && new == buf[0] && buf[1] == '\0') 274 (void)fprintf(stderr, "backspace.\n"); 275 else if (new == 0177) 276 (void)fprintf(stderr, "delete.\n"); 277 else if (new < 040) { 278 new ^= 0100; 279 (void)fprintf(stderr, "control-%c (^%c).\n", new, new); 280 } else if (new == _POSIX_VDISABLE) 281 (void)fprintf(stderr, "<undef>.\n"); 282 else 283 (void)fprintf(stderr, "%c.\n", new); 284 } 285 286 /* 287 * Convert the obsolete argument form into something that getopt can handle. 288 * This means that -e, -i and -k get default arguments supplied for them. 289 */ 290 void 291 obsolete(argv) 292 char *argv[]; 293 { 294 for (; *argv; ++argv) { 295 if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') || 296 (argv[0][1] != 'e' && argv[0][1] != 'i' && 297 argv[0][1] != 'k') || argv[0][2] != '\0') 298 continue; 299 switch(argv[0][1]) { 300 case 'e': 301 argv[0] = "-e^H"; 302 break; 303 case 'i': 304 argv[0] = "-i^C"; 305 break; 306 case 'k': 307 argv[0] = "-k^U"; 308 break; 309 } 310 } 311 } 312 313 void 314 usage() 315 { 316 (void)fprintf(stderr, 317 "usage: tset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n"); 318 exit(1); 319 } 320