]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - test/demo_termcap.c
ncurses 5.9 - patch 20150307
[ncurses.git] / test / demo_termcap.c
index b36ba96cc9872e36adebb8cf040e2884b23bf7bb..2a29266f6bb50ef3b6fe0eff0a4776e9a4c33243 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
 /****************************************************************************
- * Copyright (c) 2005-2008,2009 Free Software Foundation, Inc.              *
+ * Copyright (c) 2005-2013,2014 Free Software Foundation, Inc.              *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
 /*
  * Author: Thomas E. Dickey
  *
 /*
  * Author: Thomas E. Dickey
  *
- * $Id: demo_termcap.c,v 1.11 2009/08/02 00:02:53 tom Exp $
+ * $Id: demo_termcap.c,v 1.46 2014/10/10 00:35:43 tom Exp $
  *
  * A simple demo of the termcap interface.
  */
 #define USE_TINFO
 #include <test.priv.h>
  *
  * A simple demo of the termcap interface.
  */
 #define USE_TINFO
 #include <test.priv.h>
+#include <sys/stat.h>
+
+#if NCURSES_XNAMES
+#if HAVE_TERM_ENTRY_H
+#include <term_entry.h>
+#else
+#undef NCURSES_XNAMES
+#define NCURSES_XNAMES 0
+#endif
+#endif
+
+static void
+failed(const char *msg)
+{
+    fprintf(stderr, "%s\n", msg);
+    ExitProgram(EXIT_FAILURE);
+}
 
 #if HAVE_TGETENT
 
 
 #if HAVE_TGETENT
 
 #define FCOLS 8
 #define FNAME(type) "%s %-*s = ", #type, FCOLS
 
 #define FCOLS 8
 #define FNAME(type) "%s %-*s = ", #type, FCOLS
 
-#if USE_CODE_LISTS
 static bool b_opt = FALSE;
 static bool n_opt = FALSE;
 static bool s_opt = FALSE;
 static bool b_opt = FALSE;
 static bool n_opt = FALSE;
 static bool s_opt = FALSE;
-#endif
+static bool q_opt = FALSE;
+static bool x_opt = FALSE;
+static bool y_opt = FALSE;
+
+static char *d_opt;
+static char *e_opt;
+static char **db_list;
+static int db_item;
+
+static char *my_blob;
+static char **my_boolcodes;
+static char **my_numcodes;
+static char **my_numvalues;
+static char **my_strcodes;
+static char **my_strvalues;
+
+static long total_values;
+static long total_b_values;
+static long total_n_values;
+static long total_s_values;
+
+#define isCapName(c) (isgraph(c) && strchr("^=:\\", c) == 0)
+#define EachCapName(n) n = 33; n < 127; ++n
+
+static char *
+make_dbitem(char *p, char *q)
+{
+    char *result = malloc(strlen(e_opt) + 2 + (size_t) (p - q));
+    sprintf(result, "%s=%.*s", e_opt, (int) (p - q), q);
+    return result;
+}
+
+static void
+make_dblist(void)
+{
+    if (d_opt && e_opt) {
+       int pass;
+
+       for (pass = 0; pass < 2; ++pass) {
+           char *p, *q;
+           size_t count = 0;
+
+           for (p = q = d_opt; *p != '\0'; ++p) {
+               if (*p == ':') {
+                   if (p != q + 1) {
+                       if (pass) {
+                           db_list[count] = make_dbitem(p, q);
+                       }
+                       count++;
+                   }
+                   q = p + 1;
+               }
+           }
+           if (p != q + 1) {
+               if (pass) {
+                   db_list[count] = make_dbitem(p, q);
+               }
+               count++;
+           }
+           if (!pass) {
+               db_list = typeCalloc(char *, count + 1);
+           }
+       }
+    }
+}
 
 
-#define isCapName(c) (isgraph(c) && strchr("^#=:\\", c) == 0)
+static char *
+next_dbitem(void)
+{
+    char *result = 0;
+
+    if (db_list) {
+       if ((result = db_list[db_item]) == 0) {
+           db_item = 0;
+           result = db_list[0];
+       } else {
+           db_item++;
+       }
+    }
+    printf("** %s\n", result);
+    return result;
+}
+
+static void
+free_dblist(void)
+{
+    if (db_list) {
+       int n;
+       for (n = 0; db_list[n]; ++n)
+           free(db_list[n]);
+       free(db_list);
+       db_list = 0;
+    }
+}
 
 static void
 dumpit(NCURSES_CONST char *cap)
 
 static void
 dumpit(NCURSES_CONST char *cap)
