ncurses 6.0 - patch 20160618
[ncurses.git] / test / list_keys.c
1 /****************************************************************************
2  * Copyright (c) 2016 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  * $Id: list_keys.c,v 1.9 2016/06/18 22:18:30 tom Exp $
30  *
31  * Author: Thomas E Dickey
32  *
33  * List function keys for one or more terminals.
34  */
35
36 #define USE_TINFO
37 #include <test.priv.h>
38
39 #if NCURSES_XNAMES
40 #if HAVE_TERM_ENTRY_H
41 #include <term_entry.h>
42 #else
43 #undef NCURSES_XNAMES
44 #define NCURSES_XNAMES 0
45 #endif
46 #endif
47
48 #if HAVE_TIGETSTR
49 #if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES)
50
51 static bool f_opt = FALSE;
52 static bool t_opt = FALSE;
53 static bool x_opt = FALSE;
54
55 typedef enum {
56     ktCursor
57     ,ktFunction
58     ,ktOther
59 #if HAVE_USE_EXTENDED_NAMES
60     ,ktExtended
61 #endif
62 } KEYTYPE;
63
64 typedef struct {
65     KEYTYPE type;
66     const char *name;
67 } KEYNAMES;
68
69 #define Type(n) list[n].type
70 #define Name(n) list[n].name
71
72 static const char *
73 full_name(const char *name)
74 {
75     const char *result = name;
76     int n;
77     for (n = 0; strnames[n] != 0; ++n) {
78         if (!strcmp(name, strnames[n])) {
79             result = strfnames[n];
80             break;
81         }
82     }
83     return result;
84 }
85
86 static int
87 show_key(const char *name, bool show)
88 {
89     int width = 0;
90     char buffer[10];
91     char *value = tigetstr(name);
92
93     if (show && t_opt)
94         fputc('"', stdout);
95
96     if (value != 0 && value != (char *) -1) {
97         while (*value != 0) {
98             int ch = UChar(*value++);
99             switch (ch) {
100             case '\177':
101                 strcpy(buffer, "^?");
102                 break;
103             case '\033':
104                 strcpy(buffer, "\\E");
105                 break;
106             case '\b':
107                 strcpy(buffer, "\\b");
108                 break;
109             case '\f':
110                 strcpy(buffer, "\\f");
111                 break;
112             case '\n':
113                 strcpy(buffer, "\\n");
114                 break;
115             case '\r':
116                 strcpy(buffer, "\\r");
117                 break;
118             case ' ':
119                 strcpy(buffer, "\\s");
120                 break;
121             case '\t':
122                 strcpy(buffer, "\\t");
123                 break;
124             case '^':
125                 strcpy(buffer, "\\^");
126                 break;
127             case ':':
128                 strcpy(buffer, "\\072");
129                 break;
130             case '\\':
131                 strcpy(buffer, "\\\\");
132                 break;
133             default:
134                 if (t_opt && ch == '"') {
135                     strcpy(buffer, "\"\"");
136                 } else if (isgraph(ch)) {
137                     sprintf(buffer, "%c", ch);
138                 } else if (ch < 32) {
139                     sprintf(buffer, "^%c", ch + '@');
140                 } else {
141                     sprintf(buffer, "\\%03o", ch);
142                 }
143                 break;
144             }
145             width += (int) strlen(buffer);
146             if (show)
147                 fputs(buffer, stdout);
148         }
149     }
150
151     if (show && t_opt)
152         fputc('"', stdout);
153
154     return width;
155 }
156
157 static bool
158 valid_key(const char *name, TERMINAL ** terms, int count)
159 {
160     bool result = FALSE;
161     if (*name == 'k') {
162         int k;
163         for (k = 0; k < count; ++k) {
164             set_curterm(terms[k]);
165             if (show_key(name, FALSE)) {
166                 result = TRUE;
167                 break;
168             }
169         }
170     }
171     return result;
172 }
173
174 static int
175 compare_keys(const void *a, const void *b)
176 {
177     const KEYNAMES *p = (const KEYNAMES *) a;
178     const KEYNAMES *q = (const KEYNAMES *) b;
179     int result = (int) (p->type - q->type);
180     int pn, qn;
181     if (result == 0) {
182         if (p->type == ktFunction &&
183             sscanf(p->name, "kf%d", &pn) == 1 &&
184             sscanf(q->name, "kf%d", &qn) == 1) {
185             result = (pn - qn);
186         } else {
187             result = strcmp(p->name, q->name);
188         }
189     }
190     return result;
191 }
192
193 static void
194 draw_line(int width)
195 {
196     int j;
197     if (!t_opt) {
198         for (j = 0; j < width; ++j) {
199             printf("-");
200         }
201         printf("\n");
202     }
203 }
204
205 static void
206 list_keys(TERMINAL ** terms, int count)
207 {
208     int j, k;
209     int widths0 = 0;
210     int widths1 = 0;
211     int widthsx;
212     int check;
213     size_t total = 0;
214     size_t actual = 0;
215     const char *name = f_opt ? "strfname" : "strname";
216     KEYNAMES *list;
217
218     for (total = 0; strnames[total]; ++total) {
219         ;
220     }
221 #if NCURSES_XNAMES
222     if (x_opt) {
223         TERMTYPE *term;
224         for (k = 0; k < count; ++k) {
225             set_curterm(terms[k]);
226             term = &(cur_term->type);
227             total += (size_t) (NUM_STRINGS(term) - STRCOUNT);
228         }
229     }
230 #endif
231     list = typeCalloc(KEYNAMES, total + 1);
232     for (j = 0; strnames[j]; ++j) {
233         Type(j) = ktOther;
234         if (sscanf(strnames[j], "kf%d", &k) == 1) {
235             Type(j) = ktFunction;
236         } else if (!strncmp(strnames[j], "kcu", 3)) {
237             Type(j) = ktCursor;
238         }
239         Name(j) = strnames[j];
240     }
241 #if NCURSES_XNAMES
242     if (x_opt) {
243         TERMTYPE *term;
244         int m, n;
245         for (k = 0; k < count; ++k) {
246             set_curterm(terms[k]);
247             term = &(cur_term->type);
248             for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
249                 bool found = FALSE;
250                 const char *estr = ExtStrname(term, (int) n, strnames);
251                 for (m = STRCOUNT; m < j; ++m) {
252                     if (!strcmp(estr, Name(m))) {
253                         found = TRUE;
254                         break;
255                     }
256                 }
257                 if (!found) {
258                     Type(j) = ktExtended;
259                     Name(j++) = estr;
260                 }
261             }
262         }
263     }
264 #endif
265     actual = (size_t) j;
266     qsort(list, actual, sizeof(KEYNAMES), compare_keys);
267
268     widths0 = (int) strlen(name);
269     for (k = 0; k < count; ++k) {
270         set_curterm(terms[k]);
271         check = (int) strlen(termname());
272         if (widths1 < check)
273             widths1 = check;
274     }
275     for (j = 0; Name(j) != 0; ++j) {
276         if (valid_key(Name(j), terms, count)) {
277             const char *label = f_opt ? full_name(Name(j)) : Name(j);
278             check = (int) strlen(label);
279             if (widths0 < check)
280                 widths0 = check;
281             for (k = 0; k < count; ++k) {
282                 set_curterm(terms[k]);
283                 check = show_key(Name(j), FALSE);
284                 if (widths1 < check)
285                     widths1 = check;
286             }
287         }
288     }
289
290     if (t_opt) {
291         printf("\"%s\"", name);
292     } else {
293         printf("%-*s", widths0, name);
294     }
295     for (k = 0; k < count; ++k) {
296         set_curterm(terms[k]);
297         if (t_opt) {
298             printf(",\"%s\"", termname());
299         } else if (k + 1 >= count) {
300             printf(" %s", termname());
301         } else {
302             printf(" %-*s", widths1, termname());
303         }
304     }
305     printf("\n");
306
307     widthsx = widths0 + ((count + 1) * widths1);
308
309     for (j = 0; Name(j) != 0; ++j) {
310         if (j == 0 || (Type(j) != Type(j - 1)))
311             draw_line(widthsx);
312         if (valid_key(Name(j), terms, count)) {
313             const char *label = f_opt ? full_name(Name(j)) : Name(j);
314             if (t_opt) {
315                 printf("\"%s\"", label);
316             } else {
317                 printf("%-*s", widths0, label);
318             }
319             for (k = 0; k < count; ++k) {
320                 printf(t_opt ? "," : " ");
321                 set_curterm(terms[k]);
322                 check = show_key(Name(j), TRUE);
323                 if (!t_opt) {
324                     if (k + 1 < count) {
325                         printf("%*s", widths1 - check, " ");
326                     }
327                 }
328             }
329             printf("\n");
330         }
331     }
332 }
333
334 static void
335 usage(void)
336 {
337     static const char *msg[] =
338     {
339         "Usage: list_keys [options] [terminal [terminal2 [...]]]",
340         "",
341         "Print capabilities for terminal special keys.",
342         "",
343         "Options:",
344         " -f       print full names",
345         " -t       print result as CSV table",
346 #ifdef NCURSES_VERSION
347         " -x       print extended capabilities",
348 #endif
349     };
350     unsigned n;
351     for (n = 0; n < SIZEOF(msg); ++n) {
352         fprintf(stderr, "%s\n", msg[n]);
353     }
354     ExitProgram(EXIT_FAILURE);
355 }
356
357 int
358 main(int argc, char *argv[])
359 {
360     int n;
361     TERMINAL **terms = typeCalloc(TERMINAL *, argc);
362
363     while ((n = getopt(argc, argv, "ftx")) != -1) {
364         switch (n) {
365         case 'f':
366             f_opt = TRUE;
367             break;
368         case 't':
369             t_opt = TRUE;
370             break;
371 #ifdef NCURSES_VERSION
372         case 'x':
373             x_opt = TRUE;
374             break;
375 #endif
376         default:
377             usage();
378             break;
379         }
380     }
381
382 #if HAVE_USE_EXTENDED_NAMES
383     use_extended_names(x_opt);
384 #endif
385
386     for (n = optind; n < argc; ++n) {
387         setupterm((NCURSES_CONST char *) argv[n], 1, (int *) 0);
388         terms[n - optind] = cur_term;
389     }
390     list_keys(terms, argc - optind);
391
392     ExitProgram(EXIT_SUCCESS);
393 }
394
395 #else
396 int
397 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
398 {
399     printf("This program requires the terminfo arrays\n");
400     ExitProgram(EXIT_FAILURE);
401 }
402 #endif
403 #else /* !HAVE_TIGETSTR */
404 int
405 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
406 {
407     printf("This program requires the terminfo functions such as tigetstr\n");
408     ExitProgram(EXIT_FAILURE);
409 }
410 #endif /* HAVE_TIGETSTR */