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