]> ncurses.scripts.mit.edu Git - ncurses.git/blob - test/demo_terminfo.c
ncurses 5.9 - patch 20141129
[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.38 2014/10/10 00:35:28 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     my_blob[sb.st_size] = '\0';
457     fclose(fp);
458
459     /*
460      * First, get rid of comments and escaped newlines, as well as repeated
461      * colons to construct a canonical entry.
462      */
463     state = pNewline;
464     for (j = k = 0; j < len; ++j) {
465         int ch = my_blob[j];
466         if (ch == '\t') {
467             ch = ' ';
468         }
469         switch (state) {
470         case pNewline:
471             if (ch == ' ') {
472                 continue;
473             }
474             if (ch == '#') {
475                 state = pComment;
476                 continue;
477             }
478             state = pDefault;
479             /* FALLTHRU */
480         case pDefault:
481             switch (ch) {
482             case '|':
483                 state = pDescription;
484                 continue;
485             case '\\':
486                 state = pEscaped;
487                 continue;
488             case '\n':
489                 state = pNewline;
490                 continue;
491             case ' ':
492                 break;
493             case ',':
494                 my_blob[k++] = (char) ch;
495                 break;
496             default:
497                 if (isalpha(UChar(ch)))
498                     state = pName;
499                 else
500                     fprintf(stderr, "OOPS @%d:%.20s\n", __LINE__, my_blob + j);
501                 my_blob[k++] = (char) ch;
502                 break;
503             }
504             break;
505         case pComment:
506             if (ch == '\n')
507                 state = pNewline;
508             break;
509         case pDescription:
510             switch (ch) {
511             case ',':
512                 state = pDefault;
513                 break;
514             case '\n':
515                 state = pNewline;
516                 break;
517             }
518             break;
519         case pEscaped:
520             if (ch != '\n') {
521                 my_blob[k++] = (char) ch;
522                 state = pDefault;
523             } else {
524                 state = pNewline;
525             }
526             break;
527         case pName:
528             switch (ch) {
529             case '\n':
530                 state = pNewline;
531                 continue;
532             case ' ':
533             case ',':
534                 state = pDefault;
535                 break;
536             case '#':
537                 state = pNumber;
538                 break;
539             case '=':
540                 state = pString;
541                 break;
542             case '|':
543                 state = pDescription;
544                 continue;
545             }
546             my_blob[k++] = (char) ch;
547             break;
548         case pNumber:
549             switch (ch) {
550             case '\n':
551                 state = pNewline;
552                 continue;
553             case ',':
554                 state = pDefault;
555                 break;
556             case ' ':
557                 state = pDefault;
558                 continue;
559             }
560             my_blob[k++] = (char) ch;
561             break;
562         case pString:
563             switch (ch) {
564             case '\n':
565                 state = pNewline;
566                 break;
567             case ',':
568                 state = pDefault;
569                 my_blob[k++] = (char) ch;
570                 break;
571             default:
572                 my_blob[k++] = (char) ch;
573                 break;
574             }
575             break;
576         default:
577             /* not used */
578             break;
579         }
580     }
581     my_blob[k] = '\0';
582
583     /*
584      * Then, parse what's left, making indexes of the names and values.
585      */
586     state = pDefault;
587     for (j = 0; my_blob[j] != '\0'; ++j) {
588         switch (state) {
589         case pDefault:
590             switch (my_blob[j]) {
591             case '\\':
592                 state = pEscaped;
593                 break;
594             case ',':
595                 my_blob[j] = '\0';
596                 if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ',')
597                     state = pName;
598                 break;
599             case ' ':
600                 break;
601             default:
602                 break;
603             }
604         case pEscaped:
605             break;
606         case pName:
607             state = pDefault;
608             if (isalpha(UChar(my_blob[j]))) {
609                 for (jl = 1; isalnum(UChar(my_blob[j + jl])); ++jl) {
610                     ;
611                 }
612             } else {
613                 jl = 0;
614             }
615             if (jl != 0) {
616                 switch (my_blob[j + jl]) {
617                 case '#':
618                     my_numvalues[count_nums] = &my_blob[j + jl + 1];
619                     my_numcodes[count_nums++] = &my_blob[j];
620                     my_blob[j + jl] = '\0';
621                     state = pNumber;
622                     j += jl;
623                     break;
624                 case '=':
625                     my_strvalues[count_strs] = &my_blob[j + jl + 1];
626                     my_strcodes[count_strs++] = &my_blob[j];
627                     my_blob[j + jl] = '\0';
628                     state = pString;
629                     j += jl;
630                     break;
631                 default:
632                     if (my_blob[j + jl] == '@') {
633                         /*
634                          * We cannot get the type for a cancelled item
635                          * directly, but can infer it assuming the input
636                          * came from infocmp, which puts the data in a
637                          * known order.
638                          */
639                         if (count_strs) {
640                             my_strvalues[count_strs] = empty;
641                             my_strcodes[count_strs++] = &my_blob[j];
642                         } else if (count_nums) {
643                             my_numvalues[count_nums] = empty;
644                             my_numcodes[count_nums++] = &my_blob[j];
645                         } else {
646                             my_boolcodes[count_bools++] = &my_blob[j];
647                         }
648                         my_blob[j + jl] = '\0';
649                         j += jl + 1;
650                     } else {
651                         my_boolcodes[count_bools++] = &my_blob[j];
652                         my_blob[j + jl] = '\0';
653                         j += jl;
654                     }
655                     state = (isCapName(my_blob[j + 1])
656                              ? pName
657                              : pDefault);
658                     break;
659                 }
660             }
661             break;
662         case pNumber:
663             if (!isdigit(UChar(my_blob[j]))) {
664                 --j;
665                 state = pDefault;
666             }
667             break;
668         case pString:
669             switch (my_blob[j]) {
670             case '\\':
671                 if (my_blob[j + 1] != '\0') {
672                     ++j;
673                 } else {
674                     --j;
675                     state = pDefault;
676                 }
677                 break;
678             case ',':
679                 --j;
680                 state = pDefault;
681                 break;
682             }
683             break;
684         case pNewline:
685         case pComment:
686         case pDescription:
687         default:
688             break;
689         }
690     }
691     my_boolcodes[count_bools] = 0;
692     my_numcodes[count_nums] = 0;
693     my_numvalues[count_nums] = 0;
694     my_strcodes[count_strs] = 0;
695     my_strvalues[count_strs] = 0;
696
697 #if 0
698     printf("# bools:%d\n", (int) count_bools);
699     for (j = 0; my_boolcodes[j]; ++j)
700         printf("\t%s,\n", my_boolcodes[j]);
701
702     printf("# numbers:%d\n", (int) count_nums);
703     for (j = 0; my_numcodes[j]; ++j)
704         printf("\t%s#%s,\n", my_numcodes[j], my_numvalues[j]);
705
706     printf("# strings:%d\n", (int) count_strs);
707     for (j = 0; my_strcodes[j]; ++j)
708         printf("\t%s=%s,\n", my_strcodes[j], my_strvalues[j]);
709 #endif
710 }
711
712 #if USE_CODE_LISTS
713 static char **
714 copy_code_list(NCURSES_CONST char *const *list)
715 {
716     int pass;
717     size_t count;
718     size_t length = 1;
719     char **result = 0;
720     char *blob = 0;
721     char *unused = 0;
722
723     for (pass = 0; pass < 2; ++pass) {
724         for (count = 0; list[count] != 0; ++count) {
725             size_t chunk = strlen(list[count]) + 1;
726             if (pass == 0) {
727                 length += chunk;
728             } else {
729                 result[count] = unused;
730                 strcpy(unused, list[count]);
731                 unused += chunk;
732             }
733         }
734         if (pass == 0) {
735             blob = malloc(length);
736             result = typeCalloc(char *, count + 1);
737             unused = blob;
738             if (blob == 0 || result == 0)
739                 failed("copy_code_list failed");
740         }
741     }
742
743     return result;
744 }
745 #endif
746
747 static void
748 usage(void)
749 {
750     static const char *msg[] =
751     {
752         "Usage: demo_terminfo [options] [terminal]",
753         "",
754         "If no options are given, print all (boolean, numeric, string)",
755         "capabilities for the given terminal, using short names.",
756         "",
757         "Options:",
758         " -a       try all names, print capabilities found",
759         " -b       print boolean-capabilities",
760         " -d LIST  colon-separated list of databases to use",
761         " -e NAME  environment variable to set with -d option",
762         " -f       print full names",
763         " -i NAME  terminal description to use as names for \"-a\" option",
764         " -n       print numeric-capabilities",
765         " -q       quiet (prints only counts)",
766         " -r COUNT repeat for given count",
767         " -s       print string-capabilities",
768 #ifdef NCURSES_VERSION
769         " -x       print extended capabilities",
770         " -y       direct-lookup names of extended capabilities",
771 #endif
772     };
773     unsigned n;
774     for (n = 0; n < SIZEOF(msg); ++n) {
775         fprintf(stderr, "%s\n", msg[n]);
776     }
777     ExitProgram(EXIT_FAILURE);
778 }
779
780 int
781 main(int argc, char *argv[])
782 {
783     int n;
784     int repeat;
785     char *name;
786     int r_opt = 1;
787     char *input_name = 0;
788
789     while ((n = getopt(argc, argv, "abd:e:fi:nqr:sxy")) != -1) {
790         switch (n) {
791         case 'a':
792             a_opt = TRUE;
793             break;
794         case 'b':
795             b_opt = TRUE;
796             break;
797         case 'd':
798             d_opt = optarg;
799             break;
800         case 'e':
801             e_opt = optarg;
802             break;
803         case 'f':
804             f_opt = TRUE;
805             break;
806         case 'i':
807             input_name = optarg;
808             break;
809         case 'n':
810             n_opt = TRUE;
811             break;
812         case 'q':
813             q_opt = TRUE;
814             break;
815         case 'r':
816             if ((r_opt = atoi(optarg)) <= 0)
817                 usage();
818             break;
819         case 's':
820             s_opt = TRUE;
821             break;
822 #ifdef NCURSES_VERSION
823         case 'x':
824             x_opt = TRUE;
825             break;
826         case 'y':
827             y_opt = TRUE;
828             x_opt = TRUE;
829             break;
830 #endif
831         default:
832             usage();
833             break;
834         }
835     }
836
837 #if HAVE_USE_EXTENDED_NAMES
838     use_extended_names(x_opt);
839 #endif
840
841     if (!(b_opt || n_opt || s_opt)) {
842         b_opt = TRUE;
843         n_opt = TRUE;
844         s_opt = TRUE;
845     }
846
847     make_dblist();
848
849     if (a_opt) {
850         for (repeat = 0; repeat < r_opt; ++repeat) {
851             if (optind < argc) {
852                 for (n = optind; n < argc; ++n) {
853                     brute_force(argv[n]);
854                 }
855             } else if ((name = getenv("TERM")) != 0) {
856                 brute_force(name);
857             } else {
858                 static char dumb[] = "dumb";
859                 brute_force(dumb);
860             }
861         }
862     } else {
863         if (input_name != 0) {
864             parse_description(input_name);
865         }
866 #if USE_CODE_LISTS
867         else {
868             my_boolcodes = copy_code_list(boolnames);
869             my_numcodes = copy_code_list(numnames);
870             my_strcodes = copy_code_list(strnames);
871         }
872 #else
873         else {
874             failed("no capability-lists available (use -i option)");
875         }
876 #endif /* USE_CODE_LISTS */
877         for (repeat = 0; repeat < r_opt; ++repeat) {
878             if (optind < argc) {
879                 for (n = optind; n < argc; ++n) {
880                     demo_terminfo(argv[n]);
881                 }
882             } else if ((name = getenv("TERM")) != 0) {
883                 demo_terminfo(name);
884             } else {
885                 static char dumb[] = "dumb";
886                 demo_terminfo(dumb);
887             }
888         }
889     }
890
891     printf("%ld values (%ld booleans, %ld numbers, %ld strings)\n",
892            total_values, total_b_values, total_n_values, total_s_values);
893
894 #ifdef NO_LEAKS
895     free_dblist();
896     if (my_blob != 0) {
897         free(my_blob);
898         free(my_boolcodes);
899         free(my_numcodes);
900         free(my_numvalues);
901         free(my_strcodes);
902         free(my_strvalues);
903     }
904 #endif
905
906     ExitProgram(EXIT_SUCCESS);
907 }
908
909 #else /* !HAVE_TIGETSTR */
910 int
911 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
912 {
913     printf("This program requires the terminfo functions such as tigetstr\n");
914     ExitProgram(EXIT_FAILURE);
915 }
916 #endif /* HAVE_TIGETSTR */