root/usr/src/lib/libcurses/screen/print.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1988 AT&T */
/*        All Rights Reserved   */

/*
 * University Copyright- Copyright (c) 1982, 1986, 1988
 * The Regents of the University of California
 * All Rights Reserved
 *
 * University Acknowledgment- Portions of this document are derived from
 * software developed by the University of California, Berkeley, and its
 * contributors.
 */

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "curses_inc.h"
#include "print.h"
#include <signal.h>   /* use this file to determine if this is SVR4.0 system */

#ifdef SIGSTOP  /* SVR4.0 and beyond */
#define _ULIBTI "/usr/share/lib/terminfo"
#else
#define _ULIBTI "/usr/lib/terminfo"
#endif

char *progname;

/* global variables */
static enum printtypes printing = pr_none;
static int onecolumn = 0;               /* print a single column */
static int width = 60;                  /* width of multi-column printing */
static int restrictterm = 1;            /* restrict termcap names */

/* local variables */
static int printed = 0;
static size_t caplen = 0;

void
pr_init(enum printtypes type)
{
        printing = type;
}

void
pr_onecolumn(int onoff)
{
        onecolumn = onoff;
}

void
pr_width(int nwidth)
{
        if (nwidth > 0)
                width = nwidth;
}

void
pr_caprestrict(int onoff)
{
        restrictterm = onoff;
}

static char capbools[] =
        "ambsbwdadbeoeshchshzinkmmimsncnsosptulxbxnxoxsxt";
static int ncapbools = sizeof (capbools) / sizeof (capbools[0]);

static char capnums[] =
        "codBdCdFdNdTknlipbsgug";
static int ncapnums = sizeof (capnums) / sizeof (capnums[0]);

static char capstrs[] =
        "ALDCDLDOICLERISFSRUPaealasbcbtcdcechclcmcsctcvdcdldmdsedeifshoi1i2i"
            "cifimipisk0k1k2k3k4k5k6k7k8k9kbkdkekhklkokrkskul0l1l2l3l4l5l6l7l"
            "8l9ndnlpcr1r2r3rcrfrpscsesosrsttetitsucueupusvbvevivs";
static int ncapstrs = sizeof (capstrs) / sizeof (capstrs[0]);

static int
findcapname(char *capname, char *caplist, int listsize)
{
        int low = 0, mid, high = listsize - 2;
        while (low <= high) {
                mid = (low + high) / 4 * 2;
                if (capname[0] == caplist[mid]) {
                        if (capname[1] == caplist[mid + 1])
                                return (1);
                        else if (capname[1] < caplist[mid + 1])
                                high = mid - 2;
                        else
                                low = mid + 2;
                } else if (capname[0] < caplist[mid])
                        high = mid - 2;
                else
                        low = mid + 2;
        }
        return (0);
/*
 *      for (; *caplist; caplist += 2)
 *              if (caplist[0] == capname[0] && caplist[1] == capname[1])
 *                      return (1);
 *      return (0);
 */
}

/*
 *  Print out the first line of an entry.
 */
void
pr_heading(char *term, char *synonyms)
{
        int     do_print = 0;   /* Can we print the path of the file ? */
        char    buffer[512];    /* Holds search pathname */
        FILE    *work_fp;       /* Used to try and open the files */
        char    tail[4];        /* Used for terminfo pathname suffix */
        char    *terminfo;      /* The value of $TERMINFO */


        /*
         *      Try to obtain $TERMINFO
         */
        terminfo = getenv("TERMINFO");

        if (term == (char *)0)
                term = "";
        /*
         *      Build the suffix for this device
         */
        tail[0] = '/';
        tail[1] = *term;
        tail[2] = '/';
        tail[3] = '\0';

        /*
         *      If we have it - use it, otherwise use /usr/share/lib/terminfo
         *      as base directory
         */
        if (terminfo != NULL)
                (void) sprintf(buffer, "%s%s%s", terminfo, tail, term);
        else
                (void) sprintf(buffer, "%s%s%s", _ULIBTI, tail, term);

        /*
         *      Attempt to open the file.
         */
        if ((work_fp = fopen(buffer, "rF")) == NULL) {
                /*
                 * Open failed. If we were looking in /usr/share/lib/terminfo
                 *      we are done, otherwise look there next.
                 */
                if (strncmp(buffer, _ULIBTI, strlen(_ULIBTI)) == 0) {
                                /*
                                 * We are done. Not in /usr/share/lib/terminfo,
                                 *      and $TERMINFO is not set.
                                 */
                                (void) fprintf(stderr, "Error: Term \"%s\" not "
                                    "found in %s\n", term, _ULIBTI);
                } else {
                        /*
                         * Check /usr/share/lib/terminfo last. If this fails,
                         * all hope is lost as we know it is not in $TERMINFO.
                         */
                        (void) sprintf(buffer, "%s%s%s", _ULIBTI, tail, term);

                        if ((work_fp = fopen(buffer, "rF")) == NULL) {
                                /*
                                 *      All hope is lost
                                 */
                                (void) fprintf(stderr, "Error: Term \"%s\" not "
                                    "found in %s or %s\n", term, _ULIBTI,
                                    getenv("TERMINFO"));
                        } else do_print = 1;
                }
        } else do_print = 1;

        /*
         *      If we found it - print the comment(after closing the file)
         */
        if (do_print && *term) {
                (void) fclose(work_fp);
                (void) printf("#        Reconstructed via infocmp from file: "
                    "%s\n", buffer);
        }

        switch ((int)printing) {
                case (int)pr_terminfo:
                        (void) printf("%s,\n", synonyms);
                        break;
                case (int)pr_cap:
                        (void) printf("%s:\\\n", synonyms);
                        caplen = strlen(synonyms) + 1;
                        break;
                case (int)pr_longnames:
                        (void) printf("Terminal type %s\n", term);
                        (void) printf("  %s\n", synonyms);
                        break;
        }
}

