dump: add back kccgst names
[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: failed to 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, size_t *offset)
122 {
123     int num_vmods = 0;
124     int i;
125
126     for (i = 0; i < XkbNumVirtualMods; i++) {
127         if (!keymap->names->vmods[i])
128             continue;
129         if (num_vmods == 0)
130             write_buf(keymap, buf, size, offset, "\t\tvirtual_modifiers ");
131         else
132             write_buf(keymap, buf, size, offset, ",");
133         write_buf(keymap, buf, size, offset, "%s", keymap->names->vmods[i]);
134         num_vmods++;
135     }
136
137     if (num_vmods > 0)
138         write_buf(keymap, buf, size, offset, ";\n\n");
139
140     return true;
141 }
142
143 #define GET_TEXT_BUF_SIZE 512
144
145 #define append_get_text(...) do { \
146     int _size = snprintf(ret, GET_TEXT_BUF_SIZE, __VA_ARGS__); \
147     if (_size >= GET_TEXT_BUF_SIZE) \
148         return NULL; \
149 } while(0)
150
151 /* FIXME: Merge with src/xkbcomp/expr.c::modIndexNames. */
152 static const char *core_mod_names[] = {
153     "Shift",
154     "Lock",
155     "Control",
156     "Mod1",
157     "Mod2",
158     "Mod3",
159     "Mod4",
160     "Mod5",
161 };
162
163 static const char *
164 get_mod_index_text(uint8_t real_mod)
165 {
166     return core_mod_names[real_mod];
167 }
168
169 static char *
170 get_mod_mask_text(struct xkb_keymap *keymap, uint8_t real_mods, uint32_t vmods)
171 {
172     static char ret[GET_TEXT_BUF_SIZE], ret2[GET_TEXT_BUF_SIZE];
173     int i;
174
175     memset(ret, 0, GET_TEXT_BUF_SIZE);
176
177     if (real_mods == 0 && vmods == 0) {
178         strcpy(ret, "none");
179         return ret;
180     }
181
182     /* This is so broken.  If we have a real modmask of 0xff and a
183      * vmodmask, we'll get, e.g., all+RightControl.  But, it's what xkbfile
184      * does, so ... */
185     if (real_mods == 0xff) {
186         strcpy(ret, "all");
187     }
188     else if (real_mods) {
189         for (i = 0; i < XkbNumModifiers; i++) {
190             if (!(real_mods & (1 << i)))
191                 continue;
192             if (ret[0] != '\0') {
193                 strcpy(ret2, ret);
194                 append_get_text("%s+%s", ret2, core_mod_names[i]);
195             }
196             else {
197                 append_get_text("%s", core_mod_names[i]);
198             }
199         }
200     }
201
202     if (vmods == 0)
203         return ret;
204
205     for (i = 0; i < XkbNumVirtualMods; i++) {
206         if (!(vmods & (1 << i)))
207             continue;
208         if (ret[0] != '\0') {
209             strcpy(ret2, ret);
210             append_get_text("%s+%s", ret2, keymap->names->vmods[i]);
211         }
212         else {
213             append_get_text("%s", keymap->names->vmods[i]);
214         }
215     }
216
217     return ret;
218 }
219
220 static char *
221 get_indicator_state_text(uint8_t which)
222 {
223     int i;
224     static char ret[GET_TEXT_BUF_SIZE];
225     /* FIXME: Merge with ... something ... in xkbcomp? */
226     static const char *state_names[] = {
227         "base",
228         "latched",
229         "locked",
230         "effective",
231         "compat"
232     };
233
234     memset(ret, 0, GET_TEXT_BUF_SIZE);
235
236     which &= XkbIM_UseAnyMods;
237
238     if (which == 0) {
239         strcpy(ret, "0");
240         return NULL;
241     }
242
243     for (i = 0; which != 0; i++) {
244         if (!(which & (1 << i)))
245             continue;
246         which &= ~(1 << i);
247
248         if (ret[0] != '\0')
249             append_get_text("%s+%s", ret, state_names[i]);
250         else
251             append_get_text("%s", state_names[i]);
252     }
253
254     return ret;
255 }
256
257 static char *
258 get_control_mask_text(uint32_t control_mask)
259 {
260     int i;
261     static char ret[GET_TEXT_BUF_SIZE];
262     /* FIXME: Merge with ... something ... in xkbcomp. */
263     static const char *ctrl_names[] = {
264         "RepeatKeys",
265         "SlowKeys",
266         "BounceKeys",
267         "StickyKeys",
268         "MouseKeys",
269         "MouseKeysAccel",
270         "AccessXKeys",
271         "AccessXTimeout",
272         "AccessXFeedback",
273         "AudibleBell",
274         "Overlay1",
275         "Overlay2",
276         "IgnoreGroupLock"
277     };
278
279     memset(ret, 0, GET_TEXT_BUF_SIZE);
280
281     control_mask &= XkbAllBooleanCtrlsMask;
282
283     if (control_mask == 0) {
284         strcpy(ret, "none");
285         return ret;
286     }
287     else if (control_mask == XkbAllBooleanCtrlsMask) {
288         strcpy(ret, "all");
289         return ret;
290     }
291
292     for (i = 0; control_mask; i++) {
293         if (!(control_mask & (1 << i)))
294             continue;
295         control_mask &= ~(1 << i);
296
297         if (ret[0] != '\0')
298             append_get_text("%s+%s", ret, ctrl_names[i]);
299         else
300             append_get_text("%s", ctrl_names[i]);
301     }
302
303     return ret;
304 }
305
306 static bool
307 write_keycodes(struct xkb_keymap *keymap, char **buf, size_t *size,
308                size_t *offset)
309 {
310     xkb_keycode_t key;
311     struct xkb_key_alias *alias;
312     int i;
313
314     if (keymap->names->keycodes)
315         write_buf(keymap, buf, size, offset, "\txkb_keycodes \"%s\" {\n",
316                   keymap->names->keycodes);
317     else
318         write_buf(keymap, buf, size, offset, "\txkb_keycodes {\n");
319
320     write_buf(keymap, buf, size, offset, "\t\tminimum = %d;\n",
321               keymap->min_key_code);
322     write_buf(keymap, buf, size, offset, "\t\tmaximum = %d;\n",
323               keymap->max_key_code);
324
325     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
326         const char *alternate = "";
327
328         if (darray_item(keymap->names->keys, key).name[0] == '\0')
329             continue;
330         if (XkbcFindKeycodeByName(keymap,
331                                   darray_item(keymap->names->keys, key).name,
332                                   true) != key)
333             alternate = "alternate ";
334         write_buf(keymap, buf, size, offset, "\t\t%s%6s = %d;\n", alternate,
335                   XkbcKeyNameText(darray_item(keymap->names->keys, key).name),
336                                   key);
337     }
338
339     for (i = 0; i < XkbNumIndicators; i++) {
340         if (!keymap->names->indicators[i])
341             continue;
342         write_buf(keymap, buf, size, offset, "\t\tindicator %d = \"%s\";\n",
343                   i + 1, keymap->names->indicators[i]);
344     }
345
346
347     darray_foreach(alias, keymap->names->key_aliases)
348         write_buf(keymap, buf, size, offset, "\t\talias %6s = %6s;\n",
349                   XkbcKeyNameText(alias->alias),
350                   XkbcKeyNameText(alias->real));
351
352     write_buf(keymap, buf, size, offset, "\t};\n\n");
353     return true;
354 }
355
356 static bool
357 write_types(struct xkb_keymap *keymap, char **buf, size_t *size,
358             size_t *offset)
359 {
360     int n;
361     struct xkb_key_type *type;
362
363     if (keymap->names->keytypes)
364         write_buf(keymap, buf, size, offset, "\txkb_types \"%s\" {\n\n",
365                   keymap->names->keytypes);
366     else
367         write_buf(keymap, buf, size, offset, "\txkb_types {\n\n");
368
369     write_vmods(keymap, buf, size, offset);
370
371     darray_foreach(type, keymap->map->types) {
372         write_buf(keymap, buf, size, offset, "\t\ttype \"%s\" {\n",
373                   type->name);
374         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
375                   get_mod_mask_text(keymap, type->mods.real_mods,
376                                     type->mods.vmods));
377
378         for (n = 0; n < darray_size(type->map); n++) {
379             struct xkb_kt_map_entry *entry = &darray_item(type->map, n);
380             char *str;
381
382             str = get_mod_mask_text(keymap, entry->mods.real_mods,
383                                     entry->mods.vmods);
384             write_buf(keymap, buf, size, offset, "\t\t\tmap[%s]= Level%d;\n",
385                       str, entry->level + 1);
386
387             if (!type->preserve || (!type->preserve[n].real_mods &&
388                                     !type->preserve[n].vmods))
389                 continue;
390             write_buf(keymap, buf, size, offset, "\t\t\tpreserve[%s]= ", str);
391             write_buf(keymap, buf, size, offset, "%s;\n",
392                       get_mod_mask_text(keymap, type->preserve[n].real_mods,
393                                         type->preserve[n].vmods));
394         }
395
396         if (type->level_names) {
397             for (n = 0; n < type->num_levels; n++) {
398                 if (!type->level_names[n])
399                     continue;
400                 write_buf(keymap, buf, size, offset,
401                           "\t\t\tlevel_name[Level%d]= \"%s\";\n", n + 1,
402                           type->level_names[n]);
403             }
404         }
405         write_buf(keymap, buf, size, offset, "\t\t};\n");
406     }
407
408     write_buf(keymap, buf, size, offset, "\t};\n\n");
409     return true;
410 }
411
412 static bool
413 write_indicator_map(struct xkb_keymap *keymap, char **buf, size_t *size,
414                     size_t *offset, int num)
415 {
416     struct xkb_indicator_map *led = &keymap->indicators->maps[num];
417
418     write_buf(keymap, buf, size, offset, "\t\tindicator \"%s\" {\n",
419               keymap->names->indicators[num]);
420
421     if (led->which_groups) {
422         if (led->which_groups != XkbIM_UseEffective) {
423             write_buf(keymap, buf, size, offset, "\t\t\twhichGroupState= %s;\n",
424                       get_indicator_state_text(led->which_groups));
425         }
426         write_buf(keymap, buf, size, offset, "\t\t\tgroups= 0x%02x;\n",
427                   led->groups);
428     }
429
430     if (led->which_mods) {
431         if (led->which_mods != XkbIM_UseEffective) {
432             write_buf(keymap, buf, size, offset, "\t\t\twhichModState= %s;\n",
433                       get_indicator_state_text(led->which_mods));
434         }
435         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
436                   get_mod_mask_text(keymap, led->mods.real_mods,
437                   led->mods.vmods));
438     }
439
440     if (led->ctrls) {
441         write_buf(keymap, buf, size, offset, "\t\t\tcontrols= %s;\n",
442                   get_control_mask_text(led->ctrls));
443     }
444
445     write_buf(keymap, buf, size, offset, "\t\t};\n");
446     return true;
447 }
448
449 static char *
450 get_interp_match_text(uint8_t type)
451 {
452     static char ret[16];
453
454     switch (type & XkbSI_OpMask) {
455         case XkbSI_NoneOf:
456             sprintf(ret, "NoneOf");
457             break;
458         case XkbSI_AnyOfOrNone:
459             sprintf(ret, "AnyOfOrNone");
460             break;
461         case XkbSI_AnyOf:
462             sprintf(ret, "AnyOf");
463             break;
464         case XkbSI_AllOf:
465             sprintf(ret, "AllOf");
466             break;
467         case XkbSI_Exactly:
468             sprintf(ret, "Exactly");
469             break;
470         default:
471             sprintf(ret, "0x%x", type & XkbSI_OpMask);
472             break;
473     }
474
475     return ret;
476 }
477
478 static bool
479 write_action(struct xkb_keymap *keymap, char **buf, size_t *size,
480              size_t *offset, union xkb_action *action, const char *prefix,
481              const char *suffix)
482 {
483     const char *type = NULL;
484     const char *args = NULL;
485
486     if (!prefix)
487         prefix = "";
488     if (!suffix)
489         suffix = "";
490
491     switch (action->any.type) {
492     case XkbSA_SetMods:
493         if (!type)
494             type = "SetMods";
495     case XkbSA_LatchMods:
496         if (!type)
497             type = "LatchMods";
498     case XkbSA_LockMods:
499         if (!type)
500             type = "LockMods";
501         if (action->mods.flags & XkbSA_UseModMapMods)
502             args = "modMapMods";
503         else
504             args = get_mod_mask_text(keymap, action->mods.real_mods,
505                                      action->mods.vmods);
506         write_buf(keymap, buf, size, offset, "%s%s(modifiers=%s%s%s)%s",
507                   prefix, type, args,
508                   (action->any.type != XkbSA_LockGroup &&
509                    action->mods.flags & XkbSA_ClearLocks) ? ",clearLocks" : "",
510                   (action->any.type != XkbSA_LockGroup &&
511                    action->mods.flags & XkbSA_LatchToLock) ? ",latchToLock" : "",
512                   suffix);
513         break;
514     case XkbSA_SetGroup:
515         if (!type)
516             type = "SetGroup";
517     case XkbSA_LatchGroup:
518         if (!type)
519             type = "LatchGroup";
520     case XkbSA_LockGroup:
521         if (!type)
522             type = "LockGroup";
523         write_buf(keymap, buf, size, offset, "%s%s(group=%s%d%s%s)%s",
524                   prefix, type,
525                   (!(action->group.flags & XkbSA_GroupAbsolute) &&
526                    action->group.group > 0) ? "+" : "",
527                   (action->group.flags & XkbSA_GroupAbsolute) ?
528                    action->group.group + 1 : action->group.group,
529                   (action->any.type != XkbSA_LockGroup &&
530                    action->group.flags & XkbSA_ClearLocks) ? ",clearLocks" : "",
531                   (action->any.type != XkbSA_LockGroup &&
532                    action->group.flags & XkbSA_LatchToLock) ? ",latchToLock" : "",
533                   suffix);
534         break;
535     case XkbSA_Terminate:
536         write_buf(keymap, buf, size, offset, "%sTerminate()%s", prefix, suffix);
537         break;
538     case XkbSA_MovePtr:
539         write_buf(keymap, buf, size, offset, "%sMovePtr(x=%s%d,y=%s%d%s)%s",
540                   prefix,
541                   (!(action->ptr.flags & XkbSA_MoveAbsoluteX) &&
542                    action->ptr.x >= 0) ? "+" : "",
543                   action->ptr.x,
544                   (!(action->ptr.flags & XkbSA_MoveAbsoluteY) &&
545                    action->ptr.y >= 0) ? "+" : "",
546                   action->ptr.y,
547                   (action->ptr.flags & XkbSA_NoAcceleration) ? ",!accel" : "",
548                   suffix);
549         break;
550     case XkbSA_PtrBtn:
551         if (!type)
552             type = "PtrBtn";
553     case XkbSA_LockPtrBtn:
554         if (!type) {
555             type = "LockPtrBtn";
556             switch (action->btn.flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
557             case XkbSA_LockNoUnlock:
558                 args = ",affect=lock";
559                 break;
560             case XkbSA_LockNoLock:
561                 args = ",affect=unlock";
562                 break;
563             case XkbSA_LockNoLock | XkbSA_LockNoUnlock:
564                 args = ",affect=neither";
565                 break;
566             default:
567                 args = ",affect=both";
568                 break;
569             }
570         }
571         else {
572             args = NULL;
573         }
574         write_buf(keymap, buf, size, offset, "%s%s(button=", prefix, type);
575         if (action->btn.button > 0 && action->btn.button <= 5)
576             write_buf(keymap, buf, size, offset, "%d", action->btn.button);
577         else
578             write_buf(keymap, buf, size, offset, "default");
579         if (action->btn.count)
580             write_buf(keymap, buf, size, offset, ",count=%d",
581                       action->btn.count);
582         if (args)
583             write_buf(keymap, buf, size, offset, "%s", args);
584         write_buf(keymap, buf, size, offset, ")%s", suffix);
585         break;
586     case XkbSA_SetPtrDflt:
587         write_buf(keymap, buf, size, offset, "%sSetPtrDflt(", prefix);
588         if (action->dflt.affect == XkbSA_AffectDfltBtn)
589             write_buf(keymap, buf, size, offset, "affect=button,button=%s%d",
590                       (!(action->dflt.flags & XkbSA_DfltBtnAbsolute) &&
591                        action->dflt.value >= 0) ? "+" : "",
592                       action->dflt.value);
593         write_buf(keymap, buf, size, offset, ")%s", suffix);
594         break;
595     case XkbSA_SwitchScreen:
596         write_buf(keymap, buf, size, offset,
597                   "%sSwitchScreen(screen=%s%d,%ssame)%s", prefix,
598                   (!(action->screen.flags & XkbSA_SwitchAbsolute) &&
599                    action->screen.screen >= 0) ? "+" : "",
600                   action->screen.screen,
601                   (action->screen.flags & XkbSA_SwitchApplication) ? "!" : "",
602                   suffix);
603         break;
604     /* Deprecated actions below here */
605     case XkbSA_SetControls:
606         if (!type)
607             type = "SetControls";
608     case XkbSA_LockControls:
609         if (!type)
610             type = "LockControls";
611         write_buf(keymap, buf, size, offset, "%s%s(controls=%s)%s",
612                   prefix, type, get_control_mask_text(action->ctrls.ctrls),
613                   suffix);
614         break;
615     case XkbSA_ISOLock:
616     case XkbSA_ActionMessage:
617     case XkbSA_RedirectKey:
618     case XkbSA_DeviceBtn:
619     case XkbSA_LockDeviceBtn:
620     case XkbSA_NoAction:
621         /* XXX TODO */
622         write_buf(keymap, buf, size, offset, "%sNoAction()%s", prefix, suffix);
623         break;
624     case XkbSA_XFree86Private:
625     default:
626         write_buf(keymap, buf, size, offset,
627                   "%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",
628                   prefix, action->any.type, action->any.data[0],
629                   action->any.data[1], action->any.data[2],
630                   action->any.data[3], action->any.data[4],
631                   action->any.data[5], action->any.data[6], suffix);
632         break;
633     }
634
635     return true;
636 }
637
638 static bool
639 write_compat(struct xkb_keymap *keymap, char **buf, size_t *size,
640              size_t *offset)
641 {
642     int i;
643     struct xkb_sym_interpret *interp;
644
645     if (keymap->names->compat)
646         write_buf(keymap, buf, size, offset, "\txkb_compatibility \"%s\" {\n\n",
647                   keymap->names->compat);
648     else
649         write_buf(keymap, buf, size, offset, "\txkb_compatibility {\n\n");
650
651     write_vmods(keymap, buf, size, offset);
652
653     write_buf(keymap, buf, size, offset, "\t\tinterpret.useModMapMods= AnyLevel;\n");
654     write_buf(keymap, buf, size, offset, "\t\tinterpret.repeat= False;\n");
655     write_buf(keymap, buf, size, offset, "\t\tinterpret.locking= False;\n");
656
657     darray_foreach(interp, keymap->compat->sym_interpret) {
658         char keysym_name[64];
659
660         if (interp->sym == XKB_KEY_NoSymbol)
661             sprintf(keysym_name, "Any");
662         else
663             xkb_keysym_get_name(interp->sym, keysym_name, sizeof(keysym_name));
664
665         write_buf(keymap, buf, size, offset, "\t\tinterpret %s+%s(%s) {\n",
666                   keysym_name,
667                   get_interp_match_text(interp->match),
668                   get_mod_mask_text(keymap, interp->mods, 0));
669
670         if (interp->virtual_mod != XkbNoModifier) {
671             write_buf(keymap, buf, size, offset, "\t\t\tvirtualModifier= %s;\n",
672                       keymap->names->vmods[interp->virtual_mod]);
673         }
674
675         if (interp->match & XkbSI_LevelOneOnly)
676             write_buf(keymap, buf, size, offset, "\t\t\tuseModMapMods=level1;\n");
677         if (interp->flags & XkbSI_LockingKey)
678             write_buf(keymap, buf, size, offset, "\t\t\tlocking= True;\n");
679         if (interp->flags & XkbSI_AutoRepeat)
680             write_buf(keymap, buf, size, offset, "\t\t\trepeat= True;\n");
681
682         write_action(keymap, buf, size, offset, &interp->act,
683                      "\t\t\taction= ", ";\n");
684         write_buf(keymap, buf, size, offset, "\t\t};\n");
685     }
686
687     for (i = 0; i < XkbNumKbdGroups; i++) {
688         struct xkb_mods *gc;
689
690         gc = &keymap->compat->groups[i];
691         if (gc->real_mods == 0 && gc->vmods ==0)
692             continue;
693         write_buf(keymap, buf, size, offset,
694                   "\t\tgroup %d = %s;\n", i + 1,
695                   get_mod_mask_text(keymap, gc->real_mods, gc->vmods));
696     }
697
698     for (i = 0; i < XkbNumIndicators; i++) {
699         struct xkb_indicator_map *map = &keymap->indicators->maps[i];
700         if (map->flags == 0 && map->which_groups == 0 &&
701             map->groups == 0 && map->which_mods == 0 &&
702             map->mods.real_mods == 0 && map->mods.vmods == 0 &&
703             map->ctrls == 0)
704             continue;
705         write_indicator_map(keymap, buf, size, offset, i);
706     }
707
708     write_buf(keymap, buf, size, offset, "\t};\n\n");
709
710     return true;
711 }
712
713 static bool
714 write_keysyms(struct xkb_keymap *keymap, char **buf, size_t *size,
715               size_t *offset, xkb_keycode_t key, unsigned int group)
716 {
717     const xkb_keysym_t *syms;
718     int num_syms, level;
719 #define OUT_BUF_LEN 128
720     char out_buf[OUT_BUF_LEN];
721
722     for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
723         if (level != 0)
724             write_buf(keymap, buf, size, offset, ", ");
725         num_syms = xkb_key_get_syms_by_level(keymap, key, group, level,
726                                              &syms);
727         if (num_syms == 0) {
728             write_buf(keymap, buf, size, offset, "%15s", "NoSymbol");
729         }
730         else if (num_syms == 1) {
731             xkb_keysym_get_name(syms[0], out_buf, OUT_BUF_LEN);
732             write_buf(keymap, buf, size, offset, "%15s", out_buf);
733         }
734         else {
735             int s;
736             write_buf(keymap, buf, size, offset, "{ ");
737             for (s = 0; s < num_syms; s++) {
738                 if (s != 0)
739                     write_buf(keymap, buf, size, offset, ", ");
740                 xkb_keysym_get_name(syms[s], out_buf, OUT_BUF_LEN);
741                 write_buf(keymap, buf, size, offset, "%15s", out_buf);
742             }
743             write_buf(keymap, buf, size, offset, " }");
744         }
745     }
746 #undef OUT_BUF_LEN
747
748     return true;
749 }
750
751 static bool
752 write_symbols(struct xkb_keymap *keymap, char **buf, size_t *size,
753               size_t *offset)
754 {
755     struct xkb_client_map *map = keymap->map;
756     struct xkb_server_map *srv = keymap->server;
757     xkb_keycode_t key;
758     int group, tmp;
759     bool showActions;
760
761     if (keymap->names->symbols)
762         write_buf(keymap, buf, size, offset, "\txkb_symbols \"%s\" {\n\n",
763                   keymap->names->symbols);
764     else
765         write_buf(keymap, buf, size, offset, "\txkb_symbols {\n\n");
766
767     for (tmp = group = 0; group < XkbNumKbdGroups; group++) {
768         if (!keymap->names->groups[group])
769             continue;
770         write_buf(keymap, buf, size, offset,
771                   "\t\tname[group%d]=\"%s\";\n", group + 1,
772                   keymap->names->groups[group]);
773         tmp++;
774     }
775     if (tmp > 0)
776         write_buf(keymap, buf, size, offset, "\n");
777
778     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
779         bool simple = true;
780
781         if (xkb_key_num_groups(keymap, key) == 0)
782             continue;
783         if (XkbcFindKeycodeByName(keymap,
784                                   darray_item(keymap->names->keys, key).name,
785                                   true) != key)
786             continue;
787
788         write_buf(keymap, buf, size, offset, "\t\tkey %6s {",
789                   XkbcKeyNameText(darray_item(keymap->names->keys, key).name));
790         if (srv->explicit) {
791             if ((srv->explicit[key] & XkbExplicitKeyTypesMask)) {
792                 bool multi_type = false;
793                 int type = XkbKeyTypeIndex(keymap, key, 0);
794
795                 simple = false;
796
797                 for (group = 0; group < xkb_key_num_groups(keymap, key); group++) {
798                     if (XkbKeyTypeIndex(keymap, key, group) != type) {
799                         multi_type = true;
800                         break;
801                     }
802                 }
803                 if (multi_type) {
804                     for (group = 0;
805                          group < xkb_key_num_groups(keymap, key);
806                          group++) {
807                         if (!(srv->explicit[key] & (1 << group)))
808                             continue;
809                         type = XkbKeyTypeIndex(keymap, key, group);
810                         write_buf(keymap, buf, size, offset,
811                                   "\n\t\t\ttype[group%d]= \"%s\",",
812                                   group + 1,
813                                   darray_item(map->types, type).name);
814                     }
815                 }
816                 else {
817                     write_buf(keymap, buf, size, offset,
818                               "\n\t\t\ttype= \"%s\",",
819                               darray_item(map->types, type).name);
820                 }
821             }
822             if (keymap->ctrls && (srv->explicit[key] & XkbExplicitAutoRepeatMask)) {
823                 if (keymap->ctrls->per_key_repeat[key / 8] & (1 << (key % 8)))
824                      write_buf(keymap, buf, size, offset,
825                                "\n\t\t\trepeat= Yes,");
826                 else
827                     write_buf(keymap, buf, size, offset,
828                               "\n\t\t\trepeat= No,");
829                 simple = false;
830             }
831             if (keymap->server->vmodmap[key] &&
832                 (srv->explicit[key] & XkbExplicitVModMapMask)) {
833                 write_buf(keymap, buf, size, offset, "\n\t\t\tvirtualMods= %s,",
834                           get_mod_mask_text(keymap, 0, keymap->server->vmodmap[key]));
835             }
836         }
837
838         switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(keymap, key))) {
839             case XkbClampIntoRange:
840                 write_buf(keymap, buf, size, offset, "\n\t\t\tgroupsClamp,");
841                 break;
842             case XkbRedirectIntoRange:
843                 write_buf(keymap, buf, size, offset,
844                           "\n\t\t\tgroupsRedirect= Group%d,",
845                           XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(keymap, key)) + 1);
846                 break;
847         }
848
849         if (srv->explicit == NULL ||
850             (srv->explicit[key] & XkbExplicitInterpretMask))
851             showActions = XkbKeyHasActions(keymap, key);
852         else
853             showActions = false;
854
855         if (xkb_key_num_groups(keymap, key) > 1 || showActions)
856             simple = false;
857
858         if (simple) {
859             write_buf(keymap, buf, size, offset, "\t[ ");
860             if (!write_keysyms(keymap, buf, size, offset, key, 0))
861                 return false;
862             write_buf(keymap, buf, size, offset, " ] };\n");
863         }
864         else {
865             union xkb_action *acts;
866             int level;
867
868             acts = XkbKeyActionsPtr(keymap, key);
869             for (group = 0; group < xkb_key_num_groups(keymap, key); group++) {
870                 if (group != 0)
871                     write_buf(keymap, buf, size, offset, ",");
872                 write_buf(keymap, buf, size, offset,
873                           "\n\t\t\tsymbols[Group%d]= [ ", group + 1);
874                 if (!write_keysyms(keymap, buf, size, offset, key, group))
875                     return false;
876                 write_buf(keymap, buf, size, offset, " ]");
877                 if (showActions) {
878                     write_buf(keymap, buf, size, offset,
879                               ",\n\t\t\tactions[Group%d]= [ ", group + 1);
880                     for (level = 0;
881                          level < XkbKeyGroupWidth(keymap, key, group);
882                          level++) {
883                         if (level != 0)
884                             write_buf(keymap, buf, size, offset, ", ");
885                         write_action(keymap, buf, size, offset, &acts[level],
886                                      NULL, NULL);
887                     }
888                     write_buf(keymap, buf, size, offset, " ]");
889                     acts += XkbKeyGroupsWidth(keymap, key);
890                 }
891             }
892             write_buf(keymap, buf, size, offset, "\n\t\t};\n");
893         }
894     }
895     if (map && map->modmap) {
896         for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
897             int mod;
898
899             if (map->modmap[key] == 0)
900                 continue;
901
902             for (mod = 0; mod < XkbNumModifiers; mod++) {
903                 if (!(map->modmap[key] & (1 << mod)))
904                     continue;
905
906                 write_buf(keymap, buf, size, offset,
907                           "\t\tmodifier_map %s { %s };\n",
908                           get_mod_index_text(mod),
909                           XkbcKeyNameText(darray_item(keymap->names->keys,
910                                                       key).name));
911             }
912         }
913     }
914
915     write_buf(keymap, buf, size, offset, "\t};\n\n");
916     return true;
917 }
918
919 _X_EXPORT char *
920 xkb_map_get_as_string(struct xkb_keymap *keymap)
921 {
922     char *ret = NULL;
923     size_t size = 0;
924     size_t offset = 0;
925
926     check_write_buf(keymap, &ret, &size, &offset, "xkb_keymap {\n");
927     if (ret == NULL)
928         return NULL;
929     if (!write_keycodes(keymap, &ret, &size, &offset))
930         return NULL;
931     if (!write_types(keymap, &ret, &size, &offset))
932         return NULL;
933     if (!write_compat(keymap, &ret, &size, &offset))
934         return NULL;
935     if (!write_symbols(keymap, &ret, &size, &offset))
936         return NULL;
937     check_write_buf(keymap, &ret, &size, &offset, "};\n");
938     if (ret == NULL)
939         return NULL;
940
941     return ret;
942 }