xref: /dragonfly/contrib/ncurses/progs/tput.c (revision b5302a4e)
1 /****************************************************************************
2  * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  *     and: Thomas E. Dickey                        1996-on                 *
33  ****************************************************************************/
34 
35 /*
36  * tput.c -- shellscript access to terminal capabilities
37  *
38  * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
39  * Ross Ridge's mytinfo package.
40  */
41 
42 #include <tparm_type.h>
43 
44 #if !PURE_TERMINFO
45 #include <dump_entry.h>
46 #include <termsort.c>
47 #endif
48 #include <transform.h>
49 
50 MODULE_ID("$Id: tput.c,v 1.51 2015/05/23 23:42:55 tom Exp $")
51 
52 #define PUTS(s)		fputs(s, stdout)
53 #define PUTCHAR(c)	putchar(c)
54 #define FLUSH		fflush(stdout)
55 
56 static char *prg_name;
57 static bool is_init = FALSE;
58 static bool is_reset = FALSE;
59 
60 static void
61 quit(int status, const char *fmt,...)
62 {
63     va_list argp;
64 
65     va_start(argp, fmt);
66     fprintf(stderr, "%s: ", prg_name);
67     vfprintf(stderr, fmt, argp);
68     fprintf(stderr, "\n");
69     va_end(argp);
70     ExitProgram(status);
71 }
72 
73 static void
74 usage(void)
75 {
76     fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name);
77     ExitProgram(EXIT_FAILURE);
78 }
79 
80 static void
81 check_aliases(const char *name)
82 {
83     is_init = same_program(name, PROG_INIT);
84     is_reset = same_program(name, PROG_RESET);
85 }
86 
87 static int
88 exit_code(int token, int value)
89 {
90     int result = 99;
91 
92     switch (token) {
93     case BOOLEAN:
94 	result = !value;	/* TRUE=0, FALSE=1 */
95 	break;
96     case NUMBER:
97 	result = 0;		/* always zero */
98 	break;
99     case STRING:
100 	result = value;		/* 0=normal, 1=missing */
101 	break;
102     }
103     return result;
104 }
105 
106 static int
107 tput(int argc, char *argv[])
108 {
109     NCURSES_CONST char *name;
110     char *s;
111     int i, j, c;
112     int status;
113     FILE *f;
114 #if !PURE_TERMINFO
115     bool termcap = FALSE;
116 #endif
117 
118     if ((name = argv[0]) == 0)
119 	name = "";
120     check_aliases(name);
121     if (is_reset || is_init) {
122 	if (init_prog != 0) {
123 	    IGNORE_RC(system(init_prog));
124 	}
125 	FLUSH;
126 
127 	if (is_reset && reset_1string != 0) {
128 	    PUTS(reset_1string);
129 	} else if (init_1string != 0) {
130 	    PUTS(init_1string);
131 	}
132 	FLUSH;
133 
134 	if (is_reset && reset_2string != 0) {
135 	    PUTS(reset_2string);
136 	} else if (init_2string != 0) {
137 	    PUTS(init_2string);
138 	}
139 	FLUSH;
140 
141 #ifdef set_lr_margin
142 	if (set_lr_margin != 0) {
143 	    PUTS(TPARM_2(set_lr_margin, 0, columns - 1));
144 	} else
145 #endif
146 #ifdef set_left_margin_parm
147 	    if (set_left_margin_parm != 0
148 		&& set_right_margin_parm != 0) {
149 	    PUTS(TPARM_1(set_left_margin_parm, 0));
150 	    PUTS(TPARM_1(set_right_margin_parm, columns - 1));
151 	} else
152 #endif
153 	    if (clear_margins != 0
154 		&& set_left_margin != 0
155 		&& set_right_margin != 0) {
156 	    PUTS(clear_margins);
157 	    if (carriage_return != 0) {
158 		PUTS(carriage_return);
159 	    } else {
160 		PUTCHAR('\r');
161 	    }
162 	    PUTS(set_left_margin);
163 	    if (parm_right_cursor) {
164 		PUTS(TPARM_1(parm_right_cursor, columns - 1));
165 	    } else {
166 		for (i = 0; i < columns - 1; i++) {
167 		    PUTCHAR(' ');
168 		}
169 	    }
170 	    PUTS(set_right_margin);
171 	    if (carriage_return != 0) {
172 		PUTS(carriage_return);
173 	    } else {
174 		PUTCHAR('\r');
175 	    }
176 	}
177 	FLUSH;
178 
179 	if (init_tabs != 8) {
180 	    if (clear_all_tabs != 0 && set_tab != 0) {
181 		for (i = 0; i < columns - 1; i += 8) {
182 		    if (parm_right_cursor) {
183 			PUTS(TPARM_1(parm_right_cursor, 8));
184 		    } else {
185 			for (j = 0; j < 8; j++)
186 			    PUTCHAR(' ');
187 		    }
188 		    PUTS(set_tab);
189 		}
190 		FLUSH;
191 	    }
192 	}
193 
194 	if (is_reset && reset_file != 0) {
195 	    f = fopen(reset_file, "r");
196 	    if (f == 0) {
197 		quit(4 + errno, "Can't open reset_file: '%s'", reset_file);
198 	    }
199 	    while ((c = fgetc(f)) != EOF) {
200 		PUTCHAR(c);
201 	    }
202 	    fclose(f);
203 	} else if (init_file != 0) {
204 	    f = fopen(init_file, "r");
205 	    if (f == 0) {
206 		quit(4 + errno, "Can't open init_file: '%s'", init_file);
207 	    }
208 	    while ((c = fgetc(f)) != EOF) {
209 		PUTCHAR(c);
210 	    }
211 	    fclose(f);
212 	}
213 	FLUSH;
214 
215 	if (is_reset && reset_3string != 0) {
216 	    PUTS(reset_3string);
217 	} else if (init_3string != 0) {
218 	    PUTS(init_3string);
219 	}
220 	FLUSH;
221 	return 0;
222     }
223 
224     if (strcmp(name, "longname") == 0) {
225 	PUTS(longname());
226 	return 0;
227     }
228 #if !PURE_TERMINFO
229   retry:
230 #endif
231     if ((status = tigetflag(name)) != -1) {
232 	return exit_code(BOOLEAN, status);
233     } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
234 	(void) printf("%d\n", status);
235 	return exit_code(NUMBER, 0);
236     } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
237 #if !PURE_TERMINFO
238 	if (!termcap) {
239 	    const struct name_table_entry *np;
240 
241 	    termcap = TRUE;
242 	    if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
243 		switch (np->nte_type) {
244 		case BOOLEAN:
245 		    if (bool_from_termcap[np->nte_index])
246 			name = boolnames[np->nte_index];
247 		    break;
248 
249 		case NUMBER:
250 		    if (num_from_termcap[np->nte_index])
251 			name = numnames[np->nte_index];
252 		    break;
253 
254 		case STRING:
255 		    if (str_from_termcap[np->nte_index])
256 			name = strnames[np->nte_index];
257 		    break;
258 		}
259 		goto retry;
260 	    }
261 	}
262 #endif
263 	quit(4, "unknown terminfo capability '%s'", name);
264     } else if (s != ABSENT_STRING) {
265 	if (argc > 1) {
266 	    int k;
267 	    int ignored;
268 	    long numbers[1 + NUM_PARM];
269 	    char *strings[1 + NUM_PARM];
270 	    char *p_is_s[NUM_PARM];
271 
272 	    /* Nasty hack time. The tparm function needs to see numeric
273 	     * parameters as numbers, not as pointers to their string
274 	     * representations
275 	     */
276 
277 	    for (k = 1; k < argc; k++) {
278 		char *tmp = 0;
279 		strings[k] = argv[k];
280 		numbers[k] = strtol(argv[k], &tmp, 0);
281 		if (tmp == 0 || *tmp != 0)
282 		    numbers[k] = 0;
283 	    }
284 	    for (k = argc; k <= NUM_PARM; k++) {
285 		numbers[k] = 0;
286 		strings[k] = 0;
287 	    }
288 
289 	    switch (tparm_type(name)) {
290 	    case Num_Str:
291 		s = TPARM_2(s, numbers[1], strings[2]);
292 		break;
293 	    case Num_Str_Str:
294 		s = TPARM_3(s, numbers[1], strings[2], strings[3]);
295 		break;
296 	    case Numbers:
297 	    default:
298 		(void) _nc_tparm_analyze(s, p_is_s, &ignored);
299 #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
300 		s = TPARM_9(s,
301 			    myParam(1),
302 			    myParam(2),
303 			    myParam(3),
304 			    myParam(4),
305 			    myParam(5),
306 			    myParam(6),
307 			    myParam(7),
308 			    myParam(8),
309 			    myParam(9));
310 		break;
311 	    }
312 	}
313 
314 	/* use putp() in order to perform padding */
315 	putp(s);
316 	return exit_code(STRING, 0);
317     }
318     return exit_code(STRING, 1);
319 }
320 
321 int
322 main(int argc, char **argv)
323 {
324     char *term;
325     int errret;
326     bool cmdline = TRUE;
327     int c;
328     char buf[BUFSIZ];
329     int result = 0;
330 
331     check_aliases(prg_name = _nc_rootname(argv[0]));
332 
333     term = getenv("TERM");
334 
335     while ((c = getopt(argc, argv, "ST:V")) != -1) {
336 	switch (c) {
337 	case 'S':
338 	    cmdline = FALSE;
339 	    break;
340 	case 'T':
341 	    use_env(FALSE);
342 	    term = optarg;
343 	    break;
344 	case 'V':
345 	    puts(curses_version());
346 	    ExitProgram(EXIT_SUCCESS);
347 	default:
348 	    usage();
349 	    /* NOTREACHED */
350 	}
351     }
352 
353     /*
354      * Modify the argument list to omit the options we processed.
355      */
356     if (is_reset || is_init) {
357 	if (optind-- < argc) {
358 	    argc -= optind;
359 	    argv += optind;
360 	}
361 	argv[0] = prg_name;
362     } else {
363 	argc -= optind;
364 	argv += optind;
365     }
366 
367     if (term == 0 || *term == '\0')
368 	quit(2, "No value for $TERM and no -T specified");
369 
370     if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0)
371 	quit(3, "unknown terminal \"%s\"", term);
372 
373     if (cmdline) {
374 	if ((argc <= 0) && !is_reset && !is_init)
375 	    usage();
376 	ExitProgram(tput(argc, argv));
377     }
378 
379     while (fgets(buf, sizeof(buf), stdin) != 0) {
380 	char *argvec[16];	/* command, 9 parms, null, & slop */
381 	int argnum = 0;
382 	char *cp;
383 
384 	/* crack the argument list into a dope vector */
385 	for (cp = buf; *cp; cp++) {
386 	    if (isspace(UChar(*cp))) {
387 		*cp = '\0';
388 	    } else if (cp == buf || cp[-1] == 0) {
389 		argvec[argnum++] = cp;
390 		if (argnum >= (int) SIZEOF(argvec) - 1)
391 		    break;
392 	    }
393 	}
394 	argvec[argnum] = 0;
395 
396 	if (argnum != 0
397 	    && tput(argnum, argvec) != 0) {
398 	    if (result == 0)
399 		result = 4;	/* will return value >4 */
400 	    ++result;
401 	}
402     }
403 
404     ExitProgram(result);
405 }
406