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