[net.sources] termcap to terminfo translator

robert@gitpyr.UUCP (Robert Viduya) (01/30/85)

The following is a program that converts termcap database files to terminfo
source files.  It reads the termcap file from standard input and writes the
terminfo source to standard output.  I tried to be as complete as possible,
but I wasn't able to implement some things due to ambiguous documentation.
The unimplemented parts are in the %-escapes.  I wasn't sure about some
of the more exotic termcap %-escapes like '%B'.  However, things like '%c',
'%d', '%2d' and '%+' are implemented.

		as usual, send bug reports...

			robert

------
#!/bin/sh
# Posted from gitpyr!robert
#	Run the following text with /bin/sh to create:
#	Makefile
#	captoinfo.c
#	getcap.c
#	putinfo.c
#	tget.c
sed 's/^X//' << '--burp--' > Makefile
XCFLAGS	=	-O
XOBJS	=	captoinfo.o getcap.o putinfo.o tget.o
X
Xcaptoinfo:	$(OBJS)
X		cc $(CFLAGS) $(OBJS) -o captoinfo
X
Xcaptoinfo.o:	captoinfo.c
X
Xgetcap.o:	getcap.c
X
Xputinfo.o:	putinfo.c
X
Xtget.o:		tget.c
--burp--
sed 's/^X//' << '--burp--' > captoinfo.c
X/*
X * captoinfo:
X *	Translate termcap terminal database to terminfo source
X *	format.
X *
X *	Captoinfo reads standard input, which is assumed to be
X *	a termcap file and writes the equivalent to standard
X *	output in terminfo source format.
X *
X * Robert Viduya - Georgia Institute of Technology.
X *
X *	gitpyr!robert
X */
X#include <stdio.h>
X
X#define	bool	char
X#define	TRUE	1
X#define	FALSE	0
X
Xchar    buffer[2048];
X
X
Xmain ()
X{
X    int		c;
X
X    while ((c = getchar ()) != EOF) {
X	if (c == '#') {
X	    (void) putchar (c);
X	    do {
X		c = getchar ();
X		(void) putchar (c);
X	    } while (c != '\n');
X	}
X	else {
X	    if (ungetc (c, stdin) == EOF) {
X		fprintf (stderr, "ungetc failed.\n");
X		exit (1);
X	    }
X	    get_termcap ();
X	    print_name ();
X	    print_bools ();
X	    print_nums ();
X	    print_strs ();
X	}
X    }
X    exit (0);
X}
--burp--
sed 's/^X//' << '--burp--' > getcap.c
X#include <stdio.h>
X#include <ctype.h>
X
X#define	bool	char
X#define	TRUE	1
X#define	FALSE	0
X
Xextern char    buffer[];
X
X
X/*
X * get_termcap:
X *	read next termcap entry into buffer from standard input.
X */
Xget_termcap ()
X{
X    int		c;
X    char	*bptr;
X
X    bptr = buffer;
X    while ((c = getchar ()) != '\n') {
X	if (c == '\\') {
X	    if ((c = getchar ()) != '\n') {
X		if (ungetc (c, stdin) == EOF) {
X		    fprintf (stderr, "ungetc failed.\n");
X		    exit (1);
X		}
X		*(bptr++) = '\\';
X	    }
X	}
X	else {
X	    *(bptr++) = c;
X	}
X    }
X    *bptr = '\0';
X}
--burp--
sed 's/^X//' << '--burp--' > putinfo.c
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X
X#define	bool	char
X#define	TRUE	1
X#define	FALSE	0
X
X#define	MAXINDEX(array)	(sizeof(array)/sizeof(array[0]))
X
X/*
X * bools & boolcaps:
X *	lookup translate table for boolean fields.
X */
Xstruct	bools {
X    char	*capname;	/* termcap name */
X    char	*infoname;	/* terminfo name */
X};
Xstruct	bools	boolcaps[] = {
X    { "bw", "bw" },	{ "am", "am" },		{ "xb", "xsb" },
X    { "xs", "xhp" },	{ "xn", "xenl" },	{ "eo", "eo" },
X    { "gn", "gn" },	{ "hc", "hc" },		{ "km", "km" },
X    { "hs", "hs" },	{ "in", "in" },		{ "da", "da" },
X    { "db", "db" },	{ "mi", "mir" },	{ "ms", "msgr" },
X    { "os", "os" },	{ "es", "eslok" },	{ "xt", "xt" },
X    { "hz", "hz" },	{ "ul", "ul" },		{ "xo", "xon" }
X};
X#define MAXBOOLS	MAXINDEX(boolcaps)
X
X/*
X * nums & numcaps:
X *	lookup translate table for numeric capabilities.
X */
Xstruct	nums {
X    char	*capname;	/* termcap name */
X    char	*infoname;	/* terminfo name */
X};
Xstruct	nums	numcaps[] = {
X    { "co", "cols" },	{ "it", "it" },		{ "li", "lines" },
X    { "lm", "lm" },	{ "sg", "xmc" },	{ "pb", "pb" },
X    { "vt", "vt" },	{ "ws", "wsl" }
X};
X#define	MAXNUMS		MAXINDEX(numcaps)
X
X/*
X * strs & strcaps:
X *	lookup translate table for string capabilities.
X */
Xstruct	strs	{
X    char	*capname;	/* termcap name */
X    char	*infoname;	/* terminfo name */
X    char	*dflt;		/* default value */
X};
Xstruct	strs	strcaps[] = {
X    { "bt",	"cbt",		((char *)0) },
X    { "bl",	"bel",		"\007" },
X    { "cr",	"cr",		"\r" },
X    { "cs",	"csr",		((char *)0) },
X    { "ct",	"tbc",		((char *)0) },
X    { "cl",	"clear",	((char *)0) },
X    { "ce",	"el",		((char *)0) },
X    { "cd",	"ed",		((char *)0) },
X    { "ch",	"hpa",		((char *)0) },
X    { "CC",	"cmdch",	((char *)0) },
X    { "cm",	"cup",		((char *)0) },
X    { "do",	"cud1",		"\n" },
X    { "ho",	"home",		((char *)0) },
X    { "vi",	"civis",	((char *)0) },
X    { "le",	"cub1",		"\b" },		/* special case - check bc */
X    { "CM",	"mrcup",	((char *)0) },
X    { "ve",	"cnorm",	((char *)0) },
X    { "nd",	"cuf1",		((char *)0) },
X    { "ll",	"ll",		((char *)0) },
X    { "up",	"cuu1",		((char *)0) },
X    { "vs",	"cvvis",	((char *)0) },
X    { "dc",	"dch1",		((char *)0) },
X    { "dl",	"dl1",		((char *)0) },
X    { "ds",	"dsl",		((char *)0) },
X    { "hd",	"hd",		((char *)0) },
X    { "as",	"smacs",	((char *)0) },
X    { "mb",	"blink",	((char *)0) },
X    { "md",	"bold",		((char *)0) },
X    { "ti",	"smcup",	((char *)0) },
X    { "dm",	"smdc",		((char *)0) },
X    { "mh",	"dim",		((char *)0) },
X    { "im",	"smir",		((char *)0) },
X    { "mp",	"prot",		((char *)0) },
X    { "mr",	"rev",		((char *)0) },
X    { "mk",	"invis",	((char *)0) },
X    { "so",	"smso",		((char *)0) },
X    { "us",	"smul",		((char *)0) },
X    { "ec",	"ech",		((char *)0) },
X    { "ae",	"rmacs",	((char *)0) },
X    { "me",	"sgr0",		((char *)0) },
X    { "te",	"rmcup",	((char *)0) },
X    { "ed",	"rmdc",		((char *)0) },
X    { "ei",	"rmir",		((char *)0) },
X    { "se",	"rmso",		((char *)0) },
X    { "ue",	"rmul",		((char *)0) },
X    { "vb",	"flash",	((char *)0) },
X    { "ff",	"ff",		((char *)0) },
X    { "fs",	"fsl",		((char *)0) },
X    { "is",	"is1",		((char *)0) },
X    { "i1",	"is2",		((char *)0) },
X    { "i2",	"is3",		((char *)0) },
X    { "if",	"if",		((char *)0) },
X    { "ic",	"ich1",		((char *)0) },
X    { "al",	"il1",		((char *)0) },
X    { "ip",	"ip",		((char *)0) },
X    { "kb",	"kbs",		"\b" },
X    { "ka",	"ktbc",		((char *)0) },
X    { "kC",	"kclr",		((char *)0) },
X    { "kt",	"kctab",	((char *)0) },
X    { "kD",	"kdch1",	((char *)0) },
X    { "kL",	"kdl1",		((char *)0) },
X    { "kd",	"kcud1",	"\n" },
X    { "kM",	"krmir",	((char *)0) },
X    { "kE",	"kel",		((char *)0) },
X    { "kS",	"ked",		((char *)0) },
X    { "k0",	"kf0",		((char *)0) },
X    { "k1",	"kf1",		((char *)0) },
X    { "k2",	"kf2",		((char *)0) },
X    { "k3",	"kf3",		((char *)0) },
X    { "k4",	"kf4",		((char *)0) },
X    { "k5",	"kf5",		((char *)0) },
X    { "k6",	"kf6",		((char *)0) },
X    { "k7",	"kf7",		((char *)0) },
X    { "k8",	"kf8",		((char *)0) },
X    { "k9",	"kf9",		((char *)0) },
X    { "kh",	"khome",	((char *)0) },
X    { "kI",	"kich1",	((char *)0) },
X    { "kA",	"kil1",		((char *)0) },
X    { "kl",	"kcub1",	"\b" },
X    { "kH",	"kll",		((char *)0) },
X    { "kN",	"knp",		((char *)0) },
X    { "kP",	"kpp",		((char *)0) },
X    { "kr",	"kcuf1",	((char *)0) },
X    { "kF",	"kind",		((char *)0) },
X    { "kR",	"kri",		((char *)0) },
X    { "kT",	"khts",		((char *)0) },
X    { "ku",	"kcuu1",	((char *)0) },
X    { "ke",	"rmkx",		((char *)0) },
X    { "ks",	"smkx",		((char *)0) },
X    { "l0",	"lf0",		((char *)0) },
X    { "l1",	"lf1",		((char *)0) },
X    { "l2",	"lf2",		((char *)0) },
X    { "l3",	"lf3",		((char *)0) },
X    { "l4",	"lf4",		((char *)0) },
X    { "l5",	"lf5",		((char *)0) },
X    { "l6",	"lf6",		((char *)0) },
X    { "l7",	"lf7",		((char *)0) },
X    { "l8",	"lf8",		((char *)0) },
X    { "l9",	"lf9",		((char *)0) },
X    { "mm",	"smm",		((char *)0) },
X    { "mo",	"rmm",		((char *)0) },
X    { "nw",	"nel",		"\r\n" },
X    { "pc",	"pad",		((char *)0) },
X    { "DC",	"dch",		((char *)0) },
X    { "DL",	"dl",		((char *)0) },
X    { "DO",	"cud",		((char *)0) },
X    { "IC",	"ich",		((char *)0) },
X    { "SF",	"indn",		((char *)0) },
X    { "AL",	"il",		((char *)0) },
X    { "LE",	"cub",		((char *)0) },
X    { "RI",	"cuf",		((char *)0) },
X    { "SR",	"rin",		((char *)0) },
X    { "UP",	"cuu",		((char *)0) },
X    { "pk",	"pfkey",	((char *)0) },
X    { "pl",	"pfloc",	((char *)0) },
X    { "px",	"pfx",		((char *)0) },
X    { "ps",	"mc0",		((char *)0) },
X    { "pf",	"mc4",		((char *)0) },
X    { "po",	"mc5",		((char *)0) },
X    { "rp",	"rep",		((char *)0) },
X    { "rs",	"rs1",		((char *)0) },
X    { "r1",	"rs2",		((char *)0) },
X    { "r2",	"rs3",		((char *)0) },
X    { "rf",	"rf",		((char *)0) },
X    { "rc",	"rc",		((char *)0) },
X    { "cv",	"vpa",		((char *)0) },
X    { "sc",	"sc",		((char *)0) },
X    { "sf",	"ind",		"\n" },
X    { "sr",	"ri",		((char *)0) },
X    { "sa",	"sgr",		((char *)0) },
X    { "st",	"hts",		((char *)0) },
X    { "wi",	"wind",		((char *)0) },
X    { "ta",	"ht",		((char *)0) },	/* conditional - check pt */
X    { "ts",	"tsl",		((char *)0) },
X    { "uc",	"uc",		((char *)0) },
X    { "hu",	"hu",		((char *)0) },
X    { "iP",	"iprog",	((char *)0) },
X    { "K1",	"ka1",		((char *)0) },
X    { "K2",	"kb2",		((char *)0) },
X    { "K3",	"ka3",		((char *)0) },
X    { "K4",	"kc1",		((char *)0) },
X    { "K5",	"kc3",		((char *)0) },
X    { "pO",	"mc5p",		((char *)0) },
X    { "tc",	"use",		((char *)0) }
X};
X#define	MAXSTRS		MAXINDEX(strcaps)
X
Xint	tgetname ();	/* get termcap name */
Xint	tgetflag ();	/* get termcap boolean value */
Xint	tgetnum ();	/* get termcap numeric value */
Xint	tgetstr ();	/* get termcap string value */
X
X
X/*
X * print_name:
X *	print name and aliases of current termcap entry.
X */
Xprint_name ()
X{
X    char	name[100];
X
X    tgetname (name);
X    printf ("%s,\n", name);
X}
X
X/*
X * print_bools:
X *	print all boolean fields of current termcap entry.
X */
Xprint_bools ()
X{
X    int		i, val;
X    bool	stuffprinted = FALSE;
X
X    for (i = 0; i < MAXBOOLS; i++)
X	if (val = tgetflag (boolcaps[i].capname)) {
X	    if (val == 1)
X		printf ("\t%s,", boolcaps[i].infoname);
X	    else
X		printf ("\t%s@,", boolcaps[i].infoname);
X	    stuffprinted = TRUE;
X	}
X    if (stuffprinted)
X	(void) putchar ('\n');
X}
X
X/*
X * print_nums:
X *	print all numeric fields of current termcap entry.
X */
Xprint_nums ()
X{
X    int		i, capval;
X    bool	stuffprinted = FALSE;
X
X    for (i = 0; i < MAXNUMS; i++)
X	if ((capval = tgetnum (numcaps[i].capname)) >= 0) {
X	    printf ("\t%s#%d,", numcaps[i].infoname, capval);
X	    stuffprinted = TRUE;
X	}
X	else if (capval == -2) {
X	    printf ("\t%s@,", numcaps[i].infoname);
X	    stuffprinted = TRUE;
X	}
X    if (stuffprinted)
X	(void) putchar ('\n');
X}
X
X/*
X * print_strs:
X *	print all string fields of current termcap entry.
X */
Xprint_strs ()
X{
X    int		i, count = 0;
X    char	capval[100];
X
X    for (i = 0; i < MAXSTRS; i++) {
X	tgetstr (strcaps[i].capname, capval);
X	if (!capval[0]) {
X	    if (strcmp (strcaps[i].capname, "le") == 0) {
X		tgetstr ("bc", capval);
X	    }
X	    else if (strcmp (strcaps[i].capname, "ta") == 0) { 
X		if (tgetflag ("pt")) {
X		    capval[0] = '\t';
X		    capval[1] = '\0';
X		}
X	    }
X	}
X	if ((!capval[0]) && (strcaps[i].dflt))
X	    (void) strcpy (capval, strcaps[i].dflt);
X	if (capval[0]) {
X	    if (strcmp (capval, "@") != 0) {
X		printf ("\t%s=", strcaps[i].infoname);
X		if (strcmp(strcaps[i].infoname,"use") != 0) {
X		    put_str (capval);
X		    printf (",");
X		}
X		else
X		    printf ("%s,", capval);
X	    }
X	    else
X		printf ("%s@,", strcaps[i].infoname);
X	    count++;
X	    if (!(count %= 3))
X		putchar ('\n');
X	}
X    }
X    if (count)
X	(void) putchar ('\n');
X}
X
X/*
X * put_str:
X *	translate strings to printable format and print them.
X */
Xput_str (s)
Xchar	*s;
X{
X    bool	rflag = FALSE;	/* % codes */
X    char	*c;
X    int		parm;
X
X    if ((isdigit (*s)) || (*s == '.')) {	/* handle padding */
X	printf ("$<");
X	while ((isdigit (*s)) || (*s == '.')) {
X	    (void) putchar (*s);
X	    s++;
X	}
X	if (*s == '*') {
X	    (void) putchar (*s);
X	    s++;
X	}
X	(void) putchar ('>');
X    }
X    for (c = s; *c; c++) {	/* scan for % codes (needs work) */
X	if (*c == '%') {
X	    c++;
X	    switch (*c) {
X		case 'r':
X		    rflag = TRUE;
X		    break;
X		default:
X		    break;	/* ignore */
X	    }
X	}
X    }
X    parm = 0;
X    while (*s) {		/* print the string */
X	switch (*s) {
X	    case '%':
X		s++;
X		switch (*s) {
X		    case '%':
X			printf ("%%%%");
X			break;
X		    case 'i':
X			printf ("%%i");
X			break;
X		    case 'd':
X			parm++;
X			if ((rflag) && (parm <= 2)) {
X			    if (parm == 1)
X				printf ("%%p2%%d");
X			    else
X				printf ("%%p1%%d");
X			}
X			else
X			    printf ("%%p%d%%d", parm);
X			break;
X		    case '2':
X			parm++;
X			if ((rflag) && (parm <= 2)) {
X			    if (parm == 1)
X				printf ("%%p2%%02d");
X			    else
X				printf ("%%p1%%02d");
X			}
X			else
X			    printf ("%%p%d%%02d", parm);
X			break;
X		    case '3':
X			parm++;
X			if ((rflag) && (parm <= 2)) {
X			    if (parm == 1)
X				printf ("%%p2%%03d");
X			    else
X				printf ("%%p1%%03d");
X			}
X			else
X			    printf ("%%p%d%%03d", parm);
X			break;
X		    case '.':
X			parm++;
X			if ((rflag) && (parm <= 2)) {
X			    if (parm == 1)
X				printf ("%%p2%%c");
X			    else
X				printf ("%%p1%%c");
X			}
X			else
X			    printf ("%%p%d%%c", parm);
X			break;
X		    case '+':
X			s++;
X			parm++;
X			if ((rflag) && (parm <= 2)) {
X			    if (parm == 1)
X				printf ("%%p2%%'%c'%%+%%c", *s);
X			    else
X				printf ("%%p1%%'%c'%%+%%c", *s);
X			}
X			else
X			    printf ("%%p%d%%'%c'%%+%%c", parm, *s);
X			break;
X		    default:
X			break;	/* ignore */
X		}
X		break;
X	    case '\200':
X		printf ("\\0");
X		break;
X	    case '\177':
X		printf ("^?");
X		break;
X	    case ',':
X		printf ("\\,");
X		break;
X	    case '\\':
X		printf ("\\\\");
X		break;
X	    case '^':
X		printf ("\\^");
X		break;
X	    case ':':
X		printf ("\\:");
X		break;
X	    case '\033':
X		printf ("\\E");
X		break;
X	    case '\n':
X		printf ("\\n");
X		break;
X	    case '\r':
X		printf ("\\r");
X		break;
X	    case '\t':
X		printf ("\\t");
X		break;
X	    case '\b':
X		printf ("\\b");
X		break;
X	    case '\f':
X		printf ("\\f");
X		break;
X	    case ' ':
X		printf ("\\s");
X		break;
X	    default:
X		if (*s < ' ')
X		    printf ("^%c", *s + 'A' - 1);
X		else
X		    (void) putchar (*s);
X		break;
X	}
X	s++;
X    }
X}
--burp--
sed 's/^X//' << '--burp--' > tget.c
X#include <stdio.h>
X#include <ctype.h>
X#include <strings.h>
X
X#define	bool	char
X#define	TRUE	1
X#define	FALSE	0
X
Xextern char    buffer[];
X
X
X/*
X * scan:
X *	scan for character in string, return position of character.
X *	similar to index/strchr, except that if char not found, returns
X *	pointer to null at end of string, instead of a null pointer.
X */
Xchar *
Xscan (s, c)
Xregister char	*s;
Xregister char	c;
X{
X    while ((*s) && (*s != c))
X	s++;
X    return (s);
X}
X
X/* findcap:
X * 	returns pointer to just after capname (trailing ':' for flags,
X *	'#' for nums, '=' for strs, '@' for disabled stuff) or to null
X *	 after termcap if not found.
X */
Xchar *
Xfindcap (capname)
Xchar	*capname;
X{
X    register char	*bptr = buffer;
X    register bool	found = FALSE;
X    char		cap[3];
X
X    cap[2] = '\0';
X    while ((!found) && (*bptr)) {
X	bptr = scan (bptr, ':');
X	if (*bptr) {
X	    cap[0] = *(bptr + 1);
X	    cap[1] = *(bptr + 2);
X	    if (strcmp (cap,capname) == 0) {
X		found = TRUE;
X		bptr += 3;	/* skip colon and capname */
X	    }
X	    else
X		bptr++;		/* skip colon */
X	}
X    }
X    return (bptr);
X}
X
X/*
X * tgetname:
X *	store name of termcap entry in name
X */
Xtgetname (name)
Xchar	*name;
X{
X    char	*bptr;
X
X    bptr = buffer;
X
X    while ((*bptr) && (*bptr != ':'))
X	*(name++) = *(bptr++);
X    *(name) = '\0';
X}
X
X/*
X * tgetflag:
X *	return 1 if capname present, 0 otherwise, -1 if '@'ed.
X */
Xint
Xtgetflag (capname)
Xchar	*capname;
X{
X    char	*c;
X
X    c = findcap (capname);
X    if (*c == '\0')
X	return (0);
X    else if (*c == '@')
X	return (-1);
X    else
X	return (1);
X}
X
X/*
X * tgetnum:
X *	return value of capname, -1 if not present, -2 if '@'ed.
X */
Xint
Xtgetnum (capname)
Xchar	*capname;
X{
X    char	*c;
X    int		val;
X
X    c = findcap (capname);
X    if (*c == '@')
X	return (-2);
X    else if (*c != '\0') {
X	c++;	/* skip '#' */
X	val = 0;
X	while (isdigit (*c)) {
X	    val = (val * 10) + (*c - '0');
X	    c++;
X	}
X	return (val);
X    }
X    else
X	return (-1);
X}
X
X/*
X * tgetstr:
X *	store binary value of capname into value, store null if
X *	not present, store "@" if '@'ed.
X */
Xtgetstr (capname, value)
Xchar		*capname;
Xregister char	*value;
X{
X    register char	*c;
X
X    c = findcap (capname);
X    if (*c == '@')
X	strcpy (value, "@");
X    else if (*c != '\0') {
X	c++;	/* skip '=' */
X	while ((*c) && (*c != ':')) {
X	    if (*c == '^') {
X		c++;
X		if (islower (*c)) 
X		    *(value++) = toupper(*(c++)) - '@';	/* ascii dependent */
X		else
X		    *(value++) = *(c++) - '@';	/* ascii dependent */
X	    }
X	    else if (*c == '\\') {
X		c++;
X		switch (*c) {
X		    case 'E':
X			*(value++) = '\033';
X			c++;
X			break;
X		    case 'n':
X			*(value++) = '\n';
X			c++;
X			break;
X		    case 'r':
X			*(value++) = '\r';
X			c++;
X			break;
X		    case 't':
X			*(value++) = '\t';
X			c++;
X			break;
X		    case 'b':
X			*(value++) = '\b';
X			c++;
X			break;
X		    case 'f':
X			*(value++) = '\f';
X			c++;
X			break;
X		    default:
X			if (isdigit (*c)) {	/* octal value */
X			    *value = '\0';
X			    while (isdigit (*c)) {
X				*value = ((*value) * 8) + ((*c) - '0');
X				c++;
X			    }
X			    value++;
X			}
X			else
X			    *(value++) = *(c++);
X			break;
X		}
X	    }
X	    else
X		*(value++) = *(c++);
X	}
X	*value = '\0';
X    }
X    else
X	*value = '\0';
X}
--burp--
exit
-- 
Robert Viduya
Georgia Institute of Technology

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert