]> ncurses.scripts.mit.edu Git - ncurses.git/blob - test/demo_terminfo.c
533a5f0a1960ac00e84b724d39a54a3155748d46
[ncurses.git] / test / demo_terminfo.c
1 /****************************************************************************
2  * Copyright (c) 2009-2013,2014 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /*
30  * Author: Thomas E. Dickey
31  *
32  * $Id: demo_terminfo.c,v 1.34 2014/08/31 23:11:39 tom Exp $
33  *
34  * A simple demo of the terminfo interface.
35  */
36 #define USE_TINFO
37 #include <test.priv.h>
38 #include <sys/stat.h>
39
40 #if NCURSES_XNAMES
41 #if HAVE_TERM_ENTRY_H
42 #include <term_entry.h>
43 #else
44 #undef NCURSES_XNAMES
45 #define NCURSES_XNAMES 0
46 #endif
47 #endif
48
49 static void
50 failed(const char *msg)
51 {
52     fprintf(stderr, "%s\n", msg);
53     ExitProgram(EXIT_FAILURE);
54 }
55
56 #if HAVE_TIGETSTR
57
58 #if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
59 #define USE_CODE_LISTS 1
60 #else
61 #define USE_CODE_LISTS 0
62 #endif
63
64 static bool a_opt = FALSE;
65 static bool b_opt = FALSE;
66 static bool f_opt = FALSE;
67 static bool n_opt = FALSE;
68 static bool q_opt = FALSE;
69 static bool s_opt = FALSE;
70 static bool x_opt = FALSE;
71 static bool y_opt = FALSE;
72
73 static char *d_opt;
74 static char *e_opt;
75 static char **db_list;
76 static int db_item;
77
78 static char *my_blob;
79 static char **my_boolcodes;
80 static char **my_numcodes;
81 static char **my_numvalues;
82 static char **my_strcodes;
83 static char **my_strvalues;
84
85 static long total_values;
86 static long total_b_values;
87 static long total_n_values;
88 static long total_s_values;
89
90 #define FCOLS 8
91 #define FNAME(type) "%s %-*s = ", #type, FCOLS
92
93 static char *
94 make_dbitem(char *p, char *q)
95 {
96     char *result = malloc(strlen(e_opt) + 2 + (size_t) (p - q));
97     sprintf(result, "%s=%.*s", e_opt, (int) (p - q), q);
98     return result;
99 }
100
101 static void
102 make_dblist(void)
103 {
104     if (d_opt && e_opt) {
105         int pass;
106
107         for (pass = 0; pass < 2; ++pass) {
108             char *p, *q;
109             size_t count = 0;
110
111             for (p = q = d_opt; *p != '\0'; ++p) {
112                 if (*p == ':') {
113                     if (p != q + 1) {
114                         if (pass) {
115                             db_list[count] = make_dbitem(p, q);
116                         }
117                         count++;
118                     }
119                     q = p + 1;
120                 }
121             }
122             if (p != q + 1) {
123                 if (pass) {
124                     db_list[count] = make_dbitem(p, q);
125                 }
126                 count++;
127             }
128             if (!pass) {
129                 db_list = typeCalloc(char *, count + 1);
130             }
131         }
132     }
133 }
134
135 static char *
136 next_dbitem(void)
137 {
138     char *result = 0;
139
140     if (db_list) {
141         if ((result = db_list[db_item]) == 0) {
142             db_item = 0;
143             result = db_list[0];
144         } else {
145             db_item++;
146         }
147     }
148     printf("** %s\n", result);
149     return result;
150 }
151
152 #ifdef NO_LEAKS
153 static void
154 free_dblist(void)
155 {
156     if (db_list) {
157         int n;
158         for (n = 0; db_list[n]; ++n)
159             free(db_list[n]);
160         free(db_list);
161         db_list = 0;
162     }
163 }
164 #endif
165
166 static void
167 dumpit(NCURSES_CONST char *cap)
168 {
169     const char *str;
170     int num;
171
172     if ((str = tigetstr(cap)) != 0 && (str != (char *) -1)) {
173         total_values++;
174         total_s_values++;
175         if (!q_opt) {
176             printf(FNAME(str), cap);
177             while (*str != 0) {
178                 int ch = UChar(*str++);
179                 switch (ch) {
180                 case '\177':
181                     fputs("^?", stdout);
182                     break;
183                 case '\033':
184                     fputs("\\E", stdout);
185                     break;
186                 case '\b':
187                     fputs("\\b", stdout);
188                     break;
189                 case '\f':
190                     fputs("\\f", stdout);
191                     break;
192                 case '\n':
193                     fputs("\\n", stdout);
194                     break;
195                 case '\r':
196                     fputs("\\r", stdout);
197                     break;
198                 case ' ':
199                     fputs("\\s", stdout);
200                     break;
201                 case '\t':
202                     fputs("\\t", stdout);
203                     break;
204                 case '^':
205                     fputs("\\^", stdout);
206                     break;
207                 case ':':
208                     fputs("\\072", stdout);
209                     break;
210                 case '\\':
211                     fputs("\\\\", stdout);
212                     break;
213                 default:
214                     if (isgraph(ch))
215                         fputc(ch, stdout);
216                     else if (ch < 32)
217                         printf("^%c", ch + '@');
218                     else
219                         printf("\\%03o", ch);
220                     break;
221                 }
222             }
223             printf("\n");
224         }
225     } else if ((num = tigetnum(cap)) >= 0) {
226         total_values++;
227         total_n_values++;
228         if (!q_opt) {
229             printf(FNAME(num), cap);
230             printf(" %d\n", num);
231         }
232     } else if ((num = tigetflag(cap)) >= 0) {
233         total_values++;
234         total_b_values++;
235         if (!q_opt) {
236             printf(FNAME(flg), cap);
237             printf("%s\n", num ? "true" : "false");
238         }
239     }
240
241     if (!q_opt)
242         fflush(stdout);
243 }
244
245 #define isCapName(c) (isalnum(UChar(c)) || ((c) == '_'))
246 #define LegalItem(c,n) (n)
247
248 static void
249 brute_force(const char *name)
250 {
251 #define MAX_FORCE 5             /* omit "colors", since CPU-time is a problem */
252     static const char legal[] = "\
253 0123456789\
254 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
255 abcdefghijklmnopqrstuvwxyz_";
256     int length;
257     int j, k;
258     bool carry;
259     bool changed;
260     char cap[MAX_FORCE + 1];
261     int item[MAX_FORCE + 1];
262
263     if (db_list) {
264         putenv(next_dbitem());
265     }
266     if (!q_opt)
267         printf("Terminal type \"%s\"\n", name);
268     setupterm((NCURSES_CONST char *) name, 1, (int *) 0);
269
270     for (length = 1; length <= MAX_FORCE; ++length) {
271         /* set all digits to zeros */
272         for (j = 0; j < length; ++j) {
273             item[j] = LegalItem(j, 0);
274         }
275
276         do {
277             changed = FALSE;
278             /* copy digits to cap-name */
279             for (j = 0; j < length; ++j) {
280                 cap[j] = legal[item[j]];
281             }
282             cap[length] = '\0';
283             dumpit(cap);
284
285             k = length - 1;
286             do {
287                 carry = FALSE;
288                 for (; k >= 0; --k) {
289                     item[k] += 1;
290                     if (legal[item[k]]) {
291                         changed = TRUE;
292                         break;
293                     }
294                     if (k > 0 &&
295                         legal[item[k - 1] + 1]) {
296                         for (j = k; j < length; ++j) {
297                             item[j] = LegalItem(j, 0);
298                         }
299                         carry = TRUE;
300                         changed = TRUE;
301                     }
302                 }
303             } while (carry);
304         } while (changed);
305     }
306     del_curterm(cur_term);
307 }
308
309 static void
310 demo_terminfo(char *name)
311 {
312     unsigned n;
313     NCURSES_CONST char *cap;
314
315     if (db_list) {
316         putenv(next_dbitem());
317     }
318     if (!q_opt)
319         printf("Terminal type \"%s\"\n", name);
320     setupterm(name, 1, (int *) 0);
321
322     if (b_opt) {
323         for (n = 0;; ++n) {
324             cap = f_opt ? boolfnames[n] : my_boolcodes[n];
325             if (cap == 0)
326                 break;
327             dumpit(cap);
328         }
329     }
330
331     if (n_opt) {
332         for (n = 0;; ++n) {
333             cap = f_opt ? numfnames[n] : my_numcodes[n];
334             if (cap == 0)
335                 break;
336             dumpit(cap);
337         }
338     }
339
340     if (s_opt) {
341         for (n = 0;; ++n) {
342             cap = f_opt ? strfnames[n] : my_strcodes[n];
343             if (cap == 0)
344                 break;
345             dumpit(cap);
346         }
347     }
348 #ifdef NCURSES_VERSION
349     if (x_opt && (my_blob == 0)) {
350         int mod;
351         if (y_opt) {
352 #if NCURSES_XNAMES
353             TERMTYPE *term = &(cur_term->type);
354             if (term != 0
355                 && ((NUM_BOOLEANS(term) != BOOLCOUNT)
356                     || (NUM_NUMBERS(term) != NUMCOUNT)
357                     || (NUM_STRINGS(term) != STRCOUNT))) {
358                 for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
359                     dumpit(ExtBoolname(term, (int) n, boolnames));
360                 }
361                 for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
362                     dumpit(ExtNumname(term, (int) n, numnames));
363                 }
364                 for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
365                     dumpit(ExtStrname(term, (int) n, strnames));
366                 }
367             }
368 #endif
369         } else {
370             char temp[80];
371             static const char *xterm_keys[] =
372             {
373                 "kDC", "kDN", "kEND", "kHOM", "kIC",
374                 "kLFT", "kNXT", "kPRV", "kRIT", "kUP",
375             };
376             for (n = 0; n < SIZEOF(xterm_keys); ++n) {
377                 for (mod = 0; mod < 8; ++mod) {
378                     if (mod == 0) {
379                         /* these happen to be standard - avoid duplicates */
380                         if (!strcmp(xterm_keys[n], "kDC") ||
381                             !strcmp(xterm_keys[n], "kEND") ||
382                             !strcmp(xterm_keys[n], "kHOM") ||
383                             !strcmp(xterm_keys[n], "kLFT") ||
384                             !strcmp(xterm_keys[n], "kRIT")) {
385                             continue;
386                         }
387                         sprintf(temp, "%.*s", 8, xterm_keys[n]);
388                     } else {
389                         sprintf(temp, "%.*s%d", 8, xterm_keys[n], mod);
390                     }
391                     dumpit(temp);
392                 }
393             }
394         }
395     }
396 #endif
397     del_curterm(cur_term);
398 }
399
400 typedef enum {
401     pDefault = 0
402     ,pComment
403     ,pDescription
404     ,pEscaped
405     ,pNewline
406     ,pName
407     ,pNumber
408     ,pString
409 } STATE;
410
411 static void
412 parse_description(const char *input_name)
413 {
414     FILE *fp;
415     struct stat sb;
416     size_t count_bools = 0;
417     size_t count_nums = 0;
418     size_t count_strs = 0;
419     size_t len;
420     size_t j, k, jl;
421     STATE state;
422
423     if (stat(input_name, &sb) != 0
424         || (sb.st_mode & S_IFMT) != S_IFREG) {
425         failed("input is not a file");
426     }
427
428     if (sb.st_size == 0) {
429         failed("input is empty");
430     }
431
432     /*
433      * None of the arrays could be larger than the input-file, and since it
434      * is small, just allocate the maximum for simplicity.
435      */
436     if ((my_blob = malloc((size_t) sb.st_size + 1)) == 0 ||
437         (my_boolcodes = typeCalloc(char *, sb.st_size)) == 0 ||
438           (my_numcodes = typeCalloc(char *, sb.st_size)) == 0 ||
439           (my_numvalues = typeCalloc(char *, sb.st_size)) == 0 ||
440           (my_strcodes = typeCalloc(char *, sb.st_size)) == 0 ||
441           (my_strvalues = typeCalloc(char *, sb.st_size)) == 0) {
442         failed("cannot allocate memory for input-file");
443     }
444
445     if ((fp = fopen(input_name, "r")) == 0)
446         failed("cannot open input-file");
447     len = fread(my_blob, sizeof(char), (size_t) sb.st_size, fp);
448     fclose(fp);
449
450     /*
451      * First, get rid of comments and escaped newlines, as well as repeated
452      * colons to construct a canonical entry.
453      */
454     state = pNewline;
455     for (j = k = 0; j < len; ++j) {
456         int ch = my_blob[j];
457         if (ch == '\t') {
458             ch = ' ';
459         }
460         switch (state) {
461         case pNewline:
462             if (ch == ' ') {
463                 continue;
464             }
465             if (ch == '#') {
466                 state = pComment;
467                 continue;
468             }
469             state = pDefault;
470             /* FALLTHRU */
471         case pDefault:
472             switch (ch) {
473             case '|':
474                 state = pDescription;
475                 continue;
476             case '\\':
477                 state = pEscaped;
478                 continue;
479             case '\n':
480                 state = pNewline;
481                 continue;
482             case ' ':
483                 break;
484             case ',':
485                 my_blob[k++] = (char) ch;
486                 break;
487             default:
488                 if (isalpha(UChar(ch)))
489                     state = pName;
490                 else
491                     fprintf(stderr, "OOPS @%d:%.20s\n", __LINE__, my_blob + j);
492                 my_blob[k++] = (char) ch;
493                 break;
494             }
495             break;
496         case pComment:
497             if (ch == '\n')
498                 state = pNewline;
499             break;
500         case pDescription:
501             switch (ch) {
502             case ',':
503                 state = pDefault;
504                 break;
505             case '\n':
506                 state = pNewline;
507                 break;
508             }
509             break;
510         case pEscaped:
511             if (ch != '\n') {
512                 my_blob[k++] = (char) ch;
513                 state = pDefault;
514             } else {
515                 state = pNewline;
516             }
517             break;
518         case pName:
519             switch (ch) {
520             case '\n':
521                 state = pNewline;
522                 continue;
523             case ' ':
524             case ',':
525                 state = pDefault;
526                 break;
527             case '#':
528                 state = pNumber;
529                 break;
530             case '=':
531                 state = pString;
532                 break;
533             case '|':
534                 state = pDescription;
535                 continue;
536             }
537             my_blob[k++] = (char) ch;
538             break;
539         case pNumber:
540             switch (ch) {
541             case '\n':
542                 state = pNewline;
543                 continue;
544             case ',':
545                 state = pDefault;
546                 break;
547             case ' ':
548                 state = pDefault;
549                 continue;
550             }
551             my_blob[k++] = (char) ch;
552             break;
553         case pString:
554             switch (ch) {
555             case '\n':
556                 state = pNewline;
557                 break;
558             case ',':
559                 state = pDefault;
560                 my_blob[k++] = (char) ch;
561                 break;
562             default:
563                 my_blob[k++] = (char) ch;
564                 break;
565             }
566             break;
567         default:
568             /* not used */
569             break;
570         }
571     }
572     my_blob[k] = '\0';
573
574     /*
575      * Then, parse what's left, making indexes of the names and values.
576      */
577     state = pDefault;
578     for (j = 0; my_blob[j] != '\0'; ++j) {
579         switch (state) {
580         case pDefault:
581             switch (my_blob[j]) {
582             case '\\':
583                 state = pEscaped;
584                 break;
585             case ',':
586                 my_blob[j] = '\0';
587                 if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ',')
588                     state = pName;
589                 break;
590             case ' ':
591                 break;
592             default:
593                 break;
594             }
595         case pEscaped:
596             break;
597         case pName:
598             state = pDefault;
599             if (isalpha(UChar(my_blob[j]))) {
600                 for (jl = 1; isalnum(UChar(my_blob[j + jl])); ++jl) {
601                     ;
602                 }
603             } else {
604                 jl = 0;
605             }
606             if (jl != 0) {
607                 switch (my_blob[j + jl]) {
608                 case '#':
609                     my_numvalues[count_nums] = &my_blob[j + jl + 1];
610                     my_numcodes[count_nums++] = &my_blob[j];
611                     my_blob[j + jl] = '\0';
612                     state = pNumber;
613                     j += jl;
614                     break;
615                 case '=':
616                     my_strvalues[count_strs] = &my_blob[j + jl + 1];
617                     my_strcodes[count_strs++] = &my_blob[j];
618                     my_blob[j + jl] = '\0';
619                     state = pString;
620                     j += jl;
621                     break;
622                 default:
623                     if (my_blob[j + jl] == '@') {
624                         /*
625                          * We cannot get the type for a cancelled item
626                          * directly, but can infer it assuming the input
627                          * came from infocmp, which puts the data in a
628                          * known order.
629                          */
630                         if (count_strs) {
631                             my_strvalues[count_strs] = "";
632                             my_strcodes[count_strs++] = &my_blob[j];
633                         } else if (count_nums) {
634                             my_numvalues[count_nums] = "";
635                             my_numcodes[count_nums++] = &my_blob[j];
636                         } else {
637                             my_boolcodes[count_bools++] = &my_blob[j];
638                         }
639                         my_blob[j + jl] = '\0';
640                         j += jl + 1;
641                     } else {
642                         my_boolcodes[count_bools++] = &my_blob[j];
643                         my_blob[j + jl] = '\0';
644                         j += jl;
645                     }
646                     state = (isCapName(my_blob[j + 1])
647                              ? pName
648                              : pDefault);
649                     break;
650                 }
651             }
652             break;
653         case pNumber:
654             if (!isdigit(UChar(my_blob[j]))) {
655                 --j;
656                 state = pDefault;
657             }
658             break;
659         case pString:
660             switch (my_blob[j]) {
661             case '\\':
662                 if (my_blob[j + 1] != '\0') {
663                     ++j;
664                 } else {
665                     --j;
666                     state = pDefault;
667                 }
668                 break;
669             case ',':
670                 --j;
671                 state = pDefault;
672                 break;
673             }
674             break;
675         case pNewline:
676         case pComment:
677         case pDescription:
678         default:
679             break;
680         }
681     }
682     my_boolcodes[count_bools] = 0;
683     my_numcodes[count_nums] = 0;
684     my_numvalues[count_nums] = 0;
685     my_strcodes[count_strs] = 0;
686     my_strvalues[count_strs] = 0;
687
688 #if 0
689     printf("# bools:%d\n", (int) count_bools);
690     for (j = 0; my_boolcodes[j]; ++j)
691         printf("\t%s,\n", my_boolcodes[j]);
692
693     printf("# numbers:%d\n", (int) count_nums);
694     for (j = 0; my_numcodes[j]; ++j)
695         printf("\t%s#%s,\n", my_numcodes[j], my_numvalues[j]);
696
697     printf("# strings:%d\n", (int) count_strs);
698     for (j = 0; my_strcodes[j]; ++j)
699         printf("\t%s=%s,\n", my_strcodes[j], my_strvalues[j]);
700 #endif
701 }
702
703 #if USE_CODE_LISTS
704 static char **
705 copy_code_list(NCURSES_CONST char *const *list)
706 {
707     int pass;
708     size_t count;
709     size_t length = 0;
710     char **result = 0;
711     char *blob = 0;
712     char *unused = 0;
713
714     for (pass = 0; pass < 2; ++pass) {
715         for (count = 0; list[count] != 0; ++count) {
716             size_t chunk = strlen(list[count]) + 1;
717             if (pass == 0) {
718                 length += chunk;
719             } else {
720                 result[count] = unused;
721                 strcpy(unused, list[count]);
722                 unused += chunk;
723             }
724         }
725         if (pass == 0) {
726             blob = malloc(length);
727             result = typeCalloc(char *, count + 1);
728             unused = blob;
729             if (blob == 0 || result == 0)
730                 failed("copy_code_list failed");
731         }
732     }
733
734     return result;
735 }
736 #endif
737
738 static void
739 usage(void)
740 {
741     static const char *msg[] =
742     {
743         "Usage: demo_terminfo [options] [terminal]",
744         "",
745         "If no options are given, print all (boolean, numeric, string)",
746         "capabilities for the given terminal, using short names.",
747         "",
748         "Options:",
749         " -a       try all names, print capabilities found",
750         " -b       print boolean-capabilities",
751         " -d LIST  colon-separated list of databases to use",
752         " -e NAME  environment variable to set with -d option",
753         " -f       print full names",
754         " -i NAME  terminal description to use as names for \"-a\" option",
755         " -n       print numeric-capabilities",
756         " -q       quiet (prints only counts)",
757         " -r COUNT repeat for given count",
758         " -s       print string-capabilities",
759 #ifdef NCURSES_VERSION
760         " -x       print extended capabilities",
761         " -y       direct-lookup names of extended capabilities",
762 #endif
763     };
764     unsigned n;
765     for (n = 0; n < SIZEOF(msg); ++n) {
766         fprintf(stderr, "%s\n", msg[n]);
767     }
768     ExitProgram(EXIT_FAILURE);
769 }
770
771 int
772 main(int argc, char *argv[])
773 {
774     int n;
775     int repeat;
776     char *name;
777     int r_opt = 1;
778     char *input_name = 0;
779
780     while ((n = getopt(argc, argv, "abd:e:fi:nqr:sxy")) != -1) {
781         switch (n) {
782         case 'a':
783             a_opt = TRUE;
784             break;
785         case 'b':
786             b_opt = TRUE;
787             break;
788         case 'd':
789             d_opt = optarg;
790             break;
791         case 'e':
792             e_opt = optarg;
793             break;
794         case 'f':
795             f_opt = TRUE;
796             break;
797         case 'i':
798             input_name = optarg;
799             break;
800         case 'n':
801             n_opt = TRUE;
802             break;
803         case 'q':
804             q_opt = TRUE;
805             break;
806         case 'r':
807             if ((r_opt = atoi(optarg)) <= 0)
808                 usage();
809             break;
810         case 's':
811             s_opt = TRUE;
812             break;
813 #ifdef NCURSES_VERSION
814         case 'x':
815             x_opt = TRUE;
816             break;
817         case 'y':
818             y_opt = TRUE;
819             x_opt = TRUE;
820             break;
821 #endif
822         default:
823             usage();
824             break;
825         }
826     }
827
828 #if NCURSES_XNAMES
829     use_extended_names(x_opt);
830 #endif
831
832     if (!(b_opt || n_opt || s_opt)) {
833         b_opt = TRUE;
834         n_opt = TRUE;
835         s_opt = TRUE;
836     }
837
838     make_dblist();
839
840     if (a_opt) {
841         for (repeat = 0; repeat < r_opt; ++repeat) {
842             if (optind < argc) {
843                 for (n = optind; n < argc; ++n) {
844                     brute_force(argv[n]);
845                 }
846             } else if ((name = getenv("TERM")) != 0) {
847                 brute_force(name);
848             } else {
849                 static char dumb[] = "dumb";
850                 brute_force(dumb);
851             }
852         }
853     } else {
854         if (input_name != 0) {
855             parse_description(input_name);
856         }
857 #if USE_CODE_LISTS
858         else {
859             my_boolcodes = copy_code_list(boolnames);
860             my_numcodes = copy_code_list(numnames);
861             my_strcodes = copy_code_list(strnames);
862         }
863 #else
864         else {
865             failed("no capability-lists available (use -i option)");
866         }
867 #endif /* USE_CODE_LISTS */
868         for (repeat = 0; repeat < r_opt; ++repeat) {
869             if (optind < argc) {
870                 for (n = optind; n < argc; ++n) {
871                     demo_terminfo(argv[n]);
872                 }
873             } else if ((name = getenv("TERM")) != 0) {
874                 demo_terminfo(name);
875             } else {
876                 static char dumb[] = "dumb";
877                 demo_terminfo(dumb);
878             }
879         }
880     }
881
882     printf("%ld values (%ld booleans, %ld numbers, %ld strings)\n",
883            total_values, total_b_values, total_n_values, total_s_values);
884
885 #ifdef NO_LEAKS
886     free_dblist();
887     if (my_blob != 0) {
888         free(my_blob);
889         free(my_boolcodes);
890         free(my_numcodes);
891         free(my_numvalues);
892         free(my_strcodes);
893         free(my_strvalues);
894     }
895 #endif
896
897     ExitProgram(EXIT_SUCCESS);
898 }
899
900 #else /* !HAVE_TIGETSTR */
901 int
902 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
903 {
904     printf("This program requires the terminfo functions such as tigetstr\n");
905     ExitProgram(EXIT_FAILURE);
906 }
907 #endif /* HAVE_TIGETSTR */