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