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