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
51static Bool
52WriteXKBVModDecl(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
92static Bool
93WriteXKBAction(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
107Bool
108XkbWriteXKBKeycodes(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
176Bool
177XkbWriteXKBKeyTypes(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
251static Bool
252WriteXKBIndicatorMap(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
297Bool
298XkbWriteXKBCompatMap(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
380Bool
381XkbWriteXKBSymbols(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
595static Bool
596WriteXKBOutline(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
638static Bool
639WriteXKBDoodad(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*/
730static Bool
731WriteXKBOverlay(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
768static Bool
769WriteXKBSection(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
865Bool
866XkbWriteXKBGeometry(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*/
985Bool
986XkbWriteXKBSemantics(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*/
1003Bool
1004XkbWriteXKBLayout(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*/
1029Bool
1030XkbWriteXKBKeymap(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
1056Bool
1057XkbWriteXKBFile(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