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