1 /**************************************************************************** 2 * Copyright (c) 1998-2009,2010 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.46 2010/01/09 16:53:24 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 * FIXME: If we want extensibility, analyze the capability string as we do 99 * in tparm() to decide how to parse the varargs list. 100 */ 101 static TParams 102 tparm_type(const char *name) 103 { 104 #define TD(code, longname, ti, tc) {code,longname},{code,ti},{code,tc} 105 TParams result = Numbers; 106 /* *INDENT-OFF* */ 107 static const struct { 108 TParams code; 109 const char *name; 110 } table[] = { 111 TD(Num_Str, "pkey_key", "pfkey", "pk"), 112 TD(Num_Str, "pkey_local", "pfloc", "pl"), 113 TD(Num_Str, "pkey_xmit", "pfx", "px"), 114 TD(Num_Str, "plab_norm", "pln", "pn"), 115 TD(Num_Str_Str, "pkey_plab", "pfxl", "xl"), 116 }; 117 /* *INDENT-ON* */ 118 119 unsigned n; 120 for (n = 0; n < SIZEOF(table); n++) { 121 if (!strcmp(name, table[n].name)) { 122 result = table[n].code; 123 break; 124 } 125 } 126 return result; 127 } 128 129 static int 130 exit_code(int token, int value) 131 { 132 int result = 99; 133 134 switch (token) { 135 case BOOLEAN: 136 result = !value; /* TRUE=0, FALSE=1 */ 137 break; 138 case NUMBER: 139 result = 0; /* always zero */ 140 break; 141 case STRING: 142 result = value; /* 0=normal, 1=missing */ 143 break; 144 } 145 return result; 146 } 147 148 static int 149 tput(int argc, char *argv[]) 150 { 151 NCURSES_CONST char *name; 152 char *s; 153 int i, j, c; 154 int status; 155 FILE *f; 156 #if !PURE_TERMINFO 157 bool termcap = FALSE; 158 #endif 159 160 if ((name = argv[0]) == 0) 161 name = ""; 162 check_aliases(name); 163 if (is_reset || is_init) { 164 if (init_prog != 0) { 165 system(init_prog); 166 } 167 FLUSH; 168 169 if (is_reset && reset_1string != 0) { 170 PUTS(reset_1string); 171 } else if (init_1string != 0) { 172 PUTS(init_1string); 173 } 174 FLUSH; 175 176 if (is_reset && reset_2string != 0) { 177 PUTS(reset_2string); 178 } else if (init_2string != 0) { 179 PUTS(init_2string); 180 } 181 FLUSH; 182 183 #ifdef set_lr_margin 184 if (set_lr_margin != 0) { 185 PUTS(TPARM_2(set_lr_margin, 0, columns - 1)); 186 } else 187 #endif 188 #ifdef set_left_margin_parm 189 if (set_left_margin_parm != 0 190 && set_right_margin_parm != 0) { 191 PUTS(TPARM_1(set_left_margin_parm, 0)); 192 PUTS(TPARM_1(set_right_margin_parm, columns - 1)); 193 } else 194 #endif 195 if (clear_margins != 0 196 && set_left_margin != 0 197 && set_right_margin != 0) { 198 PUTS(clear_margins); 199 if (carriage_return != 0) { 200 PUTS(carriage_return); 201 } else { 202 PUTCHAR('\r'); 203 } 204 PUTS(set_left_margin); 205 if (parm_right_cursor) { 206 PUTS(TPARM_1(parm_right_cursor, columns - 1)); 207 } else { 208 for (i = 0; i < columns - 1; i++) { 209 PUTCHAR(' '); 210 } 211 } 212 PUTS(set_right_margin); 213 if (carriage_return != 0) { 214 PUTS(carriage_return); 215 } else { 216 PUTCHAR('\r'); 217 } 218 } 219 FLUSH; 220 221 if (init_tabs != 8) { 222 if (clear_all_tabs != 0 && set_tab != 0) { 223 for (i = 0; i < columns - 1; i += 8) { 224 if (parm_right_cursor) { 225 PUTS(TPARM_1(parm_right_cursor, 8)); 226 } else { 227 for (j = 0; j < 8; j++) 228 PUTCHAR(' '); 229 } 230 PUTS(set_tab); 231 } 232 FLUSH; 233 } 234 } 235 236 if (is_reset && reset_file != 0) { 237 f = fopen(reset_file, "r"); 238 if (f == 0) { 239 quit(4 + errno, "Can't open reset_file: '%s'", reset_file); 240 } 241 while ((c = fgetc(f)) != EOF) { 242 PUTCHAR(c); 243 } 244 fclose(f); 245 } else if (init_file != 0) { 246 f = fopen(init_file, "r"); 247 if (f == 0) { 248 quit(4 + errno, "Can't open init_file: '%s'", init_file); 249 } 250 while ((c = fgetc(f)) != EOF) { 251 PUTCHAR(c); 252 } 253 fclose(f); 254 } 255 FLUSH; 256 257 if (is_reset && reset_3string != 0) { 258 PUTS(reset_3string); 259 } else if (init_3string != 0) { 260 PUTS(init_3string); 261 } 262 FLUSH; 263 return 0; 264 } 265 266 if (strcmp(name, "longname") == 0) { 267 PUTS(longname()); 268 return 0; 269 } 270 #if !PURE_TERMINFO 271 retry: 272 #endif 273 if ((status = tigetflag(name)) != -1) { 274 return exit_code(BOOLEAN, status); 275 } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) { 276 (void) printf("%d\n", status); 277 return exit_code(NUMBER, 0); 278 } else if ((s = tigetstr(name)) == CANCELLED_STRING) { 279 #if !PURE_TERMINFO 280 if (!termcap) { 281 const struct name_table_entry *np; 282 283 termcap = TRUE; 284 if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) { 285 switch (np->nte_type) { 286 case BOOLEAN: 287 if (bool_from_termcap[np->nte_index]) 288 name = boolnames[np->nte_index]; 289 break; 290 291 case NUMBER: 292 if (num_from_termcap[np->nte_index]) 293 name = numnames[np->nte_index]; 294 break; 295 296 case STRING: 297 if (str_from_termcap[np->nte_index]) 298 name = strnames[np->nte_index]; 299 break; 300 } 301 goto retry; 302 } 303 } 304 #endif 305 quit(4, "unknown terminfo capability '%s'", name); 306 } else if (s != ABSENT_STRING) { 307 if (argc > 1) { 308 int k; 309 int popcount; 310 long numbers[1 + NUM_PARM]; 311 char *strings[1 + NUM_PARM]; 312 char *p_is_s[NUM_PARM]; 313 314 /* Nasty hack time. The tparm function needs to see numeric 315 * parameters as numbers, not as pointers to their string 316 * representations 317 */ 318 319 for (k = 1; k < argc; k++) { 320 char *tmp = 0; 321 strings[k] = argv[k]; 322 numbers[k] = strtol(argv[k], &tmp, 0); 323 if (tmp == 0 || *tmp != 0) 324 numbers[k] = 0; 325 } 326 for (k = argc; k <= NUM_PARM; k++) { 327 numbers[k] = 0; 328 strings[k] = 0; 329 } 330 331 switch (tparm_type(name)) { 332 case Num_Str: 333 s = TPARM_2(s, numbers[1], strings[2]); 334 break; 335 case Num_Str_Str: 336 s = TPARM_3(s, numbers[1], strings[2], strings[3]); 337 break; 338 case Numbers: 339 default: 340 (void) _nc_tparm_analyze(s, p_is_s, &popcount); 341 #define myParam(n) (p_is_s[n - 1] != 0 ? ((long) strings[n]) : numbers[n]) 342 s = TPARM_9(s, 343 myParam(1), 344 myParam(2), 345 myParam(3), 346 myParam(4), 347 myParam(5), 348 myParam(6), 349 myParam(7), 350 myParam(8), 351 myParam(9)); 352 break; 353 } 354 } 355 356 /* use putp() in order to perform padding */ 357 putp(s); 358 return exit_code(STRING, 0); 359 } 360 return exit_code(STRING, 1); 361 } 362 363 int 364 main(int argc, char **argv) 365 { 366 char *term; 367 int errret; 368 bool cmdline = TRUE; 369 int c; 370 char buf[BUFSIZ]; 371 int result = 0; 372 373 check_aliases(prg_name = _nc_rootname(argv[0])); 374 375 term = getenv("TERM"); 376 377 while ((c = getopt(argc, argv, "ST:V")) != -1) { 378 switch (c) { 379 case 'S': 380 cmdline = FALSE; 381 break; 382 case 'T': 383 use_env(FALSE); 384 term = optarg; 385 break; 386 case 'V': 387 puts(curses_version()); 388 ExitProgram(EXIT_SUCCESS); 389 default: 390 usage(); 391 /* NOTREACHED */ 392 } 393 } 394 395 /* 396 * Modify the argument list to omit the options we processed. 397 */ 398 if (is_reset || is_init) { 399 if (optind-- < argc) { 400 argc -= optind; 401 argv += optind; 402 } 403 argv[0] = prg_name; 404 } else { 405 argc -= optind; 406 argv += optind; 407 } 408 409 if (term == 0 || *term == '\0') 410 quit(2, "No value for $TERM and no -T specified"); 411 412 if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0) 413 quit(3, "unknown terminal \"%s\"", term); 414 415 if (cmdline) { 416 if ((argc <= 0) && !is_reset && !is_init) 417 usage(); 418 ExitProgram(tput(argc, argv)); 419 } 420 421 while (fgets(buf, sizeof(buf), stdin) != 0) { 422 char *argvec[16]; /* command, 9 parms, null, & slop */ 423 int argnum = 0; 424 char *cp; 425 426 /* crack the argument list into a dope vector */ 427 for (cp = buf; *cp; cp++) { 428 if (isspace(UChar(*cp))) { 429 *cp = '\0'; 430 } else if (cp == buf || cp[-1] == 0) { 431 argvec[argnum++] = cp; 432 if (argnum >= (int) SIZEOF(argvec) - 1) 433 break; 434 } 435 } 436 argvec[argnum] = 0; 437 438 if (argnum != 0 439 && tput(argnum, argvec) != 0) { 440 if (result == 0) 441 result = 4; /* will return value >4 */ 442 ++result; 443 } 444 } 445 446 ExitProgram(result); 447 } 448