home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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);
- }
-
-