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