home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume24
/
untic
/
untic.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
19KB
|
651 lines
/*
* Untic.c -- Uncompile a terminfo file
*
* Usage:
* untic terminal_name . . .
*
* This program finds the terminal description in
* /usr/lib/terminfo/?/terminal_name
* It then converts the information into an ASCII file suitable for
* running into "tic". The resulting file is written to standard output.
*
* Compile by:
* cc -DSYSVR3 -O -o untic untic.c
*
* It is probably a good idea to ensure that the file produced will compile
* to the original file before trusting "untic".
*
* Structure of terminfo file:
* short magic number
* short length of terminal names + NUL
* short length of booleans
* short length of numerics
* short length of strings
* short length of string table
* chars NUL terminated terminal name
* chars boolean flags for each of the possible booleans
* shorts values for each of the possible numerics
* shorts offsets (from start of strings) for each of the
* possible strings
* chars NUL terminated strings for each of the defined strings
*
* Most of the variables are in the order that the documentation lists
* them. This is important, as the information is stored in the file
* based upon the ordinal position of the variable. Some of the string
* variables are not in order. Presumably, if they add more variables,
* it will be to the end of the list, and not in the middle.
*
* This has been tested on
* Plexus P20 (M68010), System 5 Release 2 (I think)
*
* Bugs:
* The longest string capability is limited to 4096 bytes. If a longer
* string is encountered, the program will do unpredicatable things.
* (Who uses strings that long anyway?) The longest that the terminfo
* file can be is 4096 bytes anyway, so this isn't too big a problem.
*
* Credits:
* Written by Dave Regan orstcs!regan 16 May 86
* TERMINFO environment variable added by G A Moffett (amdahl!gam)
* 31 May 86
* TERMINFO environment variable added by hp-pcd!hplabs!csun!aeusemrs
* (again) 16 Jan 87. Time to get this out.
*
* I disclaim that this program does anything useful. It might also
* do accidental damage. Backup your original terminfo files.
*
* This program is public domain. That means you can do anything
* you want with it.
*
* New Notes 16 Jan 1987
* I want to thank the people who have written to me to let
* me know that they have a use for this program, and have added
* suggestions. I am also glad that Unipress have this tool on
* their distribution tape.
*
* It has been brought to my attention (by Tony Hansen -
* ihnp4!pegasus!hansen) that there is a program in the ATT toolchest
* and to be distributed in system V, release 3 called "infocmp" that
* does what "untic" does, as well as a lot more. See the System V
* Administration Guide.
*
* Thanks to everyone who gave me information,
* Dave Regan 16 Jan 87
*
*
* Notes 10 December 1990
* I have added the capabilities necessary to support a more modern
* version of System V. To get these new capabilities, add -DSYSVR3
* to the command line. In general, it should not hurt to have too many
* capabilities in this list, as long as it is a strict superset of
* what you have in your "tic". (These changes were basically noted
* by Kirk Webb (kirk@ico.ISC.COM) on 13 Feb 1987. I have added
* some beyond what he had called out.)
*
* If it comes to figuring out why this doesn't work, run "strings -2"
* on the Terminfo Compiler (tic) and look at the output. You should
* see the tables of capabilities go by. Copy these capabilities
* into the appropriate tables, and you should be fine.
*
* Some of the terminfo compilers have more symbols than others.
* I modified the error checking to not emit an error unless one of
* the "extended" symbols is actually referenced.
*
* I have added "void" as a return type to some of the functions.
* If this gives your C compiler a fit, then do a "-Dvoid=int" on
* the command line.
*
* Thanks to Joe Wasik at the Unix/C Reusable Code Library
* (jcwasik@clib.PacBell.COM) to get me to put this together
* again with current tables. The test program (untic.tst) was
* also written by him.
*
* It appears that current versions of infocmp will somehow derive
* the "ma#1" capability on older terminfo files. I have looked
* at the various terminfo files in reasonable detail, and cannot
* figure out how it can tell the difference. So I am punting,
* and simply enumerate all of the "special" cases. This is a
* gross hack, and if anyone can tell me an algorithmic way to
* do this, I would apperciate it. Actually, it does this even
* on "modern" terminfo files. See "fortune" for an example of
* a terminfo file which could represent the "ma" capability but
* the value is 0xFFFF (not used). Yet, the "ma#1" capability is
* printed by terminfo. I am almost beginning to think that this
* is a bug on terminfo's part, but processing it correctly is so
* trivial, that I don't see how this could be messed up; it must
* be by design. Well, if you find out, let me know.
*
* Dave Regan 10 December 1990
*/
#include <stdio.h>
#include <ctype.h>
#ifdef __MSDOS__
#include <stdlib.h>
#include <string.h>
#define OPEN_MODE "rb"
#define CVPTR const void
#define F(x) x /* Function prototypes */
#else
extern char *strcpy(); /* This should be in strings.h */
extern char * malloc(); /* This is supposed to be in stdlib.h, but
* that file doesn't exist on older systems. */
#define OPEN_MODE "r" /* Mode used to open terminfo files */
#define CVPTR char
#define F(x) () /* No prototypes */
#endif /* __MSDOS__ */
/***
*** Local constants
***/
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif /* TRUE */
#define DEBUG FALSE /* TRUE/FALSE to enable debugging output */
#ifndef TERMINFO_DIR
#define TERMINFO_DIR "/usr/lib/terminfo"
#endif /* TERMINFO_DIR */
#define MAGIC 0x011A /* Terminfo magic number */
#define MAXLINE 55 /* Longest emited line */
#define MAX_CAP 4096 /* Longest single capability */
/***
*** Forward declarations
***/
extern char * addchar F((char *cptr, int ch));
extern char * addoctal F((char *cptr, int ch));
extern char * addstr F((char *cptr, char *str));
extern void convert F((FILE *file, char *name));
extern void emit F((char *str));
extern unsigned short get2 F((FILE *file));
extern int xstrcmp F((CVPTR *a, CVPTR *b));
/***
*** Global data
***/
int Line_len; /* Current length of line */
/***
*** Definitions of attributes
***/
char *Booleans[] = /* Names of boolean variables, in order */
{ "bw", "am", "xsb", "xhp", "xenl", "eo", "gn", "hc", "km",
"hs", "in", "da", "db", "mir", "msgr", "os", "eslok", "xt",
"hz", "ul", "xon"
#ifdef SYSVR3
, "nxon", "mc5i", "chts", "nrrmc", "npc"
, "ndscr"
#endif /* SYSVR3 */
};
#define BOOL_LENGTH (sizeof(Booleans) / sizeof(char *))
char *Numerics[] = /* Names of numeric variables, in order */
{ "cols", "it", "lines", "lm", "xmc", "pb", "vt", "wsl"
#ifdef SYSVR3
, "nlab", "lh", "lw"
, "ma", "wnum"
#endif /* SYSVR3 */
};
#define NUM_LENGTH (sizeof(Numerics) / sizeof(char *))
char *Strings[] = /* Names of string variables, not in strict
order. Makes things a little harder */
{ "cbt", "bel", "cr", "csr", "tbc", "clear", "el", "ed", "hpa",
"cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup",
"cnorm", "cuf1", "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl",
"hd", "smacs", "blink", "bold", "smcup", "smdc", "dim", "smir",
"invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0",
"rmcup", "rmdc", "rmir", "rmso", "rmul", "flash", "ff", "fsl",
"is1", "is2", "is3", "if", "ich1", "il1", "ip", "kbs", "ktbc",
"kclr", "kctab", "kdch1", "kdl1", "kcud1", "krmir", "kel", "ked",
"kf0", "kf1", "kf10", "kf2", "kf3", "kf4", "kf5", "kf6", "kf7",
"kf8", "kf9", "khome", "kich1", "kil1", "kcub1", "kll", "knp",
"kpp", "kcuf1", "kind", "kri", "khts", "kcuu1", "rmkx", "smkx",
"lf0", "lf1", "lf10", "lf2", "lf3", "lf4", "lf5", "lf6", "lf7",
"lf8", "lf9", "rmm", "smm", "nel", "pad", "dch", "dl", "cud",
"ich", "indn", "il", "cub", "cuf", "rin", "cuu", "pfkey", "pfloc",
"pfx", "mc0", "mc4", "mc5", "rep", "rs1", "rs2", "rs3", "rf",
"rc", "vpa", "sc", "ind", "ri", "sgr", "hts", "wind", "ht", "tsl",
"uc", "hu", "iprog", "ka1", "ka3", "kb2", "kc1", "kc3", "mc5p"
#ifdef SYSVR3
, "rmp", "acsc", "pln", "kcbt", "smxon", "rmxon", "smam", "rmam",
"xonc", "xoffc", "enacs", "smln", "rmln", "kbeg", "kcan", "kclo",
"kcmd", "kcpy", "kcrt", "kend", "kent", "kext", "kfnd", "khlp",
"kmrk", "kmsg", "kmov", "knxt", "kopn", "kopt", "kprv", "kprt",
"krdo", "kref", "krfr", "krpl", "krst", "kres", "ksav", "kspd",
"kund", "kBEG", "kCAN", "kCMD", "kCPY", "kCRT", "kDC", "kDL",
"kslt", "kEND", "kEOL", "kEXT", "kFND", "kHLP", "kHOM", "kIC",
"kLFT", "kMSG", "kMOV", "kNXT", "kOPT", "kPRV", "kPRT", "kRDO",
"kRPL", "kRIT", "kRES", "kSAV", "kSPD", "kUND", "rfi", "kf11",
"kf12", "kf13", "kf14", "kf15", "kf16", "kf17", "kf18", "kf19",
"kf20", "kf21", "kf22", "kf23", "kf24", "kf25", "kf26", "kf27",
"kf28", "kf29", "kf30", "kf31", "kf32", "kf33", "kf34", "kf35",
"kf36", "kf37", "kf38", "kf39", "kf40", "kf41", "kf42", "kf43",
"kf44", "kf45", "kf46", "kf47", "kf48", "kf49", "kf50", "kf51",
"kf52", "kf53", "kf54", "kf55", "kf56", "kf57", "kf58", "kf59",
"kf60", "kf61", "kf62", "kf63", "el1", "mgc", "smgl", "smgr",
"fln", "sclk", "dclk", "rmclk", "cwin", "wingo", "hup", "dial",
"qdial", "tone", "pulse", "hook", "pause", "wait", "u0", "u1",
"u2", "u3", "u4", "u5", "u6", "u7", "u8", "u9"
#endif /* SYSVR3 */
#ifdef HPUX5
, "meml", "memu"
#endif /* HPUX5 */
};
#define STR_LENGTH (sizeof(Strings) / sizeof(char *))
char *Exceptions[] =
{ "912b", "912cc", "920b", "adm5", "d800", "dtc", "f1720", "fortune",
"hp", "hp110", "intext", "ofos", "pe1251", "regent100", "regent40",
"regent40-s", "regent60", "regent60-na", "sb1", "sb2", "sbi",
"smartvid", "t1061", "t1061f", "tec400", "trs16", "tvi2p", "tvi803",
"tvi912", "tvi912-2p", "tvi9122p", "tvi9202p", "tvi925", "tvi925-v",
"tvi950", "tvi950-2p", "tvi950-4p", "tvi950-ap", "tvi950-b",
"tvi950-ns", "tvi950-rv", "tvi950-rv-2p", "tvi950-rv-4p",
"tvi9502p", "tvi9504p", "tvi950b", "tvi950ns", "tvi950rv",
"tvi950rv2p", "tvi950rv4p", "vt100-nav", "vt100-nav-w", "xtalk",
"ya", NULL
};
/***
*** Function definitions
***/
void
main(argc, argv)
int argc; /* Number of paramters */
char *argv[]; /* The parameters themselves */
{
char subdir[2]; /* Subdirectory name */
FILE *file;
char *terminfo;
extern FILE *fopen();
extern char *getenv();
/* Change directory to the working directory */
terminfo = getenv("TERMINFO");
if (terminfo == NULL) {
terminfo = TERMINFO_DIR;
}
#if DEBUG
fprintf(stderr, "Looking in %s/?/... for entry.\n", terminfo);
#endif
(void)chdir(terminfo);
/* Go through the arguments */
subdir[1] = '\0';
if (argc == 1)
convert(stdin, "stdin");
else
{
while (--argc)
{
++argv;
subdir[0] = argv[0][0];
(void)chdir(subdir);
if ((file = fopen(*argv, OPEN_MODE)) == NULL)
{
perror(*argv);
}
else
{
convert(file, *argv);
(void)fclose(file);
}
(void)chdir("..");
}
}
exit(0);
}
/*
* Addchar -- Add a character
*/
char *
addchar(cptr, ch)
char *cptr;
int ch;
{
char *addstr(), *addoctal();
if (ch == '\0')
return (addstr(cptr, "\\200"));
if (ch == 0x1B)
return (addstr(cptr, "\\E"));
if (ch == '\n')
return (addstr(cptr, "\\n"));
if (ch == '\r')
return (addstr(cptr, "\\r"));
if (ch == '\t')
return (addstr(cptr, "\\t"));
if (ch == '\b')
return (addstr(cptr, "\\b"));
if (ch == '\f')
return (addstr(cptr, "\\f"));
if (ch == ' ')
return (addstr(cptr, "\\s"));
if (ch == '^')
return (addstr(cptr, "\\^"));
if (ch == '\\')
return (addstr(cptr, "\\\\"));
if (ch == ',')
return (addstr(cptr, "\\,"));
if (ch == 0x7F)
return (addstr(cptr, "\^?"));
if (ch >= ('A' - '@') && ch <= ('_' - '@'))
{
*cptr++ = '^';
*cptr++ = ch + '@';
return (cptr);
}
if (ch > 0x7F)
return (addoctal(cptr, ch));
*cptr++ = ch;
return (cptr);
}
/*
* Addoctal -- Add an octal character
*
* Use sprintf just in case "0" through "7" are not contiguous. Some
* machines are weird.
*/
char *
addoctal(cptr, ch)
char *cptr;
int ch;
{
char *addstr();
ch &= 0xFF;
if (ch == 0x80)
return (addstr(cptr, "\\200"));
(void)sprintf(cptr, "\\%03o", ch);
while (*cptr != '\0')
cptr++;
return (cptr);
}
/*
* Addstr -- Add a string to the capability
*/
char *
addstr(cptr, str)
char *cptr, *str;
{
while (*str)
*cptr++ = *str++;
return (cptr);
}
/*
* Convert -- Do the actual conversion
*/
void
convert(file, name)
FILE *file; /* The file with the compiled information */
char *name; /* Printable version of the filename */
{
int ch, val, i, j;
int name_length, bool_length, num_length, str_length, s_length;
char capability[MAX_CAP+1], *cptr, *addchar();
char **scan;
char term_name[80];
int str_cap[STR_LENGTH];
/* Check the magic number out */
if (get2(file) != MAGIC)
{
fprintf(stderr, "\"%s\" is not a terminfo file\n", name);
return;
}
/* Get the rest of the header information */
name_length = get2(file); /* Get the length of the terminal names */
bool_length = get2(file); /* Get the length of the booleans */
num_length = get2(file); /* Get the length of the numerics */
str_length = get2(file); /* Get the length of the strings */
s_length = get2(file); /* Get the length of the string tables */
/* Time to get real information */
cptr = term_name;
while ((ch = getc(file)) != '\0' && ch != EOF)
{
if (cptr != NULL)
{
if (ch == '|')
{
*cptr = '\0';
cptr = NULL;
}
else
*cptr++ = ch;
}
putchar(ch);
}
if (cptr != NULL)
*cptr = '\0';
printf(",\n");
/* Send out the non-null boolean variables */
Line_len = 0;
for (i = 0; i < bool_length; i++)
{
if ((ch = getc(file)) != 0)
{
if (i < BOOL_LENGTH)
emit(Booleans[i]);
else
fprintf(stderr, "Undefined boolean capability #%d\n", i);
}
}
emit((char *) NULL); /* Force output */
/* The rest of the file is on a 16 bit boundary, so adjust the file */
if ((name_length + bool_length) & 0x01)
(void)getc(file);
#ifdef STRICT_TERMINFO_COMPATIBILITY
/* Bozo alert!!! It appears that there is special code in infocmp to
* put out ma#1 if this is a special terminfo file. Presumably this
* is a good default. Definitately odd.
*/
for (scan = Exceptions;
*scan != NULL && strcmp(*scan, term_name) != 0; scan++)
;
if (*scan != NULL)
emit("ma#1");
/* End bozo alert */
#endif /* STRICT_TERMINFO_COMPATIBILITY */
/* Get the numeric variables */
for (i = 0; i < num_length; i++)
{
if ((val = get2(file)) != 0xFFFF)
{
if (i < NUM_LENGTH)
{
(void)sprintf(capability, "%s#%d", Numerics[i], val);
emit(capability);
}
else
{
fprintf(stderr, "Undefined numeric capability #%d (%d)\n",
i, val);
}
}
}
emit((char *) NULL); /* Force output */
/* Get the string variables offsets */
for (i = 0; i < str_length; i++)
str_cap[i] = get2(file);
/* Get the string variables themselves */
for (i = 0; i < s_length; i++)
{
for (j = 0; j < str_length; j++) /* Find the name */
if (str_cap[j] == i)
break;
if (j >= str_length)
{
#if DEBUG
fprintf(stderr, "Cannot find address %d\n", i);
#endif /* DEBUG */
(void)getc(file);
continue;
}
if (j < STR_LENGTH)
(void)strcpy(capability, Strings[j]);
else
(void) strcpy(capability, "OOPS");
cptr = &capability[strlen(capability)];
*cptr++ = '=';
for (; (ch = getc(file)) != '\0' && ch != EOF; i++)
cptr = addchar(cptr, ch);
*cptr = '\0';
emit(capability);
if (j >= STR_LENGTH)
{
fprintf(stderr, "Undefined string capability #%d (%s)\n",
j, &capability[5]);
}
}
emit((char *) NULL); /* Force output */
}
/*
* Emit -- Emit the string
*
* Emit the given string, and append a comma. If the line gets too long,
* send out a newline and a tab.
*
* In order to make the output to be more directly comparable to infocmp,
* save up all of the output for a category, sort it, and then write it out.
*/
void
emit(str)
char *str; /* String to emit */
{
#ifdef SIMPLE_OUTPUT
if (str == NULL)
{
Line_len = 0;
printf("\n");
}
else
{
if (Line_len == 0)
printf("\t");
if ((Line_len += strlen(str) + 2) > MAXLINE)
{
Line_len = strlen(str) + 2;
printf("\n\t");
}
printf("%s, ", str);
}
#else /* SIMPLE_OUTPUT */
/* Array is over large, but will be enough */
static char *table[STR_LENGTH + BOOL_LENGTH + NUM_LENGTH];
static int next = 0;
int len;
int scan;
if (str != NULL)
{
if ((table[next] = (char *) malloc(strlen(str) + 1)) == NULL)
{
fprintf(stderr, "OUT OF MEMORY\n");
exit(1);
}
strcpy(table[next++], str);
}
else if (next > 0)
{
/* strcmp isn't quite the right type, but should work */
qsort(table, next, sizeof(char *), xstrcmp);
printf("\t");
for (Line_len = scan = 0; scan < next; scan++)
{
len = strlen(table[scan]) + 2;
if ((Line_len += len) > MAXLINE)
{
Line_len = len;
printf("\n\t");
}
else if (Line_len != len)
printf(" ");
printf("%s,", table[scan]);
free(table[scan]);
}
printf("\n");
next = 0;
}
#endif /* SIMPLE_OUTPUT */
}
/*
* Get2 -- Get a two byte number
*/
unsigned short
get2(file)
FILE *file; /* The file with the compiled information */
{
unsigned short temp;
temp = getc(file) & 0xFF;
return (temp + (getc(file) << 8));
}
/*
* Xstrcmp -- Compare function for qsort
*
* Infocmp only compares the base string. Strip of equals signs.
* This routine is an awful hack. There is probably a more elegant
* way of doing this with standard routines. One possibility would
* be to put a NUL at a possible '=', and restore it later (if one was
* destroyed). Call strcmp in between.
*/
int
xstrcmp(a, b)
CVPTR *a;
CVPTR *b;
{
char *str1, *str2;
str1 = *(char **) a;
str2 = *(char **) b;
while (*str1 != '\0' && *str1 != '=' &&
*str2 != '\0' && *str2 != '=' &&
*str1 == *str2)
{
str1++;
str2++;
}
if ((*str1 == '\0' || *str1 == '=') &&
(*str2 == '\0' || *str2 == '='))
return (0);
if (*str1 == '\0' || *str1 == '=')
return (-1);
if (*str2 == '\0' || *str2 == '=')
return (1);
return (*str1 - *str2);
}