/*+++*
 *  title:	untic.c
 *  abstract:	uncompile terminfo entry
 *  author:	T.R.Hageman, Groningen, The Netherlands.
 *  created:	february 1990
 *  modified:	
 *  description:
 *	Uncompile a terminfo entry.
 *---*/

char	*version = "v0.2   5-Jul-93  (c) Tom Hageman";

#include <stdio.h>
#include <curses.h>
#include <term.h>
#include "portdefs.h"
#if _ANSI_HEADERS_
#   include <string.h>
#   include <stdlib.h>
#endif
#include "tinfocap.h"

void inittables __(( void ));
void putentry __(( void ));
void usage __(( void ));
void vsn __(( void ));

/* command line options */

#define DEF_WIDTH	72

int	width = DEF_WIDTH;

const char	*_pname;

void
main(argc, argv)
int	argc;
char	*argv[];
{
	register const char	*arg;

	_pname = *argv++;

	/* get command line options */
	while ((arg = *argv++) && *arg == '-') {
		++arg;
		while (*arg) {
			switch (*arg++) {
			case '1':	
				width = 0;
				continue;
			case 'w':	
				if ((width = atoi(arg)) <= 40)
					width = DEF_WIDTH;
				break;
			case '?':
				vsn();
			default:
				usage();
			}
			break;
		}
	}

	inittables();
	
	do {
		int	result;

		setupterm(arg, 1, &result);
		if (result != 1) {
			if (arg == NULL)
				usage();

			fprintf(stderr,
		"%s: description of \"%s\" not found in terminfo database\n", 
			_pname, arg);

			continue;
		}

		putentry();

	} while (arg && (arg = *argv++));

	exit(0);
}

void
vsn()
{
	fprintf(stderr, "%s: %s\n", _pname, version);
	exit(2);
}

void
usage()
{
	fprintf(stderr, "usage: %s -[? 1 w#(D=72)] [terminals] (D=$TERM)\n",
		_pname);
	exit(2);
}


typedef struct {
	char	name[6];	/* terminfo capability name */
	short	offset;		/* offset in struct term. */
} Where;

int	Nflag, Nnum, Nstr;

extern
Where	FlagTab[], NumTab[], StrTab[];

/* expand string `s' in buffer `d' */

void
expand(d, s)
register char	*d;
register const char	*s;
{
	register const char	*t;
	register int	c;

	while (c = *s++) {
		if ((c &= 0377) <= 040) {
			/* special escapes */
			for (t = "\bb\nn\rr\33E\tt\ff s";
			     *t && (*t++ != c);
			     t++) ;
			if (*t)
				*d++ = '\\', *d++ = *t;
			else
				*d++ = '^', *d++ = c + '@';
		}
		else if (c >= 0177) {
			sprintf(d, "\\%03o", c);
			d += 4;
		}
		else switch (c) {
		case ':':
		case '^':
		case ',':
		case '\\':
			*d++ = '\\';
		default:
			*d++ = c;
		}
	}
	*d = '\0';
}

/* output terminfo entry */

#define Flag(off)	(*(char *) OFFSET_TO_TI(off))
#define Num(off)	(*(short *)OFFSET_TO_TI(off))
#define Str(off)	(*(char **)OFFSET_TO_TI(off))

void
putentry()
{
	extern char	ttytype[];	/* filled by setupterm */
	char	work[BUFSIZ];

	register Where	*wp, *ep;
	register int	i, len;

	fputs(ttytype, stdout);

	for (i = width, wp = FlagTab, ep = wp + Nflag; wp < ep; wp++) {
		if (!Flag(wp->offset))
			continue;

		if ((i += 2 + (len = strlen(wp->name))) >= width)
			fputs(",\n\t", stdout),
			i = len + 8;
		else
			fputs(", ", stdout);

		fputs(wp->name, stdout);
	}

	for (i = width, wp = NumTab, ep = wp + Nnum; wp < ep; wp++) {
		if (Num(wp->offset) < 0)
			continue;

		sprintf(work, "%s#%d", wp->name, Num(wp->offset));

		if ((i += 2 + (len = strlen(work))) >= width)
			fputs(",\n\t", stdout),
			i = len + 8;
		else
			fputs(", ", stdout);

		fputs(work, stdout);
	}

	for (i = width, wp = StrTab, ep = wp + Nstr; wp < ep; wp++) {
		if (Str(wp->offset) == NULL)
			continue;

		sprintf(work, "%s=", wp->name);
		expand(work + strlen(work), Str(wp->offset));
 
		if ((i += 2 + (len = strlen(work))) >= width)
			fputs(",\n\t", stdout),
			i = len + 8;
		else
			fputs(", ", stdout);

		fputs(work, stdout);
	}
	fputs("\n\n", stdout);
}

/* initialize tables */

/*
 * Enter a capability in the table.
 * "Standard" terminfo entries are defined using ENTRY.
 * "Extended" entries are defined using EXTRY for easy recognition,
 * and surrounded with "#ifdef <variable-name> ... #endif" so these are
 * only compiled in when defined in term.h.
 * The tables are lexically ordered on termcap id. (a,b) 
 */

#define ENTRY(i,d, ti_name, pad_parm, ti_variable) {	\
		ti_name,				\
		(short) TI_TO_OFFSET(ti_variable)	\
	},
	/* (Note the trailing comma.) */

/* Determine size of table at compile-time. (don't count zero-termination) */

#define TABLESIZE(tab)		(sizeof(tab) / sizeof(tab[0]) -1)

/* These includes define the tables proper. */

Where FlagTab[] = {
#define TABLE FLAGS
#include "tinfocap.h"
	{0}
};

Where NumTab[] = {
#define TABLE NUMBERS
#include "tinfocap.h"
	{0}
};

Where StrTab[] = {
#define TABLE STRINGS
#include "tinfocap.h"
	{0}
};

/* We want the table ordered on capability name. */

private int
cmp(p1, p2)
Where *p1, *p2;
{
	return strncmp(p1->name, p2->name, sizeof(p1->name));
}

void
inittables()
{
	qsort(FlagTab, Nflag = TABLESIZE(FlagTab), sizeof(Where), cmp);
	qsort(NumTab, Nnum = TABLESIZE(NumTab), sizeof(Where), cmp);
	qsort(StrTab, Nstr = TABLESIZE(StrTab), sizeof(Where), cmp);
}
