tput.c revision 262629
150276Speter/****************************************************************************
2262629Sdelphij * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
3250276Speter ****************************************************************************/
3350276Speter
3450276Speter/*
3550276Speter * tput.c -- shellscript access to terminal capabilities
3650276Speter *
3750276Speter * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
3850276Speter * Ross Ridge's mytinfo package.
3950276Speter */
4050276Speter
41174993Srafan#define USE_LIBTINFO
4250276Speter#include <progs.priv.h>
4366963Speter
4466963Speter#if !PURE_TERMINFO
45184989Srafan#include <dump_entry.h>
4650276Speter#include <termsort.c>
4750276Speter#endif
4866963Speter#include <transform.h>
4950276Speter
50262629SdelphijMODULE_ID("$Id: tput.c,v 1.46 2010/01/09 16:53:24 tom Exp $")
5150276Speter
5250276Speter#define PUTS(s)		fputs(s, stdout)
5350276Speter#define PUTCHAR(c)	putchar(c)
5450276Speter#define FLUSH		fflush(stdout)
5550276Speter
5666963Spetertypedef enum {
5766963Speter    Numbers = 0
5866963Speter    ,Num_Str
5966963Speter    ,Num_Str_Str
6066963Speter} TParams;
6166963Speter
6250276Speterstatic char *prg_name;
6366963Speterstatic bool is_init = FALSE;
6466963Speterstatic bool is_reset = FALSE;
6550276Speter
6662449Speterstatic void
6762449Speterquit(int status, const char *fmt,...)
6850276Speter{
6962449Speter    va_list argp;
7050276Speter
7162449Speter    va_start(argp, fmt);
72166124Srafan    fprintf(stderr, "%s: ", prg_name);
7362449Speter    vfprintf(stderr, fmt, argp);
7462449Speter    fprintf(stderr, "\n");
7562449Speter    va_end(argp);
76166124Srafan    ExitProgram(status);
7750276Speter}
7850276Speter
7962449Speterstatic void
8062449Speterusage(void)
8150276Speter{
8266963Speter    fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name);
83166124Srafan    ExitProgram(EXIT_FAILURE);
8450276Speter}
8550276Speter
8666963Speterstatic void
8766963Spetercheck_aliases(const char *name)
8866963Speter{
89262629Sdelphij    is_init = same_program(name, PROG_INIT);
90262629Sdelphij    is_reset = same_program(name, PROG_RESET);
9166963Speter}
9266963Speter
9366963Speter/*
9466963Speter * Lookup the type of call we should make to tparm().  This ignores the actual
9566963Speter * terminfo capability (bad, because it is not extensible), but makes this
9666963Speter * code portable to platforms where sizeof(int) != sizeof(char *).
9766963Speter *
9866963Speter * FIXME: If we want extensibility, analyze the capability string as we do
9966963Speter * in tparm() to decide how to parse the varargs list.
10066963Speter */
10166963Speterstatic TParams
10276726Spetertparm_type(const char *name)
10366963Speter{
10466963Speter#define TD(code, longname, ti, tc) {code,longname},{code,ti},{code,tc}
10566963Speter    TParams result = Numbers;
10666963Speter    /* *INDENT-OFF* */
10766963Speter    static const struct {
10866963Speter	TParams code;
10966963Speter	const char *name;
11066963Speter    } table[] = {
11166963Speter	TD(Num_Str,	"pkey_key",	"pfkey",	"pk"),
11266963Speter	TD(Num_Str,	"pkey_local",	"pfloc",	"pl"),
11366963Speter	TD(Num_Str,	"pkey_xmit",	"pfx",		"px"),
11466963Speter	TD(Num_Str,	"plab_norm",	"pln",		"pn"),
11566963Speter	TD(Num_Str_Str, "pkey_plab",	"pfxl",		"xl"),
11666963Speter    };
11766963Speter    /* *INDENT-ON* */
11866963Speter
11966963Speter    unsigned n;
12066963Speter    for (n = 0; n < SIZEOF(table); n++) {
12166963Speter	if (!strcmp(name, table[n].name)) {
12266963Speter	    result = table[n].code;
12366963Speter	    break;
12466963Speter	}
12566963Speter    }
12666963Speter    return result;
12766963Speter}
12866963Speter
12962449Speterstatic int
130166124Srafanexit_code(int token, int value)
131166124Srafan{
132166124Srafan    int result = 99;
133166124Srafan
134166124Srafan    switch (token) {
135166124Srafan    case BOOLEAN:
136166124Srafan	result = !value;	/* TRUE=0, FALSE=1 */
137166124Srafan	break;
138166124Srafan    case NUMBER:
139166124Srafan	result = 0;		/* always zero */
140166124Srafan	break;
141166124Srafan    case STRING:
142166124Srafan	result = value;		/* 0=normal, 1=missing */
143166124Srafan	break;
144166124Srafan    }
145166124Srafan    return result;
146166124Srafan}
147166124Srafan
148166124Srafanstatic int
14962449Spetertput(int argc, char *argv[])
15050276Speter{
15162449Speter    NCURSES_CONST char *name;
15262449Speter    char *s;
15362449Speter    int i, j, c;
15466963Speter    int status;
15562449Speter    FILE *f;
156262629Sdelphij#if !PURE_TERMINFO
157262629Sdelphij    bool termcap = FALSE;
158262629Sdelphij#endif
15950276Speter
16097049Speter    if ((name = argv[0]) == 0)
16197049Speter	name = "";
16297049Speter    check_aliases(name);
16366963Speter    if (is_reset || is_init) {
16462449Speter	if (init_prog != 0) {
16562449Speter	    system(init_prog);
16650276Speter	}
16762449Speter	FLUSH;
16850276Speter
16966963Speter	if (is_reset && reset_1string != 0) {
17062449Speter	    PUTS(reset_1string);
17162449Speter	} else if (init_1string != 0) {
17262449Speter	    PUTS(init_1string);
17362449Speter	}
17462449Speter	FLUSH;
17550276Speter
17666963Speter	if (is_reset && reset_2string != 0) {
17762449Speter	    PUTS(reset_2string);
17862449Speter	} else if (init_2string != 0) {
17962449Speter	    PUTS(init_2string);
18062449Speter	}
18162449Speter	FLUSH;
18250276Speter
18397049Speter#ifdef set_lr_margin
18462449Speter	if (set_lr_margin != 0) {
185166124Srafan	    PUTS(TPARM_2(set_lr_margin, 0, columns - 1));
18697049Speter	} else
18797049Speter#endif
18897049Speter#ifdef set_left_margin_parm
18997049Speter	    if (set_left_margin_parm != 0
19097049Speter		&& set_right_margin_parm != 0) {
191166124Srafan	    PUTS(TPARM_1(set_left_margin_parm, 0));
192166124Srafan	    PUTS(TPARM_1(set_right_margin_parm, columns - 1));
19397049Speter	} else
19497049Speter#endif
19597049Speter	    if (clear_margins != 0
19697049Speter		&& set_left_margin != 0
19797049Speter		&& set_right_margin != 0) {
19862449Speter	    PUTS(clear_margins);
19962449Speter	    if (carriage_return != 0) {
20062449Speter		PUTS(carriage_return);
20162449Speter	    } else {
20262449Speter		PUTCHAR('\r');
20362449Speter	    }
20462449Speter	    PUTS(set_left_margin);
20562449Speter	    if (parm_right_cursor) {
206166124Srafan		PUTS(TPARM_1(parm_right_cursor, columns - 1));
20762449Speter	    } else {
20862449Speter		for (i = 0; i < columns - 1; i++) {
20962449Speter		    PUTCHAR(' ');
21050276Speter		}
21162449Speter	    }
21262449Speter	    PUTS(set_right_margin);
21362449Speter	    if (carriage_return != 0) {
21462449Speter		PUTS(carriage_return);
21562449Speter	    } else {
21662449Speter		PUTCHAR('\r');
21762449Speter	    }
21862449Speter	}
21962449Speter	FLUSH;
22050276Speter
22162449Speter	if (init_tabs != 8) {
22262449Speter	    if (clear_all_tabs != 0 && set_tab != 0) {
22362449Speter		for (i = 0; i < columns - 1; i += 8) {
22462449Speter		    if (parm_right_cursor) {
225166124Srafan			PUTS(TPARM_1(parm_right_cursor, 8));
22662449Speter		    } else {
22762449Speter			for (j = 0; j < 8; j++)
22862449Speter			    PUTCHAR(' ');
22962449Speter		    }
23062449Speter		    PUTS(set_tab);
23150276Speter		}
23250276Speter		FLUSH;
23362449Speter	    }
23462449Speter	}
23550276Speter
23666963Speter	if (is_reset && reset_file != 0) {
23762449Speter	    f = fopen(reset_file, "r");
23862449Speter	    if (f == 0) {
239166124Srafan		quit(4 + errno, "Can't open reset_file: '%s'", reset_file);
24062449Speter	    }
24162449Speter	    while ((c = fgetc(f)) != EOF) {
24262449Speter		PUTCHAR(c);
24362449Speter	    }
24462449Speter	    fclose(f);
24562449Speter	} else if (init_file != 0) {
24662449Speter	    f = fopen(init_file, "r");
24762449Speter	    if (f == 0) {
248166124Srafan		quit(4 + errno, "Can't open init_file: '%s'", init_file);
24962449Speter	    }
25062449Speter	    while ((c = fgetc(f)) != EOF) {
25162449Speter		PUTCHAR(c);
25262449Speter	    }
25362449Speter	    fclose(f);
25450276Speter	}
25562449Speter	FLUSH;
25650276Speter
25766963Speter	if (is_reset && reset_3string != 0) {
25862449Speter	    PUTS(reset_3string);
259166124Srafan	} else if (init_3string != 0) {
260166124Srafan	    PUTS(init_3string);
26150276Speter	}
26262449Speter	FLUSH;
26362449Speter	return 0;
26462449Speter    }
26550276Speter
26662449Speter    if (strcmp(name, "longname") == 0) {
26762449Speter	PUTS(longname());
26862449Speter	return 0;
26962449Speter    }
27066963Speter#if !PURE_TERMINFO
271262629Sdelphij  retry:
27250276Speter#endif
27362449Speter    if ((status = tigetflag(name)) != -1) {
274166124Srafan	return exit_code(BOOLEAN, status);
27562449Speter    } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
27662449Speter	(void) printf("%d\n", status);
277166124Srafan	return exit_code(NUMBER, 0);
27862449Speter    } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
279262629Sdelphij#if !PURE_TERMINFO
280262629Sdelphij	if (!termcap) {
281262629Sdelphij	    const struct name_table_entry *np;
282262629Sdelphij
283262629Sdelphij	    termcap = TRUE;
284262629Sdelphij	    if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
285262629Sdelphij		switch (np->nte_type) {
286262629Sdelphij		case BOOLEAN:
287262629Sdelphij		    if (bool_from_termcap[np->nte_index])
288262629Sdelphij			name = boolnames[np->nte_index];
289262629Sdelphij		    break;
290262629Sdelphij
291262629Sdelphij		case NUMBER:
292262629Sdelphij		    if (num_from_termcap[np->nte_index])
293262629Sdelphij			name = numnames[np->nte_index];
294262629Sdelphij		    break;
295262629Sdelphij
296262629Sdelphij		case STRING:
297262629Sdelphij		    if (str_from_termcap[np->nte_index])
298262629Sdelphij			name = strnames[np->nte_index];
299262629Sdelphij		    break;
300262629Sdelphij		}
301262629Sdelphij		goto retry;
302262629Sdelphij	    }
303262629Sdelphij	}
304262629Sdelphij#endif
305166124Srafan	quit(4, "unknown terminfo capability '%s'", name);
30666963Speter    } else if (s != ABSENT_STRING) {
30762449Speter	if (argc > 1) {
30862449Speter	    int k;
309166124Srafan	    int popcount;
310166124Srafan	    long numbers[1 + NUM_PARM];
311166124Srafan	    char *strings[1 + NUM_PARM];
312166124Srafan	    char *p_is_s[NUM_PARM];
31350276Speter
31462449Speter	    /* Nasty hack time. The tparm function needs to see numeric
31562449Speter	     * parameters as numbers, not as pointers to their string
31662449Speter	     * representations
31762449Speter	     */
31850276Speter
31962449Speter	    for (k = 1; k < argc; k++) {
32066963Speter		char *tmp = 0;
32166963Speter		strings[k] = argv[k];
32266963Speter		numbers[k] = strtol(argv[k], &tmp, 0);
32366963Speter		if (tmp == 0 || *tmp != 0)
32466963Speter		    numbers[k] = 0;
32562449Speter	    }
326166124Srafan	    for (k = argc; k <= NUM_PARM; k++) {
32766963Speter		numbers[k] = 0;
32866963Speter		strings[k] = 0;
32966963Speter	    }
33050276Speter
33166963Speter	    switch (tparm_type(name)) {
33266963Speter	    case Num_Str:
333166124Srafan		s = TPARM_2(s, numbers[1], strings[2]);
33466963Speter		break;
33566963Speter	    case Num_Str_Str:
336166124Srafan		s = TPARM_3(s, numbers[1], strings[2], strings[3]);
33766963Speter		break;
338174993Srafan	    case Numbers:
33966963Speter	    default:
340166124Srafan		(void) _nc_tparm_analyze(s, p_is_s, &popcount);
341166124Srafan#define myParam(n) (p_is_s[n - 1] != 0 ? ((long) strings[n]) : numbers[n])
342166124Srafan		s = TPARM_9(s,
343166124Srafan			    myParam(1),
344166124Srafan			    myParam(2),
345166124Srafan			    myParam(3),
346166124Srafan			    myParam(4),
347166124Srafan			    myParam(5),
348166124Srafan			    myParam(6),
349166124Srafan			    myParam(7),
350166124Srafan			    myParam(8),
351166124Srafan			    myParam(9));
35266963Speter		break;
35366963Speter	    }
35450276Speter	}
35562449Speter
35662449Speter	/* use putp() in order to perform padding */
35762449Speter	putp(s);
358166124Srafan	return exit_code(STRING, 0);
35962449Speter    }
360166124Srafan    return exit_code(STRING, 1);
36150276Speter}
36250276Speter
36362449Speterint
36462449Spetermain(int argc, char **argv)
36550276Speter{
36666963Speter    char *term;
36766963Speter    int errret;
36866963Speter    bool cmdline = TRUE;
36962449Speter    int c;
37062449Speter    char buf[BUFSIZ];
371166124Srafan    int result = 0;
37250276Speter
37397049Speter    check_aliases(prg_name = _nc_rootname(argv[0]));
37450276Speter
37562449Speter    term = getenv("TERM");
37650276Speter
377174993Srafan    while ((c = getopt(argc, argv, "ST:V")) != -1) {
37862449Speter	switch (c) {
37962449Speter	case 'S':
38066963Speter	    cmdline = FALSE;
38162449Speter	    break;
38262449Speter	case 'T':
38362449Speter	    use_env(FALSE);
38462449Speter	    term = optarg;
38562449Speter	    break;
38666963Speter	case 'V':
38766963Speter	    puts(curses_version());
388166124Srafan	    ExitProgram(EXIT_SUCCESS);
38962449Speter	default:
39062449Speter	    usage();
39162449Speter	    /* NOTREACHED */
39250276Speter	}
39366963Speter    }
39450276Speter
39566963Speter    /*
39666963Speter     * Modify the argument list to omit the options we processed.
39766963Speter     */
39866963Speter    if (is_reset || is_init) {
39966963Speter	if (optind-- < argc) {
40066963Speter	    argc -= optind;
40166963Speter	    argv += optind;
40266963Speter	}
40366963Speter	argv[0] = prg_name;
40466963Speter    } else {
40566963Speter	argc -= optind;
40666963Speter	argv += optind;
40762449Speter    }
40850276Speter
40962449Speter    if (term == 0 || *term == '\0')
41062449Speter	quit(2, "No value for $TERM and no -T specified");
41150276Speter
41262449Speter    if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0)
41362449Speter	quit(3, "unknown terminal \"%s\"", term);
41450276Speter
41566963Speter    if (cmdline) {
41666963Speter	if ((argc <= 0) && !is_reset && !is_init)
41766963Speter	    usage();
418166124Srafan	ExitProgram(tput(argc, argv));
41966963Speter    }
42050276Speter
42162449Speter    while (fgets(buf, sizeof(buf), stdin) != 0) {
42262449Speter	char *argvec[16];	/* command, 9 parms, null, & slop */
42362449Speter	int argnum = 0;
42462449Speter	char *cp;
42550276Speter
42662449Speter	/* crack the argument list into a dope vector */
42762449Speter	for (cp = buf; *cp; cp++) {
42897049Speter	    if (isspace(UChar(*cp))) {
42962449Speter		*cp = '\0';
43097049Speter	    } else if (cp == buf || cp[-1] == 0) {
43162449Speter		argvec[argnum++] = cp;
43297049Speter		if (argnum >= (int) SIZEOF(argvec) - 1)
43397049Speter		    break;
43497049Speter	    }
43550276Speter	}
43662449Speter	argvec[argnum] = 0;
43750276Speter
43897049Speter	if (argnum != 0
439166124Srafan	    && tput(argnum, argvec) != 0) {
440166124Srafan	    if (result == 0)
441166124Srafan		result = 4;	/* will return value >4 */
442166124Srafan	    ++result;
443166124Srafan	}
44462449Speter    }
44562449Speter
446166124Srafan    ExitProgram(result);
44750276Speter}
448