@@ -70,66 +177,80 @@ dumpit(NCURSES_CONST char *cap)
     int num;
 
     if ((str = tgetstr(cap, &ap)) != 0) {
     int num;
 
     if ((str = tgetstr(cap, &ap)) != 0) {
-       /*
-        * Note that the strings returned are mostly terminfo format, since
-        * ncurses does not convert except for a handful of special cases.
-        */
-       printf(FNAME(str), cap);
-       while (*str != 0) {
-           int ch = UChar(*str++);
-           switch (ch) {
-           case '\177':
-               fputs("^?", stdout);
-               break;
-           case '\033':
-               fputs("\\E", stdout);
-               break;
-           case '\b':
-               fputs("\\b", stdout);
-               break;
-           case '\f':
-               fputs("\\f", stdout);
-               break;
-           case '\n':
-               fputs("\\n", stdout);
-               break;
-           case '\r':
-               fputs("\\r", stdout);
-               break;
-           case ' ':
-               fputs("\\s", stdout);
-               break;
-           case '\t':
-               fputs("\\t", stdout);
-               break;
-           case '^':
-               fputs("\\^", stdout);
-               break;
-           case ':':
-               fputs("\\072", stdout);
-               break;
-           case '\\':
-               fputs("\\\\", stdout);
-               break;
-           default:
-               if (isgraph(ch))
-                   fputc(ch, stdout);
-               else if (ch < 32)
-                   printf("^%c", ch + '@');
-               else
-                   printf("\\%03o", ch);
-               break;
+       total_values++;
+       total_s_values++;
+       if (!q_opt) {
+           /*
+            * Note that the strings returned are mostly terminfo format, since
+            * ncurses does not convert except for a handful of special cases.
+            */
+           printf(FNAME(str), cap);
+           while (*str != 0) {
+               int ch = UChar(*str++);
+               switch (ch) {
+               case '\177':
+                   fputs("^?", stdout);
+                   break;
+               case '\033':
+                   fputs("\\E", stdout);
+                   break;
+               case '\b':
+                   fputs("\\b", stdout);
+                   break;
+               case '\f':
+                   fputs("\\f", stdout);
+                   break;
+               case '\n':
+                   fputs("\\n", stdout);
+                   break;
+               case '\r':
+                   fputs("\\r", stdout);
+                   break;
+               case ' ':
+                   fputs("\\s", stdout);
+                   break;
+               case '\t':
+                   fputs("\\t", stdout);
+                   break;
+               case '^':
+                   fputs("\\^", stdout);
+                   break;
+               case ':':
+                   fputs("\\072", stdout);
+                   break;
+               case '\\':
+                   fputs("\\\\", stdout);
+                   break;
+               default:
+                   if (isgraph(ch))
+                       fputc(ch, stdout);
+                   else if (ch < 32)
+                       printf("^%c", ch + '@');
+                   else
+                       printf("\\%03o", ch);
+                   break;
+               }
            }
            }
+           printf("\n");
        }
        }
-       printf("\n");
     } else if ((num = tgetnum(cap)) >= 0) {
     } else if ((num = tgetnum(cap)) >= 0) {
-       printf(FNAME(num), cap);
-       printf(" %d\n", num);
-    } else if ((num = tgetflag(cap)) > 0) {
-       printf(FNAME(flg), cap);
-       printf("%s\n", "true");
+       total_values++;
+       total_n_values++;
+       if (!q_opt) {
+           printf(FNAME(num), cap);
+           printf(" %d\n", num);
+       }
+    } else if (tgetflag(cap) > 0) {
+       total_values++;
+       total_b_values++;
+       if (!q_opt) {
+           printf(FNAME(flg), cap);
+           printf("%s\n", "true");
+       }
     }
     }
