blob: 5e78015c36e0d45709a2fcda7fbc8546e57434c0 [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 2009-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_terminfo.c,v 1.57 2023/05/27 20:13:10 tom Exp $
Steve Kondikae271bc2015-11-15 02:50:53 +010034 *
35 * A simple demo of the terminfo 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 -040050static GCC_NORETURN void failed(const char *);
51
Steve Kondikae271bc2015-11-15 02:50:53 +010052static void
53failed(const char *msg)
54{
55 fprintf(stderr, "%s\n", msg);
56 ExitProgram(EXIT_FAILURE);
57}
58
59#if HAVE_TIGETSTR
60
61#if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
62#define USE_CODE_LISTS 1
63#else
64#define USE_CODE_LISTS 0
65#endif
66
67static bool a_opt = FALSE;
68static bool b_opt = FALSE;
69static bool f_opt = FALSE;
70static bool n_opt = FALSE;
71static bool q_opt = FALSE;
72static bool s_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -040073#ifdef NCURSES_VERSION
Steve Kondikae271bc2015-11-15 02:50:53 +010074static bool x_opt = FALSE;
75static bool y_opt = FALSE;
micky3879b9f5e72025-07-08 18:04:53 -040076#endif
Steve Kondikae271bc2015-11-15 02:50:53 +010077
78static char *d_opt;
79static char *e_opt;
80static char **db_list;
81static int db_item;
82
83static char *my_blob;
84static char **my_boolcodes;
85static char **my_numcodes;
86static char **my_numvalues;
87static char **my_strcodes;
88static char **my_strvalues;
89
90static long total_values;
91static long total_b_values;
92static long total_n_values;
93static long total_s_values;
94
95#define FCOLS 8
micky3879b9f5e72025-07-08 18:04:53 -040096#define FNAME(type) "%s %-*s = ", #type, f_opt ? 24 : FCOLS
Steve Kondikae271bc2015-11-15 02:50:53 +010097
98static char *
micky3879b9f5e72025-07-08 18:04:53 -040099make_dbitem(const char *const p, const char *const q)
Steve Kondikae271bc2015-11-15 02:50:53 +0100100{
micky3879b9f5e72025-07-08 18:04:53 -0400101 size_t need = strlen(e_opt) + 2 + (size_t) (p - q);
102 char *result = malloc(need);
103 _nc_SPRINTF(result, _nc_SLIMIT(need) "%s=%.*s", e_opt, (int) (p - q), q);
Steve Kondikae271bc2015-11-15 02:50:53 +0100104 return result;
105}
106
107static void
108make_dblist(void)
109{
110 if (d_opt && e_opt) {
111 int pass;
112
113 for (pass = 0; pass < 2; ++pass) {
114 char *p, *q;
115 size_t count = 0;
116
117 for (p = q = d_opt; *p != '\0'; ++p) {
118 if (*p == ':') {
119 if (p != q + 1) {
120 if (pass) {
121 db_list[count] = make_dbitem(p, q);
122 }
123 count++;
124 }
125 q = p + 1;
126 }
127 }
128 if (p != q + 1) {
129 if (pass) {
130 db_list[count] = make_dbitem(p, q);
131 }
132 count++;
133 }
134 if (!pass) {
135 db_list = typeCalloc(char *, count + 1);
136 }
137 }
138 }
139}
140
141static char *
142next_dbitem(void)
143{
144 char *result = 0;
145
146 if (db_list) {
147 if ((result = db_list[db_item]) == 0) {
148 db_item = 0;
149 result = db_list[0];
150 } else {
151 db_item++;
152 }
153 }
micky3879b9f5e72025-07-08 18:04:53 -0400154 if (result != 0)
155 printf("** %s\n", result);
Steve Kondikae271bc2015-11-15 02:50:53 +0100156 return result;
157}
158
micky3879b9f5e72025-07-08 18:04:53 -0400159#if NO_LEAKS
Steve Kondikae271bc2015-11-15 02:50:53 +0100160static void
161free_dblist(void)
162{
163 if (db_list) {
164 int n;
165 for (n = 0; db_list[n]; ++n)
166 free(db_list[n]);
167 free(db_list);
168 db_list = 0;
169 }
170}
171#endif
172
173static void
micky3879b9f5e72025-07-08 18:04:53 -0400174dumpit(NCURSES_CONST char *cap, const char *show)
Steve Kondikae271bc2015-11-15 02:50:53 +0100175{
176 const char *str;
177 int num;
178
179 if ((str = tigetstr(cap)) != 0 && (str != (char *) -1)) {
180 total_values++;
181 total_s_values++;
182 if (!q_opt) {
micky3879b9f5e72025-07-08 18:04:53 -0400183 printf(FNAME(str), show ? show : cap);
Steve Kondikae271bc2015-11-15 02:50:53 +0100184 while (*str != 0) {
185 int ch = UChar(*str++);
186 switch (ch) {
187 case '\177':
188 fputs("^?", stdout);
189 break;
190 case '\033':
191 fputs("\\E", stdout);
192 break;
193 case '\b':
194 fputs("\\b", stdout);
195 break;
196 case '\f':
197 fputs("\\f", stdout);
198 break;
199 case '\n':
200 fputs("\\n", stdout);
201 break;
202 case '\r':
203 fputs("\\r", stdout);
204 break;
205 case ' ':
206 fputs("\\s", stdout);
207 break;
208 case '\t':
209 fputs("\\t", stdout);
210 break;
211 case '^':
212 fputs("\\^", stdout);
213 break;
214 case ':':
215 fputs("\\072", stdout);
216 break;
217 case '\\':
218 fputs("\\\\", stdout);
219 break;
220 default:
221 if (isgraph(ch))
222 fputc(ch, stdout);
223 else if (ch < 32)
224 printf("^%c", ch + '@');
225 else
226 printf("\\%03o", ch);
227 break;
228 }
229 }
230 printf("\n");
231 }
232 } else if ((num = tigetnum(cap)) >= 0) {
233 total_values++;
234 total_n_values++;
235 if (!q_opt) {
micky3879b9f5e72025-07-08 18:04:53 -0400236 printf(FNAME(num), show ? show : cap);
Steve Kondikae271bc2015-11-15 02:50:53 +0100237 printf(" %d\n", num);
238 }
239 } else if ((num = tigetflag(cap)) >= 0) {
240 total_values++;
241 total_b_values++;
242 if (!q_opt) {
micky3879b9f5e72025-07-08 18:04:53 -0400243 printf(FNAME(flg), show ? show : cap);
Steve Kondikae271bc2015-11-15 02:50:53 +0100244 printf("%s\n", num ? "true" : "false");
245 }
246 }
247
248 if (!q_opt)
249 fflush(stdout);
250}
251
252#define isCapName(c) (isalnum(UChar(c)) || ((c) == '_'))
253#define LegalItem(c,n) (n)
254
255static void
256brute_force(const char *name)
257{
258#define MAX_FORCE 5 /* omit "colors", since CPU-time is a problem */
259 static const char legal[] = "\
2600123456789\
261ABCDEFGHIJKLMNOPQRSTUVWXYZ\
262abcdefghijklmnopqrstuvwxyz_";
263 int length;
264 int j, k;
265 bool carry;
266 bool changed;
267 char cap[MAX_FORCE + 1];
268 int item[MAX_FORCE + 1];
269
270 if (db_list) {
271 putenv(next_dbitem());
272 }
273 if (!q_opt)
274 printf("Terminal type \"%s\"\n", name);
275 setupterm((NCURSES_CONST char *) name, 1, (int *) 0);
276 if (!q_opt) {
277 if (strcmp(name, ttytype))
278 printf("... actual \"%s\"\n", ttytype);
279 }
280
281 for (length = 1; length <= MAX_FORCE; ++length) {
282 /* set all digits to zeros */
283 for (j = 0; j < length; ++j) {
284 item[j] = LegalItem(j, 0);
285 }
286
287 do {
288 changed = FALSE;
289 /* copy digits to cap-name */
290 for (j = 0; j < length; ++j) {
291 cap[j] = legal[item[j]];
292 }
293 cap[length] = '\0';
micky3879b9f5e72025-07-08 18:04:53 -0400294 dumpit(cap, NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +0100295
296 k = length - 1;
297 do {
298 carry = FALSE;
299 for (; k >= 0; --k) {
300 item[k] += 1;
301 if (legal[item[k]]) {
302 changed = TRUE;
303 break;
304 }
305 if (k > 0 &&
306 legal[item[k - 1] + 1]) {
307 for (j = k; j < length; ++j) {
308 item[j] = LegalItem(j, 0);
309 }
310 carry = TRUE;
311 changed = TRUE;
312 }
313 }
314 } while (carry);
315 } while (changed);
316 }
317 del_curterm(cur_term);
318}
319
320#if USE_CODE_LISTS
micky3879b9f5e72025-07-08 18:04:53 -0400321#define fullname(type,n) f_opt ? type##fnames[n] : cap
Steve Kondikae271bc2015-11-15 02:50:53 +0100322#else
micky3879b9f5e72025-07-08 18:04:53 -0400323#define fullname(type,n) cap
Steve Kondikae271bc2015-11-15 02:50:53 +0100324#endif
325
326static void
327demo_terminfo(char *name)
328{
329 unsigned n;
330 NCURSES_CONST char *cap;
331
332 if (db_list) {
333 putenv(next_dbitem());
334 }
335 if (!q_opt)
336 printf("Terminal type \"%s\"\n", name);
337 setupterm(name, 1, (int *) 0);
338
339 if (b_opt) {
340 for (n = 0;; ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400341 cap = my_boolcodes[n];
Steve Kondikae271bc2015-11-15 02:50:53 +0100342 if (cap == 0)
343 break;
micky3879b9f5e72025-07-08 18:04:53 -0400344 dumpit(cap, fullname(bool, n));
Steve Kondikae271bc2015-11-15 02:50:53 +0100345 }
346 }
347
348 if (n_opt) {
349 for (n = 0;; ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400350 cap = my_numcodes[n];
Steve Kondikae271bc2015-11-15 02:50:53 +0100351 if (cap == 0)
352 break;
micky3879b9f5e72025-07-08 18:04:53 -0400353 dumpit(cap, fullname(num, n));
Steve Kondikae271bc2015-11-15 02:50:53 +0100354 }
355 }
356
357 if (s_opt) {
358 for (n = 0;; ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400359 cap = my_strcodes[n];
Steve Kondikae271bc2015-11-15 02:50:53 +0100360 if (cap == 0)
361 break;
micky3879b9f5e72025-07-08 18:04:53 -0400362 dumpit(cap, fullname(str, n));
Steve Kondikae271bc2015-11-15 02:50:53 +0100363 }
364 }
365#ifdef NCURSES_VERSION
366 if (x_opt && (my_blob == 0)) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100367 if (y_opt) {
368#if NCURSES_XNAMES
micky3879b9f5e72025-07-08 18:04:53 -0400369 TERMTYPE *term = (TERMTYPE *) cur_term;
Steve Kondikae271bc2015-11-15 02:50:53 +0100370 if (term != 0
371 && ((NUM_BOOLEANS(term) != BOOLCOUNT)
372 || (NUM_NUMBERS(term) != NUMCOUNT)
373 || (NUM_STRINGS(term) != STRCOUNT))) {
374 for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400375 dumpit(ExtBoolname(term, (int) n, boolnames), NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +0100376 }
377 for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400378 dumpit(ExtNumname(term, (int) n, numnames), NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +0100379 }
380 for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400381 dumpit(ExtStrname(term, (int) n, strnames), NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +0100382 }
383 }
384#endif
385 } else {
386 char temp[80];
387 static const char *xterm_keys[] =
388 {
389 "kDC", "kDN", "kEND", "kHOM", "kIC",
390 "kLFT", "kNXT", "kPRV", "kRIT", "kUP",
391 };
392 for (n = 0; n < SIZEOF(xterm_keys); ++n) {
micky3879b9f5e72025-07-08 18:04:53 -0400393 int mod;
Steve Kondikae271bc2015-11-15 02:50:53 +0100394 for (mod = 0; mod < 8; ++mod) {
395 if (mod == 0) {
396 /* these happen to be standard - avoid duplicates */
397 if (!strcmp(xterm_keys[n], "kDC") ||
398 !strcmp(xterm_keys[n], "kEND") ||
399 !strcmp(xterm_keys[n], "kHOM") ||
400 !strcmp(xterm_keys[n], "kLFT") ||
401 !strcmp(xterm_keys[n], "kRIT")) {
402 continue;
403 }
micky3879b9f5e72025-07-08 18:04:53 -0400404 _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
405 "%.*s", 8, xterm_keys[n]);
Steve Kondikae271bc2015-11-15 02:50:53 +0100406 } else {
micky3879b9f5e72025-07-08 18:04:53 -0400407 _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
408 "%.*s%d", 8, xterm_keys[n], mod);
Steve Kondikae271bc2015-11-15 02:50:53 +0100409 }
micky3879b9f5e72025-07-08 18:04:53 -0400410 dumpit(temp, NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +0100411 }
412 }
413 }
414 }
415#endif
416 del_curterm(cur_term);
417}
418
419typedef enum {
420 pDefault = 0
421 ,pComment
422 ,pDescription
423 ,pEscaped
424 ,pNewline
425 ,pName
426 ,pNumber
427 ,pString
428} STATE;
429
430static void
431parse_description(const char *input_name)
432{
micky3879b9f5e72025-07-08 18:04:53 -0400433 static char empty[1] =
434 {0};
Steve Kondikae271bc2015-11-15 02:50:53 +0100435
436 FILE *fp;
437 struct stat sb;
438 size_t count_bools = 0;
439 size_t count_nums = 0;
440 size_t count_strs = 0;
441 size_t len;
442 size_t j, k, jl;
443 STATE state;
444
445 if (stat(input_name, &sb) != 0
446 || (sb.st_mode & S_IFMT) != S_IFREG) {
447 failed("input is not a file");
448 }
449
450 if (sb.st_size == 0) {
451 failed("input is empty");
452 }
453
454 /*
455 * None of the arrays could be larger than the input-file, and since it
456 * is small, just allocate the maximum for simplicity.
457 */
458 if ((my_blob = malloc((size_t) sb.st_size + 1)) == 0 ||
459 (my_boolcodes = typeCalloc(char *, sb.st_size)) == 0 ||
460 (my_numcodes = typeCalloc(char *, sb.st_size)) == 0 ||
461 (my_numvalues = typeCalloc(char *, sb.st_size)) == 0 ||
462 (my_strcodes = typeCalloc(char *, sb.st_size)) == 0 ||
463 (my_strvalues = typeCalloc(char *, sb.st_size)) == 0) {
464 failed("cannot allocate memory for input-file");
465 }
466
micky3879b9f5e72025-07-08 18:04:53 -0400467 if ((fp = fopen(input_name, "r")) == 0) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100468 failed("cannot open input-file");
micky3879b9f5e72025-07-08 18:04:53 -0400469 } else {
470 len = fread(my_blob, sizeof(char), (size_t) sb.st_size, fp);
471 my_blob[sb.st_size] = '\0';
472 fclose(fp);
473 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100474
475 /*
476 * First, get rid of comments and escaped newlines, as well as repeated
477 * colons to construct a canonical entry.
478 */
479 state = pNewline;
480 for (j = k = 0; j < len; ++j) {
481 int ch = my_blob[j];
482 if (ch == '\t') {
483 ch = ' ';
484 }
485 switch (state) {
486 case pNewline:
487 if (ch == ' ') {
488 continue;
489 }
490 if (ch == '#') {
491 state = pComment;
492 continue;
493 }
494 state = pDefault;
495 /* FALLTHRU */
496 case pDefault:
497 switch (ch) {
498 case '|':
499 state = pDescription;
500 continue;
501 case '\\':
502 state = pEscaped;
503 continue;
504 case '\n':
505 state = pNewline;
506 continue;
507 case ' ':
508 break;
509 case ',':
510 my_blob[k++] = (char) ch;
511 break;
512 default:
513 if (isalpha(UChar(ch)))
514 state = pName;
515 else
516 fprintf(stderr, "OOPS @%d:%.20s\n", __LINE__, my_blob + j);
517 my_blob[k++] = (char) ch;
518 break;
519 }
520 break;
521 case pComment:
522 if (ch == '\n')
523 state = pNewline;
524 break;
525 case pDescription:
526 switch (ch) {
527 case ',':
528 state = pDefault;
529 break;
530 case '\n':
531 state = pNewline;
532 break;
533 }
534 break;
535 case pEscaped:
536 if (ch != '\n') {
537 my_blob[k++] = (char) ch;
538 state = pDefault;
539 } else {
540 state = pNewline;
541 }
542 break;
543 case pName:
544 switch (ch) {
545 case '\n':
546 state = pNewline;
547 continue;
548 case ' ':
549 case ',':
550 state = pDefault;
551 break;
552 case '#':
553 state = pNumber;
554 break;
555 case '=':
556 state = pString;
557 break;
558 case '|':
559 state = pDescription;
560 continue;
561 }
562 my_blob[k++] = (char) ch;
563 break;
564 case pNumber:
565 switch (ch) {
566 case '\n':
567 state = pNewline;
568 continue;
569 case ',':
570 state = pDefault;
571 break;
572 case ' ':
573 state = pDefault;
574 continue;
575 }
576 my_blob[k++] = (char) ch;
577 break;
578 case pString:
579 switch (ch) {
580 case '\n':
581 state = pNewline;
582 break;
583 case ',':
584 state = pDefault;
585 my_blob[k++] = (char) ch;
586 break;
587 default:
588 my_blob[k++] = (char) ch;
589 break;
590 }
591 break;
592 default:
593 /* not used */
594 break;
595 }
596 }
597 my_blob[k] = '\0';
598
599 /*
600 * Then, parse what's left, making indexes of the names and values.
601 */
602 state = pDefault;
603 for (j = 0; my_blob[j] != '\0'; ++j) {
604 switch (state) {
605 case pDefault:
606 switch (my_blob[j]) {
607 case '\\':
608 state = pEscaped;
609 break;
610 case ',':
611 my_blob[j] = '\0';
612 if (my_blob[j + 1] != '\0' && my_blob[j + 1] != ',')
613 state = pName;
614 break;
615 case ' ':
616 break;
617 default:
618 break;
619 }
620 case pEscaped:
621 break;
622 case pName:
623 state = pDefault;
624 if (isalpha(UChar(my_blob[j]))) {
625 for (jl = 1; isalnum(UChar(my_blob[j + jl])); ++jl) {
626 ;
627 }
628 } else {
629 jl = 0;
630 }
631 if (jl != 0) {
632 switch (my_blob[j + jl]) {
633 case '#':
634 my_numvalues[count_nums] = &my_blob[j + jl + 1];
635 my_numcodes[count_nums++] = &my_blob[j];
636 my_blob[j + jl] = '\0';
637 state = pNumber;
638 j += jl;
639 break;
640 case '=':
641 my_strvalues[count_strs] = &my_blob[j + jl + 1];
642 my_strcodes[count_strs++] = &my_blob[j];
643 my_blob[j + jl] = '\0';
644 state = pString;
645 j += jl;
646 break;
647 default:
648 if (my_blob[j + jl] == '@') {
649 /*
650 * We cannot get the type for a cancelled item
651 * directly, but can infer it assuming the input
652 * came from infocmp, which puts the data in a
653 * known order.
654 */
655 if (count_strs) {
656 my_strvalues[count_strs] = empty;
657 my_strcodes[count_strs++] = &my_blob[j];
658 } else if (count_nums) {
659 my_numvalues[count_nums] = empty;
660 my_numcodes[count_nums++] = &my_blob[j];
661 } else {
662 my_boolcodes[count_bools++] = &my_blob[j];
663 }
664 my_blob[j + jl] = '\0';
665 j += jl + 1;
666 } else {
667 my_boolcodes[count_bools++] = &my_blob[j];
668 my_blob[j + jl] = '\0';
669 j += jl;
670 }
671 state = (isCapName(my_blob[j + 1])
672 ? pName
673 : pDefault);
674 break;
675 }
676 }
677 break;
678 case pNumber:
679 if (!isdigit(UChar(my_blob[j]))) {
680 --j;
681 state = pDefault;
682 }
683 break;
684 case pString:
685 switch (my_blob[j]) {
686 case '\\':
687 if (my_blob[j + 1] != '\0') {
688 ++j;
689 } else {
690 --j;
691 state = pDefault;
692 }
693 break;
694 case ',':
695 --j;
696 state = pDefault;
697 break;
698 }
699 break;
700 case pNewline:
701 case pComment:
702 case pDescription:
703 default:
704 break;
705 }
706 }
707 my_boolcodes[count_bools] = 0;
708 my_numcodes[count_nums] = 0;
709 my_numvalues[count_nums] = 0;
710 my_strcodes[count_strs] = 0;
711 my_strvalues[count_strs] = 0;
712
713#if 0
714 printf("# bools:%d\n", (int) count_bools);
715 for (j = 0; my_boolcodes[j]; ++j)
716 printf("\t%s,\n", my_boolcodes[j]);
717
718 printf("# numbers:%d\n", (int) count_nums);
719 for (j = 0; my_numcodes[j]; ++j)
720 printf("\t%s#%s,\n", my_numcodes[j], my_numvalues[j]);
721
722 printf("# strings:%d\n", (int) count_strs);
723 for (j = 0; my_strcodes[j]; ++j)
724 printf("\t%s=%s,\n", my_strcodes[j], my_strvalues[j]);
725#endif
726}
727
728#if USE_CODE_LISTS
729static char **
730copy_code_list(NCURSES_CONST char *const *list)
731{
732 int pass;
733 size_t count;
734 size_t length = 1;
735 char **result = 0;
Steve Kondikae271bc2015-11-15 02:50:53 +0100736 char *unused = 0;
737
738 for (pass = 0; pass < 2; ++pass) {
739 for (count = 0; list[count] != 0; ++count) {
740 size_t chunk = strlen(list[count]) + 1;
741 if (pass == 0) {
742 length += chunk;
743 } else {
744 result[count] = unused;
micky3879b9f5e72025-07-08 18:04:53 -0400745 _nc_STRCPY(unused, list[count], length);
Steve Kondikae271bc2015-11-15 02:50:53 +0100746 unused += chunk;
747 }
748 }
749 if (pass == 0) {
micky3879b9f5e72025-07-08 18:04:53 -0400750 char *blob = malloc(length);
Steve Kondikae271bc2015-11-15 02:50:53 +0100751 result = typeCalloc(char *, count + 1);
752 unused = blob;
753 if (blob == 0 || result == 0)
754 failed("copy_code_list failed");
755 }
756 }
757
758 return result;
759}
micky3879b9f5e72025-07-08 18:04:53 -0400760
761#if NO_LEAKS
762static void
763free_code_list(char **list)
764{
765 if (list) {
766 free(list[0]);
767 free(list);
768 }
769}
Steve Kondikae271bc2015-11-15 02:50:53 +0100770#endif
micky3879b9f5e72025-07-08 18:04:53 -0400771#endif /* USE_CODE_LISTS */
Steve Kondikae271bc2015-11-15 02:50:53 +0100772
773static void
micky3879b9f5e72025-07-08 18:04:53 -0400774usage(int ok)
Steve Kondikae271bc2015-11-15 02:50:53 +0100775{
776 static const char *msg[] =
777 {
micky3879b9f5e72025-07-08 18:04:53 -0400778 "Usage: demo_terminfo [options] [terminal]"
779 ,""
780 ,"If no options are given, print all (boolean, numeric, string)"
781 ,"capabilities for the given terminal, using short names."
782 ,""
783 ,USAGE_COMMON
784 ,"Options:"
785 ," -a try all names, print capabilities found"
786 ," -b print boolean-capabilities"
787 ," -d LIST colon-separated list of databases to use"
788 ," -e NAME environment variable to set with -d option"
789 ," -f print full names"
790 ," -i NAME terminal description to use as names for \"-a\" option"
791 ," -n print numeric-capabilities"
792 ," -q quiet (prints only counts)"
793 ," -r COUNT repeat for given count"
794 ," -s print string-capabilities"
Steve Kondikae271bc2015-11-15 02:50:53 +0100795#ifdef NCURSES_VERSION
micky3879b9f5e72025-07-08 18:04:53 -0400796 ," -x print extended capabilities"
797 ," -y direct-lookup names of extended capabilities"
Steve Kondikae271bc2015-11-15 02:50:53 +0100798#endif
799 };
800 unsigned n;
801 for (n = 0; n < SIZEOF(msg); ++n) {
802 fprintf(stderr, "%s\n", msg[n]);
803 }
micky3879b9f5e72025-07-08 18:04:53 -0400804 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100805}
micky3879b9f5e72025-07-08 18:04:53 -0400806/* *INDENT-OFF* */
807VERSION_COMMON()
808/* *INDENT-ON* */
Steve Kondikae271bc2015-11-15 02:50:53 +0100809
810int
811main(int argc, char *argv[])
812{
micky3879b9f5e72025-07-08 18:04:53 -0400813 int ch;
Steve Kondikae271bc2015-11-15 02:50:53 +0100814 int n;
815 int repeat;
816 char *name;
817 int r_opt = 1;
818 char *input_name = 0;
819
micky3879b9f5e72025-07-08 18:04:53 -0400820 while ((ch = getopt(argc, argv, OPTS_COMMON "abd:e:fi:nqr:sxy")) != -1) {
821 switch (ch) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100822 case 'a':
823 a_opt = TRUE;
824 break;
825 case 'b':
826 b_opt = TRUE;
827 break;
828 case 'd':
829 d_opt = optarg;
830 break;
831 case 'e':
832 e_opt = optarg;
833 break;
834 case 'f':
835 f_opt = TRUE;
836 break;
837 case 'i':
838 input_name = optarg;
839 break;
840 case 'n':
841 n_opt = TRUE;
842 break;
843 case 'q':
844 q_opt = TRUE;
845 break;
846 case 'r':
847 if ((r_opt = atoi(optarg)) <= 0)
micky3879b9f5e72025-07-08 18:04:53 -0400848 usage(FALSE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100849 break;
850 case 's':
851 s_opt = TRUE;
852 break;
Steve Kondikae271bc2015-11-15 02:50:53 +0100853 case 'x':
micky3879b9f5e72025-07-08 18:04:53 -0400854#ifdef NCURSES_VERSION
Steve Kondikae271bc2015-11-15 02:50:53 +0100855 x_opt = TRUE;
micky3879b9f5e72025-07-08 18:04:53 -0400856#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100857 break;
micky3879b9f5e72025-07-08 18:04:53 -0400858#ifdef NCURSES_VERSION
Steve Kondikae271bc2015-11-15 02:50:53 +0100859 case 'y':
860 y_opt = TRUE;
861 x_opt = TRUE;
862 break;
863#endif
micky3879b9f5e72025-07-08 18:04:53 -0400864 case OPTS_VERSION:
865 show_version(argv);
866 ExitProgram(EXIT_SUCCESS);
Steve Kondikae271bc2015-11-15 02:50:53 +0100867 default:
micky3879b9f5e72025-07-08 18:04:53 -0400868 usage(ch == OPTS_USAGE);
869 /* NOTREACHED */
Steve Kondikae271bc2015-11-15 02:50:53 +0100870 }
871 }
872
873#if HAVE_USE_EXTENDED_NAMES
874 use_extended_names(x_opt);
875#endif
876
877 if (!(b_opt || n_opt || s_opt)) {
878 b_opt = TRUE;
879 n_opt = TRUE;
880 s_opt = TRUE;
881 }
882
883 make_dblist();
884
885 if (a_opt) {
886 for (repeat = 0; repeat < r_opt; ++repeat) {
887 if (optind < argc) {
888 for (n = optind; n < argc; ++n) {
889 brute_force(argv[n]);
890 }
891 } else if ((name = getenv("TERM")) != 0) {
892 brute_force(name);
893 } else {
894 static char dumb[] = "dumb";
895 brute_force(dumb);
896 }
897 }
898 } else {
899 if (input_name != 0) {
900 parse_description(input_name);
901 }
902#if USE_CODE_LISTS
903 else {
904 my_boolcodes = copy_code_list(boolnames);
905 my_numcodes = copy_code_list(numnames);
906 my_strcodes = copy_code_list(strnames);
907 }
908#else
909 else {
910 failed("no capability-lists available (use -i option)");
911 }
912#endif /* USE_CODE_LISTS */
913 for (repeat = 0; repeat < r_opt; ++repeat) {
914 if (optind < argc) {
915 for (n = optind; n < argc; ++n) {
916 demo_terminfo(argv[n]);
917 }
918 } else if ((name = getenv("TERM")) != 0) {
919 demo_terminfo(name);
920 } else {
921 static char dumb[] = "dumb";
922 demo_terminfo(dumb);
923 }
924 }
925 }
926
micky3879b9f5e72025-07-08 18:04:53 -0400927#define PLURAL(n) n, (n != 1) ? "s" : ""
928 printf("%ld value%s (%ld boolean%s, %ld number%s, %ld string%s)\n",
929 PLURAL(total_values),
930 PLURAL(total_b_values),
931 PLURAL(total_n_values),
932 PLURAL(total_s_values));
Steve Kondikae271bc2015-11-15 02:50:53 +0100933
micky3879b9f5e72025-07-08 18:04:53 -0400934#if NO_LEAKS
Steve Kondikae271bc2015-11-15 02:50:53 +0100935 free_dblist();
micky3879b9f5e72025-07-08 18:04:53 -0400936 if (input_name != 0) {
937 if (my_blob != 0) {
938 free(my_blob);
939 free(my_boolcodes);
940 free(my_numcodes);
941 free(my_numvalues);
942 free(my_strcodes);
943 free(my_strvalues);
944 }
945 }
946#if USE_CODE_LISTS
947 else {
948 free_code_list(my_boolcodes);
949 free_code_list(my_numcodes);
950 free_code_list(my_strcodes);
Steve Kondikae271bc2015-11-15 02:50:53 +0100951 }
952#endif
micky3879b9f5e72025-07-08 18:04:53 -0400953#endif /* NO_LEAKS */
Steve Kondikae271bc2015-11-15 02:50:53 +0100954
955 ExitProgram(EXIT_SUCCESS);
956}
957
958#else /* !HAVE_TIGETSTR */
959int
micky3879b9f5e72025-07-08 18:04:53 -0400960main(void)
Steve Kondikae271bc2015-11-15 02:50:53 +0100961{
micky3879b9f5e72025-07-08 18:04:53 -0400962 failed("This program requires the terminfo functions such as tigetstr");
Steve Kondikae271bc2015-11-15 02:50:53 +0100963 ExitProgram(EXIT_FAILURE);
964}
965#endif /* HAVE_TIGETSTR */