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