Run source tree through uncrustify
[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->names->vmods[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->names->vmods[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->names->vmods[i]);
213         }
214         else {
215             append_get_text("%s", keymap->names->vmods[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 key;
313     struct xkb_key_alias *alias;
314     int i;
315
316     if (keymap->names->keycodes)
317         write_buf(keymap, buf, size, offset, "\txkb_keycodes \"%s\" {\n",
318                   keymap->names->keycodes);
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 (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
328         if (darray_item(keymap->names->keys, key).name[0] == '\0')
329             continue;
330
331         write_buf(keymap, buf, size, offset, "\t\t%6s = %d;\n",
332                   XkbcKeyNameText(darray_item(keymap->names->keys, key).name),
333                   key);
334     }
335
336     for (i = 0; i < XkbNumIndicators; i++) {
337         if (!keymap->names->indicators[i])
338             continue;
339         write_buf(keymap, buf, size, offset, "\t\tindicator %d = \"%s\";\n",
340                   i + 1, keymap->names->indicators[i]);
341     }
342
343     darray_foreach(alias, keymap->names->key_aliases)
344     write_buf(keymap, buf, size, offset, "\t\talias %6s = %6s;\n",
345               XkbcKeyNameText(alias->alias),
346               XkbcKeyNameText(alias->real));
347
348     write_buf(keymap, buf, size, offset, "\t};\n\n");
349     return true;
350 }
351
352 static bool
353 write_types(struct xkb_keymap *keymap, char **buf, size_t *size,
354             size_t *offset)
355 {
356     int n;
357     struct xkb_key_type *type;
358
359     if (keymap->names->keytypes)
360         write_buf(keymap, buf, size, offset, "\txkb_types \"%s\" {\n\n",
361                   keymap->names->keytypes);
362     else
363         write_buf(keymap, buf, size, offset, "\txkb_types {\n\n");
364
365     write_vmods(keymap, buf, size, offset);
366
367     darray_foreach(type, keymap->map->types) {
368         write_buf(keymap, buf, size, offset, "\t\ttype \"%s\" {\n",
369                   type->name);
370         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
371                   get_mod_mask_text(keymap, type->mods.real_mods,
372                                     type->mods.vmods));
373
374         for (n = 0; n < darray_size(type->map); n++) {
375             struct xkb_kt_map_entry *entry = &darray_item(type->map, n);
376             char *str;
377
378             str = get_mod_mask_text(keymap, entry->mods.real_mods,
379                                     entry->mods.vmods);
380             write_buf(keymap, buf, size, offset, "\t\t\tmap[%s]= Level%d;\n",
381                       str, entry->level + 1);
382
383             if (!type->preserve || (!type->preserve[n].real_mods &&
384                                     !type->preserve[n].vmods))
385                 continue;
386             write_buf(keymap, buf, size, offset, "\t\t\tpreserve[%s]= ", str);
387             write_buf(keymap, buf, size, offset, "%s;\n",
388                       get_mod_mask_text(keymap, type->preserve[n].real_mods,
389                                         type->preserve[n].vmods));
390         }
391
392         if (type->level_names) {
393             for (n = 0; n < type->num_levels; n++) {
394                 if (!type->level_names[n])
395                     continue;
396                 write_buf(keymap, buf, size, offset,
397                           "\t\t\tlevel_name[Level%d]= \"%s\";\n", n + 1,
398                           type->level_names[n]);
399             }
400         }
401         write_buf(keymap, buf, size, offset, "\t\t};\n");
402     }
403
404     write_buf(keymap, buf, size, offset, "\t};\n\n");
405     return true;
406 }
407
408 static bool
409 write_indicator_map(struct xkb_keymap *keymap, char **buf, size_t *size,
410                     size_t *offset, int num)
411 {
412     struct xkb_indicator_map *led = &keymap->indicators->maps[num];
413
414     write_buf(keymap, buf, size, offset, "\t\tindicator \"%s\" {\n",
415               keymap->names->indicators[num]);
416
417     if (led->which_groups) {
418         if (led->which_groups != XkbIM_UseEffective) {
419             write_buf(keymap, buf, size, offset,
420                       "\t\t\twhichGroupState= %s;\n",
421                       get_indicator_state_text(
422                           led->which_groups));
423         }
424         write_buf(keymap, buf, size, offset, "\t\t\tgroups= 0x%02x;\n",
425                   led->groups);
426     }
427
428     if (led->which_mods) {
429         if (led->which_mods != XkbIM_UseEffective) {
430             write_buf(keymap, buf, size, offset, "\t\t\twhichModState= %s;\n",
431                       get_indicator_state_text(led->which_mods));
432         }
433         write_buf(keymap, buf, size, offset, "\t\t\tmodifiers= %s;\n",
434                   get_mod_mask_text(keymap, led->mods.real_mods,
435                                     led->mods.vmods));
436     }
437
438     if (led->ctrls) {
439         write_buf(keymap, buf, size, offset, "\t\t\tcontrols= %s;\n",
440                   get_control_mask_text(led->ctrls));
441     }
442
443     write_buf(keymap, buf, size, offset, "\t\t};\n");
444     return true;
445 }
446
447 static char *
448 get_interp_match_text(uint8_t type)
449 {
450     static char ret[16];
451
452     switch (type & XkbSI_OpMask) {
453     case XkbSI_NoneOf:
454         sprintf(ret, "NoneOf");
455         break;
456
457     case XkbSI_AnyOfOrNone:
458         sprintf(ret, "AnyOfOrNone");
459         break;
460
461     case XkbSI_AnyOf:
462         sprintf(ret, "AnyOf");
463         break;
464
465     case XkbSI_AllOf:
466         sprintf(ret, "AllOf");
467         break;
468
469     case XkbSI_Exactly:
470         sprintf(ret, "Exactly");
471         break;
472
473     default:
474         sprintf(ret, "0x%x", type & XkbSI_OpMask);
475         break;
476     }
477
478     return ret;
479 }
480
481 static bool
482 write_action(struct xkb_keymap *keymap, char **buf, size_t *size,
483              size_t *offset, union xkb_action *action, const char *prefix,
484              const char *suffix)
485 {
486     const char *type = NULL;
487     const char *args = NULL;
488
489     if (!prefix)
490         prefix = "";
491     if (!suffix)
492         suffix = "";
493
494     switch (action->any.type) {
495     case XkbSA_SetMods:
496         if (!type)
497             type = "SetMods";
498     case XkbSA_LatchMods:
499         if (!type)
500             type = "LatchMods";
501     case XkbSA_LockMods:
502         if (!type)
503             type = "LockMods";
504         if (action->mods.flags & XkbSA_UseModMapMods)
505             args = "modMapMods";
506         else
507             args = get_mod_mask_text(keymap, action->mods.real_mods,
508                                      action->mods.vmods);
509         write_buf(keymap, buf, size, offset, "%s%s(modifiers=%s%s%s)%s",
510                   prefix, type, args,
511                   (action->any.type != XkbSA_LockGroup &&
512                    (action->mods.flags & XkbSA_ClearLocks)) ?
513                    ",clearLocks" : "",
514                   (action->any.type != XkbSA_LockGroup &&
515                    (action->mods.flags & XkbSA_LatchToLock)) ?
516                    ",latchToLock" : "",
517                   suffix);
518         break;
519
520     case XkbSA_SetGroup:
521         if (!type)
522             type = "SetGroup";
523     case XkbSA_LatchGroup:
524         if (!type)
525             type = "LatchGroup";
526     case XkbSA_LockGroup:
527         if (!type)
528             type = "LockGroup";
529         write_buf(
530             keymap, buf, size, offset, "%s%s(group=%s%d%s%s)%s",
531             prefix, type,
532             (!(action->group.flags & XkbSA_GroupAbsolute) &&
533              action->group.group > 0) ? "+" : "",
534             (action->group.flags & XkbSA_GroupAbsolute) ?
535              action->group.group + 1 : action->group.group,
536             (action->any.type != XkbSA_LockGroup &&
537              (action->group.flags & XkbSA_ClearLocks)) ?
538              ",clearLocks" : "",
539             (action->any.type != XkbSA_LockGroup &&
540              (action->group.flags & XkbSA_LatchToLock)) ?
541              ",latchToLock" : "",
542             suffix);
543         break;
544
545     case XkbSA_Terminate:
546         write_buf(keymap, buf, size, offset, "%sTerminate()%s", prefix,
547                   suffix);
548         break;
549
550     case XkbSA_MovePtr:
551         write_buf(keymap, buf, size, offset, "%sMovePtr(x=%s%d,y=%s%d%s)%s",
552                   prefix,
553                   (!(action->ptr.flags & XkbSA_MoveAbsoluteX) &&
554                    action->ptr.x >= 0) ? "+" : "",
555                   action->ptr.x,
556                   (!(action->ptr.flags & XkbSA_MoveAbsoluteY) &&
557                    action->ptr.y >= 0) ? "+" : "",
558                   action->ptr.y,
559                   (action->ptr.flags & XkbSA_NoAcceleration) ? ",!accel" : "",
560                   suffix);
561         break;
562
563     case XkbSA_PtrBtn:
564         if (!type)
565             type = "PtrBtn";
566     case XkbSA_LockPtrBtn:
567         if (!type) {
568             type = "LockPtrBtn";
569             switch (action->btn.flags &
570                     (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
571             case XkbSA_LockNoUnlock:
572                 args = ",affect=lock";
573                 break;
574
575             case XkbSA_LockNoLock:
576                 args = ",affect=unlock";
577                 break;
578
579             case XkbSA_LockNoLock | XkbSA_LockNoUnlock:
580                 args = ",affect=neither";
581                 break;
582
583             default:
584                 args = ",affect=both";
585                 break;
586             }
587         }
588         else {
589             args = NULL;
590         }
591         write_buf(keymap, buf, size, offset, "%s%s(button=", prefix, type);
592         if (action->btn.button > 0 && action->btn.button <= 5)
593             write_buf(keymap, buf, size, offset, "%d", action->btn.button);
594         else
595             write_buf(keymap, buf, size, offset, "default");
596         if (action->btn.count)
597             write_buf(keymap, buf, size, offset, ",count=%d",
598                       action->btn.count);
599         if (args)
600             write_buf(keymap, buf, size, offset, "%s", args);
601         write_buf(keymap, buf, size, offset, ")%s", suffix);
602         break;
603
604     case XkbSA_SetPtrDflt:
605         write_buf(keymap, buf, size, offset, "%sSetPtrDflt(", prefix);
606         if (action->dflt.affect == XkbSA_AffectDfltBtn)
607             write_buf(keymap, buf, size, offset, "affect=button,button=%s%d",
608                       (!(action->dflt.flags & XkbSA_DfltBtnAbsolute) &&
609                        action->dflt.value >= 0) ? "+" : "",
610                       action->dflt.value);
611         write_buf(keymap, buf, size, offset, ")%s", suffix);
612         break;
613
614     case XkbSA_SwitchScreen:
615         write_buf(keymap, buf, size, offset,
616                   "%sSwitchScreen(screen=%s%d,%ssame)%s", prefix,
617                   (!(action->screen.flags & XkbSA_SwitchAbsolute) &&
618                    action->screen.screen >= 0) ? "+" : "",
619                   action->screen.screen,
620                   (action->screen.flags & XkbSA_SwitchApplication) ? "!" : "",
621                   suffix);
622         break;
623
624     /* Deprecated actions below here */
625     case XkbSA_SetControls:
626         if (!type)
627             type = "SetControls";
628     case XkbSA_LockControls:
629         if (!type)
630             type = "LockControls";
631         write_buf(keymap, buf, size, offset, "%s%s(controls=%s)%s",
632                   prefix, type, get_control_mask_text(action->ctrls.ctrls),
633                   suffix);
634         break;
635
636     case XkbSA_ISOLock:
637     case XkbSA_ActionMessage:
638     case XkbSA_RedirectKey:
639     case XkbSA_DeviceBtn:
640     case XkbSA_LockDeviceBtn:
641     case XkbSA_NoAction:
642         /* XXX TODO */
643         write_buf(keymap, buf, size, offset, "%sNoAction()%s", prefix, suffix);
644         break;
645
646     case XkbSA_XFree86Private:
647     default:
648         write_buf(keymap, buf, size, offset,
649                   "%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",
650                   prefix, action->any.type, action->any.data[0],
651                   action->any.data[1], action->any.data[2],
652                   action->any.data[3], action->any.data[4],
653                   action->any.data[5], action->any.data[6],
654                   suffix);
655         break;
656     }
657
658     return true;
659 }
660
661 static bool
662 write_compat(struct xkb_keymap *keymap, char **buf, size_t *size,
663              size_t *offset)
664 {
665     int i;
666     struct xkb_sym_interpret *interp;
667
668     if (keymap->names->compat)
669         write_buf(keymap, buf, size, offset,
670                   "\txkb_compatibility \"%s\" {\n\n",
671                   keymap->names->compat);
672     else
673         write_buf(keymap, buf, size, offset, "\txkb_compatibility {\n\n");
674
675     write_vmods(keymap, buf, size, offset);
676
677     write_buf(keymap, buf, size, offset,
678               "\t\tinterpret.useModMapMods= AnyLevel;\n");
679     write_buf(keymap, buf, size, offset, "\t\tinterpret.repeat= False;\n");
680     write_buf(keymap, buf, size, offset, "\t\tinterpret.locking= False;\n");
681
682     darray_foreach(interp, keymap->compat->sym_interpret) {
683         char keysym_name[64];
684
685         if (interp->sym == XKB_KEY_NoSymbol)
686             sprintf(keysym_name, "Any");
687         else
688             xkb_keysym_get_name(interp->sym, keysym_name, sizeof(keysym_name));
689
690         write_buf(keymap, buf, size, offset, "\t\tinterpret %s+%s(%s) {\n",
691                   keysym_name,
692                   get_interp_match_text(interp->match),
693                   get_mod_mask_text(keymap, interp->mods, 0));
694
695         if (interp->virtual_mod != XkbNoModifier) {
696             write_buf(keymap, buf, size, offset,
697                       "\t\t\tvirtualModifier= %s;\n",
698                       keymap->names->vmods[interp->virtual_mod]);
699         }
700
701         if (interp->match & XkbSI_LevelOneOnly)
702             write_buf(keymap, buf, size, offset,
703                       "\t\t\tuseModMapMods=level1;\n");
704         if (interp->flags & XkbSI_LockingKey)
705             write_buf(keymap, buf, size, offset, "\t\t\tlocking= True;\n");
706         if (interp->flags & XkbSI_AutoRepeat)
707             write_buf(keymap, buf, size, offset, "\t\t\trepeat= True;\n");
708
709         write_action(keymap, buf, size, offset, &interp->act,
710                      "\t\t\taction= ", ";\n");
711         write_buf(keymap, buf, size, offset, "\t\t};\n");
712     }
713
714     for (i = 0; i < XkbNumKbdGroups; i++) {
715         struct xkb_mods *gc;
716
717         gc = &keymap->compat->groups[i];
718         if (gc->real_mods == 0 && gc->vmods == 0)
719             continue;
720         write_buf(keymap, buf, size, offset,
721                   "\t\tgroup %d = %s;\n", i + 1,
722                   get_mod_mask_text(keymap, gc->real_mods, gc->vmods));
723     }
724
725     for (i = 0; i < XkbNumIndicators; i++) {
726         struct xkb_indicator_map *map = &keymap->indicators->maps[i];
727         if (map->flags == 0 && map->which_groups == 0 &&
728             map->groups == 0 && map->which_mods == 0 &&
729             map->mods.real_mods == 0 && map->mods.vmods == 0 &&
730             map->ctrls == 0)
731             continue;
732         write_indicator_map(keymap, buf, size, offset, i);
733     }
734
735     write_buf(keymap, buf, size, offset, "\t};\n\n");
736
737     return true;
738 }
739
740 static bool
741 write_keysyms(struct xkb_keymap *keymap, char **buf, size_t *size,
742               size_t *offset, xkb_keycode_t key, unsigned int group)
743 {
744     const xkb_keysym_t *syms;
745     int num_syms, level;
746 #define OUT_BUF_LEN 128
747     char out_buf[OUT_BUF_LEN];
748
749     for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); level++) {
750         if (level != 0)
751             write_buf(keymap, buf, size, offset, ", ");
752         num_syms = xkb_key_get_syms_by_level(keymap, key, group, level,
753                                              &syms);
754         if (num_syms == 0) {
755             write_buf(keymap, buf, size, offset, "%15s", "NoSymbol");
756         }
757         else if (num_syms == 1) {
758             xkb_keysym_get_name(syms[0], out_buf, OUT_BUF_LEN);
759             write_buf(keymap, buf, size, offset, "%15s", out_buf);
760         }
761         else {
762             int s;
763             write_buf(keymap, buf, size, offset, "{ ");
764             for (s = 0; s < num_syms; s++) {
765                 if (s != 0)
766                     write_buf(keymap, buf, size, offset, ", ");
767                 xkb_keysym_get_name(syms[s], out_buf, OUT_BUF_LEN);
768                 write_buf(keymap, buf, size, offset, "%15s", out_buf);
769             }
770             write_buf(keymap, buf, size, offset, " }");
771         }
772     }
773 #undef OUT_BUF_LEN
774
775     return true;
776 }
777
778 static bool
779 write_symbols(struct xkb_keymap *keymap, char **buf, size_t *size,
780               size_t *offset)
781 {
782     struct xkb_client_map *map = keymap->map;
783     struct xkb_server_map *srv = keymap->server;
784     xkb_keycode_t key;
785     int group, tmp;
786     bool showActions;
787
788     if (keymap->names->symbols)
789         write_buf(keymap, buf, size, offset, "\txkb_symbols \"%s\" {\n\n",
790                   keymap->names->symbols);
791     else
792         write_buf(keymap, buf, size, offset, "\txkb_symbols {\n\n");
793
794     for (tmp = group = 0; group < XkbNumKbdGroups; group++) {
795         if (!keymap->names->groups[group])
796             continue;
797         write_buf(keymap, buf, size, offset,
798                   "\t\tname[group%d]=\"%s\";\n", group + 1,
799                   keymap->names->groups[group]);
800         tmp++;
801     }
802     if (tmp > 0)
803         write_buf(keymap, buf, size, offset, "\n");
804
805     for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
806         bool simple = true;
807
808         if (xkb_key_num_groups(keymap, key) == 0)
809             continue;
810
811         write_buf(keymap, buf, size, offset, "\t\tkey %6s {",
812                   XkbcKeyNameText(darray_item(keymap->names->keys, key).name));
813         if (srv->explicit) {
814             if ((srv->explicit[key] & XkbExplicitKeyTypesMask)) {
815                 bool multi_type = false;
816                 int type = XkbKeyTypeIndex(keymap, key, 0);
817
818                 simple = false;
819
820                 for (group = 0; group < xkb_key_num_groups(keymap, key);
821                      group++) {
822                     if (XkbKeyTypeIndex(keymap, key, group) != type) {
823                         multi_type = true;
824                         break;
825                     }
826                 }
827                 if (multi_type) {
828                     for (group = 0;
829                          group < xkb_key_num_groups(keymap, key);
830                          group++) {
831                         if (!(srv->explicit[key] & (1 << group)))
832                             continue;
833                         type = XkbKeyTypeIndex(keymap, key, group);
834                         write_buf(keymap, buf, size, offset,
835                                   "\n\t\t\ttype[group%d]= \"%s\",",
836                                   group + 1,
837                                   darray_item(map->types, type).name);
838                     }
839                 }
840                 else {
841                     write_buf(keymap, buf, size, offset,
842                               "\n\t\t\ttype= \"%s\",",
843                               darray_item(map->types, type).name);
844                 }
845             }
846             if (keymap->ctrls &&
847                 (srv->explicit[key] & XkbExplicitAutoRepeatMask)) {
848                 if (keymap->ctrls->per_key_repeat[key / 8] & (1 << (key % 8)))
849                     write_buf(keymap, buf, size, offset,
850                               "\n\t\t\trepeat= Yes,");
851                 else
852                     write_buf(keymap, buf, size, offset,
853                               "\n\t\t\trepeat= No,");
854                 simple = false;
855             }
856             if (keymap->server->vmodmap[key] &&
857                 (srv->explicit[key] & XkbExplicitVModMapMask)) {
858                 write_buf(keymap, buf, size, offset,
859                           "\n\t\t\tvirtualMods= %s,",
860                           get_mod_mask_text(keymap, 0,
861                                             keymap->server->vmodmap[key]));
862             }
863         }
864
865         switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(keymap, key))) {
866         case XkbClampIntoRange:
867             write_buf(keymap, buf, size, offset, "\n\t\t\tgroupsClamp,");
868             break;
869
870         case XkbRedirectIntoRange:
871             write_buf(keymap, buf, size, offset,
872                       "\n\t\t\tgroupsRedirect= Group%d,",
873                       XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(keymap,
874                                                                key)) + 1);
875             break;
876         }
877
878         if (srv->explicit == NULL ||
879             (srv->explicit[key] & XkbExplicitInterpretMask))
880             showActions = XkbKeyHasActions(keymap, key);
881         else
882             showActions = false;
883
884         if (xkb_key_num_groups(keymap, key) > 1 || showActions)
885             simple = false;
886
887         if (simple) {
888             write_buf(keymap, buf, size, offset, "\t[ ");
889             if (!write_keysyms(keymap, buf, size, offset, key, 0))
890                 return false;
891             write_buf(keymap, buf, size, offset, " ] };\n");
892         }
893         else {
894             union xkb_action *acts;
895             int level;
896
897             acts = XkbKeyActionsPtr(keymap, key);
898             for (group = 0; group < xkb_key_num_groups(keymap, key);
899                  group++) {
900                 if (group != 0)
901                     write_buf(keymap, buf, size, offset, ",");
902                 write_buf(keymap, buf, size, offset,
903                           "\n\t\t\tsymbols[Group%d]= [ ", group + 1);
904                 if (!write_keysyms(keymap, buf, size, offset, key, group))
905                     return false;
906                 write_buf(keymap, buf, size, offset, " ]");
907                 if (showActions) {
908                     write_buf(keymap, buf, size, offset,
909                               ",\n\t\t\tactions[Group%d]= [ ", group + 1);
910                     for (level = 0;
911                          level < XkbKeyGroupWidth(keymap, key, group);
912                          level++) {
913                         if (level != 0)
914                             write_buf(keymap, buf, size, offset, ", ");
915                         write_action(keymap, buf, size, offset, &acts[level],
916                                      NULL, NULL);
917                     }
918                     write_buf(keymap, buf, size, offset, " ]");
919                     acts += XkbKeyGroupsWidth(keymap, key);
920                 }
921             }
922             write_buf(keymap, buf, size, offset, "\n\t\t};\n");
923         }
924     }
925     if (map && map->modmap) {
926         for (key = keymap->min_key_code; key <= keymap->max_key_code;
927              key++) {
928             int mod;
929
930             if (map->modmap[key] == 0)
931                 continue;
932
933             for (mod = 0; mod < XkbNumModifiers; mod++) {
934                 if (!(map->modmap[key] & (1 << mod)))
935                     continue;
936
937                 write_buf(keymap, buf, size, offset,
938                           "\t\tmodifier_map %s { %s };\n",
939                           get_mod_index_text(mod),
940                           XkbcKeyNameText(darray_item(keymap->names->keys,
941                                                       key).name));
942             }
943         }
944     }
945
946     write_buf(keymap, buf, size, offset, "\t};\n\n");
947     return true;
948 }
949
950 _X_EXPORT char *
951 xkb_map_get_as_string(struct xkb_keymap *keymap)
952 {
953     char *ret = NULL;
954     size_t size = 0;
955     size_t offset = 0;
956
957     check_write_buf(keymap, &ret, &size, &offset, "xkb_keymap {\n");
958     if (ret == NULL)
959         return NULL;
960     if (!write_keycodes(keymap, &ret, &size, &offset))
961         return NULL;
962     if (!write_types(keymap, &ret, &size, &offset))
963         return NULL;
964     if (!write_compat(keymap, &ret, &size, &offset))
965         return NULL;
966     if (!write_symbols(keymap, &ret, &size, &offset))
967         return NULL;
968     check_write_buf(keymap, &ret, &size, &offset, "};\n");
969     if (ret == NULL)
970         return NULL;
971
972     return ret;
973 }