aea3289891855f698514d9010229bce1038540dc
[ncurses.git] / test / demo_terminfo.c
1 /****************************************************************************
2  * Copyright (c) 2009-2012,2013 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.18 2013/09/07 17:37:20 tom Exp $
33  *
34  * A simple demo of the terminfo interface.
35  */
36 #define USE_TINFO
37 #include <test.priv.h>
38
39 #if NCURSES_XNAMES
40 #include <term_entry.h>
41 #endif
42
43 #if HAVE_TIGETSTR
44 #if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
45
46 static bool b_opt = FALSE;
47 static bool f_opt = FALSE;
48 static bool n_opt = FALSE;
49 static bool q_opt = FALSE;
50 static bool s_opt = FALSE;
51 static bool x_opt = FALSE;
52
53 static char *d_opt;
54 static char *e_opt;
55 static char **db_list;
56 static int db_item;
57
58 static long total_values;
59
60 #define FCOLS 8
61 #define FNAME(type) "%s %-*s = ", #type, FCOLS
62
63 static char *
64 make_dbitem(char *p, char *q)
65 {
66     char *result = malloc(strlen(e_opt) + 2 + (size_t) (p - q));
67     sprintf(result, "%s=%.*s", e_opt, (int) (p - q), q);
68     return result;
69 }
70
71 static void
72 make_dblist(void)
73 {
74     if (d_opt && e_opt) {
75         int pass;
76
77         for (pass = 0; pass < 2; ++pass) {
78             char *p, *q;
79             size_t count = 0;
80
81             for (p = q = d_opt; *p != '\0'; ++p) {
82                 if (*p == ':') {
83                     if (p != q + 1) {
84                         if (pass) {
85                             db_list[count] = make_dbitem(p, q);
86                         }
87                         count++;
88                     }
89                     q = p + 1;
90                 }
91             }
92             if (p != q + 1) {
93                 if (pass) {
94                     db_list[count] = make_dbitem(p, q);
95                 }
96                 count++;
97             }
98             if (!pass) {
99                 db_list = typeCalloc(char *, count + 1);
100             }
101         }
102     }
103 }
104
105 static char *
106 next_dbitem(void)
107 {
108     char *result = 0;
109
110     if (db_list) {
111         if ((result = db_list[db_item]) == 0) {
112             db_item = 0;
113             result = db_list[0];
114         } else {
115             db_item++;
116         }
117     }
118     printf("** %s\n", result);
119     return result;
120 }
121
122 static void
123 free_dblist(void)
124 {
125     if (db_list) {
126         int n;
127         for (n = 0; db_list[n]; ++n)
128             free(db_list[n]);
129         free(db_list);
130         db_list = 0;
131     }
132 }
133 static void
134 dumpit(NCURSES_CONST char *cap)
135 {
136     /*
137      * One of the limitations of the termcap interface is that the library
138      * cannot determine the size of the buffer passed via tgetstr(), nor the
139      * amount of space remaining.  This demo simply reuses the whole buffer
140      * for each call; a normal termcap application would try to use the buffer
141      * to hold all of the strings extracted from the terminal entry.
142      */
143     const char *str;
144     int num;
145
146     if ((str = tigetstr(cap)) != 0 && (str != (char *) -1)) {
147         total_values++;
148         if (!q_opt) {
149             /*
150              * Note that the strings returned are mostly terminfo format, since
151              * ncurses does not convert except for a handful of special cases.
152              */
153             printf(FNAME(str), cap);
154             while (*str != 0) {
155                 int ch = UChar(*str++);
156                 switch (ch) {
157                 case '\177':
158                     fputs("^?", stdout);
159                     break;
160                 case '\033':
161                     fputs("\\E", stdout);
162                     break;
163                 case '\b':
164                     fputs("\\b", stdout);
165                     break;
166                 case '\f':
167                     fputs("\\f", stdout);
168                     break;
169                 case '\n':
170                     fputs("\\n", stdout);
171                     break;
172                 case '\r':
173                     fputs("\\r", stdout);
174                     break;
175                 case ' ':
176                     fputs("\\s", stdout);
177                     break;
178                 case '\t':
179                     fputs("\\t", stdout);
180                     break;
181                 case '^':
182                     fputs("\\^", stdout);
183                     break;
184                 case ':':
185                     fputs("\\072", stdout);
186                     break;
187                 case '\\':
188                     fputs("\\\\", stdout);
189                     break;
190                 default:
191                     if (isgraph(ch))
192                         fputc(ch, stdout);
193                     else if (ch < 32)
194                         printf("^%c", ch + '@');
195                     else
196                         printf("\\%03o", ch);
197                     break;
198                 }
199             }
200             printf("\n");
201         }
202     } else if ((num = tigetnum(cap)) >= 0) {
203         total_values++;
204         if (!q_opt) {
205             printf(FNAME(num), cap);
206             printf(" %d\n", num);
207         }
208     } else if ((num = tigetflag(cap)) >= 0) {
209         total_values++;
210         if (!q_opt) {
211             printf(FNAME(flg), cap);
212             printf("%s\n", num ? "true" : "false");
213         }
214     }
215
216     if (!q_opt)
217         fflush(stdout);
218 }
219
220 static void
221 demo_terminfo(char *name)
222 {
223     unsigned n;
224     NCURSES_CONST char *cap;
225
226     if (db_list) {
227         putenv(next_dbitem());
228     }
229     printf("Terminal type \"%s\"\n", name);
230     setupterm(name, 1, (int *) 0);
231
232     if (b_opt) {
233         for (n = 0;; ++n) {
234             cap = f_opt ? boolfnames[n] : boolnames[n];
235             if (cap == 0)
236                 break;
237             dumpit(cap);
238         }
239     }
240
241     if (n_opt) {
242         for (n = 0;; ++n) {
243             cap = f_opt ? numfnames[n] : numnames[n];
244             if (cap == 0)
245                 break;
246             dumpit(cap);
247         }
248     }
249
250     if (s_opt) {
251         for (n = 0;; ++n) {
252             cap = f_opt ? strfnames[n] : strnames[n];
253             if (cap == 0)
254                 break;
255             dumpit(cap);
256         }
257     }
258 #ifdef NCURSES_VERSION
259     if (x_opt) {
260         int mod;
261         if (f_opt) {
262 #if NCURSES_XNAMES
263             TERMTYPE *term = &(cur_term->type);
264             if (term != 0
265                 && ((NUM_BOOLEANS(term) != BOOLCOUNT)
266                     || (NUM_NUMBERS(term) != NUMCOUNT)
267                     || (NUM_STRINGS(term) != STRCOUNT))) {
268                 for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
269                     dumpit(ExtBoolname(term, (int) n, boolnames));
270                 }
271                 for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
272                     dumpit(ExtNumname(term, (int) n, numnames));
273                 }
274                 for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
275                     dumpit(ExtStrname(term, (int) n, strnames));
276                 }
277             }
278 #endif
279         } else {
280             char temp[80];
281             static const char *xterm_keys[] =
282             {
283                 "kDC", "kDN", "kEND", "kHOM", "kIC",
284                 "kLFT", "kNXT", "kPRV", "kRIT", "kUP",
285             };
286             for (n = 0; n < SIZEOF(xterm_keys); ++n) {
287                 for (mod = 0; mod < 8; ++mod) {
288                     if (mod == 0)
289                         sprintf(temp, "%.*s", 8, xterm_keys[n]);
290                     else
291                         sprintf(temp, "%.*s%d", 8, xterm_keys[n], mod);
292                     dumpit(temp);
293                 }
294             }
295         }
296     }
297 #endif
298
299 }
300
301 static void
302 usage(void)
303 {
304     static const char *msg[] =
305     {
306         "Usage: demo_terminfo [options] [terminal]",
307         "",
308         "If no options are given, print all (boolean, numeric, string)",
309         "capabilities for the given terminal, using short names.",
310         "",
311         "Options:",
312         " -b       print boolean-capabilities",
313         " -d LIST  colon-separated list of databases to use",
314         " -e NAME  environment variable to set with -d option",
315         " -f       print full names",
316         " -n       print numeric-capabilities",
317         " -q       quiet (prints only counts)",
318         " -r COUNT repeat for given count",
319         " -s       print string-capabilities",
320 #ifdef NCURSES_VERSION
321         " -x       print extended capabilities",
322         " -y       disable extended capabilities",
323 #endif
324     };
325     unsigned n;
326     for (n = 0; n < SIZEOF(msg); ++n) {
327         fprintf(stderr, "%s\n", msg[n]);
328     }
329     ExitProgram(EXIT_FAILURE);
330 }
331
332 int
333 main(int argc, char *argv[])
334 {
335     int n;
336     int repeat;
337     char *name;
338     int r_opt = 1;
339 #ifdef NCURSES_VERSION
340     bool xy_opt = TRUE;         /* by default, use_extended_names is true */
341 #endif
342
343     while ((n = getopt(argc, argv, "bd:e:fnqr:sxy")) != -1) {
344         switch (n) {
345         case 'b':
346             b_opt = TRUE;
347             break;
348         case 'd':
349             d_opt = optarg;
350             break;
351         case 'e':
352             e_opt = optarg;
353             break;
354         case 'f':
355             f_opt = TRUE;
356             break;
357         case 'n':
358             n_opt = TRUE;
359             break;
360         case 'q':
361             q_opt = TRUE;
362             break;
363         case 'r':
364             if ((r_opt = atoi(optarg)) <= 0)
365                 usage();
366             break;
367         case 's':
368             s_opt = TRUE;
369             break;
370 #ifdef NCURSES_VERSION
371         case 'x':
372             x_opt = TRUE;
373             xy_opt = TRUE;
374             break;
375         case 'y':
376             xy_opt = FALSE;
377             break;
378 #endif
379         default:
380             usage();
381             break;
382         }
383     }
384
385 #if NCURSES_XNAMES
386     use_extended_names(xy_opt);
387 #endif
388
389     if (!(b_opt || n_opt || s_opt || x_opt)) {
390         b_opt = TRUE;
391         n_opt = TRUE;
392         s_opt = TRUE;
393     }
394
395     make_dblist();
396
397     for (repeat = 0; repeat < r_opt; ++repeat) {
398         if (optind < argc) {
399             for (n = optind; n < argc; ++n) {
400                 demo_terminfo(argv[n]);
401             }
402         } else if ((name = getenv("TERM")) != 0) {
403             demo_terminfo(name);
404         } else {
405             static char dumb[] = "dumb";
406             demo_terminfo(dumb);
407         }
408     }
409
410     printf("%ld values\n", total_values);
411
412     free_dblist();
413
414     ExitProgram(EXIT_SUCCESS);
415 }
416
417 #else
418 int
419 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
420 {
421     printf("This program requires the terminfo arrays\n");
422     ExitProgram(EXIT_FAILURE);
423 }
424 #endif
425 #else /* !HAVE_TIGETSTR */
426 int
427 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
428 {
429     printf("This program requires the terminfo functions such as tigetstr\n");
430     ExitProgram(EXIT_FAILURE);
431 }
432 #endif /* HAVE_TIGETSTR */