blob: 69f4aba879746c65fbf6179b32476970b46442fc [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2020-2021,2024 Thomas E. Dickey *
3 * Copyright 1998-2016,2017 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304 * *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
12 * *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
15 * *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
27 * authorization. *
28 ****************************************************************************/
29
30/****************************************************************************
31 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
32 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
33 * and: Thomas E. Dickey 1996-on *
34 ****************************************************************************/
35
36/*
Steve Kondikae271bc2015-11-15 02:50:53 +010037 * Notes:
38 * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686
39 * lines from that version, and made changes/additions for 150 lines. There
40 * was no reformatting, so with/without ignoring whitespace, the amount of
41 * change is the same.
42 *
43 * Comparing with current (2009) source, excluding this comment:
44 * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines
45 * changed/added.
46 * a) Ignoring whitespace, the current version still uses 516 lines from the
47 * 4.4BSD Lite sources, with 402 lines changed/added.
48 *
49 * Raymond's original comment on this follows...
50 */
51
52/*
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053053 * tset.c - terminal initialization utility
54 *
55 * This code was mostly swiped from 4.4BSD tset, with some obsolescent
56 * cruft removed and substantial portions rewritten. A Regents of the
57 * University of California copyright applies to some portions of the
58 * code, and is reproduced below:
59 */
60/*-
61 * Copyright (c) 1980, 1991, 1993
62 * The Regents of the University of California. All rights reserved.
63 *
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
66 * are met:
67 * 1. Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
Steve Kondikae271bc2015-11-15 02:50:53 +010072 * 3. Neither the name of the University nor the names of its contributors
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053073 * may be used to endorse or promote products derived from this software
74 * without specific prior written permission.
75 *
76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86 * SUCH DAMAGE.
87 */
88
micky3879b9f5e72025-07-08 18:04:53 -040089#include <reset_cmd.h>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053090#include <termcap.h>
micky3879b9f5e72025-07-08 18:04:53 -040091#include <transform.h>
92#include <tty_settings.h>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053093
micky3879b9f5e72025-07-08 18:04:53 -040094#if HAVE_GETTTYNAM
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053095#include <ttyent.h>
96#endif
97#ifdef NeXT
98char *ttyname(int fd);
99#endif
100
micky3879b9f5e72025-07-08 18:04:53 -0400101MODULE_ID("$Id: tset.c,v 1.135 2024/04/20 22:20:41 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530102
Steve Kondikae271bc2015-11-15 02:50:53 +0100103#ifndef environ
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530104extern char **environ;
Steve Kondikae271bc2015-11-15 02:50:53 +0100105#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530106
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530107const char *_nc_progname = "tset";
108
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530109#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
110
micky3879b9f5e72025-07-08 18:04:53 -0400111static GCC_NORETURN void exit_error(void);
112
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530113static int
114CaselessCmp(const char *a, const char *b)
115{ /* strcasecmp isn't portable */
116 while (*a && *b) {
117 int cmp = LOWERCASE(*a) - LOWERCASE(*b);
118 if (cmp != 0)
119 break;
120 a++, b++;
121 }
122 return LOWERCASE(*a) - LOWERCASE(*b);
123}
124
micky3879b9f5e72025-07-08 18:04:53 -0400125static GCC_NORETURN void
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530126exit_error(void)
127{
micky3879b9f5e72025-07-08 18:04:53 -0400128 restore_tty_settings();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530129 (void) fprintf(stderr, "\n");
130 fflush(stderr);
131 ExitProgram(EXIT_FAILURE);
132 /* NOTREACHED */
133}
134
micky3879b9f5e72025-07-08 18:04:53 -0400135static GCC_NORETURN void
136err(const char *fmt, ...)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530137{
138 va_list ap;
139 va_start(ap, fmt);
140 (void) fprintf(stderr, "%s: ", _nc_progname);
141 (void) vfprintf(stderr, fmt, ap);
142 va_end(ap);
143 exit_error();
144 /* NOTREACHED */
145}
146
micky3879b9f5e72025-07-08 18:04:53 -0400147static GCC_NORETURN void
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530148failed(const char *msg)
149{
150 char temp[BUFSIZ];
Steve Kondikae271bc2015-11-15 02:50:53 +0100151 size_t len = strlen(_nc_progname) + 2;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530152
153 if ((int) len < (int) sizeof(temp) - 12) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100154 _nc_STRCPY(temp, _nc_progname, sizeof(temp));
155 _nc_STRCAT(temp, ": ", sizeof(temp));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530156 } else {
Steve Kondikae271bc2015-11-15 02:50:53 +0100157 _nc_STRCPY(temp, "tset: ", sizeof(temp));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530158 }
micky3879b9f5e72025-07-08 18:04:53 -0400159 _nc_STRNCAT(temp, msg, sizeof(temp), sizeof(temp) - strlen(temp) - 2);
160 perror(temp);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530161 exit_error();
162 /* NOTREACHED */
163}
164
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530165/* Prompt the user for a terminal type. */
166static const char *
167askuser(const char *dflt)
168{
169 static char answer[256];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530170
171 /* We can get recalled; if so, don't continue uselessly. */
172 clearerr(stdin);
173 if (feof(stdin) || ferror(stdin)) {
174 (void) fprintf(stderr, "\n");
175 exit_error();
176 /* NOTREACHED */
177 }
micky3879b9f5e72025-07-08 18:04:53 -0400178
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530179 for (;;) {
micky3879b9f5e72025-07-08 18:04:53 -0400180 char *p;
181
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530182 if (dflt)
183 (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
184 else
185 (void) fprintf(stderr, "Terminal type? ");
186 (void) fflush(stderr);
187
188 if (fgets(answer, sizeof(answer), stdin) == 0) {
189 if (dflt == 0) {
190 exit_error();
191 /* NOTREACHED */
192 }
193 return (dflt);
194 }
195
196 if ((p = strchr(answer, '\n')) != 0)
197 *p = '\0';
198 if (answer[0])
199 return (answer);
200 if (dflt != 0)
201 return (dflt);
202 }
203}
204
205/**************************************************************************
206 *
207 * Mapping logic begins here
208 *
209 **************************************************************************/
210
211/* Baud rate conditionals for mapping. */
212#define GT 0x01
213#define EQ 0x02
214#define LT 0x04
215#define NOT 0x08
216#define GE (GT | EQ)
217#define LE (LT | EQ)
218
219typedef struct map {
220 struct map *next; /* Linked list of maps. */
221 const char *porttype; /* Port type, or "" for any. */
222 const char *type; /* Terminal type to select. */
223 int conditional; /* Baud rate conditionals bitmask. */
224 int speed; /* Baud rate to compare against. */
225} MAP;
226
227static MAP *cur, *maplist;
228
Steve Kondikae271bc2015-11-15 02:50:53 +0100229#define DATA(name,value) { { name }, value }
230
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530231typedef struct speeds {
micky3879b9f5e72025-07-08 18:04:53 -0400232 const char string[8];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530233 int speed;
234} SPEEDS;
235
micky3879b9f5e72025-07-08 18:04:53 -0400236#if defined(EXP_WIN32_DRIVER)
237static const SPEEDS speeds[] =
238{
239 {"0", 0}
240};
241#else
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530242static const SPEEDS speeds[] =
243{
Steve Kondikae271bc2015-11-15 02:50:53 +0100244 DATA("0", B0),
245 DATA("50", B50),
246 DATA("75", B75),
247 DATA("110", B110),
248 DATA("134", B134),
249 DATA("134.5", B134),
250 DATA("150", B150),
251 DATA("200", B200),
252 DATA("300", B300),
253 DATA("600", B600),
254 DATA("1200", B1200),
255 DATA("1800", B1800),
256 DATA("2400", B2400),
257 DATA("4800", B4800),
258 DATA("9600", B9600),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530259 /* sgttyb may define up to this point */
260#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100261 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530262#endif
263#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100264 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530265#endif
266#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100267 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530268#endif
269#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100270 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530271#endif
272#ifdef B19200
Steve Kondikae271bc2015-11-15 02:50:53 +0100273 DATA("19200", B19200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530274#else
275#ifdef EXTA
Steve Kondikae271bc2015-11-15 02:50:53 +0100276 DATA("19200", EXTA),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530277#endif
278#endif
279#ifdef B38400
Steve Kondikae271bc2015-11-15 02:50:53 +0100280 DATA("38400", B38400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530281#else
282#ifdef EXTB
Steve Kondikae271bc2015-11-15 02:50:53 +0100283 DATA("38400", EXTB),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530284#endif
285#endif
286#ifdef B57600
Steve Kondikae271bc2015-11-15 02:50:53 +0100287 DATA("57600", B57600),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530288#endif
micky3879b9f5e72025-07-08 18:04:53 -0400289#ifdef B76800
290 DATA("76800", B57600),
291#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530292#ifdef B115200
Steve Kondikae271bc2015-11-15 02:50:53 +0100293 DATA("115200", B115200),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530294#endif
micky3879b9f5e72025-07-08 18:04:53 -0400295#ifdef B153600
296 DATA("153600", B153600),
297#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530298#ifdef B230400
Steve Kondikae271bc2015-11-15 02:50:53 +0100299 DATA("230400", B230400),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530300#endif
micky3879b9f5e72025-07-08 18:04:53 -0400301#ifdef B307200
302 DATA("307200", B307200),
303#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530304#ifdef B460800
Steve Kondikae271bc2015-11-15 02:50:53 +0100305 DATA("460800", B460800),
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530306#endif
micky3879b9f5e72025-07-08 18:04:53 -0400307#ifdef B500000
308 DATA("500000", B500000),
309#endif
310#ifdef B576000
311 DATA("576000", B576000),
312#endif
313#ifdef B921600
314 DATA("921600", B921600),
315#endif
316#ifdef B1000000
317 DATA("1000000", B1000000),
318#endif
319#ifdef B1152000
320 DATA("1152000", B1152000),
321#endif
322#ifdef B1500000
323 DATA("1500000", B1500000),
324#endif
325#ifdef B2000000
326 DATA("2000000", B2000000),
327#endif
328#ifdef B2500000
329 DATA("2500000", B2500000),
330#endif
331#ifdef B3000000
332 DATA("3000000", B3000000),
333#endif
334#ifdef B3500000
335 DATA("3500000", B3500000),
336#endif
337#ifdef B4000000
338 DATA("4000000", B4000000),
339#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530340};
Steve Kondikae271bc2015-11-15 02:50:53 +0100341#undef DATA
micky3879b9f5e72025-07-08 18:04:53 -0400342#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530343
344static int
345tbaudrate(char *rate)
346{
Steve Kondikae271bc2015-11-15 02:50:53 +0100347 const SPEEDS *sp = 0;
348 size_t n;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530349
350 /* The baudrate number can be preceded by a 'B', which is ignored. */
351 if (*rate == 'B')
352 ++rate;
353
Steve Kondikae271bc2015-11-15 02:50:53 +0100354 for (n = 0; n < SIZEOF(speeds); ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400355 if (n > 0 && (speeds[n].speed <= speeds[n - 1].speed)) {
356 /* if the speeds are not increasing, likely a numeric overflow */
357 break;
358 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100359 if (!CaselessCmp(rate, speeds[n].string)) {
360 sp = speeds + n;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530361 break;
362 }
363 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100364 if (sp == 0)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530365 err("unknown baud rate %s", rate);
366 return (sp->speed);
367}
368
369/*
370 * Syntax for -m:
371 * [port-type][test baudrate]:terminal-type
372 * The baud rate tests are: >, <, @, =, !
373 */
374static void
375add_mapping(const char *port, char *arg)
376{
377 MAP *mapp;
378 char *copy, *p;
379 const char *termp;
380 char *base = 0;
381
382 copy = strdup(arg);
Steve Kondikae271bc2015-11-15 02:50:53 +0100383 mapp = typeMalloc(MAP, 1);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530384 if (copy == 0 || mapp == 0)
385 failed("malloc");
Steve Kondikae271bc2015-11-15 02:50:53 +0100386
387 assert(copy != 0);
388 assert(mapp != 0);
389
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530390 mapp->next = 0;
391 if (maplist == 0)
392 cur = maplist = mapp;
393 else {
394 cur->next = mapp;
395 cur = mapp;
396 }
397
398 mapp->porttype = arg;
399 mapp->conditional = 0;
400
401 arg = strpbrk(arg, "><@=!:");
402
403 if (arg == 0) { /* [?]term */
404 mapp->type = mapp->porttype;
405 mapp->porttype = 0;
406 goto done;
407 }
408
409 if (arg == mapp->porttype) /* [><@=! baud]:term */
410 termp = mapp->porttype = 0;
411 else
412 termp = base = arg;
413
414 for (;; ++arg) { /* Optional conditionals. */
415 switch (*arg) {
416 case '<':
417 if (mapp->conditional & GT)
418 goto badmopt;
419 mapp->conditional |= LT;
420 break;
421 case '>':
422 if (mapp->conditional & LT)
423 goto badmopt;
424 mapp->conditional |= GT;
425 break;
426 case '@':
427 case '=': /* Not documented. */
428 mapp->conditional |= EQ;
429 break;
430 case '!':
431 mapp->conditional |= NOT;
432 break;
433 default:
434 goto next;
435 }
436 }
437
438 next:
439 if (*arg == ':') {
440 if (mapp->conditional)
441 goto badmopt;
442 ++arg;
443 } else { /* Optional baudrate. */
444 arg = strchr(p = arg, ':');
445 if (arg == 0)
446 goto badmopt;
447 *arg++ = '\0';
448 mapp->speed = tbaudrate(p);
449 }
450
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530451 mapp->type = arg;
452
453 /* Terminate porttype, if specified. */
454 if (termp != 0)
455 *base = '\0';
456
457 /* If a NOT conditional, reverse the test. */
458 if (mapp->conditional & NOT)
459 mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
460
461 /* If user specified a port with an option flag, set it. */
462 done:
463 if (port) {
464 if (mapp->porttype) {
465 badmopt:
466 err("illegal -m option format: %s", copy);
467 }
468 mapp->porttype = port;
469 }
470 free(copy);
471#ifdef MAPDEBUG
472 (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
473 (void) printf("type: %s\n", mapp->type);
474 (void) printf("conditional: ");
475 p = "";
476 if (mapp->conditional & GT) {
477 (void) printf("GT");
478 p = "/";
479 }
480 if (mapp->conditional & EQ) {
481 (void) printf("%sEQ", p);
482 p = "/";
483 }
484 if (mapp->conditional & LT)
485 (void) printf("%sLT", p);
486 (void) printf("\nspeed: %d\n", mapp->speed);
487#endif
488}
489
490/*
491 * Return the type of terminal to use for a port of type 'type', as specified
492 * by the first applicable mapping in 'map'. If no mappings apply, return
493 * 'type'.
494 */
495static const char *
496mapped(const char *type)
497{
498 MAP *mapp;
499 int match;
500
501 for (mapp = maplist; mapp; mapp = mapp->next)
502 if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
503 switch (mapp->conditional) {
504 case 0: /* No test specified. */
505 match = TRUE;
506 break;
507 case EQ:
Steve Kondikae271bc2015-11-15 02:50:53 +0100508 match = ((int) ospeed == mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530509 break;
510 case GE:
Steve Kondikae271bc2015-11-15 02:50:53 +0100511 match = ((int) ospeed >= mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530512 break;
513 case GT:
Steve Kondikae271bc2015-11-15 02:50:53 +0100514 match = ((int) ospeed > mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530515 break;
516 case LE:
Steve Kondikae271bc2015-11-15 02:50:53 +0100517 match = ((int) ospeed <= mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530518 break;
519 case LT:
Steve Kondikae271bc2015-11-15 02:50:53 +0100520 match = ((int) ospeed < mapp->speed);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530521 break;
522 default:
523 match = FALSE;
524 }
525 if (match)
526 return (mapp->type);
527 }
528 /* No match found; return given type. */
529 return (type);
530}
531
532/**************************************************************************
533 *
534 * Entry fetching
535 *
536 **************************************************************************/
537
538/*
539 * Figure out what kind of terminal we're dealing with, and then read in
540 * its termcap entry.
541 */
542static const char *
micky3879b9f5e72025-07-08 18:04:53 -0400543get_termcap_entry(int fd, char *userarg)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530544{
545 int errret;
546 char *p;
547 const char *ttype;
micky3879b9f5e72025-07-08 18:04:53 -0400548#if HAVE_PATH_TTYS
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530549#if HAVE_GETTTYNAM
550 struct ttyent *t;
551#else
552 FILE *fp;
553#endif
554 char *ttypath;
micky3879b9f5e72025-07-08 18:04:53 -0400555#endif /* HAVE_PATH_TTYS */
556
557 (void) fd;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530558
559 if (userarg) {
560 ttype = userarg;
561 goto found;
562 }
563
564 /* Try the environment. */
565 if ((ttype = getenv("TERM")) != 0)
566 goto map;
567
micky3879b9f5e72025-07-08 18:04:53 -0400568#if HAVE_PATH_TTYS
569 if ((ttypath = ttyname(fd)) != 0) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530570 p = _nc_basename(ttypath);
571#if HAVE_GETTTYNAM
572 /*
573 * We have the 4.3BSD library call getttynam(3); that means
574 * there's an /etc/ttys to look up device-to-type mappings in.
575 * Try ttyname(3); check for dialup or other mapping.
576 */
577 if ((t = getttynam(p))) {
578 ttype = t->ty_type;
579 goto map;
580 }
581#else
582 if ((fp = fopen("/etc/ttytype", "r")) != 0
583 || (fp = fopen("/etc/ttys", "r")) != 0) {
584 char buffer[BUFSIZ];
585 char *s, *t, *d;
586
587 while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
588 for (s = buffer, t = d = 0; *s; s++) {
589 if (isspace(UChar(*s)))
590 *s = '\0';
591 else if (t == 0)
592 t = s;
593 else if (d == 0 && s != buffer && s[-1] == '\0')
594 d = s;
595 }
596 if (t != 0 && d != 0 && !strcmp(d, p)) {
597 ttype = strdup(t);
598 fclose(fp);
599 goto map;
600 }
601 }
602 fclose(fp);
603 }
604#endif /* HAVE_GETTTYNAM */
605 }
micky3879b9f5e72025-07-08 18:04:53 -0400606#endif /* HAVE_PATH_TTYS */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530607
608 /* If still undefined, use "unknown". */
609 ttype = "unknown";
610
611 map:ttype = mapped(ttype);
612
613 /*
614 * If not a path, remove TERMCAP from the environment so we get a
615 * real entry from /etc/termcap. This prevents us from being fooled
616 * by out of date stuff in the environment.
617 */
Steve Kondikae271bc2015-11-15 02:50:53 +0100618 found:
619 if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530620 /* 'unsetenv("TERMCAP")' is not portable.
621 * The 'environ' array is better.
622 */
623 int n;
624 for (n = 0; environ[n] != 0; n++) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100625 if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530626 while ((environ[n] = environ[n + 1]) != 0) {
627 n++;
628 }
629 break;
630 }
631 }
632 }
633
634 /*
635 * ttype now contains a pointer to the type of the terminal.
636 * If the first character is '?', ask the user.
637 */
638 if (ttype[0] == '?') {
639 if (ttype[1] != '\0')
640 ttype = askuser(ttype + 1);
641 else
642 ttype = askuser(0);
643 }
644 /* Find the terminfo entry. If it doesn't exist, ask the user. */
micky3879b9f5e72025-07-08 18:04:53 -0400645 while (setupterm((NCURSES_CONST char *) ttype, fd, &errret)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530646 != OK) {
647 if (errret == 0) {
648 (void) fprintf(stderr, "%s: unknown terminal type %s\n",
649 _nc_progname, ttype);
650 ttype = 0;
651 } else {
652 (void) fprintf(stderr,
653 "%s: can't initialize terminal type %s (error %d)\n",
654 _nc_progname, ttype, errret);
655 ttype = 0;
656 }
657 ttype = askuser(ttype);
658 }
659#if BROKEN_LINKER
660 tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
661#endif
662 return (ttype);
663}
664
665/**************************************************************************
666 *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530667 * Main sequence
668 *
669 **************************************************************************/
670
671/*
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530672 * Convert the obsolete argument forms into something that getopt can handle.
673 * This means that -e, -i and -k get default arguments supplied for them.
674 */
675static void
676obsolete(char **argv)
677{
678 for (; *argv; ++argv) {
679 char *parm = argv[0];
680
681 if (parm[0] == '-' && parm[1] == '\0') {
682 argv[0] = strdup("-q");
683 continue;
684 }
685
686 if ((parm[0] != '-')
687 || (argv[1] && argv[1][0] != '-')
688 || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
689 || (parm[2] != '\0'))
690 continue;
691 switch (argv[0][1]) {
692 case 'e':
693 argv[0] = strdup("-e^H");
694 break;
695 case 'i':
696 argv[0] = strdup("-i^C");
697 break;
698 case 'k':
699 argv[0] = strdup("-k^U");
700 break;
701 }
702 }
703}
704
705static void
micky3879b9f5e72025-07-08 18:04:53 -0400706print_shell_commands(const char *ttype)
707{
708 const char *p;
709 int len;
710 char *var;
711 char *leaf;
712 /*
713 * Figure out what shell we're using. A hack, we look for an
714 * environmental variable SHELL ending in "csh".
715 */
716 if ((var = getenv("SHELL")) != 0
717 && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3)
718 && !strcmp(leaf + len - 3, "csh"))
719 p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
720 else
721 p = "TERM=%s;\n";
722 (void) printf(p, ttype);
723}
724
725static void
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530726usage(void)
727{
micky3879b9f5e72025-07-08 18:04:53 -0400728#define SKIP(s) /* nothing */
729#define KEEP(s) s "\n"
Steve Kondikae271bc2015-11-15 02:50:53 +0100730 static const char msg[] =
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530731 {
micky3879b9f5e72025-07-08 18:04:53 -0400732 KEEP("")
733 KEEP("Options:")
734 SKIP(" -a arpanet (obsolete)")
735 KEEP(" -c set control characters")
736 SKIP(" -d dialup (obsolete)")
737 KEEP(" -e ch erase character")
738 KEEP(" -I no initialization strings")
739 KEEP(" -i ch interrupt character")
740 KEEP(" -k ch kill character")
741 KEEP(" -m mapping map identifier to type")
742 SKIP(" -p plugboard (obsolete)")
743 KEEP(" -Q do not output control key settings")
744 KEEP(" -q display term only, do no changes")
745 KEEP(" -r display term on stderr")
746 SKIP(" -S (obsolete)")
747 KEEP(" -s output TERM set command")
748 KEEP(" -V print curses-version")
749 KEEP(" -w set window-size")
750 KEEP("")
751 KEEP("If neither -c/-w are given, both are assumed.")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530752 };
micky3879b9f5e72025-07-08 18:04:53 -0400753#undef KEEP
754#undef SKIP
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530755 (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname);
Steve Kondikae271bc2015-11-15 02:50:53 +0100756 fputs(msg, stderr);
micky3879b9f5e72025-07-08 18:04:53 -0400757 ExitProgram(EXIT_FAILURE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530758 /* NOTREACHED */
759}
760
761static char
762arg_to_char(void)
763{
764 return (char) ((optarg[0] == '^' && optarg[1] != '\0')
765 ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
766 : optarg[0]);
767}
768
769int
770main(int argc, char **argv)
771{
772 int ch, noinit, noset, quiet, Sflag, sflag, showterm;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530773 const char *ttype;
micky3879b9f5e72025-07-08 18:04:53 -0400774 int terasechar = -1; /* new erase character */
775 int intrchar = -1; /* new interrupt character */
776 int tkillchar = -1; /* new kill character */
777 int my_fd;
778 bool opt_c = FALSE; /* set control-chars */
779 bool opt_w = FALSE; /* set window-size */
780 TTY mode, oldmode;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530781
micky3879b9f5e72025-07-08 18:04:53 -0400782 _nc_progname = _nc_rootname(*argv);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530783 obsolete(argv);
784 noinit = noset = quiet = Sflag = sflag = showterm = 0;
micky3879b9f5e72025-07-08 18:04:53 -0400785 while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQrSsVw")) != -1) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530786 switch (ch) {
787 case 'c': /* set control-chars */
788 opt_c = TRUE;
789 break;
790 case 'a': /* OBSOLETE: map identifier to type */
791 add_mapping("arpanet", optarg);
792 break;
793 case 'd': /* OBSOLETE: map identifier to type */
794 add_mapping("dialup", optarg);
795 break;
796 case 'e': /* erase character */
797 terasechar = arg_to_char();
798 break;
799 case 'I': /* no initialization strings */
800 noinit = 1;
801 break;
802 case 'i': /* interrupt character */
803 intrchar = arg_to_char();
804 break;
805 case 'k': /* kill character */
806 tkillchar = arg_to_char();
807 break;
808 case 'm': /* map identifier to type */
809 add_mapping(0, optarg);
810 break;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530811 case 'p': /* OBSOLETE: map identifier to type */
812 add_mapping("plugboard", optarg);
813 break;
814 case 'Q': /* don't output control key settings */
815 quiet = 1;
816 break;
817 case 'q': /* display term only */
818 noset = 1;
819 break;
820 case 'r': /* display term on stderr */
821 showterm = 1;
822 break;
823 case 'S': /* OBSOLETE: output TERM & TERMCAP */
824 Sflag = 1;
825 break;
826 case 's': /* output TERM set command */
827 sflag = 1;
828 break;
829 case 'V': /* print curses-version */
830 puts(curses_version());
831 ExitProgram(EXIT_SUCCESS);
832 case 'w': /* set window-size */
833 opt_w = TRUE;
834 break;
835 case '?':
836 default:
837 usage();
838 }
839 }
840
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530841 argc -= optind;
842 argv += optind;
843
844 if (argc > 1)
845 usage();
846
847 if (!opt_c && !opt_w)
848 opt_c = opt_w = TRUE;
849
micky3879b9f5e72025-07-08 18:04:53 -0400850 my_fd = save_tty_settings(&mode, TRUE);
851 oldmode = mode;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530852#ifdef TERMIOS
853 ospeed = (NCURSES_OSPEED) cfgetospeed(&mode);
micky3879b9f5e72025-07-08 18:04:53 -0400854#elif defined(EXP_WIN32_DRIVER)
855 ospeed = 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530856#else
857 ospeed = (NCURSES_OSPEED) mode.sg_ospeed;
858#endif
859
Steve Kondikae271bc2015-11-15 02:50:53 +0100860 if (same_program(_nc_progname, PROG_RESET)) {
micky3879b9f5e72025-07-08 18:04:53 -0400861 reset_start(stderr, TRUE, FALSE);
862 reset_tty_settings(my_fd, &mode, noset);
863 } else {
864 reset_start(stderr, FALSE, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530865 }
866
micky3879b9f5e72025-07-08 18:04:53 -0400867 ttype = get_termcap_entry(my_fd, *argv);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530868
869 if (!noset) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100870#if HAVE_SIZECHANGE
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530871 if (opt_w) {
micky3879b9f5e72025-07-08 18:04:53 -0400872 NCURSES_INT2 my_rows = lines;
873 NCURSES_INT2 my_cols = columns;
874 set_window_size(my_fd, &my_rows, &my_cols);
875 lines = my_rows;
876 columns = my_cols;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530877 }
878#endif
879 if (opt_c) {
micky3879b9f5e72025-07-08 18:04:53 -0400880 set_control_chars(&mode, terasechar, intrchar, tkillchar);
881 set_conversions(&mode);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530882
micky3879b9f5e72025-07-08 18:04:53 -0400883 if (!noinit) {
884 if (send_init_strings(my_fd, &oldmode)) {
885 const char *name;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530886
micky3879b9f5e72025-07-08 18:04:53 -0400887 (void) putc('\r', stderr);
888 (void) fflush(stderr);
889 if (IsRealTty(my_fd, name)) {
890 (void) napms(1000); /* Settle the terminal. */
891 }
892 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530893 }
micky3879b9f5e72025-07-08 18:04:53 -0400894
895 update_tty_settings(&oldmode, &mode);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530896 }
897 }
898
micky3879b9f5e72025-07-08 18:04:53 -0400899 if (noset) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530900 (void) printf("%s\n", ttype);
micky3879b9f5e72025-07-08 18:04:53 -0400901 } else {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530902 if (showterm)
903 (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
904 /*
905 * If erase, kill and interrupt characters could have been
906 * modified and not -Q, display the changes.
907 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530908 if (!quiet) {
micky3879b9f5e72025-07-08 18:04:53 -0400909 print_tty_chars(&oldmode, &mode);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530910 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530911 }
912
913 if (Sflag)
914 err("The -S option is not supported under terminfo.");
915
916 if (sflag) {
micky3879b9f5e72025-07-08 18:04:53 -0400917 print_shell_commands(ttype);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530918 }
919
920 ExitProgram(EXIT_SUCCESS);
921}