Annotation of src/usr.bin/tset/tset.c, Revision 1.31
1.31 ! chl 1: /* $OpenBSD: tset.c,v 1.30 2007/09/11 15:47:17 gilles Exp $ */
1.22 niklas 2:
1.7 millert 3: /****************************************************************************
1.16 millert 4: * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. *
1.7 millert 5: * *
6: * Permission is hereby granted, free of charge, to any person obtaining a *
7: * copy of this software and associated documentation files (the *
8: * "Software"), to deal in the Software without restriction, including *
9: * without limitation the rights to use, copy, modify, merge, publish, *
10: * distribute, distribute with modifications, sublicense, and/or sell *
11: * copies of the Software, and to permit persons to whom the Software is *
12: * furnished to do so, subject to the following conditions: *
13: * *
14: * The above copyright notice and this permission notice shall be included *
15: * in all copies or substantial portions of the Software. *
16: * *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
18: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
19: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
20: * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
21: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
22: * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
23: * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
24: * *
25: * Except as contained in this notice, the name(s) of the above copyright *
26: * holders shall not be used in advertising or otherwise to promote the *
27: * sale, use or other dealings in this Software without prior written *
28: * authorization. *
29: ****************************************************************************/
30:
31: /****************************************************************************
32: * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
33: * and: Eric S. Raymond <esr@snark.thyrsus.com> *
34: ****************************************************************************/
1.1 deraadt 35:
1.7 millert 36: /*
37: * tset.c - terminal initialization utility
38: *
39: * This code was mostly swiped from 4.4BSD tset, with some obsolescent
40: * cruft removed and substantial portions rewritten. A Regents of the
41: * University of California copyright applies to some portions of the
42: * code, and is reproduced below:
43: */
1.1 deraadt 44: /*-
45: * Copyright (c) 1980, 1991, 1993
46: * The Regents of the University of California. All rights reserved.
47: *
48: * Redistribution and use in source and binary forms, with or without
49: * modification, are permitted provided that the following conditions
50: * are met:
51: * 1. Redistributions of source code must retain the above copyright
52: * notice, this list of conditions and the following disclaimer.
53: * 2. Redistributions in binary form must reproduce the above copyright
54: * notice, this list of conditions and the following disclaimer in the
55: * documentation and/or other materials provided with the distribution.
1.26 millert 56: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 57: * may be used to endorse or promote products derived from this software
58: * without specific prior written permission.
59: *
60: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70: * SUCH DAMAGE.
71: */
72:
1.7 millert 73: #define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */
74: #include <progs.priv.h>
75:
1.1 deraadt 76: #include <errno.h>
77: #include <stdio.h>
1.7 millert 78: #include <termcap.h>
79: #include <fcntl.h>
80:
81: #if HAVE_GETTTYNAM && HAVE_TTYENT_H
82: #include <ttyent.h>
83: #endif
84: #ifdef NeXT
85: char *ttyname(int fd);
86: #endif
87:
88: /* this is just to stifle a missing-prototype warning */
1.24 pvalchev 89: #if defined(linux) || defined(__OpenBSD__)
1.7 millert 90: # include <sys/ioctl.h>
91: #endif
92:
93: #if NEED_PTEM_H
94: /* they neglected to define struct winsize in termios.h -- it's only
95: in termio.h */
96: #include <sys/stream.h>
97: #include <sys/ptem.h>
98: #endif
99:
1.16 millert 100: #include <curses.h> /* for bool typedef */
1.7 millert 101: #include <dump_entry.h>
1.20 millert 102: #include <transform.h>
1.7 millert 103:
1.23 millert 104: MODULE_ID("$From: tset.c,v 0.49 2001/02/24 23:29:33 tom Exp $")
1.7 millert 105:
106: extern char **environ;
107:
108: #undef CTRL
109: #define CTRL(x) ((x) & 0x1f)
110:
111: const char *_nc_progname = "tset";
112:
113: static TTY mode, oldmode;
114:
1.20 millert 115: static bool isreset = FALSE; /* invoked as reset */
1.16 millert 116: static int terasechar = -1; /* new erase character */
117: static int intrchar = -1; /* new interrupt character */
118: static int tkillchar = -1; /* new kill character */
119: static int tlines, tcolumns; /* window size */
1.7 millert 120:
1.21 millert 121: #define LOWERCASE(c) ((isalpha(CharOf(c)) && isupper(CharOf(c))) ? tolower(CharOf(c)) : (c))
1.7 millert 122:
123: static int
1.16 millert 124: CaselessCmp(const char *a, const char *b)
125: { /* strcasecmp isn't portable */
126: while (*a && *b) {
127: int cmp = LOWERCASE(*a) - LOWERCASE(*b);
128: if (cmp != 0)
129: break;
130: a++, b++;
131: }
132: return LOWERCASE(*a) - LOWERCASE(*b);
1.7 millert 133: }
134:
135: static void
1.16 millert 136: err(const char *fmt,...)
1.7 millert 137: {
1.16 millert 138: va_list ap;
139: va_start(ap, fmt);
140: (void) fprintf(stderr, "tset: ");
141: (void) vfprintf(stderr, fmt, ap);
142: va_end(ap);
143: (void) fprintf(stderr, "\n");
144: exit(EXIT_FAILURE);
145: /* NOTREACHED */
1.7 millert 146: }
147:
148: static void
149: failed(const char *msg)
150: {
1.16 millert 151: (void)fputs("tset: ", stderr);
152: perror(msg);
153: exit(EXIT_FAILURE);
154: /* NOTREACHED */
1.7 millert 155: }
156:
157: static void
158: cat(char *file)
159: {
1.25 mpech 160: int fd, nr;
1.16 millert 161: char buf[BUFSIZ];
1.7 millert 162:
1.16 millert 163: if ((fd = open(file, O_RDONLY, 0)) < 0)
164: failed(file);
1.7 millert 165:
1.16 millert 166: while ((nr = read(fd, buf, sizeof(buf))) > 0)
1.23 millert 167: if (write(STDERR_FILENO, buf, (size_t) nr) == -1)
1.16 millert 168: failed("write to stderr");
169: if (nr != 0)
170: failed(file);
171: (void) close(fd);
1.7 millert 172: }
173:
174: static int
175: outc(int c)
176: {
1.16 millert 177: return putc(c, stderr);
1.7 millert 178: }
179:
180: /* Prompt the user for a terminal type. */
181: static const char *
182: askuser(const char *dflt)
183: {
1.16 millert 184: static char answer[256];
1.7 millert 185:
1.16 millert 186: /* We can get recalled; if so, don't continue uselessly. */
187: if (feof(stdin) || ferror(stdin)) {
188: (void) fprintf(stderr, "\n");
189: exit(EXIT_FAILURE);
190: }
191: for (;;) {
192: if (dflt)
193: (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
194: else
195: (void) fprintf(stderr, "Terminal type? ");
196: (void) fflush(stderr);
197:
1.28 cloder 198: if (fgets(answer, sizeof(answer), stdin) == NULL) {
1.16 millert 199: if (dflt == 0) {
200: (void) fprintf(stderr, "\n");
1.7 millert 201: exit(EXIT_FAILURE);
1.16 millert 202: }
203: return (dflt);
1.7 millert 204: }
205:
1.30 gilles 206: answer[strcspn(answer, "\n")] = '\0';
1.16 millert 207: if (answer[0])
208: return (answer);
209: if (dflt != 0)
210: return (dflt);
211: }
1.7 millert 212: }
213:
214: /**************************************************************************
215: *
216: * Mapping logic begins here
217: *
218: **************************************************************************/
219:
220: /* Baud rate conditionals for mapping. */
221: #define GT 0x01
222: #define EQ 0x02
223: #define LT 0x04
224: #define NOT 0x08
225: #define GE (GT | EQ)
226: #define LE (LT | EQ)
227:
228: typedef struct map {
1.16 millert 229: struct map *next; /* Linked list of maps. */
230: const char *porttype; /* Port type, or "" for any. */
231: const char *type; /* Terminal type to select. */
232: int conditional; /* Baud rate conditionals bitmask. */
1.20 millert 233: int speed; /* Baud rate to compare against. */
1.7 millert 234: } MAP;
235:
236: static MAP *cur, *maplist;
237:
238: typedef struct speeds {
1.16 millert 239: const char *string;
240: int speed;
1.7 millert 241: } SPEEDS;
242:
1.16 millert 243: static const SPEEDS speeds[] =
244: {
245: {"0", B0},
246: {"50", B50},
247: {"75", B75},
248: {"110", B110},
249: {"134", B134},
250: {"134.5", B134},
251: {"150", B150},
252: {"200", B200},
253: {"300", B300},
254: {"600", B600},
255: {"1200", B1200},
256: {"1800", B1800},
257: {"2400", B2400},
258: {"4800", B4800},
259: {"9600", B9600},
1.19 millert 260: /* sgttyb may define up to this point */
261: #ifdef B19200
1.16 millert 262: {"19200", B19200},
1.19 millert 263: #endif
264: #ifdef B38400
1.16 millert 265: {"38400", B38400},
1.19 millert 266: #endif
267: #ifdef B19200
1.16 millert 268: {"19200", B19200},
1.19 millert 269: #endif
270: #ifdef B38400
1.16 millert 271: {"38400", B38400},
1.19 millert 272: #endif
1.7 millert 273: #ifdef B19200
1.16 millert 274: {"19200", B19200},
1.7 millert 275: #else
276: #ifdef EXTA
1.16 millert 277: {"19200", EXTA},
1.7 millert 278: #endif
279: #endif
280: #ifdef B38400
1.16 millert 281: {"38400", B38400},
1.7 millert 282: #else
283: #ifdef EXTB
1.16 millert 284: {"38400", EXTB},
1.7 millert 285: #endif
286: #endif
287: #ifdef B57600
1.16 millert 288: {"57600", B57600},
1.7 millert 289: #endif
290: #ifdef B115200
1.16 millert 291: {"115200", B115200},
1.7 millert 292: #endif
293: #ifdef B230400
1.16 millert 294: {"230400", B230400},
1.7 millert 295: #endif
296: #ifdef B460800
1.16 millert 297: {"460800", B460800},
1.7 millert 298: #endif
1.16 millert 299: {(char *) 0, 0}
1.7 millert 300: };
301:
302: static int
303: tbaudrate(char *rate)
304: {
1.16 millert 305: const SPEEDS *sp;
306: int found = FALSE;
1.7 millert 307:
1.16 millert 308: /* The baudrate number can be preceded by a 'B', which is ignored. */
309: if (*rate == 'B')
310: ++rate;
311:
312: for (sp = speeds; sp->string; ++sp) {
313: if (!CaselessCmp(rate, sp->string)) {
314: found = TRUE;
315: break;
316: }
317: }
318: if (!found)
319: err("unknown baud rate %s", rate);
320: return (sp->speed);
1.7 millert 321: }
322:
323: /*
324: * Syntax for -m:
325: * [port-type][test baudrate]:terminal-type
326: * The baud rate tests are: >, <, @, =, !
327: */
328: static void
329: add_mapping(const char *port, char *arg)
330: {
1.16 millert 331: MAP *mapp;
332: char *copy, *p;
333: const char *termp;
334: char *base = 0;
335:
336: copy = strdup(arg);
337: mapp = malloc(sizeof(MAP));
338: if (copy == 0 || mapp == 0)
339: failed("malloc");
340: mapp->next = 0;
341: if (maplist == 0)
342: cur = maplist = mapp;
343: else {
344: cur->next = mapp;
345: cur = mapp;
346: }
347:
348: mapp->porttype = arg;
349: mapp->conditional = 0;
350:
351: arg = strpbrk(arg, "><@=!:");
352:
353: if (arg == 0) { /* [?]term */
354: mapp->type = mapp->porttype;
355: mapp->porttype = 0;
356: goto done;
357: }
358:
359: if (arg == mapp->porttype) /* [><@=! baud]:term */
360: termp = mapp->porttype = 0;
361: else
362: termp = base = arg;
363:
1.17 millert 364: for (;; ++arg) { /* Optional conditionals. */
1.16 millert 365: switch (*arg) {
366: case '<':
367: if (mapp->conditional & GT)
368: goto badmopt;
369: mapp->conditional |= LT;
370: break;
371: case '>':
372: if (mapp->conditional & LT)
1.7 millert 373: goto badmopt;
1.16 millert 374: mapp->conditional |= GT;
375: break;
376: case '@':
377: case '=': /* Not documented. */
378: mapp->conditional |= EQ;
379: break;
380: case '!':
381: mapp->conditional |= NOT;
382: break;
383: default:
384: goto next;
385: }
1.17 millert 386: }
1.16 millert 387:
1.17 millert 388: next:
389: if (*arg == ':') {
1.16 millert 390: if (mapp->conditional)
391: goto badmopt;
392: ++arg;
393: } else { /* Optional baudrate. */
394: arg = strchr(p = arg, ':');
395: if (arg == 0)
396: goto badmopt;
397: *arg++ = '\0';
398: mapp->speed = tbaudrate(p);
399: }
400:
401: if (arg == (char *) 0) /* Non-optional type. */
402: goto badmopt;
403:
404: mapp->type = arg;
405:
406: /* Terminate porttype, if specified. */
407: if (termp != 0)
408: *base = '\0';
409:
410: /* If a NOT conditional, reverse the test. */
411: if (mapp->conditional & NOT)
412: mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
413:
414: /* If user specified a port with an option flag, set it. */
415: done:if (port) {
416: if (mapp->porttype)
417: badmopt:err("illegal -m option format: %s", copy);
418: mapp->porttype = port;
419: }
1.7 millert 420: #ifdef MAPDEBUG
1.16 millert 421: (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
422: (void) printf("type: %s\n", mapp->type);
423: (void) printf("conditional: ");
424: p = "";
425: if (mapp->conditional & GT) {
426: (void) printf("GT");
427: p = "/";
428: }
429: if (mapp->conditional & EQ) {
430: (void) printf("%sEQ", p);
431: p = "/";
432: }
433: if (mapp->conditional & LT)
434: (void) printf("%sLT", p);
435: (void) printf("\nspeed: %d\n", mapp->speed);
1.7 millert 436: #endif
437: }
438:
439: /*
440: * Return the type of terminal to use for a port of type 'type', as specified
441: * by the first applicable mapping in 'map'. If no mappings apply, return
442: * 'type'.
443: */
444: static const char *
445: mapped(const char *type)
446: {
1.16 millert 447: MAP *mapp;
448: int match;
1.7 millert 449:
1.16 millert 450: for (mapp = maplist; mapp; mapp = mapp->next)
451: if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
452: switch (mapp->conditional) {
453: case 0: /* No test specified. */
454: match = TRUE;
455: break;
456: case EQ:
457: match = (ospeed == mapp->speed);
458: break;
459: case GE:
460: match = (ospeed >= mapp->speed);
461: break;
462: case GT:
463: match = (ospeed > mapp->speed);
464: break;
465: case LE:
466: match = (ospeed <= mapp->speed);
467: break;
468: case LT:
469: match = (ospeed < mapp->speed);
470: break;
471: default:
472: match = FALSE;
473: }
474: if (match)
475: return (mapp->type);
476: }
477: /* No match found; return given type. */
478: return (type);
1.7 millert 479: }
480:
481: /**************************************************************************
482: *
483: * Entry fetching
484: *
485: **************************************************************************/
486:
487: /*
488: * Figure out what kind of terminal we're dealing with, and then read in
489: * its termcap entry.
490: */
491: static const char *
492: get_termcap_entry(char *userarg)
493: {
1.23 millert 494: int errret;
1.16 millert 495: char *p;
496: const char *ttype;
1.7 millert 497: #if HAVE_GETTTYNAM
1.16 millert 498: struct ttyent *t;
1.7 millert 499: #else
1.16 millert 500: FILE *fp;
1.7 millert 501: #endif
1.16 millert 502: char *ttypath;
1.7 millert 503:
1.16 millert 504: if (userarg) {
505: ttype = userarg;
506: goto found;
507: }
508:
509: /* Try the environment. */
510: if ((ttype = getenv("TERM")) != 0)
511: goto map;
512:
513: if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
1.20 millert 514: p = _nc_basename(ttypath);
1.16 millert 515: #if HAVE_GETTTYNAM
516: /*
517: * We have the 4.3BSD library call getttynam(3); that means
518: * there's an /etc/ttys to look up device-to-type mappings in.
519: * Try ttyname(3); check for dialup or other mapping.
520: */
521: if ((t = getttynam(p))) {
522: ttype = t->ty_type;
523: goto map;
1.7 millert 524: }
1.16 millert 525: #else
526: if ((fp = fopen("/etc/ttytype", "r")) != 0
527: || (fp = fopen("/etc/ttys", "r")) != 0) {
528: char buffer[BUFSIZ];
529: char *s, *t, *d;
530:
1.29 ray 531: while (fgets(buffer, sizeof(buffer), fp) != NULL) {
1.16 millert 532: for (s = buffer, t = d = 0; *s; s++) {
1.21 millert 533: if (isspace(CharOf(*s)))
1.16 millert 534: *s = '\0';
535: else if (t == 0)
536: t = s;
537: else if (d == 0 && s != buffer && s[-1] == '\0')
538: d = s;
1.7 millert 539: }
1.16 millert 540: if (t != 0 && d != 0 && !strcmp(d, p)) {
541: ttype = strdup(t);
542: fclose(fp);
543: goto map;
1.7 millert 544: }
1.16 millert 545: }
546: fclose(fp);
547: }
1.7 millert 548: #endif /* HAVE_GETTTYNAM */
1.16 millert 549: }
1.7 millert 550:
1.16 millert 551: /* If still undefined, use "unknown". */
552: ttype = "unknown";
1.7 millert 553:
1.16 millert 554: map:ttype = mapped(ttype);
1.7 millert 555:
1.16 millert 556: /*
557: * If not a path, remove TERMCAP from the environment so we get a
558: * real entry from /etc/termcap. This prevents us from being fooled
559: * by out of date stuff in the environment.
560: */
561: found:if ((p = getenv("TERMCAP")) != 0 && *p != '/') {
562: /* 'unsetenv("TERMCAP")' is not portable.
563: * The 'environ' array is better.
1.7 millert 564: */
1.16 millert 565: int n;
566: for (n = 0; environ[n] != 0; n++) {
567: if (!strncmp("TERMCAP=", environ[n], 8)) {
568: while ((environ[n] = environ[n + 1]) != 0) {
569: n++;
1.7 millert 570: }
1.16 millert 571: break;
572: }
1.7 millert 573: }
1.16 millert 574: }
1.7 millert 575:
1.16 millert 576: /*
577: * ttype now contains a pointer to the type of the terminal.
578: * If the first character is '?', ask the user.
579: */
580: if (ttype[0] == '?') {
581: if (ttype[1] != '\0')
582: ttype = askuser(ttype + 1);
583: else
584: ttype = askuser(0);
585: }
586: /* Find the terminfo entry. If it doesn't exist, ask the user. */
1.23 millert 587: while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
588: != OK) {
1.16 millert 589: if (errret == 0) {
590: (void) fprintf(stderr, "tset: unknown terminal type %s\n",
1.20 millert 591: ttype);
1.16 millert 592: ttype = 0;
593: } else {
594: (void) fprintf(stderr,
1.20 millert 595: "tset: can't initialize terminal type %s (error %d)\n",
596: ttype, errret);
1.16 millert 597: ttype = 0;
1.7 millert 598: }
1.16 millert 599: ttype = askuser(ttype);
600: }
1.7 millert 601: #if BROKEN_LINKER
1.16 millert 602: tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */
1.7 millert 603: #endif
1.16 millert 604: return (ttype);
1.7 millert 605: }
606:
607: /**************************************************************************
608: *
609: * Mode-setting logic
610: *
611: **************************************************************************/
612:
613: /* some BSD systems have these built in, some systems are missing
614: * one or more definitions. The safest solution is to override.
615: */
616: #undef CEOF
617: #undef CERASE
618: #undef CINTR
619: #undef CKILL
620: #undef CLNEXT
621: #undef CRPRNT
622: #undef CQUIT
623: #undef CSTART
624: #undef CSTOP
625: #undef CSUSP
626:
627: /* control-character defaults */
628: #define CEOF CTRL('D')
629: #define CERASE CTRL('H')
630: #define CINTR 127 /* ^? */
631: #define CKILL CTRL('U')
632: #define CLNEXT CTRL('v')
633: #define CRPRNT CTRL('r')
634: #define CQUIT CTRL('\\')
635: #define CSTART CTRL('Q')
636: #define CSTOP CTRL('S')
637: #define CSUSP CTRL('Z')
638:
639: #define CHK(val, dft) ((int)val <= 0 ? dft : val)
640:
1.16 millert 641: static bool set_tabs(void);
1.7 millert 642:
643: /*
644: * Reset the terminal mode bits to a sensible state. Very useful after
645: * a child program dies in raw mode.
646: */
647: static void
648: reset_mode(void)
649: {
650: #ifdef TERMIOS
1.16 millert 651: tcgetattr(STDERR_FILENO, &mode);
1.7 millert 652: #else
1.16 millert 653: stty(STDERR_FILENO, &mode);
1.7 millert 654: #endif
655:
656: #ifdef TERMIOS
657: #if defined(VDISCARD) && defined(CDISCARD)
1.16 millert 658: mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
1.7 millert 659: #endif
1.16 millert 660: mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
661: mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
1.7 millert 662: #if defined(VFLUSH) && defined(CFLUSH)
1.16 millert 663: mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
1.7 millert 664: #endif
1.16 millert 665: mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
666: mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
1.7 millert 667: #if defined(VLNEXT) && defined(CLNEXT)
1.16 millert 668: mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
1.7 millert 669: #endif
1.16 millert 670: mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
1.7 millert 671: #if defined(VREPRINT) && defined(CRPRNT)
1.16 millert 672: mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
1.7 millert 673: #endif
674: #if defined(VSTART) && defined(CSTART)
1.16 millert 675: mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
1.7 millert 676: #endif
677: #if defined(VSTOP) && defined(CSTOP)
1.16 millert 678: mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
1.7 millert 679: #endif
680: #if defined(VSUSP) && defined(CSUSP)
1.16 millert 681: mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
1.7 millert 682: #endif
683: #if defined(VWERASE) && defined(CWERASE)
1.16 millert 684: mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
1.7 millert 685: #endif
686:
1.16 millert 687: mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
1.7 millert 688: #ifdef IUCLC
1.20 millert 689: | IUCLC
1.7 millert 690: #endif
691: #ifdef IXANY
1.20 millert 692: | IXANY
1.7 millert 693: #endif
1.20 millert 694: | IXOFF);
1.7 millert 695:
1.16 millert 696: mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
1.7 millert 697: #ifdef IMAXBEL
1.20 millert 698: | IMAXBEL
1.7 millert 699: #endif
1.16 millert 700: );
1.7 millert 701:
1.16 millert 702: mode.c_oflag &= ~(0
1.7 millert 703: #ifdef OLCUC
1.20 millert 704: | OLCUC
1.7 millert 705: #endif
706: #ifdef OCRNL
1.20 millert 707: | OCRNL
1.7 millert 708: #endif
709: #ifdef ONOCR
1.20 millert 710: | ONOCR
1.7 millert 711: #endif
712: #ifdef ONLRET
1.20 millert 713: | ONLRET
1.7 millert 714: #endif
715: #ifdef OFILL
1.20 millert 716: | OFILL
1.7 millert 717: #endif
718: #ifdef OFDEL
1.20 millert 719: | OFDEL
1.7 millert 720: #endif
721: #ifdef NLDLY
1.20 millert 722: | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
1.7 millert 723: #endif
1.16 millert 724: );
1.7 millert 725:
1.16 millert 726: mode.c_oflag |= (OPOST
1.7 millert 727: #ifdef ONLCR
1.20 millert 728: | ONLCR
1.7 millert 729: #endif
1.16 millert 730: );
1.7 millert 731:
1.16 millert 732: mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
733: mode.c_cflag |= (CS8 | CREAD);
734: mode.c_lflag &= ~(ECHONL | NOFLSH
1.7 millert 735: #ifdef TOSTOP
1.20 millert 736: | TOSTOP
1.7 millert 737: #endif
738: #ifdef ECHOPTR
1.20 millert 739: | ECHOPRT
1.7 millert 740: #endif
741: #ifdef XCASE
1.20 millert 742: | XCASE
1.7 millert 743: #endif
1.16 millert 744: );
1.7 millert 745:
1.16 millert 746: mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
1.7 millert 747: #ifdef ECHOCTL
1.20 millert 748: | ECHOCTL
1.7 millert 749: #endif
750: #ifdef ECHOKE
1.20 millert 751: | ECHOKE
1.7 millert 752: #endif
1.16 millert 753: );
1.7 millert 754: #endif
755:
756: #ifdef TERMIOS
1.16 millert 757: tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1.7 millert 758: #else
1.16 millert 759: stty(STDERR_FILENO, &mode);
1.7 millert 760: #endif
761: }
762:
763: /*
764: * Returns a "good" value for the erase character. This is loosely based on
765: * the BSD4.4 logic.
766: */
1.19 millert 767: #ifdef TERMIOS
1.7 millert 768: static int
769: default_erase(void)
770: {
1.16 millert 771: int result;
1.7 millert 772:
1.16 millert 773: if (over_strike
774: && key_backspace != 0
775: && strlen(key_backspace) == 1)
776: result = key_backspace[0];
777: else
778: result = CERASE;
1.7 millert 779:
1.16 millert 780: return result;
1.7 millert 781: }
1.19 millert 782: #endif
1.7 millert 783:
784: /*
785: * Update the values of the erase, interrupt, and kill characters in 'mode'.
786: *
787: * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
788: * characters if they're unset, or if we specify them as options. This differs
789: * from BSD 4.4 tset, which always sets erase.
790: */
791: static void
792: set_control_chars(void)
793: {
794: #ifdef TERMIOS
1.16 millert 795: if (mode.c_cc[VERASE] == 0 || terasechar >= 0)
796: mode.c_cc[VERASE] = terasechar >= 0 ? terasechar : default_erase();
1.7 millert 797:
1.16 millert 798: if (mode.c_cc[VINTR] == 0 || intrchar >= 0)
799: mode.c_cc[VINTR] = intrchar >= 0 ? intrchar : CINTR;
1.7 millert 800:
1.16 millert 801: if (mode.c_cc[VKILL] == 0 || tkillchar >= 0)
802: mode.c_cc[VKILL] = tkillchar >= 0 ? tkillchar : CKILL;
1.7 millert 803: #endif
804: }
805:
806: /*
807: * Set up various conversions in 'mode', including parity, tabs, returns,
808: * echo, and case, according to the termcap entry. If the program we're
809: * running was named with a leading upper-case character, map external
810: * uppercase to internal lowercase.
811: */
812: static void
813: set_conversions(void)
814: {
815: #ifdef __OBSOLETE__
1.16 millert 816: /*
817: * Conversion logic for some *really* ancient terminal glitches,
818: * not supported in terminfo. Left here for succeeding generations
819: * to marvel at.
820: */
821: if (tgetflag("UC")) {
1.7 millert 822: #ifdef IUCLC
1.16 millert 823: mode.c_iflag |= IUCLC;
824: mode.c_oflag |= OLCUC;
1.7 millert 825: #endif
1.16 millert 826: } else if (tgetflag("LC")) {
1.7 millert 827: #ifdef IUCLC
1.16 millert 828: mode.c_iflag &= ~IUCLC;
829: mode.c_oflag &= ~OLCUC;
1.7 millert 830: #endif
1.16 millert 831: }
832: mode.c_iflag &= ~(PARMRK | INPCK);
833: mode.c_lflag |= ICANON;
834: if (tgetflag("EP")) {
835: mode.c_cflag |= PARENB;
836: mode.c_cflag &= ~PARODD;
837: }
838: if (tgetflag("OP")) {
839: mode.c_cflag |= PARENB;
840: mode.c_cflag |= PARODD;
841: }
1.7 millert 842: #endif /* __OBSOLETE__ */
843:
844: #ifdef TERMIOS
845: #ifdef ONLCR
1.16 millert 846: mode.c_oflag |= ONLCR;
1.7 millert 847: #endif
1.16 millert 848: mode.c_iflag |= ICRNL;
849: mode.c_lflag |= ECHO;
1.7 millert 850: #ifdef OXTABS
1.16 millert 851: mode.c_oflag |= OXTABS;
1.7 millert 852: #endif /* OXTABS */
853:
1.16 millert 854: /* test used to be tgetflag("NL") */
855: if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
856: /* Newline, not linefeed. */
1.7 millert 857: #ifdef ONLCR
1.16 millert 858: mode.c_oflag &= ~ONLCR;
1.7 millert 859: #endif
1.16 millert 860: mode.c_iflag &= ~ICRNL;
861: }
1.7 millert 862: #ifdef __OBSOLETE__
1.16 millert 863: if (tgetflag("HD")) /* Half duplex. */
864: mode.c_lflag &= ~ECHO;
1.7 millert 865: #endif /* __OBSOLETE__ */
866: #ifdef OXTABS
1.16 millert 867: /* test used to be tgetflag("pt") */
868: if (has_hardware_tabs) /* Print tabs. */
869: mode.c_oflag &= ~OXTABS;
1.7 millert 870: #endif /* OXTABS */
1.16 millert 871: mode.c_lflag |= (ECHOE | ECHOK);
1.7 millert 872: #endif
873: }
874:
875: /* Output startup string. */
876: static void
877: set_init(void)
878: {
1.16 millert 879: char *p;
880: bool settle;
1.7 millert 881:
882: #ifdef __OBSOLETE__
1.16 millert 883: if (pad_char != (char *) 0) /* Get/set pad character. */
884: PC = pad_char[0];
1.7 millert 885: #endif /* OBSOLETE */
886:
887: #ifdef TAB3
1.16 millert 888: if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
889: oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
890: tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
891: }
892: #endif
893: settle = set_tabs();
894:
895: if (isreset) {
896: if ((p = reset_1string) != 0) {
897: tputs(p, 0, outc);
898: settle = TRUE;
899: }
900: if ((p = reset_2string) != 0) {
901: tputs(p, 0, outc);
902: settle = TRUE;
903: }
904: /* What about rf, rs3, as per terminfo man page? */
905: /* also might be nice to send rmacs, rmul, rmm */
906: if ((p = reset_file) != 0
907: || (p = init_file) != 0) {
908: cat(p);
909: settle = TRUE;
910: }
911: }
912:
913: if (settle) {
914: (void) putc('\r', stderr);
915: (void) fflush(stderr);
916: (void) napms(1000); /* Settle the terminal. */
917: }
1.7 millert 918: }
919:
920: /*
921: * Set the hardware tabs on the terminal, using the ct (clear all tabs),
922: * st (set one tab) and ch (horizontal cursor addressing) capabilities.
923: * This is done before if and is, so they can patch in case we blow this.
924: * Return TRUE if we set any tab stops, FALSE if not.
925: */
926: static bool
1.27 deraadt 927: set_tabs(void)
1.7 millert 928: {
1.16 millert 929: if (set_tab && clear_all_tabs) {
930: int c;
1.7 millert 931:
1.16 millert 932: (void) putc('\r', stderr); /* Force to left margin. */
933: tputs(clear_all_tabs, 0, outc);
1.7 millert 934:
1.16 millert 935: for (c = 8; c < tcolumns; c += 8) {
936: /* Get to the right column. In BSD tset, this
937: * used to try a bunch of half-clever things
938: * with cup and hpa, for an average saving of
939: * somewhat less than two character times per
940: * tab stop, less that .01 sec at 2400cps. We
941: * lost all this cruft because it seemed to be
942: * introducing some odd bugs.
943: * ----------12345678----------- */
944: (void) fputs(" ", stderr);
945: tputs(set_tab, 0, outc);
946: }
947: putc('\r', stderr);
948: return (TRUE);
949: }
950: return (FALSE);
1.7 millert 951: }
952:
953: /**************************************************************************
954: *
955: * Main sequence
956: *
957: **************************************************************************/
958:
959: /*
960: * Tell the user if a control key has been changed from the default value.
961: */
1.19 millert 962: #ifdef TERMIOS
1.7 millert 963: static void
1.11 millert 964: report(const char *name, int which, unsigned def)
1.7 millert 965: {
1.16 millert 966: unsigned older, newer;
967: char *p;
1.7 millert 968:
1.16 millert 969: newer = mode.c_cc[which];
970: older = oldmode.c_cc[which];
1.7 millert 971:
1.16 millert 972: if (older == newer && older == def)
973: return;
1.7 millert 974:
1.16 millert 975: (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
976:
977: /*
978: * Check 'delete' before 'backspace', since the key_backspace value
979: * is ambiguous.
980: */
981: if (newer == 0177)
982: (void) fprintf(stderr, "delete.\n");
983: else if ((p = key_backspace) != 0
1.20 millert 984: && newer == (unsigned char) p[0]
985: && p[1] == '\0')
1.16 millert 986: (void) fprintf(stderr, "backspace.\n");
987: else if (newer < 040) {
988: newer ^= 0100;
989: (void) fprintf(stderr, "control-%c (^%c).\n", newer, newer);
990: } else
991: (void) fprintf(stderr, "%c.\n", newer);
1.19 millert 992: }
1.7 millert 993: #endif
994:
995: /*
996: * Convert the obsolete argument forms into something that getopt can handle.
997: * This means that -e, -i and -k get default arguments supplied for them.
998: */
999: static void
1000: obsolete(char **argv)
1001: {
1.16 millert 1002: for (; *argv; ++argv) {
1003: char *parm = argv[0];
1.7 millert 1004:
1.16 millert 1005: if (parm[0] == '-' && parm[1] == '\0') {
1006: argv[0] = strdup("-q");
1007: continue;
1008: }
1009:
1010: if ((parm[0] != '-')
1011: || (argv[1] && argv[1][0] != '-')
1012: || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
1013: || (parm[2] != '\0'))
1014: continue;
1015: switch (argv[0][1]) {
1016: case 'e':
1017: argv[0] = strdup("-e^H");
1018: break;
1019: case 'i':
1020: argv[0] = strdup("-i^C");
1021: break;
1022: case 'k':
1023: argv[0] = strdup("-k^U");
1024: break;
1.7 millert 1025: }
1.16 millert 1026: }
1.7 millert 1027: }
1028:
1029: static void
1.16 millert 1030: usage(const char *pname)
1.7 millert 1031: {
1.16 millert 1032: (void) fprintf(stderr,
1.20 millert 1033: "usage: %s [-IQVrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n", pname);
1.16 millert 1034: exit(EXIT_FAILURE);
1.7 millert 1035: }
1036:
1.16 millert 1037: static char
1038: arg_to_char(void)
1.7 millert 1039: {
1.16 millert 1040: return (optarg[0] == '^' && optarg[1] != '\0')
1041: ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
1042: : optarg[0];
1.7 millert 1043: }
1.1 deraadt 1044:
1045: int
1.7 millert 1046: main(int argc, char **argv)
1.1 deraadt 1047: {
1.7 millert 1048: #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
1.16 millert 1049: struct winsize win;
1.1 deraadt 1050: #endif
1.16 millert 1051: int ch, noinit, noset, quiet, Sflag, sflag, showterm;
1052: const char *p;
1053: const char *ttype;
1.7 millert 1054: #ifdef __OpenBSD__
1.16 millert 1055: char tcapbuf[1024], *t;
1056: int tcgetent(char *, const char *);
1057: void wrtermcap (char *);
1058: #endif /* __OpenBSD__ */
1.1 deraadt 1059:
1.19 millert 1060: if (GET_TTY(STDERR_FILENO, &mode) < 0)
1.16 millert 1061: failed("standard error");
1062: oldmode = mode;
1.19 millert 1063: #ifdef TERMIOS
1.16 millert 1064: ospeed = cfgetospeed(&mode);
1.7 millert 1065: #else
1.16 millert 1066: ospeed = mode.sg_ospeed;
1.7 millert 1067: #endif
1.1 deraadt 1068:
1.20 millert 1069: p = _nc_basename(*argv);
1070: if (!strcmp(p, PROG_RESET)) {
1071: isreset = TRUE;
1.16 millert 1072: reset_mode();
1073: }
1074:
1075: obsolete(argv);
1076: noinit = noset = quiet = Sflag = sflag = showterm = 0;
1.20 millert 1077: while ((ch = getopt(argc, argv, "a:d:e:Ii:k:m:np:qQSrsV")) != -1) {
1.16 millert 1078: switch (ch) {
1079: case 'q': /* display term only */
1080: noset = 1;
1081: break;
1082: case 'a': /* OBSOLETE: map identifier to type */
1083: add_mapping("arpanet", optarg);
1084: break;
1085: case 'd': /* OBSOLETE: map identifier to type */
1086: add_mapping("dialup", optarg);
1087: break;
1088: case 'e': /* erase character */
1089: terasechar = arg_to_char();
1090: break;
1091: case 'I': /* no initialization strings */
1092: noinit = 1;
1093: break;
1094: case 'i': /* interrupt character */
1095: intrchar = arg_to_char();
1096: break;
1097: case 'k': /* kill character */
1098: tkillchar = arg_to_char();
1099: break;
1100: case 'm': /* map identifier to type */
1101: add_mapping(0, optarg);
1102: break;
1103: case 'n': /* OBSOLETE: set new tty driver */
1104: break;
1105: case 'p': /* OBSOLETE: map identifier to type */
1106: add_mapping("plugboard", optarg);
1107: break;
1108: case 'Q': /* don't output control key settings */
1109: quiet = 1;
1110: break;
1111: case 'S': /* OBSOLETE: output TERM & TERMCAP */
1112: Sflag = 1;
1113: break;
1114: case 'r': /* display term on stderr */
1115: showterm = 1;
1116: break;
1117: case 's': /* output TERM set command */
1118: sflag = 1;
1119: break;
1.20 millert 1120: case 'V':
1121: puts(curses_version());
1122: return EXIT_SUCCESS;
1.16 millert 1123: case '?':
1124: default:
1125: usage(*argv);
1126: }
1127: }
1128: argc -= optind;
1129: argv += optind;
1.1 deraadt 1130:
1.16 millert 1131: if (argc > 1)
1132: usage(*argv);
1.1 deraadt 1133:
1.16 millert 1134: ttype = get_termcap_entry(*argv);
1.7 millert 1135: #ifdef __OpenBSD__
1.16 millert 1136: if (tcgetent(tcapbuf, ttype) < 0)
1137: tcapbuf[0] = '\0';
1138: #endif /* __OpenBSD__ */
1.1 deraadt 1139:
1.16 millert 1140: if (!noset) {
1141: tcolumns = columns;
1142: tlines = lines;
1.1 deraadt 1143:
1.7 millert 1144: #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
1.16 millert 1145: /* Set window size */
1146: (void) ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
1147: if (win.ws_row == 0 && win.ws_col == 0 &&
1148: tlines > 0 && tcolumns > 0) {
1149: win.ws_row = tlines;
1150: win.ws_col = tcolumns;
1151: (void) ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
1152: }
1.1 deraadt 1153: #endif
1.16 millert 1154: set_control_chars();
1155: set_conversions();
1.1 deraadt 1156:
1.16 millert 1157: if (!noinit)
1158: set_init();
1.1 deraadt 1159:
1.16 millert 1160: /* Set the modes if they've changed. */
1.17 millert 1161: if (memcmp(&mode, &oldmode, sizeof(mode))) {
1.7 millert 1162: #ifdef TERMIOS
1.16 millert 1163: tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1.7 millert 1164: #else
1.16 millert 1165: stty(STDERR_FILENO, &mode);
1.7 millert 1166: #endif
1.17 millert 1167: }
1.16 millert 1168: }
1.1 deraadt 1169:
1.16 millert 1170: /* Get the terminal name from the entry. */
1171: ttype = _nc_first_name(cur_term->type.term_names);
1.1 deraadt 1172:
1.16 millert 1173: if (noset)
1174: (void) printf("%s\n", ttype);
1175: else {
1176: if (showterm)
1177: (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
1178: /*
1179: * If erase, kill and interrupt characters could have been
1180: * modified and not -Q, display the changes.
1181: */
1.19 millert 1182: #ifdef TERMIOS
1.16 millert 1183: if (!quiet) {
1184: report("Erase", VERASE, CERASE);
1185: report("Kill", VKILL, CINTR);
1186: report("Interrupt", VINTR, CKILL);
1.1 deraadt 1187: }
1.19 millert 1188: #endif
1.16 millert 1189: }
1.1 deraadt 1190:
1.7 millert 1191: #ifdef __OpenBSD__
1.16 millert 1192: if (Sflag) {
1193: if (tcapbuf[0]) {
1194: (void) printf("%s ", ttype);
1195: wrtermcap(tcapbuf);
1196: } else
1197: err("No termcap entry for %s, only terminfo.", ttype);
1198: }
1199: #else
1200: if (Sflag)
1201: err("The -S option is not supported under terminfo.");
1.7 millert 1202: #endif /* __OpenBSD__ */
1.1 deraadt 1203:
1.7 millert 1204: #ifdef __OpenBSD__
1.16 millert 1205: if (sflag) {
1206: /*
1207: * Figure out what shell we're using. A hack, we look for an
1208: * environmental variable SHELL ending in "csh".
1209: */
1210: if ((p = getenv("SHELL")) != 0 && !strcmp(p + strlen(p) - 3, "csh")) {
1211: if (tcapbuf[0])
1212: p = "set noglob histchars="";\nsetenv TERM %s;\nsetenv TERMCAP ";
1213: else
1214: p = "set noglob histchars="";\nsetenv TERM %s;\n";
1215: t = "unset noglob histchars;\n";
1216: } else {
1217: if (tcapbuf) {
1218: p = "TERM=%s;\nTERMCAP=";
1219: t = "export TERMCAP TERM;\n";
1220: } else {
1221: if (tcapbuf) {
1222: p = "TERM=%s;\nTERMCAP=";
1223: t = "export TERMCAP TERM;\n";
1.1 deraadt 1224: } else {
1.16 millert 1225: p = "TERM=%s;\n";
1226: t = "export TERMCAP;\n";
1.1 deraadt 1227: }
1.16 millert 1228: }
1229: }
1230: (void) printf(p, ttype);
1231: if (tcapbuf[0]) {
1232: putchar('\'');
1233: wrtermcap(tcapbuf);
1234: fputs("';\n", stdout);
1.1 deraadt 1235: }
1.18 deraadt 1236: (void)fputs(t, stdout);
1.16 millert 1237: }
1.7 millert 1238: #else
1.16 millert 1239: if (sflag) {
1240: /*
1241: * Figure out what shell we're using. A hack, we look for an
1242: * environmental variable SHELL ending in "csh".
1243: */
1244: if ((p = getenv("SHELL")) != 0
1245: && !strcmp(p + strlen(p) - 3, "csh"))
1246: p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
1247: else
1248: p = "TERM=%s;\n";
1249: (void) printf(p, ttype);
1250: }
1.7 millert 1251: #endif /* __OpenBSD__ */
1.1 deraadt 1252:
1.16 millert 1253: return EXIT_SUCCESS;
1.1 deraadt 1254: }
1255:
1.7 millert 1256: /* tset.c ends here */