X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Ftset.c;h=7fd916346aee2346e6291579358d1395d0814615;hp=1df3fd64986923cdb79957030eefbd81dd91b315;hb=d30f99439fcc8d4bb4c38e5c4afb4f6555fc6ad4;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/progs/tset.c b/progs/tset.c index 1df3fd64..7fd91634 100644 --- a/progs/tset.c +++ b/progs/tset.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998 Free Software Foundation, Inc. * + * Copyright 2020,2021 Thomas E. Dickey * + * Copyright 1998-2016,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -29,8 +30,24 @@ /**************************************************************************** * Author: Zeyd M. Ben-Halim 1992,1995 * * and: Eric S. Raymond * + * and: Thomas E. Dickey 1996-on * ****************************************************************************/ +/* + * Notes: + * The initial adaptation from 4.4BSD Lite sources in September 1995 used 686 + * lines from that version, and made changes/additions for 150 lines. There + * was no reformatting, so with/without ignoring whitespace, the amount of + * change is the same. + * + * Comparing with current (2009) source, excluding this comment: + * a) 209 lines match identically to the 4.4BSD Lite sources, with 771 lines + * changed/added. + * a) Ignoring whitespace, the current version still uses 516 lines from the + * 4.4BSD Lite sources, with 402 lines changed/added. + * + * Raymond's original comment on this follows... + */ /* * tset.c - terminal initialization utility @@ -52,11 +69,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -73,13 +86,10 @@ * SUCH DAMAGE. */ -#define __INTERNAL_CAPS_VISIBLE /* we need to see has_hardware_tabs */ -#include - -#include -#include +#include #include -#include +#include +#include #if HAVE_GETTTYNAM && HAVE_TTYENT_H #include @@ -88,143 +98,108 @@ char *ttyname(int fd); #endif -/* this is just to stifle a missing-prototype warning */ -#ifdef linux -# include -#endif - -#if NEED_PTEM_H -/* they neglected to define struct winsize in termios.h -- it's only - in termio.h */ -#include -#include -#endif - -#include /* for bool typedef */ -#include - -MODULE_ID("$Id: tset.c,v 0.31 1998/02/11 12:14:02 tom Exp $") +MODULE_ID("$Id: tset.c,v 1.128 2021/04/03 23:03:48 tom Exp $") +#ifndef environ extern char **environ; - -#undef CTRL -#define CTRL(x) ((x) & 0x1f) +#endif const char *_nc_progname = "tset"; -static TTY mode, oldmode; - -static int terasechar = -1; /* new erase character */ -static int intrchar = -1; /* new interrupt character */ -static int isreset; /* invoked as reset */ -static int tkillchar = -1; /* new kill character */ -static int tlines, tcolumns; /* window size */ +#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c)) -#define LOWERCASE(c) ((isalpha(c) && isupper(c)) ? tolower(c) : (c)) +static GCC_NORETURN void exit_error(void); static int -CaselessCmp(const char *a, const char *b) /* strcasecmp isn't portable */ -{ - while (*a && *b) { - int cmp = LOWERCASE(*a) - LOWERCASE(*b); - if (cmp != 0) - break; - a++, b++; - } - return LOWERCASE(*a) - LOWERCASE(*b); +CaselessCmp(const char *a, const char *b) +{ /* strcasecmp isn't portable */ + while (*a && *b) { + int cmp = LOWERCASE(*a) - LOWERCASE(*b); + if (cmp != 0) + break; + a++, b++; + } + return LOWERCASE(*a) - LOWERCASE(*b); } -#if !HAVE_STRDUP -static char *strdup (char *s) +static GCC_NORETURN void +exit_error(void) { - char *p; - - p = malloc(strlen(s)+1); - if (p) - strcpy(p,s); - return(p); + restore_tty_settings(); + (void) fprintf(stderr, "\n"); + fflush(stderr); + ExitProgram(EXIT_FAILURE); + /* NOTREACHED */ } -#endif /* not HAVE_STRDUP */ -static void +static GCC_NORETURN void err(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - (void)fprintf(stderr, "tset: "); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, "\n"); - exit(EXIT_FAILURE); - /* NOTREACHED */ + va_list ap; + va_start(ap, fmt); + (void) fprintf(stderr, "%s: ", _nc_progname); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + exit_error(); + /* NOTREACHED */ } -static void +static GCC_NORETURN void failed(const char *msg) { - char temp[BUFSIZ]; - perror(strcat(strcpy(temp, "tset: "), msg)); - exit(EXIT_FAILURE); - /* NOTREACHED */ -} - -static void -cat(char *file) -{ - register int fd, nr, nw; - char buf[BUFSIZ]; - - if ((fd = open(file, O_RDONLY, 0)) < 0) - failed(file); - - while ((nr = read(fd, buf, sizeof(buf))) > 0) - if ((nw = write(STDERR_FILENO, buf, (size_t)nr)) == -1) - failed("write to stderr"); - if (nr != 0) - failed(file); - (void)close(fd); -} - -static int -outc(int c) -{ - return putc(c, stderr); + char temp[BUFSIZ]; + size_t len = strlen(_nc_progname) + 2; + + if ((int) len < (int) sizeof(temp) - 12) { + _nc_STRCPY(temp, _nc_progname, sizeof(temp)); + _nc_STRCAT(temp, ": ", sizeof(temp)); + } else { + _nc_STRCPY(temp, "tset: ", sizeof(temp)); + } + _nc_STRNCAT(temp, msg, sizeof(temp), sizeof(temp) - strlen(temp) - 2); + perror(temp); + exit_error(); + /* NOTREACHED */ } /* Prompt the user for a terminal type. */ static const char * askuser(const char *dflt) { - static char answer[256]; + static char answer[256]; + + /* We can get recalled; if so, don't continue uselessly. */ + clearerr(stdin); + if (feof(stdin) || ferror(stdin)) { + (void) fprintf(stderr, "\n"); + exit_error(); + /* NOTREACHED */ + } + + for (;;) { char *p; - /* We can get recalled; if so, don't continue uselessly. */ - if (feof(stdin) || ferror(stdin)) { - (void)fprintf(stderr, "\n"); - exit(EXIT_FAILURE); + if (dflt) + (void) fprintf(stderr, "Terminal type? [%s] ", dflt); + else + (void) fprintf(stderr, "Terminal type? "); + (void) fflush(stderr); + + if (fgets(answer, sizeof(answer), stdin) == 0) { + if (dflt == 0) { + exit_error(); + /* NOTREACHED */ + } + return (dflt); } - for (;;) { - if (dflt) - (void)fprintf(stderr, "Terminal type? [%s] ", dflt); - else - (void)fprintf(stderr, "Terminal type? "); - (void)fflush(stderr); - - if (fgets(answer, sizeof(answer), stdin) == 0) { - if (dflt == 0) { - (void)fprintf(stderr, "\n"); - exit(EXIT_FAILURE); - } - return (dflt); - } - if ((p = strchr(answer, '\n')) != 0) - *p = '\0'; - if (answer[0]) - return (answer); - if (dflt != 0) - return (dflt); - } + if ((p = strchr(answer, '\n')) != 0) + *p = '\0'; + if (answer[0]) + return (answer); + if (dflt != 0) + return (dflt); + } } /************************************************************************** @@ -242,88 +217,153 @@ askuser(const char *dflt) #define LE (LT | EQ) typedef struct map { - struct map *next; /* Linked list of maps. */ - const char *porttype; /* Port type, or "" for any. */ - const char *type; /* Terminal type to select. */ - int conditional; /* Baud rate conditionals bitmask. */ - int speed; /* Baud rate to compare against. */ + struct map *next; /* Linked list of maps. */ + const char *porttype; /* Port type, or "" for any. */ + const char *type; /* Terminal type to select. */ + int conditional; /* Baud rate conditionals bitmask. */ + int speed; /* Baud rate to compare against. */ } MAP; static MAP *cur, *maplist; +#define DATA(name,value) { { name }, value } + typedef struct speeds { - const char *string; - int speed; + const char string[8]; + int speed; } SPEEDS; -static const SPEEDS speeds[] = { - { "0", B0 }, - { "50", B50 }, - { "75", B75 }, - { "110", B110 }, - { "134", B134 }, - { "134.5", B134 }, - { "150", B150 }, - { "200", B200 }, - { "300", B300 }, - { "600", B600 }, - { "1200", B1200 }, - { "1800", B1800 }, - { "2400", B2400 }, - { "4800", B4800 }, - { "9600", B9600 }, - { "19200", B19200 }, - { "38400", B38400 }, - { "19200", B19200 }, - { "38400", B38400 }, +#if defined(EXP_WIN32_DRIVER) +static const SPEEDS speeds[] = +{ + {"0", 0} +}; +#else +static const SPEEDS speeds[] = +{ + DATA("0", B0), + DATA("50", B50), + DATA("75", B75), + DATA("110", B110), + DATA("134", B134), + DATA("134.5", B134), + DATA("150", B150), + DATA("200", B200), + DATA("300", B300), + DATA("600", B600), + DATA("1200", B1200), + DATA("1800", B1800), + DATA("2400", B2400), + DATA("4800", B4800), + DATA("9600", B9600), + /* sgttyb may define up to this point */ +#ifdef B19200 + DATA("19200", B19200), +#endif +#ifdef B38400 + DATA("38400", B38400), +#endif +#ifdef B19200 + DATA("19200", B19200), +#endif +#ifdef B38400 + DATA("38400", B38400), +#endif #ifdef B19200 - { "19200", B19200 }, + DATA("19200", B19200), #else #ifdef EXTA - { "19200", EXTA }, + DATA("19200", EXTA), #endif #endif #ifdef B38400 - { "38400", B38400 }, + DATA("38400", B38400), #else #ifdef EXTB - { "38400", EXTB }, + DATA("38400", EXTB), #endif #endif #ifdef B57600 - { "57600", B57600 }, + DATA("57600", B57600), +#endif +#ifdef B76800 + DATA("76800", B57600), #endif #ifdef B115200 - { "115200", B115200 }, + DATA("115200", B115200), +#endif +#ifdef B153600 + DATA("153600", B153600), #endif #ifdef B230400 - { "230400", B230400 }, + DATA("230400", B230400), +#endif +#ifdef B307200 + DATA("307200", B307200), #endif #ifdef B460800 - { "460800", B460800 }, + DATA("460800", B460800), +#endif +#ifdef B500000 + DATA("500000", B500000), +#endif +#ifdef B576000 + DATA("576000", B576000), +#endif +#ifdef B921600 + DATA("921600", B921600), +#endif +#ifdef B1000000 + DATA("1000000", B1000000), +#endif +#ifdef B1152000 + DATA("1152000", B1152000), +#endif +#ifdef B1500000 + DATA("1500000", B1500000), +#endif +#ifdef B2000000 + DATA("2000000", B2000000), +#endif +#ifdef B2500000 + DATA("2500000", B2500000), +#endif +#ifdef B3000000 + DATA("3000000", B3000000), +#endif +#ifdef B3500000 + DATA("3500000", B3500000), +#endif +#ifdef B4000000 + DATA("4000000", B4000000), #endif - { (char *)0, 0 } }; +#undef DATA +#endif static int tbaudrate(char *rate) { - const SPEEDS *sp; - int found = FALSE; + const SPEEDS *sp = 0; + size_t n; - /* The baudrate number can be preceded by a 'B', which is ignored. */ - if (*rate == 'B') - ++rate; + /* The baudrate number can be preceded by a 'B', which is ignored. */ + if (*rate == 'B') + ++rate; - for (sp = speeds; sp->string; ++sp) { - if (!CaselessCmp(rate, sp->string)) { - found = TRUE; - break; - } + for (n = 0; n < SIZEOF(speeds); ++n) { + if (n > 0 && (speeds[n].speed <= speeds[n - 1].speed)) { + /* if the speeds are not increasing, likely a numeric overflow */ + break; } - if (!found) - err("unknown baud rate %s", rate); - return (sp->speed); + if (!CaselessCmp(rate, speeds[n].string)) { + sp = speeds + n; + break; + } + } + if (sp == 0) + err("unknown baud rate %s", rate); + return (sp->speed); } /* @@ -334,110 +374,116 @@ tbaudrate(char *rate) static void add_mapping(const char *port, char *arg) { - MAP *mapp; - char *copy, *p; - const char *termp; - char *base = 0; - - copy = strdup(arg); - mapp = malloc((u_int)sizeof(MAP)); - if (copy == 0 || mapp == 0) - failed("malloc"); - mapp->next = 0; - if (maplist == 0) - cur = maplist = mapp; - else { - cur->next = mapp; - cur = mapp; - } - - mapp->porttype = arg; - mapp->conditional = 0; - - arg = strpbrk(arg, "><@=!:"); - - if (arg == 0) { /* [?]term */ - mapp->type = mapp->porttype; - mapp->porttype = 0; - goto done; - } - - if (arg == mapp->porttype) /* [><@=! baud]:term */ - termp = mapp->porttype = 0; - else - termp = base = arg; - - for (;; ++arg) /* Optional conditionals. */ - switch(*arg) { - case '<': - if (mapp->conditional & GT) - goto badmopt; - mapp->conditional |= LT; - break; - case '>': - if (mapp->conditional & LT) - goto badmopt; - mapp->conditional |= GT; - break; - case '@': - case '=': /* Not documented. */ - mapp->conditional |= EQ; - break; - case '!': - mapp->conditional |= NOT; - break; - default: - goto next; - } - -next: if (*arg == ':') { - if (mapp->conditional) - goto badmopt; - ++arg; - } else { /* Optional baudrate. */ - arg = strchr(p = arg, ':'); - if (arg == 0) - goto badmopt; - *arg++ = '\0'; - mapp->speed = tbaudrate(p); - } - - if (arg == (char *)0) /* Non-optional type. */ + MAP *mapp; + char *copy, *p; + const char *termp; + char *base = 0; + + copy = strdup(arg); + mapp = typeMalloc(MAP, 1); + if (copy == 0 || mapp == 0) + failed("malloc"); + + assert(copy != 0); + assert(mapp != 0); + + mapp->next = 0; + if (maplist == 0) + cur = maplist = mapp; + else { + cur->next = mapp; + cur = mapp; + } + + mapp->porttype = arg; + mapp->conditional = 0; + + arg = strpbrk(arg, "><@=!:"); + + if (arg == 0) { /* [?]term */ + mapp->type = mapp->porttype; + mapp->porttype = 0; + goto done; + } + + if (arg == mapp->porttype) /* [><@=! baud]:term */ + termp = mapp->porttype = 0; + else + termp = base = arg; + + for (;; ++arg) { /* Optional conditionals. */ + switch (*arg) { + case '<': + if (mapp->conditional & GT) goto badmopt; - - mapp->type = arg; - - /* Terminate porttype, if specified. */ - if (termp != 0) - *base = '\0'; - - /* If a NOT conditional, reverse the test. */ - if (mapp->conditional & NOT) - mapp->conditional = ~mapp->conditional & (EQ | GT | LT); - - /* If user specified a port with an option flag, set it. */ -done: if (port) { - if (mapp->porttype) -badmopt: err("illegal -m option format: %s", copy); - mapp->porttype = port; - } - -#ifdef MAPDEBUG - (void)printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY"); - (void)printf("type: %s\n", mapp->type); - (void)printf("conditional: "); - p = ""; - if (mapp->conditional & GT) { - (void)printf("GT"); - p = "/"; + mapp->conditional |= LT; + break; + case '>': + if (mapp->conditional & LT) + goto badmopt; + mapp->conditional |= GT; + break; + case '@': + case '=': /* Not documented. */ + mapp->conditional |= EQ; + break; + case '!': + mapp->conditional |= NOT; + break; + default: + goto next; } - if (mapp->conditional & EQ) { - (void)printf("%sEQ", p); - p = "/"; + } + + next: + if (*arg == ':') { + if (mapp->conditional) + goto badmopt; + ++arg; + } else { /* Optional baudrate. */ + arg = strchr(p = arg, ':'); + if (arg == 0) + goto badmopt; + *arg++ = '\0'; + mapp->speed = tbaudrate(p); + } + + mapp->type = arg; + + /* Terminate porttype, if specified. */ + if (termp != 0) + *base = '\0'; + + /* If a NOT conditional, reverse the test. */ + if (mapp->conditional & NOT) + mapp->conditional = ~mapp->conditional & (EQ | GT | LT); + + /* If user specified a port with an option flag, set it. */ + done: + if (port) { + if (mapp->porttype) { + badmopt: + err("illegal -m option format: %s", copy); } - if (mapp->conditional & LT) - (void)printf("%sLT", p); - (void)printf("\nspeed: %d\n", mapp->speed); + mapp->porttype = port; + } + free(copy); +#ifdef MAPDEBUG + (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY"); + (void) printf("type: %s\n", mapp->type); + (void) printf("conditional: "); + p = ""; + if (mapp->conditional & GT) { + (void) printf("GT"); + p = "/"; + } + if (mapp->conditional & EQ) { + (void) printf("%sEQ", p); + p = "/"; + } + if (mapp->conditional & LT) + (void) printf("%sLT", p); + (void) printf("\nspeed: %d\n", mapp->speed); #endif } @@ -449,38 +495,38 @@ badmopt: err("illegal -m option format: %s", copy); static const char * mapped(const char *type) { - MAP *mapp; - int match; - - for (mapp = maplist; mapp; mapp = mapp->next) - if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) { - switch (mapp->conditional) { - case 0: /* No test specified. */ - match = TRUE; - break; - case EQ: - match = (ospeed == mapp->speed); - break; - case GE: - match = (ospeed >= mapp->speed); - break; - case GT: - match = (ospeed > mapp->speed); - break; - case LE: - match = (ospeed <= mapp->speed); - break; - case LT: - match = (ospeed < mapp->speed); - break; - default: - match = FALSE; - } - if (match) - return (mapp->type); - } - /* No match found; return given type. */ - return (type); + MAP *mapp; + int match; + + for (mapp = maplist; mapp; mapp = mapp->next) + if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) { + switch (mapp->conditional) { + case 0: /* No test specified. */ + match = TRUE; + break; + case EQ: + match = ((int) ospeed == mapp->speed); + break; + case GE: + match = ((int) ospeed >= mapp->speed); + break; + case GT: + match = ((int) ospeed > mapp->speed); + break; + case LE: + match = ((int) ospeed <= mapp->speed); + break; + case LT: + match = ((int) ospeed < mapp->speed); + break; + default: + match = FALSE; + } + if (match) + return (mapp->type); + } + /* No match found; return given type. */ + return (type); } /************************************************************************** @@ -494,715 +540,370 @@ mapped(const char *type) * its termcap entry. */ static const char * -get_termcap_entry(char *userarg) +get_termcap_entry(int fd, char *userarg) { - int rval, errret; - char *p; - const char *ttype; + int errret; + char *p; + const char *ttype; #if HAVE_GETTTYNAM - struct ttyent *t; + struct ttyent *t; #else - FILE *fp; + FILE *fp; #endif - char *ttypath; - - if (userarg) { - ttype = userarg; - goto found; - } + char *ttypath; - /* Try the environment. */ - if ((ttype = getenv("TERM")) != 0) - goto map; + (void) fd; - if ((ttypath = ttyname(STDERR_FILENO)) != 0) { - if ((p = strrchr(ttypath, '/')) != 0) - ++p; - else - p = ttypath; -#if HAVE_GETTTYNAM - /* - * We have the 4.3BSD library call getttynam(3); that means - * there's an /etc/ttys to look up device-to-type mappings in. - * Try ttyname(3); check for dialup or other mapping. - */ - if ((t = getttynam(p))) { - ttype = t->ty_type; - goto map; - } -#else - if ((fp = fopen("/etc/ttytype", "r")) != 0 - || (fp = fopen("/etc/ttys", "r")) != 0) { - char buffer[BUFSIZ]; - char *s, *t, *d; - - while (fgets(buffer, sizeof(buffer)-1, fp) != 0) { - for (s = buffer, t = d = 0; *s; s++) { - if (isspace(*s)) - *s = '\0'; - else if (t == 0) - t = s; - else if (d == 0 && s != buffer && s[-1] == '\0') - d = s; - } - if (t != 0 && d != 0 && !strcmp(d,p)) { - ttype = strdup(t); - fclose(fp); - goto map; - } - } - fclose(fp); - } -#endif /* HAVE_GETTTYNAM */ - } + if (userarg) { + ttype = userarg; + goto found; + } - /* If still undefined, use "unknown". */ - ttype = "unknown"; - -map: ttype = mapped(ttype); + /* Try the environment. */ + if ((ttype = getenv("TERM")) != 0) + goto map; + if ((ttypath = ttyname(fd)) != 0) { + p = _nc_basename(ttypath); +#if HAVE_GETTTYNAM /* - * If not a path, remove TERMCAP from the environment so we get a - * real entry from /etc/termcap. This prevents us from being fooled - * by out of date stuff in the environment. + * We have the 4.3BSD library call getttynam(3); that means + * there's an /etc/ttys to look up device-to-type mappings in. + * Try ttyname(3); check for dialup or other mapping. */ -found: if ((p = getenv("TERMCAP")) != 0 && *p != '/') { - /* 'unsetenv("TERMCAP")' is not portable. - * The 'environ' array is better. - */ - int n; - for (n = 0; environ[n] != 0; n++) { - if (!strncmp("TERMCAP=", environ[n], 8)) { - while ((environ[n] = environ[n+1]) != 0) { - n++; - } - break; - } + if ((t = getttynam(p))) { + ttype = t->ty_type; + goto map; + } +#else + if ((fp = fopen("/etc/ttytype", "r")) != 0 + || (fp = fopen("/etc/ttys", "r")) != 0) { + char buffer[BUFSIZ]; + char *s, *t, *d; + + while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) { + for (s = buffer, t = d = 0; *s; s++) { + if (isspace(UChar(*s))) + *s = '\0'; + else if (t == 0) + t = s; + else if (d == 0 && s != buffer && s[-1] == '\0') + d = s; } + if (t != 0 && d != 0 && !strcmp(d, p)) { + ttype = strdup(t); + fclose(fp); + goto map; + } + } + fclose(fp); } - - /* - * ttype now contains a pointer to the type of the terminal. - * If the first character is '?', ask the user. +#endif /* HAVE_GETTTYNAM */ + } + + /* If still undefined, use "unknown". */ + ttype = "unknown"; + + map:ttype = mapped(ttype); + + /* + * If not a path, remove TERMCAP from the environment so we get a + * real entry from /etc/termcap. This prevents us from being fooled + * by out of date stuff in the environment. + */ + found: + if ((p = getenv("TERMCAP")) != 0 && !_nc_is_abs_path(p)) { + /* 'unsetenv("TERMCAP")' is not portable. + * The 'environ' array is better. */ - if (ttype[0] == '?') - if (ttype[1] != '\0') - ttype = askuser(ttype + 1); - else - ttype = askuser(0); - - /* Find the terminfo entry. If it doesn't exist, ask the user. */ - while ((rval = setupterm(ttype, STDOUT_FILENO, &errret)) != OK) { - if (errret == 0) { - (void)fprintf(stderr, "tset: unknown terminal type %s\n", - ttype); - ttype = 0; + int n; + for (n = 0; environ[n] != 0; n++) { + if (!strncmp("TERMCAP=", environ[n], (size_t) 8)) { + while ((environ[n] = environ[n + 1]) != 0) { + n++; } - else { - (void)fprintf(stderr, "tset: can't initialize terminal\ - type %s (error %d)\n", ttype, errret); - ttype = 0; - } - ttype = askuser(ttype); + break; + } + } + } + + /* + * ttype now contains a pointer to the type of the terminal. + * If the first character is '?', ask the user. + */ + if (ttype[0] == '?') { + if (ttype[1] != '\0') + ttype = askuser(ttype + 1); + else + ttype = askuser(0); + } + /* Find the terminfo entry. If it doesn't exist, ask the user. */ + while (setupterm((NCURSES_CONST char *) ttype, fd, &errret) + != OK) { + if (errret == 0) { + (void) fprintf(stderr, "%s: unknown terminal type %s\n", + _nc_progname, ttype); + ttype = 0; + } else { + (void) fprintf(stderr, + "%s: can't initialize terminal type %s (error %d)\n", + _nc_progname, ttype, errret); + ttype = 0; } + ttype = askuser(ttype); + } #if BROKEN_LINKER - tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */ + tgetflag("am"); /* force lib_termcap.o to be linked for 'ospeed' */ #endif - return (ttype); + return (ttype); } /************************************************************************** * - * Mode-setting logic + * Main sequence * **************************************************************************/ -/* some BSD systems have these built in, some systems are missing - * one or more definitions. The safest solution is to override. - */ -#undef CEOF -#undef CERASE -#undef CINTR -#undef CKILL -#undef CLNEXT -#undef CRPRNT -#undef CQUIT -#undef CSTART -#undef CSTOP -#undef CSUSP - -/* control-character defaults */ -#define CEOF CTRL('D') -#define CERASE CTRL('H') -#define CINTR 127 /* ^? */ -#define CKILL CTRL('U') -#define CLNEXT CTRL('v') -#define CRPRNT CTRL('r') -#define CQUIT CTRL('\\') -#define CSTART CTRL('Q') -#define CSTOP CTRL('S') -#define CSUSP CTRL('Z') - -#define CHK(val, dft) ((int)val <= 0 ? dft : val) - -static bool set_tabs (void); - -/* - * Reset the terminal mode bits to a sensible state. Very useful after - * a child program dies in raw mode. - */ -static void -reset_mode(void) -{ -#ifdef TERMIOS - tcgetattr(STDERR_FILENO, &mode); -#else - stty(STDERR_FILENO,&mode); -#endif - -#ifdef TERMIOS -#if defined(VDISCARD) && defined(CDISCARD) - mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD); -#endif - mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF); - mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE); -#if defined(VFLUSH) && defined(CFLUSH) - mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH); -#endif - mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR); - mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL); -#if defined(VLNEXT) && defined(CLNEXT) - mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT); -#endif - mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT); -#if defined(VREPRINT) && defined(CRPRNT) - mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT); -#endif -#if defined(VSTART) && defined(CSTART) - mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART); -#endif -#if defined(VSTOP) && defined(CSTOP) - mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP); -#endif -#if defined(VSUSP) && defined(CSUSP) - mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP); -#endif -#if defined(VWERASE) && defined(CWERASE) - mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE); -#endif - - mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR -#ifdef IUCLC - | IUCLC -#endif -#ifdef IXANY - | IXANY -#endif - | IXOFF); - - mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON -#ifdef IMAXBEL - | IMAXBEL -#endif - ); - - mode.c_oflag &= ~(0 -#ifdef OLCUC - | OLCUC -#endif -#ifdef OCRNL - | OCRNL -#endif -#ifdef ONOCR - | ONOCR -#endif -#ifdef ONLRET - | ONLRET -#endif -#ifdef OFILL - | OFILL -#endif -#ifdef OFDEL - | OFDEL -#endif -#ifdef NLDLY - | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY -#endif - ); - - mode.c_oflag |= (OPOST -#ifdef ONLCR - | ONLCR -#endif - ); - - mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); - mode.c_cflag |= (CS8 | CREAD); - mode.c_lflag &= ~(ECHONL | NOFLSH -#ifdef TOSTOP - | TOSTOP -#endif -#ifdef ECHOPTR - | ECHOPRT -#endif -#ifdef XCASE - | XCASE -#endif - ); - - mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK -#ifdef ECHOCTL - | ECHOCTL -#endif -#ifdef ECHOKE - | ECHOKE -#endif - ); -#endif - -#ifdef TERMIOS - tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); -#else - stty(STDERR_FILENO, &mode); -#endif -} - /* - * Returns a "good" value for the erase character. This is loosely based on - * the BSD4.4 logic. - */ -static int -default_erase(void) -{ - int result; - - if (over_strike - && key_backspace != 0 - && strlen(key_backspace) == 1) - result = key_backspace[0]; - else - result = CERASE; - - return result; -} - -/* - * Update the values of the erase, interrupt, and kill characters in 'mode'. - * - * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase - * characters if they're unset, or if we specify them as options. This differs - * from BSD 4.4 tset, which always sets erase. + * Convert the obsolete argument forms into something that getopt can handle. + * This means that -e, -i and -k get default arguments supplied for them. */ static void -set_control_chars(void) +obsolete(char **argv) { -#ifdef TERMIOS - if (mode.c_cc[VERASE] == 0 || terasechar >= 0) - mode.c_cc[VERASE] = terasechar >= 0 ? terasechar : default_erase(); - - if (mode.c_cc[VINTR] == 0 || intrchar >= 0) - mode.c_cc[VINTR] = intrchar >= 0 ? intrchar : CINTR; + for (; *argv; ++argv) { + char *parm = argv[0]; - if (mode.c_cc[VKILL] == 0 || tkillchar >= 0) - mode.c_cc[VKILL] = tkillchar >= 0 ? tkillchar : CKILL; -#endif -} - -/* - * Set up various conversions in 'mode', including parity, tabs, returns, - * echo, and case, according to the termcap entry. If the program we're - * running was named with a leading upper-case character, map external - * uppercase to internal lowercase. - */ -static void -set_conversions(void) -{ -#ifdef __OBSOLETE__ - /* - * Conversion logic for some *really* ancient terminal glitches, - * not supported in terminfo. Left here for succeeding generations - * to marvel at. - */ - if (tgetflag("UC")) { -#ifdef IUCLC - mode.c_iflag |= IUCLC; - mode.c_oflag |= OLCUC; -#endif - } else if (tgetflag("LC")) { -#ifdef IUCLC - mode.c_iflag &= ~IUCLC; - mode.c_oflag &= ~OLCUC; -#endif - } - mode.c_iflag &= ~(PARMRK | INPCK); - mode.c_lflag |= ICANON; - if (tgetflag("EP")) { - mode.c_cflag |= PARENB; - mode.c_cflag &= ~PARODD; + if (parm[0] == '-' && parm[1] == '\0') { + argv[0] = strdup("-q"); + continue; } - if (tgetflag("OP")) { - mode.c_cflag |= PARENB; - mode.c_cflag |= PARODD; - } -#endif /* __OBSOLETE__ */ -#ifdef TERMIOS -#ifdef ONLCR - mode.c_oflag |= ONLCR; -#endif - mode.c_iflag |= ICRNL; - mode.c_lflag |= ECHO; -#ifdef OXTABS - mode.c_oflag |= OXTABS; -#endif /* OXTABS */ - - /* test used to be tgetflag("NL") */ - if (newline != (char *)0 && newline[0] == '\n' && !newline[1]) { - /* Newline, not linefeed. */ -#ifdef ONLCR - mode.c_oflag &= ~ONLCR; -#endif - mode.c_iflag &= ~ICRNL; + if ((parm[0] != '-') + || (argv[1] && argv[1][0] != '-') + || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k') + || (parm[2] != '\0')) + continue; + switch (argv[0][1]) { + case 'e': + argv[0] = strdup("-e^H"); + break; + case 'i': + argv[0] = strdup("-i^C"); + break; + case 'k': + argv[0] = strdup("-k^U"); + break; } -#ifdef __OBSOLETE__ - if (tgetflag("HD")) /* Half duplex. */ - mode.c_lflag &= ~ECHO; -#endif /* __OBSOLETE__ */ -#ifdef OXTABS - /* test used to be tgetflag("pt") */ - if (has_hardware_tabs) /* Print tabs. */ - mode.c_oflag &= ~OXTABS; -#endif /* OXTABS */ - mode.c_lflag |= (ECHOE | ECHOK); -#endif + } } -/* Output startup string. */ static void -set_init(void) +print_shell_commands(const char *ttype) { - char *p; - bool settle; - -#ifdef __OBSOLETE__ - if (pad_char != (char *)0) /* Get/set pad character. */ - PC = pad_char[0]; -#endif /* OBSOLETE */ - -#ifdef TAB3 - if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) { - oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET); - tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode); - } -#endif - settle = set_tabs(); - - if (isreset) { - if ((p = reset_1string) != 0) { - tputs(p, 0, outc); - settle = TRUE; - } - if ((p = reset_2string) != 0) { - tputs(p, 0, outc); - settle = TRUE; - } - /* What about rf, rs3, as per terminfo man page? */ - /* also might be nice to send rmacs, rmul, rmm */ - if ((p = reset_file) != 0 - || (p = init_file) != 0) { - cat(p); - settle = TRUE; - } - } - - if (settle) { - (void)putc('\r', stderr); - (void)fflush(stderr); - (void)napms(1000); /* Settle the terminal. */ - } + const char *p; + int len; + char *var; + char *leaf; + /* + * Figure out what shell we're using. A hack, we look for an + * environmental variable SHELL ending in "csh". + */ + if ((var = getenv("SHELL")) != 0 + && ((len = (int) strlen(leaf = _nc_basename(var))) >= 3) + && !strcmp(leaf + len - 3, "csh")) + p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n"; + else + p = "TERM=%s;\n"; + (void) printf(p, ttype); } -/* - * Set the hardware tabs on the terminal, using the ct (clear all tabs), - * st (set one tab) and ch (horizontal cursor addressing) capabilities. - * This is done before if and is, so they can patch in case we blow this. - * Return TRUE if we set any tab stops, FALSE if not. - */ -static bool -set_tabs() +static void +usage(void) { - if (set_tab && clear_all_tabs) { - int c; - - (void)putc('\r', stderr); /* Force to left margin. */ - tputs(clear_all_tabs, 0, outc); - - for (c = 8; c < tcolumns; c += 8) { - /* Get to the right column. In BSD tset, this - * used to try a bunch of half-clever things - * with cup and hpa, for an average saving of - * somewhat less than two character times per - * tab stop, less that .01 sec at 2400cps. We - * lost all this cruft because it seemed to be - * introducing some odd bugs. - * ----------12345678----------- */ - (void)fputs(" ", stderr); - tputs(set_tab, 0, outc); - } - putc('\r', stderr); - return (TRUE); - } - return (FALSE); +#define SKIP(s) /* nothing */ +#define KEEP(s) s "\n" + static const char msg[] = + { + KEEP("") + KEEP("Options:") + SKIP(" -a arpanet (obsolete)") + KEEP(" -c set control characters") + SKIP(" -d dialup (obsolete)") + KEEP(" -e ch erase character") + KEEP(" -I no initialization strings") + KEEP(" -i ch interrupt character") + KEEP(" -k ch kill character") + KEEP(" -m mapping map identifier to type") + SKIP(" -p plugboard (obsolete)") + KEEP(" -Q do not output control key settings") + KEEP(" -q display term only, do no changes") + KEEP(" -r display term on stderr") + SKIP(" -S (obsolete)") + KEEP(" -s output TERM set command") + KEEP(" -V print curses-version") + KEEP(" -w set window-size") + KEEP("") + KEEP("If neither -c/-w are given, both are assumed.") + }; +#undef KEEP +#undef SKIP + (void) fprintf(stderr, "Usage: %s [options] [terminal]\n", _nc_progname); + fputs(msg, stderr); + ExitProgram(EXIT_FAILURE); + /* NOTREACHED */ } -/************************************************************************** - * - * Main sequence - * - **************************************************************************/ - -/* - * Tell the user if a control key has been changed from the default value. - */ -static void -report(const char *name, int which, u_int def) +static char +arg_to_char(void) { -#ifdef TERMIOS - u_int older, newer; - char *p; - - newer = mode.c_cc[which]; - older = oldmode.c_cc[which]; - - if (older == newer && older == def) - return; - - (void)fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to"); - - /* - * Check 'delete' before 'backspace', since the key_backspace value - * is ambiguous. - */ - if (newer == 0177) - (void)fprintf(stderr, "delete.\n"); - else if ((p = key_backspace) != 0 - && newer == (u_int)p[0] - && p[1] == '\0') - (void)fprintf(stderr, "backspace.\n"); - else if (newer < 040) { - newer ^= 0100; - (void)fprintf(stderr, "control-%c (^%c).\n", newer, newer); - } else - (void)fprintf(stderr, "%c.\n", newer); -#endif + return (char) ((optarg[0] == '^' && optarg[1] != '\0') + ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1])) + : optarg[0]); } -/* - * Convert the obsolete argument forms into something that getopt can handle. - * This means that -e, -i and -k get default arguments supplied for them. - */ -static void -obsolete(char **argv) +int +main(int argc, char **argv) { - for (; *argv; ++argv) { - char *parm = argv[0]; - - if (parm[0] == '-' && parm[1] == '\0') - { - argv[0] = strdup("-q"); - continue; - } - - if ((parm[0] != '-') - || (argv[1] && argv[1][0] != '-') - || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k') - || (parm[2] != '\0')) - continue; - switch(argv[0][1]) { - case 'e': - argv[0] = strdup("-e^H"); - break; - case 'i': - argv[0] = strdup("-i^C"); - break; - case 'k': - argv[0] = strdup("-k^U"); - break; - } + int ch, noinit, noset, quiet, Sflag, sflag, showterm; + const char *ttype; + int terasechar = -1; /* new erase character */ + int intrchar = -1; /* new interrupt character */ + int tkillchar = -1; /* new kill character */ + int my_fd; + bool opt_c = FALSE; /* set control-chars */ + bool opt_w = FALSE; /* set window-size */ + TTY mode, oldmode; + + obsolete(argv); + noinit = noset = quiet = Sflag = sflag = showterm = 0; + while ((ch = getopt(argc, argv, "a:cd:e:Ii:k:m:p:qQrSsVw")) != -1) { + switch (ch) { + case 'c': /* set control-chars */ + opt_c = TRUE; + break; + case 'a': /* OBSOLETE: map identifier to type */ + add_mapping("arpanet", optarg); + break; + case 'd': /* OBSOLETE: map identifier to type */ + add_mapping("dialup", optarg); + break; + case 'e': /* erase character */ + terasechar = arg_to_char(); + break; + case 'I': /* no initialization strings */ + noinit = 1; + break; + case 'i': /* interrupt character */ + intrchar = arg_to_char(); + break; + case 'k': /* kill character */ + tkillchar = arg_to_char(); + break; + case 'm': /* map identifier to type */ + add_mapping(0, optarg); + break; + case 'p': /* OBSOLETE: map identifier to type */ + add_mapping("plugboard", optarg); + break; + case 'Q': /* don't output control key settings */ + quiet = 1; + break; + case 'q': /* display term only */ + noset = 1; + break; + case 'r': /* display term on stderr */ + showterm = 1; + break; + case 'S': /* OBSOLETE: output TERM & TERMCAP */ + Sflag = 1; + break; + case 's': /* output TERM set command */ + sflag = 1; + break; + case 'V': /* print curses-version */ + puts(curses_version()); + ExitProgram(EXIT_SUCCESS); + case 'w': /* set window-size */ + opt_w = TRUE; + break; + case '?': + default: + usage(); } -} + } -static void -usage(const char* pname) -{ - (void)fprintf(stderr, -"usage: %s [-IQrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n", pname); - exit(EXIT_FAILURE); -} + _nc_progname = _nc_rootname(*argv); + argc -= optind; + argv += optind; -static char arg_to_char(void) -{ - return (optarg[0] == '^' && optarg[1] != '\0') - ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1])) - : optarg[0]; -} + if (argc > 1) + usage(); -int -main(int argc, char **argv) -{ -#if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) - struct winsize win; -#endif - int ch, noinit, noset, quiet, Sflag, sflag, showterm; - const char *p; - const char *ttype; + if (!opt_c && !opt_w) + opt_c = opt_w = TRUE; + my_fd = save_tty_settings(&mode, TRUE); + oldmode = mode; #ifdef TERMIOS - if (tcgetattr(STDERR_FILENO, &mode) < 0) - failed("standard error"); - - oldmode = mode; - ospeed = cfgetospeed(&mode); + ospeed = (NCURSES_OSPEED) cfgetospeed(&mode); +#elif defined(EXP_WIN32_DRIVER) + ospeed = 0; #else - if (gtty(STDERR_FILENO, &mode) < 0) - failed("standard error"); - - oldmode = mode; - ospeed = mode.sg_ospeed; + ospeed = (NCURSES_OSPEED) mode.sg_ospeed; #endif - if ((p = strrchr(*argv, '/')) != 0) - ++p; - else - p = *argv; - if (!CaselessCmp(p, "reset")) { - isreset = 1; - reset_mode(); - } + if (same_program(_nc_progname, PROG_RESET)) { + reset_start(stderr, TRUE, FALSE); + reset_tty_settings(my_fd, &mode); + } else { + reset_start(stderr, FALSE, TRUE); + } - obsolete(argv); - noinit = noset = quiet = Sflag = sflag = showterm = 0; - while ((ch = getopt(argc, argv, "a:d:e:Ii:k:m:np:qQSrs")) != EOF) { - switch (ch) { - case 'q': /* display term only */ - noset = 1; - break; - case 'a': /* OBSOLETE: map identifier to type */ - add_mapping("arpanet", optarg); - break; - case 'd': /* OBSOLETE: map identifier to type */ - add_mapping("dialup", optarg); - break; - case 'e': /* erase character */ - terasechar = arg_to_char(); - break; - case 'I': /* no initialization strings */ - noinit = 1; - break; - case 'i': /* interrupt character */ - intrchar = arg_to_char(); - break; - case 'k': /* kill character */ - tkillchar = arg_to_char(); - break; - case 'm': /* map identifier to type */ - add_mapping(0, optarg); - break; - case 'n': /* OBSOLETE: set new tty driver */ - break; - case 'p': /* OBSOLETE: map identifier to type */ - add_mapping("plugboard", optarg); - break; - case 'Q': /* don't output control key settings */ - quiet = 1; - break; - case 'S': /* OBSOLETE: output TERM & TERMCAP */ - Sflag = 1; - break; - case 'r': /* display term on stderr */ - showterm = 1; - break; - case 's': /* output TERM set command */ - sflag = 1; - break; - case '?': - default: - usage(*argv); - } + ttype = get_termcap_entry(my_fd, *argv); + + if (!noset) { +#if HAVE_SIZECHANGE + if (opt_w) { + set_window_size(my_fd, &lines, &columns); } - argc -= optind; - argv += optind; - - if (argc > 1) - usage(*argv); - - ttype = get_termcap_entry(*argv); - - if (!noset) { - tcolumns = columns; - tlines = lines; - -#if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) - /* Set window size */ - (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win); - if (win.ws_row == 0 && win.ws_col == 0 && - tlines > 0 && tcolumns > 0) { - win.ws_row = tlines; - win.ws_col = tcolumns; - (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win); - } #endif - set_control_chars(); - set_conversions(); + if (opt_c) { + set_control_chars(&mode, terasechar, intrchar, tkillchar); + set_conversions(&mode); - if (!noinit) - set_init(); + if (!noinit) { + if (send_init_strings(my_fd, &oldmode)) { + (void) putc('\r', stderr); + (void) fflush(stderr); + (void) napms(1000); /* Settle the terminal. */ + } + } - /* Set the modes if they've changed. */ - if (memcmp(&mode, &oldmode, sizeof(mode))) -#ifdef TERMIOS - tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); -#else - stty(STDERR_FILENO, &mode); -#endif + update_tty_settings(&oldmode, &mode); } + } - /* Get the terminal name from the entry. */ - ttype = _nc_first_name(cur_term->type.term_names); - - if (noset) - (void)printf("%s\n", ttype); - else { - if (showterm) - (void)fprintf(stderr, "Terminal type is %s.\n", ttype); - /* - * If erase, kill and interrupt characters could have been - * modified and not -Q, display the changes. - */ - if (!quiet) { - report("Erase", VERASE, CERASE); - report("Kill", VKILL, CINTR); - report("Interrupt", VINTR, CKILL); - } + if (noset) { + (void) printf("%s\n", ttype); + } else { + if (showterm) + (void) fprintf(stderr, "Terminal type is %s.\n", ttype); + /* + * If erase, kill and interrupt characters could have been + * modified and not -Q, display the changes. + */ + if (!quiet) { + print_tty_chars(&oldmode, &mode); } + } - if (Sflag) - err("The -S option is not supported under terminfo."); - - if (sflag) { - /* - * Figure out what shell we're using. A hack, we look for an - * environmental variable SHELL ending in "csh". - */ - if ((p = getenv("SHELL")) != 0 - && !strcmp(p + strlen(p) - 3, "csh")) - p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n"; - else - p = "TERM=%s;\n"; - (void) printf(p, ttype); - } + if (Sflag) + err("The -S option is not supported under terminfo."); - return EXIT_SUCCESS; -} + if (sflag) { + print_shell_commands(ttype); + } -/* tset.c ends here */ + ExitProgram(EXIT_SUCCESS); +}