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