4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2012 Gary Mills
28 /* Copyright (c) 1988 AT&T */
29 /* All Rights Reserved */
32 * tput - print terminal attribute
34 * return-codes - command line arguments:
35 * 0: ok if boolean capname -> TRUE
36 * 1: for boolean capname -> FALSE
38 * return-codes - standard input arguments:
39 * 0: ok; tput for all lines was successful
41 * return-codes - both cases:
43 * 3 bad terminal type given or no terminfo database
45 * -1 capname is a numeric variable that is not specified in the
46 * terminfo database(E.g. tpu -T450 lines).
48 * tput printfs a value if an INT capname was given; e.g. cols.
49 * putp's a string if a STRING capname was given; e.g. clear. and
50 * for BOOLEAN capnames, e.g. hard-copy, just returns the boolean value.
59 #include <sys/types.h>
63 /* externs from libcurses */
64 extern int tigetnum();
66 static int outputcap(char *cap
, int argc
, char **argv
);
67 static int allnumeric(char *string
);
68 static int getpad(char *cap
);
69 static void setdelay();
70 static void settabs();
71 static void cat(char *file
);
72 static void initterm();
73 static void reset_term();
75 static char *progname
; /* argv[0] */
76 static int CurrentBaudRate
; /* current baud rate */
77 static int reset
= 0; /* called as reset_term */
78 static int fildes
= 1;
81 main(int argc
, char **argv
)
84 char *term
= getenv("TERM");
85 char *cap
, std_input
= FALSE
;
88 (void) setlocale(LC_ALL
, "");
89 #if !defined(TEXT_DOMAIN)
90 #define TEXT_DOMAIN "SYS_TEST"
92 (void) textdomain(TEXT_DOMAIN
);
96 while ((i
= getopt(argc
, argv
, "ST:")) != EOF
) {
100 (void) putenv("LINES=");
101 (void) putenv("COLUMNS=");
109 case '?': /* FALLTHROUGH */
110 usage
: /* FALLTHROUGH */
112 (void) fprintf(stderr
, gettext(
113 "usage:\t%s [-T [term]] capname "
114 "[parm argument...]\n"), progname
);
115 (void) fprintf(stderr
, gettext("OR:\t%s -S <<\n"),
121 if (!term
|| !*term
) {
122 (void) fprintf(stderr
,
123 gettext("%s: No value for $TERM and no -T specified\n"),
128 (void) setupterm(term
, fildes
, &setuperr
);
132 (void) fprintf(stderr
,
133 gettext("%s: unreadable terminal descriptor \"%s\"\n"),
139 (void) fprintf(stderr
,
140 gettext("%s: no terminfo database\n"), progname
);
145 (void) fprintf(stderr
,
146 gettext("%s: unknown terminal \"%s\"\n"),
153 /* command line arguments */
158 cap
= argv
[optind
++];
160 if (strcmp(cap
, "init") == 0)
162 else if (strcmp(cap
, "reset") == 0)
164 else if (strcmp(cap
, "longname") == 0)
165 (void) printf("%s\n", longname());
167 exit(outputcap(cap
, argc
, argv
));
169 } else { /* standard input argumets */
173 /* allocate storage for the 'faked' argv[] array */
174 v
= (char **)malloc(10 * sizeof (char *));
175 for (i
= 0; i
< 10; i
++)
176 v
[i
] = (char *)malloc(32 * sizeof (char));
178 while (fgets(buff
, sizeof (buff
), stdin
) != NULL
) {
179 /* read standard input line; skip over empty lines */
182 "%31s %31s %31s %31s %31s %31s %31s %31s "
184 v
[0], v
[1], v
[2], v
[3], v
[4], v
[5], v
[6], v
[7],
192 if (strcmp(cap
, "init") == 0) {
194 } else if (strcmp(cap
, "reset") == 0) {
196 } else if (strcmp(cap
, "longname") == 0) {
197 (void) printf("%s\n", longname());
199 (void) outputcap(cap
, std_argc
, v
);
201 (void) fflush(stdout
);
208 static long parm
[9] = {
209 0, 0, 0, 0, 0, 0, 0, 0, 0
213 outputcap(char *cap
, int argc
, char **argv
)
219 if ((i
= tigetflag(cap
)) >= 0)
222 if ((i
= tigetnum(cap
)) >= -1) {
223 (void) printf("%d\n", i
);
227 if ((thisstr
= tigetstr(cap
)) != (char *)-1) {
231 for (parmset
= 0; optind
< argc
; optind
++, parmset
++)
232 if (allnumeric(argv
[optind
]))
233 parm
[parmset
] = atoi(argv
[optind
]);
235 parm
[parmset
] = (int)argv
[optind
];
239 parm
[0], parm
[1], parm
[2], parm
[3],
240 parm
[4], parm
[5], parm
[6], parm
[7], parm
[8]));
246 (void) fprintf(stderr
,
247 gettext("%s: unknown terminfo capability '%s'\n"), progname
, cap
);
254 * The decision as to whether an argument is a number or not is to simply
255 * look at whether there are any non-digits in the string.
258 allnumeric(char *string
)
262 if (!isdigit(*string
++)) {
273 * SYSTEM DEPENDENT TERMINAL DELAY TABLES
275 * These tables maintain the correspondence between the delays
276 * defined in terminfo and the delay algorithms in the tty driver
277 * on the particular systems. For each type of delay, the bits used
278 * for that delay must be specified, in XXbits, and a table
279 * must be defined giving correspondences between delays and
280 * algorithms. Algorithms which are not fixed delays, such
281 * as dependent on current column or line number, must be
282 * kludged in some way at this time.
284 * Some of this was taken from tset(1).
293 /* The appropriate speeds for various termio settings. */
294 static int speeds
[] = {
313 115200, /* B115200, */
314 153600, /* B153600, */
315 230400, /* B230400, */
316 307200, /* B307200, */
317 460800, /* B460800, */
318 921600, /* B921600, */
322 #if defined(SYSV) || defined(USG)
325 /* Carriage Return delays */
327 static int CRbits
= CRDLY
;
328 static struct delay CRdelay
[] =
337 /* New Line delays */
339 static int NLbits
= NLDLY
;
340 static struct delay NLdelay
[] =
347 /* Back Space delays */
349 static int BSbits
= BSDLY
;
350 static struct delay BSdelay
[] =
359 static int TBbits
= TABDLY
;
360 static struct delay TBdelay
[] =
363 11, TAB1
, /* special M37 delay */
365 /* TAB3 is XTABS and not a delay */
369 /* Form Feed delays */
371 static int FFbits
= FFDLY
;
372 static struct delay FFdelay
[] =
381 /* Carriage Return delays */
383 int CRbits
= CRDELAY
;
384 struct delay CRdelay
[] =
393 /* New Line delays */
395 int NLbits
= NLDELAY
;
396 struct delay NLdelay
[] =
399 66, NL1
, /* special M37 delay */
406 int TBbits
= TBDELAY
;
407 struct delay TBdelay
[] =
410 11, TAB1
, /* special M37 delay */
414 /* Form Feed delays */
416 int FFbits
= VTDELAY
;
417 struct delay FFdelay
[] =
426 * Initterm, a.k.a. reset_term, does terminal specific initialization. In
427 * particular, the init_strings from terminfo are output and tabs are
428 * set, if they aren't hardwired in. Much of this stuff was done by
429 * the tset(1) program.
433 * Figure out how many milliseconds of padding the capability cap
434 * needs and return that number. Padding is stored in the string as "$<n>",
435 * where n is the number of milliseconds of padding. More than one
436 * padding string is allowed within the string, although this is unlikely.
444 /* No padding needed at speeds below padding_baud_rate */
445 if (padding_baud_rate
> CurrentBaudRate
|| cap
== NULL
)
449 if ((cap
[0] == '$') && (cap
[1] == '<')) {
452 padding
+= atoi(cap
);
453 while (isdigit (*cap
))
455 while (*cap
== '.' || *cap
== '/' || *cap
== '*' ||
469 * Set the appropriate delay bits in the termio structure for
473 setdelay(delay
, delaytable
, bits
, flags
)
475 struct delay delaytable
[];
480 unsigned short *flags
;
483 register struct delay
*p
;
484 register struct delay
*lastdelay
;
486 /* Clear out the bits, replace with new ones */
489 /* Scan the delay table for first entry with adequate delay */
490 for (lastdelay
= p
= delaytable
;
491 (p
-> d_delay
>= 0) && (p
-> d_delay
< delay
);
496 /* use last entry if none will do */
497 *flags
|= lastdelay
-> d_bits
;
501 * Set the hardware tabs on the terminal, using clear_all_tabs,
502 * set_tab, and column_address capabilities. Cursor_address and cursor_right
503 * may also be used, if necessary.
504 * This is done before the init_file and init_3string, so they can patch in
513 /* Do not set tabs if they power up properly. */
518 /* Force the cursor to be at the left margin. */
520 putp(carriage_return
);
522 (void) putchar('\r');
524 /* Clear any current tab settings. */
526 putp(clear_all_tabs
);
529 for (c
= 8; c
< columns
; c
+= 8) {
530 /* Get to that column. */
531 (void) fputs(" ", stdout
);
537 /* Get back to the left column. */
539 putp(carriage_return
);
541 (void) putchar('\r');
547 * Copy "file" onto standard output.
552 char *file
; /* File to copy. */
554 register int fd
; /* File descriptor. */
555 register ssize_t i
; /* Number characters read. */
556 char buf
[BUFSIZ
]; /* Buffer to read into. */
558 fd
= open(file
, O_RDONLY
);
561 perror("Cannot open initialization file");
563 while ((i
= read(fd
, buf
, BUFSIZ
)) > (ssize_t
)0)
564 (void) write(fileno(stdout
), buf
, (unsigned)i
);
570 * Initialize the terminal.
571 * Send the initialization strings to the terminal.
577 register int filedes
; /* File descriptor for ioctl's. */
578 #if defined(SYSV) || defined(USG)
579 struct termio termmode
; /* To hold terminal settings. */
580 struct termios termmodes
; /* To hold terminal settings. */
583 #define GTTY(fd, mode) ioctl(fd, TCGETA, mode)
584 #define GTTYS(fd, mode) \
585 (istermios = ioctl(fd, TCGETS, mode))
586 #define STTY(fd, mode) ioctl(fd, TCSETAW, mode)
587 #define STTYS(fd, mode) ioctl(fd, TCSETSW, mode)
588 #define SPEED(mode) (mode.c_cflag & CBAUD)
589 #define SPEEDS(mode) (cfgetospeed(&mode))
590 #define OFLAG(mode) mode.c_oflag
592 struct sgttyb termmode
; /* To hold terminal settings. */
593 #define GTTY(fd, mode) gtty(fd, mode)
594 #define STTY(fd, mode) stty(fd, mode)
595 #define SPEED(mode) (mode.sg_ospeed & 017)
596 #define OFLAG(mode) mode.sg_flags
600 /* Get the terminal settings. */
601 /* First try standard output, then standard error, */
602 /* then standard input, then /dev/tty. */
604 if ((filedes
= 1, GTTYS(filedes
, &termmodes
) < 0) ||
605 (filedes
= 2, GTTYS(filedes
, &termmodes
) < 0) ||
606 (filedes
= 0, GTTYS(filedes
, &termmodes
) < 0) ||
607 (filedes
= open("/dev/tty", O_RDWR
),
608 GTTYS(filedes
, &termmodes
) < 0)) {
610 if ((filedes
= 1, GTTY(filedes
, &termmode
) == -1) ||
611 (filedes
= 2, GTTY(filedes
, &termmode
) == -1) ||
612 (filedes
= 0, GTTY(filedes
, &termmode
) == -1) ||
613 (filedes
= open("/dev/tty", O_RDWR
),
614 GTTY(filedes
, &termmode
) == -1)) {
616 CurrentBaudRate
= speeds
[B1200
];
618 CurrentBaudRate
= speeds
[SPEED(termmode
)];
620 termmodes
.c_lflag
= termmode
.c_lflag
;
621 termmodes
.c_oflag
= termmode
.c_oflag
;
622 termmodes
.c_iflag
= termmode
.c_iflag
;
623 termmodes
.c_cflag
= termmode
.c_cflag
;
624 for (i
= 0; i
< NCC
; i
++)
625 termmodes
.c_cc
[i
] = termmode
.c_cc
[i
];
627 CurrentBaudRate
= speeds
[SPEEDS(termmodes
)];
633 ~(NLbits
| CRbits
| BSbits
| FFbits
| TBbits
);
636 ~(NLbits
| CRbits
| BSbits
| FFbits
| TBbits
);
640 setdelay(getpad(carriage_return
),
641 CRdelay
, CRbits
, &OFLAG(termmodes
));
642 setdelay(getpad(scroll_forward
),
643 NLdelay
, NLbits
, &OFLAG(termmodes
));
644 setdelay(getpad(cursor_left
),
645 BSdelay
, BSbits
, &OFLAG(termmodes
));
646 setdelay(getpad(form_feed
),
647 FFdelay
, FFbits
, &OFLAG(termmodes
));
648 setdelay(getpad(tab
),
649 TBdelay
, TBbits
, &OFLAG(termmodes
));
651 setdelay(getpad(carriage_return
),
652 CRdelay
, CRbits
, &OFLAG(termmode
));
653 setdelay(getpad(scroll_forward
),
654 NLdelay
, NLbits
, &OFLAG(termmode
));
655 setdelay(getpad(cursor_left
),
656 BSdelay
, BSbits
, &OFLAG(termmode
));
657 setdelay(getpad(form_feed
),
658 FFdelay
, FFbits
, &OFLAG(termmode
));
659 setdelay(getpad(tab
),
660 TBdelay
, TBbits
, &OFLAG(termmode
));
664 /* If tabs can be sent to the tty, turn off their expansion. */
665 if (tab
&& set_tab
|| init_tabs
== 8) {
667 OFLAG(termmodes
) &= ~(TAB3
);
669 OFLAG(termmode
) &= ~(TAB3
);
673 OFLAG(termmodes
) |= TAB3
;
675 OFLAG(termmode
) |= TAB3
;
679 /* Do the changes to the terminal settings */
684 termmode
.c_lflag
= termmodes
.c_lflag
;
685 termmode
.c_oflag
= termmodes
.c_oflag
;
686 termmode
.c_iflag
= termmodes
.c_iflag
;
687 termmode
.c_cflag
= termmodes
.c_cflag
;
688 for (i
= 0; i
< NCC
; i
++)
689 termmode
.c_cc
[i
] = termmodes
.c_cc
[i
];
690 (void) STTY(filedes
, &termmode
);
692 (void) STTYS(filedes
, &termmodes
);
695 (void) STTY(filedes
, &termmode
);
698 /* Send first initialization strings. */
700 (void) system(init_prog
);
702 if (reset
&& reset_1string
) {
704 } else if (init_1string
) {
708 if (reset
&& reset_2string
) {
710 } else if (init_2string
) {
714 /* Set up the tabs stops. */
717 /* Send out initializing file. */
718 if (reset
&& reset_file
) {
720 } else if (init_file
) {
724 /* Send final initialization strings. */
725 if (reset
&& reset_3string
) {
727 } else if (init_3string
) {
731 if (carriage_return
) {
732 putp(carriage_return
);
734 (void) putchar('\r');
737 /* Send color initialization strings */
745 /* Let the terminal settle down. */
746 (void) fflush(stdout
);