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