home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / untic / untic.c < prev    next >
C/C++ Source or Header  |  1991-06-05  |  19KB  |  651 lines

  1. /*
  2.  * Untic.c -- Uncompile a terminfo file
  3.  *
  4.  * Usage:
  5.  *    untic terminal_name . . .
  6.  *
  7.  * This program finds the terminal description in
  8.  *    /usr/lib/terminfo/?/terminal_name
  9.  * It then converts the information into an ASCII file suitable for
  10.  * running into "tic".  The resulting file is written to standard output.
  11.  *
  12.  * Compile by:
  13.  *    cc -DSYSVR3 -O -o untic untic.c
  14.  *
  15.  * It is probably a good idea to ensure that the file produced will compile
  16.  * to the original file before trusting "untic".
  17.  *
  18.  * Structure of terminfo file:
  19.  *    short    magic number
  20.  *    short    length of terminal names + NUL
  21.  *    short    length of booleans
  22.  *    short    length of numerics
  23.  *    short    length of strings
  24.  *    short    length of string table
  25.  *    chars    NUL terminated terminal name
  26.  *    chars    boolean flags for each of the possible booleans
  27.  *    shorts    values for each of the possible numerics
  28.  *    shorts    offsets (from start of strings) for each of the
  29.  *        possible strings
  30.  *    chars    NUL terminated strings for each of the defined strings
  31.  *
  32.  * Most of the variables are in the order that the documentation lists
  33.  * them.  This is important, as the information is stored in the file
  34.  * based upon the ordinal position of the variable.  Some of the string
  35.  * variables are not in order.  Presumably, if they add more variables,
  36.  * it will be to the end of the list, and not in the middle.
  37.  *
  38.  * This has been tested on
  39.  *    Plexus P20 (M68010), System 5 Release 2 (I think)
  40.  *
  41.  * Bugs:
  42.  *    The longest string capability is limited to 4096 bytes.  If a longer
  43.  *    string is encountered, the program will do unpredicatable things.
  44.  *    (Who uses strings that long anyway?)  The longest that the terminfo
  45.  *    file can be is 4096 bytes anyway, so this isn't too big a problem.
  46.  *
  47.  * Credits:
  48.  *    Written by Dave Regan    orstcs!regan    16 May 86
  49.  *    TERMINFO environment variable added by G A Moffett (amdahl!gam)
  50.  *        31 May 86
  51.  *    TERMINFO environment variable added by hp-pcd!hplabs!csun!aeusemrs
  52.  *    (again) 16 Jan 87.  Time to get this out.
  53.  *
  54.  *    I disclaim that this program does anything useful.  It might also
  55.  *    do accidental damage.  Backup your original terminfo files.
  56.  *
  57.  *    This program is public domain.  That means you can do anything
  58.  *    you want with it.
  59.  *
  60.  *        New Notes        16 Jan 1987
  61.  *    I want to thank the people who have written to me to let
  62.  *    me know that they have a use for this program, and have added
  63.  *    suggestions.  I am also glad that Unipress have this tool on
  64.  *    their distribution tape.
  65.  *
  66.  *    It has been brought to my attention (by Tony Hansen -
  67.  *    ihnp4!pegasus!hansen) that there is a program in the ATT toolchest
  68.  *    and to be distributed in system V, release 3 called "infocmp" that
  69.  *    does what "untic" does, as well as a lot more.  See the System V
  70.  *    Administration Guide.
  71.  *
  72.  *            Thanks to everyone who gave me information,
  73.  *            Dave Regan    16 Jan 87
  74.  *
  75.  *
  76.  *        Notes            10 December 1990
  77.  *    I have added the capabilities necessary to support a more modern
  78.  *    version of System V.  To get these new capabilities, add -DSYSVR3
  79.  *    to the command line.  In general, it should not hurt to have too many
  80.  *    capabilities in this list, as long as it is a strict superset of
  81.  *    what you have in your "tic".  (These changes were basically noted
  82.  *    by Kirk Webb (kirk@ico.ISC.COM) on 13 Feb 1987.  I have added
  83.  *    some beyond what he had called out.)
  84.  *
  85.  *    If it comes to figuring out why this doesn't work, run "strings -2"
  86.  *    on the Terminfo Compiler (tic) and look at the output.  You should
  87.  *    see the tables of capabilities go by.  Copy these capabilities
  88.  *    into the appropriate tables, and you should be fine.
  89.  *
  90.  *    Some of the terminfo compilers have more symbols than others.
  91.  *    I modified the error checking to not emit an error unless one of
  92.  *    the "extended" symbols is actually referenced.
  93.  *
  94.  *    I have added "void" as a return type to some of the functions.
  95.  *    If this gives your C compiler a fit, then do a "-Dvoid=int" on
  96.  *    the command line.
  97.  *
  98.  *    Thanks to Joe Wasik at the Unix/C Reusable Code Library
  99.  *    (jcwasik@clib.PacBell.COM) to get me to put this together
  100.  *    again with current tables.  The test program (untic.tst) was
  101.  *    also written by him.
  102.  *
  103.  *    It appears that current versions of infocmp will somehow derive
  104.  *    the "ma#1" capability on older terminfo files.  I have looked
  105.  *    at the various terminfo files in reasonable detail, and cannot
  106.  *    figure out how it can tell the difference.  So I am punting,
  107.  *    and simply enumerate all of the "special" cases.  This is a
  108.  *    gross hack, and if anyone can tell me an algorithmic way to
  109.  *    do this, I would apperciate it.  Actually, it does this even
  110.  *    on "modern" terminfo files.  See "fortune" for an example of
  111.  *    a terminfo file which could represent the "ma" capability but
  112.  *    the value is 0xFFFF (not used).  Yet, the "ma#1" capability is
  113.  *    printed by terminfo.  I am almost beginning to think that this
  114.  *    is a bug on terminfo's part, but processing it correctly is so
  115.  *    trivial, that I don't see how this could be messed up; it must
  116.  *    be by design.  Well, if you find out, let me know.
  117.  *
  118.  *            Dave Regan    10 December 1990
  119.  */
  120.  
  121. #include <stdio.h>
  122. #include <ctype.h>
  123.  
  124. #ifdef __MSDOS__
  125. #include <stdlib.h>
  126. #include <string.h>
  127. #define    OPEN_MODE    "rb"
  128. #define    CVPTR        const void
  129. #define    F(x)        x    /* Function prototypes            */
  130. #else
  131. extern char *strcpy();        /* This should be in strings.h        */
  132. extern char *    malloc();    /* This is supposed to be in stdlib.h, but
  133.                  * that file doesn't exist on older systems. */
  134. #define    OPEN_MODE    "r"    /* Mode used to open terminfo files    */
  135. #define    CVPTR        char
  136. #define    F(x)        ()    /* No prototypes            */
  137. #endif    /* __MSDOS__ */
  138.  
  139. /***
  140.  ***    Local constants
  141.  ***/
  142. #ifndef TRUE
  143. #define    TRUE    1
  144. #define    FALSE    0
  145. #endif        /* TRUE */
  146.  
  147. #define    DEBUG    FALSE        /* TRUE/FALSE to enable debugging output */
  148.  
  149. #ifndef TERMINFO_DIR
  150. #define    TERMINFO_DIR    "/usr/lib/terminfo"
  151. #endif        /* TERMINFO_DIR */
  152.  
  153.  
  154. #define    MAGIC    0x011A        /* Terminfo magic number        */
  155. #define    MAXLINE    55        /* Longest emited line            */
  156. #define    MAX_CAP    4096        /* Longest single capability        */
  157.  
  158. /***
  159.  ***    Forward declarations
  160.  ***/
  161. extern char *    addchar F((char *cptr, int ch));
  162. extern char *    addoctal F((char *cptr, int ch));
  163. extern char *    addstr F((char *cptr, char *str));
  164. extern void    convert F((FILE *file, char *name));
  165. extern void    emit F((char *str));
  166. extern unsigned short get2 F((FILE *file));
  167. extern int    xstrcmp F((CVPTR *a, CVPTR *b));
  168.  
  169. /***
  170.  ***    Global data
  171.  ***/
  172. int    Line_len;        /* Current length of line        */
  173.  
  174. /***
  175.  ***    Definitions of attributes
  176.  ***/
  177. char    *Booleans[] =    /* Names of boolean variables, in order    */
  178.     { "bw", "am", "xsb", "xhp", "xenl", "eo", "gn", "hc", "km",
  179.       "hs", "in", "da", "db", "mir", "msgr", "os", "eslok", "xt",
  180.       "hz", "ul", "xon"
  181. #ifdef SYSVR3
  182.     , "nxon", "mc5i", "chts", "nrrmc", "npc"
  183.     , "ndscr"
  184. #endif    /* SYSVR3 */
  185.      };
  186. #define    BOOL_LENGTH    (sizeof(Booleans) / sizeof(char *))
  187.  
  188. char    *Numerics[] =    /* Names of numeric variables, in order    */
  189.     { "cols", "it", "lines", "lm", "xmc", "pb", "vt", "wsl"
  190. #ifdef SYSVR3
  191.     , "nlab", "lh", "lw"
  192.     , "ma", "wnum"    
  193. #endif    /* SYSVR3 */
  194.     };
  195. #define    NUM_LENGTH    (sizeof(Numerics) / sizeof(char *))
  196.  
  197. char    *Strings[] =    /* Names of string variables, not in strict
  198.                    order.  Makes things a little harder    */
  199.     { "cbt", "bel", "cr", "csr", "tbc", "clear", "el", "ed", "hpa",
  200.       "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup",
  201.       "cnorm", "cuf1", "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl",
  202.       "hd", "smacs", "blink", "bold", "smcup", "smdc", "dim", "smir",
  203.       "invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0", 
  204.       "rmcup", "rmdc", "rmir", "rmso", "rmul", "flash", "ff", "fsl",
  205.       "is1", "is2", "is3", "if", "ich1", "il1", "ip", "kbs", "ktbc",
  206.       "kclr", "kctab", "kdch1", "kdl1", "kcud1", "krmir", "kel", "ked",
  207.       "kf0", "kf1", "kf10", "kf2", "kf3", "kf4", "kf5", "kf6", "kf7",
  208.       "kf8", "kf9", "khome", "kich1", "kil1", "kcub1", "kll", "knp",
  209.       "kpp", "kcuf1", "kind", "kri", "khts", "kcuu1", "rmkx", "smkx", 
  210.       "lf0", "lf1", "lf10", "lf2", "lf3", "lf4", "lf5", "lf6", "lf7",
  211.       "lf8", "lf9", "rmm", "smm", "nel", "pad", "dch", "dl", "cud",
  212.       "ich", "indn", "il", "cub", "cuf", "rin", "cuu", "pfkey", "pfloc",
  213.       "pfx", "mc0", "mc4", "mc5", "rep", "rs1", "rs2", "rs3", "rf",
  214.       "rc", "vpa", "sc", "ind", "ri", "sgr", "hts", "wind", "ht", "tsl",
  215.       "uc", "hu", "iprog", "ka1", "ka3", "kb2", "kc1", "kc3", "mc5p"
  216. #ifdef SYSVR3
  217.     , "rmp", "acsc", "pln", "kcbt", "smxon", "rmxon", "smam", "rmam",
  218.       "xonc", "xoffc", "enacs", "smln", "rmln", "kbeg", "kcan", "kclo",
  219.       "kcmd", "kcpy", "kcrt", "kend", "kent", "kext", "kfnd", "khlp",
  220.       "kmrk", "kmsg", "kmov", "knxt", "kopn", "kopt", "kprv", "kprt",
  221.       "krdo", "kref", "krfr", "krpl", "krst", "kres", "ksav", "kspd",
  222.       "kund", "kBEG", "kCAN", "kCMD", "kCPY", "kCRT", "kDC", "kDL",
  223.       "kslt", "kEND", "kEOL", "kEXT", "kFND", "kHLP", "kHOM", "kIC",
  224.       "kLFT", "kMSG", "kMOV", "kNXT", "kOPT", "kPRV", "kPRT", "kRDO",
  225.       "kRPL", "kRIT", "kRES", "kSAV", "kSPD", "kUND", "rfi", "kf11",
  226.       "kf12", "kf13", "kf14", "kf15", "kf16", "kf17", "kf18", "kf19",
  227.       "kf20", "kf21", "kf22", "kf23", "kf24", "kf25", "kf26", "kf27",
  228.       "kf28", "kf29", "kf30", "kf31", "kf32", "kf33", "kf34", "kf35",
  229.       "kf36", "kf37", "kf38", "kf39", "kf40", "kf41", "kf42", "kf43",
  230.       "kf44", "kf45", "kf46", "kf47", "kf48", "kf49", "kf50", "kf51",
  231.       "kf52", "kf53", "kf54", "kf55", "kf56", "kf57", "kf58", "kf59",
  232.       "kf60", "kf61", "kf62", "kf63", "el1", "mgc", "smgl", "smgr",
  233.       "fln", "sclk", "dclk", "rmclk", "cwin", "wingo", "hup", "dial",
  234.       "qdial", "tone", "pulse", "hook", "pause", "wait", "u0", "u1",
  235.       "u2", "u3", "u4", "u5", "u6", "u7", "u8", "u9"
  236. #endif    /* SYSVR3 */
  237. #ifdef HPUX5
  238.       , "meml", "memu"
  239. #endif    /* HPUX5 */
  240.       };
  241. #define    STR_LENGTH    (sizeof(Strings) / sizeof(char *))
  242.  
  243. char    *Exceptions[] =
  244.     { "912b", "912cc", "920b", "adm5", "d800", "dtc", "f1720", "fortune",
  245.       "hp", "hp110", "intext", "ofos", "pe1251", "regent100", "regent40",
  246.       "regent40-s", "regent60", "regent60-na", "sb1", "sb2", "sbi",
  247.       "smartvid", "t1061", "t1061f", "tec400", "trs16", "tvi2p", "tvi803",
  248.       "tvi912", "tvi912-2p", "tvi9122p", "tvi9202p", "tvi925", "tvi925-v",
  249.       "tvi950", "tvi950-2p", "tvi950-4p", "tvi950-ap", "tvi950-b",
  250.       "tvi950-ns", "tvi950-rv", "tvi950-rv-2p", "tvi950-rv-4p",
  251.       "tvi9502p", "tvi9504p", "tvi950b", "tvi950ns", "tvi950rv",
  252.       "tvi950rv2p", "tvi950rv4p", "vt100-nav", "vt100-nav-w", "xtalk",
  253.       "ya", NULL
  254.     };
  255.  
  256. /***
  257.  ***    Function definitions
  258.  ***/
  259.  
  260. void
  261. main(argc, argv)
  262.   int    argc;            /* Number of paramters            */
  263.   char    *argv[];        /* The parameters themselves        */
  264.     {
  265.     char subdir[2];        /* Subdirectory name            */
  266.     FILE *file;
  267.     char *terminfo;
  268.     extern FILE *fopen();
  269.     extern char *getenv();
  270.  
  271.     /* Change directory to the working directory            */
  272.     terminfo = getenv("TERMINFO");
  273.     if (terminfo == NULL) {
  274.      terminfo = TERMINFO_DIR;
  275.     }
  276. #if DEBUG
  277.     fprintf(stderr, "Looking in %s/?/... for entry.\n", terminfo);
  278. #endif
  279.     (void)chdir(terminfo);
  280.  
  281.     /* Go through the arguments                        */
  282.     subdir[1] = '\0';
  283.     if (argc == 1)
  284.     convert(stdin, "stdin");
  285.     else
  286.     {
  287.     while (--argc)
  288.         {
  289.         ++argv;
  290.         subdir[0] = argv[0][0];
  291.         (void)chdir(subdir);
  292.         if ((file = fopen(*argv, OPEN_MODE)) == NULL)
  293.         {
  294.         perror(*argv);
  295.         }
  296.         else
  297.         {
  298.         convert(file, *argv);
  299.         (void)fclose(file);
  300.         }
  301.         (void)chdir("..");
  302.         }
  303.     }
  304.     exit(0);
  305.     }
  306.  
  307.  
  308. /*
  309.  * Addchar -- Add a character
  310.  */
  311. char *
  312. addchar(cptr, ch)
  313.   char    *cptr;
  314.   int    ch;
  315.     {
  316.     char *addstr(), *addoctal();
  317.  
  318.     if (ch == '\0')
  319.     return (addstr(cptr, "\\200"));
  320.     if (ch == 0x1B)
  321.     return (addstr(cptr, "\\E"));
  322.     if (ch == '\n')
  323.     return (addstr(cptr, "\\n"));
  324.     if (ch == '\r')
  325.     return (addstr(cptr, "\\r"));
  326.     if (ch == '\t')
  327.     return (addstr(cptr, "\\t"));
  328.     if (ch == '\b')
  329.     return (addstr(cptr, "\\b"));
  330.     if (ch == '\f')
  331.     return (addstr(cptr, "\\f"));
  332.     if (ch == ' ')
  333.     return (addstr(cptr, "\\s"));
  334.     if (ch == '^')
  335.     return (addstr(cptr, "\\^"));
  336.     if (ch == '\\')
  337.     return (addstr(cptr, "\\\\"));
  338.     if (ch == ',')
  339.     return (addstr(cptr, "\\,"));
  340.     if (ch == 0x7F)
  341.     return (addstr(cptr, "\^?"));
  342.     if (ch >= ('A' - '@') && ch <= ('_' - '@'))
  343.     {
  344.     *cptr++ = '^';
  345.     *cptr++ = ch + '@';
  346.     return (cptr);
  347.     }
  348.     if (ch > 0x7F)
  349.         return (addoctal(cptr, ch));
  350.     *cptr++ = ch;
  351.     return (cptr);
  352.     }
  353.  
  354.  
  355. /*
  356.  * Addoctal -- Add an octal character
  357.  *
  358.  * Use sprintf just in case "0" through "7" are not contiguous.  Some
  359.  * machines are weird.
  360.  */
  361. char *
  362. addoctal(cptr, ch)
  363.   char    *cptr;
  364.   int    ch;
  365.     {
  366.     char *addstr();
  367.  
  368.     ch &= 0xFF;
  369.  
  370.     if (ch == 0x80)
  371.     return (addstr(cptr, "\\200"));
  372.     (void)sprintf(cptr, "\\%03o", ch);
  373.     while (*cptr != '\0')
  374.     cptr++;
  375.     return (cptr);
  376.     }
  377.  
  378.  
  379. /*
  380.  * Addstr -- Add a string to the capability
  381.  */
  382. char *
  383. addstr(cptr, str)
  384.   char    *cptr, *str;
  385.     {
  386.     while (*str)
  387.     *cptr++ = *str++;
  388.     return (cptr);
  389.     }
  390.  
  391.  
  392. /*
  393.  * Convert -- Do the actual conversion
  394.  */
  395. void
  396. convert(file, name)
  397.   FILE    *file;        /* The file with the compiled information    */
  398.   char    *name;        /* Printable version of the filename        */
  399.     {
  400.     int    ch, val, i, j;
  401.     int name_length, bool_length, num_length, str_length, s_length;
  402.     char capability[MAX_CAP+1], *cptr, *addchar();
  403.     char **scan;
  404.     char term_name[80];
  405.     int str_cap[STR_LENGTH];
  406.  
  407.     /* Check the magic number out                    */
  408.     if (get2(file) != MAGIC)
  409.     {
  410.     fprintf(stderr, "\"%s\" is not a terminfo file\n", name);
  411.     return;
  412.     }
  413.  
  414.     /* Get the rest of the header information                */
  415.     name_length = get2(file);    /* Get the length of the terminal names    */
  416.     bool_length = get2(file);    /* Get the length of the booleans    */
  417.     num_length = get2(file);    /* Get the length of the numerics    */
  418.     str_length = get2(file);    /* Get the length of the strings    */
  419.     s_length = get2(file);    /* Get the length of the string tables    */
  420.  
  421.     /* Time to get real information                    */
  422.     cptr = term_name;
  423.     while ((ch = getc(file)) != '\0' && ch != EOF)
  424.     {
  425.     if (cptr != NULL)
  426.         {
  427.         if (ch == '|')
  428.         {
  429.         *cptr = '\0';
  430.         cptr = NULL;
  431.         }
  432.         else
  433.         *cptr++ = ch;
  434.         }
  435.     putchar(ch);
  436.     }
  437.     if (cptr != NULL)
  438.     *cptr = '\0';
  439.     printf(",\n");
  440.  
  441.     /* Send out the non-null boolean variables                */
  442.     Line_len = 0;
  443.     for (i = 0; i < bool_length; i++)
  444.     {
  445.     if ((ch = getc(file)) != 0)
  446.         {
  447.         if (i < BOOL_LENGTH)
  448.         emit(Booleans[i]);
  449.         else
  450.         fprintf(stderr, "Undefined boolean capability #%d\n", i);
  451.         }
  452.     }
  453.     emit((char *) NULL);    /* Force output */
  454.  
  455.     /* The rest of the file is on a 16 bit boundary, so adjust the file    */
  456.     if ((name_length + bool_length) & 0x01)
  457.     (void)getc(file);
  458.  
  459. #ifdef STRICT_TERMINFO_COMPATIBILITY
  460.     /* Bozo alert!!!  It appears that there is special code in infocmp to
  461.      * put out ma#1 if this is a special terminfo file.  Presumably this
  462.      * is a good default.  Definitately odd.
  463.      */
  464.     for (scan = Exceptions;
  465.             *scan != NULL && strcmp(*scan, term_name) != 0; scan++)
  466.     ;
  467.     if (*scan != NULL)
  468.     emit("ma#1");
  469.     /* End bozo alert */
  470. #endif    /* STRICT_TERMINFO_COMPATIBILITY */
  471.  
  472.     /* Get the numeric variables                    */
  473.     for (i = 0; i < num_length; i++)
  474.     {
  475.     if ((val = get2(file)) != 0xFFFF)
  476.         {
  477.         if (i < NUM_LENGTH)
  478.         {
  479.         (void)sprintf(capability, "%s#%d", Numerics[i], val);
  480.         emit(capability);
  481.         }
  482.         else
  483.         {
  484.         fprintf(stderr, "Undefined numeric capability #%d (%d)\n",
  485.                         i, val);
  486.         }
  487.         }
  488.     }
  489.     emit((char *) NULL);    /* Force output */
  490.  
  491.     /* Get the string variables offsets                    */
  492.     for (i = 0; i < str_length; i++)
  493.     str_cap[i] = get2(file);
  494.  
  495.     /* Get the string variables themselves                */
  496.     for (i = 0; i < s_length; i++)
  497.     {
  498.     for (j = 0; j < str_length; j++)    /* Find the name    */
  499.         if (str_cap[j] == i)
  500.         break;
  501.     if (j >= str_length)
  502.         {
  503. #if DEBUG
  504.         fprintf(stderr, "Cannot find address %d\n", i);
  505. #endif        /* DEBUG */
  506.         (void)getc(file);
  507.         continue;
  508.         }
  509.     if (j < STR_LENGTH)
  510.         (void)strcpy(capability, Strings[j]);
  511.     else
  512.         (void) strcpy(capability, "OOPS");
  513.     cptr = &capability[strlen(capability)];
  514.     *cptr++ = '=';
  515.     for (; (ch = getc(file)) != '\0' && ch != EOF; i++)
  516.         cptr = addchar(cptr, ch);
  517.     *cptr = '\0';
  518.     emit(capability);
  519.     if (j >= STR_LENGTH)
  520.         {
  521.         fprintf(stderr, "Undefined string capability #%d (%s)\n",
  522.                             j, &capability[5]);
  523.         }
  524.     }
  525.     emit((char *) NULL);    /* Force output */
  526.     }
  527.  
  528.  
  529. /*
  530.  * Emit -- Emit the string
  531.  *
  532.  * Emit the given string, and append a comma.  If the line gets too long,
  533.  * send out a newline and a tab.
  534.  *
  535.  * In order to make the output to be more directly comparable to infocmp,
  536.  * save up all of the output for a category, sort it, and then write it out.
  537.  */
  538. void
  539. emit(str)
  540.   char    *str;        /* String to emit                */
  541.     {
  542. #ifdef SIMPLE_OUTPUT
  543.     if (str == NULL)
  544.     {
  545.     Line_len = 0;
  546.     printf("\n");
  547.     }
  548.     else
  549.     {
  550.     if (Line_len == 0)
  551.         printf("\t");
  552.     if ((Line_len += strlen(str) + 2) > MAXLINE)
  553.         {
  554.         Line_len = strlen(str) + 2;
  555.         printf("\n\t");
  556.         }
  557.     printf("%s, ", str);
  558.     }
  559. #else    /* SIMPLE_OUTPUT */
  560.     /* Array is over large, but will be enough */
  561.     static char        *table[STR_LENGTH + BOOL_LENGTH + NUM_LENGTH];
  562.     static int        next = 0;
  563.  
  564.     int            len;
  565.     int            scan;
  566.  
  567.     if (str != NULL)
  568.     {
  569.     if ((table[next] = (char *) malloc(strlen(str) + 1)) == NULL)
  570.         {
  571.         fprintf(stderr, "OUT OF MEMORY\n");
  572.         exit(1);
  573.         }
  574.     strcpy(table[next++], str);
  575.     }
  576.     else if (next > 0)
  577.     {
  578.     /* strcmp isn't quite the right type, but should work */
  579.     qsort(table, next, sizeof(char *), xstrcmp);
  580.     printf("\t");
  581.     for (Line_len = scan = 0; scan < next; scan++)
  582.         {
  583.         len = strlen(table[scan]) + 2;
  584.         if ((Line_len += len) > MAXLINE)
  585.         {
  586.         Line_len = len;
  587.         printf("\n\t");
  588.         }
  589.         else if (Line_len != len)
  590.         printf(" ");
  591.         printf("%s,", table[scan]);
  592.         free(table[scan]);
  593.         }
  594.     printf("\n");
  595.     next = 0;
  596.     }
  597. #endif    /* SIMPLE_OUTPUT */
  598.     }
  599.  
  600.  
  601. /*
  602.  * Get2 -- Get a two byte number
  603.  */
  604. unsigned short
  605. get2(file)
  606.   FILE *file;        /* The file with the compiled information    */
  607.     {
  608.     unsigned short        temp;
  609.  
  610.     temp = getc(file) & 0xFF;
  611.     return (temp + (getc(file) << 8));
  612.     }
  613.  
  614.  
  615. /*
  616.  * Xstrcmp -- Compare function for qsort
  617.  *
  618.  * Infocmp only compares the base string.  Strip of equals signs.
  619.  * This routine is an awful hack.  There is probably a more elegant
  620.  * way of doing this with standard routines.  One possibility would
  621.  * be to put a NUL at a possible '=', and restore it later (if one was
  622.  * destroyed).  Call strcmp in between.
  623.  */
  624. int
  625. xstrcmp(a, b)
  626.   CVPTR            *a;
  627.   CVPTR            *b;
  628.     {
  629.     char        *str1, *str2;
  630.  
  631.     str1 = *(char **) a;
  632.     str2 = *(char **) b;
  633.  
  634.     while (*str1 != '\0' && *str1 != '=' &&
  635.        *str2 != '\0' && *str2 != '=' &&
  636.        *str1 == *str2)
  637.     {
  638.     str1++;
  639.     str2++;
  640.     }
  641.     if ((*str1 == '\0' || *str1 == '=') &&
  642.                 (*str2 == '\0' || *str2 == '='))
  643.     return (0);
  644.     if (*str1 == '\0' || *str1 == '=')
  645.     return (-1);
  646.     if (*str2 == '\0' || *str2 == '=')
  647.     return (1);
  648.     return (*str1 - *str2);
  649.     }
  650.  
  651.