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 
52 static char textBuffer[BUFFER_SIZE];
53 static int tbNext = 0;
54 
55 static char *
tbGetBuffer(unsigned size)56 tbGetBuffer(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 
71 char *
XkbAtomText(Display * dpy,Atom atm,unsigned format)72 XkbAtomText(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 
105 char *
XkbVModIndexText(Display * dpy,XkbDescPtr xkb,unsigned ndx,unsigned format)106 XkbVModIndexText(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 
142 char *
XkbVModMaskText(Display * dpy,XkbDescPtr xkb,unsigned modMask,unsigned mask,unsigned format)143 XkbVModMaskText(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 
232 static const char *modNames[XkbNumModifiers] = {
233     "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5"
234 };
235 
236 char *
XkbModIndexText(unsigned ndx,unsigned format)237 XkbModIndexText(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 
263 char *
XkbModMaskText(unsigned mask,unsigned format)264 XkbModMaskText(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*/
310 char *
XkbConfigText(unsigned config,unsigned format)311 XkbConfigText(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 
358 char *
XkbKeysymText(KeySym sym,unsigned format)359 XkbKeysymText(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 
376 char *
XkbKeyNameText(char * name,unsigned format)377 XkbKeyNameText(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 
402 static char *siMatchText[5] = {
403     "NoneOf", "AnyOfOrNone", "AnyOf", "AllOf", "Exactly"
404 };
405 
406 char *
XkbSIMatchText(unsigned type,unsigned format)407 XkbSIMatchText(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 
435 static const char *imWhichNames[] = {
436     "base",
437     "latched",
438     "locked",
439     "effective",
440     "compat"
441 };
442 
443 char *
XkbIMWhichStateMaskText(unsigned use_which,unsigned format)444 XkbIMWhichStateMaskText(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 
489 char *
XkbAccessXDetailText(unsigned state,unsigned format)490 XkbAccessXDetailText(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 
530 static const char *nknNames[] = {
531     "keycodes", "geometry", "deviceID"
532 };
533 #define	NUM_NKN	(sizeof(nknNames)/sizeof(char *))
534 
535 char *
XkbNKNDetailMaskText(unsigned detail,unsigned format)536 XkbNKNDetailMaskText(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 
614 static 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 
630 char *
XkbControlsMaskText(unsigned ctrls,unsigned format)631 XkbControlsMaskText(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 
678 char *
XkbStringText(char * str,unsigned format)679 XkbStringText(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 
748 char *
XkbGeomFPText(int val,unsigned format)749 XkbGeomFPText(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 = abs(val % XkbGeomPtsPerMM);
762         if (frac != 0) {
763             if (val < 0)
764             {
765                 int wholeabs;
766                 wholeabs = abs(whole);
767                 snprintf(buf, bufsize, "-%d.%d", wholeabs, frac);
768             }
769             else
770                 snprintf(buf, bufsize, "%d.%d", whole, frac);
771         }
772         else
773             snprintf(buf, bufsize, "%d", whole);
774     }
775     return buf;
776 }
777 
778 char *
XkbDoodadTypeText(unsigned type,unsigned format)779 XkbDoodadTypeText(unsigned type, unsigned format)
780 {
781     char *buf;
782 
783     if (format == XkbCFile) {
784         const int bufsize = 24;
785         buf = tbGetBuffer(bufsize);
786         if (type == XkbOutlineDoodad)
787             strcpy(buf, "XkbOutlineDoodad");
788         else if (type == XkbSolidDoodad)
789             strcpy(buf, "XkbSolidDoodad");
790         else if (type == XkbTextDoodad)
791             strcpy(buf, "XkbTextDoodad");
792         else if (type == XkbIndicatorDoodad)
793             strcpy(buf, "XkbIndicatorDoodad");
794         else if (type == XkbLogoDoodad)
795             strcpy(buf, "XkbLogoDoodad");
796         else
797             snprintf(buf, bufsize, "UnknownDoodad%d", type);
798     }
799     else {
800         const int bufsize = 12;
801         buf = tbGetBuffer(bufsize);
802         if (type == XkbOutlineDoodad)
803             strcpy(buf, "outline");
804         else if (type == XkbSolidDoodad)
805             strcpy(buf, "solid");
806         else if (type == XkbTextDoodad)
807             strcpy(buf, "text");
808         else if (type == XkbIndicatorDoodad)
809             strcpy(buf, "indicator");
810         else if (type == XkbLogoDoodad)
811             strcpy(buf, "logo");
812         else
813             snprintf(buf, bufsize, "unknown%d", type);
814     }
815     return buf;
816 }
817 
818 static char *actionTypeNames[XkbSA_NumActions] = {
819     "NoAction",
820     "SetMods",      "LatchMods",    "LockMods",
821     "SetGroup",     "LatchGroup",   "LockGroup",
822     "MovePtr",
823     "PtrBtn",       "LockPtrBtn",
824     "SetPtrDflt",
825     "ISOLock",
826     "Terminate",    "SwitchScreen",
827     "SetControls",  "LockControls",
828     "ActionMessage",
829     "RedirectKey",
830     "DeviceBtn",    "LockDeviceBtn"
831 };
832 
833 char *
XkbActionTypeText(unsigned type,unsigned format)834 XkbActionTypeText(unsigned type, unsigned format)
835 {
836     static char buf[32];
837     char *rtrn;
838 
839     if (type <= XkbSA_LastAction) {
840         rtrn = actionTypeNames[type];
841         if (format == XkbCFile) {
842             snprintf(buf, sizeof(buf), "XkbSA_%s", rtrn);
843             return buf;
844         }
845         return rtrn;
846     }
847     snprintf(buf, sizeof(buf), "Private");
848     return buf;
849 }
850 
851 /***====================================================================***/
852 
853 static int
TryCopyStr(char * to,const char * from,int * pLeft)854 TryCopyStr(char *to, const char *from, int *pLeft)
855 {
856     register int len;
857 
858     if (*pLeft > 0) {
859         len = strlen(from);
860         if (len < ((*pLeft) - 3)) {
861             strcat(to, from);
862             *pLeft -= len;
863             return True;
864         }
865     }
866     *pLeft = -1;
867     return False;
868 }
869 
870 /*ARGSUSED*/
871 static Bool
CopyNoActionArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)872 CopyNoActionArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
873                  char *buf, int *sz)
874 {
875     return True;
876 }
877 
878 static Bool
CopyModActionArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)879 CopyModActionArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
880                   char *buf, int *sz)
881 {
882     XkbModAction *act;
883     unsigned tmp;
884 
885     act = &action->mods;
886     tmp = XkbModActionVMods(act);
887     TryCopyStr(buf, "modifiers=", sz);
888     if (act->flags & XkbSA_UseModMapMods)
889         TryCopyStr(buf, "modMapMods", sz);
890     else if (act->real_mods || tmp) {
891         TryCopyStr(buf,
892                    XkbVModMaskText(dpy, xkb, act->real_mods, tmp, XkbXKBFile),
893                    sz);
894     }
895     else
896         TryCopyStr(buf, "none", sz);
897     if (act->type == XkbSA_LockMods) {
898         switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
899         case XkbSA_LockNoLock:
900             TryCopyStr(buf, ",affect=unlock", sz);
901             break;
902         case XkbSA_LockNoUnlock:
903             TryCopyStr(buf, ",affect=lock", sz);
904             break;
905         case XkbSA_LockNoUnlock|XkbSA_LockNoLock:
906             TryCopyStr(buf, ",affect=neither", sz);
907             break;
908         default:
909             break;
910         }
911         return True;
912     }
913     if (act->flags & XkbSA_ClearLocks)
914         TryCopyStr(buf, ",clearLocks", sz);
915     if (act->flags & XkbSA_LatchToLock)
916         TryCopyStr(buf, ",latchToLock", sz);
917     return True;
918 }
919 
920 /*ARGSUSED*/
921 static Bool
CopyGroupActionArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)922 CopyGroupActionArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
923                     char *buf, int *sz)
924 {
925     XkbGroupAction *act;
926     char tbuf[32];
927 
928     act = &action->group;
929     TryCopyStr(buf, "group=", sz);
930     if (act->flags & XkbSA_GroupAbsolute)
931         snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
932     else if (XkbSAGroup(act) < 0)
933         snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
934     else
935         snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
936     TryCopyStr(buf, tbuf, sz);
937     if (act->type == XkbSA_LockGroup)
938         return True;
939     if (act->flags & XkbSA_ClearLocks)
940         TryCopyStr(buf, ",clearLocks", sz);
941     if (act->flags & XkbSA_LatchToLock)
942         TryCopyStr(buf, ",latchToLock", sz);
943     return True;
944 }
945 
946 /*ARGSUSED*/
947 static Bool
CopyMovePtrArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)948 CopyMovePtrArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
949                 char *buf, int *sz)
950 {
951     XkbPtrAction *act;
952     int x, y;
953     char tbuf[32];
954 
955     act = &action->ptr;
956     x = XkbPtrActionX(act);
957     y = XkbPtrActionY(act);
958     if ((act->flags & XkbSA_MoveAbsoluteX) || (x < 0))
959         snprintf(tbuf, sizeof(tbuf), "x=%d", x);
960     else
961         snprintf(tbuf, sizeof(tbuf), "x=+%d", x);
962     TryCopyStr(buf, tbuf, sz);
963 
964     if ((act->flags & XkbSA_MoveAbsoluteY) || (y < 0))
965         snprintf(tbuf, sizeof(tbuf), ",y=%d", y);
966     else
967         snprintf(tbuf, sizeof(tbuf), ",y=+%d", y);
968     TryCopyStr(buf, tbuf, sz);
969     if (act->flags & XkbSA_NoAcceleration)
970         TryCopyStr(buf, ",!accel", sz);
971     return True;
972 }
973 
974 /*ARGSUSED*/
975 static Bool
CopyPtrBtnArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)976 CopyPtrBtnArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
977                char *buf, int *sz)
978 {
979     XkbPtrBtnAction *act;
980     char tbuf[32];
981 
982     act = &action->btn;
983     TryCopyStr(buf, "button=", sz);
984     if ((act->button > 0) && (act->button < 6)) {
985         snprintf(tbuf, sizeof(tbuf), "%d", act->button);
986         TryCopyStr(buf, tbuf, sz);
987     }
988     else
989         TryCopyStr(buf, "default", sz);
990     if (act->count > 0) {
991         snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
992         TryCopyStr(buf, tbuf, sz);
993     }
994     if (action->type == XkbSA_LockPtrBtn) {
995         switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
996         case XkbSA_LockNoLock:
997             snprintf(tbuf, sizeof(tbuf), ",affect=unlock");
998             break;
999         case XkbSA_LockNoUnlock:
1000             snprintf(tbuf, sizeof(tbuf), ",affect=lock");
1001             break;
1002         case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1003             snprintf(tbuf, sizeof(tbuf), ",affect=neither");
1004             break;
1005         default:
1006             snprintf(tbuf, sizeof(tbuf), ",affect=both");
1007             break;
1008         }
1009         TryCopyStr(buf, tbuf, sz);
1010     }
1011     return True;
1012 }
1013 
1014 /*ARGSUSED*/
1015 static Bool
CopySetPtrDfltArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1016 CopySetPtrDfltArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1017                    char *buf, int *sz)
1018 {
1019     XkbPtrDfltAction *act;
1020     char tbuf[32];
1021 
1022     act = &action->dflt;
1023     if (act->affect == XkbSA_AffectDfltBtn) {
1024         TryCopyStr(buf, "affect=button,button=", sz);
1025         if ((act->flags & XkbSA_DfltBtnAbsolute) ||
1026             (XkbSAPtrDfltValue(act) < 0))
1027             snprintf(tbuf, sizeof(tbuf), "%d", XkbSAPtrDfltValue(act));
1028         else
1029             snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAPtrDfltValue(act));
1030         TryCopyStr(buf, tbuf, sz);
1031     }
1032     return True;
1033 }
1034 
1035 static Bool
CopyISOLockArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1036 CopyISOLockArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1037                 char *buf, int *sz)
1038 {
1039     XkbISOAction *act;
1040     char tbuf[64];
1041 
1042     act = &action->iso;
1043     if (act->flags & XkbSA_ISODfltIsGroup) {
1044         TryCopyStr(tbuf, "group=", sz);
1045         if (act->flags & XkbSA_GroupAbsolute)
1046             snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
1047         else if (XkbSAGroup(act) < 0)
1048             snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
1049         else
1050             snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
1051         TryCopyStr(buf, tbuf, sz);
1052     }
1053     else {
1054         unsigned tmp;
1055 
1056         tmp = XkbModActionVMods(act);
1057         TryCopyStr(buf, "modifiers=", sz);
1058         if (act->flags & XkbSA_UseModMapMods)
1059             TryCopyStr(buf, "modMapMods", sz);
1060         else if (act->real_mods || tmp) {
1061             if (act->real_mods) {
1062                 TryCopyStr(buf, XkbModMaskText(act->real_mods, XkbXKBFile), sz);
1063                 if (tmp)
1064                     TryCopyStr(buf, "+", sz);
1065             }
1066             if (tmp)
1067                 TryCopyStr(buf, XkbVModMaskText(dpy, xkb, 0, tmp, XkbXKBFile),
1068                            sz);
1069         }
1070         else
1071             TryCopyStr(buf, "none", sz);
1072     }
1073     TryCopyStr(buf, ",affect=", sz);
1074     if ((act->affect & XkbSA_ISOAffectMask) == 0) {
1075         TryCopyStr(buf, "all", sz);
1076     }
1077     else if ((act->affect & XkbSA_ISOAffectMask) == XkbSA_ISOAffectMask) {
1078         TryCopyStr(buf, "none", sz);
1079     }
1080     else {
1081         int nOut = 0;
1082 
1083         if ((act->affect & XkbSA_ISONoAffectMods) == 0) {
1084             TryCopyStr(buf, "mods", sz);
1085             nOut++;
1086         }
1087         if ((act->affect & XkbSA_ISONoAffectGroup) == 0) {
1088             snprintf(tbuf, sizeof(tbuf), "%sgroups", (nOut > 0 ? "+" : ""));
1089             TryCopyStr(buf, tbuf, sz);
1090             nOut++;
1091         }
1092         if ((act->affect & XkbSA_ISONoAffectPtr) == 0) {
1093             snprintf(tbuf, sizeof(tbuf), "%spointer", (nOut > 0 ? "+" : ""));
1094             TryCopyStr(buf, tbuf, sz);
1095             nOut++;
1096         }
1097         if ((act->affect & XkbSA_ISONoAffectCtrls) == 0) {
1098             snprintf(tbuf, sizeof(tbuf), "%scontrols", (nOut > 0 ? "+" : ""));
1099             TryCopyStr(buf, tbuf, sz);
1100             nOut++;
1101         }
1102     }
1103     switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
1104     case XkbSA_LockNoLock:
1105         TryCopyStr(buf, "+unlock", sz);
1106         break;
1107     case XkbSA_LockNoUnlock:
1108         TryCopyStr(buf, "+lock", sz);
1109         break;
1110     case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1111         TryCopyStr(buf, "+neither", sz);
1112         break;
1113     default: ;
1114     }
1115     return True;
1116 }
1117 
1118 /*ARGSUSED*/
1119 static Bool
CopySwitchScreenArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1120 CopySwitchScreenArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1121                      char *buf, int *sz)
1122 {
1123     XkbSwitchScreenAction *act;
1124     char tbuf[32];
1125 
1126     act = &action->screen;
1127     if ((act->flags & XkbSA_SwitchAbsolute) || (XkbSAScreen(act) < 0))
1128         snprintf(tbuf, sizeof(tbuf), "screen=%d", XkbSAScreen(act));
1129     else
1130         snprintf(tbuf, sizeof(tbuf), "screen=+%d", XkbSAScreen(act));
1131     TryCopyStr(buf, tbuf, sz);
1132     if (act->flags & XkbSA_SwitchApplication)
1133         TryCopyStr(buf, ",!same", sz);
1134     else
1135         TryCopyStr(buf, ",same", sz);
1136     return True;
1137 }
1138 
1139 /*ARGSUSED*/
1140 static Bool
CopySetLockControlsArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1141 CopySetLockControlsArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1142                         char *buf, int *sz)
1143 {
1144     XkbCtrlsAction *act;
1145     unsigned tmp;
1146     char tbuf[32];
1147 
1148     act = &action->ctrls;
1149     tmp = XkbActionCtrls(act);
1150     TryCopyStr(buf, "controls=", sz);
1151     if (tmp == 0)
1152         TryCopyStr(buf, "none", sz);
1153     else if ((tmp & XkbAllBooleanCtrlsMask) == XkbAllBooleanCtrlsMask)
1154         TryCopyStr(buf, "all", sz);
1155     else {
1156         int nOut = 0;
1157 
1158         if (tmp & XkbRepeatKeysMask) {
1159             snprintf(tbuf, sizeof(tbuf), "%sRepeatKeys", (nOut > 0 ? "+" : ""));
1160             TryCopyStr(buf, tbuf, sz);
1161             nOut++;
1162         }
1163         if (tmp & XkbSlowKeysMask) {
1164             snprintf(tbuf, sizeof(tbuf), "%sSlowKeys", (nOut > 0 ? "+" : ""));
1165             TryCopyStr(buf, tbuf, sz);
1166             nOut++;
1167         }
1168         if (tmp & XkbBounceKeysMask) {
1169             snprintf(tbuf, sizeof(tbuf), "%sBounceKeys", (nOut > 0 ? "+" : ""));
1170             TryCopyStr(buf, tbuf, sz);
1171             nOut++;
1172         }
1173         if (tmp & XkbStickyKeysMask) {
1174             snprintf(tbuf, sizeof(tbuf), "%sStickyKeys", (nOut > 0 ? "+" : ""));
1175             TryCopyStr(buf, tbuf, sz);
1176             nOut++;
1177         }
1178         if (tmp & XkbMouseKeysMask) {
1179             snprintf(tbuf, sizeof(tbuf), "%sMouseKeys", (nOut > 0 ? "+" : ""));
1180             TryCopyStr(buf, tbuf, sz);
1181             nOut++;
1182         }
1183         if (tmp & XkbMouseKeysAccelMask) {
1184             snprintf(tbuf, sizeof(tbuf), "%sMouseKeysAccel", (nOut > 0 ? "+" : ""));
1185             TryCopyStr(buf, tbuf, sz);
1186             nOut++;
1187         }
1188         if (tmp & XkbAccessXKeysMask) {
1189             snprintf(tbuf, sizeof(tbuf), "%sAccessXKeys", (nOut > 0 ? "+" : ""));
1190             TryCopyStr(buf, tbuf, sz);
1191             nOut++;
1192         }
1193         if (tmp & XkbAccessXTimeoutMask) {
1194             snprintf(tbuf, sizeof(tbuf), "%sAccessXTimeout", (nOut > 0 ? "+" : ""));
1195             TryCopyStr(buf, tbuf, sz);
1196             nOut++;
1197         }
1198         if (tmp & XkbAccessXFeedbackMask) {
1199             snprintf(tbuf, sizeof(tbuf), "%sAccessXFeedback", (nOut > 0 ? "+" : ""));
1200             TryCopyStr(buf, tbuf, sz);
1201             nOut++;
1202         }
1203         if (tmp & XkbAudibleBellMask) {
1204             snprintf(tbuf, sizeof(tbuf), "%sAudibleBell", (nOut > 0 ? "+" : ""));
1205             TryCopyStr(buf, tbuf, sz);
1206             nOut++;
1207         }
1208         if (tmp & XkbOverlay1Mask) {
1209             snprintf(tbuf, sizeof(tbuf), "%sOverlay1", (nOut > 0 ? "+" : ""));
1210             TryCopyStr(buf, tbuf, sz);
1211             nOut++;
1212         }
1213         if (tmp & XkbOverlay2Mask) {
1214             snprintf(tbuf, sizeof(tbuf), "%sOverlay2", (nOut > 0 ? "+" : ""));
1215             TryCopyStr(buf, tbuf, sz);
1216             nOut++;
1217         }
1218         if (tmp & XkbIgnoreGroupLockMask) {
1219             snprintf(tbuf, sizeof(tbuf), "%sIgnoreGroupLock", (nOut > 0 ? "+" : ""));
1220             TryCopyStr(buf, tbuf, sz);
1221             nOut++;
1222         }
1223     }
1224     if (action->type == XkbSA_LockControls) {
1225         switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
1226         case XkbSA_LockNoLock:
1227             TryCopyStr(buf, ",affect=unlock", sz);
1228             break;
1229         case XkbSA_LockNoUnlock:
1230             TryCopyStr(buf, ",affect=lock", sz);
1231             break;
1232         case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1233             TryCopyStr(buf, ",affect=neither", sz);
1234             break;
1235         default: ;
1236         }
1237     }
1238     return True;
1239 }
1240 
1241 /*ARGSUSED*/
1242 static Bool
CopyActionMessageArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1243 CopyActionMessageArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1244                       char *buf, int *sz)
1245 {
1246     XkbMessageAction *act;
1247     unsigned all;
1248     char tbuf[32];
1249 
1250     act = &action->msg;
1251     all = XkbSA_MessageOnPress | XkbSA_MessageOnRelease;
1252     TryCopyStr(buf, "report=", sz);
1253     if ((act->flags & all) == 0)
1254         TryCopyStr(buf, "none", sz);
1255     else if ((act->flags & all) == all)
1256         TryCopyStr(buf, "all", sz);
1257     else if (act->flags & XkbSA_MessageOnPress)
1258         TryCopyStr(buf, "KeyPress", sz);
1259     else
1260         TryCopyStr(buf, "KeyRelease", sz);
1261     snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->message[0]);
1262     TryCopyStr(buf, tbuf, sz);
1263     snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->message[1]);
1264     TryCopyStr(buf, tbuf, sz);
1265     snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->message[2]);
1266     TryCopyStr(buf, tbuf, sz);
1267     snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->message[3]);
1268     TryCopyStr(buf, tbuf, sz);
1269     snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->message[4]);
1270     TryCopyStr(buf, tbuf, sz);
1271     snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->message[5]);
1272     TryCopyStr(buf, tbuf, sz);
1273     if (act->flags & XkbSA_MessageGenKeyEvent)
1274         TryCopyStr(buf, ",genKeyEvent", sz);
1275     return True;
1276 }
1277 
1278 static Bool
CopyRedirectKeyArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1279 CopyRedirectKeyArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1280                     char *buf, int *sz)
1281 {
1282     XkbRedirectKeyAction *act;
1283     char tbuf[32], *tmp;
1284     unsigned kc;
1285     unsigned vmods, vmods_mask;
1286 
1287     act = &action->redirect;
1288     kc = act->new_key;
1289     vmods = XkbSARedirectVMods(act);
1290     vmods_mask = XkbSARedirectVModsMask(act);
1291     if (xkb && xkb->names && xkb->names->keys && (kc <= xkb->max_key_code) &&
1292         (xkb->names->keys[kc].name[0] != '\0')) {
1293         char *kn;
1294 
1295         kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1296         snprintf(tbuf, sizeof(tbuf), "key=%s", kn);
1297     }
1298     else
1299         snprintf(tbuf, sizeof(tbuf), "key=%d", kc);
1300     TryCopyStr(buf, tbuf, sz);
1301     if ((act->mods_mask == 0) && (vmods_mask == 0))
1302         return True;
1303     if ((act->mods_mask == XkbAllModifiersMask) &&
1304         (vmods_mask == XkbAllVirtualModsMask)) {
1305         tmp = XkbVModMaskText(dpy, xkb, act->mods, vmods, XkbXKBFile);
1306         TryCopyStr(buf, ",mods=", sz);
1307         TryCopyStr(buf, tmp, sz);
1308     }
1309     else {
1310         if ((act->mods_mask & act->mods) || (vmods_mask & vmods)) {
1311             tmp = XkbVModMaskText(dpy, xkb, act->mods_mask & act->mods,
1312                                   vmods_mask & vmods, XkbXKBFile);
1313             TryCopyStr(buf, ",mods= ", sz);
1314             TryCopyStr(buf, tmp, sz);
1315         }
1316         if ((act->mods_mask & (~act->mods)) || (vmods_mask & (~vmods))) {
1317             tmp = XkbVModMaskText(dpy, xkb, act->mods_mask & (~act->mods),
1318                                   vmods_mask & (~vmods), XkbXKBFile);
1319             TryCopyStr(buf, ",clearMods= ", sz);
1320             TryCopyStr(buf, tmp, sz);
1321         }
1322     }
1323     return True;
1324 }
1325 
1326 /*ARGSUSED*/
1327 static Bool
CopyDeviceBtnArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1328 CopyDeviceBtnArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1329                   char *buf, int *sz)
1330 {
1331     XkbDeviceBtnAction *act;
1332     char tbuf[32];
1333 
1334     act = &action->devbtn;
1335     snprintf(tbuf, sizeof(tbuf), "device= %d", act->device);
1336     TryCopyStr(buf, tbuf, sz);
1337     TryCopyStr(buf, ",button=", sz);
1338     snprintf(tbuf, sizeof(tbuf), "%d", act->button);
1339     TryCopyStr(buf, tbuf, sz);
1340     if (act->count > 0) {
1341         snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
1342         TryCopyStr(buf, tbuf, sz);
1343     }
1344     if (action->type == XkbSA_LockDeviceBtn) {
1345         switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
1346         case XkbSA_LockNoLock:
1347             snprintf(tbuf, sizeof(tbuf), ",affect=unlock");
1348             break;
1349         case XkbSA_LockNoUnlock:
1350             snprintf(tbuf, sizeof(tbuf), ",affect=lock");
1351             break;
1352         case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1353             snprintf(tbuf, sizeof(tbuf), ",affect=neither");
1354             break;
1355         default:
1356             snprintf(tbuf, sizeof(tbuf), ",affect=both");
1357             break;
1358         }
1359         TryCopyStr(buf, tbuf, sz);
1360     }
1361     return True;
1362 }
1363 
1364 /*ARGSUSED*/
1365 static Bool
CopyOtherArgs(Display * dpy,XkbDescPtr xkb,XkbAction * action,char * buf,int * sz)1366 CopyOtherArgs(Display *dpy, XkbDescPtr xkb, XkbAction *action,
1367               char *buf, int *sz)
1368 {
1369     XkbAnyAction *act;
1370     char tbuf[32];
1371 
1372     act = &action->any;
1373     snprintf(tbuf, sizeof(tbuf), "type=0x%02x", act->type);
1374     TryCopyStr(buf, tbuf, sz);
1375     snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->data[0]);
1376     TryCopyStr(buf, tbuf, sz);
1377     snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->data[1]);
1378     TryCopyStr(buf, tbuf, sz);
1379     snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->data[2]);
1380     TryCopyStr(buf, tbuf, sz);
1381     snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->data[3]);
1382     TryCopyStr(buf, tbuf, sz);
1383     snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->data[4]);
1384     TryCopyStr(buf, tbuf, sz);
1385     snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->data[5]);
1386     TryCopyStr(buf, tbuf, sz);
1387     snprintf(tbuf, sizeof(tbuf), ",data[6]=0x%02x", act->data[6]);
1388     TryCopyStr(buf, tbuf, sz);
1389     return True;
1390 }
1391 
1392 typedef Bool (*actionCopy) (Display *   /* dpy */ ,
1393                             XkbDescPtr  /* xkb */ ,
1394                             XkbAction * /* action */ ,
1395                             char *      /* buf */ ,
1396                             int *       /* sz */
1397     );
1398 
1399 static actionCopy copyActionArgs[XkbSA_NumActions] = {
1400     CopyNoActionArgs            /* NoAction     */ ,
1401     CopyModActionArgs           /* SetMods      */ ,
1402     CopyModActionArgs           /* LatchMods    */ ,
1403     CopyModActionArgs           /* LockMods     */ ,
1404     CopyGroupActionArgs         /* SetGroup     */ ,
1405     CopyGroupActionArgs         /* LatchGroup   */ ,
1406     CopyGroupActionArgs         /* LockGroup    */ ,
1407     CopyMovePtrArgs             /* MovePtr      */ ,
1408     CopyPtrBtnArgs              /* PtrBtn       */ ,
1409     CopyPtrBtnArgs              /* LockPtrBtn   */ ,
1410     CopySetPtrDfltArgs          /* SetPtrDflt   */ ,
1411     CopyISOLockArgs             /* ISOLock      */ ,
1412     CopyNoActionArgs            /* Terminate    */ ,
1413     CopySwitchScreenArgs        /* SwitchScreen */ ,
1414     CopySetLockControlsArgs     /* SetControls  */ ,
1415     CopySetLockControlsArgs     /* LockControls */ ,
1416     CopyActionMessageArgs       /* ActionMessage */ ,
1417     CopyRedirectKeyArgs         /* RedirectKey  */ ,
1418     CopyDeviceBtnArgs           /* DeviceBtn    */ ,
1419     CopyDeviceBtnArgs           /* LockDeviceBtn */
1420 };
1421 
1422 #define	ACTION_SZ	256
1423 
1424 char *
XkbActionText(Display * dpy,XkbDescPtr xkb,XkbAction * action,unsigned format)1425 XkbActionText(Display *dpy, XkbDescPtr xkb, XkbAction *action, unsigned format)
1426 {
1427     char buf[ACTION_SZ], *tmp;
1428     int sz;
1429 
1430     if (format == XkbCFile) {
1431         snprintf(buf, sizeof(buf),
1432                 "{ %20s, { 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x } }",
1433                 XkbActionTypeText(action->type, XkbCFile),
1434                 action->any.data[0], action->any.data[1], action->any.data[2],
1435                 action->any.data[3], action->any.data[4], action->any.data[5],
1436                 action->any.data[6]);
1437     }
1438     else {
1439         snprintf(buf, sizeof(buf),
1440                  "%s(", XkbActionTypeText(action->type, XkbXKBFile));
1441         sz = ACTION_SZ - strlen(buf) + 2;       /* room for close paren and NULL */
1442         if (action->type < (unsigned) XkbSA_NumActions)
1443             (*copyActionArgs[action->type]) (dpy, xkb, action, buf, &sz);
1444         else
1445             CopyOtherArgs(dpy, xkb, action, buf, &sz);
1446         TryCopyStr(buf, ")", &sz);
1447     }
1448     tmp = tbGetBuffer(strlen(buf) + 1);
1449     if (tmp != NULL)
1450         strcpy(tmp, buf);
1451     return tmp;
1452 }
1453 
1454 char *
XkbBehaviorText(XkbDescPtr xkb,XkbBehavior * behavior,unsigned format)1455 XkbBehaviorText(XkbDescPtr xkb, XkbBehavior * behavior, unsigned format)
1456 {
1457     char buf[256], *tmp;
1458 
1459     if (format == XkbCFile) {
1460         if (behavior->type == XkbKB_Default)
1461             snprintf(buf, sizeof(buf), "{   0,    0 }");
1462         else
1463             snprintf(buf, sizeof(buf), "{ %3d, 0x%02x }", behavior->type, behavior->data);
1464     }
1465     else {
1466         unsigned type, permanent;
1467 
1468         type = behavior->type & XkbKB_OpMask;
1469         permanent = ((behavior->type & XkbKB_Permanent) != 0);
1470 
1471         if (type == XkbKB_Lock) {
1472             snprintf(buf, sizeof(buf), "lock= %s", (permanent ? "Permanent" : "True"));
1473         }
1474         else if (type == XkbKB_RadioGroup) {
1475             int g;
1476             char *tmp;
1477             size_t tmpsize;
1478 
1479             g = ((behavior->data) & (~XkbKB_RGAllowNone)) + 1;
1480             if (XkbKB_RGAllowNone & behavior->data) {
1481                 snprintf(buf, sizeof(buf), "allowNone,");
1482                 tmp = &buf[strlen(buf)];
1483             }
1484             else
1485                 tmp = buf;
1486             tmpsize = sizeof(buf) - (tmp - buf);
1487             if (permanent)
1488                 snprintf(tmp, tmpsize, "permanentRadioGroup= %d", g);
1489             else
1490                 snprintf(tmp, tmpsize, "radioGroup= %d", g);
1491         }
1492         else if ((type == XkbKB_Overlay1) || (type == XkbKB_Overlay2)) {
1493             int ndx, kc;
1494             char *kn;
1495 
1496             ndx = ((type == XkbKB_Overlay1) ? 1 : 2);
1497             kc = behavior->data;
1498             if ((xkb) && (xkb->names) && (xkb->names->keys))
1499                 kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1500             else {
1501                 static char tbuf[8];
1502 
1503                 snprintf(tbuf, sizeof(tbuf), "%d", kc);
1504                 kn = tbuf;
1505             }
1506             if (permanent)
1507                 snprintf(buf, sizeof(buf), "permanentOverlay%d= %s", ndx, kn);
1508             else
1509                 snprintf(buf, sizeof(buf), "overlay%d= %s", ndx, kn);
1510         }
1511     }
1512     tmp = tbGetBuffer(strlen(buf) + 1);
1513     if (tmp != NULL)
1514         strcpy(tmp, buf);
1515     return tmp;
1516 }
1517 
1518 /***====================================================================***/
1519 
1520 char *
XkbIndentText(unsigned size)1521 XkbIndentText(unsigned size)
1522 {
1523     static char buf[32];
1524     register int i;
1525 
1526     if (size > 31)
1527         size = 31;
1528 
1529     for (i = 0; i < size; i++) {
1530         buf[i] = ' ';
1531     }
1532     buf[size] = '\0';
1533     return buf;
1534 }
1535 
1536 
1537 /***====================================================================***/
1538 
1539 #define	PIXEL_MAX	65535
1540 
1541 Bool
XkbLookupCanonicalRGBColor(char * def,XColor * color)1542 XkbLookupCanonicalRGBColor(char *def, XColor *color)
1543 {
1544     int tmp;
1545 
1546     if (_XkbStrCaseEqual(def, "black")) {
1547         color->red = color->green = color->blue = 0;
1548         return True;
1549     }
1550     else if (_XkbStrCaseEqual(def, "white")) {
1551         color->red = color->green = color->blue = PIXEL_MAX;
1552         return True;
1553     }
1554     else if ((sscanf(def, "grey%d", &tmp) == 1) ||
1555              (sscanf(def, "gray%d", &tmp) == 1) ||
1556              (sscanf(def, "Grey%d", &tmp) == 1) ||
1557              (sscanf(def, "Gray%d", &tmp) == 1)) {
1558         if ((tmp > 0) && (tmp <= 100)) {
1559             tmp = (PIXEL_MAX * tmp) / 100;
1560             color->red = color->green = color->blue = tmp;
1561             return True;
1562         }
1563     }
1564     else if ((tmp = (_XkbStrCaseEqual(def, "red") * 100)) ||
1565              (sscanf(def, "red%d", &tmp) == 1)) {
1566         if ((tmp > 0) && (tmp <= 100)) {
1567             tmp = (PIXEL_MAX * tmp) / 100;
1568             color->red = tmp;
1569             color->green = color->blue = 0;
1570             return True;
1571         }
1572     }
1573     else if ((tmp = (_XkbStrCaseEqual(def, "green") * 100)) ||
1574              (sscanf(def, "green%d", &tmp) == 1)) {
1575         if ((tmp > 0) && (tmp <= 100)) {
1576             tmp = (PIXEL_MAX * tmp) / 100;
1577             color->green = tmp;
1578             color->red = color->blue = 0;
1579             return True;
1580         }
1581     }
1582     else if ((tmp = (_XkbStrCaseEqual(def, "blue") * 100)) ||
1583              (sscanf(def, "blue%d", &tmp) == 1)) {
1584         if ((tmp > 0) && (tmp <= 100)) {
1585             tmp = (PIXEL_MAX * tmp) / 100;
1586             color->blue = tmp;
1587             color->red = color->green = 0;
1588             return True;
1589         }
1590     }
1591     else if ((tmp = (_XkbStrCaseEqual(def, "magenta") * 100)) ||
1592              (sscanf(def, "magenta%d", &tmp) == 1)) {
1593         if ((tmp > 0) && (tmp <= 100)) {
1594             tmp = (PIXEL_MAX * tmp) / 100;
1595             color->green = 0;
1596             color->red = color->blue = tmp;
1597             return True;
1598         }
1599     }
1600     else if ((tmp = (_XkbStrCaseEqual(def, "cyan") * 100)) ||
1601              (sscanf(def, "cyan%d", &tmp) == 1)) {
1602         if ((tmp > 0) && (tmp <= 100)) {
1603             tmp = (PIXEL_MAX * tmp) / 100;
1604             color->red = 0;
1605             color->green = color->blue = tmp;
1606             return True;
1607         }
1608     }
1609     else if ((tmp = (_XkbStrCaseEqual(def, "yellow") * 100)) ||
1610              (sscanf(def, "yellow%d", &tmp) == 1)) {
1611         if ((tmp > 0) && (tmp <= 100)) {
1612             tmp = (PIXEL_MAX * tmp) / 100;
1613             color->blue = 0;
1614             color->red = color->green = tmp;
1615             return True;
1616         }
1617     }
1618     return False;
1619 }
1620 
1621