Replace xkb_keycode_t 'key' variable name by 'kc'
[platform/upstream/libxkbcommon.git] / src / keymap-dump.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 /*
28  * Copyright © 2012 Intel Corporation
29  *
30  * Permission is hereby granted, free of charge, to any person obtaining a
31  * copy of this software and associated documentation files (the "Software"),
32  * to deal in the Software without restriction, including without limitation
33  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34  * and/or sell copies of the Software, and to permit persons to whom the
35  * Software is furnished to do so, subject to the following conditions:
36  *
37  * The above copyright notice and this permission notice (including the next
38  * paragraph) shall be included in all copies or substantial portions of the
39  * Software.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47  * DEALINGS IN THE SOFTWARE.
48  *
49  * Author: Daniel Stone <daniel@fooishbar.org>
50  */
51
52 #include <config.h>
53
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <stdlib.h>
57
58 #include "xkb-priv.h"
59 #include "text.h"
60
61 #define VMOD_HIDE_VALUE    0
62 #define VMOD_SHOW_VALUE    1
63 #define VMOD_COMMENT_VALUE 2
64
65 #define BUF_CHUNK_SIZE     4096
66
67 static bool
68 do_realloc(char **buf, size_t *size, size_t offset, size_t at_least)
69 {
70     char *new;
71
72     *size += BUF_CHUNK_SIZE;
73     if (at_least >= BUF_CHUNK_SIZE)
74         *size += at_least;
75
76     new = realloc(*buf, *size);
77     if (!new)
78         return false;
79     *buf = new;
80
81     memset(*buf + offset, 0, *size - offset);
82
83     return true;
84 }
85
86 /* This whole thing should be a function, but you can't call vsnprintf
87  * multiple times. */
88 #define check_write_buf(keymap, buf, size, offset, ...) \
89     do { \
90         size_t _printed; \
91         bool _ret = true; \
92     \
93         /* Concatenate the strings, and check whether or not the output was \
94          * truncated. */                                                                           \
95         while ((_printed = snprintf(*buf + *offset, *size - *offset, \
96                                     __VA_ARGS__)) >= \
97                (*size - *offset)) { \
98             /* If it was truncated, embiggen the string and roll from the top. */ \
99             if (!do_realloc(buf, size, *offset, _printed)) { \
100                 fprintf(stderr, \
101                         "xkbcommon: couldn't allocate %zu bytes for keymap\n", \
102                         *size); \
103                 free(*buf); \
104                 *buf = NULL; \
105                 _ret = false; \
106                 break; \
107             } \
108         } \
109         if (_ret == true) \
110             *offset += _printed; \
111     } while (0)
112
113 #define write_buf(keymap, buf, size, offset, ...) \
114     do { \
115         check_write_buf(keymap, buf, size, offset, __VA_ARGS__); \
116         if (*buf == NULL) \
117             return false; \
118     } while (0)
119
120 static bool
121 write_vmods(struct xkb_keymap *keymap, char **buf, size_t *size,
122             size_t *offset)
123 {
124     int num_vmods = 0;
125     int i;
126
127     for (i = 0; i < XkbNumVirtualMods; i++) {
128         if (!keymap->vmod_names[i])
129             continue;
130         if (num_vmods == 0)
131             write_buf(keymap, buf, size, offset, "\t\tvirtual_modifiers ");
132         else
133             write_buf(keymap, buf, size, offset, ",");
134         write_buf(keymap, buf, size, offset, "%s", keymap->vmod_names[i]);
135         num_vmods++;
136     }
137
138     if (num_vmods > 0)
139         write_buf(keymap, buf, size, offset, ";\n\n");
140
141     return true;
142 }
143
144 #define GET_TEXT_BUF_SIZE 512
145
146 #define append_get_text(...) do { \
147         int _size = snprintf(ret, GET_TEXT_BUF_SIZE, __VA_ARGS__); \
148         if (_size >= GET_TEXT_BUF_SIZE) \
149             return NULL; \
150 } while (0)
151
152 /* FIXME: Merge with src/xkbcomp/expr.c::modIndexNames. */
153 static const char *core_mod_names[] = {
154     "Shift",
155     "Lock",
156     "Control",
157     "Mod1",
158     "Mod2",
159     "Mod3",
160     "Mod4",
161     "Mod5",
162 };
163
164 static const char *
165 get_mod_index_text(uint8_t real_mod)
166 {
167     return core_mod_names[real_mod];
168 }
169
170 static char *
171 get_mod_mask_text(struct xkb_keymap *keymap, uint8_t real_mods,
172                   uint32_t vmods)
173 {
174     static char ret[GET_TEXT_BUF_SIZE], ret2[GET_TEXT_BUF_SIZE];
175     int i;
176
177     memset(ret, 0, GET_TEXT_BUF_SIZE);
178
179     if (real_mods == 0 && vmods == 0) {
180         strcpy(ret, "none");
181         return ret;
182     }
183
184     /* This is so broken.  If we have a real modmask of 0xff and a
185      * vmodmask, we'll get, e.g., all+RightControl.  But, it's what xkbfile
186      * does, so ... */
187     if (real_mods == 0xff) {
188         strcpy(ret, "all");
189     }
190     else if (real_mods) {
191         for (i = 0; i < XkbNumModifiers; i++) {
192             if (!(real_mods & (1 << i)))
193                 continue;
194             if (ret[0] != '\0') {
195                 strcpy(ret2, ret);
196                 append_get_text("%s+%s", ret2, core_mod_names[i]);
197             }
198             else {
199                 append_get_text("%s", core_mod_names[i]);
200             }
201         }
202     }
203
204     if (vmods == 0)
205         return ret;
206
207     for (i = 0; i < XkbNumVirtualMods; i++) {
208         if (!(vmods & (1 << i)))
209             continue;
210         if (ret[0] != '\0') {
211             strcpy(ret2, ret);
212             append_get_text("%s+%s", ret2, keymap->vmod_names[i]);
213         }
214         else {
215             append_get_text("%s", keymap->vmod_names[i]);
216         }
217     }
218
219     return ret;
220 }
221
222 static char *
223 get_indicator_state_text(uint8_t which)
224 {
225     int i;
226     static char ret[GET_TEXT_BUF_SIZE];
227     /* FIXME: Merge with ... something ... in xkbcomp? */
228     static const char *state_names[] = {
229         "base",
230         "latched",
231         "locked",
232         "effective",
233         "compat"
234     };
235
236     memset(ret, 0, GET_TEXT_BUF_SIZE);
237
238     which &= XkbIM_UseAnyMods;
239
240     if (which == 0) {
241         strcpy(ret, "0");
242         return NULL;
243     }
244
245     for (i = 0; which != 0; i++) {
246         if (!(which & (1 << i)))
247             continue;
248         which &= ~(1 << i);
249
250         if (ret[0] != '\0')
251             append_get_text("%s+%s", ret, state_names[i]);
252         else
253             append_get_text("%s", state_names[i]);
254     }
255
256     return ret;
257 }
258
259 static char *
260 get_control_mask_text(uint32_t control_mask)
261 {
262     int i;
263     static char ret[GET_TEXT_BUF_SIZE];
264     /* FIXME: Merge with ... something ... in xkbcomp. */
265     static const char *ctrl_names[] = {
266         "RepeatKeys",
267         "SlowKeys",
268         "BounceKeys",
269         "StickyKeys",
270         "MouseKeys",
271         "MouseKeysAccel",
272         "AccessXKeys",
273         "AccessXTimeout",
274         "AccessXFeedback",
275         "AudibleBell",
276         "Overlay1",
277         "Overlay2",
278         "IgnoreGroupLock"
279     };
280
281     memset(ret, 0, GET_TEXT_BUF_SIZE);
282
283     control_mask &= XkbAllBooleanCtrlsMask;
284
285     if (control_mask == 0) {
286         strcpy(ret, "none");
287         return ret;
288     }
289     else if (control_mask == XkbAllBooleanCtrlsMask) {
290         strcpy(ret, "all");
291         return ret;
292     }
293
294     for (i = 0; control_mask; i++) {
295         if (!(control_mask & (1 << i)))
296             continue;
297         control_mask &= ~(1 << i);
298
299         if (ret[0] != '\0')
300             append_get_text("%s+%s", ret, ctrl_names[i]);
301         else
302             append_get_text("%s", ctrl_names[i]);
303     }
304
305     return ret;
306 }
307
308 static bool
309 write_keycodes(struct xkb_keymap *keymap, char **buf, size_t *size,
310                size_t *offset)
311 {
312     xkb_keycode_t kc;
313     struct xkb_key_alias *alias;
314     int i;
315
316     if (keymap->keycodes_section_name)
317         write_buf(keymap, buf, size, offset, "\txkb_keycodes \"%s\" {\n",
318                   keymap->keycodes_section_name);
319     else
320         write_buf(keymap, buf, size, offset, "\txkb_keycodes {\n");
321
322     write_buf(keymap, buf, size, offset, "\t\tminimum = %d;\n",
323               keymap->min_key_code);
324     write_buf(keymap, buf, size, offset, "\t\tmaximum = %d;\n",
325               keymap->max_key_code);
326
327     for (kc = keymap->min_key_code; kc <= keymap->max_key_code; kc++) {
328         if (darray_item(keymap->key_names, kc).name[0] == '\0')
329             continue;
330
331         write_buf(keymap, buf, size, offset, "\t\t%6s = %d;\n",
332                   XkbcKeyNameText(darray_item(keymap->key_names, kc).name),
333                   kc);
334     }
335
336     for (i = 0; i < XkbNumIndicators; i++) {
337         if (!keymap->indicator_names[i])
338             continue;
339         write_buf(keymap, buf, size, offset, "\t\tindicator %d = \"%s\";\n",
340                   i + 1, keymap->indicator_names[i]);
341     }
342
343
344     darray_foreach(alias, keymap->key_aliases)
345         write_buf(keymap, buf, size, offset, "\t\talias %6s = %6s;\n",
346                   XkbcKeyNameText(alias->alias),
347                   XkbcKeyNameText(alias->real));
348
349     write_buf(keymap, buf, size, offset, "\t};\n\n");
350     return true;
351 }
352
353 static bool
354 write_types(struct xkb_keymap *keymap, char **buf, size_t *size,
355             size_t *offset)
356 {
357     int n;
358     struct xkb_key_type *type;
359
360     if (keymap->types_section_name)
361         write_buf(keymap, buf, size, offset, "\txkb_types \"%s\" {\n\n",
362                   keymap->types_section_name);
363     else
364         write_buf(keymap, buf, size, offset, "\txkb_types {\n\n");
365
366     write_vmods(keymap, buf, size, offset);
367
368     darray_foreach(type, keymap->types) {
369         write_buf(keymap, buf, size, offset, "\t\ttype \"%s\" {\n",
370                   type->name);
371         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
372                   get_mod_mask_text(keymap, type->mods.real_mods,
373                                     type->mods.vmods));
374
375         for (n = 0; n < darray_size(type->map); n++) {
376             struct xkb_kt_map_entry *entry = &darray_item(type->map, n);
377             char *str;
378
379             str = get_mod_mask_text(keymap, entry->mods.real_mods,
380                                     entry->mods.vmods);
381             write_buf(keymap, buf, size, offset, "\t\t\tmap[%s]= Level%d;\n",
382                       str, entry->level + 1);
383
384             if (!type->preserve || (!type->preserve[n].real_mods &&
385                                     !type->preserve[n].vmods))
386                 continue;
387             write_buf(keymap, buf, size, offset, "\t\t\tpreserve[%s]= ", str);
388             write_buf(keymap, buf, size, offset, "%s;\n",
389                       get_mod_mask_text(keymap, type->preserve[n].real_mods,
390                                         type->preserve[n].vmods));
391         }
392
393         if (type->level_names) {
394             for (n = 0; n < type->num_levels; n++) {
395                 if (!type->level_names[n])
396                     continue;
397                 write_buf(keymap, buf, size, offset,
398                           "\t\t\tlevel_name[Level%d]= \"%s\";\n", n + 1,
399                           type->level_names[n]);
400             }
401         }
402         write_buf(keymap, buf, size, offset, "\t\t};\n");
403     }
404
405     write_buf(keymap, buf, size, offset, "\t};\n\n");
406     return true;
407 }
408
409 static bool
410 write_indicator_map(struct xkb_keymap *keymap, char **buf, size_t *size,
411                     size_t *offset, int num)
412 {
413     struct xkb_indicator_map *led = &keymap->indicators[num];
414
415     write_buf(keymap, buf, size, offset, "\t\tindicator \"%s\" {\n",
416               keymap->indicator_names[num]);
417
418     if (led->which_groups) {
419         if (led->which_groups != XkbIM_UseEffective) {
420             write_buf(keymap, buf, size, offset,
421                       "\t\t\twhichGroupState= %s;\n",
422                       get_indicator_state_text(
423                           led->which_groups));
424         }
425         write_buf(keymap, buf, size, offset, "\t\t\tgroups= 0x%02x;\n",
426                   led->groups);
427     }
428
429     if (led->which_mods) {
430         if (led->which_mods != XkbIM_UseEffective) {
431             write_buf(keymap, buf, size, offset, "\t\t\twhichModState= %s;\n",
432                       get_indicator_state_text(led->which_mods));
433         }
434         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
435                   get_mod_mask_text(keymap, led->mods.real_mods,
436                                     led->mods.vmods));
437     }
438
439     if (led->ctrls) {
440         write_buf(keymap, buf, size, offset, "\t\t\tcontrols= %s;\n",
441                   get_control_mask_text(led->ctrls));
442     }
443
444     write_buf(keymap, buf, size, offset, "\t\t};\n");
445     return true;
446 }
447
448 static char *
449 get_interp_match_text(uint8_t type)
450 {
451     static char ret[16];
452
453     switch (type & XkbSI_OpMask) {
454     case XkbSI_NoneOf:
455         sprintf(ret, "NoneOf");
456         break;
457
458     case XkbSI_AnyOfOrNone:
459         sprintf(ret, "AnyOfOrNone");
460         break;
461
462     case XkbSI_AnyOf:
463         sprintf(ret, "AnyOf");
464         break;
465
466     case XkbSI_AllOf:
467         sprintf(ret, "AllOf");
468         break;
469
470     case XkbSI_Exactly:
471         sprintf(ret, "Exactly");
472         break;
473
474     default:
475         sprintf(ret, "0x%x", type & XkbSI_OpMask);
476         break;
477     }
478
479     return ret;
480 }
481
482 static bool
483 write_action(struct xkb_keymap *keymap, char **buf, size_t *size,
484              size_t *offset, union xkb_action *action, const char *prefix,
485              const char *suffix)
486 {
487     const char *type = NULL;
488     const char *args = NULL;
489
490     if (!prefix)
491         prefix = "";
492     if (!suffix)
493         suffix = "";
494
495     switch (action->any.type) {
496     case XkbSA_SetMods:
497         if (!type)
498             type = "SetMods";
499     case XkbSA_LatchMods:
500         if (!type)
501             type = "LatchMods";
502     case XkbSA_LockMods:
503         if (!type)
504             type = "LockMods";
505         if (action->mods.flags & XkbSA_UseModMapMods)
506             args = "modMapMods";
507         else
508             args = get_mod_mask_text(keymap, action->mods.real_mods,
509                                      action->mods.vmods);
510         write_buf(keymap, buf, size, offset, "%s%s(modifiers=%s%s%s)%s",
511                   prefix, type, args,
512                   (action->any.type != XkbSA_LockGroup &&
513                    (action->mods.flags & XkbSA_ClearLocks)) ?
514                    ",clearLocks" : "",
515                   (action->any.type != XkbSA_LockGroup &&
516                    (action->mods.flags & XkbSA_LatchToLock)) ?
517                    ",latchToLock" : "",
518                   suffix);
519         break;
520
521     case XkbSA_SetGroup:
522         if (!type)
523             type = "SetGroup";
524     case XkbSA_LatchGroup:
525         if (!type)
526             type = "LatchGroup";
527     case XkbSA_LockGroup:
528         if (!type)
529             type = "LockGroup";
530         write_buf(
531             keymap, buf, size, offset, "%s%s(group=%s%d%s%s)%s",
532             prefix, type,
533             (!(action->group.flags & XkbSA_GroupAbsolute) &&
534              action->group.group > 0) ? "+" : "",
535             (action->group.flags & XkbSA_GroupAbsolute) ?
536              action->group.group + 1 : action->group.group,
537             (action->any.type != XkbSA_LockGroup &&
538              (action->group.flags & XkbSA_ClearLocks)) ?
539              ",clearLocks" : "",
540             (action->any.type != XkbSA_LockGroup &&
541              (action->group.flags & XkbSA_LatchToLock)) ?
542              ",latchToLock" : "",
543             suffix);
544         break;
545
546     case XkbSA_Terminate:
547         write_buf(keymap, buf, size, offset, "%sTerminate()%s", prefix,
548                   suffix);
549         break;
550
551     case XkbSA_MovePtr:
552         write_buf(keymap, buf, size, offset, "%sMovePtr(x=%s%d,y=%s%d%s)%s",
553                   prefix,
554                   (!(action->ptr.flags & XkbSA_MoveAbsoluteX) &&
555                    action->ptr.x >= 0) ? "+" : "",
556                   action->ptr.x,
557                   (!(action->ptr.flags & XkbSA_MoveAbsoluteY) &&
558                    action->ptr.y >= 0) ? "+" : "",
559                   action->ptr.y,
560                   (action->ptr.flags & XkbSA_NoAcceleration) ? ",!accel" : "",
561                   suffix);
562         break;
563
564     case XkbSA_PtrBtn:
565         if (!type)
566             type = "PtrBtn";
567     case XkbSA_LockPtrBtn:
568         if (!type) {
569             type = "LockPtrBtn";
570             switch (action->btn.flags &
571                     (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
572             case XkbSA_LockNoUnlock:
573                 args = ",affect=lock";
574                 break;
575
576             case XkbSA_LockNoLock:
577                 args = ",affect=unlock";
578                 break;
579
580             case XkbSA_LockNoLock | XkbSA_LockNoUnlock:
581                 args = ",affect=neither";
582                 break;
583
584             default:
585                 args = ",affect=both";
586                 break;
587             }
588         }
589         else {
590             args = NULL;
591         }
592         write_buf(keymap, buf, size, offset, "%s%s(button=", prefix, type);
593         if (action->btn.button > 0 && action->btn.button <= 5)
594             write_buf(keymap, buf, size, offset, "%d", action->btn.button);
595         else
596             write_buf(keymap, buf, size, offset, "default");
597         if (action->btn.count)
598             write_buf(keymap, buf, size, offset, ",count=%d",
599                       action->btn.count);
600         if (args)
601             write_buf(keymap, buf, size, offset, "%s", args);
602         write_buf(keymap, buf, size, offset, ")%s", suffix);
603         break;
604
605     case XkbSA_SetPtrDflt:
606         write_buf(keymap, buf, size, offset, "%sSetPtrDflt(", prefix);
607         if (action->dflt.affect == XkbSA_AffectDfltBtn)
608             write_buf(keymap, buf, size, offset, "affect=button,button=%s%d",
609                       (!(action->dflt.flags & XkbSA_DfltBtnAbsolute) &&
610                        action->dflt.value >= 0) ? "+" : "",
611                       action->dflt.value);
612         write_buf(keymap, buf, size, offset, ")%s", suffix);
613         break;
614
615     case XkbSA_SwitchScreen:
616         write_buf(keymap, buf, size, offset,
617                   "%sSwitchScreen(screen=%s%d,%ssame)%s", prefix,
618                   (!(action->screen.flags & XkbSA_SwitchAbsolute) &&
619                    action->screen.screen >= 0) ? "+" : "",
620                   action->screen.screen,
621                   (action->screen.flags & XkbSA_SwitchApplication) ? "!" : "",
622                   suffix);
623         break;
624
625     /* Deprecated actions below here */
626     case XkbSA_SetControls:
627         if (!type)
628             type = "SetControls";
629     case XkbSA_LockControls:
630         if (!type)
631             type = "LockControls";
632         write_buf(keymap, buf, size, offset, "%s%s(controls=%s)%s",
633                   prefix, type, get_control_mask_text(action->ctrls.ctrls),
634                   suffix);
635         break;
636
637     case XkbSA_ISOLock:
638     case XkbSA_ActionMessage:
639     case XkbSA_RedirectKey:
640     case XkbSA_DeviceBtn:
641     case XkbSA_LockDeviceBtn:
642     case XkbSA_NoAction:
643         /* XXX TODO */
644         write_buf(keymap, buf, size, offset, "%sNoAction()%s", prefix, suffix);
645         break;
646
647     case XkbSA_XFree86Private:
648     default:
649         write_buf(keymap, buf, size, offset,
650                   "%sPrivate(type=0x%02x,data[0]=0x%02x,data[1]=0x%02x,data[2]=0x%02x,data[3]=0x%02x,data[4]=0x%02x,data[5]=0x%02x,data[6]=0x%02x)%s",
651                   prefix, action->any.type, action->any.data[0],
652                   action->any.data[1], action->any.data[2],
653                   action->any.data[3], action->any.data[4],
654                   action->any.data[5], action->any.data[6],
655                   suffix);
656         break;
657     }
658
659     return true;
660 }
661
662 static bool
663 write_compat(struct xkb_keymap *keymap, char **buf, size_t *size,
664              size_t *offset)
665 {
666     int i;
667     struct xkb_sym_interpret *interp;
668
669     if (keymap->compat_section_name)
670         write_buf(keymap, buf, size, offset,
671                   "\txkb_compatibility \"%s\" {\n\n",
672                   keymap->compat_section_name);
673     else
674         write_buf(keymap, buf, size, offset, "\txkb_compatibility {\n\n");
675
676     write_vmods(keymap, buf, size, offset);
677
678     write_buf(keymap, buf, size, offset,
679               "\t\tinterpret.useModMapMods= AnyLevel;\n");
680     write_buf(keymap, buf, size, offset, "\t\tinterpret.repeat= False;\n");
681     write_buf(keymap, buf, size, offset, "\t\tinterpret.locking= False;\n");
682
683     darray_foreach(interp, keymap->sym_interpret) {
684         char keysym_name[64];
685
686         if (interp->sym == XKB_KEY_NoSymbol)
687             sprintf(keysym_name, "Any");
688         else
689             xkb_keysym_get_name(interp->sym, keysym_name, sizeof(keysym_name));
690
691         write_buf(keymap, buf, size, offset, "\t\tinterpret %s+%s(%s) {\n",
692                   keysym_name,
693                   get_interp_match_text(interp->match),
694                   get_mod_mask_text(keymap, interp->mods, 0));
695
696         if (interp->virtual_mod != XkbNoModifier) {
697             write_buf(keymap, buf, size, offset,
698                       "\t\t\tvirtualModifier= %s;\n",
699                       keymap->vmod_names[interp->virtual_mod]);
700         }
701
702         if (interp->match & XkbSI_LevelOneOnly)
703             write_buf(keymap, buf, size, offset,
704                       "\t\t\tuseModMapMods=level1;\n");
705         if (interp->flags & XkbSI_LockingKey)
706             write_buf(keymap, buf, size, offset, "\t\t\tlocking= True;\n");
707         if (interp->flags & XkbSI_AutoRepeat)
708             write_buf(keymap, buf, size, offset, "\t\t\trepeat= True;\n");
709
710         write_action(keymap, buf, size, offset, &interp->act,
711                      "\t\t\taction= ", ";\n");
712         write_buf(keymap, buf, size, offset, "\t\t};\n");
713     }
714
715     for (i = 0; i < XkbNumKbdGroups; i++) {
716         struct xkb_mods *gc;
717
718         gc = &keymap->groups[i];
719         if (gc->real_mods == 0 && gc->vmods == 0)
720             continue;
721         write_buf(keymap, buf, size, offset,
722                   "\t\tgroup %d = %s;\n", i + 1,
723                   get_mod_mask_text(keymap, gc->real_mods, gc->vmods));
724     }
725
726     for (i = 0; i < XkbNumIndicators; i++) {
727         struct xkb_indicator_map *map = &keymap->indicators[i];
728         if (map->flags == 0 && map->which_groups == 0 &&
729             map->groups == 0 && map->which_mods == 0 &&
730             map->mods.real_mods == 0 && map->mods.vmods == 0 &&
731             map->ctrls == 0)
732             continue;
733         write_indicator_map(keymap, buf, size, offset, i);
734     }
735
736     write_buf(keymap, buf, size, offset, "\t};\n\n");
737
738     return true;
739 }
740
741 static bool
742 write_keysyms(struct xkb_keymap *keymap, char **buf, size_t *size,
743               size_t *offset, xkb_keycode_t kc, unsigned int group)
744 {
745     const xkb_keysym_t *syms;
746     int num_syms, level;
747 #define OUT_BUF_LEN 128
748     char out_buf[OUT_BUF_LEN];
749
750     for (level = 0; level < XkbKeyGroupWidth(keymap, kc, group); level++) {
751         if (level != 0)
752             write_buf(keymap, buf, size, offset, ", ");
753         num_syms = xkb_key_get_syms_by_level(keymap, kc, group, level,
754                                              &syms);
755         if (num_syms == 0) {
756             write_buf(keymap, buf, size, offset, "%15s", "NoSymbol");
757         }
758         else if (num_syms == 1) {
759             xkb_keysym_get_name(syms[0], out_buf, OUT_BUF_LEN);
760             write_buf(keymap, buf, size, offset, "%15s", out_buf);
761         }
762         else {
763             int s;
764             write_buf(keymap, buf, size, offset, "{ ");
765             for (s = 0; s < num_syms; s++) {
766                 if (s != 0)
767                     write_buf(keymap, buf, size, offset, ", ");
768                 xkb_keysym_get_name(syms[s], out_buf, OUT_BUF_LEN);
769                 write_buf(keymap, buf, size, offset, "%15s", out_buf);
770             }
771             write_buf(keymap, buf, size, offset, " }");
772         }
773     }
774 #undef OUT_BUF_LEN
775
776     return true;
777 }
778
779 static bool
780 write_symbols(struct xkb_keymap *keymap, char **buf, size_t *size,
781               size_t *offset)
782 {
783     xkb_keycode_t kc;
784     int group, tmp;
785     bool showActions;
786
787     if (keymap->symbols_section_name)
788         write_buf(keymap, buf, size, offset, "\txkb_symbols \"%s\" {\n\n",
789                   keymap->symbols_section_name);
790     else
791         write_buf(keymap, buf, size, offset, "\txkb_symbols {\n\n");
792
793     for (tmp = group = 0; group < XkbNumKbdGroups; group++) {
794         if (!keymap->group_names[group])
795             continue;
796         write_buf(keymap, buf, size, offset,
797                   "\t\tname[group%d]=\"%s\";\n", group + 1,
798                   keymap->group_names[group]);
799         tmp++;
800     }
801     if (tmp > 0)
802         write_buf(keymap, buf, size, offset, "\n");
803
804     for (kc = keymap->min_key_code; kc <= keymap->max_key_code; kc++) {
805         bool simple = true;
806
807         if (xkb_key_num_groups(keymap, kc) == 0)
808             continue;
809
810         write_buf(keymap, buf, size, offset, "\t\tkey %6s {",
811                   XkbcKeyNameText(darray_item(keymap->key_names, kc).name));
812         if (keymap->explicit) {
813             if ((keymap->explicit[kc] & XkbExplicitKeyTypesMask)) {
814                 bool multi_type = false;
815                 int type = XkbKeyTypeIndex(keymap, kc, 0);
816
817                 simple = false;
818
819                 for (group = 0; group < xkb_key_num_groups(keymap, kc);
820                      group++) {
821                     if (XkbKeyTypeIndex(keymap, kc, group) != type) {
822                         multi_type = true;
823                         break;
824                     }
825                 }
826                 if (multi_type) {
827                     for (group = 0;
828                          group < xkb_key_num_groups(keymap, kc);
829                          group++) {
830                         if (!(keymap->explicit[kc] & (1 << group)))
831                             continue;
832                         type = XkbKeyTypeIndex(keymap, kc, group);
833                         write_buf(keymap, buf, size, offset,
834                                   "\n\t\t\ttype[group%d]= \"%s\",",
835                                   group + 1,
836                                   darray_item(keymap->types, type).name);
837                     }
838                 }
839                 else {
840                     write_buf(keymap, buf, size, offset,
841                               "\n\t\t\ttype= \"%s\",",
842                               darray_item(keymap->types, type).name);
843                 }
844             }
845             if (keymap->explicit[kc] & XkbExplicitAutoRepeatMask) {
846                 if (keymap->per_key_repeat[kc / 8] & (1 << (kc % 8)))
847                     write_buf(keymap, buf, size, offset,
848                               "\n\t\t\trepeat= Yes,");
849                 else
850                     write_buf(keymap, buf, size, offset,
851                               "\n\t\t\trepeat= No,");
852                 simple = false;
853             }
854             if (keymap->vmodmap[kc] &&
855                 (keymap->explicit[kc] & XkbExplicitVModMapMask)) {
856                 write_buf(keymap, buf, size, offset,
857                           "\n\t\t\tvirtualMods= %s,",
858                           get_mod_mask_text(keymap, 0, keymap->vmodmap[kc]));
859             }
860         }
861
862         switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(keymap, kc))) {
863         case XkbClampIntoRange:
864             write_buf(keymap, buf, size, offset, "\n\t\t\tgroupsClamp,");
865             break;
866
867         case XkbRedirectIntoRange:
868             write_buf(keymap, buf, size, offset,
869                       "\n\t\t\tgroupsRedirect= Group%d,",
870                       XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(keymap,
871                                                                kc)) + 1);
872             break;
873         }
874
875         if (keymap->explicit == NULL ||
876             (keymap->explicit[kc] & XkbExplicitInterpretMask))
877             showActions = XkbKeyHasActions(keymap, kc);
878         else
879             showActions = false;
880
881         if (xkb_key_num_groups(keymap, kc) > 1 || showActions)
882             simple = false;
883
884         if (simple) {
885             write_buf(keymap, buf, size, offset, "\t[ ");
886             if (!write_keysyms(keymap, buf, size, offset, kc, 0))
887                 return false;
888             write_buf(keymap, buf, size, offset, " ] };\n");
889         }
890         else {
891             union xkb_action *acts;
892             int level;
893
894             acts = XkbKeyActionsPtr(keymap, kc);
895             for (group = 0; group < xkb_key_num_groups(keymap, kc); group++) {
896                 if (group != 0)
897                     write_buf(keymap, buf, size, offset, ",");
898                 write_buf(keymap, buf, size, offset,
899                           "\n\t\t\tsymbols[Group%d]= [ ", group + 1);
900                 if (!write_keysyms(keymap, buf, size, offset, kc, group))
901                     return false;
902                 write_buf(keymap, buf, size, offset, " ]");
903                 if (showActions) {
904                     write_buf(keymap, buf, size, offset,
905                               ",\n\t\t\tactions[Group%d]= [ ", group + 1);
906                     for (level = 0;
907                          level < XkbKeyGroupWidth(keymap, kc, group);
908                          level++) {
909                         if (level != 0)
910                             write_buf(keymap, buf, size, offset, ", ");
911                         write_action(keymap, buf, size, offset, &acts[level],
912                                      NULL, NULL);
913                     }
914                     write_buf(keymap, buf, size, offset, " ]");
915                     acts += XkbKeyGroupsWidth(keymap, kc);
916                 }
917             }
918             write_buf(keymap, buf, size, offset, "\n\t\t};\n");
919         }
920     }
921     if (keymap->modmap) {
922         for (kc = keymap->min_key_code; kc <= keymap->max_key_code; kc++) {
923             int mod;
924
925             if (keymap->modmap[kc] == 0)
926                 continue;
927
928             for (mod = 0; mod < XkbNumModifiers; mod++) {
929                 if (!(keymap->modmap[kc] & (1 << mod)))
930                     continue;
931
932                 write_buf(keymap, buf, size, offset,
933                           "\t\tmodifier_map %s { %s };\n",
934                           get_mod_index_text(mod),
935                           XkbcKeyNameText(darray_item(keymap->key_names,
936                                                       kc).name));
937             }
938         }
939     }
940
941     write_buf(keymap, buf, size, offset, "\t};\n\n");
942     return true;
943 }
944
945 _X_EXPORT char *
946 xkb_map_get_as_string(struct xkb_keymap *keymap)
947 {
948     char *ret = NULL;
949     size_t size = 0;
950     size_t offset = 0;
951
952     check_write_buf(keymap, &ret, &size, &offset, "xkb_keymap {\n");
953     if (ret == NULL)
954         return NULL;
955     if (!write_keycodes(keymap, &ret, &size, &offset))
956         return NULL;
957     if (!write_types(keymap, &ret, &size, &offset))
958         return NULL;
959     if (!write_compat(keymap, &ret, &size, &offset))
960         return NULL;
961     if (!write_symbols(keymap, &ret, &size, &offset))
962         return NULL;
963     check_write_buf(keymap, &ret, &size, &offset, "};\n");
964     if (ret == NULL)
965         return NULL;
966
967     return ret;
968 }