1 /**************************************************************************** 2 * Copyright 2020 Thomas E. Dickey * 3 * Copyright 1998-2016,2017 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /**************************************************************************** 31 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 32 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33 * and: Thomas E. Dickey 1996-on * 34 ****************************************************************************/ 35 36 /* 37 * Notes: 38 * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686 39 * lines from that version, and made changes/additions for 150 lines. There 40 * was no reformatting, so with/without ignoring whitespace, the amount of 41 * change is the same. 42 * 43 * Comparing with current (2009) source, excluding this comment: 44 * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines 45 * changed/added. 46 * a) Ignoring whitespace, the current version still uses 516 lines from the 47 * 4.4BSD Lite sources, with 402 lines changed/added. 48 * 49 * Raymond's original comment on this follows... 50 */ 51 52 /* 53 * tset.c - terminal initialization utility 54 * 55 * This code was mostly swiped from 4.4BSD tset, with some obsolescent 56 * cruft removed and substantial portions rewritten. A Regents of the 57 * University of California copyright applies to some portions of the 58 * code, and is reproduced below: 59 */ 60 /*- 61 * Copyright (c) 1980, 1991, 1993 62 * The Regents of the University of California. All rights reserved. 63 * 64 * Redistribution and use in source and binary forms, with or without 65 * modification, are permitted provided that the following conditions 66 * are met: 67 * 1. Redistributions of source code must retain the above copyright 68 * notice, this list of conditions and the following disclaimer. 69 * 2. Redistributions in binary form must reproduce the above copyright 70 * notice, this list of conditions and the following disclaimer in the 71 * documentation and/or other materials provided with the distribution. 72 * 3. Neither the name of the University nor the names of its contributors 73 * may be used to endorse or promote products derived from this software 74 * without specific prior written permission. 75 * 76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 86 * SUCH DAMAGE. 87 */ 88 89 #include <reset_cmd.h> 90 #include <termcap.h> 91 #include <transform.h> 92 #include <tty_settings.h> 93 94 #if HAVE_GETTTYNAM && HAVE_TTYENT_H 95 #include <ttyent.h> 96 #endif 97 #ifdef NeXT 98 char *ttyname(int fd); 99 #endif 100 101 MODULE_ID("$Id: tset.c,v 1.121 2020/02/02 23:34:34 tom Exp $") 102 103 #ifndef environ 104 extern char **environ; 105 #endif 106 107 const char *_nc_progname = "tset"; 108 109 #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c)) 110 111 static void exit_error(void) GCC_NORETURN; 112 113 static int 114 CaselessCmp(const char *a, const char *b) 115 { /* strcasecmp isn't portable */ 116 while (*a && *b) { 117 int cmp = LOWERCASE(*a) - LOWERCASE(*b); 118 if (cmp != 0) 119 break; 120 a++, b++; 121 } 122 return LOWERCASE(*a) - LOWERCASE(*b); 123 } 124 125 static void 126 exit_error(void) 127 { 128 restore_tty_settings(); 129 (void) fprintf(stderr, "\n"); 130 fflush(stderr); 131 ExitProgram(EXIT_FAILURE); 132 /* NOTREACHED */ 133 } 134 135 static void 136 err(const char *fmt,...) 137 { 138 va_list ap; 139 va_start(ap, fmt); 140 (void) fprintf(stderr, "%s: ", _nc_progname); 141 (void) vfprintf(stderr, fmt, ap); 142 va_end(ap); 143 exit_error(); 144 /* NOTREACHED */ 145 } 146 147 static void 148 failed(const char *msg) 149 { 150 char temp[BUFSIZ]; 151 size_t len = strlen(_nc_progname) + 2; 152 153 if ((int) len < (int) sizeof(temp) - 12) { 154 _nc_STRCPY(temp, _nc_progname, sizeof(temp)); 155 _nc_STRCAT(temp, ": ", sizeof(temp)); 156 } else { 157 _nc_STRCPY(temp, "tset: ", sizeof(temp)); 158 } 159 _nc_STRNCAT(temp, msg, sizeof(temp), sizeof(temp) - strlen(temp) - 2); 160 perror(temp); 161 exit_error(); 162 /* NOTREACHED */ 163 } 164 165 /* Prompt the user for a terminal type. */ 166 static const char * 167 askuser(const char *dflt) 168 { 169 static char answer[256]; 170 char *p; 171 172 /* We can get recalled; if so, don't continue uselessly. */ 173 clearerr(stdin); 174 if (feof(stdin) || ferror(stdin)) { 175 (void) fprintf(stderr, "\n"); 176 exit_error(); 177 /* NOTREACHED */ 178 } 179 for (;;) { 180 if (dflt) 181 (void) fprintf(stderr, "Terminal type? [%s] ", dflt); 182 else 183 (void) fprintf(stderr, "Terminal type? "); 184 (void) fflush(stderr); 185 186 if (fgets(answer, sizeof(answer), stdin) == 0) { 187 if (dflt == 0) { 188 exit_error(); 189 /* NOTREACHED */ 190 } 191 return (dflt); 192 } 193 194 if ((p = strchr(answer, '\n')) != 0) 195 *p = '\0'; 196 if (answer[0]) 197 return (answer); 198 if (dflt != 0) 199 return (dflt); 200 } 201 } 202 203 /************************************************************************** 204 * 205 * Mapping logic begins here 206 * 207 **************************************************************************/ 208 209 /* Baud rate conditionals for mapping. */ 210 #define GT 0x01 211 #define EQ 0x02 212 #define LT 0x04 213 #define NOT 0x08 214 #define GE (GT | EQ) 215 #define LE (LT | EQ) 216 217 typedef struct map { 218 struct map *next; /* Linked list of maps. */ 219 const char *porttype; /* Port type, or "" for any. */ 220 const char *type; /* Terminal type to select. */ 221 int conditional; /* Baud rate conditionals bitmask. */ 222 int speed; /* Baud rate to compare against. */ 223 } MAP; 224 225 static MAP *cur, *maplist; 226 227 #define DATA(name,value) { { name }, value } 228 229 typedef struct speeds { 230 const char string[7]; 231 int speed; 232 } SPEEDS; 233 234 static const SPEEDS speeds[] = 235 { 236 DATA("0", B0), 237 DATA("50", B50), 238 DATA("75", B75), 239 DATA("110", B110), 240 DATA("134", B134), 241 DATA("134.5", B134), 242 DATA("150", B150), 243 DATA("200", B200), 244 DATA("300", B300), 245 DATA("600", B600), 246 DATA("1200", B1200), 247 DATA("1800", B1800), 248 DATA("2400", B2400), 249 DATA("4800", B4800), 250 DATA("9600", B9600), 251 /* sgttyb may define up to this point */ 252 #ifdef B19200 253 DATA("19200", B19200), 254 #endif 255 #ifdef B38400 256 DATA("38400", B38400), 257 #endif 258 #ifdef B19200 259 DATA("19200", B19200), 260 #endif 261 #ifdef B38400 262 DATA("38400", B38400), 263 #endif 264 #ifdef B19200 265 DATA("19200", B19200), 266 #else 267 #ifdef EXTA 268 DATA("19200", EXTA), 269 #endif 270 #endif 271 #ifdef B38400 272 DATA("38400", B38400), 273 #else 274 #ifdef EXTB 275 DATA("38400", EXTB), 276 #endif 277 #endif 278 #ifdef B57600 279 DATA("57600", B57600), 280 #endif 281 #ifdef B76800 282 DATA("76800", B57600), 283 #endif 284 #ifdef B115200 285 DATA("115200", B115200), 286 #endif 287 #ifdef B153600 288 DATA("153600", B153600), 289 #endif 290 #ifdef B230400 291 DATA("230400", B230400), 292 #endif 293 #ifdef B307200 294 DATA("307200", B307200), 295 #endif 296 #ifdef B460800 297 DATA("460800", B460800), 298 #endif 299 #ifdef B500000 300 DATA("500000", B500000), 301 #endif 302 #ifdef B576000 303 DATA("576000", B576000), 304 #endif 305 #ifdef B921600 306 DATA("921600", B921600), 307 #endif 308 #ifdef B1000000 309 DATA("1000000", B1000000), 310 #endif 311 #ifdef B1152000 312 DATA("1152000", B1152000), 313 #endif 314 #ifdef B1500000 315 DATA("1500000", B1500000), 316 #endif 317 #ifdef B2000000 318 DATA("2000000", B2000000), 319 #endif 320 #ifdef B2500000 321 DATA("2500000", B2500000), 322 #endif 323 #ifdef B3000000 324 DATA("3000000", B3000000), 325 #endif 326 #ifdef B3500000 327 DATA("3500000", B3500000), 328 #endif 329 #ifdef B4000000 330 DATA("4000000", B4000000), 331 #endif 332 }; 333 #undef DATA 334 335 static int 336 tbaudrate(char *rate) 337 { 338 const SPEEDS *sp = 0; 339 size_t n; 340 341 /* The baudrate number can be preceded by a 'B', which is ignored. */ 342 if (*rate == 'B') 343 ++rate; 344 345 for (n = 0; n < SIZEOF(speeds); ++n) { 346 if (n > 0 && (speeds[n].speed <= speeds[n - 1].speed)) { 347 /* if the speeds are not increasing, likely a numeric overflow */ 348 break; 349 } 350 if (!CaselessCmp(rate, speeds[n].string)) { 351 sp = speeds + n; 352 break; 353 } 354 } 355 if (sp == 0) 356 err("unknown baud rate %s", rate); 357 return (sp->speed); 358 } 359 360 /* 361 * Syntax for -m: 362 * [port-type][test baudrate]:terminal-type 363 * The baud rate tests are: >, <, @, =, ! 364 */ 365 static void 366 add_mapping(const char *port, char *arg) 367 { 368 MAP *mapp; 369 char *copy, *p; 370 const char *termp; 371 char *base = 0; 372 373 copy = strdup(arg); 374 mapp = typeMalloc(MAP, 1); 375 if (copy == 0 || mapp == 0) 376 failed("malloc"); 377 378 assert(copy != 0); 379 assert(mapp != 0); 380 381 mapp->next = 0; 382 if (maplist == 0) 383 cur = maplist = mapp; 384 else { 385 cur->next = mapp; 386 cur = mapp; 387 } 388 389 mapp->porttype = arg; 390 mapp->conditional = 0; 391 392 arg = strpbrk(arg, "><@=!:"); 393 394 if (arg == 0) { /* [?]term */ 395 mapp->type = mapp->porttype; 396 mapp->porttype = 0; 397 goto done; 398 } 399 400 if (arg == mapp->porttype) /* [><@=! baud]:term */ 401 termp = mapp->porttype = 0; 402 else 403 termp = base = arg; 404 405 for (;; ++arg) { /* Optional conditionals. */ 406 switch (*arg) { 407 case '<': 408 if (mapp->conditional & GT) 409 goto badmopt; 410 mapp->conditional |= LT; 411 break; 412 case '>': 413 if (mapp->conditional & LT) 414 goto badmopt; 415 mapp->conditional |= GT; 416 break; 417 case '@': 418 case '=': /* Not documented. */ 419 mapp->conditional |= EQ; 420 break; 421 case '!': 422 mapp->conditional |= NOT; 423 break; 424 default: 425 goto next; 426 } 427 } 428 429 next: 430 if (*arg == ':') { 431 if (mapp->conditional) 432 goto badmopt; 433 ++arg; 434 } else { /* Optional baudrate. */ 435 arg = strchr(p = arg, ':'); 436 if (arg == 0) 437 goto badmopt; 438 *arg++ = '\0'; 439 mapp->speed = tbaudrate(p); 440 } 441 442 mapp->type = arg; 443 444 /* Terminate porttype, if specified. */ 445 if (termp != 0) 446 *base = '\0'; 447 448 /* If a NOT conditional, reverse the test. */ 449 if (mapp->conditional & NOT) 450 mapp->conditional = ~mapp->conditional & (EQ | GT | LT); 451 452 /* If user specified a port with an option flag, set it. */ 453 done: 454 if (port) { 455 if (mapp->porttype) { 456 badmopt: 457 err("illegal -m option format: %s", copy); 458 } 459 mapp->porttype = port; 460 } 461 free(copy); 462 #ifdef MAPDEBUG 463 (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY"); 464 (void) printf("type: %s\n", mapp->type); 465 (void) printf("conditional: "); 466 p = ""; 467 if (mapp->conditional & GT) { 468 (void) printf("GT"); 469 p = "/"; 470 } 471 if (mapp->conditional & EQ) { 472 (void) printf("%sEQ", p); 473 p = "/"; 474 } 475 if (mapp->conditional & LT) 476 (void) printf("%sLT", p); 477 (void) printf("\nspeed: %d\n", mapp->speed); 478 #endif 479 } 480 481 /* 482 * Return the type of terminal to use for a port of type 'type', as specified 483 * by the first applicable mapping in 'map'. If no mappings apply, return 484 * 'type'. 485 */ 486 static const char * 487 mapped(const char *type) 488 { 489 MAP *mapp; 490 int match; 491 492 for (mapp = maplist; mapp; mapp = mapp->next) 493 if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) { 494 switch (mapp->conditional) { 495 case 0: /* No test specified. */ 496 match = TRUE; 497 break; 498 case EQ: 499 match = ((int) ospeed == mapp->speed); 500 break; 501 case GE: 502 match = ((int) ospeed >= mapp->speed); 503 break; 504 case GT: 505 match = ((int) ospeed > mapp->speed); 506 break; 507 case LE: 508 match = ((int) ospeed <= mapp->speed); 509 break; 510 case LT: 511 match = ((int) ospeed < mapp->speed); 512 break; 513 default: 514 match = FALSE; 515 } 516 if (match) 517 return (mapp->type); 518 } 519 /* No match found; return given type. */ 520 return (type); 521 } 522 523 /************************************************************************** 524 * 525 * Entry fetching 526 * 527 **************************************************************************/ 528 529 /* 530 * Figure out what kind of terminal we're dealing with, and then read in 531 * its termcap entry. 532 */ 533 static const char * 534 get_termcap_entry(int fd, char *userarg) 535 { 536 int errret; 537 char *p; 538 const char *ttype; 539 #if HAVE_GETTTYNAM 540 struct ttyent *t; 541 #else 542 FILE *fp; 543 #endif 544 char *ttypath; 545 546 (void) fd; 547 548 if (userarg) { 549 ttype = userarg; 550 goto found; 551 } 552 553 /* Try the environment. */ 554 if ((ttype = getenv("TERM")) != 0) 555 goto map; 556 557 if ((ttypath = ttyname(fd)) != 0) { 558 p = _nc_basename(ttypath); 559 #if HAVE_GETTTYNAM 560 /* 561 * We have the 4.3BSD library call getttynam(3); that means 562 * there's an /etc/ttys to look up device-to-type mappings in. 563 * Try ttyname(3); check for dialup or other mapping. 564 */ 565 if ((t = getttynam(p))) { 566 ttype = t->ty_type; 567 goto map; 568 } 569 #else 570 if ((fp = fopen("/etc/ttytype", "r")) != 0 571 || (fp = fopen("/etc/ttys", "r")) != 0) { 572 char buffer[BUFSIZ]; 573 char *s, *t, *d; 574 575 while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) { 576 for (s = buffer, t = d = 0; *s; s++) { 577 if (isspace(UChar(*s))) 578 *s = '\0'; 579 else if (t == 0) 580 t = s; 581 else if (d == 0 && s != buffer && s[-1] == '\0') 582 d = s; 583 } 584 if (t != 0 && d != 0 && !strcmp(d, p)) { 585 ttype = strdup(t); 586 fclose(fp); 587 goto map; 588 } 589 } 590 fclose(fp); 591 } 592 #endif /* HAVE_GETTTYNAM */ 593 } 594 595 /* If still undefined, use "unknown". */ 596 ttype = "unknown"; 597 598 map:ttype = mapped(ttype); 599 600 /* 601 * If not a path, remove TERMCAP from the environment so we get a 602 * real entry from /etc/termcap. This prevents us from being fooled 603 * by out of date stuff in the environment. 604 */ 605 found: 606 if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) { 607 /* 'unsetenv("TERMCAP")' is not portable. 608 * The 'environ' array is better. 609 */ 610 int n; 611 for (n = 0; environ[n] != 0; n++) { 612 if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) { 613 while ((environ[n] = environ[n + 1]) != 0) { 614 n++; 615 } 616 break; 617 } 618 } 619 } 620 621 /* 622 * ttype now contains a pointer to the type of the terminal. 623 * If the first character is '?', ask the user. 624 */ 625 if (ttype[0] == '?') { 626 if (ttype[1] != '\0') 627 ttype = askuser(ttype + 1); 628 else 629 ttype = askuser(0); 630 } 631 /* Find the terminfo entry. If it doesn't exist, ask the user. */ 632 while (setupterm((NCURSES_CONST char *) ttype, fd, &errret) 633 != OK) { 634 if (errret == 0) { 635 (void) fprintf(stderr, "%s: unknown terminal type %s\n", 636 _nc_progname, ttype); 637 ttype = 0; 638 } else { 639 (void) fprintf(stderr, 640 "%s: can't initialize terminal type %s (error %d)\n", 641 _nc_progname, ttype, errret); 642 ttype = 0; 643 } 644 ttype = askuser(ttype); 645 } 646 #if BROKEN_LINKER 647 tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */ 648 #endif 649 return (ttype); 650 } 651 652 /************************************************************************** 653 * 654 * Main sequence 655 * 656 **************************************************************************/ 657 658 /* 659 * Convert the obsolete argument forms into something that getopt can handle. 660 * This means that -e, -i and -k get default arguments supplied for them. 661 */ 662 static void 663 obsolete(char **argv) 664 { 665 for (; *argv; ++argv) { 666 char *parm = argv[0]; 667 668 if (parm[0] == '-' && parm[1] == '\0') { 669 argv[0] = strdup("-q"); 670 continue; 671 } 672 673 if ((parm[0] != '-') 674 || (argv[1] && argv[1][0] != '-') 675 || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k') 676 || (parm[2] != '\0')) 677 continue; 678 switch (argv[0][1]) { 679 case 'e': 680 argv[0] = strdup("-e^H"); 681 break; 682 case 'i': 683 argv[0] = strdup("-i^C"); 684 break; 685 case 'k': 686 argv[0] = strdup("-k^U"); 687 break; 688 } 689 } 690 } 691 692 static void 693 print_shell_commands(const char *ttype) 694 { 695 const char *p; 696 int len; 697 char *var; 698 char *leaf; 699 /* 700 * Figure out what shell we're using. A hack, we look for an 701 * environmental variable SHELL ending in "csh". 702 */ 703 if ((var = getenv("SHELL")) != 0 704 && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3) 705 && !strcmp(leaf + len - 3, "csh")) 706 p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n"; 707 else 708 p = "TERM=%s;\n"; 709 (void) printf(p, ttype); 710 } 711 712 static void 713 usage(void) 714 { 715 #define SKIP(s) /* nothing */ 716 #define KEEP(s) s "\n" 717 static const char msg[] = 718 { 719 KEEP("") 720 KEEP("Options:") 721 SKIP(" -a arpanet (obsolete)") 722 KEEP(" -c set control characters") 723 SKIP(" -d dialup (obsolete)") 724 KEEP(" -e ch erase character") 725 KEEP(" -I no initialization strings") 726 KEEP(" -i ch interrupt character") 727 KEEP(" -k ch kill character") 728 KEEP(" -m mapping map identifier to type") 729 SKIP(" -p plugboard (obsolete)") 730 KEEP(" -Q do not output control key settings") 731 KEEP(" -q display term only, do no changes") 732 KEEP(" -r display term on stderr") 733 SKIP(" -S (obsolete)") 734 KEEP(" -s output TERM set command") 735 KEEP(" -V print curses-version") 736 KEEP(" -w set window-size") 737 KEEP("") 738 KEEP("If neither -c/-w are given, both are assumed.") 739 }; 740 #undef KEEP 741 #undef SKIP 742 (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname); 743 fputs(msg, stderr); 744 ExitProgram(EXIT_FAILURE); 745 /* NOTREACHED */ 746 } 747 748 static char 749 arg_to_char(void) 750 { 751 return (char) ((optarg[0] == '^' && optarg[1] != '\0') 752 ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1])) 753 : optarg[0]); 754 } 755 756 int 757 main(int argc, char **argv) 758 { 759 int ch, noinit, noset, quiet, Sflag, sflag, showterm; 760 const char *ttype; 761 int terasechar = -1; /* new erase character */ 762 int intrchar = -1; /* new interrupt character */ 763 int tkillchar = -1; /* new kill character */ 764 int my_fd; 765 bool opt_c = FALSE; /* set control-chars */ 766 bool opt_w = FALSE; /* set window-size */ 767 TTY mode, oldmode; 768 769 my_fd = STDERR_FILENO; 770 obsolete(argv); 771 noinit = noset = quiet = Sflag = sflag = showterm = 0; 772 while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQrSsVw")) != -1) { 773 switch (ch) { 774 case 'c': /* set control-chars */ 775 opt_c = TRUE; 776 break; 777 case 'a': /* OBSOLETE: map identifier to type */ 778 add_mapping("arpanet", optarg); 779 break; 780 case 'd': /* OBSOLETE: map identifier to type */ 781 add_mapping("dialup", optarg); 782 break; 783 case 'e': /* erase character */ 784 terasechar = arg_to_char(); 785 break; 786 case 'I': /* no initialization strings */ 787 noinit = 1; 788 break; 789 case 'i': /* interrupt character */ 790 intrchar = arg_to_char(); 791 break; 792 case 'k': /* kill character */ 793 tkillchar = arg_to_char(); 794 break; 795 case 'm': /* map identifier to type */ 796 add_mapping(0, optarg); 797 break; 798 case 'p': /* OBSOLETE: map identifier to type */ 799 add_mapping("plugboard", optarg); 800 break; 801 case 'Q': /* don't output control key settings */ 802 quiet = 1; 803 break; 804 case 'q': /* display term only */ 805 noset = 1; 806 break; 807 case 'r': /* display term on stderr */ 808 showterm = 1; 809 break; 810 case 'S': /* OBSOLETE: output TERM & TERMCAP */ 811 Sflag = 1; 812 break; 813 case 's': /* output TERM set command */ 814 sflag = 1; 815 break; 816 case 'V': /* print curses-version */ 817 puts(curses_version()); 818 ExitProgram(EXIT_SUCCESS); 819 case 'w': /* set window-size */ 820 opt_w = TRUE; 821 break; 822 case '?': 823 default: 824 usage(); 825 } 826 } 827 828 _nc_progname = _nc_rootname(*argv); 829 argc -= optind; 830 argv += optind; 831 832 if (argc > 1) 833 usage(); 834 835 if (!opt_c && !opt_w) 836 opt_c = opt_w = TRUE; 837 838 my_fd = save_tty_settings(&mode, TRUE); 839 oldmode = mode; 840 #ifdef TERMIOS 841 ospeed = (NCURSES_OSPEED) cfgetospeed(&mode); 842 #else 843 ospeed = (NCURSES_OSPEED) mode.sg_ospeed; 844 #endif 845 846 if (same_program(_nc_progname, PROG_RESET)) { 847 reset_start(stderr, TRUE, FALSE); 848 reset_tty_settings(my_fd, &mode); 849 } else { 850 reset_start(stderr, FALSE, TRUE); 851 } 852 853 ttype = get_termcap_entry(my_fd, *argv); 854 855 if (!noset) { 856 #if HAVE_SIZECHANGE 857 if (opt_w) { 858 set_window_size(my_fd, &lines, &columns); 859 } 860 #endif 861 if (opt_c) { 862 set_control_chars(&mode, terasechar, intrchar, tkillchar); 863 set_conversions(&mode); 864 865 if (!noinit) { 866 if (send_init_strings(my_fd, &oldmode)) { 867 (void) putc('\r', stderr); 868 (void) fflush(stderr); 869 (void) napms(1000); /* Settle the terminal. */ 870 } 871 } 872 873 update_tty_settings(&oldmode, &mode); 874 } 875 } 876 877 if (noset) { 878 (void) printf("%s\n", ttype); 879 } else { 880 if (showterm) 881 (void) fprintf(stderr, "Terminal type is %s.\n", ttype); 882 /* 883 * If erase, kill and interrupt characters could have been 884 * modified and not -Q, display the changes. 885 */ 886 if (!quiet) { 887 print_tty_chars(&oldmode, &mode); 888 } 889 } 890 891 if (Sflag) 892 err("The -S option is not supported under terminfo."); 893 894 if (sflag) { 895 print_shell_commands(ttype); 896 } 897 898 ExitProgram(EXIT_SUCCESS); 899 } 900