1 /**************************************************************************** 2 * Copyright (c) 1998,1999,2000,2001 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.30 2001/07/22 00:16:33 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 vfprintf(stderr, fmt, argp); 71 fprintf(stderr, "\n"); 72 va_end(argp); 73 exit(status); 74 } 75 76 static void 77 usage(void) 78 { 79 fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name); 80 exit(EXIT_FAILURE); 81 } 82 83 static void 84 check_aliases(const char *name) 85 { 86 is_init = (strcmp(name, PROG_INIT) == 0); 87 is_reset = (strcmp(name, PROG_RESET) == 0); 88 } 89 90 /* 91 * Lookup the type of call we should make to tparm(). This ignores the actual 92 * terminfo capability (bad, because it is not extensible), but makes this 93 * code portable to platforms where sizeof(int) != sizeof(char *). 94 * 95 * FIXME: If we want extensibility, analyze the capability string as we do 96 * in tparm() to decide how to parse the varargs list. 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 tput(int argc, char *argv[]) 128 { 129 NCURSES_CONST char *name; 130 char *s; 131 int i, j, c; 132 int status; 133 FILE *f; 134 135 if ((name = argv[0]) == 0) 136 name = ""; 137 check_aliases(name); 138 if (is_reset || is_init) { 139 if (init_prog != 0) { 140 system(init_prog); 141 } 142 FLUSH; 143 144 if (is_reset && reset_1string != 0) { 145 PUTS(reset_1string); 146 } else if (init_1string != 0) { 147 PUTS(init_1string); 148 } 149 FLUSH; 150 151 if (is_reset && reset_2string != 0) { 152 PUTS(reset_2string); 153 } else if (init_2string != 0) { 154 PUTS(init_2string); 155 } 156 FLUSH; 157 158 #ifdef set_lr_margin 159 if (set_lr_margin != 0) { 160 PUTS(tparm(set_lr_margin, 0, columns - 1)); 161 } else 162 #endif 163 #ifdef set_left_margin_parm 164 if (set_left_margin_parm != 0 165 && set_right_margin_parm != 0) { 166 PUTS(tparm(set_left_margin_parm, 0)); 167 PUTS(tparm(set_right_margin_parm, columns - 1)); 168 } else 169 #endif 170 if (clear_margins != 0 171 && set_left_margin != 0 172 && set_right_margin != 0) { 173 PUTS(clear_margins); 174 if (carriage_return != 0) { 175 PUTS(carriage_return); 176 } else { 177 PUTCHAR('\r'); 178 } 179 PUTS(set_left_margin); 180 if (parm_right_cursor) { 181 PUTS(tparm(parm_right_cursor, columns - 1)); 182 } else { 183 for (i = 0; i < columns - 1; i++) { 184 PUTCHAR(' '); 185 } 186 } 187 PUTS(set_right_margin); 188 if (carriage_return != 0) { 189 PUTS(carriage_return); 190 } else { 191 PUTCHAR('\r'); 192 } 193 } 194 FLUSH; 195 196 if (init_tabs != 8) { 197 if (clear_all_tabs != 0 && set_tab != 0) { 198 for (i = 0; i < columns - 1; i += 8) { 199 if (parm_right_cursor) { 200 PUTS(tparm(parm_right_cursor, 8)); 201 } else { 202 for (j = 0; j < 8; j++) 203 PUTCHAR(' '); 204 } 205 PUTS(set_tab); 206 } 207 FLUSH; 208 } 209 } 210 211 if (is_reset && reset_file != 0) { 212 f = fopen(reset_file, "r"); 213 if (f == 0) { 214 quit(errno, "Can't open reset_file: '%s'", reset_file); 215 } 216 while ((c = fgetc(f)) != EOF) { 217 PUTCHAR(c); 218 } 219 fclose(f); 220 } else if (init_file != 0) { 221 f = fopen(init_file, "r"); 222 if (f == 0) { 223 quit(errno, "Can't open init_file: '%s'", init_file); 224 } 225 while ((c = fgetc(f)) != EOF) { 226 PUTCHAR(c); 227 } 228 fclose(f); 229 } 230 FLUSH; 231 232 if (is_reset && reset_3string != 0) { 233 PUTS(reset_3string); 234 } else if (init_2string != 0) { 235 PUTS(init_2string); 236 } 237 FLUSH; 238 return 0; 239 } 240 241 if (strcmp(name, "longname") == 0) { 242 PUTS(longname()); 243 return 0; 244 } 245 #if !PURE_TERMINFO 246 { 247 const struct name_table_entry *np; 248 249 if ((np = _nc_find_entry(name, _nc_get_hash_table(1))) != 0) 250 switch (np->nte_type) { 251 case BOOLEAN: 252 if (bool_from_termcap[np->nte_index]) 253 name = boolnames[np->nte_index]; 254 break; 255 256 case NUMBER: 257 if (num_from_termcap[np->nte_index]) 258 name = numnames[np->nte_index]; 259 break; 260 261 case STRING: 262 if (str_from_termcap[np->nte_index]) 263 name = strnames[np->nte_index]; 264 break; 265 } 266 } 267 #endif 268 269 if ((status = tigetflag(name)) != -1) { 270 return (status != 0); 271 } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) { 272 (void) printf("%d\n", status); 273 return (0); 274 } else if ((s = tigetstr(name)) == CANCELLED_STRING) { 275 quit(4, "%s: unknown terminfo capability '%s'", prg_name, name); 276 } else if (s != ABSENT_STRING) { 277 if (argc > 1) { 278 int k; 279 int numbers[10]; 280 char *strings[10]; 281 282 /* Nasty hack time. The tparm function needs to see numeric 283 * parameters as numbers, not as pointers to their string 284 * representations 285 */ 286 287 for (k = 1; k < argc; k++) { 288 char *tmp = 0; 289 strings[k] = argv[k]; 290 numbers[k] = strtol(argv[k], &tmp, 0); 291 if (tmp == 0 || *tmp != 0) 292 numbers[k] = 0; 293 } 294 for (k = argc; k <= 9; k++) { 295 numbers[k] = 0; 296 strings[k] = 0; 297 } 298 299 switch (tparm_type(name)) { 300 case Num_Str: 301 s = tparm(s, numbers[1], strings[2]); 302 break; 303 case Num_Str_Str: 304 s = tparm(s, numbers[1], strings[2], strings[3]); 305 break; 306 default: 307 s = tparm(s, 308 numbers[1], numbers[2], numbers[3], 309 numbers[4], numbers[5], numbers[6], 310 numbers[7], numbers[8], numbers[9]); 311 break; 312 } 313 } 314 315 /* use putp() in order to perform padding */ 316 putp(s); 317 return (0); 318 } 319 return (0); 320 } 321 322 int 323 main(int argc, char **argv) 324 { 325 char *term; 326 int errret; 327 bool cmdline = TRUE; 328 int c; 329 char buf[BUFSIZ]; 330 int errors = 0; 331 332 check_aliases(prg_name = _nc_rootname(argv[0])); 333 334 term = getenv("TERM"); 335 336 while ((c = getopt(argc, argv, "ST:V")) != EOF) { 337 switch (c) { 338 case 'S': 339 cmdline = FALSE; 340 break; 341 case 'T': 342 use_env(FALSE); 343 term = optarg; 344 break; 345 case 'V': 346 puts(curses_version()); 347 return EXIT_SUCCESS; 348 default: 349 usage(); 350 /* NOTREACHED */ 351 } 352 } 353 354 /* 355 * Modify the argument list to omit the options we processed. 356 */ 357 if (is_reset || is_init) { 358 if (optind-- < argc) { 359 argc -= optind; 360 argv += optind; 361 } 362 argv[0] = prg_name; 363 } else { 364 argc -= optind; 365 argv += optind; 366 } 367 368 if (term == 0 || *term == '\0') 369 quit(2, "No value for $TERM and no -T specified"); 370 371 if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0) 372 quit(3, "unknown terminal \"%s\"", term); 373 374 if (cmdline) { 375 if ((argc <= 0) && !is_reset && !is_init) 376 usage(); 377 return tput(argc, argv); 378 } 379 380 while (fgets(buf, sizeof(buf), stdin) != 0) { 381 char *argvec[16]; /* command, 9 parms, null, & slop */ 382 int argnum = 0; 383 char *cp; 384 385 /* crack the argument list into a dope vector */ 386 for (cp = buf; *cp; cp++) { 387 if (isspace(UChar(*cp))) { 388 *cp = '\0'; 389 } else if (cp == buf || cp[-1] == 0) { 390 argvec[argnum++] = cp; 391 if (argnum >= (int) SIZEOF(argvec) - 1) 392 break; 393 } 394 } 395 argvec[argnum] = 0; 396 397 if (argnum != 0 398 && tput(argnum, argvec) != 0) 399 errors++; 400 } 401 402 return errors > 0; 403 } 404