blob: 6e2aba7006798265886ac215f5642da343b72107 [file] [log] [blame]
Steve Kondikae271bc2015-11-15 02:50:53 +01001/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2019-2022,2023 Thomas E. Dickey *
3 * Copyright 2005-2016,2017 Free Software Foundation, Inc. *
Steve Kondikae271bc2015-11-15 02:50:53 +01004 * *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
12 * *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
15 * *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
27 * authorization. *
28 ****************************************************************************/
29
30/*
31 * Author: Thomas E. Dickey
32 *
micky3879b9f5e72025-07-08 18:04:53 -040033 * $Id: demo_termcap.c,v 1.65 2023/05/27 20:13:10 tom Exp $
Steve Kondikae271bc2015-11-15 02:50:53 +010034 *
35 * A simple demo of the termcap interface.
36 */
37#define USE_TINFO
38#include <test.priv.h>
39#include <sys/stat.h>
40
41#if NCURSES_XNAMES
42#if HAVE_TERM_ENTRY_H
43#include <term_entry.h>
44#else
45#undef NCURSES_XNAMES
46#define NCURSES_XNAMES 0
47#endif
48#endif
49
micky3879b9f5e72025-07-08 18:04:53 -040050#if defined(NCURSES_VERSION)
51#if HAVE_NCURSES_TERMCAP_H
52#include <ncurses/termcap.h>
53#elif HAVE_TERMCAP_H
Steve Kondikae271bc2015-11-15 02:50:53 +010054#include <termcap.h>
55#endif
micky3879b9f5e72025-07-08 18:04:53 -040056#endif
57
58static GCC_NORETURN void failed(const char *);
Steve Kondikae271bc2015-11-15 02:50:53 +010059
60static void
61failed(const char *msg)
62{
63 fprintf(stderr, "%s\n", msg);
64 ExitProgram(EXIT_FAILURE);
65}
66
67#if HAVE_TGETENT
68
69#if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
70#define USE_CODE_LISTS 1
71#else
72#define USE_CODE_LISTS 0
73#endif
74
75#define FCOLS 8
76#define FNAME(type) "%s %-*s = ", #type, FCOLS
77
78static bool b_opt = FALSE;
79static bool n_opt = FALSE;
80static bool s_opt = FALSE;
81static bool q_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -040082#ifdef NCURSES_VERSION
Steve Kondikae271bc2015-11-15 02:50:53 +010083static bool x_opt = FALSE;
84static bool y_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -040085#endif
Steve Kondikae271bc2015-11-15 02:50:53 +010086
87static char *d_opt;
88static char *e_opt;
89static char **db_list;
90static int db_item;
91
92static char *my_blob;
93static char **my_boolcodes;
94static char **my_numcodes;
95static char **my_numvalues;
96static char **my_strcodes;
97static char **my_strvalues;
98
99static long total_values;
100static long total_b_values;
101static long total_n_values;
102static long total_s_values;
103
104#define isCapName(c) (isgraph(c) && strchr("^=:\\", c) == 0)
105#define EachCapName(n) n = 33; n < 127; ++n
106
107static char *
micky3879b9f5e72025-07-08 18:04:53 -0400108make_dbitem(const char *const p, const char *const q)
Steve Kondikae271bc2015-11-15 02:50:53 +0100109{
micky3879b9f5e72025-07-08 18:04:53 -0400110 size_t need = strlen(e_opt) + 2 + (size_t) (p - q);
111 char *result = malloc(need);
112 _nc_SPRINTF(result, _nc_SLIMIT(need) "%s=%.*s", e_opt, (int) (p - q), q);
Steve Kondikae271bc2015-11-15 02:50:53 +0100113 return result;
114}
115
116static void
117make_dblist(void)
118{
119 if (d_opt && e_opt) {
120 int pass;
121
122 for (pass = 0; pass < 2; ++pass) {
123 char *p, *q;
124 size_t count = 0;
125
126 for (p = q = d_opt; *p != '\0'; ++p) {
127 if (*p == ':') {
128 if (p != q + 1) {
129 if (pass) {
130 db_list[count] = make_dbitem(p, q);
131 }
132 count++;
133 }
134 q = p + 1;
135 }
136 }
137 if (p != q + 1) {
138 if (pass) {
139 db_list[count] = make_dbitem(p, q);
140 }
141 count++;
142 }
143 if (!pass) {
144 db_list = typeCalloc(char *, count + 1);
145 }
146 }
147 }
148}
149
150static char *
151next_dbitem(void)
152{
153 char *result = 0;
154
155 if (db_list) {
156 if ((result = db_list[db_item]) == 0) {
157 db_item = 0;
158 result = db_list[0];
159 } else {
160 db_item++;
161 }
162 }
micky3879b9f5e72025-07-08 18:04:53 -0400163 if (result != 0)
164 printf("** %s\n", result);
Steve Kondikae271bc2015-11-15 02:50:53 +0100165 return result;
166}
167
micky3879b9f5e72025-07-08 18:04:53 -0400168#if NO_LEAKS
Steve Kondikae271bc2015-11-15 02:50:53 +0100169static void
170free_dblist(void)
171{
172 if (db_list) {
173 int n;
174 for (n = 0; db_list[n]; ++n)
175 free(db_list[n]);
176 free(db_list);
177 db_list = 0;
178 }
179}
micky3879b9f5e72025-07-08 18:04:53 -0400180#endif /* NO_LEAKS */
Steve Kondikae271bc2015-11-15 02:50:53 +0100181
182static void
183show_string(const char *name, const char *value)
184{
185 printf(FNAME(str), name);
186 if (value == ((char *) -1)) {
187 printf("CANCELLED");
188 } else if (value == ((char *) 0)) {
189 printf("ABSENT");
190 } else {
191 while (*value != 0) {
192 int ch = UChar(*value++);
193 switch (ch) {
194 case '\177':
195 fputs("^?", stdout);
196 break;
197 case '\033':
198 fputs("\\E", stdout);
199 break;
200 case '\b':
201 fputs("\\b", stdout);
202 break;
203 case '\f':
204 fputs("\\f", stdout);
205 break;
206 case '\n':
207 fputs("\\n", stdout);
208 break;
209 case '\r':
210 fputs("\\r", stdout);
211 break;
212 case ' ':
213 fputs("\\s", stdout);
214 break;
215 case '\t':
216 fputs("\\t", stdout);
217 break;
218 case '^':
219 fputs("\\^", stdout);
220 break;
221 case ':':
222 fputs("\\072", stdout);
223 break;
224 case '\\':
225 fputs("\\\\", stdout);
226 break;
227 default:
228 if (isgraph(ch))
229 fputc(ch, stdout);
230 else if (ch < 32)
231 printf("^%c", ch + '@');
232 else
233 printf("\\%03o", ch);
234 break;
235 }
236 }
237 }
238 printf("\n");
239}
240
241static void
242show_number(const char *name, int value)
243{
244 printf(FNAME(num), name);
245 printf(" %d\n", value);
246}
247
248static void
249dumpit(NCURSES_CONST char *cap)
250{
251 /*
252 * One of the limitations of the termcap interface is that the library
253 * cannot determine the size of the buffer passed via tgetstr(), nor the
254 * amount of space remaining. This demo simply reuses the whole buffer
255 * for each call; a normal termcap application would try to use the buffer
256 * to hold all of the strings extracted from the terminal entry.
257 */
258 char area[1024], *ap = area;
259 char *str;
260 int num;
261
262 if ((str = tgetstr(cap, &ap)) != 0) {
263 total_values++;
264 total_s_values++;
265 if (!q_opt) {
266 /*
267 * Note that the strings returned are mostly terminfo format, since
268 * ncurses does not convert except for a handful of special cases.
269 */
270 show_string(cap, str);
271 }
272 } else if ((num = tgetnum(cap)) >= 0) {
273 total_values++;
274 total_n_values++;
275 if (!q_opt) {
276 show_number(cap, num);
277 }
278 } else if (tgetflag(cap) > 0) {
279 total_values++;
280 total_b_values++;
281 if (!q_opt) {
282 printf(FNAME(flg), cap);
283 printf("%s\n", "true");
284 }
285 }
286
287 if (!q_opt)
288 fflush(stdout);
289}
290
291static void
292brute_force(const char *name)
293{
294 char buffer[1024];
295
296 if (db_list) {
297 putenv(next_dbitem());
298 }
299 if (!q_opt)
300 printf("Terminal type \"%s\"\n", name);
301 if (tgetent(buffer, name) >= 0) {
302 char cap[3];
303 int c1, c2;
304
305 cap[2] = 0;
306 for (EachCapName(c1)) {
307 cap[0] = (char) c1;
308 if (isCapName(c1)) {
309 for (EachCapName(c2)) {
310 cap[1] = (char) c2;
311 if (isCapName(c2)) {
312 dumpit(cap);
313 }
314 }
315 }
316 }
317 }
318}
319
320#if NCURSES_XNAMES
321static void
322dump_xname(NCURSES_CONST char *cap)
323{
324 if (strlen(cap) == 2)
325 dumpit(cap);
326}
327#endif
328
329static void
330demo_termcap(NCURSES_CONST char *name)
331{
Steve Kondikae271bc2015-11-15 02:50:53 +0100332 char buffer[1024];
333
334 if (db_list) {
335 putenv(next_dbitem());
336 }
337 if (!q_opt)
338 printf("Terminal type \"%s\"\n", name);
339 if (tgetent(buffer, name) >= 0) {
micky3879b9f5e72025-07-08 18:04:53 -0400340 NCURSES_CONST char *cap;
341 unsigned n;
Steve Kondikae271bc2015-11-15 02:50:53 +0100342
343 if (b_opt) {
344 for (n = 0;; ++n) {
345 cap = my_boolcodes[n];
346 if (cap == 0)
347 break;
348 dumpit(cap);
349 }
350 }
351
352 if (n_opt) {
353 for (n = 0;; ++n) {
354 cap = my_numcodes[n];
355 if (cap == 0)
356 break;
357 dumpit(cap);
358 }
359 }
360
361 if (s_opt) {
362 for (n = 0;; ++n) {
363 cap = my_strcodes[n];
364 if (cap == 0)
365 break;
366 dumpit(cap);
367 }
368 }
369#ifdef NCURSES_VERSION
370 if (x_opt && (my_blob == 0) && y_opt) {
371#if NCURSES_XNAMES
micky3879b9f5e72025-07-08 18:04:53 -0400372 TERMTYPE *term = (TERMTYPE *) cur_term;
Steve Kondikae271bc2015-11-15 02:50:53 +0100373 if (term != 0
374 && ((NUM_BOOLEANS(term) != BOOLCOUNT)
375 || (NUM_NUMBERS(term) != NUMCOUNT)
376 || (NUM_STRINGS(term) != STRCOUNT))) {
377 for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
378 dump_xname(ExtBoolname(term, (int) n, boolnames));
379 }
380 for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
381 dump_xname(ExtNumname(term, (int) n, numnames));
382 }
383 for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
384 dump_xname(ExtStrname(term, (int) n, strnames));
385 }
386 }
387#endif
388 }
389#endif
390 }
391}
392
393typedef enum {
394 pDefault = 0
395 ,pComment
396 ,pDescription
397 ,pEscaped
398 ,pNewline
399 ,pName
400 ,pNumber
401 ,pString
402} STATE;
403
404static void
405parse_description(const char *input_name)
406{
micky3879b9f5e72025-07-08 18:04:53 -0400407 static char empty[1] =
408 {0};
Steve Kondikae271bc2015-11-15 02:50:53 +0100409
410 FILE *fp;
411 struct stat sb;
412 size_t count_bools = 0;
413 size_t count_nums = 0;
414 size_t count_strs = 0;
415 size_t len;
416 size_t j, k;
417 STATE state;
418
419 if (stat(input_name, &sb) != 0
420 || (sb.st_mode & S_IFMT) != S_IFREG) {
421 failed("input is not a file");
422 }
423
424 if (sb.st_size == 0) {
425 failed("input is empty");
426 }
427
428 /*
429 * None of the arrays could be larger than the input-file, and since it
430 * is small, just allocate the maximum for simplicity.
431 */
432 if ((my_blob = malloc((size_t) sb.st_size + 1)) == 0 ||
433 (my_boolcodes = typeCalloc(char *, sb.st_size)) == 0 ||
434 (my_numcodes = typeCalloc(char *, sb.st_size)) == 0 ||
435 (my_numvalues = typeCalloc(char *, sb.st_size)) == 0 ||
436 (my_strcodes = typeCalloc(char *, sb.st_size)) == 0 ||
437 (my_strvalues = typeCalloc(char *, sb.st_size)) == 0) {
438 failed("cannot allocate memory for input-file");
439 }
440
micky3879b9f5e72025-07-08 18:04:53 -0400441 if ((fp = fopen(input_name, "r")) == 0) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100442 failed("cannot open input-file");
micky3879b9f5e72025-07-08 18:04:53 -0400443 } else {
444 len = fread(my_blob, sizeof(char), (size_t) sb.st_size, fp);
445 my_blob[sb.st_size] = '\0';
446 fclose(fp);
447 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100448
449 /*
450 * First, get rid of comments and escaped newlines, as well as repeated
451 * colons to construct a canonical entry.
452 *
453 * FIXME: actually this should make an additional pass just to strip
454 * comment-lines and escaped newlines. But it is workable for infocmp
455 * output.
456 */
457 state = pNewline;
458 for (j = k = 0; j < len; ++j) {
459 int ch = my_blob[j];
460 if (ch == '\t') {
461 ch = ' ';
462 }
463 switch (state) {
464 case pNewline:
465 if (ch == ' ') {
466 continue;
467 }
468 if (ch == '#') {
469 state = pComment;
470 continue;
471 }
472 state = pDefault;
473 /* FALLTHRU */
474 case pDefault:
475 switch (ch) {
476 case '|':
477 state = pDescription;
478 continue;
479 case '\\':
480 state = pEscaped;
481 continue;
482 case '\n':
483 state = pNewline;
484 continue;
485 case ' ':
486 case ':':
487 break;
488 default:
489 state = pName;
490 break;
491 }
492 my_blob[k++] = (char) ch;
493 break;
494 case pComment:
495 if (ch == '\n')
496 state = pNewline;
497 break;
498 case pDescription:
499 switch (ch) {
500 case ':':
501 state = pDefault;
502 break;
503 case '\n':
504 state = pNewline;
505 break;
506 }
507 break;
508 case pEscaped:
509 if (ch != '\n') {
510 my_blob[k++] = (char) ch;
511 state = pDefault;
512 } else {
513 state = pNewline;
514 }
515 break;
516 case pName:
517 switch (ch) {
518 case '\n':
519 state = pNewline;
520 continue;
521 case ' ':
522 case ':':
523 state = pDefault;
524 break;
525 case '#':
526 state = pNumber;
527 break;
528 case '|':
529 state = pDescription;
530 continue;
531 }
532 my_blob[k++] = (char) ch;
533 break;
534 case pNumber:
535 switch (ch) {
536 case '\n':
537 state = pNewline;
538 continue;
539 case ':':
540 state = pDefault;
541 break;
542 case ' ':
543 state = pDefault;
544 continue;
545 }
546 my_blob[k++] = (char) ch;
547 break;
548 case pString:
549 switch (ch) {
550 case '\\':
551 if (my_blob[j + 1] == '\0') {
552 state = pDefault;
553 continue;
554 }
555 break;
556 case '\n':
557 state = pNewline;
558 continue;
559 case ':':
560 state = pDefault;
561 break;
562 }
563 my_blob[k++] = (char) ch;
564 break;
565 default:
566 /* not used */
567 break;
568 }
569 }
570 my_blob[k] = '\0';
571
572 /*
573 * Then, parse what's left, making indexes of the names and values.
574 */
575 state = pDefault;
576 for (j = 0; my_blob[j] != '\0'; ++j) {
577 switch (state) {
578 case pDefault:
579 switch (my_blob[j]) {
580 case '\\':
581 state = pEscaped;
582 break;
583 case ':':
584 my_blob[j] = '\0';
585 if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ':')
586 state = pName;
587 break;
588 case ' ':
589 break;
590 default:
591 break;
592 }
593 case pEscaped:
594 break;
595 case pName:
596 state = pDefault;
597 /*
598 * Commented-out capabilities might be accessible (they are in
599 * ncurses).
600 */
601 if (my_blob[j] == '.' && my_blob[j + 1] == '.') {
602 j += 2;
603 }
604 if (my_blob[j + 1] != '\0') {
605 switch (my_blob[j + 2]) {
606 case '#':
607 my_numvalues[count_nums] = &my_blob[j + 3];
608 my_numcodes[count_nums++] = &my_blob[j];
609 my_blob[j + 2] = '\0';
610 state = pNumber;
611 j += 2;
612 break;
613 case '=':
614 my_strvalues[count_strs] = &my_blob[j + 3];
615 my_strcodes[count_strs++] = &my_blob[j];
616 my_blob[j + 2] = '\0';
617 state = pString;
618 j += 2;
619 break;
620 default:
621 if (my_blob[j + 2] == '@') {
622 /*
623 * We cannot get the type for a cancelled item
624 * directly, but can infer it assuming the input
625 * came from infocmp, which puts the data in a
626 * known order.
627 */
628 if (count_strs) {
629 my_strvalues[count_strs] = empty;
630 my_strcodes[count_strs++] = &my_blob[j];
631 } else if (count_nums) {
632 my_numvalues[count_nums] = empty;
633 my_numcodes[count_nums++] = &my_blob[j];
634 } else {
635 my_boolcodes[count_bools++] = &my_blob[j];
636 }
637 } else {
638 my_boolcodes[count_bools++] = &my_blob[j];
639 }
640 j++;
641 break;
642 }
643 }
644 break;
645 case pNumber:
646 if (!isdigit(UChar(my_blob[j]))) {
647 --j;
648 state = pDefault;
649 }
650 break;
651 case pString:
652 switch (my_blob[j]) {
653 case '\\':
654 if (my_blob[j + 1] == '\0') {
655 state = pDefault;
656 continue;
657 } else {
658 ++j;
659 }
660 break;
661 case '\n':
662 state = pNewline;
663 continue;
664 case ':':
665 --j;
666 state = pDefault;
667 break;
668 }
669 break;
670 case pNewline:
671 case pComment:
672 case pDescription:
673 default:
674 break;
675 }
676 }
677 my_boolcodes[count_bools] = 0;
678 my_numcodes[count_nums] = 0;
679 my_numvalues[count_nums] = 0;
680 my_strcodes[count_strs] = 0;
681 my_strvalues[count_strs] = 0;
682
683#if 0
684 printf("bools:%d\n", (int) count_bools);
685 for (j = 0; my_boolcodes[j]; ++j)
686 printf("%5d:%s\n", (int) j, my_boolcodes[j]);
687
688 printf("numbers:%d\n", (int) count_nums);
689 for (j = 0; my_numcodes[j]; ++j)
690 printf("%5d:%s(%s)\n", (int) j, my_numcodes[j], my_numvalues[j]);
691
692 printf("strings:%d\n", (int) count_strs);
693 for (j = 0; my_strcodes[j]; ++j)
694 printf("%5d:%s(%s)\n", (int) j, my_strcodes[j], my_strvalues[j]);
695#endif
696}
697
698#if USE_CODE_LISTS
699static char **
700copy_code_list(NCURSES_CONST char *const *list)
701{
702 int pass;
703 size_t count;
704 size_t length = 1;
705 char **result = 0;
Steve Kondikae271bc2015-11-15 02:50:53 +0100706 char *unused = 0;
707
708 for (pass = 0; pass < 2; ++pass) {
709 for (count = 0; list[count] != 0; ++count) {
710 size_t chunk = strlen(list[count]) + 1;
711 if (pass == 0) {
712 length += chunk;
713 } else {
714 result[count] = unused;
micky3879b9f5e72025-07-08 18:04:53 -0400715 _nc_STRCPY(unused, list[count], length);
Steve Kondikae271bc2015-11-15 02:50:53 +0100716 unused += chunk;
717 }
718 }
719 if (pass == 0) {
micky3879b9f5e72025-07-08 18:04:53 -0400720 char *blob = malloc(length);
Steve Kondikae271bc2015-11-15 02:50:53 +0100721 result = typeCalloc(char *, count + 1);
722 unused = blob;
723 if (blob == 0 || result == 0)
724 failed("copy_code_list failed");
725 }
726 }
727
728 return result;
729}
micky3879b9f5e72025-07-08 18:04:53 -0400730
731#if NO_LEAKS
732static void
733free_code_list(char **list)
734{
735 if (list) {
736 free(list[0]);
737 free(list);
738 }
739}
740#endif /* NO_LEAKS */
741#endif /* USE_CODE_LISTS */
Steve Kondikae271bc2015-11-15 02:50:53 +0100742
743static void
micky3879b9f5e72025-07-08 18:04:53 -0400744usage(int ok)
Steve Kondikae271bc2015-11-15 02:50:53 +0100745{
746 static const char *msg[] =
747 {
micky3879b9f5e72025-07-08 18:04:53 -0400748 "Usage: demo_termcap [options] [terminal]"
749 ,""
750 ,"If no options are given, print all (boolean, numeric, string)"
751 ,"capabilities for the given terminal, using short names."
752 ,""
753 ,USAGE_COMMON
754 ,"Options:"
755 ," -a try all names, print capabilities found"
756 ," -b print boolean-capabilities"
757 ," -d LIST colon-separated list of databases to use"
758 ," -e NAME environment variable to set with -d option"
759 ," -i NAME terminal description to use as names for \"-a\" option, etc."
760 ," -n print numeric-capabilities"
761 ," -q quiet (prints only counts)"
762 ," -r COUNT repeat for given count"
763 ," -s print string-capabilities"
764 ," -v print termcap-variables"
Steve Kondikae271bc2015-11-15 02:50:53 +0100765#ifdef NCURSES_VERSION
micky3879b9f5e72025-07-08 18:04:53 -0400766 ," -x print extended capabilities"
Steve Kondikae271bc2015-11-15 02:50:53 +0100767#endif
768 };
769 unsigned n;
770 for (n = 0; n < SIZEOF(msg); ++n) {
771 fprintf(stderr, "%s\n", msg[n]);
772 }
micky3879b9f5e72025-07-08 18:04:53 -0400773 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100774}
micky3879b9f5e72025-07-08 18:04:53 -0400775/* *INDENT-OFF* */
776VERSION_COMMON()
777/* *INDENT-ON* */
Steve Kondikae271bc2015-11-15 02:50:53 +0100778
779int
780main(int argc, char *argv[])
781{
micky3879b9f5e72025-07-08 18:04:53 -0400782 int ch;
Steve Kondikae271bc2015-11-15 02:50:53 +0100783 int n;
784 char *name;
785 bool a_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -0400786#if defined(NCURSES_VERSION) || defined(HAVE_CURSES_DATA_OSPEED)
Steve Kondikae271bc2015-11-15 02:50:53 +0100787 bool v_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -0400788#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100789 char *input_name = 0;
790
791 int repeat;
792 int r_opt = 1;
793
micky3879b9f5e72025-07-08 18:04:53 -0400794 while ((ch = getopt(argc, argv, OPTS_COMMON "abd:e:i:nqr:svxy")) != -1) {
795 switch (ch) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100796 case 'a':
797 a_opt = TRUE;
798 break;
799 case 'b':
800 b_opt = TRUE;
801 break;
802 case 'd':
803 d_opt = optarg;
804 break;
805 case 'e':
806 e_opt = optarg;
807 break;
808 case 'i':
809 input_name = optarg;
810 break;
811 case 'n':
812 n_opt = TRUE;
813 break;
814 case 'q':
815 q_opt = TRUE;
816 break;
817 case 'r':
818 if ((r_opt = atoi(optarg)) <= 0)
micky3879b9f5e72025-07-08 18:04:53 -0400819 usage(FALSE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100820 break;
821 case 's':
822 s_opt = TRUE;
823 break;
micky3879b9f5e72025-07-08 18:04:53 -0400824#if defined(NCURSES_VERSION) || defined(HAVE_CURSES_DATA_OSPEED)
Steve Kondikae271bc2015-11-15 02:50:53 +0100825 case 'v':
826 v_opt = TRUE;
827 break;
micky3879b9f5e72025-07-08 18:04:53 -0400828#endif
829#ifdef NCURSES_VERSION
Steve Kondikae271bc2015-11-15 02:50:53 +0100830#if NCURSES_XNAMES
831 case 'x':
832 x_opt = TRUE;
833 break;
834 case 'y':
835 y_opt = TRUE;
836 x_opt = TRUE;
837 break;
838#endif
micky3879b9f5e72025-07-08 18:04:53 -0400839#endif
840 case OPTS_VERSION:
841 show_version(argv);
842 ExitProgram(EXIT_SUCCESS);
Steve Kondikae271bc2015-11-15 02:50:53 +0100843 default:
micky3879b9f5e72025-07-08 18:04:53 -0400844 usage(ch == OPTS_USAGE);
845 /* NOTREACHED */
Steve Kondikae271bc2015-11-15 02:50:53 +0100846 }
847 }
848
849#if HAVE_USE_EXTENDED_NAMES
850 use_extended_names(x_opt);
851#endif
852
853 if (!(b_opt || n_opt || s_opt)) {
854 b_opt = TRUE;
855 n_opt = TRUE;
856 s_opt = TRUE;
857 }
858
859 make_dblist();
860
861 if (a_opt) {
862 for (repeat = 0; repeat < r_opt; ++repeat) {
863 if (optind < argc) {
864 for (n = optind; n < argc; ++n) {
865 brute_force(argv[n]);
866 }
867 } else if ((name = getenv("TERM")) != 0) {
868 brute_force(name);
869 } else {
870 static char dumb[] = "dumb";
871 brute_force(dumb);
872 }
873 }
874 } else {
875 if (input_name != 0) {
876 parse_description(input_name);
877 }
878#if USE_CODE_LISTS
879 else {
880 my_boolcodes = copy_code_list(boolcodes);
881 my_numcodes = copy_code_list(numcodes);
882 my_strcodes = copy_code_list(strcodes);
883 }
884#else
885 else {
886 failed("no capability-lists available (use -i option)");
887 }
888#endif /* USE_CODE_LISTS */
889 for (repeat = 0; repeat < r_opt; ++repeat) {
890 if (optind < argc) {
891 for (n = optind; n < argc; ++n) {
892 demo_termcap(argv[n]);
893 }
894 } else if ((name = getenv("TERM")) != 0) {
895 demo_termcap(name);
896 } else {
897 static char dumb[] = "dumb";
898 demo_termcap(dumb);
899 }
900 }
901 }
902
903 printf("%ld values (%ld booleans, %ld numbers, %ld strings)\n",
904 total_values, total_b_values, total_n_values, total_s_values);
905
906#if defined(NCURSES_VERSION) || defined(HAVE_CURSES_DATA_OSPEED)
907 if (v_opt) {
908 show_number("PC", PC);
909 show_string("UP", UP);
910 show_string("BC", BC);
micky3879b9f5e72025-07-08 18:04:53 -0400911 show_number("ospeed", (int) ospeed);
Steve Kondikae271bc2015-11-15 02:50:53 +0100912 }
913#endif
914
micky3879b9f5e72025-07-08 18:04:53 -0400915#if NO_LEAKS
Steve Kondikae271bc2015-11-15 02:50:53 +0100916 free_dblist();
micky3879b9f5e72025-07-08 18:04:53 -0400917#if USE_CODE_LISTS
918 free_code_list(my_boolcodes);
919 free_code_list(my_numcodes);
920 free_code_list(my_strcodes);
921#endif
922#endif /* NO_LEAKS */
Steve Kondikae271bc2015-11-15 02:50:53 +0100923
924 ExitProgram(EXIT_SUCCESS);
925}
926
927#else
928int
micky3879b9f5e72025-07-08 18:04:53 -0400929main(void)
Steve Kondikae271bc2015-11-15 02:50:53 +0100930{
931 failed("This program requires termcap");
932}
933#endif