xref: /illumos-gate/usr/src/lib/libxcurses/src/tput/tput.c (revision 1da57d55)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1996, by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  *	tput.c
29  *
30  *	Copyright 1990, 1994 by Mortice Kern Systems Inc.  All rights reserved.
31  *
32  *	PORTABILITY:
33  *	SVID 3 - fully
34  *	POSIX.2a UPE - needs clarification between SVID 3 exit statues.
35  *		       In particular exit 1 and 4 for string capnames.
36  *	not in XPG 3
37  *
38  *	SYNOPSIS:
39  *	tput [-T<term>] capname [parm1..parm9]
40  *	tput [-T<term>] -S
41  *
42  *	DESCRIPTION:
43  *	tput lets you change your terminal's characteristics. The capname
44  *	argument indicates how you want to change the characteristics.
45  *	Some special capnames are:
46  *
47  *	clear		clear the screen
48  *	init		initialize terminal in an implemenation-defined way
49  *	reset		reset terminal in an implemenation-defined way
50  *	longname	print the full name of the ternminal (SVID)
51  *
52  *	Other capnames are supported and may take from 0 to 9 parameters. A
53  *	list of them can be found in the SVID 3, vol 3. (SVID)
54  *
55  *	tput does its work by outputting approriate character sequences to the
56  *	standard output. These character sequences are terminal-specific. If
57  *	you specify  -T <type>, tput assumes that your terminal has the
58  *	specified type and will issue sequences appropriate to that terminal.
59  *
60  *	If you do not specify -T, tput looks for an environment variable
61  *	named TERM. If TERM exists, its value is assumed to give the terminal
62  *	type. If TERM does not exist, tput assumes a default terminal type.
63  *
64  *	The  -S  option allows more than one capability per invocation of tput.
65  *	The capabilities must be passed to tput from the standard input instead
66  *	of the comamnd line. Only one capname is allowed per line.
67  *
68  *	EXIT STATUS
69  *	tput may return the following status values:
70  *
71  *	0	Either a boolean capname is set true or a string capname was
72  *		successfully written to the terminal.
73  *
74  *	1	No error message is printed. Returned if a boolean capname is
75  *		false or a string capname is not defined for the terminal.(SVID)
76  *
77  *	2	Usage error.
78  *
79  *	3	Unknown terminal <term> or no terminfo database.
80  *
81  *	4	Unknown terminfo capability <capname>.
82  *
83  *	>4	An error occured.
84  *
85  *
86  *	NOTE 1: If the Caps file that describes the terminfo database changes
87  *	then a new term.h will be required.  See CURSES/tic related tools.
88  *
89  *	NOTE 2: tput has knowledge about the TERMINAL structure.
90  */
91 #ifdef M_RCSID
92 #ifndef lint
93 static char rcsID[] = "$Id: tput.c 1.28 1995/04/12 09:28:05 ross Exp $";
94 #endif
95 #endif
96 
97 #include <mks.h>
98 #include <curses.h>
99 #include <term.h>
100 #include <ctype.h>
101 #include <limits.h>
102 #include <stdarg.h>
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 
107 extern char *_cmdname;
108 
109 
110 /* Exit Status */
111 #define SUCCESS		0
112 #define NOT_DEFINED	1
113 #define USAGE		2
114 #define BAD_TERMINAL	3
115 #define NOT_VALID	4
116 #define ERROR		5
117 
118 static int S_flag = 0;
119 static char *term_name;
120 static char dumb_term[] = "dumb";
121 static char usage_msg[] = m_textstr(4931, "\
122 Usage: tput [-W] [-Tterm] capname [parm1..parm9]\n\
123        tput [-W] [-Tterm] -S\n", "U");
124 
125 STATREF void build_argv ANSI((int *ac, char ***av));
126 STATREF int do_tput ANSI((int _argc, char **_argv));
127 STATREF void init ANSI((void));
128 STATREF void reset ANSI((void));
129 STATREF int usage ANSI((void));
130 STATREF void err_msg ANSI((char *fmt, ...));	/* GENTEXT: err_msg */
131 STATREF void cat ANSI((char *_Fn));
132 
133 /*f
134  * mainline for tput
135  */
136 int
main(argc,argv)137 main(argc, argv)
138 int argc;
139 char **argv;
140 {
141 	int opt;
142 	int err_code;
143 	setlocale(LC_ALL, "");
144 	_cmdname = m_cmdname(*argv);
145 	if ((term_name = getenv("TERM")) == NULL) {
146 		term_name = dumb_term;
147 	} else {
148 		term_name = m_strdup(term_name);
149 	}
150 
151 	/* Default uses the terminfo database without modification. */
152 	use_env(0);
153 
154 	while ((opt = getopt(argc, argv, "ST:W")) != -1) {
155 		switch (opt) {
156 		case 'W':
157 			/* Environment/window size are consulted and may
158 			 * alter the database entries for lines and columns.
159 			 */
160 			use_env(1);
161 			break;
162 		case 'S':
163 			S_flag = 1;
164 			break;
165 
166 		case 'T':
167 			term_name = optarg;
168 			break;
169 
170 		default:
171 			return (usage());
172 		}
173 	}
174 
175 	argc -= optind;
176 	argv += optind;
177 
178 	if ((S_flag ^ (argc <= 0)) == 1)
179 		return (usage());
180 	(void) setupterm(term_name, fileno(stdout), &err_code);
181 	switch (err_code) {
182 	case 1:
183 		break;
184 	case 0:
185 		err_msg(m_textstr(202, "Unknown terminal \"%s\".\n", "E term"), term_name);
186 		return (BAD_TERMINAL);
187 	case -1:
188 		err_msg(m_textstr(203, "No terminfo database.\n", "E"));
189 		return (BAD_TERMINAL);
190 	}
191 	do {
192 		if (S_flag) {
193 			build_argv(&argc, &argv);
194 			if (argc <= 0)
195 				break;
196 		}
197 		err_code = do_tput(argc, argv);
198 	} while (S_flag && err_code == SUCCESS);
199 	return (err_code);
200 }
201 
202 /*f
203  *	Get an input line from stdin and then break it up into an argv array.
204  *	If EOF is reached then S_flag is set to 0. Only the first 10 strings
205  *	are of any interest. Any extra are ignored.
206  */
207 STATIC void
build_argv(ac,av)208 build_argv(ac, av)
209 int *ac;
210 char ***av;
211 {
212 	int i = 0;
213 	char *p;
214 	static char *v[10+1];
215 	static char buf[LINE_MAX];
216 	if ((*v = fgets(buf, LINE_MAX, stdin)) == NULL) {
217 		/* End of file or input error */
218 		S_flag = 0;
219 	} else {
220 		if ((p = strchr(buf, '\n')) != NULL)
221 			*p = '\0';
222 		for (p = buf; i < 10;) {
223 			while (isspace(*(unsigned char*) p))
224 				++p;
225 			if (*p == '\0')
226 				break;
227 			v[i++] = p;
228 			while (!isspace(*(unsigned char*) p) && *p != '\0')
229 				++p;
230 			if (*p == '\0')
231 				break;
232 			*p++ = '\0';
233 		}
234 	}
235 	v[i] = NULL;
236 	*ac = i;
237 	*av = v;
238 }
239 
240 /*f
241  *
242  */
243 STATIC int
do_tput(_argc,_argv)244 do_tput(_argc, _argv)
245 int _argc;
246 char **_argv;
247 {
248 	int i;
249 	long q[9];
250 	const char *p;
251 	char *end_num;
252 
253 	if (strcmp(*_argv, "init") == 0)
254 		init();
255 	else if (strcmp(*_argv, "reset") == 0)
256 		reset();
257 	else if (strcmp(*_argv, "longname") == 0)
258 		(void) printf("%s\n", longname());
259 	else if ((i = tigetflag(*_argv)) != -1)
260 		return (!i);
261 	else if ((i = tigetnum(*_argv)) != -2)
262 		(void) printf("%d\n", i);
263 	else if ((p = tigetstr(*_argv)) != (char*) -1) {
264 		if (p == NULL)
265 			return (NOT_DEFINED);
266 		for (i = 0; i < 9; ++i) {
267 			if (1 < _argc) {
268 				--_argc;
269 				q[i] = strtol(*++_argv, &end_num, 0);
270 				if (*end_num != '\0') {
271 					/* The parameter must be a string
272 					 * so we save the pointer instead.
273 					 */
274 					q[i] = (long) *_argv;
275 				}
276 			} else {
277 				q[i] = 0L;
278 			}
279 		}
280 		(void) putp(tparm(p, q[0], q[1], q[2], q[3],
281 			q[4], q[5], q[6], q[7], q[8]
282 		));
283 		fflush(stdout);
284 	} else {
285 		err_msg(m_textstr(1864, "Unknown terminfo capability \"%s\".\n", "E action"), *_argv);
286 		return (NOT_VALID);
287 	}
288 	return (SUCCESS);
289 }
290 
291 /*f
292  *
293  */
294 STATIC void
init()295 init()
296 {
297 	if (init_prog != NULL)
298 		(void) system(init_prog);
299 	if (init_1string != NULL)
300 		putp(init_1string);
301 	if (init_2string != NULL)
302 		putp(init_2string);
303 #if 0	/* currently not supported by our terminfo database */
304 	if (clear_margins != NULL)
305 		putp(clear_margins);
306 	if (set_left_margin != NULL)
307 		putp(set_left_margin);
308 	if (set_right_margin != NULL)
309 		putp(set_right_margin);
310 #endif
311 	/* TODO: setting of tabs using clear_all_tabs & set_tab. */
312 	if (init_file != NULL)
313 		cat(init_file);
314 	if (init_3string != NULL)
315 		putp(init_3string);
316 }
317 
318 /*f
319  *
320  */
321 STATIC void
reset()322 reset()
323 {
324 	if (reset_1string != NULL)
325 		putp(reset_1string);
326 	if (reset_2string != NULL)
327 		putp(reset_2string);
328 	if (reset_file != NULL)
329 		cat(reset_file);
330 	if (reset_3string != NULL)
331 		putp(reset_3string);
332 }
333 
334 /*f
335  * usage message for tput
336  */
337 STATIC int
usage()338 usage()
339 {
340 	(void) fprintf(stderr, m_strmsg(usage_msg));
341 	return (USAGE);
342 }
343 
344 /*f
345  * display error message
346  */
347 STATIC void
VARARG1(char *,fmt)348 err_msg VARARG1(char*, fmt)
349 {
350 	va_list ap;
351 	(void) fprintf(stderr, "%s: ", _cmdname);
352 	va_start(ap, fmt);
353 	(void) vfprintf(stderr, m_strmsg(fmt), ap);
354 	va_end(ap);
355 }
356 
357 /*
358  *  Print a file via putp().
359  */
360 STATIC void
cat(fn)361 cat(fn)
362 char *fn;
363 {
364 	FILE *fp;
365 	char buf[LINE_MAX+1];
366 	if ((fp = fopen(fn, "rb")) == NULL)
367 		return;
368 	while (fgets(buf, LINE_MAX, fp) != NULL)
369 		putp(buf);
370 	(void) fclose(fp);
371 }
372