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
CaselessCmp(const char * a,const char * b)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
exit_error(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
err(const char * fmt,...)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
failed(const char * msg)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 *
askuser(const char * dflt)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
tbaudrate(char * rate)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
add_mapping(const char * port,char * arg)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 *
mapped(const char * type)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 *
get_termcap_entry(int fd,char * userarg)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
obsolete(char ** argv)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
print_shell_commands(const char * ttype)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
usage(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
arg_to_char(void)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
main(int argc,char ** argv)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