xkbtext.c revision f2346221
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#endif
30
31#include <stdio.h>
32#include <ctype.h>
33#include <stdlib.h>
34
35#include <X11/Xos.h>
36
37#include <X11/X.h>
38#include <X11/Xproto.h>
39#include <X11/extensions/XKMformat.h>
40#include "misc.h"
41#include "inputstr.h"
42#include "dix.h"
43#include "xkbstr.h"
44#define XKBSRV_NEED_FILE_FUNCS	1
45#include <xkbsrv.h>
46#include "xkbgeom.h"
47
48/***====================================================================***/
49
50#define NUM_BUFFER      8
51static struct textBuffer {
52    int size;
53    char *buffer;
54} textBuffer[NUM_BUFFER];
55static int textBufferIndex;
56
57static char *
58tbGetBuffer(unsigned size)
59{
60    struct textBuffer *tb;
61
62    tb = &textBuffer[textBufferIndex];
63    textBufferIndex = (textBufferIndex + 1) % NUM_BUFFER;
64
65    if (size > tb->size) {
66        free(tb->buffer);
67        tb->buffer = xnfalloc(size);
68        tb->size = size;
69    }
70    return tb->buffer;
71}
72
73/***====================================================================***/
74
75char *
76XkbAtomText(Atom atm, unsigned format)
77{
78    const char *atmstr;
79    char *rtrn, *tmp;
80
81    atmstr = NameForAtom(atm);
82    if (atmstr != NULL) {
83        int len;
84
85        len = strlen(atmstr) + 1;
86        rtrn = tbGetBuffer(len);
87        strlcpy(rtrn, atmstr, len);
88    }
89    else {
90        rtrn = tbGetBuffer(1);
91        rtrn[0] = '\0';
92    }
93    if (format == XkbCFile) {
94        for (tmp = rtrn; *tmp != '\0'; tmp++) {
95            if ((tmp == rtrn) && (!isalpha(*tmp)))
96                *tmp = '_';
97            else if (!isalnum(*tmp))
98                *tmp = '_';
99        }
100    }
101    return XkbStringText(rtrn, format);
102}
103
104/***====================================================================***/
105
106char *
107XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format)
108{
109    register int len;
110    register Atom *vmodNames;
111    char *rtrn;
112    const char *tmp;
113    char numBuf[20];
114
115    if (xkb && xkb->names)
116        vmodNames = xkb->names->vmods;
117    else
118        vmodNames = NULL;
119
120    tmp = NULL;
121    if (ndx >= XkbNumVirtualMods)
122        tmp = "illegal";
123    else if (vmodNames && (vmodNames[ndx] != None))
124        tmp = NameForAtom(vmodNames[ndx]);
125    if (tmp == NULL) {
126        snprintf(numBuf, sizeof(numBuf), "%d", ndx);
127        tmp = numBuf;
128    }
129
130    len = strlen(tmp) + 1;
131    if (format == XkbCFile)
132        len += 4;
133    rtrn = tbGetBuffer(len);
134    if (format == XkbCFile) {
135        strcpy(rtrn, "vmod_");
136        strncpy(&rtrn[5], tmp, len - 4);
137    }
138    else
139        strncpy(rtrn, tmp, len);
140    return rtrn;
141}
142
143#define VMOD_BUFFER_SIZE        512
144
145char *
146XkbVModMaskText(XkbDescPtr xkb,
147                unsigned modMask, unsigned mask, unsigned format)
148{
149    register int i, bit;
150    int len;
151    char *mm, *rtrn;
152    char *str, buf[VMOD_BUFFER_SIZE];
153
154    if ((modMask == 0) && (mask == 0)) {
155        rtrn = tbGetBuffer(5);
156        if (format == XkbCFile)
157            sprintf(rtrn, "0");
158        else
159            sprintf(rtrn, "none");
160        return rtrn;
161    }
162    if (modMask != 0)
163        mm = XkbModMaskText(modMask, format);
164    else
165        mm = NULL;
166
167    str = buf;
168    buf[0] = '\0';
169    if (mask) {
170        char *tmp;
171
172        for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
173            if (mask & bit) {
174                tmp = XkbVModIndexText(xkb, i, format);
175                len = strlen(tmp) + 1 + (str == buf ? 0 : 1);
176                if (format == XkbCFile)
177                    len += 4;
178                if ((str - buf) + len > VMOD_BUFFER_SIZE)
179                    continue; /* Skip */
180                if (str != buf) {
181                    if (format == XkbCFile)
182                        *str++ = '|';
183                    else
184                        *str++ = '+';
185                    len--;
186                }
187                if (format == XkbCFile)
188                    sprintf(str, "%sMask", tmp);
189                else
190                    strcpy(str, tmp);
191                str = &str[len - 1];
192            }
193        }
194        str = buf;
195    }
196    else
197        str = NULL;
198    if (mm)
199        len = strlen(mm);
200    else
201        len = 0;
202    if (str)
203        len += strlen(str) + (mm == NULL ? 0 : 1);
204    rtrn = tbGetBuffer(len + 1);
205    rtrn[0] = '\0';
206
207    if (mm != NULL) {
208        i = strlen(mm);
209        if (i > len)
210            i = len;
211        strcpy(rtrn, mm);
212    }
213    else {
214        i = 0;
215    }
216    if (str != NULL) {
217        if (mm != NULL) {
218            if (format == XkbCFile)
219                strcat(rtrn, "|");
220            else
221                strcat(rtrn, "+");
222        }
223        strncat(rtrn, str, len - i);
224    }
225    rtrn[len] = '\0';
226    return rtrn;
227}
228
229static const char *modNames[XkbNumModifiers] = {
230    "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5"
231};
232
233char *
234XkbModIndexText(unsigned ndx, unsigned format)
235{
236    char *rtrn;
237    char buf[100];
238
239    if (format == XkbCFile) {
240        if (ndx < XkbNumModifiers)
241            snprintf(buf, sizeof(buf), "%sMapIndex", modNames[ndx]);
242        else if (ndx == XkbNoModifier)
243            snprintf(buf, sizeof(buf), "XkbNoModifier");
244        else
245            snprintf(buf, sizeof(buf), "0x%02x", ndx);
246    }
247    else {
248        if (ndx < XkbNumModifiers)
249            strcpy(buf, modNames[ndx]);
250        else if (ndx == XkbNoModifier)
251            strcpy(buf, "none");
252        else
253            snprintf(buf, sizeof(buf), "ILLEGAL_%02x", ndx);
254    }
255    rtrn = tbGetBuffer(strlen(buf) + 1);
256    strcpy(rtrn, buf);
257    return rtrn;
258}
259
260char *
261XkbModMaskText(unsigned mask, unsigned format)
262{
263    register int i, bit;
264    char buf[64], *rtrn;
265
266    if ((mask & 0xff) == 0xff) {
267        if (format == XkbCFile)
268            strcpy(buf, "0xff");
269        else
270            strcpy(buf, "all");
271    }
272    else if ((mask & 0xff) == 0) {
273        if (format == XkbCFile)
274            strcpy(buf, "0");
275        else
276            strcpy(buf, "none");
277    }
278    else {
279        char *str = buf;
280
281        buf[0] = '\0';
282        for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
283            if (mask & bit) {
284                if (str != buf) {
285                    if (format == XkbCFile)
286                        *str++ = '|';
287                    else
288                        *str++ = '+';
289                }
290                strcpy(str, modNames[i]);
291                str = &str[strlen(str)];
292                if (format == XkbCFile) {
293                    strcpy(str, "Mask");
294                    str += 4;
295                }
296            }
297        }
298    }
299    rtrn = tbGetBuffer(strlen(buf) + 1);
300    strcpy(rtrn, buf);
301    return rtrn;
302}
303
304/***====================================================================***/
305
306 /*ARGSUSED*/ char *
307XkbConfigText(unsigned config, unsigned format)
308{
309    static char *buf;
310
311    buf = tbGetBuffer(32);
312    switch (config) {
313    case XkmSemanticsFile:
314        strcpy(buf, "Semantics");
315        break;
316    case XkmLayoutFile:
317        strcpy(buf, "Layout");
318        break;
319    case XkmKeymapFile:
320        strcpy(buf, "Keymap");
321        break;
322    case XkmGeometryFile:
323    case XkmGeometryIndex:
324        strcpy(buf, "Geometry");
325        break;
326    case XkmTypesIndex:
327        strcpy(buf, "Types");
328        break;
329    case XkmCompatMapIndex:
330        strcpy(buf, "CompatMap");
331        break;
332    case XkmSymbolsIndex:
333        strcpy(buf, "Symbols");
334        break;
335    case XkmIndicatorsIndex:
336        strcpy(buf, "Indicators");
337        break;
338    case XkmKeyNamesIndex:
339        strcpy(buf, "KeyNames");
340        break;
341    case XkmVirtualModsIndex:
342        strcpy(buf, "VirtualMods");
343        break;
344    default:
345        sprintf(buf, "unknown(%d)", config);
346        break;
347    }
348    return buf;
349}
350
351/***====================================================================***/
352
353char *
354XkbKeysymText(KeySym sym, unsigned format)
355{
356    static char buf[32];
357
358    if (sym == NoSymbol)
359        strcpy(buf, "NoSymbol");
360    else
361        snprintf(buf, sizeof(buf), "0x%lx", (long) sym);
362    return buf;
363}
364
365char *
366XkbKeyNameText(char *name, unsigned format)
367{
368    char *buf;
369
370    if (format == XkbCFile) {
371        buf = tbGetBuffer(5);
372        memcpy(buf, name, 4);
373        buf[4] = '\0';
374    }
375    else {
376        int len;
377
378        buf = tbGetBuffer(7);
379        buf[0] = '<';
380        memcpy(&buf[1], name, 4);
381        buf[5] = '\0';
382        len = strlen(buf);
383        buf[len++] = '>';
384        buf[len] = '\0';
385    }
386    return buf;
387}
388
389/***====================================================================***/
390
391static const char *siMatchText[5] = {
392    "NoneOf", "AnyOfOrNone", "AnyOf", "AllOf", "Exactly"
393};
394
395const char *
396XkbSIMatchText(unsigned type, unsigned format)
397{
398    static char buf[40];
399    const char *rtrn;
400
401    switch (type & XkbSI_OpMask) {
402    case XkbSI_NoneOf:
403        rtrn = siMatchText[0];
404        break;
405    case XkbSI_AnyOfOrNone:
406        rtrn = siMatchText[1];
407        break;
408    case XkbSI_AnyOf:
409        rtrn = siMatchText[2];
410        break;
411    case XkbSI_AllOf:
412        rtrn = siMatchText[3];
413        break;
414    case XkbSI_Exactly:
415        rtrn = siMatchText[4];
416        break;
417    default:
418        snprintf(buf, sizeof(buf), "0x%x", type & XkbSI_OpMask);
419        return buf;
420    }
421    if (format == XkbCFile) {
422        if (type & XkbSI_LevelOneOnly)
423            snprintf(buf, sizeof(buf), "XkbSI_LevelOneOnly|XkbSI_%s", rtrn);
424        else
425            snprintf(buf, sizeof(buf), "XkbSI_%s", rtrn);
426        rtrn = buf;
427    }
428    return rtrn;
429}
430
431/***====================================================================***/
432
433static const char *imWhichNames[] = {
434    "base",
435    "latched",
436    "locked",
437    "effective",
438    "compat"
439};
440
441char *
442XkbIMWhichStateMaskText(unsigned use_which, unsigned format)
443{
444    int len;
445    unsigned i, bit, tmp;
446    char *buf;
447
448    if (use_which == 0) {
449        buf = tbGetBuffer(2);
450        strcpy(buf, "0");
451        return buf;
452    }
453    tmp = use_which & XkbIM_UseAnyMods;
454    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
455        if (tmp & bit) {
456            tmp &= ~bit;
457            len += strlen(imWhichNames[i]) + 1;
458            if (format == XkbCFile)
459                len += 9;
460        }
461    }
462    buf = tbGetBuffer(len + 1);
463    tmp = use_which & XkbIM_UseAnyMods;
464    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
465        if (tmp & bit) {
466            tmp &= ~bit;
467            if (format == XkbCFile) {
468                if (len != 0)
469                    buf[len++] = '|';
470                sprintf(&buf[len], "XkbIM_Use%s", imWhichNames[i]);
471                buf[len + 9] = toupper(buf[len + 9]);
472            }
473            else {
474                if (len != 0)
475                    buf[len++] = '+';
476                sprintf(&buf[len], "%s", imWhichNames[i]);
477            }
478            len += strlen(&buf[len]);
479        }
480    }
481    return buf;
482}
483
484static const char *ctrlNames[] = {
485    "repeatKeys",
486    "slowKeys",
487    "bounceKeys",
488    "stickyKeys",
489    "mouseKeys",
490    "mouseKeysAccel",
491    "accessXKeys",
492    "accessXTimeout",
493    "accessXFeedback",
494    "audibleBell",
495    "overlay1",
496    "overlay2",
497    "ignoreGroupLock"
498};
499
500char *
501XkbControlsMaskText(unsigned ctrls, unsigned format)
502{
503    int len;
504    unsigned i, bit, tmp;
505    char *buf;
506
507    if (ctrls == 0) {
508        buf = tbGetBuffer(5);
509        if (format == XkbCFile)
510            strcpy(buf, "0");
511        else
512            strcpy(buf, "none");
513        return buf;
514    }
515    tmp = ctrls & XkbAllBooleanCtrlsMask;
516    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
517        if (tmp & bit) {
518            tmp &= ~bit;
519            len += strlen(ctrlNames[i]) + 1;
520            if (format == XkbCFile)
521                len += 7;
522        }
523    }
524    buf = tbGetBuffer(len + 1);
525    tmp = ctrls & XkbAllBooleanCtrlsMask;
526    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
527        if (tmp & bit) {
528            tmp &= ~bit;
529            if (format == XkbCFile) {
530                if (len != 0)
531                    buf[len++] = '|';
532                sprintf(&buf[len], "Xkb%sMask", ctrlNames[i]);
533                buf[len + 3] = toupper(buf[len + 3]);
534            }
535            else {
536                if (len != 0)
537                    buf[len++] = '+';
538                sprintf(&buf[len], "%s", ctrlNames[i]);
539            }
540            len += strlen(&buf[len]);
541        }
542    }
543    return buf;
544}
545
546/***====================================================================***/
547
548char *
549XkbStringText(char *str, unsigned format)
550{
551    char *buf;
552    register char *in, *out;
553    int len;
554    Bool ok;
555
556    if (str == NULL) {
557        buf = tbGetBuffer(2);
558        buf[0] = '\0';
559        return buf;
560    }
561    else if (format == XkbXKMFile)
562        return str;
563    for (ok = TRUE, len = 0, in = str; *in != '\0'; in++, len++) {
564        if (!isprint(*in)) {
565            ok = FALSE;
566            switch (*in) {
567            case '\n':
568            case '\t':
569            case '\v':
570            case '\b':
571            case '\r':
572            case '\f':
573                len++;
574                break;
575            default:
576                len += 4;
577                break;
578            }
579        }
580    }
581    if (ok)
582        return str;
583    buf = tbGetBuffer(len + 1);
584    for (in = str, out = buf; *in != '\0'; in++) {
585        if (isprint(*in))
586            *out++ = *in;
587        else {
588            *out++ = '\\';
589            if (*in == '\n')
590                *out++ = 'n';
591            else if (*in == '\t')
592                *out++ = 't';
593            else if (*in == '\v')
594                *out++ = 'v';
595            else if (*in == '\b')
596                *out++ = 'b';
597            else if (*in == '\r')
598                *out++ = 'r';
599            else if (*in == '\f')
600                *out++ = 'f';
601            else if ((*in == '\033') && (format == XkbXKMFile)) {
602                *out++ = 'e';
603            }
604            else {
605                *out++ = '0';
606                sprintf(out, "%o", (unsigned char) *in);
607                while (*out != '\0')
608                    out++;
609            }
610        }
611    }
612    *out++ = '\0';
613    return buf;
614}
615
616/***====================================================================***/
617
618char *
619XkbGeomFPText(int val, unsigned format)
620{
621    int whole, frac;
622    char *buf;
623
624    buf = tbGetBuffer(12);
625    if (format == XkbCFile) {
626        sprintf(buf, "%d", val);
627    }
628    else {
629        whole = val / XkbGeomPtsPerMM;
630        frac = val % XkbGeomPtsPerMM;
631        if (frac != 0)
632            sprintf(buf, "%d.%d", whole, frac);
633        else
634            sprintf(buf, "%d", whole);
635    }
636    return buf;
637}
638
639char *
640XkbDoodadTypeText(unsigned type, unsigned format)
641{
642    char *buf;
643
644    if (format == XkbCFile) {
645        buf = tbGetBuffer(24);
646        if (type == XkbOutlineDoodad)
647            strcpy(buf, "XkbOutlineDoodad");
648        else if (type == XkbSolidDoodad)
649            strcpy(buf, "XkbSolidDoodad");
650        else if (type == XkbTextDoodad)
651            strcpy(buf, "XkbTextDoodad");
652        else if (type == XkbIndicatorDoodad)
653            strcpy(buf, "XkbIndicatorDoodad");
654        else if (type == XkbLogoDoodad)
655            strcpy(buf, "XkbLogoDoodad");
656        else
657            sprintf(buf, "UnknownDoodad%d", type);
658    }
659    else {
660        buf = tbGetBuffer(12);
661        if (type == XkbOutlineDoodad)
662            strcpy(buf, "outline");
663        else if (type == XkbSolidDoodad)
664            strcpy(buf, "solid");
665        else if (type == XkbTextDoodad)
666            strcpy(buf, "text");
667        else if (type == XkbIndicatorDoodad)
668            strcpy(buf, "indicator");
669        else if (type == XkbLogoDoodad)
670            strcpy(buf, "logo");
671        else
672            sprintf(buf, "unknown%d", type);
673    }
674    return buf;
675}
676
677static const char *actionTypeNames[XkbSA_NumActions] = {
678    "NoAction",
679    "SetMods", "LatchMods", "LockMods",
680    "SetGroup", "LatchGroup", "LockGroup",
681    "MovePtr",
682    "PtrBtn", "LockPtrBtn",
683    "SetPtrDflt",
684    "ISOLock",
685    "Terminate", "SwitchScreen",
686    "SetControls", "LockControls",
687    "ActionMessage",
688    "RedirectKey",
689    "DeviceBtn", "LockDeviceBtn"
690};
691
692const char *
693XkbActionTypeText(unsigned type, unsigned format)
694{
695    static char buf[32];
696    const char *rtrn;
697
698    if (type <= XkbSA_LastAction) {
699        rtrn = actionTypeNames[type];
700        if (format == XkbCFile) {
701            snprintf(buf, sizeof(buf), "XkbSA_%s", rtrn);
702            return buf;
703        }
704        return rtrn;
705    }
706    snprintf(buf, sizeof(buf), "Private");
707    return buf;
708}
709
710/***====================================================================***/
711
712static int
713TryCopyStr(char *to, const char *from, int *pLeft)
714{
715    register int len;
716
717    if (*pLeft > 0) {
718        len = strlen(from);
719        if (len < ((*pLeft) - 3)) {
720            strcat(to, from);
721            *pLeft -= len;
722            return TRUE;
723        }
724    }
725    *pLeft = -1;
726    return FALSE;
727}
728
729 /*ARGSUSED*/ static Bool
730CopyNoActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
731{
732    return TRUE;
733}
734
735static Bool
736CopyModActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
737{
738    XkbModAction *act;
739    unsigned tmp;
740
741    act = &action->mods;
742    tmp = XkbModActionVMods(act);
743    TryCopyStr(buf, "modifiers=", sz);
744    if (act->flags & XkbSA_UseModMapMods)
745        TryCopyStr(buf, "modMapMods", sz);
746    else if (act->real_mods || tmp) {
747        TryCopyStr(buf,
748                   XkbVModMaskText(xkb, act->real_mods, tmp, XkbXKBFile), sz);
749    }
750    else
751        TryCopyStr(buf, "none", sz);
752    if (act->type == XkbSA_LockMods)
753        return TRUE;
754    if (act->flags & XkbSA_ClearLocks)
755        TryCopyStr(buf, ",clearLocks", sz);
756    if (act->flags & XkbSA_LatchToLock)
757        TryCopyStr(buf, ",latchToLock", sz);
758    return TRUE;
759}
760
761 /*ARGSUSED*/ static Bool
762CopyGroupActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
763{
764    XkbGroupAction *act;
765    char tbuf[32];
766
767    act = &action->group;
768    TryCopyStr(buf, "group=", sz);
769    if (act->flags & XkbSA_GroupAbsolute)
770        snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
771    else if (XkbSAGroup(act) < 0)
772        snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
773    else
774        snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
775    TryCopyStr(buf, tbuf, sz);
776    if (act->type == XkbSA_LockGroup)
777        return TRUE;
778    if (act->flags & XkbSA_ClearLocks)
779        TryCopyStr(buf, ",clearLocks", sz);
780    if (act->flags & XkbSA_LatchToLock)
781        TryCopyStr(buf, ",latchToLock", sz);
782    return TRUE;
783}
784
785 /*ARGSUSED*/ static Bool
786CopyMovePtrArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
787{
788    XkbPtrAction *act;
789    int x, y;
790    char tbuf[32];
791
792    act = &action->ptr;
793    x = XkbPtrActionX(act);
794    y = XkbPtrActionY(act);
795    if ((act->flags & XkbSA_MoveAbsoluteX) || (x < 0))
796        snprintf(tbuf, sizeof(tbuf), "x=%d", x);
797    else
798        snprintf(tbuf, sizeof(tbuf), "x=+%d", x);
799    TryCopyStr(buf, tbuf, sz);
800
801    if ((act->flags & XkbSA_MoveAbsoluteY) || (y < 0))
802        snprintf(tbuf, sizeof(tbuf), ",y=%d", y);
803    else
804        snprintf(tbuf, sizeof(tbuf), ",y=+%d", y);
805    TryCopyStr(buf, tbuf, sz);
806    if (act->flags & XkbSA_NoAcceleration)
807        TryCopyStr(buf, ",!accel", sz);
808    return TRUE;
809}
810
811 /*ARGSUSED*/ static Bool
812CopyPtrBtnArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
813{
814    XkbPtrBtnAction *act;
815    char tbuf[32];
816
817    act = &action->btn;
818    TryCopyStr(buf, "button=", sz);
819    if ((act->button > 0) && (act->button < 6)) {
820        snprintf(tbuf, sizeof(tbuf), "%d", act->button);
821        TryCopyStr(buf, tbuf, sz);
822    }
823    else
824        TryCopyStr(buf, "default", sz);
825    if (act->count > 0) {
826        snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
827        TryCopyStr(buf, tbuf, sz);
828    }
829    if (action->type == XkbSA_LockPtrBtn) {
830        switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
831        case XkbSA_LockNoLock:
832            TryCopyStr(buf, ",affect=unlock", sz);
833            break;
834        case XkbSA_LockNoUnlock:
835            TryCopyStr(buf, ",affect=lock", sz);
836            break;
837        case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
838            TryCopyStr(buf, ",affect=neither", sz);
839            break;
840        default:
841            TryCopyStr(buf, ",affect=both", sz);
842            break;
843        }
844    }
845    return TRUE;
846}
847
848 /*ARGSUSED*/ static Bool
849CopySetPtrDfltArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
850{
851    XkbPtrDfltAction *act;
852    char tbuf[32];
853
854    act = &action->dflt;
855    if (act->affect == XkbSA_AffectDfltBtn) {
856        TryCopyStr(buf, "affect=button,button=", sz);
857        if ((act->flags & XkbSA_DfltBtnAbsolute) ||
858            (XkbSAPtrDfltValue(act) < 0))
859            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAPtrDfltValue(act));
860        else
861            snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAPtrDfltValue(act));
862        TryCopyStr(buf, tbuf, sz);
863    }
864    return TRUE;
865}
866
867static Bool
868CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
869{
870    XkbISOAction *act;
871    char tbuf[64];
872
873    memset(tbuf, 0, sizeof(tbuf));
874    act = &action->iso;
875    if (act->flags & XkbSA_ISODfltIsGroup) {
876        TryCopyStr(tbuf, "group=", sz);
877        if (act->flags & XkbSA_GroupAbsolute)
878            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
879        else if (XkbSAGroup(act) < 0)
880            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
881        else
882            snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
883        TryCopyStr(buf, tbuf, sz);
884    }
885    else {
886        unsigned tmp;
887
888        tmp = XkbModActionVMods(act);
889        TryCopyStr(buf, "modifiers=", sz);
890        if (act->flags & XkbSA_UseModMapMods)
891            TryCopyStr(buf, "modMapMods", sz);
892        else if (act->real_mods || tmp) {
893            if (act->real_mods) {
894                TryCopyStr(buf, XkbModMaskText(act->real_mods, XkbXKBFile), sz);
895                if (tmp)
896                    TryCopyStr(buf, "+", sz);
897            }
898            if (tmp)
899                TryCopyStr(buf, XkbVModMaskText(xkb, 0, tmp, XkbXKBFile), sz);
900        }
901        else
902            TryCopyStr(buf, "none", sz);
903    }
904    TryCopyStr(buf, ",affect=", sz);
905    if ((act->affect & XkbSA_ISOAffectMask) == 0)
906        TryCopyStr(buf, "all", sz);
907    else {
908        int nOut = 0;
909
910        if ((act->affect & XkbSA_ISONoAffectMods) == 0) {
911            TryCopyStr(buf, "mods", sz);
912            nOut++;
913        }
914        if ((act->affect & XkbSA_ISONoAffectGroup) == 0) {
915            snprintf(tbuf, sizeof(tbuf), "%sgroups", (nOut > 0 ? "+" : ""));
916            TryCopyStr(buf, tbuf, sz);
917            nOut++;
918        }
919        if ((act->affect & XkbSA_ISONoAffectPtr) == 0) {
920            snprintf(tbuf, sizeof(tbuf), "%spointer", (nOut > 0 ? "+" : ""));
921            TryCopyStr(buf, tbuf, sz);
922            nOut++;
923        }
924        if ((act->affect & XkbSA_ISONoAffectCtrls) == 0) {
925            snprintf(tbuf, sizeof(tbuf), "%scontrols", (nOut > 0 ? "+" : ""));
926            TryCopyStr(buf, tbuf, sz);
927            nOut++;
928        }
929    }
930    return TRUE;
931}
932
933 /*ARGSUSED*/ static Bool
934CopySwitchScreenArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
935{
936    XkbSwitchScreenAction *act;
937    char tbuf[32];
938
939    act = &action->screen;
940    if ((act->flags & XkbSA_SwitchAbsolute) || (XkbSAScreen(act) < 0))
941        snprintf(tbuf, sizeof(tbuf), "screen=%d", XkbSAScreen(act));
942    else
943        snprintf(tbuf, sizeof(tbuf), "screen=+%d", XkbSAScreen(act));
944    TryCopyStr(buf, tbuf, sz);
945    if (act->flags & XkbSA_SwitchApplication)
946        TryCopyStr(buf, ",!same", sz);
947    else
948        TryCopyStr(buf, ",same", sz);
949    return TRUE;
950}
951
952 /*ARGSUSED*/ static Bool
953CopySetLockControlsArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
954{
955    XkbCtrlsAction *act;
956    unsigned tmp;
957    char tbuf[32];
958
959    act = &action->ctrls;
960    tmp = XkbActionCtrls(act);
961    TryCopyStr(buf, "controls=", sz);
962    if (tmp == 0)
963        TryCopyStr(buf, "none", sz);
964    else if ((tmp & XkbAllBooleanCtrlsMask) == XkbAllBooleanCtrlsMask)
965        TryCopyStr(buf, "all", sz);
966    else {
967        int nOut = 0;
968
969        if (tmp & XkbRepeatKeysMask) {
970            snprintf(tbuf, sizeof(tbuf), "%sRepeatKeys", (nOut > 0 ? "+" : ""));
971            TryCopyStr(buf, tbuf, sz);
972            nOut++;
973        }
974        if (tmp & XkbSlowKeysMask) {
975            snprintf(tbuf, sizeof(tbuf), "%sSlowKeys", (nOut > 0 ? "+" : ""));
976            TryCopyStr(buf, tbuf, sz);
977            nOut++;
978        }
979        if (tmp & XkbBounceKeysMask) {
980            snprintf(tbuf, sizeof(tbuf), "%sBounceKeys", (nOut > 0 ? "+" : ""));
981            TryCopyStr(buf, tbuf, sz);
982            nOut++;
983        }
984        if (tmp & XkbStickyKeysMask) {
985            snprintf(tbuf, sizeof(tbuf), "%sStickyKeys", (nOut > 0 ? "+" : ""));
986            TryCopyStr(buf, tbuf, sz);
987            nOut++;
988        }
989        if (tmp & XkbMouseKeysMask) {
990            snprintf(tbuf, sizeof(tbuf), "%sMouseKeys", (nOut > 0 ? "+" : ""));
991            TryCopyStr(buf, tbuf, sz);
992            nOut++;
993        }
994        if (tmp & XkbMouseKeysAccelMask) {
995            snprintf(tbuf, sizeof(tbuf), "%sMouseKeysAccel",
996                     (nOut > 0 ? "+" : ""));
997            TryCopyStr(buf, tbuf, sz);
998            nOut++;
999        }
1000        if (tmp & XkbAccessXKeysMask) {
1001            snprintf(tbuf, sizeof(tbuf), "%sAccessXKeys",
1002                     (nOut > 0 ? "+" : ""));
1003            TryCopyStr(buf, tbuf, sz);
1004            nOut++;
1005        }
1006        if (tmp & XkbAccessXTimeoutMask) {
1007            snprintf(tbuf, sizeof(tbuf), "%sAccessXTimeout",
1008                     (nOut > 0 ? "+" : ""));
1009            TryCopyStr(buf, tbuf, sz);
1010            nOut++;
1011        }
1012        if (tmp & XkbAccessXFeedbackMask) {
1013            snprintf(tbuf, sizeof(tbuf), "%sAccessXFeedback",
1014                     (nOut > 0 ? "+" : ""));
1015            TryCopyStr(buf, tbuf, sz);
1016            nOut++;
1017        }
1018        if (tmp & XkbAudibleBellMask) {
1019            snprintf(tbuf, sizeof(tbuf), "%sAudibleBell",
1020                     (nOut > 0 ? "+" : ""));
1021            TryCopyStr(buf, tbuf, sz);
1022            nOut++;
1023        }
1024        if (tmp & XkbOverlay1Mask) {
1025            snprintf(tbuf, sizeof(tbuf), "%sOverlay1", (nOut > 0 ? "+" : ""));
1026            TryCopyStr(buf, tbuf, sz);
1027            nOut++;
1028        }
1029        if (tmp & XkbOverlay2Mask) {
1030            snprintf(tbuf, sizeof(tbuf), "%sOverlay2", (nOut > 0 ? "+" : ""));
1031            TryCopyStr(buf, tbuf, sz);
1032            nOut++;
1033        }
1034        if (tmp & XkbIgnoreGroupLockMask) {
1035            snprintf(tbuf, sizeof(tbuf), "%sIgnoreGroupLock",
1036                     (nOut > 0 ? "+" : ""));
1037            TryCopyStr(buf, tbuf, sz);
1038            nOut++;
1039        }
1040    }
1041    return TRUE;
1042}
1043
1044 /*ARGSUSED*/ static Bool
1045CopyActionMessageArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1046{
1047    XkbMessageAction *act;
1048    unsigned all;
1049    char tbuf[32];
1050
1051    act = &action->msg;
1052    all = XkbSA_MessageOnPress | XkbSA_MessageOnRelease;
1053    TryCopyStr(buf, "report=", sz);
1054    if ((act->flags & all) == 0)
1055        TryCopyStr(buf, "none", sz);
1056    else if ((act->flags & all) == all)
1057        TryCopyStr(buf, "all", sz);
1058    else if (act->flags & XkbSA_MessageOnPress)
1059        TryCopyStr(buf, "KeyPress", sz);
1060    else
1061        TryCopyStr(buf, "KeyRelease", sz);
1062    snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->message[0]);
1063    TryCopyStr(buf, tbuf, sz);
1064    snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->message[1]);
1065    TryCopyStr(buf, tbuf, sz);
1066    snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->message[2]);
1067    TryCopyStr(buf, tbuf, sz);
1068    snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->message[3]);
1069    TryCopyStr(buf, tbuf, sz);
1070    snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->message[4]);
1071    TryCopyStr(buf, tbuf, sz);
1072    snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->message[5]);
1073    TryCopyStr(buf, tbuf, sz);
1074    return TRUE;
1075}
1076
1077static Bool
1078CopyRedirectKeyArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1079{
1080    XkbRedirectKeyAction *act;
1081    char tbuf[32], *tmp;
1082    unsigned kc;
1083    unsigned vmods, vmods_mask;
1084
1085    act = &action->redirect;
1086    kc = act->new_key;
1087    vmods = XkbSARedirectVMods(act);
1088    vmods_mask = XkbSARedirectVModsMask(act);
1089    if (xkb && xkb->names && xkb->names->keys && (kc <= xkb->max_key_code) &&
1090        (xkb->names->keys[kc].name[0] != '\0')) {
1091        char *kn;
1092
1093        kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1094        snprintf(tbuf, sizeof(tbuf), "key=%s", kn);
1095    }
1096    else
1097        snprintf(tbuf, sizeof(tbuf), "key=%d", kc);
1098    TryCopyStr(buf, tbuf, sz);
1099    if ((act->mods_mask == 0) && (vmods_mask == 0))
1100        return TRUE;
1101    if ((act->mods_mask == XkbAllModifiersMask) &&
1102        (vmods_mask == XkbAllVirtualModsMask)) {
1103        tmp = XkbVModMaskText(xkb, act->mods, vmods, XkbXKBFile);
1104        TryCopyStr(buf, ",mods=", sz);
1105        TryCopyStr(buf, tmp, sz);
1106    }
1107    else {
1108        if ((act->mods_mask & act->mods) || (vmods_mask & vmods)) {
1109            tmp = XkbVModMaskText(xkb, act->mods_mask & act->mods,
1110                                  vmods_mask & vmods, XkbXKBFile);
1111            TryCopyStr(buf, ",mods= ", sz);
1112            TryCopyStr(buf, tmp, sz);
1113        }
1114        if ((act->mods_mask & (~act->mods)) || (vmods_mask & (~vmods))) {
1115            tmp = XkbVModMaskText(xkb, act->mods_mask & (~act->mods),
1116                                  vmods_mask & (~vmods), XkbXKBFile);
1117            TryCopyStr(buf, ",clearMods= ", sz);
1118            TryCopyStr(buf, tmp, sz);
1119        }
1120    }
1121    return TRUE;
1122}
1123
1124 /*ARGSUSED*/ static Bool
1125CopyDeviceBtnArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1126{
1127    XkbDeviceBtnAction *act;
1128    char tbuf[32];
1129
1130    act = &action->devbtn;
1131    snprintf(tbuf, sizeof(tbuf), "device= %d", act->device);
1132    TryCopyStr(buf, tbuf, sz);
1133    TryCopyStr(buf, ",button=", sz);
1134    snprintf(tbuf, sizeof(tbuf), "%d", act->button);
1135    TryCopyStr(buf, tbuf, sz);
1136    if (act->count > 0) {
1137        snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
1138        TryCopyStr(buf, tbuf, sz);
1139    }
1140    if (action->type == XkbSA_LockDeviceBtn) {
1141        switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
1142        case XkbSA_LockNoLock:
1143            TryCopyStr(buf, ",affect=unlock", sz);
1144            break;
1145        case XkbSA_LockNoUnlock:
1146            TryCopyStr(buf, ",affect=lock", sz);
1147            break;
1148        case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1149            TryCopyStr(buf, ",affect=neither", sz);
1150            break;
1151        default:
1152            TryCopyStr(buf, ",affect=both", sz);
1153            break;
1154        }
1155    }
1156    return TRUE;
1157}
1158
1159 /*ARGSUSED*/ static Bool
1160CopyOtherArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1161{
1162    XkbAnyAction *act;
1163    char tbuf[32];
1164
1165    act = &action->any;
1166    snprintf(tbuf, sizeof(tbuf), "type=0x%02x", act->type);
1167    TryCopyStr(buf, tbuf, sz);
1168    snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->data[0]);
1169    TryCopyStr(buf, tbuf, sz);
1170    snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->data[1]);
1171    TryCopyStr(buf, tbuf, sz);
1172    snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->data[2]);
1173    TryCopyStr(buf, tbuf, sz);
1174    snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->data[3]);
1175    TryCopyStr(buf, tbuf, sz);
1176    snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->data[4]);
1177    TryCopyStr(buf, tbuf, sz);
1178    snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->data[5]);
1179    TryCopyStr(buf, tbuf, sz);
1180    snprintf(tbuf, sizeof(tbuf), ",data[6]=0x%02x", act->data[6]);
1181    TryCopyStr(buf, tbuf, sz);
1182    return TRUE;
1183}
1184
1185typedef Bool (*actionCopy) (XkbDescPtr /* xkb */ ,
1186                            XkbAction * /* action */ ,
1187                            char * /* buf */ ,
1188                            int *       /* sz */
1189    );
1190
1191static actionCopy copyActionArgs[XkbSA_NumActions] = {
1192    CopyNoActionArgs /* NoAction     */ ,
1193    CopyModActionArgs /* SetMods      */ ,
1194    CopyModActionArgs /* LatchMods    */ ,
1195    CopyModActionArgs /* LockMods     */ ,
1196    CopyGroupActionArgs /* SetGroup     */ ,
1197    CopyGroupActionArgs /* LatchGroup   */ ,
1198    CopyGroupActionArgs /* LockGroup    */ ,
1199    CopyMovePtrArgs /* MovePtr      */ ,
1200    CopyPtrBtnArgs /* PtrBtn       */ ,
1201    CopyPtrBtnArgs /* LockPtrBtn   */ ,
1202    CopySetPtrDfltArgs /* SetPtrDflt   */ ,
1203    CopyISOLockArgs /* ISOLock      */ ,
1204    CopyNoActionArgs /* Terminate    */ ,
1205    CopySwitchScreenArgs /* SwitchScreen */ ,
1206    CopySetLockControlsArgs /* SetControls  */ ,
1207    CopySetLockControlsArgs /* LockControls */ ,
1208    CopyActionMessageArgs /* ActionMessage */ ,
1209    CopyRedirectKeyArgs /* RedirectKey  */ ,
1210    CopyDeviceBtnArgs /* DeviceBtn    */ ,
1211    CopyDeviceBtnArgs           /* LockDeviceBtn */
1212};
1213
1214#define	ACTION_SZ	256
1215
1216char *
1217XkbActionText(XkbDescPtr xkb, XkbAction *action, unsigned format)
1218{
1219    char buf[ACTION_SZ], *tmp;
1220    int sz;
1221
1222    if (format == XkbCFile) {
1223        snprintf(buf, sizeof(buf),
1224                 "{ %20s, { 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x } }",
1225                 XkbActionTypeText(action->type, XkbCFile),
1226                 action->any.data[0], action->any.data[1], action->any.data[2],
1227                 action->any.data[3], action->any.data[4], action->any.data[5],
1228                 action->any.data[6]);
1229    }
1230    else {
1231        snprintf(buf, sizeof(buf), "%s(",
1232                 XkbActionTypeText(action->type, XkbXKBFile));
1233        sz = ACTION_SZ - strlen(buf) + 2;       /* room for close paren and NULL */
1234        if (action->type < (unsigned) XkbSA_NumActions)
1235            (*copyActionArgs[action->type]) (xkb, action, buf, &sz);
1236        else
1237            CopyOtherArgs(xkb, action, buf, &sz);
1238        TryCopyStr(buf, ")", &sz);
1239    }
1240    tmp = tbGetBuffer(strlen(buf) + 1);
1241    if (tmp != NULL)
1242        strcpy(tmp, buf);
1243    return tmp;
1244}
1245
1246char *
1247XkbBehaviorText(XkbDescPtr xkb, XkbBehavior * behavior, unsigned format)
1248{
1249    char buf[256], *tmp;
1250
1251    if (format == XkbCFile) {
1252        if (behavior->type == XkbKB_Default)
1253            snprintf(buf, sizeof(buf), "{   0,    0 }");
1254        else
1255            snprintf(buf, sizeof(buf), "{ %3d, 0x%02x }", behavior->type,
1256                     behavior->data);
1257    }
1258    else {
1259        unsigned type, permanent;
1260
1261        type = behavior->type & XkbKB_OpMask;
1262        permanent = ((behavior->type & XkbKB_Permanent) != 0);
1263
1264        if (type == XkbKB_Lock) {
1265            snprintf(buf, sizeof(buf), "lock= %s",
1266                     (permanent ? "Permanent" : "TRUE"));
1267        }
1268        else if (type == XkbKB_RadioGroup) {
1269            int g;
1270
1271            g = ((behavior->data) & (~XkbKB_RGAllowNone)) + 1;
1272            if (XkbKB_RGAllowNone & behavior->data) {
1273                snprintf(buf, sizeof(buf), "allowNone,");
1274                tmp = &buf[strlen(buf)];
1275            }
1276            else
1277                tmp = buf;
1278            if (permanent)
1279                sprintf(tmp, "permanentRadioGroup= %d", g);
1280            else
1281                sprintf(tmp, "radioGroup= %d", g);
1282        }
1283        else if ((type == XkbKB_Overlay1) || (type == XkbKB_Overlay2)) {
1284            int ndx, kc;
1285            char *kn;
1286
1287            ndx = ((type == XkbKB_Overlay1) ? 1 : 2);
1288            kc = behavior->data;
1289            if ((xkb) && (xkb->names) && (xkb->names->keys))
1290                kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1291            else {
1292                static char tbuf[8];
1293
1294                snprintf(tbuf, sizeof(tbuf), "%d", kc);
1295                kn = tbuf;
1296            }
1297            if (permanent)
1298                snprintf(buf, sizeof(buf), "permanentOverlay%d= %s", ndx, kn);
1299            else
1300                snprintf(buf, sizeof(buf), "overlay%d= %s", ndx, kn);
1301        }
1302    }
1303    tmp = tbGetBuffer(strlen(buf) + 1);
1304    if (tmp != NULL)
1305        strcpy(tmp, buf);
1306    return tmp;
1307}
1308
1309/***====================================================================***/
1310
1311char *
1312XkbIndentText(unsigned size)
1313{
1314    static char buf[32];
1315    register int i;
1316
1317    if (size > 31)
1318        size = 31;
1319
1320    for (i = 0; i < size; i++) {
1321        buf[i] = ' ';
1322    }
1323    buf[size] = '\0';
1324    return buf;
1325}
1326