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