ncurses 6.0 - patch 20160806
[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.107 2016/08/06 20:54:22 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     if (userarg) {
496         ttype = userarg;
497         goto found;
498     }
499
500     /* Try the environment. */
501     if ((ttype = getenv("TERM")) != 0)
502         goto map;
503
504     if ((ttypath = ttyname(fd)) != 0) {
505         p = _nc_basename(ttypath);
506 #if HAVE_GETTTYNAM
507         /*
508          * We have the 4.3BSD library call getttynam(3); that means
509          * there's an /etc/ttys to look up device-to-type mappings in.
510          * Try ttyname(3); check for dialup or other mapping.
511          */
512         if ((t = getttynam(p))) {
513             ttype = t->ty_type;
514             goto map;
515         }
516 #else
517         if ((fp = fopen("/etc/ttytype", "r")) != 0
518             || (fp = fopen("/etc/ttys", "r")) != 0) {
519             char buffer[BUFSIZ];
520             char *s, *t, *d;
521
522             while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
523                 for (s = buffer, t = d = 0; *s; s++) {
524                     if (isspace(UChar(*s)))
525                         *s = '\0';
526                     else if (t == 0)
527                         t = s;
528                     else if (d == 0 && s != buffer && s[-1] == '\0')
529                         d = s;
530                 }
531                 if (t != 0 && d != 0 && !strcmp(d, p)) {
532                     ttype = strdup(t);
533                     fclose(fp);
534                     goto map;
535                 }
536             }
537             fclose(fp);
538         }
539 #endif /* HAVE_GETTTYNAM */
540     }
541
542     /* If still undefined, use "unknown". */
543     ttype = "unknown";
544
545   map:ttype = mapped(ttype);
546
547     /*
548      * If not a path, remove TERMCAP from the environment so we get a
549      * real entry from /etc/termcap.  This prevents us from being fooled
550      * by out of date stuff in the environment.
551      */
552   found:
553     if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
554         /* 'unsetenv("TERMCAP")' is not portable.
555          * The 'environ' array is better.
556          */
557         int n;
558         for (n = 0; environ[n] != 0; n++) {
559             if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
560                 while ((environ[n] = environ[n + 1]) != 0) {
561                     n++;
562                 }
563                 break;
564             }
565         }
566     }
567
568     /*
569      * ttype now contains a pointer to the type of the terminal.
570      * If the first character is '?', ask the user.
571      */
572     if (ttype[0] == '?') {
573         if (ttype[1] != '\0')
574             ttype = askuser(ttype + 1);
575         else
576             ttype = askuser(0);
577     }
578     /* Find the terminfo entry.  If it doesn't exist, ask the user. */
579     while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
580            != OK) {
581         if (errret == 0) {
582             (void) fprintf(stderr, "%s: unknown terminal type %s\n",
583                            _nc_progname, ttype);
584             ttype = 0;
585         } else {
586             (void) fprintf(stderr,
587                            "%s: can't initialize terminal type %s (error %d)\n",
588                            _nc_progname, ttype, errret);
589             ttype = 0;
590         }
591         ttype = askuser(ttype);
592     }
593 #if BROKEN_LINKER
594     tgetflag("am");             /* force lib_termcap.o to be linked for 'ospeed' */
595 #endif
596     return (ttype);
597 }
598
599 /**************************************************************************
600  *
601  * Main sequence
602  *
603  **************************************************************************/
604
605 /*
606  * Convert the obsolete argument forms into something that getopt can handle.
607  * This means that -e, -i and -k get default arguments supplied for them.
608  */
609 static void
610 obsolete(char **argv)
611 {
612     for (; *argv; ++argv) {
613         char *parm = argv[0];
614
615         if (parm[0] == '-' && parm[1] == '\0') {
616             argv[0] = strdup("-q");
617             continue;
618         }
619
620         if ((parm[0] != '-')
621             || (argv[1] && argv[1][0] != '-')
622             || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
623             || (parm[2] != '\0'))
624             continue;
625         switch (argv[0][1]) {
626         case 'e':
627             argv[0] = strdup("-e^H");
628             break;
629         case 'i':
630             argv[0] = strdup("-i^C");
631             break;
632         case 'k':
633             argv[0] = strdup("-k^U");
634             break;
635         }
636     }
637 }
638
639 static void
640 print_shell_commands(const char *ttype)
641 {
642     const char *p;
643     int len;
644     char *var;
645     char *leaf;
646     /*
647      * Figure out what shell we're using.  A hack, we look for an
648      * environmental variable SHELL ending in "csh".
649      */
650     if ((var = getenv("SHELL")) != 0
651         && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
652         && !strcmp(leaf + len - 3, "csh"))
653         p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
654     else
655         p = "TERM=%s;\n";
656     (void) printf(p, ttype);
657 }
658
659 static void
660 usage(void)
661 {
662 #define DATA(s) s "\n"
663     static const char msg[] =
664     {
665         DATA("")
666         DATA("Options:")
667         DATA("  -c          set control characters")
668         DATA("  -e ch       erase character")
669         DATA("  -I          no initialization strings")
670         DATA("  -i ch       interrupt character")
671         DATA("  -k ch       kill character")
672         DATA("  -m mapping  map identifier to type")
673         DATA("  -Q          do not output control key settings")
674         DATA("  -r          display term on stderr")
675         DATA("  -s          output TERM set command")
676         DATA("  -V          print curses-version")
677         DATA("  -w          set window-size")
678     };
679 #undef DATA
680     (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
681     fputs(msg, stderr);
682     exit_error();
683     /* NOTREACHED */
684 }
685
686 static char
687 arg_to_char(void)
688 {
689     return (char) ((optarg[0] == '^' && optarg[1] != '\0')
690                    ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
691                    : optarg[0]);
692 }
693
694 int
695 main(int argc, char **argv)
696 {
697     int ch, noinit, noset, quiet, Sflag, sflag, showterm;
698     const char *ttype;
699     int terasechar = -1;        /* new erase character */
700     int intrchar = -1;          /* new interrupt character */
701     int tkillchar = -1;         /* new kill character */
702     int my_fd = -1;
703     bool opt_c = FALSE;         /* set control-chars */
704     bool opt_w = FALSE;         /* set window-size */
705     TTY mode, oldmode;
706
707     my_fd = STDERR_FILENO;
708     obsolete(argv);
709     noinit = noset = quiet = Sflag = sflag = showterm = 0;
710     while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQSrsVw")) != -1) {
711         switch (ch) {
712         case 'c':               /* set control-chars */
713             opt_c = TRUE;
714             break;
715         case 'a':               /* OBSOLETE: map identifier to type */
716             add_mapping("arpanet", optarg);
717             break;
718         case 'd':               /* OBSOLETE: map identifier to type */
719             add_mapping("dialup", optarg);
720             break;
721         case 'e':               /* erase character */
722             terasechar = arg_to_char();
723             break;
724         case 'I':               /* no initialization strings */
725             noinit = 1;
726             break;
727         case 'i':               /* interrupt character */
728             intrchar = arg_to_char();
729             break;
730         case 'k':               /* kill character */
731             tkillchar = arg_to_char();
732             break;
733         case 'm':               /* map identifier to type */
734             add_mapping(0, optarg);
735             break;
736         case 'p':               /* OBSOLETE: map identifier to type */
737             add_mapping("plugboard", optarg);
738             break;
739         case 'Q':               /* don't output control key settings */
740             quiet = 1;
741             break;
742         case 'q':               /* display term only */
743             noset = 1;
744             break;
745         case 'r':               /* display term on stderr */
746             showterm = 1;
747             break;
748         case 'S':               /* OBSOLETE: output TERM & TERMCAP */
749             Sflag = 1;
750             break;
751         case 's':               /* output TERM set command */
752             sflag = 1;
753             break;
754         case 'V':               /* print curses-version */
755             puts(curses_version());
756             ExitProgram(EXIT_SUCCESS);
757         case 'w':               /* set window-size */
758             opt_w = TRUE;
759             break;
760         case '?':
761         default:
762             usage();
763         }
764     }
765
766     _nc_progname = _nc_rootname(*argv);
767     argc -= optind;
768     argv += optind;
769
770     if (argc > 1)
771         usage();
772
773     if (!opt_c && !opt_w)
774         opt_c = opt_w = TRUE;
775
776     my_fd = save_tty_settings(&mode);
777     oldmode = mode;
778 #ifdef TERMIOS
779     ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
780 #else
781     ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
782 #endif
783
784     if (same_program(_nc_progname, PROG_RESET)) {
785         reset_start(stderr, TRUE, FALSE);
786         reset_tty_settings(&mode);
787     } else {
788         reset_start(stderr, FALSE, FALSE);
789     }
790
791     ttype = get_termcap_entry(my_fd, *argv);
792
793     if (!noset) {
794 #if HAVE_SIZECHANGE
795         if (opt_w) {
796             set_window_size(my_fd, lines, columns);
797         }
798 #endif
799         if (opt_c) {
800             set_control_chars(&mode, terasechar, intrchar, tkillchar);
801             set_conversions(&mode);
802
803             if (!noinit) {
804                 if (send_init_strings(&oldmode)) {
805                     (void) putc('\r', stderr);
806                     (void) fflush(stderr);
807                     (void) napms(1000);         /* Settle the terminal. */
808                 }
809             }
810
811             update_tty_settings(&oldmode, &mode);
812         }
813     }
814
815     if (noset) {
816         (void) printf("%s\n", ttype);
817     } else {
818         if (showterm)
819             (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
820         /*
821          * If erase, kill and interrupt characters could have been
822          * modified and not -Q, display the changes.
823          */
824         if (!quiet) {
825             print_tty_chars(&oldmode, &mode);
826         }
827     }
828
829     if (Sflag)
830         err("The -S option is not supported under terminfo.");
831
832     if (sflag) {
833         print_shell_commands(ttype);
834     }
835
836     ExitProgram(EXIT_SUCCESS);
837 }