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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
45 #include <sys/types.h>
51 #include "curses_inc.h"
53 #define TERMPATH "/usr/share/lib/terminfo/"
54 #define TERMPATHLEN 512
56 extern bool _use_env
; /* in curses.c */
58 chtype bit_attributes
[NUM_ATTRIBUTES
] = {
70 char *Def_term
= "unknown", /* default terminal type */
71 term_parm_err
[32], ttytype
[BUFSIZ
], _frst_tblstr
[1400];
73 TERMINAL _first_term
, *cur_term
= &_first_term
;
74 struct _bool_struct _frst_bools
, *cur_bools
= &_frst_bools
;
75 struct _num_struct _frst_nums
, *cur_nums
= &_frst_nums
;
76 struct _str_struct _frst_strs
, *cur_strs
= &_frst_strs
;
78 /* _called_before is used/cleared by delterm.c and restart.c */
79 char _called_before
= 0;
80 short term_errno
= -1;
83 int prog_istermios
= -1;
84 int shell_istermios
= -1;
88 extern char *boolfnames
[], *boolnames
[], *boolcodes
[],
89 *numfnames
[], *numnames
[], *numcodes
[],
90 *strfnames
[], *strnames
[], *strcodes
[];
92 main(int argc
, char **argv
) /* FOR DEBUG ONLY */
95 setupterm(argv
[1], 1, (int *)0);
97 setupterm((char *)0, 1, (int *)0);
101 _Pr(int ch
) /* FOR DEBUG ONLY */
107 if ((ch
< ' ') || (ch
== 0177))
108 printf("^%c", ch
^ 0100);
113 _Sprint(int n
, char *string
) /* FOR DEBUG ONLY */
121 printf(", string = '");
122 while (ch
= *string
++)
128 _Mprint(int n
, char *memory
) /* FOR DEBUG ONLY */
132 while (ch
= *memory
++, n
-- > 0)
136 #define _Vr2getshi() _Vr2getsh(ip-2)
139 #define _Vr2getsh(ip) (* (short *)(ip))
140 #endif /* vax || pdp11 */
144 * Here is a more portable version, which does not assume byte ordering
145 * in shorts, sign extension, etc.
151 if (*p
== (char)0377)
153 rv
= (unsigned char) *p
++;
154 rv
+= (unsigned char) *p
* 256;
157 #endif /* _Vr2getsh */
161 #define _Getshi() _Getsh(ip); ip += 2
164 * "function" to get a short from a pointer. The short is in a standard
165 * format: two bytes, the first is the low order byte, the second is
166 * the high order byte (base 256). The only negative numbers allowed are
167 * -1 and -2, which are represented as 255,255 and 255,254 This format
168 * happens to be the same as the hardware on the pdp-11, vax, and 386,
169 * making it fast and convenient and small to do this on a pdp-11.
172 #if vax || pdp11 || i386
173 #define _Getsh(ip) (* (short *)ip)
174 #endif /* vax || pdp11 */
176 * The following macro is partly due to Mike Laman, laman@sdcsvax
177 * NCR @ Torrey Pines. - Tony Hansen
179 #if u3b || u3b15 || u3b2 || m68000
180 #define _Getsh(ip) ((short)(*((unsigned char *)ip) | (*(ip+1) << 8)))
181 #endif /* u3b || u3b15 || u3b2 || m68000 */
185 * Here is a more portable version, which does not assume byte ordering
186 * in shorts, sign extension, etc. For the sake of the porters,
187 * two alternative implementations, for the machines that don't have
188 * casting to "unsigned char", are also given, but commented out.
189 * Not ANSI C implementation assumes that the * C preprocessor does
190 * sign-extension the same as on the machine being compiled for.
197 rv
= (unsigned char) p
[0];
198 rv2
= (unsigned char) p
[1];
200 /* the following stuff is only for porting. See the comment above */
206 #else /* CHAR_MIN < 0 */
209 #endif /* CHAR_MIN < 0 */
211 #endif /* FOR_PORTING */
213 if ((rv2
== 0377) && ((rv
== 0377) || (rv
== 0376)))
215 return (rv
+ (rv2
* 256));
220 * setupterm: low level routine to dig up terminfo from database
221 * and read it in. Parms are terminal type (0 means use getenv("TERM"),
222 * file descriptor all output will go to (for ioctls), and a pointer
223 * to an int into which the error return code goes (0 means to bomb
224 * out with an error message if there's an error). Thus,
225 * setupterm((char *)0, 1, (int *)0) is a reasonable way for a simple
229 setupterm(char *term
, int filenum
, int *errret
)
230 /* filenum - This is a UNIX file descriptor, not a stdio ptr. */
233 char fname
[TERMPATHLEN
];
237 char *lcp
, *ccp
, **on_sequences
, **str_array
;
238 int snames
, nbools
, nints
, nstrs
, sstrtab
;
247 term
= getenv("TERM");
249 if (term
== NULL
|| *term
== '\0')
253 errno
= 0; /* ehr3 */
258 if (((cp
= getenv("TERMINFO")) != 0) && *cp
) {
259 /* $TERMINFO/?/$TERM */
260 if (snprintf(fname
, sizeof (fname
),
261 "%s/%c/%s", cp
, *term
, term
) >= sizeof (fname
)) {
262 term_errno
= TERMINFO_TOO_LONG
;
266 tfd
= open(fname
, 0);
268 printf("looking in file %s\n", fname
);
270 if ((tfd
< 0) && (errno
== EACCES
))
275 /* /usr/share/lib/terminfo/?/$TERM */
276 if (snprintf(fname
, sizeof (fname
),
277 "%s/%c/%s", TERMPATH
, *term
, term
) >= sizeof (fname
)) {
278 term_errno
= TERMINFO_TOO_LONG
;
282 tfd
= open(fname
, 0);
284 printf("looking in file %s\n", fname
);
290 if (errno
== EACCES
) {
292 term_errno
= NOT_READABLE
;
294 if (access(TERMPATH
, 0) == -1)
295 term_errno
= UNACCESSIBLE
;
297 term_errno
= NO_TERMINAL
;
303 * if the length of the specified terminal name is longer
304 * than 31, it will be chopped after the 31st byte.
305 * This should be a rare case.
307 (void) strncpy(term_parm_err
, term
, 31);
308 term_parm_err
[31] = '\0';
313 n
= (int)read(tfd
, tiebuf
, sizeof (tiebuf
));
318 term_errno
= CORRUPTED
;
321 if (n
== sizeof (tiebuf
)) {
322 term_errno
= ENTRY_TOO_LONG
;
331 Vr2val
= _Vr2getshi();
332 printf("Magic number = %d, %#o [%d, %#o].\n", snames
,
333 snames
, Vr2val
, Vr2val
);
335 if (snames
!= MAGNUM
)
339 Vr2val
= _Vr2getshi();
340 printf("Size of names = %d, %#o [%d, %#o].\n", snames
,
341 snames
, Vr2val
, Vr2val
);
346 Vr2val
= _Vr2getshi();
347 printf("Number of bools = %d, %#o [%d, %#o].\n", nbools
,
348 nbools
, Vr2val
, Vr2val
);
353 Vr2val
= _Vr2getshi();
354 printf("Number of ints = %d, %#o [%d, %#o].\n", nints
, nints
,
360 Vr2val
= _Vr2getshi();
361 printf("Number of strings = %d, %#o [%d, %#o].\n", nstrs
, nstrs
,
367 Vr2val
= _Vr2getshi();
368 printf("Size of string table = %d, %#o [%d, %#o].\n", sstrtab
,
369 sstrtab
, Vr2val
, Vr2val
);
370 printf("Names are: %.*s.\n", snames
, ip
);
373 /* allocate all of the space */
375 if (_called_before
) {
376 /* 2nd or more times through */
377 if ((cur_term
= (TERMINAL
*)
378 calloc(sizeof (TERMINAL
), 1)) == NULL
)
380 if ((cur_bools
= (struct _bool_struct
*)
381 calloc(sizeof (struct _bool_struct
), 1)) == NULL
)
383 if ((cur_nums
= (struct _num_struct
*)
384 calloc(sizeof (struct _num_struct
), 1)) == NULL
)
386 if ((cur_strs
= (struct _str_struct
*)
387 calloc(sizeof (struct _str_struct
), 1)) == NULL
) {
389 free((char *)cur_nums
);
391 free((char *)cur_bools
);
393 free((char *)cur_term
);
395 term_errno
= TERM_BAD_MALLOC
;
397 strcpy(term_parm_err
, "setupterm");
407 /* First time through */
408 _called_before
= TRUE
;
409 cur_term
= &_first_term
;
410 cur_bools
= &_frst_bools
;
411 cur_nums
= &_frst_nums
;
412 cur_strs
= &_frst_strs
;
413 if (sstrtab
< sizeof (_frst_tblstr
))
414 strtab
= _frst_tblstr
;
417 if (strtab
== NULL
) {
418 if ((strtab
= (char *)malloc((unsigned)sstrtab
)) == NULL
) {
419 if (cur_strs
!= &_frst_strs
)
420 free((char *)cur_strs
);
425 /* no more catchable errors */
429 (void) strncpy(cur_term
->_termname
, term
, 14);
430 /* In case the name is exactly 15 characters */
431 cur_term
->_termname
[14] = '\0';
432 cur_term
->_bools
= cur_bools
;
433 cur_term
->_nums
= cur_nums
;
434 cur_term
->_strs
= cur_strs
;
435 cur_term
->_strtab
= strtab
;
436 cur_term
->sgr_mode
= cur_term
->sgr_faked
= A_NORMAL
;
438 if (filenum
== 1 && !isatty(filenum
))
439 filenum
= 2; /* Allow output redirect */
441 cur_term
->Filedes
= (short)filenum
;
442 _blast_keys(cur_term
);
443 cur_term
->_iwait
= cur_term
->fl_typeahdok
= cur_term
->_chars_on_queue
=
444 cur_term
->_fl_rawmode
= cur_term
->_ungotten
= 0;
445 cur_term
->_cursorstate
= 1;
446 cur_term
->_delay
= cur_term
->_inputfd
= cur_term
->_check_fd
= -1;
447 (void) memset((char *)cur_term
->_regs
, 0, 26 * sizeof (short));
450 (void) def_shell_mode();
451 /* This is a useful default for PROGTTY, too */
453 if (shell_istermios
< 0) {
456 SHELLTTY
.c_lflag
= SHELLTTYS
.c_lflag
;
457 SHELLTTY
.c_oflag
= SHELLTTYS
.c_oflag
;
458 SHELLTTY
.c_iflag
= SHELLTTYS
.c_iflag
;
459 SHELLTTY
.c_cflag
= SHELLTTYS
.c_cflag
;
460 for (i
= 0; i
< NCC
; i
++)
461 SHELLTTY
.c_cc
[i
] = SHELLTTYS
.c_cc
[i
];
465 PROGTTYS
.c_lflag
= PROGTTY
.c_lflag
;
466 PROGTTYS
.c_oflag
= PROGTTY
.c_oflag
;
467 PROGTTYS
.c_iflag
= PROGTTY
.c_iflag
;
468 PROGTTYS
.c_cflag
= PROGTTY
.c_cflag
;
469 for (i
= 0; i
< NCC
; i
++)
470 PROGTTYS
.c_cc
[i
] = PROGTTY
.c_cc
[i
];
472 PROGTTYS
= SHELLTTYS
;
480 /* Skip names of terminals */
481 (void) memcpy((char *)cp
, (char *)ip
, (snames
* sizeof (*cp
)));
485 * Pull out the booleans.
486 * The for loop below takes care of a new curses with an old tic
487 * file and visa-versa. nbools says how many bools the tic file has.
488 * So, we only loop for as long as there are bools to read.
489 * However, if this is an old curses that doesn't have all the
490 * bools that this new tic has dumped, then the extra if
491 * "if (cp < fp)" says that if we are going to read into our structure
492 * passed its size don't do it but we still need to keep bumping
493 * up the pointer of what we read in from the terminfo file.
496 char *fp
= &cur_bools
->Sentinel
;
501 cp
= &cur_bools
->_auto_left_margin
;
505 printf("Bool %s [%s] (%s) = %d.\n",
506 boolfnames
[tempindex
], boolnames
[tempindex
],
507 boolcodes
[tempindex
], s
);
514 (void) memset(cp
, 0, ((fp
- cp
) * sizeof (bool)));
517 /* Force proper alignment */
518 if (((unsigned long) ip
) & 1)
522 * Pull out the numbers.
525 short *sp
= &cur_nums
->_columns
;
526 short *fp
= &cur_nums
->Sentinel
;
535 Vr2val
= _Vr2getshi();
536 printf("Num %s [%s] (%s) = %d [%d].\n",
537 numfnames
[tempindex
], numnames
[tempindex
],
538 numcodes
[tempindex
], s
, Vr2val
);
549 (void) memset((char *)sp
, '\377',
550 ((fp
- sp
) * sizeof (short)));
555 * This ioctl defines the window size and overrides what
556 * it says in terminfo.
561 if (ioctl(filenum
, TIOCGWINSZ
, &w
) != -1) {
563 cur_nums
->_lines
= w
.ws_row
;
565 cur_nums
->_columns
= w
.ws_col
;
567 printf("ioctl TIOCGWINSZ override: "
568 "(lines, columns) = (%d, %d)\n",
575 * Check $LINES and $COLUMNS.
578 int ilines
, icolumns
;
580 lcp
= getenv("LINES");
581 ccp
= getenv("COLUMNS");
583 if ((ilines
= atoi(lcp
)) > 0) {
585 cur_nums
->_lines
= (short)ilines
;
587 printf("$LINES override: lines = %d\n",
592 if ((icolumns
= atoi(ccp
)) > 0) {
594 cur_nums
->_columns
= (short)icolumns
;
596 printf("$COLUMNS override: columns = "
603 /* Pull out the strings. */
605 char **pp
= &cur_strs
->strs
._back_tab
;
606 char **fp
= &cur_strs
->strs4
.Sentinel
;
609 char *startstr
= ip
+ sizeof (short) *
612 printf("string table = '");
613 _Mprint(sstrtab
, startstr
);
620 Vr2val
= _Vr2getshi();
621 printf("String %s [%s] (%s) offset = %d [%d]",
622 strfnames
[tempindex
], strnames
[tempindex
],
623 strcodes
[tempindex
], n
, Vr2val
);
628 _Sprint(n
, startstr
+n
);
637 _Sprint(-1, (char *)0);
641 (void) memset((char *)pp
, 0, ((fp
- pp
) * sizeof (charptr
)));
644 (void) memcpy(strtab
, ip
, sstrtab
);
649 * If tabs are being expanded in software, turn this off
650 * so output won't get messed up. Also, don't use tab
651 * or backtab, even if the terminal has them, since the
652 * user might not have hardware tabs set right.
655 if ((PROGTTYS
.c_oflag
& TABDLY
) == TAB3
) {
656 PROGTTYS
.c_oflag
&= ~TABDLY
;
657 (void) reset_prog_mode();
661 if ((PROGTTY
.sg_flags
& XTABS
) == XTABS
) {
662 PROGTTY
.sg_flags
&= ~XTABS
;
663 (void) reset_prog_mode();
667 if (dest_tabs_magic_smso
) {
669 cur_strs
->strs2
._tab
= cur_strs
->strs
._back_tab
= NULL
;
673 ioctl(cur_term
-> Filedes
, TIOCLGET
, &n
);
677 #ifdef _VR2_COMPAT_CODE
678 (void) memcpy(&cur_term
->_b1
, &cur_bools
->_auto_left_margin
,
679 (char *)&cur_term
->_c1
- (char *)&cur_term
->_b1
);
680 (void) memcpy((char *)&cur_term
->_c1
, (char *)&cur_nums
->_columns
,
681 (char *)&cur_term
->_Vr2_Astrs
._s1
- (char *)&cur_term
->_c1
);
682 (void) memcpy((char *)&cur_term
->_Vr2_Astrs
._s1
,
683 (char *)&cur_strs
->strs
._back_tab
,
684 (char *)&cur_term
->Filedes
- (char *)&cur_term
->_Vr2_Astrs
._s1
);
685 #endif /* _VR2_COMPAT_CODE */
687 on_sequences
= cur_term
->turn_on_seq
;
688 str_array
= (char **)cur_strs
;
690 static char offsets
[] = {
691 35, /* enter_standout_mode, */
692 36, /* enter_underline_mode, */
693 25, /* enter_alt_charset_mode, */
694 34, /* enter_reverse_mode, */
695 26, /* enter_blink_mode, */
696 30, /* enter_dim_mode, */
697 27, /* enter_bold_mode, */
698 32, /* enter_secure_mode, */
699 33, /* enter_protected_mode, */
702 for (n
= 0; n
< NUM_ATTRIBUTES
; n
++) {
703 if ((on_sequences
[n
] = str_array
[offsets
[n
]]) != 0)
704 cur_term
->bit_vector
|= bit_attributes
[n
];
708 if (!(set_attributes
)) {
709 static char faked_attrs
[] = { 1, 3, 4, 6 },
711 43, /* exit_standout_mode, */
712 44, /* exit_underline_mode, */
713 38, /* exit_alt_charset_mode, */
715 char **off_sequences
= cur_term
->turn_off_seq
;
718 if ((max_attributes
== -1) && (ceol_standout_glitch
||
719 (magic_cookie_glitch
>= 0)))
722 /* Figure out what attributes need to be faked. */
723 /* See vidupdate.c */
725 for (n
= 0; n
< sizeof (faked_attrs
); n
++) {
726 if (on_sequences
[0] != NULL
) {
727 if ((!on_sequences
[i
= faked_attrs
[n
]]) ||
728 (strcmp(on_sequences
[i
],
729 on_sequences
[0]) == 0)) {
730 cur_term
->sgr_faked
|=
734 if (!on_sequences
[i
= faked_attrs
[n
]]) {
735 cur_term
->sgr_faked
|=
741 cur_term
->check_turn_off
= A_STANDOUT
| A_UNDERLINE
|
744 for (n
= 0; n
< sizeof (offsets
); n
++) {
745 if ((!(off_sequences
[n
] = str_array
[offsets
[n
]])) ||
746 ((n
> 0) && off_sequences
[0] &&
747 (strcmp(off_sequences
[n
], off_sequences
[0]) ==
748 0)) || ((n
== 2) && (exit_attribute_mode
) &&
749 (strcmp(exit_attribute_mode
, off_sequences
[n
]) ==
751 cur_term
->check_turn_off
&= ~bit_attributes
[n
];
755 cur_term
->cursor_seq
[0] = cursor_invisible
;
756 cur_term
->cursor_seq
[1] = cursor_normal
;
757 cur_term
->cursor_seq
[2] = cursor_visible
;
758 cur_term
->_pairs_tbl
= (_Color_pair
*) NULL
;
759 cur_term
->_color_tbl
= (_Color
*) NULL
;
765 _blast_keys(TERMINAL
*terminal
)
767 terminal
->_keys
= NULL
;
768 terminal
->internal_keys
= NULL
;
769 terminal
->_ksz
= terminal
->_first_macro
= 0;
770 terminal
->_lastkey_ordered
= terminal
->_lastmacro_ordered
= -1;
771 (void) memset((char *)terminal
->funckeystarter
, 0, 0400 *
778 reset_prog_mode(void)
781 if (_BRS(PROGTTYS
)) {
782 if (prog_istermios
< 0) {
785 PROGTTY
.c_lflag
= PROGTTYS
.c_lflag
;
786 PROGTTY
.c_oflag
= PROGTTYS
.c_oflag
;
787 PROGTTY
.c_iflag
= PROGTTYS
.c_iflag
;
788 PROGTTY
.c_cflag
= PROGTTYS
.c_cflag
;
789 for (i
= 0; i
< NCC
; i
++)
790 PROGTTY
.c_cc
[i
] = PROGTTYS
.c_cc
[i
];
791 (void) ioctl(cur_term
-> Filedes
, TCSETAW
, &PROGTTY
);
793 (void) ioctl(cur_term
-> Filedes
, TCSETSW
, &PROGTTYS
);
797 (void) ioctl(cur_term
-> Filedes
, TIOCSETN
, &PROGTTY
);
801 ioctl(cur_term
-> Filedes
, TIOCLGET
, &cur_term
-> oldlmode
);
802 cur_term
-> newlmode
= cur_term
-> oldlmode
& ~LTILDE
;
803 if (cur_term
-> newlmode
!= cur_term
-> oldlmode
)
804 ioctl(cur_term
-> Filedes
, TIOCLSET
, &cur_term
-> newlmode
);
807 if (cur_term
-> old
.st_termt
== 0)
808 ioctl(cur_term
->Filedes
, DIOCGETT
, &cur_term
-> old
);
809 cur_term
-> new = cur_term
-> old
;
810 cur_term
-> new.st_termt
= 0;
811 cur_term
-> new.st_flgs
|= TM_SET
;
812 ioctl(cur_term
->Filedes
, DIOCSETT
, &cur_term
-> new);
813 #endif /* DIOCSETT */
821 if ((shell_istermios
=
822 ioctl(cur_term
-> Filedes
, TCGETS
, &SHELLTTYS
)) < 0) {
825 (void) ioctl(cur_term
-> Filedes
, TCGETA
, &SHELLTTY
);
826 SHELLTTYS
.c_lflag
= SHELLTTY
.c_lflag
;
827 SHELLTTYS
.c_oflag
= SHELLTTY
.c_oflag
;
828 SHELLTTYS
.c_iflag
= SHELLTTY
.c_iflag
;
829 SHELLTTYS
.c_cflag
= SHELLTTY
.c_cflag
;
830 for (i
= 0; i
< NCC
; i
++)
831 SHELLTTYS
.c_cc
[i
] = SHELLTTY
.c_cc
[i
];
834 (void) ioctl(cur_term
-> Filedes
, TIOCGETP
, &SHELLTTY
);