blob: 9a05b3d06d0a7d1f1ea86b244983dbff6db03406 [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
Steve Kondikae271bc2015-11-15 02:50:53 +01002 * Copyright (c) 1998-2013,2015 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303 * *
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/*
Steve Kondikae271bc2015-11-15 02:50:53 +010036 * 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/*
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053052 * 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.
Steve Kondikae271bc2015-11-15 02:50:53 +010071 * 3. Neither the name of the University nor the names of its contributors
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053072 * 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#define USE_LIBTINFO
89#define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */
90#include <progs.priv.h>
91
92#include <errno.h>
93#include <stdio.h>
94#include <termcap.h>
95#include <fcntl.h>
96
97#if HAVE_GETTTYNAM && HAVE_TTYENT_H
98#include <ttyent.h>
99#endif
100#ifdef NeXT
101char *ttyname(int fd);
102#endif
103
104#if HAVE_SIZECHANGE
105# if !defined(sun) || !TERMIOS
106# if HAVE_SYS_IOCTL_H
107# include <sys/ioctl.h>
108# endif
109# endif
110#endif
111
112#if NEED_PTEM_H
113/* they neglected to define struct winsize in termios.h -- it's only
114 in termio.h */
115#include <sys/stream.h>
116#include <sys/ptem.h>
117#endif
118
119#include <dump_entry.h>
120#include <transform.h>
121
Steve Kondikae271bc2015-11-15 02:50:53 +0100122MODULE_ID("$Id: tset.c,v 1.96 2015/04/12 15:36:06 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530123
124/*
125 * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS,
126 * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
127 */
128#ifdef TIOCGSIZE
129# define IOCTL_GET_WINSIZE TIOCGSIZE
130# define IOCTL_SET_WINSIZE TIOCSSIZE
131# define STRUCT_WINSIZE struct ttysize
132# define WINSIZE_ROWS(n) n.ts_lines
133# define WINSIZE_COLS(n) n.ts_cols
134#else
135# ifdef TIOCGWINSZ
136# define IOCTL_GET_WINSIZE TIOCGWINSZ
137# define IOCTL_SET_WINSIZE TIOCSWINSZ
138# define STRUCT_WINSIZE struct winsize
139# define WINSIZE_ROWS(n) n.ws_row
140# define WINSIZE_COLS(n) n.ws_col
141# endif
142#endif
143
Steve Kondikae271bc2015-11-15 02:50:53 +0100144#ifndef environ
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530145extern char **environ;
Steve Kondikae271bc2015-11-15 02:50:53 +0100146#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530147
148#undef CTRL
149#define CTRL(x) ((x) & 0x1f)
150
Steve Kondikae271bc2015-11-15 02:50:53 +0100151static void failed(const char *) GCC_NORETURN;
152static void exit_error(void) GCC_NORETURN;
153static void err(const char *,...) GCC_NORETURN;
154
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530155const char *_nc_progname = "tset";
156
157static TTY mode, oldmode, original;
158
159static bool opt_c; /* set control-chars */
160static bool opt_w; /* set window-size */
161
162static bool can_restore = FALSE;
163static bool isreset = FALSE; /* invoked as reset */
164static int terasechar = -1; /* new erase character */
165static int intrchar = -1; /* new interrupt character */
166static int tkillchar = -1; /* new kill character */
Steve Kondikae271bc2015-11-15 02:50:53 +0100167
168#if HAVE_SIZECHANGE
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530169static int tlines, tcolumns; /* window size */
Steve Kondikae271bc2015-11-15 02:50:53 +0100170#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530171
172#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
173
174static int
175CaselessCmp(const char *a, const char *b)
176{ /* strcasecmp isn't portable */
177 while (*a && *b) {
178 int cmp = LOWERCASE(*a) - LOWERCASE(*b);
179 if (cmp != 0)
180 break;
181 a++, b++;
182 }
183 return LOWERCASE(*a) - LOWERCASE(*b);
184}
185
186static void
187exit_error(void)
188{
189 if (can_restore)
190 SET_TTY(STDERR_FILENO, &original);
191 (void) fprintf(stderr, "\n");
192 fflush(stderr);
193 ExitProgram(EXIT_FAILURE);
194 /* NOTREACHED */
195}
196
197static void
198err(const char *fmt,...)
199{
200 va_list ap;
201 va_start(ap, fmt);
202 (void) fprintf(stderr, "%s: ", _nc_progname);
203 (void) vfprintf(stderr, fmt, ap);
204 va_end(ap);
205 exit_error();
206 /* NOTREACHED */
207}
208
209static void
210failed(const char *msg)
211{
212 char temp[BUFSIZ];
Steve Kondikae271bc2015-11-15 02:50:53 +0100213 size_t len = strlen(_nc_progname) + 2;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530214
215 if ((int) len < (int) sizeof(temp) - 12) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100216 _nc_STRCPY(temp, _nc_progname, sizeof(temp));
217 _nc_STRCAT(temp, ": ", sizeof(temp));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530218 } else {
Steve Kondikae271bc2015-11-15 02:50:53 +0100219 _nc_STRCPY(temp, "tset: ", sizeof(temp));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530220 }
221 perror(strncat(temp, msg, sizeof(temp) - strlen(temp) - 2));
222 exit_error();
223 /* NOTREACHED */
224}
225
226static void
227cat(char *file)
228{
229 FILE *fp;
230 size_t nr;
231 char buf[BUFSIZ];
232
233 if ((fp = fopen(file, "r")) == 0)
234 failed(file);
235
236 while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
237 if (fwrite(buf, sizeof(char), nr, stderr) != nr)
238 failed("write to stderr");
239 fclose(fp);
240}
241
242static int
243outc(int c)
244{
245 return putc(c, stderr);
246}
247
248/* Prompt the user for a terminal type. */
249static const char *
250askuser(const char *dflt)
251{
252 static char answer[256];
253 char *p;
254
255 /* We can get recalled; if so, don't continue uselessly. */
256 clearerr(stdin);
257 if (feof(stdin) || ferror(stdin)) {
258 (void) fprintf(stderr, "\n");
259 exit_error();
260 /* NOTREACHED */
261 }
262 for (;;) {
263 if (dflt)
264 (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
265 else
266 (void) fprintf(stderr, "Terminal type? ");
267 (void) fflush(stderr);
268
269 if (fgets(answer, sizeof(answer), stdin) == 0) {
270 if (dflt == 0) {
271 exit_error();
272 /* NOTREACHED */
273 }
274 return (dflt);
275 }
276
277 if ((p = strchr(answer, '\n')) != 0)
278 *p = '\0';
279 if (answer[0])
280 return (answer);
281 if (dflt != 0)
282 return (dflt);
283 }
284}
285
286/**************************************************************************
287 *
288 * Mapping logic begins here
289 *
290 **************************************************************************/
291
292/* Baud rate conditionals for mapping. */
293#define GT 0x01
294#define EQ 0x02
295#define LT 0x04
296#define NOT 0x08
297#define GE (GT | EQ)
298#define LE (LT | EQ)
299
300typedef struct map {
301 struct map *next; /* Linked list of maps. */
302 const char *porttype; /* Port type, or "" for any. */
303 const char *type; /* Terminal type to select. */
304 int conditional; /* Baud rate conditionals bitmask. */
305 int speed; /* Baud rate to compare against. */
306} MAP;
307
308static MAP *cur, *maplist;
309
Steve Kondikae271bc2015-11-15 02:50:53 +0100310#define DATA(name,value) { { name }, value }
311
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530312typedef struct speeds {
Steve Kondikae271bc2015-11-15 02:50:53 +0100313 const char string[7];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530314 int speed;
315} SPEEDS;
316
317static const SPEEDS speeds[] =
318{
Steve Kondikae271bc2015-11-15 02:50:53 +0100319 DATA("0", B0),
320 DATA("50", B50),
321 DATA("75", B75),
322 DATA("110", B110),
323 DATA("134", B134),
324 DATA("134.5", B134),
325 DATA("150", B150),
326 DATA("200", B200),
327 DATA("300", B300),
328 DATA("600", B600),
329 DATA("1200", B1200),
330 DATA("1800", B1800),
331 DATA("2400", B2400),
332 DATA("4800", B4800),
333 DATA("9600", B9600),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530334 /* sgttyb may define up to this point */
335#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100336 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530337#endif
338#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100339 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530340#endif
341#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100342 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530343#endif
344#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100345 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530346#endif
347#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100348 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530349#else
350#ifdef EXTA
Steve Kondikae271bc2015-11-15 02:50:53 +0100351 DATA("19200", EXTA),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530352#endif
353#endif
354#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100355 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530356#else
357#ifdef EXTB
Steve Kondikae271bc2015-11-15 02:50:53 +0100358 DATA("38400", EXTB),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530359#endif
360#endif
361#ifdef B57600
Steve Kondikae271bc2015-11-15 02:50:53 +0100362 DATA("57600", B57600),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530363#endif
364#ifdef B115200
Steve Kondikae271bc2015-11-15 02:50:53 +0100365 DATA("115200", B115200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530366#endif
367#ifdef B230400
Steve Kondikae271bc2015-11-15 02:50:53 +0100368 DATA("230400", B230400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530369#endif
370#ifdef B460800
Steve Kondikae271bc2015-11-15 02:50:53 +0100371 DATA("460800", B460800),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530372#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530373};
Steve Kondikae271bc2015-11-15 02:50:53 +0100374#undef DATA
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530375
376static int
377tbaudrate(char *rate)
378{
Steve Kondikae271bc2015-11-15 02:50:53 +0100379 const SPEEDS *sp = 0;
380 size_t n;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530381
382 /* The baudrate number can be preceded by a 'B', which is ignored. */
383 if (*rate == 'B')
384 ++rate;
385
Steve Kondikae271bc2015-11-15 02:50:53 +0100386 for (n = 0; n < SIZEOF(speeds); ++n) {
387 if (!CaselessCmp(rate, speeds[n].string)) {
388 sp = speeds + n;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530389 break;
390 }
391 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100392 if (sp == 0)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530393 err("unknown baud rate %s", rate);
394 return (sp->speed);
395}
396
397/*
398 * Syntax for -m:
399 * [port-type][test baudrate]:terminal-type
400 * The baud rate tests are: >, <, @, =, !
401 */
402static void
403add_mapping(const char *port, char *arg)
404{
405 MAP *mapp;
406 char *copy, *p;
407 const char *termp;
408 char *base = 0;
409
410 copy = strdup(arg);
Steve Kondikae271bc2015-11-15 02:50:53 +0100411 mapp = typeMalloc(MAP, 1);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530412 if (copy == 0 || mapp == 0)
413 failed("malloc");
Steve Kondikae271bc2015-11-15 02:50:53 +0100414
415 assert(copy != 0);
416 assert(mapp != 0);
417
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530418 mapp->next = 0;
419 if (maplist == 0)
420 cur = maplist = mapp;
421 else {
422 cur->next = mapp;
423 cur = mapp;
424 }
425
426 mapp->porttype = arg;
427 mapp->conditional = 0;
428
429 arg = strpbrk(arg, "><@=!:");
430
431 if (arg == 0) { /* [?]term */
432 mapp->type = mapp->porttype;
433 mapp->porttype = 0;
434 goto done;
435 }
436
437 if (arg == mapp->porttype) /* [><@=! baud]:term */
438 termp = mapp->porttype = 0;
439 else
440 termp = base = arg;
441
442 for (;; ++arg) { /* Optional conditionals. */
443 switch (*arg) {
444 case '<':
445 if (mapp->conditional & GT)
446 goto badmopt;
447 mapp->conditional |= LT;
448 break;
449 case '>':
450 if (mapp->conditional & LT)
451 goto badmopt;
452 mapp->conditional |= GT;
453 break;
454 case '@':
455 case '=': /* Not documented. */
456 mapp->conditional |= EQ;
457 break;
458 case '!':
459 mapp->conditional |= NOT;
460 break;
461 default:
462 goto next;
463 }
464 }
465
466 next:
467 if (*arg == ':') {
468 if (mapp->conditional)
469 goto badmopt;
470 ++arg;
471 } else { /* Optional baudrate. */
472 arg = strchr(p = arg, ':');
473 if (arg == 0)
474 goto badmopt;
475 *arg++ = '\0';
476 mapp->speed = tbaudrate(p);
477 }
478
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530479 mapp->type = arg;
480
481 /* Terminate porttype, if specified. */
482 if (termp != 0)
483 *base = '\0';
484
485 /* If a NOT conditional, reverse the test. */
486 if (mapp->conditional & NOT)
487 mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
488
489 /* If user specified a port with an option flag, set it. */
490 done:
491 if (port) {
492 if (mapp->porttype) {
493 badmopt:
494 err("illegal -m option format: %s", copy);
495 }
496 mapp->porttype = port;
497 }
498 free(copy);
499#ifdef MAPDEBUG
500 (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
501 (void) printf("type: %s\n", mapp->type);
502 (void) printf("conditional: ");
503 p = "";
504 if (mapp->conditional & GT) {
505 (void) printf("GT");
506 p = "/";
507 }
508 if (mapp->conditional & EQ) {
509 (void) printf("%sEQ", p);
510 p = "/";
511 }
512 if (mapp->conditional & LT)
513 (void) printf("%sLT", p);
514 (void) printf("\nspeed: %d\n", mapp->speed);
515#endif
516}
517
518/*
519 * Return the type of terminal to use for a port of type 'type', as specified
520 * by the first applicable mapping in 'map'. If no mappings apply, return
521 * 'type'.
522 */
523static const char *
524mapped(const char *type)
525{
526 MAP *mapp;
527 int match;
528
529 for (mapp = maplist; mapp; mapp = mapp->next)
530 if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
531 switch (mapp->conditional) {
532 case 0: /* No test specified. */
533 match = TRUE;
534 break;
535 case EQ:
Steve Kondikae271bc2015-11-15 02:50:53 +0100536 match = ((int) ospeed == mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530537 break;
538 case GE:
Steve Kondikae271bc2015-11-15 02:50:53 +0100539 match = ((int) ospeed >= mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530540 break;
541 case GT:
Steve Kondikae271bc2015-11-15 02:50:53 +0100542 match = ((int) ospeed > mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530543 break;
544 case LE:
Steve Kondikae271bc2015-11-15 02:50:53 +0100545 match = ((int) ospeed <= mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530546 break;
547 case LT:
Steve Kondikae271bc2015-11-15 02:50:53 +0100548 match = ((int) ospeed < mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530549 break;
550 default:
551 match = FALSE;
552 }
553 if (match)
554 return (mapp->type);
555 }
556 /* No match found; return given type. */
557 return (type);
558}
559
560/**************************************************************************
561 *
562 * Entry fetching
563 *
564 **************************************************************************/
565
566/*
567 * Figure out what kind of terminal we're dealing with, and then read in
568 * its termcap entry.
569 */
570static const char *
571get_termcap_entry(char *userarg)
572{
573 int errret;
574 char *p;
575 const char *ttype;
576#if HAVE_GETTTYNAM
577 struct ttyent *t;
578#else
579 FILE *fp;
580#endif
581 char *ttypath;
582
583 if (userarg) {
584 ttype = userarg;
585 goto found;
586 }
587
588 /* Try the environment. */
589 if ((ttype = getenv("TERM")) != 0)
590 goto map;
591
592 if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
593 p = _nc_basename(ttypath);
594#if HAVE_GETTTYNAM
595 /*
596 * We have the 4.3BSD library call getttynam(3); that means
597 * there's an /etc/ttys to look up device-to-type mappings in.
598 * Try ttyname(3); check for dialup or other mapping.
599 */
600 if ((t = getttynam(p))) {
601 ttype = t->ty_type;
602 goto map;
603 }
604#else
605 if ((fp = fopen("/etc/ttytype", "r")) != 0
606 || (fp = fopen("/etc/ttys", "r")) != 0) {
607 char buffer[BUFSIZ];
608 char *s, *t, *d;
609
610 while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
611 for (s = buffer, t = d = 0; *s; s++) {
612 if (isspace(UChar(*s)))
613 *s = '\0';
614 else if (t == 0)
615 t = s;
616 else if (d == 0 && s != buffer && s[-1] == '\0')
617 d = s;
618 }
619 if (t != 0 && d != 0 && !strcmp(d, p)) {
620 ttype = strdup(t);
621 fclose(fp);
622 goto map;
623 }
624 }
625 fclose(fp);
626 }
627#endif /* HAVE_GETTTYNAM */
628 }
629
630 /* If still undefined, use "unknown". */
631 ttype = "unknown";
632
633 map:ttype = mapped(ttype);
634
635 /*
636 * If not a path, remove TERMCAP from the environment so we get a
637 * real entry from /etc/termcap. This prevents us from being fooled
638 * by out of date stuff in the environment.
639 */
Steve Kondikae271bc2015-11-15 02:50:53 +0100640 found:
641 if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530642 /* 'unsetenv("TERMCAP")' is not portable.
643 * The 'environ' array is better.
644 */
645 int n;
646 for (n = 0; environ[n] != 0; n++) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100647 if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530648 while ((environ[n] = environ[n + 1]) != 0) {
649 n++;
650 }
651 break;
652 }
653 }
654 }
655
656 /*
657 * ttype now contains a pointer to the type of the terminal.
658 * If the first character is '?', ask the user.
659 */
660 if (ttype[0] == '?') {
661 if (ttype[1] != '\0')
662 ttype = askuser(ttype + 1);
663 else
664 ttype = askuser(0);
665 }
666 /* Find the terminfo entry. If it doesn't exist, ask the user. */
667 while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
668 != OK) {
669 if (errret == 0) {
670 (void) fprintf(stderr, "%s: unknown terminal type %s\n",
671 _nc_progname, ttype);
672 ttype = 0;
673 } else {
674 (void) fprintf(stderr,
675 "%s: can't initialize terminal type %s (error %d)\n",
676 _nc_progname, ttype, errret);
677 ttype = 0;
678 }
679 ttype = askuser(ttype);
680 }
681#if BROKEN_LINKER
682 tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
683#endif
684 return (ttype);
685}
686
687/**************************************************************************
688 *
689 * Mode-setting logic
690 *
691 **************************************************************************/
692
693/* some BSD systems have these built in, some systems are missing
694 * one or more definitions. The safest solution is to override unless the
695 * commonly-altered ones are defined.
696 */
697#if !(defined(CERASE) && defined(CINTR) && defined(CKILL) && defined(CQUIT))
698#undef CEOF
699#undef CERASE
700#undef CINTR
701#undef CKILL
702#undef CLNEXT
703#undef CRPRNT
704#undef CQUIT
705#undef CSTART
706#undef CSTOP
707#undef CSUSP
708#endif
709
710/* control-character defaults */
711#ifndef CEOF
712#define CEOF CTRL('D')
713#endif
714#ifndef CERASE
715#define CERASE CTRL('H')
716#endif
717#ifndef CINTR
718#define CINTR 127 /* ^? */
719#endif
720#ifndef CKILL
721#define CKILL CTRL('U')
722#endif
723#ifndef CLNEXT
724#define CLNEXT CTRL('v')
725#endif
726#ifndef CRPRNT
727#define CRPRNT CTRL('r')
728#endif
729#ifndef CQUIT
730#define CQUIT CTRL('\\')
731#endif
732#ifndef CSTART
733#define CSTART CTRL('Q')
734#endif
735#ifndef CSTOP
736#define CSTOP CTRL('S')
737#endif
738#ifndef CSUSP
739#define CSUSP CTRL('Z')
740#endif
741
742#if defined(_POSIX_VDISABLE)
743#define DISABLED(val) (((_POSIX_VDISABLE != -1) \
744 && ((val) == _POSIX_VDISABLE)) \
745 || ((val) <= 0))
746#else
747#define DISABLED(val) ((int)(val) <= 0)
748#endif
749
Steve Kondikae271bc2015-11-15 02:50:53 +0100750#define CHK(val, dft) (unsigned char) (DISABLED(val) ? dft : val)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530751
752static bool set_tabs(void);
753
754/*
755 * Reset the terminal mode bits to a sensible state. Very useful after
756 * a child program dies in raw mode.
757 */
758static void
759reset_mode(void)
760{
761#ifdef TERMIOS
762 tcgetattr(STDERR_FILENO, &mode);
763#else
764 stty(STDERR_FILENO, &mode);
765#endif
766
767#ifdef TERMIOS
768#if defined(VDISCARD) && defined(CDISCARD)
769 mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
770#endif
771 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
772 mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
773#if defined(VFLUSH) && defined(CFLUSH)
774 mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
775#endif
776 mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
777 mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
778#if defined(VLNEXT) && defined(CLNEXT)
779 mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
780#endif
781 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
782#if defined(VREPRINT) && defined(CRPRNT)
783 mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
784#endif
785#if defined(VSTART) && defined(CSTART)
786 mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
787#endif
788#if defined(VSTOP) && defined(CSTOP)
789 mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
790#endif
791#if defined(VSUSP) && defined(CSUSP)
792 mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
793#endif
794#if defined(VWERASE) && defined(CWERASE)
795 mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
796#endif
797
Steve Kondikae271bc2015-11-15 02:50:53 +0100798 mode.c_iflag &= ~((unsigned) (IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530799#ifdef IUCLC
Steve Kondikae271bc2015-11-15 02:50:53 +0100800 | IUCLC
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530801#endif
802#ifdef IXANY
Steve Kondikae271bc2015-11-15 02:50:53 +0100803 | IXANY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530804#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100805 | IXOFF));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530806
807 mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
808#ifdef IMAXBEL
809 | IMAXBEL
810#endif
811 );
812
Steve Kondikae271bc2015-11-15 02:50:53 +0100813 mode.c_oflag &= ~((unsigned) (0
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530814#ifdef OLCUC
Steve Kondikae271bc2015-11-15 02:50:53 +0100815 | OLCUC
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530816#endif
817#ifdef OCRNL
Steve Kondikae271bc2015-11-15 02:50:53 +0100818 | OCRNL
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530819#endif
820#ifdef ONOCR
Steve Kondikae271bc2015-11-15 02:50:53 +0100821 | ONOCR
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530822#endif
823#ifdef ONLRET
Steve Kondikae271bc2015-11-15 02:50:53 +0100824 | ONLRET
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530825#endif
826#ifdef OFILL
Steve Kondikae271bc2015-11-15 02:50:53 +0100827 | OFILL
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530828#endif
829#ifdef OFDEL
Steve Kondikae271bc2015-11-15 02:50:53 +0100830 | OFDEL
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530831#endif
832#ifdef NLDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100833 | NLDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530834#endif
835#ifdef CRDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100836 | CRDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530837#endif
838#ifdef TABDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100839 | TABDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530840#endif
841#ifdef BSDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100842 | BSDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530843#endif
844#ifdef VTDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100845 | VTDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530846#endif
847#ifdef FFDLY
Steve Kondikae271bc2015-11-15 02:50:53 +0100848 | FFDLY
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530849#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100850 ));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530851
852 mode.c_oflag |= (OPOST
853#ifdef ONLCR
854 | ONLCR
855#endif
856 );
857
Steve Kondikae271bc2015-11-15 02:50:53 +0100858 mode.c_cflag &= ~((unsigned) (CSIZE | CSTOPB | PARENB | PARODD | CLOCAL));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530859 mode.c_cflag |= (CS8 | CREAD);
Steve Kondikae271bc2015-11-15 02:50:53 +0100860 mode.c_lflag &= ~((unsigned) (ECHONL | NOFLSH
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530861#ifdef TOSTOP
Steve Kondikae271bc2015-11-15 02:50:53 +0100862 | TOSTOP
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530863#endif
864#ifdef ECHOPTR
Steve Kondikae271bc2015-11-15 02:50:53 +0100865 | ECHOPRT
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530866#endif
867#ifdef XCASE
Steve Kondikae271bc2015-11-15 02:50:53 +0100868 | XCASE
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530869#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100870 ));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530871
872 mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
873#ifdef ECHOCTL
874 | ECHOCTL
875#endif
876#ifdef ECHOKE
877 | ECHOKE
878#endif
879 );
880#endif
881
882 SET_TTY(STDERR_FILENO, &mode);
883}
884
885/*
886 * Returns a "good" value for the erase character. This is loosely based on
887 * the BSD4.4 logic.
888 */
889#ifdef TERMIOS
890static int
891default_erase(void)
892{
893 int result;
894
895 if (over_strike
896 && key_backspace != 0
897 && strlen(key_backspace) == 1)
898 result = key_backspace[0];
899 else
900 result = CERASE;
901
902 return result;
903}
904#endif
905
906/*
907 * Update the values of the erase, interrupt, and kill characters in 'mode'.
908 *
909 * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
910 * characters if they're unset, or if we specify them as options. This differs
911 * from BSD 4.4 tset, which always sets erase.
912 */
913static void
914set_control_chars(void)
915{
916#ifdef TERMIOS
Steve Kondikae271bc2015-11-15 02:50:53 +0100917 if (DISABLED(mode.c_cc[VERASE]) || terasechar >= 0) {
918 mode.c_cc[VERASE] = UChar((terasechar >= 0)
919 ? terasechar
920 : default_erase());
921 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530922
Steve Kondikae271bc2015-11-15 02:50:53 +0100923 if (DISABLED(mode.c_cc[VINTR]) || intrchar >= 0) {
924 mode.c_cc[VINTR] = UChar((intrchar >= 0)
925 ? intrchar
926 : CINTR);
927 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530928
Steve Kondikae271bc2015-11-15 02:50:53 +0100929 if (DISABLED(mode.c_cc[VKILL]) || tkillchar >= 0) {
930 mode.c_cc[VKILL] = UChar((tkillchar >= 0)
931 ? tkillchar
932 : CKILL);
933 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530934#endif
935}
936
937/*
938 * Set up various conversions in 'mode', including parity, tabs, returns,
939 * echo, and case, according to the termcap entry. If the program we're
940 * running was named with a leading upper-case character, map external
941 * uppercase to internal lowercase.
942 */
943static void
944set_conversions(void)
945{
946#ifdef __OBSOLETE__
947 /*
948 * Conversion logic for some *really* ancient terminal glitches,
949 * not supported in terminfo. Left here for succeeding generations
950 * to marvel at.
951 */
952 if (tgetflag("UC")) {
953#ifdef IUCLC
954 mode.c_iflag |= IUCLC;
955 mode.c_oflag |= OLCUC;
956#endif
957 } else if (tgetflag("LC")) {
958#ifdef IUCLC
959 mode.c_iflag &= ~IUCLC;
960 mode.c_oflag &= ~OLCUC;
961#endif
962 }
963 mode.c_iflag &= ~(PARMRK | INPCK);
964 mode.c_lflag |= ICANON;
965 if (tgetflag("EP")) {
966 mode.c_cflag |= PARENB;
967 mode.c_cflag &= ~PARODD;
968 }
969 if (tgetflag("OP")) {
970 mode.c_cflag |= PARENB;
971 mode.c_cflag |= PARODD;
972 }
973#endif /* __OBSOLETE__ */
974
975#ifdef TERMIOS
976#ifdef ONLCR
977 mode.c_oflag |= ONLCR;
978#endif
979 mode.c_iflag |= ICRNL;
980 mode.c_lflag |= ECHO;
981#ifdef OXTABS
982 mode.c_oflag |= OXTABS;
983#endif /* OXTABS */
984
985 /* test used to be tgetflag("NL") */
986 if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
987 /* Newline, not linefeed. */
988#ifdef ONLCR
Steve Kondikae271bc2015-11-15 02:50:53 +0100989 mode.c_oflag &= ~((unsigned) ONLCR);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530990#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100991 mode.c_iflag &= ~((unsigned) ICRNL);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530992 }
993#ifdef __OBSOLETE__
994 if (tgetflag("HD")) /* Half duplex. */
995 mode.c_lflag &= ~ECHO;
996#endif /* __OBSOLETE__ */
997#ifdef OXTABS
998 /* test used to be tgetflag("pt") */
999 if (has_hardware_tabs) /* Print tabs. */
1000 mode.c_oflag &= ~OXTABS;
1001#endif /* OXTABS */
1002 mode.c_lflag |= (ECHOE | ECHOK);
1003#endif
1004}
1005
1006/* Output startup string. */
1007static void
1008set_init(void)
1009{
1010 char *p;
1011 bool settle;
1012
1013#ifdef __OBSOLETE__
1014 if (pad_char != (char *) 0) /* Get/set pad character. */
1015 PC = pad_char[0];
1016#endif /* OBSOLETE */
1017
1018#ifdef TAB3
1019 if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
1020 oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
1021 SET_TTY(STDERR_FILENO, &oldmode);
1022 }
1023#endif
1024 settle = set_tabs();
1025
1026 if (isreset) {
1027 if ((p = reset_1string) != 0) {
1028 tputs(p, 0, outc);
1029 settle = TRUE;
1030 }
1031 if ((p = reset_2string) != 0) {
1032 tputs(p, 0, outc);
1033 settle = TRUE;
1034 }
1035 /* What about rf, rs3, as per terminfo man page? */
1036 /* also might be nice to send rmacs, rmul, rmm */
1037 if ((p = reset_file) != 0
1038 || (p = init_file) != 0) {
1039 cat(p);
1040 settle = TRUE;
1041 }
1042 }
1043
1044 if (settle) {
1045 (void) putc('\r', stderr);
1046 (void) fflush(stderr);
1047 (void) napms(1000); /* Settle the terminal. */
1048 }
1049}
1050
1051/*
1052 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
1053 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
1054 * This is done before if and is, so they can patch in case we blow this.
1055 * Return TRUE if we set any tab stops, FALSE if not.
1056 */
1057static bool
1058set_tabs(void)
1059{
1060 if (set_tab && clear_all_tabs) {
1061 int c;
Steve Kondikae271bc2015-11-15 02:50:53 +01001062 int lim =
1063#if HAVE_SIZECHANGE
1064 tcolumns
1065#else
1066 columns
1067#endif
1068 ;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301069
1070 (void) putc('\r', stderr); /* Force to left margin. */
1071 tputs(clear_all_tabs, 0, outc);
1072
Steve Kondikae271bc2015-11-15 02:50:53 +01001073 for (c = 8; c < lim; c += 8) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301074 /* Get to the right column. In BSD tset, this
1075 * used to try a bunch of half-clever things
1076 * with cup and hpa, for an average saving of
1077 * somewhat less than two character times per
1078 * tab stop, less than .01 sec at 2400cps. We
1079 * lost all this cruft because it seemed to be
1080 * introducing some odd bugs.
1081 * -----------12345678----------- */
1082 (void) fputs(" ", stderr);
1083 tputs(set_tab, 0, outc);
1084 }
1085 putc('\r', stderr);
1086 return (TRUE);
1087 }
1088 return (FALSE);
1089}
1090
1091/**************************************************************************
1092 *
1093 * Main sequence
1094 *
1095 **************************************************************************/
1096
1097/*
1098 * Tell the user if a control key has been changed from the default value.
1099 */
1100#ifdef TERMIOS
1101static void
1102report(const char *name, int which, unsigned def)
1103{
1104 unsigned older, newer;
1105 char *p;
1106
1107 newer = mode.c_cc[which];
1108 older = oldmode.c_cc[which];
1109
1110 if (older == newer && older == def)
1111 return;
1112
1113 (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
1114
1115 if (DISABLED(newer))
1116 (void) fprintf(stderr, "undef.\n");
1117 /*
1118 * Check 'delete' before 'backspace', since the key_backspace value
1119 * is ambiguous.
1120 */
1121 else if (newer == 0177)
1122 (void) fprintf(stderr, "delete.\n");
1123 else if ((p = key_backspace) != 0
1124 && newer == (unsigned char) p[0]
1125 && p[1] == '\0')
1126 (void) fprintf(stderr, "backspace.\n");
1127 else if (newer < 040) {
1128 newer ^= 0100;
1129 (void) fprintf(stderr, "control-%c (^%c).\n", UChar(newer), UChar(newer));
1130 } else
1131 (void) fprintf(stderr, "%c.\n", UChar(newer));
1132}
1133#endif
1134
1135/*
1136 * Convert the obsolete argument forms into something that getopt can handle.
1137 * This means that -e, -i and -k get default arguments supplied for them.
1138 */
1139static void
1140obsolete(char **argv)
1141{
1142 for (; *argv; ++argv) {
1143 char *parm = argv[0];
1144
1145 if (parm[0] == '-' && parm[1] == '\0') {
1146 argv[0] = strdup("-q");
1147 continue;
1148 }
1149
1150 if ((parm[0] != '-')
1151 || (argv[1] && argv[1][0] != '-')
1152 || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
1153 || (parm[2] != '\0'))
1154 continue;
1155 switch (argv[0][1]) {
1156 case 'e':
1157 argv[0] = strdup("-e^H");
1158 break;
1159 case 'i':
1160 argv[0] = strdup("-i^C");
1161 break;
1162 case 'k':
1163 argv[0] = strdup("-k^U");
1164 break;
1165 }
1166 }
1167}
1168
1169static void
1170usage(void)
1171{
Steve Kondikae271bc2015-11-15 02:50:53 +01001172#define DATA(s) s "\n"
1173 static const char msg[] =
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301174 {
Steve Kondikae271bc2015-11-15 02:50:53 +01001175 DATA("")
1176 DATA("Options:")
1177 DATA(" -c set control characters")
1178 DATA(" -e ch erase character")
1179 DATA(" -I no initialization strings")
1180 DATA(" -i ch interrupt character")
1181 DATA(" -k ch kill character")
1182 DATA(" -m mapping map identifier to type")
1183 DATA(" -Q do not output control key settings")
1184 DATA(" -r display term on stderr")
1185 DATA(" -s output TERM set command")
1186 DATA(" -V print curses-version")
1187 DATA(" -w set window-size")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301188 };
Steve Kondikae271bc2015-11-15 02:50:53 +01001189#undef DATA
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301190 (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
Steve Kondikae271bc2015-11-15 02:50:53 +01001191 fputs(msg, stderr);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301192 exit_error();
1193 /* NOTREACHED */
1194}
1195
1196static char
1197arg_to_char(void)
1198{
1199 return (char) ((optarg[0] == '^' && optarg[1] != '\0')
1200 ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
1201 : optarg[0]);
1202}
1203
1204int
1205main(int argc, char **argv)
1206{
1207 int ch, noinit, noset, quiet, Sflag, sflag, showterm;
1208 const char *p;
1209 const char *ttype;
1210
1211 obsolete(argv);
1212 noinit = noset = quiet = Sflag = sflag = showterm = 0;
1213 while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:np:qQSrsVw")) != -1) {
1214 switch (ch) {
1215 case 'c': /* set control-chars */
1216 opt_c = TRUE;
1217 break;
1218 case 'a': /* OBSOLETE: map identifier to type */
1219 add_mapping("arpanet", optarg);
1220 break;
1221 case 'd': /* OBSOLETE: map identifier to type */
1222 add_mapping("dialup", optarg);
1223 break;
1224 case 'e': /* erase character */
1225 terasechar = arg_to_char();
1226 break;
1227 case 'I': /* no initialization strings */
1228 noinit = 1;
1229 break;
1230 case 'i': /* interrupt character */
1231 intrchar = arg_to_char();
1232 break;
1233 case 'k': /* kill character */
1234 tkillchar = arg_to_char();
1235 break;
1236 case 'm': /* map identifier to type */
1237 add_mapping(0, optarg);
1238 break;
1239 case 'n': /* OBSOLETE: set new tty driver */
1240 break;
1241 case 'p': /* OBSOLETE: map identifier to type */
1242 add_mapping("plugboard", optarg);
1243 break;
1244 case 'Q': /* don't output control key settings */
1245 quiet = 1;
1246 break;
1247 case 'q': /* display term only */
1248 noset = 1;
1249 break;
1250 case 'r': /* display term on stderr */
1251 showterm = 1;
1252 break;
1253 case 'S': /* OBSOLETE: output TERM & TERMCAP */
1254 Sflag = 1;
1255 break;
1256 case 's': /* output TERM set command */
1257 sflag = 1;
1258 break;
1259 case 'V': /* print curses-version */
1260 puts(curses_version());
1261 ExitProgram(EXIT_SUCCESS);
1262 case 'w': /* set window-size */
1263 opt_w = TRUE;
1264 break;
1265 case '?':
1266 default:
1267 usage();
1268 }
1269 }
1270
1271 _nc_progname = _nc_rootname(*argv);
1272 argc -= optind;
1273 argv += optind;
1274
1275 if (argc > 1)
1276 usage();
1277
1278 if (!opt_c && !opt_w)
1279 opt_c = opt_w = TRUE;
1280
1281 if (GET_TTY(STDERR_FILENO, &mode) < 0)
1282 failed("standard error");
1283 can_restore = TRUE;
1284 original = oldmode = mode;
1285#ifdef TERMIOS
1286 ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
1287#else
1288 ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
1289#endif
1290
Steve Kondikae271bc2015-11-15 02:50:53 +01001291 if (same_program(_nc_progname, PROG_RESET)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301292 isreset = TRUE;
1293 reset_mode();
1294 }
1295
Steve Kondikae271bc2015-11-15 02:50:53 +01001296 (void) get_termcap_entry(*argv);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301297
1298 if (!noset) {
Steve Kondikae271bc2015-11-15 02:50:53 +01001299#if HAVE_SIZECHANGE
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301300 tcolumns = columns;
1301 tlines = lines;
1302
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301303 if (opt_w) {
1304 STRUCT_WINSIZE win;
1305 /* Set window size if not set already */
1306 (void) ioctl(STDERR_FILENO, IOCTL_GET_WINSIZE, &win);
1307 if (WINSIZE_ROWS(win) == 0 &&
1308 WINSIZE_COLS(win) == 0 &&
1309 tlines > 0 && tcolumns > 0) {
Steve Kondikae271bc2015-11-15 02:50:53 +01001310 WINSIZE_ROWS(win) = (unsigned short) tlines;
1311 WINSIZE_COLS(win) = (unsigned short) tcolumns;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301312 (void) ioctl(STDERR_FILENO, IOCTL_SET_WINSIZE, &win);
1313 }
1314 }
1315#endif
1316 if (opt_c) {
1317 set_control_chars();
1318 set_conversions();
1319
1320 if (!noinit)
1321 set_init();
1322
1323 /* Set the modes if they've changed. */
1324 if (memcmp(&mode, &oldmode, sizeof(mode))) {
1325 SET_TTY(STDERR_FILENO, &mode);
1326 }
1327 }
1328 }
1329
1330 /* Get the terminal name from the entry. */
1331 ttype = _nc_first_name(cur_term->type.term_names);
1332
1333 if (noset)
1334 (void) printf("%s\n", ttype);
1335 else {
1336 if (showterm)
1337 (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
1338 /*
1339 * If erase, kill and interrupt characters could have been
1340 * modified and not -Q, display the changes.
1341 */
1342#ifdef TERMIOS
1343 if (!quiet) {
1344 report("Erase", VERASE, CERASE);
1345 report("Kill", VKILL, CKILL);
1346 report("Interrupt", VINTR, CINTR);
1347 }
1348#endif
1349 }
1350
1351 if (Sflag)
1352 err("The -S option is not supported under terminfo.");
1353
1354 if (sflag) {
1355 int len;
1356 char *var;
1357 char *leaf;
1358 /*
1359 * Figure out what shell we're using. A hack, we look for an
1360 * environmental variable SHELL ending in "csh".
1361 */
1362 if ((var = getenv("SHELL")) != 0
1363 && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
1364 && !strcmp(leaf + len - 3, "csh"))
1365 p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
1366 else
1367 p = "TERM=%s;\n";
1368 (void) printf(p, ttype);
1369 }
1370
1371 ExitProgram(EXIT_SUCCESS);
1372}