root/usr/src/lib/libxcurses/src/tput/tput.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1996, by Sun Microsystems, Inc.
 * All rights reserved.
 */

/*
 *      tput.c
 *
 *      Copyright 1990, 1994 by Mortice Kern Systems Inc.  All rights reserved.
 *
 *      PORTABILITY:
 *      SVID 3 - fully
 *      POSIX.2a UPE - needs clarification between SVID 3 exit statues.
 *                     In particular exit 1 and 4 for string capnames.
 *      not in XPG 3
 *
 *      SYNOPSIS:
 *      tput [-T<term>] capname [parm1..parm9]
 *      tput [-T<term>] -S
 *
 *      DESCRIPTION:
 *      tput lets you change your terminal's characteristics. The capname
 *      argument indicates how you want to change the characteristics.
 *      Some special capnames are:
 *
 *      clear           clear the screen
 *      init            initialize terminal in an implemenation-defined way
 *      reset           reset terminal in an implemenation-defined way
 *      longname        print the full name of the ternminal (SVID)
 *
 *      Other capnames are supported and may take from 0 to 9 parameters. A
 *      list of them can be found in the SVID 3, vol 3. (SVID)
 *
 *      tput does its work by outputting approriate character sequences to the
 *      standard output. These character sequences are terminal-specific. If
 *      you specify  -T <type>, tput assumes that your terminal has the
 *      specified type and will issue sequences appropriate to that terminal.
 *
 *      If you do not specify -T, tput looks for an environment variable
 *      named TERM. If TERM exists, its value is assumed to give the terminal
 *      type. If TERM does not exist, tput assumes a default terminal type.
 *
 *      The  -S  option allows more than one capability per invocation of tput.
 *      The capabilities must be passed to tput from the standard input instead
 *      of the comamnd line. Only one capname is allowed per line.
 *
 *      EXIT STATUS
 *      tput may return the following status values:
 *
 *      0       Either a boolean capname is set true or a string capname was
 *              successfully written to the terminal.
 *
 *      1       No error message is printed. Returned if a boolean capname is
 *              false or a string capname is not defined for the terminal.(SVID)
 *
 *      2       Usage error.
 *
 *      3       Unknown terminal <term> or no terminfo database.
 *
 *      4       Unknown terminfo capability <capname>.
 *
 *      >4      An error occured.
 *
 *
 *      NOTE 1: If the Caps file that describes the terminfo database changes
 *      then a new term.h will be required.  See CURSES/tic related tools.
 *
 *      NOTE 2: tput has knowledge about the TERMINAL structure.
 */
#ifdef M_RCSID
#ifndef lint
static char rcsID[] = "$Id: tput.c 1.28 1995/04/12 09:28:05 ross Exp $";
#endif
#endif

#include <mks.h>
#include <curses.h>
#include <term.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char *_cmdname;


/* Exit Status */
#define SUCCESS         0
#define NOT_DEFINED     1
#define USAGE           2
#define BAD_TERMINAL    3
#define NOT_VALID       4
#define ERROR           5

static int S_flag = 0;
static char *term_name;
static char dumb_term[] = "dumb";
static char usage_msg[] = m_textstr(4931, "\
Usage: tput [-W] [-Tterm] capname [parm1..parm9]\n\
       tput [-W] [-Tterm] -S\n", "U");

STATREF void build_argv ANSI((int *ac, char ***av));
STATREF int do_tput ANSI((int _argc, char **_argv));
STATREF void init ANSI((void));
STATREF void reset ANSI((void));
STATREF int usage ANSI((void));
STATREF void err_msg ANSI((char *fmt, ...));    /* GENTEXT: err_msg */
STATREF void cat ANSI((char *_Fn));

/*f
 * mainline for tput
 */
int
main(argc, argv)
int argc;
char **argv;
{
        int opt;
        int err_code;
        setlocale(LC_ALL, "");
        _cmdname = m_cmdname(*argv);
        if ((term_name = getenv("TERM")) == NULL) {
                term_name = dumb_term;
        } else {
                term_name = m_strdup(term_name);
        }

        /* Default uses the terminfo database without modification. */
        use_env(0);

        while ((opt = getopt(argc, argv, "ST:W")) != -1) {
                switch (opt) {
                case 'W':
                        /* Environment/window size are consulted and may
                         * alter the database entries for lines and columns.
                         */
                        use_env(1);
                        break;
                case 'S':
                        S_flag = 1;
                        break;

                case 'T':
                        term_name = optarg;
                        break;

                default:
                        return (usage());
                }
        }

        argc -= optind;
        argv += optind;

        if ((S_flag ^ (argc <= 0)) == 1)
                return (usage());
        (void) setupterm(term_name, fileno(stdout), &err_code);
        switch (err_code) {
        case 1:
                break;
        case 0:
                err_msg(m_textstr(202, "Unknown terminal \"%s\".\n", "E term"), term_name);
                return (BAD_TERMINAL);
        case -1:
                err_msg(m_textstr(203, "No terminfo database.\n", "E"));
                return (BAD_TERMINAL);
        }
        do {
                if (S_flag) {
                        build_argv(&argc, &argv);
                        if (argc <= 0)
                                break;
                }
                err_code = do_tput(argc, argv);
        } while (S_flag && err_code == SUCCESS);
        return (err_code);
}

