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