]> ncurses.scripts.mit.edu Git - ncurses.git/blob - test/demo_terminfo.c
b4466168fa6dc0710f354608bbd6fb0e0c8ae408
[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.37 2014/09/05 08:44:49 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 #if USE_CODE_LISTS
310 #define fullname(type,n) f_opt ? type##fnames[n] : my_##type##codes[n]
311 #else
312 #define fullname(type,n) my_##type##codes[n]
313 #endif
314
315 static void
316 demo_terminfo(char *name)
317 {
318     unsigned n;
319     NCURSES_CONST char *cap;
320
321     if (db_list) {
322         putenv(next_dbitem());
323     }
324     if (!q_opt)
325         printf("Terminal type \"%s\"\n", name);
326     setupterm(name, 1, (int *) 0);
327
328     if (b_opt) {
329         for (n = 0;; ++n) {
330             cap = fullname(bool, n);
331             if (cap == 0)
332                 break;
333             dumpit(cap);
334         }
335     }
336
337     if (n_opt) {
338         for (n = 0;; ++n) {
339             cap = fullname(num, n);
340             if (cap == 0)
341                 break;
342             dumpit(cap);
343         }
344     }
345
346     if (s_opt) {
347         for (n = 0;; ++n) {
348             cap = fullname(str, n);
349             if (cap == 0)
350                 break;
351             dumpit(cap);
352         }
353     }
354 #ifdef NCURSES_VERSION
355     if (x_opt && (my_blob == 0)) {
356         int mod;
357         if (y_opt) {
358 #if NCURSES_XNAMES
359             TERMTYPE *term = &(cur_term->type);
360             if (term != 0
361                 && ((NUM_BOOLEANS(term) != BOOLCOUNT)
362                     || (NUM_NUMBERS(term) != NUMCOUNT)
363                     || (NUM_STRINGS(term) != STRCOUNT))) {
364                 for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
365                     dumpit(ExtBoolname(term, (int) n, boolnames));
366                 }
367                 for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
368                     dumpit(ExtNumname(term, (int) n, numnames));
369                 }
370                 for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
371                     dumpit(ExtStrname(term, (int) n, strnames));
372                 }
373             }
374 #endif
375         } else {
376             char temp[80];
377             static const char *xterm_keys[] =
378             {
379                 "kDC", "kDN", "kEND", "kHOM", "kIC",
380                 "kLFT", "kNXT", "kPRV", "kRIT", "kUP",
381             };
382             for (n = 0; n < SIZEOF(xterm_keys); ++n) {
383                 for (mod = 0; mod < 8; ++mod) {
384                     if (mod == 0) {
385                         /* these happen to be standard - avoid duplicates */
386                         if (!strcmp(xterm_keys[n], "kDC") ||
387                             !strcmp(xterm_keys[n], "kEND") ||
388                             !strcmp(xterm_keys[n], "kHOM") ||
389                             !strcmp(xterm_keys[n], "kLFT") ||
390                             !strcmp(xterm_keys[n], "kRIT")) {
391                             continue;
392                         }
393                         sprintf(temp, "%.*s", 8, xterm_keys[n]);
394                     } else {
395                         sprintf(temp, "%.*s%d", 8, xterm_keys[n], mod);
396                     }
397                     dumpit(temp);
398                 }
399             }
400         }
401     }
402 #endif
403     del_curterm(cur_term);
404 }
405
406 typedef enum {
407     pDefault = 0
408     ,pComment
409     ,pDescription
410     ,pEscaped
411     ,pNewline
412     ,pName
413     ,pNumber
414     ,pString
415 } STATE;
416
417 static void
418 parse_description(const char *input_name)
419 {
420     static char empty[1];
421
422     FILE *fp;
423     struct stat sb;
424     size_t count_bools = 0;
425     size_t count_nums = 0;
426     size_t count_strs = 0;
427     size_t len;
428     size_t j, k, jl;
429     STATE state;
430
431     if (stat(input_name, &sb) != 0
432         || (sb.st_mode & S_IFMT) != S_IFREG) {
433         failed("input is not a file");
434     }
435
436     if (sb.st_size == 0) {
437         failed("input is empty");
438     }
439
440     /*
441      * None of the arrays could be larger than the input-file, and since it
442      * is small, just allocate the maximum for simplicity.
443      */
444     if ((my_blob = malloc((size_t) sb.st_size + 1)) == 0 ||
445         (my_boolcodes = typeCalloc(char *, sb.st_size)) == 0 ||
446           (my_numcodes = typeCalloc(char *, sb.st_size)) == 0 ||
447           (my_numvalues = typeCalloc(char *, sb.st_size)) == 0 ||
448           (my_strcodes = typeCalloc(char *, sb.st_size)) == 0 ||
449           (my_strvalues = typeCalloc(char *, sb.st_size)) == 0) {
450         failed("cannot allocate memory for input-file");
451     }
452
453     if ((fp = fopen(input_name, "r")) == 0)
454         failed("cannot open input-file");
455     len = fread(my_blob, sizeof(char), (size_t) sb.st_size, fp);
456     fclose(fp);
457
458     /*
459      * First, get rid of comments and escaped newlines, as well as repeated
460      * colons to construct a canonical entry.
461      */
462     state = pNewline;
463     for (j = k = 0; j < len; ++j) {
464         int ch = my_blob[j];
465         if (ch == '\t') {
466             ch = ' ';
467         }
468         switch (state) {
469         case pNewline:
470             if (ch == ' ') {
471                 continue;
472             }
473             if (ch == '#') {
474                 state = pComment;
475                 continue;
476             }
477             state = pDefault;
478             /* FALLTHRU */
479         case pDefault:
480             switch (ch) {
481             case '|':
482                 state = pDescription;
483                 continue;
484             case '\\':
485                 state = pEscaped;
486                 continue;
487             case '\n':
488                 state = pNewline;
489                 continue;
490             case ' ':
491                 break;
492             case ',':
493                 my_blob[k++] = (char) ch;
494                 break;
495             default:
496                 if (isalpha(UChar(ch)))
497                     state = pName;
498                 else
499                     fprintf(stderr, "OOPS @%d:%.20s\n", __LINE__, my_blob + j);
500                 my_blob[k++] = (char) ch;
501                 break;
502             }
503             break;
504         case pComment:
505             if (ch == '\n')
506                 state = pNewline;
507             break;
508         case pDescription:
509             switch (ch) {
510             case ',':
511                 state = pDefault;
512                 break;
513             case '\n':
514                 state = pNewline;
515                 break;
516             }
517             break;
518         case pEscaped:
519             if (ch != '\n') {
520                 my_blob[k++] = (char) ch;
521                 state = pDefault;
522             } else {
523                 state = pNewline;
524             }
525             break;
526         case pName:
527             switch (ch) {
528             case '\n':
529                 state = pNewline;
530                 continue;
531             case ' ':
532             case ',':
533                 state = pDefault;
534                 break;
535             case '#':
536                 state = pNumber;
537                 break;
538             case '=':
539                 state = pString;
540                 break;
541             case '|':
542                 state = pDescription;
543                 continue;
544             }
545             my_blob[k++] = (char) ch;
546             break;
547         case pNumber:
548             switch (ch) {
549             case '\n':
550                 state = pNewline;
551                 continue;
552             case ',':
553                 state = pDefault;
554                 break;
555             case ' ':
556                 state = pDefault;
557                 continue;
558             }
559             my_blob[k++] = (char) ch;
560             break;
561         case pString:
562             switch (ch) {
563             case '\n':
564                 state = pNewline;
565                 break;
566             case ',':
567                 state = pDefault;
568                 my_blob[k++] = (char) ch;
569                 break;
570             default:
571                 my_blob[k++] = (char) ch;
572                 break;
573             }
574             break;
575         default:
576             /* not used */
577             break;
578         }
579     }
580     my_blob[k] = '\0';
581
582     /*
583      * Then, parse what's left, making indexes of the names and values.
584      */
585     state = pDefault;
586     for (j = 0; my_blob[j] != '\0'; ++j) {
587         switch (state) {
588         case pDefault:
589             switch (my_blob[j]) {
590             case '\\':
591                 state = pEscaped;
592                 break;
593             case ',':
594                 my_blob[j] = '\0';
595                 if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ',')
596                     state = pName;
597                 break;
598             case ' ':
599                 break;
600             default:
601                 break;
602             }
603         case pEscaped:
604             break;
605         case pName:
606             state = pDefault;
607             if (isalpha(UChar(my_blob[j]))) {
608                 for (jl = 1; isalnum(UChar(my_blob[j + jl])); ++jl) {
609                     ;
610                 }
611             } else {
612                 jl = 0;
613             }
614             if (jl != 0) {
615                 switch (my_blob[j + jl]) {
616                 case '#':
617                     my_numvalues[count_nums] = &my_blob[j + jl + 1];
618                     my_numcodes[count_nums++] = &my_blob[j];
619                     my_blob[j + jl] = '\0';
620                     state = pNumber;
621                     j += jl;
622                     break;
623                 case '=':
624                     my_strvalues[count_strs] = &my_blob[j + jl + 1];
625                     my_strcodes[count_strs++] = &my_blob[j];
626                     my_blob[j + jl] = '\0';
627                     state = pString;
628                     j += jl;
629                     break;
630                 default:
631                     if (my_blob[j + jl] == '@') {
632                         /*
633                          * We cannot get the type for a cancelled item
634                          * directly, but can infer it assuming the input
635                          * came from infocmp, which puts the data in a
636                          * known order.
637                          */
638                         if (count_strs) {
639                             my_strvalues[count_strs] = empty;
640                             my_strcodes[count_strs++] = &my_blob[j];
641                         } else if (count_nums) {
642                             my_numvalues[count_nums] = empty;
643                             my_numcodes[count_nums++] = &my_blob[j];
644                         } else {
645                             my_boolcodes[count_bools++] = &my_blob[j];
646                         }
647                         my_blob[j + jl] = '\0';
648                         j += jl + 1;
649                     } else {
650                         my_boolcodes[count_bools++] = &my_blob[j];
651                         my_blob[j + jl] = '\0';
652                         j += jl;
653                     }
654                     state = (isCapName(my_blob[j + 1])
655                              ? pName
656                              : pDefault);
657                     break;
658                 }
659             }
660             break;
661         case pNumber:
662             if (!isdigit(UChar(my_blob[j]))) {
663                 --j;
664                 state = pDefault;
665             }
666             break;
667         case pString:
668             switch (my_blob[j]) {
669             case '\\':
670                 if (my_blob[j + 1] != '\0') {
671                     ++j;
672                 } else {
673                     --j;
674                     state = pDefault;
675                 }
676                 break;
677             case ',':
678                 --j;
679                 state = pDefault;
680                 break;
681             }
682             break;
683         case pNewline:
684         case pComment:
685         case pDescription:
686         default:
687             break;
688         }
689     }
690     my_boolcodes[count_bools] = 0;
691     my_numcodes[count_nums] = 0;
692     my_numvalues[count_nums] = 0;
693     my_strcodes[count_strs] = 0;
694     my_strvalues[count_strs] = 0;
695
696 #if 0
697     printf("# bools:%d\n", (int) count_bools);
698     for (j = 0; my_boolcodes[j]; ++j)
699         printf("\t%s,\n", my_boolcodes[j]);
700
701     printf("# numbers:%d\n", (int) count_nums);
702     for (j = 0; my_numcodes[j]; ++j)
703         printf("\t%s#%s,\n", my_numcodes[j], my_numvalues[j]);
704
705     printf("# strings:%d\n", (int) count_strs);
706     for (j = 0; my_strcodes[j]; ++j)
707         printf("\t%s=%s,\n", my_strcodes[j], my_strvalues[j]);
708 #endif
709 }
710
711 #if USE_CODE_LISTS
712 static char **
713 copy_code_list(NCURSES_CONST char *const *list)
714 {
715     int pass;
716     size_t count;
717     size_t length = 1;
718     char **result = 0;
719     char *blob = 0;
720     char *unused = 0;
721
722     for (pass = 0; pass < 2; ++pass) {
723         for (count = 0; list[count] != 0; ++count) {
724             size_t chunk = strlen(list[count]) + 1;
725             if (pass == 0) {
726                 length += chunk;
727             } else {
728                 result[count] = unused;
729                 strcpy(unused, list[count]);
730                 unused += chunk;
731             }
732         }
733         if (pass == 0) {
734             blob = malloc(length);
735             result = typeCalloc(char *, count + 1);
736             unused = blob;
737             if (blob == 0 || result == 0)
738                 failed("copy_code_list failed");
739         }
740     }
741
742     return result;
743 }
744 #endif
745
746 static void
747 usage(void)
748 {
749     static const char *msg[] =
750     {
751         "Usage: demo_terminfo [options] [terminal]",
752         "",
753         "If no options are given, print all (boolean, numeric, string)",
754         "capabilities for the given terminal, using short names.",
755         "",
756         "Options:",
757         " -a       try all names, print capabilities found",
758         " -b       print boolean-capabilities",
759         " -d LIST  colon-separated list of databases to use",
760         " -e NAME  environment variable to set with -d option",
761         " -f       print full names",
762         " -i NAME  terminal description to use as names for \"-a\" option",
763         " -n       print numeric-capabilities",
764         " -q       quiet (prints only counts)",
765         " -r COUNT repeat for given count",
766         " -s       print string-capabilities",
767 #ifdef NCURSES_VERSION
768         " -x       print extended capabilities",
769         " -y       direct-lookup names of extended capabilities",
770 #endif
771     };
772     unsigned n;
773     for (n = 0; n < SIZEOF(msg); ++n) {
774         fprintf(stderr, "%s\n", msg[n]);
775     }
776     ExitProgram(EXIT_FAILURE);
777 }
778
779 int
780 main(int argc, char *argv[])
781 {
782     int n;
783     int repeat;
784     char *name;
785     int r_opt = 1;
786     char *input_name = 0;
787
788     while ((n = getopt(argc, argv, "abd:e:fi:nqr:sxy")) != -1) {
789         switch (n) {
790         case 'a':
791             a_opt = TRUE;
792             break;
793         case 'b':
794             b_opt = TRUE;
795             break;
796         case 'd':
797             d_opt = optarg;
798             break;
799         case 'e':
800             e_opt = optarg;
801             break;
802         case 'f':
803             f_opt = TRUE;
804             break;
805         case 'i':
806             input_name = optarg;
807             break;
808         case 'n':
809             n_opt = TRUE;
810             break;
811         case 'q':
812             q_opt = TRUE;
813             break;
814         case 'r':
815             if ((r_opt = atoi(optarg)) <= 0)
816                 usage();
817             break;
818         case 's':
819             s_opt = TRUE;
820             break;
821 #ifdef NCURSES_VERSION
822         case 'x':
823             x_opt = TRUE;
824             break;
825         case 'y':
826             y_opt = TRUE;
827             x_opt = TRUE;
828             break;
829 #endif
830         default:
831             usage();
832             break;
833         }
834     }
835
836 #if HAVE_USE_EXTENDED_NAMES
837     use_extended_names(x_opt);
838 #endif
839
840     if (!(b_opt || n_opt || s_opt)) {
841         b_opt = TRUE;
842         n_opt = TRUE;
843         s_opt = TRUE;
844     }
845
846     make_dblist();
847
848     if (a_opt) {
849         for (repeat = 0; repeat < r_opt; ++repeat) {
850             if (optind < argc) {
851                 for (n = optind; n < argc; ++n) {
852                     brute_force(argv[n]);
853                 }
854             } else if ((name = getenv("TERM")) != 0) {
855                 brute_force(name);
856             } else {
857                 static char dumb[] = "dumb";
858                 brute_force(dumb);
859             }
860         }
861     } else {
862         if (input_name != 0) {
863             parse_description(input_name);
864         }
865 #if USE_CODE_LISTS
866         else {
867             my_boolcodes = copy_code_list(boolnames);
868             my_numcodes = copy_code_list(numnames);
869             my_strcodes = copy_code_list(strnames);
870         }
871 #else
872         else {
873             failed("no capability-lists available (use -i option)");
874         }
875 #endif /* USE_CODE_LISTS */
876         for (repeat = 0; repeat < r_opt; ++repeat) {
877             if (optind < argc) {
878                 for (n = optind; n < argc; ++n) {
879                     demo_terminfo(argv[n]);
880                 }
881             } else if ((name = getenv("TERM")) != 0) {
882                 demo_terminfo(name);
883             } else {
884                 static char dumb[] = "dumb";
885                 demo_terminfo(dumb);
886             }
887         }
888     }
889
890     printf("%ld values (%ld booleans, %ld numbers, %ld strings)\n",
891            total_values, total_b_values, total_n_values, total_s_values);
892
893 #ifdef NO_LEAKS
894     free_dblist();
895     if (my_blob != 0) {
896         free(my_blob);
897         free(my_boolcodes);
898         free(my_numcodes);
899         free(my_numvalues);
900         free(my_strcodes);
901         free(my_strvalues);
902     }
903 #endif
904
905     ExitProgram(EXIT_SUCCESS);
906 }
907
908 #else /* !HAVE_TIGETSTR */
909 int
910 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
911 {
912     printf("This program requires the terminfo functions such as tigetstr\n");
913     ExitProgram(EXIT_FAILURE);
914 }
915 #endif /* HAVE_TIGETSTR */