void
pr_bheading(void)
{
        if (printing == pr_longnames)
                (void) printf("flags\n");
        printed = 0;
}

void
pr_boolean(char *infoname, char *capname, char *fullname, int value)
{
        int     vlen;
        size_t  nlen;

        if (printing == pr_cap && restrictterm &&
            !findcapname(capname, capbools, ncapbools))
                return;

        if (onecolumn) {
                if (value < 0)
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s@,\n", infoname);
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s@:\\\n", capname);
                                        caplen += 4 + strlen(capname);
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s@\n", fullname);
                        }
                else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s,\n", infoname);
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s:\\\n", capname);
                                        caplen += 3 + strlen(capname);
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s\n", fullname);
                        }
        } else {
                switch ((int)printing) {
                        case (int)pr_terminfo:  nlen = strlen(infoname);
                                                break;
                        case (int)pr_cap:       nlen = strlen(capname);
                                                break;
                        case (int)pr_longnames:
                                                nlen = strlen(fullname);
                                                break;
                }
                vlen = (value < 0) ? 1 : 0;
                if ((printed > 0) && (printed + nlen + vlen + 1 > width)) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                                (void) printf("\n");
                                                break;
                                case (int)pr_cap:
                                                (void) printf(":\\\n");
                                                caplen += 1;
                        }
                        printed = 0;
                }
                if (printed == 0) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t");
                                        printed = 8;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:");
                                        printed = 9;
                                        caplen += 2;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  ");
                                        printed = 2;
                        }
                } else {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf(" ");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":");
                                        caplen += 1;
                        }
                        printed++;
                }
                if (value < 0)
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s@,", infoname);
                                        printed += nlen + 2;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("%s@", capname);
                                        printed += nlen + 1;
                                        caplen += nlen + 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s@,", fullname);
                                        printed += nlen + 2;
                        }
                else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s,", infoname);
                                        printed += nlen + 1;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("%s", capname);
                                        printed += nlen;
                                        caplen += nlen;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s,", fullname);
                                        printed += nlen + 1;
                        }
        }
}

void
pr_bfooting(void)
{
        if (!onecolumn && (printed > 0))
                switch ((int)printing) {
                        case (int)pr_terminfo:
                        case (int)pr_longnames:
                                (void) printf("\n");
                                break;
                        case (int)pr_cap:
                                (void) printf(":\\\n");
                        caplen += 1;
            }
}

void
pr_nheading(void)
{
        if (printing == pr_longnames)
                (void) printf("\nnumbers\n");
        printed = 0;
}

/*
 *  Return the length of the number if it were printed out
 *  with %d. The number is guaranteed to be in the range
 *  0..maxshort.
 */
static int
digitlen(int value)
{
        return (value >= 10000 ? 5 :
            value >=  1000 ? 4 :
            value >=   100 ? 3 :
            value >=    10 ? 2 :
            value >=    0 ? 1 : 0);
}

void
pr_number(char *infoname, char *capname, char *fullname, int value)
{
        int     vlen;
        size_t  nlen;

        if (printing == pr_cap && restrictterm &&
            !findcapname(capname, capnums, ncapnums))
                return;

        if (onecolumn) {
                if (value < 0)
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s@,\n", infoname);
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s@:\\\n", capname);
                                        caplen += 4 + strlen(capname);
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s @\n", fullname);
                        }
                else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s#%d,\n", infoname,
                                            value);
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s#%d:\\\n",
                                            capname, value);
                                        caplen += 4 + strlen(capname) +
                                            digitlen(value);
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s = %d\n", fullname,
                                            value);
                        }
        } else {
                switch ((int)printing) {
                        case (int)pr_terminfo:
                                        nlen = strlen(infoname);
                                        break;
                        case (int)pr_cap:
                                        nlen = strlen(capname);
                                        break;
                        case (int)pr_longnames:
                                        nlen = strlen(fullname);
                                        break;
                }
                vlen = digitlen(value);
                if ((printed > 0) && (printed + nlen + vlen + 2 > width)) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf("\n");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":\\\n");
                                        caplen += 1;
                        }
                        printed = 0;
                }
                if (printed == 0) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t");
                                        printed = 8;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:");
                                        printed = 9;
                                        caplen += 2;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  ");
                                        printed = 2;
                        }
                } else {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf(" ");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":");
                                        caplen += 1;
                        }
                        printed++;
                }
                if (value < 0) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s@,", infoname);
                                        printed += nlen + 2;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("%s@", capname);
                                        printed += nlen + 1;
                                        caplen += nlen + 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s@,", fullname);
                                        printed += nlen + 2;
                        }
                } else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s#%d,", infoname,
                                            value);
                                        printed += nlen + vlen + 2;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("%s#%d", capname, value);
                                        printed += nlen + vlen + 1;
                                        caplen += nlen + vlen + 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s = %d,", fullname,
                                            value);
                                        printed += nlen + vlen + 4;
                        }
        }
}

