15f4613f2SJohn Marino /****************************************************************************
2*32bb5217SDaniel Fojt * Copyright 2018-2019,2020 Thomas E. Dickey *
3*32bb5217SDaniel Fojt * Copyright 1998-2016,2017 Free Software Foundation, Inc. *
45f4613f2SJohn Marino * *
55f4613f2SJohn Marino * Permission is hereby granted, free of charge, to any person obtaining a *
65f4613f2SJohn Marino * copy of this software and associated documentation files (the *
75f4613f2SJohn Marino * "Software"), to deal in the Software without restriction, including *
85f4613f2SJohn Marino * without limitation the rights to use, copy, modify, merge, publish, *
95f4613f2SJohn Marino * distribute, distribute with modifications, sublicense, and/or sell *
105f4613f2SJohn Marino * copies of the Software, and to permit persons to whom the Software is *
115f4613f2SJohn Marino * furnished to do so, subject to the following conditions: *
125f4613f2SJohn Marino * *
135f4613f2SJohn Marino * The above copyright notice and this permission notice shall be included *
145f4613f2SJohn Marino * in all copies or substantial portions of the Software. *
155f4613f2SJohn Marino * *
165f4613f2SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
175f4613f2SJohn Marino * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
185f4613f2SJohn Marino * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
195f4613f2SJohn Marino * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
205f4613f2SJohn Marino * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
215f4613f2SJohn Marino * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
225f4613f2SJohn Marino * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
235f4613f2SJohn Marino * *
245f4613f2SJohn Marino * Except as contained in this notice, the name(s) of the above copyright *
255f4613f2SJohn Marino * holders shall not be used in advertising or otherwise to promote the *
265f4613f2SJohn Marino * sale, use or other dealings in this Software without prior written *
275f4613f2SJohn Marino * authorization. *
285f4613f2SJohn Marino ****************************************************************************/
295f4613f2SJohn Marino
305f4613f2SJohn Marino /****************************************************************************
315f4613f2SJohn Marino * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
325f4613f2SJohn Marino * and: Eric S. Raymond <esr@snark.thyrsus.com> *
333468e90cSJohn Marino * and: Thomas E. Dickey 1996-on *
345f4613f2SJohn Marino ****************************************************************************/
355f4613f2SJohn Marino
365f4613f2SJohn Marino /*
375f4613f2SJohn Marino * tput.c -- shellscript access to terminal capabilities
385f4613f2SJohn Marino *
395f4613f2SJohn Marino * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
405f4613f2SJohn Marino * Ross Ridge's mytinfo package.
415f4613f2SJohn Marino */
425f4613f2SJohn Marino
433468e90cSJohn Marino #include <tparm_type.h>
44*32bb5217SDaniel Fojt #include <clear_cmd.h>
45*32bb5217SDaniel Fojt #include <reset_cmd.h>
465f4613f2SJohn Marino
475f4613f2SJohn Marino #if !PURE_TERMINFO
485f4613f2SJohn Marino #include <dump_entry.h>
495f4613f2SJohn Marino #include <termsort.c>
505f4613f2SJohn Marino #endif
515f4613f2SJohn Marino #include <transform.h>
52*32bb5217SDaniel Fojt #include <tty_settings.h>
535f4613f2SJohn Marino
54*32bb5217SDaniel Fojt MODULE_ID("$Id: tput.c,v 1.81 2020/02/02 23:34:34 tom Exp $")
555f4613f2SJohn Marino
565f4613f2SJohn Marino #define PUTS(s) fputs(s, stdout)
57*32bb5217SDaniel Fojt
58*32bb5217SDaniel Fojt const char *_nc_progname = "tput";
595f4613f2SJohn Marino
605f4613f2SJohn Marino static char *prg_name;
615f4613f2SJohn Marino static bool is_init = FALSE;
625f4613f2SJohn Marino static bool is_reset = FALSE;
63*32bb5217SDaniel Fojt static bool is_clear = FALSE;
645f4613f2SJohn Marino
655f4613f2SJohn Marino static void
quit(int status,const char * fmt,...)665f4613f2SJohn Marino quit(int status, const char *fmt,...)
675f4613f2SJohn Marino {
685f4613f2SJohn Marino va_list argp;
695f4613f2SJohn Marino
705f4613f2SJohn Marino va_start(argp, fmt);
715f4613f2SJohn Marino fprintf(stderr, "%s: ", prg_name);
725f4613f2SJohn Marino vfprintf(stderr, fmt, argp);
735f4613f2SJohn Marino fprintf(stderr, "\n");
745f4613f2SJohn Marino va_end(argp);
755f4613f2SJohn Marino ExitProgram(status);
765f4613f2SJohn Marino }
775f4613f2SJohn Marino
785f4613f2SJohn Marino static void
usage(void)795f4613f2SJohn Marino usage(void)
805f4613f2SJohn Marino {
81*32bb5217SDaniel Fojt #define KEEP(s) s "\n"
82*32bb5217SDaniel Fojt static const char msg[] =
83*32bb5217SDaniel Fojt {
84*32bb5217SDaniel Fojt KEEP("")
85*32bb5217SDaniel Fojt KEEP("Options:")
86*32bb5217SDaniel Fojt KEEP(" -S << read commands from standard input")
87*32bb5217SDaniel Fojt KEEP(" -T TERM use this instead of $TERM")
88*32bb5217SDaniel Fojt KEEP(" -V print curses-version")
89*32bb5217SDaniel Fojt KEEP(" -x do not try to clear scrollback")
90*32bb5217SDaniel Fojt KEEP("")
91*32bb5217SDaniel Fojt KEEP("Commands:")
92*32bb5217SDaniel Fojt KEEP(" clear clear the screen")
93*32bb5217SDaniel Fojt KEEP(" init initialize the terminal")
94*32bb5217SDaniel Fojt KEEP(" reset reinitialize the terminal")
95*32bb5217SDaniel Fojt KEEP(" capname unlike clear/init/reset, print value for capability \"capname\"")
96*32bb5217SDaniel Fojt };
97*32bb5217SDaniel Fojt #undef KEEP
98*32bb5217SDaniel Fojt (void) fprintf(stderr, "Usage: %s [options] [command]\n", prg_name);
99*32bb5217SDaniel Fojt fputs(msg, stderr);
100*32bb5217SDaniel Fojt ExitProgram(ErrUsage);
1015f4613f2SJohn Marino }
1025f4613f2SJohn Marino
103*32bb5217SDaniel Fojt static char *
check_aliases(char * name,bool program)104*32bb5217SDaniel Fojt check_aliases(char *name, bool program)
1055f4613f2SJohn Marino {
106*32bb5217SDaniel Fojt static char my_init[] = "init";
107*32bb5217SDaniel Fojt static char my_reset[] = "reset";
108*32bb5217SDaniel Fojt static char my_clear[] = "clear";
109*32bb5217SDaniel Fojt
110*32bb5217SDaniel Fojt char *result = name;
111*32bb5217SDaniel Fojt if ((is_init = same_program(name, program ? PROG_INIT : my_init)))
112*32bb5217SDaniel Fojt result = my_init;
113*32bb5217SDaniel Fojt if ((is_reset = same_program(name, program ? PROG_RESET : my_reset)))
114*32bb5217SDaniel Fojt result = my_reset;
115*32bb5217SDaniel Fojt if ((is_clear = same_program(name, program ? PROG_CLEAR : my_clear)))
116*32bb5217SDaniel Fojt result = my_clear;
117*32bb5217SDaniel Fojt return result;
1185f4613f2SJohn Marino }
1195f4613f2SJohn Marino
1205f4613f2SJohn Marino static int
exit_code(int token,int value)1215f4613f2SJohn Marino exit_code(int token, int value)
1225f4613f2SJohn Marino {
1235f4613f2SJohn Marino int result = 99;
1245f4613f2SJohn Marino
1255f4613f2SJohn Marino switch (token) {
1265f4613f2SJohn Marino case BOOLEAN:
1275f4613f2SJohn Marino result = !value; /* TRUE=0, FALSE=1 */
1285f4613f2SJohn Marino break;
1295f4613f2SJohn Marino case NUMBER:
1305f4613f2SJohn Marino result = 0; /* always zero */
1315f4613f2SJohn Marino break;
1325f4613f2SJohn Marino case STRING:
1335f4613f2SJohn Marino result = value; /* 0=normal, 1=missing */
1345f4613f2SJohn Marino break;
1355f4613f2SJohn Marino }
1365f4613f2SJohn Marino return result;
1375f4613f2SJohn Marino }
1385f4613f2SJohn Marino
139*32bb5217SDaniel Fojt /*
140*32bb5217SDaniel Fojt * Returns nonzero on error.
141*32bb5217SDaniel Fojt */
1425f4613f2SJohn Marino static int
tput_cmd(int fd,TTY * saved_settings,bool opt_x,int argc,char * argv[])143*32bb5217SDaniel Fojt tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])
1445f4613f2SJohn Marino {
1455f4613f2SJohn Marino NCURSES_CONST char *name;
1465f4613f2SJohn Marino char *s;
1475f4613f2SJohn Marino int status;
1485f4613f2SJohn Marino #if !PURE_TERMINFO
1495f4613f2SJohn Marino bool termcap = FALSE;
1505f4613f2SJohn Marino #endif
1515f4613f2SJohn Marino
152*32bb5217SDaniel Fojt name = check_aliases(argv[0], FALSE);
1535f4613f2SJohn Marino if (is_reset || is_init) {
154*32bb5217SDaniel Fojt TTY oldmode;
1555f4613f2SJohn Marino
156*32bb5217SDaniel Fojt int terasechar = -1; /* new erase character */
157*32bb5217SDaniel Fojt int intrchar = -1; /* new interrupt character */
158*32bb5217SDaniel Fojt int tkillchar = -1; /* new kill character */
1595f4613f2SJohn Marino
160*32bb5217SDaniel Fojt if (is_reset) {
161*32bb5217SDaniel Fojt reset_start(stdout, TRUE, FALSE);
162*32bb5217SDaniel Fojt reset_tty_settings(fd, saved_settings);
163*32bb5217SDaniel Fojt } else {
164*32bb5217SDaniel Fojt reset_start(stdout, FALSE, TRUE);
1655f4613f2SJohn Marino }
1665f4613f2SJohn Marino
167*32bb5217SDaniel Fojt #if HAVE_SIZECHANGE
168*32bb5217SDaniel Fojt set_window_size(fd, &lines, &columns);
169*32bb5217SDaniel Fojt #else
170*32bb5217SDaniel Fojt (void) fd;
1715f4613f2SJohn Marino #endif
172*32bb5217SDaniel Fojt set_control_chars(saved_settings, terasechar, intrchar, tkillchar);
173*32bb5217SDaniel Fojt set_conversions(saved_settings);
174*32bb5217SDaniel Fojt if (send_init_strings(fd, &oldmode)) {
175*32bb5217SDaniel Fojt reset_flush();
1765f4613f2SJohn Marino }
1775f4613f2SJohn Marino
178*32bb5217SDaniel Fojt update_tty_settings(&oldmode, saved_settings);
1795f4613f2SJohn Marino return 0;
1805f4613f2SJohn Marino }
1815f4613f2SJohn Marino
1825f4613f2SJohn Marino if (strcmp(name, "longname") == 0) {
1835f4613f2SJohn Marino PUTS(longname());
1845f4613f2SJohn Marino return 0;
1855f4613f2SJohn Marino }
1865f4613f2SJohn Marino #if !PURE_TERMINFO
1875f4613f2SJohn Marino retry:
1885f4613f2SJohn Marino #endif
189*32bb5217SDaniel Fojt if (strcmp(name, "clear") == 0) {
190*32bb5217SDaniel Fojt return (clear_cmd(opt_x) == ERR) ? ErrUsage : 0;
191*32bb5217SDaniel Fojt } else if ((status = tigetflag(name)) != -1) {
1925f4613f2SJohn Marino return exit_code(BOOLEAN, status);
1935f4613f2SJohn Marino } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
1945f4613f2SJohn Marino (void) printf("%d\n", status);
1955f4613f2SJohn Marino return exit_code(NUMBER, 0);
1965f4613f2SJohn Marino } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
1975f4613f2SJohn Marino #if !PURE_TERMINFO
1985f4613f2SJohn Marino if (!termcap) {
1995f4613f2SJohn Marino const struct name_table_entry *np;
2005f4613f2SJohn Marino
2015f4613f2SJohn Marino termcap = TRUE;
2025f4613f2SJohn Marino if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
2035f4613f2SJohn Marino switch (np->nte_type) {
2045f4613f2SJohn Marino case BOOLEAN:
2055f4613f2SJohn Marino name = boolnames[np->nte_index];
2065f4613f2SJohn Marino break;
2075f4613f2SJohn Marino
2085f4613f2SJohn Marino case NUMBER:
2095f4613f2SJohn Marino name = numnames[np->nte_index];
2105f4613f2SJohn Marino break;
2115f4613f2SJohn Marino
2125f4613f2SJohn Marino case STRING:
2135f4613f2SJohn Marino name = strnames[np->nte_index];
2145f4613f2SJohn Marino break;
2155f4613f2SJohn Marino }
2165f4613f2SJohn Marino goto retry;
2175f4613f2SJohn Marino }
2185f4613f2SJohn Marino }
2195f4613f2SJohn Marino #endif
220*32bb5217SDaniel Fojt quit(ErrCapName, "unknown terminfo capability '%s'", name);
221*32bb5217SDaniel Fojt } else if (VALID_STRING(s)) {
2225f4613f2SJohn Marino if (argc > 1) {
2235f4613f2SJohn Marino int k;
2243468e90cSJohn Marino int ignored;
2255f4613f2SJohn Marino long numbers[1 + NUM_PARM];
2265f4613f2SJohn Marino char *strings[1 + NUM_PARM];
2275f4613f2SJohn Marino char *p_is_s[NUM_PARM];
2285f4613f2SJohn Marino
2295f4613f2SJohn Marino /* Nasty hack time. The tparm function needs to see numeric
2305f4613f2SJohn Marino * parameters as numbers, not as pointers to their string
2315f4613f2SJohn Marino * representations
2325f4613f2SJohn Marino */
2335f4613f2SJohn Marino
234*32bb5217SDaniel Fojt for (k = 1; (k < argc) && (k < NUM_PARM); k++) {
2355f4613f2SJohn Marino char *tmp = 0;
2365f4613f2SJohn Marino strings[k] = argv[k];
2375f4613f2SJohn Marino numbers[k] = strtol(argv[k], &tmp, 0);
2385f4613f2SJohn Marino if (tmp == 0 || *tmp != 0)
2395f4613f2SJohn Marino numbers[k] = 0;
2405f4613f2SJohn Marino }
2415f4613f2SJohn Marino for (k = argc; k <= NUM_PARM; k++) {
2425f4613f2SJohn Marino numbers[k] = 0;
2435f4613f2SJohn Marino strings[k] = 0;
2445f4613f2SJohn Marino }
2455f4613f2SJohn Marino
2465f4613f2SJohn Marino switch (tparm_type(name)) {
2475f4613f2SJohn Marino case Num_Str:
2485f4613f2SJohn Marino s = TPARM_2(s, numbers[1], strings[2]);
2495f4613f2SJohn Marino break;
2505f4613f2SJohn Marino case Num_Str_Str:
2515f4613f2SJohn Marino s = TPARM_3(s, numbers[1], strings[2], strings[3]);
2525f4613f2SJohn Marino break;
2535f4613f2SJohn Marino case Numbers:
2545f4613f2SJohn Marino default:
2553468e90cSJohn Marino (void) _nc_tparm_analyze(s, p_is_s, &ignored);
2563468e90cSJohn Marino #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
2575f4613f2SJohn Marino s = TPARM_9(s,
2585f4613f2SJohn Marino myParam(1),
2595f4613f2SJohn Marino myParam(2),
2605f4613f2SJohn Marino myParam(3),
2615f4613f2SJohn Marino myParam(4),
2625f4613f2SJohn Marino myParam(5),
2635f4613f2SJohn Marino myParam(6),
2645f4613f2SJohn Marino myParam(7),
2655f4613f2SJohn Marino myParam(8),
2665f4613f2SJohn Marino myParam(9));
2675f4613f2SJohn Marino break;
2685f4613f2SJohn Marino }
2695f4613f2SJohn Marino }
2705f4613f2SJohn Marino
2715f4613f2SJohn Marino /* use putp() in order to perform padding */
2725f4613f2SJohn Marino putp(s);
2735f4613f2SJohn Marino return exit_code(STRING, 0);
2745f4613f2SJohn Marino }
2755f4613f2SJohn Marino return exit_code(STRING, 1);
2765f4613f2SJohn Marino }
2775f4613f2SJohn Marino
2785f4613f2SJohn Marino int
main(int argc,char ** argv)2795f4613f2SJohn Marino main(int argc, char **argv)
2805f4613f2SJohn Marino {
2815f4613f2SJohn Marino char *term;
2825f4613f2SJohn Marino int errret;
2835f4613f2SJohn Marino bool cmdline = TRUE;
2845f4613f2SJohn Marino int c;
2855f4613f2SJohn Marino char buf[BUFSIZ];
2865f4613f2SJohn Marino int result = 0;
287*32bb5217SDaniel Fojt int fd;
288*32bb5217SDaniel Fojt TTY tty_settings;
289*32bb5217SDaniel Fojt bool opt_x = FALSE; /* clear scrollback if possible */
290*32bb5217SDaniel Fojt bool is_alias;
291*32bb5217SDaniel Fojt bool need_tty;
2925f4613f2SJohn Marino
293*32bb5217SDaniel Fojt prg_name = check_aliases(_nc_rootname(argv[0]), TRUE);
2945f4613f2SJohn Marino
2955f4613f2SJohn Marino term = getenv("TERM");
2965f4613f2SJohn Marino
297*32bb5217SDaniel Fojt while ((c = getopt(argc, argv, "ST:Vx")) != -1) {
2985f4613f2SJohn Marino switch (c) {
2995f4613f2SJohn Marino case 'S':
3005f4613f2SJohn Marino cmdline = FALSE;
3015f4613f2SJohn Marino break;
3025f4613f2SJohn Marino case 'T':
3035f4613f2SJohn Marino use_env(FALSE);
304*32bb5217SDaniel Fojt use_tioctl(TRUE);
3055f4613f2SJohn Marino term = optarg;
3065f4613f2SJohn Marino break;
3075f4613f2SJohn Marino case 'V':
3085f4613f2SJohn Marino puts(curses_version());
3095f4613f2SJohn Marino ExitProgram(EXIT_SUCCESS);
310*32bb5217SDaniel Fojt case 'x': /* do not try to clear scrollback */
311*32bb5217SDaniel Fojt opt_x = TRUE;
312*32bb5217SDaniel Fojt break;
3135f4613f2SJohn Marino default:
3145f4613f2SJohn Marino usage();
3155f4613f2SJohn Marino /* NOTREACHED */
3165f4613f2SJohn Marino }
3175f4613f2SJohn Marino }
3185f4613f2SJohn Marino
319*32bb5217SDaniel Fojt is_alias = (is_clear || is_reset || is_init);
320*32bb5217SDaniel Fojt need_tty = ((is_reset || is_init) ||
321*32bb5217SDaniel Fojt (optind < argc &&
322*32bb5217SDaniel Fojt (!strcmp(argv[optind], "reset") ||
323*32bb5217SDaniel Fojt !strcmp(argv[optind], "init"))));
324*32bb5217SDaniel Fojt
3255f4613f2SJohn Marino /*
3265f4613f2SJohn Marino * Modify the argument list to omit the options we processed.
3275f4613f2SJohn Marino */
328*32bb5217SDaniel Fojt if (is_alias) {
3295f4613f2SJohn Marino if (optind-- < argc) {
3305f4613f2SJohn Marino argc -= optind;
3315f4613f2SJohn Marino argv += optind;
3325f4613f2SJohn Marino }
3335f4613f2SJohn Marino argv[0] = prg_name;
3345f4613f2SJohn Marino } else {
3355f4613f2SJohn Marino argc -= optind;
3365f4613f2SJohn Marino argv += optind;
3375f4613f2SJohn Marino }
3385f4613f2SJohn Marino
3395f4613f2SJohn Marino if (term == 0 || *term == '\0')
340*32bb5217SDaniel Fojt quit(ErrUsage, "No value for $TERM and no -T specified");
3415f4613f2SJohn Marino
342*32bb5217SDaniel Fojt fd = save_tty_settings(&tty_settings, need_tty);
343*32bb5217SDaniel Fojt
344*32bb5217SDaniel Fojt if (setupterm(term, fd, &errret) != OK && errret <= 0)
345*32bb5217SDaniel Fojt quit(ErrTermType, "unknown terminal \"%s\"", term);
3465f4613f2SJohn Marino
3475f4613f2SJohn Marino if (cmdline) {
348*32bb5217SDaniel Fojt if ((argc <= 0) && !is_alias)
3495f4613f2SJohn Marino usage();
350*32bb5217SDaniel Fojt ExitProgram(tput_cmd(fd, &tty_settings, opt_x, argc, argv));
3515f4613f2SJohn Marino }
3525f4613f2SJohn Marino
3535f4613f2SJohn Marino while (fgets(buf, sizeof(buf), stdin) != 0) {
3545f4613f2SJohn Marino char *argvec[16]; /* command, 9 parms, null, & slop */
3555f4613f2SJohn Marino int argnum = 0;
3565f4613f2SJohn Marino char *cp;
3575f4613f2SJohn Marino
3585f4613f2SJohn Marino /* crack the argument list into a dope vector */
3595f4613f2SJohn Marino for (cp = buf; *cp; cp++) {
3605f4613f2SJohn Marino if (isspace(UChar(*cp))) {
3615f4613f2SJohn Marino *cp = '\0';
3625f4613f2SJohn Marino } else if (cp == buf || cp[-1] == 0) {
3635f4613f2SJohn Marino argvec[argnum++] = cp;
3645f4613f2SJohn Marino if (argnum >= (int) SIZEOF(argvec) - 1)
3655f4613f2SJohn Marino break;
3665f4613f2SJohn Marino }
3675f4613f2SJohn Marino }
3685f4613f2SJohn Marino argvec[argnum] = 0;
3695f4613f2SJohn Marino
3705f4613f2SJohn Marino if (argnum != 0
371*32bb5217SDaniel Fojt && tput_cmd(fd, &tty_settings, opt_x, argnum, argvec) != 0) {
3725f4613f2SJohn Marino if (result == 0)
373*32bb5217SDaniel Fojt result = ErrSystem(0); /* will return value >4 */
3745f4613f2SJohn Marino ++result;
3755f4613f2SJohn Marino }
3765f4613f2SJohn Marino }
3775f4613f2SJohn Marino
3785f4613f2SJohn Marino ExitProgram(result);
3795f4613f2SJohn Marino }
380