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

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 *      Copyright (c) 1997, by Sun Microsystems, Inc.
 *      All rights reserved.
 */

#pragma ident	"@(#)print.c	1.9	97/08/28 SMI"	/* SVr4.0 1.11	*/

#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 restrict = 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)
{
	restrict = 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, "r")) == 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, "r")) == 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 && restrict &&
	    !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 && restrict &&
	    !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 (restrict && !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");
}