-    fflush(stdout);
+
+    if (!q_opt)
+       fflush(stdout);
 }
 
 static void
 }
 
 static void
@@ -137,17 +258,21 @@ brute_force(const char *name)
 {
     char buffer[1024];
 
 {
     char buffer[1024];
 
-    printf("Terminal type %s\n", name);
+    if (db_list) {
+       putenv(next_dbitem());
+    }
+    if (!q_opt)
+       printf("Terminal type \"%s\"\n", name);
     if (tgetent(buffer, name) >= 0) {
        char cap[3];
        int c1, c2;
 
        cap[2] = 0;
     if (tgetent(buffer, name) >= 0) {
        char cap[3];
        int c1, c2;
 
        cap[2] = 0;
-       for (c1 = 0; c1 < 256; ++c1) {
-           cap[0] = c1;
+       for (EachCapName(c1)) {
+           cap[0] = (char) c1;
            if (isCapName(c1)) {
            if (isCapName(c1)) {
-               for (c2 = 0; c2 < 256; ++c2) {
-                   cap[1] = c2;
+               for (EachCapName(c2)) {
+                   cap[1] = (char) c2;
                    if (isCapName(c2)) {
                        dumpit(cap);
                    }
                    if (isCapName(c2)) {
                        dumpit(cap);
                    }
@@ -157,50 +282,422 @@ brute_force(const char *name)
     }
 }
 
     }
 }
 
-#if USE_CODE_LISTS
+#if NCURSES_XNAMES
 static void
 static void
-demo_terminfo(NCURSES_CONST char *name)
+dump_xname(NCURSES_CONST char *cap)
+{
+    if (strlen(cap) == 2)
+       dumpit(cap);
+}
+#endif
+
+static void
+demo_termcap(NCURSES_CONST char *name)
 {
     unsigned n;
     NCURSES_CONST char *cap;
 {
     unsigned n;
     NCURSES_CONST char *cap;
+    char buffer[1024];
 
 
-    printf("Terminal type \"%s\"\n", name);
-    setupterm(name, 1, (int *) 0);
+    if (db_list) {
+       putenv(next_dbitem());
+    }
+    if (!q_opt)
+       printf("Terminal type \"%s\"\n", name);
+    if (tgetent(buffer, name) >= 0) {
 
 
-    if (b_opt) {
-       for (n = 0;; ++n) {
-           cap = boolcodes[n];
-           if (cap == 0)
-               break;
-           dumpit(cap);
+       if (b_opt) {
+           for (n = 0;; ++n) {
+               cap = my_boolcodes[n];
+               if (cap == 0)
+                   break;
+               dumpit(cap);
+           }
+       }
+
+       if (n_opt) {
+           for (n = 0;; ++n) {
+               cap = my_numcodes[n];
+               if (cap == 0)
+                   break;
+               dumpit(cap);
+           }
+       }
+
+       if (s_opt) {
+           for (n = 0;; ++n) {
+               cap = my_strcodes[n];
+               if (cap == 0)
+                   break;
+               dumpit(cap);
+           }
+       }
+#ifdef NCURSES_VERSION
+       if (x_opt && (my_blob == 0) && y_opt) {
+#if NCURSES_XNAMES
+           TERMTYPE *term = &(cur_term->type);
+           if (term != 0
+               && ((NUM_BOOLEANS(term) != BOOLCOUNT)
+                   || (NUM_NUMBERS(term) != NUMCOUNT)
+                   || (NUM_STRINGS(term) != STRCOUNT))) {
+               for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
+                   dump_xname(ExtBoolname(term, (int) n, boolnames));
+               }
+               for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
+                   dump_xname(ExtNumname(term, (int) n, numnames));
+               }
+               for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
+                   dump_xname(ExtStrname(term, (int) n, strnames));
+               }
+           }
+#endif
        }
        }
+#endif
     }
     }
+}
+
+typedef enum {
+    pDefault = 0
+    ,pComment
+    ,pDescription
+    ,pEscaped
+    ,pNewline
+    ,pName
+    ,pNumber
+    ,pString
+} STATE;
+
+static void
+parse_description(const char *input_name)
+{
+    static char empty[1];
 
 
-    if (n_opt) {
-       for (n = 0;; ++n) {
-           cap = numcodes[n];
-           if (cap == 0)
+    FILE *fp;
+    struct stat sb;
+    size_t count_bools = 0;
+    size_t count_nums = 0;
+    size_t count_strs = 0;
+    size_t len;
+    size_t j, k;
+    STATE state;
+
+    if (stat(input_name, &sb) != 0
+       || (sb.st_mode & S_IFMT) != S_IFREG) {
+       failed("input is not a file");
+    }
+
+    if (sb.st_size == 0) {
+       failed("input is empty");
+    }
+
+    /*
+     * None of the arrays could be larger than the input-file, and since it
+     * is small, just allocate the maximum for simplicity.
+     */
+    if ((my_blob = malloc((size_t) sb.st_size + 1)) == 0 ||
+       (my_boolcodes = typeCalloc(char *, sb.st_size)) == 0 ||
+         (my_numcodes = typeCalloc(char *, sb.st_size)) == 0 ||
+         (my_numvalues = typeCalloc(char *, sb.st_size)) == 0 ||
+         (my_strcodes = typeCalloc(char *, sb.st_size)) == 0 ||
+         (my_strvalues = typeCalloc(char *, sb.st_size)) == 0) {
+       failed("cannot allocate memory for input-file");
+    }
+
+    if ((fp = fopen(input_name, "r")) == 0)
+       failed("cannot open input-file");
+    len = fread(my_blob, sizeof(char), (size_t) sb.st_size, fp);
+    my_blob[sb.st_size] = '\0';
+    fclose(fp);
+
+    /*
+     * First, get rid of comments and escaped newlines, as well as repeated
+     * colons to construct a canonical entry.
+     *
+     * FIXME: actually this should make an additional pass just to strip
+     * comment-lines and escaped newlines.  But it is workable for infocmp
+     * output.
+     */
+    state = pNewline;
+    for (j = k = 0; j < len; ++j) {
+       int ch = my_blob[j];
+       if (ch == '\t') {
+           ch = ' ';
+       }
+       switch (state) {
+       case pNewline:
+           if (ch == ' ') {
+               continue;
+           }
+           if (ch == '#') {
+               state = pComment;
+               continue;
+           }
+           state = pDefault;
+           /* FALLTHRU */
+       case pDefault:
+           switch (ch) {
+           case '|':
+               state = pDescription;
+               continue;
+           case '\\':
+               state = pEscaped;
+               continue;
+           case '\n':
+               state = pNewline;
+               continue;
+           case ' ':
+           case ':':
                break;
                break;
-           dumpit(cap);
+           default:
+               state = pName;
+               break;
+           }
+           my_blob[k++] = (char) ch;
+           break;
+       case pComment:
+           if (ch == '\n')
+               state = pNewline;
+           break;
+       case pDescription:
+           switch (ch) {
+           case ':':
+               state = pDefault;
+               break;
+           case '\n':
+               state = pNewline;
+               break;
+           }
+           break;
+       case pEscaped:
+           if (ch != '\n') {
+               my_blob[k++] = (char) ch;
+               state = pDefault;
+           } else {
+               state = pNewline;
+           }
+           break;
+       case pName:
+           switch (ch) {
+           case '\n':
+               state = pNewline;
+               continue;
+           case ' ':
+           case ':':
+               state = pDefault;
+               break;
+           case '#':
+               state = pNumber;
+               break;
+           case '|':
+               state = pDescription;
+               continue;
+           }
+           my_blob[k++] = (char) ch;
+           break;
+       case pNumber:
+           switch (ch) {
+           case '\n':
+               state = pNewline;
+               continue;
+           case ':':
+               state = pDefault;
+               break;
+           case ' ':
+               state = pDefault;
+               continue;
+           }
+           my_blob[k++] = (char) ch;
+           break;
+       case pString:
+           switch (ch) {
+           case '\\':
+               if (my_blob[j + 1] == '\0') {
+                   state = pDefault;
+                   continue;
+               }
+               break;
+           case '\n':
+               state = pNewline;
+               continue;
+           case ':':
+               state = pDefault;
+               break;
+           }
+           my_blob[k++] = (char) ch;
+           break;
+       default:
+           /* not used */
+           break;
        }
     }
        }
     }
+    my_blob[k] = '\0';
 
 
-    if (s_opt) {
-       for (n = 0;; ++n) {
-           cap = strcodes[n];
-           if (cap == 0)
+    /*
+     * Then, parse what's left, making indexes of the names and values.
+     */
+    state = pDefault;
+    for (j = 0; my_blob[j] != '\0'; ++j) {
+       switch (state) {
+       case pDefault:
+           switch (my_blob[j]) {
+           case '\\':
+               state = pEscaped;
                break;
                break;
-           dumpit(cap);
+           case ':':
+               my_blob[j] = '\0';
+               if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ':')
+                   state = pName;
+               break;
+           case ' ':
+               break;
+           default:
+               break;
+           }
+       case pEscaped:
+           break;
+       case pName:
+           state = pDefault;
+           /*
+            * Commented-out capabilities might be accessible (they are in
+            * ncurses).
+            */
+           if (my_blob[j] == '.' && my_blob[j + 1] == '.') {
+               j += 2;
+           }
+           if (my_blob[j + 1] != '\0') {
+               switch (my_blob[j + 2]) {
+               case '#':
+                   my_numvalues[count_nums] = &my_blob[j + 3];
+                   my_numcodes[count_nums++] = &my_blob[j];
+                   my_blob[j + 2] = '\0';
+                   state = pNumber;
+                   j += 2;
+                   break;
+               case '=':
+                   my_strvalues[count_strs] = &my_blob[j + 3];
+                   my_strcodes[count_strs++] = &my_blob[j];
+                   my_blob[j + 2] = '\0';
+                   state = pString;
+                   j += 2;
+                   break;
+               default:
+                   if (my_blob[j + 2] == '@') {
+                       /*
+                        * We cannot get the type for a cancelled item
+                        * directly, but can infer it assuming the input
+                        * came from infocmp, which puts the data in a
+                        * known order.
+                        */
+                       if (count_strs) {
+                           my_strvalues[count_strs] = empty;
+                           my_strcodes[count_strs++] = &my_blob[j];
+                       } else if (count_nums) {
+                           my_numvalues[count_nums] = empty;
+                           my_numcodes[count_nums++] = &my_blob[j];
+                       } else {
+                           my_boolcodes[count_bools++] = &my_blob[j];
+                       }
+                   } else {
+                       my_boolcodes[count_bools++] = &my_blob[j];
+                   }
+                   j++;
+                   break;
+               }
+           }
+           break;
+       case pNumber:
+           if (!isdigit(UChar(my_blob[j]))) {
+               --j;
+               state = pDefault;
+           }
+           break;
+       case pString:
+           switch (my_blob[j]) {
+           case '\\':
+               if (my_blob[j + 1] == '\0') {
+                   state = pDefault;
+                   continue;
+               } else {
+                   ++j;
+               }
+               break;
+           case '\n':
+               state = pNewline;
+               continue;
+           case ':':
+               --j;
+               state = pDefault;
+               break;
+           }
+           break;
+       case pNewline:
+       case pComment:
+       case pDescription:
+       default:
+           break;
        }
     }
        }
     }
+    my_boolcodes[count_bools] = 0;
+    my_numcodes[count_nums] = 0;
+    my_numvalues[count_nums] = 0;
+    my_strcodes[count_strs] = 0;
+    my_strvalues[count_strs] = 0;
+
+#if 0
+    printf("bools:%d\n", (int) count_bools);
+    for (j = 0; my_boolcodes[j]; ++j)
+       printf("%5d:%s\n", (int) j, my_boolcodes[j]);
+
+    printf("numbers:%d\n", (int) count_nums);
+    for (j = 0; my_numcodes[j]; ++j)
+       printf("%5d:%s(%s)\n", (int) j, my_numcodes[j], my_numvalues[j]);
+
+    printf("strings:%d\n", (int) count_strs);
+    for (j = 0; my_strcodes[j]; ++j)
+       printf("%5d:%s(%s)\n", (int) j, my_strcodes[j], my_strvalues[j]);
+#endif
 }
 
 }
 
+#if USE_CODE_LISTS
+static char **
+copy_code_list(NCURSES_CONST char *const *list)
+{
+    int pass;
+    size_t count;
+    size_t length = 1;
+    char **result = 0;
+    char *blob = 0;
+    char *unused = 0;
+
+    for (pass = 0; pass < 2; ++pass) {
+       for (count = 0; list[count] != 0; ++count) {
+           size_t chunk = strlen(list[count]) + 1;
+           if (pass == 0) {
+               length += chunk;
+           } else {
+               result[count] = unused;
+               strcpy(unused, list[count]);
+               unused += chunk;
+           }
+       }
+       if (pass == 0) {
+           blob = malloc(length);
+           result = typeCalloc(char *, count + 1);
+           unused = blob;
+           if (blob == 0 || result == 0)
+               failed("copy_code_list failed");
+       }
+    }
+
+    return result;
+}
+#endif
+
 static void
 usage(void)
 {
     static const char *msg[] =
     {
 static void
 usage(void)
 {
     static const char *msg[] =
     {
-       "Usage: demo_terminfo [options] [terminal]",
+       "Usage: demo_termcap [options] [terminal]",
        "",
        "If no options are given, print all (boolean, numeric, string)",
        "capabilities for the given terminal, using short names.",
        "",
        "If no options are given, print all (boolean, numeric, string)",
        "capabilities for the given terminal, using short names.",
@@ -208,9 +705,16 @@ usage(void)
        "Options:",
        " -a       try all names, print capabilities found",
        " -b       print boolean-capabilities",
        "Options:",
        " -a       try all names, print capabilities found",
        " -b       print boolean-capabilities",
+       " -d LIST  colon-separated list of databases to use",
+       " -e NAME  environment variable to set with -d option",
+       " -i NAME  terminal description to use as names for \"-a\" option, etc.",
        " -n       print numeric-capabilities",
        " -n       print numeric-capabilities",
+       " -q       quiet (prints only counts)",
        " -r COUNT repeat for given count",
        " -s       print string-capabilities",
        " -r COUNT repeat for given count",
        " -s       print string-capabilities",
+#ifdef NCURSES_VERSION
+       " -x       print extended capabilities",
+#endif
     };
     unsigned n;
     for (n = 0; n < SIZEOF(msg); ++n) {
     };
     unsigned n;
     for (n = 0; n < SIZEOF(msg); ++n) {
@@ -218,7 +722,6 @@ usage(void)
     }
     ExitProgram(EXIT_FAILURE);
 }
     }
     ExitProgram(EXIT_FAILURE);
 }
-#endif
 
 int
 main(int argc, char *argv[])
 
 int
 main(int argc, char *argv[])
@@ -226,12 +729,12 @@ main(int argc, char *argv[])
     int n;
     char *name;
     bool a_opt = FALSE;
     int n;
     char *name;
     bool a_opt = FALSE;
+    char *input_name = 0;
 
 
-#if USE_CODE_LISTS
     int repeat;
     int r_opt = 1;
 
     int repeat;
     int r_opt = 1;
 
-    while ((n = getopt(argc, argv, "abnr:s")) != -1) {
+    while ((n = getopt(argc, argv, "abd:e:i:nqr:sxy")) != -1) {
        switch (n) {
        case 'a':
            a_opt = TRUE;
        switch (n) {
        case 'a':
            a_opt = TRUE;
@@ -239,9 +742,21 @@ main(int argc, char *argv[])
        case 'b':
            b_opt = TRUE;
            break;
        case 'b':
            b_opt = TRUE;
            break;
+       case 'd':
+           d_opt = optarg;
+           break;
+       case 'e':
+           e_opt = optarg;
+           break;
+       case 'i':
+           input_name = optarg;
+           break;
        case 'n':
            n_opt = TRUE;
            break;
        case 'n':
            n_opt = TRUE;
            break;
+       case 'q':
+           q_opt = TRUE;
+           break;
        case 'r':
            if ((r_opt = atoi(optarg)) <= 0)
                usage();
        case 'r':
            if ((r_opt = atoi(optarg)) <= 0)
                usage();
@@ -249,49 +764,79 @@ main(int argc, char *argv[])
        case 's':
            s_opt = TRUE;
            break;
        case 's':
            s_opt = TRUE;
            break;
+#if NCURSES_XNAMES
+       case 'x':
+           x_opt = TRUE;
+           break;
+       case 'y':
+           y_opt = TRUE;
+           x_opt = TRUE;
+           break;
+#endif
        default:
            usage();
            break;
        }
     }
 
        default:
            usage();
            break;
        }
     }
 
+#if HAVE_USE_EXTENDED_NAMES
+    use_extended_names(x_opt);
+#endif
+
     if (!(b_opt || n_opt || s_opt)) {
        b_opt = TRUE;
        n_opt = TRUE;
        s_opt = TRUE;
     }
     if (!(b_opt || n_opt || s_opt)) {
        b_opt = TRUE;
        n_opt = TRUE;
        s_opt = TRUE;
     }
-#else
-    a_opt = TRUE;
-#endif
+
+    make_dblist();
 
     if (a_opt) {
 
     if (a_opt) {
-       if (optind < argc) {
-           for (n = optind; n < argc; ++n) {
-               brute_force(argv[n]);
+       for (repeat = 0; repeat < r_opt; ++repeat) {
+           if (optind < argc) {
+               for (n = optind; n < argc; ++n) {
+                   brute_force(argv[n]);
+               }
+           } else if ((name = getenv("TERM")) != 0) {
+               brute_force(name);
+           } else {
+               static char dumb[] = "dumb";
+               brute_force(dumb);
            }
            }
-       } else if ((name = getenv("TERM")) != 0) {
-           brute_force(name);
-       } else {
-           static char dumb[] = "dumb";
-           brute_force(dumb);
        }
        }
-    }
+    } else {
+       if (input_name != 0) {
+           parse_description(input_name);
+       }
 #if USE_CODE_LISTS
 #if USE_CODE_LISTS
-    else {
+       else {
+           my_boolcodes = copy_code_list(boolcodes);
+           my_numcodes = copy_code_list(numcodes);
+           my_strcodes = copy_code_list(strcodes);
+       }
+#else
+       else {
+           failed("no capability-lists available (use -i option)");
+       }
+#endif /* USE_CODE_LISTS */
        for (repeat = 0; repeat < r_opt; ++repeat) {
            if (optind < argc) {
                for (n = optind; n < argc; ++n) {
        for (repeat = 0; repeat < r_opt; ++repeat) {
            if (optind < argc) {
                for (n = optind; n < argc; ++n) {
-                   demo_terminfo(argv[n]);
+                   demo_termcap(argv[n]);
                }
            } else if ((name = getenv("TERM")) != 0) {
                }
            } else if ((name = getenv("TERM")) != 0) {
-               demo_terminfo(name);
+               demo_termcap(name);
            } else {
                static char dumb[] = "dumb";
            } else {
                static char dumb[] = "dumb";
-               demo_terminfo(dumb);
+               demo_termcap(dumb);
            }
        }
     }
            }
        }
     }
-#endif
+
+    printf("%ld values (%ld booleans, %ld numbers, %ld strings)\n",
+          total_values, total_b_values, total_n_values, total_s_values);
+
+    free_dblist();
 
     ExitProgram(EXIT_SUCCESS);
 }
 
     ExitProgram(EXIT_SUCCESS);
 }
@@ -301,7 +846,6 @@ int
 main(int argc GCC_UNUSED,
      char *argv[]GCC_UNUSED)
 {
 main(int argc GCC_UNUSED,
      char *argv[]GCC_UNUSED)
 {
-    printf("This program requires termcap\n");
-    exit(EXIT_FAILURE);
+    failed("This program requires termcap");
 }
 #endif
 }
 #endif