Annotation of src/usr.bin/tput/tput.c, Revision 1.25
1.25 ! cheloha 1: /* $OpenBSD: tput.c,v 1.24 2019/01/25 00:19:27 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.8 millert 47: #include <ctype.h>
1.1 deraadt 48: #include <err.h>
49: #include <curses.h>
1.8 millert 50: #include <term.h>
1.1 deraadt 51: #include <stdio.h>
52: #include <stdlib.h>
1.8 millert 53: #include <termios.h>
1.1 deraadt 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.8 millert 61: #include <sys/wait.h>
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.1 deraadt 70:
71: int
1.14 deraadt 72: main(int argc, char *argv[])
1.1 deraadt 73: {
1.8 millert 74: int ch, exitval, n, Sflag;
75: size_t len;
76: char *p, *term, *str;
77: char **oargv;
1.22 deraadt 78:
79: if (pledge("stdio rpath wpath tty", NULL) == -1)
80: err(1, "pledge");
1.1 deraadt 81:
1.8 millert 82: oargv = argv;
1.1 deraadt 83: term = NULL;
1.8 millert 84: Sflag = exitval = 0;
85: while ((ch = getopt(argc, argv, "ST:")) != -1)
1.1 deraadt 86: switch(ch) {
87: case 'T':
88: term = optarg;
89: break;
1.8 millert 90: case 'S':
91: Sflag = 1;
92: break;
1.1 deraadt 93: default:
94: usage();
95: }
96: argc -= optind;
97: argv += optind;
98:
1.8 millert 99: if (Sflag && argc > 0)
100: usage();
1.4 gene 101:
1.1 deraadt 102: if (!term && !(term = getenv("TERM")))
1.8 millert 103: errx(2, "No value for $TERM and no -T specified");
104:
105: /*
106: * NOTE: tgetent() will call setupterm() and set ospeed for us
107: * (this is ncurses-specific behavior)
108: */
109: if (tgetent(NULL, term) != 1)
110: errx(3, "Unknown terminal type `%s'", term);
111:
112: if (strcmp(__progname, "clear") == 0) {
113: if (Sflag)
114: usage();
115: argv = oargv;
116: *argv = __progname;
1.4 gene 117: *(argv+1) = NULL;
118: }
1.8 millert 119: if (Sflag) {
120: char **av;
121:
122: /* Build new argv based on stdin */
123: argc = n = 0;
124: av = NULL;
125: while ((str = fgetln(stdin, &len)) != NULL) {
126: if (str[len-1] != '\n')
127: errx(1, "premature EOF");
128: str[len-1] = '\0';
129: while ((p = strsep(&str, " \t")) != NULL) {
1.16 jaredy 130: /* grow av as needed */
131: if (argc + 1 >= n) {
132: n += 64;
1.20 doug 133: av = reallocarray(av, n,
134: sizeof(char *));
1.16 jaredy 135: if (av == NULL)
136: errx(1, "out of memory");
137: }
1.8 millert 138: if (*p != '\0' &&
139: (av[argc++] = strdup(p)) == NULL)
140: errx(1, "out of memory");
141: }
142: }
143: if (argc > 0) {
144: av[argc] = NULL;
145: argv = av;
146: }
147: }
148: while ((p = *argv++)) {
1.1 deraadt 149: switch (*p) {
150: case 'i':
1.8 millert 151: if (!strcmp(p, "init")) {
152: init();
153: continue;
154: }
1.1 deraadt 155: break;
156: case 'l':
157: if (!strcmp(p, "longname")) {
1.8 millert 158: puts(longname());
1.1 deraadt 159: continue;
160: }
161: break;
162: case 'r':
1.8 millert 163: if (!strcmp(p, "reset")) {
164: reset();
165: continue;
166: }
1.1 deraadt 167: break;
168: }
1.8 millert 169:
170: /* First try as terminfo */
171: if ((str = tigetstr(p)) && str != (char *)-1)
172: argv = process(p, str, argv);
173: else if ((n = tigetnum(p)) != -2)
174: (void)printf("%d\n", n);
175: else if ((n = tigetflag(p)) != -1)
176: exitval = !n;
177: /* Then fall back on termcap */
178: else if ((str = tgetstr(p, NULL)))
179: argv = process(p, str, argv);
1.7 millert 180: else if ((n = tgetnum(p)) != -1)
1.1 deraadt 181: (void)printf("%d\n", n);
1.8 millert 182: else if ((exitval = tgetflag(p)) != 0)
183: exitval = !exitval;
184: else {
185: warnx("Unknown terminfo capability `%s'", p);
186: exitval = 4;
187: }
1.1 deraadt 188: }
1.10 millert 189: exit(exitval);
1.1 deraadt 190: }
191:
192: static char **
1.14 deraadt 193: process(char *cap, char *str, char **argv)
1.1 deraadt 194: {
1.8 millert 195: char *cp, *s, *nargv[9];
196: int arg_need, popcount, i;
1.1 deraadt 197:
198: /* Count how many values we need for this capability. */
1.8 millert 199: for (cp = str, arg_need = popcount = 0; *cp != '\0'; cp++) {
200: if (*cp == '%') {
201: switch (*++cp) {
202: case '%':
203: cp++;
204: break;
205: case 'i':
206: if (popcount < 2)
207: popcount = 2;
208: break;
209: case 'p':
210: cp++;
1.18 deraadt 211: if (isdigit((unsigned char)cp[1]) &&
212: popcount < cp[1] - '0')
1.8 millert 213: popcount = cp[1] - '0';
214: break;
215: case 'd':
216: case 's':
217: case '0':
218: case '1':
219: case '2':
220: case '3':
221: case '4':
222: case '5':
223: case '6':
224: case '7':
225: case '8':
226: case '9':
227: case '.':
228: case '+':
229: arg_need++;
230: break;
231: default:
232: break;
233: }
234: }
235: }
1.21 deraadt 236: arg_need = MAXIMUM(arg_need, popcount);
1.8 millert 237: if (arg_need > 9)
238: errx(2, "too many arguments (%d) for capability `%s'",
239: arg_need, cap);
240:
241: for (i = 0; i < arg_need; i++) {
242: long l;
243:
244: if (argv[i] == NULL)
245: errx(2, "not enough arguments (%d) for capability `%s'",
246: arg_need, cap);
247:
248: /* convert ascii representation of numbers to longs */
1.19 yasuoka 249: if (isdigit((unsigned char)argv[i][0])
1.18 deraadt 250: && (l = strtol(argv[i], &cp, 10)) >= 0
1.8 millert 251: && l < LONG_MAX && *cp == '\0')
252: nargv[i] = (char *)l;
253: else
254: nargv[i] = argv[i];
255: }
1.1 deraadt 256:
1.8 millert 257: s = tparm(str, nargv[0], nargv[1], nargv[2], nargv[3],
258: nargv[4], nargv[5], nargv[6], nargv[7], nargv[8]);
259: putp(s);
260: fflush(stdout);
1.1 deraadt 261:
1.8 millert 262: return (argv + arg_need);
1.1 deraadt 263: }
264:
265: static void
1.14 deraadt 266: init(void)
1.1 deraadt 267: {
1.8 millert 268: FILE *ifile;
269: size_t len;
270: char *buf;
1.9 millert 271: int wstatus;
1.23 deraadt 272: pid_t pid;
1.1 deraadt 273:
1.8 millert 274: if (init_prog && !issetugid()) {
1.23 deraadt 275: switch (pid = vfork()) {
1.8 millert 276: case -1:
277: err(4, "vfork");
278: break;
279: case 0:
280: /* child */
1.11 deraadt 281: execl(init_prog, init_prog, (char *)NULL);
1.8 millert 282: _exit(127);
283: break;
284: default:
1.23 deraadt 285: while (waitpid(pid, &wstatus, 0) == -1) {
286: if (errno != EINTR)
287: break;
288: }
1.9 millert 289: /* parent */
1.8 millert 290: break;
291: }
292: }
293: if (init_1string)
294: putp(init_1string);
295: if (init_2string)
296: putp(init_2string);
1.9 millert 297: set_margins();
298: /* always use 8 space tabs */
299: if (init_tabs != 8 && clear_all_tabs && set_tab) {
300: int i;
301:
302: putp(clear_all_tabs);
303: for (i = 0; i < (columns - 1) / 8; i++) {
304: if (parm_right_cursor)
305: putp(tparm(parm_right_cursor, 8));
306: else
307: fputs(" ", stdout);
308: putp(set_tab);
309: }
310: }
1.8 millert 311: if (init_file && !issetugid() && (ifile = fopen(init_file, "r"))) {
312: while ((buf = fgetln(ifile, &len)) != NULL) {
313: if (buf[len-1] != '\n')
314: errx(1, "premature EOF reading %s", init_file);
315: buf[len-1] = '\0';
316: putp(buf);
317: }
318: fclose(ifile);
319: }
320: if (init_3string)
321: putp(init_3string);
322: fflush(stdout);
1.1 deraadt 323: }
324:
325: static void
1.14 deraadt 326: reset(void)
1.7 millert 327: {
1.8 millert 328: FILE *rfile;
329: size_t len;
330: char *buf;
331:
332: if (reset_1string)
333: putp(reset_1string);
334: if (reset_2string)
335: putp(reset_2string);
1.9 millert 336: set_margins();
1.8 millert 337: if (reset_file && !issetugid() && (rfile = fopen(reset_file, "r"))) {
338: while ((buf = fgetln(rfile, &len)) != NULL) {
339: if (buf[len-1] != '\n')
340: errx(1, "premature EOF reading %s", reset_file);
341: buf[len-1] = '\0';
342: putp(buf);
343: }
344: fclose(rfile);
345: }
346: if (reset_3string)
347: putp(reset_3string);
1.9 millert 348: fflush(stdout);
349: }
350:
351: static void
1.14 deraadt 352: set_margins(void)
1.9 millert 353: {
354:
355: /*
356: * Four possibilities:
357: * 1) we have set_lr_margin and can set things with one call
358: * 2) we have set_{left,right}_margin_parm, use two calls
359: * 3) we have set_{left,right}_margin, set based on position
360: * 4) none of the above, leave things the way they are
361: */
362: if (set_lr_margin) {
363: putp(tparm(set_lr_margin, 0, columns - 1));
364: } else if (set_left_margin_parm && set_right_margin_parm) {
365: putp(tparm(set_left_margin_parm, 0));
366: putp(tparm(set_right_margin_parm, columns - 1));
367: } else if (set_left_margin && set_right_margin && clear_margins) {
368: putp(clear_margins);
369:
370: /* go to column 0 and set the left margin */
371: putp(carriage_return ? carriage_return : "\r");
372: putp(set_left_margin);
373:
374: /* go to last column and set the right margin */
375: if (parm_right_cursor)
376: putp(tparm(parm_right_cursor, columns - 1));
377: else
378: printf("%*s", columns - 1, " ");
379: putp(set_right_margin);
380: putp(carriage_return ? carriage_return : "\r");
381: }
1.8 millert 382: fflush(stdout);
1.7 millert 383: }
384:
385: static void
1.14 deraadt 386: usage(void)
1.1 deraadt 387: {
1.8 millert 388:
389: if (strcmp(__progname, "clear") == 0)
390: (void)fprintf(stderr, "usage: %s [-T term]\n", __progname);
391: else
392: (void)fprintf(stderr,
393: "usage: %s [-T term] attribute [attribute-args] ...\n"
394: " %s [-T term] -S\n", __progname, __progname);
1.1 deraadt 395: exit(1);
396: }