1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg
27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
28706f2543Smrg#include <dix-config.h>
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include <stdio.h>
32706f2543Smrg#include <ctype.h>
33706f2543Smrg#include <X11/X.h>
34706f2543Smrg#include <X11/Xos.h>
35706f2543Smrg#include <X11/Xproto.h>
36706f2543Smrg#include <X11/keysym.h>
37706f2543Smrg#include <X11/extensions/XKM.h>
38706f2543Smrg#include "inputstr.h"
39706f2543Smrg#include "scrnintstr.h"
40706f2543Smrg#include "windowstr.h"
41706f2543Smrg#define	XKBSRV_NEED_FILE_FUNCS
42706f2543Smrg#include <xkbsrv.h>
43706f2543Smrg#include <X11/extensions/XI.h>
44706f2543Smrg
45706f2543Smrg#ifdef WIN32
46706f2543Smrg/* from ddxLoad.c */
47706f2543Smrgextern const char* Win32TempDir();
48706f2543Smrgextern int Win32System(const char *cmdline);
49706f2543Smrg#undef System
50706f2543Smrg#define System Win32System
51706f2543Smrg
52706f2543Smrg#define W32_tmparg " '%s'"
53706f2543Smrg#define W32_tmpfile ,tmpname
54706f2543Smrg#define W32_tmplen strlen(tmpname)+3
55706f2543Smrg#else
56706f2543Smrg#define W32_tmparg
57706f2543Smrg#define W32_tmpfile
58706f2543Smrg#define W32_tmplen 0
59706f2543Smrg#endif
60706f2543Smrg
61706f2543Smrg/***====================================================================***/
62706f2543Smrg
63706f2543Smrgstatic char *componentDirs[_XkbListNumComponents] = {
64706f2543Smrg	"keycodes", "types", "compat", "symbols", "geometry"
65706f2543Smrg};
66706f2543Smrg
67706f2543Smrg/***====================================================================***/
68706f2543Smrg
69706f2543Smrgstatic Status
70706f2543Smrg_AddListComponent(	XkbSrvListInfoPtr	list,
71706f2543Smrg			int			what,
72706f2543Smrg			unsigned		flags,
73706f2543Smrg			char *			str,
74706f2543Smrg			ClientPtr		client)
75706f2543Smrg{
76706f2543Smrgint		slen,wlen;
77706f2543Smrgunsigned char *	wire8;
78706f2543Smrgunsigned short *wire16;
79706f2543Smrgchar *		tmp;
80706f2543Smrg
81706f2543Smrg    if (list->nTotal>=list->maxRtrn) {
82706f2543Smrg	list->nTotal++;
83706f2543Smrg	return Success;
84706f2543Smrg    }
85706f2543Smrg    tmp= strchr(str,')');
86706f2543Smrg    if ((tmp==NULL)&&((tmp=strchr(str,'('))==NULL)) {
87706f2543Smrg	slen= strlen(str);
88706f2543Smrg	while ((slen>0) && isspace(str[slen-1])) {
89706f2543Smrg	    slen--;
90706f2543Smrg	}
91706f2543Smrg    }
92706f2543Smrg    else {
93706f2543Smrg	slen= (tmp-str+1);
94706f2543Smrg    }
95706f2543Smrg    wlen= (((slen+1)/2)*2)+4;	/* four bytes for flags and length, pad to */
96706f2543Smrg				/* 2-byte boundary */
97706f2543Smrg    if ((list->szPool-list->nPool)<wlen) {
98706f2543Smrg	if (wlen>1024)	list->szPool+= XkbPaddedSize(wlen*2);
99706f2543Smrg	else		list->szPool+= 1024;
100706f2543Smrg	list->pool= realloc(list->pool, list->szPool * sizeof(char));
101706f2543Smrg	if (!list->pool)
102706f2543Smrg	    return BadAlloc;
103706f2543Smrg    }
104706f2543Smrg    wire16= (unsigned short *)&list->pool[list->nPool];
105706f2543Smrg    wire8= (unsigned char *)&wire16[2];
106706f2543Smrg    wire16[0]= flags;
107706f2543Smrg    wire16[1]= slen;
108706f2543Smrg    memcpy(wire8,str,slen);
109706f2543Smrg    if (client->swapped) {
110706f2543Smrg	register int n;
111706f2543Smrg	swaps(&wire16[0],n);
112706f2543Smrg	swaps(&wire16[1],n);
113706f2543Smrg    }
114706f2543Smrg    list->nPool+= wlen;
115706f2543Smrg    list->nFound[what]++;
116706f2543Smrg    list->nTotal++;
117706f2543Smrg    return Success;
118706f2543Smrg}
119706f2543Smrg
120706f2543Smrg/***====================================================================***/
121706f2543Smrgstatic Status
122706f2543SmrgXkbDDXListComponent(	DeviceIntPtr 		dev,
123706f2543Smrg			int			what,
124706f2543Smrg			XkbSrvListInfoPtr	list,
125706f2543Smrg			ClientPtr		client)
126706f2543Smrg{
127706f2543Smrgchar 	*file,*map,*tmp,*buf=NULL;
128706f2543SmrgFILE 	*in;
129706f2543SmrgStatus	status;
130706f2543Smrgint	rval;
131706f2543SmrgBool	haveDir;
132706f2543Smrg#ifdef WIN32
133706f2543Smrgchar	tmpname[PATH_MAX];
134706f2543Smrg#endif
135706f2543Smrg
136706f2543Smrg    if ((list->pattern[what]==NULL)||(list->pattern[what][0]=='\0'))
137706f2543Smrg	return Success;
138706f2543Smrg    file= list->pattern[what];
139706f2543Smrg    map= strrchr(file,'(');
140706f2543Smrg    if (map!=NULL) {
141706f2543Smrg	char *tmp;
142706f2543Smrg	map++;
143706f2543Smrg	tmp= strrchr(map,')');
144706f2543Smrg	if ((tmp==NULL)||(tmp[1]!='\0')) {
145706f2543Smrg	    /* illegal pattern.  No error, but no match */
146706f2543Smrg	    return Success;
147706f2543Smrg	}
148706f2543Smrg    }
149706f2543Smrg
150706f2543Smrg    in= NULL;
151706f2543Smrg    haveDir= TRUE;
152706f2543Smrg#ifdef WIN32
153706f2543Smrg    strcpy(tmpname, Win32TempDir());
154706f2543Smrg    strcat(tmpname, "\\xkb_XXXXXX");
155706f2543Smrg    (void) mktemp(tmpname);
156706f2543Smrg#endif
157706f2543Smrg    if (XkbBaseDirectory!=NULL) {
158706f2543Smrg	if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) {
159706f2543Smrg	    if (asprintf(&buf, "%s/%s.dir", XkbBaseDirectory,
160706f2543Smrg			 componentDirs[what]) == -1)
161706f2543Smrg		buf = NULL;
162706f2543Smrg	    else
163706f2543Smrg		in = fopen(buf,"r");
164706f2543Smrg	}
165706f2543Smrg	if (!in) {
166706f2543Smrg	    haveDir= FALSE;
167706f2543Smrg	    free(buf);
168706f2543Smrg	    if (asprintf
169706f2543Smrg		(&buf,
170706f2543Smrg		 "'%s/xkbcomp' '-R%s/%s' -w %ld -l -vlfhpR '%s'" W32_tmparg,
171706f2543Smrg		 XkbBinDirectory, XkbBaseDirectory, componentDirs[what],
172706f2543Smrg		 (long) ((xkbDebugFlags < 2) ? 1 :
173706f2543Smrg			 ((xkbDebugFlags > 10) ? 10 : xkbDebugFlags)),
174706f2543Smrg		 file W32_tmpfile
175706f2543Smrg		    ) == -1)
176706f2543Smrg		buf = NULL;
177706f2543Smrg	}
178706f2543Smrg    }
179706f2543Smrg    else {
180706f2543Smrg	if ((list->pattern[what][0]=='*')&&(list->pattern[what][1]=='\0')) {
181706f2543Smrg	    if (asprintf(&buf, "%s.dir", componentDirs[what]) == -1)
182706f2543Smrg		buf = NULL;
183706f2543Smrg	    else
184706f2543Smrg		in = fopen(buf,"r");
185706f2543Smrg	}
186706f2543Smrg	if (!in) {
187706f2543Smrg	    haveDir= FALSE;
188706f2543Smrg	    free(buf);
189706f2543Smrg	    if (asprintf
190706f2543Smrg		(&buf,
191706f2543Smrg		 "xkbcomp -R%s -w %ld -l -vlfhpR '%s'" W32_tmparg,
192706f2543Smrg		 componentDirs[what],
193706f2543Smrg		 (long)	((xkbDebugFlags < 2) ? 1 :
194706f2543Smrg			 ((xkbDebugFlags > 10) ? 10 : xkbDebugFlags)),
195706f2543Smrg		 file W32_tmpfile
196706f2543Smrg		    ) == -1)
197706f2543Smrg		buf = NULL;
198706f2543Smrg	}
199706f2543Smrg    }
200706f2543Smrg    status= Success;
201706f2543Smrg    if (!haveDir)
202706f2543Smrg    {
203706f2543Smrg#ifndef WIN32
204706f2543Smrg	in= Popen(buf,"r");
205706f2543Smrg#else
206706f2543Smrg        if (xkbDebugFlags)
207706f2543Smrg            DebugF("[xkb] xkbList executes: %s\n",buf);
208706f2543Smrg	if (System(buf) < 0)
209706f2543Smrg	    ErrorF("[xkb] Could not invoke keymap compiler\n");
210706f2543Smrg	else
211706f2543Smrg	    in= fopen(tmpname, "r");
212706f2543Smrg#endif
213706f2543Smrg    }
214706f2543Smrg    if (!in)
215706f2543Smrg    {
216706f2543Smrg	free(buf);
217706f2543Smrg#ifdef WIN32
218706f2543Smrg	unlink(tmpname);
219706f2543Smrg#endif
220706f2543Smrg	return BadImplementation;
221706f2543Smrg    }
222706f2543Smrg    list->nFound[what]= 0;
223706f2543Smrg    free(buf);
224706f2543Smrg    buf = malloc(PATH_MAX * sizeof(char));
225706f2543Smrg    if (!buf) {
226706f2543Smrg        fclose(in);
227706f2543Smrg        return BadAlloc;
228706f2543Smrg    }
229706f2543Smrg    while ((status==Success)&&((tmp=fgets(buf,PATH_MAX,in))!=NULL)) {
230706f2543Smrg	unsigned flags;
231706f2543Smrg	register unsigned int i;
232706f2543Smrg	if (*tmp=='#') /* comment, skip it */
233706f2543Smrg	    continue;
234706f2543Smrg	if (!strncmp(tmp, "Warning:", 8) || !strncmp(tmp, "        ", 8))
235706f2543Smrg	    /* skip warnings too */
236706f2543Smrg	    continue;
237706f2543Smrg	flags= 0;
238706f2543Smrg	/* each line in the listing is supposed to start with two */
239706f2543Smrg	/* groups of eight characters, which specify the general  */
240706f2543Smrg	/* flags and the flags that are specific to the component */
241706f2543Smrg	/* if they're missing, fail with BadImplementation	  */
242706f2543Smrg	for (i=0;(i<8)&&(status==Success);i++) { /* read the general flags */
243706f2543Smrg	   if (isalpha(*tmp))	flags|= (1L<<i);
244706f2543Smrg	   else if (*tmp!='-')	status= BadImplementation;
245706f2543Smrg	   tmp++;
246706f2543Smrg	}
247706f2543Smrg	if (status != Success)  break;
248706f2543Smrg	if (!isspace(*tmp)) {
249706f2543Smrg	     status= BadImplementation;
250706f2543Smrg	     break;
251706f2543Smrg	}
252706f2543Smrg	else tmp++;
253706f2543Smrg	for (i=0;(i<8)&&(status==Success);i++) { /* read the component flags */
254706f2543Smrg	   if (isalpha(*tmp))	flags|= (1L<<(i+8));
255706f2543Smrg	   else if (*tmp!='-')	status= BadImplementation;
256706f2543Smrg	   tmp++;
257706f2543Smrg	}
258706f2543Smrg	if (status != Success)  break;
259706f2543Smrg	if (isspace(*tmp)) {
260706f2543Smrg	    while (isspace(*tmp)) {
261706f2543Smrg		tmp++;
262706f2543Smrg	    }
263706f2543Smrg	}
264706f2543Smrg	else {
265706f2543Smrg	    status= BadImplementation;
266706f2543Smrg	    break;
267706f2543Smrg	}
268706f2543Smrg	status= _AddListComponent(list,what,flags,tmp,client);
269706f2543Smrg    }
270706f2543Smrg#ifndef WIN32
271706f2543Smrg    if (haveDir)
272706f2543Smrg	fclose(in);
273706f2543Smrg    else if ((rval=Pclose(in))!=0) {
274706f2543Smrg	if (xkbDebugFlags)
275706f2543Smrg	    ErrorF("[xkb] xkbcomp returned exit code %d\n",rval);
276706f2543Smrg    }
277706f2543Smrg#else
278706f2543Smrg    fclose(in);
279706f2543Smrg    unlink(tmpname);
280706f2543Smrg#endif
281706f2543Smrg    free(buf);
282706f2543Smrg    return status;
283706f2543Smrg}
284706f2543Smrg
285706f2543Smrg/***====================================================================***/
286706f2543Smrg
287706f2543Smrg/* ARGSUSED */
288706f2543SmrgStatus
289706f2543SmrgXkbDDXList(DeviceIntPtr	dev,XkbSrvListInfoPtr list,ClientPtr client)
290706f2543Smrg{
291706f2543SmrgStatus	status;
292706f2543Smrg
293706f2543Smrg    status= XkbDDXListComponent(dev,_XkbListKeycodes,list,client);
294706f2543Smrg    if (status==Success)
295706f2543Smrg	status= XkbDDXListComponent(dev,_XkbListTypes,list,client);
296706f2543Smrg    if (status==Success)
297706f2543Smrg	status= XkbDDXListComponent(dev,_XkbListCompat,list,client);
298706f2543Smrg    if (status==Success)
299706f2543Smrg	status= XkbDDXListComponent(dev,_XkbListSymbols,list,client);
300706f2543Smrg    if (status==Success)
301706f2543Smrg	status= XkbDDXListComponent(dev,_XkbListGeometry,list,client);
302706f2543Smrg    return status;
303706f2543Smrg}
304