tput.c revision 66963
1195333Simp/****************************************************************************
2195333Simp * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc.                        *
3195333Simp *                                                                          *
4195333Simp * Permission is hereby granted, free of charge, to any person obtaining a  *
5195333Simp * copy of this software and associated documentation files (the            *
6195333Simp * "Software"), to deal in the Software without restriction, including      *
7195333Simp * without limitation the rights to use, copy, modify, merge, publish,      *
8195333Simp * distribute, distribute with modifications, sublicense, and/or sell       *
9195333Simp * copies of the Software, and to permit persons to whom the Software is    *
10195333Simp * furnished to do so, subject to the following conditions:                 *
11195333Simp *                                                                          *
12195333Simp * The above copyright notice and this permission notice shall be included  *
13195333Simp * in all copies or substantial portions of the Software.                   *
14195333Simp *                                                                          *
15195333Simp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16195333Simp * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17195333Simp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18195333Simp * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19195333Simp * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20195333Simp * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21195333Simp * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22195333Simp *                                                                          *
23195333Simp * Except as contained in this notice, the name(s) of the above copyright   *
24195333Simp * holders shall not be used in advertising or otherwise to promote the     *
25195333Simp * sale, use or other dealings in this Software without prior written       *
26195333Simp * authorization.                                                           *
27195333Simp ****************************************************************************/
28195333Simp
29195333Simp/****************************************************************************
30195333Simp *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31195333Simp *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32195333Simp ****************************************************************************/
33195333Simp
34195333Simp/*
35195333Simp * tput.c -- shellscript access to terminal capabilities
36195333Simp *
37195333Simp * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
38195333Simp * Ross Ridge's mytinfo package.
39195333Simp */
40195333Simp
41195333Simp#include <progs.priv.h>
42195333Simp
43195333Simp#if !PURE_TERMINFO
44195333Simp#include <termsort.c>
45195333Simp#endif
46195333Simp#include <transform.h>
47195333Simp
48195333SimpMODULE_ID("$Id: tput.c,v 1.24 2000/10/05 00:05:04 tom Exp $")
49195333Simp
50195333Simp#define PUTS(s)		fputs(s, stdout)
51195333Simp#define PUTCHAR(c)	putchar(c)
52195333Simp#define FLUSH		fflush(stdout)
53195333Simp
54195333Simptypedef enum {
55195333Simp    Numbers = 0
56195333Simp    ,Num_Str
57195333Simp    ,Num_Str_Str
58195333Simp} TParams;
59195333Simp
60195333Simpstatic char *prg_name;
61195333Simpstatic bool is_init = FALSE;
62195333Simpstatic bool is_reset = FALSE;
63195333Simp
64195333Simpstatic void
65195333Simpquit(int status, const char *fmt,...)
66195333Simp{
67195333Simp    va_list argp;
68195333Simp
69195333Simp    va_start(argp, fmt);
70195333Simp    vfprintf(stderr, fmt, argp);
71195333Simp    fprintf(stderr, "\n");
72195333Simp    va_end(argp);
73195333Simp    exit(status);
74195333Simp}
75195333Simp
76195333Simpstatic void
77195333Simpusage(void)
78195333Simp{
79195333Simp    fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name);
80195333Simp    exit(EXIT_FAILURE);
81195333Simp}
82195333Simp
83195333Simpstatic void
84195333Simpcheck_aliases(const char *name)
85195333Simp{
86195333Simp    is_init = (strcmp(name, PROG_INIT) == 0);
87195333Simp    is_reset = (strcmp(name, PROG_RESET) == 0);
88195333Simp}
89195333Simp
90195333Simp/*
91195333Simp * Lookup the type of call we should make to tparm().  This ignores the actual
92195333Simp * terminfo capability (bad, because it is not extensible), but makes this
93195333Simp * code portable to platforms where sizeof(int) != sizeof(char *).
94195333Simp *
95195333Simp * FIXME: If we want extensibility, analyze the capability string as we do
96203000Sneel * in tparm() to decide how to parse the varargs list.
97203000Sneel */
98198669Srrsstatic TParams
99198669Srrstparm_type(char *name)
100198669Srrs{
101198669Srrs#define TD(code, longname, ti, tc) {code,longname},{code,ti},{code,tc}
102198669Srrs    TParams result = Numbers;
103198669Srrs    /* *INDENT-OFF* */
104195333Simp    static const struct {
105195333Simp	TParams code;
106195333Simp	const char *name;
107195333Simp    } table[] = {
108195333Simp	TD(Num_Str,	"pkey_key",	"pfkey",	"pk"),
109195333Simp	TD(Num_Str,	"pkey_local",	"pfloc",	"pl"),
110195333Simp	TD(Num_Str,	"pkey_xmit",	"pfx",		"px"),
111195333Simp	TD(Num_Str,	"plab_norm",	"pln",		"pn"),
112195333Simp	TD(Num_Str_Str, "pkey_plab",	"pfxl",		"xl"),
113195333Simp    };
114195333Simp    /* *INDENT-ON* */
115195333Simp
116195333Simp    unsigned n;
117195333Simp    for (n = 0; n < SIZEOF(table); n++) {
118195333Simp	if (!strcmp(name, table[n].name)) {
119195333Simp	    result = table[n].code;
120195333Simp	    break;
121195333Simp	}
122195333Simp    }
123195333Simp    return result;
124195333Simp}
125195333Simp
126195333Simpstatic int
127195333Simptput(int argc, char *argv[])
128195333Simp{
129195333Simp    NCURSES_CONST char *name;
130195333Simp    char *s;
131195333Simp    int i, j, c;
132195333Simp    int status;
133195333Simp    FILE *f;
134195333Simp
135195333Simp    check_aliases(name = argv[0]);
136195333Simp    if (is_reset || is_init) {
137195333Simp	if (init_prog != 0) {
138195333Simp	    system(init_prog);
139195333Simp	}
140195333Simp	FLUSH;
141195333Simp
142195333Simp	if (is_reset && reset_1string != 0) {
143195333Simp	    PUTS(reset_1string);
144195333Simp	} else if (init_1string != 0) {
145195333Simp	    PUTS(init_1string);
146195333Simp	}
147195333Simp	FLUSH;
148195333Simp
149195333Simp	if (is_reset && reset_2string != 0) {
150195333Simp	    PUTS(reset_2string);
151195333Simp	} else if (init_2string != 0) {
152195333Simp	    PUTS(init_2string);
153195333Simp	}
154195333Simp	FLUSH;
155195333Simp
156195333Simp	if (set_lr_margin != 0) {
157195333Simp	    PUTS(tparm(set_lr_margin, 0, columns - 1));
158195333Simp	} else if (set_left_margin_parm != 0
159195333Simp		   && set_right_margin_parm != 0) {
160195333Simp	    PUTS(tparm(set_left_margin_parm, 0));
161195333Simp	    PUTS(tparm(set_right_margin_parm, columns - 1));
162195333Simp	} else if (clear_margins != 0
163195333Simp		   && set_left_margin != 0
164195333Simp		   && set_right_margin != 0) {
165195333Simp	    PUTS(clear_margins);
166195333Simp	    if (carriage_return != 0) {
167195333Simp		PUTS(carriage_return);
168195333Simp	    } else {
169195333Simp		PUTCHAR('\r');
170195333Simp	    }
171195333Simp	    PUTS(set_left_margin);
172195333Simp	    if (parm_right_cursor) {
173195333Simp		PUTS(tparm(parm_right_cursor, columns - 1));
174202954Sgonzo	    } else {
175195333Simp		for (i = 0; i < columns - 1; i++) {
176195333Simp		    PUTCHAR(' ');
177195333Simp		}
178195333Simp	    }
179195333Simp	    PUTS(set_right_margin);
180195333Simp	    if (carriage_return != 0) {
181195333Simp		PUTS(carriage_return);
182195333Simp	    } else {
183195333Simp		PUTCHAR('\r');
184195333Simp	    }
185195333Simp	}
186195333Simp	FLUSH;
187195333Simp
188203000Sneel	if (init_tabs != 8) {
189203000Sneel	    if (clear_all_tabs != 0 && set_tab != 0) {
190203000Sneel		for (i = 0; i < columns - 1; i += 8) {
191203000Sneel		    if (parm_right_cursor) {
192203000Sneel			PUTS(tparm(parm_right_cursor, 8));
193203000Sneel		    } else {
194203000Sneel			for (j = 0; j < 8; j++)
195203000Sneel			    PUTCHAR(' ');
196203000Sneel		    }
197203000Sneel		    PUTS(set_tab);
198203000Sneel		}
199203000Sneel		FLUSH;
200203000Sneel	    }
201203000Sneel	}
202203000Sneel
203203000Sneel	if (is_reset && reset_file != 0) {
204203000Sneel	    f = fopen(reset_file, "r");
205203000Sneel	    if (f == 0) {
206203000Sneel		quit(errno, "Can't open reset_file: '%s'", reset_file);
207203000Sneel	    }
208203000Sneel	    while ((c = fgetc(f)) != EOF) {
209203000Sneel		PUTCHAR(c);
210195333Simp	    }
211195333Simp	    fclose(f);
212195333Simp	} else if (init_file != 0) {
213195333Simp	    f = fopen(init_file, "r");
214195333Simp	    if (f == 0) {
215195333Simp		quit(errno, "Can't open init_file: '%s'", init_file);
216195333Simp	    }
217195333Simp	    while ((c = fgetc(f)) != EOF) {
218195333Simp		PUTCHAR(c);
219195333Simp	    }
220195333Simp	    fclose(f);
221195333Simp	}
222195333Simp	FLUSH;
223195333Simp
224195333Simp	if (is_reset && reset_3string != 0) {
225195333Simp	    PUTS(reset_3string);
226195333Simp	} else if (init_2string != 0) {
227195333Simp	    PUTS(init_2string);
228195333Simp	}
229195333Simp	FLUSH;
230195333Simp	return 0;
231195333Simp    }
232195333Simp
233195333Simp    if (strcmp(name, "longname") == 0) {
234195333Simp	PUTS(longname());
235195333Simp	return 0;
236195333Simp    }
237195333Simp#if !PURE_TERMINFO
238195333Simp    {
239195333Simp	const struct name_table_entry *np;
240195333Simp
241195333Simp	if ((np = _nc_find_entry(name, _nc_get_hash_table(1))) != 0)
242195333Simp	    switch (np->nte_type) {
243195333Simp	    case BOOLEAN:
244195333Simp		if (bool_from_termcap[np->nte_index])
245195333Simp		    name = boolnames[np->nte_index];
246195333Simp		break;
247195333Simp
248195333Simp	    case NUMBER:
249195333Simp		if (num_from_termcap[np->nte_index])
250195333Simp		    name = numnames[np->nte_index];
251195333Simp		break;
252195333Simp
253195333Simp	    case STRING:
254195333Simp		if (str_from_termcap[np->nte_index])
255195333Simp		    name = strnames[np->nte_index];
256195333Simp		break;
257202864Sneel	    }
258202864Sneel    }
259202864Sneel#endif
260202864Sneel
261202864Sneel    if ((status = tigetflag(name)) != -1) {
262202864Sneel	return (status != 0);
263202864Sneel    } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
264202864Sneel	(void) printf("%d\n", status);
265202864Sneel	return (0);
266202864Sneel    } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
267202864Sneel	quit(4, "%s: unknown terminfo capability '%s'", prg_name, name);
268202864Sneel    } else if (s != ABSENT_STRING) {
269195333Simp	if (argc > 1) {
270201631Sneel	    int k;
271201631Sneel	    int numbers[10];
272195333Simp	    char *strings[10];
273202864Sneel
274202864Sneel	    /* Nasty hack time. The tparm function needs to see numeric
275202864Sneel	     * parameters as numbers, not as pointers to their string
276202864Sneel	     * representations
277202864Sneel	     */
278195333Simp
279195333Simp	    for (k = 1; k < argc; k++) {
280202954Sgonzo		char *tmp = 0;
281195333Simp		strings[k] = argv[k];
282201845Simp		numbers[k] = strtol(argv[k], &tmp, 0);
283201881Simp		if (tmp == 0 || *tmp != 0)
284201845Simp		    numbers[k] = 0;
285195333Simp	    }
286195333Simp	    for (k = argc; k <= 9; k++) {
287195333Simp		numbers[k] = 0;
288195333Simp		strings[k] = 0;
289201631Sneel	    }
290201631Sneel
291201631Sneel	    switch (tparm_type(name)) {
292201631Sneel	    case Num_Str:
293201631Sneel		s = tparm(s, numbers[1], strings[2]);
294195333Simp		break;
295201631Sneel	    case Num_Str_Str:
296201631Sneel		s = tparm(s, numbers[1], strings[2], strings[3]);
297195333Simp		break;
298195333Simp	    default:
299195333Simp		s = tparm(s,
300195333Simp			  numbers[1], numbers[2], numbers[3],
301195333Simp			  numbers[4], numbers[5], numbers[6],
302195333Simp			  numbers[7], numbers[8], numbers[9]);
303195333Simp		break;
304	    }
305	}
306
307	/* use putp() in order to perform padding */
308	putp(s);
309	return (0);
310    }
311    return (0);
312}
313
314int
315main(int argc, char **argv)
316{
317    char *term;
318    int errret;
319    bool cmdline = TRUE;
320    int c;
321    char buf[BUFSIZ];
322    int errors = 0;
323
324    check_aliases(prg_name = _nc_basename(argv[0]));
325
326    term = getenv("TERM");
327
328    while ((c = getopt(argc, argv, "ST:V")) != EOF) {
329	switch (c) {
330	case 'S':
331	    cmdline = FALSE;
332	    break;
333	case 'T':
334	    use_env(FALSE);
335	    term = optarg;
336	    break;
337	case 'V':
338	    puts(curses_version());
339	    return EXIT_SUCCESS;
340	default:
341	    usage();
342	    /* NOTREACHED */
343	}
344    }
345
346    /*
347     * Modify the argument list to omit the options we processed.
348     */
349    if (is_reset || is_init) {
350	if (optind-- < argc) {
351	    argc -= optind;
352	    argv += optind;
353	}
354	argv[0] = prg_name;
355    } else {
356	argc -= optind;
357	argv += optind;
358    }
359
360    if (term == 0 || *term == '\0')
361	quit(2, "No value for $TERM and no -T specified");
362
363    if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0)
364	quit(3, "unknown terminal \"%s\"", term);
365
366    if (cmdline) {
367	if ((argc <= 0) && !is_reset && !is_init)
368	    usage();
369	return tput(argc, argv);
370    }
371
372    while (fgets(buf, sizeof(buf), stdin) != 0) {
373	char *argvec[16];	/* command, 9 parms, null, & slop */
374	int argnum = 0;
375	char *cp;
376
377	/* crack the argument list into a dope vector */
378	for (cp = buf; *cp; cp++) {
379	    if (isspace(*cp))
380		*cp = '\0';
381	    else if (cp == buf || cp[-1] == 0)
382		argvec[argnum++] = cp;
383	}
384	argvec[argnum] = 0;
385
386	if (tput(argnum, argvec) != 0)
387	    errors++;
388    }
389
390    return errors > 0;
391}
392