1 /**************************************************************************** 2 * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 ****************************************************************************/ 33 34 /* 35 * tput.c -- shellscript access to terminal capabilities 36 * 37 * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from 38 * Ross Ridge's mytinfo package. 39 */ 40 41 #define USE_LIBTINFO 42 #include <progs.priv.h> 43 44 #if !PURE_TERMINFO 45 #include <dump_entry.h> 46 #include <termsort.c> 47 #endif 48 #include <transform.h> 49 50 MODULE_ID("$Id: tput.c,v 1.49 2013/09/28 20:57:25 tom Exp $") 51 52 #define PUTS(s) fputs(s, stdout) 53 #define PUTCHAR(c) putchar(c) 54 #define FLUSH fflush(stdout) 55 56 typedef enum { 57 Numbers = 0 58 ,Num_Str 59 ,Num_Str_Str 60 } TParams; 61 62 static char *prg_name; 63 static bool is_init = FALSE; 64 static bool is_reset = FALSE; 65 66 static void 67 quit(int status, const char *fmt,...) 68 { 69 va_list argp; 70 71 va_start(argp, fmt); 72 fprintf(stderr, "%s: ", prg_name); 73 vfprintf(stderr, fmt, argp); 74 fprintf(stderr, "\n"); 75 va_end(argp); 76 ExitProgram(status); 77 } 78 79 static void 80 usage(void) 81 { 82 fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name); 83 ExitProgram(EXIT_FAILURE); 84 } 85 86 static void 87 check_aliases(const char *name) 88 { 89 is_init = same_program(name, PROG_INIT); 90 is_reset = same_program(name, PROG_RESET); 91 } 92 93 /* 94 * Lookup the type of call we should make to tparm(). This ignores the actual 95 * terminfo capability (bad, because it is not extensible), but makes this 96 * code portable to platforms where sizeof(int) != sizeof(char *). 97 */ 98 static TParams 99 tparm_type(const char *name) 100 { 101 #define TD(code, longname, ti, tc) {code,longname},{code,ti},{code,tc} 102 TParams result = Numbers; 103 /* *INDENT-OFF* */ 104 static const struct { 105 TParams code; 106 const char *name; 107 } table[] = { 108 TD(Num_Str, "pkey_key", "pfkey", "pk"), 109 TD(Num_Str, "pkey_local", "pfloc", "pl"), 110 TD(Num_Str, "pkey_xmit", "pfx", "px"), 111 TD(Num_Str, "plab_norm", "pln", "pn"), 112 TD(Num_Str_Str, "pkey_plab", "pfxl", "xl"), 113 }; 114 /* *INDENT-ON* */ 115 116 unsigned n; 117 for (n = 0; n < SIZEOF(table); n++) { 118 if (!strcmp(name, table[n].name)) { 119 result = table[n].code; 120 break; 121 } 122 } 123 return result; 124 } 125 126 static int 127 exit_code(int token, int value) 128 { 129 int result = 99; 130 131 switch (token) { 132 case BOOLEAN: 133 result = !value; /* TRUE=0, FALSE=1 */ 134 break; 135 case NUMBER: 136 result = 0; /* always zero */ 137 break; 138 case STRING: 139 result = value; /* 0=normal, 1=missing */ 140 break; 141 } 142 return result; 143 } 144 145 static int 146 tput(int argc, char *argv[]) 147 { 148 NCURSES_CONST char *name; 149 char *s; 150 int i, j, c; 151 int status; 152 FILE *f; 153 #if !PURE_TERMINFO 154 bool termcap = FALSE; 155 #endif 156 157 if ((name = argv[0]) == 0) 158 name = ""; 159 check_aliases(name); 160 if (is_reset || is_init) { 161 if (init_prog != 0) { 162 system(init_prog); 163 } 164 FLUSH; 165 166 if (is_reset && reset_1string != 0) { 167 PUTS(reset_1string); 168 } else if (init_1string != 0) { 169 PUTS(init_1string); 170 } 171 FLUSH; 172 173 if (is_reset && reset_2string != 0) { 174 PUTS(reset_2string); 175 } else if (init_2string != 0) { 176 PUTS(init_2string); 177 } 178 FLUSH; 179 180 #ifdef set_lr_margin 181 if (set_lr_margin != 0) { 182 PUTS(TPARM_2(set_lr_margin, 0, columns - 1)); 183 } else 184 #endif 185 #ifdef set_left_margin_parm 186 if (set_left_margin_parm != 0 187 && set_right_margin_parm != 0) { 188 PUTS(TPARM_1(set_left_margin_parm, 0)); 189 PUTS(TPARM_1(set_right_margin_parm, columns - 1)); 190 } else 191 #endif 192 if (clear_margins != 0 193 && set_left_margin != 0 194 && set_right_margin != 0) { 195 PUTS(clear_margins); 196 if (carriage_return != 0) { 197 PUTS(carriage_return); 198 } else { 199 PUTCHAR('\r'); 200 } 201 PUTS(set_left_margin); 202 if (parm_right_cursor) { 203 PUTS(TPARM_1(parm_right_cursor, columns - 1)); 204 } else { 205 for (i = 0; i < columns - 1; i++) { 206 PUTCHAR(' '); 207 } 208 } 209 PUTS(set_right_margin); 210 if (carriage_return != 0) { 211 PUTS(carriage_return); 212 } else { 213 PUTCHAR('\r'); 214 } 215 } 216 FLUSH; 217 218 if (init_tabs != 8) { 219 if (clear_all_tabs != 0 && set_tab != 0) { 220 for (i = 0; i < columns - 1; i += 8) { 221 if (parm_right_cursor) { 222 PUTS(TPARM_1(parm_right_cursor, 8)); 223 } else { 224 for (j = 0; j < 8; j++) 225 PUTCHAR(' '); 226 } 227 PUTS(set_tab); 228 } 229 FLUSH; 230 } 231 } 232 233 if (is_reset && reset_file != 0) { 234 f = fopen(reset_file, "r"); 235 if (f == 0) { 236 quit(4 + errno, "Can't open reset_file: '%s'", reset_file); 237 } 238 while ((c = fgetc(f)) != EOF) { 239 PUTCHAR(c); 240 } 241 fclose(f); 242 } else if (init_file != 0) { 243 f = fopen(init_file, "r"); 244 if (f == 0) { 245 quit(4 + errno, "Can't open init_file: '%s'", init_file); 246 } 247 while ((c = fgetc(f)) != EOF) { 248 PUTCHAR(c); 249 } 250 fclose(f); 251 } 252 FLUSH; 253 254 if (is_reset && reset_3string != 0) { 255 PUTS(reset_3string); 256 } else if (init_3string != 0) { 257 PUTS(init_3string); 258 } 259 FLUSH; 260 return 0; 261 } 262 263 if (strcmp(name, "longname") == 0) { 264 PUTS(longname()); 265 return 0; 266 } 267 #if !PURE_TERMINFO 268 retry: 269 #endif 270 if ((status = tigetflag(name)) != -1) { 271 return exit_code(BOOLEAN, status); 272 } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) { 273 (void) printf("%d\n", status); 274 return exit_code(NUMBER, 0); 275 } else if ((s = tigetstr(name)) == CANCELLED_STRING) { 276 #if !PURE_TERMINFO 277 if (!termcap) { 278 const struct name_table_entry *np; 279 280 termcap = TRUE; 281 if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) { 282 switch (np->nte_type) { 283 case BOOLEAN: 284 if (bool_from_termcap[np->nte_index]) 285 name = boolnames[np->nte_index]; 286 break; 287 288 case NUMBER: 289 if (num_from_termcap[np->nte_index]) 290 name = numnames[np->nte_index]; 291 break; 292 293 case STRING: 294 if (str_from_termcap[np->nte_index]) 295 name = strnames[np->nte_index]; 296 break; 297 } 298 goto retry; 299 } 300 } 301 #endif 302 quit(4, "unknown terminfo capability '%s'", name); 303 } else if (s != ABSENT_STRING) { 304 if (argc > 1) { 305 int k; 306 int ignored; 307 long numbers[1 + NUM_PARM]; 308 char *strings[1 + NUM_PARM]; 309 char *p_is_s[NUM_PARM]; 310 311 /* Nasty hack time. The tparm function needs to see numeric 312 * parameters as numbers, not as pointers to their string 313 * representations 314 */ 315 316 for (k = 1; k < argc; k++) { 317 char *tmp = 0; 318 strings[k] = argv[k]; 319 numbers[k] = strtol(argv[k], &tmp, 0); 320 if (tmp == 0 || *tmp != 0) 321 numbers[k] = 0; 322 } 323 for (k = argc; k <= NUM_PARM; k++) { 324 numbers[k] = 0; 325 strings[k] = 0; 326 } 327 328 switch (tparm_type(name)) { 329 case Num_Str: 330 s = TPARM_2(s, numbers[1], strings[2]); 331 break; 332 case Num_Str_Str: 333 s = TPARM_3(s, numbers[1], strings[2], strings[3]); 334 break; 335 case Numbers: 336 default: 337 (void) _nc_tparm_analyze(s, p_is_s, &ignored); 338 #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n]) 339 s = TPARM_9(s, 340 myParam(1), 341 myParam(2), 342 myParam(3), 343 myParam(4), 344 myParam(5), 345 myParam(6), 346 myParam(7), 347 myParam(8), 348 myParam(9)); 349 break; 350 } 351 } 352 353 /* use putp() in order to perform padding */ 354 putp(s); 355 return exit_code(STRING, 0); 356 } 357 return exit_code(STRING, 1); 358 } 359 360 int 361 main(int argc, char **argv) 362 { 363 char *term; 364 int errret; 365 bool cmdline = TRUE; 366 int c; 367 char buf[BUFSIZ]; 368 int result = 0; 369 370 check_aliases(prg_name = _nc_rootname(argv[0])); 371 372 term = getenv("TERM"); 373 374 while ((c = getopt(argc, argv, "ST:V")) != -1) { 375 switch (c) { 376 case 'S': 377 cmdline = FALSE; 378 break; 379 case 'T': 380 use_env(FALSE); 381 term = optarg; 382 break; 383 case 'V': 384 puts(curses_version()); 385 ExitProgram(EXIT_SUCCESS); 386 default: 387 usage(); 388 /* NOTREACHED */ 389 } 390 } 391 392 /* 393 * Modify the argument list to omit the options we processed. 394 */ 395 if (is_reset || is_init) { 396 if (optind-- < argc) { 397 argc -= optind; 398 argv += optind; 399 } 400 argv[0] = prg_name; 401 } else { 402 argc -= optind; 403 argv += optind; 404 } 405 406 if (term == 0 || *term == '\0') 407 quit(2, "No value for $TERM and no -T specified"); 408 409 if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0) 410 quit(3, "unknown terminal \"%s\"", term); 411 412 if (cmdline) { 413 if ((argc <= 0) && !is_reset && !is_init) 414 usage(); 415 ExitProgram(tput(argc, argv)); 416 } 417 418 while (fgets(buf, sizeof(buf), stdin) != 0) { 419 char *argvec[16]; /* command, 9 parms, null, & slop */ 420 int argnum = 0; 421 char *cp; 422 423 /* crack the argument list into a dope vector */ 424 for (cp = buf; *cp; cp++) { 425 if (isspace(UChar(*cp))) { 426 *cp = '\0'; 427 } else if (cp == buf || cp[-1] == 0) { 428 argvec[argnum++] = cp; 429 if (argnum >= (int) SIZEOF(argvec) - 1) 430 break; 431 } 432 } 433 argvec[argnum] = 0; 434 435 if (argnum != 0 436 && tput(argnum, argvec) != 0) { 437 if (result == 0) 438 result = 4; /* will return value >4 */ 439 ++result; 440 } 441 } 442 443 ExitProgram(result); 444 } 445