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