ncurses 5.9 - patch 20120630
[ncurses.git] / test / demo_termcap.c
1 /****************************************************************************
2  * Copyright (c) 2005-2011,2012 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_termcap.c,v 1.21 2012/06/30 22:02:56 tom Exp $
33  *
34  * A simple demo of the termcap interface.
35  */
36 #define USE_TINFO
37 #include <test.priv.h>
38
39 #if HAVE_TGETENT
40
41 #if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
42 #define USE_CODE_LISTS 1
43 #else
44 #define USE_CODE_LISTS 0
45 #endif
46
47 #define FCOLS 8
48 #define FNAME(type) "%s %-*s = ", #type, FCOLS
49
50 #if USE_CODE_LISTS
51 static bool b_opt = FALSE;
52 static bool n_opt = FALSE;
53 static bool q_opt = FALSE;
54 static bool s_opt = FALSE;
55 #endif
56
57 static char *d_opt;
58 static char *e_opt;
59 static char **db_list;
60 static int db_item;
61
62 static long total_values;
63
64 #define isCapName(c) (isgraph(c) && strchr("^#=:\\", c) == 0)
65
66 #if NO_LEAKS && USE_CODE_LISTS
67
68 #define MYSCR struct _myscr
69 MYSCR {
70     MYSCR *next;
71     TERMINAL *term;
72 };
73
74 static MYSCR *my_screens;
75
76 static void
77 save_screen(void)
78 {
79     MYSCR *obj = malloc(sizeof(MYSCR));
80     obj->next = my_screens;
81     obj->term = cur_term;
82     my_screens = obj;
83 }
84 #else
85 #define save_screen()           /* nothing */
86 #endif
87
88 static char *
89 make_dbitem(char *p, char *q)
90 {
91     char *result = malloc(strlen(e_opt) + 2 + (size_t) (p - q));
92     sprintf(result, "%s=%.*s", e_opt, p - q, q);
93     return result;
94 }
95
96 static void
97 make_dblist(void)
98 {
99     if (d_opt && e_opt) {
100         int pass;
101
102         for (pass = 0; pass < 2; ++pass) {
103             char *p, *q;
104             size_t count = 0;
105
106             for (p = q = d_opt; *p != '\0'; ++p) {
107                 if (*p == ':') {
108                     if (p != q + 1) {
109                         if (pass) {
110                             db_list[count] = make_dbitem(p, q);
111                         }
112                         count++;
113                     }
114                     q = p + 1;
115                 }
116             }
117             if (p != q + 1) {
118                 if (pass) {
119                     db_list[count] = make_dbitem(p, q);
120                 }
121                 count++;
122             }
123             if (!pass) {
124                 db_list = typeCalloc(char *, count + 1);
125             }
126         }
127     }
128 }
129
130 static char *
131 next_dbitem(void)
132 {
133     char *result = 0;
134
135     if (db_list) {
136         if ((result = db_list[db_item]) == 0) {
137             db_item = 0;
138             result = db_list[0];
139         } else {
140             db_item++;
141         }
142     }
143     printf("** %s\n", result);
144     return result;
145 }
146
147 static void
148 free_dblist(void)
149 {
150     if (db_list) {
151         int n;
152         for (n = 0; db_list[n]; ++n)
153             free(db_list[n]);
154         free(db_list);
155         db_list = 0;
156     }
157 }
158
159 static void
160 dumpit(NCURSES_CONST char *cap)
161 {
162     /*
163      * One of the limitations of the termcap interface is that the library
164      * cannot determine the size of the buffer passed via tgetstr(), nor the
165      * amount of space remaining.  This demo simply reuses the whole buffer
166      * for each call; a normal termcap application would try to use the buffer
167      * to hold all of the strings extracted from the terminal entry.
168      */
169     char area[1024], *ap = area;
170     char *str;
171     int num;
172
173     if ((str = tgetstr(cap, &ap)) != 0) {
174         total_values++;
175         if (!q_opt) {
176             /*
177              * Note that the strings returned are mostly terminfo format, since
178              * ncurses does not convert except for a handful of special cases.
179              */
180             printf(FNAME(str), cap);
181             while (*str != 0) {
182                 int ch = UChar(*str++);
183                 switch (ch) {
184                 case '\177':
185                     fputs("^?", stdout);
186                     break;
187                 case '\033':
188                     fputs("\\E", stdout);
189                     break;
190                 case '\b':
191                     fputs("\\b", stdout);
192                     break;
193                 case '\f':
194                     fputs("\\f", stdout);
195                     break;
196                 case '\n':
197                     fputs("\\n", stdout);
198                     break;
199                 case '\r':
200                     fputs("\\r", stdout);
201                     break;
202                 case ' ':
203                     fputs("\\s", stdout);
204                     break;
205                 case '\t':
206                     fputs("\\t", stdout);
207                     break;
208                 case '^':
209                     fputs("\\^", stdout);
210                     break;
211                 case ':':
212                     fputs("\\072", stdout);
213                     break;
214                 case '\\':
215                     fputs("\\\\", stdout);
216                     break;
217                 default:
218                     if (isgraph(ch))
219                         fputc(ch, stdout);
220                     else if (ch < 32)
221                         printf("^%c", ch + '@');
222                     else
223                         printf("\\%03o", ch);
224                     break;
225                 }
226             }
227             printf("\n");
228         }
229     } else if ((num = tgetnum(cap)) >= 0) {
230         total_values++;
231         if (!q_opt) {
232             printf(FNAME(num), cap);
233             printf(" %d\n", num);
234         }
235     } else if (tgetflag(cap) > 0) {
236         ++total_values;
237         if (!q_opt) {
238             printf(FNAME(flg), cap);
239             printf("%s\n", "true");
240         }
241     }
242
243     if (!q_opt)
244         fflush(stdout);
245 }
246
247 static void
248 brute_force(const char *name)
249 {
250     char buffer[1024];
251
252     if (db_list) {
253         putenv(next_dbitem());
254     }
255     printf("Terminal type %s\n", name);
256     if (tgetent(buffer, name) >= 0) {
257         char cap[3];
258         int c1, c2;
259
260         cap[2] = 0;
261         for (c1 = 0; c1 < 256; ++c1) {
262             cap[0] = (char) c1;
263             if (isCapName(c1)) {
264                 for (c2 = 0; c2 < 256; ++c2) {
265                     cap[1] = (char) c2;
266                     if (isCapName(c2)) {
267                         dumpit(cap);
268                     }
269                 }
270             }
271         }
272     }
273 }
274
275 #if USE_CODE_LISTS
276 static void
277 demo_termcap(NCURSES_CONST char *name)
278 {
279     unsigned n;
280     NCURSES_CONST char *cap;
281
282     if (db_list) {
283         putenv(next_dbitem());
284     }
285     printf("Terminal type \"%s\"\n", name);
286 #if HAVE_SETUPTERM
287     setupterm(name, 1, (int *) 0);
288 #else
289     setterm(name);
290 #endif
291     save_screen();
292
293     if (b_opt) {
294         for (n = 0;; ++n) {
295             cap = boolcodes[n];
296             if (cap == 0)
297                 break;
298             dumpit(cap);
299         }
300     }
301
302     if (n_opt) {
303         for (n = 0;; ++n) {
304             cap = numcodes[n];
305             if (cap == 0)
306                 break;
307             dumpit(cap);
308         }
309     }
310
311     if (s_opt) {
312         for (n = 0;; ++n) {
313             cap = strcodes[n];
314             if (cap == 0)
315                 break;
316             dumpit(cap);
317         }
318     }
319 }
320
321 static void
322 usage(void)
323 {
324     static const char *msg[] =
325     {
326         "Usage: demo_termcap [options] [terminal]",
327         "",
328         "If no options are given, print all (boolean, numeric, string)",
329         "capabilities for the given terminal, using short names.",
330         "",
331         "Options:",
332         " -a       try all names, print capabilities found",
333         " -b       print boolean-capabilities",
334         " -d LIST  colon-separated list of databases to use",
335         " -e NAME  environment variable to set with -d option",
336         " -n       print numeric-capabilities",
337         " -q       quiet (prints only counts)",
338         " -r COUNT repeat for given count",
339         " -s       print string-capabilities",
340     };
341     unsigned n;
342     for (n = 0; n < SIZEOF(msg); ++n) {
343         fprintf(stderr, "%s\n", msg[n]);
344     }
345     ExitProgram(EXIT_FAILURE);
346 }
347 #endif
348
349 int
350 main(int argc, char *argv[])
351 {
352     int n;
353     char *name;
354     bool a_opt = FALSE;
355
356 #if USE_CODE_LISTS
357     int repeat;
358     int r_opt = 1;
359
360     while ((n = getopt(argc, argv, "abd:e:nqr:s")) != -1) {
361         switch (n) {
362         case 'a':
363             a_opt = TRUE;
364             break;
365         case 'b':
366             b_opt = TRUE;
367             break;
368         case 'd':
369             d_opt = optarg;
370             break;
371         case 'e':
372             e_opt = optarg;
373             break;
374         case 'n':
375             n_opt = TRUE;
376             break;
377         case 'q':
378             q_opt = TRUE;
379             break;
380         case 'r':
381             if ((r_opt = atoi(optarg)) <= 0)
382                 usage();
383             break;
384         case 's':
385             s_opt = TRUE;
386             break;
387         default:
388             usage();
389             break;
390         }
391     }
392
393     if (!(b_opt || n_opt || s_opt)) {
394         b_opt = TRUE;
395         n_opt = TRUE;
396         s_opt = TRUE;
397     }
398 #else
399     a_opt = TRUE;
400 #endif
401
402     make_dblist();
403
404     if (a_opt) {
405         if (optind < argc) {
406             for (n = optind; n < argc; ++n) {
407                 brute_force(argv[n]);
408             }
409         } else if ((name = getenv("TERM")) != 0) {
410             brute_force(name);
411         } else {
412             static char dumb[] = "dumb";
413             brute_force(dumb);
414         }
415     }
416 #if USE_CODE_LISTS
417     else {
418         for (repeat = 0; repeat < r_opt; ++repeat) {
419             if (optind < argc) {
420                 for (n = optind; n < argc; ++n) {
421                     demo_termcap(argv[n]);
422                 }
423             } else if ((name = getenv("TERM")) != 0) {
424                 demo_termcap(name);
425             } else {
426                 static char dumb[] = "dumb";
427                 demo_termcap(dumb);
428             }
429         }
430 #if NO_LEAKS
431         /*
432          * ncurses' tgetent() interface caches some entries and its no-leaks
433          * code discards those.  The calls to setupterm() on the other hand
434          * are not cached, and each call allocates a chunk of memory, even
435          * if the same terminal type is requested repeatedly.
436          */
437         while (my_screens != 0) {
438             MYSCR *next = my_screens->next;
439             del_curterm(my_screens->term);
440             free(my_screens);
441             my_screens = next;
442         }
443 #endif
444     }
445 #endif /* USE_CODE_LISTS */
446
447     printf("%ld values\n", total_values);
448
449     free_dblist();
450
451     ExitProgram(EXIT_SUCCESS);
452 }
453
454 #else
455 int
456 main(int argc GCC_UNUSED,
457      char *argv[]GCC_UNUSED)
458 {
459     printf("This program requires termcap\n");
460     ExitProgram(EXIT_FAILURE);
461 }
462 #endif