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.125 2020/09/05 22:54:47 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[8]; 231 int speed; 232 } SPEEDS; 233 234 #if defined(EXP_WIN32_DRIVER) 235 static const SPEEDS speeds[] = 236 { 237 {"0", 0} 238 }; 239 #else 240 static const SPEEDS speeds[] = 241 { 242 DATA("0", B0), 243 DATA("50", B50), 244 DATA("75", B75), 245 DATA("110", B110), 246 DATA("134", B134), 247 DATA("134.5", B134), 248 DATA("150", B150), 249 DATA("200", B200), 250 DATA("300", B300), 251 DATA("600", B600), 252 DATA("1200", B1200), 253 DATA("1800", B1800), 254 DATA("2400", B2400), 255 DATA("4800", B4800), 256 DATA("9600", B9600), 257 /* sgttyb may define up to this point */ 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 #endif 267 #ifdef B38400 268 DATA("38400", B38400), 269 #endif 270 #ifdef B19200 271 DATA("19200", B19200), 272 #else 273 #ifdef EXTA 274 DATA("19200", EXTA), 275 #endif 276 #endif 277 #ifdef B38400 278 DATA("38400", B38400), 279 #else 280 #ifdef EXTB 281 DATA("38400", EXTB), 282 #endif 283 #endif 284 #ifdef B57600 285 DATA("57600", B57600), 286 #endif 287 #ifdef B76800 288 DATA("76800", B57600), 289 #endif 290 #ifdef B115200 291 DATA("115200", B115200), 292 #endif 293 #ifdef B153600 294 DATA("153600", B153600), 295 #endif 296 #ifdef B230400 297 DATA("230400", B230400), 298 #endif 299 #ifdef B307200 300 DATA("307200", B307200), 301 #endif 302 #ifdef B460800 303 DATA("460800", B460800), 304 #endif 305 #ifdef B500000 306 DATA("500000", B500000), 307 #endif 308 #ifdef B576000 309 DATA("576000", B576000), 310 #endif 311 #ifdef B921600 312 DATA("921600", B921600), 313 #endif 314 #ifdef B1000000 315 DATA("1000000", B1000000), 316 #endif 317 #ifdef B1152000 318 DATA("1152000", B1152000), 319 #endif 320 #ifdef B1500000 321 DATA("1500000", B1500000), 322 #endif 323 #ifdef B2000000 324 DATA("2000000", B2000000), 325 #endif 326 #ifdef B2500000 327 DATA("2500000", B2500000), 328 #endif 329 #ifdef B3000000 330 DATA("3000000", B3000000), 331 #endif 332 #ifdef B3500000 333 DATA("3500000", B3500000), 334 #endif 335 #ifdef B4000000 336 DATA("4000000", B4000000), 337 #endif 338 }; 339 #undef DATA 340 #endif 341 342 static int 343 tbaudrate(char *rate) 344 { 345 const SPEEDS *sp = 0; 346 size_t n; 347 348 /* The baudrate number can be preceded by a 'B', which is ignored. */ 349 if (*rate == 'B') 350 ++rate; 351 352 for (n = 0; n < SIZEOF(speeds); ++n) { 353 if (n > 0 && (speeds[n].speed <= speeds[n - 1].speed)) { 354 /* if the speeds are not increasing, likely a numeric overflow */ 355 break; 356 } 357 if (!CaselessCmp(rate, speeds[n].string)) { 358 sp = speeds + n; 359 break; 360 } 361 } 362 if (sp == 0) 363 err("unknown baud rate %s", rate); 364 return (sp->speed); 365 } 366 367 /* 368 * Syntax for -m: 369 * [port-type][test baudrate]:terminal-type 370 * The baud rate tests are: >, <, @, =, ! 371 */ 372 static void 373 add_mapping(const char *port, char *arg) 374 { 375 MAP *mapp; 376 char *copy, *p; 377 const char *termp; 378 char *base = 0; 379 380 copy = strdup(arg); 381 mapp = typeMalloc(MAP, 1); 382 if (copy == 0 || mapp == 0) 383 failed("malloc"); 384 385 assert(copy != 0); 386 assert(mapp != 0); 387 388 mapp->next = 0; 389 if (maplist == 0) 390 cur = maplist = mapp; 391 else { 392 cur->next = mapp; 393 cur = mapp; 394 } 395 396 mapp->porttype = arg; 397 mapp->conditional = 0; 398 399 arg = strpbrk(arg, "><@=!:"); 400 401 if (arg == 0) { /* [?]term */ 402 mapp->type = mapp->porttype; 403 mapp->porttype = 0; 404 goto done; 405 } 406 407 if (arg == mapp->porttype) /* [><@=! baud]:term */ 408 termp = mapp->porttype = 0; 409 else 410 termp = base = arg; 411 412 for (;; ++arg) { /* Optional conditionals. */ 413 switch (*arg) { 414 case '<': 415 if (mapp->conditional & GT) 416 goto badmopt; 417 mapp->conditional |= LT; 418 break; 419 case '>': 420 if (mapp->conditional & LT) 421 goto badmopt; 422 mapp->conditional |= GT; 423 break; 424 case '@': 425 case '=': /* Not documented. */ 426 mapp->conditional |= EQ; 427 break; 428 case '!': 429 mapp->conditional |= NOT; 430 break; 431 default: 432 goto next; 433 } 434 } 435 436 next: 437 if (*arg == ':') { 438 if (mapp->conditional) 439 goto badmopt; 440 ++arg; 441 } else { /* Optional baudrate. */ 442 arg = strchr(p = arg, ':'); 443 if (arg == 0) 444 goto badmopt; 445 *arg++ = '\0'; 446 mapp->speed = tbaudrate(p); 447 } 448 449 mapp->type = arg; 450 451 /* Terminate porttype, if specified. */ 452 if (termp != 0) 453 *base = '\0'; 454 455 /* If a NOT conditional, reverse the test. */ 456 if (mapp->conditional & NOT) 457 mapp->conditional = ~mapp->conditional & (EQ | GT | LT); 458 459 /* If user specified a port with an option flag, set it. */ 460 done: 461 if (port) { 462 if (mapp->porttype) { 463 badmopt: 464 err("illegal -m option format: %s", copy); 465 } 466 mapp->porttype = port; 467 } 468 free(copy); 469 #ifdef MAPDEBUG 470 (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY"); 471 (void) printf("type: %s\n", mapp->type); 472 (void) printf("conditional: "); 473 p = ""; 474 if (mapp->conditional & GT) { 475 (void) printf("GT"); 476 p = "/"; 477 } 478 if (mapp->conditional & EQ) { 479 (void) printf("%sEQ", p); 480 p = "/"; 481 } 482 if (mapp->conditional & LT) 483 (void) printf("%sLT", p); 484 (void) printf("\nspeed: %d\n", mapp->speed); 485 #endif 486 } 487 488 /* 489 * Return the type of terminal to use for a port of type 'type', as specified 490 * by the first applicable mapping in 'map'. If no mappings apply, return 491 * 'type'. 492 */ 493 static const char * 494 mapped(const char *type) 495 { 496 MAP *mapp; 497 int match; 498 499 for (mapp = maplist; mapp; mapp = mapp->next) 500 if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) { 501 switch (mapp->conditional) { 502 case 0: /* No test specified. */ 503 match = TRUE; 504 break; 505 case EQ: 506 match = ((int) ospeed == mapp->speed); 507 break; 508 case GE: 509 match = ((int) ospeed >= mapp->speed); 510 break; 511 case GT: 512 match = ((int) ospeed > mapp->speed); 513 break; 514 case LE: 515 match = ((int) ospeed <= mapp->speed); 516 break; 517 case LT: 518 match = ((int) ospeed < mapp->speed); 519 break; 520 default: 521 match = FALSE; 522 } 523 if (match) 524 return (mapp->type); 525 } 526 /* No match found; return given type. */ 527 return (type); 528 } 529 530 /************************************************************************** 531 * 532 * Entry fetching 533 * 534 **************************************************************************/ 535 536 /* 537 * Figure out what kind of terminal we're dealing with, and then read in 538 * its termcap entry. 539 */ 540 static const char * 541 get_termcap_entry(int fd, char *userarg) 542 { 543 int errret; 544 char *p; 545 const char *ttype; 546 #if HAVE_GETTTYNAM 547 struct ttyent *t; 548 #else 549 FILE *fp; 550 #endif 551 char *ttypath; 552 553 (void) fd; 554 555 if (userarg) { 556 ttype = userarg; 557 goto found; 558 } 559 560 /* Try the environment. */ 561 if ((ttype = getenv("TERM")) != 0) 562 goto map; 563 564 if ((ttypath = ttyname(fd)) != 0) { 565 p = _nc_basename(ttypath); 566 #if HAVE_GETTTYNAM 567 /* 568 * We have the 4.3BSD library call getttynam(3); that means 569 * there's an /etc/ttys to look up device-to-type mappings in. 570 * Try ttyname(3); check for dialup or other mapping. 571 */ 572 if ((t = getttynam(p))) { 573 ttype = t->ty_type; 574 goto map; 575 } 576 #else 577 if ((fp = fopen("/etc/ttytype", "r")) != 0 578 || (fp = fopen("/etc/ttys", "r")) != 0) { 579 char buffer[BUFSIZ]; 580 char *s, *t, *d; 581 582 while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) { 583 for (s = buffer, t = d = 0; *s; s++) { 584 if (isspace(UChar(*s))) 585 *s = '\0'; 586 else if (t == 0) 587 t = s; 588 else if (d == 0 && s != buffer && s[-1] == '\0') 589 d = s; 590 } 591 if (t != 0 && d != 0 && !strcmp(d, p)) { 592 ttype = strdup(t); 593 fclose(fp); 594 goto map; 595 } 596 } 597 fclose(fp); 598 } 599 #endif /* HAVE_GETTTYNAM */ 600 } 601 602 /* If still undefined, use "unknown". */ 603 ttype = "unknown"; 604 605 map:ttype = mapped(ttype); 606 607 /* 608 * If not a path, remove TERMCAP from the environment so we get a 609 * real entry from /etc/termcap. This prevents us from being fooled 610 * by out of date stuff in the environment. 611 */ 612 found: 613 if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) { 614 /* 'unsetenv("TERMCAP")' is not portable. 615 * The 'environ' array is better. 616 */ 617 int n; 618 for (n = 0; environ[n] != 0; n++) { 619 if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) { 620 while ((environ[n] = environ[n + 1]) != 0) { 621 n++; 622 } 623 break; 624 } 625 } 626 } 627 628 /* 629 * ttype now contains a pointer to the type of the terminal. 630 * If the first character is '?', ask the user. 631 */ 632 if (ttype[0] == '?') { 633 if (ttype[1] != '\0') 634 ttype = askuser(ttype + 1); 635 else 636 ttype = askuser(0); 637 } 638 /* Find the terminfo entry. If it doesn't exist, ask the user. */ 639 while (setupterm((NCURSES_CONST char *) ttype, fd, &errret) 640 != OK) { 641 if (errret == 0) { 642 (void) fprintf(stderr, "%s: unknown terminal type %s\n", 643 _nc_progname, ttype); 644 ttype = 0; 645 } else { 646 (void) fprintf(stderr, 647 "%s: can't initialize terminal type %s (error %d)\n", 648 _nc_progname, ttype, errret); 649 ttype = 0; 650 } 651 ttype = askuser(ttype); 652 } 653 #if BROKEN_LINKER 654 tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */ 655 #endif 656 return (ttype); 657 } 658 659 /************************************************************************** 660 * 661 * Main sequence 662 * 663 **************************************************************************/ 664 665 /* 666 * Convert the obsolete argument forms into something that getopt can handle. 667 * This means that -e, -i and -k get default arguments supplied for them. 668 */ 669 static void 670 obsolete(char **argv) 671 { 672 for (; *argv; ++argv) { 673 char *parm = argv[0]; 674 675 if (parm[0] == '-' && parm[1] == '\0') { 676 argv[0] = strdup("-q"); 677 continue; 678 } 679 680 if ((parm[0] != '-') 681 || (argv[1] && argv[1][0] != '-') 682 || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k') 683 || (parm[2] != '\0')) 684 continue; 685 switch (argv[0][1]) { 686 case 'e': 687 argv[0] = strdup("-e^H"); 688 break; 689 case 'i': 690 argv[0] = strdup("-i^C"); 691 break; 692 case 'k': 693 argv[0] = strdup("-k^U"); 694 break; 695 } 696 } 697 } 698 699 static void 700 print_shell_commands(const char *ttype) 701 { 702 const char *p; 703 int len; 704 char *var; 705 char *leaf; 706 /* 707 * Figure out what shell we're using. A hack, we look for an 708 * environmental variable SHELL ending in "csh". 709 */ 710 if ((var = getenv("SHELL")) != 0 711 && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3) 712 && !strcmp(leaf + len - 3, "csh")) 713 p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n"; 714 else 715 p = "TERM=%s;\n"; 716 (void) printf(p, ttype); 717 } 718 719 static void 720 usage(void) 721 { 722 #define SKIP(s) /* nothing */ 723 #define KEEP(s) s "\n" 724 static const char msg[] = 725 { 726 KEEP("") 727 KEEP("Options:") 728 SKIP(" -a arpanet (obsolete)") 729 KEEP(" -c set control characters") 730 SKIP(" -d dialup (obsolete)") 731 KEEP(" -e ch erase character") 732 KEEP(" -I no initialization strings") 733 KEEP(" -i ch interrupt character") 734 KEEP(" -k ch kill character") 735 KEEP(" -m mapping map identifier to type") 736 SKIP(" -p plugboard (obsolete)") 737 KEEP(" -Q do not output control key settings") 738 KEEP(" -q display term only, do no changes") 739 KEEP(" -r display term on stderr") 740 SKIP(" -S (obsolete)") 741 KEEP(" -s output TERM set command") 742 KEEP(" -V print curses-version") 743 KEEP(" -w set window-size") 744 KEEP("") 745 KEEP("If neither -c/-w are given, both are assumed.") 746 }; 747 #undef KEEP 748 #undef SKIP 749 (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname); 750 fputs(msg, stderr); 751 ExitProgram(EXIT_FAILURE); 752 /* NOTREACHED */ 753 } 754 755 static char 756 arg_to_char(void) 757 { 758 return (char) ((optarg[0] == '^' && optarg[1] != '\0') 759 ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1])) 760 : optarg[0]); 761 } 762 763 int 764 main(int argc, char **argv) 765 { 766 int ch, noinit, noset, quiet, Sflag, sflag, showterm; 767 const char *ttype; 768 int terasechar = -1; /* new erase character */ 769 int intrchar = -1; /* new interrupt character */ 770 int tkillchar = -1; /* new kill character */ 771 int my_fd; 772 bool opt_c = FALSE; /* set control-chars */ 773 bool opt_w = FALSE; /* set window-size */ 774 TTY mode, oldmode; 775 776 my_fd = STDERR_FILENO; 777 obsolete(argv); 778 noinit = noset = quiet = Sflag = sflag = showterm = 0; 779 while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQrSsVw")) != -1) { 780 switch (ch) { 781 case 'c': /* set control-chars */ 782 opt_c = TRUE; 783 break; 784 case 'a': /* OBSOLETE: map identifier to type */ 785 add_mapping("arpanet", optarg); 786 break; 787 case 'd': /* OBSOLETE: map identifier to type */ 788 add_mapping("dialup", optarg); 789 break; 790 case 'e': /* erase character */ 791 terasechar = arg_to_char(); 792 break; 793 case 'I': /* no initialization strings */ 794 noinit = 1; 795 break; 796 case 'i': /* interrupt character */ 797 intrchar = arg_to_char(); 798 break; 799 case 'k': /* kill character */ 800 tkillchar = arg_to_char(); 801 break; 802 case 'm': /* map identifier to type */ 803 add_mapping(0, optarg); 804 break; 805 case 'p': /* OBSOLETE: map identifier to type */ 806 add_mapping("plugboard", optarg); 807 break; 808 case 'Q': /* don't output control key settings */ 809 quiet = 1; 810 break; 811 case 'q': /* display term only */ 812 noset = 1; 813 break; 814 case 'r': /* display term on stderr */ 815 showterm = 1; 816 break; 817 case 'S': /* OBSOLETE: output TERM & TERMCAP */ 818 Sflag = 1; 819 break; 820 case 's': /* output TERM set command */ 821 sflag = 1; 822 break; 823 case 'V': /* print curses-version */ 824 puts(curses_version()); 825 ExitProgram(EXIT_SUCCESS); 826 case 'w': /* set window-size */ 827 opt_w = TRUE; 828 break; 829 case '?': 830 default: 831 usage(); 832 } 833 } 834 835 _nc_progname = _nc_rootname(*argv); 836 argc -= optind; 837 argv += optind; 838 839 if (argc > 1) 840 usage(); 841 842 if (!opt_c && !opt_w) 843 opt_c = opt_w = TRUE; 844 845 my_fd = save_tty_settings(&mode, TRUE); 846 oldmode = mode; 847 #ifdef TERMIOS 848 ospeed = (NCURSES_OSPEED) cfgetospeed(&mode); 849 #elif defined(EXP_WIN32_DRIVER) 850 ospeed = 0; 851 #else 852 ospeed = (NCURSES_OSPEED) mode.sg_ospeed; 853 #endif 854 855 if (same_program(_nc_progname, PROG_RESET)) { 856 reset_start(stderr, TRUE, FALSE); 857 reset_tty_settings(my_fd, &mode); 858 } else { 859 reset_start(stderr, FALSE, TRUE); 860 } 861 862 ttype = get_termcap_entry(my_fd, *argv); 863 864 if (!noset) { 865 #if HAVE_SIZECHANGE 866 if (opt_w) { 867 set_window_size(my_fd, &lines, &columns); 868 } 869 #endif 870 if (opt_c) { 871 set_control_chars(&mode, terasechar, intrchar, tkillchar); 872 set_conversions(&mode); 873 874 if (!noinit) { 875 if (send_init_strings(my_fd, &oldmode)) { 876 (void) putc('\r', stderr); 877 (void) fflush(stderr); 878 (void) napms(1000); /* Settle the terminal. */ 879 } 880 } 881 882 update_tty_settings(&oldmode, &mode); 883 } 884 } 885 886 if (noset) { 887 (void) printf("%s\n", ttype); 888 } else { 889 if (showterm) 890 (void) fprintf(stderr, "Terminal type is %s.\n", ttype); 891 /* 892 * If erase, kill and interrupt characters could have been 893 * modified and not -Q, display the changes. 894 */ 895 if (!quiet) { 896 print_tty_chars(&oldmode, &mode); 897 } 898 } 899 900 if (Sflag) 901 err("The -S option is not supported under terminfo."); 902 903 if (sflag) { 904 print_shell_commands(ttype); 905 } 906 907 ExitProgram(EXIT_SUCCESS); 908 } 909