1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * University Copyright- Copyright (c) 1982, 1986, 1988
  32  * The Regents of the University of California
  33  * All Rights Reserved
  34  *
  35  * University Acknowledgment- Portions of this document are derived from
  36  * software developed by the University of California, Berkeley, and its
  37  * contributors.
  38  */
  39 
  40 /*LINTLIBRARY*/
  41 
  42 #include        <stdio.h>
  43 #include        <sys/types.h>
  44 #include        <fcntl.h>
  45 #include        <stdlib.h>
  46 #include        <string.h>
  47 #include        <unistd.h>
  48 #include        <errno.h>
  49 #include        <zone.h>
  50 #include        "curses_inc.h"
  51 
  52 #define TERMPATH        "/usr/share/lib/terminfo/"
  53 #define TERMPATHLEN     512
  54 
  55 extern  bool    _use_env;       /* in curses.c */
  56 
  57 chtype  bit_attributes[NUM_ATTRIBUTES] = {
  58             A_STANDOUT,
  59             A_UNDERLINE,
  60             A_ALTCHARSET,
  61             A_REVERSE,
  62             A_BLINK,
  63             A_DIM,
  64             A_BOLD,
  65             A_INVIS,
  66             A_PROTECT
  67         };
  68 
  69 char    *Def_term = "unknown",  /* default terminal type */
  70         term_parm_err[32], ttytype[BUFSIZ], _frst_tblstr[1400];
  71 
  72 TERMINAL                _first_term, *cur_term = &_first_term;
  73 struct  _bool_struct    _frst_bools, *cur_bools = &_frst_bools;
  74 struct  _num_struct     _frst_nums, *cur_nums = &_frst_nums;
  75 struct  _str_struct     _frst_strs, *cur_strs = &_frst_strs;
  76 
  77 /* _called_before is used/cleared by delterm.c and restart.c */
  78 char    _called_before = 0;
  79 short   term_errno = -1;
  80 
  81 #ifdef SYSV
  82 int     prog_istermios = -1;
  83 int     shell_istermios = -1;
  84 #endif
  85 
  86 #ifdef  DUMPTI
  87 extern  char    *boolfnames[], *boolnames[], *boolcodes[],
  88                 *numfnames[], *numnames[], *numcodes[],
  89                 *strfnames[], *strnames[], *strcodes[];
  90 
  91 main(int argc, char **argv)     /* FOR DEBUG ONLY */
  92 {
  93         if (argc > 1)
  94                 setupterm(argv[1], 1, (int *)0);
  95         else
  96                 setupterm((char *)0, 1, (int *)0);
  97         return (0);
  98 }
  99 
 100 _Pr(int ch)     /* FOR DEBUG ONLY */
 101 {
 102         if (ch >= 0200) {
 103                 printf("M-");
 104                 ch -= 0200;
 105         }
 106         if ((ch < ' ') || (ch == 0177))
 107                 printf("^%c", ch ^ 0100);
 108         else
 109                 printf("%c", ch);
 110 }
 111 
 112 _Sprint(int n, char *string)    /* FOR DEBUG ONLY */
 113 {
 114         int     ch;
 115 
 116         if (n == -1) {
 117                 printf(".\n");
 118                 return;
 119         }
 120         printf(", string = '");
 121         while (ch = *string++)
 122                 _Pr(ch&0377);
 123 
 124         printf("'.\n");
 125 }
 126 
 127 _Mprint(int n, char *memory)    /* FOR DEBUG ONLY */
 128 {
 129         unsigned        char    ch;
 130 
 131         while (ch = *memory++, n-- > 0)
 132                 _Pr(ch&0377);
 133 }
 134 
 135 #define _Vr2getshi()    _Vr2getsh(ip-2)
 136 
 137 #if     vax || pdp11
 138 #define _Vr2getsh(ip)   (* (short *)(ip))
 139 #endif  /* vax || pdp11 */
 140 
 141 #ifndef _Vr2getsh
 142 /*
 143  * Here is a more portable version, which does not assume byte ordering
 144  * in shorts, sign extension, etc.
 145  */
 146 _Vr2getsh(char *p)
 147 {
 148         int     rv;
 149 
 150         if (*p == (char)0377)
 151                 return (-1);
 152         rv = (unsigned char) *p++;
 153         rv += (unsigned char) *p * 256;
 154         return (rv);
 155 }
 156 #endif  /* _Vr2getsh */
 157 
 158 #endif  /* DUMPTI */
 159 
 160 #define _Getshi()       _Getsh(ip); ip += 2
 161 
 162 /*
 163  * "function" to get a short from a pointer.  The short is in a standard
 164  * format: two bytes, the first is the low order byte, the second is
 165  * the high order byte (base 256).  The only negative numbers allowed are
 166  * -1 and -2, which are represented as 255,255 and 255,254  This format
 167  * happens to be the same as the hardware on the pdp-11, vax, and 386,
 168  * making it fast and convenient and small to do this on a pdp-11.
 169  */
 170 
 171 #if     vax || pdp11 || i386
 172 #define _Getsh(ip)      (* (short *)ip)
 173 #endif  /* vax || pdp11 */
 174 /*
 175  * The following macro is partly due to Mike Laman, laman@sdcsvax
 176  *      NCR @ Torrey Pines.             - Tony Hansen
 177  */
 178 #if     u3b || u3b15 || u3b2 || m68000
 179 #define _Getsh(ip)      ((short)(*((unsigned char *)ip) | (*(ip+1) << 8)))
 180 #endif  /* u3b || u3b15 || u3b2 || m68000 */
 181 
 182 #ifndef _Getsh
 183 /*
 184  * Here is a more portable version, which does not assume byte ordering
 185  * in shorts, sign extension, etc.  For the sake of the porters,
 186  * two alternative implementations, for the machines that don't have
 187  * casting to "unsigned char", are also given, but commented out.
 188  * Not ANSI C implementation assumes that the * C preprocessor does
 189  * sign-extension the same as on the machine being compiled for.
 190  */
 191 static int
 192 _Getsh(char *p)
 193 {
 194         int     rv, rv2;
 195 
 196         rv  = (unsigned char) p[0];
 197         rv2 = (unsigned char) p[1];
 198 
 199         /* the following stuff is only for porting.  See the comment above */
 200 
 201 #ifdef FOR_PORTING
 202 #if    CHAR_MIN < 0
 203         rv = (*p++) & 0377;
 204         rv2 = (*p) & 0377;
 205 #else   /* CHAR_MIN < 0 */
 206         rv = *p++;
 207         rv2 = *p;
 208 #endif  /* CHAR_MIN < 0 */
 209 
 210 #endif  /* FOR_PORTING  */
 211 
 212         if ((rv2 == 0377) && ((rv == 0377) || (rv == 0376)))
 213                 return (-1);
 214         return (rv + (rv2 * 256));
 215 }
 216 #endif  /* _Getsh */
 217 
 218 /*
 219  * setupterm: low level routine to dig up terminfo from database
 220  * and read it in.  Parms are terminal type (0 means use getenv("TERM"),
 221  * file descriptor all output will go to (for ioctls), and a pointer
 222  * to an int into which the error return code goes (0 means to bomb
 223  * out with an error message if there's an error).  Thus,
 224  * setupterm((char *)0, 1, (int *)0) is a reasonable way for a simple
 225  * program to set up.
 226  */
 227 int
 228 setupterm(char *term, int filenum, int *errret)
 229         /* filenum - This is a UNIX file descriptor, not a stdio ptr. */
 230 {
 231         char    tiebuf[4096];
 232         char    fname[TERMPATHLEN];
 233         char    *ip;
 234         char    *cp;
 235         int     n, tfd;
 236         char    *lcp, *ccp, **on_sequences, **str_array;
 237         int     snames, nbools, nints, nstrs, sstrtab;
 238         char    *strtab;
 239 #ifdef  DUMPTI
 240         int             Vr2val;
 241 #endif  /* DUMPTI */
 242 
 243         (void) mbgetwidth();
 244 
 245         if (term == NULL)
 246                 term = getenv("TERM");
 247 
 248         if (term == NULL || *term == '\0')
 249                 term = Def_term;
 250 
 251         tfd = -1;
 252         errno = 0;      /* ehr3 */
 253 
 254         if (errret != 0)
 255                 *errret = -1;
 256 
 257         if (((cp = getenv("TERMINFO")) != 0) && *cp) {
 258                 /* $TERMINFO/?/$TERM */
 259                 if (snprintf(fname, sizeof (fname),
 260                         "%s/%c/%s", cp, *term, term) >= sizeof (fname)) {
 261                         term_errno = TERMINFO_TOO_LONG;
 262                         goto out_err;
 263                 }
 264 
 265                 tfd = open(fname, 0);
 266 #ifdef  DUMPTI
 267                 printf("looking in file %s\n", fname);
 268 #endif  /* DUMPTI */
 269                 if ((tfd < 0) && (errno == EACCES))
 270                         goto cant_read;
 271         }
 272 
 273         if (tfd < 0) {
 274                 const char *zroot = zone_get_nroot();
 275                 /* /usr/share/lib/terminfo/?/$TERM */
 276                 if (snprintf(fname, sizeof (fname),
 277                         "%s/%s/%c/%s", zroot == NULL ? "" : zroot, TERMPATH,
 278                         *term, term) >= sizeof (fname)) {
 279                         term_errno = TERMINFO_TOO_LONG;
 280                         goto out_err;
 281                 }
 282 
 283                 tfd = open(fname, 0);
 284 #ifdef  DUMPTI
 285                 printf("looking in file %s\n", fname);
 286 #endif  /* DUMPTI */
 287 
 288         }
 289 
 290         if (tfd < 0) {
 291                 if (errno == EACCES) {
 292 cant_read:
 293                         term_errno = NOT_READABLE;
 294                 } else {
 295                         if (access(TERMPATH, 0) == -1)
 296                                 term_errno = UNACCESSIBLE;
 297                         else {
 298                                 term_errno = NO_TERMINAL;
 299                                 if (errret != 0)
 300                                         *errret = 0;
 301                         }
 302                 }
 303                 /*
 304                  * if the length of the specified terminal name is longer
 305                  * than 31, it will be chopped after the 31st byte.
 306                  * This should be a rare case.
 307                  */
 308                 (void) strncpy(term_parm_err, term, 31);
 309                 term_parm_err[31] = '\0';
 310                 goto out_err;
 311         }
 312 
 313         /* LINTED */
 314         n = (int)read(tfd, tiebuf, sizeof (tiebuf));
 315         (void) close(tfd);
 316 
 317         if (n <= 0) {
 318 corrupt:
 319                 term_errno = CORRUPTED;
 320                 goto out_err;
 321         } else
 322                 if (n == sizeof (tiebuf)) {
 323                         term_errno = ENTRY_TOO_LONG;
 324                         goto out_err;
 325                 }
 326         cp = ttytype;
 327         ip = tiebuf;
 328 
 329         /* Pick up header */
 330         snames = _Getshi();
 331 #ifdef  DUMPTI
 332         Vr2val = _Vr2getshi();
 333         printf("Magic number = %d, %#o [%d, %#o].\n", snames,
 334             snames, Vr2val, Vr2val);
 335 #endif  /* DUMPTI */
 336         if (snames != MAGNUM)
 337                 goto corrupt;
 338         snames = _Getshi();
 339 #ifdef  DUMPTI
 340         Vr2val = _Vr2getshi();
 341         printf("Size of names = %d, %#o [%d, %#o].\n", snames,
 342             snames, Vr2val, Vr2val);
 343 #endif  /* DUMPTI */
 344 
 345         nbools = _Getshi();
 346 #ifdef  DUMPTI
 347         Vr2val = _Vr2getshi();
 348         printf("Number of bools = %d, %#o [%d, %#o].\n", nbools,
 349             nbools, Vr2val, Vr2val);
 350 #endif  /* DUMPTI */
 351 
 352         nints = _Getshi();
 353 #ifdef  DUMPTI
 354         Vr2val = _Vr2getshi();
 355         printf("Number of ints = %d, %#o [%d, %#o].\n", nints, nints,
 356             Vr2val, Vr2val);
 357 #endif  /* DUMPTI */
 358 
 359         nstrs = _Getshi();
 360 #ifdef  DUMPTI
 361         Vr2val = _Vr2getshi();
 362         printf("Number of strings = %d, %#o [%d, %#o].\n", nstrs, nstrs,
 363             Vr2val, Vr2val);
 364 #endif  /* DUMPTI */
 365 
 366         sstrtab = _Getshi();
 367 #ifdef  DUMPTI
 368         Vr2val = _Vr2getshi();
 369         printf("Size of string table = %d, %#o [%d, %#o].\n", sstrtab,
 370             sstrtab, Vr2val, Vr2val);
 371         printf("Names are: %.*s.\n", snames, ip);
 372 #endif  /* DUMPTI */
 373 
 374         /* allocate all of the space */
 375         strtab = NULL;
 376         if (_called_before) {
 377                 /* 2nd or more times through */
 378                 if ((cur_term = (TERMINAL *)
 379                     calloc(sizeof (TERMINAL), 1)) == NULL)
 380                         goto badmalloc;
 381                 if ((cur_bools = (struct _bool_struct *)
 382                     calloc(sizeof (struct _bool_struct), 1)) == NULL)
 383                         goto freeterminal;
 384                 if ((cur_nums = (struct _num_struct *)
 385                     calloc(sizeof (struct _num_struct), 1)) == NULL)
 386                         goto freebools;
 387                 if ((cur_strs = (struct _str_struct *)
 388                     calloc(sizeof (struct _str_struct), 1)) == NULL) {
 389 freenums:
 390                         free((char *)cur_nums);
 391 freebools:
 392                         free((char *)cur_bools);
 393 freeterminal:
 394                         free((char *)cur_term);
 395 badmalloc:
 396                         term_errno = TERM_BAD_MALLOC;
 397 #ifdef  DEBUG
 398                         strcpy(term_parm_err, "setupterm");
 399 #endif  /* DEBUG */
 400 out_err:
 401                         if (errret == 0) {
 402                                 termerr();
 403                                 exit(-term_errno);
 404                         } else
 405                                 return (ERR);
 406                 }
 407         } else {
 408                 /* First time through */
 409                 _called_before = TRUE;
 410                 cur_term = &_first_term;
 411                 cur_bools = &_frst_bools;
 412                 cur_nums = &_frst_nums;
 413                 cur_strs = &_frst_strs;
 414                 if (sstrtab < sizeof (_frst_tblstr))
 415                         strtab = _frst_tblstr;
 416         }
 417 
 418         if (strtab == NULL) {
 419                 if ((strtab = (char *)malloc((unsigned)sstrtab)) == NULL) {
 420                         if (cur_strs != &_frst_strs)
 421                                 free((char *)cur_strs);
 422                         goto freenums;
 423                 }
 424         }
 425 
 426         /* no more catchable errors */
 427         if (errret)
 428                 *errret = 1;
 429 
 430         (void) strncpy(cur_term->_termname, term, 14);
 431         /* In case the name is exactly 15 characters */
 432         cur_term->_termname[14] = '\0';
 433         cur_term->_bools = cur_bools;
 434         cur_term->_nums = cur_nums;
 435         cur_term->_strs = cur_strs;
 436         cur_term->_strtab = strtab;
 437         cur_term->sgr_mode = cur_term->sgr_faked = A_NORMAL;
 438 
 439         if (filenum == 1 && !isatty(filenum))
 440                 filenum = 2;    /* Allow output redirect */
 441         /* LINTED */
 442         cur_term->Filedes = (short)filenum;
 443         _blast_keys(cur_term);
 444         cur_term->_iwait = cur_term->fl_typeahdok = cur_term->_chars_on_queue =
 445                 cur_term->_fl_rawmode = cur_term->_ungotten = 0;
 446         cur_term->_cursorstate = 1;
 447         cur_term->_delay = cur_term->_inputfd = cur_term->_check_fd = -1;
 448         (void) memset((char *)cur_term->_regs, 0, 26 * sizeof (short));
 449 
 450 #ifndef DUMPTI
 451         (void) def_shell_mode();
 452         /* This is a useful default for PROGTTY, too */
 453 #ifdef SYSV
 454         if (shell_istermios < 0) {
 455                 int i;
 456 
 457                 SHELLTTY.c_lflag = SHELLTTYS.c_lflag;
 458                 SHELLTTY.c_oflag = SHELLTTYS.c_oflag;
 459                 SHELLTTY.c_iflag = SHELLTTYS.c_iflag;
 460                 SHELLTTY.c_cflag = SHELLTTYS.c_cflag;
 461                 for (i = 0; i < NCC; i++)
 462                         SHELLTTY.c_cc[i] = SHELLTTYS.c_cc[i];
 463                 PROGTTY = SHELLTTY;
 464                 prog_istermios = -1;
 465 
 466                 PROGTTYS.c_lflag = PROGTTY.c_lflag;
 467                 PROGTTYS.c_oflag = PROGTTY.c_oflag;
 468                 PROGTTYS.c_iflag = PROGTTY.c_iflag;
 469                 PROGTTYS.c_cflag = PROGTTY.c_cflag;
 470                 for (i = 0; i < NCC; i++)
 471                         PROGTTYS.c_cc[i] = PROGTTY.c_cc[i];
 472         } else {
 473                 PROGTTYS = SHELLTTYS;
 474                 prog_istermios = 0;
 475         }
 476 #else   /* SYSV */
 477         PROGTTY = SHELLTTY;
 478 #endif  /* SYSV */
 479 #endif  /* DUMPTI */
 480 
 481         /* Skip names of terminals */
 482         (void) memcpy((char *)cp, (char *)ip, (snames * sizeof (*cp)));
 483         ip += snames;
 484 
 485         /*
 486          * Pull out the booleans.
 487          * The for loop below takes care of a new curses with an old tic
 488          * file and visa-versa.  nbools says how many bools the tic file has.
 489          * So, we only loop for as long as there are bools to read.
 490          * However, if this is an old curses that doesn't have all the
 491          * bools that this new tic has dumped, then the extra if
 492          * "if (cp < fp)" says that if we are going to read into our structure
 493          * passed its size don't do it but we still need to keep bumping
 494          * up the pointer of what we read in from the terminfo file.
 495          */
 496         {
 497                 char    *fp = &cur_bools->Sentinel;
 498                 char    s;
 499 #ifdef  DUMPTI
 500                 int     tempindex = 0;
 501 #endif  /* DUMPTI */
 502                 cp = &cur_bools->_auto_left_margin;
 503                 while (nbools--) {
 504                         s = *ip++;
 505 #ifdef  DUMPTI
 506                         printf("Bool %s [%s] (%s) = %d.\n",
 507                             boolfnames[tempindex], boolnames[tempindex],
 508                             boolcodes[tempindex], s);
 509                         tempindex++;
 510 #endif  /* DUMPTI */
 511                         if (cp < fp)
 512                                 *cp++ = s & 01;
 513                 }
 514                 if (cp < fp)
 515                         (void) memset(cp, 0, ((fp - cp) * sizeof (bool)));
 516         }
 517 
 518         /* Force proper alignment */
 519         if (((unsigned long) ip) & 1)
 520                 ip++;
 521 
 522         /*
 523          * Pull out the numbers.
 524          */
 525         {
 526                 short   *sp = &cur_nums->_columns;
 527                 short   *fp = &cur_nums->Sentinel;
 528                 int     s;
 529 #ifdef  DUMPTI
 530                 int     tempindex = 0;
 531 #endif  /* DUMPTI */
 532 
 533                 while (nints--) {
 534                         s = _Getshi();
 535 #ifdef  DUMPTI
 536                         Vr2val = _Vr2getshi();
 537                         printf("Num %s [%s] (%s) = %d [%d].\n",
 538                             numfnames[tempindex], numnames[tempindex],
 539                             numcodes[tempindex], s, Vr2val);
 540                         tempindex++;
 541 #endif  /* DUMPTI */
 542                         if (sp < fp)
 543                                 if (s < 0)
 544                                         *sp++ = -1;
 545                                 else
 546                                         /* LINTED */
 547                                         *sp++ = (short)s;
 548                 }
 549                 if (sp < fp)
 550                         (void) memset((char *)sp, '\377',
 551                             ((fp - sp) * sizeof (short)));
 552         }
 553 
 554         if (_use_env) {
 555                 /*
 556                  * This ioctl defines the window size and overrides what
 557                  * it says in terminfo.
 558                  */
 559                 {
 560                         struct  winsize w;
 561 
 562                         if (ioctl(filenum, TIOCGWINSZ, &w) != -1) {
 563                                 if (w.ws_row != 0)
 564                                         cur_nums->_lines = w.ws_row;
 565                                 if (w.ws_col != 0)
 566                                         cur_nums->_columns = w.ws_col;
 567 #ifdef  DUMPTI
 568                                 printf("ioctl TIOCGWINSZ override: "
 569                                     "(lines, columns) = (%d, %d)\n",
 570                                     w.ws_row, w.ws_col);
 571 #endif  /* DUMPTI */
 572                         }
 573                 }
 574 
 575                 /*
 576                  * Check $LINES and $COLUMNS.
 577                  */
 578                 {
 579                         int     ilines, icolumns;
 580 
 581                         lcp = getenv("LINES");
 582                         ccp = getenv("COLUMNS");
 583                         if (lcp)
 584                                 if ((ilines = atoi(lcp)) > 0) {
 585                                         /* LINTED */
 586                                         cur_nums->_lines = (short)ilines;
 587 #ifdef  DUMPTI
 588                                         printf("$LINES override: lines = %d\n",
 589                                             ilines);
 590 #endif  /* DUMPTI */
 591                                 }
 592                         if (ccp)
 593                                 if ((icolumns = atoi(ccp)) > 0) {
 594                                         /* LINTED */
 595                                         cur_nums->_columns = (short)icolumns;
 596 #ifdef  DUMPTI
 597                                         printf("$COLUMNS override: columns = "
 598                                             "%d\n", icolumns);
 599 #endif  /* DUMPTI */
 600                                 }
 601                 }
 602         }
 603 
 604         /* Pull out the strings. */
 605         {
 606                 char    **pp = &cur_strs->strs._back_tab;
 607                 char    **fp = &cur_strs->strs4.Sentinel;
 608 #ifdef  DUMPTI
 609                 int     tempindex = 0;
 610                 char    *startstr = ip + sizeof (short) *
 611                                             nstrs;
 612 
 613                 printf("string table = '");
 614                 _Mprint(sstrtab, startstr);
 615                 printf("'\n");
 616 #endif  /* DUMPTI */
 617 
 618                 while (nstrs--) {
 619                         n = _Getshi();
 620 #ifdef  DUMPTI
 621                         Vr2val = _Vr2getshi();
 622                         printf("String %s [%s] (%s) offset = %d [%d]",
 623                             strfnames[tempindex], strnames[tempindex],
 624                             strcodes[tempindex], n, Vr2val);
 625                         tempindex++;
 626 #endif  /* DUMPTI */
 627                         if (pp < fp) {
 628 #ifdef  DUMPTI
 629                                 _Sprint(n, startstr+n);
 630 #endif  /* DUMPTI */
 631                                 if (n < 0)
 632                                         *pp++ = NULL;
 633                                 else
 634                                         *pp++ = strtab + n;
 635                         }
 636 #ifdef  DUMPTI
 637                         else
 638                                 _Sprint(-1, (char *)0);
 639 #endif  /* DUMPTI */
 640                 }
 641                 if (pp < fp)
 642                 (void) memset((char *)pp, 0, ((fp - pp) * sizeof (charptr)));
 643         }
 644 
 645         (void) memcpy(strtab, ip, sstrtab);
 646 
 647 #ifndef DUMPTI
 648 
 649         /*
 650          * If tabs are being expanded in software, turn this off
 651          * so output won't get messed up.  Also, don't use tab
 652          * or backtab, even if the terminal has them, since the
 653          * user might not have hardware tabs set right.
 654          */
 655 #ifdef  SYSV
 656         if ((PROGTTYS.c_oflag & TABDLY) == TAB3) {
 657                 PROGTTYS.c_oflag &= ~TABDLY;
 658                 (void) reset_prog_mode();
 659                 goto next;
 660         }
 661 #else   /* SYSV */
 662         if ((PROGTTY.sg_flags & XTABS) == XTABS) {
 663                 PROGTTY.sg_flags &= ~XTABS;
 664                 (void) reset_prog_mode();
 665                 goto next;
 666         }
 667 #endif  /* SYSV */
 668         if (dest_tabs_magic_smso) {
 669 next:
 670                 cur_strs->strs2._tab = cur_strs->strs._back_tab = NULL;
 671         }
 672 
 673 #ifdef  LTILDE
 674         ioctl(cur_term -> Filedes, TIOCLGET, &n);
 675 #endif  /* LTILDE */
 676 #endif  /* DUMPTI */
 677 
 678 #ifdef  _VR2_COMPAT_CODE
 679         (void) memcpy(&cur_term->_b1, &cur_bools->_auto_left_margin,
 680             (char *)&cur_term->_c1 - (char *)&cur_term->_b1);
 681         (void) memcpy((char *)&cur_term->_c1, (char *)&cur_nums->_columns,
 682             (char *)&cur_term->_Vr2_Astrs._s1 - (char *)&cur_term->_c1);
 683         (void) memcpy((char *)&cur_term->_Vr2_Astrs._s1,
 684             (char *)&cur_strs->strs._back_tab,
 685             (char *)&cur_term->Filedes - (char *)&cur_term->_Vr2_Astrs._s1);
 686 #endif  /* _VR2_COMPAT_CODE */
 687 
 688         on_sequences = cur_term->turn_on_seq;
 689         str_array = (char **)cur_strs;
 690         {
 691                 static  char    offsets[] = {
 692                             35, /* enter_standout_mode, */
 693                             36, /* enter_underline_mode, */
 694                             25, /* enter_alt_charset_mode, */
 695                             34, /* enter_reverse_mode, */
 696                             26, /* enter_blink_mode, */
 697                             30, /* enter_dim_mode, */
 698                             27, /* enter_bold_mode, */
 699                             32, /* enter_secure_mode, */
 700                             33, /* enter_protected_mode, */
 701                         };
 702 
 703                 for (n = 0; n < NUM_ATTRIBUTES; n++) {
 704                         if ((on_sequences[n] = str_array[offsets[n]]) != 0)
 705                                 cur_term->bit_vector |= bit_attributes[n];
 706                 }
 707         }
 708 
 709         if (!(set_attributes)) {
 710                 static  char    faked_attrs[] = { 1, 3, 4, 6 },
 711                         offsets[] = {
 712                             43, /* exit_standout_mode, */
 713                             44, /* exit_underline_mode, */
 714                             38, /* exit_alt_charset_mode, */
 715                         };
 716                 char            **off_sequences = cur_term->turn_off_seq;
 717                 int             i;
 718 
 719                 if ((max_attributes == -1) && (ceol_standout_glitch ||
 720                     (magic_cookie_glitch >= 0)))
 721                         max_attributes = 1;
 722 
 723                 /* Figure out what attributes need to be faked. */
 724                 /* See vidupdate.c */
 725 
 726                 for (n = 0; n < sizeof (faked_attrs); n++) {
 727                         if (on_sequences[0] != NULL) {
 728                                 if ((!on_sequences[i = faked_attrs[n]]) ||
 729                                     (strcmp(on_sequences[i],
 730                                     on_sequences[0]) == 0)) {
 731                                         cur_term->sgr_faked |=
 732                                             bit_attributes[i];
 733                                 }
 734                         } else {
 735                                 if (!on_sequences[i = faked_attrs[n]]) {
 736                                         cur_term->sgr_faked |=
 737                                             bit_attributes[i];
 738                                 }
 739                         }
 740                 }
 741 
 742                 cur_term->check_turn_off = A_STANDOUT | A_UNDERLINE |
 743                     A_ALTCHARSET;
 744 
 745                 for (n = 0; n < sizeof (offsets); n++) {
 746                         if ((!(off_sequences[n] = str_array[offsets[n]])) ||
 747                             ((n > 0) && off_sequences[0] &&
 748                             (strcmp(off_sequences[n], off_sequences[0]) ==
 749                             0)) || ((n == 2) && (exit_attribute_mode) &&
 750                             (strcmp(exit_attribute_mode, off_sequences[n]) ==
 751                             0))) {
 752                                 cur_term->check_turn_off &= ~bit_attributes[n];
 753                         }
 754                 }
 755         }
 756         cur_term->cursor_seq[0] = cursor_invisible;
 757         cur_term->cursor_seq[1] = cursor_normal;
 758         cur_term->cursor_seq[2] = cursor_visible;
 759         cur_term->_pairs_tbl = (_Color_pair *) NULL;
 760         cur_term->_color_tbl = (_Color *) NULL;
 761 
 762         return (OK);
 763 }
 764 
 765 void
 766 _blast_keys(TERMINAL *terminal)
 767 {
 768         terminal->_keys = NULL;
 769         terminal->internal_keys = NULL;
 770         terminal->_ksz = terminal->_first_macro = 0;
 771         terminal->_lastkey_ordered = terminal->_lastmacro_ordered = -1;
 772         (void) memset((char *)terminal->funckeystarter, 0, 0400 *
 773             sizeof (bool));
 774 }
 775 
 776 #ifndef DUMPTI
 777 
 778 int
 779 reset_prog_mode(void)
 780 {
 781 #ifdef  SYSV
 782         if (_BRS(PROGTTYS)) {
 783                 if (prog_istermios < 0) {
 784                         int i;
 785 
 786                         PROGTTY.c_lflag = PROGTTYS.c_lflag;
 787                         PROGTTY.c_oflag = PROGTTYS.c_oflag;
 788                         PROGTTY.c_iflag = PROGTTYS.c_iflag;
 789                         PROGTTY.c_cflag = PROGTTYS.c_cflag;
 790                         for (i = 0; i < NCC; i++)
 791                                 PROGTTY.c_cc[i] = PROGTTYS.c_cc[i];
 792                         (void) ioctl(cur_term -> Filedes, TCSETAW, &PROGTTY);
 793                 } else
 794                         (void) ioctl(cur_term -> Filedes, TCSETSW, &PROGTTYS);
 795         }
 796 #else   /* SYSV */
 797         if (_BR(PROGTTY))
 798                 (void) ioctl(cur_term -> Filedes, TIOCSETN, &PROGTTY);
 799 #endif  /* SYSV */
 800 
 801 #ifdef  LTILDE
 802         ioctl(cur_term -> Filedes, TIOCLGET, &cur_term -> oldlmode);
 803         cur_term -> newlmode = cur_term -> oldlmode & ~LTILDE;
 804         if (cur_term -> newlmode != cur_term -> oldlmode)
 805                 ioctl(cur_term -> Filedes, TIOCLSET, &cur_term -> newlmode);
 806 #endif  /* LTILDE */
 807 #ifdef  DIOCSETT
 808         if (cur_term -> old.st_termt == 0)
 809                 ioctl(cur_term->Filedes, DIOCGETT, &cur_term -> old);
 810         cur_term -> new = cur_term -> old;
 811         cur_term -> new.st_termt = 0;
 812         cur_term -> new.st_flgs |= TM_SET;
 813         ioctl(cur_term->Filedes, DIOCSETT, &cur_term -> new);
 814 #endif  /* DIOCSETT */
 815         return (OK);
 816 }
 817 
 818 int
 819 def_shell_mode(void)
 820 {
 821 #ifdef  SYSV
 822         if ((shell_istermios =
 823             ioctl(cur_term -> Filedes, TCGETS, &SHELLTTYS)) < 0) {
 824                 int i;
 825 
 826                 (void) ioctl(cur_term -> Filedes, TCGETA, &SHELLTTY);
 827                 SHELLTTYS.c_lflag = SHELLTTY.c_lflag;
 828                 SHELLTTYS.c_oflag = SHELLTTY.c_oflag;
 829                 SHELLTTYS.c_iflag = SHELLTTY.c_iflag;
 830                 SHELLTTYS.c_cflag = SHELLTTY.c_cflag;
 831                 for (i = 0; i < NCC; i++)
 832                         SHELLTTYS.c_cc[i] = SHELLTTY.c_cc[i];
 833         }
 834 #else   /* SYSV */
 835         (void) ioctl(cur_term -> Filedes, TIOCGETP, &SHELLTTY);
 836 #endif  /* SYSV */
 837         return (OK);
 838 }
 839 
 840 #endif  /* DUMPTI */