702 tput calls gets()
[unleashed.git] / usr / src / cmd / tput / tput.c
blobc8a61cc2eebea9ad57a846c5d8fa87e4e3b2a50b
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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:
42 * 2 usage error
43 * 3 bad terminal type given or no terminfo database
44 * 4 unknown capname
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.
53 #include <curses.h>
54 #include <term.h>
55 #include <fcntl.h>
56 #include <ctype.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <sys/types.h>
60 #include <unistd.h>
61 #include <locale.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;
80 int
81 main(int argc, char **argv)
83 int i, std_argc;
84 char *term = getenv("TERM");
85 char *cap, std_input = FALSE;
86 int setuperr;
88 (void) setlocale(LC_ALL, "");
89 #if !defined(TEXT_DOMAIN)
90 #define TEXT_DOMAIN "SYS_TEST"
91 #endif
92 (void) textdomain(TEXT_DOMAIN);
94 progname = argv[0];
96 while ((i = getopt(argc, argv, "ST:")) != EOF) {
97 switch (i) {
98 case 'T':
99 fildes = -1;
100 (void) putenv("LINES=");
101 (void) putenv("COLUMNS=");
102 term = optarg;
103 break;
105 case 'S':
106 std_input = TRUE;
107 break;
109 case '?': /* FALLTHROUGH */
110 usage: /* FALLTHROUGH */
111 default:
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"),
116 progname);
117 exit(2);
121 if (!term || !*term) {
122 (void) fprintf(stderr,
123 gettext("%s: No value for $TERM and no -T specified\n"),
124 progname);
125 exit(2);
128 (void) setupterm(term, fildes, &setuperr);
130 switch (setuperr) {
131 case -2:
132 (void) fprintf(stderr,
133 gettext("%s: unreadable terminal descriptor \"%s\"\n"),
134 progname, term);
135 exit(3);
136 break;
138 case -1:
139 (void) fprintf(stderr,
140 gettext("%s: no terminfo database\n"), progname);
141 exit(3);
142 break;
144 case 0:
145 (void) fprintf(stderr,
146 gettext("%s: unknown terminal \"%s\"\n"),
147 progname, term);
148 exit(3);
151 reset_shell_mode();
153 /* command line arguments */
154 if (!std_input) {
155 if (argc == optind)
156 goto usage;
158 cap = argv[optind++];
160 if (strcmp(cap, "init") == 0)
161 initterm();
162 else if (strcmp(cap, "reset") == 0)
163 reset_term();
164 else if (strcmp(cap, "longname") == 0)
165 (void) printf("%s\n", longname());
166 else
167 exit(outputcap(cap, argc, argv));
168 return (0);
169 } else { /* standard input argumets */
170 char buff[128];
171 char **v;
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 */
180 if ((std_argc =
181 sscanf(buff,
182 "%31s %31s %31s %31s %31s %31s %31s %31s "
183 "%31s %31s",
184 v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],
185 v[8], v[9])) < 1) {
186 continue;
189 cap = v[0];
190 optind = 1;
192 if (strcmp(cap, "init") == 0) {
193 initterm();
194 } else if (strcmp(cap, "reset") == 0) {
195 reset_term();
196 } else if (strcmp(cap, "longname") == 0) {
197 (void) printf("%s\n", longname());
198 } else {
199 (void) outputcap(cap, std_argc, v);
201 (void) fflush(stdout);
204 return (0);
208 static long parm[9] = {
209 0, 0, 0, 0, 0, 0, 0, 0, 0
212 static int
213 outputcap(char *cap, int argc, char **argv)
215 int parmset = 0;
216 char *thisstr;
217 int i;
219 if ((i = tigetflag(cap)) >= 0)
220 return (1 - i);
222 if ((i = tigetnum(cap)) >= -1) {
223 (void) printf("%d\n", i);
224 return (0);
227 if ((thisstr = tigetstr(cap)) != (char *)-1) {
228 if (!thisstr) {
229 return (1);
231 for (parmset = 0; optind < argc; optind++, parmset++)
232 if (allnumeric(argv[optind]))
233 parm[parmset] = atoi(argv[optind]);
234 else
235 parm[parmset] = (int)argv[optind];
237 if (parmset)
238 putp(tparm(thisstr,
239 parm[0], parm[1], parm[2], parm[3],
240 parm[4], parm[5], parm[6], parm[7], parm[8]));
241 else
242 putp(thisstr);
243 return (0);
246 (void) fprintf(stderr,
247 gettext("%s: unknown terminfo capability '%s'\n"), progname, cap);
249 exit(4);
250 /* NOTREACHED */
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.
257 static int
258 allnumeric(char *string)
260 if (*string) {
261 while (*string) {
262 if (!isdigit(*string++)) {
263 return (0);
266 return (1);
267 } else {
268 return (0);
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).
287 struct delay
289 int d_delay;
290 int d_bits;
293 /* The appropriate speeds for various termio settings. */
294 static int speeds[] = {
295 0, /* B0, */
296 50, /* B50, */
297 75, /* B75, */
298 110, /* B110, */
299 134, /* B134, */
300 150, /* B150, */
301 200, /* B200, */
302 300, /* B300, */
303 600, /* B600, */
304 1200, /* B1200, */
305 1800, /* B1800, */
306 2400, /* B2400, */
307 4800, /* B4800, */
308 9600, /* B9600, */
309 19200, /* EXTA, */
310 38400, /* EXTB, */
311 57600, /* B57600, */
312 76800, /* B76800, */
313 115200, /* B115200, */
314 153600, /* B153600, */
315 230400, /* B230400, */
316 307200, /* B307200, */
317 460800, /* B460800, */
318 921600, /* B921600, */
322 #if defined(SYSV) || defined(USG)
323 /* Unix 3.0 on up */
325 /* Carriage Return delays */
327 static int CRbits = CRDLY;
328 static struct delay CRdelay[] =
330 0, CR0,
331 80, CR1,
332 100, CR2,
333 150, CR3,
337 /* New Line delays */
339 static int NLbits = NLDLY;
340 static struct delay NLdelay[] =
342 0, NL0,
343 100, NL1,
347 /* Back Space delays */
349 static int BSbits = BSDLY;
350 static struct delay BSdelay[] =
352 0, BS0,
353 50, BS1,
357 /* TaB delays */
359 static int TBbits = TABDLY;
360 static struct delay TBdelay[] =
362 0, TAB0,
363 11, TAB1, /* special M37 delay */
364 100, TAB2,
365 /* TAB3 is XTABS and not a delay */
369 /* Form Feed delays */
371 static int FFbits = FFDLY;
372 static struct delay FFdelay[] =
374 0, FF0,
375 2000, FF1,
379 #else /* BSD */
381 /* Carriage Return delays */
383 int CRbits = CRDELAY;
384 struct delay CRdelay[] =
386 0, CR0,
387 9, CR3,
388 80, CR1,
389 160, CR2,
393 /* New Line delays */
395 int NLbits = NLDELAY;
396 struct delay NLdelay[] =
398 0, NL0,
399 66, NL1, /* special M37 delay */
400 100, NL2,
404 /* Tab delays */
406 int TBbits = TBDELAY;
407 struct delay TBdelay[] =
409 0, TAB0,
410 11, TAB1, /* special M37 delay */
414 /* Form Feed delays */
416 int FFbits = VTDELAY;
417 struct delay FFdelay[] =
419 0, FF0,
420 2000, FF1,
423 #endif /* BSD */
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.
439 static int
440 getpad(char *cap)
442 int padding = 0;
444 /* No padding needed at speeds below padding_baud_rate */
445 if (padding_baud_rate > CurrentBaudRate || cap == NULL)
446 return (0);
448 while (*cap) {
449 if ((cap[0] == '$') && (cap[1] == '<')) {
450 cap++;
451 cap++;
452 padding += atoi(cap);
453 while (isdigit (*cap))
454 cap++;
455 while (*cap == '.' || *cap == '/' || *cap == '*' ||
456 isdigit(*cap))
457 cap++;
458 while (*cap == '>')
459 cap++;
460 } else {
461 cap++;
465 return (padding);
469 * Set the appropriate delay bits in the termio structure for
470 * the given delay.
472 static void
473 setdelay(delay, delaytable, bits, flags)
474 register int delay;
475 struct delay delaytable[];
476 int bits;
477 #ifdef SYSV
478 tcflag_t *flags;
479 #else /* SYSV */
480 unsigned short *flags;
481 #endif /* SYSV */
483 register struct delay *p;
484 register struct delay *lastdelay;
486 /* Clear out the bits, replace with new ones */
487 *flags &= ~bits;
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);
492 p++) {
493 lastdelay = p;
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
505 * case we blow this.
508 static void
509 settabs()
511 register int c;
513 /* Do not set tabs if they power up properly. */
514 if (init_tabs == 8)
515 return;
517 if (set_tab) {
518 /* Force the cursor to be at the left margin. */
519 if (carriage_return)
520 putp(carriage_return);
521 else
522 (void) putchar('\r');
524 /* Clear any current tab settings. */
525 if (clear_all_tabs)
526 putp(clear_all_tabs);
528 /* Set the tabs. */
529 for (c = 8; c < columns; c += 8) {
530 /* Get to that column. */
531 (void) fputs(" ", stdout);
533 /* Set the tab. */
534 putp(set_tab);
537 /* Get back to the left column. */
538 if (carriage_return)
539 putp(carriage_return);
540 else
541 (void) putchar('\r');
547 * Copy "file" onto standard output.
550 static void
551 cat(file)
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);
560 if (fd < 0) {
561 perror("Cannot open initialization file");
562 } else {
563 while ((i = read(fd, buf, BUFSIZ)) > (ssize_t)0)
564 (void) write(fileno(stdout), buf, (unsigned)i);
565 (int)close(fd);
570 * Initialize the terminal.
571 * Send the initialization strings to the terminal.
574 static void
575 initterm()
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. */
581 int i;
582 int istermios = -1;
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
591 #else /* BSD */
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
597 #define TAB3 XTABS
598 #endif
600 /* Get the terminal settings. */
601 /* First try standard output, then standard error, */
602 /* then standard input, then /dev/tty. */
603 #ifdef SYSV
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)) {
609 #endif /* SYSV */
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)) {
615 filedes = -1;
616 CurrentBaudRate = speeds[B1200];
617 } else
618 CurrentBaudRate = speeds[SPEED(termmode)];
619 #ifdef SYSV
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];
626 } else
627 CurrentBaudRate = speeds[SPEEDS(termmodes)];
628 #endif /* SYSV */
630 if (xon_xoff) {
631 #ifdef SYSV
632 OFLAG(termmodes) &=
633 ~(NLbits | CRbits | BSbits | FFbits | TBbits);
634 #else /* SYSV */
635 OFLAG(termmode) &=
636 ~(NLbits | CRbits | BSbits | FFbits | TBbits);
637 #endif /* SYSV */
638 } else {
639 #ifdef SYSV
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));
650 #else /* SYSV */
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));
661 #endif /* SYSV */
664 /* If tabs can be sent to the tty, turn off their expansion. */
665 if (tab && set_tab || init_tabs == 8) {
666 #ifdef SYSV
667 OFLAG(termmodes) &= ~(TAB3);
668 #else /* SYSV */
669 OFLAG(termmode) &= ~(TAB3);
670 #endif /* SYSV */
671 } else {
672 #ifdef SYSV
673 OFLAG(termmodes) |= TAB3;
674 #else /* SYSV */
675 OFLAG(termmode) |= TAB3;
676 #endif /* SYSV */
679 /* Do the changes to the terminal settings */
680 #ifdef SYSV
681 if (istermios < 0) {
682 int i;
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);
691 } else
692 (void) STTYS(filedes, &termmodes);
694 #else /* SYSV */
695 (void) STTY(filedes, &termmode);
696 #endif /* SYSV */
698 /* Send first initialization strings. */
699 if (init_prog)
700 (void) system(init_prog);
702 if (reset && reset_1string) {
703 putp(reset_1string);
704 } else if (init_1string) {
705 putp(init_1string);
708 if (reset && reset_2string) {
709 putp(reset_2string);
710 } else if (init_2string) {
711 putp(init_2string);
714 /* Set up the tabs stops. */
715 settabs();
717 /* Send out initializing file. */
718 if (reset && reset_file) {
719 cat(reset_file);
720 } else if (init_file) {
721 cat(init_file);
724 /* Send final initialization strings. */
725 if (reset && reset_3string) {
726 putp(reset_3string);
727 } else if (init_3string) {
728 putp(init_3string);
731 if (carriage_return) {
732 putp(carriage_return);
733 } else {
734 (void) putchar('\r');
737 /* Send color initialization strings */
739 if (orig_colors)
740 putp(orig_colors);
742 if (orig_pair)
743 putp(orig_pair);
745 /* Let the terminal settle down. */
746 (void) fflush(stdout);
747 (void) sleep(1);
750 static void
751 reset_term()
753 reset++;
754 initterm();