Annotation of src/usr.bin/tput/tput.c, Revision 1.29
1.29 ! jsg 1: /* $OpenBSD: tput.c,v 1.28 2023/02/08 15:56:32 millert Exp $ */
1.1 deraadt 2:
1.8 millert 3: /*
1.24 millert 4: * Copyright (c) 1999 Todd C. Miller <millert@openbsd.org>
1.8 millert 5: *
1.13 millert 6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.8 millert 9: *
1.15 millert 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.8 millert 17: */
1.1 deraadt 18: /*-
19: * Copyright (c) 1980, 1988, 1993
20: * The Regents of the University of California. All rights reserved.
21: *
22: * Redistribution and use in source and binary forms, with or without
23: * modification, are permitted provided that the following conditions
24: * are met:
25: * 1. Redistributions of source code must retain the above copyright
26: * notice, this list of conditions and the following disclaimer.
27: * 2. Redistributions in binary form must reproduce the above copyright
28: * notice, this list of conditions and the following disclaimer in the
29: * documentation and/or other materials provided with the distribution.
1.13 millert 30: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 31: * may be used to endorse or promote products derived from this software
32: * without specific prior written permission.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: * SUCH DAMAGE.
45: */
46:
1.28 millert 47: #include <sys/wait.h>
1.8 millert 48: #include <ctype.h>
1.1 deraadt 49: #include <err.h>
50: #include <curses.h>
1.8 millert 51: #include <term.h>
1.1 deraadt 52: #include <stdio.h>
53: #include <stdlib.h>
54: #include <unistd.h>
1.23 deraadt 55: #include <errno.h>
1.21 deraadt 56: #include <limits.h>
1.5 dgregor 57: #include <string.h>
1.1 deraadt 58:
1.21 deraadt 59: #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
60:
1.28 millert 61: #define NUM_PARM 9 /* must match tic.h */
1.8 millert 62:
1.12 millert 63: static void init(void);
64: static char **process(char *, char *, char **);
65: static void reset(void);
66: static void set_margins(void);
67: static void usage(void);
1.8 millert 68:
69: extern char *__progname;
1.28 millert 70: extern int _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount);
1.1 deraadt 71:
72: int
1.14 deraadt 73: main(int argc, char *argv[])
1.1 deraadt 74: {
1.8 millert 75: int ch, exitval, n, Sflag;
76: size_t len;
77: char *p, *term, *str;
78: char **oargv;
1.22 deraadt 79:
80: if (pledge("stdio rpath wpath tty", NULL) == -1)
81: err(1, "pledge");
1.1 deraadt 82:
1.8 millert 83: oargv = argv;
1.1 deraadt 84: term = NULL;
1.8 millert 85: Sflag = exitval = 0;
86: while ((ch = getopt(argc, argv, "ST:")) != -1)
1.1 deraadt 87: switch(ch) {
88: case 'T':
89: term = optarg;
90: break;
1.8 millert 91: case 'S':
92: Sflag = 1;
93: break;
1.1 deraadt 94: default:
95: usage();
96: }
97: argc -= optind;
98: argv += optind;
99:
1.8 millert 100: if (Sflag && argc > 0)
101: usage();
1.4 gene 102:
1.1 deraadt 103: if (!term && !(term = getenv("TERM")))
1.8 millert 104: errx(2, "No value for $TERM and no -T specified");
105:
106: /*
107: * NOTE: tgetent() will call setupterm() and set ospeed for us
108: * (this is ncurses-specific behavior)
109: */
110: if (tgetent(NULL, term) != 1)
111: errx(3, "Unknown terminal type `%s'", term);
112:
113: if (strcmp(__progname, "clear") == 0) {
114: if (Sflag)
115: usage();
116: argv = oargv;
117: *argv = __progname;
1.4 gene 118: *(argv+1) = NULL;
119: }
1.8 millert 120: if (Sflag) {
121: char **av;
122:
123: /* Build new argv based on stdin */
124: argc = n = 0;
125: av = NULL;
126: while ((str = fgetln(stdin, &len)) != NULL) {
127: if (str[len-1] != '\n')
128: errx(1, "premature EOF");
129: str[len-1] = '\0';
130: while ((p = strsep(&str, " \t")) != NULL) {
1.16 jaredy 131: /* grow av as needed */
132: if (argc + 1 >= n) {
133: n += 64;
1.20 doug 134: av = reallocarray(av, n,
135: sizeof(char *));
1.16 jaredy 136: if (av == NULL)
137: errx(1, "out of memory");
138: }
1.8 millert 139: if (*p != '\0' &&
140: (av[argc++] = strdup(p)) == NULL)
141: errx(1, "out of memory");
142: }
143: }
144: if (argc > 0) {
145: av[argc] = NULL;
146: argv = av;
147: }
148: }
149: while ((p = *argv++)) {
1.1 deraadt 150: switch (*p) {
151: case 'i':
1.8 millert 152: if (!strcmp(p, "init")) {
153: init();
154: continue;
155: }
1.1 deraadt 156: break;
157: case 'l':
158: if (!strcmp(p, "longname")) {
1.8 millert 159: puts(longname());
1.1 deraadt 160: continue;
161: }
162: break;
163: case 'r':
1.8 millert 164: if (!strcmp(p, "reset")) {
165: reset();
166: continue;
167: }
1.1 deraadt 168: break;
169: }
1.8 millert 170:
171: /* First try as terminfo */
172: if ((str = tigetstr(p)) && str != (char *)-1)
173: argv = process(p, str, argv);
174: else if ((n = tigetnum(p)) != -2)
175: (void)printf("%d\n", n);
176: else if ((n = tigetflag(p)) != -1)
177: exitval = !n;
178: /* Then fall back on termcap */
179: else if ((str = tgetstr(p, NULL)))
180: argv = process(p, str, argv);
1.7 millert 181: else if ((n = tgetnum(p)) != -1)
1.1 deraadt 182: (void)printf("%d\n", n);
1.8 millert 183: else if ((exitval = tgetflag(p)) != 0)
184: exitval = !exitval;
185: else {
186: warnx("Unknown terminfo capability `%s'", p);
187: exitval = 4;
188: }
1.1 deraadt 189: }
1.10 millert 190: exit(exitval);
1.1 deraadt 191: }
192:
193: static char **
1.14 deraadt 194: process(char *cap, char *str, char **argv)
1.1 deraadt 195: {
1.29 ! jsg 196: char *s, *nargv[NUM_PARM] = {0};
1.28 millert 197: char *p_is_s[NUM_PARM];
198: int arg_need, i;
1.1 deraadt 199:
200: /* Count how many values we need for this capability. */
1.28 millert 201: i = _nc_tparm_analyze(str, p_is_s, &arg_need);
202: if (arg_need == 0)
203: arg_need = i;
204: if (arg_need > NUM_PARM)
1.8 millert 205: errx(2, "too many arguments (%d) for capability `%s'",
206: arg_need, cap);
207:
208: for (i = 0; i < arg_need; i++) {
1.28 millert 209: const char *errstr;
1.8 millert 210: long l;
211:
212: if (argv[i] == NULL)
213: errx(2, "not enough arguments (%d) for capability `%s'",
214: arg_need, cap);
215:
1.28 millert 216: if (p_is_s[i] != 0) {
217: nargv[i] = argv[i];
218: } else {
219: /* convert ascii representation of numbers to longs */
220: l = strtonum(argv[i], LONG_MIN, LONG_MAX, &errstr);
221: if (errstr != NULL)
222: errx(2, "capability `%s' is %s", cap, errstr);
1.8 millert 223: nargv[i] = (char *)l;
1.28 millert 224: }
1.8 millert 225: }
1.1 deraadt 226:
1.8 millert 227: s = tparm(str, nargv[0], nargv[1], nargv[2], nargv[3],
228: nargv[4], nargv[5], nargv[6], nargv[7], nargv[8]);
229: putp(s);
230: fflush(stdout);
1.1 deraadt 231:
1.8 millert 232: return (argv + arg_need);
1.1 deraadt 233: }
234:
235: static void
1.14 deraadt 236: init(void)
1.1 deraadt 237: {
1.8 millert 238: FILE *ifile;
239: size_t len;
240: char *buf;
1.9 millert 241: int wstatus;
1.23 deraadt 242: pid_t pid;
1.1 deraadt 243:
1.8 millert 244: if (init_prog && !issetugid()) {
1.23 deraadt 245: switch (pid = vfork()) {
1.8 millert 246: case -1:
247: err(4, "vfork");
248: break;
249: case 0:
250: /* child */
1.11 deraadt 251: execl(init_prog, init_prog, (char *)NULL);
1.8 millert 252: _exit(127);
253: break;
254: default:
1.23 deraadt 255: while (waitpid(pid, &wstatus, 0) == -1) {
256: if (errno != EINTR)
257: break;
258: }
1.9 millert 259: /* parent */
1.8 millert 260: break;
261: }
262: }
263: if (init_1string)
264: putp(init_1string);
265: if (init_2string)
266: putp(init_2string);
1.9 millert 267: set_margins();
268: /* always use 8 space tabs */
269: if (init_tabs != 8 && clear_all_tabs && set_tab) {
270: int i;
271:
272: putp(clear_all_tabs);
273: for (i = 0; i < (columns - 1) / 8; i++) {
274: if (parm_right_cursor)
275: putp(tparm(parm_right_cursor, 8));
276: else
277: fputs(" ", stdout);
278: putp(set_tab);
279: }
280: }
1.8 millert 281: if (init_file && !issetugid() && (ifile = fopen(init_file, "r"))) {
282: while ((buf = fgetln(ifile, &len)) != NULL) {
283: if (buf[len-1] != '\n')
284: errx(1, "premature EOF reading %s", init_file);
285: buf[len-1] = '\0';
286: putp(buf);
287: }
288: fclose(ifile);
289: }
290: if (init_3string)
291: putp(init_3string);
292: fflush(stdout);
1.1 deraadt 293: }
294:
295: static void
1.14 deraadt 296: reset(void)
1.7 millert 297: {
1.8 millert 298: FILE *rfile;
299: size_t len;
300: char *buf;
301:
302: if (reset_1string)
303: putp(reset_1string);
304: if (reset_2string)
305: putp(reset_2string);
1.9 millert 306: set_margins();
1.8 millert 307: if (reset_file && !issetugid() && (rfile = fopen(reset_file, "r"))) {
308: while ((buf = fgetln(rfile, &len)) != NULL) {
309: if (buf[len-1] != '\n')
310: errx(1, "premature EOF reading %s", reset_file);
311: buf[len-1] = '\0';
312: putp(buf);
313: }
314: fclose(rfile);
315: }
316: if (reset_3string)
317: putp(reset_3string);
1.9 millert 318: fflush(stdout);
319: }
320:
321: static void
1.14 deraadt 322: set_margins(void)
1.9 millert 323: {
324:
325: /*
326: * Four possibilities:
327: * 1) we have set_lr_margin and can set things with one call
328: * 2) we have set_{left,right}_margin_parm, use two calls
329: * 3) we have set_{left,right}_margin, set based on position
330: * 4) none of the above, leave things the way they are
331: */
332: if (set_lr_margin) {
333: putp(tparm(set_lr_margin, 0, columns - 1));
334: } else if (set_left_margin_parm && set_right_margin_parm) {
335: putp(tparm(set_left_margin_parm, 0));
336: putp(tparm(set_right_margin_parm, columns - 1));
337: } else if (set_left_margin && set_right_margin && clear_margins) {
338: putp(clear_margins);
339:
340: /* go to column 0 and set the left margin */
341: putp(carriage_return ? carriage_return : "\r");
342: putp(set_left_margin);
343:
344: /* go to last column and set the right margin */
345: if (parm_right_cursor)
346: putp(tparm(parm_right_cursor, columns - 1));
347: else
348: printf("%*s", columns - 1, " ");
349: putp(set_right_margin);
350: putp(carriage_return ? carriage_return : "\r");
351: }
1.8 millert 352: fflush(stdout);
1.7 millert 353: }
354:
355: static void
1.14 deraadt 356: usage(void)
1.1 deraadt 357: {
1.8 millert 358:
359: if (strcmp(__progname, "clear") == 0)
360: (void)fprintf(stderr, "usage: %s [-T term]\n", __progname);
361: else
362: (void)fprintf(stderr,
1.26 kn 363: "usage: %s [-T term] attribute [attribute-arg ...] ...\n"
1.8 millert 364: " %s [-T term] -S\n", __progname, __progname);
1.1 deraadt 365: exit(1);
366: }