1 /*
2 * $Id: dlg_keys.c,v 1.34 2011/10/14 00:41:08 tom Exp $
3 *
4 * dlg_keys.c -- runtime binding support for dialog
5 *
6 * Copyright 2006-2009,2011 Thomas E. Dickey
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License, version 2.1
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to
19 * Free Software Foundation, Inc.
20 * 51 Franklin St., Fifth Floor
21 * Boston, MA 02110, USA.
22 */
23
24 #include <dialog.h>
25 #include <dlg_keys.h>
26
27 #define LIST_BINDINGS struct _list_bindings
28
29 LIST_BINDINGS {
30 LIST_BINDINGS *link;
31 WINDOW *win; /* window on which widget gets input */
32 const char *name; /* widget name */
33 bool buttons; /* true only for dlg_register_buttons() */
34 DLG_KEYS_BINDING *binding; /* list of bindings */
35 };
36
37 #define WILDNAME "*"
38 static LIST_BINDINGS *all_bindings;
39 static const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING;
40
41 /*
42 * For a given named widget's window, associate a binding table.
43 */
44 void
dlg_register_window(WINDOW * win,const char * name,DLG_KEYS_BINDING * binding)45 dlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding)
46 {
47 LIST_BINDINGS *p, *q;
48
49 for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
50 if (p->win == win && !strcmp(p->name, name)) {
51 p->binding = binding;
52 return;
53 }
54 }
55 /* add built-in bindings at the end of the list (see compare_bindings). */
56 if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
57 p->win = win;
58 p->name = name;
59 p->binding = binding;
60 if (q != 0)
61 q->link = p;
62 else
63 all_bindings = p;
64 }
65 #if defined(HAVE_DLG_TRACE) && defined(HAVE_RC_FILE)
66 /*
67 * Trace the binding information assigned to this window. For most widgets
68 * there is only one binding table. forms have two, so the trace will be
69 * longer. Since compiled-in bindings are only visible when the widget is
70 * registered, there is no other way to see what bindings are available,
71 * than by running dialog and tracing it.
72 */
73 dlg_trace_msg("# dlg_register_window %s\n", name);
74 dlg_dump_window_keys(dialog_state.trace_output, win);
75 #endif
76 }
77
78 /*
79 * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file
80 * definitions, depending on whether 'win' is null.
81 */
82 static int
key_is_bound(WINDOW * win,const char * name,int curses_key,int function_key)83 key_is_bound(WINDOW *win, const char *name, int curses_key, int function_key)
84 {
85 LIST_BINDINGS *p;
86
87 for (p = all_bindings; p != 0; p = p->link) {
88 if (p->win == win && !dlg_strcmp(p->name, name)) {
89 int n;
90 for (n = 0; p->binding[n].is_function_key >= 0; ++n) {
91 if (p->binding[n].curses_key == curses_key
92 && p->binding[n].is_function_key == function_key) {
93 return TRUE;
94 }
95 }
96 }
97 }
98 return FALSE;
99 }
100
101 /*
102 * Call this function after dlg_register_window(), for the list of button
103 * labels associated with the widget.
104 *
105 * Ensure that dlg_lookup_key() will not accidentally translate a key that
106 * we would like to use for a button abbreviation to some other key, e.g.,
107 * h/j/k/l for navigation into a cursor key. Do this by binding the key
108 * to itself.
109 *
110 * See dlg_char_to_button().
111 */
112 void
dlg_register_buttons(WINDOW * win,const char * name,const char ** buttons)113 dlg_register_buttons(WINDOW *win, const char *name, const char **buttons)
114 {
115 int n;
116 LIST_BINDINGS *p;
117 DLG_KEYS_BINDING *q;
118
119 if (buttons == 0)
120 return;
121
122 for (n = 0; buttons[n] != 0; ++n) {
123 int curses_key = dlg_button_to_char(buttons[n]);
124
125 /* ignore multibyte characters */
126 if (curses_key >= KEY_MIN)
127 continue;
128
129 /* if it is not bound in the widget, skip it (no conflicts) */
130 if (!key_is_bound(win, name, curses_key, FALSE))
131 continue;
132
133 #ifdef HAVE_RC_FILE
134 /* if it is bound in the rc-file, skip it */
135 if (key_is_bound(0, name, curses_key, FALSE))
136 continue;
137 #endif
138
139 if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
140 if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) {
141 q[0].is_function_key = 0;
142 q[0].curses_key = curses_key;
143 q[0].dialog_key = curses_key;
144 q[1] = end_keys_binding;
145
146 p->win = win;
147 p->name = name;
148 p->buttons = TRUE;
149 p->binding = q;
150
151 /* put these at the beginning, to override the widget's table */
152 p->link = all_bindings;
153 all_bindings = p;
154 } else {
155 free(p);
156 }
157 }
158 }
159 }
160
161 /*
162 * Remove the bindings for a given window.
163 */
164 void
dlg_unregister_window(WINDOW * win)165 dlg_unregister_window(WINDOW *win)
166 {
167 LIST_BINDINGS *p, *q;
168
169 for (p = all_bindings, q = 0; p != 0; p = p->link) {
170 if (p->win == win) {
171 if (q != 0) {
172 q->link = p->link;
173 } else {
174 all_bindings = p->link;
175 }
176 /* the user-defined and buttons-bindings all are length=1 */
177 if (p->binding[1].is_function_key < 0)
178 free(p->binding);
179 free(p);
180 dlg_unregister_window(win);
181 break;
182 }
183 q = p;
184 }
185 }
186
187 /*
188 * Call this after wgetch(), using the same window pointer and passing
189 * the curses-key.
190 *
191 * If there is no binding associated with the widget, it simply returns
192 * the given curses-key.
193 *
194 * Parameters:
195 * win is the window on which the wgetch() was done.
196 * curses_key is the value returned by wgetch().
197 * fkey in/out (on input, it is true if curses_key is a function key,
198 * and on output, it is true if the result is a function key).
199 */
200 int
dlg_lookup_key(WINDOW * win,int curses_key,int * fkey)201 dlg_lookup_key(WINDOW *win, int curses_key, int *fkey)
202 {
203 LIST_BINDINGS *p;
204 DLG_KEYS_BINDING *q;
205
206 /*
207 * Ignore mouse clicks, since they are already encoded properly.
208 */
209 #ifdef KEY_MOUSE
210 if (*fkey != 0 && curses_key == KEY_MOUSE) {
211 ;
212 } else
213 #endif
214 /*
215 * Ignore resize events, since they are already encoded properly.
216 */
217 #ifdef KEY_RESIZE
218 if (*fkey != 0 && curses_key == KEY_RESIZE) {
219 ;
220 } else
221 #endif
222 if (*fkey == 0 || curses_key < KEY_MAX) {
223 const char *name = WILDNAME;
224 if (win != 0) {
225 for (p = all_bindings; p != 0; p = p->link) {
226 if (p->win == win) {
227 name = p->name;
228 break;
229 }
230 }
231 }
232 for (p = all_bindings; p != 0; p = p->link) {
233 if (p->win == win || (p->win == 0 && !strcmp(p->name, name))) {
234 int function_key = (*fkey != 0);
235 for (q = p->binding; q->is_function_key >= 0; ++q) {
236 if (p->buttons
237 && !function_key
238 && q->curses_key == (int) dlg_toupper(curses_key)) {
239 *fkey = 0;
240 return q->dialog_key;
241 }
242 if (q->curses_key == curses_key
243 && q->is_function_key == function_key) {
244 *fkey = q->dialog_key;
245 return *fkey;
246 }
247 }
248 }
249 }
250 }
251 return curses_key;
252 }
253
254 /*
255 * Test a dialog internal keycode to see if it corresponds to one of the push
256 * buttons on the widget such as "OK".
257 *
258 * This is only useful if there are user-defined key bindings, since there are
259 * no built-in bindings that map directly to DLGK_OK, etc.
260 *
261 * See also dlg_ok_buttoncode().
262 */
263 int
dlg_result_key(int dialog_key,int fkey GCC_UNUSED,int * resultp)264 dlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp)
265 {
266 int done = FALSE;
267
268 #ifdef HAVE_RC_FILE
269 if (fkey) {
270 switch ((DLG_KEYS_ENUM) dialog_key) {
271 case DLGK_OK:
272 *resultp = DLG_EXIT_OK;
273 done = TRUE;
274 break;
275 case DLGK_CANCEL:
276 if (!dialog_vars.nocancel) {
277 *resultp = DLG_EXIT_CANCEL;
278 done = TRUE;
279 }
280 break;
281 case DLGK_EXTRA:
282 if (dialog_vars.extra_button) {
283 *resultp = DLG_EXIT_EXTRA;
284 done = TRUE;
285 }
286 break;
287 case DLGK_HELP:
288 if (dialog_vars.help_button) {
289 *resultp = DLG_EXIT_HELP;
290 done = TRUE;
291 }
292 break;
293 case DLGK_ESC:
294 *resultp = DLG_EXIT_ESC;
295 done = TRUE;
296 break;
297 default:
298 break;
299 }
300 } else
301 #endif
302 if (dialog_key == ESC) {
303 *resultp = DLG_EXIT_ESC;
304 done = TRUE;
305 } else if (dialog_key == ERR) {
306 *resultp = DLG_EXIT_ERROR;
307 done = TRUE;
308 }
309
310 return done;
311 }
312
313 #ifdef HAVE_RC_FILE
314 typedef struct {
315 const char *name;
316 int code;
317 } CODENAME;
318
319 #define ASCII_NAME(name,code) { #name, code }
320 #define CURSES_NAME(upper) { #upper, KEY_ ## upper }
321 #define COUNT_CURSES sizeof(curses_names)/sizeof(curses_names[0])
322 static const CODENAME curses_names[] =
323 {
324 ASCII_NAME(ESC, '\033'),
325 ASCII_NAME(CR, '\r'),
326 ASCII_NAME(LF, '\n'),
327 ASCII_NAME(FF, '\f'),
328 ASCII_NAME(TAB, '\t'),
329 ASCII_NAME(DEL, '\177'),
330
331 CURSES_NAME(DOWN),
332 CURSES_NAME(UP),
333 CURSES_NAME(LEFT),
334 CURSES_NAME(RIGHT),
335 CURSES_NAME(HOME),
336 CURSES_NAME(BACKSPACE),
337 CURSES_NAME(F0),
338 CURSES_NAME(DL),
339 CURSES_NAME(IL),
340 CURSES_NAME(DC),
341 CURSES_NAME(IC),
342 CURSES_NAME(EIC),
343 CURSES_NAME(CLEAR),
344 CURSES_NAME(EOS),
345 CURSES_NAME(EOL),
346 CURSES_NAME(SF),
347 CURSES_NAME(SR),
348 CURSES_NAME(NPAGE),
349 CURSES_NAME(PPAGE),
350 CURSES_NAME(STAB),
351 CURSES_NAME(CTAB),
352 CURSES_NAME(CATAB),
353 CURSES_NAME(ENTER),
354 CURSES_NAME(PRINT),
355 CURSES_NAME(LL),
356 CURSES_NAME(A1),
357 CURSES_NAME(A3),
358 CURSES_NAME(B2),
359 CURSES_NAME(C1),
360 CURSES_NAME(C3),
361 CURSES_NAME(BTAB),
362 CURSES_NAME(BEG),
363 CURSES_NAME(CANCEL),
364 CURSES_NAME(CLOSE),
365 CURSES_NAME(COMMAND),
366 CURSES_NAME(COPY),
367 CURSES_NAME(CREATE),
368 CURSES_NAME(END),
369 CURSES_NAME(EXIT),
370 CURSES_NAME(FIND),
371 CURSES_NAME(HELP),
372 CURSES_NAME(MARK),
373 CURSES_NAME(MESSAGE),
374 CURSES_NAME(MOVE),
375 CURSES_NAME(NEXT),
376 CURSES_NAME(OPEN),
377 CURSES_NAME(OPTIONS),
378 CURSES_NAME(PREVIOUS),
379 CURSES_NAME(REDO),
380 CURSES_NAME(REFERENCE),
381 CURSES_NAME(REFRESH),
382 CURSES_NAME(REPLACE),
383 CURSES_NAME(RESTART),
384 CURSES_NAME(RESUME),
385 CURSES_NAME(SAVE),
386 CURSES_NAME(SBEG),
387 CURSES_NAME(SCANCEL),
388 CURSES_NAME(SCOMMAND),
389 CURSES_NAME(SCOPY),
390 CURSES_NAME(SCREATE),
391 CURSES_NAME(SDC),
392 CURSES_NAME(SDL),
393 CURSES_NAME(SELECT),
394 CURSES_NAME(SEND),
395 CURSES_NAME(SEOL),
396 CURSES_NAME(SEXIT),
397 CURSES_NAME(SFIND),
398 CURSES_NAME(SHELP),
399 CURSES_NAME(SHOME),
400 CURSES_NAME(SIC),
401 CURSES_NAME(SLEFT),
402 CURSES_NAME(SMESSAGE),
403 CURSES_NAME(SMOVE),
404 CURSES_NAME(SNEXT),
405 CURSES_NAME(SOPTIONS),
406 CURSES_NAME(SPREVIOUS),
407 CURSES_NAME(SPRINT),
408 CURSES_NAME(SREDO),
409 CURSES_NAME(SREPLACE),
410 CURSES_NAME(SRIGHT),
411 CURSES_NAME(SRSUME),
412 CURSES_NAME(SSAVE),
413 CURSES_NAME(SSUSPEND),
414 CURSES_NAME(SUNDO),
415 CURSES_NAME(SUSPEND),
416 CURSES_NAME(UNDO),
417 };
418
419 #define DIALOG_NAME(upper) { #upper, DLGK_ ## upper }
420 #define COUNT_DIALOG sizeof(dialog_names)/sizeof(dialog_names[0])
421 static const CODENAME dialog_names[] =
422 {
423 DIALOG_NAME(OK),
424 DIALOG_NAME(CANCEL),
425 DIALOG_NAME(EXTRA),
426 DIALOG_NAME(HELP),
427 DIALOG_NAME(ESC),
428 DIALOG_NAME(PAGE_FIRST),
429 DIALOG_NAME(PAGE_LAST),
430 DIALOG_NAME(PAGE_NEXT),
431 DIALOG_NAME(PAGE_PREV),
432 DIALOG_NAME(ITEM_FIRST),
433 DIALOG_NAME(ITEM_LAST),
434 DIALOG_NAME(ITEM_NEXT),
435 DIALOG_NAME(ITEM_PREV),
436 DIALOG_NAME(FIELD_FIRST),
437 DIALOG_NAME(FIELD_LAST),
438 DIALOG_NAME(FIELD_NEXT),
439 DIALOG_NAME(FIELD_PREV),
440 DIALOG_NAME(FORM_FIRST),
441 DIALOG_NAME(FORM_LAST),
442 DIALOG_NAME(FORM_NEXT),
443 DIALOG_NAME(FORM_PREV),
444 DIALOG_NAME(GRID_UP),
445 DIALOG_NAME(GRID_DOWN),
446 DIALOG_NAME(GRID_LEFT),
447 DIALOG_NAME(GRID_RIGHT),
448 DIALOG_NAME(DELETE_LEFT),
449 DIALOG_NAME(DELETE_RIGHT),
450 DIALOG_NAME(DELETE_ALL),
451 DIALOG_NAME(ENTER),
452 DIALOG_NAME(BEGIN),
453 DIALOG_NAME(FINAL),
454 DIALOG_NAME(SELECT),
455 DIALOG_NAME(HELPFILE),
456 DIALOG_NAME(TRACE)
457 };
458
459 static char *
skip_white(char * s)460 skip_white(char *s)
461 {
462 while (*s != '\0' && isspace(UCH(*s)))
463 ++s;
464 return s;
465 }
466
467 static char *
skip_black(char * s)468 skip_black(char *s)
469 {
470 while (*s != '\0' && !isspace(UCH(*s)))
471 ++s;
472 return s;
473 }
474
475 /*
476 * Find a user-defined binding, given the curses key code.
477 */
478 static DLG_KEYS_BINDING *
find_binding(char * widget,int curses_key)479 find_binding(char *widget, int curses_key)
480 {
481 LIST_BINDINGS *p;
482 DLG_KEYS_BINDING *result = 0;
483
484 for (p = all_bindings; p != 0; p = p->link) {
485 if (p->win == 0
486 && !dlg_strcmp(p->name, widget)
487 && p->binding->curses_key == curses_key) {
488 result = p->binding;
489 break;
490 }
491 }
492 return result;
493 }
494
495 /*
496 * Built-in bindings have a nonzero "win" member, and the associated binding
497 * table can have more than one entry. We keep those last, since lookups will
498 * find the user-defined bindings first and use those.
499 *
500 * Sort "*" (all-widgets) entries past named widgets, since those are less
501 * specific.
502 */
503 static int
compare_bindings(LIST_BINDINGS * a,LIST_BINDINGS * b)504 compare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b)
505 {
506 int result = 0;
507 if (a->win == b->win) {
508 if (!strcmp(a->name, b->name)) {
509 result = a->binding[0].curses_key - b->binding[0].curses_key;
510 } else if (!strcmp(b->name, WILDNAME)) {
511 result = -1;
512 } else if (!strcmp(a->name, WILDNAME)) {
513 result = 1;
514 } else {
515 result = dlg_strcmp(a->name, b->name);
516 }
517 } else if (b->win) {
518 result = -1;
519 } else {
520 result = 1;
521 }
522 return result;
523 }
524
525 /*
526 * Find a user-defined binding, given the curses key code. If it does not
527 * exist, create a new one, inserting it into the linked list, keeping it
528 * sorted to simplify lookups for user-defined bindings that can override
529 * the built-in bindings.
530 */
531 static DLG_KEYS_BINDING *
make_binding(char * widget,int curses_key,int is_function,int dialog_key)532 make_binding(char *widget, int curses_key, int is_function, int dialog_key)
533 {
534 LIST_BINDINGS *entry = 0;
535 DLG_KEYS_BINDING *data = 0;
536 char *name;
537 LIST_BINDINGS *p, *q;
538 DLG_KEYS_BINDING *result = find_binding(widget, curses_key);
539
540 if (result == 0
541 && (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0
542 && (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0
543 && (name = dlg_strclone(widget)) != 0) {
544
545 entry->name = name;
546 entry->binding = data;
547
548 data[0].is_function_key = is_function;
549 data[0].curses_key = curses_key;
550 data[0].dialog_key = dialog_key;
551
552 data[1] = end_keys_binding;
553
554 for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
555 if (compare_bindings(entry, p) < 0) {
556 break;
557 }
558 }
559 if (q != 0) {
560 q->link = entry;
561 } else {
562 all_bindings = entry;
563 }
564 if (p != 0) {
565 entry->link = p;
566 }
567 result = data;
568 } else if (entry != 0) {
569 free(entry);
570 if (data)
571 free(data);
572 }
573
574 return result;
575 }
576
577 /*
578 * Parse the parameters of the "bindkeys" configuration-file entry. This
579 * expects widget name which may be "*", followed by curses key definition and
580 * then dialog key definition.
581 *
582 * The curses key "should" be one of the names (ignoring case) from
583 * curses_names[], but may also be a single control character (prefix "^" or
584 * "~" depending on whether it is C0 or C1), or an escaped single character.
585 * Binding a printable character with dialog is possible but not useful.
586 *
587 * The dialog key must be one of the names from dialog_names[].
588 */
589 int
dlg_parse_bindkey(char * params)590 dlg_parse_bindkey(char *params)
591 {
592 char *p = skip_white(params);
593 char *q;
594 bool escaped = FALSE;
595 int modified = 0;
596 int result = FALSE;
597 unsigned xx;
598 char *widget;
599 int is_function = FALSE;
600 int curses_key;
601 int dialog_key;
602
603 curses_key = -1;
604 dialog_key = -1;
605 widget = p;
606
607 p = skip_black(p);
608 if (p != widget && *p != '\0') {
609 *p++ = '\0';
610 p = skip_white(p);
611 q = p;
612 while (*p != '\0' && curses_key < 0) {
613 if (escaped) {
614 escaped = FALSE;
615 curses_key = *p;
616 } else if (*p == '\\') {
617 escaped = TRUE;
618 } else if (modified) {
619 if (*p == '?') {
620 curses_key = ((modified == '^')
621 ? 127
622 : 255);
623 } else {
624 curses_key = ((modified == '^')
625 ? (*p & 0x1f)
626 : ((*p & 0x1f) | 0x80));
627 }
628 } else if (*p == '^') {
629 modified = *p;
630 } else if (*p == '~') {
631 modified = *p;
632 } else if (isspace(UCH(*p))) {
633 break;
634 }
635 ++p;
636 }
637 if (!isspace(UCH(*p))) {
638 ;
639 } else {
640 *p++ = '\0';
641 if (curses_key < 0) {
642 char fprefix[2];
643 char check[2];
644 int keynumber;
645 if (sscanf(q, "%[Ff]%d%c", fprefix, &keynumber, check) == 2) {
646 curses_key = KEY_F(keynumber);
647 is_function = TRUE;
648 } else {
649 for (xx = 0; xx < COUNT_CURSES; ++xx) {
650 if (!dlg_strcmp(curses_names[xx].name, q)) {
651 curses_key = curses_names[xx].code;
652 is_function = (curses_key >= KEY_MIN);
653 break;
654 }
655 }
656 }
657 }
658 }
659 q = skip_white(p);
660 p = skip_black(q);
661 if (p != q) {
662 for (xx = 0; xx < COUNT_DIALOG; ++xx) {
663 if (!dlg_strcmp(dialog_names[xx].name, q)) {
664 dialog_key = dialog_names[xx].code;
665 break;
666 }
667 }
668 }
669 if (*widget != '\0'
670 && curses_key >= 0
671 && dialog_key >= 0
672 && make_binding(widget, curses_key, is_function, dialog_key) != 0) {
673 result = TRUE;
674 }
675 }
676 return result;
677 }
678
679 static void
dump_curses_key(FILE * fp,int curses_key)680 dump_curses_key(FILE *fp, int curses_key)
681 {
682 if (curses_key > KEY_MIN) {
683 unsigned n;
684 bool found = FALSE;
685 for (n = 0; n < COUNT_CURSES; ++n) {
686 if (curses_names[n].code == curses_key) {
687 fprintf(fp, "%s", curses_names[n].name);
688 found = TRUE;
689 break;
690 }
691 }
692 if (!found) {
693 if (curses_key >= KEY_F(0)) {
694 fprintf(fp, "F%d", curses_key - KEY_F(0));
695 } else {
696 fprintf(fp, "curses%d", curses_key);
697 }
698 }
699 } else if (curses_key >= 0 && curses_key < 32) {
700 fprintf(fp, "^%c", curses_key + 64);
701 } else if (curses_key == 127) {
702 fprintf(fp, "^?");
703 } else if (curses_key >= 128 && curses_key < 160) {
704 fprintf(fp, "~%c", curses_key - 64);
705 } else if (curses_key == 255) {
706 fprintf(fp, "~?");
707 } else {
708 fprintf(fp, "\\%c", curses_key);
709 }
710 }
711
712 static void
dump_dialog_key(FILE * fp,int dialog_key)713 dump_dialog_key(FILE *fp, int dialog_key)
714 {
715 unsigned n;
716 bool found = FALSE;
717 for (n = 0; n < COUNT_DIALOG; ++n) {
718 if (dialog_names[n].code == dialog_key) {
719 fputs(dialog_names[n].name, fp);
720 found = TRUE;
721 break;
722 }
723 }
724 if (!found) {
725 fprintf(fp, "dialog%d", dialog_key);
726 }
727 }
728
729 static void
dump_one_binding(FILE * fp,const char * widget,DLG_KEYS_BINDING * binding)730 dump_one_binding(FILE *fp, const char *widget, DLG_KEYS_BINDING * binding)
731 {
732 fprintf(fp, "bindkey %s ", widget);
733 dump_curses_key(fp, binding->curses_key);
734 fputc(' ', fp);
735 dump_dialog_key(fp, binding->dialog_key);
736 fputc('\n', fp);
737 }
738
739 /*
740 * Dump bindings for the given window. If it is a null, then this dumps the
741 * initial bindings which were loaded from the rc-file that are used as
742 * overall defaults.
743 */
744 void
dlg_dump_window_keys(FILE * fp,WINDOW * win)745 dlg_dump_window_keys(FILE *fp, WINDOW *win)
746 {
747 if (fp != 0) {
748 LIST_BINDINGS *p;
749 DLG_KEYS_BINDING *q;
750 const char *last = "";
751
752 for (p = all_bindings; p != 0; p = p->link) {
753 if (p->win == win) {
754 if (dlg_strcmp(last, p->name)) {
755 fprintf(fp, "\n# key bindings for %s widgets\n",
756 !strcmp(p->name, WILDNAME) ? "all" : p->name);
757 last = p->name;
758 }
759 for (q = p->binding; q->is_function_key >= 0; ++q) {
760 dump_one_binding(fp, p->name, q);
761 }
762 }
763 }
764 }
765 }
766
767 /*
768 * Dump all of the bindings which are not specific to a given widget, i.e.,
769 * the "win" member is null.
770 */
771 void
dlg_dump_keys(FILE * fp)772 dlg_dump_keys(FILE *fp)
773 {
774 if (fp != 0) {
775 LIST_BINDINGS *p;
776 unsigned count = 0;
777
778 for (p = all_bindings; p != 0; p = p->link) {
779 if (p->win == 0) {
780 ++count;
781 }
782 }
783 if (count != 0) {
784 dlg_dump_window_keys(fp, 0);
785 }
786 }
787 }
788 #endif /* HAVE_RC_FILE */
789