tput.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
  31. * and: Eric S. Raymond <esr@snark.thyrsus.com> *
  32. * and: Thomas E. Dickey 1996-on *
  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. #include <tparm_type.h>
  41. #include <clear_cmd.h>
  42. #include <reset_cmd.h>
  43. #if !PURE_TERMINFO
  44. #include <dump_entry.h>
  45. #include <termsort.c>
  46. #endif
  47. #include <transform.h>
  48. #include <tty_settings.h>
  49. MODULE_ID("$Id: tput.c,v 1.83 2020/05/27 23:47:51 tom Exp $")
  50. #define PUTS(s) fputs(s, stdout)
  51. const char *_nc_progname = "tput";
  52. static char *prg_name;
  53. static bool is_init = FALSE;
  54. static bool is_reset = FALSE;
  55. static bool is_clear = FALSE;
  56. static void
  57. quit(int status, const char *fmt, ...)
  58. {
  59. va_list argp;
  60. va_start(argp, fmt);
  61. fprintf(stderr, "%s: ", prg_name);
  62. vfprintf(stderr, fmt, argp);
  63. fprintf(stderr, "\n");
  64. va_end(argp);
  65. ExitProgram(status);
  66. }
  67. static void
  68. usage(void)
  69. {
  70. #define KEEP(s) s "\n"
  71. static const char msg[] =
  72. {
  73. KEEP("")
  74. KEEP("Options:")
  75. KEEP(" -S << read commands from standard input")
  76. KEEP(" -T TERM use this instead of $TERM")
  77. KEEP(" -V print curses-version")
  78. KEEP(" -x do not try to clear scrollback")
  79. KEEP("")
  80. KEEP("Commands:")
  81. KEEP(" clear clear the screen")
  82. KEEP(" init initialize the terminal")
  83. KEEP(" reset reinitialize the terminal")
  84. KEEP(" capname unlike clear/init/reset, print value for capability \"capname\"")
  85. };
  86. #undef KEEP
  87. (void) fprintf(stderr, "Usage: %s [options] [command]\n", prg_name);
  88. fputs(msg, stderr);
  89. ExitProgram(ErrUsage);
  90. }
  91. static char *
  92. check_aliases(char *name, bool program)
  93. {
  94. static char my_init[] = "init";
  95. static char my_reset[] = "reset";
  96. static char my_clear[] = "clear";
  97. char *result = name;
  98. if ((is_init = same_program(name, program ? PROG_INIT : my_init)))
  99. result = my_init;
  100. if ((is_reset = same_program(name, program ? PROG_RESET : my_reset)))
  101. result = my_reset;
  102. if ((is_clear = same_program(name, program ? PROG_CLEAR : my_clear)))
  103. result = my_clear;
  104. return result;
  105. }
  106. static int
  107. exit_code(int token, int value)
  108. {
  109. int result = 99;
  110. switch (token) {
  111. case BOOLEAN:
  112. result = !value; /* TRUE=0, FALSE=1 */
  113. break;
  114. case NUMBER:
  115. result = 0; /* always zero */
  116. break;
  117. case STRING:
  118. result = value; /* 0=normal, 1=missing */
  119. break;
  120. }
  121. return result;
  122. }
  123. /*
  124. * Returns nonzero on error.
  125. */
  126. static int
  127. tput_cmd(int fd, TTY * saved_settings, bool opt_x, int argc, char *argv[])
  128. {
  129. NCURSES_CONST char *name;
  130. char *s;
  131. int status;
  132. #if !PURE_TERMINFO
  133. bool termcap = FALSE;
  134. #endif
  135. name = check_aliases(argv[0], FALSE);
  136. if (is_reset || is_init) {
  137. TTY oldmode;
  138. int terasechar = -1; /* new erase character */
  139. int intrchar = -1; /* new interrupt character */
  140. int tkillchar = -1; /* new kill character */
  141. if (is_reset) {
  142. reset_start(stdout, TRUE, FALSE);
  143. reset_tty_settings(fd, saved_settings);
  144. } else {
  145. reset_start(stdout, FALSE, TRUE);
  146. }
  147. #if HAVE_SIZECHANGE
  148. set_window_size(fd, &lines, &columns);
  149. #else
  150. (void) fd;
  151. #endif
  152. set_control_chars(saved_settings, terasechar, intrchar, tkillchar);
  153. set_conversions(saved_settings);
  154. if (send_init_strings(fd, &oldmode)) {
  155. reset_flush();
  156. }
  157. update_tty_settings(&oldmode, saved_settings);
  158. return 0;
  159. }
  160. if (strcmp(name, "longname") == 0) {
  161. PUTS(longname());
  162. return 0;
  163. }
  164. #if !PURE_TERMINFO
  165. retry:
  166. #endif
  167. if (strcmp(name, "clear") == 0) {
  168. return (clear_cmd(opt_x) == ERR) ? ErrUsage : 0;
  169. } else if ((status = tigetflag(name)) != -1) {
  170. return exit_code(BOOLEAN, status);
  171. } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
  172. (void) printf("%d\n", status);
  173. return exit_code(NUMBER, 0);
  174. } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
  175. #if !PURE_TERMINFO
  176. if (!termcap) {
  177. const struct name_table_entry *np;
  178. termcap = TRUE;
  179. if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
  180. switch (np->nte_type) {
  181. case BOOLEAN:
  182. name = boolnames[np->nte_index];
  183. break;
  184. case NUMBER:
  185. name = numnames[np->nte_index];
  186. break;
  187. case STRING:
  188. name = strnames[np->nte_index];
  189. break;
  190. }
  191. goto retry;
  192. }
  193. }
  194. #endif
  195. quit(ErrCapName, "unknown terminfo capability '%s'", name);
  196. } else if (VALID_STRING(s)) {
  197. if (argc > 1) {
  198. int k;
  199. int ignored;
  200. long numbers[1 + NUM_PARM];
  201. char *strings[1 + NUM_PARM];
  202. char *p_is_s[NUM_PARM];
  203. /* Nasty hack time. The tparm function needs to see numeric
  204. * parameters as numbers, not as pointers to their string
  205. * representations
  206. */
  207. for (k = 1; (k < argc) && (k < NUM_PARM); k++) {
  208. char *tmp = 0;
  209. strings[k] = argv[k];
  210. numbers[k] = strtol(argv[k], &tmp, 0);
  211. if (tmp == 0 || *tmp != 0)
  212. numbers[k] = 0;
  213. }
  214. for (k = argc; k <= NUM_PARM; k++) {
  215. numbers[k] = 0;
  216. strings[k] = 0;
  217. }
  218. switch (tparm_type(name)) {
  219. case Num_Str:
  220. s = TPARM_2(s, numbers[1], strings[2]);
  221. break;
  222. case Num_Str_Str:
  223. s = TPARM_3(s, numbers[1], strings[2], strings[3]);
  224. break;
  225. case Numbers:
  226. #define myParam(n) numbers[n]
  227. s = TIPARM_9(s,
  228. myParam(1),
  229. myParam(2),
  230. myParam(3),
  231. myParam(4),
  232. myParam(5),
  233. myParam(6),
  234. myParam(7),
  235. myParam(8),
  236. myParam(9));
  237. #undef myParam
  238. break;
  239. default:
  240. (void) _nc_tparm_analyze(s, p_is_s, &ignored);
  241. #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
  242. s = TPARM_9(s,
  243. myParam(1),
  244. myParam(2),
  245. myParam(3),
  246. myParam(4),
  247. myParam(5),
  248. myParam(6),
  249. myParam(7),
  250. myParam(8),
  251. myParam(9));
  252. #undef myParam
  253. break;
  254. }
  255. }
  256. /* use putp() in order to perform padding */
  257. putp(s);
  258. return exit_code(STRING, 0);
  259. }
  260. return exit_code(STRING, 1);
  261. }
  262. int
  263. main(int argc, char **argv)
  264. {
  265. char *term;
  266. int errret;
  267. bool cmdline = TRUE;
  268. int c;
  269. char buf[BUFSIZ];
  270. int result = 0;
  271. int fd;
  272. TTY tty_settings;
  273. bool opt_x = FALSE; /* clear scrollback if possible */
  274. bool is_alias;
  275. bool need_tty;
  276. prg_name = check_aliases(_nc_rootname(argv[0]), TRUE);
  277. term = getenv("TERM");
  278. while ((c = getopt(argc, argv, "ST:Vx")) != -1) {
  279. switch (c) {
  280. case 'S':
  281. cmdline = FALSE;
  282. break;
  283. case 'T':
  284. use_env(FALSE);
  285. use_tioctl(TRUE);
  286. term = optarg;
  287. break;
  288. case 'V':
  289. puts(curses_version());
  290. ExitProgram(EXIT_SUCCESS);
  291. case 'x': /* do not try to clear scrollback */
  292. opt_x = TRUE;
  293. break;
  294. default:
  295. usage();
  296. /* NOTREACHED */
  297. }
  298. }
  299. is_alias = (is_clear || is_reset || is_init);
  300. need_tty = ((is_reset || is_init) ||
  301. (optind < argc &&
  302. (!strcmp(argv[optind], "reset") ||
  303. !strcmp(argv[optind], "init"))));
  304. /*
  305. * Modify the argument list to omit the options we processed.
  306. */
  307. if (is_alias) {
  308. if (optind-- < argc) {
  309. argc -= optind;
  310. argv += optind;
  311. }
  312. argv[0] = prg_name;
  313. } else {
  314. argc -= optind;
  315. argv += optind;
  316. }
  317. if (term == 0 || *term == '\0')
  318. quit(ErrUsage, "No value for $TERM and no -T specified");
  319. fd = save_tty_settings(&tty_settings, need_tty);
  320. if (setupterm(term, fd, &errret) != OK && errret <= 0)
  321. quit(ErrTermType, "unknown terminal \"%s\"", term);
  322. if (cmdline) {
  323. if ((argc <= 0) && !is_alias)
  324. usage();
  325. ExitProgram(tput_cmd(fd, &tty_settings, opt_x, argc, argv));
  326. }
  327. while (fgets(buf, sizeof(buf), stdin) != 0) {
  328. char *argvec[16]; /* command, 9 parms, null, & slop */
  329. int argnum = 0;
  330. char *cp;
  331. /* crack the argument list into a dope vector */
  332. for (cp = buf; *cp; cp++) {
  333. if (isspace(UChar(*cp))) {
  334. *cp = '\0';
  335. } else if (cp == buf || cp[-1] == 0) {
  336. argvec[argnum++] = cp;
  337. if (argnum >= (int) SIZEOF(argvec) - 1)
  338. break;
  339. }
  340. }
  341. argvec[argnum] = 0;
  342. if (argnum != 0
  343. && tput_cmd(fd, &tty_settings, opt_x, argnum, argvec) != 0) {
  344. if (result == 0)
  345. result = ErrSystem(0); /* will return value >4 */
  346. ++result;
  347. }
  348. }
  349. ExitProgram(result);
  350. }