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