1 /**************************************************************************** 2 * Copyright 2018-2019,2020 Thomas E. Dickey * 3 * Copyright 1998-2016,2017 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /**************************************************************************** 31 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 32 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33 * and: Thomas E. Dickey 1996-on * 34 ****************************************************************************/ 35 36 /* 37 * tput.c -- shellscript access to terminal capabilities 38 * 39 * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from 40 * Ross Ridge's mytinfo package. 41 */ 42 43 #include <tparm_type.h> 44 #include <clear_cmd.h> 45 #include <reset_cmd.h> 46 47 #if !PURE_TERMINFO 48 #include <dump_entry.h> 49 #include <termsort.c> 50 #endif 51 #include <transform.h> 52 #include <tty_settings.h> 53 54 MODULE_ID("$Id: tput.c,v 1.81 2020/02/02 23:34:34 tom Exp $") 55 56 #define PUTS(s) fputs(s, stdout) 57 58 const char *_nc_progname = "tput"; 59 60 static char *prg_name; 61 static bool is_init = FALSE; 62 static bool is_reset = FALSE; 63 static bool is_clear = FALSE; 64 65 static void 66 quit(int status, const char *fmt,...) 67 { 68 va_list argp; 69 70 va_start(argp, fmt); 71 fprintf(stderr, "%s: ", prg_name); 72 vfprintf(stderr, fmt, argp); 73 fprintf(stderr, "\n"); 74 va_end(argp); 75 ExitProgram(status); 76 } 77 78 static void 79 usage(void) 80 { 81 #define KEEP(s) s "\n" 82 static const char msg[] = 83 { 84 KEEP("") 85 KEEP("Options:") 86 KEEP(" -S << read commands from standard input") 87 KEEP(" -T TERM use this instead of $TERM") 88 KEEP(" -V print curses-version") 89 KEEP(" -x do not try to clear scrollback") 90 KEEP("") 91 KEEP("Commands:") 92 KEEP(" clear clear the screen") 93 KEEP(" init initialize the terminal") 94 KEEP(" reset reinitialize the terminal") 95 KEEP(" capname unlike clear/init/reset, print value for capability \"capname\"") 96 }; 97 #undef KEEP 98 (void) fprintf(stderr, "Usage: %s [options] [command]\n", prg_name); 99 fputs(msg, stderr); 100 ExitProgram(ErrUsage); 101 } 102 103 static char * 104 check_aliases(char *name, bool program) 105 { 106 static char my_init[] = "init"; 107 static char my_reset[] = "reset"; 108 static char my_clear[] = "clear"; 109 110 char *result = name; 111 if ((is_init = same_program(name, program ? PROG_INIT : my_init))) 112 result = my_init; 113 if ((is_reset = same_program(name, program ? PROG_RESET : my_reset))) 114 result = my_reset; 115 if ((is_clear = same_program(name, program ? PROG_CLEAR : my_clear))) 116 result = my_clear; 117 return result; 118 } 119 120 static int 121 exit_code(int token, int value) 122 { 123 int result = 99; 124 125 switch (token) { 126 case BOOLEAN: 127 result = !value; /* TRUE=0, FALSE=1 */ 128 break; 129 case NUMBER: 130 result = 0; /* always zero */ 131 break; 132 case STRING: 133 result = value; /* 0=normal, 1=missing */ 134 break; 135 } 136 return result; 137 } 138 139 /* 140 * Returns nonzero on error. 141 */ 142 static int 143 tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[]) 144 { 145 NCURSES_CONST char *name; 146 char *s; 147 int status; 148 #if !PURE_TERMINFO 149 bool termcap = FALSE; 150 #endif 151 152 name = check_aliases(argv[0], FALSE); 153 if (is_reset || is_init) { 154 TTY oldmode; 155 156 int terasechar = -1; /* new erase character */ 157 int intrchar = -1; /* new interrupt character */ 158 int tkillchar = -1; /* new kill character */ 159 160 if (is_reset) { 161 reset_start(stdout, TRUE, FALSE); 162 reset_tty_settings(fd, saved_settings); 163 } else { 164 reset_start(stdout, FALSE, TRUE); 165 } 166 167 #if HAVE_SIZECHANGE 168 set_window_size(fd, &lines, &columns); 169 #else 170 (void) fd; 171 #endif 172 set_control_chars(saved_settings, terasechar, intrchar, tkillchar); 173 set_conversions(saved_settings); 174 if (send_init_strings(fd, &oldmode)) { 175 reset_flush(); 176 } 177 178 update_tty_settings(&oldmode, saved_settings); 179 return 0; 180 } 181 182 if (strcmp(name, "longname") == 0) { 183 PUTS(longname()); 184 return 0; 185 } 186 #if !PURE_TERMINFO 187 retry: 188 #endif 189 if (strcmp(name, "clear") == 0) { 190 return (clear_cmd(opt_x) == ERR) ? ErrUsage : 0; 191 } else if ((status = tigetflag(name)) != -1) { 192 return exit_code(BOOLEAN, status); 193 } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) { 194 (void) printf("%d\n", status); 195 return exit_code(NUMBER, 0); 196 } else if ((s = tigetstr(name)) == CANCELLED_STRING) { 197 #if !PURE_TERMINFO 198 if (!termcap) { 199 const struct name_table_entry *np; 200 201 termcap = TRUE; 202 if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) { 203 switch (np->nte_type) { 204 case BOOLEAN: 205 name = boolnames[np->nte_index]; 206 break; 207 208 case NUMBER: 209 name = numnames[np->nte_index]; 210 break; 211 212 case STRING: 213 name = strnames[np->nte_index]; 214 break; 215 } 216 goto retry; 217 } 218 } 219 #endif 220 quit(ErrCapName, "unknown terminfo capability '%s'", name); 221 } else if (VALID_STRING(s)) { 222 if (argc > 1) { 223 int k; 224 int ignored; 225 long numbers[1 + NUM_PARM]; 226 char *strings[1 + NUM_PARM]; 227 char *p_is_s[NUM_PARM]; 228 229 /* Nasty hack time. The tparm function needs to see numeric 230 * parameters as numbers, not as pointers to their string 231 * representations 232 */ 233 234 for (k = 1; (k < argc) && (k < NUM_PARM); k++) { 235 char *tmp = 0; 236 strings[k] = argv[k]; 237 numbers[k] = strtol(argv[k], &tmp, 0); 238 if (tmp == 0 || *tmp != 0) 239 numbers[k] = 0; 240 } 241 for (k = argc; k <= NUM_PARM; k++) { 242 numbers[k] = 0; 243 strings[k] = 0; 244 } 245 246 switch (tparm_type(name)) { 247 case Num_Str: 248 s = TPARM_2(s, numbers[1], strings[2]); 249 break; 250 case Num_Str_Str: 251 s = TPARM_3(s, numbers[1], strings[2], strings[3]); 252 break; 253 case Numbers: 254 default: 255 (void) _nc_tparm_analyze(s, p_is_s, &ignored); 256 #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n]) 257 s = TPARM_9(s, 258 myParam(1), 259 myParam(2), 260 myParam(3), 261 myParam(4), 262 myParam(5), 263 myParam(6), 264 myParam(7), 265 myParam(8), 266 myParam(9)); 267 break; 268 } 269 } 270 271 /* use putp() in order to perform padding */ 272 putp(s); 273 return exit_code(STRING, 0); 274 } 275 return exit_code(STRING, 1); 276 } 277 278 int 279 main(int argc, char **argv) 280 { 281 char *term; 282 int errret; 283 bool cmdline = TRUE; 284 int c; 285 char buf[BUFSIZ]; 286 int result = 0; 287 int fd; 288 TTY tty_settings; 289 bool opt_x = FALSE; /* clear scrollback if possible */ 290 bool is_alias; 291 bool need_tty; 292 293 prg_name = check_aliases(_nc_rootname(argv[0]), TRUE); 294 295 term = getenv("TERM"); 296 297 while ((c = getopt(argc, argv, "ST:Vx")) != -1) { 298 switch (c) { 299 case 'S': 300 cmdline = FALSE; 301 break; 302 case 'T': 303 use_env(FALSE); 304 use_tioctl(TRUE); 305 term = optarg; 306 break; 307 case 'V': 308 puts(curses_version()); 309 ExitProgram(EXIT_SUCCESS); 310 case 'x': /* do not try to clear scrollback */ 311 opt_x = TRUE; 312 break; 313 default: 314 usage(); 315 /* NOTREACHED */ 316 } 317 } 318 319 is_alias = (is_clear || is_reset || is_init); 320 need_tty = ((is_reset || is_init) || 321 (optind < argc && 322 (!strcmp(argv[optind], "reset") || 323 !strcmp(argv[optind], "init")))); 324 325 /* 326 * Modify the argument list to omit the options we processed. 327 */ 328 if (is_alias) { 329 if (optind-- < argc) { 330 argc -= optind; 331 argv += optind; 332 } 333 argv[0] = prg_name; 334 } else { 335 argc -= optind; 336 argv += optind; 337 } 338 339 if (term == 0 || *term == '\0') 340 quit(ErrUsage, "No value for $TERM and no -T specified"); 341 342 fd = save_tty_settings(&tty_settings, need_tty); 343 344 if (setupterm(term, fd, &errret) != OK && errret <= 0) 345 quit(ErrTermType, "unknown terminal \"%s\"", term); 346 347 if (cmdline) { 348 if ((argc <= 0) && !is_alias) 349 usage(); 350 ExitProgram(tput_cmd(fd, &tty_settings, opt_x, argc, argv)); 351 } 352 353 while (fgets(buf, sizeof(buf), stdin) != 0) { 354 char *argvec[16]; /* command, 9 parms, null, & slop */ 355 int argnum = 0; 356 char *cp; 357 358 /* crack the argument list into a dope vector */ 359 for (cp = buf; *cp; cp++) { 360 if (isspace(UChar(*cp))) { 361 *cp = '\0'; 362 } else if (cp == buf || cp[-1] == 0) { 363 argvec[argnum++] = cp; 364 if (argnum >= (int) SIZEOF(argvec) - 1) 365 break; 366 } 367 } 368 argvec[argnum] = 0; 369 370 if (argnum != 0 371 && tput_cmd(fd, &tty_settings, opt_x, argnum, argvec) != 0) { 372 if (result == 0) 373 result = ErrSystem(0); /* will return value >4 */ 374 ++result; 375 } 376 } 377 378 ExitProgram(result); 379 } 380