void
pr_nfooting(void)
{
        if (!onecolumn && (printed > 0))
                switch ((int)printing) {
                        case (int)pr_terminfo:
                        case (int)pr_longnames:
                                (void) printf("\n");
                                break;
                        case (int)pr_cap:
                                (void) printf(":\\\n");
                                caplen += 1;
                }
}

void
pr_sheading(void)
{
        if (printing == pr_longnames)
                (void) printf("\nstrings\n");
        printed = 0;
}

void
pr_string(char *infoname, char *capname, char *fullname, char *value)
{
        char *evalue;
        int badcapvalue;
        size_t nlen, vlen;

        if (printing == pr_cap) {
                if (restrictterm && !findcapname(capname, capstrs, ncapstrs))
                        return;
                if (value)
                        value = infotocap(value, &badcapvalue);
        }

        if (onecolumn) {
                if (value == NULL)
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s@,\n", infoname);
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s@:\\\n", capname);
                                        caplen += 4 + strlen(capname);
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s@\n", fullname);
                        }
                else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t%s=", infoname);
                                        tpr(stdout, value);
                                        (void) printf(",\n");
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:%s%s=",
                                            badcapvalue ? "." : "", capname);
                                        caplen += 3 + strlen(capname) +
                                            (badcapvalue ? 1 : 0);
                                        caplen += cpr(stdout, value);
                                        (void) printf(":\\\n");
                                        caplen += 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  %s = '", fullname);
                                        tpr(stdout, value);
                                        (void) printf("'\n");
                        }
        } else {
                switch ((int)printing) {
                        case (int)pr_terminfo:
                                nlen = strlen(infoname);
                                break;
                        case (int)pr_cap:
                                nlen = strlen(capname);
                                if (badcapvalue)
                                        nlen++;
                                break;
                        case (int)pr_longnames:
                                nlen = strlen(fullname);
                }
                if (value == NULL)
                        vlen = 1;
                else
                        if (printing == pr_cap)
                                vlen = strlen(evalue = cexpand(value));
                        else
                                vlen = strlen(evalue = iexpand(value));
                if ((printed > 0) && (printed + nlen + vlen + 1 > width)) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf("\n");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":\\\n");
                                        caplen += 1;
                        }
                        printed = 0;
                }
                if (printed == 0) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("\t");
                                        printed = 8;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("\t:");
                                        printed = 9;
                                        caplen += 2;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("  ");
                                        printed = 2;
                        }
                } else {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf(" ");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":");
                                        caplen += 1;
                        }
                        printed++;
                }
                if (value == NULL) {
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s@,", infoname);
                                        printed += nlen + 2;
                                        break;
                                case (int)pr_cap:
                                        (void) printf("%s@", capname);
                                        printed += nlen + 1;
                                        caplen += nlen + 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s@,", fullname);
                                        printed += nlen + 2;
                        }
                } else
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                        (void) printf("%s=%s,", infoname,
                                            evalue);
                                        printed += nlen + vlen + 2;
                                        break;
                                case (int)pr_cap:
                                        if (badcapvalue) {
                                                (void) printf(".");
                                                caplen += 1;
                                        }
                                        (void) printf("%s=%s", capname,
                                            evalue);
                                        printed += nlen + vlen + 1;
                                        caplen += nlen + vlen + 1;
                                        break;
                                case (int)pr_longnames:
                                        (void) printf("%s = '%s',", fullname,
                                            evalue);
                                        printed += nlen + vlen + 6;
                        }
        }
}

void
pr_sfooting(void)
{
        if (onecolumn) {
                if (printing == pr_cap)
                        (void) printf("\n");
        } else {
                if (printed > 0)
                        switch ((int)printing) {
                                case (int)pr_terminfo:
                                case (int)pr_longnames:
                                        (void) printf("\n");
                                        break;
                                case (int)pr_cap:
                                        (void) printf(":\n");
                                        caplen += 1;
                        }
        }
        if (caplen >= 1024) {
                (void) fprintf(stderr, "%s: WARNING: termcap entry is too "
                    "long!\n", progname);
        }

        if (printing == pr_longnames)
                (void) printf("end of strings\n");
}