/*f
 *      Get an input line from stdin and then break it up into an argv array.
 *      If EOF is reached then S_flag is set to 0. Only the first 10 strings
 *      are of any interest. Any extra are ignored.
 */
STATIC void
build_argv(ac, av)
int *ac;
char ***av;
{
        int i = 0;
        char *p;
        static char *v[10+1];
        static char buf[LINE_MAX];
        if ((*v = fgets(buf, LINE_MAX, stdin)) == NULL) {
                /* End of file or input error */
                S_flag = 0;
        } else {
                if ((p = strchr(buf, '\n')) != NULL)
                        *p = '\0';
                for (p = buf; i < 10;) {
                        while (isspace(*(unsigned char*) p))
                                ++p;
                        if (*p == '\0')
                                break;
                        v[i++] = p;
                        while (!isspace(*(unsigned char*) p) && *p != '\0')
                                ++p;
                        if (*p == '\0')
                                break;
                        *p++ = '\0';
                }
        }
        v[i] = NULL;
        *ac = i;
        *av = v;
}

/*f
 *
 */
STATIC int
do_tput(_argc, _argv)
int _argc;
char **_argv;
{
        int i;
        long q[9];
        const char *p;
        char *end_num;

        if (strcmp(*_argv, "init") == 0)
                init();
        else if (strcmp(*_argv, "reset") == 0)
                reset();
        else if (strcmp(*_argv, "longname") == 0)
                (void) printf("%s\n", longname());
        else if ((i = tigetflag(*_argv)) != -1)
                return (!i);
        else if ((i = tigetnum(*_argv)) != -2)
                (void) printf("%d\n", i);
        else if ((p = tigetstr(*_argv)) != (char*) -1) {
                if (p == NULL)
                        return (NOT_DEFINED);
                for (i = 0; i < 9; ++i) {
                        if (1 < _argc) {
                                --_argc;
                                q[i] = strtol(*++_argv, &end_num, 0);
                                if (*end_num != '\0') {
                                        /* The parameter must be a string
                                         * so we save the pointer instead.
                                         */
                                        q[i] = (long) *_argv;
                                }
                        } else {
                                q[i] = 0L;
                        }
                }
                (void) putp(tparm(p, q[0], q[1], q[2], q[3],
                        q[4], q[5], q[6], q[7], q[8]
                ));
                fflush(stdout);
        } else {
                err_msg(m_textstr(1864, "Unknown terminfo capability \"%s\".\n", "E action"), *_argv);
                return (NOT_VALID);
        }
        return (SUCCESS);
}

/*f
 *
 */
STATIC void
init()
{
        if (init_prog != NULL)
                (void) system(init_prog);
        if (init_1string != NULL)
                putp(init_1string);
        if (init_2string != NULL)
                putp(init_2string);
#if 0   /* currently not supported by our terminfo database */
        if (clear_margins != NULL)
                putp(clear_margins);
        if (set_left_margin != NULL)
                putp(set_left_margin);
        if (set_right_margin != NULL)
                putp(set_right_margin);
#endif
        /* TODO: setting of tabs using clear_all_tabs & set_tab. */
        if (init_file != NULL)
                cat(init_file);
        if (init_3string != NULL)
                putp(init_3string);
}

/*f
 *
 */
STATIC void
reset()
{
        if (reset_1string != NULL)
                putp(reset_1string);
        if (reset_2string != NULL)
                putp(reset_2string);
        if (reset_file != NULL)
                cat(reset_file);
        if (reset_3string != NULL)
                putp(reset_3string);
}

/*f
 * usage message for tput
 */
STATIC int
usage()
{
        (void) fprintf(stderr, m_strmsg(usage_msg));
        return (USAGE);
}

/*f
 * display error message
 */
STATIC void
err_msg VARARG1(char*, fmt)
{
        va_list ap;
        (void) fprintf(stderr, "%s: ", _cmdname);
        va_start(ap, fmt);
        (void) vfprintf(stderr, m_strmsg(fmt), ap);
        va_end(ap);
}

/*
 *  Print a file via putp().
 */
STATIC void
cat(fn)
char *fn;
{
        FILE *fp;
        char buf[LINE_MAX+1];
        if ((fp = fopen(fn, "rb")) == NULL)
                return;
        while (fgets(buf, LINE_MAX, fp) != NULL)
                putp(buf);
        (void) fclose(fp);
}