10e3d5408SPeter Wemm /**************************************************************************** 2*e1865124SBaptiste Daroussin * Copyright 2018-2019,2020 Thomas E. Dickey * 3*e1865124SBaptiste Daroussin * Copyright 1998-2016,2017 Free Software Foundation, Inc. * 40e3d5408SPeter Wemm * * 50e3d5408SPeter Wemm * Permission is hereby granted, free of charge, to any person obtaining a * 60e3d5408SPeter Wemm * copy of this software and associated documentation files (the * 70e3d5408SPeter Wemm * "Software"), to deal in the Software without restriction, including * 80e3d5408SPeter Wemm * without limitation the rights to use, copy, modify, merge, publish, * 90e3d5408SPeter Wemm * distribute, distribute with modifications, sublicense, and/or sell * 100e3d5408SPeter Wemm * copies of the Software, and to permit persons to whom the Software is * 110e3d5408SPeter Wemm * furnished to do so, subject to the following conditions: * 120e3d5408SPeter Wemm * * 130e3d5408SPeter Wemm * The above copyright notice and this permission notice shall be included * 140e3d5408SPeter Wemm * in all copies or substantial portions of the Software. * 150e3d5408SPeter Wemm * * 160e3d5408SPeter Wemm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 170e3d5408SPeter Wemm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 180e3d5408SPeter Wemm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 190e3d5408SPeter Wemm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 200e3d5408SPeter Wemm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 210e3d5408SPeter Wemm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 220e3d5408SPeter Wemm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 230e3d5408SPeter Wemm * * 240e3d5408SPeter Wemm * Except as contained in this notice, the name(s) of the above copyright * 250e3d5408SPeter Wemm * holders shall not be used in advertising or otherwise to promote the * 260e3d5408SPeter Wemm * sale, use or other dealings in this Software without prior written * 270e3d5408SPeter Wemm * authorization. * 280e3d5408SPeter Wemm ****************************************************************************/ 290e3d5408SPeter Wemm 300e3d5408SPeter Wemm /**************************************************************************** 310e3d5408SPeter Wemm * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 320e3d5408SPeter Wemm * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33aae38d10SBaptiste Daroussin * and: Thomas E. Dickey 1996-on * 340e3d5408SPeter Wemm ****************************************************************************/ 350e3d5408SPeter Wemm 360e3d5408SPeter Wemm /* 370e3d5408SPeter Wemm * tput.c -- shellscript access to terminal capabilities 380e3d5408SPeter Wemm * 390e3d5408SPeter Wemm * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from 400e3d5408SPeter Wemm * Ross Ridge's mytinfo package. 410e3d5408SPeter Wemm */ 420e3d5408SPeter Wemm 43aae38d10SBaptiste Daroussin #include <tparm_type.h> 44aae38d10SBaptiste Daroussin #include <clear_cmd.h> 45aae38d10SBaptiste Daroussin #include <reset_cmd.h> 4618259542SPeter Wemm 4718259542SPeter Wemm #if !PURE_TERMINFO 485d08fb1fSRong-En Fan #include <dump_entry.h> 490e3d5408SPeter Wemm #include <termsort.c> 500e3d5408SPeter Wemm #endif 5118259542SPeter Wemm #include <transform.h> 52aae38d10SBaptiste Daroussin #include <tty_settings.h> 530e3d5408SPeter Wemm 54*e1865124SBaptiste Daroussin MODULE_ID("$Id: tput.c,v 1.81 2020/02/02 23:34:34 tom Exp $") 550e3d5408SPeter Wemm 560e3d5408SPeter Wemm #define PUTS(s) fputs(s, stdout) 570e3d5408SPeter Wemm 58aae38d10SBaptiste Daroussin const char *_nc_progname = "tput"; 5918259542SPeter Wemm 600e3d5408SPeter Wemm static char *prg_name; 6118259542SPeter Wemm static bool is_init = FALSE; 6218259542SPeter Wemm static bool is_reset = FALSE; 63aae38d10SBaptiste Daroussin static bool is_clear = FALSE; 640e3d5408SPeter Wemm 6515589c42SPeter Wemm static void 6615589c42SPeter Wemm quit(int status, const char *fmt,...) 670e3d5408SPeter Wemm { 680e3d5408SPeter Wemm va_list argp; 690e3d5408SPeter Wemm 700e3d5408SPeter Wemm va_start(argp, fmt); 714a1a9510SRong-En Fan fprintf(stderr, "%s: ", prg_name); 720e3d5408SPeter Wemm vfprintf(stderr, fmt, argp); 730e3d5408SPeter Wemm fprintf(stderr, "\n"); 740e3d5408SPeter Wemm va_end(argp); 754a1a9510SRong-En Fan ExitProgram(status); 760e3d5408SPeter Wemm } 770e3d5408SPeter Wemm 7815589c42SPeter Wemm static void 7915589c42SPeter Wemm usage(void) 800e3d5408SPeter Wemm { 81aae38d10SBaptiste Daroussin #define KEEP(s) s "\n" 82aae38d10SBaptiste Daroussin static const char msg[] = 8318259542SPeter Wemm { 84aae38d10SBaptiste Daroussin KEEP("") 85aae38d10SBaptiste Daroussin KEEP("Options:") 86aae38d10SBaptiste Daroussin KEEP(" -S << read commands from standard input") 87aae38d10SBaptiste Daroussin KEEP(" -T TERM use this instead of $TERM") 88aae38d10SBaptiste Daroussin KEEP(" -V print curses-version") 89aae38d10SBaptiste Daroussin KEEP(" -x do not try to clear scrollback") 90aae38d10SBaptiste Daroussin KEEP("") 91aae38d10SBaptiste Daroussin KEEP("Commands:") 92aae38d10SBaptiste Daroussin KEEP(" clear clear the screen") 93aae38d10SBaptiste Daroussin KEEP(" init initialize the terminal") 94aae38d10SBaptiste Daroussin KEEP(" reset reinitialize the terminal") 95aae38d10SBaptiste Daroussin KEEP(" capname unlike clear/init/reset, print value for capability \"capname\"") 9618259542SPeter Wemm }; 97aae38d10SBaptiste Daroussin #undef KEEP 98aae38d10SBaptiste Daroussin (void) fprintf(stderr, "Usage: %s [options] [command]\n", prg_name); 99aae38d10SBaptiste Daroussin fputs(msg, stderr); 100aae38d10SBaptiste Daroussin ExitProgram(ErrUsage); 101aae38d10SBaptiste Daroussin } 10218259542SPeter Wemm 103aae38d10SBaptiste Daroussin static char * 104aae38d10SBaptiste Daroussin check_aliases(char *name, bool program) 105aae38d10SBaptiste Daroussin { 106aae38d10SBaptiste Daroussin static char my_init[] = "init"; 107aae38d10SBaptiste Daroussin static char my_reset[] = "reset"; 108aae38d10SBaptiste Daroussin static char my_clear[] = "clear"; 109aae38d10SBaptiste Daroussin 110aae38d10SBaptiste Daroussin char *result = name; 111aae38d10SBaptiste Daroussin if ((is_init = same_program(name, program ? PROG_INIT : my_init))) 112aae38d10SBaptiste Daroussin result = my_init; 113aae38d10SBaptiste Daroussin if ((is_reset = same_program(name, program ? PROG_RESET : my_reset))) 114aae38d10SBaptiste Daroussin result = my_reset; 115aae38d10SBaptiste Daroussin if ((is_clear = same_program(name, program ? PROG_CLEAR : my_clear))) 116aae38d10SBaptiste Daroussin result = my_clear; 11718259542SPeter Wemm return result; 11818259542SPeter Wemm } 11918259542SPeter Wemm 12015589c42SPeter Wemm static int 1214a1a9510SRong-En Fan exit_code(int token, int value) 1224a1a9510SRong-En Fan { 1234a1a9510SRong-En Fan int result = 99; 1244a1a9510SRong-En Fan 1254a1a9510SRong-En Fan switch (token) { 1264a1a9510SRong-En Fan case BOOLEAN: 1274a1a9510SRong-En Fan result = !value; /* TRUE=0, FALSE=1 */ 1284a1a9510SRong-En Fan break; 1294a1a9510SRong-En Fan case NUMBER: 1304a1a9510SRong-En Fan result = 0; /* always zero */ 1314a1a9510SRong-En Fan break; 1324a1a9510SRong-En Fan case STRING: 1334a1a9510SRong-En Fan result = value; /* 0=normal, 1=missing */ 1344a1a9510SRong-En Fan break; 1354a1a9510SRong-En Fan } 1364a1a9510SRong-En Fan return result; 1374a1a9510SRong-En Fan } 1384a1a9510SRong-En Fan 139aae38d10SBaptiste Daroussin /* 140aae38d10SBaptiste Daroussin * Returns nonzero on error. 141aae38d10SBaptiste Daroussin */ 1424a1a9510SRong-En Fan static int 143aae38d10SBaptiste Daroussin tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[]) 1440e3d5408SPeter Wemm { 14515589c42SPeter Wemm NCURSES_CONST char *name; 1460e3d5408SPeter Wemm char *s; 14718259542SPeter Wemm int status; 14806bfebdeSXin LI #if !PURE_TERMINFO 14906bfebdeSXin LI bool termcap = FALSE; 15006bfebdeSXin LI #endif 1510e3d5408SPeter Wemm 152aae38d10SBaptiste Daroussin name = check_aliases(argv[0], FALSE); 15318259542SPeter Wemm if (is_reset || is_init) { 154aae38d10SBaptiste Daroussin TTY oldmode; 1550e3d5408SPeter Wemm 156aae38d10SBaptiste Daroussin int terasechar = -1; /* new erase character */ 157aae38d10SBaptiste Daroussin int intrchar = -1; /* new interrupt character */ 158aae38d10SBaptiste Daroussin int tkillchar = -1; /* new kill character */ 1590e3d5408SPeter Wemm 160aae38d10SBaptiste Daroussin if (is_reset) { 161aae38d10SBaptiste Daroussin reset_start(stdout, TRUE, FALSE); 162aae38d10SBaptiste Daroussin reset_tty_settings(fd, saved_settings); 163aae38d10SBaptiste Daroussin } else { 164aae38d10SBaptiste Daroussin reset_start(stdout, FALSE, TRUE); 1650e3d5408SPeter Wemm } 1660e3d5408SPeter Wemm 167aae38d10SBaptiste Daroussin #if HAVE_SIZECHANGE 168aae38d10SBaptiste Daroussin set_window_size(fd, &lines, &columns); 169aae38d10SBaptiste Daroussin #else 170aae38d10SBaptiste Daroussin (void) fd; 17139f2269fSPeter Wemm #endif 172aae38d10SBaptiste Daroussin set_control_chars(saved_settings, terasechar, intrchar, tkillchar); 173aae38d10SBaptiste Daroussin set_conversions(saved_settings); 174aae38d10SBaptiste Daroussin if (send_init_strings(fd, &oldmode)) { 175aae38d10SBaptiste Daroussin reset_flush(); 1760e3d5408SPeter Wemm } 1770e3d5408SPeter Wemm 178aae38d10SBaptiste Daroussin update_tty_settings(&oldmode, saved_settings); 1790e3d5408SPeter Wemm return 0; 1800e3d5408SPeter Wemm } 1810e3d5408SPeter Wemm 1820e3d5408SPeter Wemm if (strcmp(name, "longname") == 0) { 1830e3d5408SPeter Wemm PUTS(longname()); 1840e3d5408SPeter Wemm return 0; 1850e3d5408SPeter Wemm } 18618259542SPeter Wemm #if !PURE_TERMINFO 18706bfebdeSXin LI retry: 18806bfebdeSXin LI #endif 189aae38d10SBaptiste Daroussin if (strcmp(name, "clear") == 0) { 190aae38d10SBaptiste Daroussin return (clear_cmd(opt_x) == ERR) ? ErrUsage : 0; 191aae38d10SBaptiste Daroussin } else if ((status = tigetflag(name)) != -1) { 19206bfebdeSXin LI return exit_code(BOOLEAN, status); 19306bfebdeSXin LI } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) { 19406bfebdeSXin LI (void) printf("%d\n", status); 19506bfebdeSXin LI return exit_code(NUMBER, 0); 19606bfebdeSXin LI } else if ((s = tigetstr(name)) == CANCELLED_STRING) { 19706bfebdeSXin LI #if !PURE_TERMINFO 19806bfebdeSXin LI if (!termcap) { 1990e3d5408SPeter Wemm const struct name_table_entry *np; 2000e3d5408SPeter Wemm 20106bfebdeSXin LI termcap = TRUE; 20206bfebdeSXin LI if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) { 20315589c42SPeter Wemm switch (np->nte_type) { 2040e3d5408SPeter Wemm case BOOLEAN: 2050e3d5408SPeter Wemm name = boolnames[np->nte_index]; 2060e3d5408SPeter Wemm break; 2070e3d5408SPeter Wemm 2080e3d5408SPeter Wemm case NUMBER: 2090e3d5408SPeter Wemm name = numnames[np->nte_index]; 2100e3d5408SPeter Wemm break; 2110e3d5408SPeter Wemm 2120e3d5408SPeter Wemm case STRING: 2130e3d5408SPeter Wemm name = strnames[np->nte_index]; 2140e3d5408SPeter Wemm break; 2150e3d5408SPeter Wemm } 21606bfebdeSXin LI goto retry; 21706bfebdeSXin LI } 2180e3d5408SPeter Wemm } 2190e3d5408SPeter Wemm #endif 220aae38d10SBaptiste Daroussin quit(ErrCapName, "unknown terminfo capability '%s'", name); 221aae38d10SBaptiste Daroussin } else if (VALID_STRING(s)) { 2220e3d5408SPeter Wemm if (argc > 1) { 2230e3d5408SPeter Wemm int k; 22473f0a83dSXin LI int ignored; 2254a1a9510SRong-En Fan long numbers[1 + NUM_PARM]; 2264a1a9510SRong-En Fan char *strings[1 + NUM_PARM]; 2274a1a9510SRong-En Fan char *p_is_s[NUM_PARM]; 2280e3d5408SPeter Wemm 2290e3d5408SPeter Wemm /* Nasty hack time. The tparm function needs to see numeric 2300e3d5408SPeter Wemm * parameters as numbers, not as pointers to their string 2310e3d5408SPeter Wemm * representations 2320e3d5408SPeter Wemm */ 2330e3d5408SPeter Wemm 234aae38d10SBaptiste Daroussin for (k = 1; (k < argc) && (k < NUM_PARM); k++) { 23518259542SPeter Wemm char *tmp = 0; 23618259542SPeter Wemm strings[k] = argv[k]; 23718259542SPeter Wemm numbers[k] = strtol(argv[k], &tmp, 0); 23818259542SPeter Wemm if (tmp == 0 || *tmp != 0) 23918259542SPeter Wemm numbers[k] = 0; 2400e3d5408SPeter Wemm } 2414a1a9510SRong-En Fan for (k = argc; k <= NUM_PARM; k++) { 24218259542SPeter Wemm numbers[k] = 0; 24318259542SPeter Wemm strings[k] = 0; 24415589c42SPeter Wemm } 2450e3d5408SPeter Wemm 24618259542SPeter Wemm switch (tparm_type(name)) { 24718259542SPeter Wemm case Num_Str: 2484a1a9510SRong-En Fan s = TPARM_2(s, numbers[1], strings[2]); 24918259542SPeter Wemm break; 25018259542SPeter Wemm case Num_Str_Str: 2514a1a9510SRong-En Fan s = TPARM_3(s, numbers[1], strings[2], strings[3]); 25218259542SPeter Wemm break; 2535ca44d1cSRong-En Fan case Numbers: 25418259542SPeter Wemm default: 25573f0a83dSXin LI (void) _nc_tparm_analyze(s, p_is_s, &ignored); 25673f0a83dSXin LI #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n]) 2574a1a9510SRong-En Fan s = TPARM_9(s, 2584a1a9510SRong-En Fan myParam(1), 2594a1a9510SRong-En Fan myParam(2), 2604a1a9510SRong-En Fan myParam(3), 2614a1a9510SRong-En Fan myParam(4), 2624a1a9510SRong-En Fan myParam(5), 2634a1a9510SRong-En Fan myParam(6), 2644a1a9510SRong-En Fan myParam(7), 2654a1a9510SRong-En Fan myParam(8), 2664a1a9510SRong-En Fan myParam(9)); 26718259542SPeter Wemm break; 26818259542SPeter Wemm } 2690e3d5408SPeter Wemm } 2700e3d5408SPeter Wemm 2710e3d5408SPeter Wemm /* use putp() in order to perform padding */ 2720e3d5408SPeter Wemm putp(s); 2734a1a9510SRong-En Fan return exit_code(STRING, 0); 2740e3d5408SPeter Wemm } 2754a1a9510SRong-En Fan return exit_code(STRING, 1); 2760e3d5408SPeter Wemm } 2770e3d5408SPeter Wemm 27815589c42SPeter Wemm int 27915589c42SPeter Wemm main(int argc, char **argv) 2800e3d5408SPeter Wemm { 28118259542SPeter Wemm char *term; 28218259542SPeter Wemm int errret; 28318259542SPeter Wemm bool cmdline = TRUE; 2840e3d5408SPeter Wemm int c; 2850e3d5408SPeter Wemm char buf[BUFSIZ]; 2864a1a9510SRong-En Fan int result = 0; 287aae38d10SBaptiste Daroussin int fd; 288aae38d10SBaptiste Daroussin TTY tty_settings; 289aae38d10SBaptiste Daroussin bool opt_x = FALSE; /* clear scrollback if possible */ 290aae38d10SBaptiste Daroussin bool is_alias; 291aae38d10SBaptiste Daroussin bool need_tty; 2920e3d5408SPeter Wemm 293aae38d10SBaptiste Daroussin prg_name = check_aliases(_nc_rootname(argv[0]), TRUE); 2940e3d5408SPeter Wemm 2950e3d5408SPeter Wemm term = getenv("TERM"); 2960e3d5408SPeter Wemm 297aae38d10SBaptiste Daroussin while ((c = getopt(argc, argv, "ST:Vx")) != -1) { 29815589c42SPeter Wemm switch (c) { 2990e3d5408SPeter Wemm case 'S': 30018259542SPeter Wemm cmdline = FALSE; 3010e3d5408SPeter Wemm break; 3020e3d5408SPeter Wemm case 'T': 3030e3d5408SPeter Wemm use_env(FALSE); 304aae38d10SBaptiste Daroussin use_tioctl(TRUE); 3050e3d5408SPeter Wemm term = optarg; 3060e3d5408SPeter Wemm break; 30718259542SPeter Wemm case 'V': 30818259542SPeter Wemm puts(curses_version()); 3094a1a9510SRong-En Fan ExitProgram(EXIT_SUCCESS); 310aae38d10SBaptiste Daroussin case 'x': /* do not try to clear scrollback */ 311aae38d10SBaptiste Daroussin opt_x = TRUE; 312aae38d10SBaptiste Daroussin break; 3130e3d5408SPeter Wemm default: 3140e3d5408SPeter Wemm usage(); 3150e3d5408SPeter Wemm /* NOTREACHED */ 3160e3d5408SPeter Wemm } 31718259542SPeter Wemm } 31818259542SPeter Wemm 319aae38d10SBaptiste Daroussin is_alias = (is_clear || is_reset || is_init); 320aae38d10SBaptiste Daroussin need_tty = ((is_reset || is_init) || 321aae38d10SBaptiste Daroussin (optind < argc && 322aae38d10SBaptiste Daroussin (!strcmp(argv[optind], "reset") || 323aae38d10SBaptiste Daroussin !strcmp(argv[optind], "init")))); 324aae38d10SBaptiste Daroussin 32518259542SPeter Wemm /* 32618259542SPeter Wemm * Modify the argument list to omit the options we processed. 32718259542SPeter Wemm */ 328aae38d10SBaptiste Daroussin if (is_alias) { 32918259542SPeter Wemm if (optind-- < argc) { 3300e3d5408SPeter Wemm argc -= optind; 3310e3d5408SPeter Wemm argv += optind; 33218259542SPeter Wemm } 33318259542SPeter Wemm argv[0] = prg_name; 33418259542SPeter Wemm } else { 33518259542SPeter Wemm argc -= optind; 33618259542SPeter Wemm argv += optind; 3370e3d5408SPeter Wemm } 3380e3d5408SPeter Wemm 33915589c42SPeter Wemm if (term == 0 || *term == '\0') 340aae38d10SBaptiste Daroussin quit(ErrUsage, "No value for $TERM and no -T specified"); 3410e3d5408SPeter Wemm 342aae38d10SBaptiste Daroussin fd = save_tty_settings(&tty_settings, need_tty); 343aae38d10SBaptiste Daroussin 344aae38d10SBaptiste Daroussin if (setupterm(term, fd, &errret) != OK && errret <= 0) 345aae38d10SBaptiste Daroussin quit(ErrTermType, "unknown terminal \"%s\"", term); 3460e3d5408SPeter Wemm 34718259542SPeter Wemm if (cmdline) { 348aae38d10SBaptiste Daroussin if ((argc <= 0) && !is_alias) 34918259542SPeter Wemm usage(); 350aae38d10SBaptiste Daroussin ExitProgram(tput_cmd(fd, &tty_settings, opt_x, argc, argv)); 35118259542SPeter Wemm } 3520e3d5408SPeter Wemm 35315589c42SPeter Wemm while (fgets(buf, sizeof(buf), stdin) != 0) { 3540e3d5408SPeter Wemm char *argvec[16]; /* command, 9 parms, null, & slop */ 3550e3d5408SPeter Wemm int argnum = 0; 3560e3d5408SPeter Wemm char *cp; 3570e3d5408SPeter Wemm 3580e3d5408SPeter Wemm /* crack the argument list into a dope vector */ 3590e3d5408SPeter Wemm for (cp = buf; *cp; cp++) { 36039f2269fSPeter Wemm if (isspace(UChar(*cp))) { 3610e3d5408SPeter Wemm *cp = '\0'; 36239f2269fSPeter Wemm } else if (cp == buf || cp[-1] == 0) { 3630e3d5408SPeter Wemm argvec[argnum++] = cp; 36439f2269fSPeter Wemm if (argnum >= (int) SIZEOF(argvec) - 1) 36539f2269fSPeter Wemm break; 36639f2269fSPeter Wemm } 3670e3d5408SPeter Wemm } 36815589c42SPeter Wemm argvec[argnum] = 0; 3690e3d5408SPeter Wemm 37039f2269fSPeter Wemm if (argnum != 0 371aae38d10SBaptiste Daroussin && tput_cmd(fd, &tty_settings, opt_x, argnum, argvec) != 0) { 3724a1a9510SRong-En Fan if (result == 0) 373aae38d10SBaptiste Daroussin result = ErrSystem(0); /* will return value >4 */ 3744a1a9510SRong-En Fan ++result; 3754a1a9510SRong-En Fan } 3760e3d5408SPeter Wemm } 3770e3d5408SPeter Wemm 3784a1a9510SRong-En Fan ExitProgram(result); 3790e3d5408SPeter Wemm } 380