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 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #elif defined(HAVE_CONFIG_H)
30 #include <config.h>
31 #endif
32 
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <X11/Xfuncs.h>
37 
38 
39 #include <X11/Xlib.h>
40 #include <X11/XKBlib.h>
41 #include <X11/extensions/XKBgeom.h>
42 
43 #include "XKMformat.h"
44 #include "XKBfileInt.h"
45 
46 
47 #define	VMOD_HIDE_VALUE	0
48 #define	VMOD_SHOW_VALUE	1
49 #define	VMOD_COMMENT_VALUE 2
50 
51 static Bool
WriteXKBVModDecl(FILE * file,Display * dpy,XkbDescPtr xkb,int showValue)52 WriteXKBVModDecl(FILE *file, Display *dpy, XkbDescPtr xkb, int showValue)
53 {
54     register int i, nMods;
55     Atom *vmodNames;
56 
57     if (xkb == NULL)
58         return False;
59     if (xkb->names != NULL)
60         vmodNames = xkb->names->vmods;
61     else
62         vmodNames = NULL;
63 
64     for (i = nMods = 0; i < XkbNumVirtualMods; i++) {
65         if ((vmodNames != NULL) && (vmodNames[i] != None)) {
66             if (nMods == 0)
67                 fprintf(file, "    virtual_modifiers ");
68             else
69                 fprintf(file, ",");
70             fprintf(file, "%s", XkbAtomText(dpy, vmodNames[i], XkbXKBFile));
71             if ((showValue != VMOD_HIDE_VALUE) &&
72                 (xkb->server) && (xkb->server->vmods[i] != XkbNoModifierMask)) {
73                 if (showValue == VMOD_COMMENT_VALUE) {
74                     fprintf(file, "/* = %s */",
75                             XkbModMaskText(xkb->server->vmods[i], XkbXKBFile));
76                 }
77                 else {
78                     fprintf(file, "= %s",
79                             XkbModMaskText(xkb->server->vmods[i], XkbXKBFile));
80                 }
81             }
82             nMods++;
83         }
84     }
85     if (nMods > 0)
86         fprintf(file, ";\n\n");
87     return True;
88 }
89 
90 /***====================================================================***/
91 
92 static Bool
WriteXKBAction(FILE * file,XkbFileInfo * result,XkbAnyAction * action)93 WriteXKBAction(FILE *file, XkbFileInfo *result, XkbAnyAction *action)
94 {
95     XkbDescPtr xkb;
96     Display *dpy;
97 
98     xkb = result->xkb;
99     dpy = xkb->dpy;
100     fprintf(file, "%s",
101             XkbActionText(dpy, xkb, (XkbAction *) action, XkbXKBFile));
102     return True;
103 }
104 
105 /***====================================================================***/
106 
107 Bool
XkbWriteXKBKeycodes(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)108 XkbWriteXKBKeycodes(FILE *              file,
109                     XkbFileInfo *       result,
110                     Bool                topLevel,
111                     Bool                showImplicit,
112                     XkbFileAddOnFunc    addOn,
113                     void *              priv)
114 {
115     Atom kcName;
116     register unsigned i;
117     XkbDescPtr xkb;
118     Display *dpy;
119     const char *alternate;
120 
121     xkb = result->xkb;
122     if ((!xkb) || (!xkb->names) || (!xkb->names->keys)) {
123         _XkbLibError(_XkbErrMissingNames, "XkbWriteXKBKeycodes", 0);
124         return False;
125     }
126     dpy = xkb->dpy;
127     kcName = xkb->names->keycodes;
128     if (kcName != None)
129         fprintf(file, "xkb_keycodes \"%s\" {\n",
130                 XkbAtomText(dpy, kcName, XkbXKBFile));
131     else
132         fprintf(file, "xkb_keycodes {\n");
133     fprintf(file, "    minimum = %d;\n", xkb->min_key_code);
134     fprintf(file, "    maximum = %d;\n", xkb->max_key_code);
135     for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
136         if (xkb->names->keys[i].name[0] != '\0') {
137             if (XkbFindKeycodeByName(xkb, xkb->names->keys[i].name, True) != i)
138                 alternate = "alternate ";
139             else
140                 alternate = "";
141             fprintf(file, "    %s%6s = %d;\n", alternate,
142                     XkbKeyNameText(xkb->names->keys[i].name, XkbXKBFile), i);
143         }
144     }
145     if (xkb->indicators != NULL) {
146         for (i = 0; i < XkbNumIndicators; i++) {
147             const char *type;
148 
149             if (xkb->indicators->phys_indicators & (1 << i))
150                 type = "    ";
151             else
152                 type = "    virtual ";
153             if (xkb->names->indicators[i] != None) {
154                 fprintf(file, "%sindicator %d = \"%s\";\n", type, i + 1,
155                         XkbAtomText(dpy, xkb->names->indicators[i],
156                                     XkbXKBFile));
157             }
158         }
159     }
160     if (xkb->names->key_aliases != NULL) {
161         XkbKeyAliasPtr pAl;
162 
163         pAl = xkb->names->key_aliases;
164         for (i = 0; i < xkb->names->num_key_aliases; i++, pAl++) {
165             fprintf(file, "    alias %6s = %6s;\n",
166                     XkbKeyNameText(pAl->alias, XkbXKBFile),
167                     XkbKeyNameText(pAl->real, XkbXKBFile));
168         }
169     }
170     if (addOn)
171         (*addOn) (file, result, topLevel, showImplicit, XkmKeyNamesIndex, priv);
172     fprintf(file, "};\n\n");
173     return True;
174 }
175 
176 Bool
XkbWriteXKBKeyTypes(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)177 XkbWriteXKBKeyTypes(FILE *              file,
178                     XkbFileInfo *       result,
179                     Bool                topLevel,
180                     Bool                showImplicit,
181                     XkbFileAddOnFunc    addOn,
182                     void *              priv)
183 {
184     Display *dpy;
185     register unsigned i, n;
186     XkbKeyTypePtr type;
187     XkbKTMapEntryPtr entry;
188     XkbDescPtr xkb;
189 
190     xkb = result->xkb;
191     if ((!xkb) || (!xkb->map) || (!xkb->map->types)) {
192         _XkbLibError(_XkbErrMissingTypes, "XkbWriteXKBKeyTypes", 0);
193         return False;
194     }
195     dpy = xkb->dpy;
196     if (xkb->map->num_types < XkbNumRequiredTypes) {
197         _XkbLibError(_XkbErrMissingReqTypes, "XkbWriteXKBKeyTypes", 0);
198         return 0;
199     }
200     if ((xkb->names == NULL) || (xkb->names->types == None))
201         fprintf(file, "xkb_types {\n\n");
202     else
203         fprintf(file, "xkb_types \"%s\" {\n\n",
204                 XkbAtomText(dpy, xkb->names->types, XkbXKBFile));
205     WriteXKBVModDecl(file, dpy, xkb,
206                      (showImplicit ? VMOD_COMMENT_VALUE : VMOD_HIDE_VALUE));
207 
208     type = xkb->map->types;
209     for (i = 0; i < xkb->map->num_types; i++, type++) {
210         fprintf(file, "    type \"%s\" {\n",
211                 XkbAtomText(dpy, type->name, XkbXKBFile));
212         fprintf(file, "        modifiers= %s;\n",
213                 XkbVModMaskText(dpy, xkb, type->mods.real_mods,
214                                 type->mods.vmods, XkbXKBFile));
215         entry = type->map;
216         for (n = 0; n < type->map_count; n++, entry++) {
217             char *str;
218 
219             str =
220                 XkbVModMaskText(dpy, xkb, entry->mods.real_mods,
221                                 entry->mods.vmods, XkbXKBFile);
222             fprintf(file, "        map[%s]= Level%d;\n", str, entry->level + 1);
223             if ((type->preserve) && ((type->preserve[n].real_mods) ||
224                                      (type->preserve[n].vmods))) {
225                 fprintf(file, "        preserve[%s]= ", str);
226                 fprintf(file, "%s;\n", XkbVModMaskText(dpy, xkb,
227                                                        type->preserve[n].
228                                                        real_mods,
229                                                        type->preserve[n].vmods,
230                                                        XkbXKBFile));
231             }
232         }
233         if (type->level_names != NULL) {
234             Atom *name = type->level_names;
235 
236             for (n = 0; n < type->num_levels; n++, name++) {
237                 if ((*name) == None)
238                     continue;
239                 fprintf(file, "        level_name[Level%d]= \"%s\";\n", n + 1,
240                         XkbAtomText(dpy, *name, XkbXKBFile));
241             }
242         }
243         fprintf(file, "    };\n");
244     }
245     if (addOn)
246         (*addOn) (file, result, topLevel, showImplicit, XkmTypesIndex, priv);
247     fprintf(file, "};\n\n");
248     return True;
249 }
250 
251 static Bool
WriteXKBIndicatorMap(FILE * file,XkbFileInfo * result,Atom name,XkbIndicatorMapPtr led,XkbFileAddOnFunc addOn,void * priv)252 WriteXKBIndicatorMap(FILE *             file,
253                      XkbFileInfo *      result,
254                      Atom               name,
255                      XkbIndicatorMapPtr led,
256                      XkbFileAddOnFunc   addOn,
257                      void *             priv)
258 {
259     XkbDescPtr xkb;
260     char *tmp;
261 
262     xkb = result->xkb;
263     tmp = XkbAtomGetString(xkb->dpy, name);
264     fprintf(file, "    indicator \"%s\" {\n", tmp);
265     _XkbFree(tmp);
266     if (led->flags & XkbIM_NoExplicit)
267         fprintf(file, "        !allowExplicit;\n");
268     if (led->flags & XkbIM_LEDDrivesKB)
269         fprintf(file, "        indicatorDrivesKeyboard;\n");
270     if (led->which_groups != 0) {
271         if (led->which_groups != XkbIM_UseEffective) {
272             fprintf(file, "        whichGroupState= %s;\n",
273                     XkbIMWhichStateMaskText(led->which_groups, XkbXKBFile));
274         }
275         fprintf(file, "        groups= 0x%02x;\n", led->groups);
276     }
277     if (led->which_mods != 0) {
278         if (led->which_mods != XkbIM_UseEffective) {
279             fprintf(file, "        whichModState= %s;\n",
280                     XkbIMWhichStateMaskText(led->which_mods, XkbXKBFile));
281         }
282         fprintf(file, "        modifiers= %s;\n",
283                 XkbVModMaskText(xkb->dpy, xkb,
284                                 led->mods.real_mods, led->mods.vmods,
285                                 XkbXKBFile));
286     }
287     if (led->ctrls != 0) {
288         fprintf(file, "        controls= %s;\n",
289                 XkbControlsMaskText(led->ctrls, XkbXKBFile));
290     }
291     if (addOn)
292         (*addOn) (file, result, False, True, XkmIndicatorsIndex, priv);
293     fprintf(file, "    };\n");
294     return True;
295 }
296 
297 Bool
XkbWriteXKBCompatMap(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)298 XkbWriteXKBCompatMap(FILE *             file,
299                      XkbFileInfo *      result,
300                      Bool               topLevel,
301                      Bool               showImplicit,
302                      XkbFileAddOnFunc   addOn,
303                      void *             priv)
304 {
305     Display *           dpy;
306     register unsigned   i;
307     XkbSymInterpretPtr  interp;
308     XkbDescPtr          xkb;
309 
310     xkb = result->xkb;
311     if ((!xkb) || (!xkb->compat) || (!xkb->compat->sym_interpret)) {
312         _XkbLibError(_XkbErrMissingCompatMap, "XkbWriteXKBCompatMap", 0);
313         return False;
314     }
315     dpy = xkb->dpy;
316     if ((xkb->names == NULL) || (xkb->names->compat == None))
317         fprintf(file, "xkb_compatibility {\n\n");
318     else
319         fprintf(file, "xkb_compatibility \"%s\" {\n\n",
320                 XkbAtomText(dpy, xkb->names->compat, XkbXKBFile));
321     WriteXKBVModDecl(file, dpy, xkb,
322                      (showImplicit ? VMOD_COMMENT_VALUE : VMOD_HIDE_VALUE));
323 
324     fprintf(file, "    interpret.useModMapMods= AnyLevel;\n");
325     fprintf(file, "    interpret.repeat= False;\n");
326     fprintf(file, "    interpret.locking= False;\n");
327     interp = xkb->compat->sym_interpret;
328     for (i = 0; i < xkb->compat->num_si; i++, interp++) {
329         fprintf(file, "    interpret %s+%s(%s) {\n",
330                 ((interp->sym == NoSymbol) ? "Any" :
331                  XkbKeysymText(interp->sym, XkbXKBFile)),
332                 XkbSIMatchText(interp->match, XkbXKBFile),
333                 XkbModMaskText(interp->mods, XkbXKBFile));
334         if (interp->virtual_mod != XkbNoModifier) {
335             fprintf(file, "        virtualModifier= %s;\n",
336                     XkbVModIndexText(dpy, xkb, interp->virtual_mod,
337                                      XkbXKBFile));
338         }
339         if (interp->match & XkbSI_LevelOneOnly)
340             fprintf(file, "        useModMapMods=level1;\n");
341         if (interp->flags & XkbSI_LockingKey)
342             fprintf(file, "        locking= True;\n");
343         if (interp->flags & XkbSI_AutoRepeat)
344             fprintf(file, "        repeat= True;\n");
345         fprintf(file, "        action= ");
346         WriteXKBAction(file, result, &interp->act);
347         fprintf(file, ";\n");
348         fprintf(file, "    };\n");
349     }
350     for (i = 0; i < XkbNumKbdGroups; i++) {
351         XkbModsPtr gc;
352 
353         gc = &xkb->compat->groups[i];
354         if ((gc->real_mods == 0) && (gc->vmods == 0))
355             continue;
356         fprintf(file, "    group %d = %s;\n", i + 1,
357                 XkbVModMaskText(xkb->dpy, xkb, gc->real_mods, gc->vmods,
358                                 XkbXKBFile));
359     }
360     if (xkb->indicators) {
361         for (i = 0; i < XkbNumIndicators; i++) {
362             XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
363 
364             if ((map->flags != 0) || (map->which_groups != 0) ||
365                 (map->groups != 0) || (map->which_mods != 0) ||
366                 (map->mods.real_mods != 0) || (map->mods.vmods != 0) ||
367                 (map->ctrls != 0)) {
368                 WriteXKBIndicatorMap(file, result, xkb->names->indicators[i],
369                                      map, addOn, priv);
370             }
371         }
372     }
373     if (addOn)
374         (*addOn) (file, result, topLevel, showImplicit, XkmCompatMapIndex,
375                   priv);
376     fprintf(file, "};\n\n");
377     return True;
378 }
379 
380 Bool
XkbWriteXKBSymbols(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)381 XkbWriteXKBSymbols(FILE *               file,
382                    XkbFileInfo *        result,
383                    Bool                 topLevel,
384                    Bool                 showImplicit,
385                    XkbFileAddOnFunc     addOn,
386                    void *               priv)
387 {
388     Display *dpy;
389     register unsigned i, tmp;
390     XkbDescPtr xkb;
391     XkbClientMapPtr map;
392     XkbServerMapPtr srv;
393     Bool showActions;
394 
395     xkb = result->xkb;
396 
397     if ((!xkb) || (!xkb->map) || (!xkb->map->syms) || (!xkb->map->key_sym_map)) {
398         _XkbLibError(_XkbErrMissingSymbols, "XkbWriteXKBSymbols", 0);
399         return False;
400     }
401     if ((!xkb->names) || (!xkb->names->keys)) {
402         _XkbLibError(_XkbErrMissingNames, "XkbWriteXKBSymbols", 0);
403         return False;
404     }
405 
406     map = xkb->map;
407     srv = xkb->server;
408     dpy = xkb->dpy;
409 
410     if ((xkb->names == NULL) || (xkb->names->symbols == None))
411         fprintf(file, "xkb_symbols {\n\n");
412     else
413         fprintf(file, "xkb_symbols \"%s\" {\n\n",
414                 XkbAtomText(dpy, xkb->names->symbols, XkbXKBFile));
415     for (tmp = i = 0; i < XkbNumKbdGroups; i++) {
416         if (xkb->names->groups[i] != None) {
417             fprintf(file, "    name[group%d]=\"%s\";\n", i + 1,
418                     XkbAtomText(dpy, xkb->names->groups[i], XkbXKBFile));
419             tmp++;
420         }
421     }
422     if (tmp > 0)
423         fprintf(file, "\n");
424     for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
425         Bool simple;
426 
427         if ((int) XkbKeyNumSyms(xkb, i) < 1)
428             continue;
429         if (XkbFindKeycodeByName(xkb, xkb->names->keys[i].name, True) != i)
430             continue;
431         simple = True;
432         fprintf(file, "    key %6s {",
433                 XkbKeyNameText(xkb->names->keys[i].name, XkbXKBFile));
434         if (srv->explicit) {
435             if (((srv->explicit[i] & XkbExplicitKeyTypesMask) != 0) ||
436                 (showImplicit)) {
437                 int typeNdx, g;
438                 Bool multi;
439                 const char *comment = "  ";
440 
441                 if ((srv->explicit[i] & XkbExplicitKeyTypesMask) == 0)
442                     comment = "//";
443                 multi = False;
444                 typeNdx = XkbKeyKeyTypeIndex(xkb, i, 0);
445                 for (g = 1; (g < XkbKeyNumGroups(xkb, i)) && (!multi); g++) {
446                     if (XkbKeyKeyTypeIndex(xkb, i, g) != typeNdx)
447                         multi = True;
448                 }
449                 if (multi) {
450                     for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) {
451                         typeNdx = XkbKeyKeyTypeIndex(xkb, i, g);
452                         if (srv->explicit[i] & (1 << g)) {
453                             fprintf(file, "\n%s      type[group%d]= \"%s\",",
454                                     comment, g + 1,
455                                     XkbAtomText(dpy, map->types[typeNdx].name,
456                                                 XkbXKBFile));
457                         }
458                         else if (showImplicit) {
459                             fprintf(file, "\n//      type[group%d]= \"%s\",",
460                                     g + 1,
461                                     XkbAtomText(dpy, map->types[typeNdx].name,
462                                                 XkbXKBFile));
463                         }
464                     }
465                 }
466                 else {
467                     fprintf(file, "\n%s      type= \"%s\",", comment,
468                             XkbAtomText(dpy, map->types[typeNdx].name,
469                                         XkbXKBFile));
470                 }
471                 simple = False;
472             }
473             if (((srv->explicit[i] & XkbExplicitAutoRepeatMask) != 0) &&
474                 (xkb->ctrls != NULL)) {
475                 if (xkb->ctrls->per_key_repeat[i / 8] & (1 << (i % 8)))
476                     fprintf(file, "\n        repeat= Yes,");
477                 else
478                     fprintf(file, "\n        repeat= No,");
479                 simple = False;
480             }
481             if ((xkb->server != NULL) && (xkb->server->vmodmap != NULL) &&
482                 (xkb->server->vmodmap[i] != 0)) {
483                 if ((srv->explicit[i] & XkbExplicitVModMapMask) != 0) {
484                     fprintf(file, "\n        virtualMods= %s,",
485                             XkbVModMaskText(dpy, xkb, 0,
486                                             xkb->server->vmodmap[i],
487                                             XkbXKBFile));
488                 }
489                 else if (showImplicit) {
490                     fprintf(file, "\n//      virtualMods= %s,",
491                             XkbVModMaskText(dpy, xkb, 0,
492                                             xkb->server->vmodmap[i],
493                                             XkbXKBFile));
494                 }
495             }
496         }
497         switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(xkb, i))) {
498         case XkbClampIntoRange:
499             fprintf(file, "\n        groupsClamp,");
500             break;
501         case XkbRedirectIntoRange:
502             fprintf(file, "\n        groupsRedirect= Group%d,",
503                     XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(xkb, i)) + 1);
504             break;
505         }
506         if (srv->behaviors != NULL) {
507             unsigned type;
508 
509             type = srv->behaviors[i].type & XkbKB_OpMask;
510 
511             if (type != XkbKB_Default) {
512                 simple = False;
513                 fprintf(file, "\n        %s,",
514                         XkbBehaviorText(xkb, &srv->behaviors[i], XkbXKBFile));
515             }
516         }
517         if ((srv->explicit == NULL) || showImplicit ||
518             ((srv->explicit[i] & XkbExplicitInterpretMask) != 0))
519             showActions = XkbKeyHasActions(xkb, i);
520         else
521             showActions = False;
522 
523         if (((unsigned) XkbKeyNumGroups(xkb, i) > 1) || showActions)
524             simple = False;
525         if (simple) {
526             KeySym *syms;
527             unsigned s;
528 
529             syms = XkbKeySymsPtr(xkb, i);
530             fprintf(file, "         [ ");
531             for (s = 0; s < XkbKeyGroupWidth(xkb, i, XkbGroup1Index); s++) {
532                 if (s != 0)
533                     fprintf(file, ", ");
534                 fprintf(file, "%15s", XkbKeysymText(*syms++, XkbXKBFile));
535             }
536             fprintf(file, " ] };\n");
537         }
538         else {
539             unsigned g, s;
540             KeySym *syms;
541             XkbAction *acts;
542 
543             syms = XkbKeySymsPtr(xkb, i);
544             acts = XkbKeyActionsPtr(xkb, i);
545             for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) {
546                 if (g != 0)
547                     fprintf(file, ",");
548                 fprintf(file, "\n        symbols[Group%d]= [ ", g + 1);
549                 for (s = 0; s < XkbKeyGroupWidth(xkb, i, g); s++) {
550                     if (s != 0)
551                         fprintf(file, ", ");
552                     fprintf(file, "%15s", XkbKeysymText(syms[s], XkbXKBFile));
553                 }
554                 fprintf(file, " ]");
555                 syms += XkbKeyGroupsWidth(xkb, i);
556                 if (showActions) {
557                     fprintf(file, ",\n        actions[Group%d]= [ ", g + 1);
558                     for (s = 0; s < XkbKeyGroupWidth(xkb, i, g); s++) {
559                         if (s != 0)
560                             fprintf(file, ", ");
561                         WriteXKBAction(file, result,
562                                        (XkbAnyAction *) & acts[s]);
563                     }
564                     fprintf(file, " ]");
565                     acts += XkbKeyGroupsWidth(xkb, i);
566                 }
567             }
568             fprintf(file, "\n    };\n");
569         }
570     }
571     if (map && map->modmap) {
572         for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
573             if (map->modmap[i] != 0) {
574                 register int n, bit;
575 
576                 for (bit = 1, n = 0; n < XkbNumModifiers; n++, bit <<= 1) {
577                     if (map->modmap[i] & bit) {
578                         char buf[5];
579 
580                         memcpy(buf, xkb->names->keys[i].name, 4);
581                         buf[4] = '\0';
582                         fprintf(file, "    modifier_map %s { <%s> };\n",
583                                 XkbModIndexText(n, XkbXKBFile), buf);
584                     }
585                 }
586             }
587         }
588     }
589     if (addOn)
590         (*addOn) (file, result, topLevel, showImplicit, XkmSymbolsIndex, priv);
591     fprintf(file, "};\n\n");
592     return True;
593 }
594 
595 static Bool
WriteXKBOutline(FILE * file,XkbShapePtr shape,XkbOutlinePtr outline,int lastRadius,int first,int indent)596 WriteXKBOutline(FILE *          file,
597                 XkbShapePtr     shape,
598                 XkbOutlinePtr   outline,
599                 int             lastRadius,
600                 int             first,
601                 int             indent)
602 {
603     register int i;
604     XkbPointPtr pt;
605     char *iStr;
606 
607     fprintf(file, "%s", iStr = XkbIndentText(first));
608     if (first != indent)
609         iStr = XkbIndentText(indent);
610     if (outline->corner_radius != lastRadius) {
611         fprintf(file, "corner= %s,",
612                 XkbGeomFPText(outline->corner_radius, XkbMessage));
613         if (shape != NULL) {
614             fprintf(file, "\n%s", iStr);
615         }
616     }
617     if (shape) {
618         if (outline == shape->approx)
619             fprintf(file, "approx= ");
620         else if (outline == shape->primary)
621             fprintf(file, "primary= ");
622     }
623     fprintf(file, "{");
624     for (pt = outline->points, i = 0; i < outline->num_points; i++, pt++) {
625         if (i == 0)
626             fprintf(file, " ");
627         else if ((i % 4) == 0)
628             fprintf(file, ",\n%s  ", iStr);
629         else
630             fprintf(file, ", ");
631         fprintf(file, "[ %3s, %3s ]", XkbGeomFPText(pt->x, XkbXKBFile),
632                 XkbGeomFPText(pt->y, XkbXKBFile));
633     }
634     fprintf(file, " }");
635     return True;
636 }
637 
638 static Bool
WriteXKBDoodad(FILE * file,Display * dpy,unsigned indent,XkbGeometryPtr geom,XkbDoodadPtr doodad)639 WriteXKBDoodad(FILE *           file,
640                Display *        dpy,
641                unsigned         indent,
642                XkbGeometryPtr   geom,
643                XkbDoodadPtr     doodad)
644 {
645     register char *i_str;
646     XkbShapePtr shape;
647     XkbColorPtr color;
648 
649     i_str = XkbIndentText(indent);
650     fprintf(file, "%s%s \"%s\" {\n", i_str,
651             XkbDoodadTypeText(doodad->any.type, XkbMessage),
652             XkbAtomText(dpy, doodad->any.name, XkbMessage));
653     fprintf(file, "%s    top=      %s;\n", i_str,
654             XkbGeomFPText(doodad->any.top, XkbXKBFile));
655     fprintf(file, "%s    left=     %s;\n", i_str,
656             XkbGeomFPText(doodad->any.left, XkbXKBFile));
657     fprintf(file, "%s    priority= %d;\n", i_str, doodad->any.priority);
658     switch (doodad->any.type) {
659     case XkbOutlineDoodad:
660     case XkbSolidDoodad:
661         if (doodad->shape.angle != 0) {
662             fprintf(file, "%s    angle=  %s;\n", i_str,
663                     XkbGeomFPText(doodad->shape.angle, XkbXKBFile));
664         }
665         if (doodad->shape.color_ndx != 0) {
666             fprintf(file, "%s    color= \"%s\";\n", i_str,
667                     XkbShapeDoodadColor(geom, &doodad->shape)->spec);
668         }
669         shape = XkbShapeDoodadShape(geom, &doodad->shape);
670         fprintf(file, "%s    shape= \"%s\";\n", i_str,
671                 XkbAtomText(dpy, shape->name, XkbXKBFile));
672         break;
673     case XkbTextDoodad:
674         if (doodad->text.angle != 0) {
675             fprintf(file, "%s    angle=  %s;\n", i_str,
676                     XkbGeomFPText(doodad->text.angle, XkbXKBFile));
677         }
678         if (doodad->text.width != 0) {
679             fprintf(file, "%s    width=  %s;\n", i_str,
680                     XkbGeomFPText(doodad->text.width, XkbXKBFile));
681 
682         }
683         if (doodad->text.height != 0) {
684             fprintf(file, "%s    height=  %s;\n", i_str,
685                     XkbGeomFPText(doodad->text.height, XkbXKBFile));
686 
687         }
688         if (doodad->text.color_ndx != 0) {
689             color = XkbTextDoodadColor(geom, &doodad->text);
690             fprintf(file, "%s    color= \"%s\";\n", i_str,
691                     XkbStringText(color->spec, XkbXKBFile));
692         }
693         fprintf(file, "%s    XFont= \"%s\";\n", i_str,
694                 XkbStringText(doodad->text.font, XkbXKBFile));
695         fprintf(file, "%s    text=  \"%s\";\n", i_str,
696                 XkbStringText(doodad->text.text, XkbXKBFile));
697         break;
698     case XkbIndicatorDoodad:
699         shape = XkbIndicatorDoodadShape(geom, &doodad->indicator);
700         color = XkbIndicatorDoodadOnColor(geom, &doodad->indicator);
701         fprintf(file, "%s    onColor= \"%s\";\n", i_str,
702                 XkbStringText(color->spec, XkbXKBFile));
703         color = XkbIndicatorDoodadOffColor(geom, &doodad->indicator);
704         fprintf(file, "%s    offColor= \"%s\";\n", i_str,
705                 XkbStringText(color->spec, XkbXKBFile));
706         fprintf(file, "%s    shape= \"%s\";\n", i_str,
707                 XkbAtomText(dpy, shape->name, XkbXKBFile));
708         break;
709     case XkbLogoDoodad:
710         fprintf(file, "%s    logoName= \"%s\";\n", i_str,
711                 XkbStringText(doodad->logo.logo_name, XkbXKBFile));
712         if (doodad->shape.angle != 0) {
713             fprintf(file, "%s    angle=  %s;\n", i_str,
714                     XkbGeomFPText(doodad->logo.angle, XkbXKBFile));
715         }
716         if (doodad->shape.color_ndx != 0) {
717             fprintf(file, "%s    color= \"%s\";\n", i_str,
718                     XkbLogoDoodadColor(geom, &doodad->logo)->spec);
719         }
720         shape = XkbLogoDoodadShape(geom, &doodad->logo);
721         fprintf(file, "%s    shape= \"%s\";\n", i_str,
722                 XkbAtomText(dpy, shape->name, XkbXKBFile));
723         break;
724     }
725     fprintf(file, "%s};\n", i_str);
726     return True;
727 }
728 
729 /*ARGSUSED*/
730 static Bool
WriteXKBOverlay(FILE * file,Display * dpy,unsigned indent,XkbGeometryPtr geom,XkbOverlayPtr ol)731 WriteXKBOverlay(FILE *          file,
732                 Display *       dpy,
733                 unsigned        indent,
734                 XkbGeometryPtr  geom,
735                 XkbOverlayPtr   ol)
736 {
737     register char *i_str;
738     int r, k, nOut;
739     XkbOverlayRowPtr row;
740     XkbOverlayKeyPtr key;
741 
742     i_str = XkbIndentText(indent);
743     if (ol->name != None) {
744         fprintf(file, "%soverlay \"%s\" {\n", i_str,
745                 XkbAtomText(dpy, ol->name, XkbMessage));
746     }
747     else
748         fprintf(file, "%soverlay {\n", i_str);
749     for (nOut = r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
750         for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
751             char *over, *under;
752 
753             over = XkbKeyNameText(key->over.name, XkbXKBFile);
754             under = XkbKeyNameText(key->under.name, XkbXKBFile);
755             if (nOut == 0)
756                 fprintf(file, "%s    %6s=%6s", i_str, under, over);
757             else if ((nOut % 4) == 0)
758                 fprintf(file, ",\n%s    %6s=%6s", i_str, under, over);
759             else
760                 fprintf(file, ", %6s=%6s", under, over);
761             nOut++;
762         }
763     }
764     fprintf(file, "\n%s};\n", i_str);
765     return True;
766 }
767 
768 static Bool
WriteXKBSection(FILE * file,Display * dpy,XkbSectionPtr s,XkbGeometryPtr geom)769 WriteXKBSection(FILE *          file,
770                 Display *       dpy,
771                 XkbSectionPtr   s,
772                 XkbGeometryPtr  geom)
773 {
774     register int i;
775     XkbRowPtr row;
776     int dfltKeyColor = 0;
777 
778     fprintf(file, "    section \"%s\" {\n",
779             XkbAtomText(dpy, s->name, XkbXKBFile));
780     if (s->rows && (s->rows->num_keys > 0)) {
781         dfltKeyColor = s->rows->keys[0].color_ndx;
782         fprintf(file, "        key.color= \"%s\";\n",
783                 XkbStringText(geom->colors[dfltKeyColor].spec, XkbXKBFile));
784     }
785     fprintf(file, "        priority=  %d;\n", s->priority);
786     fprintf(file, "        top=       %s;\n",
787             XkbGeomFPText(s->top, XkbXKBFile));
788     fprintf(file, "        left=      %s;\n",
789             XkbGeomFPText(s->left, XkbXKBFile));
790     fprintf(file, "        width=     %s;\n",
791             XkbGeomFPText(s->width, XkbXKBFile));
792     fprintf(file, "        height=    %s;\n",
793             XkbGeomFPText(s->height, XkbXKBFile));
794     if (s->angle != 0) {
795         fprintf(file, "        angle=  %s;\n",
796                 XkbGeomFPText(s->angle, XkbXKBFile));
797     }
798     for (i = 0, row = s->rows; row && i < s->num_rows; i++, row++) {
799         fprintf(file, "        row {\n");
800         fprintf(file, "            top=  %s;\n",
801                 XkbGeomFPText(row->top, XkbXKBFile));
802         fprintf(file, "            left= %s;\n",
803                 XkbGeomFPText(row->left, XkbXKBFile));
804         if (row->vertical)
805             fprintf(file, "            vertical;\n");
806         if (row->num_keys > 0) {
807             register int k;
808             register XkbKeyPtr key;
809             int forceNL = 0;
810             int nThisLine = 0;
811 
812             fprintf(file, "            keys {\n");
813             for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
814                 XkbShapePtr shape;
815 
816                 if (key->color_ndx != dfltKeyColor)
817                     forceNL = 1;
818                 if (k == 0) {
819                     fprintf(file, "                ");
820                     nThisLine = 0;
821                 }
822                 else if (((nThisLine % 2) == 1) || (forceNL)) {
823                     fprintf(file, ",\n                ");
824                     forceNL = nThisLine = 0;
825                 }
826                 else {
827                     fprintf(file, ", ");
828                     nThisLine++;
829                 }
830                 shape = XkbKeyShape(geom, key);
831                 fprintf(file, "{ %6s, \"%s\", %3s",
832                         XkbKeyNameText(key->name.name, XkbXKBFile),
833                         XkbAtomText(dpy, shape->name, XkbXKBFile),
834                         XkbGeomFPText(key->gap, XkbXKBFile));
835                 if (key->color_ndx != dfltKeyColor) {
836                     fprintf(file, ", color=\"%s\"",
837                             XkbKeyColor(geom, key)->spec);
838                     forceNL = 1;
839                 }
840                 fprintf(file, " }");
841             }
842             fprintf(file, "\n            };\n");
843         }
844         fprintf(file, "        };\n");
845     }
846     if (s->doodads != NULL) {
847         XkbDoodadPtr doodad;
848 
849         for (i = 0, doodad = s->doodads; i < s->num_doodads; i++, doodad++) {
850             WriteXKBDoodad(file, dpy, 8, geom, doodad);
851         }
852     }
853     if (s->overlays != NULL) {
854         XkbOverlayPtr ol;
855 
856         for (i = 0, ol = s->overlays; i < s->num_overlays; i++, ol++) {
857             WriteXKBOverlay(file, dpy, 8, geom, ol);
858         }
859     }
860     fprintf(file, "    }; // End of \"%s\" section\n\n",
861             XkbAtomText(dpy, s->name, XkbXKBFile));
862     return True;
863 }
864 
865 Bool
XkbWriteXKBGeometry(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)866 XkbWriteXKBGeometry(FILE *              file,
867                     XkbFileInfo *       result,
868                     Bool                topLevel,
869                     Bool                showImplicit,
870                     XkbFileAddOnFunc    addOn,
871                     void *              priv)
872 {
873     Display *dpy;
874     register unsigned i, n;
875     XkbDescPtr xkb;
876     XkbGeometryPtr geom;
877 
878     xkb = result->xkb;
879     if ((!xkb) || (!xkb->geom)) {
880         _XkbLibError(_XkbErrMissingGeometry, "XkbWriteXKBGeometry", 0);
881         return False;
882     }
883     dpy = xkb->dpy;
884     geom = xkb->geom;
885     if (geom->name == None)
886         fprintf(file, "xkb_geometry {\n\n");
887     else
888         fprintf(file, "xkb_geometry \"%s\" {\n\n",
889                 XkbAtomText(dpy, geom->name, XkbXKBFile));
890     fprintf(file, "    width=       %s;\n",
891             XkbGeomFPText(geom->width_mm, XkbXKBFile));
892     fprintf(file, "    height=      %s;\n\n",
893             XkbGeomFPText(geom->height_mm, XkbXKBFile));
894 
895     if (geom->key_aliases != NULL) {
896         XkbKeyAliasPtr pAl;
897 
898         pAl = geom->key_aliases;
899         for (i = 0; i < geom->num_key_aliases; i++, pAl++) {
900             fprintf(file, "    alias %6s = %6s;\n",
901                     XkbKeyNameText(pAl->alias, XkbXKBFile),
902                     XkbKeyNameText(pAl->real, XkbXKBFile));
903         }
904         fprintf(file, "\n");
905     }
906 
907     if (geom->base_color != NULL)
908         fprintf(file, "    baseColor=   \"%s\";\n",
909                 XkbStringText(geom->base_color->spec, XkbXKBFile));
910     if (geom->label_color != NULL)
911         fprintf(file, "    labelColor=  \"%s\";\n",
912                 XkbStringText(geom->label_color->spec, XkbXKBFile));
913     if (geom->label_font != NULL)
914         fprintf(file, "    xfont=       \"%s\";\n",
915                 XkbStringText(geom->label_font, XkbXKBFile));
916     if ((geom->num_colors > 0) && (showImplicit)) {
917         XkbColorPtr color;
918 
919         for (color = geom->colors, i = 0; i < geom->num_colors; i++, color++) {
920             fprintf(file, "//     color[%d]= \"%s\"\n", i,
921                     XkbStringText(color->spec, XkbXKBFile));
922         }
923         fprintf(file, "\n");
924     }
925     if (geom->num_properties > 0) {
926         XkbPropertyPtr prop;
927 
928         for (prop = geom->properties, i = 0; i < geom->num_properties;
929              i++, prop++) {
930             fprintf(file, "    %s= \"%s\";\n", prop->name,
931                     XkbStringText(prop->value, XkbXKBFile));
932         }
933         fprintf(file, "\n");
934     }
935     if (geom->num_shapes > 0) {
936         XkbShapePtr shape;
937         XkbOutlinePtr outline;
938         int lastR;
939 
940         for (shape = geom->shapes, i = 0; i < geom->num_shapes; i++, shape++) {
941             lastR = 0;
942             fprintf(file, "    shape \"%s\" {",
943                     XkbAtomText(dpy, shape->name, XkbXKBFile));
944             outline = shape->outlines;
945             if (shape->num_outlines > 1) {
946                 for (n = 0; n < shape->num_outlines; n++, outline++) {
947                     if (n == 0)
948                         fprintf(file, "\n");
949                     else
950                         fprintf(file, ",\n");
951                     WriteXKBOutline(file, shape, outline, lastR, 8, 8);
952                     lastR = outline->corner_radius;
953                 }
954                 fprintf(file, "\n    };\n");
955             }
956             else {
957                 WriteXKBOutline(file, NULL, outline, lastR, 1, 8);
958                 fprintf(file, " };\n");
959             }
960         }
961     }
962     if (geom->num_sections > 0) {
963         XkbSectionPtr section;
964 
965         for (section = geom->sections, i = 0; i < geom->num_sections;
966              i++, section++) {
967             WriteXKBSection(file, dpy, section, geom);
968         }
969     }
970     if (geom->num_doodads > 0) {
971         XkbDoodadPtr doodad;
972 
973         for (i = 0, doodad = geom->doodads; i < geom->num_doodads;
974              i++, doodad++) {
975             WriteXKBDoodad(file, dpy, 4, geom, doodad);
976         }
977     }
978     if (addOn)
979         (*addOn) (file, result, topLevel, showImplicit, XkmGeometryIndex, priv);
980     fprintf(file, "};\n\n");
981     return True;
982 }
983 
984 /*ARGSUSED*/
985 Bool
XkbWriteXKBSemantics(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)986 XkbWriteXKBSemantics(FILE * 		file,
987                      XkbFileInfo * 	result,
988                      Bool 		topLevel,
989                      Bool 		showImplicit,
990                      XkbFileAddOnFunc	addOn,
991                      void *		priv)
992 {
993     Bool ok;
994 
995     fprintf(file, "xkb_semantics {\n");
996     ok = XkbWriteXKBKeyTypes(file, result, False, False, addOn, priv);
997     ok = ok && XkbWriteXKBCompatMap(file, result, False, False, addOn, priv);
998     fprintf(file, "};\n");
999     return ok;
1000 }
1001 
1002 /*ARGSUSED*/
1003 Bool
XkbWriteXKBLayout(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)1004 XkbWriteXKBLayout(FILE *                file,
1005                   XkbFileInfo *         result,
1006                   Bool                  topLevel,
1007                   Bool                  showImplicit,
1008                   XkbFileAddOnFunc      addOn,
1009                   void *                priv)
1010 {
1011     Bool ok;
1012     XkbDescPtr xkb;
1013 
1014     xkb = result->xkb;
1015     fprintf(file, "xkb_layout {\n");
1016     ok = XkbWriteXKBKeycodes(file, result, False, showImplicit, addOn, priv);
1017     ok = ok &&
1018         XkbWriteXKBKeyTypes(file, result, False, showImplicit, addOn, priv);
1019     ok = ok &&
1020         XkbWriteXKBSymbols(file, result, False, showImplicit, addOn, priv);
1021     if (xkb->geom)
1022         ok = ok &&
1023             XkbWriteXKBGeometry(file, result, False, showImplicit, addOn, priv);
1024     fprintf(file, "};\n");
1025     return ok;
1026 }
1027 
1028 /*ARGSUSED*/
1029 Bool
XkbWriteXKBKeymap(FILE * file,XkbFileInfo * result,Bool topLevel,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)1030 XkbWriteXKBKeymap(FILE *                file,
1031                   XkbFileInfo *         result,
1032                   Bool                  topLevel,
1033                   Bool                  showImplicit,
1034                   XkbFileAddOnFunc      addOn,
1035                   void *                priv)
1036 {
1037     Bool ok;
1038     XkbDescPtr xkb;
1039 
1040     xkb = result->xkb;
1041     fprintf(file, "xkb_keymap {\n");
1042     ok = XkbWriteXKBKeycodes(file, result, False, showImplicit, addOn, priv);
1043     ok = ok &&
1044         XkbWriteXKBKeyTypes(file, result, False, showImplicit, addOn, priv);
1045     ok = ok &&
1046         XkbWriteXKBCompatMap(file, result, False, showImplicit, addOn, priv);
1047     ok = ok &&
1048         XkbWriteXKBSymbols(file, result, False, showImplicit, addOn, priv);
1049     if (xkb->geom)
1050         ok = ok &&
1051             XkbWriteXKBGeometry(file, result, False, showImplicit, addOn, priv);
1052     fprintf(file, "};\n");
1053     return ok;
1054 }
1055 
1056 Bool
XkbWriteXKBFile(FILE * out,XkbFileInfo * result,Bool showImplicit,XkbFileAddOnFunc addOn,void * priv)1057 XkbWriteXKBFile(FILE *                  out,
1058                 XkbFileInfo *           result,
1059                 Bool                    showImplicit,
1060                 XkbFileAddOnFunc        addOn,
1061                 void *                  priv)
1062 {
1063     Bool ok = False;
1064 
1065     Bool (*func) (FILE *                /* file */ ,
1066                   XkbFileInfo *         /* result */ ,
1067                   Bool                  /* topLevel */ ,
1068                   Bool                  /* showImplicit */ ,
1069                   XkbFileAddOnFunc      /* addOn */ ,
1070                   void *                /* priv */
1071         ) = NULL;
1072 
1073     switch (result->type) {
1074     case XkmSemanticsFile:
1075         func = XkbWriteXKBSemantics;
1076         break;
1077     case XkmLayoutFile:
1078         func = XkbWriteXKBLayout;
1079         break;
1080     case XkmKeymapFile:
1081         func = XkbWriteXKBKeymap;
1082         break;
1083     case XkmTypesIndex:
1084         func = XkbWriteXKBKeyTypes;
1085         break;
1086     case XkmCompatMapIndex:
1087         func = XkbWriteXKBCompatMap;
1088         break;
1089     case XkmSymbolsIndex:
1090         func = XkbWriteXKBSymbols;
1091         break;
1092     case XkmKeyNamesIndex:
1093         func = XkbWriteXKBKeycodes;
1094         break;
1095     case XkmGeometryFile:
1096     case XkmGeometryIndex:
1097         func = XkbWriteXKBGeometry;
1098         break;
1099     case XkmVirtualModsIndex:
1100     case XkmIndicatorsIndex:
1101         _XkbLibError(_XkbErrBadImplementation,
1102                      XkbConfigText(result->type, XkbMessage), 0);
1103         return False;
1104     }
1105     if (out == NULL) {
1106         _XkbLibError(_XkbErrFileCannotOpen, "XkbWriteXkbFile", 0);
1107         ok = False;
1108     }
1109     else if (func) {
1110         ok = (*func) (out, result, True, showImplicit, addOn, priv);
1111     }
1112     return ok;
1113 }
1114